HTML Tidy Sample Program in C++17 This is an exercise to use C++, Cevelop IDE &amp; libtidy rather than the HTML Tidy command line tool. The program just reads from standarg input, processes the contents with HTML Tidy then puts the cleaned up version to standard out. Errors and diagnostics go to standard error. Function tidyit takes a std::string and returns one with error messages going to stderr while main handles the standard I/O.

I am using the most current C++17 with no concerns for older versions. The version of Cevelop IDE is 1.7.1. HTML Tidy provides both a command line tool and a C library, libtidy. The code is based upon the C code in the Sample Program. 

I am looking for improvements given it is in C++ rather than the original in C.

// tidyit.cpp
#include &lt;sstream&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;

const std::string tidyit(const std::string a_input);           // Change to auto in cevelop 1.8.

int main(int argc, char **argv) {
   std::stringstream input;
   input &lt;&lt; std::cin.rdbuf();
   std::cout &lt;&lt; tidyit(input.str());
   }

#include &lt;tidy/tidy.h&gt;
#include &lt;tidy/buffio.h&gt;

bool is_severe_error(int a_code){return (a_code&lt;0);}           // Change to auto in cevelop 1.8.

const std::string tidyit(const std::string a_input) {          // Change to auto in cevelop 1.8.
   TidyBuffer errbuf = {0}, outbuf = {0};
   TidyDoc tdoc = tidyCreate();
   tidyOptSetInt(tdoc, TidyIndentContent, yes);
   tidyOptSetBool(tdoc, TidyXhtmlOut, yes);
   tidyOptSetBool(tdoc, TidyForceOutput,yes);
   int rc{-1};                                                 // Change to auto in cevelop 1.8.
   if (is_severe_error(rc=tidySetErrorBuffer(tdoc, &amp;errbuf))
         || is_severe_error(rc=tidyParseString(tdoc, a_input.c_str()))
         || is_severe_error(rc=tidyCleanAndRepair(tdoc))
         || is_severe_error(rc=tidyRunDiagnostics(tdoc))
         || is_severe_error(rc=tidySaveBuffer(tdoc,&amp;outbuf))){
      std::cerr &lt;&lt; "tidyit-A severe error (" &lt;&lt; rc &lt;&lt; ") occurred.\n";
      }
   else {
      if(errbuf.bp)
         std::cerr &lt;&lt; "tidyit-Diagnostics:\n\n" &lt;&lt; errbuf.bp &lt;&lt; "\n";
      }
   const std::string outstr{(char*)(outbuf.bp)};
   tidyBufFree(&amp;outbuf);
   tidyBufFree(&amp;errbuf);
   tidyRelease(tdoc);
   return outstr;
   }


Cevelop C++ IDE 


  Version: 1.7.1-201704211123


Compiler info


  Command: clang++-4.0
  
  All options: -std=c++1z -O0 -g3 -Wall -c -fmessage-length=0
  -Wno-attributes


Library info


  Libraries: tidy


Updated code available at: CodeReview - HTML Tidy Sample Program in C++17 (pastebin)
Observation.

Though you are compiling this with a C++ compiler and using a couple of C++ classes this is still C code. The style is C and does not reflect the standard idioms of C++.

We refer to code written like this as "C with classes".

Exception Safety

When you see code that looks like:

&lt;Create Resource&gt;

&lt;Do Stuff&gt;

&lt;Destroy Resource&gt;


This is not exception safe. If the code in &lt;Do Stuff&gt; throws an exception then &lt;Destroy Resource&gt; will not be executed. Now you think none of this code throws exceptions and Tidy is a C-library so it will not. But I bet Tidy allows you to register callbacks. These callbacks can throw exceptions and eventually you will add one to the code.

Example:

   TidyDoc tdoc = tidyCreate();
   // Stuff
   tidyRelease(tdoc);


The correct way to do this is to use the RAII idiom. This means creating a class where the constructor allocates the resource and the destructor deallocates the resource.

Since the destructor of an object is automatically called when an object goes out of scope (this includes when the stack is unwound by an exception being thrown) this makes resource allocation/deallocation exception safe.

class TidyDocCPP
{
    TidyDoc tdoc;
    public:
        TidyDocCPP() {
            tdoc = tidyCreate();
        }
        ~TidyDocCPP() {
            tidyRelease(tdoc);
        }
        // This is used to convert an object back to the C form
        // so it can be used in the normal C tidy functions.
        operator TidyDoc() const {
            return tdoc;
        }

        // Need to do this to satisfy rule of 5
        // Don't worry about this section yet.
        TidyDocCPP(TidyDocCPP const&amp;)            = delete;
        TidyDocCPP(TidyDocCPP&amp;&amp;)                 = delete;
        TidyDocCPP&amp; operator=(TidyDocCPP const&amp;) = delete;
        TidyDocCPP&amp; operator=(TidyDocCPP&amp;&amp;)      = delete;
};


Now it can be used like this:

{
    TidyDocCPP    doc;
    tidyOptSetInt(doc, TidyIndentContent, yes); // doc is auto converted
}
// doc goes out of scope here.
// This calls the destructor and releases the resource.


Design

You read the input into a string. Then pass this string to tidyit().

The first issue I have with this is that you pass the string by value. This basically makes a copy of the whole string. Given that modern web pages are huge this is a terrible idea. The main page of stackoverflow.com is 250K.

You should pass immutable strings by const reference (this prevents the copy but still allows full read access).

But even reading the data into a string is incorrect. You have a stream of data (the input) you should use Tidy stream reading capabilities.

Rather than using

 tidyParseString(tdoc, a_input.c_str()


You should use:

 tidyParseStdin(doc);


If you want to be more generic:

 tidyParseSource(doc, inputSource);
 // You will need to build a wrapper aournd TidyInputSource
 // http://tidy.sourceforge.net/docs/api/group__IO.html#g86fcc3c86bd63b26a559938bc38d34bb


Vertical Space

Add vertical space to make your code readable. The current way it is all jammed together makes it highly unreadable.

Brace Alignment

Use one of the standard brae alignment strategies. Yours does not match any standard I have seen.

// K&amp;R Style.  Very common
if () {
}

// Allman.     Very common
if ()
{
}


What you are using seems to be a mix of K&amp;R and Ratliff Style

// Ratliff     Very uncommon
if () {
    }


I have never seen it outside this wikipedia page: https://en.wikipedia.org/wiki/Indent_style 

Pick one and use it consistently.