Home | History | Annotate | Download | only in gen_manual
      1 /*
      2 Copyright (c) 2016-present, Przemyslaw Skibinski
      3 All rights reserved.
      4 
      5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
      6 
      7 Redistribution and use in source and binary forms, with or without
      8 modification, are permitted provided that the following conditions are
      9 met:
     10 
     11 * Redistributions of source code must retain the above copyright
     12 notice, this list of conditions and the following disclaimer.
     13 * Redistributions in binary form must reproduce the above
     14 copyright notice, this list of conditions and the following disclaimer
     15 in the documentation and/or other materials provided with the
     16 distribution.
     17 
     18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 You can contact the author at :
     31 - LZ4 homepage : http://www.lz4.org
     32 - LZ4 source repository : https://github.com/lz4/lz4
     33 */
     34 
     35 #include <iostream>
     36 #include <fstream>
     37 #include <sstream>
     38 #include <vector>
     39 using namespace std;
     40 
     41 
     42 /* trim string at the beginning and at the end */
     43 void trim(string& s, string characters)
     44 {
     45     size_t p = s.find_first_not_of(characters);
     46     s.erase(0, p);
     47 
     48     p = s.find_last_not_of(characters);
     49     if (string::npos != p)
     50        s.erase(p+1);
     51 }
     52 
     53 
     54 /* trim C++ style comments */
     55 void trim_comments(string &s)
     56 {
     57     size_t spos, epos;
     58 
     59     spos = s.find("/*");
     60     epos = s.find("*/");
     61     s = s.substr(spos+3, epos-(spos+3));
     62 }
     63 
     64 
     65 /* get lines until a given terminator */
     66 vector<string> get_lines(vector<string>& input, int& linenum, string terminator)
     67 {
     68     vector<string> out;
     69     string line;
     70     size_t epos;
     71 
     72     while ((size_t)linenum < input.size()) {
     73         line = input[linenum];
     74 
     75         if (terminator.empty() && line.empty()) { linenum--; break; }
     76 
     77         epos = line.find(terminator);
     78         if (!terminator.empty() && epos!=string::npos) {
     79             out.push_back(line);
     80             break;
     81         }
     82         out.push_back(line);
     83         linenum++;
     84     }
     85     return out;
     86 }
     87 
     88 
     89 /* print line with LZ4LIB_API removed and C++ comments not bold */
     90 void print_line(stringstream &sout, string line)
     91 {
     92     size_t spos, epos;
     93 
     94     if (line.substr(0,11) == "LZ4LIB_API ") line = line.substr(11);
     95     if (line.substr(0,12) == "LZ4FLIB_API ") line = line.substr(12);
     96     spos = line.find("/*");
     97     epos = line.find("*/");
     98     if (spos!=string::npos && epos!=string::npos) {
     99         sout << line.substr(0, spos);
    100         sout << "</b>" << line.substr(spos) << "<b>" << endl;
    101     } else {
    102       //  fprintf(stderr, "lines=%s\n", line.c_str());
    103         sout << line << endl;
    104     }
    105 }
    106 
    107 
    108 int main(int argc, char *argv[]) {
    109     char exclam;
    110     int linenum, chapter = 1;
    111     vector<string> input, lines, comments, chapters;
    112     string line, version;
    113     size_t spos, l;
    114     stringstream sout;
    115     ifstream istream;
    116     ofstream ostream;
    117 
    118     if (argc < 4) {
    119         cout << "usage: " << argv[0] << " [lz4_version] [input_file] [output_html]" << endl;
    120         return 1;
    121     }
    122 
    123     version = string(argv[1]) + " Manual";
    124 
    125     istream.open(argv[2], ifstream::in);
    126     if (!istream.is_open()) {
    127         cout << "Error opening file " << argv[2] << endl;
    128         return 1;
    129     }
    130 
    131     ostream.open(argv[3], ifstream::out);
    132     if (!ostream.is_open()) {
    133         cout << "Error opening file " << argv[3] << endl;
    134         return 1;
    135    }
    136 
    137     while (getline(istream, line)) {
    138         input.push_back(line);
    139     }
    140 
    141     for (linenum=0; (size_t)linenum < input.size(); linenum++) {
    142         line = input[linenum];
    143 
    144         /* typedefs are detected and included even if uncommented */
    145         if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
    146             lines = get_lines(input, linenum, "}");
    147             sout << "<pre><b>";
    148             for (l=0; l<lines.size(); l++) {
    149                 print_line(sout, lines[l]);
    150             }
    151             sout << "</b></pre><BR>" << endl;
    152             continue;
    153         }
    154 
    155         /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */
    156         if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) {
    157             sout << "<pre><b>";
    158             print_line(sout, line);
    159             sout << "</b></pre><BR>" << endl;
    160             continue;
    161         }
    162 
    163         spos = line.find("/**=");
    164         if (spos==string::npos) {
    165             spos = line.find("/*!");
    166             if (spos==string::npos)
    167                 spos = line.find("/**");
    168             if (spos==string::npos)
    169                 spos = line.find("/*-");
    170             if (spos==string::npos)
    171                 spos = line.find("/*=");
    172             if (spos==string::npos)
    173                 continue;
    174             exclam = line[spos+2];
    175         }
    176         else exclam = '=';
    177 
    178         comments = get_lines(input, linenum, "*/");
    179         if (!comments.empty()) comments[0] = line.substr(spos+3);
    180         if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/"));
    181         for (l=0; l<comments.size(); l++) {
    182             if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2);
    183             else if (comments[l].find("  *")==0) comments[l] = comments[l].substr(3);
    184             trim(comments[l], "*-=");
    185         }
    186         while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
    187         while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
    188 
    189         /* comments of type /*! mean: this is a function declaration; switch comments with declarations */
    190         if (exclam == '!') {
    191             if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "LZ4_XXX() :" */
    192             linenum++;
    193             lines = get_lines(input, linenum, "");
    194 
    195             sout << "<pre><b>";
    196             for (l=0; l<lines.size(); l++) {
    197               //  fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str());
    198                 print_line(sout, lines[l]);
    199             }
    200             sout << "</b><p>";
    201             for (l=0; l<comments.size(); l++) {
    202                 print_line(sout, comments[l]);
    203             }
    204             sout << "</p></pre><BR>" << endl << endl;
    205         } else if (exclam == '=') { /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */
    206             trim(comments[0], " ");
    207             sout << "<h3>" << comments[0] << "</h3><pre>";
    208             for (l=1; l<comments.size(); l++) {
    209                 print_line(sout, comments[l]);
    210             }
    211             sout << "</pre><b><pre>";
    212             lines = get_lines(input, ++linenum, "");
    213             for (l=0; l<lines.size(); l++) {
    214                 print_line(sout, lines[l]);
    215             }
    216             sout << "</pre></b><BR>" << endl;
    217         } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */
    218             if (comments.empty()) continue;
    219 
    220             trim(comments[0], " ");
    221             sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
    222             chapters.push_back(comments[0]);
    223             chapter++;
    224 
    225             for (l=1; l<comments.size(); l++) {
    226                 print_line(sout, comments[l]);
    227             }
    228             if (comments.size() > 1)
    229                 sout << "<BR></pre>" << endl << endl;
    230             else
    231                 sout << "</pre>" << endl << endl;
    232         }
    233     }
    234 
    235     ostream << "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>" << version << "</title>\n</head>\n<body>" << endl;
    236     ostream << "<h1>" << version << "</h1>\n";
    237 
    238     ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
    239     for (size_t i=0; i<chapters.size(); i++)
    240         ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
    241     ostream << "</ol>\n<hr>\n";
    242 
    243     ostream << sout.str();
    244     ostream << "</html>" << endl << "</body>" << endl;
    245 
    246     return 0;
    247 }