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