diff --git a/html/inc/LinkDef.h b/html/inc/LinkDef.h index 86d57fcbc79414f18cdcc4198084d11c8549c914..12c4ef79dd54bde8959fbe3fcecd76f98bd3827a 100644 --- a/html/inc/LinkDef.h +++ b/html/inc/LinkDef.h @@ -13,6 +13,7 @@ #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; +#pragma link C++ nestedclasses; #pragma link C++ global gHtml; @@ -27,4 +28,11 @@ #pragma link C++ class TClassDocInfo; #pragma link C++ class TModuleDocInfo; #pragma link C++ class TLibraryDocInfo; +#pragma link C++ class THtml::THelperBase; +#pragma link C++ class THtml::TModuleDefinition; +#pragma link C++ class THtml::TFileDefinition; +#pragma link C++ class THtml::TPathDefinition; +#pragma link C++ class THtml::TFileSysEntry; +#pragma link C++ class THtml::TFileSysDir; +#pragma link C++ class THtml::TFileSysDB; #endif diff --git a/html/inc/TDocDirective.h b/html/inc/TDocDirective.h index 42830a7d5a25bbbdf96590f70b8219b6189029ce..212752dbccbfdd0c3dab546e32db6b8771118b05 100644 --- a/html/inc/TDocDirective.h +++ b/html/inc/TDocDirective.h @@ -58,6 +58,7 @@ protected: void SetParameters(const char* params); void SetTag(const char* tag) { SetTitle(tag); } void SetCounter(Int_t count) { fCounter = count; } + virtual void DeleteOutputFiles(const char* ext) const; public: // get the tag ending this directive @@ -69,6 +70,9 @@ public: // retrieve the result (replacement) of the directive; return false if invalid virtual Bool_t GetResult(TString& result) = 0; + // Delete output for the parser's current class or module. + virtual void DeleteOutput() const {} + friend class TDocParser; ClassDef(TDocDirective, 0); // THtml directive handler @@ -107,6 +111,8 @@ public: virtual void AddLine(const TSubString& line); virtual const char* GetEndTag() const { return "end_macro"; } virtual Bool_t GetResult(TString& result); + // Delete output for the parser's current class or module. + virtual void DeleteOutput() const { DeleteOutputFiles(".gif"); } ClassDef(TDocMacroDirective, 0); // Handler for "Begin_Macro"/"End_Macro" for code that is executed and that can generate an image for documentation }; @@ -140,6 +146,8 @@ public: TList* GetListOfLines() const; virtual Bool_t GetResult(TString& result); + // Delete output for the parser's current class or module. + virtual void DeleteOutput() const { DeleteOutputFiles(".gif"); } ClassDef(TDocLatexDirective, 0); // Handler for "Begin_Latex"/"End_Latex" to generate an image from latex }; diff --git a/html/inc/TDocInfo.h b/html/inc/TDocInfo.h index d596885f6c5a13d04652d3248cd786a2842c4eca..ca6e2c437d6e469375084884bd720443006a3177 100644 --- a/html/inc/TDocInfo.h +++ b/html/inc/TDocInfo.h @@ -12,18 +12,15 @@ #ifndef ROOT_TDocInfo #define ROOT_TDocInfo -#ifndef ROOT_TList -#include "TList.h" -#endif -#ifndef ROOT_TNamed -#include "TNamed.h" -#endif -#ifndef ROOT_TString -#include "TString.h" +#ifndef ROOT_THashList +#include "THashList.h" #endif #ifndef ROOT_TClassRef #include "TClassRef.h" #endif +#ifndef ROOT_TNamed +#include "TNamed.h" +#endif #include <string> #include <set> @@ -37,23 +34,38 @@ class TModuleDocInfo; class TClassDocInfo: public TObject { public: // initialize the object - TClassDocInfo(TClass* cl, const char* filename): - fClass(cl), fModule(0), fHtmlFileName(filename), - fSelected(kTRUE), fHaveSource(kFALSE) { } + TClassDocInfo(TClass* cl, + const char* htmlfilename = "", + const char* fsdecl = "", const char* fsimpl = "", + const char* decl = 0, const char* impl = 0): + fClass(cl), fModule(0), fHtmlFileName(htmlfilename), + fDeclFileName(decl ? decl : cl->GetDeclFileName()), + fImplFileName(impl ? impl : cl->GetImplFileName()), + fDeclFileSysName(fsdecl), fImplFileSysName(fsimpl), + fSelected(kTRUE) { } + virtual ~TClassDocInfo() {} TClass* GetClass() const { return fClass; } virtual const char* GetName() const; const char* GetHtmlFileName() const { return fHtmlFileName; } + const char* GetDeclFileName() const { return fDeclFileName; } + const char* GetImplFileName() const { return fImplFileName; } + const char* GetDeclFileSysName() const { return fDeclFileSysName; } + const char* GetImplFileSysName() const { return fImplFileSysName; } void SetModule(TModuleDocInfo* module) { fModule = module; } TModuleDocInfo* GetModule() const { return fModule; } void SetSelected(Bool_t sel = kTRUE) { fSelected = sel; } Bool_t IsSelected() const { return fSelected; } - Bool_t HaveSource() const { return fHaveSource; } + Bool_t HaveSource() const { return fImplFileSysName.Length(); } - void SetHaveSource(Bool_t have = kTRUE) { fHaveSource = have; } + void SetHtmlFileName(const char* name) { fHtmlFileName = name; } + void SetDeclFileName(const char* name) { fDeclFileName = name; } + void SetImplFileName(const char* name) { fImplFileName = name; } + void SetDeclFileSysName(const char* fsname) { fDeclFileSysName = fsname; } + void SetImplFileSysName(const char* fsname) { fImplFileSysName = fsname; } ULong_t Hash() const; @@ -66,8 +78,11 @@ private: TClassRef fClass; // class represented by this info object TModuleDocInfo* fModule; // module this class is in TString fHtmlFileName; // name of the HTML doc file + TString fDeclFileName; // header + TString fImplFileName; // source + TString fDeclFileSysName; // file system's location of the header + TString fImplFileSysName; // file system's location of the source Bool_t fSelected; // selected for doc output - Bool_t fHaveSource; // whether we can find the source locally ClassDef(TClassDocInfo,0); // info cache for class documentation }; @@ -78,8 +93,10 @@ private: // class TModuleDocInfo: public TNamed { public: - TModuleDocInfo(const char* name, const char* doc = ""): - TNamed(name, doc), fSelected(kTRUE) {} + TModuleDocInfo(const char* name, TModuleDocInfo* super, const char* doc = ""): + TNamed(name, doc), fSuper(super), fSub(0), fSelected(kTRUE) { + if (super) super->GetSub().Add(this); + } virtual ~TModuleDocInfo() {} void SetDoc(const char* doc) { SetTitle(doc); } @@ -91,12 +108,13 @@ public: void AddClass(TClassDocInfo* cl) { fClasses.Add(cl); } TList* GetClasses() { return &fClasses; } - const TString& GetSourceDir() const { return fSourceDir; } - void SetSourceDir(const char* dir); + TModuleDocInfo* GetSuper() const { return fSuper; } + THashList& GetSub() { return fSub; } private: + TModuleDocInfo* fSuper; // module containing this module + THashList fSub; // modules contained in this module TList fClasses; - TString fSourceDir; // (a) directory containing the modules' sources Bool_t fSelected; // selected for doc output ClassDef(TModuleDocInfo,0); // documentation for a group of classes diff --git a/html/inc/TDocOutput.h b/html/inc/TDocOutput.h index 019d72887004d6c37af696f732e71835300686a8..0266b15db772b312af08f6795efc7613cb097f47 100644 --- a/html/inc/TDocOutput.h +++ b/html/inc/TDocOutput.h @@ -35,6 +35,7 @@ class TClass; class TDataMember; class TDataType; class THtml; +class TModuleDocInfo; class TString; class TSubString; class TVirtualPad; @@ -62,6 +63,8 @@ protected: const char *copyright, const char* footer); virtual void WriteSearch(std::ostream& out); void WriteModuleLinks(std::ostream& out); + void WriteModuleLinks(std::ostream& out, TModuleDocInfo* super); + void WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname = 0); public: enum EFileType { kSource, kInclude, kTree, kDoc }; diff --git a/html/inc/TDocParser.h b/html/inc/TDocParser.h index 962cccbc5b57b8f3f77a3ef686f12b5d4492a024..2b7c487734b7cab4354eb3a8a52853218ae5399a 100644 --- a/html/inc/TDocParser.h +++ b/html/inc/TDocParser.h @@ -57,6 +57,8 @@ public: kInfoLastUpdate, kInfoAuthor, kInfoCopyright, + kInfoLastChanged, + kInfoLastGenerated, kNumSourceInfos }; enum EAccess { @@ -99,6 +101,7 @@ protected: TString fFirstClassDoc; // first class-doc found - per file, taken if fLastClassDoc is empty TString fLastClassDoc; // last class-doc found - becomes class doc at ClassImp or first method TClass* fCurrentClass; // current class context of sources being parsed + TString fCurrentModule; // current module context of sources being parsed TString fCurrentMethodTag;// name_idx of the currently parsed method Int_t fDirectiveCount; // index of directive for current method TString fCurrentFile; // current source / header file name @@ -164,12 +167,15 @@ public: void DecrementMethodCount(const char* name); virtual void DecorateKeywords(std::ostream& out, const char* text); virtual void DecorateKeywords(TString& text); + virtual void DeleteDirectiveOutput() const; const TList* GetMethods(EAccess access) const { return &fMethods[access]; } TClass* GetCurrentClass() const { return fCurrentClass; } + void GetCurrentModule(TString& out_module) const; TDocOutput* GetDocOutput() const { return fDocOutput; } const TList* GetDataMembers(EAccess access) const { return &fDataMembers[access]; } const TList* GetEnums(EAccess access) const { return &fDataMembers[access+3]; } const char* GetSourceInfo(ESourceInfo type) const { return fSourceInfo[type]; } + void SetCurrentModule(const char* module) { fCurrentModule = module; } UInt_t InContext(Int_t context) const; static Bool_t IsName(UChar_t c); diff --git a/html/inc/THtml.h b/html/inc/THtml.h index 5b126322d4a66e8b32e4fda788ee8de115a8ce4b..434b757632e68fa64c9d66a49302f0aab975464d 100644 --- a/html/inc/THtml.h +++ b/html/inc/THtml.h @@ -26,68 +26,180 @@ #include "THashList.h" #endif +#ifndef ROOT_THashTable +#include "THashTable.h" +#endif + +#ifndef ROOT_TExMap +#include "TExMap.h" +#endif + #include <map> class TClass; class TClassDocInfo; class TVirtualMutex; -class THtml : public TObject { -protected: - enum ETraverse { - kUp, kDown, kBoth // direction to traverse class tree in ClassHtmlTree() +class THtml: public TObject { +public: + //______________________________________________________________ + // Helper base class. + class THelperBase: public TObject { + public: + THelperBase(): fHtml(0) {} + virtual ~THelperBase(); + void SetOwner(THtml* html); + THtml* GetOwner() const { return fHtml; } + private: + THtml* fHtml; // object owning the helper + ClassDef(THelperBase, 0); // a helper object's base class }; -protected: - TString fXwho; // URL for name lookup - TString fROOTURL; // Root URL for ROOT's reference guide for libs that are not in fLibURLs - std::map<std::string, TString> fLibURLs; // URL for documentation of external libraries - TString fClassDocTag; // tag for class documentation - TString fAuthorTag; // tag for author - TString fLastUpdateTag; // tag for last update - TString fCopyrightTag; // tag for copyright - TString fHeader; // header file name - TString fFooter; // footerer file name - TString fHomepage; // URL of homepage - TString fSearchStemURL; // URL stem used to build search URL - TString fSearchEngine; // link to search engine - TString fViewCVS; // link to ViewCVS; %f is replaced by the filename (no %f: it's appended) - TString fWikiURL; // URL stem of class's wiki page, %c replaced by mangled class name (no %c: appended) - TString fCharset; // Charset for doc pages - TString fDocStyle; // doc style (only "Doc++" has special treatment) - - TString fSourcePrefix; // prefix to relative source path - TString fSourceDir; // source path - TString fIncludePath; // include path - TString fOutputDir; // output directory - TString fDotDir; // directory of GraphViz's dot binary - TString fEtcDir; // directory containing auxiliary files - Int_t fFoundDot; // whether dot is accessible (-1 dunno, 1 yes, 0 no) - TString fCounter; // counter string - TString fCounterFormat; // counter printf-like format - TString fClassFilter; // filter used for buidling known classes - TString fProductName; // name of the product to document - TString fProductDocDir; // directory containing documentation for the product - TString fMacroPath; // path for macros run via the Begin/End Macro directive - TString fModuleDocPath; // path to check for module documentation - THashList fClasses; // known classes - THashList fModules; // known modules - std::map<TClass*,std::string> fGuessedDeclFileNames; // names of additional decl file names - std::map<TClass*,std::string> fGuessedImplFileNames; // names of additional impl file names - THashList fLibDeps; // Library dependencies - TIter *fThreadedClassIter; // fClasses iterator for MakeClassThreaded - Int_t fThreadedClassCount; // counter of processed classes for MakeClassThreaded + //______________________________________________________________ + // Helper class to translate between classes and their + // modules. Can be derived from and thus replaced by + // the user; see THtml::SetModuleDefinition(). + class TModuleDefinition: public THelperBase { + public: + virtual bool GetModule(TClass* cl, TString& out_modulename) const; + ClassDef(TModuleDefinition, 0); // helper class to determine a class's module + }; - TVirtualMutex *fMakeClassMutex; // Mutex for MakeClassThreaded + //______________________________________________________________ + // Helper class to translate between classes and their + // filenames. Can be derived from and thus replaced by + // the user; see THtml::SetFileDefinition(). + class TFileDefinition: public THelperBase { + public: + virtual bool GetDeclFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const; + virtual bool GetImplFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const; + protected: + virtual bool GetFileName(const TClass* cl, bool decl, TString& out_filename, TString& out_fsys) const; - virtual void CreateJavascript() const; - virtual void CreateStyleSheet() const; - void CreateListOfTypes(); - void CreateListOfClasses(const char* filter); - void MakeClass(void* cdi, Bool_t force=kFALSE); - TClassDocInfo *GetNextClass(); + void SplitClassIntoDirFile(const TString& clname, TString& dir, TString& filename) const; + void ExpandSearchPath(TString& path) const; + ClassDef(TFileDefinition, 0); // helper class to determine a class's source files + }; + + //______________________________________________________________ + // Helper class to translate between file names and their + // version used for documentation. Can be derived from and thus + // replaced by the user; see THtml::SetPathDefinition(). + class TPathDefinition: public THelperBase { + public: + virtual bool GetMacroPath(const TString& module, TString& out_dir) const; + virtual bool GetIncludeAs(TClass* cl, TString& out_include_as) const; + virtual bool GetFileNameFromInclude(const char* included, TString& out_fsname) const; + virtual bool GetDocDir(const TString& module, TString& doc_dir) const; + protected: + ClassDef(TPathDefinition, 0); // helper class to determine directory layouts + }; + + class TFileSysDir; + class TFileSysDB; + //______________________________________________________________ + // Utility class representing a directory entry + class TFileSysEntry: public TObject { + public: + TFileSysEntry(const char* name, TFileSysDir* parent): + fName(name), fParent(parent), fLevel(parent ? parent->GetLevel() + 1 : 0) {} + const char* GetName() const { return fName; } + virtual ULong_t Hash() const { return fName.Hash(); } + void GetFullName(TString& fullname) const { + fullname = ""; + if (fParent) { + fParent->GetFullName(fullname); + fullname += "/"; + } + fullname += fName; + } + + TFileSysDir* GetParent() const { return fParent; } + Int_t GetLevel() const { return fLevel; } + private: + TString fName; // name of the element + TFileSysDir* fParent; // parent directory + Int_t fLevel; // level of directory + ClassDef(TFileSysEntry, 0); // an entry of the local file system + }; + + //______________________________________________________________ + // Utility class representing a directory + class TFileSysDir: public TFileSysEntry { + public: + TFileSysDir(const char* name, TFileSysDir* parent): + TFileSysEntry(name, parent) + { fFiles.SetOwner(); fDirs.SetOwner(); } + const TList* GetFiles() const { return &fFiles; } + const TList* GetSubDirs() const { return &fDirs; } + + void Recurse(TFileSysDB* db, const char* path); + + private: + TList fFiles; + TList fDirs; + ClassDef(TFileSysDir, 0); // an directory if the local file system + }; + + //______________________________________________________________ + // Utility class representing a directory + class TFileSysDB: public TFileSysDir { + public: + TFileSysDB(const char* path, const char* ignore, Int_t maxdirlevel): + TFileSysDir(path, 0), fIgnorePath(ignore), fMaxLevel(maxdirlevel) + { Fill(); } + + TExMap& GetMapIno() { return fMapIno; } + THashTable& GetEntries() { return fEntries; } + const TString& GetIgnore() const { return fIgnorePath; } + Int_t GetMaxLevel() const { return fMaxLevel; } + + protected: + void Fill() { Recurse(this, GetName()); } + + private: + TExMap fMapIno; // inode to TFileSysDir map, to detect softlinks + THashTable fEntries; // hash map of all filenames without paths + TString fIgnorePath; // regexp of path to ignore while building entry tree + Int_t fMaxLevel; // maximum level of directory nesting + ClassDef(TFileSysDB, 0); // instance of file system data + }; + + + //______________________________________________________________ + // Configuration holder for path related settings + struct TPathInfo { + enum EDotAccess { + kDotUnknown, + kDotFound, + kDotNotFound + }; + + TPathInfo(): + fFoundDot(kDotUnknown), +#ifdef R__WIN32 + fInputPath("./;src/;include/"), +#else + fInputPath("./:src/:include/"), +#endif + fIncludePath("include"), + // .whatever implicitly ignored, no need to add .svn! + fIgnorePath("\\b(include|CVS|test|tutorials|doc|lib|python|demo|freetype-|gdk|libAfterImage|etc|config|build|bin)\\b"), + fDocPath("doc"), + fMacroPath("macros:."), + fOutputDir("htmldoc") {} + + EDotAccess fFoundDot; // whether dot is accessible + TString fInputPath; // directories to look for classes; prepended to Decl/ImplFileName() + TString fIncludePath; // directory prefixes (":" delimited) to remove when quoting include files + TString fIgnorePath; // regexp pattern for directories to ignore ("\b(CVS|\.svn)\b") for ROOT + TString fDocPath; // subdir to check for module documentation ("doc" for ROOT) + TString fMacroPath; // subdir of fDocPath for macros run via the Begin/End Macro directive; ("macros" for ROOT) + TString fDotDir; // directory of GraphViz's dot binary + TString fEtcDir; // directory containing auxiliary files + TString fOutputDir; // output directory + }; - static void *MakeClassThreaded(void* info); public: THtml(); @@ -106,85 +218,94 @@ public: void MakeTree(const char *className, Bool_t force=kFALSE); // Configuration setters + void SetModuleDefinition(const TModuleDefinition& md); + void SetFileDefinition(const TFileDefinition& fd); + void SetPathDefinition(const TPathDefinition& pd); void SetProductName(const char* product) { fProductName = product; } - void SetOutputDir(const char *dir) { fOutputDir = dir; } - void SetSourceDir(const char *dir); - void SetIncludePath(const char *path) { fIncludePath = path; } - void SetSourcePrefix(const char *prefix); - void SetEtcDir(const char* dir) { fEtcDir = dir; } - void SetModuleDocPath(const char* path) { fModuleDocPath = path; } - void SetProductDocDir(const char* dir) { fProductDocDir = dir; } - void SetDotDir(const char* dir) { fDotDir = dir; fFoundDot = -1; } - void SetRootURL(const char* url) { fROOTURL = url; } - void SetLibURL(const char* lib, const char* url) { fLibURLs[lib] = url; } - void SetXwho(const char *xwho) { fXwho = xwho; } - void SetMacroPath(const char* path) {fMacroPath = path;} + void SetOutputDir(const char *dir) { fPathInfo.fOutputDir = dir; } + void SetInputDir(const char *dir); + void SetEtcDir(const char* dir) { fPathInfo.fEtcDir = dir; } + void SetDocPath(const char* path) { fPathInfo.fDocPath = path; } + void SetDotDir(const char* dir) { fPathInfo.fDotDir = dir; fPathInfo.fFoundDot = TPathInfo::kDotUnknown; } + void SetRootURL(const char* url) { fLinkInfo.fROOTURL = url; } + void SetLibURL(const char* lib, const char* url) { fLinkInfo.fLibURLs[lib] = url; } + void SetXwho(const char *xwho) { fLinkInfo.fXwho = xwho; } + void SetMacroPath(const char* path) {fPathInfo.fMacroPath = path;} void AddMacroPath(const char* path); void SetCounterFormat(const char* format) { fCounterFormat = format; } - void SetClassDocTag(const char* tag) { fClassDocTag = tag; } - void SetAuthorTag(const char* tag) { fAuthorTag = tag; } - void SetLastUpdateTag(const char* tag) { fLastUpdateTag = tag; } - void SetCopyrightTag(const char* tag) { fCopyrightTag = tag; } - void SetHeader(const char* file) { fHeader = file; } - void SetFooter(const char* file) { fFooter = file; } - void SetHomepage(const char* url) { fHomepage = url; } - void SetSearchStemURL(const char* url) { fSearchStemURL = url; } - void SetSearchEngine(const char* url) { fSearchEngine = url; } - void SetViewCVS(const char* url) { fViewCVS = url; } - void SetWikiURL(const char* url) { fWikiURL = url; } - void SetCharset(const char* charset) { fCharset = charset; } - void SetDocStyle(const char* style) { fDocStyle = style; } + void SetClassDocTag(const char* tag) { fDocSyntax.fClassDocTag = tag; } + void SetAuthorTag(const char* tag) { fDocSyntax.fAuthorTag = tag; } + void SetLastUpdateTag(const char* tag) { fDocSyntax.fLastUpdateTag = tag; } + void SetCopyrightTag(const char* tag) { fDocSyntax.fCopyrightTag = tag; } + void SetHeader(const char* file) { fOutputStyle.fHeader = file; } + void SetFooter(const char* file) { fOutputStyle.fFooter = file; } + void SetHomepage(const char* url) { fLinkInfo.fHomepage = url; } + void SetSearchStemURL(const char* url) { fLinkInfo.fSearchStemURL = url; } + void SetSearchEngine(const char* url) { fLinkInfo.fSearchEngine = url; } + void SetViewCVS(const char* url) { fLinkInfo.fViewCVS = url; } + void SetWikiURL(const char* url) { fLinkInfo.fWikiURL = url; } + void SetCharset(const char* charset) { fOutputStyle.fCharset = charset; } + void SetDocStyle(const char* style) { fDocSyntax.fDocStyle = style; } // Configuration getters + const TModuleDefinition& GetModuleDefinition() const; + const TFileDefinition& GetFileDefinition() const; + const TPathDefinition& GetPathDefinition() const; const TString& GetProductName() const { return fProductName; } + const TString& GetInputPath() const { return fPathInfo.fInputPath; } const TString& GetOutputDir(Bool_t createDir = kTRUE) const; - const TString& GetSourceDir() const { return fSourceDir; } - const TString& GetIncludePath() const { return fIncludePath; } - const TString& GetSourcePrefix() const { return fSourcePrefix; } virtual const char* GetEtcDir(); - const TString& GetModuleDocPath() const { return fModuleDocPath; } - const TString& GetProductDocDir() const { return fProductDocDir; } - const TString& GetDotDir() const { return fDotDir; } + const TString& GetModuleDocPath() const { return fPathInfo.fDocPath; } + const TString& GetDotDir() const { return fPathInfo.fDotDir; } const char* GetURL(const char* lib = 0) const; - const TString& GetXwho() const { return fXwho; } - const TString& GetMacroPath() const { return fMacroPath; } + const TString& GetXwho() const { return fLinkInfo.fXwho; } + const TString& GetMacroPath() const { return fPathInfo.fMacroPath; } const char* GetCounterFormat() const { return fCounterFormat; } - const TString& GetClassDocTag() const { return fClassDocTag; } - const TString& GetAuthorTag() const { return fAuthorTag; } - const TString& GetLastUpdateTag() const { return fLastUpdateTag; } - const TString& GetCopyrightTag() const { return fCopyrightTag; } - const TString& GetHeader() const { return fHeader; } - const TString& GetFooter() const { return fFooter; } - const TString& GetHomepage() const { return fHomepage; } - const TString& GetSearchStemURL() const { return fSearchStemURL; } - const TString& GetSearchEngine() const { return fSearchEngine; } - const TString& GetViewCVS() const { return fViewCVS; } - const TString& GetWikiURL() const { return fWikiURL; } - const TString& GetCharset() const { return fCharset; } - const TString& GetDocStyle() const { return fDocStyle; } + const TString& GetClassDocTag() const { return fDocSyntax.fClassDocTag; } + const TString& GetAuthorTag() const { return fDocSyntax.fAuthorTag; } + const TString& GetLastUpdateTag() const { return fDocSyntax.fLastUpdateTag; } + const TString& GetCopyrightTag() const { return fDocSyntax.fCopyrightTag; } + const TString& GetHeader() const { return fOutputStyle.fHeader; } + const TString& GetFooter() const { return fOutputStyle.fFooter; } + const TString& GetHomepage() const { return fLinkInfo.fHomepage; } + const TString& GetSearchStemURL() const { return fLinkInfo.fSearchStemURL; } + const TString& GetSearchEngine() const { return fLinkInfo.fSearchEngine; } + const TString& GetViewCVS() const { return fLinkInfo.fViewCVS; } + const TString& GetWikiURL() const { return fLinkInfo.fWikiURL; } + const TString& GetCharset() const { return fOutputStyle.fCharset; } + const TString& GetDocStyle() const { return fDocSyntax.fDocStyle; } // Functions that should only be used by TDocOutput etc. Bool_t CopyFileFromEtcDir(const char* filename) const; virtual void CreateAuxiliaryFiles() const; virtual TClass* GetClass(const char *name) const; const char* GetCounter() const { return fCounter; } - virtual const char* GetDeclFileName(TClass* cl) const; + void GetModuleMacroPath(const TString& module, TString& out_path) const { GetPathDefinition().GetMacroPath(module, out_path); } + virtual bool GetDeclFileName(TClass* cl, Bool_t filesys, TString& out_name) const; void GetDerivedClasses(TClass* cl, std::map<TClass*, Int_t>& derived) const; - virtual const char* GetImplFileName(TClass* cl) const; - virtual const char* GetFileName(const char *filename) const; - virtual void GetSourceFileName(TString& filename); + static const char* GetDirDelimiter() { + // ";" on windows, ":" everywhere else +#ifdef R__WIN32 + return ";"; +#else + return ":"; +#endif + } + virtual bool GetImplFileName(TClass* cl, Bool_t filesys, TString& out_name) const; virtual void GetHtmlFileName(TClass *classPtr, TString& filename) const; virtual const char* GetHtmlFileName(const char* classname) const; - TCollection* GetLibraryDependencies() { return &fLibDeps; } - const TList* GetListOfModules() const { return &fModules; } - const TList* GetListOfClasses() const { return &fClasses; } + TList* GetLibraryDependencies() { return &fDocEntityInfo.fLibDeps; } + const TList* GetListOfModules() const { return &fDocEntityInfo.fModules; } + const TList* GetListOfClasses() const { return &fDocEntityInfo.fClasses; } + TFileSysDB* GetLocalFiles() const { if (!fLocalFiles) SetLocalFiles(); return fLocalFiles; } TVirtualMutex* GetMakeClassMutex() const { return fMakeClassMutex; } - virtual void GetModuleName(TString& module, const char* filename) const; virtual void GetModuleNameForClass(TString& module, TClass* cl) const; + const TPathInfo& GetPathInfo() const { return fPathInfo; } Bool_t HaveDot(); + void HelperDeleted(THelperBase* who); static Bool_t IsNamespace(const TClass*cl); void SetDeclFileName(TClass* cl, const char* filename); - void SetFoundDot(Bool_t found = kTRUE) { fFoundDot = found; } + void SetFoundDot(Bool_t found = kTRUE); void SetImplFileName(TClass* cl, const char* filename); // unused @@ -193,6 +314,68 @@ public: "Removed, call TDocOutput::ReplaceSpecialChars() instead!"); } void SetEscape(char /*esc*/ ='\\') {} // for backward comp +protected: + struct TDocSyntax { + TString fClassDocTag; // tag for class documentation + TString fAuthorTag; // tag for author + TString fLastUpdateTag; // tag for last update + TString fCopyrightTag; // tag for copyright + TString fDocStyle; // doc style (only "Doc++" has special treatment) + }; + + struct TLinkInfo { + TString fXwho; // URL for name lookup + TString fROOTURL; // Root URL for ROOT's reference guide for libs that are not in fLibURLs + std::map<std::string, TString> fLibURLs; // URL for documentation of external libraries + TString fHomepage; // URL of homepage + TString fSearchStemURL; // URL stem used to build search URL + TString fSearchEngine; // link to search engine + TString fViewCVS; // link to ViewCVS; %f is replaced by the filename (no %f: it's appended) + TString fWikiURL; // URL stem of class's wiki page, %c replaced by mangled class name (no %c: appended) + }; + + struct TOutputStyle { + TString fHeader; // header file name + TString fFooter; // footerer file name + TString fCharset; // Charset for doc pages + }; + + struct TDocEntityInfo { + TString fClassFilter; // filter used for buidling known classes + THashList fClasses; // known classes + THashList fModules; // known modules + THashList fLibDeps; // Library dependencies + }; + +protected: + virtual void CreateJavascript() const; + virtual void CreateStyleSheet() const; + void CreateListOfTypes(); + void CreateListOfClasses(const char* filter); + virtual bool GetDeclImplFileName(TClass* cl, bool filesys, bool decl, TString& out_name) const; + void MakeClass(void* cdi, Bool_t force=kFALSE); + TClassDocInfo *GetNextClass(); + void SetLocalFiles() const; + + static void *MakeClassThreaded(void* info); + +protected: + TString fCounter; // counter string + TString fCounterFormat; // counter printf-like format + TString fProductName; // name of the product to document + TIter *fThreadedClassIter; // fClasses iterator for MakeClassThreaded + Int_t fThreadedClassCount; // counter of processed classes for MakeClassThreaded + TVirtualMutex *fMakeClassMutex; // Mutex for MakeClassThreaded + TDocSyntax fDocSyntax; // doc syntax configuration + TLinkInfo fLinkInfo; // link (URL) configuration + TOutputStyle fOutputStyle; // output style configuration + TPathInfo fPathInfo; // path configuration + TDocEntityInfo fDocEntityInfo; // data for documented entities + mutable TPathDefinition *fPathDef; // object translating classes to module names + mutable TModuleDefinition *fModuleDef; // object translating classes to module names + mutable TFileDefinition* fFileDef; // object translating classes to file names + mutable TFileSysDB *fLocalFiles; // files found locally for a given source path + ClassDef(THtml,0) //Convert class(es) into HTML file(s) }; diff --git a/html/src/TClassDocOutput.cxx b/html/src/TClassDocOutput.cxx index 42bdd8fdedfa7020ee5122a7ad336420db0e899f..f95b7157166166722e185b611124c5c276195790 100644 --- a/html/src/TClassDocOutput.cxx +++ b/html/src/TClassDocOutput.cxx @@ -97,9 +97,8 @@ void TClassDocOutput::Class2Html(Bool_t force) WriteClassDocHeader(classFile); // copy .h file to the Html output directory - TString declf(fHtml->GetDeclFileName(fCurrentClass)); - fHtml->GetSourceFileName(declf); - if (declf.Length()) + TString declf; + if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, declf)) CopyHtmlFile(declf); // process a '.cxx' file @@ -124,11 +123,13 @@ void TClassDocOutput::ListFunctions(std::ostream& classFile) << ":Function_Members\"></a>Function Members (Methods)</h2>" << endl; const char* tab4nbsp=" "; + TString declFile; + fHtml->GetDeclFileName(fCurrentClass, kFALSE, declFile); if (fCurrentClass->Property() & kIsAbstract) classFile << " <br /><b>" << tab4nbsp << "This is an abstract class, constructors will not be documented.<br />" << endl << tab4nbsp << "Look at the <a href=\"" - << fHtml->GetFileName(fHtml->GetDeclFileName(fCurrentClass)) + << gSystem->BaseName(declFile) << "\">header</a> to check for available constructors.</b><br />" << endl; for (Int_t access = TDocParser::kPublic; access >= 0 && !fHtml->IsNamespace(fCurrentClass); --access) { @@ -194,6 +195,29 @@ void TClassDocOutput::ListFunctions(std::ostream& classFile) classFile << "</a>"; fParser->DecorateKeywords(classFile, const_cast<TMethod*>(method)->GetSignature()); + bool propSignal = false; + bool propMenu = false; + bool propToggle = false; + bool propGetter = false; + if (method->GetTitle()) { + propSignal = (strstr(method->GetTitle(), "*SIGNAL*")); + propMenu = (strstr(method->GetTitle(), "*MENU*")); + propToggle = (strstr(method->GetTitle(), "*TOGGLE*")); + propGetter = (strstr(method->GetTitle(), "*GETTER")); + if (propSignal || propMenu || propToggle || propGetter) { + classFile << "<span class=\"funcprop\">"; + if (propSignal) classFile << "<abbr title=\"emits a signal\"/>SIGNAL</abbr> "; + if (propMenu) classFile << "<abbr title=\"has a popup menu entry\"/>MENU</abbr> "; + if (propToggle) classFile << "<abbr title=\"toggles a state\"/>TOGGLE</abbr> "; + if (propGetter) { + TString getter(method->GetTitle()); + Ssiz_t posGetter = getter.Index("*GETTER="); + getter.Remove(0, posGetter + 8); + classFile << "<abbr title=\"use " + getter + "() as getter\"/>GETTER</abbr> "; + } + classFile << "</span>"; + } + } classFile << "</td></tr>" << endl; } classFile << endl << "</table></div>" << endl; @@ -715,75 +739,85 @@ Bool_t TClassDocOutput::CreateDotClassChartInhMem(const char* filename) { //Bool_t haveMembers = (cl->GetListOfDataMembers() && cl->GetListOfDataMembers()->GetSize()); Bool_t haveFuncs = cl->GetListOfMethods() && cl->GetListOfMethods()->GetSize(); - // make sure each member name is listed only once - // that's useless for data members, but symmetric to what we have for methods - std::map<std::string, TDataMember*> dmMap; - TIter iDM(cl->GetListOfDataMembers()); - TDataMember* dm = 0; - while ((dm = (TDataMember*) iDM())) - dmMap[dm->GetName()] = dm; - - outdot << "subgraph \"clusterData0" << cl->GetName() << "\" {" << endl - << " color=white;" << endl - << " label=\"\";" << endl - << " \"clusterNode0" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; - TString prevColumnNode; - Int_t pos = dmMap.size(); - Int_t column = 0; - Int_t newColumnEvery = (pos + numColumns - 1) / numColumns; - for (std::map<std::string, TDataMember*>::iterator iDM = dmMap.begin(); - iDM != dmMap.end(); ++iDM, --pos) { - TDataMember* dm = iDM->second; - TString nodeName(cl->GetName()); - nodeName += "::"; - nodeName += dm->GetName(); - if (iDM == dmMap.begin()) - prevColumnNode = nodeName; - - outdot << "\"" << nodeName << "\" [label=\"" - << dm->GetName() << "\""; - if (dm->Property() & kIsPrivate) - outdot << ",color=\"#FFCCCC\""; - else if (dm->Property() & kIsProtected) - outdot << ",color=\"#FFFF77\""; - else - outdot << ",color=\"#CCFFCC\""; - outdot << "];" << endl; - if (pos % newColumnEvery == 1) { - ++column; - outdot << "};" << endl // end dataR - << "subgraph \"clusterData" << column << cl->GetName() << "\" {" << endl - << " color=white;" << endl - << " label=\"\";" << endl - << " \"clusterNode" << column << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; - } else if (iDM != dmMap.begin() && pos % newColumnEvery == 0) { - ssDep << "\"" << prevColumnNode - << "\" -> \"" << nodeName << "\""<< " [style=invis,weight=100];" << endl; - prevColumnNode = nodeName; + // DATA MEMBERS + { + // make sure each member name is listed only once + // that's useless for data members, but symmetric to what we have for methods + std::map<std::string, TDataMember*> dmMap; + + { + TIter iDM(cl->GetListOfDataMembers()); + TDataMember* dm = 0; + while ((dm = (TDataMember*) iDM())) + dmMap[dm->GetName()] = dm; } - } - while (column < numColumns - 1) { - ++column; - outdot << " \"clusterNode" << column << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; - } + outdot << "subgraph \"clusterData0" << cl->GetName() << "\" {" << endl + << " color=white;" << endl + << " label=\"\";" << endl + << " \"clusterNode0" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; + TString prevColumnNode; + Int_t pos = dmMap.size(); + Int_t column = 0; + Int_t newColumnEvery = (pos + numColumns - 1) / numColumns; + for (std::map<std::string, TDataMember*>::iterator iDM = dmMap.begin(); + iDM != dmMap.end(); ++iDM, --pos) { + TDataMember* dm = iDM->second; + TString nodeName(cl->GetName()); + nodeName += "::"; + nodeName += dm->GetName(); + if (iDM == dmMap.begin()) + prevColumnNode = nodeName; + + outdot << "\"" << nodeName << "\" [label=\"" + << dm->GetName() << "\""; + if (dm->Property() & kIsPrivate) + outdot << ",color=\"#FFCCCC\""; + else if (dm->Property() & kIsProtected) + outdot << ",color=\"#FFFF77\""; + else + outdot << ",color=\"#CCFFCC\""; + outdot << "];" << endl; + if (pos % newColumnEvery == 1) { + ++column; + outdot << "};" << endl // end dataR + << "subgraph \"clusterData" << column << cl->GetName() << "\" {" << endl + << " color=white;" << endl + << " label=\"\";" << endl + << " \"clusterNode" << column << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; + } else if (iDM != dmMap.begin() && pos % newColumnEvery == 0) { + ssDep << "\"" << prevColumnNode + << "\" -> \"" << nodeName << "\""<< " [style=invis,weight=100];" << endl; + prevColumnNode = nodeName; + } + } + + while (column < numColumns - 1) { + ++column; + outdot << " \"clusterNode" << column << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; + } - outdot << "};" << endl; // subgraph dataL/R + outdot << "};" << endl; // subgraph dataL/R + } // DATA MEMBERS + // FUNCTION MEMBERS if (haveFuncs) { // make sure each member name is listed only once std::map<std::string, TMethod*> methMap; - TIter iMeth(cl->GetListOfMethods()); - TMethod* meth = 0; - while ((meth = (TMethod*) iMeth())) - methMap[meth->GetName()] = meth; + + { + TIter iMeth(cl->GetListOfMethods()); + TMethod* meth = 0; + while ((meth = (TMethod*) iMeth())) + methMap[meth->GetName()] = meth; + } outdot << "subgraph \"clusterFunc0" << cl->GetName() << "\" {" << endl << " color=white;" << endl << " label=\"\";" << endl << " \"clusterNode0" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl; - TString prevColumnNode; + TString prevColumnNodeFunc; Int_t pos = methMap.size(); Int_t column = 0; Int_t newColumnEvery = (pos + numColumns - 1) / numColumns; @@ -794,7 +828,7 @@ Bool_t TClassDocOutput::CreateDotClassChartInhMem(const char* filename) { nodeName += "::"; nodeName += meth->GetName(); if (iMeth == methMap.begin()) - prevColumnNode = nodeName; + prevColumnNodeFunc = nodeName; outdot << "\"" << nodeName << "\" [label=\"" << meth->GetName() << "\""; if (cl != fCurrentClass && @@ -814,9 +848,9 @@ Bool_t TClassDocOutput::CreateDotClassChartInhMem(const char* filename) { << " color=white;" << endl << " label=\"\";" << endl; } else if (iMeth != methMap.begin() && pos % newColumnEvery == 0) { - ssDep << "\"" << prevColumnNode + ssDep << "\"" << prevColumnNodeFunc << "\" -> \"" << nodeName << "\""<< " [style=invis,weight=100];" << endl; - prevColumnNode = nodeName; + prevColumnNodeFunc = nodeName; } } outdot << "};" << endl; // subgraph funcL/R @@ -860,19 +894,19 @@ Bool_t TClassDocOutput::CreateDotClassChartIncl(const char* filename) { std::map<std::string, std::string> filesToParse; std::list<std::string> listFilesToParse; - const char* declFileName = fHtml->GetDeclFileName(fCurrentClass); - const char* implFileName = fHtml->GetImplFileName(fCurrentClass); - if (declFileName && strlen(declFileName)) { - char* real = gSystem->Which(fHtml->GetSourceDir(), declFileName, kReadPermission); - if (real) { - filesToParse[declFileName] = real; - listFilesToParse.push_back(declFileName); - delete [] real; + TString declFileName; + TString implFileName; + fHtml->GetImplFileName(fCurrentClass, kFALSE, implFileName); + if (fHtml->GetDeclFileName(fCurrentClass, kFALSE, declFileName)) { + TString real; + if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, real)) { + filesToParse[declFileName.Data()] = real.Data(); + listFilesToParse.push_back(declFileName.Data()); } } /* do it only for the header if (implFileName && strlen(implFileName)) { - char* real = gSystem->Which(fHtml->GetSourceDir(), implFileName, kReadPermission); + char* real = gSystem->Which(fHtml->GetInputPath(), implFileName, kReadPermission); if (real) { filesToParse[implFileName] = real; listFilesToParse.push_back(implFileName); @@ -916,12 +950,12 @@ Bool_t TClassDocOutput::CreateDotClassChartIncl(const char* filename) { if (pos == std::string::npos) continue; line.erase(pos); if (filesToParse.find(line) == filesToParse.end()) { - char* filename = gSystem->Which(fHtml->GetSourceDir(), line.c_str(), kReadPermission); - if (!filename) continue; + TString sysfilename; + if (!GetHtml()->GetPathDefinition().GetFileNameFromInclude(line.c_str(), sysfilename)) + continue; listFilesToParse.push_back(line); - filesToParse[line] = filename; - delete [] filename; - if (*iFile == implFileName || *iFile == declFileName) + filesToParse[line] = sysfilename; + if (*iFile == implFileName.Data() || *iFile == declFileName.Data()) outdot << "\"" << *iFile << "\" [style=filled,fillcolor=lightgray];" << endl; } outdot << "\"" << *iFile << "\" -> \"" << line << "\";" << endl; @@ -961,9 +995,13 @@ Bool_t TClassDocOutput::CreateDotClassChartLib(const char* filename) { firstLib.Remove(end, firstLib.Length()); libs.Remove(0, end + 1); } else libs = ""; - Ssiz_t posExt = firstLib.First("."); - if (posExt != kNPOS) - firstLib.Remove(posExt, firstLib.Length()); + + { + Ssiz_t posExt = firstLib.First("."); + if (posExt != kNPOS) + firstLib.Remove(posExt, firstLib.Length()); + } + outdot << "\"All Libraries\" -> \"" << firstLib << "\" [style=invis];" << endl; outdot << "\"" << firstLib << "\" -> {" << endl; @@ -1373,28 +1411,7 @@ void TClassDocOutput::WriteClassDocHeader(std::ostream& classFile) TString sInclude; TString sLib; const char* lib=fCurrentClass->GetSharedLibs(); - const char* incl=fHtml->GetDeclFileName(fCurrentClass); - if (incl) { - TString inclPath(GetHtml()->GetIncludePath()); - Ssiz_t posDelim = 0; - TString inclDir; - TString sIncl(incl); -#ifdef R__WIN32 - const char* pdelim = ";"; - static const char ddelim = '\\'; -#else - const char* pdelim = ":"; - static const char ddelim = '/'; -#endif - while (inclPath.Tokenize(inclDir, posDelim, pdelim)) - if (sIncl.BeginsWith(inclDir)) { - incl += inclDir.Length(); - if (incl[0] == ddelim || incl[0] == '/') - ++incl; - break; - } - sInclude = incl; - } + GetHtml()->GetPathDefinition().GetIncludeAs(fCurrentClass, sInclude); if (lib) { char* libDup=StrDup(lib); char* libDupSpace=strchr(libDup,' '); @@ -1411,40 +1428,10 @@ void TClassDocOutput::WriteClassDocHeader(std::ostream& classFile) classFile << "<script type=\"text/javascript\">WriteFollowPageBox('" << sTitle << "','" << sLib << "','" << sInclude << "');</script>" << endl; - // top links - classFile << "<div id=\"toplinks\">" << endl; - - // make a link to the description - TString currClassNameMangled(fCurrentClass->GetName()); - NameSpace2FileName(currClassNameMangled); - classFile << "<div class=\"descrhead\">" << endl - << "<span class=\"descrtitle\">Location:</span>" << endl; - const char *productName = fHtml->GetProductName(); - classFile << "<a class=\"descrheadentry\" href=\"ClassIndex.html\">" << productName << "</a> » " << endl; - - TString module; - fHtml->GetModuleNameForClass(module, fCurrentClass); - if (module.Length()) - classFile << "<a class=\"descrheadentry\" href=\"./" << module << "_Index.html\">" << module << "</a> » " << endl; - - classFile << "<a class=\"descrheadentry\" href=\"#TopOfPage\">"; - ReplaceSpecialChars(classFile, fCurrentClass->GetName()); - classFile << "</a>" << endl - << "</div>" << endl; - - classFile << "<div class=\"descrhead\">" << endl - << "<span class=\"descrtitle\">Quick Links:</span>" << endl; - - // link to the user home page (if exist) - const char* userHomePage = GetHtml()->GetHomepage(); - if (productName && !strcmp(productName, "ROOT")) - userHomePage = ""; - if (userHomePage && *userHomePage) - classFile << "<a class=\"descrheadentry\" href=\"" << userHomePage << "\">" << productName << "</a>" << endl; - classFile << "<a class=\"descrheadentry\" href=\"http://root.cern.ch/root/Welcome.html\">ROOT</a>" << endl - << "<a class=\"descrheadentry\" href=\"./ClassIndex.html\">Class Index</a>" << endl - << "<a class=\"descrheadentry\" href=\"./ClassHierarchy.html\">Class Hierarchy</a>" << endl - << "</div>" << endl; + TString modulename; + fHtml->GetModuleNameForClass(modulename, fCurrentClass); + TModuleDocInfo* module = (TModuleDocInfo*) fHtml->GetListOfModules()->FindObject(modulename); + WriteTopLinks(classFile, module, fCurrentClass->GetName()); classFile << "<div class=\"descrhead\">" << endl << "<span class=\"descrtitle\">Source:</span>" << endl; @@ -1453,18 +1440,15 @@ void TClassDocOutput::WriteClassDocHeader(std::ostream& classFile) TString classFileName(fCurrentClass->GetName()); NameSpace2FileName(classFileName); - const char* headerFileName = fHtml->GetDeclFileName(fCurrentClass); - if (headerFileName && !headerFileName[0]) - headerFileName = 0; - const char* sourceFileName = fHtml->GetImplFileName(fCurrentClass); - if (sourceFileName && !sourceFileName[0]) - sourceFileName = 0; - - if (headerFileName) + TString headerFileName; + fHtml->GetDeclFileName(fCurrentClass, kFALSE, headerFileName); + TString sourceFileName; + fHtml->GetImplFileName(fCurrentClass, kFALSE, sourceFileName); + if (headerFileName.Length()) classFile << "<a class=\"descrheadentry\" href=\"src/" << classFileName << ".h.html\">header file</a>" << endl; - if (sourceFileName) + if (sourceFileName.Length()) classFile << "<a class=\"descrheadentry\" href=\"src/" << classFileName << ".cxx.html\">source file</a>" << endl; @@ -1517,6 +1501,9 @@ void TClassDocOutput::WriteClassDocHeader(std::ostream& classFile) } } + TString currClassNameMangled(fCurrentClass->GetName()); + NameSpace2FileName(currClassNameMangled); + TString wikiLink = GetHtml()->GetWikiURL(); if (wikiLink.Length()) { if (wikiLink.Contains("%c")) wikiLink.ReplaceAll("%c", currClassNameMangled); diff --git a/html/src/TDocDirective.cxx b/html/src/TDocDirective.cxx index f018ccf652cffbf90d261b9ccf5ee6f9c339d3f3..874c4c063b98c3517eb716d5e896574cbe45bf15 100644 --- a/html/src/TDocDirective.cxx +++ b/html/src/TDocDirective.cxx @@ -43,6 +43,25 @@ ClassImp(TDocDirective); +//______________________________________________________________________________ +void TDocDirective::DeleteOutputFiles(const char* ext) const +{ + // Delete all output generated by the directive beginning + // with Name() and ending with ext + TString basename; + GetName(basename); + basename += "_"; + TString dirname(GetOutputDir()); + void* hDir = gSystem->OpenDirectory(dirname); + const char* entry = 0; + while ((entry = gSystem->GetDirEntry(hDir))) { + TString sEntry(entry); + if (sEntry.BeginsWith(basename) && isdigit(sEntry[basename.Length()]) && (!ext || sEntry.EndsWith(ext))) + gSystem->Unlink((dirname + "/" + entry).Data()); + } + gSystem->FreeDirectory(hDir); +} + //______________________________________________________________________________ void TDocDirective::GetName(TString& name) const { @@ -51,7 +70,12 @@ void TDocDirective::GetName(TString& name) const name = fName; if (fDocParser && fDocParser->GetCurrentClass()) { name += "_"; - name += fDocParser->GetCurrentClass()->GetName(); + TString outfilename; + GetHtml()->GetHtmlFileName(fDocParser->GetCurrentClass(), outfilename); + outfilename = gSystem->BaseName(outfilename); + Ssiz_t posExt = outfilename.Last('.'); + outfilename.Remove(posExt, outfilename.Length() - posExt); + name += outfilename; } if (GetTitle() && strlen(GetTitle())) { name += "_"; @@ -245,7 +269,6 @@ void TDocMacroDirective::AddLine(const TSubString& line) fMacro->AddLine(sLine); fIsFilename &= !sLine.Contains('{'); } - //______________________________________________________________________________ Bool_t TDocMacroDirective::GetResult(TString& result) { @@ -286,17 +309,17 @@ Bool_t TDocMacroDirective::GetResult(TString& result) while (filename.Length() == 0) filename = ((TObjString*)iLine())->String().Strip(TString::kBoth); - TString pwd; - if (GetHtml() && GetDocParser() && GetDocParser()->GetCurrentClass()) { - TString modulename; - GetHtml()->GetModuleNameForClass(modulename, GetDocParser()->GetCurrentClass()); - TModuleDocInfo* module = 0; - if (modulename.Length() - && (module = (TModuleDocInfo*)GetHtml()->GetListOfModules()->FindObject(modulename))) - pwd = module->GetSourceDir(); - else pwd = gSystem->pwd(); - } else pwd = gSystem->pwd(); - TString macroPath(GetHtml()->GetMacroPath()); + TString macroPath; + TString modulename; + if (GetHtml() && GetDocParser()) { + if (GetDocParser()->GetCurrentClass()) + GetHtml()->GetModuleNameForClass(modulename, GetDocParser()->GetCurrentClass()); + else GetDocParser()->GetCurrentModule(modulename); + } + if (modulename.Length()) { + GetHtml()->GetModuleMacroPath(modulename, macroPath); + } else macroPath = gSystem->pwd(); + const char* pathDelimiter = ":"; // use ":" even on windows TObjArray* arrDirs(macroPath.Tokenize(pathDelimiter)); TIter iDir(arrDirs); @@ -305,8 +328,8 @@ Bool_t TDocMacroDirective::GetResult(TString& result) TString filenameDirPart(gSystem->DirName(filename)); filenameDirPart.Prepend('/'); // as dir delimiter, not as root dir while ((osDir = (TObjString*)iDir())) { - if (!gSystem->IsAbsoluteFileName(osDir->String())) - gSystem->PrependPathName(pwd, osDir->String()); + if (osDir->String().EndsWith("\\")) + osDir->String().Remove(osDir->String().Length() - 1); osDir->String() += filenameDirPart; macroPath += osDir->String() + pathDelimiter; } @@ -618,7 +641,7 @@ void TDocLatexDirective::CreateLatex(const char* filename) latex.SetTextAlign(12); // calculate positions - TIter iLine(fLatex->GetListOfLines()); + TIter iterLine(fLatex->GetListOfLines()); TObjString* line = 0; TPRegexp regexp; if (fSeparator.Length()) { @@ -626,7 +649,7 @@ void TDocLatexDirective::CreateLatex(const char* filename) regexp = TPRegexp(fSeparator); } else fSepIsRegexp = kFALSE; - while ((line = (TObjString*) iLine())) { + while ((line = (TObjString*) iterLine())) { const TString& str = line->String(); TObjArray* split = 0; if (!fSepIsRegexp) { diff --git a/html/src/TDocInfo.cxx b/html/src/TDocInfo.cxx index 660550de99029d8f547bd4f342c6441712bec06d..91ad5cfe7d3dfd533a91d145fc587ead9feff261 100644 --- a/html/src/TDocInfo.cxx +++ b/html/src/TDocInfo.cxx @@ -52,7 +52,7 @@ Int_t TClassDocInfo::Compare(const TObject* obj) const // which is documented <a href="./HTML_index.html">here</a>. The list of // all modules is shown e.g. in the <a href="ClassIndex.html">class index</a>.</p> // <p>A module's documentation is searched by combining its source directory -// (see <a href="#TModuleDocInfo:SetSourceDir">SetSourceDir()</a>) and the +// (see <a href="#TModuleDocInfo:SetInputDir">SetInputDir()</a>) and the // module documentation search path defined by // <a href="./THtml.html#THtml:SetModuleDocPath">THtml::SetModuleDocPath()</a>; // it defaults to "../doc", i.e. for a module's sources in "module/src" its @@ -62,11 +62,3 @@ Int_t TClassDocInfo::Compare(const TObject* obj) const ClassImp(TModuleDocInfo); - -void TModuleDocInfo::SetSourceDir(const char* dir) -{ - // Set the module's source directory. It serves as part of - // the search path for the module documentation. - fSourceDir = dir; - gSystem->ExpandPathName(fSourceDir); -} diff --git a/html/src/TDocOutput.cxx b/html/src/TDocOutput.cxx index f213851a061d90a019c953a05e87e9d5273f116f..182c903843ec8103a4bfbe3c77e542a79b4700a6 100644 --- a/html/src/TDocOutput.cxx +++ b/html/src/TDocOutput.cxx @@ -173,8 +173,7 @@ namespace { } - -namespace { +extern "C" { // std::qsort on solaris wants the sorter to be extern "C" //______________________________________________________________________________ static int CaseInsensitiveSort(const void *name1, const void *name2) @@ -194,6 +193,9 @@ namespace { return (strcasecmp(*((char **) name1), *((char **) name2))); } +} + +namespace { // std::list::sort(with_stricmp_predicate) doesn't work with Solaris CC... static void sort_strlist_stricmp(std::list<std::string>& l) @@ -333,7 +335,7 @@ Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName) // Copy file to HTML directory // // -// Input: sourceName - source file name +// Input: sourceName - source file name (fully qualified i.e. file system path) // destName - optional destination name, if not // specified it would be the same // as the source file name @@ -347,16 +349,7 @@ Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName) R__LOCKGUARD(GetHtml()->GetMakeClassMutex()); - // source file name - char *tmp1 = gSystem->Which(fHtml->GetSourceDir(), sourceName, kReadPermission); - if (!tmp1) { - Error("Copy", "Can't copy file '%s' to '%s/%s' - can't find source file!", sourceName, - fHtml->GetOutputDir().Data(), destName); - return kFALSE; - } - - TString sourceFile(tmp1); - delete[]tmp1; + TString sourceFile(sourceName); if (!sourceFile.Length()) { Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName, @@ -367,9 +360,9 @@ Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName) // destination file name TString destFile; if (!destName || !*destName) - destFile = fHtml->GetFileName(sourceFile); + destFile = gSystem->BaseName(sourceFile); else - destFile = fHtml->GetFileName(destName); + destFile = gSystem->BaseName(destName); gSystem->PrependPathName(fHtml->GetOutputDir(), destFile); @@ -414,9 +407,12 @@ void TDocOutput::CreateHierarchy() // write out header WriteHtmlHeader(out, "Class Hierarchy"); + + WriteTopLinks(out, 0); + out << "</div></div>" << endl; + out << "<h1>Class Hierarchy</h1>" << endl; - WriteSearch(out); // loop on all classes TClassDocInfo* cdi = 0; @@ -465,7 +461,10 @@ void TDocOutput::CreateClassIndex() // write indexFile header WriteHtmlHeader(indexFile, "Class Index"); - indexFile << "<h1>Index</h1>" << endl; + WriteTopLinks(indexFile, 0); + indexFile << "</div></div>" << endl; + + indexFile << "<h1>Class Index</h1>" << endl; WriteModuleLinks(indexFile); @@ -493,8 +492,6 @@ void TDocOutput::CreateClassIndex() } } - WriteSearch(indexFile); - indexFile << "<ul id=\"indx\">" << endl; // loop on all classes @@ -548,15 +545,15 @@ void TDocOutput::CreateClassIndex() void TDocOutput::CreateModuleIndex() { // Create the class index for each module, picking up documentation from the - // module's TModuleDocInfo::GetSourceDir() plus the (possibly relative) + // module's TModuleDocInfo::GetInputPath() plus the (possibly relative) // THtml::GetModuleDocPath(). Also creates the library dependency plot if dot // exists, see THtml::HaveDot(). const char* title = "LibraryDependencies"; - TString filename(title); - gSystem->PrependPathName(fHtml->GetOutputDir(), filename); + TString dotfilename(title); + gSystem->PrependPathName(fHtml->GetOutputDir(), dotfilename); - std::ofstream libDepDotFile(filename + ".dot"); + std::ofstream libDepDotFile(dotfilename + ".dot"); libDepDotFile << "digraph G {" << endl << "ratio=compress;" << endl << "node [fontsize=22,labeldistance=0.1];" << endl @@ -568,29 +565,36 @@ void TDocOutput::CreateModuleIndex() << "K=0.1;" << endl; TModuleDocInfo* module = 0; - TIter iModule(fHtml->GetListOfModules()); + TIter iterModule(fHtml->GetListOfModules()); std::stringstream sstrCluster; std::stringstream sstrDeps; - while ((module = (TModuleDocInfo*)iModule())) { + while ((module = (TModuleDocInfo*)iterModule())) { if (!module->IsSelected()) continue; std::vector<std::string> indexChars; TString filename(module->GetName()); + filename.ToUpper(); + filename.ReplaceAll("/","_"); filename += "_Index.html"; gSystem->PrependPathName(fHtml->GetOutputDir(), filename); std::ofstream outputFile(filename.Data()); if (!outputFile.good()) { - Error("MakeIndex", "Can't open file '%s' !", filename.Data()); + Error("CreateModuleIndex", "Can't open file '%s' !", filename.Data()); continue; } Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data()); TString htmltitle("Index of "); - htmltitle += module->GetName(); - htmltitle += " classes"; + TString moduletitle(module->GetName()); + moduletitle.ToUpper(); + htmltitle += moduletitle; WriteHtmlHeader(outputFile, htmltitle); + + WriteTopLinks(outputFile, module); + outputFile << "</div></div>" << endl; + outputFile << "<h2>" << htmltitle << "</h2>" << endl; // Module doc @@ -598,12 +602,13 @@ void TDocOutput::CreateModuleIndex() TString outdir(module->GetName()); gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir); - TString moduleDocDir(GetHtml()->GetModuleDocPath()); - if (!gSystem->IsAbsoluteFileName(moduleDocDir)) - gSystem->PrependPathName(module->GetSourceDir(), moduleDocDir); + TString moduleDocDir; + GetHtml()->GetPathDefinition().GetDocDir(module->GetName(), moduleDocDir); ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName()); } + WriteModuleLinks(outputFile, module); + std::list<std::string> classNames; { TIter iClass(module->GetClasses()); @@ -620,9 +625,12 @@ void TDocOutput::CreateModuleIndex() TString thisLib(libs); if (posDepLibs != kNPOS) thisLib.Remove(posDepLibs, thisLib.Length()); - Ssiz_t posExt = thisLib.First('.'); - if (posExt != kNPOS) - thisLib.Remove(posExt, thisLib.Length()); + + { + Ssiz_t posExt = thisLib.First('.'); + if (posExt != kNPOS) + thisLib.Remove(posExt, thisLib.Length()); + } if (!thisLib.Length()) continue; @@ -659,22 +667,6 @@ void TDocOutput::CreateModuleIndex() } // while next class in module } // just a scope block - if (classNames.size() > 10) { - outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl; - UInt_t numSections = classNames.size() / 10; - if (numSections < 10) numSections = 10; - if (numSections > 50) numSections = 50; - // find index chars - GetIndexChars(classNames, numSections, indexChars); - for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) { - outputFile << "<a href=\"#idx" << iIdxEntry << "\">"; - ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str()); - outputFile << "</a>" << endl; - } - outputFile << "</div><br />" << endl; - } - outputFile << "<ul id=\"indx\">" << endl; - TIter iClass(module->GetClasses()); TClassDocInfo* cdi = 0; UInt_t count = 0; @@ -685,10 +677,31 @@ void TDocOutput::CreateModuleIndex() TClass *classPtr = cdi->GetClass(); if (!classPtr) { - Error("MakeIndex", "Unknown class '%s' !", cdi->GetName()); + Error("CreateModuleIndex", "Unknown class '%s' !", cdi->GetName()); continue; } + if (!count) { + outputFile << "<h2>Class Index</h2>" << endl; + + if (classNames.size() > 10) { + outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl; + UInt_t numSections = classNames.size() / 10; + if (numSections < 10) numSections = 10; + if (numSections > 50) numSections = 50; + // find index chars + GetIndexChars(classNames, numSections, indexChars); + for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) { + outputFile << "<a href=\"#idx" << iIdxEntry << "\">"; + ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str()); + outputFile << "</a>" << endl; + } + outputFile << "</div><br />" << endl; + } + + outputFile << "<ul id=\"indx\">" << endl; + } + // write a classname to an index file outputFile << "<li class=\"idxl" << (count++)%2 << "\">"; if (currentIndexEntry < indexChars.size() @@ -715,7 +728,8 @@ void TDocOutput::CreateModuleIndex() } - outputFile << "</ul>" << endl; + if (count) + outputFile << "</ul>" << endl; // write outputFile footer WriteHtmlFooter(outputFile); @@ -776,7 +790,6 @@ void TDocOutput::CreateModuleIndex() sstrCluster << "Everything depends on "; sstrCluster << libinfo->GetName() << "\";" << endl; - const std::set<std::string>& modules = libinfo->GetModules(); for (std::set<std::string>::const_iterator iModule = modules.begin(); iModule != modules.end(); ++iModule) { sstrCluster << "\"" << *iModule << "\" [style=filled,color=white,URL=\"" @@ -821,21 +834,23 @@ void TDocOutput::CreateModuleIndex() libDepDotFile << "}" << endl; libDepDotFile.close(); - std::ofstream out(filename + ".html"); + std::ofstream out(dotfilename + ".html"); if (!out.good()) { Error("CreateModuleIndex", "Can't open file '%s.html' !", - filename.Data()); + dotfilename.Data()); return; } - Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (filename + ".html").Data()); + Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (dotfilename + ".html").Data()); // write out header WriteHtmlHeader(out, "Library Dependencies"); - out << "<h1>Library Dependencies</h1>" << endl; - WriteSearch(out); + WriteTopLinks(out, 0); + out << "</div></div>" << endl; + + out << "<h1>Library Dependencies</h1>" << endl; - RunDot(filename, &out, kFdp); + RunDot(dotfilename, &out, kFdp); out << "<img alt=\"Library Dependencies\" class=\"classcharts\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl; @@ -863,10 +878,15 @@ void TDocOutput::CreateProductIndex() Printf(fHtml->GetCounterFormat(), "", "", outFile.Data()); WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide"); + + WriteTopLinks(out, 0); + out << "</div></div>" << endl; + out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl; - if (GetHtml()->GetProductDocDir().Length()) - ProcessDocInDir(out, GetHtml()->GetProductDocDir(), GetHtml()->GetOutputDir(), "./"); + TString prodDoc; + if (GetHtml()->GetPathDefinition().GetDocDir("", prodDoc)) + ProcessDocInDir(out, prodDoc, GetHtml()->GetOutputDir(), "./"); WriteModuleLinks(out); @@ -907,16 +927,20 @@ void TDocOutput::CreateTypeIndex() typesList << "<dl><dd>" << endl; // make loop on data types - TDataType *type; - TIter nextType(gROOT->GetListOfTypes()); - std::list<std::string> typeNames; - while ((type = (TDataType *) nextType())) - // no templates ('<' and '>'), no idea why the '(' is in here... - if (*type->GetTitle() && !strchr(type->GetName(), '(') - && !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>')) - && type->GetName()) + + { + TDataType *type; + TIter nextType(gROOT->GetListOfTypes()); + + while ((type = (TDataType *) nextType())) + // no templates ('<' and '>'), no idea why the '(' is in here... + if (*type->GetTitle() && !strchr(type->GetName(), '(') + && !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>')) + && type->GetName()) typeNames.push_back(type->GetName()); + } + sort_strlist_stricmp(typeNames); std::vector<std::string> indexChars; @@ -934,7 +958,6 @@ void TDocOutput::CreateTypeIndex() typesList << "<ul id=\"indx\">" << endl; - nextType.Reset(); int idx = 0; UInt_t currentIndexEntry = 0; @@ -1131,11 +1154,9 @@ Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type) switch (type) { case kSource: if (classPtr->GetImplFileLine()) { - sourceFile = fHtml->GetImplFileName(classPtr); - fHtml->GetSourceFileName(sourceFile); + fHtml->GetImplFileName(classPtr, kTRUE, sourceFile); } else { - sourceFile = fHtml->GetDeclFileName(classPtr); - fHtml->GetSourceFileName(sourceFile); + fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile); } dir = "src"; gSystem->PrependPathName(fHtml->GetOutputDir(), dir); @@ -1149,16 +1170,14 @@ Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type) break; case kInclude: - filename = fHtml->GetDeclFileName(classPtr); - sourceFile = filename; - fHtml->GetSourceFileName(sourceFile); - filename = fHtml->GetFileName(filename); + fHtml->GetDeclFileName(classPtr, kFALSE, filename); + filename = gSystem->BaseName(filename); + fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile); gSystem->PrependPathName(fHtml->GetOutputDir(), filename); break; case kTree: - sourceFile = fHtml->GetDeclFileName(classPtr); - fHtml->GetSourceFileName(sourceFile); + fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile); NameSpace2FileName(classname); gSystem->PrependPathName(fHtml->GetOutputDir(), classname); filename = classname; @@ -1167,11 +1186,9 @@ Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type) case kDoc: if (classPtr->GetImplFileLine()) { - sourceFile = fHtml->GetImplFileName(classPtr); - fHtml->GetSourceFileName(sourceFile); + fHtml->GetImplFileName(classPtr, kTRUE, sourceFile); } else { - sourceFile = fHtml->GetDeclFileName(classPtr); - fHtml->GetSourceFileName(sourceFile); + fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile); } filename = classname; NameSpace2FileName(filename); @@ -1277,13 +1294,13 @@ void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir, // convert first outfile.Remove(outfile.Length()-3, 3); outfile += "html"; - std::ifstream in(filename); - std::ofstream out(outfile); - if (in && out) { - out << "<pre>"; // this is what e.g. the html directive expects + std::ifstream inFurther(filename); + std::ofstream outFurther(outfile); + if (inFurther && outFurther) { + outFurther << "<pre>"; // this is what e.g. the html directive expects TDocParser parser(*this); - parser.Convert(out, in, "../"); - out << "</pre>"; + parser.Convert(outFurther, inFurther, "../"); + outFurther << "</pre>"; } } else { if (gSystem->CopyFile(filename, outfile, kTRUE) == -1) @@ -1631,6 +1648,11 @@ void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial, return; } + TString declFileName; + if (cls) fHtml->GetDeclFileName(cls, kFALSE, declFileName); + TString implFileName; + if (cls) fHtml->GetImplFileName(cls, kFALSE, implFileName); + const TString& charset = GetHtml()->GetCharset(); TDatime date; TString strDate(date.AsString()); @@ -1659,8 +1681,8 @@ void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial, if (cls) { txt.ReplaceAll("%CLASS%", cls->GetName()); - txt.ReplaceAll("%INCFILE%", fHtml->GetDeclFileName(cls)); - txt.ReplaceAll("%SRCFILE%", fHtml->GetImplFileName(cls)); + txt.ReplaceAll("%INCFILE%", declFileName); + txt.ReplaceAll("%SRCFILE%", implFileName); } out << txt << endl; @@ -1726,7 +1748,7 @@ void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/, // // Internal method invoked by the overload - static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%"}; + static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%", "%CHANGED%", "%GENERATED%"}; TString datimeString; if (!lastUpdate || !strlen(lastUpdate)) { @@ -1734,7 +1756,10 @@ void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/, datimeString = date.AsString(); lastUpdate = datimeString.Data(); } - const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright }; + TString today; + TDatime dtToday; + today.Form("%d-%02d-%02d %02d:%02d", dtToday.GetYear(), dtToday.GetMonth(), dtToday.GetDay(), dtToday.GetHour(), dtToday.GetMinute()); + const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright, lastUpdate, today }; ifstream addFooterFile(footer); @@ -1788,8 +1813,8 @@ void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir, // Allows optional user provided footer to be written. Root.Html.Footer holds // the file name for this footer. For details see THtml::WriteHtmlHeader (here, // the "+" means the user's footer is written in front of Root's!) Occurences -// of %AUTHOR%, %UPDATE%, and %COPYRIGHT% in the user's file are replaced by -// their corresponding values (author, lastUpdate, and copyright) before +// of %AUTHOR%, %CHANGED%, %GENERATED%, and %COPYRIGHT% in the user's file are replaced by +// their corresponding values (author, lastUpdate, today, and copyright) before // written to out. // If no author is set (author == "", e.g. for ClassIndex.html") skip the whole // line of the footer template containing %AUTHOR%. Accordingly for %COPYRIGHT%. @@ -1815,17 +1840,51 @@ void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir, //______________________________________________________________________________ void TDocOutput::WriteModuleLinks(std::ostream& out) { - // Create a dov containing links to all modules + // Create a dov containing links to all topmost modules if (fHtml->GetListOfModules()->GetSize()) { out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl; // find index chars TIter iModule(fHtml->GetListOfModules()); TModuleDocInfo* module = 0; - while ((module = (TModuleDocInfo*) iModule())) - if (module->IsSelected()) - out << "<a href=\"" << module->GetName() << "_Index.html\">" - << module->GetName() << "</a>" << endl; + while ((module = (TModuleDocInfo*) iModule())) { + if (!module->GetName() || strchr(module->GetName(), '/')) + continue; + if (module->IsSelected()) { + TString name(module->GetName()); + name.ToUpper(); + out << "<a href=\"" << name << "_Index.html\">" + << name << "</a>" << endl; + } + } + out<< "</div><br />" << endl; + } +} + +//______________________________________________________________________________ +void TDocOutput::WriteModuleLinks(std::ostream& out, TModuleDocInfo* super) +{ + // Create a dov containing links to all modules + + if (super->GetSub().GetSize()) { + TString superName(super->GetName()); + superName.ToUpper(); + out << "<div id=\"indxModules\"><h4>" << superName << " Modules</h4>" << endl; + // find index chars + TIter iModule(&super->GetSub()); + TModuleDocInfo* module = 0; + while ((module = (TModuleDocInfo*) iModule())) { + if (module->IsSelected()) { + TString name(module->GetName()); + name.ToUpper(); + TString link(name); + link.ReplaceAll("/", "_"); + Ssiz_t posSlash = name.Last('/'); + if (posSlash != kNPOS) + name.Remove(0, posSlash + 1); + out << "<a href=\"" << link << "_Index.html\">" << name << "</a>" << endl; + } + } out<< "</div><br />" << endl; } } @@ -1836,8 +1895,13 @@ void TDocOutput::WriteSearch(std::ostream& out) // Write a search link or a search box, based on THtml::GetSearchStemURL() // and THtml::GetSearchEngine(). The first one is preferred. - // e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u"; + // e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u+-site%3A%u%2Fsrc%2F+-site%3A%u%2Fexamples%2F"; const TString& searchCmd = GetHtml()->GetSearchStemURL(); + const TString& searchEngine = GetHtml()->GetSearchEngine(); + + if (!searchCmd.Length() && !searchEngine.Length()) + return; + if (searchCmd.Length()) { // create search input out << "<script type=\"text/javascript\">" << endl @@ -1846,15 +1910,77 @@ void TDocOutput::WriteSearch(std::ostream& out) << "var ref=String(document.location.href).replace(/https?:\\/\\//,'').replace(/\\/[^\\/]*$/,'').replace(/\\//g,'%2F');" << endl << "window.location.href=s.replace(/%u/ig,ref).replace(/%s/ig,escape(document.searchform.t.value));" << endl << "return false;}" << endl - << "</script><form action=\"javascript:onSearch();\" id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\">" << endl - << "<input name=\"t\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input>" << endl - << "<button type=\"submit\">Search</button></form>" << endl; - return; + << "</script>" << endl + << "<a class=\"descrheadentry\"> </a>" << endl + << "<form id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\" >" << endl + << "<input name=\"t\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value==' Search documentation... ') document.searchform.t.value='';\"></input></form>" << endl + << "<a id=\"searchlink\" href=\"javascript:onSearch();\" onclick=\"return onSearch()\">Search</a>" << endl; + } else if (searchEngine.Length()) + // create link to search engine page + out << "<a class=\"descrheadentry\" href=\"" << searchEngine + << "\">Search the Class Reference Guide</a>" << endl; +} + +//______________________________________________________________________________ +void TDocOutput::WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname) +{ + // Write the first part of the links shown ontop of each doc page; + // two <div>s have to be closed by caller so additional items can still + // be added. + + out << "<div id=\"toplinks\">" << endl; + + // make a link to the description + out << "<div class=\"descrhead\">" << endl + << "<span class=\"descrtitle\">Location:</span>" << endl; + const char *productName = fHtml->GetProductName(); + out << "<a class=\"descrheadentry\" href=\"index.html\">" << productName << "</a>" << endl; + + if (module) { + TString modulename(module->GetName()); + modulename.ToUpper(); + TString modulePart; + TString modulePath; + Ssiz_t pos = 0; + while (modulename.Tokenize(modulePart, pos, "/")) { + if (pos == kNPOS && !classname) + // we are documenting the module itself, no need to link it: + break; + if (modulePath.Length()) modulePath += "_"; + modulePath += modulePart; + out << " » <a class=\"descrheadentry\" href=\"./" << modulePath << "_Index.html\">" << modulePart << "</a>" << endl; + } } - const TString& searchEngine = GetHtml()->GetSearchEngine(); - if (searchEngine.Length()) - // create link to search engine page - out << "<h2><a href=\"" << searchEngine - << "\">Search the Class Reference Guide</a></h2>" << endl; + TString entityName; + if (classname) entityName = classname; + else if (module) { + entityName = module->GetName(); + Ssiz_t posSlash = entityName.Last('/'); + if (posSlash != kNPOS) + entityName.Remove(0, posSlash + 1); + entityName.ToUpper(); + } + if (entityName.Length()) { + out << " » <a class=\"descrheadentry\" href=\"#TopOfPage\">"; + ReplaceSpecialChars(out, entityName); + out << "</a>" << endl; + } + out << "</div>" << endl; + + out << "<div class=\"descrhead\">" << endl + << "<span class=\"descrtitle\">Quick Links:</span>" << endl; + + // link to the user home page (if exist) + const char* userHomePage = GetHtml()->GetHomepage(); + if (productName && !strcmp(productName, "ROOT")) + userHomePage = ""; + if (userHomePage && *userHomePage) + out << "<a class=\"descrheadentry\" href=\"" << userHomePage << "\">" << productName << "</a>" << endl; + out << "<a class=\"descrheadentry\" href=\"http://root.cern.ch\">ROOT Homepage</a>" << endl + << "<a class=\"descrheadentry\" href=\"./ClassIndex.html\">Class Index</a>" << endl + << "<a class=\"descrheadentry\" href=\"./ClassHierarchy.html\">Class Hierarchy</a>" << endl; + WriteSearch(out); + out << "</div>" << endl; + } diff --git a/html/src/TDocParser.cxx b/html/src/TDocParser.cxx index 1be2e801ed2db907a5c7a79ad95aae1a38e75380..958c3cb133ae2b7c6302dd60188c830c34193e72 100644 --- a/html/src/TDocParser.cxx +++ b/html/src/TDocParser.cxx @@ -131,7 +131,7 @@ std::set<std::string> TDocParser::fgKeywords; //______________________________________________________________________________ TDocParser::TDocParser(TClassDocOutput& docOutput, TClass* cl): fHtml(docOutput.GetHtml()), fDocOutput(&docOutput), fLineNo(0), - fCurrentClass(cl), fDirectiveCount(0), fDocContext(kIgnore), + fCurrentClass(cl), fCurrentModule(0), fDirectiveCount(0), fDocContext(kIgnore), fCheckForMethod(kFALSE), fClassDocState(kClassDoc_Uninitialized), fCommentAtBOL(kFALSE) { @@ -750,6 +750,25 @@ void TDocParser::DecrementMethodCount(const char* name) } } +//______________________________________________________________________________ +void TDocParser::DeleteDirectiveOutput() const +{ + // Delete output generated by prior runs of all known directives; + // the output file names might have changes. + + TIter iClass(gROOT->GetListOfClasses()); + TClass* cl = 0; + while ((cl = (TClass*) iClass())) + if (cl != TDocDirective::Class() + && cl->InheritsFrom(TDocDirective::Class())) { + TDocDirective* directive = (TDocDirective*) cl->New(); + if (!directive) continue; + directive->SetParser(const_cast<TDocParser*>(this)); + directive->DeleteOutput(); + delete directive; + } +} + //______________________________________________________________________________ void TDocParser::ExpandCPPLine(TString& line, Ssiz_t& pos) { @@ -777,8 +796,8 @@ void TDocParser::ExpandCPPLine(TString& line, Ssiz_t& pos) if (line.Tokenize(filename, posEndFilename, "[>\"]")) { R__LOCKGUARD(fHtml->GetMakeClassMutex()); - TString filesysFileName(filename); - if (gSystem->FindFile(fHtml->GetSourceDir(), filesysFileName, kReadPermission)) { + TString filesysFileName; + if (fHtml->GetPathDefinition().GetFileNameFromInclude(filename, filesysFileName)) { fDocOutput->CopyHtmlFile(filesysFileName); TString endOfLine(line(posEndFilename - 1, line.Length())); @@ -787,7 +806,7 @@ void TDocParser::ExpandCPPLine(TString& line, Ssiz_t& pos) fDocOutput->ReplaceSpecialChars(line, i); line += "<a href=\"../"; - line += fHtml->GetFileName(filename); + line += gSystem->BaseName(filename); line += "\">"; line += filename + "</a>" + endOfLine[0]; // add include file's closing '>' or '"' posEndOfLine = line.Length() - 1; // set the "processed up to" to it @@ -814,6 +833,15 @@ void TDocParser::ExpandCPPLine(TString& line, Ssiz_t& pos) pos = posEndOfLine; } + +//______________________________________________________________________________ +void TDocParser::GetCurrentModule(TString& out_module) const { + // Return the name of module for which sources are currently parsed. + if (fCurrentModule) out_module = fCurrentModule; + else if (fCurrentClass) fHtml->GetModuleNameForClass(out_module, fCurrentClass); + else out_module = "(UNKNOWN MODULE WHILE PARSING)"; +} + //______________________________________________________________________________ Bool_t TDocParser::HandleDirective(TString& line, Ssiz_t& pos, TString& word, Ssiz_t& copiedToCommentUpTo) @@ -1124,7 +1152,7 @@ TClass* TDocParser::IsDirective(const TString& line, Ssiz_t pos, TClass* clDirective = fHtml->GetClass(tag); - if (!clDirective) + if (gDebug > 0 && !clDirective) Warning("IsDirective", "Unknown THtml directive %s in line %d!", word.Data(), fLineNo); return clDirective; @@ -1403,6 +1431,8 @@ void TDocParser::Parse(std::ostream& out) fClassDocState = kClassDoc_LookingNothingFound; + DeleteDirectiveOutput(); + LocateMethodsInSource(out); LocateMethodsInHeaderInline(out); LocateMethodsInHeaderClassDecl(out); @@ -1440,10 +1470,10 @@ void TDocParser::LocateMethods(std::ostream& out, const char* filename, TString sourceFileName(filename); fCurrentFile = filename; - fHtml->GetSourceFileName(sourceFileName); if (!sourceFileName.Length()) { + fHtml->GetImplFileName(fCurrentClass, kFALSE, sourceFileName); Error("LocateMethods", "Can't find source file '%s' for class %s!", - fHtml->GetImplFileName(fCurrentClass), fCurrentClass->GetName()); + sourceFileName.Data(), fCurrentClass->GetName()); return; } ifstream sourceFile(sourceFileName.Data()); @@ -1652,8 +1682,8 @@ void TDocParser::LocateMethodsInSource(std::ostream& out) pattern.Remove(0, posLastScope + 2); pattern += "::"; - const char* implFileName = fHtml->GetImplFileName(fCurrentClass); - if (implFileName && implFileName[0]) + TString implFileName; + if (fHtml->GetImplFileName(fCurrentClass, kTRUE, implFileName)) LocateMethods(out, implFileName, kFALSE /*source info*/, useDocxxStyle, kFALSE /*allowPureVirtual*/, pattern, ".cxx.html"); else out << "</div>" << endl; // close class descr div @@ -1675,8 +1705,8 @@ void TDocParser::LocateMethodsInHeaderInline(std::ostream& out) pattern.Remove(0, posLastScope + 1); pattern += "::"; - const char* declFileName = fHtml->GetDeclFileName(fCurrentClass); - if (declFileName && declFileName[0]) + TString declFileName; + if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, declFileName)) LocateMethods(out, declFileName, kTRUE /*source info*/, useDocxxStyle, kFALSE /*allowPureVirtual*/, pattern, 0); } @@ -1688,8 +1718,8 @@ void TDocParser::LocateMethodsInHeaderClassDecl(std::ostream& out) // class declaration block, and extract documentation to out, // while beautifying the header file in parallel. - const char* declFileName = fHtml->GetDeclFileName(fCurrentClass); - if (declFileName && declFileName[0]) + TString declFileName; + if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, declFileName)) LocateMethods(out, declFileName, kTRUE/*source info*/, kTRUE /*useDocxxStyle*/, kTRUE /*allowPureVirtual*/, 0, ".h.html"); } diff --git a/html/src/THtml.cxx b/html/src/THtml.cxx index 1f015727d838b3c1688f50c29edb26d8ca84ec31..75b4cda312d5b9b1edab23c623481af0c931b4d4 100644 --- a/html/src/THtml.cxx +++ b/html/src/THtml.cxx @@ -1,5 +1,5 @@ // @(#)root/html:$Id$ -// Author: Nenad Buncic (18/10/95), Axel Naumann <mailto:axel@fnal.gov> (09/28/01) +// Author: Nenad Buncic (18/10/95), Axel Naumann (09/28/01) /************************************************************************* * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. * @@ -22,6 +22,7 @@ #include "TEnv.h" #include "TInterpreter.h" #include "TObjString.h" +#include "TPRegexp.h" #include "TRegexp.h" #include "TROOT.h" #include "TSystem.h" @@ -35,6 +36,8 @@ THtml *gHtml = 0; +//______________________________________________________________________________ +//______________________________________________________________________________ namespace { class THtmlThreadInfo { public: @@ -49,6 +52,532 @@ namespace { }; +//______________________________________________________________________________ +THtml::THelperBase::~THelperBase() +{ + // Helper's destructor. + // Check that no THtml object is attached to the helper - it might still need it! + if (fHtml) { + fHtml->HelperDeleted(this); + } +} + + +//______________________________________________________________________________ +void THtml::THelperBase::SetOwner(THtml* html) { + // Set the THtml object owning this object; if it's already set to + // a different THtml object than issue an error message and signal to + // the currently set object that we are not belonging to it anymore. + if (fHtml && html && html != fHtml) { + Error("SetOwner()", "Object already owned by an THtml instance!"); + fHtml->HelperDeleted(this); + } + fHtml = html; +} + + +//______________________________________________________________________________ +bool THtml::TModuleDefinition::GetModule(TClass* cl, TString& out_modulename) const +{ + // Set out_modulename to cl's module name; return true if it's valid. + // If applicable, the module contains super modules separated by "/". + // + // ROOT takes the directory part of cl's implementation file name + // (or declaration file name, if the implementation file name is empty), + // removes the last subdirectory if it is "src/" or "inc/", and interprets + // the remaining path as the module hierarchy, converting it to upper case. + // hist/histpainter/src/THistPainter.cxx thus becomes the module + // HIST/HISTPAINTER. (Node: some ROOT packages get special treatment.) + // If the file cannot be mapped into this scheme, the class's library + // name (without directories, leading "lib" prefix or file extensions) + // ius taken as the module name. If the module cannot be determined it is + // set to "USER" and false is returned. + // + // If your software cannot be mapped into this scheme then derive your + // own class from TModuleDefinition and pass it to THtml::SetModuleDefinition(). + + out_modulename = "USER"; + if (!cl) return false; + + // Filename: impl or decl? + TString filename; + if (!GetOwner()->GetImplFileName(cl, kFALSE, filename)) + if (!GetOwner()->GetDeclFileName(cl, kFALSE, filename)) + return false; + + // take the directory name without "/" or leading "." + out_modulename = gSystem->DirName(filename); + while (out_modulename[0] == '.') + out_modulename.Remove(0, 1); + out_modulename.ReplaceAll("\\", "/"); + while (out_modulename[0] == '/') + out_modulename.Remove(0, 1); + while (out_modulename.EndsWith("/")) + out_modulename.Remove(out_modulename.Length() - 1); + + // remove "/src", "/inc" + if (out_modulename.EndsWith("/src") + || out_modulename.EndsWith("/inc")) + out_modulename.Remove(out_modulename.Length() - 4, 4); + else { + // remove "/src/whatever", "/inc/whatever" + Ssiz_t pos = out_modulename.Index("/src/"); + if (pos == kNPOS) + pos = out_modulename.Index("/inc/"); + if (pos != kNPOS) + out_modulename.Remove(pos); + } + + while (out_modulename.EndsWith("/")) + out_modulename.Remove(out_modulename.Length() - 1); + + // special treatment: + if (out_modulename == "MATH/GENVECTOR") + out_modulename = "MATHCORE"; + else if (out_modulename == "MATH/MATRIX") + out_modulename = "SMATRIX"; + else if (!out_modulename.Length()) { + const char* cname= cl->GetName(); + if (strstr(cname, "::SMatrix<") || strstr(cname, "::SVector<")) + out_modulename = "SMATRIX"; + else if (strstr(cname, "::TArrayProxy<") || strstr(cname, "::TClaArrayProxy<") + || strstr(cname, "::TImpProxy<") || strstr(cname, "::TClaImpProxy<")) + out_modulename = "TREEPLAYER"; + else { + // determine the module name from the library name: + out_modulename = cl->GetSharedLibs(); + Ssiz_t pos = out_modulename.Index(' '); + if (pos != kNPOS) + out_modulename.Remove(pos, out_modulename.Length()); + if (out_modulename.BeginsWith("lib")) + out_modulename.Remove(0,3); + pos = out_modulename.Index('.'); + if (pos != kNPOS) + out_modulename.Remove(pos, out_modulename.Length()); + + if (!out_modulename.Length()) { + out_modulename = "USER"; + return false; + } + } + } + + return true; +} + +//______________________________________________________________________________ +void THtml::TFileDefinition::ExpandSearchPath(TString& path) const +{ + // Create all permutations of path and THtml's input path: + // path being PP/ and THtml's input being .:include/:src/ gives + // .:./PP/:include:include/PP/:src/:src/PP + THtml* owner = GetOwner(); + if (!owner) return; + + TString pathext; + TString inputdir = owner->GetInputPath(); + TString tok; + Ssiz_t start = 0; + while (inputdir.Tokenize(tok, start, THtml::GetDirDelimiter())) { + if (pathext.Length()) + pathext += GetDirDelimiter(); + if (tok.EndsWith("\\")) + tok.Remove(tok.Length() - 1); + pathext += tok; + pathext += GetDirDelimiter() + tok + "/" + path; + } + path = pathext; + +} + +//______________________________________________________________________________ +void THtml::TFileDefinition::SplitClassIntoDirFile(const TString& clname, TString& dir, TString& filename) const +{ + // Given a class name with a scope, split the class name into directory part + // and file name: A::B::C becomes module B, filename C. + TString token; + Ssiz_t from = 0; + filename = ""; + dir = ""; + while (clname.Tokenize(token, from, "::") ) { + dir = filename; + filename = token; + } + + // convert from Scope, class to module, filename.h + dir.ToLower(); +} + + +//______________________________________________________________________________ +bool THtml::TFileDefinition::GetDeclFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const +{ + // Determine cl's declaration file name. Usually it's just + // cl->GetDeclFileName(), but sometimes conversions need to be done + // like include/ to abc/cde/inc/. If no declaration file name is + // available, look for b/inc/C.h for class A::B::C. out_fsys will contain + // the file system's (i.e. local machine's) full path name to the file. + // The function returns false if the class's header file cannot be found. + // + // If your software cannot be mapped into this scheme then derive your + // own class from TFileDefinition and pass it to THtml::SetFileDefinition(). + + return GetFileName(cl, true, out_filename, out_fsys); +} + +//______________________________________________________________________________ +bool THtml::TFileDefinition::GetImplFileName(const TClass* cl, TString& out_filename, TString& out_fsys) const +{ + // Determine cl's implementation file name. Usually it's just + // cl->GetImplFileName(), but sometimes conversions need to be done. + // If no implementation file name is available look for b/src/C.cxx for + // class A::B::C. out_fsys will contain the file system's (i.e. local + // machine's) full path name to the file. + // The function returns false if the class's source file cannot be found. + // + // If your software cannot be mapped into this scheme then derive your + // own class from TFileDefinition and pass it to THtml::SetFileDefinition(). + + return GetFileName(cl, false, out_filename, out_fsys); +} + + +//______________________________________________________________________________ +bool THtml::TFileDefinition::GetFileName(const TClass* cl, bool decl, TString& out_filename, TString& out_fsys) const +{ + // Common implementation for GetDeclFileName(), GetImplFileName() + + out_fsys = ""; + + if (!cl) { + out_filename = ""; + return false; + } + + TString possibleFileName; + TString possiblePath; + TString filesysname; + + TString clfile = decl ? cl->GetDeclFileName() : cl->GetImplFileName(); + out_filename = clfile; + if (clfile.Length()) { + // check that clfile doesn't start with one of the include paths; + // that's not what we want (include/TObject.h), we want the actual file + // if it exists (core/base/inc/TObject.h) + TString inclDir; + TString inclPath(GetOwner()->GetPathInfo().fIncludePath); + Ssiz_t pos = 0; + Ssiz_t longestMatch = kNPOS; + while (inclPath.Tokenize(inclDir, pos, GetOwner()->GetDirDelimiter())) { + if (clfile.BeginsWith(inclDir) && (longestMatch == kNPOS || inclDir.Length() > longestMatch)) + longestMatch = inclDir.Length(); + } + if (longestMatch != kNPOS) { + clfile.Remove(0, longestMatch); + if (clfile.BeginsWith("/") || clfile.BeginsWith("\\")) + clfile.Remove(0, 1); + TString asincl(clfile); + GetOwner()->GetPathDefinition().GetFileNameFromInclude(asincl, clfile); + out_filename = clfile; + } + } else { + // check for a file named like the class: + filesysname = cl->GetName(); + int templateLevel = 0; + Ssiz_t end = filesysname.Length(); + Ssiz_t start = end - 1; + for (; start >= 0 && (templateLevel || filesysname[start] != ':'); --start) { + if (filesysname[start] == '>') + ++templateLevel; + else if (filesysname[start] == '<') { + --templateLevel; + if (!templateLevel) + end = start; + } + } + filesysname = filesysname(start + 1, end - start - 1); + if (decl) + filesysname += ".h"; + else + filesysname += ".cxx"; + TFileSysEntry* fsentry = (TFileSysEntry*) GetOwner()->GetLocalFiles()->GetEntries().FindObject(filesysname); + if (fsentry) { + fsentry->GetFullName(filesysname); + clfile = filesysname; + out_filename = filesysname; + } + } + + if (!decl && !clfile.Length()) { + // determine possiblt impl file name from the decl file name, + // replacing ".whatever" by ".cxx", and looking for it in the known + // file names + TString declSysFileName; + if (GetFileName(cl, true, filesysname, declSysFileName)) { + filesysname = gSystem->BaseName(filesysname); + Ssiz_t posExt = filesysname.Last('.'); + if (posExt != kNPOS) + filesysname.Remove(posExt); + filesysname += ".cxx"; + TFileSysEntry* fsentry = (TFileSysEntry*) GetOwner()->GetLocalFiles()->GetEntries().FindObject(filesysname); + if (fsentry) { + fsentry->GetFullName(filesysname); + clfile = filesysname; + out_filename = filesysname; + } + } + } + + if (!clfile.Length()) { + // determine possible decl file name from class + scope name: + // A::B::C::myclass will result in possible file name myclass.h + // in directory C/inc/ + out_filename = cl->GetName(); + if (!out_filename.Contains("::")) { + out_filename = ""; + return false; + } + SplitClassIntoDirFile(out_filename, possiblePath, possibleFileName); + + // convert from Scope, class to module, filename.h + if (possibleFileName.Length()) { + if (decl) + possibleFileName += ".h"; + else + possibleFileName += ".cxx"; + } + if (possiblePath.Length()) + possiblePath += "/"; + if (decl) + possiblePath += "inc/"; + else + possiblePath += "src/"; + out_filename = possiblePath + "/" + possibleFileName; + } else { + possiblePath = gSystem->DirName(clfile); + possibleFileName = gSystem->BaseName(clfile); + } + + if (possiblePath.Length()) + ExpandSearchPath(possiblePath); + + out_fsys = gSystem->FindFile(possiblePath, possibleFileName, kReadPermission); + if (out_fsys.Length()) return true; + out_filename = ""; + return false; +} + +//______________________________________________________________________________ +bool THtml::TPathDefinition::GetMacroPath(const TString& module, TString& out_dir) const +{ + // Determine the path to look for macros (see TDocMacroDirective) for + // classes from a given module. If the path was sucessfully determined return true. + // For ROOT, this directory is the "doc/macros" subdirectory of the module + // directory; the path returned is GetDocDir(module) + "/macros". + // + // If your software cannot be mapped into this scheme then derive your + // own class from TPathDefinition and pass it to THtml::SetPathDefinition(). + + TString moduledoc; + if (!GetDocDir(module, moduledoc)) + return false; + if (moduledoc.EndsWith("\\")) + moduledoc.Remove(moduledoc.Length() - 1); + + TString macropath(GetOwner()->GetMacroPath()); + TString macrodirpart; + out_dir = ""; + Ssiz_t pos = 0; + while (macropath.Tokenize(macrodirpart, pos, ":")) { + out_dir += moduledoc + "/" + macrodirpart + ":"; + } + return true; +} + + +//______________________________________________________________________________ +bool THtml::TPathDefinition::GetDocDir(const TString& module, TString& doc_dir) const +{ + // Determine the module's documentation directory. If module is empty, + // set doc_dir to the product's documentation directory. + // If the path was sucessfuly determined return true. + // For ROOT, this directory is the subdir "doc/" in the + // module's path; the directory returned is module + "/doc". + // + // If your software cannot be mapped into this scheme then derive your + // own class from TPathDefinition and pass it to THtml::SetPathDefinition(). + + if (module.Length()) + doc_dir = module + "/"; + doc_dir += GetOwner()->GetPathInfo().fDocPath; + return true; +} + + +//______________________________________________________________________________ +bool THtml::TPathDefinition::GetIncludeAs(TClass* cl, TString& out_dir) const +{ + // Determine the path and filename used in an include statement for the + // header file of the given class. E.g. the class ROOT::Math::Boost is + // meant to be included as "Math/Genvector/Boost.h" - which is what + // out_dir is set to. GetIncludeAs() returns whether the include + // statement's path was successfully determined. + // + // Any leading directory part that is part of fIncludePath (see SetIncludePath) + // will be removed. For ROOT, leading "include/" is removed; everything after + // is the include path. Only classes from TMVA are different; they are included + // as TMVA/ClassName.h. + // + // If your software cannot be mapped into this scheme then derive your + // own class from TPathDefinition and pass it to THtml::SetPathDefinition(). + + out_dir = ""; + if (!cl || !GetOwner()) return false; + + const char* clname = cl->GetName(); + TString hdr; + if (!GetOwner()->GetDeclFileName(cl, kFALSE, hdr)) + return false; + + out_dir = hdr; + bool includePathMatches = false; + TString tok; + Ssiz_t pos = 0; + while (!includePathMatches && GetOwner()->GetPathInfo().fIncludePath.Tokenize(tok, pos, THtml::GetDirDelimiter())) + if (out_dir.BeginsWith(tok)) { + out_dir = hdr(tok.Length(), hdr.Length()); + includePathMatches = true; + } + + if (!includePathMatches) { + // We probably have a file super/module/inc/optional/filename.h. + // That gets translated into optional/filename.h. + // Assume that only one occurrence of "/inc/" exists in hdr. + // If /inc/ is not part of the include file name then + // just return the full path. + // If we have matched any include path then this ROOT-only + // algorithm is skipped! + hdr = strstr(hdr, "/inc/"); + if (!hdr) return true; + hdr += 5; + out_dir = hdr; + + // TMVA special treatment: + // TMVA::Whatever claims to be in in math/tmva/inc/Whatever.h + // but it needs to get included as TMVA/Whatever.h + if (strstr(clname, "TMVA::")) + out_dir.Prepend("TMVA/"); + } + + return (out_dir.Length()); +} + + +//______________________________________________________________________________ +bool THtml::TPathDefinition::GetFileNameFromInclude(const char* included, TString& out_fsname) const +{ + // Set out_fsname to the full pathname corresponding to a file + // included as "included". Return false if this file cannot be determined + // or found. For ROOT, out_fsname corresponds to included prepended with + // "include"; only THtml prefers to work on the original files, e.g. + // core/base/inc/TObject.h instead of include/TObject.h, so the + // default implementation searches the TFileSysDB for an entry with + // basename(included) and with matching directory part, setting out_fsname + // to the TFileSysEntry's path. + + if (!included) return false; + + out_fsname = included; + + if (!strncmp(included, "TMVA/", 5)) { + out_fsname.Remove(0, 4); + out_fsname.Prepend("tmva/inc"); + return true; + } + + TString incBase(gSystem->BaseName(included)); + TList* bucket = GetOwner()->GetLocalFiles()->GetEntries().GetListForObject(incBase); + if (!bucket) return false; + + TString alldir(gSystem->DirName(included)); + TObjArray* arrSubDirs = alldir.Tokenize("/"); + TIter iEntry(bucket); + TFileSysEntry* entry = 0; + while ((entry = (TFileSysEntry*) iEntry())) { + if (incBase != entry->GetName()) continue; + // find entry with matching enclosing directory + THtml::TFileSysDir* parent = entry->GetParent(); + for (int i = arrSubDirs->GetEntries() - 1; parent && i >= 0; --i) { + const TString& subdir(((TObjString*)(*arrSubDirs)[i])->String()); + if (!subdir.Length() || subdir == ".") + continue; + if (subdir == parent->GetName()) + parent = parent->GetParent(); + else parent = 0; + } + if (parent) { + // entry found! + entry->GetFullName(out_fsname); + delete arrSubDirs; + return true; + } + } + delete arrSubDirs; + return false; +} + +//______________________________________________________________________________ +void THtml::TFileSysDir::Recurse(TFileSysDB* db, const char* path) +{ + // Recursively fill entries by parsing the path; + // can be a THtml::GetDirDelimiter() delimited list of paths. + + TString sPath(path); + printf("scanning %s...\n", path); + TString dir; + Ssiz_t posPath = 0; + TPMERegexp regexp(db->GetIgnore()); + while (sPath.Tokenize(dir, posPath, THtml::GetDirDelimiter())) { + dir += "/"; + void* hDir = gSystem->OpenDirectory(dir); + const char* direntry = 0; + while ((direntry = gSystem->GetDirEntry(hDir))) { + if (!direntry[0] || direntry[0] == '.') continue; + TString entryPath(dir + direntry); + if (gSystem->AccessPathName(entryPath, kReadPermission) + || regexp.Match(entryPath)) + continue; + FileStat_t buf; + gSystem->GetPathInfo(entryPath, buf); + if (R_ISDIR(buf.fMode)) { + // skip if we would nest too deeply, and skip soft links: + if (GetLevel() > db->GetMaxLevel() +#ifndef R__WIN32 + || db->GetMapIno().GetValue(buf.fIno) +#endif + ) continue; + TFileSysDir* subdir = new TFileSysDir(direntry, this); + fDirs.Add(subdir); +#ifndef R__WIN32 + db->GetMapIno().Add(buf.fIno, (Long_t)subdir); +#endif + subdir->Recurse(db, entryPath); + } else { + int delen = strlen(direntry); + // only .cxx and .h are taken + if (strcmp(direntry + delen - 4, ".cxx") + && strcmp(direntry + delen - 2, ".h")) + continue; + TFileSysEntry* entry = new TFileSysEntry(direntry, this); + db->GetEntries().Add(entry); + fFiles.Add(entry); + } + } // while dir entry + gSystem->FreeDirectory(hDir); + } // while sPath token +} + + //////////////////////////////////////////////////////////////////////////////// /* BEGIN_HTML <p>The THtml class is designed to easily document @@ -121,7 +650,7 @@ which you can set in your .rootrc. <p>In your .rootrc, define Root.Html.SourceDir to point to directories containing .cxx and .h files (see: <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>) -of the classes you want to document, or call THtml::SetSourceDir()</p> +of the classes you want to document, or call THtml::SetInputDir()</p> <p>Example:</p><pre> Root.Html.SourceDir: .:src:include @@ -141,7 +670,7 @@ will create it.</p> <h4><a name="conf:liblink">II.3 Linking other documentation</a></h4> <p>When trying to document a class, THtml searches for a source file in -the directories set via SetSourceDir(). If it cannot find it, it assumes +the directories set via SetInputDir(). If it cannot find it, it assumes that this class must have been documented before. Based on the library this class is defined in, it checks the configuration variable <tt>Root.Html.LibName</tt>, and creates a link using its value. @@ -516,43 +1045,40 @@ END_HTML */ ClassImp(THtml) //______________________________________________________________________________ -THtml::THtml(): fIncludePath("include"), fFoundDot(-1), +THtml::THtml(): fCounterFormat("%12s %5s %s"), - fProductName("(UNKNOWN PRODUCT)"), fProductDocDir("doc"), - fMacroPath("../doc/macros:."), fModuleDocPath("../doc"), - fThreadedClassIter(0), fMakeClassMutex(0) - + fProductName("(UNKNOWN PRODUCT)"), + fThreadedClassIter(0), fMakeClassMutex(0), + fPathDef(0), fModuleDef(0), fFileDef(0), + fLocalFiles(0) { // Create a THtml object. // In case output directory does not exist an error // will be printed and gHtml stays 0 also zombie bit will be set. - // get prefix for source directory - fSourcePrefix = gEnv->GetValue("Root.Html.SourcePrefix", ""); - // check for source directory - fSourceDir = gEnv->GetValue("Root.Html.SourceDir", "./:src/:include/"); + fPathInfo.fInputPath = gEnv->GetValue("Root.Html.SourceDir", "./:src/:include/"); // check for output directory - fOutputDir = gEnv->GetValue("Root.Html.OutputDir", "htmldoc"); - - fXwho = gEnv->GetValue("Root.Html.XWho", "http://consult.cern.ch/xwho/people?"); - fROOTURL = gEnv->GetValue("Root.Html.Root", "http://root.cern.ch/root/html"); - fClassDocTag = gEnv->GetValue("Root.Html.Description", "//____________________"); - fAuthorTag = gEnv->GetValue("Root.Html.Author", "// Author:"); - fLastUpdateTag = gEnv->GetValue("Root.Html.LastUpdate", "// @(#)"); - fCopyrightTag = gEnv->GetValue("Root.Html.Copyright", "* Copyright"); - fHeader = gEnv->GetValue("Root.Html.Header", ""); - fFooter = gEnv->GetValue("Root.Html.Footer", ""); - fHomepage = gEnv->GetValue("Root.Html.Homepage", ""); - fSearchStemURL = gEnv->GetValue("Root.Html.Search", ""); - fSearchEngine = gEnv->GetValue("Root.Html.SearchEngine", ""); - fViewCVS = gEnv->GetValue("Root.Html.ViewCVS", ""); - fCharset = gEnv->GetValue("Root.Html.Charset", "ISO-8859-1"); - fDocStyle = gEnv->GetValue("Root.Html.DescriptionStyle", ""); - - fClasses.SetOwner(); - fModules.SetOwner(); + fPathInfo.fOutputDir = gEnv->GetValue("Root.Html.OutputDir", "htmldoc"); + + fLinkInfo.fXwho = gEnv->GetValue("Root.Html.XWho", "http://consult.cern.ch/xwho/people?"); + fLinkInfo.fROOTURL = gEnv->GetValue("Root.Html.Root", "http://root.cern.ch/root/html"); + fDocSyntax.fClassDocTag = gEnv->GetValue("Root.Html.Description", "//____________________"); + fDocSyntax.fAuthorTag = gEnv->GetValue("Root.Html.Author", "// Author:"); + fDocSyntax.fLastUpdateTag = gEnv->GetValue("Root.Html.LastUpdate", "// @(#)"); + fDocSyntax.fCopyrightTag = gEnv->GetValue("Root.Html.Copyright", "* Copyright"); + fOutputStyle.fHeader = gEnv->GetValue("Root.Html.Header", ""); + fOutputStyle.fFooter = gEnv->GetValue("Root.Html.Footer", ""); + fLinkInfo.fHomepage = gEnv->GetValue("Root.Html.Homepage", ""); + fLinkInfo.fSearchStemURL = gEnv->GetValue("Root.Html.Search", ""); + fLinkInfo.fSearchEngine = gEnv->GetValue("Root.Html.SearchEngine", ""); + fLinkInfo.fViewCVS = gEnv->GetValue("Root.Html.ViewCVS", ""); + fOutputStyle.fCharset = gEnv->GetValue("Root.Html.Charset", "ISO-8859-1"); + fDocSyntax.fDocStyle = gEnv->GetValue("Root.Html.DescriptionStyle", ""); + + fDocEntityInfo.fClasses.SetOwner(); + fDocEntityInfo.fModules.SetOwner(); // insert html object in the list of special ROOT objects if (!gHtml) { gHtml = this; @@ -567,12 +1093,16 @@ THtml::~THtml() { // Default destructor - fClasses.Clear(); - fModules.Clear(); + fDocEntityInfo.fClasses.Clear(); + fDocEntityInfo.fModules.Clear(); if (gHtml == this) { gROOT->GetListOfSpecials()->Remove(gHtml); gHtml = 0; } + delete fPathDef; + delete fModuleDef; + delete fFileDef; + delete fLocalFiles; } //______________________________________________________________________________ @@ -589,8 +1119,8 @@ void THtml::AddMacroPath(const char* path) #else ':'; #endif - fMacroPath += pathDelimiter; - fMacroPath += path; + fPathInfo.fMacroPath += pathDelimiter; + fPathInfo.fMacroPath += path; } @@ -603,31 +1133,71 @@ void THtml::CreateAuxiliaryFiles() const CopyFileFromEtcDir("HELP.html"); } +//______________________________________________________________________________ +const THtml::TModuleDefinition& THtml::GetModuleDefinition() const +{ + // Return the TModuleDefinition (or derived) object as set by + // SetModuleDefinition(); create and return a TModuleDefinition object + // if none was set. + if (!fModuleDef) { + fModuleDef = new TModuleDefinition(); + fModuleDef->SetOwner(const_cast<THtml*>(this)); + } + return *fModuleDef; +} + +//______________________________________________________________________________ +const THtml::TFileDefinition& THtml::GetFileDefinition() const +{ + // Return the TFileDefinition (or derived) object as set by + // SetFileDefinition(); create and return a TFileDefinition object + // if none was set. + if (!fFileDef) { + fFileDef = new TFileDefinition(); + fFileDef->SetOwner(const_cast<THtml*>(this)); + } + return *fFileDef; +} + +//______________________________________________________________________________ +const THtml::TPathDefinition& THtml::GetPathDefinition() const +{ + // Return the TModuleDefinition (or derived) object as set by + // SetModuleDefinition(); create and return a TModuleDefinition object + // if none was set. + if (!fPathDef) { + fPathDef = new TPathDefinition(); + fPathDef->SetOwner(const_cast<THtml*>(this)); + } + return *fPathDef; +} + + //______________________________________________________________________________ const char* THtml::GetEtcDir() { // Get the directory containing THtml's auxiliary files ($ROOTSYS/etc/html) - if (fEtcDir.Length()) - return fEtcDir; + if (fPathInfo.fEtcDir.Length()) + return fPathInfo.fEtcDir; R__LOCKGUARD(GetMakeClassMutex()); - fEtcDir = "html"; + fPathInfo.fEtcDir = "html"; #ifdef ROOTETCDIR - gSystem->PrependPathName(ROOTETCDIR, fEtcDir); + gSystem->PrependPathName(ROOTETCDIR, fPathInfo.fEtcDir); #else - gSystem->PrependPathName("etc", fEtcDir); + gSystem->PrependPathName("etc", fPathInfo.fEtcDir); # ifdef ROOTPREFIX - gSystem->PrependPathName(ROOTPREFIX, fEtcDir); + gSystem->PrependPathName(ROOTPREFIX, fPathInfo.fEtcDir); # else if (getenv("ROOTSYS")) - gSystem->PrependPathName(getenv("ROOTSYS"), fEtcDir); + gSystem->PrependPathName(getenv("ROOTSYS"), fPathInfo.fEtcDir); # endif #endif - return fEtcDir; + return fPathInfo.fEtcDir; } @@ -649,7 +1219,7 @@ TClassDocInfo *THtml::GetNextClass() fThreadedClassIter = 0; } - fCounter.Form("%5d", fClasses.GetSize() - fThreadedClassCount++); + fCounter.Form("%5d", fDocEntityInfo.fClasses.GetSize() - fThreadedClassCount++); return classinfo; } @@ -665,11 +1235,11 @@ const char* THtml::GetURL(const char* lib /*=0*/) const R__LOCKGUARD(GetMakeClassMutex()); if (lib && strlen(lib)) { - std::map<std::string, TString>::const_iterator iUrl = fLibURLs.find(lib); - if (iUrl != fLibURLs.end()) return iUrl->second; - return gEnv->GetValue(TString("Root.Html.") + lib, fROOTURL); + std::map<std::string, TString>::const_iterator iUrl = fLinkInfo.fLibURLs.find(lib); + if (iUrl != fLinkInfo.fLibURLs.end()) return iUrl->second; + return gEnv->GetValue(TString("Root.Html.") + lib, fLinkInfo.fROOTURL); } - return fROOTURL; + return fLinkInfo.fROOTURL; } //______________________________________________________________________________ @@ -678,27 +1248,40 @@ Bool_t THtml::HaveDot() // Check whether dot is available in $PATH or in the directory set // by SetDotPath() - if (fFoundDot != -1) - return (Bool_t)fFoundDot; + if (fPathInfo.fFoundDot != -1) + return (Bool_t)fPathInfo.fFoundDot; R__LOCKGUARD(GetMakeClassMutex()); Info("HaveDot", "Checking for Graphviz (dot)..."); TString runDot("dot"); - if (fDotDir.Length()) - gSystem->PrependPathName(fDotDir, runDot); + if (fPathInfo.fDotDir.Length()) + gSystem->PrependPathName(fPathInfo.fDotDir, runDot); runDot += " -V"; if (gDebug > 3) Info("HaveDot", "Running: %s", runDot.Data()); if (gSystem->Exec(runDot)) { - fFoundDot = 0; + fPathInfo.fFoundDot = TPathInfo::kDotNotFound; return kFALSE; } - fFoundDot = 1; + fPathInfo.fFoundDot = TPathInfo::kDotFound; return kTRUE; } +//______________________________________________________________________________ +void THtml::HelperDeleted(THtml::THelperBase* who) +{ + // Inform the THtml object that one of its helper objects was deleted. + // Called by THtml::HelperBase::~HelperBase(). + + THelperBase* helpers[3] = {fPathDef, fModuleDef, fFileDef}; + for (int i = 0; who && i < 3; ++i) + if (who == helpers[i]) + helpers[i] = who = 0; +} + + //______________________________________________________________________________ void THtml::Convert(const char *filename, const char *title, const char *dirname /*= ""*/, const char *relpath /*= "../"*/) @@ -723,8 +1306,8 @@ void THtml::Convert(const char *filename, const char *title, // if it's not defined, make the "examples" as a default directory if (!*dirname) { - gSystem->ExpandPathName(fOutputDir); - dir = gSystem->ConcatFileName(fOutputDir, "examples"); + gSystem->ExpandPathName(fPathInfo.fOutputDir); + dir = gSystem->ConcatFileName(fPathInfo.fOutputDir, "examples"); } else dir = dirname; @@ -734,7 +1317,7 @@ void THtml::Convert(const char *filename, const char *title, // find a file char *realFilename = - gSystem->Which(fSourceDir, filename, kReadPermission); + gSystem->Which(fPathInfo.fInputPath, filename, kReadPermission); if (!realFilename) { Error("Convert", "Can't find file '%s' !", filename); @@ -759,7 +1342,7 @@ void THtml::Convert(const char *filename, const char *title, return; } char *tmp1 = - gSystem->ConcatFileName(dir, GetFileName(filename)); + gSystem->ConcatFileName(dir, gSystem->BaseName(filename)); TDocOutput output(*this); output.Convert(sourceFile, tmp1, title, relpath); @@ -769,66 +1352,26 @@ void THtml::Convert(const char *filename, const char *title, tmp1 = 0; } - -//______________________________________________________________________________ -void THtml::GetModuleName(TString& modulename, const char* filename) const -{ - // Returns the module a class with filename belongs to. - // For ROOT, this is determined by MODULE/src/*.cxx or MODULE/inc/*.h. - // Math/GenVector (MATHCORE) and Math/Matrix (SMATRIX) get special - // treatment. - // All classes not fitting into this layout are assigned to the - // module USER. - - size_t offset = 0; - if (filename[0] == '.' && (filename[1] == '/' || filename[1] == '\\')) - offset = 2; - - modulename = filename + offset; - const char* posSlash = strchr(filename + offset, '/'); - const char *srcdir = 0; - if (posSlash) { - // for new ROOT install the impl file name has the form: base/src/TROOT.cxx - srcdir = strstr(posSlash, "/src/"); - - // if impl is unset, check for decl and see if it matches - // format "base/inc/TROOT.h" - in which case it's not a USER - // class, but a BASE class. - if (!srcdir) srcdir=strstr(posSlash, "/inc/"); - } else srcdir = 0; - - if (srcdir && srcdir == posSlash) { - modulename.Remove(srcdir - (filename + offset), modulename.Length()); - modulename.ToUpper(); - } else { - if (posSlash && !strncmp(posSlash,"/Math/GenVector/", 16)) - modulename = "MATHCORE"; - else if (posSlash && !strncmp(posSlash,"/Math/Matrix", 12)) - modulename = "SMATRIX"; - else - modulename = "USER"; - } -} - //______________________________________________________________________________ void THtml::GetModuleNameForClass(TString& module, TClass* cl) const { // Return the module name for a given class. - // Use the cached information from fClasses. + // Use the cached information from fDocEntityInfo.fClasses. module = "(UNKNOWN)"; - TClassDocInfo* cdi = (TClassDocInfo*)fClasses.FindObject(cl->GetName()); + TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(cl->GetName()); if (!cdi || !cdi->GetModule()) return; module = cdi->GetModule()->GetName(); } + //______________________________________________________________________________ void THtml::CreateListOfClasses(const char* filter) { // Create the list of all known classes - if (fClasses.GetSize() && fClassFilter == filter) + if (fDocEntityInfo.fClasses.GetSize() && fDocEntityInfo.fClassFilter == filter) return; Info("CreateListOfClasses", "Initializing - this might take a while..."); @@ -836,10 +1379,10 @@ void THtml::CreateListOfClasses(const char* filter) Int_t totalNumberOfClasses = gClassTable->Classes(); // allocate memory - fClasses.Clear(); - fModules.Clear(); + fDocEntityInfo.fClasses.Clear(); + fDocEntityInfo.fModules.Clear(); - fClassFilter = filter; + fDocEntityInfo.fClassFilter = filter; // start from begining gClassTable->Init(); @@ -861,157 +1404,106 @@ void THtml::CreateListOfClasses(const char* filter) TClass *classPtr = TClass::GetClass((const char *) cname, kTRUE); if (!classPtr) continue; - TString srcGuess; - TString hdrGuess; - const char *impname=GetImplFileName(classPtr); - if (!impname || !impname[0]) { - impname = GetDeclFileName(classPtr); - if (impname && !impname[0]) { - // no impl, no decl - might be a cintex dict - // use namespace to decrypt path. - TString impnameString(cname); - TObjArray* arrScopes = impnameString.Tokenize("::"); - - // for A::B::C, we assume B to be the module, - // b/inc/B/C.h the header, and b/src/C.cxx the source. - TIter iScope(arrScopes, kIterBackward); - TObjString *osFile = (TObjString*)iScope(); - TObjString *osModule = 0; - if (osFile) osModule = (TObjString*)iScope(); - - if (osModule) { - hdrGuess = osModule->String(); - hdrGuess.ToLower(); - hdrGuess += "/inc/"; - hdrGuess += osModule->String(); - hdrGuess += "/"; - hdrGuess += osFile->String(); - hdrGuess += ".h"; - char* realFile = gSystem->Which(fSourceDir, hdrGuess, kReadPermission); - if (realFile) { - delete realFile; - fGuessedDeclFileNames[classPtr] = hdrGuess.Data(); - impname = hdrGuess.Data(); - - // only check for source if we've found the header! - srcGuess = osModule->String(); - srcGuess.ToLower(); - srcGuess += "/src/"; - srcGuess += osFile->String(); - srcGuess += ".cxx"; - realFile = gSystem->Which(fSourceDir, srcGuess, kReadPermission); - if (realFile) { - delete realFile; - fGuessedImplFileNames[classPtr] = srcGuess.Data(); - impname = srcGuess.Data(); - } - } - } - delete arrScopes; + // we cannot document namespaces yet - and TMath is really a class + if (IsNamespace(classPtr) && s != "TMath") + continue; + + TString hdr; + TString hdrFS; + TString src; + TString srcFS; + TString htmlfilename; + + TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cname); + if (cdi) { + hdr = cdi->GetDeclFileName(); + hdrFS = cdi->GetDeclFileSysName(); + src = cdi->GetImplFileName(); + srcFS = cdi->GetImplFileSysName(); + htmlfilename = cdi->GetHtmlFileName(); + } + + if (!hdrFS.Length()) { + if (!GetFileDefinition().GetDeclFileName(classPtr, hdr, hdrFS)) { + // we don't even know where the class is defined; + // just skip + if (!classPtr->GetDeclFileName() || !strstr(classPtr->GetDeclFileName(),"prec_stl/")) + Warning("CreateListOfClasses", + "Cannot determine declaration file name for %s!", cname); + continue; } } - if (!impname || !impname[0]) { - cout << "WARNING class " << cname << - " has no implementation file name !" << endl; - continue; + Bool_t haveSource = (srcFS.Length()); + if (!haveSource) + haveSource = GetFileDefinition().GetImplFileName(classPtr, src, srcFS); + + if (!haveSource && gDebug > 3) { + Info("CreateListOfClasses", + "Cannot determine implementation file name for %s!", cname); } - if (strstr(impname,"prec_stl/")) continue; - //if (strstr(cname, "ROOT::") && !strstr(cname,"Math::") - // && !strstr(cname,"Reflex::") && !strstr(cname,"Cintex::")) - // continue; + if (!htmlfilename.Length()) + GetHtmlFileName(classPtr, htmlfilename); + + if (!cdi) { + cdi = new TClassDocInfo(classPtr, htmlfilename, hdrFS, srcFS, hdr, src); + fDocEntityInfo.fClasses.Add(cdi); + } else { + cdi->SetDeclFileName(hdr); + cdi->SetImplFileName(src); + cdi->SetDeclFileSysName(hdrFS); + cdi->SetImplFileSysName(srcFS); + cdi->SetHtmlFileName(htmlfilename); + } - TString htmlfilename; - GetHtmlFileName(classPtr, htmlfilename); - TClassDocInfo* cdi = new TClassDocInfo(classPtr, htmlfilename.Data()); cdi->SetSelected(!(filter && filter[0] && strcmp(filter,"*") && s.Index(re) == kNPOS)); - char* realFile = gSystem->Which(fSourceDir, impname, kReadPermission); // delete at end of block - cdi->SetHaveSource((realFile)); - - fClasses.Add(cdi); TString modulename; - GetModuleName(modulename, impname); + GetModuleDefinition().GetModule(classPtr, modulename); if (!modulename.Length() || modulename == "USER") GetModuleNameForClass(modulename, classPtr); - if (modulename == "(UNKNOWN)") modulename = "USER"; - if (!modulename.Length() || modulename == "USER") { - modulename = classPtr->GetSharedLibs(); - Ssiz_t pos = modulename.Index(' '); - if (pos != kNPOS) - modulename.Remove(pos, modulename.Length()); - if (modulename.BeginsWith("lib")) - modulename.Remove(0,3); - pos = modulename.Index('.'); - if (pos != kNPOS) - modulename.Remove(pos, modulename.Length()); - modulename.ToUpper(); - } - if (!modulename.Length()) { - if (strstr(cname, "::SMatrix<") || strstr(cname, "::SVector<")) - modulename = "SMATRIX"; - else if (strstr(cname, "::TArrayProxy<") || strstr(cname, "::TClaArrayProxy<") - || strstr(cname, "::TImpProxy<") || strstr(cname, "::TClaImpProxy<")) - modulename = "TREEPLAYER"; - } - if (!modulename.Length()) - modulename = "USER"; - TModuleDocInfo* module = (TModuleDocInfo*) fModules.FindObject(modulename); + TModuleDocInfo* module = (TModuleDocInfo*) fDocEntityInfo.fModules.FindObject(modulename); if (!module) { - module = new TModuleDocInfo(modulename); - - TString moduledir; - if (modulename == "MATHCORE") - moduledir = "mathcore/src"; - else if (modulename == "MATHMORE") - moduledir = "mathmore/src"; - else if (modulename == "REFLEX") - moduledir = "reflex/src"; - else if (modulename == "TMVA") - moduledir = "tmva/src"; - else if (modulename == "SMATRIX") - moduledir = "smatrix/src"; - if (moduledir.Length()) - module->SetSourceDir(moduledir); - - module->SetSelected(kFALSE); - fModules.Add(module); - } - if (module) { - if (!strcmp(module->GetName(), "REFLEX") - // take class doc from header, so ignore sources: - //|| !strcmp(module->GetName(), "MATHCORE") - //|| !strcmp(module->GetName(), "MATHMORE") - ) { - TString srcFile = gSystem->BaseName(impname); - srcFile.ReplaceAll(".h", ".cxx"); - gSystem->PrependPathName(module->GetSourceDir(), srcFile); - if (!gSystem->AccessPathName(srcFile)) - SetImplFileName(classPtr, srcFile); + bool moduleSelected = cdi->IsSelected(); + + TString parentModuleName(gSystem->DirName(modulename)); + TModuleDocInfo* super = 0; + if (parentModuleName.Length() && parentModuleName != ".") { + super = (TModuleDocInfo*) fDocEntityInfo.fModules.FindObject(parentModuleName); + if (!super) { + // create parents: + TString token; + Ssiz_t pos = 0; + while (parentModuleName.Tokenize(token, pos, "/")) { + if (!token.Length() || token == ".") continue; + super = new TModuleDocInfo(token, super); + super->SetSelected(moduleSelected); + fDocEntityInfo.fModules.Add(super); + } + } } + module = new TModuleDocInfo(modulename, super); + module->SetSelected(moduleSelected); + fDocEntityInfo.fModules.Add(module); + } + if (module) { module->AddClass(cdi); cdi->SetModule(module); if (cdi->HaveSource() && cdi->IsSelected()) module->SetSelected(); - if (cdi->HaveSource() && !module->GetSourceDir().Length()) { - TString realfile(GetImplFileName(classPtr)); - if (gSystem->FindFile(fSourceDir, realfile, kReadPermission)) - module->SetSourceDir(gSystem->DirName(realfile)); - } } - delete[] realFile; } - fClasses.Sort(); - fModules.Sort(); + fDocEntityInfo.fClasses.Sort(); + fDocEntityInfo.fModules.Sort(); if (fProductName == "(UNKNOWN PRODUCT)" - && fModules.FindObject("BASE") - && fModules.FindObject("CONT") - && fModules.FindObject("RINT") + && fDocEntityInfo.fModules.FindObject("core/base") + && fDocEntityInfo.fModules.FindObject("core/cont") + && fDocEntityInfo.fModules.FindObject("core/rint") && gProgName && strstr(gProgName, "root")) // if we have these modules we're probably building the root doc fProductName = "ROOT"; @@ -1090,7 +1582,7 @@ void THtml::GetDerivedClasses(TClass* cl, std::map<TClass*, Int_t>& derived) con // fill derived with all classes inheriting from cl and their inheritance // distance to cl - TIter iClass(&fClasses); + TIter iClass(&fDocEntityInfo.fClasses); TClassDocInfo* cdi = 0; while ((cdi = (TClassDocInfo*) iClass())) { TClass* candidate = cdi->GetClass(); @@ -1116,51 +1608,6 @@ void THtml::GetDerivedClasses(TClass* cl, std::map<TClass*, Int_t>& derived) con } } -//______________________________________________________________________________ -const char *THtml::GetFileName(const char *filename) const -{ -// It discards any directory information inside filename -// -// -// Input: filename - pointer to the file name -// -// Output: pointer to the string containing just a file name -// without any other directory information, i.e. -// '/usr/root/test.dat' will return 'test.dat' -// - - if (!filename || !filename[0]) return ""; - return gSystem->BaseName(filename); -} - -//______________________________________________________________________________ -void THtml::GetSourceFileName(TString& filename) -{ - // Find the source file. If filename contains a path it will be used - // together with the possible source prefix. If not found we try - // old algorithm, by stripping off the path and trying to find it in the - // specified source search path. - - TString found(filename); - - if (strchr(filename, '/') -#ifdef WIN32 - || strchr(filename, '\\') -#endif - ){ - TString found(fSourcePrefix); - if (found.Length()) - gSystem->PrependPathName(found, filename); - gSystem->FindFile(fSourceDir, filename, kReadPermission); - if (filename.Length()) - return; - } - - filename = GetFileName(filename); - if (filename.Length()) - gSystem->FindFile(fSourceDir, filename, kReadPermission); -} - //______________________________________________________________________________ void THtml::GetHtmlFileName(TClass * classPtr, TString& filename) const { @@ -1175,13 +1622,13 @@ void THtml::GetHtmlFileName(TClass * classPtr, TString& filename) const filename.Remove(0); if (!classPtr) return; - const char* cFilename = GetImplFileName(classPtr); - if (!cFilename || !cFilename[0]) - cFilename = GetDeclFileName(classPtr); + TString cFilename; + if (!GetImplFileName(classPtr, kFALSE, cFilename)) + GetDeclFileName(classPtr, kFALSE, cFilename); // classes without Impl/DeclFileName don't have docs, // and classes without docs don't have output file names - if (!cFilename || !cFilename[0]) + if (!cFilename.Length()) return; TString libName; @@ -1213,7 +1660,7 @@ void THtml::GetHtmlFileName(TClass * classPtr, TString& filename) const filename = cFilename; TString htmlFileName; if (!filename.Length() || - !gSystem->FindFile(fSourceDir, filename, kReadPermission)) { + !gSystem->FindFile(fPathInfo.fInputPath, filename, kReadPermission)) { htmlFileName = GetURL(libName); } else htmlFileName = "./"; @@ -1235,7 +1682,7 @@ const char* THtml::GetHtmlFileName(const char* classname) const { // Get the html file name for a class named classname. // Returns 0 if the class is not documented. - TClassDocInfo* cdi = (TClassDocInfo*) fClasses.FindObject(classname); + TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(classname); if (cdi) return cdi->GetHtmlFileName(); return 0; @@ -1256,7 +1703,7 @@ TClass *THtml::GetClass(const char *name1) const if (ret) return 0; } - TClassDocInfo* cdi = (TClassDocInfo*)fClasses.FindObject(name1); + TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(name1); if (!cdi) return 0; TClass *cl=cdi->GetClass(); // hack to get rid of prec_stl types @@ -1266,31 +1713,79 @@ TClass *THtml::GetClass(const char *name1) const strstr(GetDeclFileName(cl),"prec_stl/")) cl = 0; */ - if (cl && GetDeclFileName(cl) && GetDeclFileName(cl)[0]) + TString declFileName; + if (cl && GetDeclFileName(cl, kFALSE, declFileName)) return cl; return 0; } //______________________________________________________________________________ -const char* THtml::GetDeclFileName(TClass * cl) const +bool THtml::GetDeclFileName(TClass * cl, Bool_t filesys, TString& out_name) const { - // Return declaration file name - - R__LOCKGUARD(GetMakeClassMutex()); - std::map<TClass*,std::string>::const_iterator iClDecl = fGuessedDeclFileNames.find(cl); - if (iClDecl == fGuessedDeclFileNames.end()) return cl->GetDeclFileName(); - return iClDecl->second.c_str(); + // Return declaration file name; return the full path if filesys is true. + return GetDeclImplFileName(cl, filesys, true, out_name); } //______________________________________________________________________________ -const char* THtml::GetImplFileName(TClass * cl) const +bool THtml::GetImplFileName(TClass * cl, Bool_t filesys, TString& out_name) const { // Return implementation file name + return GetDeclImplFileName(cl, filesys, false, out_name); +} + +//______________________________________________________________________________ +bool THtml::GetDeclImplFileName(TClass * cl, bool filesys, bool decl, TString& out_name) const +{ + // Combined implementation for GetDeclFileName(), GetImplFileName(): + // Return declaration / implementation file name (depending on decl); + // return the full path if filesys is true. + + out_name = ""; R__LOCKGUARD(GetMakeClassMutex()); - std::map<TClass*,std::string>::const_iterator iClImpl = fGuessedImplFileNames.find(cl); - if (iClImpl == fGuessedImplFileNames.end()) return cl->GetImplFileName(); - return iClImpl->second.c_str(); + TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName()); + // whether we need to determine the fil name + bool determine = (!cdi); // no cdi + if (!determine) determine |= decl && filesys && !cdi->GetDeclFileSysName()[0]; + if (!determine) determine |= decl && !filesys && !cdi->GetDeclFileName()[0]; + if (!determine) determine |= !decl && filesys && !cdi->GetImplFileSysName()[0]; + if (!determine) determine |= !decl && !filesys && !cdi->GetImplFileName()[0]; + if (determine) { + TString name; + TString sysname; + if (decl) { + if (!GetFileDefinition().GetDeclFileName(cl, name, sysname)) + return false; + } else { + if (!GetFileDefinition().GetImplFileName(cl, name, sysname)) + return false; + } + if (cdi) { + if (decl) { + if (!cdi->GetDeclFileName() || !cdi->GetDeclFileName()[0]) + cdi->SetDeclFileName(name); + if (!cdi->GetDeclFileSysName() || !cdi->GetDeclFileSysName()[0]) + cdi->SetDeclFileSysName(sysname); + } else { + if (!cdi->GetImplFileName() || !cdi->GetImplFileName()[0]) + cdi->SetImplFileName(name); + if (!cdi->GetImplFileSysName() || !cdi->GetImplFileSysName()[0]) + cdi->SetImplFileSysName(sysname); + } + } + + if (filesys) out_name = sysname; + else out_name = name; + return true; + } + if (filesys) { + if (decl) out_name = cdi->GetDeclFileSysName(); + else out_name = cdi->GetImplFileSysName(); + } else { + if (decl) out_name = cdi->GetDeclFileName(); + else out_name = cdi->GetImplFileName(); + } + return true; } //______________________________________________________________________________ @@ -1302,19 +1797,19 @@ const TString& THtml::GetOutputDir(Bool_t createDir /*= kTRUE*/) const if (createDir) { R__LOCKGUARD(GetMakeClassMutex()); - gSystem->ExpandPathName(const_cast<THtml*>(this)->fOutputDir); + gSystem->ExpandPathName(const_cast<THtml*>(this)->fPathInfo.fOutputDir); Long64_t sSize; Long_t sId, sFlags, sModtime; - Int_t st = gSystem->GetPathInfo(fOutputDir, &sId, &sSize, &sFlags, &sModtime); + Int_t st = gSystem->GetPathInfo(fPathInfo.fOutputDir, &sId, &sSize, &sFlags, &sModtime); if (st || !(sFlags & 2)) { if (st == 0) Error("GetOutputDir", "output directory %s is an existing file", - fOutputDir.Data()); - else if (gSystem->MakeDirectory(fOutputDir) == -1) - Error("GetOutputDir", "output directory %s does not exist and can't create it", fOutputDir.Data()); + fPathInfo.fOutputDir.Data()); + else if (gSystem->MakeDirectory(fPathInfo.fOutputDir) == -1) + Error("GetOutputDir", "output directory %s does not exist and can't create it", fPathInfo.fOutputDir.Data()); } } - return fOutputDir; + return fPathInfo.fOutputDir; } //______________________________________________________________________________ @@ -1393,13 +1888,13 @@ void THtml::MakeAll(Bool_t force, const char *filter, int numthreads /*= -1*/) if (numthreads == 1) { // CreateListOfClasses(filter); already done by MakeIndex TClassDocInfo* classinfo = 0; - TIter iClassInfo(&fClasses); + TIter iClassInfo(&fDocEntityInfo.fClasses); UInt_t count = 0; while ((classinfo = (TClassDocInfo*)iClassInfo())) { if (!classinfo->IsSelected()) continue; - fCounter.Form("%5d", fClasses.GetSize() - count++); + fCounter.Form("%5d", fDocEntityInfo.fClasses.GetSize() - count++); MakeClass(classinfo, force); } } else { @@ -1411,7 +1906,7 @@ void THtml::MakeAll(Bool_t force, const char *filter, int numthreads /*= -1*/) numthreads = 2; } fThreadedClassCount = 0; - fThreadedClassIter = new TIter(&fClasses); + fThreadedClassIter = new TIter(&fDocEntityInfo.fClasses); THtmlThreadInfo hti(this, force); if (!fMakeClassMutex && gGlobalMutex) { gGlobalMutex->Lock(); @@ -1455,7 +1950,7 @@ void THtml::MakeClass(const char *className, Bool_t force) // CreateListOfClasses("*"); - TClassDocInfo* cdi = (TClassDocInfo*)fClasses.FindObject(className); + TClassDocInfo* cdi = (TClassDocInfo*)fDocEntityInfo.fClasses.FindObject(className); if (!cdi) { if (!TClassEdit::IsStdClass(className)) // stl classes won't be available, so no warning Error("MakeClass", "Unknown class '%s'!", className); @@ -1473,7 +1968,7 @@ void THtml::MakeClass(void *cdi_void, Bool_t force) // // Input: cdi - doc info for class to process // - if (!fClasses.GetSize()) + if (!fDocEntityInfo.fClasses.GetSize()) CreateListOfClasses("*"); TClassDocInfo* cdi = (TClassDocInfo*) cdi_void; @@ -1562,23 +2057,55 @@ void THtml::MakeTree(const char *className, Bool_t force) } //______________________________________________________________________________ -void THtml::SetSourcePrefix(const char *prefix) +void THtml::SetFoundDot(Bool_t found) { + // Set whether "dot" (a GraphViz utility) is avaliable + if (found) fPathInfo.fFoundDot = TPathInfo::kDotFound; + else fPathInfo.fFoundDot = TPathInfo::kDotNotFound; +} + +//______________________________________________________________________________ +void THtml::SetLocalFiles() const { - // Sets the source prefix, see GetSourceFileName(). - // Also resets the class structure, in case new files can - // be found after this call. + // Fill the files available in the file system below fPathInfo.fInputPath + if (fLocalFiles) delete fLocalFiles; + fLocalFiles = new TFileSysDB(fPathInfo.fInputPath, fPathInfo.fIgnorePath + "|(\\b" + GetOutputDir(kFALSE) + "\\b)" , 6); +} + +//______________________________________________________________________________ +void THtml::SetModuleDefinition(const TModuleDefinition& md) +{ + // Set the module defining object to be used; can also be a user derived + // object (a la traits). + delete fModuleDef; + fModuleDef = (TModuleDefinition*) md.Clone(); + fModuleDef->SetOwner(const_cast<THtml*>(this)); +} - fSourcePrefix = prefix; - // reset class table - fClasses.Clear(); - fModules.Clear(); - fGuessedDeclFileNames.clear(); - fGuessedImplFileNames.clear(); +//______________________________________________________________________________ +void THtml::SetFileDefinition(const TFileDefinition& md) +{ + // Set the file defining object to be used; can also be a user derived + // object (a la traits). + delete fFileDef; + fFileDef = (TFileDefinition*) md.Clone(); + fFileDef->SetOwner(const_cast<THtml*>(this)); } + //______________________________________________________________________________ -void THtml::SetSourceDir(const char *dir) +void THtml::SetPathDefinition(const TPathDefinition& md) +{ + // Set the path defining object to be used; can also be a user derived + // object (a la traits). + delete fPathDef; + fPathDef = (TPathDefinition*) md.Clone(); + fPathDef->SetOwner(const_cast<THtml*>(this)); +} + + +//______________________________________________________________________________ +void THtml::SetInputDir(const char *dir) { // Set the directory containing the source files. // The source file for a class MyClass will be searched @@ -1588,25 +2115,33 @@ void THtml::SetSourceDir(const char *dir) // Also resets the class structure, in case new files can // be found after this call. - fSourceDir = dir; + fPathInfo.fInputPath = dir; // reset class table - fClasses.Clear(); - fModules.Clear(); - fGuessedDeclFileNames.clear(); - fGuessedImplFileNames.clear(); + fDocEntityInfo.fClasses.Clear(); + fDocEntityInfo.fModules.Clear(); } //______________________________________________________________________________ void THtml::SetDeclFileName(TClass* cl, const char* filename) { // Explicitly set a decl file name for TClass cl. - fGuessedDeclFileNames[cl] = filename; + TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName()); + if (!cdi) { + cdi = new TClassDocInfo(cl, "" /*html*/, "" /*fsdecl*/, "" /*fsimpl*/, filename); + fDocEntityInfo.fClasses.Add(cdi); + } else + cdi->SetDeclFileName(filename); } //______________________________________________________________________________ void THtml::SetImplFileName(TClass* cl, const char* filename) { // Explicitly set a impl file name for TClass cl. - fGuessedImplFileNames[cl] = filename; + TClassDocInfo* cdi = (TClassDocInfo*) fDocEntityInfo.fClasses.FindObject(cl->GetName()); + if (!cdi) { + cdi = new TClassDocInfo(cl, "" /*html*/, "" /*fsdecl*/, "" /*fsimpl*/, 0 /*decl*/, filename); + fDocEntityInfo.fClasses.Add(cdi); + } else + cdi->SetImplFileName(filename); }