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 */
trim(string & s,string characters)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 */
trim_comments(string & s)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 */
get_lines(vector<string> & input,int & linenum,string 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 */
print_line(stringstream & sout,string line)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
main(int argc,char * argv[])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 }