• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016-present, Przemyslaw Skibinski, Facebook, Inc.
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 */
trim(string & s,string characters)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 */
trim_comments(string & s)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 */
get_lines(vector<string> & input,int & linenum,string 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 */
print_line(stringstream & sout,string line)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 
main(int argc,char * argv[])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 
215     ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
216     for (size_t i=0; i<chapters.size(); i++)
217         ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
218     ostream << "</ol>\n<hr>\n";
219 
220     ostream << sout.str();
221     ostream << "</html>" << endl << "</body>" << endl;
222 
223     return 0;
224 }
225