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