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