ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/Utils/src/TDocOutput.cxx
Revision: 1.1
Committed: Tue Aug 11 23:09:28 2009 UTC (15 years, 8 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_018, Mit_017, Mit_017pre3, Mit_017pre2, Mit_017pre1, Mit_016, Mit_015b, Mit_015a, Mit_015, Mit_014e, Mit_014d, Mit_014c, Mit_014b, Mit_014a, Mit_014, Mit_014pre3, Mit_014pre2, Mit_014pre1, Mit_013d, Mit_013c, Mit_013b, Mit_013a, Mit_013, Mit_013pre1, Mit_012i, Mit_012h, Mit_012g, Mit_012f, Mit_012e, Mit_012d, Mit_012c, Mit_012b, Mit_012a, Mit_012, Mit_011a, Mit_011, Mit_010a
Log Message:
Added THtml from ROOT

File Contents

# User Rev Content
1 loizides 1.1 // @(#)root/html:$Id: TDocOutput.cxx 26944 2008-12-16 10:27:55Z brun $
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     &gClientGetListOfWindows, gclient));
421     gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGClient*)0x%lx)->GetDefaultRoot();",
422     &gClientGetDefaultRoot, 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     &winGetParent, 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     &winGetParent, win));
462     Bool_t winIsMapped = kFALSE;
463     if (winGetParent == gClientGetDefaultRoot)
464     gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TGWindow*)0x%lx)->IsMapped();",
465     &winIsMapped, win));
466     if (winIsMapped && previousWindows.find(win) == previousWindows.end()
467     && win->InheritsFrom(clGMainFrame)) {
468     gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->MapRaised();", 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     &hasEditor, win));
474     }
475     if (isRootCanvas && !hasEditor) {
476     TVirtualPad* pad = 0;
477     gROOT->ProcessLine(TString::Format("*((TVirtualPad**)0x%lx) = ((TRootCanvas*)0x%lx)->Canvas();",
478     &pad, 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     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     }