• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>" << '\n';
100     } else {
101         sout << line << '\n';
102     }
103 }
104 
105 
main(int argc,char * argv[])106 int main(int argc, char *argv[]) {
107     char exclam;
108     int linenum, chapter = 1;
109     vector<string> input, lines, comments, chapters;
110     string line, version;
111     size_t spos, l;
112     stringstream sout;
113     ifstream istream;
114     ofstream ostream;
115 
116     if (argc < 4) {
117         cout << "usage: " << argv[0] << " [lz4_version] [input_file] [output_html]" << endl;
118         return 1;
119     }
120 
121     version = string(argv[1]) + " Manual";
122 
123     istream.open(argv[2], ifstream::in);
124     if (!istream.is_open()) {
125         cout << "Error opening file " << argv[2] << endl;
126         return 1;
127     }
128 
129     ostream.open(argv[3], ifstream::out);
130     if (!ostream.is_open()) {
131         cout << "Error opening file " << argv[3] << endl;
132         return 1;
133    }
134 
135     while (getline(istream, line)) {
136         input.push_back(line);
137     }
138 
139     for (linenum=0; (size_t)linenum < input.size(); linenum++) {
140         line = input[linenum];
141 
142         /* typedefs are detected and included even if uncommented */
143         if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
144             lines = get_lines(input, linenum, "}");
145             sout << "<pre><b>";
146             for (l=0; l<lines.size(); l++) {
147                 print_line(sout, lines[l]);
148             }
149             sout << "</b></pre><BR>" << endl;
150             continue;
151         }
152 
153         /* comments of type  / * * < and  / * ! <  are detected, and only function declaration is highlighted (bold) */
154         if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos)
155           && line.find("*/")!=string::npos) {
156             sout << "<pre><b>";
157             print_line(sout, line);
158             sout << "</b></pre><BR>" << endl;
159             continue;
160         }
161 
162         spos = line.find("/**=");
163         if (spos==string::npos) {
164             spos = line.find("/*!");
165             if (spos==string::npos)
166                 spos = line.find("/**");
167             if (spos==string::npos)
168                 spos = line.find("/*-");
169             if (spos==string::npos)
170                 spos = line.find("/*=");
171             if (spos==string::npos)
172                 continue;
173             exclam = line[spos+2];
174         }
175         else exclam = '=';
176 
177         comments = get_lines(input, linenum, "*/");
178         if (!comments.empty()) comments[0] = line.substr(spos+3);
179         if (!comments.empty())
180             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].compare(0, 2, " *") == 0)
183                 comments[l] = comments[l].substr(2);
184             else if (comments[l].compare(0, 3, "  *") == 0)
185                 comments[l] = comments[l].substr(3);
186             trim(comments[l], "*-=");
187         }
188         while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
189         while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
190 
191         /* comments of type  / * !  mean: this is a function declaration; switch comments with declarations */
192         if (exclam == '!') {
193             if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "LZ4_XXX() :" */
194             linenum++;
195             lines = get_lines(input, linenum, "");
196 
197             sout << "<pre><b>";
198             for (l=0; l<lines.size(); l++) {
199                 print_line(sout, lines[l]);
200             }
201             sout << "</b><p>";
202             for (l=0; l<comments.size(); l++) {
203                 print_line(sout, comments[l]);
204             }
205             sout << "</p></pre><BR>" << endl << endl;
206         } else if (exclam == '=') { /* comments of type  / * =  and  / * * =  mean: use a <H3> header and show also all functions until first empty line */
207             trim(comments[0], " ");
208             sout << "<h3>" << comments[0] << "</h3><pre>";
209             for (l=1; l<comments.size(); l++) {
210                 print_line(sout, comments[l]);
211             }
212             sout << "</pre><b><pre>";
213             lines = get_lines(input, ++linenum, "");
214             for (l=0; l<lines.size(); l++) {
215                 print_line(sout, lines[l]);
216             }
217             sout << "</pre></b><BR>" << endl;
218         } else { /* comments of type  / * *  and  / * -  mean: this is a comment; use a <H2> header for the first line */
219             if (comments.empty()) continue;
220 
221             trim(comments[0], " ");
222             sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
223             chapters.push_back(comments[0]);
224             chapter++;
225 
226             for (l=1; l<comments.size(); l++) {
227                 print_line(sout, comments[l]);
228             }
229             if (comments.size() > 1)
230                 sout << "<BR></pre>" << endl << endl;
231             else
232                 sout << "</pre>" << endl << endl;
233         }
234     }
235 
236     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;
237     ostream << "<h1>" << version << "</h1>\n";
238 
239     ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
240     for (size_t i=0; i<chapters.size(); i++)
241         ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
242     ostream << "</ol>\n<hr>\n";
243 
244     ostream << sout.str();
245     ostream << "</html>" << endl << "</body>" << endl;
246 
247     return 0;
248 }
249