// @(#)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;
// 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;
}