Home | History | Annotate | Line # | Download | only in gen_html
      1 /*
      2  * Copyright (c) Meta Platforms, Inc. and affiliates.
      3  * All rights reserved.
      4  *
      5  * This source code is licensed under both the BSD-style license (found in the
      6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
      7  * in the COPYING file in the root directory of this source tree).
      8  */
      9 
     10 #include <iostream>
     11 #include <fstream>
     12 #include <sstream>
     13 #include <vector>
     14 using namespace std;
     15 
     16 
     17 /* trim string at the beginning and at the end */
     18 void trim(string& s, string characters)
     19 {
     20     size_t p = s.find_first_not_of(characters);
     21     s.erase(0, p);
     22 
     23     p = s.find_last_not_of(characters);
     24     if (string::npos != p)
     25        s.erase(p+1);
     26 }
     27 
     28 
     29 /* trim C++ style comments */
     30 void trim_comments(string &s)
     31 {
     32     size_t spos, epos;
     33 
     34     spos = s.find("/*");
     35     epos = s.find("*/");
     36     s = s.substr(spos+3, epos-(spos+3));
     37 }
     38 
     39 
     40 /* get lines until a given terminator */
     41 vector<string> get_lines(vector<string>& input, int& linenum, string terminator)
     42 {
     43     vector<string> out;
     44     string line;
     45     size_t epos;
     46 
     47     while ((size_t)linenum < input.size()) {
     48         line = input[linenum];
     49 
     50         if (terminator.empty() && line.empty()) { linenum--; break; }
     51 
     52         epos = line.find(terminator);
     53         if (!terminator.empty() && epos!=string::npos) {
     54             out.push_back(line);
     55             break;
     56         }
     57         out.push_back(line);
     58         linenum++;
     59     }
     60     return out;
     61 }
     62 
     63 
     64 /* print line with ZSTDLIB_API removed and C++ comments not bold */
     65 void print_line(stringstream &sout, string line)
     66 {
     67     size_t spos;
     68 
     69     if (line.substr(0,12) == "ZSTDLIB_API ") line = line.substr(12);
     70     spos = line.find("/*");
     71     if (spos!=string::npos) {
     72         sout << line.substr(0, spos);
     73         sout << "</b>" << line.substr(spos) << "<b>" << endl;
     74     } else {
     75       //  fprintf(stderr, "lines=%s\n", line.c_str());
     76         sout << line << endl;
     77     }
     78 }
     79 
     80 
     81 int main(int argc, char *argv[]) {
     82     char exclam;
     83     int linenum, chapter = 1;
     84     vector<string> input, lines, comments, chapters;
     85     string line, version;
     86     size_t spos, l;
     87     stringstream sout;
     88     ifstream istream;
     89     ofstream ostream;
     90 
     91     if (argc < 4) {
     92         cout << "usage: " << argv[0] << " [zstd_version] [input_file] [output_html]" << endl;
     93         return 1;
     94     }
     95 
     96     version = "zstd " + string(argv[1]) + " Manual";
     97 
     98     istream.open(argv[2], ifstream::in);
     99     if (!istream.is_open()) {
    100         cout << "Error opening file " << argv[2] << endl;
    101         return 1;
    102     }
    103 
    104     ostream.open(argv[3], ifstream::out);
    105     if (!ostream.is_open()) {
    106         cout << "Error opening file " << argv[3] << endl;
    107         return 1;
    108    }
    109 
    110     while (getline(istream, line)) {
    111         input.push_back(line);
    112     }
    113 
    114     for (linenum=0; (size_t)linenum < input.size(); linenum++) {
    115         line = input[linenum];
    116 
    117         /* typedefs are detected and included even if uncommented */
    118         if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
    119             lines = get_lines(input, linenum, "}");
    120             sout << "<pre><b>";
    121             for (l=0; l<lines.size(); l++) {
    122                 print_line(sout, lines[l]);
    123             }
    124             sout << "</b></pre><BR>" << endl;
    125             continue;
    126         }
    127 
    128         /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */
    129         if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) {
    130             sout << "<pre><b>";
    131             print_line(sout, line);
    132             sout << "</b></pre><BR>" << endl;
    133             continue;
    134         }
    135 
    136         spos = line.find("/**=");
    137         if (spos==string::npos) {
    138             spos = line.find("/*!");
    139             if (spos==string::npos)
    140                 spos = line.find("/**");
    141             if (spos==string::npos)
    142                 spos = line.find("/*-");
    143             if (spos==string::npos)
    144                 spos = line.find("/*=");
    145             if (spos==string::npos)
    146                 continue;
    147             exclam = line[spos+2];
    148         }
    149         else exclam = '=';
    150 
    151         comments = get_lines(input, linenum, "*/");
    152         if (!comments.empty()) comments[0] = line.substr(spos+3);
    153         if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/"));
    154         for (l=0; l<comments.size(); l++) {
    155             if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2);
    156             else if (comments[l].find("  *")==0) comments[l] = comments[l].substr(3);
    157             trim(comments[l], "*-=");
    158         }
    159         while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
    160         while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
    161 
    162         /* comments of type /*! mean: this is a function declaration; switch comments with declarations */
    163         if (exclam == '!') {
    164             if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "ZSTD_XXX() :" */
    165             linenum++;
    166             lines = get_lines(input, linenum, "");
    167 
    168             sout << "<pre><b>";
    169             for (l=0; l<lines.size(); l++) {
    170               //  fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str());
    171                 string fline = lines[l];
    172                 if (fline.substr(0, 12) == "ZSTDLIB_API " ||
    173                     fline.substr(0, 12) == string(12, ' '))
    174                   fline = fline.substr(12);
    175                 print_line(sout, fline);
    176             }
    177             sout << "</b><p>";
    178             for (l=0; l<comments.size(); l++) {
    179                 print_line(sout, comments[l]);
    180             }
    181             sout << "</p></pre><BR>" << endl << endl;
    182         } else if (exclam == '=') { /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */
    183             trim(comments[0], " ");
    184             sout << "<h3>" << comments[0] << "</h3><pre>";
    185             for (l=1; l<comments.size(); l++) {
    186                 print_line(sout, comments[l]);
    187             }
    188             sout << "</pre><b><pre>";
    189             lines = get_lines(input, ++linenum, "");
    190             for (l=0; l<lines.size(); l++) {
    191                 print_line(sout, lines[l]);
    192             }
    193             sout << "</pre></b><BR>" << endl;
    194         } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */
    195             if (comments.empty()) continue;
    196 
    197             trim(comments[0], " ");
    198             sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
    199             chapters.push_back(comments[0]);
    200             chapter++;
    201 
    202             for (l=1; l<comments.size(); l++) {
    203                 print_line(sout, comments[l]);
    204             }
    205             if (comments.size() > 1)
    206                 sout << "<BR></pre>" << endl << endl;
    207             else
    208                 sout << "</pre>" << endl << endl;
    209         }
    210     }
    211 
    212     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;
    213     ostream << "<h1>" << version << "</h1>\n";
    214     ostream << "Note: the content of this file has been automatically generated by parsing \"zstd.h\" \n";
    215 
    216     ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
    217     for (size_t i=0; i<chapters.size(); i++)
    218         ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
    219     ostream << "</ol>\n<hr>\n";
    220 
    221     ostream << sout.str();
    222     ostream << "</html>" << endl << "</body>" << endl;
    223 
    224     return 0;
    225 }
    226