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;
     93 
     94     if (line.substr(0,11) == "LZ4LIB_API ") line = line.substr(11);
     95     spos = line.find("/*");
     96     if (spos!=string::npos) {
     97         sout << line.substr(0, spos);
     98         sout << "</b>" << line.substr(spos) << "<b>" << endl;
     99     } else {
    100       //  fprintf(stderr, "lines=%s\n", line.c_str());
    101         sout << line << endl;
    102     }
    103 }
    104 
    105 
    106 int main(int argc, char *argv[]) {
    107     char exclam;
    108     int linenum, chapter = 1;
    109     vector<string> input, lines, comments, chapters;
    110     string line, version;
    111     size_t spos, l;
    112     stringstream sout;
    113     ifstream istream;
    114     ofstream ostream;
    115 
    116     if (argc < 4) {
    117         cout << "usage: " << argv[0] << " [lz4_version] [input_file] [output_html]" << endl;
    118         return 1;
    119     }
    120 
    121     version = "lz4 " + string(argv[1]) + " Manual";
    122 
    123     istream.open(argv[2], ifstream::in);
    124     if (!istream.is_open()) {
    125         cout << "Error opening file " << argv[2] << endl;
    126         return 1;
    127     }
    128 
    129     ostream.open(argv[3], ifstream::out);
    130     if (!ostream.is_open()) {
    131         cout << "Error opening file " << argv[3] << endl;
    132         return 1;
    133    }
    134 
    135     while (getline(istream, line)) {
    136         input.push_back(line);
    137     }
    138 
    139     for (linenum=0; (size_t)linenum < input.size(); linenum++) {
    140         line = input[linenum];
    141 
    142         /* typedefs are detected and included even if uncommented */
    143         if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
    144             lines = get_lines(input, linenum, "}");
    145             sout << "<pre><b>";
    146             for (l=0; l<lines.size(); l++) {
    147                 print_line(sout, lines[l]);
    148             }
    149             sout << "</b></pre><BR>" << endl;
    150             continue;
    151         }
    152 
    153         /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */
    154         if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) {
    155             sout << "<pre><b>";
    156             print_line(sout, line);
    157             sout << "</b></pre><BR>" << endl;
    158             continue;
    159         }
    160 
    161         /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */
    162         if ((line.substr(0,3) == "/*=" || line.substr(0,4) == "/**=") && line.find("*/")!=string::npos) {
    163             trim_comments(line);
    164             trim(line, "= ");
    165             sout << "<h3>" << line << "</h3><pre><b>";
    166             lines = get_lines(input, ++linenum, "");
    167             for (l=0; l<lines.size(); l++) {
    168                 print_line(sout, lines[l]);
    169             }
    170             sout << "</b></pre><BR>" << endl;
    171             continue;
    172         }
    173 
    174         spos = line.find("/*!");
    175         if (spos==string::npos)
    176             spos = line.find("/**");
    177         if (spos==string::npos)
    178             spos = line.find("/*-");
    179 
    180         if (spos==string::npos)
    181             continue;
    182 
    183         exclam = line[spos+2];
    184         comments = get_lines(input, linenum, "*/");
    185         if (!comments.empty()) comments[0] = line.substr(spos+3);
    186         if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/"));
    187         for (l=0; l<comments.size(); l++) {
    188             if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2);
    189             else if (comments[l].find("  *")==0) comments[l] = comments[l].substr(3);
    190             trim(comments[l], "*-");
    191         }
    192         while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
    193         while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
    194 
    195         /* comments of type /*! mean: this is a function declaration; switch comments with declarations */
    196         if (exclam == '!') {
    197             if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "LZ4_XXX() :" */
    198             linenum++;
    199             lines = get_lines(input, linenum, "");
    200 
    201             sout << "<pre><b>";
    202             for (l=0; l<lines.size(); l++) {
    203               //  fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str());
    204                 print_line(sout, lines[l]);
    205             }
    206             sout << "</b><p>";
    207             for (l=0; l<comments.size(); l++) {
    208                 print_line(sout, comments[l]);
    209             }
    210             sout << "</p></pre><BR>" << endl << endl;
    211         } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */
    212             if (comments.empty()) continue;
    213 
    214             trim(comments[0], " ");
    215             sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
    216             chapters.push_back(comments[0]);
    217             chapter++;
    218 
    219             for (l=1; l<comments.size(); l++) {
    220                 print_line(sout, comments[l]);
    221             }
    222             if (comments.size() > 1)
    223                 sout << "<BR></pre>" << endl << endl;
    224             else
    225                 sout << "</pre>" << endl << endl;
    226         }
    227     }
    228 
    229     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;
    230     ostream << "<h1>" << version << "</h1>\n";
    231 
    232     ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
    233     for (size_t i=0; i<chapters.size(); i++)
    234         ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
    235     ostream << "</ol>\n<hr>\n";
    236 
    237     ostream << sout.str();
    238     ostream << "</html>" << endl << "</body>" << endl;
    239 
    240     return 0;
    241 }
    242