StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
writeHtml.cc
1 /***************************************************************************
2  *
3  * $Id: writeHtml.cc,v 1.1 1999/02/17 12:38:48 ullrich Exp $
4  *
5  * Author: Thomas Ullrich, August 1998
6  ***************************************************************************
7  *
8  * Description:
9  *
10  ***************************************************************************
11  *
12  * $Log: writeHtml.cc,v $
13  * Revision 1.1 1999/02/17 12:38:48 ullrich
14  * Initial Revision
15  *
16  **************************************************************************/
17 #include <string>
18 #include <fstream.h>
19 #include <cstdlib>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <utility>
23 #include <list>
24 #include <vector>
25 #include <map>
26 #include <stdexcept>
27 #include <time.h>
28 #include <assert.h>
29 
30 //#define DEBUG
31 #define PR(x) cout << #x << " = " << (x) << endl;
32 
33 typedef map<string, string, less<string> > keywordMap_type;
34 typedef keywordMap_type::value_type keyword_type;
35 
36 template<class A, class B>
37 ostream& operator<<(ostream& out, const pair<A,B> &p)
38 {
39  out << p.first << " is defined in " << p.second;
40  return out;
41 }
42 
43 class FileInfo {
44 public:
45  FileInfo(const string&);
46  string& filename() {return mFilename;}
47  string& htmlFile() {return mHTMLFile;}
48  vector<string>& keywords() {return mKeywords;}
49  vector<string>& body() {return mBody;}
50  string basename() const;
51 
52 private:
53  string mFilename;
54  string mHTMLFile;
55  vector<string> mKeywords;
56  vector<string> mBody;
57  FileInfo();
58 };
59 
60 FileInfo::FileInfo() { /* noop */ }
61 
62 FileInfo::FileInfo(const string& fname)
63 {
64  size_t pos;
65  pos = fname.rfind(".out");
66  if (pos == string::npos) {
67  throw(invalid_argument("FileInfo::FileInfo(): error file must have extension '.out'"));
68  }
69  mFilename = fname;
70  ifstream ifs(mFilename.c_str());
71  if (!ifs) {
72  throw(invalid_argument("FileInfo::FileInfo(): cannot open file."));
73  }
74  string line;
75  while (ifs.good()) {
76  getline(ifs, line, '\n');
77  if (ifs.eof()) break;
78  if (line.empty()) continue;
79  mBody.push_back(line);
80  }
81  ifs.close();
82  string keyfile = mFilename;
83  pos = keyfile.find(".out", pos);
84  keyfile.replace(keyfile.find(".out", pos), 4 , ".keywords");
85  if (access(keyfile.c_str(), R_OK) == 0) {
86  ifs.open(keyfile.c_str());
87  if (!ifs) {
88  throw(invalid_argument("FileInfo::FileInfo(): cannot open keywords file."));
89  }
90  while (ifs.good()) {
91  getline(ifs, line, '\n');
92  if (ifs.eof()) break;
93  if (line.empty()) continue;
94  mKeywords.push_back(line);
95  }
96  ifs.close();
97  }
98  mHTMLFile = basename();
99  mHTMLFile += ".html";
100 }
101 
102 string FileInfo::basename() const
103 {
104  size_t pos;
105  string bname = mFilename;
106  pos = bname.rfind(".out");
107  if (pos != string::npos)
108  bname.erase(pos, bname.size()-pos);
109  pos = bname.rfind("/");
110  if (pos != string::npos)
111  bname.erase(0, pos);
112  return bname;
113 }
114 
115 void writeHtmlHeader(ostream& ofs, const string& name)
116 {
117  string context(name);
118  size_t pos = context.rfind(".");
119  if (pos != string::npos)
120  context.erase(pos, context.size()-pos);
121 
122  ofs << "<html>" << endl;
123  ofs << "<!-- This code is generated automatically. Dont' modify it! -->" << endl;
124  ofs << "<head>" << endl;
125  ofs << "<title>StarClassLibrary: " << context << "</title>" << endl;
126  ofs << "</head>" << endl;
127  ofs << "<body bgcolor=#ffffff text=#000000>" << endl;
128  ofs << "<table border=0 width=110% cellpadding=0>" << endl;
129  ofs << "<tr bgcolor=darkblue>" << endl;
130  ofs << "<td align=left valign=top>" << endl;
131  ofs << "<ul>" << endl;
132  ofs << "<h4><br></h4>" << endl;
133  ofs << "<h1><font color=white>StarClassLibrary: </font><font color=red>"
134  << context << "</font></h1>" << endl;
135  ofs << "</ul>" << endl;
136  ofs << "</td>" << endl;
137  ofs << "<tr>" << endl;
138  ofs << "<td align=left> <font size=-1>" << endl;
139  ofs << "&nbsp; <a href=index.html>Back to Index</a>" << endl;
140  ofs << "</td>" << endl;
141  ofs << "</tr>" << endl;
142  ofs << "</table>" << endl;
143 
144  ofs << "<h3>Synopsis</h3>" << endl;
145  ofs << "<pre>" << endl;
146  ofs << "#include \"" << name << "\"" << endl;
147 }
148 
149 void writeHtmlTrailor(ostream& ofs)
150 {
151  time_t now = time(0);
152  ofs << "<hr noshade=noshade>" << endl;
153  ofs << "See the <font color=green><i>StarClassLibrary User Guide and Reference Manual</i></font> for more.<br>" << endl;
154  ofs << "File generated on " << ctime(&now);
155  ofs << "</body>" << endl;
156  ofs << "</html>" << endl;
157 }
158 
159 void writeLine(ostream& ofs, const string& str, const keywordMap_type &theMap)
160 {
161  //
162  // Translate special characters in 'str'
163  //
164  string line(str);
165  size_t pos;
166  while (true) {
167  pos = line.find("<",0);
168  if (pos == string::npos) break;
169  line.replace(pos, 1 , "&lt;");
170  }
171  while (true) {
172  pos = line.find(">",0);
173  if (pos == string::npos) break;
174  line.replace(pos, 1 , "&gt;");
175  }
176  pos = line.find(" ;");
177  if (pos != string::npos)
178  line.replace(pos, 2 , ";");
179 
180  //
181  // Add the hyperlinks
182  //
183  keywordMap_type::const_iterator iter;
184  size_t lpos;
185  string html;
186  bool isComplete;
187  for (iter = theMap.begin(); iter != theMap.end(); iter++) {
188  lpos = 0;
189  while (lpos < line.size()) {
190  const string& search = iter->first;
191  pos = line.find(search,lpos);
192  if (pos == string::npos) break;
193  // keyword candidate found,
194  // make sure its the full name
195  isComplete = true;
196  lpos = pos+search.size();
197  if (lpos < line.size() && isalnum(line[lpos])) isComplete = false;
198  if (pos > 5 && line.substr(pos-5, 5) == string("href=")) isComplete = false;
199  if (isComplete) {
200  html = "<a href=";
201  html += iter->second;
202  html += '>';
203  html += iter->first;
204  html += "</a>";
205  line.replace(pos, search.size(), html);
206  lpos = pos+html.size();
207  }
208  }
209  }
210 
211  // Write to stream
212  ofs << line << endl;
213 }
214 
215 int main(int argc, char* argv[])
216 {
217  int i, j, k;
218 
219  if (argc < 2) {
220  cerr << "Usage: " << argv[0] << " file ..." << endl;
221  return 2;
222  }
223 
224  //
225  // Collect all the info we got
226  //
227  vector<FileInfo> files;
228  for (i=1; i<argc; i++) {
229  FileInfo *info;
230  try {
231  info = new FileInfo(string(argv[i]));
232  }
233  catch (exception &e) {
234  cerr << e.what() << endl;
235  continue;
236  }
237  files.push_back(*info);
238  delete info;
239  }
240 
241 #ifdef DEBUG
242  PR(files.size());
243  for (i=0; i<files.size(); i++) {
244  PR(i);
245  PR(files[i].basename());
246  PR(files[i].filename());
247  PR(files[i].htmlFile());
248  PR(files[i].keywords().size());
249  PR(files[i].body().size());
250  }
251 #endif
252 
253  //
254  // Prepare new list of keywords and filenames
255  //
256  keywordMap_type keywordMap, emptyMap;
257  string hname;
258  for (i=0; i<files.size(); i++) {
259  hname = files[i].htmlFile();
260  for (k=0; k<files[i].keywords().size(); k++)
261  keywordMap.insert(keyword_type(files[i].keywords()[k], hname));
262  }
263 #ifdef DEBUG
264  copy(keywordMap.begin(), keywordMap.end(), ostream_iterator<keyword_type>(cout, "\n"));
265 #endif
266 
267  //
268  // Write the HTML file(s)
269  //
270  ofstream ofs;
271  for (i=0; i<files.size(); i++) {
272  ofs.open(files[i].htmlFile().c_str());
273  if (!ofs) {
274  cerr << argv[0] << ": error cannot open file " << files[i].htmlFile() << endl;
275  continue;
276  }
277  cout << "writing file " << files[i].htmlFile() << " .";
278 
279  writeHtmlHeader(ofs,files[i].basename());
280  cout << '.'; cout.flush();
281 
282  //
283  // Write the HTML body
284  //
285  vector<string> &theBody = files[i].body();
286 
287  // complete the synopsis section
288  string search, line;
289  size_t pos;
290  for (k=0; k<theBody.size(); k++) {
291  if (k+1 >= theBody.size()) continue;
292  if (theBody[k+1][0] != '{') continue;
293  for (j=0; j<files[i].keywords().size(); j++) {
294  search = "class ";
295  search += files[i].keywords()[j];
296  search += ' ';
297  if (theBody[k].find(search) != string::npos) {
298  line = theBody[k];
299  pos = line.find(":");
300  if (pos != string::npos)
301  line.erase(pos, line.size()-pos);
302  line += ';';
303  writeLine(ofs, line, emptyMap);
304  }
305  }
306  }
307  ofs << "</pre>" << endl; // end synopsis section
308  cout << '.'; cout.flush();
309 
310  // some formatting
311  int indentLevel = 0;
312  const int indentSpaces = 3;
313  for (k=0; k<theBody.size(); k++) {
314  if (theBody[k].find("}") != string::npos) indentLevel--;
315  assert(indentLevel >= 0);
316  if (theBody[k].find("public:") != string::npos && indentLevel > 0)
317  theBody[k].insert(0, string((indentLevel-1)*indentSpaces, ' '));
318  else
319  theBody[k].insert(0, string(indentLevel*indentSpaces, ' '));
320  if (theBody[k].find("{") != string::npos) indentLevel++;
321  }
322  cout << '.'; cout.flush();
323 
324  // write the interface section
325  ofs << "<h3>Interface</h3>" << endl;
326  ofs << "<pre>" << endl;
327  for (k=0; k<theBody.size(); k++) {
328  writeLine(ofs, theBody[k], keywordMap);
329  }
330  ofs << "</pre>" << endl;
331  ofs << "<p>" << endl;
332  cout << '.'; cout.flush();
333 
334  writeHtmlTrailor(ofs);
335  ofs.close();
336  cout << ". done" << endl;
337  }
338  return 0;
339 }