gen_html.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. #include <iostream>
  10. #include <fstream>
  11. #include <sstream>
  12. #include <vector>
  13. using namespace std;
  14. /* trim string at the beginning and at the end */
  15. void trim(string& s, string characters)
  16. {
  17. size_t p = s.find_first_not_of(characters);
  18. s.erase(0, p);
  19. p = s.find_last_not_of(characters);
  20. if (string::npos != p)
  21. s.erase(p+1);
  22. }
  23. /* trim C++ style comments */
  24. void trim_comments(string &s)
  25. {
  26. size_t spos, epos;
  27. spos = s.find("/*");
  28. epos = s.find("*/");
  29. s = s.substr(spos+3, epos-(spos+3));
  30. }
  31. /* get lines until a given terminator */
  32. vector<string> get_lines(vector<string>& input, int& linenum, string terminator)
  33. {
  34. vector<string> out;
  35. string line;
  36. size_t epos;
  37. while ((size_t)linenum < input.size()) {
  38. line = input[linenum];
  39. if (terminator.empty() && line.empty()) { linenum--; break; }
  40. epos = line.find(terminator);
  41. if (!terminator.empty() && epos!=string::npos) {
  42. out.push_back(line);
  43. break;
  44. }
  45. out.push_back(line);
  46. linenum++;
  47. }
  48. return out;
  49. }
  50. /* print line with ZSTDLIB_API removed and C++ comments not bold */
  51. void print_line(stringstream &sout, string line)
  52. {
  53. size_t spos;
  54. if (line.substr(0,12) == "ZSTDLIB_API ") line = line.substr(12);
  55. spos = line.find("/*");
  56. if (spos!=string::npos) {
  57. sout << line.substr(0, spos);
  58. sout << "</b>" << line.substr(spos) << "<b>" << endl;
  59. } else {
  60. // fprintf(stderr, "lines=%s\n", line.c_str());
  61. sout << line << endl;
  62. }
  63. }
  64. int main(int argc, char *argv[]) {
  65. char exclam;
  66. int linenum, chapter = 1;
  67. vector<string> input, lines, comments, chapters;
  68. string line, version;
  69. size_t spos, l;
  70. stringstream sout;
  71. ifstream istream;
  72. ofstream ostream;
  73. if (argc < 4) {
  74. cout << "usage: " << argv[0] << " [zstd_version] [input_file] [output_html]" << endl;
  75. return 1;
  76. }
  77. version = "zstd " + string(argv[1]) + " Manual";
  78. istream.open(argv[2], ifstream::in);
  79. if (!istream.is_open()) {
  80. cout << "Error opening file " << argv[2] << endl;
  81. return 1;
  82. }
  83. ostream.open(argv[3], ifstream::out);
  84. if (!ostream.is_open()) {
  85. cout << "Error opening file " << argv[3] << endl;
  86. return 1;
  87. }
  88. while (getline(istream, line)) {
  89. input.push_back(line);
  90. }
  91. for (linenum=0; (size_t)linenum < input.size(); linenum++) {
  92. line = input[linenum];
  93. /* typedefs are detected and included even if uncommented */
  94. if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
  95. lines = get_lines(input, linenum, "}");
  96. sout << "<pre><b>";
  97. for (l=0; l<lines.size(); l++) {
  98. print_line(sout, lines[l]);
  99. }
  100. sout << "</b></pre><BR>" << endl;
  101. continue;
  102. }
  103. /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */
  104. if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) {
  105. sout << "<pre><b>";
  106. print_line(sout, line);
  107. sout << "</b></pre><BR>" << endl;
  108. continue;
  109. }
  110. spos = line.find("/**=");
  111. if (spos==string::npos) {
  112. spos = line.find("/*!");
  113. if (spos==string::npos)
  114. spos = line.find("/**");
  115. if (spos==string::npos)
  116. spos = line.find("/*-");
  117. if (spos==string::npos)
  118. spos = line.find("/*=");
  119. if (spos==string::npos)
  120. continue;
  121. exclam = line[spos+2];
  122. }
  123. else exclam = '=';
  124. comments = get_lines(input, linenum, "*/");
  125. if (!comments.empty()) comments[0] = line.substr(spos+3);
  126. if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/"));
  127. for (l=0; l<comments.size(); l++) {
  128. if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2);
  129. else if (comments[l].find(" *")==0) comments[l] = comments[l].substr(3);
  130. trim(comments[l], "*-=");
  131. }
  132. while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
  133. while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
  134. /* comments of type /*! mean: this is a function declaration; switch comments with declarations */
  135. if (exclam == '!') {
  136. if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "ZSTD_XXX() :" */
  137. linenum++;
  138. lines = get_lines(input, linenum, "");
  139. sout << "<pre><b>";
  140. for (l=0; l<lines.size(); l++) {
  141. // fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str());
  142. string fline = lines[l];
  143. if (fline.substr(0, 12) == "ZSTDLIB_API " ||
  144. fline.substr(0, 12) == string(12, ' '))
  145. fline = fline.substr(12);
  146. print_line(sout, fline);
  147. }
  148. sout << "</b><p>";
  149. for (l=0; l<comments.size(); l++) {
  150. print_line(sout, comments[l]);
  151. }
  152. sout << "</p></pre><BR>" << endl << endl;
  153. } else if (exclam == '=') { /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */
  154. trim(comments[0], " ");
  155. sout << "<h3>" << comments[0] << "</h3><pre>";
  156. for (l=1; l<comments.size(); l++) {
  157. print_line(sout, comments[l]);
  158. }
  159. sout << "</pre><b><pre>";
  160. lines = get_lines(input, ++linenum, "");
  161. for (l=0; l<lines.size(); l++) {
  162. print_line(sout, lines[l]);
  163. }
  164. sout << "</pre></b><BR>" << endl;
  165. } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */
  166. if (comments.empty()) continue;
  167. trim(comments[0], " ");
  168. sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
  169. chapters.push_back(comments[0]);
  170. chapter++;
  171. for (l=1; l<comments.size(); l++) {
  172. print_line(sout, comments[l]);
  173. }
  174. if (comments.size() > 1)
  175. sout << "<BR></pre>" << endl << endl;
  176. else
  177. sout << "</pre>" << endl << endl;
  178. }
  179. }
  180. 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;
  181. ostream << "<h1>" << version << "</h1>\n";
  182. ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
  183. for (size_t i=0; i<chapters.size(); i++)
  184. ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
  185. ostream << "</ol>\n<hr>\n";
  186. ostream << sout.str();
  187. ostream << "</html>" << endl << "</body>" << endl;
  188. return 0;
  189. }