ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/Utils/src/TDocOutput.cxx
Revision: 1.2
Committed: Fri Mar 11 04:03:54 2011 UTC (14 years, 1 month ago) by bendavid
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_032, Mit_031, Mit_025c_branch2, Mit_025c_branch1, Mit_030, Mit_029c, Mit_029b, Mit_030_pre1, Mit_029a, Mit_029, Mit_029_pre1, Mit_028a, Mit_025c_branch0, Mit_028, Mit_027a, Mit_027, Mit_026, Mit_025e, Mit_025d, Mit_025c, Mit_025b, Mit_025a, Mit_025, Mit_025pre2, Mit_024b, Mit_025pre1, Mit_024a, Mit_024, Mit_023, Mit_022a, Mit_022, Mit_020d, TMit_020d, Mit_020c, Mit_021, Mit_021pre2, Mit_021pre1, Mit_020b, Mit_020a, Mit_020, Mit_020pre1, HEAD
Branch point for: Mit_025c_branch
Changes since 1.1: +10 -10 lines
Log Message:
various minor changes to acommodate new root and architecture

File Contents

# Content
1 // @(#)root/html:$Id: TDocOutput.cxx,v 1.1 2009/08/11 23:09:28 loizides Exp $
2 // Author: Axel Naumann 2007-01-09
3
4 /*************************************************************************
5 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12 #include "MitAna/Utils/interface/TDocOutput.h"
13
14 #include "Riostream.h"
15 #include "MitAna/Utils/interface/TClassDocOutput.h"
16 #include "TDataMember.h"
17 #include "TDataType.h"
18 #include "MitAna/Utils/interface/TDocInfo.h"
19 #include "MitAna/Utils/interface/TDocParser.h"
20 #include "TEnv.h"
21 #include "TGlobal.h"
22 #include "MitAna/Utils/interface/THtml.h"
23 #include "TInterpreter.h"
24 #include "TMethod.h"
25 #include "TROOT.h"
26 #include "TSystem.h"
27 #include "TUrl.h"
28 #include "TVirtualMutex.h"
29 #include "TVirtualPad.h"
30 #include "TVirtualViewer3D.h"
31 #include <vector>
32 #include <list>
33 #include <set>
34 #include <sstream>
35 #include <stdlib.h>
36
37 namespace {
38
39 typedef std::vector<std::string> Words_t;
40 typedef Words_t::const_iterator SectionStart_t;
41
42 class TSectionInfo {
43 public:
44 TSectionInfo(SectionStart_t start, size_t chars, size_t size):
45 fStart(start), fChars(chars), fSize(size) {};
46
47 SectionStart_t fStart;
48 size_t fChars;
49 size_t fSize;
50 };
51 typedef std::list<TSectionInfo> SectionStarts_t;
52
53 static void Sections_BuildIndex(SectionStarts_t& sectionStarts,
54 SectionStart_t begin, SectionStart_t end,
55 size_t maxPerSection)
56 {
57 // for each assumed section border, check that previous entry's
58 // char[selectionChar] differs, else move section start forward
59
60 SectionStart_t cursor = begin;
61 if (sectionStarts.empty() || sectionStarts.back().fStart != cursor)
62 sectionStarts.push_back(TSectionInfo(cursor, 1, 0));
63
64 SectionStarts_t::iterator prevSection = sectionStarts.end();
65 --prevSection;
66
67 while (cursor != end) {
68 size_t numLeft = end - cursor;
69 size_t assumedNumSections = (numLeft + maxPerSection - 1 ) / maxPerSection;
70 size_t step = ((numLeft + assumedNumSections - 1) / assumedNumSections);
71 if (!step || step >= numLeft) return;
72 cursor += step;
73 if (cursor == end) break;
74
75 SectionStart_t addWhichOne = prevSection->fStart;
76
77 size_t selectionChar=1;
78 for (; selectionChar <= cursor->length() && addWhichOne == prevSection->fStart;
79 ++selectionChar) {
80 SectionStart_t checkPrev = cursor;
81 while (--checkPrev != prevSection->fStart
82 && !strncasecmp(checkPrev->c_str(), cursor->c_str(), selectionChar)) { }
83
84 SectionStart_t checkNext = cursor;
85 while (++checkNext != end
86 && !strncasecmp(checkNext->c_str(), cursor->c_str(), selectionChar)) { }
87
88 // if the previous matching one is closer but not previous section start, take it!
89 if (checkPrev != prevSection->fStart) {
90 if ((cursor - checkPrev) <= (checkNext - cursor))
91 addWhichOne = ++checkPrev;
92 else if (checkNext != end
93 && (size_t)(checkNext - cursor) < maxPerSection) {
94 addWhichOne = checkNext;
95 }
96 }
97 }
98 if (addWhichOne == prevSection->fStart)
99 addWhichOne = cursor;
100
101 selectionChar = 1;
102 while (selectionChar <= prevSection->fStart->length()
103 && selectionChar <= addWhichOne->length()
104 && !strncasecmp(prevSection->fStart->c_str(), addWhichOne->c_str(), selectionChar))
105 ++selectionChar;
106
107 sectionStarts.push_back(TSectionInfo(addWhichOne, selectionChar, 0));
108 cursor = addWhichOne;
109 ++prevSection;
110 } // while cursor != end
111 }
112
113 static void Sections_SetSize(SectionStarts_t& sectionStarts, const Words_t &words)
114 {
115 // Update the length of the sections
116 for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
117 iSectionStart != sectionStarts.end(); ++iSectionStart) {
118 SectionStarts_t::iterator next = iSectionStart;
119 ++next;
120 if (next == sectionStarts.end()) {
121 iSectionStart->fSize = (words.end() - iSectionStart->fStart);
122 break;
123 }
124 iSectionStart->fSize = (next->fStart - iSectionStart->fStart);
125 }
126 }
127
128 static void Sections_PostMerge(SectionStarts_t& sectionStarts, const size_t maxPerSection)
129 {
130 // Merge sections that ended up being too small, up to maxPerSection entries
131 for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
132 iSectionStart != sectionStarts.end();) {
133 SectionStarts_t::iterator iNextSectionStart = iSectionStart;
134 ++iNextSectionStart;
135 if (iNextSectionStart == sectionStarts.end()) break;
136 if (iNextSectionStart->fSize + iSectionStart->fSize < maxPerSection) {
137 iSectionStart->fSize += iNextSectionStart->fSize;
138 sectionStarts.erase(iNextSectionStart);
139 } else ++iSectionStart;
140 }
141 }
142
143 static void GetIndexChars(const Words_t& words, UInt_t numSectionsIn,
144 std::vector<std::string> &sectionMarkersOut)
145 {
146 // Given a list of words (class names, in this case), this function builds an
147 // optimal set of about numSectionIn sections (even if almost all words start
148 // with a "T"...), and returns the significant characters for each section start
149 // in sectionMarkersOut.
150
151 const size_t maxPerSection = (words.size() + numSectionsIn - 1)/ numSectionsIn;
152 SectionStarts_t sectionStarts;
153 Sections_BuildIndex(sectionStarts, words.begin(), words.end(), maxPerSection);
154 Sections_SetSize(sectionStarts, words);
155 Sections_PostMerge(sectionStarts, maxPerSection);
156
157 // convert to index markers
158 sectionMarkersOut.clear();
159 sectionMarkersOut.resize(sectionStarts.size());
160 size_t idx = 0;
161 for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
162 iSectionStart != sectionStarts.end(); ++iSectionStart)
163 sectionMarkersOut[idx++] =
164 iSectionStart->fStart->substr(0, iSectionStart->fChars);
165 }
166
167 static void GetIndexChars(const std::list<std::string>& wordsIn, UInt_t numSectionsIn,
168 std::vector<std::string> &sectionMarkersOut)
169 {
170 // initialize word vector
171 Words_t words(wordsIn.size());
172 size_t idx = 0;
173 for (std::list<std::string>::const_iterator iWord = wordsIn.begin(); iWord != wordsIn.end(); ++iWord)
174 words[idx++] = *iWord;
175 GetIndexChars(words, numSectionsIn, sectionMarkersOut);
176 }
177
178 }
179
180 extern "C" { // std::qsort on solaris wants the sorter to be extern "C"
181
182 //______________________________________________________________________________
183 static int CaseInsensitiveSort(const void *name1, const void *name2)
184 {
185 // Friend function for sorting strings, case insensitive
186 //
187 //
188 // Input: name1 - pointer to the first string
189 // name2 - pointer to the second string
190 //
191 // NOTE: This function compares its arguments and returns an integer less
192 // than, equal to, or greater than zero, depending on whether name1
193 // is lexicographically less than, equal to, or greater than name2,
194 // but characters are forced to lower-case prior to comparison.
195 //
196 //
197
198 return (strcasecmp(*((char **) name1), *((char **) name2)));
199 }
200 }
201
202 namespace {
203
204 // std::list::sort(with_stricmp_predicate) doesn't work with Solaris CC...
205 static void sort_strlist_stricmp(std::list<std::string>& l)
206 {
207 // sort strings ignoring case - easier for humans
208 struct posList {
209 const char* str;
210 std::list<std::string>::const_iterator pos;
211 };
212 posList* carr = new posList[l.size()];
213 size_t idx = 0;
214 for (std::list<std::string>::const_iterator iS = l.begin(); iS != l.end(); ++iS) {
215 carr[idx].pos = iS;
216 carr[idx++].str = iS->c_str();
217 }
218 qsort(&carr[0].str, idx, sizeof(posList), CaseInsensitiveSort);
219 std::list<std::string> lsort;
220 for (idx = 0; idx < l.size(); ++idx) {
221 lsort.push_back(*carr[idx].pos);
222 }
223 delete [] carr;
224 l.swap(lsort);
225 }
226
227 }
228
229 //______________________________________________________________________________
230 //
231 // THtml generated documentation is written to file by TDocOutput. So far only
232 // output of HTML is implemented. Customization of the output should be done
233 // with THtml's interfaces - TDocOutput should not be used nor re-implemented
234 // directly.
235 //
236 // TDocOutput generates the index tables:
237 // * classes (THtml invokes TClassDocOutput for each),
238 // * inheritance hierarchy,
239 // * types and typedefs,
240 // * libraries,
241 // * the product index, and
242 // * the module index (including the links to per-module documentation).
243 // It invokes AT&T's GraphViz tool (dot) if available; charts benefit a lot
244 // from it.
245 //
246 // TDocOutput also writes all pages' header and footer, which can be customized
247 // by calling THtml::SetHeader(), THtml::SetFooter().
248 //______________________________________________________________________________
249
250 ClassImp(TDocOutput)
251
252 //______________________________________________________________________________
253 TDocOutput::TDocOutput(THtml& html): fHtml(&html)
254 {}
255
256 //______________________________________________________________________________
257 TDocOutput::~TDocOutput()
258 {}
259
260 //______________________________________________________________________________
261 void TDocOutput::AddLink(TSubString& str, TString& link, const char* comment)
262 {
263 // Add a link around str, with title comment.
264 // Update str so it surrounds the link.
265
266 // prepend "./" to allow callers to replace a different relative directory
267 if (ReferenceIsRelative(link) && !link.BeginsWith("./"))
268 link.Prepend("./");
269 link.Prepend("<a href=\"");
270 link += "\"";
271 if (comment && strlen(comment)) {
272 link += " title=\"";
273 TString description(comment);
274 ReplaceSpecialChars(description);
275 description.ReplaceAll("\"", "&quot;");
276 link += description;
277 link += "\"";
278 }
279 link += ">";
280
281 str.String().Insert(str.Start() + str.Length(), "</a>");
282 str.String().Insert(str.Start(), link);
283
284 TString &strString = str.String();
285 TSubString update = strString(str.Start(), str.Length() + link.Length() + 4);
286 str = update;
287 }
288
289 //______________________________________________________________________________
290 void TDocOutput::AdjustSourcePath(TString& line, const char* relpath /*= "../"*/)
291 {
292 // adjust the path of links for source files, which are in src/, but need
293 // to point to relpath (usually "../"). Simply replaces "=\"./" by "=\"../"
294
295 TString replWithRelPath("=\"");
296 replWithRelPath += relpath;
297 line.ReplaceAll("=\"./", replWithRelPath);
298 }
299
300 //______________________________________________________________________________
301 void TDocOutput::Convert(std::istream& in, const char* infilename,
302 const char* outfilename, const char *title,
303 const char *relpath /*= "../"*/, Int_t includeOutput /*=0*/,
304 const char* context /*= ""*/,
305 TGClient* gclient /*= 0*/)
306 {
307 // Convert a text file into a html file.
308 // outfilename doesn't have an extension yet; up to us to decide.
309 // We generate HTML, so our extension is ".html".
310 // See THtml::Convert() for the other parameters.
311
312 TString htmlFilename(outfilename);
313 htmlFilename += ".html";
314
315 std::ofstream out(htmlFilename);
316
317 if (!out.good()) {
318 Error("Convert", "Can't open file '%s' !", htmlFilename.Data());
319 return;
320 }
321
322 // write a HTML header
323 WriteHtmlHeader(out, title, relpath);
324
325 if (context || context[0])
326 out << context << endl;
327 else if (title && title[0])
328 out << "<h1 class=\"convert\">" << title << "</h1>" << endl;
329
330 Int_t numReuseCanvases = 0;
331 if (includeOutput && !(includeOutput & THtml::kForceOutput)) {
332 void* dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
333 if (dirHandle) {
334 FileStat_t infile_stat;
335 if (!gSystem->GetPathInfo(infilename, infile_stat)) {
336 // can stat.
337 const char* outfile = 0;
338 TString firstCanvasFileBase(gSystem->BaseName(outfilename));
339 firstCanvasFileBase += "_0.png";
340 // first check whether the firstCanvasFile exists:
341 Bool_t haveFirstCanvasFile = false;
342 while ((outfile = gSystem->GetDirEntry(dirHandle))) {
343 if (firstCanvasFileBase == outfile) {
344 haveFirstCanvasFile = true;
345 break;
346 }
347 }
348 gSystem->FreeDirectory(dirHandle);
349
350 FileStat_t outfile_stat;
351 TString firstCanvasFile = outfilename;
352 firstCanvasFile += "_0.png";
353 Int_t maxIdx = -1;
354 if (haveFirstCanvasFile && !gSystem->GetPathInfo(firstCanvasFile, outfile_stat)
355 && outfile_stat.fMtime > infile_stat.fMtime) {
356 // the first canvas file exists and it is newer than the script, so we reuse
357 // the canvas files. We need to know how many there are:
358 dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
359 TString stem(gSystem->BaseName(outfilename));
360 stem += "_";
361 TString dir(gSystem->DirName(htmlFilename));
362 while ((outfile = gSystem->GetDirEntry(dirHandle))) {
363 if (strncmp(outfile, stem, stem.Length()))
364 continue;
365 const char* posext = strrchr(outfile, '.');
366 if (!posext || strcmp(posext, ".png"))
367 continue;
368
369 // extract the mod time of the PNG file
370 if (gSystem->GetPathInfo(dir + "/" + outfile, outfile_stat))
371 // can't stat!
372 continue;
373
374 if (outfile_stat.fMtime > infile_stat.fMtime) {
375 ++numReuseCanvases;
376 // The canvas PNG is newer than the script, so
377 // extract the index of the canvas
378 TString idxStr(outfile + stem.Length());
379 idxStr.Remove(idxStr.Length() - 4);
380 Int_t idx = idxStr.Atoi();
381 if (maxIdx < idx)
382 maxIdx = idx;
383 }
384 }
385 gSystem->FreeDirectory(dirHandle);
386 if (maxIdx + 1 != numReuseCanvases)
387 // bad: the number of canvases to reuse noes not correspond to the highest index we saw.
388 // we will need to regenerate evrything.
389 numReuseCanvases = 0;
390 }
391 } // infile can be stat'ed
392 } // can open output directory
393 } // canvases wanted
394
395 if (numReuseCanvases)
396 Printf("Convert: %s (reusing %d saved canvas%s)", htmlFilename.Data(), numReuseCanvases, (numReuseCanvases > 1 ? "es" : ""));
397 else
398 Printf("Convert: %s", htmlFilename.Data());
399
400 UInt_t nCanvases = numReuseCanvases;
401 if (includeOutput) {
402 if (!numReuseCanvases) {
403 // need to run the script
404 if (includeOutput & THtml::kSeparateProcessOutput) {
405 gSystem->Exec(TString::Format("ROOT_HIST=0 root.exe -l -q %s $ROOTSYS/etc/html/saveScriptOutput.C\\(\\\"%s\\\",\\\"%s\\\",%d\\)",
406 gROOT->IsBatch() ? "-b" : "",
407 infilename,
408 gSystem->DirName(outfilename),
409 includeOutput & THtml::kCompiledOutput));
410 } else {
411 // run in this ROOT process
412 TString pwd(gSystem->pwd());
413 gSystem->cd(gSystem->DirName(infilename));
414
415 TList* gClientGetListOfWindows = 0;
416 TObject* gClientGetDefaultRoot = 0;
417 std::set<TObject*> previousWindows;
418 if (gclient) {
419 gROOT->ProcessLine(TString::Format("*((TList**)0x%lx) = ((TGClient*)0x%lx)->GetListOfWindows();",
420 (ULong_t)&gClientGetListOfWindows, (ULong_t)gclient));
421 gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGClient*)0x%lx)->GetDefaultRoot();",
422 (ULong_t)&gClientGetDefaultRoot, (ULong_t)gclient));
423 TObject* win = 0;
424 TIter iWin(gClientGetListOfWindows);
425 while((win = iWin())) {
426 TObject* winGetParent = 0;
427 gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
428 (ULong_t)&winGetParent, (ULong_t)win));
429 if (winGetParent == gClientGetDefaultRoot)
430 previousWindows.insert(win);
431 }
432 } else {
433 if (gROOT->GetListOfCanvases()->GetSize())
434 previousWindows.insert(gROOT->GetListOfCanvases()->Last());
435 }
436 TIter iTimer(gSystem->GetListOfTimers());
437 std::set<TObject*> timersBefore;
438 TObject* timerOld = 0;
439 while ((timerOld = iTimer()))
440 timersBefore.insert(timerOld);
441
442 TString cmd(".x ");
443 cmd += gSystem->BaseName(infilename);
444 if (includeOutput & THtml::kCompiledOutput)
445 cmd += "+";
446 gInterpreter->SaveContext();
447 gInterpreter->SaveGlobalsContext();
448 Int_t err;
449 gROOT->ProcessLine(cmd, &err);
450 gSystem->cd(pwd);
451
452 if (err == TInterpreter::kNoError) {
453 if (gclient) {
454 TClass* clRootCanvas = TClass::GetClass("TRootCanvas");
455 TClass* clGMainFrame = TClass::GetClass("TGMainFrame");
456 TObject* win = 0;
457 TIter iWin(gClientGetListOfWindows);
458 while((win = iWin())) {
459 TObject* winGetParent = 0;
460 gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
461 (ULong_t)&winGetParent, (ULong_t)win));
462 Bool_t winIsMapped = kFALSE;
463 if (winGetParent == gClientGetDefaultRoot)
464 gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TGWindow*)0x%lx)->IsMapped();",
465 (ULong_t)&winIsMapped, (ULong_t)win));
466 if (winIsMapped && previousWindows.find(win) == previousWindows.end()
467 && win->InheritsFrom(clGMainFrame)) {
468 gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->MapRaised();", (ULong_t)win));
469 Bool_t isRootCanvas = win->InheritsFrom(clRootCanvas);
470 Bool_t hasEditor = false;
471 if (isRootCanvas) {
472 gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TRootCanvas*)0x%lx)->HasEditor();",
473 (ULong_t)&hasEditor, (ULong_t)win));
474 }
475 if (isRootCanvas && !hasEditor) {
476 TVirtualPad* pad = 0;
477 gROOT->ProcessLine(TString::Format("*((TVirtualPad**)0x%lx) = ((TRootCanvas*)0x%lx)->Canvas();",
478 (ULong_t)&pad, (ULong_t)win));
479 if (!pad->HasViewer3D() || pad->GetViewer3D()->InheritsFrom("TViewer3DPad")) {
480 pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
481 }
482 } else
483 gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->SaveAs(\"%s_%d.png\");",
484 (ULong_t)win, outfilename, nCanvases++));
485 }
486 }
487 } else {
488 // no gClient
489 TVirtualPad* pad = 0;
490 TVirtualPad* last = 0;
491 if (!previousWindows.empty())
492 last = (TVirtualPad*) *previousWindows.begin();
493 TIter iCanvas(gROOT->GetListOfCanvases());
494 while ((pad = (TVirtualPad*) iCanvas())) {
495 if (last) {
496 if (last == pad) last = 0;
497 continue;
498 }
499 pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
500 }
501 }
502 gInterpreter->Reset();
503 gInterpreter->ResetGlobals();
504 TIter iTimerRemove(gSystem->GetListOfTimers());
505 TTimer* timer = 0;
506 while ((timer = (TTimer*) iTimerRemove()))
507 if (timersBefore.find(timer) == timersBefore.end())
508 gSystem->RemoveTimer(timer);
509 }
510 } // run script in this ROOT process
511 }
512 out << "<table><tr><td style=\"vertical-align:top;padding-right:2em;\">" << endl;
513 }
514 out << "<pre>" << endl;
515
516 TDocParser parser(*this);
517 parser.Convert(out, in, relpath, (includeOutput) /* determines whether it's code or not */);
518
519 out << "</pre>" << endl;
520
521 if (includeOutput) {
522 out << "</td><td style=\"vertical-align:top;\">" << endl;
523 out << "<table>" << endl;
524 for (UInt_t i = 0; i < nCanvases; ++i) {
525 TString pngname = TString::Format("%s_%d.png", gSystem->BaseName(outfilename), i);
526 out << "<tr><td><a href=\"" << pngname << "\">" << endl
527 << "<img src=\"" << pngname << "\" id=\"canv" << i << "\" alt=\"thumb\" style=\"border:none;width:22em;\" "
528 "onmouseover=\"javascript:canv" << i << ".style.width='auto';\" />" << endl
529 << "</a></td></tr>" << endl;
530 }
531 out << "</table>" << endl;
532 out << "</td></tr></table>" << endl;
533 }
534
535 // write a HTML footer
536 WriteHtmlFooter(out, relpath);
537 }
538
539 //______________________________________________________________________________
540 Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName)
541 {
542 // Copy file to HTML directory
543 //
544 //
545 // Input: sourceName - source file name (fully qualified i.e. file system path)
546 // destName - optional destination name, if not
547 // specified it would be the same
548 // as the source file name
549 //
550 // Output: TRUE if file is successfully copied, or
551 // FALSE if it's not
552 //
553 //
554 // NOTE: The destination directory is always fHtml->GetOutputDir()
555 //
556
557 R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
558
559 TString sourceFile(sourceName);
560
561 if (!sourceFile.Length()) {
562 Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName,
563 fHtml->GetOutputDir().Data());
564 return kFALSE;
565 }
566
567 // destination file name
568 TString destFile;
569 if (!destName || !*destName)
570 destFile = gSystem->BaseName(sourceFile);
571 else
572 destFile = gSystem->BaseName(destName);
573
574 gSystem->PrependPathName(fHtml->GetOutputDir(), destFile);
575
576 // Get info about a file
577 Long64_t size;
578 Long_t id, flags, sModtime, dModtime;
579 sModtime = 0;
580 dModtime = 0;
581 if (gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)
582 || gSystem->GetPathInfo(destFile, &id, &size, &flags, &dModtime)
583 || sModtime > dModtime)
584 gSystem->CopyFile(sourceFile, destFile, kTRUE);
585
586 return kTRUE;
587 }
588
589
590
591 //______________________________________________________________________________
592 void TDocOutput::CreateHierarchy()
593 {
594 // Create a hierarchical class list
595 // The algorithm descends from the base classes and branches into
596 // all derived classes. Mixing classes are displayed several times.
597 //
598 //
599
600 // if (CreateHierarchyDot()) return;
601
602 TString filename("ClassHierarchy.html");
603 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
604
605 // open out file
606 std::ofstream out(filename);
607
608 if (!out.good()) {
609 Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
610 return;
611 }
612
613 Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
614
615 // write out header
616 WriteHtmlHeader(out, "Class Hierarchy");
617
618 WriteTopLinks(out, 0);
619 out << "</div></div>" << endl;
620
621 out << "<h1>Class Hierarchy</h1>" << endl;
622
623
624 // loop on all classes
625 TClassDocInfo* cdi = 0;
626 TIter iClass(fHtml->GetListOfClasses());
627 while ((cdi = (TClassDocInfo*)iClass())) {
628 if (!cdi->HaveSource())
629 continue;
630
631 // get class
632 TDictionary *dictPtr = cdi->GetClass();
633 TClass *basePtr = dynamic_cast<TClass*>(dictPtr);
634 if (basePtr == 0) {
635 if (!dictPtr)
636 Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
637 continue;
638 }
639
640 TClassDocOutput cdo(*fHtml, basePtr, 0);
641 cdo.CreateClassHierarchy(out, cdi->GetHtmlFileName());
642 }
643
644 // write out footer
645 WriteHtmlFooter(out);
646 }
647
648 //______________________________________________________________________________
649 void TDocOutput::CreateClassIndex()
650 {
651 // Create index of all classes
652 //
653
654 // create CSS file, we need it
655 fHtml->CreateAuxiliaryFiles();
656
657 TString filename("ClassIndex.html");
658 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
659
660 // open indexFile file
661 std::ofstream indexFile(filename.Data());
662
663 if (!indexFile.good()) {
664 Error("CreateClassIndex", "Can't open file '%s' !", filename.Data());
665 return;
666 }
667
668 Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
669
670 // write indexFile header
671 WriteHtmlHeader(indexFile, "Class Index");
672
673 WriteTopLinks(indexFile, 0);
674 indexFile << "</div></div>" << endl;
675
676 indexFile << "<h1>Class Index</h1>" << endl;
677
678 WriteModuleLinks(indexFile);
679
680 std::vector<std::string> indexChars;
681 if (fHtml->GetListOfClasses()->GetSize() > 10) {
682 std::vector<std::string> classNames;
683 {
684 TIter iClass(fHtml->GetListOfClasses());
685 TClassDocInfo* cdi = 0;
686 while ((cdi = (TClassDocInfo*)iClass()))
687 if (cdi->IsSelected() && cdi->HaveSource())
688 classNames.push_back(cdi->GetName());
689 }
690
691 if (classNames.size() > 10) {
692 indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
693 // find index chars
694 GetIndexChars(classNames, 50 /*sections*/, indexChars);
695 for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
696 indexFile << "<a href=\"#idx" << iIdxEntry << "\">";
697 ReplaceSpecialChars(indexFile, indexChars[iIdxEntry].c_str());
698 indexFile << "</a>" << endl;
699 }
700 indexFile << "</div><br />" << endl;
701 }
702 }
703
704 indexFile << "<ul id=\"indx\">" << endl;
705
706 // loop on all classes
707 UInt_t currentIndexEntry = 0;
708 TIter iClass(fHtml->GetListOfClasses());
709 TClassDocInfo* cdi = 0;
710 Int_t i = 0;
711 while ((cdi = (TClassDocInfo*)iClass())) {
712 if (!cdi->IsSelected() || !cdi->HaveSource())
713 continue;
714
715 // get class
716 TDictionary *currentDict = cdi->GetClass();
717 TClass* currentClass = dynamic_cast<TClass*>(currentDict);
718 if (!currentClass) {
719 if (!currentDict)
720 Warning("THtml::CreateClassIndex", "skipping class %s\n", cdi->GetName());
721 continue;
722 }
723
724 indexFile << "<li class=\"idxl" << (i++)%2 << "\">";
725 if (currentIndexEntry < indexChars.size()
726 && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
727 indexChars[currentIndexEntry].length()))
728 indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
729
730 TString htmlFile(cdi->GetHtmlFileName());
731 if (htmlFile.Length()) {
732 indexFile << "<a href=\"";
733 indexFile << htmlFile;
734 indexFile << "\"><span class=\"typename\">";
735 ReplaceSpecialChars(indexFile, cdi->GetName());
736 indexFile << "</span></a> ";
737 } else {
738 indexFile << "<span class=\"typename\">";
739 ReplaceSpecialChars(indexFile, cdi->GetName());
740 indexFile << "</span> ";
741 }
742
743 // write title == short doc
744 ReplaceSpecialChars(indexFile, currentClass->GetTitle());
745 indexFile << "</li>" << endl;
746 }
747
748 indexFile << "</ul>" << endl;
749
750 // write indexFile footer
751 WriteHtmlFooter(indexFile);
752 }
753
754
755 //______________________________________________________________________________
756 void TDocOutput::CreateModuleIndex()
757 {
758 // Create the class index for each module, picking up documentation from the
759 // module's TModuleDocInfo::GetInputPath() plus the (possibly relative)
760 // THtml::GetModuleDocPath(). Also creates the library dependency plot if dot
761 // exists, see THtml::HaveDot().
762
763 const char* title = "LibraryDependencies";
764 TString dotfilename(title);
765 gSystem->PrependPathName(fHtml->GetOutputDir(), dotfilename);
766
767 std::ofstream libDepDotFile(dotfilename + ".dot");
768 libDepDotFile << "digraph G {" << endl
769 << "ratio=compress;" << endl
770 << "node [fontsize=22,labeldistance=0.1];" << endl
771 << "edge [len=0.01];" << endl
772 << "fontsize=22;" << endl
773 << "size=\"16,16\";" << endl
774 << "overlap=false;" << endl
775 << "splines=true;" << endl
776 << "K=0.1;" << endl;
777
778 TModuleDocInfo* module = 0;
779 TIter iterModule(fHtml->GetListOfModules());
780
781 std::stringstream sstrCluster;
782 std::stringstream sstrDeps;
783 while ((module = (TModuleDocInfo*)iterModule())) {
784 if (!module->IsSelected())
785 continue;
786
787 std::vector<std::string> indexChars;
788 TString filename(module->GetName());
789 filename.ToUpper();
790 filename.ReplaceAll("/","_");
791 filename += "_Index.html";
792 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
793 std::ofstream outputFile(filename.Data());
794 if (!outputFile.good()) {
795 Error("CreateModuleIndex", "Can't open file '%s' !", filename.Data());
796 continue;
797 }
798 Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
799
800 TString htmltitle("Index of ");
801 TString moduletitle(module->GetName());
802 moduletitle.ToUpper();
803 htmltitle += moduletitle;
804 WriteHtmlHeader(outputFile, htmltitle);
805
806 WriteTopLinks(outputFile, module);
807 outputFile << "</div></div>" << endl;
808
809 outputFile << "<h2>" << htmltitle << "</h2>" << endl;
810
811 // Module doc
812 if (GetHtml()->GetModuleDocPath().Length()) {
813 TString outdir(module->GetName());
814 gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir);
815
816 TString moduleDocDir;
817 GetHtml()->GetPathDefinition().GetDocDir(module->GetName(), moduleDocDir);
818 ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName());
819 }
820
821 WriteModuleLinks(outputFile, module);
822
823 std::list<std::string> classNames;
824 {
825 TIter iClass(module->GetClasses());
826 TClassDocInfo* cdi = 0;
827 while ((cdi = (TClassDocInfo*) iClass())) {
828 if (!cdi->IsSelected() || !cdi->HaveSource())
829 continue;
830 classNames.push_back(cdi->GetName());
831
832 if (classNames.size() > 1) continue;
833
834 TClass* cdiClass = dynamic_cast<TClass*>(cdi->GetClass());
835 if (!cdiClass)
836 continue;
837
838 TString libs(cdiClass->GetSharedLibs());
839 Ssiz_t posDepLibs = libs.Index(' ');
840 TString thisLib(libs);
841 if (posDepLibs != kNPOS)
842 thisLib.Remove(posDepLibs, thisLib.Length());
843
844 {
845 Ssiz_t posExt = thisLib.First('.');
846 if (posExt != kNPOS)
847 thisLib.Remove(posExt, thisLib.Length());
848 }
849
850 if (!thisLib.Length())
851 continue;
852
853 // allocate entry, even if no dependencies
854 TLibraryDocInfo *libdeps =
855 (TLibraryDocInfo*)fHtml->GetLibraryDependencies()->FindObject(thisLib);
856 if (!libdeps) {
857 libdeps = new TLibraryDocInfo(thisLib);
858 fHtml->GetLibraryDependencies()->Add(libdeps);
859 }
860 libdeps->AddModule(module->GetName());
861 if (posDepLibs != kNPOS) {
862 std::string lib;
863 for(Ssiz_t pos = posDepLibs + 1; libs[pos]; ++pos) {
864 if (libs[pos] == ' ') {
865 if (thisLib.Length() && lib.length()) {
866 size_t posExt = lib.find('.');
867 if (posExt != std::string::npos)
868 lib.erase(posExt);
869 libdeps->AddDependency(lib);
870 }
871 lib.erase();
872 } else
873 lib += libs[pos];
874 }
875 if (lib.length() && thisLib.Length()) {
876 size_t posExt = lib.find('.');
877 if (posExt != std::string::npos)
878 lib.erase(posExt);
879 libdeps->AddDependency(lib);
880 }
881 } // if dependencies
882 } // while next class in module
883 } // just a scope block
884
885 TIter iClass(module->GetClasses());
886 TClassDocInfo* cdi = 0;
887 UInt_t count = 0;
888 UInt_t currentIndexEntry = 0;
889 while ((cdi = (TClassDocInfo*) iClass())) {
890 if (!cdi->IsSelected() || !cdi->HaveSource())
891 continue;
892
893 TDictionary *classPtr = cdi->GetClass();
894 if (!classPtr) {
895 Error("CreateModuleIndex", "Unknown class '%s' !", cdi->GetName());
896 continue;
897 }
898
899 if (!count) {
900 outputFile << "<h2>Class Index</h2>" << endl;
901
902 if (classNames.size() > 10) {
903 outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
904 UInt_t numSections = classNames.size() / 10;
905 if (numSections < 10) numSections = 10;
906 if (numSections > 50) numSections = 50;
907 // find index chars
908 GetIndexChars(classNames, numSections, indexChars);
909 for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
910 outputFile << "<a href=\"#idx" << iIdxEntry << "\">";
911 ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str());
912 outputFile << "</a>" << endl;
913 }
914 outputFile << "</div><br />" << endl;
915 }
916
917 outputFile << "<ul id=\"indx\">" << endl;
918 }
919
920 // write a classname to an index file
921 outputFile << "<li class=\"idxl" << (count++)%2 << "\">";
922 if (currentIndexEntry < indexChars.size()
923 && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
924 indexChars[currentIndexEntry].length()))
925 outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
926
927 TString htmlFile(cdi->GetHtmlFileName());
928 if (htmlFile.Length()) {
929 outputFile << "<a href=\"";
930 outputFile << htmlFile;
931 outputFile << "\"><span class=\"typename\">";
932 ReplaceSpecialChars(outputFile, classPtr->GetName());
933 outputFile << "</span></a> ";
934 } else {
935 outputFile << "<span class=\"typename\">";
936 ReplaceSpecialChars(outputFile, classPtr->GetName());
937 outputFile << "</span> ";
938 }
939
940 // write title
941 ReplaceSpecialChars(outputFile, classPtr->GetTitle());
942 outputFile << "</li>" << endl;
943 }
944
945
946 if (count)
947 outputFile << "</ul>" << endl;
948
949 // write outputFile footer
950 WriteHtmlFooter(outputFile);
951 } // while next module
952
953 // libCint is missing as we don't have class doc for it
954 // We need it for dependencies nevertheless, so add it by hand.
955 /*
956 sstrCluster << "subgraph clusterlibCint {" << endl
957 << "style=filled;" << endl
958 << "color=lightgray;" << endl
959 << "label=\"libCint\";" << endl
960 << "\"CINT\" [style=filled,color=white,fontsize=10]" << endl
961 << "}" << endl;
962 */
963
964 // simplify the library dependencies, by removing direct links
965 // that are equivalent to indirect ones, e.g. instead of having both
966 // A->C, A->B->C, keep only A->B->C.
967
968 TIter iLib(fHtml->GetLibraryDependencies());
969 TLibraryDocInfo* libinfo = 0;
970 while ((libinfo = (TLibraryDocInfo*)iLib())) {
971 if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
972
973 std::set<std::string>& deps = libinfo->GetDependencies();
974 for (std::set<std::string>::iterator iDep = deps.begin();
975 iDep != deps.end(); ++iDep) {
976 Bool_t already_indirect = kFALSE;
977 for (std::set<std::string>::const_iterator iDep2 = deps.begin();
978 !already_indirect && iDep2 != deps.end(); ++iDep2) {
979 if (iDep == iDep2) continue;
980 TLibraryDocInfo* libinfo2 = (TLibraryDocInfo*)
981 fHtml->GetLibraryDependencies()->FindObject(iDep2->c_str());
982 if (!libinfo2) continue;
983 const std::set<std::string>& deps2 = libinfo2->GetDependencies();
984 already_indirect |= deps2.find(*iDep) != deps2.end();
985 }
986 if (already_indirect) {
987 std::set<std::string>::iterator iRemove = iDep;
988 --iDep; // otherwise we cannot do the for loop's ++iDep
989 deps.erase(*iRemove);
990 }
991 } // for library dependencies of module in library
992 } // for libaries
993
994 iLib.Reset();
995 while ((libinfo = (TLibraryDocInfo*)iLib())) {
996 if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
997
998 const std::set<std::string>& modules = libinfo->GetModules();
999 if (modules.size() > 1) {
1000 sstrCluster << "subgraph cluster" << libinfo->GetName() << " {" << endl
1001 << "style=filled;" << endl
1002 << "color=lightgray;" << endl
1003 << "label=\"";
1004 if (!strcmp(libinfo->GetName(), "libCore"))
1005 sstrCluster << "Everything depends on ";
1006 sstrCluster << libinfo->GetName() << "\";" << endl;
1007
1008 for (std::set<std::string>::const_iterator iModule = modules.begin();
1009 iModule != modules.end(); ++iModule) {
1010 sstrCluster << "\"" << *iModule << "\" [style=filled,color=white,URL=\""
1011 << *iModule << "_Index.html\"];" << endl;
1012 }
1013 sstrCluster << endl
1014 << "}" << endl;
1015 } else {
1016 // only one module
1017 sstrCluster << "\"" << *modules.begin()
1018 << "\" [label=\"" << libinfo->GetName()
1019 << "\",style=filled,color=lightgray,shape=box,URL=\""
1020 << *modules.begin() << "_Index.html\"];" << endl;
1021 }
1022
1023 // GetSharedLib doesn't mention libCore or libCint; add them by hand
1024 /*
1025 if (iLibDep->first != "libCore")
1026 sstrDeps << "\"" << iModule->first << "\" -> \"BASE\" [lhead=clusterlibCore];" << endl;
1027 sstrDeps << "\"" << iModule->first << "\" -> \"CINT\" [lhead=clusterlibCint];" << endl;
1028 */
1029
1030 const std::string& mod = *(modules.begin());
1031 const std::set<std::string>& deps = libinfo->GetDependencies();
1032 for (std::set<std::string>::const_iterator iDep = deps.begin();
1033 iDep != deps.end(); ++iDep) {
1034 // cannot create dependency on iDep directly, use its first module instead.
1035 TLibraryDocInfo* depLibInfo = (TLibraryDocInfo*)
1036 fHtml->GetLibraryDependencies()->FindObject(iDep->c_str());
1037 if (!depLibInfo || depLibInfo->GetModules().empty())
1038 continue; // ouch!
1039
1040 const std::string& moddep = *(depLibInfo->GetModules().begin());
1041 sstrDeps << "\"" << mod << "\" -> \"" << moddep << "\";" << endl;
1042 }
1043 // make sure libCore ends up at the bottom
1044 sstrDeps << "\"" << mod << "\" -> \"CONT\" [style=invis];" << endl;
1045 } // for libs
1046
1047 libDepDotFile << sstrCluster.str() << endl
1048 << sstrDeps.str();
1049 libDepDotFile << "}" << endl;
1050 libDepDotFile.close();
1051
1052 std::ofstream out(dotfilename + ".html");
1053 if (!out.good()) {
1054 Error("CreateModuleIndex", "Can't open file '%s.html' !",
1055 dotfilename.Data());
1056 return;
1057 }
1058
1059 Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (dotfilename + ".html").Data());
1060 // write out header
1061 WriteHtmlHeader(out, "Library Dependencies");
1062
1063 WriteTopLinks(out, 0);
1064 out << "</div></div>" << endl;
1065
1066 out << "<h1>Library Dependencies</h1>" << endl;
1067
1068 RunDot(dotfilename, &out, kFdp);
1069
1070 out << "<img alt=\"Library Dependencies\" class=\"classcharts\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
1071
1072 // write out footer
1073 WriteHtmlFooter(out);
1074 }
1075
1076 //______________________________________________________________________________
1077 void TDocOutput::CreateProductIndex()
1078 {
1079 // Fetch documentation from THtml::GetProductDocDir() and put it into the
1080 // product index page.
1081
1082 //TString outFile(GetHtml()->GetProductName());
1083 //outFile += ".html";
1084 TString outFile("index.html");
1085 gSystem->PrependPathName(GetHtml()->GetOutputDir(), outFile);
1086 std::ofstream out(outFile);
1087
1088 if (!out.good()) {
1089 Error("CreateProductIndex", "Can't open file '%s' !", outFile.Data());
1090 return;
1091 }
1092
1093 Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
1094
1095 WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide");
1096
1097 WriteTopLinks(out, 0);
1098 out << "</div></div>" << endl;
1099
1100 out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl;
1101
1102 TString prodDoc;
1103 if (GetHtml()->GetPathDefinition().GetDocDir("", prodDoc))
1104 ProcessDocInDir(out, prodDoc, GetHtml()->GetOutputDir(), "./");
1105
1106 WriteModuleLinks(out);
1107
1108 out << "<h2>Chapters</h2>" << std::endl
1109 << "<h3><a href=\"./ClassIndex.html\">Class Index</a></h3>" << std::endl
1110 << "<p>A complete list of all classes defined in " << GetHtml()->GetProductName() << "</p>" << std::endl
1111 << "<h3><a href=\"./ClassHierarchy.html\">Class Hierarchy</a></h3>" << std::endl
1112 << "<p>A hierarchy graph of all classes, showing each class's base and derived classes</p>" << std::endl
1113 << "<h3><a href=\"./ListOfTypes.html\">Type Index</a></h3>" << std::endl
1114 << "<p>A complete list of all types</p>" << std::endl
1115 << "<h3><a href=\"./LibraryDependencies.html\">Library Dependency</a></h3>" << std::endl
1116 << "<p>A diagram showing all of " << GetHtml()->GetProductName() << "'s libraries and their dependencies</p>" << std::endl;
1117
1118 WriteHtmlFooter(out);
1119 }
1120
1121 //______________________________________________________________________________
1122 void TDocOutput::CreateClassTypeDefs()
1123 {
1124 // Create a forwarding page for each typedef pointing to a class.
1125 TDocParser parser(*this);
1126
1127 TIter iClass(GetHtml()->GetListOfClasses());
1128 TClassDocInfo* cdi = 0;
1129 while ((cdi = (TClassDocInfo*) iClass())) {
1130 if (cdi->GetListOfTypedefs().IsEmpty())
1131 continue;
1132 TIter iTypedefs(&cdi->GetListOfTypedefs());
1133 TDataType* dt = 0;
1134 while ((dt = (TDataType*) iTypedefs())) {
1135 if (gDebug > 0)
1136 Info("CreateClassTypeDefs", "Creating typedef %s to class %s",
1137 dt->GetName(), cdi->GetName());
1138 // create a filename
1139 TString filename(dt->GetName());
1140 NameSpace2FileName(filename);
1141
1142 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
1143
1144 filename += ".html";
1145
1146 // open class file
1147 std::ofstream outfile(filename);
1148
1149 if (!outfile.good()) {
1150 Error("CreateClassTypeDefs", "Can't open file '%s' !", filename.Data());
1151 continue;
1152 }
1153
1154 WriteHtmlHeader(outfile, dt->GetName());
1155
1156 outfile << "<a name=\"TopOfPage\"></a>" << endl;
1157
1158 TString dtName(dt->GetName());
1159 ReplaceSpecialChars(dtName);
1160 TString sTitle("typedef ");
1161 sTitle += dtName;
1162
1163 TClass* cls = dynamic_cast<TClass*>(cdi->GetClass());
1164 if (cls) {
1165 // show box with lib, include
1166 // needs to go first to allow title on the left
1167 TString sInclude;
1168 TString sLib;
1169 const char* lib=cls->GetSharedLibs();
1170 GetHtml()->GetPathDefinition().GetIncludeAs(cls, sInclude);
1171 if (lib) {
1172 char* libDup=StrDup(lib);
1173 char* libDupSpace=strchr(libDup,' ');
1174 if (libDupSpace) *libDupSpace = 0;
1175 char* libDupEnd=libDup+strlen(libDup);
1176 while (libDupEnd!=libDup)
1177 if (*(--libDupEnd)=='.') {
1178 *libDupEnd=0;
1179 break;
1180 }
1181 sLib = libDup;
1182 delete[] libDup;
1183 }
1184 outfile << "<script type=\"text/javascript\">WriteFollowPageBox('"
1185 << sTitle << "','" << sLib << "','" << sInclude << "');</script>" << endl;
1186 }
1187
1188 TString modulename;
1189 fHtml->GetModuleNameForClass(modulename, cls);
1190 TModuleDocInfo* module = (TModuleDocInfo*) fHtml->GetListOfModules()->FindObject(modulename);
1191 WriteTopLinks(outfile, module, dt->GetName());
1192
1193 outfile << "</div><div class=\"dropshadow\"><div class=\"withshadow\">";
1194 outfile << "<h1>" << sTitle << "</h1>" << endl
1195 << "<div class=\"classdescr\">" << endl;
1196
1197 outfile << dtName << " is a typedef to ";
1198 parser.DecorateKeywords(outfile, cls->GetName());
1199 outfile << endl
1200 << "</div>" << std::endl
1201 << "</div></div><div style=\"clear:both;\"></div>" << std::endl;
1202
1203 // the typedef isn't a data member, but the CSS is applicable nevertheless
1204 outfile << endl << "<div id=\"datamembers\">" << endl
1205 << "<table class=\"data\" cellspacing=\"0\">" << endl;
1206 outfile << "<tr class=\"data";
1207 outfile << "\"><td class=\"datatype\">typedef ";
1208 parser.DecorateKeywords(outfile, dt->GetFullTypeName());
1209 outfile << "</td><td class=\"dataname\">";
1210 ReplaceSpecialChars(outfile, dt->GetName());
1211 if (dt->GetTitle() && dt->GetTitle()[0]) {
1212 outfile << "</td><td class=\"datadesc\">";
1213 ReplaceSpecialChars(outfile, dt->GetTitle());
1214 } else outfile << "</td><td>";
1215 outfile << "</td></tr>" << endl
1216 << "</table></div>" << endl;
1217
1218 // write footer
1219 WriteHtmlFooter(outfile);
1220
1221 }
1222 }
1223 }
1224
1225 //______________________________________________________________________________
1226 void TDocOutput::CreateTypeIndex()
1227 {
1228 // Create index of all data types
1229
1230 // open file
1231 TString outFile("ListOfTypes.html");
1232 gSystem->PrependPathName(fHtml->GetOutputDir(), outFile);
1233 std::ofstream typesList(outFile);
1234
1235 if (!typesList.good()) {
1236 Error("CreateTypeIndex", "Can't open file '%s' !", outFile.Data());
1237 return;
1238 }
1239
1240 Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
1241
1242 // write typesList header
1243 WriteHtmlHeader(typesList, "List of data types");
1244 typesList << "<h2> List of data types </h2>" << endl;
1245
1246 typesList << "<dl><dd>" << endl;
1247
1248 // make loop on data types
1249 std::list<std::string> typeNames;
1250
1251 {
1252 TDataType *type;
1253 TIter nextType(gROOT->GetListOfTypes());
1254
1255 while ((type = (TDataType *) nextType()))
1256 // no templates ('<' and '>'), no idea why the '(' is in here...
1257 if (*type->GetTitle() && !strchr(type->GetName(), '(')
1258 && !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>'))
1259 && type->GetName())
1260 typeNames.push_back(type->GetName());
1261 }
1262
1263 sort_strlist_stricmp(typeNames);
1264
1265 std::vector<std::string> indexChars;
1266 if (typeNames.size() > 10) {
1267 typesList << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
1268 // find index chars
1269 GetIndexChars(typeNames, 10 /*sections*/, indexChars);
1270 for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
1271 typesList << "<a href=\"#idx" << iIdxEntry << "\">";
1272 ReplaceSpecialChars(typesList, indexChars[iIdxEntry].c_str());
1273 typesList << "</a>" << endl;
1274 }
1275 typesList << "</div><br />" << endl;
1276 }
1277
1278 typesList << "<ul id=\"indx\">" << endl;
1279
1280 int idx = 0;
1281 UInt_t currentIndexEntry = 0;
1282
1283 for (std::list<std::string>::iterator iTypeName = typeNames.begin();
1284 iTypeName != typeNames.end(); ++iTypeName) {
1285 TDataType* type = gROOT->GetType(iTypeName->c_str(), kFALSE);
1286 typesList << "<li class=\"idxl" << idx%2 << "\">";
1287 if (currentIndexEntry < indexChars.size()
1288 && !strncmp(indexChars[currentIndexEntry].c_str(), iTypeName->c_str(),
1289 indexChars[currentIndexEntry].length()))
1290 typesList << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
1291 typesList << "<a name=\"";
1292 ReplaceSpecialChars(typesList, iTypeName->c_str());
1293 typesList << "\"><span class=\"typename\">";
1294 ReplaceSpecialChars(typesList, iTypeName->c_str());
1295 typesList << "</span></a> ";
1296 ReplaceSpecialChars(typesList, type->GetTitle());
1297 typesList << "</li>" << endl;
1298 ++idx;
1299 }
1300 typesList << "</ul>" << endl;
1301
1302 // write typesList footer
1303 WriteHtmlFooter(typesList);
1304
1305 // close file
1306 typesList.close();
1307
1308 }
1309
1310
1311 //______________________________________________________________________________
1312 void TDocOutput::DecorateEntityBegin(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
1313 {
1314 // Add some colors etc to a source entity, contained in str.
1315 // The type of what's contained in str is given by type.
1316 // It's called e.g. by TDocParser::BeautifyLine().
1317 // This function should assume that only str.Begin() is valid.
1318 // When inserting into str.String(), str.Begin() must be updated.
1319
1320 Ssiz_t originalLen = str.Length();
1321
1322 switch (type) {
1323 case TDocParser::kCode: break;
1324 case TDocParser::kComment:
1325 str.Insert(pos, "<span class=\"comment\">");
1326 break;
1327 case TDocParser::kDirective:
1328 break;
1329 case TDocParser::kString:
1330 str.Insert(pos, "<span class=\"string\">");
1331 break;
1332 case TDocParser::kKeyword:
1333 str.Insert(pos, "<span class=\"keyword\">");
1334 break;
1335 case TDocParser::kCPP:
1336 str.Insert(pos, "<span class=\"cpp\">");
1337 break;
1338 case TDocParser::kVerbatim:
1339 str.Insert(pos, "<pre>");
1340 break;
1341 default:
1342 Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
1343 return;
1344 }
1345
1346 Ssiz_t addedLen = str.Length() - originalLen;
1347 pos += addedLen;
1348 }
1349
1350 //______________________________________________________________________________
1351 void TDocOutput::DecorateEntityEnd(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
1352 {
1353 // Add some colors etc to a source entity, contained in str.
1354 // The type of what's contained in str is given by type.
1355 // It's called e.g. by TDocParser::BeautifyLine().
1356 // This function should assume that only str."End()"
1357 // (i.e. str.Begin()+str.Length()) is valid.
1358 // When inserting into str.String(), str.Length() must be updated.
1359
1360 Ssiz_t originalLen = str.Length();
1361
1362 switch (type) {
1363 case TDocParser::kCode: break;
1364 case TDocParser::kComment:
1365 str.Insert(pos, "</span>");
1366 break;
1367 case TDocParser::kDirective:
1368 break;
1369 case TDocParser::kString:
1370 str.Insert(pos, "</span>");
1371 break;
1372 case TDocParser::kKeyword:
1373 str.Insert(pos, "</span>");
1374 break;
1375 case TDocParser::kCPP:
1376 str.Insert(pos, "</span>");
1377 break;
1378 case TDocParser::kVerbatim:
1379 str.Insert(pos, "</pre>");
1380 break;
1381 default:
1382 Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
1383 return;
1384 }
1385 Ssiz_t addedLen = str.Length() - originalLen;
1386 pos += addedLen;
1387 }
1388
1389 //______________________________________________________________________________
1390 void TDocOutput::FixupAuthorSourceInfo(TString& authors)
1391 {
1392 // Special author treatment; called when TDocParser::fSourceInfo[kInfoAuthor] is set.
1393 // Modifies the author(s) description, which is a comma separated list of tokens
1394 // either in the format
1395 // (i) "FirstName LastName " or
1396 // (ii) "FirstName LastName <link> more stuff"
1397 // The first one generates an XWho link (CERN compatible),
1398 // the second a http link (WORLD compatible), <link> being e.g.
1399 // <mailto:user@host.bla> or <http://www.host.bla/page>.
1400
1401 TString original(authors);
1402 authors = "";
1403
1404 TString author;
1405 Ssiz_t pos = 0;
1406 Bool_t firstAuthor = kTRUE;
1407 while (original.Tokenize(author, pos, ",")) {
1408 author.Strip(TString::kBoth);
1409
1410 if (!firstAuthor)
1411 authors += ", ";
1412 firstAuthor = kFALSE;
1413
1414 // do we have a link for the current name?
1415 Ssiz_t cLink = author.First('<'); // look for link start tag
1416 if (cLink != kNPOS) {
1417 // split NAME <LINK> POST
1418 // into <a href="LINK">NAME</a> POST
1419 Ssiz_t endLink = author.Index(">", cLink + 1);
1420 if(endLink == kNPOS)
1421 endLink = author.Length();
1422 authors += "<a href=\"";
1423 authors += author(cLink + 1, endLink - (cLink + 1));
1424 authors += "\">";
1425 authors += author(0, cLink);
1426 authors += "</a>";
1427 if (endLink != author.Length())
1428 authors += author(endLink + 1, author.Length());
1429 } else {
1430 authors += "<a href=\"";
1431 authors += fHtml->GetXwho();
1432
1433 // separate Firstname Middlename Lastname by '+'
1434 TString namePart;
1435 Ssiz_t posNamePart = 0;
1436 Bool_t firstNamePart = kTRUE;
1437 while (author.Tokenize(namePart, posNamePart, " ")) {
1438 namePart.Strip(TString::kBoth);
1439 if (!namePart.Length())
1440 continue;
1441 if (isdigit(namePart[0])) continue; //likely a date
1442 if (!firstNamePart)
1443 authors += '+';
1444 firstNamePart = kFALSE;
1445 authors += namePart;
1446 }
1447 authors += "\">";
1448 authors += author;
1449 authors += "</a>";
1450 }
1451 } // while next author
1452 }
1453
1454 //______________________________________________________________________________
1455 Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type)
1456 {
1457 // Check if file is modified
1458 //
1459 //
1460 // Input: classPtr - pointer to the class
1461 // type - file type to compare with
1462 // values: kSource, kInclude, kTree
1463 //
1464 // Output: TRUE - if file is modified since last time
1465 // FALSE - if file is up to date
1466 //
1467
1468 TString sourceFile;
1469 TString classname(classPtr->GetName());
1470 TString filename;
1471 TString dir;
1472
1473 switch (type) {
1474 case kSource:
1475 if (classPtr->GetImplFileLine()) {
1476 fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
1477 } else {
1478 fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
1479 }
1480 dir = "src";
1481 gSystem->PrependPathName(fHtml->GetOutputDir(), dir);
1482 filename = classname;
1483 NameSpace2FileName(filename);
1484 gSystem->PrependPathName(dir, filename);
1485 if (classPtr->GetImplFileLine())
1486 filename += ".cxx.html";
1487 else
1488 filename += ".h.html";
1489 break;
1490
1491 case kInclude:
1492 fHtml->GetDeclFileName(classPtr, kFALSE, filename);
1493 filename = gSystem->BaseName(filename);
1494 fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
1495 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
1496 break;
1497
1498 case kTree:
1499 fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
1500 NameSpace2FileName(classname);
1501 gSystem->PrependPathName(fHtml->GetOutputDir(), classname);
1502 filename = classname;
1503 filename += "_Tree.pdf";
1504 break;
1505
1506 case kDoc:
1507 if (classPtr->GetImplFileLine()) {
1508 fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
1509 } else {
1510 fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
1511 }
1512 filename = classname;
1513 NameSpace2FileName(filename);
1514 gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
1515 filename += ".html";
1516 break;
1517
1518 default:
1519 Error("IsModified", "Unknown file type !");
1520 }
1521
1522 R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
1523
1524 // Get info about a file
1525 Long64_t size;
1526 Long_t id, flags, sModtime, dModtime;
1527
1528 if (!(gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)))
1529 if (!(gSystem->GetPathInfo(filename, &id, &size, &flags, &dModtime)))
1530 return (sModtime > dModtime);
1531
1532 return kTRUE;
1533 }
1534
1535
1536 //______________________________________________________________________________
1537 void TDocOutput::NameSpace2FileName(TString& name)
1538 {
1539 // Replace "::" in name by "__"
1540 // Replace "<", ">", " ", ",", "~", "=" in name by "_"
1541 // Replace "A::X<A::Y>" by "A::X<-p0Y>",
1542 // "A::B::X<A::B::Y>" by "A::B::X<-p1Y>", etc
1543
1544 TString encScope(name);
1545 Ssiz_t posTemplate = encScope.Index('<');
1546 if (posTemplate != kNPOS) {
1547 TString templateArgs = encScope(posTemplate, encScope.Length());
1548 encScope.Remove(posTemplate, encScope.Length());
1549 // shorten the name a bit:
1550 // convert A::B::X<A::B::Y> to A::X<-p1Y>, i.e.
1551 // the filename A__X_A__Y_ to A__X_-p1Y_
1552 // The rule: if the enclosing scope up to the N-th scope matches,
1553 // the name becomes -pN
1554 Ssiz_t posName = encScope.Last(':');
1555 if (posName != kNPOS) {
1556 Int_t numDblColumn = encScope.CountChar(':');
1557 while (numDblColumn > 1) {
1558 encScope.Remove(posName + 1, encScope.Length());
1559 numDblColumn -= 2;
1560 templateArgs.ReplaceAll(encScope, TString::Format("-p%d", numDblColumn / 2));
1561 encScope.Remove(encScope.Length() - 2, 2);
1562 posName = encScope.Last(':');
1563 if (posName == kNPOS)
1564 break; // should be handled by numDblColumn...
1565 }
1566 name.Replace(posTemplate, name.Length(), templateArgs);
1567 }
1568 }
1569
1570 if (name.Length() > 240) { // really 240! It might get some extra prefix or extension
1571 // 8.3 is dead, but e.g. ext2 can only hold 255 chars in a file name.
1572 // So mangle name to "beginning_of_name"-h"hash"."extension", where
1573 // beginning_of_name is short enough such that the full name is <255 characters.
1574
1575 TString hash;
1576 TDocParser::AnchorFromLine(name, hash);
1577 hash.Prepend("-h");
1578 Ssiz_t posDot = name.Last('.');
1579 TString ext;
1580 if (posDot != kNPOS)
1581 ext = name(posDot, name.Length());
1582 Ssiz_t namelen = 240 - hash.Length() - ext.Length();
1583 name = name(0, namelen) + hash + ext;
1584 }
1585
1586 const char* replaceWhat = ":<> ,~=";
1587 for (Ssiz_t i=0; i < name.Length(); ++i)
1588 if (strchr(replaceWhat, name[i]))
1589 name[i] = '_';
1590 }
1591
1592 //______________________________________________________________________________
1593 void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir,
1594 const char* outdir, const char* linkdir)
1595 {
1596 // Write links to files indir/*.txt, indir/*.html (non-recursive) to out.
1597 // If one of the files is called "index.{html,txt}" it will be
1598 // included in out (instead of copying it to outdir and generating a link
1599 // to linkdir). txt files are passed through Convert().
1600 // The files' links are sorted alphabetically.
1601
1602 R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
1603
1604 void * dirHandle = gSystem->OpenDirectory(indir);
1605 if (!dirHandle) return;
1606
1607 const char* entry = 0;
1608 std::list<std::string> files;
1609 while ((entry = gSystem->GetDirEntry(dirHandle))) {
1610 FileStat_t stat;
1611 TString filename(entry);
1612 gSystem->PrependPathName(indir, filename);
1613 if (gSystem->GetPathInfo(filename, stat)) // funny ret
1614 continue;
1615 if (!R_ISREG(stat.fMode)) continue;
1616
1617 if (TString(entry).BeginsWith("index.", TString::kIgnoreCase)) {
1618 // This is the part we put directly (verbatim) into the module index.
1619 // If it ends on ".txt" we run Convert first.
1620 if (filename.EndsWith(".txt", TString::kIgnoreCase)) {
1621 std::ifstream in(filename);
1622 if (in) {
1623 out << "<pre>"; // this is what e.g. the html directive expects
1624 TDocParser parser(*this);
1625 parser.Convert(out, in, "./", kFALSE /* no code */);
1626 out << "</pre>";
1627 }
1628 } else if (filename.EndsWith(".html", TString::kIgnoreCase)) {
1629 std::ifstream in(filename);
1630 TString line;
1631 while (in) {
1632 if (!line.ReadLine(in)) break;
1633 out << line << endl;
1634 }
1635 }
1636 } else
1637 files.push_back(filename.Data());
1638 }
1639
1640 std::stringstream furtherReading;
1641 files.sort();
1642 for (std::list<std::string>::const_iterator iFile = files.begin();
1643 iFile != files.end(); ++iFile) {
1644 TString filename(iFile->c_str());
1645 if (!filename.EndsWith(".txt", TString::kIgnoreCase)
1646 && !filename.EndsWith(".html", TString::kIgnoreCase))
1647 continue;
1648
1649 // Just copy and link this page.
1650 if (gSystem->AccessPathName(outdir))
1651 if (gSystem->mkdir(outdir, kTRUE) == -1)
1652 // bad - but let's still try to create the output
1653 Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
1654
1655 TString outfile(gSystem->BaseName(filename));
1656 gSystem->PrependPathName(outdir, outfile);
1657 if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
1658 // convert first
1659 outfile.Remove(outfile.Length()-3, 3);
1660 outfile += "html";
1661 std::ifstream inFurther(filename);
1662 std::ofstream outFurther(outfile);
1663 if (inFurther && outFurther) {
1664 outFurther << "<pre>"; // this is what e.g. the html directive expects
1665 TDocParser parser(*this);
1666 parser.Convert(outFurther, inFurther, "../", kFALSE /*no code*/);
1667 outFurther << "</pre>";
1668 }
1669 } else {
1670 if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
1671 continue;
1672 }
1673 TString showname(gSystem->BaseName(outfile));
1674 furtherReading << "<a class=\"linkeddoc\" href=\"" << linkdir << "/" << showname << "\">";
1675 showname.Remove(showname.Length() - 5, 5); // .html
1676 showname.ReplaceAll("_", " ");
1677 ReplaceSpecialChars(furtherReading, showname);
1678 furtherReading << "</a> " << endl;
1679 }
1680
1681 gSystem->FreeDirectory(dirHandle);
1682 if (furtherReading.str().length())
1683 out << "<h3>Further Reading</h3><div id=\"furtherreading\">" << endl
1684 << furtherReading.str() << "</div><h3>List of Classes</h3>" << endl;
1685 }
1686
1687 //______________________________________________________________________________
1688 void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment /*= 0*/)
1689 {
1690 // Create a reference to a class documentation page.
1691 // str encloses the text to create the reference for (e.g. name of instance).
1692 // comment will be added e.g. as tooltip text.
1693 // After the reference is put into str.String(), str will enclose the reference
1694 // and the original text. Example:
1695 // Input:
1696 // str.String(): "a gHtml test"
1697 // str.Begin(): 2
1698 // str.Length(): 5
1699 // Output:
1700 // str.String(): "a <a href="THtml.html">gHtml</a> test"
1701 // str.Begin(): 2
1702 // str.Length(): 30
1703
1704 TString link;
1705 fHtml->GetHtmlFileName(entity, link);
1706
1707 if (comment && !strcmp(comment, entity->GetName()))
1708 comment = "";
1709
1710 AddLink(str, link, comment);
1711 }
1712
1713 //______________________________________________________________________________
1714 void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment /*= 0*/)
1715 {
1716 // Create a reference to a data member documentation page.
1717 // str encloses the text to create the reference for (e.g. name of instance).
1718 // comment will be added e.g. as tooltip text.
1719 // After the reference is put into str.String(), str will enclose the reference
1720 // and the original text. Example:
1721 // Input:
1722 // str.String(): "a gHtml test"
1723 // str.Begin(): 2
1724 // str.Length(): 5
1725 // Output:
1726 // str.String(): "a <a href="THtml.html">gHtml</a> test"
1727 // str.Begin(): 2
1728 // str.Length(): 30
1729 TString link;
1730 TClass* scope = entity->GetClass();
1731 fHtml->GetHtmlFileName(scope, link);
1732 link += "#";
1733
1734 TString mangledName(scope->GetName());
1735 NameSpace2FileName(mangledName);
1736 link += mangledName;
1737 link += ":";
1738
1739 mangledName = entity->GetName();
1740 NameSpace2FileName(mangledName);
1741 link += mangledName;
1742
1743 TString description;
1744 if (!comment) {
1745 description = entity->GetFullTypeName();
1746 description += " ";
1747 if (scope) {
1748 description += scope->GetName();
1749 description += "::";
1750 }
1751 description += entity->GetName();
1752 comment = description.Data();
1753 }
1754
1755 if (comment && !strcmp(comment, entity->GetName()))
1756 comment = "";
1757
1758 AddLink(str, link, comment);
1759 }
1760
1761 //______________________________________________________________________________
1762 void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment /*= 0*/)
1763 {
1764 // Create a reference to a type documentation page.
1765 // str encloses the text to create the reference for (e.g. name of instance).
1766 // comment will be added e.g. as tooltip text.
1767 // After the reference is put into str.String(), str will enclose the reference
1768 // and the original text. Example:
1769 // Input:
1770 // str.String(): "a gHtml test"
1771 // str.Begin(): 2
1772 // str.Length(): 5
1773 // Output:
1774 // str.String(): "a <a href="THtml.html">gHtml</a> test"
1775 // str.Begin(): 2
1776 // str.Length(): 30
1777
1778 TString mangledEntity(entity->GetName());
1779 NameSpace2FileName(mangledEntity);
1780
1781 TString link;
1782 TClassDocInfo* cdi = 0;
1783 bool isClassTypedef = entity->GetType() == -1;
1784 if (isClassTypedef)
1785 /* is class/ struct / union */
1786 isClassTypedef = isClassTypedef && (entity->Property() & 7);
1787 if (isClassTypedef)
1788 cdi = (TClassDocInfo*) GetHtml()->GetListOfClasses()->FindObject(entity->GetFullTypeName());
1789 if (cdi) {
1790 link = mangledEntity + ".html";
1791 } else {
1792 link = "ListOfTypes.html#";
1793 link += mangledEntity;
1794 }
1795
1796 if (comment && !strcmp(comment, entity->GetName()))
1797 comment = "";
1798
1799 AddLink(str, link, comment);
1800 }
1801
1802 //______________________________________________________________________________
1803 void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment /*= 0*/)
1804 {
1805 // Create a reference to a method documentation page.
1806 // str encloses the text to create the reference for (e.g. name of instance).
1807 // comment will be added e.g. as tooltip text.
1808 // After the reference is put into str.String(), str will enclose the reference
1809 // and the original text. Example:
1810 // Input:
1811 // str.String(): "a gHtml test"
1812 // str.Begin(): 2
1813 // str.Length(): 5
1814 // Output:
1815 // str.String(): "a <a href="THtml.html">gHtml</a> test"
1816 // str.Begin(): 2
1817 // str.Length(): 30
1818
1819 TString link;
1820 TClass* scope = entity->GetClass();
1821 fHtml->GetHtmlFileName(scope, link);
1822 link += "#";
1823
1824 TString mangledName(scope->GetName());
1825 NameSpace2FileName(mangledName);
1826 link += mangledName;
1827 link += ":";
1828
1829 mangledName = entity->GetName();
1830 NameSpace2FileName(mangledName);
1831 link += mangledName;
1832
1833 TString description;
1834 if (!comment && entity->GetClass()) {
1835 TIter iMeth(scope->GetListOfMethods());
1836 TMethod* mCand = 0;
1837 while ((mCand = (TMethod*)iMeth()))
1838 if (!strcmp(mCand->GetName(), entity->GetName())) {
1839 if (description.Length()) {
1840 description += " or overloads";
1841 break;
1842 }
1843 description = mCand->GetPrototype();
1844 }
1845 comment = description.Data();
1846 }
1847
1848 if (comment && !strcmp(comment, entity->GetName()))
1849 comment = "";
1850
1851 AddLink(str, link, comment);
1852 }
1853
1854 //______________________________________________________________________________
1855 Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
1856 {
1857 // Check whether reference is a relative reference, and can (or should)
1858 // be prependen by relative paths. For HTML, check that it doesn't start
1859 // with "http://" or "https://"
1860
1861 return !reference ||
1862 strncmp(reference, "http", 4) ||
1863 (strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4));
1864 }
1865
1866 //______________________________________________________________________________
1867 const char* TDocOutput::ReplaceSpecialChars(char c)
1868 {
1869 // Replace ampersand, less-than and greater-than character, writing to out.
1870 // If 0 is returned, no replacement needs to be done.
1871
1872 /*
1873 if (fEscFlag) {
1874 fEscFlag = kFALSE;
1875 return buf;
1876 } else if (c == fEsc) {
1877 // text.Remove(pos, 1); - NO! we want to keep it nevertheless!
1878 fEscFlag = kTRUE;
1879 return buf;
1880 }
1881
1882 */
1883 switch (c) {
1884 case '<': return "&lt;";
1885 case '&': return "&amp;";
1886 case '>': return "&gt;";
1887 };
1888 return 0;
1889 }
1890
1891 //______________________________________________________________________________
1892 void TDocOutput::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
1893 {
1894 // Replace ampersand, less-than and greater-than character
1895 //
1896 //
1897 // Input: text - text where replacement will happen,
1898 // pos - index of char to be replaced; will point to next char to be
1899 // replaced when function returns
1900 //
1901
1902 const char c = text[pos];
1903 const char* replaced = ReplaceSpecialChars(c);
1904 if (replaced) {
1905 text.Replace(pos, 1, replaced);
1906 pos += strlen(replaced) - 1;
1907 }
1908 ++pos;
1909 }
1910
1911 //______________________________________________________________________________
1912 void TDocOutput::ReplaceSpecialChars(TString& text) {
1913 // Replace ampersand, less-than and greater-than character
1914 //
1915 //
1916 // Input: text - text where replacement will happen,
1917 //
1918 Ssiz_t pos = 0;
1919 while (pos < text.Length())
1920 ReplaceSpecialChars(text, pos);
1921 }
1922
1923 //______________________________________________________________________________
1924 void TDocOutput::ReplaceSpecialChars(std::ostream& out, const char *string)
1925 {
1926 // Replace ampersand, less-than and greater-than characters, writing to out
1927 //
1928 //
1929 // Input: out - output file stream
1930 // string - pointer to an array of characters
1931 //
1932
1933 while (string && *string) {
1934 const char* replaced = ReplaceSpecialChars(*string);
1935 if (replaced)
1936 out << replaced;
1937 else
1938 out << *string;
1939 string++;
1940 }
1941 }
1942
1943 //______________________________________________________________________________
1944 Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap /* =0 */,
1945 EGraphvizTool gvwhat /*= kDot*/) {
1946 // Run filename".dot", creating filename".gif", and - if outMap is !=0,
1947 // filename".map", which gets then included literally into outMap.
1948
1949 if (!fHtml->HaveDot())
1950 return kFALSE;
1951
1952 TString runDot;
1953 switch (gvwhat) {
1954 case kNeato: runDot = "neato"; break;
1955 case kFdp: runDot = "fdp"; break;
1956 case kCirco: runDot = "circo"; break;
1957 default: runDot = "dot";
1958 };
1959 if (fHtml->GetDotDir() && *fHtml->GetDotDir())
1960 gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
1961 runDot += " -q1 -Tgif -o";
1962 runDot += filename;
1963 runDot += ".gif ";
1964 if (outMap) {
1965 runDot += "-Tcmap -o";
1966 runDot += filename;
1967 runDot += ".map ";
1968 }
1969 runDot += filename;
1970 runDot += ".dot";
1971
1972 if (gDebug > 3)
1973 Info("RunDot", "Running: %s", runDot.Data());
1974 Int_t retDot = gSystem->Exec(runDot);
1975 if (gDebug < 4 && !retDot)
1976 gSystem->Unlink(Form("%s.dot", filename));
1977
1978 if (!retDot && outMap) {
1979 ifstream inmap(Form("%s.map", filename));
1980 std::string line;
1981 std::getline(inmap, line);
1982 if (inmap && !inmap.eof()) {
1983 *outMap << "<map name=\"Map" << gSystem->BaseName(filename)
1984 << "\" id=\"Map" << gSystem->BaseName(filename) << "\">" << endl;
1985 while (inmap && !inmap.eof()) {
1986 if (line.compare(0, 6, "<area ") == 0) {
1987 size_t posEndTag = line.find('>');
1988 if (posEndTag != std::string::npos)
1989 line.replace(posEndTag, 1, "/>");
1990 }
1991 *outMap << line << endl;
1992 std::getline(inmap, line);
1993 }
1994 *outMap << "</map>" << endl;
1995 }
1996 inmap.close();
1997 if (gDebug < 7)
1998 gSystem->Unlink(Form("%s.map", filename));
1999 }
2000
2001 if (retDot) {
2002 Error("RunDot", "Error running %s!", runDot.Data());
2003 fHtml->SetFoundDot(kFALSE);
2004 return kFALSE;
2005 }
2006
2007 return kTRUE;
2008 }
2009
2010
2011 //______________________________________________________________________________
2012 void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial,
2013 const char* dir /*=""*/, TClass *cls /*=0*/,
2014 const char* header)
2015 {
2016 // Write HTML header
2017 //
2018 // Internal method invoked by the overload
2019
2020 ifstream addHeaderFile(header);
2021
2022 if (!addHeaderFile.good()) {
2023 Warning("THtml::WriteHtmlHeader",
2024 "Can't open html header file %s\n", header);
2025 return;
2026 }
2027
2028 TString declFileName;
2029 if (cls) fHtml->GetDeclFileName(cls, kFALSE, declFileName);
2030 TString implFileName;
2031 if (cls) fHtml->GetImplFileName(cls, kFALSE, implFileName);
2032
2033 const TString& charset = GetHtml()->GetCharset();
2034 TDatime date;
2035 TString strDate(date.AsString());
2036 TString line;
2037
2038 while (!addHeaderFile.eof()) {
2039
2040 line.ReadLine(addHeaderFile, kFALSE);
2041 if (addHeaderFile.eof())
2042 break;
2043
2044 if (line) {
2045
2046 if (!cls && (
2047 line.Index("%CLASS%") != kNPOS ||
2048 line.Index("%INCFILE%") != kNPOS ||
2049 line.Index("%SRCFILE%") != kNPOS))
2050 continue; // skip class line for non-class files
2051
2052 TString txt(line);
2053
2054 txt.ReplaceAll("%TITLE%", titleNoSpecial);
2055 txt.ReplaceAll("%DATE%", strDate);
2056 txt.ReplaceAll("%RELDIR%", dir);
2057 txt.ReplaceAll("%CHARSET%", charset);
2058
2059 if (cls) {
2060 txt.ReplaceAll("%CLASS%", cls->GetName());
2061 txt.ReplaceAll("%INCFILE%", declFileName);
2062 txt.ReplaceAll("%SRCFILE%", implFileName);
2063 }
2064
2065 out << txt << endl;
2066 }
2067 }
2068 }
2069
2070 //______________________________________________________________________________
2071 void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title,
2072 const char* dir /*=""*/, TClass *cls/*=0*/)
2073 {
2074 // Write HTML header
2075 //
2076 //
2077 // Input: out - output file stream
2078 // title - title for the HTML page
2079 // cls - current class
2080 // dir - relative directory to reach the top
2081 // ("" for html doc, "../" for src/*cxx.html etc)
2082 //
2083 // evaluates the Root.Html.Header setting:
2084 // * if not set, the standard header is written. (ROOT)
2085 // * if set, and ends with a "+", the standard header is written and this file
2086 // included afterwards. (ROOT, USER)
2087 // * if set but doesn't end on "+" the file specified will be written instead
2088 // of the standard header (USER)
2089 //
2090 // Any occurrence of "%TITLE%" (without the quotation marks) in the user
2091 // provided header file will be replaced by the value of this method's
2092 // parameter "title" before written to the output file. %CLASS% is replaced by
2093 // the class name, %INCFILE% by the header file name as given by
2094 // TClass::GetDeclFileName() and %SRCFILE% by the source file name as given by
2095 // TClass::GetImplFileName(). If the header is written for a non-class page,
2096 // i.e. cls==0, lines containing %CLASS%, %INCFILE%, or %SRCFILE% will be
2097 // skipped.
2098
2099 TString userHeader = GetHtml()->GetHeader();
2100 TString noSpecialCharTitle(title);
2101 ReplaceSpecialChars(noSpecialCharTitle);
2102
2103 Ssiz_t lenUserHeader = userHeader.Length();
2104 // standard header output if Root.Html.Header is not set, or it's set and it ends with a "+".
2105 Bool_t bothHeaders = lenUserHeader > 0 && userHeader[lenUserHeader - 1] == '+';
2106 if (lenUserHeader == 0 || bothHeaders) {
2107 TString header("header.html");
2108 gSystem->PrependPathName(fHtml->GetEtcDir(), header);
2109 WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, header);
2110 }
2111
2112 if (lenUserHeader != 0) {
2113 if (bothHeaders)
2114 userHeader.Remove(lenUserHeader - 1);
2115 WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, userHeader);
2116 };
2117 }
2118
2119 //______________________________________________________________________________
2120 void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/,
2121 const char* lastUpdate, const char* author,
2122 const char* copyright, const char* footer)
2123 {
2124 // Write HTML footer
2125 //
2126 // Internal method invoked by the overload
2127
2128 static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%", "%CHANGED%", "%GENERATED%"};
2129
2130 TString datimeString;
2131 if (!lastUpdate || !strlen(lastUpdate)) {
2132 TDatime date;
2133 datimeString = date.AsString();
2134 lastUpdate = datimeString.Data();
2135 }
2136 TString today;
2137 TDatime dtToday;
2138 today.Form("%d-%02d-%02d %02d:%02d", dtToday.GetYear(), dtToday.GetMonth(), dtToday.GetDay(), dtToday.GetHour(), dtToday.GetMinute());
2139 const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright, lastUpdate, today };
2140
2141 ifstream addFooterFile(footer);
2142
2143 if (!addFooterFile.good()) {
2144 Warning("THtml::WriteHtmlFooter",
2145 "Can't open html footer file %s\n", footer);
2146 return;
2147 }
2148
2149 TString line;
2150 while (!addFooterFile.eof()) {
2151
2152 line.ReadLine(addFooterFile, kFALSE);
2153 if (addFooterFile.eof())
2154 break;
2155
2156 if (!line)
2157 continue;
2158
2159 for (Int_t siTag = 0; siTag < (Int_t) TDocParser::kNumSourceInfos; ++siTag) {
2160 Ssiz_t siPos = line.Index(templateSITags[siTag]);
2161 if (siPos != kNPOS) {
2162 if (siValues[siTag] && siValues[siTag][0])
2163 line.Replace(siPos, strlen(templateSITags[siTag]), siValues[siTag]);
2164 else
2165 line = ""; // skip e.g. %AUTHOR% lines if no author is set
2166 }
2167 }
2168
2169 out << line << std::endl;
2170 }
2171
2172 }
2173
2174 //______________________________________________________________________________
2175 void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
2176 const char *lastUpdate, const char *author,
2177 const char *copyright)
2178 {
2179 // Write HTML footer
2180 //
2181 //
2182 // Input: out - output file stream
2183 // dir - usually equal to "" or "../", depends of
2184 // current file directory position, i.e. if
2185 // file is in the fHtml->GetOutputDir(), then dir will be ""
2186 // lastUpdate - last update string
2187 // author - author's name
2188 // copyright - copyright note
2189 //
2190 // Allows optional user provided footer to be written. Root.Html.Footer holds
2191 // the file name for this footer. For details see THtml::WriteHtmlHeader (here,
2192 // the "+" means the user's footer is written in front of Root's!) Occurences
2193 // of %AUTHOR%, %CHANGED%, %GENERATED%, and %COPYRIGHT% in the user's file are replaced by
2194 // their corresponding values (author, lastUpdate, today, and copyright) before
2195 // written to out.
2196 // If no author is set (author == "", e.g. for ClassIndex.html") skip the whole
2197 // line of the footer template containing %AUTHOR%. Accordingly for %COPYRIGHT%.
2198
2199 out << endl;
2200
2201 TString userFooter = GetHtml()->GetFooter();
2202
2203 if (userFooter.Length() != 0) {
2204 TString footer(userFooter);
2205 if (footer.EndsWith("+"))
2206 footer.Remove(footer.Length() - 1);
2207 WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
2208 };
2209
2210 if (userFooter.Length() == 0 || userFooter.EndsWith("+")) {
2211 TString footer("footer.html");
2212 gSystem->PrependPathName(fHtml->GetEtcDir(), footer);
2213 WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
2214 }
2215 }
2216
2217 //______________________________________________________________________________
2218 void TDocOutput::WriteModuleLinks(std::ostream& out)
2219 {
2220 // Create a div containing links to all topmost modules
2221
2222 if (fHtml->GetListOfModules()->GetSize()) {
2223 out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
2224 // find index chars
2225 fHtml->SortListOfModules();
2226 TIter iModule(fHtml->GetListOfModules());
2227 TModuleDocInfo* module = 0;
2228 while ((module = (TModuleDocInfo*) iModule())) {
2229 if (!module->GetName() || strchr(module->GetName(), '/'))
2230 continue;
2231 if (module->IsSelected()) {
2232 TString name(module->GetName());
2233 name.ToUpper();
2234 out << "<a href=\"" << name << "_Index.html\">"
2235 << name << "</a>" << endl;
2236 }
2237 }
2238 out<< "</div><br />" << endl;
2239 }
2240 }
2241
2242 //______________________________________________________________________________
2243 void TDocOutput::WriteModuleLinks(std::ostream& out, TModuleDocInfo* super)
2244 {
2245 // Create a div containing links to all modules
2246
2247 if (super->GetSub().GetSize()) {
2248 TString superName(super->GetName());
2249 superName.ToUpper();
2250 out << "<div id=\"indxModules\"><h4>" << superName << " Modules</h4>" << endl;
2251 // find index chars
2252 super->GetSub().Sort();
2253 TIter iModule(&super->GetSub());
2254 TModuleDocInfo* module = 0;
2255 while ((module = (TModuleDocInfo*) iModule())) {
2256 if (module->IsSelected()) {
2257 TString name(module->GetName());
2258 name.ToUpper();
2259 TString link(name);
2260 link.ReplaceAll("/", "_");
2261 Ssiz_t posSlash = name.Last('/');
2262 if (posSlash != kNPOS)
2263 name.Remove(0, posSlash + 1);
2264 out << "<a href=\"" << link << "_Index.html\">" << name << "</a>" << endl;
2265 }
2266 }
2267 out<< "</div><br />" << endl;
2268 }
2269 }
2270
2271 //______________________________________________________________________________
2272 void TDocOutput::WriteSearch(std::ostream& out)
2273 {
2274 // Write a search link or a search box, based on THtml::GetSearchStemURL()
2275 // and THtml::GetSearchEngine(). The first one is preferred.
2276
2277 // e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u+-site%3A%u%2Fsrc%2F+-site%3A%u%2Fexamples%2F";
2278 const TString& searchCmd = GetHtml()->GetSearchStemURL();
2279 const TString& searchEngine = GetHtml()->GetSearchEngine();
2280
2281 if (!searchCmd.Length() && !searchEngine.Length())
2282 return;
2283
2284 if (searchCmd.Length()) {
2285 TUrl url(searchCmd);
2286 TString serverName(url.GetHost());
2287 if (serverName.Length()) {
2288 serverName.Prepend(" title=\"");
2289 serverName += "\" ";
2290 }
2291 // create search input
2292 out << "<script type=\"text/javascript\">" << endl
2293 << "function onSearch() {" << endl
2294 << "var s='" << searchCmd <<"';" << endl
2295 << "var ref=String(document.location.href).replace(/https?:\\/\\//,'').replace(/\\/[^\\/]*$/,'').replace(/\\//g,'%2F');" << endl
2296 << "window.location.href=s.replace(/%u/ig,ref).replace(/%s/ig,escape(document.searchform.t.value));" << endl
2297 << "return false;}" << endl
2298 << "</script>" << endl
2299 << "<a class=\"descrheadentry\"> </a>" << endl
2300 << "<form id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\" action=\"javascript:onSearch();\" method=\"post\">" << endl
2301 << "<input name=\"t\" size=\"30\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input></form>" << endl
2302 << "<a id=\"searchlink\" " << serverName << " href=\"javascript:onSearch();\" onclick=\"return onSearch()\">Search</a>" << endl;
2303 } else if (searchEngine.Length())
2304 // create link to search engine page
2305 out << "<a class=\"descrheadentry\" href=\"" << searchEngine
2306 << "\">Search the Class Reference Guide</a>" << endl;
2307 }
2308
2309 //______________________________________________________________________________
2310 void TDocOutput::WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname)
2311 {
2312 // Write the first part of the links shown ontop of each doc page;
2313 // two <div>s have to be closed by caller so additional items can still
2314 // be added.
2315
2316 out << "<div id=\"toplinks\">" << endl;
2317
2318 // make a link to the description
2319 out << "<div class=\"descrhead\">" << endl
2320 << "<span class=\"descrtitle\">Location:</span>" << endl;
2321 const char *productName = fHtml->GetProductName();
2322 out << "<a class=\"descrheadentry\" href=\"index.html\">" << productName << "</a>" << endl;
2323
2324 if (module) {
2325 TString modulename(module->GetName());
2326 modulename.ToUpper();
2327 TString modulePart;
2328 TString modulePath;
2329 Ssiz_t pos = 0;
2330 while (modulename.Tokenize(modulePart, pos, "/")) {
2331 if (pos == kNPOS && !classname)
2332 // we are documenting the module itself, no need to link it:
2333 break;
2334 if (modulePath.Length()) modulePath += "_";
2335 modulePath += modulePart;
2336 out << " &#187; <a class=\"descrheadentry\" href=\"./" << modulePath << "_Index.html\">" << modulePart << "</a>" << endl;
2337 }
2338 }
2339
2340 TString entityName;
2341 if (classname) entityName = classname;
2342 else if (module) {
2343 entityName = module->GetName();
2344 Ssiz_t posSlash = entityName.Last('/');
2345 if (posSlash != kNPOS)
2346 entityName.Remove(0, posSlash + 1);
2347 entityName.ToUpper();
2348 }
2349 if (entityName.Length()) {
2350 out << " &#187; <a class=\"descrheadentry\" href=\"#TopOfPage\">";
2351 ReplaceSpecialChars(out, entityName);
2352 out << "</a>" << endl;
2353 }
2354 out << "</div>" << endl;
2355
2356 out << "<div class=\"descrhead\">" << endl
2357 << "<span class=\"descrtitle\">Quick Links:</span>" << endl;
2358
2359 // link to the user home page (if exist)
2360 const char* userHomePage = GetHtml()->GetHomepage();
2361 if (productName && !strcmp(productName, "ROOT"))
2362 userHomePage = "";
2363 if (userHomePage && *userHomePage)
2364 out << "<a class=\"descrheadentry\" href=\"" << userHomePage << "\">" << productName << "</a>" << endl;
2365 out << "<a class=\"descrheadentry\" href=\"http://root.cern.ch\">ROOT Homepage</a>" << endl
2366 << "<a class=\"descrheadentry\" href=\"./ClassIndex.html\">Class Index</a>" << endl
2367 << "<a class=\"descrheadentry\" href=\"./ClassHierarchy.html\">Class Hierarchy</a>" << endl;
2368 WriteSearch(out);
2369 out << "</div>" << endl;
2370
2371 }