Rizin
unix-like reverse engineering framework and cli tools
gen_manual.cpp
Go to the documentation of this file.
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 */
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 */
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 */
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 */
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 
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 }
static char * version
Definition: acr.h:4
lzma_index ** i
Definition: index.h:629
static RzBinSourceLineInfo * lines(RzBinFile *bf)
Definition: bin_symbols.c:427
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
int main(int argc, char *argv[])
Definition: gen_manual.cpp:106
vector< string > get_lines(vector< string > &input, int &linenum, string terminator)
Definition: gen_manual.cpp:66
void trim_comments(string &s)
Definition: gen_manual.cpp:55
void print_line(stringstream &sout, string line)
Definition: gen_manual.cpp:89
void trim(string &s, string characters)
Definition: gen_manual.cpp:43
void * p
Definition: libc.cpp:67
static int compare(const char *s1, const char *s2, int l1, int l2)
Definition: chmd.c:864
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
line
Definition: setup.py:34
static RzSocket * s
Definition: rtr.c:28
int size_t
Definition: sftypes.h:40
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)