// @(#)root/html:$Name: not supported by cvs2svn $:$Id: MHtml.cc,v 1.2 2001-04-18 15:26:04 tbretz Exp $ // Author: Nenad Buncic 18/10/95 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include "TROOT.h" #include "TBaseClass.h" #include "TVirtualPad.h" #include "TClass.h" #include "TClassTable.h" #include "TDataMember.h" #include "TDataType.h" #include "TDatime.h" #include "TEnv.h" #include "TError.h" #include "MHtml.h" #include "TMethod.h" #include "TSystem.h" #include "TString.h" #include "TInterpreter.h" #include #include #include #include MHtml *gHtml = 0; const Int_t kSpaceNum = 1; const char *formatStr = "%12s %5s %s"; enum ESortType {kCaseInsensitive, kCaseSensitive}; enum EFileType {kSource, kInclude, kTree}; //////////////////////////////////////////////////////////////////////////////// // // This is some kind of clone of the Root THtml class. I didn't change // anything, but enhanced the functionality a little bit. // // The HyperText Markup Language (HTML) is a simple data format used to // create hypertext documents that are portable from one platform to another. // HTML documents are SGML documents with generic semantics that are // appropriate for representing information from a wide range of domains. // // The MHtml class is designed to provide an easy way for converting ROOT // classes, and files as well, into HTML documents. Here is the few rules // and suggestions for a configuration, coding and usage. // // // Configuration: // ------------- // // The output directory could be specified using the Root.Html.OutputDir // environment variable ( default value: "html/" ). Also it is necessary to // define Root.Html.SourceDir to point to directories containing .cxx and .h // files ( see: TEnv ). // // Examples: // Root.Html.OutputDir: html // Root.Html.SourceDir: src:include:.:/usr/user/source // Root.Html.Root: http://root.cern.ch/root/html // // // During the conversion, MHtml will look for the certain number of // user defined strings, i.e. author's name, copyright note, etc. // This could be defined with following environment variables: // // Root.Html.Author ( default: // Author:) // Root.Html.LastUpdate ( default: // @(#)) // Root.Html.Copyright ( default: * Copyright) // // // // Coding rules: // ------------ // // A class description block, which must be placed before the first // member function, has a following form: // // //////////////////////////////////////////////////////////////// // // // // // TMyClass // // // // // // This is the description block. // // // // // //////////////////////////////////////////////////////////////// // // The environment variable Root.Html.Description ( see: TEnv ) contents // the delimiter string ( default value: //_________________ ). It means // that you can also write your class description block like this: // // //_____________________________________________________________ // // A description of the class starts with the line above, and // // will take place here ! // // // // Note that EVERYTHING until the first non-commented line is considered // as a valid class description block. // // A member function description block starts immediately after '{' // and looks like this: // // void TWorld::HelloWorldFunc( string *text ) // { // // This is an example of description for the // // TWorld member function // // helloWorld.Print( text ); // } // // Like in a class description block, EVERYTHING until the first // non-commented line is considered as a valid member function // description block. // // ==> The "Begin_Html" and "End_Html" special keywords <========= // -------------------------------------------- // You can insert pure html code in your comment lines. During the // generation of the documentation, this code will be inserted as is // in the html file. // Pure html code must be inserted between the keywords "Begin_Html" // and "End_Html" starting/finishing anywhere in the comment lines. // Examples of pure html code are given in many Root classes. // See for example the classes TDataMember and TMinuit. // // ==> The escape character // -------------------- // Outside blocks starting with "Begin_Html" and finishing with "End_Html" // one can prevent the automatic translation of symbols like "<" and ">" // to "<" and ">" by using the escape character in front. // The default escape character is backslash and can be changed // via the member function SetEscape. // // Usage: // ----- // // Root> gHtml.MakeAll // invoke a make for all classes // Root> gHtml.MakeClass( TMyClass ) // create a HTML files for that class only // Root> gHtml.MakeIndex() // creates an index files only // Root> gHtml.MakeTree( TMyClass ) // creates an inheritance tree for a class // // Root> gHtml.Convert( hist1.mac, "Histogram example" ) // // // Environment variables: // --------------------- // // Root.Html.OutputDir ( default: htmldoc/) // Root.Html.SourceDir ( default: .:src/:include/) // Root.Html.Author ( default: // Author:) // Root.Html.LastUpdate ( default: // @(#)) // Root.Html.Copyright ( default: * Copyright) // Root.Html.Description ( default: //____________________ ) // Root.Html.HomePage ( URL to the user defined home page ) // Root.Html.SearchEngine ( link to the search engine ) // //////////////////////////////////////////////////////////////////////////////// ClassImp( MHtml ) //______________________________________________________________________________ MHtml::MHtml() { // Create a MHtml object. Use object directly or via the global // pointer gHtml. In case output directory does not exist an error // will be printed and gHtml stays 0 also zombie bit will be set. fLen = 1024; fLine = new char [fLen]; fCounter = new char [6]; fEscFlag = kFALSE; SetEscape(); // get prefix for source directory fSourcePrefix = gEnv->GetValue( "Root.Html.SourcePrefix", ""); // check for source directory fSourceDir = gEnv->GetValue( "Root.Html.SourceDir", "./:src/:include/" ); // check for output directory fOutputDir = gEnv->GetValue( "Root.Html.OutputDir", "htmldoc/" ); fXwho = "http://consult.cern.ch/xwho/people?"; Int_t st; Long_t sId, sSize, sFlags, sModtime; if ((st = gSystem->GetPathInfo(fOutputDir, &sId, &sSize, &sFlags, &sModtime)) || !(sFlags & 2)) { if (st == 0) { Error("MHtml", "output directory %s is an existing file", fOutputDir); MakeZombie(); return; } // Try creating directory if (gSystem->MakeDirectory(fOutputDir) == -1) { Error("MHtml", "output directory %s does not exist", fOutputDir); MakeZombie(); return; } } // insert html object in the list of special ROOT objects gHtml = this; gROOT->GetListOfSpecials()->Add(gHtml); } //______________________________________________________________________________ MHtml::~MHtml() { // Default destructor if( fLine ) delete [] fLine; if( fCounter ) delete [] fCounter; fSourceDir = 0; fLen = 0; } //______________________________________________________________________________ int CaseSensitiveSort( const void *name1, const void *name2 ) { // Friend function for sorting strings, case sensitive // // // Input: name1 - pointer to the first string // name2 - pointer to the second string // // NOTE: This function compares its arguments and returns an integer less // than, equal to, or greater than zero, depending on whether name1 // is lexicographically less than, equal to, or greater than name2. // // return( strcmp( *( (char **) name1 ), *( (char **) name2 )) ); } //______________________________________________________________________________ int CaseInsensitiveSort( const void *name1, const void *name2 ) { // Friend function for sorting strings, case insensitive // // // Input: name1 - pointer to the first string // name2 - pointer to the second string // // NOTE: This function compares its arguments and returns an integer less // than, equal to, or greater than zero, depending on whether name1 // is lexicographically less than, equal to, or greater than name2, // but characters are forced to lower-case prior to comparison. // // return( strcasecmp( *( (char **) name1 ), *( (char **) name2 )) ); } //______________________________________________________________________________ void MHtml::Class2Html( TClass *classPtr, Bool_t force ) { // It creates HTML file for a single class // // // Input: classPtr - pointer to the class const char *tab = ""; const char *tab2 = " "; const char *tab4 = " "; const char *tab6 = " "; gROOT->GetListOfGlobals( kTRUE ); // create a filename char *tmp1 = gSystem->ExpandPathName( fOutputDir ); char *tmp2 = gSystem->ConcatFileName( tmp1, classPtr->GetName() ); char *filename = StrDup( tmp2, 6 ); strcat( filename, ".html" ); if( tmp1 ) delete [] tmp1; if( tmp2 ) delete [] tmp2; tmp1 = tmp2 = 0; if( IsModified( classPtr, kSource ) || force ) { // open class file ofstream classFile; classFile.open( filename, ios::out ); Bool_t classFlag = kFALSE; if( classFile.good() ) { Printf( formatStr, "", fCounter, filename ); // write a HTML header for the classFile file WriteHtmlHeader( classFile, classPtr->GetName() ); // make a link to the description classFile << "" << endl; classFile << "
" << endl; classFile << "

" << classPtr->GetName() << "

" << endl; classFile << "
" << endl; classFile << "GetName() << ":description>class description"; // make a link to the '.cxx' file classFile << " - GetName() << ".cxx.html\""; classFile << ">source file"; // make a link to the inheritance tree classFile << " - GetName() << "_Tree.ps\""; classFile << ">inheritance tree"; classFile << "" << endl; classFile << "
" << endl; classFile << "
" << endl; // make a link to the '.h' file classFile << "

" << "class GetName() << "\" href=\""; classFile << GetFileName( (const char * ) classPtr->GetDeclFileName() ) << "\""; classFile << ">" << classPtr->GetName() << " "; // copy .h file to the Html output directory char *declf = GetSourceFileName(classPtr->GetDeclFileName()); CopyHtmlFile(declf); delete [] declf; // make a loop on base classes Bool_t first = kTRUE; TBaseClass *inheritFrom; TIter nextBase( classPtr->GetListOfBases() ); while (( inheritFrom = ( TBaseClass * ) nextBase() )) { if( first ) { classFile << ": "; first = kFALSE; } else classFile << ", "; classFile << "public "; // get a class TClass *classInh = GetClass( (const char * ) inheritFrom->GetName() ); char *htmlFile = GetHtmlFileName( classInh ); if( htmlFile ) { classFile << "" << inheritFrom->GetName() << ""; delete [] htmlFile; htmlFile = 0; } else classFile << inheritFrom->GetName(); } classFile << "

" << endl; classFile << "
" << endl;


            // make a loop on member functions
            TMethod *method;
            TIter nextMethod( classPtr->GetListOfMethods() );

            Int_t len, maxLen[3];
            len = maxLen[0] = maxLen[1] = maxLen[2] = 0;

            // loop to get a pointers to a method names
            const Int_t nMethods = classPtr->GetNmethods();
            const char **methodNames = new const char*[3*2*nMethods];

            Int_t mtype, num[3];
            mtype = num[0] = num[1] = num[2] = 0;

            while (( method = ( TMethod * ) nextMethod() )) {

                if(
                    !strcmp( method->GetName(), "Dictionary"    ) ||
                    !strcmp( method->GetName(), "Class_Version" ) ||
                    !strcmp( method->GetName(), "Class_Name"    ) ||
                    !strcmp( method->GetName(), "DeclFileName"  ) ||
                    !strcmp( method->GetName(), "DeclFileLine"  ) ||
                    !strcmp( method->GetName(), "ImplFileName"  ) ||
                    !strcmp( method->GetName(), "ImplFileLine"  )
                ) continue;


                if( kIsPrivate & method->Property() )
                    mtype = 0;
                else if( kIsProtected & method->Property() )
                    mtype = 1;
                else if( kIsPublic & method->Property() )
                    mtype = 2;

                methodNames[mtype*2*nMethods+2*num[mtype]] = method->GetName();

                if (method->GetReturnTypeName() ) len = strlen( method->GetReturnTypeName() );
                else len = 0;

                if( kIsVirtual & method->Property() ) len += 8;
                if( kIsStatic & method->Property() ) len += 7;

                maxLen[mtype] = maxLen[mtype] > len ? maxLen[mtype] : len;

                const char* type = strrchr( method->GetReturnTypeName(), ' ' );
                if( ! type ) type = method->GetReturnTypeName();
                else type++;

                if( classPtr && !strcmp( type, classPtr->GetName() ))
                    methodNames[mtype*2*nMethods+2*num[mtype]] = "A00000000";

                // if this is the destructor
                while( '~' == *methodNames[mtype*2*nMethods+2*num[mtype]] )
                    methodNames[mtype*2*nMethods+2*num[mtype]] = "A00000001";

                methodNames[mtype*2*nMethods+2*num[mtype]+1] = (char *) method;

                num[mtype]++;
            }

            Int_t i, j;

            for( j = 0; j < 3; j ++ ) {
                if( *( methodNames+j*2*nMethods ) ) {
                    qsort( methodNames+j*2*nMethods, num[j], 2*sizeof( methodNames ), CaseInsensitiveSort );

                    const char *ftitle = 0;
                    switch( j ) {
                        case 0: ftitle = "private:";
                                break;
                        case 1: ftitle = "protected:";
                                break;
                        case 2: ftitle = "public:";
                                break;
                    }
                    if( j ) classFile << endl;
                    classFile << tab4 << "" << ftitle << "
" << endl; for( i = 0; i < num[j]; i++ ) { method = (TMethod *) methodNames[j*2*nMethods+2*i+1]; if( method ) { Int_t w = 0; if( method->GetReturnTypeName() ) len = strlen( method->GetReturnTypeName() ); else len = 0; if( kIsVirtual & method->Property() ) len += 8; if( kIsStatic & method->Property() ) len += 7; classFile << tab6; for( w = 0; w < ( maxLen[j]-len ); w++ ) classFile << " "; if( kIsVirtual & method->Property() ) classFile << "virtual "; if( kIsStatic & method->Property() ) classFile << "static "; strcpy( fLine, method->GetReturnTypeName() ); ExpandKeywords( classFile, fLine, classPtr, classFlag ); classFile << " " << tab << ""; classFile << "GetName(); classFile << ":"; ReplaceSpecialChars( classFile, method->GetName() ); classFile << "\">"; ReplaceSpecialChars( classFile, method->GetName() ); classFile << ""; strcpy( fLine, method->GetSignature() ); ExpandKeywords( classFile, fLine, classPtr, classFlag ); classFile << endl; } } } } delete [] methodNames; // make a loop on data members first = kFALSE; TDataMember *member; TIter nextMember( classPtr->GetListOfDataMembers() ); Int_t len1, len2, maxLen1[3], maxLen2[3]; len1 = len2 = maxLen1[0] = maxLen1[1] = maxLen1[2] = 0; maxLen2[0] = maxLen2[1] = maxLen2[2] = 0; mtype = num[0] = num[1] = num[2] = 0; Int_t ndata = classPtr->GetNdata(); // if data member exist if( ndata ) { TDataMember **memberArray = new TDataMember*[3*ndata]; if( memberArray ) { while (( member = ( TDataMember * ) nextMember() )) { if( !strcmp( member->GetName(), "fgIsA" ) ) continue; if( kIsPrivate & member->Property() ) mtype = 0; else if( kIsProtected & member->Property() ) mtype = 1; else if( kIsPublic & member->Property() ) mtype = 2; memberArray[mtype*ndata+num[mtype]] = member; num[mtype]++; if( member->GetFullTypeName() ) len1 = strlen( (char * ) member->GetFullTypeName() ); else len1 = 0; if( member->GetName() ) len2 = strlen( member->GetName() ); else len2 = 0; if( kIsStatic & member->Property() ) len1 += 7; // Take in account the room the array index will occupy Int_t dim = member->GetArrayDim(); Int_t indx = 0; while (indx < dim ){ indx++; len2 += Int_t(TMath::Log10(member->GetMaxIndex(indx))) + 3; } maxLen1[mtype] = maxLen1[mtype] > len1 ? maxLen1[mtype] : len1; maxLen2[mtype] = maxLen2[mtype] > len2 ? maxLen2[mtype] : len2; } classFile << endl; classFile << "

" << tab2 << "GetName(); classFile << ":Data Members\">Data Members

" << endl; for( j = 0; j < 3; j++ ) { if( memberArray[j*ndata] ) { const char *ftitle = 0; switch( j ) { case 0: ftitle = "private:"; break; case 1: ftitle = "protected:"; break; case 2: ftitle = "public:"; break; } if( j ) classFile << endl; classFile << tab4 << "" << ftitle << "
" << endl; for( i = 0; i < num[j]; i++ ) { Int_t w = 0; member = memberArray[j*ndata+i]; classFile << tab6; if ( member->GetFullTypeName() ) len1 = strlen( member->GetFullTypeName() ); else len1 = 0; if( kIsStatic & member->Property() ) len1 += 7; for( w = 0; w < ( maxLen1[j]-len1 ); w++ ) classFile << " "; if( kIsStatic & member->Property() ) classFile << "static "; strcpy( fLine, member->GetFullTypeName() ); ExpandKeywords( classFile, fLine, classPtr, classFlag ); classFile << " " << tab << ""; classFile << "GetName() << ":"; classFile << member->GetName(); classFile << "\">" << member->GetName(); // Add the dimensions to "array" members Int_t dim = member->GetArrayDim(); Int_t indx = 0; Int_t indxlen = 0; while (indx < dim ){ classFile << "[" << member->GetMaxIndex(indx)<<"]"; // Take in account the room this index will occupy indxlen += Int_t(TMath::Log10(member->GetMaxIndex(indx))) + 3; indx++; } classFile << " "; len2 = 0; if( member->GetName() ) len2 = strlen( member->GetName() ) + indxlen; for( w = 0; w < ( maxLen2[j]-len2 ); w++ ) classFile << " "; classFile << " " << tab; classFile << "GetName(); classFile << "\">"; strcpy( fLine, member->GetTitle() ); ReplaceSpecialChars( classFile, fLine ); classFile << "" << endl; } } } classFile << "
" << endl; delete [] memberArray; } } classFile << "" << endl; // create a 'See also' part DerivedClasses( classFile, classPtr ); // process a '.cxx' file ClassDescription( classFile, classPtr, classFlag ); // close a file classFile.close(); } else Error( "Make", "Can't open file '%s' !", filename ); } else Printf( formatStr, "-no change-", fCounter, filename ); if( filename ) delete [] filename; filename = 0; } //______________________________________________________________________________ void MHtml::ClassDescription( ofstream &out, TClass *classPtr, Bool_t &flag ) { // This function builds the description of the class // // // Input: out - output file stream // classPtr - pointer to the class // flag - this is a 'begin_html/end_html' flag // char *ptr, *key; Bool_t tempFlag = kFALSE; char *filename = 0; // allocate memory char *nextLine = new char [256]; char *pattern = new char [80]; char *lastUpdate = new char [256]; char *author = new char [80]; char *copyright = new char [80]; char *funcName = new char [64]; const char *lastUpdateStr; const char *authorStr; const char *copyrightStr; const char *descriptionStr; // just in case *lastUpdate = *author = *copyright = 0; // define pattern strcpy( pattern, classPtr->GetName() ); strcat( pattern, "::" ); Int_t len = strlen( pattern ); // get environment variables lastUpdateStr = gEnv->GetValue( "Root.Html.LastUpdate", "// @(#)" ); authorStr = gEnv->GetValue( "Root.Html.Author", "// Author:" ); copyrightStr = gEnv->GetValue( "Root.Html.Copyright", " * Copyright" ); descriptionStr = gEnv->GetValue( "Root.Html.Description", "//____________________" ); // find a .cxx file char *tmp1 = GetSourceFileName(classPtr->GetImplFileName()); char *realFilename = StrDup( tmp1, 16 ); if( !realFilename ) Error( "Make", "Can't find file '%s' !", tmp1 ); if( tmp1 ) delete [] tmp1; tmp1 = 0; Bool_t classDescription = kTRUE; Bool_t foundLastUpdate = kFALSE; Bool_t foundAuthor = kFALSE; Bool_t foundCopyright = kFALSE; Bool_t firstCommentLine = kTRUE; Bool_t extractComments = kFALSE; Bool_t thisLineIsCommented = kFALSE; Bool_t thisLineIsPpLine = kFALSE; Bool_t postponeMemberDescr = kFALSE; Bool_t skipMemberName = kFALSE; Bool_t writeBracket = kFALSE; streampos postponedpos = 0; // Class Description Title out << "
" << endl; out << ""; out << "

GetName(); out << ":description\">Class Description

" << endl; // open source file ifstream sourceFile; sourceFile.open( realFilename, ios::in ); if( sourceFile.good() ) { // open a .cxx.html file tmp1 = gSystem->ExpandPathName( fOutputDir ); char *tmp2 = gSystem->ConcatFileName( tmp1, "src" ); char *dirname = StrDup( tmp2 ); if( tmp1 ) delete [] tmp1; if( tmp2 ) delete [] tmp2; tmp1 = tmp2 = 0; // create directory if necessary if( gSystem->AccessPathName( dirname )) gSystem->MakeDirectory( dirname ); tmp1 = gSystem->ConcatFileName( dirname, classPtr->GetName() ); filename = StrDup( tmp1, 16 ); strcat( filename, ".cxx.html" ); ofstream tempFile; tempFile.open( filename, ios::out ); if( dirname ) delete [] dirname; if( tmp1 ) delete [] tmp1; tmp1 = 0; if( tempFile.good() ) { // create an array of method names Int_t i = 0; TMethod *method; TIter nextMethod( classPtr->GetListOfMethods() ); Int_t numberOfMethods = classPtr->GetNmethods(); const char **methodNames = new const char* [2*numberOfMethods]; while (( method = ( TMethod * ) nextMethod() )) { methodNames[2*i] = method->GetName(); methodNames[2*i+1] = ( const char * ) method; i++; } // write a HTML header char *sourceTitle = StrDup( classPtr->GetName(), 16 ); strcat( sourceTitle, " - source file" ); WriteHtmlHeader( tempFile, sourceTitle ); if( sourceTitle ) delete [] sourceTitle; tempFile << "
" << endl;

            while( !sourceFile.eof() ) {

                sourceFile.getline( fLine, fLen-1 );
                if( sourceFile.eof() ) break;


                // set start & end of the line
                if (!fLine) {
                   fLine = (char *) " ";
                   Warning("ClassDescription", "found an empty line");
                }
                char *startOfLine = fLine;
                char *endOfLine   = fLine + strlen( fLine ) - 1;


                // remove leading spaces
                while( isspace( *startOfLine )) startOfLine++;

                // remove trailing spaces
                while( isspace( *endOfLine )) endOfLine--;
                if( *startOfLine == '#' && !tempFlag )
                    thisLineIsPpLine = kTRUE;

                // if this line is a comment line
                else if( !strncmp( startOfLine, "//", 2 )) {

                    thisLineIsCommented = kTRUE;
                    thisLineIsPpLine    = kFALSE;

                    // remove a repeating characters from the end of the line
                    while( (*endOfLine == *startOfLine ) &&
                            ( endOfLine >= startOfLine )) endOfLine--;
                    endOfLine++;
                    char tempChar = *endOfLine;
                    *endOfLine = 0;


                    if( extractComments) {
                        if( firstCommentLine ) {
                            out << "
";
                            firstCommentLine = kFALSE;
                        }
                        if( endOfLine >= startOfLine+2 )
                            ExpandKeywords( out, startOfLine+2, classPtr, flag );
                        out << endl;
                    }

                    *endOfLine = tempChar;

                    // if line is composed of the same characters
                    if( (endOfLine == startOfLine ) && *( startOfLine+2 ) && classDescription ) {
                        extractComments  = kTRUE;
                        classDescription = kFALSE;
                    }
                }
                else {
                    thisLineIsCommented = kFALSE;
                    if( flag ) {
                        out << fLine << endl;
                    }
                    else {
                        extractComments = kFALSE;
                        if( !firstCommentLine ) {
                            out << "
"; firstCommentLine = kTRUE; } } } // if NOT member function key = strstr( fLine, pattern ); if( !key ) { // check for a lastUpdate string if( !foundLastUpdate && lastUpdateStr) { if( !strncmp( fLine, lastUpdateStr, strlen( lastUpdateStr )) ) { strcpy( lastUpdate, fLine+strlen( lastUpdateStr )); foundLastUpdate = kTRUE; } } // check for an author string if( !foundAuthor && authorStr) { if( !strncmp( fLine, authorStr, strlen( authorStr )) ) { strcpy( author, fLine+strlen( authorStr )); foundAuthor = kTRUE; } } // check for a copyright string if( !foundCopyright && copyrightStr) { if( !strncmp( fLine, copyrightStr, strlen( copyrightStr )) ) { strcpy( copyright, fLine+strlen( copyrightStr )); foundCopyright = kTRUE; } } // check for a description comments if( descriptionStr && !strncmp( fLine, descriptionStr, strlen( descriptionStr )) ) { if( classDescription ) { // write description out classDescription = kFALSE; extractComments = kTRUE; } else { postponeMemberDescr = kTRUE; postponedpos = sourceFile.tellg(); } } } else { Bool_t found = kFALSE; // find method name char *funcName = key + len; while( *funcName && isspace( *funcName ) ) funcName++; char *nameEndPtr = funcName; // In case of destructor if( *nameEndPtr == '~' ) nameEndPtr++; while( *nameEndPtr && IsName( *nameEndPtr ) ) nameEndPtr++; char c1 = *nameEndPtr; char pe = 0; char *params, *paramsEnd; params = nameEndPtr; paramsEnd = NULL; while( *params && isspace( *params ) ) params++; if( *params != '(') params = NULL; else params++; paramsEnd = params; // if signature exist, try to find the ending character if( paramsEnd ) { Int_t count = 1; while( *paramsEnd ) { if( *paramsEnd == '(') count++; if( *paramsEnd == ')') if( !--count ) break; paramsEnd++; } pe = *paramsEnd; *paramsEnd = 0; } *nameEndPtr = 0; // get method TMethod *method; method = classPtr->GetMethodAny( funcName ); // restore characters if( paramsEnd ) *paramsEnd = pe; if( nameEndPtr ) *nameEndPtr = c1; if( method ) { if (skipMemberName) { skipMemberName = kFALSE; writeBracket = kTRUE; sourceFile.seekg(postponedpos); } else { char *typeEnd = NULL; char c2 = 0; found = kFALSE; // try to get type typeEnd = key-1; while( ( typeEnd > fLine ) && (isspace( *typeEnd ) || *typeEnd == '*') ) typeEnd--; typeEnd++; c2 = *typeEnd; *typeEnd = 0; char *type = typeEnd - 1; while( IsName( *type ) && ( type > fLine )) type--; if( !IsWord( *type )) type++; while( (type > fLine ) && isspace( *( type-1 )) ) type--; if( type > fLine ) { if( !strncmp( type-5, "const", 5 )) found = kTRUE; else found = kFALSE; } else if( type == fLine ) found = kTRUE; if( !strcmp( type, "void" ) && ( *funcName == '~' ) ) found = kTRUE; *typeEnd = c2; if( found ) { ptr = strchr( nameEndPtr, '{'); char *semicolon = strchr( nameEndPtr, ';'); if( semicolon ) if( !ptr || ( semicolon < ptr )) found = kFALSE; if( !ptr && found ) { found = kFALSE; while( sourceFile.getline( nextLine, 255 ) && fLine && nextLine && ( strlen( fLine ) < ( fLen-strlen( nextLine )) )) { strcat( fLine, "\n" ); strcat( fLine, nextLine ); if (( ptr = strchr( fLine, '{') )) { found = kTRUE; *ptr = 0; break; } } } else if( ptr ) *ptr = 0; if( found ) { char *colonPtr = strrchr( fLine, ':'); if( colonPtr > funcName ) *colonPtr = 0; if( found ) { out << "
" << endl; out << ""; if( typeEnd ) { c2 = *typeEnd; *typeEnd = 0; ExpandKeywords( out, fLine, classPtr, flag ); *typeEnd = c2; while( typeEnd < key ) { if( *typeEnd == '*') out << *typeEnd; typeEnd++; } } *nameEndPtr = 0; out << " GetName() << ":"; out << funcName << "\" href=\"src/"; out << classPtr->GetName() << ".cxx.html#" << classPtr->GetName() << ":"; ReplaceSpecialChars( out, funcName ); out << "\">"; ReplaceSpecialChars( out, funcName ); out << ""; tempFile << "GetName() << ":"; ReplaceSpecialChars( tempFile, funcName ); tempFile << "\"> "; // remove this method name from the list of methods i = 0; while( i < numberOfMethods ) { const char *mptr = methodNames[2*i]; if( mptr ) { while( *mptr == '*') mptr++; if( !strcmp( mptr, funcName )) { methodNames[2*i] = NULL; break; } } i++; } *nameEndPtr = c1; if( colonPtr ) *colonPtr = ':'; ExpandKeywords( out, nameEndPtr, classPtr, flag ); out << "
" << endl; if (postponeMemberDescr) { streampos pos = sourceFile.tellg(); sourceFile.seekg(postponedpos); postponedpos = pos; skipMemberName = kTRUE; postponeMemberDescr = kFALSE; } extractComments = kTRUE; } } if( ptr ) *ptr = '{'; } } } } // write to '.cxx.html' file if (!skipMemberName) { if( thisLineIsPpLine ) ExpandPpLine( tempFile, fLine ); else { if( thisLineIsCommented) tempFile << ""; ExpandKeywords( tempFile, fLine, classPtr, tempFlag, "../" ); if( thisLineIsCommented ) tempFile << ""; } tempFile << endl; if (writeBracket) { writeBracket = kFALSE; tempFile << "{" << endl; } } } tempFile << "
" << endl; // do some checking Bool_t inlineFunc = kFALSE; i = 0; while( i++ < numberOfMethods ) { if( methodNames[2*i] ) { inlineFunc = kTRUE; break; } } if( inlineFunc ) { out << "


" << endl; out << "

Inline Functions

" << endl; out << "
" << endl; out << "
" << endl;

                Int_t maxlen = 0, len = 0;
                for( i = 0; i < numberOfMethods; i++ ) {
                    if( methodNames[2*i] ) {
                        method = ( TMethod * ) methodNames[2*i+1];
                        if ( method->GetReturnTypeName() ) len = strlen( method->GetReturnTypeName() );
                        else len = 0;
                        maxlen = len > maxlen ? len : maxlen;
                    }
                }


                // write out an inline functions
                for( i = 0; i < numberOfMethods; i++ ) {
                    if( methodNames[2*i] ) {

                        method = ( TMethod * ) methodNames[2*i+1];

                        if( method ) {

                            if(
                                !strcmp( method->GetName(), "Dictionary"    ) ||
                                !strcmp( method->GetName(), "Class_Version" ) ||
                                !strcmp( method->GetName(), "Class_Name"    ) ||
                                !strcmp( method->GetName(), "DeclFileName"  ) ||
                                !strcmp( method->GetName(), "DeclFileLine"  ) ||
                                !strcmp( method->GetName(), "ImplFileName"  ) ||
                                !strcmp( method->GetName(), "ImplFileLine"  )
                            ) continue;

                            out << "";
                            if(method->GetReturnTypeName() ) len = strlen( method->GetReturnTypeName() );
                            else len = 0;

                            out << "      ";
                            while( len++ < maxlen+2 ) out << " ";

                            char *tmpstr = StrDup( method->GetReturnTypeName() );
                            if( tmpstr ) {
                                ExpandKeywords( out, tmpstr, classPtr, flag );
                                delete [] tmpstr;
                            }

                            out << " GetName();
                            out << ":" << method->GetName() << "\" href=\"";
                            out << GetFileName( classPtr->GetDeclFileName() ) << "\">";
                            out << method->GetName() << "";

                            strcpy( fLine, method->GetSignature() );
                            ExpandKeywords( out, fLine, classPtr, flag );
                            out << endl;
                        }
                    }
                }
                out << "
" << endl; } // write tempFile footer WriteHtmlFooter( tempFile, "../" ); // close a temp file tempFile.close(); delete [] methodNames; } else Error( "MakeClass", "Can't open file '%s' !", filename ); // close a source file sourceFile.close(); } else Error( "Make", "Can't open file '%s' !", realFilename ); // write classFile footer WriteHtmlFooter( out, "", lastUpdate, author, copyright ); // free memory if( nextLine ) delete [] nextLine; if( pattern ) delete [] pattern; if( lastUpdate ) delete [] lastUpdate; if( author ) delete [] author; if( copyright ) delete [] copyright; if( funcName ) delete [] funcName; if( realFilename ) delete [] realFilename; if( filename ) delete [] filename; } //______________________________________________________________________________ void MHtml::ClassTree( TVirtualPad *psCanvas, TClass *classPtr, Bool_t force ) { // It makes a class tree // // // Input: psCanvas - pointer to the current canvas // classPtr - pointer to the class // if( psCanvas && classPtr ) { char *tmp1 = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), classPtr->GetName() ); char *filename = StrDup( tmp1 , 16 ); strcat( filename, "_Tree.ps" ); if( tmp1 ) delete [] tmp1; tmp1 = 0; if( IsModified( classPtr, kTree ) || force ) { Printf( formatStr, "", "", filename ); classPtr->Draw( "same" ); psCanvas->SaveAs(filename); } else Printf( formatStr, "-no change-", "", filename ); if( filename ) delete [] filename; } } //______________________________________________________________________________ void MHtml::Convert( const char *filename, const char *title, const char *dirname ) { // It converts a single text file to HTML // // // Input: filename - name of the file to convert // title - title which will be placed at the top of the HTML file // dirname - optional parameter, if it's not specified, output will // be placed in html/examples directory. // // NOTE: Output file name is the same as filename, but with extension .html // const char *dir; char *ptr; Bool_t isCommentedLine = kFALSE; Bool_t tempFlag = kFALSE; // if it's not defined, make the "examples" as a default directory if( !*dirname ) { dir = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), "examples" ); // create directory if necessary if( gSystem->AccessPathName( dir )) gSystem->MakeDirectory( dir ); } else dir = dirname; // find a file char *realFilename = gSystem->Which( fSourceDir, filename, kReadPermission ); if( realFilename ) { // open source file ifstream sourceFile; sourceFile.open( realFilename, ios::in ); delete [] realFilename; realFilename = 0; if( sourceFile.good() ) { // open temp file with extension '.html' if( !gSystem->AccessPathName( dir )) { char *tmp1 = gSystem->ConcatFileName( dir, GetFileName( filename )); char *htmlFilename = StrDup( tmp1, 16 ); strcat( htmlFilename, ".html" ); if( tmp1 ) delete [] tmp1; tmp1 = 0; ofstream tempFile; tempFile.open( htmlFilename, ios::out ); if( tempFile.good() ) { Printf( "Convert: %s", htmlFilename ); // write a HTML header WriteHtmlHeader( tempFile, title ); tempFile << "

" << title << "

" << endl; tempFile << "
" << endl;

                    while( !sourceFile.eof() ) {
                        sourceFile.getline( fLine, fLen-1 );
                        if( sourceFile.eof() ) break;


                        // remove leading spaces
                        ptr = fLine;
                        while( isspace( *ptr )) ptr++;


                        // check for a commented line
                        if( !strncmp( ptr, "//", 2 )) isCommentedLine = kTRUE;
                        else isCommentedLine = kFALSE;


                        // write to a '.html' file
                        if( isCommentedLine ) tempFile << "";
                        gROOT->GetListOfGlobals(kTRUE); // force update of this list
                        ExpandKeywords( tempFile, fLine, NULL, tempFlag, "../" );
                        if( isCommentedLine ) tempFile << "";
                        tempFile << endl;
                    }
                    tempFile << "
" << endl; // write a HTML footer WriteHtmlFooter( tempFile, "../" ); // close a temp file tempFile.close(); } else Error( "Convert", "Can't open file '%s' !", htmlFilename ); // close a source file sourceFile.close(); if( htmlFilename ) delete [] htmlFilename; htmlFilename = 0; } else Error( "Convert", "Directory '%s' doesn't exist, or it's write protected !", dir ); } else Error( "Convert", "Can't open file '%s' !", realFilename ); } else Error( "Convert", "Can't find file '%s' !", filename ); } //______________________________________________________________________________ Bool_t MHtml::CopyHtmlFile( const char *sourceName, const char *destName ) { // Copy file to HTML directory // // // Input: sourceName - source file name // destName - optional destination name, if not // specified it would be the same // as the source file name // // Output: TRUE if file is successfully copied, or // FALSE if it's not // // // NOTE: The destination directory is always fOutputDir // Bool_t ret = kFALSE; Int_t check = 0; // source file name char *tmp1 = gSystem->Which( fSourceDir, sourceName, kReadPermission ); char *sourceFile = StrDup( tmp1, 16 ); if( tmp1 ) delete [] tmp1; tmp1 = 0; if( sourceFile ) { // destination file name char *tmpstr = 0; if( !*destName ) tmpstr = StrDup( GetFileName( sourceFile ), 16 ); else tmpstr = StrDup( GetFileName( destName ), 16 ); destName = tmpstr; tmp1 = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), destName ); char *filename = StrDup( tmp1, 16 ); if( tmp1 ) delete [] tmp1; tmp1 = 0; // Get info about a file Long_t sId, sSize, sFlags, sModtime; Long_t dId, dSize, dFlags, dModtime; if( !( check = gSystem->GetPathInfo( sourceFile, &sId, &sSize, &sFlags, &sModtime )) ) check = gSystem->GetPathInfo( filename, &dId, &dSize, &dFlags, &dModtime ); if( (sModtime != dModtime ) || check ) { char *cmd = new char[256]; #ifdef R__UNIX strcpy( cmd, "/bin/cp " ); strcat( cmd, sourceFile ); strcat( cmd, " " ); strcat( cmd, filename ); #endif #ifdef WIN32 strcpy( cmd, "copy \"" ); strcat( cmd, sourceFile ); strcat( cmd, "\" \"" ); strcat( cmd, filename ); strcat( cmd, "\""); char *bptr = 0; while( bptr = strchr( cmd, '/') ) *bptr = '\\'; #endif ret = !gSystem->Exec( cmd ); delete [] cmd; delete [] filename; delete [] tmpstr; delete [] sourceFile; } } else Error( "Copy", "Can't copy file '%s' to '%s' directory !", sourceName, fOutputDir ); return( ret ); } //______________________________________________________________________________ void MHtml::CreateIndex( const char **classNames, Int_t numberOfClasses ) { // Create an index // // // Input: classNames - pointer to an array of class names // numberOfClasses - number of elements // Int_t i, len, maxLen = 0; char *tmp1 = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), "ClassIndex.html" ); char *filename = StrDup( tmp1 ); if( tmp1 ) delete [] tmp1; tmp1 = 0; // open indexFile file ofstream indexFile; indexFile.open( filename, ios::out ); for( i = 0; i < numberOfClasses; i++ ) { len = strlen( classNames[i] ); maxLen = maxLen > len ? maxLen : len; } if( indexFile.good() ) { Printf( formatStr, "", fCounter, filename ); // write indexFile header WriteHtmlHeader( indexFile, "Class Index" ); indexFile << "

Index

" << endl; // check for a search engine const char *searchEngine = gEnv->GetValue( "Root.Html.SearchEngine", "" ); // if exists ... if( *searchEngine ) { // create link to search engine page indexFile << "

Search the Class Reference Guide

" << endl; } indexFile << "
" << endl; indexFile << "
" << endl;
        indexFile << "" << endl;
        indexFile << "
" << endl; // write indexFile footer TDatime date; WriteHtmlFooter( indexFile, "", date.AsString() ); // close file indexFile.close(); } else Error( "MakeIndex", "Can't open file '%s' !", filename ); if( filename ) delete [] filename; } //______________________________________________________________________________ void MHtml::CreateIndexByTopic( char **fileNames, Int_t numberOfNames, Int_t maxLen ) { // It creates several index files // // // Input: fileNames - pointer to an array of file names // numberOfNames - number of elements in the fileNames array // maxLen - maximum length of a single name // ofstream outputFile; char *filename = NULL; Int_t i; for( i = 0; i < numberOfNames; i++ ) { if( !filename ) { // create a filename char *tmp1 = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), fileNames[i] ); filename = StrDup( tmp1, 16); if( tmp1 ) delete [] tmp1; tmp1 = 0; char *underlinePtr = strrchr( filename, '_'); *underlinePtr = 0; strcat( filename, "_Index.html" ); // open a file outputFile.open( filename, ios::out ); // check if it's OK if( outputFile.good() ) { Printf( formatStr, "", fCounter, filename ); // write outputFile header WriteHtmlHeader( outputFile, "Index" ); outputFile << "

" << "Index" << "


" << endl; outputFile << "
" << endl;
                outputFile << "
    " << endl; } else Error( "MakeIndex", "Can't open file '%s' !", filename ); delete [] filename; } // get a class TClass *classPtr = GetClass( (const char * ) strrchr( fileNames[i], '_')+1 ); if( classPtr ) { // write a classname to an index file outputFile << "
  • "; char *htmlFile = GetHtmlFileName( classPtr ); if( htmlFile ) { outputFile << "GetName(); outputFile << "\" href=\""; outputFile << htmlFile; outputFile << "\">"; outputFile << classPtr->GetName(); outputFile << " "; delete [] htmlFile; htmlFile = 0; } else outputFile << classPtr->GetName(); // write title Int_t len = strlen( classPtr->GetName() ); for( Int_t w = 0; w < maxLen-len; w++ ) outputFile << "."; outputFile << " "; outputFile << "GetName(); outputFile << "\">"; ReplaceSpecialChars( outputFile, classPtr->GetTitle() ); outputFile << "" << endl; } else Error( "MakeIndex", "Unknown class '%s' !", strchr( fileNames[i], '_')+1 ); // first base name char *first = strrchr( fileNames[i], '_'); if( first ) *first = 0; // second base name char *second = NULL; if( i < ( numberOfNames - 1 )) { second = strrchr( fileNames[i+1], '_'); if( second ) *second = 0; } // check and close the file if necessary if( !first || !second || strcmp( fileNames[i], fileNames[i+1] )) { if( outputFile.good() ) { outputFile << "
" << endl; outputFile << "
" << endl; // write outputFile footer TDatime date; WriteHtmlFooter( outputFile, "", date.AsString() ); // close file outputFile.close(); filename = NULL; } else Error( "MakeIndex", "Corrupted file '%s' !", filename ); } if( first ) *first = '_'; if( second ) *second = '_'; } // free memory for( i = 0; i < numberOfNames; i++ ) if( *fileNames[i] ) delete [] fileNames[i]; } //______________________________________________________________________________ void MHtml::CreateListOfTypes() { // Create list of all data types Int_t maxLen = 0; Int_t len; // open file ofstream typesList; char *outFile = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), "ListOfTypes.html" ); typesList.open( outFile, ios::out ); if( typesList.good() ) { Printf( formatStr, "", "", outFile ); // write typesList header WriteHtmlHeader( typesList, "List of data types" ); typesList << "

List of data types


" << endl; typesList << "
" << endl; typesList << "
" << endl;

        // make loop on data types
        TDataType *type;
        TIter nextType( gROOT->GetListOfTypes() );

        while (( type = ( TDataType * ) nextType() )) {
            if( *type->GetTitle() && !strchr( type->GetName(), '(' ) ) {
                if( type->GetName() ) len = strlen( type->GetName() );
                else len = 0;
                maxLen = maxLen > len ? maxLen : len;
            }
        }
        nextType.Reset();

        maxLen += kSpaceNum;

        while (( type = ( TDataType * ) nextType() )) {
            if( *type->GetTitle() && !strchr( type->GetName(), '(' ) ) {
                typesList << "GetName();
                typesList << "\">" << type->GetName();
                typesList << "";

                if( type->GetName() ) len = strlen( type->GetName() );
                else len = 0;
                typesList << " ";
                for( Int_t j = 0; j < ( maxLen-len ); j++ )
                    typesList << ".";
                typesList << " ";

                typesList << "GetTitle();
                typesList << "\">";
                char *tempstr = StrDup( type->GetTitle() );
                ReplaceSpecialChars( typesList, tempstr );
                typesList << "" << endl;

                if( tempstr ) delete [] tempstr;
            }
        }

        typesList << "
" << endl; typesList << "
" << endl; // write typesList footer TDatime date; WriteHtmlFooter( typesList, "", date.AsString() ); // close file typesList.close(); } else Error( "Make", "Can't open file '%s' !", outFile ); if (outFile) delete [] outFile; } //______________________________________________________________________________ void MHtml::DerivedClasses( ofstream &out, TClass *classPtr ) { // It creates a list of derived classes // // // Input: out - output file stream // classPtr - pointer to the class // Bool_t first = kTRUE; Bool_t found = kFALSE; // get total number of classes Int_t numberOfClasses = gClassTable->Classes(); // start from begining gClassTable->Init(); // get class names TClass *derivedClassPtr; const char *derivedClassName; for( Int_t i = 0; i < numberOfClasses; i++ ) { // get class name derivedClassName = gClassTable->Next(); // get class pointer derivedClassPtr = GetClass( derivedClassName ); if ( !derivedClassPtr ) { Warning("DerivedClasses","Can not find a definition for class <%s>",derivedClassName); continue; } // make a loop on base classes TBaseClass *inheritFrom; TIter nextBase( derivedClassPtr->GetListOfBases() ); while (( inheritFrom = ( TBaseClass * ) nextBase() )) { if( !strcmp( inheritFrom->GetName(), classPtr->GetName() )) { if( first ) { out << "

" << endl; out << ""; out << "

See also

" << endl; } if( !first ) out << ", "; char *htmlFile = GetHtmlFileName( derivedClassPtr ); if( htmlFile ) { out << ""; out << derivedClassPtr->GetName() << ""; delete [] htmlFile; htmlFile = 0; } else out << derivedClassPtr->GetName(); if( first ) { first = kFALSE; found = kTRUE; } } } } if( found ) out << "
" << endl; } //______________________________________________________________________________ void MHtml::ExpandKeywords( ofstream &out, char *text, TClass *ptr2class, Bool_t &flag, const char *dir ) { // Find keywords in text & create URLs // // // Input: out - output file stream // text - pointer to the array of the characters to process // ptr2class - pointer to the class // flag - this is a 'html_begin/html_end' flag // dir - usually "" or "../", depends of current file // directory position // char *keyword = text; char *end; char *funcName; char *funcNameEnd; char *funcSig; char *funcSigEnd; char c, c2, c3; char *tempEndPtr; c2 = c3 = 0; Bool_t hide; Bool_t mmf = 0; do { tempEndPtr = end = funcName = funcNameEnd = funcSig = funcSigEnd = NULL; hide = kFALSE; // skip until start of the word while( !IsWord( *keyword ) && *keyword ) { if( !flag ) ReplaceSpecialChars( out, *keyword ); else out << *keyword; keyword++; } // get end of the word end = keyword; while( IsName( *end ) && *end ) end++; // put '\0' at the end of the keyword c = *end; *end = 0; if( strlen( keyword ) > 50 ) { out << keyword; *end = c; keyword = end; continue; } // check if this is a HTML block if( flag ) { if( !strcasecmp( keyword, "end_html" ) && *( keyword-1 ) != '\"') { flag = kFALSE; hide = kTRUE; } } else { if( !strcasecmp( keyword, "begin_html" ) && *( keyword-1 ) != '\"') { flag = kTRUE; hide = kTRUE; } else { *end = c; tempEndPtr = end; // skip leading spaces while( *tempEndPtr && isspace( *tempEndPtr ) ) tempEndPtr++; // check if we have a something like a 'name[arg].name' Int_t count = 0; if( *tempEndPtr == '[') { count++; tempEndPtr++; } // wait until the last ']' while( count && *tempEndPtr ) { switch( *tempEndPtr ) { case '[': count++; break; case ']': count--; break; } tempEndPtr++; } if( !strncmp( tempEndPtr, "::", 2 ) || !strncmp( tempEndPtr, "->", 2 ) || ( *tempEndPtr == '.') ) { funcName = tempEndPtr; // skip leading spaces while( isspace( *funcName )) funcName++; // check if we have a '.' or '->' if( *tempEndPtr == '.') funcName++; else funcName += 2; if( !strncmp( tempEndPtr, "::", 2 )) mmf = kTRUE; else mmf = kFALSE; // skip leading spaces while( *funcName && isspace( *funcName )) funcName++; // get the end of the word if( !IsWord( *funcName )) funcName = NULL; if( funcName ) { funcNameEnd = funcName; // find the end of the function name part while( IsName( *funcNameEnd ) && *funcNameEnd ) funcNameEnd++; c2 = *funcNameEnd; if( !mmf ) { // try to find a signature funcSig = funcNameEnd; // skip leading spaces while( *funcSig && isspace( *funcSig )) funcSig++; if( *funcSig != '(') funcSig = NULL; else funcSig++; funcSigEnd = funcSig; // if signature exist, try to find the ending character if( funcSigEnd ) { Int_t count = 1; while( *funcSigEnd ) { if( *funcSigEnd == '(') count++; if( *funcSigEnd == ')') if( !--count ) break; funcSigEnd++; } c3 = *funcSigEnd; *funcSigEnd = 0; } } *funcNameEnd = 0; } } *end = 0; } } if( !flag && !hide && *keyword ) { // get class TClass *classPtr = GetClass( (const char * ) keyword ); if( classPtr ) { char *htmlFile = GetHtmlFileName( classPtr ); if( htmlFile ) { out << "GetName() << ":"; out << funcName; out << "\">"; out << classPtr->GetName() << "::"; out << funcName; out << ""; *funcNameEnd = c2; keyword = funcNameEnd; } else { // make a link to the class out << "\">"; out << classPtr->GetName(); out << ""; keyword = end; } delete [] htmlFile; htmlFile = 0; } else { out << keyword; keyword = end; } *end = c; if( funcName ) *funcNameEnd = c2; if( funcSig ) *funcSigEnd = c3; } else { // get data type TDataType *type = gROOT->GetType( (const char *) keyword ); if( type ) { // make a link to the data type out << ""; out << keyword << ""; *end = c; keyword = end; } else { // look for '(' Bool_t isfunc = ( (*tempEndPtr == '(') || c == '(')? kTRUE: kFALSE; if( !isfunc ) { char *bptr = tempEndPtr + 1; while( *bptr && isspace( *bptr ) ) bptr++; if( *bptr == '(') isfunc = kTRUE; } if( isfunc && ptr2class && ( ptr2class->GetMethodAny( keyword )) ) { out << "GetName(); out << ":" << keyword << "\">"; out << keyword << ""; *end = c; keyword = end; } else { const char *anyname = gROOT->FindObjectClassName( keyword ); const char *namePtr = NULL; TClass *cl = 0; TClass *cdl = 0; if( anyname ) { cl = GetClass( anyname ); namePtr = ( const char * ) anyname; cdl = cl; } else if( ptr2class ) { cl = ptr2class->GetBaseDataMember( keyword ); if( cl ) { namePtr = cl->GetName(); TDataMember *member = cl->GetDataMember( keyword ); if( member ) cdl = GetClass( member->GetTypeName() ); } } if( cl ) { char *htmlFile = GetHtmlFileName( cl ); if( htmlFile ) { out << "GetDataMember( keyword ) ) { out << "#" << namePtr << ":"; out << keyword; } out << "\">"; out << keyword; out << ""; delete [] htmlFile; htmlFile = 0; } else out << keyword; if( funcName ) { char *ptr = end; ptr++; ReplaceSpecialChars( out, c ); while( ptr < funcName ) ReplaceSpecialChars( out, *ptr++ ); TMethod *method = NULL; if( cdl ) method = cdl->GetMethodAny( funcName ); if( method ) { TClass *cm = method->GetClass(); if( cm ) { char *htmlFile2 = GetHtmlFileName( cm ); if( htmlFile2 ) { out << "GetName() << ":"; out << funcName; out << "\">"; out << funcName; out << ""; delete [] htmlFile2; htmlFile2 = 0; } else out << funcName; keyword = funcNameEnd; } else keyword = funcName; } else keyword = funcName; *funcNameEnd = c2; if( funcSig ) *funcSigEnd = c3; } else keyword = end; *end = c; } else { if( funcName ) *funcNameEnd = c2; if( funcSig ) *funcSigEnd = c3; out << keyword; *end = c; keyword = end; } } } } } else { if( !hide && *keyword ) out << keyword; *end = c; keyword = end; } } while( *keyword ); } //______________________________________________________________________________ void MHtml::ExpandPpLine( ofstream &out, char *line ) { // Expand preprocessor statements // // // Input: out - output file stream // line - pointer to the array of characters, // usually one line from the source file // // NOTE: Looks for the #include statements and // creates link to the corresponding file // if such file exists // const char *ptr; const char *ptrStart; const char *ptrEnd; char *fileName; Bool_t linkExist = kFALSE; ptrEnd = strstr( line, "include" ); if( ptrEnd ) { ptrEnd += 7; if (( ptrStart = strpbrk( ptrEnd, "<\"" ))) { ptrStart++; ptrEnd = strpbrk( ptrStart, ">\"" ); if( ptrEnd ) { Int_t len = ptrEnd - ptrStart; fileName = new char [len + 1]; strncpy( fileName, ptrStart, len ); char *tmpstr = gSystem->Which( fSourceDir, fileName, kReadPermission ); if( tmpstr ) { char *realFileName = StrDup( tmpstr ); if( realFileName ) { CopyHtmlFile( realFileName ); ptr = line; while( ptr < ptrStart ) ReplaceSpecialChars( out, *ptr++ ); out << ""; out << fileName << ""; out << ptrEnd; linkExist = kTRUE; } if( realFileName ) delete [] realFileName; if( fileName ) delete [] fileName; delete [] tmpstr; } } } } if( !linkExist ) ReplaceSpecialChars( out, line ); } //______________________________________________________________________________ const char *MHtml::GetFileName( const char *filename ) { // 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' // return( gSystem->BaseName( gSystem->UnixPathName( filename )) ); } //______________________________________________________________________________ char *MHtml::GetSourceFileName(const char *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. Returned string must be deleted by the // user. In case filename is not found 0 is returned. char *tmp1; #ifdef WIN32 if (strchr(filename, '/') || strchr(filename, '\\')) { #else if (strchr(filename, '/')) { #endif char *tmp; if (strlen(fSourcePrefix) > 0) tmp = gSystem->ConcatFileName(fSourcePrefix, filename); else tmp = StrDup(filename); if ((tmp1 = gSystem->Which(fSourceDir, tmp, kReadPermission))) { delete [] tmp; return tmp1; } delete [] tmp; } if ((tmp1 = gSystem->Which(fSourceDir, GetFileName(filename), kReadPermission))) return tmp1; return 0; } //______________________________________________________________________________ char *MHtml::GetHtmlFileName( TClass *classPtr ) { // Return real HTML filename // // // Input: classPtr - pointer to a class // // Output: pointer to the string containing a full name // of the corresponding HTML file. The string must be deleted by the user. // char htmlFileName [128]; char *ret = 0; Bool_t found = kFALSE; if( classPtr ) { const char *filename = classPtr->GetImplFileName(); char varName[80]; const char *colon = strchr( filename, ':'); // this should be a prefix strcpy( varName, "Root.Html." ); if( colon ) strncat( varName, filename, colon-filename ); else strcat( varName, "Root" ); char *tmp; if( !(tmp = gSystem->Which( fSourceDir, filename, kReadPermission ))) { strcpy( htmlFileName, gEnv->GetValue( varName, "" )); if( !*htmlFileName ) found = kFALSE; else found = kTRUE; } else { strcpy( htmlFileName, "." ); found = kTRUE; } delete [] tmp; if( found ) { char *tmp1 = gSystem->ConcatFileName( htmlFileName, classPtr->GetName() ); ret = StrDup( tmp1, 16 ); strcat( ret, ".html" ); if( tmp1 ) delete [] tmp1; tmp1 = 0; } else ret = 0; } return ret; } //______________________________________________________________________________ TClass *MHtml::GetClass(const char *name1, Bool_t load) { //*-*-*-*-*Return pointer to class with name*-*-*-*-*-*-*-*-*-*-*-*-* //*-* ================================= Int_t n = strlen(name1); char *name = new char[n+1]; strcpy(name, name1); char *t = name+n-1; while(*t == ' ') { *t = 0; if (t == name) break; t--; } t = name; while(*t == ' ') t++; TClass *cl = gROOT->GetClass(t,load); delete [] name; return cl; } //______________________________________________________________________________ Bool_t MHtml::IsModified( TClass *classPtr, const Int_t type ) { // Check if file is modified // // // Input: classPtr - pointer to the class // type - file type to compare with // values: kSource, kInclude, kTree // // Output: TRUE - if file is modified since last time // FALSE - if file is up to date // Bool_t ret = kTRUE; char sourceFile[1024], filename[1024]; char *strPtr, *strPtr2; switch( type ) { case kSource: strPtr2 = GetSourceFileName(classPtr->GetImplFileName()); if (strPtr2) strcpy( sourceFile, strPtr2 ); strPtr = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), "src" ); strcpy( filename, strPtr ); delete [] strPtr; delete [] strPtr2; #ifdef WIN32 strcat( filename, "\\" ); #else strcat( filename, "/" ); #endif strcat( filename, classPtr->GetName() ); strcat( filename, ".cxx.html" ); break; case kInclude: strPtr2 = GetSourceFileName(classPtr->GetDeclFileName()); if (strPtr2) strcpy( sourceFile, strPtr2 ); strPtr = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), GetFileName( classPtr->GetDeclFileName() )); strcpy( filename,strPtr ); delete [] strPtr; delete [] strPtr2; break; case kTree: strPtr2 = GetSourceFileName(classPtr->GetDeclFileName()); if (strPtr2) strcpy( sourceFile, strPtr2 ); strPtr = gSystem->ConcatFileName( gSystem->ExpandPathName( fOutputDir ), GetFileName( classPtr->GetName() )); strcpy( filename, strPtr); delete [] strPtr; delete [] strPtr2; strcat( filename, "_Tree.ps" ); break; default: Error( "IsModified", "Unknown file type !" ); } // Get info about a file Long_t sId, sSize, sFlags, sModtime; Long_t dId, dSize, dFlags, dModtime; if( !( gSystem->GetPathInfo( sourceFile, &sId, &sSize, &sFlags, &sModtime )) ) if( !( gSystem->GetPathInfo( filename, &dId, &dSize, &dFlags, &dModtime )) ) ret = ( sModtime > dModtime ) ? kTRUE : kFALSE; return( ret ); } //______________________________________________________________________________ Bool_t MHtml::IsName( Int_t c ) { // Check if c is a valid C++ name character // // // Input: c - a single character // // Output: TRUE if c is a valid C++ name character // and FALSE if it's not. // // NOTE: Valid name characters are [a..zA..Z0..9_], // Bool_t ret = kFALSE; if( isalnum( c ) || c == '_') ret = kTRUE; return ret; } //______________________________________________________________________________ Bool_t MHtml::IsWord( Int_t c ) { // Check if c is a valid first character for C++ name // // // Input: c - a single character // // Output: TRUE if c is a valid first character for C++ name, // and FALSE if it's not. // // NOTE: Valid first characters are [a..zA..Z_] // Bool_t ret = kFALSE; if( isalpha( c ) || c == '_') ret = kTRUE; return ret; } //______________________________________________________________________________ void MHtml::MakeAll( Bool_t force ) { // It makes everything // Int_t i; MakeIndex(); Int_t numberOfClasses = gClassTable->Classes(); const char **className = new const char* [numberOfClasses]; // start from begining gClassTable->Init(); for( i = 0; i < numberOfClasses; i++ ) className[i] = gClassTable->Next(); for( i = 0; i < numberOfClasses; i++ ) { sprintf( fCounter, "%5d", numberOfClasses - i ); MakeClass( (char * ) className[i], force ); } *fCounter = 0; delete [] className; } //______________________________________________________________________________ void MHtml::MakeClass(const char *className, Bool_t force ) { // Make HTML files for a single class // // // Input: className - name of the class to process // TClass *classPtr = GetClass( className ); if( classPtr ) { char *htmlFile = GetHtmlFileName( classPtr ); if( htmlFile && !strncmp( htmlFile, "http://", 7 )) { delete [] htmlFile; htmlFile = 0; } if( htmlFile ) { Class2Html( classPtr, force ); MakeTree( className, force ); delete [] htmlFile; htmlFile = 0; } else Printf( formatStr, "-skipped-", fCounter, className ); } else Error( "MakeClass", "Unknown class '%s' !", className ); } //______________________________________________________________________________ void MHtml::MakeIndex() { // It makes an index files CreateListOfTypes(); // get total number of classes Int_t numberOfClasses = gClassTable->Classes(); // allocate memory const char **classNames = new const char *[numberOfClasses]; char **fileNames = new char *[numberOfClasses]; // start from begining gClassTable->Init(); // get class names Int_t len = 0; Int_t maxLen = 0; Int_t numberOfImpFiles = 0; for( Int_t i = 0; i < numberOfClasses; i++ ) { // get class name classNames[i] = gClassTable->Next(); len = strlen( classNames[i] ); maxLen = maxLen > len ? maxLen : len; // get class & filename TClass *classPtr = GetClass( (const char * ) classNames[i] ); const char *impname = classPtr->GetImplFileName(); if( impname ) { fileNames[numberOfImpFiles] = StrDup( impname, 64 ); char *underline = strchr( fileNames[numberOfImpFiles], '_'); if( underline ) strcpy( underline + 1, classNames[i] ); else { // for new ROOT install the impl file name has the form: base/src/TROOT.cxx char *srcdir = strstr(fileNames[numberOfImpFiles], "/src/"); if (srcdir) { strcpy(srcdir, "_"); for (char *t = fileNames[numberOfImpFiles]; (t[0] = toupper(t[0])); t++) ; strcat(srcdir, classNames[i]); } else { strcpy( fileNames[i], "USER_" ); strcat( fileNames[i], classNames[i] ); } } numberOfImpFiles++; } else cout << "WARNING class:" << classNames[i] << " has no implementation file name !" << endl; } maxLen += kSpaceNum; // quick sort SortNames( classNames, numberOfClasses ); SortNames( (const char ** ) fileNames, numberOfImpFiles ); // create an index CreateIndex( classNames, numberOfClasses ); CreateIndexByTopic( fileNames, numberOfClasses, maxLen ); // free allocated memory delete [] classNames; delete [] fileNames; } //______________________________________________________________________________ void MHtml::MakeTree(const char *className, Bool_t force ) { // Make an inheritance tree // // // Input: className - name of the class to process // // create canvas & set fill color TVirtualPad *psCanvas = 0; gROOT->ProcessLineFast("new TCanvas(\"\",\"psCanvas\",0,0,1000,750);"); psCanvas = gPad->GetVirtCanvas(); TClass *classPtr = GetClass( className ); if( classPtr ) { char *htmlFile = GetHtmlFileName( classPtr ); if( htmlFile && !strncmp( htmlFile, "http://", 7 )) { delete [] htmlFile; htmlFile = 0; } if( htmlFile ) { // make a class tree ClassTree( psCanvas, classPtr, force ); delete [] htmlFile; htmlFile = 0; } else Printf( formatStr, "-skipped-", "", className ); } else Error( "MakeTree", "Unknown class '%s' !", className ); // close canvas psCanvas->Close(); delete psCanvas; } //______________________________________________________________________________ void MHtml::ReplaceSpecialChars( ofstream &out, const char c ) { // Replace ampersand, less-than and greater-than character // // // Input: out - output file stream // c - single character // if (fEscFlag) { out << c; fEscFlag = kFALSE; } else if (c == fEsc) fEscFlag = kTRUE; else { switch( c ) { case '<': out << "<"; break; case '&': out << "&"; break; case '>': out << ">"; break; default: out << c; } } } //______________________________________________________________________________ void MHtml::ReplaceSpecialChars( ofstream &out, const char *string ) { // Replace ampersand, less-than and greater-than characters // // // Input: out - output file stream // string - pointer to an array of characters // if( string ) { char *data = StrDup( string ); if( data ) { char *ptr = NULL; char *start = data; while (( ptr = strpbrk( start, "<&>" ))) { char c = *ptr; *ptr = 0; out << start; ReplaceSpecialChars( out, c ); start = ptr+1; } out << start; delete [] data; } } } //______________________________________________________________________________ void MHtml::SortNames( const char **strings, Int_t num, Bool_t type ) { // Sort strings // // // Input: strings - pointer to an array of strings // type - sort type // values : kCaseInsensitive, kCaseSensitive // default: kCaseInsensitive // if( type == kCaseSensitive ) qsort( strings, num, sizeof( strings ), CaseSensitiveSort ); else qsort( strings, num, sizeof( strings ), CaseInsensitiveSort ); } //______________________________________________________________________________ char *MHtml::StrDup( const char *s1, Int_t n ) { // Returns a pointer to a new string which is a duplicate // of the string to which 's1' points. The space for the // new string is obtained using the 'new' operator. The new // string has the length of 'strlen(s1) + n'. char *str = 0; if( s1 ) { if( n < 0 ) n = 0; str = new char[ strlen( s1 ) + n + 1 ]; if( str ) strcpy( str, s1 ); } return( str ); } //______________________________________________________________________________ void MHtml::WriteHtmlHeader( ofstream &out, const char *title ) { // Write HTML header // // // Input: out - output file stream // title - title for the HTML page // TDatime date; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << ""; ReplaceSpecialChars( out, title ); out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; out << "" << endl; } //______________________________________________________________________________ void MHtml::WriteHtmlFooter( ofstream &out, const char *dir, const char *lastUpdate, const char *author, const char *copyright ) { // Write HTML footer // // // Input: out - output file stream // dir - usually equal to "" or "../", depends of // current file directory position, i.e. if // file is in the fOutputDir, then dir will be "" // lastUpdate - last update string // author - author's name // copyright - copyright note // out << endl; if( *author || *lastUpdate || *copyright ) out << "

" << endl; out << "" << endl; // get the author( s ) if( *author ) { out << "Author: "; char *auth = StrDup(author); char *name = strtok( auth, "," ); Bool_t firstAuthor = kTRUE; do { char *ptr = name; char c; // remove leading spaces while( *ptr && isspace( *ptr ) ) ptr++; if( !firstAuthor ) out << ", "; if( !strncmp( ptr, "Nicolas", 7 ) ) { out << "" << name << ""; *ptr = c; out << ptr; firstAuthor = kFALSE; } while (( name = strtok( NULL, "," ))); out << "
" << endl; delete [] auth; } if( *lastUpdate ) out << "Last update: " << lastUpdate << "
" << endl; if( *copyright ) out << "Copyright " << copyright << "
" << endl; // this is a menu out << "
" << endl; out << "
" << endl; out << "
" << endl; out << "
" << endl; // link to the ROOT home page out << "ROOT page - "; // link to the user home page( if exist ) const char *userHomePage = gEnv->GetValue( "Root.Html.HomePage", "" ); if( *userHomePage ) { out << "Home page - "; } // link to the index file out << "Class index - "; // link to the top of the page out << "Top of the page
" << endl; out << "
" << endl; out << "
This page has been automatically generated. If you have any comments or suggestions "; out << "about the page layout send a mail to ROOT support, or "; out << "contact the developers with any questions or problems regarding ROOT." << endl; out << "
" << endl; out << "" << endl; out << "" << endl; }