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

File Contents

# User Rev Content
1 bendavid 1.2 // @(#)root/html:$Id: THtml.cxx,v 1.1 2009/08/11 23:09:28 loizides Exp $
2 loizides 1.1 // Author: Nenad Buncic (18/10/95), Axel Naumann (09/28/01)
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/THtml.h"
13     #include "RConfigure.h"
14     #include "Riostream.h"
15     #include "TBaseClass.h"
16     #include "TClass.h"
17     #include "MitAna/Utils/interface/TClassDocOutput.h"
18     #include "TClassEdit.h"
19     #include "TClassTable.h"
20     #include "TDataType.h"
21     #include "MitAna/Utils/interface/TDocInfo.h"
22     #include "MitAna/Utils/interface/TDocOutput.h"
23     #include "TEnv.h"
24     #include "TInterpreter.h"
25     #include "TObjString.h"
26     #include "TPRegexp.h"
27     #include "TRegexp.h"
28     #include "TROOT.h"
29     #include "TSystem.h"
30     #include "TThread.h"
31    
32     #include <stdlib.h>
33     #include <string.h>
34     #include <ctype.h>
35     #include <set>
36     #include <fstream>
37    
38     //THtml *gHtml = 0;
39    
40     //______________________________________________________________________________
41     //______________________________________________________________________________
42     namespace {
43     class THtmlThreadInfo {
44     public:
45     THtmlThreadInfo(THtml* html, bool force): fHtml(html), fForce(force) {}
46     Bool_t GetForce() const {return fForce;}
47     THtml* GetHtml() const {return fHtml;}
48    
49     private:
50     THtml* fHtml;
51     Bool_t fForce;
52     };
53     }
54    
55    
56     //______________________________________________________________________________
57     THtml::THelperBase::~THelperBase()
58     {
59     // Helper's destructor.
60     // Check that no THtml object is attached to the helper - it might still need it!
61     if (fHtml) {
62     fHtml->HelperDeleted(this);
63     }
64     }
65    
66    
67     //______________________________________________________________________________
68     void THtml::THelperBase::SetOwner(THtml* html) {
69     // Set the THtml object owning this object; if it's already set to
70     // a different THtml object than issue an error message and signal to
71     // the currently set object that we are not belonging to it anymore.
72     if (fHtml && html && html != fHtml) {
73     Error("SetOwner()", "Object already owned by an THtml instance!");
74     fHtml->HelperDeleted(this);
75     }
76     fHtml = html;
77     }
78    
79    
80     //______________________________________________________________________________
81     bool THtml::TModuleDefinition::GetModule(TClass* cl, TString& out_modulename) const
82     {
83     // Set out_modulename to cl's module name; return true if it's valid.
84     // If applicable, the module contains super modules separated by "/".
85     //
86     // ROOT takes the directory part of cl's implementation file name
87     // (or declaration file name, if the implementation file name is empty),
88     // removes the last subdirectory if it is "src/" or "inc/", and interprets
89     // the remaining path as the module hierarchy, converting it to upper case.
90     // hist/histpainter/src/THistPainter.cxx thus becomes the module
91     // HIST/HISTPAINTER. (Node: some ROOT packages get special treatment.)
92     // If the file cannot be mapped into this scheme, the class's library
93     // name (without directories, leading "lib" prefix or file extensions)
94     // ius taken as the module name. If the module cannot be determined it is
95     // set to "USER" and false is returned.
96     //
97     // If your software cannot be mapped into this scheme then derive your
98     // own class from TModuleDefinition and pass it to THtml::SetModuleDefinition().
99    
100     out_modulename = "USER";
101     if (!cl) return false;
102    
103     // Filename: impl or decl?
104     TString filename;
105     if (!GetOwner()->GetImplFileName(cl, kFALSE, filename))
106     if (!GetOwner()->GetDeclFileName(cl, kFALSE, filename))
107     return false;
108    
109     // take the directory name without "/" or leading "."
110     out_modulename = gSystem->DirName(filename);
111    
112     TString inputdir = GetOwner()->GetInputPath();
113     TString tok;
114     Ssiz_t start = 0;
115     while (inputdir.Tokenize(tok, start, THtml::GetDirDelimiter())) {
116     if (out_modulename.BeginsWith(tok)) {
117     out_modulename.Remove(0, tok.Length());
118     break;
119     }
120     }
121     while (out_modulename[0] == '.')
122     out_modulename.Remove(0, 1);
123     out_modulename.ReplaceAll("\\", "/");
124     while (out_modulename[0] == '/')
125     out_modulename.Remove(0, 1);
126     while (out_modulename.EndsWith("/"))
127     out_modulename.Remove(out_modulename.Length() - 1);
128    
129     // remove "/src", "/inc"
130     if (out_modulename.EndsWith("/src")
131     || out_modulename.EndsWith("/inc"))
132     out_modulename.Remove(out_modulename.Length() - 4, 4);
133     else {
134     // remove "/src/whatever", "/inc/whatever"
135     Ssiz_t pos = out_modulename.Index("/src/");
136     if (pos == kNPOS)
137     pos = out_modulename.Index("/inc/");
138     if (pos != kNPOS)
139     out_modulename.Remove(pos);
140     }
141    
142     while (out_modulename.EndsWith("/"))
143     out_modulename.Remove(out_modulename.Length() - 1);
144    
145     // special treatment:
146     if (out_modulename == "MATH/GENVECTOR")
147     out_modulename = "MATHCORE";
148     else if (out_modulename == "MATH/MATRIX")
149     out_modulename = "SMATRIX";
150     else if (!out_modulename.Length()) {
151     const char* cname= cl->GetName();
152     if (strstr(cname, "::SMatrix<") || strstr(cname, "::SVector<"))
153     out_modulename = "SMATRIX";
154     else if (strstr(cname, "::TArrayProxy<") || strstr(cname, "::TClaArrayProxy<")
155     || strstr(cname, "::TImpProxy<") || strstr(cname, "::TClaImpProxy<"))
156     out_modulename = "TREEPLAYER";
157     else {
158     // determine the module name from the library name:
159     out_modulename = cl->GetSharedLibs();
160     Ssiz_t pos = out_modulename.Index(' ');
161     if (pos != kNPOS)
162     out_modulename.Remove(pos, out_modulename.Length());
163     if (out_modulename.BeginsWith("lib"))
164     out_modulename.Remove(0,3);
165     pos = out_modulename.Index('.');
166     if (pos != kNPOS)
167     out_modulename.Remove(pos, out_modulename.Length());
168    
169     if (!out_modulename.Length()) {
170     out_modulename = "USER";
171     return false;
172     }
173     }
174     }
175    
176     return true;
177     }
178    
179     //______________________________________________________________________________
180     void THtml::TFileDefinition::ExpandSearchPath(TString& path) const
181     {
182     // Create all permutations of path and THtml's input path:
183     // path being PP/ and THtml's input being .:include/:src/ gives
184     // .:./PP/:include:include/PP/:src/:src/PP
185     THtml* owner = GetOwner();
186     if (!owner) return;
187    
188     TString pathext;
189     TString inputdir = owner->GetInputPath();
190     TString tok;
191     Ssiz_t start = 0;
192     while (inputdir.Tokenize(tok, start, THtml::GetDirDelimiter())) {
193     if (pathext.Length())
194     pathext += GetDirDelimiter();
195     if (tok.EndsWith("\\"))
196     tok.Remove(tok.Length() - 1);
197     pathext += tok;
198     if (path.BeginsWith(tok))
199     pathext += GetDirDelimiter() + path;
200     else
201     pathext += GetDirDelimiter() + tok + "/" + path;
202     }
203     path = pathext;
204    
205     }
206    
207     //______________________________________________________________________________
208     void THtml::TFileDefinition::SplitClassIntoDirFile(const TString& clname, TString& dir, TString& filename) const
209     {
210     // Given a class name with a scope, split the class name into directory part
211     // and file name: A::B::C becomes module B, filename C.
212     TString token;
213     Ssiz_t from = 0;
214     filename = "";
215     dir = "";
216     while (clname.Tokenize(token, from, "::") ) {
217     dir = filename;
218     filename = token;
219     }
220    
221     // convert from Scope, class to module, filename.h
222     dir.ToLower();
223     }
224    
225    
226     //______________________________________________________________________________
227     bool THtml::TFileDefinition::GetDeclFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const
228     {
229     // Determine cl's declaration file name. Usually it's just
230     // cl->GetDeclFileName(), but sometimes conversions need to be done
231     // like include/ to abc/cde/inc/. If no declaration file name is
232     // available, look for b/inc/C.h for class A::B::C. out_fsys will contain
233     // the file system's (i.e. local machine's) full path name to the file.
234     // The function returns false if the class's header file cannot be found.
235     //
236     // If your software cannot be mapped into this scheme then derive your
237     // own class from TFileDefinition and pass it to THtml::SetFileDefinition().
238    
239     return GetFileName(cl, true, out_filename, out_fsys);
240     }
241    
242     //______________________________________________________________________________
243     bool THtml::TFileDefinition::GetImplFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const
244     {
245     // Determine cl's implementation file name. Usually it's just
246     // cl->GetImplFileName(), but sometimes conversions need to be done.
247     // If no implementation file name is available look for b/src/C.cxx for
248     // class A::B::C. out_fsys will contain the file system's (i.e. local
249     // machine's) full path name to the file.
250     // The function returns false if the class's source file cannot be found.
251     //
252     // If your software cannot be mapped into this scheme then derive your
253     // own class from TFileDefinition and pass it to THtml::SetFileDefinition().
254    
255     return GetFileName(cl, false, out_filename, out_fsys);
256     }
257    
258    
259     //______________________________________________________________________________
260     bool THtml::TFileDefinition::GetFileName(const TClass* cl, bool decl, TString& out_filename, TString& out_fsys) const
261     {
262     // Common implementation for GetDeclFileName(), GetImplFileName()
263    
264     out_fsys = "";
265    
266     if (!cl) {
267     out_filename = "";
268     return false;
269     }
270    
271     TString possibleFileName;
272     TString possiblePath;
273     TString filesysname;
274    
275     TString clfile = decl ? cl->GetDeclFileName() : cl->GetImplFileName();
276     out_filename = clfile;
277     if (clfile.Length()) {
278     // check that clfile doesn't start with one of the include paths;
279     // that's not what we want (include/TObject.h), we want the actual file
280     // if it exists (core/base/inc/TObject.h)
281    
282     // special case for TMath namespace:
283     if (clfile == "include/TMathBase.h") {
284     clfile = "math/mathcore/inc/TMath.h";
285     out_filename = clfile;
286     }
287    
288     TString inclDir;
289     TString inclPath(GetOwner()->GetPathInfo().fIncludePath);
290     Ssiz_t pos = 0;
291     Ssiz_t longestMatch = kNPOS;
292     while (inclPath.Tokenize(inclDir, pos, GetOwner()->GetDirDelimiter())) {
293     if (clfile.BeginsWith(inclDir) && (longestMatch == kNPOS || inclDir.Length() > longestMatch))
294     longestMatch = inclDir.Length();
295     }
296     if (longestMatch != kNPOS) {
297     clfile.Remove(0, longestMatch);
298     if (clfile.BeginsWith("/") || clfile.BeginsWith("\\"))
299     clfile.Remove(0, 1);
300     TString asincl(clfile);
301     GetOwner()->GetPathDefinition().GetFileNameFromInclude(asincl, clfile);
302     out_filename = clfile;
303     }
304     } else {
305     // check for a file named like the class:
306     filesysname = cl->GetName();
307     int templateLevel = 0;
308     Ssiz_t end = filesysname.Length();
309     Ssiz_t start = end - 1;
310     for (; start >= 0 && (templateLevel || filesysname[start] != ':'); --start) {
311     if (filesysname[start] == '>')
312     ++templateLevel;
313     else if (filesysname[start] == '<') {
314     --templateLevel;
315     if (!templateLevel)
316     end = start;
317     }
318     }
319     filesysname = filesysname(start + 1, end - start - 1);
320     if (decl)
321     filesysname += ".h";
322     else
323     filesysname += ".cxx";
324     TFileSysEntry* fsentry = (TFileSysEntry*) GetOwner()->GetLocalFiles()->GetEntries().FindObject(filesysname);
325     if (fsentry) {
326     fsentry->GetFullName(filesysname, kFALSE);
327     clfile = filesysname;
328     out_filename = filesysname;
329     }
330     }
331    
332     if (!decl && !clfile.Length()) {
333     // determine possible impl file name from the decl file name,
334     // replacing ".whatever" by ".cxx", and looking for it in the known
335     // file names
336     TString declSysFileName;
337     if (GetFileName(cl, true, filesysname, declSysFileName)) {
338     filesysname = gSystem->BaseName(filesysname);
339     Ssiz_t posExt = filesysname.Last('.');
340     if (posExt != kNPOS)
341     filesysname.Remove(posExt);
342     filesysname += ".cxx";
343     TFileSysEntry* fsentry = (TFileSysEntry*) GetOwner()->GetLocalFiles()->GetEntries().FindObject(filesysname);
344     if (fsentry) {
345     fsentry->GetFullName(filesysname, kFALSE);
346     clfile = filesysname;
347     out_filename = filesysname;
348     }
349     }
350     }
351    
352     if (clfile.Length() && !decl) {
353     // Do not return the source file for these packages, even though we can find them.
354     // THtml needs to have the class description in the source file if it finds the
355     // source file, and these classes have their class descriptions in the header files.
356     // THtml needs to be improved to collect all of a class' documentation before writing
357     // it out, so it can take the class doc from the header even though a source exists.
358     static const char* vetoClasses[] = {"math/mathcore/", "math/mathmore/", "math/genvector/",
359     "math/minuit2/", "math/smatrix/"};
360     for (unsigned int i = 0; i < sizeof(vetoClasses) / sizeof(char*); ++i) {
361     if (clfile.Contains(vetoClasses[i])) {
362     // of course there are exceptions from the exceptions:
363     // TComplex and TRandom, TRandom1,...
364     if (strcmp(cl->GetName(), "TComplex")
365     && strcmp(cl->GetName(), "TMath")
366     && strncmp(cl->GetName(), "TRandom", 7)) {
367     out_filename = "";
368     return false;
369     } else break;
370     }
371     }
372     }
373    
374    
375     if (!clfile.Length()) {
376     // determine possible decl file name from class + scope name:
377     // A::B::C::myclass will result in possible file name myclass.h
378     // in directory C/inc/
379     out_filename = cl->GetName();
380     if (!out_filename.Contains("::")) {
381     out_filename = "";
382     return false;
383     }
384     SplitClassIntoDirFile(out_filename, possiblePath, possibleFileName);
385    
386     // convert from Scope, class to module, filename.h
387     if (possibleFileName.Length()) {
388     if (decl)
389     possibleFileName += ".h";
390     else
391     possibleFileName += ".cxx";
392     }
393     if (possiblePath.Length())
394     possiblePath += "/";
395     if (decl)
396     possiblePath += "inc/";
397     else
398     possiblePath += "src/";
399     out_filename = possiblePath + "/" + possibleFileName;
400     } else {
401     possiblePath = gSystem->DirName(clfile);
402     possibleFileName = gSystem->BaseName(clfile);
403     }
404    
405     if (possiblePath.Length())
406     ExpandSearchPath(possiblePath);
407     else possiblePath=".";
408    
409     out_fsys = gSystem->FindFile(possiblePath, possibleFileName, kReadPermission);
410     if (out_fsys.Length()) return true;
411     out_filename = "";
412     return false;
413     }
414    
415     //______________________________________________________________________________
416     bool THtml::TPathDefinition::GetMacroPath(const TString& module, TString& out_dir) const
417     {
418     // Determine the path to look for macros (see TDocMacroDirective) for
419     // classes from a given module. If the path was sucessfully determined return true.
420     // For ROOT, this directory is the "doc/macros" subdirectory of the module
421     // directory; the path returned is GetDocDir(module) + "/macros".
422     //
423     // If your software cannot be mapped into this scheme then derive your
424     // own class from TPathDefinition and pass it to THtml::SetPathDefinition().
425    
426     TString moduledoc;
427     if (!GetDocDir(module, moduledoc))
428     return false;
429     if (moduledoc.EndsWith("\\"))
430     moduledoc.Remove(moduledoc.Length() - 1);
431    
432     TString macropath(GetOwner()->GetMacroPath());
433     TString macrodirpart;
434     out_dir = "";
435     Ssiz_t pos = 0;
436     while (macropath.Tokenize(macrodirpart, pos, ":")) {
437     out_dir += moduledoc + "/" + macrodirpart + ":";
438     }
439     return true;
440     }
441    
442    
443     //______________________________________________________________________________
444     bool THtml::TPathDefinition::GetDocDir(const TString& module, TString& doc_dir) const
445     {
446     // Determine the module's documentation directory. If module is empty,
447     // set doc_dir to the product's documentation directory.
448     // If the path was sucessfuly determined return true.
449     // For ROOT, this directory is the subdir "doc/" in the
450     // module's path; the directory returned is module + "/doc".
451     //
452     // If your software cannot be mapped into this scheme then derive your
453     // own class from TPathDefinition and pass it to THtml::SetPathDefinition().
454    
455     if (module.Length())
456     doc_dir = module + "/";
457     doc_dir += GetOwner()->GetPathInfo().fDocPath;
458     return true;
459     }
460    
461    
462     //______________________________________________________________________________
463     bool THtml::TPathDefinition::GetIncludeAs(TClass* cl, TString& out_dir) const
464     {
465     // Determine the path and filename used in an include statement for the
466     // header file of the given class. E.g. the class ROOT::Math::Boost is
467     // meant to be included as "Math/Genvector/Boost.h" - which is what
468     // out_dir is set to. GetIncludeAs() returns whether the include
469     // statement's path was successfully determined.
470     //
471     // Any leading directory part that is part of fIncludePath (see SetIncludePath)
472     // will be removed. For ROOT, leading "include/" is removed; everything after
473     // is the include path. Only classes from TMVA are different; they are included
474     // as TMVA/ClassName.h.
475     //
476     // If your software cannot be mapped into this scheme then derive your
477     // own class from TPathDefinition and pass it to THtml::SetPathDefinition().
478    
479     out_dir = "";
480     if (!cl || !GetOwner()) return false;
481    
482     const char* clname = cl->GetName();
483     TString hdr;
484     if (!GetOwner()->GetDeclFileName(cl, kFALSE, hdr))
485     return false;
486    
487     out_dir = hdr;
488     bool includePathMatches = false;
489     TString tok;
490     Ssiz_t pos = 0;
491     while (!includePathMatches && GetOwner()->GetPathInfo().fIncludePath.Tokenize(tok, pos, THtml::GetDirDelimiter()))
492     if (out_dir.BeginsWith(tok)) {
493     out_dir = hdr(tok.Length(), hdr.Length());
494     includePathMatches = true;
495     }
496    
497     if (!includePathMatches) {
498     // We probably have a file super/module/inc/optional/filename.h.
499     // That gets translated into optional/filename.h.
500     // Assume that only one occurrence of "/inc/" exists in hdr.
501     // If /inc/ is not part of the include file name then
502     // just return the full path.
503     // If we have matched any include path then this ROOT-only
504     // algorithm is skipped!
505     Ssiz_t posInc = hdr.Index("/inc/");
506     if (posInc == kNPOS) return true;
507     hdr.Remove(0, posInc + 5);
508     out_dir = hdr;
509    
510     // TMVA and RooStats special treatment:
511     // TMVA::Whatever claims to be in in math/tmva/inc/Whatever.h
512     // but it needs to get included as TMVA/Whatever.h
513     if (strstr(clname, "TMVA::"))
514     out_dir.Prepend("TMVA/");
515     if (strstr(clname, "RooStats::"))
516     out_dir.Prepend("RooStats/");
517     }
518    
519     return (out_dir.Length());
520     }
521    
522    
523     //______________________________________________________________________________
524     bool THtml::TPathDefinition::GetFileNameFromInclude(const char* included, TString& out_fsname) const
525     {
526     // Set out_fsname to the full pathname corresponding to a file
527     // included as "included". Return false if this file cannot be determined
528     // or found. For ROOT, out_fsname corresponds to included prepended with
529     // "include"; only THtml prefers to work on the original files, e.g.
530     // core/base/inc/TObject.h instead of include/TObject.h, so the
531     // default implementation searches the TFileSysDB for an entry with
532     // basename(included) and with matching directory part, setting out_fsname
533     // to the TFileSysEntry's path.
534    
535     if (!included) return false;
536    
537     out_fsname = included;
538    
539     if (!strncmp(included, "TMVA/", 5)) {
540     out_fsname.Remove(0, 4);
541     out_fsname.Prepend("tmva/inc");
542     return true;
543     }
544     // special treatment for roostats (same as in TMVA)
545     if (!strncmp(included, "RooStats/", 9)) {
546     out_fsname.Remove(0, 8);
547     out_fsname.Prepend("roofit/roostats/inc");
548     return true;
549     }
550    
551     TString incBase(gSystem->BaseName(included));
552     TList* bucket = GetOwner()->GetLocalFiles()->GetEntries().GetListForObject(incBase);
553     if (!bucket) return false;
554    
555     TString alldir(gSystem->DirName(included));
556     TObjArray* arrSubDirs = alldir.Tokenize("/");
557     TIter iEntry(bucket);
558     TFileSysEntry* entry = 0;
559     while ((entry = (TFileSysEntry*) iEntry())) {
560     if (incBase != entry->GetName()) continue;
561     // find entry with matching enclosing directory
562     THtml::TFileSysDir* parent = entry->GetParent();
563     for (int i = arrSubDirs->GetEntries() - 1; parent && i >= 0; --i) {
564     const TString& subdir(((TObjString*)(*arrSubDirs)[i])->String());
565     if (!subdir.Length() || subdir == ".")
566     continue;
567     if (subdir == parent->GetName())
568     parent = parent->GetParent();
569     else parent = 0;
570     }
571     if (parent) {
572     // entry found!
573     entry->GetFullName(out_fsname, kFALSE);
574     delete arrSubDirs;
575     return true;
576     }
577     }
578     delete arrSubDirs;
579     return false;
580     }
581    
582     //______________________________________________________________________________
583     void THtml::TFileSysDir::Recurse(TFileSysDB* db, const char* path)
584     {
585     // Recursively fill entries by parsing the contents of path.
586    
587     TString dir(path);
588     if (gDebug > 0 || GetLevel() < 2)
589     Info("Recurse", "scanning %s...", path);
590     TPMERegexp regexp(db->GetIgnore());
591     dir += "/";
592     void* hDir = gSystem->OpenDirectory(dir);
593     const char* direntry = 0;
594     while ((direntry = gSystem->GetDirEntry(hDir))) {
595     if (!direntry[0] || direntry[0] == '.' || regexp.Match(direntry)) continue;
596     TString entryPath(dir + direntry);
597     if (gSystem->AccessPathName(entryPath, kReadPermission))
598     continue;
599     FileStat_t buf;
600     gSystem->GetPathInfo(entryPath, buf);
601     if (R_ISDIR(buf.fMode)) {
602     // skip if we would nest too deeply, and skip soft links:
603     if (GetLevel() > db->GetMaxLevel()
604     #ifndef R__WIN32
605     || db->GetMapIno().GetValue(buf.fIno)
606     #endif
607     ) continue;
608     TFileSysDir* subdir = new TFileSysDir(direntry, this);
609     fDirs.Add(subdir);
610     #ifndef R__WIN32
611     db->GetMapIno().Add(buf.fIno, (Long_t)subdir);
612     #endif
613     subdir->Recurse(db, entryPath);
614     } else {
615     int delen = strlen(direntry);
616     // only .cxx and .h are taken
617     if (strcmp(direntry + delen - 4, ".cxx")
618     && strcmp(direntry + delen - 2, ".h"))
619     continue;
620     TFileSysEntry* entry = new TFileSysEntry(direntry, this);
621     db->GetEntries().Add(entry);
622     fFiles.Add(entry);
623     }
624     } // while dir entry
625     gSystem->FreeDirectory(hDir);
626     }
627    
628    
629     //______________________________________________________________________________
630     void THtml::TFileSysDB::Fill()
631     {
632     // Recursively fill entries by parsing the path specified in GetName();
633     // can be a THtml::GetDirDelimiter() delimited list of paths.
634    
635     TString dir;
636     Ssiz_t posPath = 0;
637     while (fName.Tokenize(dir, posPath, THtml::GetDirDelimiter())) {
638     if (gSystem->AccessPathName(dir, kReadPermission)) {
639     Warning("Fill", "Cannot read InputPath \"%s\"!", dir.Data());
640     continue;
641     }
642     FileStat_t buf;
643     gSystem->GetPathInfo(dir, buf);
644     if (R_ISDIR(buf.fMode)) {
645     #ifndef R__WIN32
646     TFileSysRoot* prevroot = (TFileSysRoot*) GetMapIno().GetValue(buf.fIno);
647     if (prevroot != 0) {
648     Warning("Fill", "InputPath \"%s\" already present as \"%s\"!", dir.Data(), prevroot->GetName());
649     continue;
650     }
651     #endif
652     TFileSysRoot* root = new TFileSysRoot(dir, this);
653     fDirs.Add(root);
654     #ifndef R__WIN32
655     GetMapIno().Add(buf.fIno, (Long_t)root);
656     #endif
657     root->Recurse(this, dir);
658     } else {
659     Warning("Fill", "Cannot read InputPath \"%s\"!", dir.Data());
660     }
661     }
662     }
663    
664    
665     ////////////////////////////////////////////////////////////////////////////////
666     /* BEGIN_HTML
667     <p>The THtml class is designed to easily document
668     classes, code, and code related text files (like change logs). It generates HTML
669     pages conforming to the XHTML 1.0 transitional specifications; an example of
670     these pages is ROOT's own <a href="http://root.cern.ch/root/html/ClassIndex.html">
671     reference guide</a>. This page was verified to be valid XHTML 1.0 transitional,
672     which proves that all pages generated by THtml can be valid, as long as the user
673     provided XHTML (documentation, header, etc) is valid. You can check the current
674     THtml by clicking this icon:
675     <a href="http://validator.w3.org/check?uri=referer"><img
676     src="http://www.w3.org/Icons/valid-xhtml10"
677     alt="Valid XHTML 1.0 Transitional" height="31" width="88" style="border: none;"/></a></p>
678     Overview:
679     <ol style="list-style-type: upper-roman;">
680     <li><a href="#usage">Usage</a></li>
681     <li><a href="#conf">Configuration</a>
682     <ol><li><a href="#conf:input">Input files</a></li>
683     <li><a href="#conf:output">Output directory</a></li>
684     <li><a href="#conf:liblink">Linking other documentation</a></li>
685     <li><a href="#conf:classdoc">Recognizing class documentation</a></li>
686     <li><a href="#conf:tags">Author, copyright, etc.</a></li>
687     <li><a href="#conf:header">Header and footer</a></li>
688     <li><a href="#conf:search">Links to searches, home page, ViewVC</a></li>
689     <li><a href="#conf:charset">HTML Charset</a></li>
690     </ol></li>
691     <li><a href="#syntax">Documentation syntax</a>
692     <ol><li><a href="#syntax:classdesc">Class description</a></li>
693     <li><a href="#syntax:classidx">Class index</a></li>
694     <li><a href="#syntax:meth">Method documentation</a></li>
695     <li><a href="#syntax:datamem">Data member documentation</a></li>
696     </ol></li>
697     <li><a href="#directive">Documentation directives</a>
698     <ol><li><a href="#directive:html"><tt>BEGIN<!-- -->_HTML</tt> <tt>END<!-- -->_HTML</tt>: include 'raw' HTML</a></li>
699     <li><a href="#directive:macro"><tt>BEGIN<!-- -->_MACRO</tt> <tt>END<!-- -->_MACRO</tt>: include a picture generated by a macro</a></li>
700     <li><a href="#directive:latex"><tt>BEGIN<!-- -->_LATEX</tt> <tt>END<!-- -->_LATEX</tt>: include a latex picture</a></li>
701     </ol></li>
702     <li><a href="#index">Product and module index</a></li>
703     <li><a href="#aux">Auxiliary files: style sheet, JavaScript, help page</a></li>
704     <li><a href="#charts">Class Charts</a></li>
705     <li><a href="#confvar">Configuration variables</a></li>
706     <li><a href="#how">Behind the scenes</a></li>
707     </ol>
708    
709    
710     <h3><a name="usage">I. Usage</a></h3>
711     These are typical things people do with THtml:
712     <pre>
713     root[] <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> html; // create a <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> object
714     root[] html.MakeAll(); // generate documentation for all changed classes
715     </pre>
716     or to run on just a few classes:
717     <pre>
718     root[] <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> html; // create a <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> object
719     root[] html.MakeIndex(); // create auxilliary files (style sheet etc) and indices
720     root[] html.MakeClass("TMyClass"); // create documentation for TMyClass only
721     </pre>
722     To "beautify" (i.e. create links to documentation for class names etc) some text
723     file or macro, use:
724     <pre>
725     root[] html.Convert( "hsimple.C", "Histogram example" )
726     </pre>
727    
728    
729     <h3><a name="conf">II. Configuration</a></h3>
730     Most configuration options can be set as a call to THtml, or as a TEnv variable,
731     which you can set in your .rootrc.
732    
733     <h4><a name="conf:input">II.1 Input files</a></h4>
734    
735     <p>In your .rootrc, define Root.Html.SourceDir to point to directories containing
736     .cxx and .h files (see: <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>)
737     of the classes you want to document, or call THtml::SetInputDir()</p>
738    
739     <p>Example:</p><pre>
740     Root.Html.SourceDir: .:src:include
741     Root.Html.Root: http://root.cern.ch/root/html</pre>
742    
743    
744     <h4><a name="conf:output">II.2 Output directory</a></h4>
745    
746     <p>The output directory can be specified using the Root.Html.OutputDir
747     configuration variable (default value: "htmldoc"). If that directory
748     doesn't exist <a href="http://root.cern.ch/root/html/THtml.html">THtml</a>
749     will create it.</p>
750    
751     <p>Example:</p><pre>
752     Root.Html.OutputDir: htmldoc</pre>
753    
754     <h4><a name="conf:liblink">II.3 Linking other documentation</a></h4>
755    
756     <p>When trying to document a class, THtml searches for a source file in
757     the directories set via SetInputDir(). If it cannot find it, it assumes
758     that this class must have been documented before. Based on the library
759     this class is defined in, it checks the configuration variable
760     <tt>Root.Html.LibName</tt>, and creates a link using its value.
761     Alternatively, you can set these URLs via THtml::SetLibURL().</p>
762    
763     <p>Example:<br/>
764     If a class MyClass is defined in class mylibs/libMyLib.so, and .rootrc
765     contains</p><pre>
766     Root.Html.MyLib: ../mylib/</pre>
767     <p>THtml will create a link to "../mylib/MyClass.html".</p>
768    
769     <p>The library name association can be set up using the rootmap facility.
770     For the library in the example above, which contains a dictionary
771     generated from the linkdef MyLinkdef.h, the command to generate the
772     rootmap file is</p>
773     <pre> $ rlibmap -f -r rootmap -l mylib/libMyLib.so -d libCore.so -c MyLinkdef.h</pre>
774     <p>Here, <tt>-r</tt> specifies that the entries for libMyLib should be updated,
775     <tt>-l</tt> specifies the library we're dealing with, <tt>-d</tt> its
776     dependencies, and <tt>-c</tt> its linkdef. The rootmap file must be within
777     one of the <tt>LD_LIBRARY_PATH</tt> (or <tt>PATH</tt> for Windows) directories
778     when ROOT is started, otherwise ROOT will not use it.</p>
779    
780     <h4><a name="conf:classdoc">II.4 Recognizing class documentation</a></h4>
781    
782     <p>The class documentation has to appear in the header file containing the
783     class, right in front of its declaration. It is introduced by a string
784     defined by Root.Html.Description or SetClassDocTag(). See the section on
785     <a href="#syntax">documentation syntax</a> for further details.</p>
786    
787     <p>Example:</p><pre>
788     Root.Html.Description: //____________________</pre>
789    
790     <p>The class documentation will show which include statement is to be used
791     and which library needs to be linked to access it.
792     The include file name is determined via
793     <a href="http://root.cern.ch/root/html/TClass.html#TClass:GetDeclFileName">
794     TClass::GetDeclFileName()</a>;
795     leading parts are removed if they match any of the ':' separated entries in
796     THtml::GetIncludePath().</p>
797    
798     <h4><a name="conf:tags">II.5 Author, copyright, etc.</a></h4>
799    
800     <p>During the conversion,
801     <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will look for
802     some strings ("tags") in the source file, which have to appear right in
803     front of e.g. the author's name, copyright notice, etc. These tags can be
804     defined with the following environment variables: Root.Html.Author,
805     Root.Html.LastUpdate and Root.Html.Copyright, or with
806     SetAuthorTag(), SetLastUpdateTag(), SetCopyrightTag().</p>
807    
808     <p>If the LastUpdate tag is not found, the current date and time are used.
809     This is useful when using
810     <a href="http://root.cern.ch/root/html/THtml.html#THtml:MakeAll">THtml::MakeAll()</a>'s
811     default option force=kFALSE, in which case
812     <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates
813     documentation only for changed classes.</p>
814    
815     Authors can be a comma separated list of author entries. Each entry has
816     one of the following two formats
817     <ul><li><tt>Name (non-alpha)</tt>.
818     <p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate an
819     HTML link for <tt>Name</tt>, taking the Root.Html.XWho configuration
820     variable (defaults to "http://consult.cern.ch/xwho/people?") and adding
821     all parts of the name with spaces replaces by '+'. Non-alphanumerical
822     characters are printed out behind <tt>Name</tt>.</p>
823    
824     <p>Example:</p>
825     <tt>// Author: Enrico Fermi</tt> appears in the source file.
826     <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate the link
827     <tt>http://consult.cern.ch/xwho/people?Enrico+Fermi</tt>. This works well for
828     people at CERN.</li>
829    
830     <li><tt>Name &lt;link&gt; Info</tt>.
831     <p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate
832     an HTML link for <tt>Name</tt> as specified by <tt>link</tt> and print
833     <tt>Info</tt> behind <tt>Name</tt>.</p>
834    
835     <p>Example:</p>
836     <tt>// Author: Enrico Fermi &lt;http://www.enricos-home.it&gt;</tt> or<br/>
837     <tt>// Author: Enrico Fermi &lt;mailto:enrico@fnal.gov&gt;</tt> in the
838     source file. That's world compatible.</li>
839     </ul>
840    
841     <p>Example (with defaults given):</p><pre>
842     Root.Html.Author: // Author:
843     Root.Html.LastUpdate: // @(#)
844     Root.Html.Copyright: * Copyright
845     Root.Html.XWho: http://consult.cern.ch/xwho/people?</pre>
846    
847    
848     <h4><a name="conf:header">II.6 Header and footer</a></h4>
849    
850     <p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates
851     a default header and footer for all pages. You can
852     specify your own versions with the configuration variables Root.Html.Header
853     and Root.Html.Footer, or by calling SetHeader(), SetFooter().
854     Both variables default to "", using the standard Root
855     versions. If it has a "+" appended, <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will
856     write both versions (user and root) to a file, for the header in the order
857     1st root, 2nd user, and for the footer 1st user, 2nd root (the root
858     versions containing "&lt;html&gt;" and &lt;/html&gt; tags, resp).</p>
859    
860     <p>If you want to replace root's header you have to write a file containing
861     all HTML elements necessary starting with the &lt;doctype&gt; tag and ending with
862     (and including) the &lt;body&gt; tag. If you add your header it will be added
863     directly after Root's &lt;body&gt; tag. Any occurrence of the string <tt>%TITLE%</tt>
864     in the user's header file will be replaced by
865     a sensible, automatically generated title. If the header is generated for a
866     class, occurrences of <tt>%CLASS%</tt> will be replaced by the current class's name,
867     <tt>%SRCFILE%</tt> and <tt>%INCFILE%</tt> by the name of the source and header file, resp.
868     (as given by <a href="http://root.cern.ch/root/html/TClass.html#TClass:GetImplFileLine">TClass::GetImplFileName()</a>,
869     <a href="http://root.cern.ch/root/html/TClass.html#TClass:GetImplFileLine">TClass::GetDeclFileName()</a>).
870     If the header is not generated for a class, they will be replaced by "".</p>
871    
872     <p>Root's footer starts with the tag &lt;!--SIGNATURE--&gt;. It includes the
873     author(s), last update, copyright, the links to the Root home page, to the
874     user home page, to the index file (ClassIndex.html), to the top of the page
875     and <tt>this page is automatically generated</tt> infomation. It ends with the
876     tags <tt>&lt;/body&gt;&lt;/html&gt;</tt>. If you want to replace it,
877     <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will search for some
878     tags in your footer: Occurrences of the strings <tt>%AUTHOR%</tt>, <tt>%UPDATE%</tt>, and
879     <tt>%COPYRIGHT%</tt> are replaced by their
880     corresponding values before writing the html file. The <tt>%AUTHOR%</tt> tag will be
881     replaced by the exact string that follows Root.Html.Author, no link
882     generation will occur.</p>
883    
884    
885     <h4><a name="conf:search">II.7 Links to searches, home page, ViewVC</a></h4>
886    
887     <p>Additional parameters can be set by Root.Html.Homepage (address of the
888     user's home page), Root.Html.SearchEngine (search engine for the class
889     documentation), Root.Html.Search (search URL, where %u is replaced by the
890     referer and %s by the escaped search expression), and a ViewVC base URL
891     Root.Html.ViewCVS. For the latter, the file name is appended or, if
892     the URL contains %f, %f is replaced by the file name.
893     All values default to "".</p>
894    
895     <p>Examples:</p><pre>
896     Root.Html.Homepage: http://www.enricos-home.it
897     Root.Html.SearchEngine: http://root.cern.ch/root/Search.phtml
898     Root.Html.Search: http://www.google.com/search?q=%s+site%3A%u</pre>
899    
900    
901     <h4><a name="conf:charset">II.8 HTML Charset</a></h4>
902    
903     <p>XHTML 1.0 transitional recommends the specification of the charset in the
904     content type meta tag, see e.g. <a href="http://www.w3.org/TR/2002/REC-xhtml1-20020801/">http://www.w3.org/TR/2002/REC-xhtml1-20020801/</a>
905     <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates it for the HTML output files. It defaults to ISO-8859-1, and
906     can be changed using Root.Html.Charset.</p>
907    
908     <p>Example:</p><pre>
909     Root.Html.Charset: EUC-JP</pre>
910    
911     <h3><a name="syntax">III. Documentation syntax</a></h3>
912     <h4><a name="syntax:classdesc">III.1 Class description</a></h4>
913    
914     <p>A class description block, which must be placed before the first
915     member function, has a following form:</p>
916     <pre>
917     ////////////////////////////////////////////////////////////////
918     // //
919     // TMyClass //
920     // //
921     // This is the description block. //
922     // //
923     ////////////////////////////////////////////////////////////////
924     </pre>
925     <p>The environment variable Root.Html.Description
926     (see: <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>) contains
927     the delimiter string (default value: <tt>//_________________</tt>). It means
928     that you can also write your class description block like this:</p>
929     <pre>
930     //_____________________________________________________________
931     // A description of the class starts with the line above, and
932     // will take place here !
933     //
934     </pre>
935     <p>Note that <b><i>everything</i></b> until the first non-commented line is considered
936     as a valid class description block.</p>
937    
938     <h4><a name="syntax:classidx">III.2 Class index</a></h4>
939    
940     <p>All classes to be documented will have an entry in the ClassIndex.html,
941     showing their name with a link to their documentation page and a miniature
942     description. This discription for e.g. the class MyClass has to be given
943     in MyClass's header as a comment right after ClassDef(MyClass, n).</p>
944    
945     <h4><a name="syntax:meth">III.3 Method documentation</a></h4>
946     <p>A member function description block starts immediately after '{'
947     and looks like this:</p>
948     <pre>
949     void TWorld::HelloWorldFunc(string *text)
950     {
951     // This is an example of description for the
952     // TWorld member function
953    
954     helloWorld.Print( text );
955     }
956     </pre>
957     Like in a class description block, <b><i>everything</i></b> until the first
958     non-commented line is considered as a valid member function
959     description block.
960    
961     If the rootrc variable <tt>Root.Html.DescriptionStyle</tt> is set to
962     <tt>Doc++</tt> THtml will also look for method documentation in front of
963     the function implementation. This feature is not recommended; source code
964     making use of this does not comply to the ROOT documentation standards, which
965     means future versions of THtml might not support it anymore.
966    
967     <h4><a name="syntax:datamem">III.4 Data member documentation</a></h4>
968    
969     <p>Data members are documented by putting a C++ comment behind their
970     declaration in the header file, e.g.</p>
971     <pre>
972     int fIAmADataMember; // this is a data member
973     </pre>
974    
975    
976     <h3><a name="directive">IV. Documentation directives</a></h3>
977     <em>NOTE that THtml does not yet support nested directives
978     (i.e. latex inside html etc)!</em>
979    
980     <h4><a name="directive:html">IV.1 <tt>BEGIN<!-- -->_HTML</tt> <tt>END<!-- -->_HTML</tt>: include 'raw' HTML</a></h4>
981    
982     <p>You can insert pure html code into your documentation comments. During the
983     generation of the documentation, this code will be inserted as is
984     into the html file.</p>
985     <p>Pure html code must be surrounded by the keywords
986     <tt>BEGIN<!-- -->_HTML</tt> and <tt>END<!-- -->_HTML</tt>, where the
987     case is ignored.
988     An example of pure html code is this class description you are reading right now.
989     THtml uses a
990     <a href="http://root.cern.ch/root/html/TDocHtmlDirective.html">TDocHtmlDirective</a>
991     object to process this directive.</p>
992    
993     <h4><a name="directive:macro">IV.2 <tt>BEGIN<!-- -->_MACRO</tt> <tt>END<!-- -->_MACRO</tt>: include a picture generated by a macro</a></h4>
994    
995     <p>THtml can create images from scripts. You can either call an external
996     script by surrounding it by "begin_macro"/"end_macro", or include an unnamed
997     macro within these keywords. The macro should return a pointer to an object;
998     this object will then be saved as a GIF file.</p>
999     <p>Objects deriving from
1000     <a href="http://root.cern.ch/root/html/TGObject.html">TGObject</a> (GUI elements)
1001     will need to run in graphics mode (non-batch). You must specify this as a parameter:
1002     "Begin_macro(GUI)...".
1003     To create a second tab that displays the source of the macro you can specify
1004     the argument "Begin_macro(source)...".
1005     Of course you can combine them,
1006     e.g. as "Begin_macro(source,gui)...".
1007     THtml uses a
1008     <a href="http://root.cern.ch/root/html/TDocMacroDirective.html">TDocMacroDirective</a>
1009     object to process this directive.</p>
1010     <p>This is an example:</p> END_HTML
1011     BEGIN_MACRO(source)
1012     {
1013     TCanvas* macro_example_canvas = new TCanvas("macro_example_canvas", "", 150, 150);
1014     macro_example_canvas->SetBorderSize(0);
1015     macro_example_canvas->SetFillStyle(1001);
1016     macro_example_canvas->SetFillColor(kWhite);
1017     macro_example_canvas->cd();
1018     TArc* macro_example_arc = new TArc(0.5,0.32,0.11,180,360);
1019     macro_example_arc->Draw();
1020     TEllipse* macro_example_ellipsis = new TEllipse(0.42,0.58,0.014,0.014,0,360,0);
1021     macro_example_ellipsis->SetFillStyle(0);
1022     macro_example_ellipsis->Draw();
1023     macro_example_ellipsis = new TEllipse(0.58,0.58,0.014,0.014,0,360,0);
1024     macro_example_ellipsis->SetFillStyle(0);
1025     macro_example_ellipsis->Draw();
1026     macro_example_ellipsis = new TEllipse(0.50,0.48,0.22,0.32,0,360,0);
1027     macro_example_ellipsis->SetFillStyle(0);
1028     macro_example_ellipsis->Draw();
1029     TLine* macro_example_line = new TLine(0.48,0.53,0.52,0.41);
1030     macro_example_line->Draw();
1031     return macro_example_canvas;
1032     }
1033     END_MACRO
1034    
1035     BEGIN_HTML
1036     <h4><a name="directive:latex">IV.3 <tt>BEGIN<!-- -->_LATEX</tt> <tt>END<!-- -->_LATEX</tt>: include a latex picture</a></h4>
1037    
1038     <p>You can specify <a href="http://root.cern.ch/root/html/TLatex.html">TLatex</a>
1039     style text and let THtml convert it into an image by surrounding it by "Begin_Latex", "End_Latex".
1040     You can have multiple lines, and e.g. align each line at the '=' sign by passing
1041     the argument <tt>separator='='</tt>. You can also specify how to align these parts;
1042     if you want the part left of the separator to be right aligned, and the right part
1043     to be left aligned, you could specify <tt>align='rl'</tt>.
1044     THtml uses a <a href="http://root.cern.ch/root/html/TDocLatexDirective.html">TDocLatexDirective</a>
1045     object to process the directive.
1046     This is an example output with arguments <tt>separator='=', align='rl'</tt>:</p>
1047     END_HTML BEGIN_LATEX(separator='=', align='rl')#kappa(x)^{2}=sin(x)^{x}
1048     x=#chi^{2} END_LATEX
1049    
1050     BEGIN_HTML
1051    
1052     <h3><a name="index">V. Product and module index</a></h3>
1053    
1054     <p><a href="#THtml:MakeIndex">THtml::MakeIndex()</a> will generate index files for classes
1055     and types, all modules, and the product which you can set by
1056     <a href="#THtml:SetProductName">THtml::SetProductName()</a>.
1057     THtml will make use of external documentation in the module and product index,
1058     either by linking it or by including it.
1059     For the product THtml will include files found in the directory defined by
1060     <a href="#THtml:SetProductDocDir">THtml::SetProductDocDir()</a>.
1061     The files for modules are searched based on the source file directory of the
1062     module's classes; the (possibly relative) path set by
1063     <a href="#THtml:SetModuleDocPath">THtml::SetModuleDocPath()</a> will guide THtml
1064     to the files.</p>
1065    
1066     <p>A filename starting with "index." will be included in the index page;
1067     all other files will be linked.
1068     Only files ending on <tt>.html</tt> or <tt>.txt</tt> will be taken into account;
1069     the text files will first be run through
1070     <a href="#THtml:Convert">THtml::Convert()</a>.
1071     You can see an example <a href="http://root.cern.ch/root/html/HIST_Index.html">here</a>;
1072     the part between "Index of HIST classes" and "Jump to" is created by parsing
1073     the module's doc directory.</p>
1074    
1075     <h3><a name="aux">VI. Auxiliary files: style sheet, JavaScript, help page</a></h3>
1076    
1077     <p>The documentation pages share a common set of javascript and CSS files. They
1078     are generated automatically when running <a href="#THtml:MakeAll">MakeAll()</a>;
1079     they can be generated on
1080     demand by calling <a href="#THtml:CreateAuxiliaryFiles">CreateAuxiliaryFiles()</a>.</p>
1081    
1082    
1083     <h3><a name="charts">VII. Class Charts</a></h3>
1084     THtml can generate a number of graphical representations for a class, which
1085     are displayed as a tabbed set of imaged ontop of the class description.
1086     It can show the inheritance, inherited and hidden members, directly and
1087     indirectly included files, and library dependencies.
1088    
1089     These graphs are generated using the <a href="http://www.graphviz.org/">Graphviz</a>
1090     package. You can install it from <a href="http://www.graphviz.org">http://www.graphviz.org</a>.
1091     You can either put it into your $PATH, or tell THtml where to find it by calling
1092     <a href="#THtml:SetDotDir">SetDotDir()</a>.
1093    
1094    
1095     <h3><a name="confvar">VIII. Configuration variables</a></h3>
1096    
1097     <p>Here is a list of all configuration variables that are known to THtml.
1098     You can set them in your .rootrc file, see
1099     <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>.</p>
1100    
1101     <pre>
1102     Root.Html.OutputDir (default: htmldoc)
1103     Root.Html.SourceDir (default: .:src/:include/)
1104     Root.Html.Author (default: // Author:) - start tag for authors
1105     Root.Html.LastUpdate (default: // @(#)) - start tag for last update
1106     Root.Html.Copyright (default: * Copyright) - start tag for copyright notice
1107     Root.Html.Description (default: //____________________ ) - start tag for class descr
1108     Root.Html.HomePage (default: ) - URL to the user defined home page
1109     Root.Html.Header (default: ) - location of user defined header
1110     Root.Html.Footer (default: ) - location of user defined footer
1111     Root.Html.Root (default: ) - URL of Root's class documentation
1112     Root.Html.SearchEngine (default: ) - link to the search engine
1113     Root.Html.Search (defualt: ) - link to search by replacing "%s" with user input
1114     Root.Html.ViewCVS (default: ) - URL of ViewCVS base
1115     Root.Html.XWho (default: http://consult.cern.ch/xwho/people?) - URL of CERN's xWho
1116     Root.Html.Charset (default: ISO-8859-1) - HTML character set
1117     </pre>
1118    
1119     <h3><a name="how">IX. Behind the scene</a></h3>
1120    
1121     <p>Internally, THtml is just an API class that sets up the list of known
1122     classes, and forwards API invocations to the "work horses".
1123     <a href="http://root.cern.ch/root/html/TDocOutput.html">TDocOutput</a>
1124     generates the output by letting a
1125     <a href="http://root.cern.ch/root/html/TDocParser.html">TDocParser</a>
1126     object parse the sources, which in turn invokes objects deriving from
1127     <a href="http://root.cern.ch/root/html/TDocDirective.html">TDocDirective</a>
1128     to process directives.</p>
1129    
1130     END_HTML */
1131     ////////////////////////////////////////////////////////////////////////////////
1132    
1133     ClassImp(THtml)
1134     //______________________________________________________________________________
1135     THtml::THtml():
1136     fCounterFormat("%12s %5s %s"),
1137     fProductName("(UNKNOWN PRODUCT)"),
1138     fThreadedClassIter(0), fMakeClassMutex(0),
1139     fGClient(0), fPathDef(0), fModuleDef(0), fFileDef(0),
1140     fLocalFiles(0), fBatch(kFALSE)
1141     {
1142     // Create a THtml object.
1143     // In case output directory does not exist an error
1144     // will be printed and gHtml stays 0 also zombie bit will be set.
1145    
1146     // check for source directory
1147     fPathInfo.fInputPath = gEnv->GetValue("Root.Html.SourceDir", "./:src/:include/");
1148    
1149     // check for output directory
1150     fPathInfo.fOutputDir = gEnv->GetValue("Root.Html.OutputDir", "htmldoc");
1151    
1152     fLinkInfo.fXwho = gEnv->GetValue("Root.Html.XWho", "http://consult.cern.ch/xwho/people?");
1153     fLinkInfo.fROOTURL = gEnv->GetValue("Root.Html.Root", "http://root.cern.ch/root/html");
1154     fDocSyntax.fClassDocTag = gEnv->GetValue("Root.Html.Description", "//____________________");
1155     fDocSyntax.fAuthorTag = gEnv->GetValue("Root.Html.Author", "// Author:");
1156     fDocSyntax.fLastUpdateTag = gEnv->GetValue("Root.Html.LastUpdate", "// @(#)");
1157     fDocSyntax.fCopyrightTag = gEnv->GetValue("Root.Html.Copyright", "* Copyright");
1158     fOutputStyle.fHeader = gEnv->GetValue("Root.Html.Header", "");
1159     fOutputStyle.fFooter = gEnv->GetValue("Root.Html.Footer", "");
1160     fLinkInfo.fHomepage = gEnv->GetValue("Root.Html.Homepage", "");
1161     fLinkInfo.fSearchStemURL = gEnv->GetValue("Root.Html.Search", "");
1162     fLinkInfo.fSearchEngine = gEnv->GetValue("Root.Html.SearchEngine", "");
1163     fLinkInfo.fViewCVS = gEnv->GetValue("Root.Html.ViewCVS", "");
1164     fOutputStyle.fCharset = gEnv->GetValue("Root.Html.Charset", "ISO-8859-1");
1165     fDocSyntax.fDocStyle = gEnv->GetValue("Root.Html.DescriptionStyle", "");
1166    
1167     fDocEntityInfo.fClasses.SetOwner();
1168     fDocEntityInfo.fModules.SetOwner();
1169     // insert html object in the list of special ROOT objects
1170     // if (!gHtml) {
1171     // gHtml = this;
1172     // gROOT->GetListOfSpecials()->Add(gHtml);
1173     // }
1174     cout << "THTML from MitAna/Utils ... " <<endl;
1175     }
1176    
1177    
1178     //______________________________________________________________________________
1179     THtml::~THtml()
1180     {
1181     // Default destructor
1182    
1183     fDocEntityInfo.fClasses.Clear();
1184     fDocEntityInfo.fModules.Clear();
1185     // if (gHtml == this) {
1186     // gROOT->GetListOfSpecials()->Remove(gHtml);
1187     // gHtml = 0;
1188     // }
1189     delete fPathDef;
1190     delete fModuleDef;
1191     delete fFileDef;
1192     delete fLocalFiles;
1193     }
1194    
1195     //______________________________________________________________________________
1196     void THtml::AddMacroPath(const char* path)
1197     {
1198     // Add path to the directories to be searched for macro files
1199     // that are to be executed via the TDocMacroDirective
1200     // ("Begin_Macro"/"End_Macro"); relative to the source file
1201     // that the directive is run on.
1202    
1203     const char pathDelimiter =
1204     #ifdef R__WIN32
1205     ';';
1206     #else
1207     ':';
1208     #endif
1209     fPathInfo.fMacroPath += pathDelimiter;
1210     fPathInfo.fMacroPath += path;
1211     }
1212    
1213    
1214     //______________________________________________________________________________
1215     void THtml::CreateAuxiliaryFiles() const
1216     {
1217     // copy CSS, javascript file, etc to the output dir
1218     CreateJavascript();
1219     CreateStyleSheet();
1220     CopyFileFromEtcDir("HELP.html");
1221     }
1222    
1223     //______________________________________________________________________________
1224     const THtml::TModuleDefinition& THtml::GetModuleDefinition() const
1225     {
1226     // Return the TModuleDefinition (or derived) object as set by
1227     // SetModuleDefinition(); create and return a TModuleDefinition object
1228     // if none was set.
1229     if (!fModuleDef) {
1230     fModuleDef = new TModuleDefinition();
1231     fModuleDef->SetOwner(const_cast<THtml*>(this));
1232     }
1233     return *fModuleDef;
1234     }
1235    
1236     //______________________________________________________________________________
1237     const THtml::TFileDefinition& THtml::GetFileDefinition() const
1238     {
1239     // Return the TFileDefinition (or derived) object as set by
1240     // SetFileDefinition(); create and return a TFileDefinition object
1241     // if none was set.
1242     if (!fFileDef) {
1243     fFileDef = new TFileDefinition();
1244     fFileDef->SetOwner(const_cast<THtml*>(this));
1245     }
1246     return *fFileDef;
1247     }
1248    
1249     //______________________________________________________________________________
1250     const THtml::TPathDefinition& THtml::GetPathDefinition() const
1251     {
1252     // Return the TModuleDefinition (or derived) object as set by
1253     // SetModuleDefinition(); create and return a TModuleDefinition object
1254     // if none was set.
1255     if (!fPathDef) {
1256     fPathDef = new TPathDefinition();
1257     fPathDef->SetOwner(const_cast<THtml*>(this));
1258     }
1259     return *fPathDef;
1260     }
1261    
1262    
1263     //______________________________________________________________________________
1264     const char* THtml::GetEtcDir() const
1265     {
1266     // Get the directory containing THtml's auxiliary files ($ROOTSYS/etc/html)
1267    
1268     if (fPathInfo.fEtcDir.Length())
1269     return fPathInfo.fEtcDir;
1270    
1271     R__LOCKGUARD(GetMakeClassMutex());
1272    
1273     fPathInfo.fEtcDir = "html";
1274    
1275     #ifdef ROOTETCDIR
1276     gSystem->PrependPathName(ROOTETCDIR, fPathInfo.fEtcDir);
1277     #else
1278     gSystem->PrependPathName("etc", fPathInfo.fEtcDir);
1279     # ifdef ROOTPREFIX
1280     gSystem->PrependPathName(ROOTPREFIX, fPathInfo.fEtcDir);
1281     # else
1282     if (getenv("ROOTSYS"))
1283     gSystem->PrependPathName(getenv("ROOTSYS"), fPathInfo.fEtcDir);
1284     # endif
1285     #endif
1286    
1287     return fPathInfo.fEtcDir;
1288     }
1289    
1290    
1291     //______________________________________________________________________________
1292     TClassDocInfo *THtml::GetNextClass()
1293     {
1294     // Return the next class to be generated for MakeClassThreaded.
1295    
1296     if (!fThreadedClassIter) return 0;
1297    
1298     R__LOCKGUARD(GetMakeClassMutex());
1299    
1300     TClassDocInfo* classinfo = 0;
1301     while ((classinfo = (TClassDocInfo*)(*fThreadedClassIter)())
1302     && !classinfo->IsSelected()) { }
1303    
1304     if (!classinfo) {
1305     delete fThreadedClassIter;
1306     fThreadedClassIter = 0;
1307     }
1308    
1309     fCounter.Form("%5d", fDocEntityInfo.fClasses.GetSize() - fThreadedClassCount++);
1310    
1311     return classinfo;
1312     }
1313    
1314    
1315     //______________________________________________________________________________
1316     const char* THtml::GetURL(const char* lib /*=0*/) const
1317     {
1318     // Get the documentation URL for library lib.
1319     // If lib == 0 or no documentation URL has been set for lib, return the ROOT
1320     // documentation URL. The return value is always != 0.
1321    
1322     R__LOCKGUARD(GetMakeClassMutex());
1323    
1324     if (lib && strlen(lib)) {
1325     std::map<std::string, TString>::const_iterator iUrl = fLinkInfo.fLibURLs.find(lib);
1326     if (iUrl != fLinkInfo.fLibURLs.end()) return iUrl->second;
1327     return gEnv->GetValue(TString("Root.Html.") + lib, fLinkInfo.fROOTURL);
1328     }
1329     return fLinkInfo.fROOTURL;
1330     }
1331    
1332     //______________________________________________________________________________
1333     Bool_t THtml::HaveDot()
1334     {
1335     // Check whether dot is available in $PATH or in the directory set
1336     // by SetDotPath()
1337    
1338     if (fPathInfo.fFoundDot != PathInfo_t::kDotUnknown)
1339     return (fPathInfo.fFoundDot == PathInfo_t::kDotFound);
1340    
1341     R__LOCKGUARD(GetMakeClassMutex());
1342    
1343     Info("HaveDot", "Checking for Graphviz (dot)...");
1344     TString runDot("dot");
1345     if (fPathInfo.fDotDir.Length())
1346     gSystem->PrependPathName(fPathInfo.fDotDir, runDot);
1347     runDot += " -V";
1348     if (gDebug > 3)
1349     Info("HaveDot", "Running: %s", runDot.Data());
1350     if (gSystem->Exec(runDot)) {
1351     fPathInfo.fFoundDot = PathInfo_t::kDotNotFound;
1352     return kFALSE;
1353     }
1354     fPathInfo.fFoundDot = PathInfo_t::kDotFound;
1355     return kTRUE;
1356    
1357     }
1358    
1359     //______________________________________________________________________________
1360     void THtml::HelperDeleted(THtml::THelperBase* who)
1361     {
1362     // Inform the THtml object that one of its helper objects was deleted.
1363     // Called by THtml::HelperBase::~HelperBase().
1364    
1365     THelperBase* helpers[3] = {fPathDef, fModuleDef, fFileDef};
1366     for (int i = 0; who && i < 3; ++i)
1367     if (who == helpers[i])
1368     helpers[i] = who = 0;
1369     }
1370    
1371    
1372     //______________________________________________________________________________
1373     void THtml::Convert(const char *filename, const char *title,
1374     const char *dirname /*= ""*/, const char *relpath /*= "../"*/,
1375     Int_t includeOutput /* = kNoOutput */,
1376     const char* context /* = "" */)
1377     {
1378     // It converts a single text file to HTML
1379     //
1380     //
1381     // Input: filename - name of the file to convert
1382     // title - title which will be placed at the top of the HTML file
1383     // dirname - optional parameter, if it's not specified, output will
1384     // be placed in htmldoc/examples directory.
1385     // relpath - optional parameter pointing to the THtml generated doc
1386     // on the server, relative to the current page.
1387     // includeOutput - if != kNoOutput, run the script passed as filename and
1388     // store all created canvases in PNG files that are
1389     // shown next to the converted source. Bitwise-ORing with
1390     // re-runs the script even if output PNGs exist that are newer
1391     // than the script. If kCompiledOutput is passed, the script is
1392     // run through ACLiC (.x filename+)
1393     // context - line shown verbatim at the top of the page; e.g. for links.
1394     // If context is non-empty it is expected to also print the
1395     // title.
1396     //
1397     // NOTE: Output file name is the same as filename, but with extension .html
1398     //
1399    
1400     gROOT->GetListOfGlobals(kTRUE); // force update of this list
1401     CreateListOfClasses("*");
1402    
1403     const char *dir;
1404    
1405     // if it's not defined, make the "examples" as a default directory
1406     if (!*dirname) {
1407     gSystem->ExpandPathName(fPathInfo.fOutputDir);
1408     dir = gSystem->ConcatFileName(fPathInfo.fOutputDir, "examples");
1409     } else
1410     dir = dirname;
1411    
1412     // create directory if necessary
1413     if (gSystem->AccessPathName(dir))
1414     gSystem->MakeDirectory(dir);
1415    
1416     // find a file
1417     char *cRealFilename =
1418     gSystem->Which(fPathInfo.fInputPath, filename, kReadPermission);
1419    
1420     if (!cRealFilename) {
1421     Error("Convert", "Can't find file '%s' !", filename);
1422     return;
1423     }
1424    
1425     TString realFilename(cRealFilename);
1426     delete[] cRealFilename;
1427     cRealFilename = 0;
1428    
1429     // open source file
1430     ifstream sourceFile;
1431     sourceFile.open(realFilename, ios::in);
1432    
1433     if (!sourceFile.good()) {
1434     Error("Convert", "Can't open file '%s' !", realFilename.Data());
1435     return;
1436     }
1437    
1438     if (gSystem->AccessPathName(dir)) {
1439     Error("Convert",
1440     "Directory '%s' doesn't exist, or it's write protected !", dir);
1441     return;
1442     }
1443     char *tmp1 =
1444     gSystem->ConcatFileName(dir, gSystem->BaseName(filename));
1445    
1446     TDocOutput output(*this);
1447     if (!fGClient)
1448     gROOT->ProcessLine(TString::Format("*((TGClient**)0x%lx) = gClient;",
1449 bendavid 1.2 (ULong_t)&fGClient));
1450 loizides 1.1 if (includeOutput && !fGClient)
1451     Warning("Convert", "Output requested but cannot initialize graphics: GUI and GL windows not be available");
1452     output.Convert(sourceFile, realFilename, tmp1, title, relpath, includeOutput, context, fGClient);
1453    
1454     if (tmp1)
1455     delete[]tmp1;
1456     tmp1 = 0;
1457     }
1458    
1459     //______________________________________________________________________________
1460     void THtml::GetModuleNameForClass(TString& module, TClass* cl) const
1461     {
1462     // Return the module name for a given class.
1463     // Use the cached information from fDocEntityInfo.fClasses.
1464    
1465     module = "(UNKNOWN)";
1466     TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(cl->GetName());
1467     if (!cdi || !cdi->GetModule())
1468     return;
1469     module = cdi->GetModule()->GetName();
1470     }
1471    
1472    
1473     //______________________________________________________________________________
1474     void THtml::CreateListOfClasses(const char* filter)
1475     {
1476     // Create the list of all known classes
1477    
1478     if (fDocEntityInfo.fClasses.GetSize() && fDocEntityInfo.fClassFilter == filter)
1479     return;
1480    
1481     Info("CreateListOfClasses", "Initializing - this might take a while...");
1482     // get total number of classes
1483     Int_t totalNumberOfClasses = gClassTable->Classes();
1484    
1485     // allocate memory
1486     fDocEntityInfo.fClasses.Clear();
1487     fDocEntityInfo.fModules.Clear();
1488    
1489     fDocEntityInfo.fClassFilter = filter;
1490    
1491     // start from begining
1492     gClassTable->Init();
1493     if (filter && (!filter[0] || !strcmp(filter, "*")))
1494     filter = ".*";
1495     TString reg = filter;
1496     TPMERegexp re(reg);
1497    
1498     for (Int_t i = 0; i < totalNumberOfClasses; i++) {
1499    
1500     // get class name
1501     const char *cname = gClassTable->Next();
1502     TString s = cname;
1503    
1504     // This is a hack for until after Cint and Reflex are one.
1505     if (strstr(cname, "__gnu_cxx::")) continue;
1506    
1507     // get class & filename - use TROOT::GetClass, as we also
1508     // want those classes without decl file name!
1509     TClass *classPtr = TClass::GetClass((const char *) cname, kTRUE);
1510     if (!classPtr) continue;
1511    
1512     Bool_t matchesSelection = re.Match(s);
1513    
1514     TString hdr;
1515     TString hdrFS;
1516     TString src;
1517     TString srcFS;
1518     TString htmlfilename;
1519    
1520     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cname);
1521     if (cdi) {
1522     hdr = cdi->GetDeclFileName();
1523     hdrFS = cdi->GetDeclFileSysName();
1524     src = cdi->GetImplFileName();
1525     srcFS = cdi->GetImplFileSysName();
1526     htmlfilename = cdi->GetHtmlFileName();
1527     }
1528    
1529     if (!hdrFS.Length()) {
1530     if (!GetFileDefinition().GetDeclFileName(classPtr, hdr, hdrFS)) {
1531     // we don't even know where the class is defined;
1532     // just skip. Silence if it doesn't match the selection anyway
1533     if (matchesSelection && (!classPtr->GetDeclFileName() || !strstr(classPtr->GetDeclFileName(),"prec_stl/")))
1534     Warning("CreateListOfClasses",
1535     "Cannot determine declaration file name for %s!", cname);
1536     continue;
1537     }
1538     }
1539    
1540     Bool_t haveSource = (srcFS.Length());
1541     if (!haveSource)
1542     haveSource = GetFileDefinition().GetImplFileName(classPtr, src, srcFS);
1543    
1544     if (!haveSource && gDebug > 3) {
1545     Info("CreateListOfClasses",
1546     "Cannot determine implementation file name for %s!", cname);
1547     }
1548    
1549     if (!htmlfilename.Length())
1550     GetHtmlFileName(classPtr, htmlfilename);
1551    
1552     if (!cdi) {
1553     cdi = new TClassDocInfo(classPtr, htmlfilename, hdrFS, srcFS, hdr, src);
1554     fDocEntityInfo.fClasses.Add(cdi);
1555     } else {
1556     cdi->SetDeclFileName(hdr);
1557     cdi->SetImplFileName(src);
1558     cdi->SetDeclFileSysName(hdrFS);
1559     cdi->SetImplFileSysName(srcFS);
1560     cdi->SetHtmlFileName(htmlfilename);
1561     }
1562    
1563     cdi->SetSelected(matchesSelection);
1564    
1565     TString modulename;
1566     GetModuleDefinition().GetModule(classPtr, modulename);
1567     if (!modulename.Length() || modulename == "USER")
1568     GetModuleNameForClass(modulename, classPtr);
1569    
1570     TModuleDocInfo* module = (TModuleDocInfo*) fDocEntityInfo.fModules.FindObject(modulename);
1571     if (!module) {
1572     bool moduleSelected = cdi->IsSelected();
1573    
1574     TString parentModuleName(gSystem->DirName(modulename));
1575     TModuleDocInfo* super = 0;
1576     if (parentModuleName.Length() && parentModuleName != ".") {
1577     super = (TModuleDocInfo*) fDocEntityInfo.fModules.FindObject(parentModuleName);
1578     if (!super) {
1579     // create parents:
1580     TString token;
1581     Ssiz_t pos = 0;
1582     while (parentModuleName.Tokenize(token, pos, "/")) {
1583     if (!token.Length() || token == ".") continue;
1584     super = new TModuleDocInfo(token, super);
1585     super->SetSelected(moduleSelected);
1586     fDocEntityInfo.fModules.Add(super);
1587     }
1588     }
1589     }
1590     module = new TModuleDocInfo(modulename, super);
1591     module->SetSelected(moduleSelected);
1592     fDocEntityInfo.fModules.Add(module);
1593     }
1594    
1595     if (module) {
1596     module->AddClass(cdi);
1597     cdi->SetModule(module);
1598     if (cdi->HaveSource() && cdi->IsSelected())
1599     module->SetSelected();
1600     }
1601    
1602     // clear the typedefs; we fill them later
1603     cdi->GetListOfTypedefs().Clear();
1604    
1605     if (gDebug > 0)
1606     Info("CreateListOfClasses", "Adding class %s, module %s (%sselected)",
1607     cdi->GetName(), module ? module->GetName() : "[UNKNOWN]",
1608     cdi->IsSelected() ? "" : "not ");
1609     }
1610    
1611     // fill typedefs
1612     TIter iTypedef(gROOT->GetListOfTypes());
1613     TDataType* dt = 0;
1614     TDocOutput output(*this);
1615     while ((dt = (TDataType*) iTypedef())) {
1616     if (dt->GetType() != -1) continue;
1617     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(dt->GetFullTypeName());
1618     if (cdi) {
1619     cdi->GetListOfTypedefs().Add(dt);
1620     if (gDebug > 1)
1621     Info("CreateListOfClasses", "Adding typedef %s to class %s",
1622     dt->GetName(), cdi->GetName());
1623    
1624     bool inNamespace = true;
1625     TString surroundingNamespace(dt->GetName());
1626     Ssiz_t posTemplate = surroundingNamespace.Last('>');
1627     inNamespace = inNamespace && (posTemplate == kNPOS);
1628     if (inNamespace) {
1629     Ssiz_t posColumn = surroundingNamespace.Last(':');
1630     if (posColumn != kNPOS) {
1631     surroundingNamespace.Remove(posColumn - 1);
1632     TClass* clSurrounding = GetClass(surroundingNamespace);
1633     inNamespace = inNamespace && (!clSurrounding || IsNamespace(clSurrounding));
1634     }
1635     }
1636     if (inNamespace && cdi->GetModule()) {
1637     TString htmlfilename(dt->GetName());
1638     output.NameSpace2FileName(htmlfilename);
1639     htmlfilename += ".html";
1640     TClassDocInfo* cdiTD = new TClassDocInfo(dt, htmlfilename);
1641     cdiTD->SetModule(cdi->GetModule());
1642     cdiTD->SetSelected(cdi->IsSelected());
1643     cdi->GetModule()->AddClass(cdiTD);
1644     }
1645     }
1646     }
1647    
1648     fDocEntityInfo.fClasses.Sort();
1649     fDocEntityInfo.fModules.Sort();
1650     TIter iterModule(&fDocEntityInfo.fModules);
1651     TModuleDocInfo* mdi = 0;
1652     while ((mdi = (TModuleDocInfo*) iterModule()))
1653     mdi->GetClasses()->Sort();
1654    
1655     if (fProductName == "(UNKNOWN PRODUCT)"
1656     && fDocEntityInfo.fModules.FindObject("core/base")
1657     && fDocEntityInfo.fModules.FindObject("core/cont")
1658     && fDocEntityInfo.fModules.FindObject("core/rint")
1659     && gProgName && strstr(gProgName, "root"))
1660     // if we have these modules we're probably building the root doc
1661     fProductName = "ROOT";
1662    
1663     if (fProductName == "(UNKNOWN PRODUCT)")
1664     Warning("CreateListOfClasses", "Product not set. You should call THtml->SetProduct(\"MyProductName\");");
1665    
1666     if (fDocEntityInfo.fModules.GetEntries() == 1
1667     && fDocEntityInfo.fModules.At(0)->GetName()
1668     && !strcmp(fDocEntityInfo.fModules.At(0)->GetName(), "(UNKNOWN)"))
1669     // Only one module, and its name is not known.
1670     // Let's call it "MAIN":
1671     ((TModuleDocInfo*) fDocEntityInfo.fModules.At(0))->SetName("MAIN");
1672    
1673     Info("CreateListOfClasses", "Initializing - DONE.");
1674     }
1675    
1676    
1677     //______________________________________________________________________________
1678     void THtml::CreateListOfTypes()
1679     {
1680     // Create index of all data types and a page for each typedef-to-class
1681    
1682     TDocOutput output(*this);
1683     output.CreateTypeIndex();
1684     output.CreateClassTypeDefs();
1685     }
1686    
1687     //______________________________________________________________________________
1688     Bool_t THtml::CopyFileFromEtcDir(const char* filename) const {
1689     // Copy a file from $ROOTSYS/etc/html into GetOutputDir()
1690    
1691     R__LOCKGUARD(GetMakeClassMutex());
1692    
1693     TString outFile(filename);
1694    
1695     TString inFile(outFile);
1696     gSystem->PrependPathName(GetEtcDir(), inFile);
1697    
1698     gSystem->PrependPathName(GetOutputDir(), outFile);
1699    
1700     if (gSystem->CopyFile(inFile, outFile, kTRUE) != 0) {
1701     Warning("CopyFileFromEtcDir", "Could not copy %s to %s", inFile.Data(), outFile.Data());
1702     return kFALSE;
1703     }
1704    
1705     return kTRUE;
1706     }
1707    
1708     //______________________________________________________________________________
1709     void THtml::CreateHierarchy()
1710     {
1711     // Create the inheritance hierarchy diagram for all classes
1712     TDocOutput output(*this);
1713     output.CreateHierarchy();
1714     }
1715    
1716     //______________________________________________________________________________
1717     void THtml::CreateJavascript() const {
1718     // Write the default ROOT style sheet.
1719     CopyFileFromEtcDir("ROOT.js");
1720     }
1721    
1722     //______________________________________________________________________________
1723     void THtml::CreateStyleSheet() const {
1724     // Write the default ROOT style sheet.
1725     CopyFileFromEtcDir("ROOT.css");
1726     CopyFileFromEtcDir("shadowAlpha.png");
1727     CopyFileFromEtcDir("shadow.gif");
1728     }
1729    
1730    
1731    
1732     //______________________________________________________________________________
1733     void THtml::GetDerivedClasses(TClass* cl, std::map<TClass*, Int_t>& derived) const
1734     {
1735     // fill derived with all classes inheriting from cl and their inheritance
1736     // distance to cl
1737    
1738     TIter iClass(&fDocEntityInfo.fClasses);
1739     TClassDocInfo* cdi = 0;
1740     while ((cdi = (TClassDocInfo*) iClass())) {
1741     TClass* candidate = dynamic_cast<TClass*>(cdi->GetClass());
1742     if (!candidate) continue;
1743     if (candidate != cl && candidate->InheritsFrom(cl)) {
1744     Int_t level = 0;
1745     TClass* currentBaseOfCandidate = candidate;
1746     while (currentBaseOfCandidate != cl) {
1747     TList* bases = currentBaseOfCandidate->GetListOfBases();
1748     if (!bases) continue;
1749     TIter iBase(bases);
1750     TBaseClass* base = 0;
1751     while ((base = (TBaseClass*) iBase())) {
1752     TClass* clBase = base->GetClassPointer();
1753     if (clBase && clBase->InheritsFrom(cl)) {
1754     ++level;
1755     currentBaseOfCandidate = clBase;
1756     }
1757     }
1758     }
1759     derived[candidate] = level;
1760     }
1761     }
1762     }
1763    
1764     //______________________________________________________________________________
1765     void THtml::GetHtmlFileName(TClass * classPtr, TString& filename) const
1766     {
1767     // Return real HTML filename
1768     //
1769     //
1770     // Input: classPtr - pointer to a class
1771     // filename - string containing a full name
1772     // of the corresponding HTML file after the function returns.
1773     //
1774    
1775     filename.Remove(0);
1776     if (!classPtr) return;
1777    
1778     TString cFilename;
1779     if (!GetImplFileName(classPtr, kFALSE, cFilename))
1780     GetDeclFileName(classPtr, kFALSE, cFilename);
1781    
1782     // classes without Impl/DeclFileName don't have docs,
1783     // and classes without docs don't have output file names
1784     if (!cFilename.Length())
1785     return;
1786    
1787     TString libName;
1788     const char *colon = strchr(cFilename, ':');
1789     if (colon)
1790     // old version, where source file name is prepended by "TAG:"
1791     libName = TString(cFilename, colon - cFilename);
1792     else
1793     // New version, check class's libname.
1794     // If libname is dir/libMyLib.so, check Root.Html.MyLib
1795     // If libname is myOtherLib.so.2.3, check Root.Html.myOtherLib
1796     // (i.e. remove directories, "lib" prefix, and any "extension")
1797     if (classPtr->GetSharedLibs()) {
1798     // first one is the class's lib
1799     TString libname(classPtr->GetSharedLibs());
1800     Ssiz_t posSpace = libname.First(' ');
1801     if (posSpace != kNPOS)
1802     libname.Remove(posSpace, libname.Length());
1803     TString libnameBase = gSystem->BaseName(libname);
1804     if (libnameBase.BeginsWith("lib"))
1805     libnameBase.Remove(0, 3);
1806     Ssiz_t posExt = libnameBase.First('.');
1807     if (posExt != '.')
1808     libnameBase.Remove(posExt, libnameBase.Length());
1809     if (libnameBase.Length())
1810     libName = libnameBase;
1811     }
1812    
1813     filename = cFilename;
1814     TString htmlFileName;
1815     if (!filename.Length() ||
1816     !gSystem->FindFile(fPathInfo.fInputPath, filename, kReadPermission)) {
1817     htmlFileName = GetURL(libName);
1818     } else
1819     htmlFileName = "./";
1820    
1821     if (htmlFileName.Length()) {
1822     filename = htmlFileName;
1823     TString className(classPtr->GetName());
1824     TDocOutput output(*const_cast<THtml*>(this));
1825     output.NameSpace2FileName(className);
1826     gSystem->PrependPathName(filename, className);
1827     filename = className;
1828     filename.ReplaceAll("\\", "/");
1829     filename += ".html";
1830     } else filename.Remove(0);
1831     }
1832    
1833     //______________________________________________________________________________
1834     const char* THtml::GetHtmlFileName(const char* classname) const
1835     {
1836     // Get the html file name for a class named classname.
1837     // Returns 0 if the class is not documented.
1838     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(classname);
1839     if (cdi)
1840     return cdi->GetHtmlFileName();
1841     return 0;
1842     }
1843    
1844     //______________________________________________________________________________
1845     TClass *THtml::GetClass(const char *name1) const
1846     {
1847     //*-*-*-*-*Return pointer to class with name*-*-*-*-*-*-*-*-*-*-*-*-*
1848     //*-* =================================
1849     if(!name1 || !name1[0]) return 0;
1850     // no doc for internal classes
1851     if (strstr(name1,"ROOT::")==name1) {
1852     Bool_t ret = kTRUE;
1853     if (!strncmp(name1 + 6,"Math", 4)) ret = kFALSE;
1854     if (!strncmp(name1 + 6,"Reflex", 6)) ret = kFALSE;
1855     if (!strncmp(name1 + 6,"Cintex", 6)) ret = kFALSE;
1856     if (ret) return 0;
1857     }
1858    
1859     TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(name1);
1860     if (!cdi) return 0;
1861     TClass *cl = dynamic_cast<TClass*>(cdi->GetClass());
1862     // hack to get rid of prec_stl types
1863     // TClassEdit checks are far too slow...
1864     /*
1865     if (cl && GetDeclFileName(cl) &&
1866     strstr(GetDeclFileName(cl),"prec_stl/"))
1867     cl = 0;
1868     */
1869     TString declFileName;
1870     if (cl && GetDeclFileName(cl, kFALSE, declFileName))
1871     return cl;
1872     return 0;
1873     }
1874    
1875     //______________________________________________________________________________
1876     bool THtml::GetDeclFileName(TClass * cl, Bool_t filesys, TString& out_name) const
1877     {
1878     // Return declaration file name; return the full path if filesys is true.
1879     return GetDeclImplFileName(cl, filesys, true, out_name);
1880     }
1881    
1882     //______________________________________________________________________________
1883     bool THtml::GetImplFileName(TClass * cl, Bool_t filesys, TString& out_name) const
1884     {
1885     // Return implementation file name
1886     return GetDeclImplFileName(cl, filesys, false, out_name);
1887     }
1888    
1889     //______________________________________________________________________________
1890     bool THtml::GetDeclImplFileName(TClass * cl, bool filesys, bool decl, TString& out_name) const
1891     {
1892     // Combined implementation for GetDeclFileName(), GetImplFileName():
1893     // Return declaration / implementation file name (depending on decl);
1894     // return the full path if filesys is true.
1895    
1896     out_name = "";
1897    
1898     R__LOCKGUARD(GetMakeClassMutex());
1899     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName());
1900     // whether we need to determine the fil name
1901     bool determine = (!cdi); // no cdi
1902     if (!determine) determine |= decl && filesys && !cdi->GetDeclFileSysName()[0];
1903     if (!determine) determine |= decl && !filesys && !cdi->GetDeclFileName()[0];
1904     if (!determine) determine |= !decl && filesys && !cdi->GetImplFileSysName()[0];
1905     if (!determine) determine |= !decl && !filesys && !cdi->GetImplFileName()[0];
1906     if (determine) {
1907     TString name;
1908     TString sysname;
1909     if (decl) {
1910     if (!GetFileDefinition().GetDeclFileName(cl, name, sysname))
1911     return false;
1912     } else {
1913     if (!GetFileDefinition().GetImplFileName(cl, name, sysname))
1914     return false;
1915     }
1916     if (cdi) {
1917     if (decl) {
1918     if (!cdi->GetDeclFileName() || !cdi->GetDeclFileName()[0])
1919     cdi->SetDeclFileName(name);
1920     if (!cdi->GetDeclFileSysName() || !cdi->GetDeclFileSysName()[0])
1921     cdi->SetDeclFileSysName(sysname);
1922     } else {
1923     if (!cdi->GetImplFileName() || !cdi->GetImplFileName()[0])
1924     cdi->SetImplFileName(name);
1925     if (!cdi->GetImplFileSysName() || !cdi->GetImplFileSysName()[0])
1926     cdi->SetImplFileSysName(sysname);
1927     }
1928     }
1929    
1930     if (filesys) out_name = sysname;
1931     else out_name = name;
1932     return true;
1933     }
1934     if (filesys) {
1935     if (decl) out_name = cdi->GetDeclFileSysName();
1936     else out_name = cdi->GetImplFileSysName();
1937     } else {
1938     if (decl) out_name = cdi->GetDeclFileName();
1939     else out_name = cdi->GetImplFileName();
1940     }
1941     return true;
1942     }
1943    
1944     //______________________________________________________________________________
1945     const TString& THtml::GetOutputDir(Bool_t createDir /*= kTRUE*/) const
1946     {
1947     // Return the output directory as set by SetOutputDir().
1948     // Create it if it doesn't exist and if createDir is kTRUE.
1949    
1950     if (createDir) {
1951     R__LOCKGUARD(GetMakeClassMutex());
1952    
1953     gSystem->ExpandPathName(const_cast<THtml*>(this)->fPathInfo.fOutputDir);
1954     Long64_t sSize;
1955     Long_t sId, sFlags, sModtime;
1956     Int_t st = gSystem->GetPathInfo(fPathInfo.fOutputDir, &sId, &sSize, &sFlags, &sModtime);
1957     if (st || !(sFlags & 2)) {
1958     if (st == 0)
1959     Error("GetOutputDir", "output directory %s is an existing file",
1960     fPathInfo.fOutputDir.Data());
1961     else if (gSystem->MakeDirectory(fPathInfo.fOutputDir) == -1)
1962     Error("GetOutputDir", "output directory %s does not exist and can't create it", fPathInfo.fOutputDir.Data());
1963     }
1964     }
1965     return fPathInfo.fOutputDir;
1966     }
1967    
1968     //______________________________________________________________________________
1969     Bool_t THtml::IsNamespace(const TClass*cl)
1970     {
1971     // Check whether cl is a namespace
1972     return (cl->Property() & kIsNamespace);
1973     }
1974    
1975     //______________________________________________________________________________
1976     void THtml::LoadAllLibs()
1977     {
1978     // Load all libraries known to ROOT via the rootmap system.
1979    
1980     TEnv* mapfile = gInterpreter->GetMapfile();
1981     if (!mapfile || !mapfile->GetTable()) return;
1982    
1983     std::set<std::string> loadedlibs;
1984     std::set<std::string> failedlibs;
1985    
1986     TEnvRec* rec = 0;
1987     TIter iEnvRec(mapfile->GetTable());
1988     while ((rec = (TEnvRec*) iEnvRec())) {
1989     TString libs = rec->GetValue();
1990     TString lib;
1991     Ssiz_t pos = 0;
1992     while (libs.Tokenize(lib, pos)) {
1993     // check that none of the libs failed to load
1994     if (failedlibs.find(lib.Data()) != failedlibs.end()) {
1995     // don't load it or any of its dependencies
1996     libs = "";
1997     break;
1998     }
1999     }
2000     pos = 0;
2001     while (libs.Tokenize(lib, pos)) {
2002     // ignore libCore - it's already loaded
2003     if (lib.BeginsWith("libCore"))
2004     continue;
2005    
2006     if (loadedlibs.find(lib.Data()) == loadedlibs.end()) {
2007     // just load the first library - TSystem will do the rest.
2008     gSystem->Load(lib);
2009     loadedlibs.insert(lib.Data());
2010     }
2011     }
2012     }
2013     }
2014    
2015    
2016     //______________________________________________________________________________
2017     void THtml::MakeAll(Bool_t force, const char *filter, int numthreads /*= -1*/)
2018     {
2019     // Produce documentation for all the classes specified in the filter (by default "*")
2020     // To process all classes having a name starting with XX, do:
2021     // html.MakeAll(kFALSE,"XX*");
2022     // If force=kFALSE (default), only the classes that have been modified since
2023     // the previous call to this function will be generated.
2024     // If force=kTRUE, all classes passing the filter will be processed.
2025     // If numthreads is != -1, use numthreads threads, else decide automatically
2026     // based on the number of CPUs.
2027    
2028     MakeIndex(filter);
2029    
2030     if (numthreads == 1) {
2031     // CreateListOfClasses(filter); already done by MakeIndex
2032     TClassDocInfo* classinfo = 0;
2033     TIter iClassInfo(&fDocEntityInfo.fClasses);
2034     UInt_t count = 0;
2035    
2036     while ((classinfo = (TClassDocInfo*)iClassInfo())) {
2037     if (!classinfo->IsSelected())
2038     continue;
2039     fCounter.Form("%5d", fDocEntityInfo.fClasses.GetSize() - count++);
2040     MakeClass(classinfo, force);
2041     }
2042     } else {
2043     if (numthreads == -1) {
2044     SysInfo_t sysinfo;
2045     gSystem->GetSysInfo(&sysinfo);
2046     numthreads = sysinfo.fCpus;
2047     if (numthreads < 1)
2048     numthreads = 2;
2049     }
2050     fThreadedClassCount = 0;
2051     fThreadedClassIter = new TIter(&fDocEntityInfo.fClasses);
2052     THtmlThreadInfo hti(this, force);
2053     if (!fMakeClassMutex && gGlobalMutex) {
2054     gGlobalMutex->Lock();
2055     fMakeClassMutex = gGlobalMutex->Factory(kTRUE);
2056     gGlobalMutex->UnLock();
2057     }
2058    
2059     TList threads;
2060     gSystem->Load("libThread");
2061     while (--numthreads >= 0) {
2062     TThread* thread = new TThread(MakeClassThreaded, &hti);
2063     thread->Run();
2064     threads.Add(thread);
2065     }
2066    
2067     TIter iThread(&threads);
2068     TThread* thread = 0;
2069     Bool_t wait = kTRUE;
2070     while (wait) {
2071     while (wait && (thread = (TThread*) iThread()))
2072     wait &= (thread->GetState() == TThread::kRunningState);
2073     gSystem->ProcessEvents();
2074     gSystem->Sleep(500);
2075     }
2076    
2077     iThread.Reset();
2078     while ((thread = (TThread*) iThread()))
2079     thread->Join();
2080     }
2081     fCounter.Remove(0);
2082     }
2083    
2084    
2085     //______________________________________________________________________________
2086     void THtml::MakeClass(const char *className, Bool_t force)
2087     {
2088     // Make HTML files for a single class
2089     //
2090     //
2091     // Input: className - name of the class to process
2092     //
2093     CreateListOfClasses("*");
2094    
2095     TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(className);
2096     if (!cdi) {
2097     if (!TClassEdit::IsStdClass(className)) // stl classes won't be available, so no warning
2098     Error("MakeClass", "Unknown class '%s'!", className);
2099     return;
2100     }
2101    
2102     MakeClass(cdi, force);
2103     }
2104    
2105     //______________________________________________________________________________
2106     void THtml::MakeClass(void *cdi_void, Bool_t force)
2107     {
2108     // Make HTML files for a single class
2109     //
2110     //
2111     // Input: cdi - doc info for class to process
2112     //
2113     if (!fDocEntityInfo.fClasses.GetSize())
2114     CreateListOfClasses("*");
2115    
2116     TClassDocInfo* cdi = (TClassDocInfo*) cdi_void;
2117     TClass* currentClass = dynamic_cast<TClass*>(cdi->GetClass());
2118    
2119     if (!currentClass) {
2120     if (!cdi->GetClass() &&
2121     !TClassEdit::IsStdClass(cdi->GetName())) // stl classes won't be available, so no warning
2122     Error("MakeClass", "Class '%s' is known, but I cannot find its TClass object!", cdi->GetName());
2123     return;
2124     }
2125     TString htmlFile(cdi->GetHtmlFileName());
2126     if (htmlFile.Length()
2127     && (htmlFile.BeginsWith("http://")
2128     || htmlFile.BeginsWith("https://")
2129     || gSystem->IsAbsoluteFileName(htmlFile))
2130     ) {
2131     htmlFile.Remove(0);
2132     }
2133     if (htmlFile.Length()) {
2134     TClassDocOutput cdo(*this, currentClass, &cdi->GetListOfTypedefs());
2135     cdo.Class2Html(force);
2136     cdo.MakeTree(force);
2137     } else {
2138     TString what(cdi->GetName());
2139     what += " (sources not found)";
2140     Printf(fCounterFormat.Data(), "-skipped-", fCounter.Data(), what.Data());
2141     }
2142     }
2143    
2144    
2145     //______________________________________________________________________________
2146     void* THtml::MakeClassThreaded(void* info) {
2147     // Entry point of worker threads for multi-threaded MakeAll().
2148     // info points to an (internal) THtmlThreadInfo object containing the current
2149     // THtml object, and whether "force" was passed to MakeAll().
2150     // The thread will poll GetNextClass() until no further class is available.
2151    
2152     const THtmlThreadInfo* hti = (const THtmlThreadInfo*)info;
2153     if (!hti) return 0;
2154     TClassDocInfo* classinfo = 0;
2155     while ((classinfo = hti->GetHtml()->GetNextClass()))
2156     hti->GetHtml()->MakeClass(classinfo, hti->GetForce());
2157    
2158     return 0;
2159     }
2160    
2161     //______________________________________________________________________________
2162     void THtml::MakeIndex(const char *filter)
2163     {
2164     // Create the index files for the product, modules, all types, etc.
2165     // By default all classes are indexed (if filter="*");
2166     // to generate an index for all classes starting with "XX", do
2167     // html.MakeIndex("XX*");
2168    
2169     CreateListOfClasses(filter);
2170    
2171     TDocOutput output(*this);
2172     // create indices
2173     output.CreateTypeIndex();
2174     output.CreateClassTypeDefs();
2175     output.CreateModuleIndex();
2176     output.CreateClassIndex();
2177     output.CreateProductIndex();
2178    
2179     // create a class hierarchy
2180     output.CreateHierarchy();
2181     }
2182    
2183    
2184     //______________________________________________________________________________
2185     void THtml::MakeTree(const char *className, Bool_t force)
2186     {
2187     // Make an inheritance tree
2188     //
2189     //
2190     // Input: className - name of the class to process
2191     //
2192    
2193     // create canvas & set fill color
2194     TClass *classPtr = GetClass(className);
2195    
2196     if (!classPtr) {
2197     Error("MakeTree", "Unknown class '%s' !", className);
2198     return;
2199     }
2200    
2201     TClassDocOutput cdo(*this, classPtr, 0);
2202     cdo.MakeTree(force);
2203     }
2204    
2205     //______________________________________________________________________________
2206     void THtml::SetFoundDot(Bool_t found) {
2207     // Set whether "dot" (a GraphViz utility) is avaliable
2208     if (found) fPathInfo.fFoundDot = PathInfo_t::kDotFound;
2209     else fPathInfo.fFoundDot = PathInfo_t::kDotNotFound;
2210     }
2211    
2212     //______________________________________________________________________________
2213     void THtml::SetLocalFiles() const
2214     {
2215     // Fill the files available in the file system below fPathInfo.fInputPath
2216     if (fLocalFiles) delete fLocalFiles;
2217     fLocalFiles = new TFileSysDB(fPathInfo.fInputPath, fPathInfo.fIgnorePath + "|(\\b" + GetOutputDir(kFALSE) + "\\b)" , 6);
2218     }
2219    
2220     //______________________________________________________________________________
2221     void THtml::SetModuleDefinition(const TModuleDefinition& md)
2222     {
2223     // Set the module defining object to be used; can also be a user derived
2224     // object (a la traits).
2225     delete fModuleDef;
2226     fModuleDef = (TModuleDefinition*) md.Clone();
2227     fModuleDef->SetOwner(const_cast<THtml*>(this));
2228     }
2229    
2230    
2231     //______________________________________________________________________________
2232     void THtml::SetFileDefinition(const TFileDefinition& md)
2233     {
2234     // Set the file defining object to be used; can also be a user derived
2235     // object (a la traits).
2236     delete fFileDef;
2237     fFileDef = (TFileDefinition*) md.Clone();
2238     fFileDef->SetOwner(const_cast<THtml*>(this));
2239     }
2240    
2241    
2242     //______________________________________________________________________________
2243     void THtml::SetPathDefinition(const TPathDefinition& md)
2244     {
2245     // Set the path defining object to be used; can also be a user derived
2246     // object (a la traits).
2247     delete fPathDef;
2248     fPathDef = (TPathDefinition*) md.Clone();
2249     fPathDef->SetOwner(const_cast<THtml*>(this));
2250     }
2251    
2252    
2253     //______________________________________________________________________________
2254     void THtml::SetInputDir(const char *dir)
2255     {
2256     // Set the directory containing the source files.
2257     // The source file for a class MyClass will be searched
2258     // by prepending dir to the value of
2259     // MyClass::Class()->GetImplFileName() - which can contain
2260     // directory information!
2261     // Also resets the class structure, in case new files can
2262     // be found after this call.
2263    
2264     fPathInfo.fInputPath = dir;
2265     gSystem->ExpandPathName(fPathInfo.fInputPath);
2266    
2267     // reset class table
2268     fDocEntityInfo.fClasses.Clear();
2269     fDocEntityInfo.fModules.Clear();
2270     }
2271    
2272     //______________________________________________________________________________
2273     void THtml::SetDeclFileName(TClass* cl, const char* filename)
2274     {
2275     // Explicitly set a decl file name for TClass cl.
2276     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName());
2277     if (!cdi) {
2278     cdi = new TClassDocInfo(cl, "" /*html*/, "" /*fsdecl*/, "" /*fsimpl*/, filename);
2279     fDocEntityInfo.fClasses.Add(cdi);
2280     } else
2281     cdi->SetDeclFileName(filename);
2282     }
2283    
2284     //______________________________________________________________________________
2285     void THtml::SetImplFileName(TClass* cl, const char* filename)
2286     {
2287     // Explicitly set a impl file name for TClass cl.
2288     TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName());
2289     if (!cdi) {
2290     cdi = new TClassDocInfo(cl, "" /*html*/, "" /*fsdecl*/, "" /*fsimpl*/, 0 /*decl*/, filename);
2291     fDocEntityInfo.fClasses.Add(cdi);
2292     } else
2293     cdi->SetImplFileName(filename);
2294     }