#include "TBaseClass.h"
#include "TVirtualPad.h"
#include "TClass.h"
#include "TClassTable.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TGlobal.h"
#include "TDatime.h"
#include "TEnv.h"
#include "TError.h"
#include "THtml.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TSystem.h"
#include "TObjString.h"
#include "TInterpreter.h"
#include "TRegexp.h"
#include "Riostream.h"
#include "TPluginManager.h"
#include "TVirtualUtilPad.h"
#include "TPaveText.h"
#include "TClassEdit.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <list>
#include <vector>
#include <algorithm>
THtml *gHtml = 0;
const Int_t kSpaceNum = 1;
const char *formatStr = "%12s %5s %s";
enum ESortType { kCaseInsensitive, kCaseSensitive };
enum EFileType { kSource, kInclude, kTree };
std::set<std::string> THtml::fgKeywords;
http://www.w3.org/TR/REC-html40/charset.html
ClassImp(THtml)
THtml::THtml(): fCurrentClass(0), fDocContext(kIgnore), fParseContext(kCode),
fHierarchyLines(0), fNumberOfClasses(0), fClassNames(0), fNumberOfFileNames(0), fFileNames(0)
{
fEscFlag = kFALSE;
fClassNames = 0;
fFileNames = 0;
SetEscape();
fSourcePrefix = gEnv->GetValue("Root.Html.SourcePrefix", "");
fSourceDir = gEnv->GetValue("Root.Html.SourceDir", "./:src/:include/");
fOutputDir = gEnv->GetValue("Root.Html.OutputDir", "htmldoc");
fXwho =
gEnv->GetValue("Root.Html.XWho",
"http:);
Int_t st;
Long64_t sSize;
Long_t sId, sFlags, sModtime;
if ((st =
gSystem->GetPathInfo(fOutputDir, &sId, &sSize, &sFlags, &sModtime))
|| !(sFlags & 2)) {
if (st == 0) {
Error("THtml", "output directory %s is an existing file",
fOutputDir.Data());
MakeZombie();
return;
}
if (gSystem->MakeDirectory(fOutputDir) == -1) {
Error("THtml", "output directory %s does not exist", fOutputDir.Data());
MakeZombie();
return;
}
}
if (!gHtml) {
gHtml = this;
gROOT->GetListOfSpecials()->Add(gHtml);
}
if (fgKeywords.empty()) {
fgKeywords.insert("asm");
fgKeywords.insert("auto");
fgKeywords.insert("bool");
fgKeywords.insert("break");
fgKeywords.insert("case");
fgKeywords.insert("catch");
fgKeywords.insert("char");
fgKeywords.insert("class");
fgKeywords.insert("const");
fgKeywords.insert("const_cast");
fgKeywords.insert("continue");
fgKeywords.insert("default");
fgKeywords.insert("delete");
fgKeywords.insert("do");
fgKeywords.insert("double");
fgKeywords.insert("dynamic_cast");
fgKeywords.insert("else");
fgKeywords.insert("enum");
fgKeywords.insert("explicit");
fgKeywords.insert("export");
fgKeywords.insert("extern");
fgKeywords.insert("false");
fgKeywords.insert("float");
fgKeywords.insert("for");
fgKeywords.insert("friend");
fgKeywords.insert("goto");
fgKeywords.insert("if");
fgKeywords.insert("inline");
fgKeywords.insert("int");
fgKeywords.insert("long");
fgKeywords.insert("mutable");
fgKeywords.insert("namespace");
fgKeywords.insert("new");
fgKeywords.insert("operator");
fgKeywords.insert("private");
fgKeywords.insert("protected");
fgKeywords.insert("public");
fgKeywords.insert("register");
fgKeywords.insert("reinterpret_cast");
fgKeywords.insert("return");
fgKeywords.insert("short");
fgKeywords.insert("signed");
fgKeywords.insert("sizeof");
fgKeywords.insert("static");
fgKeywords.insert("static_cast");
fgKeywords.insert("struct");
fgKeywords.insert("switch");
fgKeywords.insert("template");
fgKeywords.insert("this");
fgKeywords.insert("throw");
fgKeywords.insert("true");
fgKeywords.insert("try");
fgKeywords.insert("typedef");
fgKeywords.insert("typeid");
fgKeywords.insert("typename");
fgKeywords.insert("union");
fgKeywords.insert("unsigned");
fgKeywords.insert("using");
fgKeywords.insert("virtual");
fgKeywords.insert("void");
fgKeywords.insert("volatile");
fgKeywords.insert("wchar_t");
fgKeywords.insert("while");
}
}
THtml::~THtml()
{
delete []fClassNames;
delete []fFileNames;
if (gHtml == this) {
gROOT->GetListOfSpecials()->Remove(gHtml);
gHtml = 0;
}
}
bool IsNamespace(TClass*cl)
{
return (cl->Property() & kIsNamespace);
}
int CaseSensitiveSort(const void *name1, const void *name2)
{
return (strcmp(*((char **) name1), *((char **) name2)));
}
int CaseInsensitiveSort(const void *name1, const void *name2)
{
return (strcasecmp(*((char **) name1), *((char **) name2)));
}
namespace {
typedef std::vector<std::string> Words_t;
typedef Words_t::const_iterator SectionStart_t;
class TSectionInfo {
public:
TSectionInfo(SectionStart_t start, size_t chars, size_t size):
fStart(start), fChars(chars), fSize(size) {};
SectionStart_t fStart;
size_t fChars;
size_t fSize;
};
typedef std::list<TSectionInfo> SectionStarts_t;
void Sections_BuildIndex(SectionStarts_t& sectionStarts,
SectionStart_t begin, SectionStart_t end,
size_t maxPerSection)
{
SectionStart_t cursor = begin;
if (sectionStarts.empty() || sectionStarts.back().fStart != cursor)
sectionStarts.push_back(TSectionInfo(cursor, 1, 0));
SectionStarts_t::iterator prevSection = sectionStarts.end();
--prevSection;
while (cursor != end) {
size_t numLeft = end - cursor;
size_t assumedNumSections = (numLeft + maxPerSection - 1 ) / maxPerSection;
size_t step = ((numLeft + assumedNumSections - 1) / assumedNumSections);
if (!step || step >= numLeft) return;
cursor += step;
if (cursor == end) break;
SectionStart_t addWhichOne = prevSection->fStart;
size_t selectionChar=1;
for (; selectionChar <= cursor->length() && addWhichOne == prevSection->fStart;
++selectionChar) {
SectionStart_t checkPrev = cursor;
while (--checkPrev != prevSection->fStart
&& !strncasecmp(checkPrev->c_str(), cursor->c_str(), selectionChar));
SectionStart_t checkNext = cursor;
while (++checkNext != end
&& !strncasecmp(checkNext->c_str(), cursor->c_str(), selectionChar));
if (checkPrev != prevSection->fStart)
if ((cursor - checkPrev) <= (checkNext - cursor))
addWhichOne = ++checkPrev;
else if (checkNext != end
&& (size_t)(checkNext - cursor) < maxPerSection) {
addWhichOne = checkNext;
}
}
if (addWhichOne == prevSection->fStart)
addWhichOne = cursor;
selectionChar = 1;
while (selectionChar <= prevSection->fStart->length()
&& selectionChar <= addWhichOne->length()
&& !strncasecmp(prevSection->fStart->c_str(), addWhichOne->c_str(), selectionChar))
++selectionChar;
sectionStarts.push_back(TSectionInfo(addWhichOne, selectionChar, 0));
cursor = addWhichOne;
++prevSection;
}
}
void Sections_SetSize(SectionStarts_t& sectionStarts, const Words_t &words)
{
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
iSectionStart != sectionStarts.end(); ++iSectionStart) {
SectionStarts_t::iterator next = iSectionStart;
++next;
if (next == sectionStarts.end()) {
iSectionStart->fSize = (words.end() - iSectionStart->fStart);
break;
}
iSectionStart->fSize = (next->fStart - iSectionStart->fStart);
}
}
void Sections_PostMerge(SectionStarts_t& sectionStarts, const size_t maxPerSection)
{
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
iSectionStart != sectionStarts.end();) {
SectionStarts_t::iterator iNextSectionStart = iSectionStart;
++iNextSectionStart;
if (iNextSectionStart == sectionStarts.end()) break;
if (iNextSectionStart->fSize + iSectionStart->fSize < maxPerSection) {
iSectionStart->fSize += iNextSectionStart->fSize;
sectionStarts.erase(iNextSectionStart);
} else ++iSectionStart;
}
}
void GetIndexChars(const Words_t& words, UInt_t numSectionsIn,
std::vector<std::string> §ionMarkersOut)
{
const size_t maxPerSection = (words.size() + numSectionsIn - 1)/ numSectionsIn;
SectionStarts_t sectionStarts;
Sections_BuildIndex(sectionStarts, words.begin(), words.end(), maxPerSection);
Sections_SetSize(sectionStarts, words);
Sections_PostMerge(sectionStarts, maxPerSection);
sectionMarkersOut.clear();
sectionMarkersOut.resize(sectionStarts.size());
size_t idx = 0;
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
iSectionStart != sectionStarts.end(); ++iSectionStart)
sectionMarkersOut[idx++] =
iSectionStart->fStart->substr(0, iSectionStart->fChars);
}
void GetIndexChars(const char** wordsIn, UInt_t numWordsIn, UInt_t numSectionsIn,
std::vector<std::string> §ionMarkersOut)
{
Words_t words(numWordsIn);
for (UInt_t iWord = 0; iWord < numWordsIn; ++iWord)
words[iWord] = wordsIn[iWord];
GetIndexChars(words, numSectionsIn, sectionMarkersOut);
}
void GetIndexChars(const std::list<std::string>& wordsIn, UInt_t numSectionsIn,
std::vector<std::string> §ionMarkersOut)
{
Words_t words(wordsIn.size());
size_t idx = 0;
for (std::list<std::string>::const_iterator iWord = wordsIn.begin(); iWord != wordsIn.end(); ++iWord)
words[idx++] = *iWord;
GetIndexChars(words, numSectionsIn, sectionMarkersOut);
}
void sort_strlist_stricmp(std::list<std::string>& l)
{
struct posList {
const char* str;
std::list<std::string>::const_iterator pos;
};
posList* carr = new posList[l.size()];
size_t idx = 0;
for (std::list<std::string>::const_iterator iS = l.begin(); iS != l.end(); ++iS) {
carr[idx].pos = iS;
carr[idx++].str = iS->c_str();
}
qsort(&carr[0].str, idx, sizeof(posList), CaseInsensitiveSort);
std::list<std::string> lsort;
for (idx = 0; idx < l.size(); ++idx) {
lsort.push_back(*carr[idx].pos);
}
delete [] carr;
l.swap(lsort);
}
}
void THtml::Class2Html(Bool_t force)
{
const char *tab = "";
const char *tab2 = " ";
const char *tab4 = " ";
const char *tab6 = " ";
gROOT->GetListOfGlobals(kTRUE);
TString filename(fCurrentClass->GetName());
NameSpace2FileName(filename);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, filename);
filename += ".html";
if (IsModified(fCurrentClass, kSource) || force) {
ofstream classFile;
classFile.open(filename, ios::out);
if (classFile.good()) {
Printf(formatStr, "", fCounter.Data(), filename.Data());
WriteHtmlHeader(classFile, fCurrentClass->GetName(), "", fCurrentClass);
const char* lib=fCurrentClass->GetSharedLibs();
const char* incl=GetDeclFileName(fCurrentClass);
if (incl) incl=gSystem->BaseName(incl);
if (lib && strlen(lib)|| incl && strlen(incl)) {
classFile << "<table class=\"libinfo\"><tr><td>";
if (lib) {
char* libDup=StrDup(lib);
char* libDupSpace=strchr(libDup,' ');
if (libDupSpace) *libDupSpace=0;
char* libDupEnd=libDup+strlen(libDup);
while (libDupEnd!=libDup)
if (*(--libDupEnd)=='.') {
*libDupEnd=0;
break;
}
classFile << "library: "
<< libDup;
delete[] libDup;
}
if (incl) {
if (lib)
classFile << "<br/>";
classFile << "#include \""
<< incl << "\"";
}
classFile << "</td></tr></table>"
<< endl;
}
classFile << "<!--BEGIN-->" << endl;
classFile << "<center>" << endl;
classFile << "<h1>";
ReplaceSpecialChars(classFile, fCurrentClass->GetName());
classFile << "</h1>" << endl;
classFile << "<hr width=300>" << endl;
classFile << "<!--SDL--><em><a href=\"#" << fCurrentClass->GetName();
if (IsNamespace(fCurrentClass)) {
classFile << ":description\">namespace description</a>";
} else {
classFile << ":description\">class description</a>";
}
TString classFileName(fCurrentClass->GetName());
NameSpace2FileName(classFileName);
classFile << " - <a href=\"src/" << classFileName <<
".h.html\"";
classFile << ">header file</a>";
classFile << " - <a href=\"src/" << classFileName <<
".cxx.html\"";
classFile << ">source file</a>";
if (!IsNamespace(fCurrentClass)) {
classFile << " - <a href=\"" << classFileName << "_Tree.pdf\"";
classFile << ">inheritance tree (.pdf)</a>";
}
classFile << "</em>" << endl;
classFile << "<hr width=300>" << endl;
classFile << "</center>" << endl;
TString headerHtmlFileName = fCurrentClass->GetName();
NameSpace2FileName(headerHtmlFileName);
gSystem->PrependPathName("src", headerHtmlFileName);
headerHtmlFileName += ".h.html";
classFile << "<h2>class <a name=\"" << fCurrentClass->GetName()
<< "\" href=\"";
classFile << headerHtmlFileName << "\">";
ReplaceSpecialChars(classFile, fCurrentClass->GetName());
classFile << "</a> ";
TString declf(GetDeclFileName(fCurrentClass));
GetSourceFileName(declf);
if (declf.Length())
CopyHtmlFile(declf);
Bool_t first = kTRUE;
TBaseClass *inheritFrom;
TIter nextBase(fCurrentClass->GetListOfBases());
while ((inheritFrom = (TBaseClass *) nextBase())) {
if (first) {
classFile << ": ";
first = kFALSE;
} else
classFile << ", ";
classFile << "public ";
TClass *classInh =
GetClass((const char *) inheritFrom->GetName());
TString htmlFile;
GetHtmlFileName(classInh, htmlFile);
if (htmlFile.Length()) {
classFile << "<a href=\"";
classFile << htmlFile;
classFile << "\">";
ReplaceSpecialChars(classFile, inheritFrom->GetName());
classFile << "</a>";
} else
ReplaceSpecialChars(classFile, inheritFrom->GetName());
}
classFile << "</h2>" << endl;
if (!IsNamespace(fCurrentClass)) ClassHtmlTree(classFile, fCurrentClass);
TMethod *method;
TIter nextMethod(fCurrentClass->GetListOfMethods());
Int_t len, maxLen[3];
len = maxLen[0] = maxLen[1] = maxLen[2] = 0;
const Int_t nMethods = fCurrentClass->GetNmethods();
const char **fMethodNames = 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;
fMethodNames[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 (fCurrentClass && !strcmp(type, fCurrentClass->GetName()))
fMethodNames[mtype * 2 * nMethods + 2 * num[mtype]] =
"A00000000";
while ('~' ==
*fMethodNames[mtype * 2 * nMethods + 2 * num[mtype]])
fMethodNames[mtype * 2 * nMethods + 2 * num[mtype]] =
"A00000001";
fMethodNames[mtype * 2 * nMethods + 2 * num[mtype] + 1] =
(char *) method;
num[mtype]++;
}
const char* tab4nbsp=" ";
if (fCurrentClass->Property() & kIsAbstract)
classFile << " <br><b>"
<< tab4nbsp << "This is an abstract class, constructors will not be documented.<br>" << endl
<< tab4nbsp << "Look at the <a href=\""
<< GetFileName((const char *) GetDeclFileName(fCurrentClass))
<< "\">header</a> to check for available constructors.</b><br>" << endl;
classFile << "<pre>" << endl;
Int_t i, j;
if (IsNamespace(fCurrentClass)) {
j = 2;
} else {
j = 0;
}
for (; j < 3; j++) {
if (num[j]) {
qsort(fMethodNames + j * 2 * nMethods, num[j],
2 * sizeof(fMethodNames), 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 << "<b>" << ftitle << "</b><br>" << endl;
TString strClassNameNoScope(fCurrentClass->GetName());
UInt_t templateNest = 0;
Ssiz_t posLastScope = strClassNameNoScope.Length()-1;
for (;posLastScope && (templateNest || strClassNameNoScope[posLastScope] != ':'); --posLastScope)
if (strClassNameNoScope[posLastScope] == '>') ++templateNest;
else if (strClassNameNoScope[posLastScope] == '<') --templateNest;
else if (!strncmp(strClassNameNoScope.Data()+posLastScope,"operator", 8) && templateNest==1)
--templateNest;
if (strClassNameNoScope[posLastScope] == ':'
&& strClassNameNoScope[posLastScope-1] == ':')
strClassNameNoScope.Remove(0, posLastScope+1);
for (i = 0; i < num[j]; i++) {
method =
(TMethod *) fMethodNames[j * 2 * nMethods + 2 * i +
1];
if (method) {
Int_t w = 0;
Bool_t isctor=false;
Bool_t isdtor=false;
if (method->GetReturnTypeName())
len = strlen(method->GetReturnTypeName());
else
len = 0;
if (!strcmp(method->GetName(),strClassNameNoScope.Data()))
isctor=true;
if (!isctor && method->GetName()[0] == '~' && !strcmp(method->GetName()+1,strClassNameNoScope.Data()))
isdtor=true;
if (isctor || isdtor)
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())
if (!isdtor)
classFile << "virtual ";
else
classFile << " virtual";
if (kIsStatic & method->Property())
classFile << "static ";
if (!isctor && !isdtor)
ExpandKeywords(classFile, method->GetReturnTypeName());
classFile << " " << tab << "<!--BOLD-->";
classFile << "<a href=\"#" << fCurrentClass->GetName();
classFile << ":";
ReplaceSpecialChars(classFile, method->GetName());
classFile << "\">";
ReplaceSpecialChars(classFile, method->GetName());
classFile << "</a><!--PLAIN-->";
ExpandKeywords(classFile, method->GetSignature());
classFile << endl;
}
}
}
}
delete[]fMethodNames;
classFile << "</pre>" << endl;
first = kFALSE;
TDataMember *member;
TIter nextMember(fCurrentClass->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 = fCurrentClass->GetNdata();
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;
Int_t dim = member->GetArrayDim();
Int_t indx = 0;
Int_t maxidx;
while (indx < dim) {
maxidx = member->GetMaxIndex(indx);
if (maxidx <= 0)
break;
else
len2 += (Int_t)TMath::Log10(maxidx) + 3;
indx++;
}
maxLen1[mtype] =
maxLen1[mtype] > len1 ? maxLen1[mtype] : len1;
maxLen2[mtype] =
maxLen2[mtype] > len2 ? maxLen2[mtype] : len2;
}
classFile << endl;
classFile << "<h3>" << tab2 << "<a name=\"";
classFile << fCurrentClass->GetName();
classFile << ":Data Members\">Data Members</a></h3>" <<
endl;
classFile << "<pre>" << endl;
for (j = 0; j < 3; j++) {
if (num[j]) {
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 << "<b>" << ftitle << "</b><br>" <<
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 ";
ExpandKeywords(classFile, member->GetFullTypeName());
classFile << " " << tab << "<!--BOLD-->";
classFile << "<a name=\"" << fCurrentClass->
GetName() << ":";
classFile << member->GetName();
classFile << "\">" << member->GetName();
Int_t dim = member->GetArrayDim();
Int_t indx = 0;
Int_t indxlen = 0;
while (indx < dim) {
if (member->GetMaxIndex(indx) <= 0)
break;
classFile << "[" << member->
GetMaxIndex(indx) << "]";
indxlen +=
Int_t(TMath::
Log10(member->GetMaxIndex(indx))) + 3;
indx++;
}
classFile << "</a><!--PLAIN--> ";
len2 = 0;
if (member->GetName())
len2 = strlen(member->GetName()) + indxlen;
for (w = 0; w < (maxLen2[j] - len2); w++)
classFile << " ";
classFile << " " << tab;
classFile << "<i><a name=\"Title:";
classFile << member->GetName();
classFile << "\">";
ReplaceSpecialChars(classFile, member->GetTitle());
classFile << "</a></i>" << endl;
}
}
}
classFile << "</pre>" << endl;
delete[]memberArray;
}
}
classFile << "<!--END-->" << endl;
ClassDescription(classFile);
classFile.close();
} else
Error("Make", "Can't open file '%s' !", filename.Data());
} else
Printf(formatStr, "-no change-", fCounter.Data(), filename.Data());
}
void THtml::CreateSourceOutputStream(std::ofstream& out, const char* extension,
TString& sourceHtmlFileName)
{
gSystem->ExpandPathName(fOutputDir);
TString sourceHtmlDir("src");
gSystem->PrependPathName(fOutputDir, sourceHtmlDir);
if (gSystem->AccessPathName(sourceHtmlDir))
gSystem->MakeDirectory(sourceHtmlDir);
sourceHtmlFileName = fCurrentClass->GetName();
NameSpace2FileName(sourceHtmlFileName);
gSystem->PrependPathName(sourceHtmlDir, sourceHtmlFileName);
sourceHtmlFileName += extension;
out.open(sourceHtmlFileName);
if (!out) {
Warning("LocateMethodsInSource", "Can't open beautified source file '%s' for writing!",
sourceHtmlFileName.Data());
sourceHtmlFileName.Remove(0);
return;
}
TString title(fCurrentClass->GetName());
title += " - source file";
WriteHtmlHeader(out, title, "../", fCurrentClass);
out << "<pre class=\"code\">" << std::endl;
}
void THtml::BeautifyLine(std::ostream &sOut, TString* anchor )
{
enum EBeautifyContext {
kNothingSpecialMoveOn,
kCommentC,
kCommentCXX,
kPreProc,
kDontTouch,
kNumBeautifyContexts
};
EBeautifyContext context = kNothingSpecialMoveOn;
TString lineStripped(fLine.Strip(TString::kBoth));
switch (fParseContext) {
case kCode:
context = kNothingSpecialMoveOn;
if (lineStripped.Length() && lineStripped[0] == '#') {
context = kPreProc;
sOut << "<span class=\"cpp\">";
ExpandPpLine(sOut);
sOut << "</span>" << std::endl;
context = kNothingSpecialMoveOn;
return;
}
break;
case kBeginEndHtml:
case kBeginEndHtmlInCComment:
context = kDontTouch;
break;
case kCComment:
context = kCommentC;
break;
default: ;
}
if (anchor) {
*anchor += lineStripped.Hash();
sOut << "<a name=\"" << *anchor << "\"></a>";
anchor->Prepend("#");
}
if (context == kDontTouch || fLine.Contains("End_Html") && !fLine.Contains("\"End_Html")) {
ReplaceSpecialChars(sOut, fLine);
sOut << std::endl;
return;
}
TSubString stripSubExpanded = fLineExpanded.Strip(TString::kBoth);
TString lineExpandedDotDot(stripSubExpanded);
lineExpandedDotDot.ReplaceAll("=\"./", "=\"../");
if (stripSubExpanded.Start() > 0)
sOut << fLineExpanded(0,stripSubExpanded.Start());
for (Int_t i = 0; i < lineExpandedDotDot.Length(); ++i)
switch (lineExpandedDotDot[i]) {
case '/':
if (lineExpandedDotDot.Length() > i + 1)
if (lineExpandedDotDot[i + 1] == '/') {
if (context == kPreProc) {
sOut << "</span>";
context = kNothingSpecialMoveOn;
}
if (context == kNothingSpecialMoveOn)
sOut << "<span class=\"comment\">";
sOut << lineExpandedDotDot.Data() + i << "</span>";
i = lineExpandedDotDot.Length();
} else if (lineExpandedDotDot[i + 1] == '*') {
if (context == kPreProc) {
sOut << "</span>";
context = kNothingSpecialMoveOn;
}
if (context == kNothingSpecialMoveOn || context == kCommentC) {
sOut << "<span class=\"comment\">";
context = kCommentC;
fParseContext = kCComment;
Ssiz_t posEndComment = lineExpandedDotDot.Index("*/", i);
if (posEndComment == kNPOS)
posEndComment = lineExpandedDotDot.Length();
TString comment(lineExpandedDotDot(i, posEndComment - i));
sOut << comment;
i = posEndComment - 1;
} else
sOut << "/";
} else
sOut << "/";
else
sOut << "/";
break;
case '*':
if (lineExpandedDotDot.Length() > i + 1 &&
lineExpandedDotDot[i + 1] == '/' &&
(context == kCommentC ||
context == kNothingSpecialMoveOn)) {
sOut << "*/</span>";
context = kNothingSpecialMoveOn;
fParseContext = kCode;
i += 1;
}
else sOut << "*";
break;
default:
sOut << lineExpandedDotDot[i];
}
sOut << std::endl;
}
TMethod* THtml::LocateMethodInCurrentLine(Ssiz_t &posMethodName, TString& ret, TString& name, TString& params,
std::ostream &srcOut, TString &anchor, std::ifstream& sourceFile, Bool_t allowPureVirtual)
{
if (posMethodName == kNPOS) {
name.Remove(0);
TMethod * meth = 0;
for (MethodNames_t::iterator iMethodName = fMethodNames.begin();
!name.Length() && iMethodName != fMethodNames.end(); ++iMethodName) {
TString lookFor(" ");
lookFor += iMethodName->first;
lookFor += "(";
posMethodName = fLine.Index(lookFor);
if (posMethodName != kNPOS) {
++posMethodName;
meth = LocateMethodInCurrentLine(posMethodName, ret, name, params, srcOut,
anchor, sourceFile, allowPureVirtual);
if (name.Length())
return meth;
}
}
return 0;
}
name = fLine(posMethodName, fLine.Length() - posMethodName);
ret = fLine(0, posMethodName);
if (ret.Length()) {
while (ret.Length() && (IsName(ret[ret.Length() - 1]) || ret[ret.Length()-1] == ':'))
ret.Remove(ret.Length() - 1, 1);
ret = ret.Strip(TString::kBoth);
Bool_t didSomething = kTRUE;
while (didSomething) {
didSomething = kFALSE;
if (ret.BeginsWith("inline ")) {
didSomething = kTRUE;
ret.Remove(0, 7);
}
if (ret.BeginsWith("static ")) {
didSomething = kTRUE;
ret.Remove(0, 7);
}
if (ret.BeginsWith("virtual ")) {
didSomething = kTRUE;
ret.Remove(0, 8);
}
}
ret = ret.Strip(TString::kBoth);
}
Ssiz_t posParam = name.First('(');
if (posParam == kNPOS ||
ret.Contains("{") || ret.Contains("}") || ret.Contains("(") || ret.Contains(")")) {
ret.Remove(0);
name.Remove(0);
params.Remove(0);
return 0;
}
if (name.BeginsWith("operator")) {
Ssiz_t checkOpBracketParam = posParam + 1;
while (isspace(name[checkOpBracketParam]))
++checkOpBracketParam;
if (name[checkOpBracketParam] == ')') {
++checkOpBracketParam;
while (isspace(name[checkOpBracketParam]))
++checkOpBracketParam;
if (name[checkOpBracketParam] == '(')
posParam = checkOpBracketParam;
}
}
if (posParam == kNPOS) {
ret.Remove(0);
name.Remove(0);
params.Remove(0);
return 0;
}
params = name(posParam, name.Length() - posParam);
name.Remove(posParam);
MethodNames_t::const_iterator iMethodName = fMethodNames.find(name.Data());
if (iMethodName == fMethodNames.end() || iMethodName->second <= 0) {
ret.Remove(0);
name.Remove(0);
params.Remove(0);
return 0;
}
Ssiz_t posParamEnd = 1;
Int_t bracketLevel = 1;
while (bracketLevel) {
const char* paramEnd = strpbrk(params.Data() + posParamEnd, ")(\"'");
if (!paramEnd) {
if (!anchor.Length())
BeautifyLine(srcOut, &anchor);
else
BeautifyLine(srcOut);
fLine.ReadLine(sourceFile, kFALSE);
if (sourceFile.eof()) {
Error("LocateMethodInCurrentLine",
"Cannot find end of signature for function %s!",
name.Data());
break;
}
fLineExpanded = fLine;
ExpandKeywords(fLineExpanded);
posParamEnd = params.Length();
params += fLine;
} else
posParamEnd = paramEnd - params.Data();
switch (params[posParamEnd]) {
case '(': ++bracketLevel; ++posParamEnd; break;
case ')': --bracketLevel; ++posParamEnd; break;
case '"':
++posParamEnd;
while (params.Length() > posParamEnd && params[posParamEnd] != '"') {
if (params[posParamEnd] == '\\') ++posParamEnd;
++posParamEnd;
}
if (params.Length() <= posParamEnd) {
ret.Remove(0);
name.Remove(0);
params.Remove(0);
return 0;
}
++posParamEnd;
break;
case '\'':
++posParamEnd;
if (params[posParamEnd] == '\\') ++posParamEnd;
posParamEnd += 2;
break;
default:
++posParamEnd;
}
}
Ssiz_t posBlock = params.Index('{', posParamEnd);
Ssiz_t posSemicolon = params.Index(';', posParamEnd);
Ssiz_t posPureVirt = params.Index('=', posParamEnd);
if (posSemicolon != kNPOS)
if ((posBlock == kNPOS || (posSemicolon < posBlock)) &&
(posPureVirt == kNPOS || !allowPureVirtual)
&& !allowPureVirtual)
params.Remove(0);
if (params.Length())
params.Remove(posParamEnd);
if (!params.Length()) {
ret.Remove(0);
name.Remove(0);
return 0;
}
posMethodName = posParam + posParamEnd;
if (fCurrentClass)
return fCurrentClass->GetMethodAny(name);
return 0;
}
void THtml::LocateMethods(std::ofstream & out, const char* filename,
Bool_t lookForSourceInfo ,
Bool_t useDocxxStyle ,
Bool_t lookForClassDescr ,
Bool_t allowPureVirtual ,
const char* methodPattern ,
const char* sourceExt )
{
// Collect methods from the source or header file called filename.
// It generates a beautified version of the source file on the fly;
// the output file is given by the fCurrentClass's name, and sourceExt.
// Documentation is extracted to out.
// lookForSourceInfo: if set, author, lastUpdate, and copyright are
// extracted (i.e. the values contained in fSourceInfo)
// useDocxxStyle: if set, documentation can be in front of the method
// name, not only inside the method. Useful doc Doc++/Doxygen style,
// and inline methods.
// lookForClassDescr: if set, the first line matching the class description
// rules is assumed to be the class description for fCurrentClass; the
// description is written to out.
// methodPattern: if set, methods have to be prepended by this tag. Usually
TString sourceFileName(filename);
GetSourceFileName(sourceFileName);
if (!sourceFileName.Length()) {
Error("LocateMethods", "Can't find source file '%s' for class %s!",
GetImplFileName(fCurrentClass), fCurrentClass->GetName());
return;
}
ifstream sourceFile(sourceFileName.Data());
if (!sourceFile || !sourceFile.good()) {
Error("LocateMethods", "Can't open file '%s' for reading!", sourceFileName.Data());
return;
}
const char *sourceInfoTags[kNumSourceInfos];
sourceInfoTags[kInfoLastUpdate] = gEnv->GetValue("Root.Html.LastUpdate", ");
sourceInfoTags[kInfoAuthor] = gEnv->GetValue("Root.Html.Author", ");
sourceInfoTags[kInfoCopyright] = gEnv->GetValue("Root.Html.Copyright", " * Copyright");
const char *descriptionStr =
gEnv->GetValue("Root.Html.Description", ");
Bool_t foundClassDescription = !lookForClassDescr;
TString pattern(methodPattern);
TString prevComment;
Bool_t wroteMethodNowWaitingForOpenBlock = kFALSE;
ofstream srcHtmlOut;
TString srcHtmlOutName;
if (sourceExt && sourceExt[0])
CreateSourceOutputStream(srcHtmlOut, sourceExt, srcHtmlOutName);
else {
sourceExt = 0;
srcHtmlOutName = fCurrentClass->GetName();
NameSpace2FileName(srcHtmlOutName);
gSystem->PrependPathName("src", srcHtmlOutName);
srcHtmlOutName += ".h.html";
}
fParseContext = kCode;
fDocContext = kIgnore;
while (!sourceFile.eof()) {
Bool_t needAnchor = kFALSE;
TString anchor;
fLine.ReadLine(sourceFile, kFALSE);
if (sourceFile.eof()) break;
fLineExpanded = fLine;
ExpandKeywords(fLineExpanded);
TString lineExpandedStripped(fLineExpanded.Strip(TString::kBoth));
TString commentLine(lineExpandedStripped);
TString methodRet;
TString methodName;
TString methodParam;
if (fParseContext == kCComment || fParseContext == kBeginEndHtml ||
fParseContext == kBeginEndHtmlInCComment ||
lineExpandedStripped.Length() > 1 &&
lineExpandedStripped[0] == '/' &&
(lineExpandedStripped[1] == '/' || lineExpandedStripped[1] == '*')) {
if (!foundClassDescription && commentLine.Length() > 3) {
TString lineAllOneChar(commentLine);
Ssiz_t len = lineAllOneChar.Length();
Char_t c = lineAllOneChar[len - 1];
if (c == lineAllOneChar[len - 2] && c == lineAllOneChar[len - 3] &&
lineAllOneChar.Strip(TString::kTrailing, c).Length() == 0)
commentLine.Remove(0);
}
if (!foundClassDescription && !prevComment.Length() && fDocContext == kIgnore &&
(!commentLine.Length() || lineExpandedStripped.Contains(descriptionStr))) {
fDocContext = kDocClass;
foundClassDescription = kTRUE;
}
while (fParseContext != kBeginEndHtml && fParseContext != kBeginEndHtmlInCComment &&
commentLine.Length() > 2 &&
commentLine[0] == commentLine[commentLine.Length() - 1] &&
(commentLine[0] == '/' || commentLine[0] == '*')) {
commentLine = commentLine.Strip(TString::kBoth, commentLine[0]);
}
if (commentLine.Length()>1 &&
(commentLine[0] == '/' &&
(commentLine[1] == '/' || commentLine[1] == '*') ||
(commentLine[0] == '*' &&
(commentLine[1] == '/'))))
commentLine.Remove(0, 2);
prevComment += commentLine + "\n";
} else {
Ssiz_t posPattern = pattern.Length() ? fLine.Index(pattern) : kNPOS;
if (posPattern != kNPOS || !pattern.Length()) {
posPattern += pattern.Length();
LocateMethodInCurrentLine(posPattern, methodRet, methodName,
methodParam, srcHtmlOut, anchor, sourceFile, allowPureVirtual);
if (methodName.Length()) {
fDocContext = kDocFunc;
needAnchor = !anchor.Length();
if (!useDocxxStyle)
prevComment.Remove(0);
wroteMethodNowWaitingForOpenBlock = fLine.Index("{", posPattern) == kNPOS;
if (wroteMethodNowWaitingForOpenBlock)
wroteMethodNowWaitingForOpenBlock = fLine.Index(";", posPattern) == kNPOS;
}
}
}
Ssiz_t posTag = kNPOS;
if (lookForSourceInfo)
for (Int_t si = 0; si < (Int_t) kNumSourceInfos; ++si)
if (!fSourceInfo[si].Length() && (posTag = fLine.Index(sourceInfoTags[si])) != kNPOS)
fSourceInfo[si] = fLine(posTag + strlen(sourceInfoTags[si]), fLine.Length() - posTag);
if (sourceExt)
if (needAnchor)
BeautifyLine(srcHtmlOut, &anchor);
else
BeautifyLine(srcHtmlOut);
Bool_t writeMethod = anchor.Length() && fDocContext == kDocFunc && methodName.Length();
if (writeMethod) {
if (fDocContext == kDocFunc && !foundClassDescription)
out << "</div>";
ExpandKeywords(methodRet);
ExpandKeywords(methodParam);
out << "<div class=\"funcdoc\"><span class=\"funcname\">";
out << methodRet << " <a name=\"";
ReplaceSpecialChars(out, fCurrentClass->GetName());
out << ":";
ReplaceSpecialChars(out, methodName);
out << "\" href=\"src/" << gSystem->BaseName(srcHtmlOutName) << anchor << "\">";
ReplaceSpecialChars(out, methodName);
out << "</a>" << methodParam << "</span><br>" << std::endl;
MethodNames_t::iterator iMethodName = fMethodNames.find(methodName.Data());
if (iMethodName != fMethodNames.end()) {
--(iMethodName->second);
if (iMethodName->second <= 0)
fMethodNames.erase(iMethodName);
}
}
if (fParseContext != kBeginEndHtml && fParseContext != kBeginEndHtmlInCComment &&
fParseContext != kCComment &&
(!wroteMethodNowWaitingForOpenBlock && !writeMethod || useDocxxStyle) &&
(lineExpandedStripped.Length() < 2 || lineExpandedStripped[0] != '/' ||
lineExpandedStripped[1] != '/')) {
if (fDocContext == kDocFunc || fDocContext == kDocClass) {
out << "<pre>" << prevComment << "</pre></div>" << std::endl;
if (fDocContext == kDocClass)
out << "</div>";
}
prevComment.Remove(0);
fDocContext = kIgnore;
} else if (wroteMethodNowWaitingForOpenBlock && fLine.Index('{') != kNPOS)
wroteMethodNowWaitingForOpenBlock = kFALSE;
}
srcHtmlOut << "</pre>" << std::endl;
WriteHtmlFooter(srcHtmlOut, "../");
fParseContext = kCode;
fDocContext = kIgnore;
}
void THtml::LocateMethodsInSource(ofstream & out)
{
const char* docxxEnv = gEnv->GetValue("Root.Html.DescriptionStyle", "");
Bool_t useDocxxStyle = (strcmp(docxxEnv, "Doc++") == 0);
TString pattern(fCurrentClass->GetName());
Ssiz_t posLastScope = kNPOS;
while ((posLastScope = pattern.Index("::")) != kNPOS)
pattern.Remove(0, posLastScope + 1);
pattern += "::";
const char* implFileName = GetImplFileName(fCurrentClass);
if (implFileName && implFileName[0])
LocateMethods(out, implFileName, kTRUE, useDocxxStyle, kTRUE,
kFALSE, pattern, ".cxx.html");
}
void THtml::LocateMethodsInHeaderInline(ofstream & out)
{
Bool_t useDocxxStyle = kTRUE;
TString pattern(fCurrentClass->GetName());
Ssiz_t posLastScope = kNPOS;
while ((posLastScope = pattern.Index("::")) != kNPOS)
pattern.Remove(0, posLastScope + 1);
pattern += "::";
const char* declFileName = GetDeclFileName(fCurrentClass);
if (declFileName && declFileName[0])
LocateMethods(out, declFileName, kFALSE, useDocxxStyle, kFALSE,
kFALSE, pattern, 0);
}
void THtml::LocateMethodsInHeaderClassDecl(ofstream & out)
{
const char* declFileName = GetDeclFileName(fCurrentClass);
if (declFileName && declFileName[0])
LocateMethods(out, declFileName, kFALSE, kTRUE, kFALSE, kTRUE, 0, ".h.html");
}
void THtml::ClassDescription(ofstream & out)
{
out << "<hr>" << endl;
out << "<!--DESCRIPTION-->";
out << "<div class=\"classdescr\">";
out << "<h2><a name=\"" << fCurrentClass->GetName();
out << ":description\">Class Description</a></h2>" << endl;
TMethod *method;
TIter nextMethod(fCurrentClass->GetListOfMethods());
fMethodNames.clear();
while ((method = (TMethod *) nextMethod())) {
++fMethodNames[method->GetName()];
}
for (Int_t si = 0; si < (Int_t) kNumSourceInfos; ++si)
fSourceInfo[si].Remove(0);
LocateMethodsInSource(out);
LocateMethodsInHeaderInline(out);
LocateMethodsInHeaderClassDecl(out);
TDatime date;
if (!fSourceInfo[kInfoLastUpdate].Length())
fSourceInfo[kInfoLastUpdate] = date.AsString();
WriteHtmlFooter(out, "", fSourceInfo[kInfoLastUpdate],
fSourceInfo[kInfoAuthor], fSourceInfo[kInfoCopyright]);
}
void THtml::ClassHtmlTree(ofstream & out, TClass * classPtr,
ETraverse dir, int depth)
{
if (dir == kBoth) {
out << "<!--INHERITANCE TREE-->" << endl;
out << "<table><tr><td width=\"10%\"></td><td width=\"70%\">Inheritance Chart:</td></tr>";
out << "<tr class=\"inhtree\"><td width=\"10%\"></td><td width=\"70%\">";
out << "<table class=\"inhtree\" width=\"100%\"><tr><td>" << endl;
out << "<table width=\"100%\" border=\"0\" ";
out << "cellpadding =\"0\" cellspacing=\"2\"><tr>" << endl;
} else {
out << "<table><tr>";
}
if (dir == kUp || dir == kBoth) {
TBaseClass *inheritFrom;
TIter nextBase(classPtr->GetListOfBases());
UInt_t bgcolor=255-depth*8;
Bool_t first = kTRUE;
while ((inheritFrom = (TBaseClass *) nextBase())) {
if (first) {
out << "<td><table><tr>" << endl;
first = kFALSE;
} else
out << "</tr><tr>" << endl;
out << "<td bgcolor=\""
<< Form("#%02x%02x%02x", bgcolor, bgcolor, bgcolor)
<< "\" align=\"right\">" << endl;
TClass *classInh = GetClass((const char *) inheritFrom->GetName());
if (classInh)
ClassHtmlTree(out, classInh, kUp, depth+1);
else
out << "<tt>"
<< (const char *) inheritFrom->GetName()
<< "</tt>";
out << "</td>"<< endl;
}
if (!first) {
out << "</tr></table></td>" << endl;
out << "<td><-</td>";
}
}
out << "<td>" << endl;
const char *className = classPtr->GetName();
TString htmlFile;
GetHtmlFileName(classPtr, htmlFile);
if (dir == kUp) {
if (htmlFile) {
out << "<center><tt><a name=\"" << className;
out << "\" href=\"" << htmlFile << "\">";
ReplaceSpecialChars(out, className);
out << "</a></tt></center>" << endl;
} else
ReplaceSpecialChars(out, className);
}
if (dir == kBoth) {
if (htmlFile.Length()) {
out << "<center><big><b><tt><a name=\"" << className;
out << "\" href=\"" << htmlFile << "\">";
ReplaceSpecialChars(out, className);
out << "</a></tt></b></big></center>" << endl;
} else
ReplaceSpecialChars(out, className);
}
out << "</td>" << endl;
if (dir == kDown || dir == kBoth) {
out << "<td><table><tr>" << endl;
fHierarchyLines = 0;
DescendHierarchy(out,classPtr,fClassNames,fNumberOfClasses,10);
out << "</tr></table>";
if (dir==kBoth && fHierarchyLines>=10)
out << "</td><td align=\"left\"> <a href=\"ClassHierarchy.html\">[more...]</a>";
out<<"</td>" << endl;
}
out << "</tr></table>" << endl;
if (dir == kBoth)
out << "</td></tr></table></td></tr></table>"<<endl;
}
void THtml::ClassTree(TVirtualPad * psCanvas, TClass * classPtr,
Bool_t force)
{
if (psCanvas && classPtr) {
TString filename(classPtr->GetName());
NameSpace2FileName(filename);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, filename);
filename += "_Tree.pdf";
if (IsModified(classPtr, kTree) || force) {
classPtr->Draw("same");
psCanvas->SaveAs(filename);
} else
Printf(formatStr, "-no change-", "", filename.Data());
}
}
void THtml::Convert(const char *filename, const char *title,
const char *dirname)
{
gROOT->GetListOfGlobals(kTRUE);
CreateListOfClasses("*");
const char *dir;
Bool_t isCommentedLine = kFALSE;
if (!*dirname) {
gSystem->ExpandPathName(fOutputDir);
dir = gSystem->ConcatFileName(fOutputDir, "examples");
if (gSystem->AccessPathName(dir))
gSystem->MakeDirectory(dir);
} else
dir = dirname;
char *realFilename =
gSystem->Which(fSourceDir, filename, kReadPermission);
if (realFilename) {
ifstream sourceFile;
sourceFile.open(realFilename, ios::in);
delete[]realFilename;
realFilename = 0;
if (sourceFile.good()) {
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);
WriteHtmlHeader(tempFile, title);
tempFile << "<h1>" << title << "</h1>" << endl;
tempFile << "<pre>" << endl;
while (!sourceFile.eof()) {
fLine.ReadLine(sourceFile, kFALSE);
if (sourceFile.eof())
break;
fLine = fLine.Strip(TString::kBoth);
isCommentedLine = fLine.BeginsWith(");
if (isCommentedLine)
tempFile << "<b>";
ExpandKeywords(fLine);
fLine.ReplaceAll("=\"./", "=\"../");
tempFile << fLine;
if (isCommentedLine)
tempFile << "</b>";
tempFile << endl;
}
tempFile << "</pre>" << endl;
WriteHtmlFooter(tempFile, "../");
tempFile.close();
} else
Error("Convert", "Can't open file '%s' !", htmlFilename);
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 THtml::CopyHtmlFile(const char *sourceName, const char *destName)
{
Bool_t ret = kFALSE;
Int_t check = 0;
char *tmp1 = gSystem->Which(fSourceDir, sourceName, kReadPermission);
char *sourceFile = StrDup(tmp1, 16);
if (tmp1)
delete[]tmp1;
tmp1 = 0;
if (sourceFile) {
char *tmpstr = 0;
if (!*destName)
tmpstr = StrDup(GetFileName(sourceFile), 16);
else
tmpstr = StrDup(GetFileName(destName), 16);
destName = tmpstr;
gSystem->ExpandPathName(fOutputDir);
tmp1 = gSystem->ConcatFileName(fOutputDir, destName);
char *filename = StrDup(tmp1, 16);
if (tmp1)
delete[]tmp1;
tmp1 = 0;
Long64_t sSize, dSize;
Long_t sId, sFlags, sModtime;
Long_t dId, dFlags, dModtime;
sModtime = 0;
dModtime = 0;
if (!(check =
gSystem->GetPathInfo(sourceFile, &sId, &sSize, &sFlags,
&sModtime)))
check = gSystem->GetPathInfo(filename, &dId, &dSize, &dFlags,
&dModtime);
if ((sModtime != dModtime) || check)
gSystem->CopyFile(sourceFile, filename, kTRUE);
delete[]filename;
delete[]tmpstr;
delete[]sourceFile;
} else
Error("Copy", "Can't copy file '%s' to '%s' directory !", sourceName,
fOutputDir.Data());
return (ret);
}
void THtml::CreateIndex(const char **classNames, Int_t numberOfClasses)
{
Int_t i = 0;
gSystem->ExpandPathName(fOutputDir);
char *tmp1 = gSystem->ConcatFileName(fOutputDir, "ClassIndex.html");
char *filename = StrDup(tmp1);
if (tmp1)
delete[]tmp1;
tmp1 = 0;
CreateStyleSheet();
ofstream indexFile;
indexFile.open(filename, ios::out);
if (indexFile.good()) {
Printf(formatStr, "", fCounter.Data(), filename);
WriteHtmlHeader(indexFile, "Class Index");
indexFile << "<h1>Index</h1>" << endl;
if (fModules.size()) {
indexFile << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
sort_strlist_stricmp(fModules);
for (std::list<std::string>::iterator iModule = fModules.begin();
iModule != fModules.end(); ++iModule) {
indexFile << "<a href=\"" << *iModule << "_Index.html\">" << *iModule << "</a>" << endl;
}
indexFile << "</div><br/>" << endl;
}
std::vector<std::string> indexChars;
if (numberOfClasses > 10) {
indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
GetIndexChars(classNames, (Int_t)numberOfClasses, 50 , indexChars);
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
indexFile << "<a href=\"#idx" << iIdxEntry << "\">" << indexChars[iIdxEntry]
<< "</a>" << endl;
}
indexFile << "</div><br/>" << endl;
}
const char *searchEngine =
gEnv->GetValue("Root.Html.SearchEngine", "");
if (*searchEngine) {
indexFile << "<h2><a href=\"" << searchEngine
<< "\">Search the Class Reference Guide</a></h2>" << endl;
} else {
const char *searchCmd =
gEnv->GetValue("Root.Html.Search", "");
if (*searchCmd) {
indexFile << "<script language=\"javascript\">" << endl
<< "function onSearch() {" << endl
<< "var s='" << searchCmd <<"';" << endl
<< "window.location.href=s.replace(/%s/ig,escape(document.searchform.t.value));" << endl
<< "return false;}" << endl
<< "</script><form action=\"javascript:onSearch();\" id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\">" << endl
<< "<input name=\"t\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input>" << endl
<< "<button type=\"submit\">Search</button></form>" << endl;
}
}
indexFile << "<ul id=\"indx\">" << endl;
UInt_t currentIndexEntry = 0;
for (i = 0; i < numberOfClasses; i++) {
fCurrentClass = GetClass((const char *) classNames[i]);
if (fCurrentClass == 0) {
Warning("THtml::CreateIndex", "skipping class %s\n", classNames[i]);
continue;
}
indexFile << "<li class=\"idxl" << i%2 << "\"><tt>";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), classNames[i],
indexChars[currentIndexEntry].length()))
indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
TString htmlFile;
GetHtmlFileName(fCurrentClass, htmlFile);
if (htmlFile.Length()) {
indexFile << "<a name=\"";
indexFile << classNames[i];
indexFile << "\" href=\"";
indexFile << htmlFile;
indexFile << "\">";
ReplaceSpecialChars(indexFile, classNames[i]);
indexFile << "</a>";
} else
ReplaceSpecialChars(indexFile, classNames[i]);
indexFile << "</tt>";
indexFile << "<a name=\"Title:";
indexFile << fCurrentClass->GetName();
indexFile << "\"></a>";
ReplaceSpecialChars(indexFile, fCurrentClass->GetTitle());
indexFile << "</li>" << endl;
}
indexFile << "</ul>" << endl;
TDatime date;
WriteHtmlFooter(indexFile, "", date.AsString());
indexFile.close();
} else
Error("MakeIndex", "Can't open file '%s' !", filename);
if (filename)
delete[]filename;
fCurrentClass = 0;
}
void THtml::CreateIndexByTopic(char **fileNames, Int_t numberOfNames)
{
ofstream outputFile;
char *filename = 0;
Int_t i;
UInt_t currentIndexEntry = 0;
Int_t firstIdxEntry = 0;
std::vector<std::string> indexChars;
fModules.clear();
for (i = 0; i < numberOfNames; i++) {
if (!filename) {
gSystem->ExpandPathName(fOutputDir);
char *tmp1 = gSystem->ConcatFileName(fOutputDir, fileNames[i]);
filename = StrDup(tmp1, 16);
if (tmp1)
delete[]tmp1;
tmp1 = 0;
char *underlinePtr = strrchr(filename, '/');
if (!underlinePtr)
underlinePtr=strchr(filename,'_');
else underlinePtr=strchr(underlinePtr,'_');
*underlinePtr = 0;
char modulename[1024];
strcpy(modulename, GetFileName(filename));
char htmltitle[1024];
strcpy(htmltitle, "Index of ");
strcat(htmltitle, modulename);
strcat(htmltitle, " classes");
strcat(filename, "_Index.html");
outputFile.open(filename, ios::out);
if (outputFile.good()) {
fModules.push_back(modulename);
Printf(formatStr, "", fCounter.Data(), filename);
WriteHtmlHeader(outputFile, htmltitle);
outputFile << "<h2>" << htmltitle << "</h2>" << endl;
std::list<std::string> classNames;
char *classname = strrchr(fileNames[i], '/');
if (!classname)
classname=strchr(fileNames[i],'_');
else classname=strchr(classname,'_');
for (int j=i; j < numberOfNames;) {
classNames.push_back(classname + 1);
char *first = strrchr(fileNames[j], '/');
if (!first)
first=strchr(fileNames[j],'_');
else first=strchr(first,'_');
if (first)
*first = 0;
char *second = 0;
if (j < (numberOfNames - 1)) {
second = strrchr(fileNames[j + 1], '/');
if (!second)
second=strchr(fileNames[j + 1],'_');
else second=strchr(second,'_');
if (second)
*second = 0;
}
Bool_t nextDiffers = (!first || !second || strcmp(fileNames[j], fileNames[j + 1]));
if (first)
*first = '_';
if (second)
*second = '_';
if (nextDiffers) break;
++j;
classname = strrchr(fileNames[j], '/');
if (!classname)
classname=strchr(fileNames[j],'_');
else classname=strchr(classname,'_');
}
if (classNames.size() > 10) {
outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
UInt_t numSections = classNames.size() / 10;
if (numSections < 10) numSections = 10;
if (numSections > 50) numSections = 50;
GetIndexChars(classNames, numSections, indexChars);
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
outputFile << "<a href=\"#idx" << iIdxEntry << "\">" << indexChars[iIdxEntry]
<< "</a>" << endl;
}
outputFile << "</div><br/>" << endl;
}
outputFile << "<ul id=\"indx\">" << endl;
currentIndexEntry = 0;
} else
Error("MakeIndex", "Can't open file '%s' !", filename);
delete[]filename;
firstIdxEntry = i;
}
char *classname = strrchr(fileNames[i], '/');
if (!classname)
classname=strchr(fileNames[i],'_');
else classname=strchr(classname,'_');
TClass *classPtr =
GetClass((const char *) classname + 1);
if (classPtr) {
outputFile << "<li class=\"idxl" << (i-firstIdxEntry)%2 << "\"><tt>";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), classname + 1,
indexChars[currentIndexEntry].length()))
outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
TString htmlFile;
GetHtmlFileName(classPtr, htmlFile);
if (htmlFile.Length()) {
outputFile << "<a name=\"";
outputFile << classPtr->GetName();
outputFile << "\" href=\"";
outputFile << htmlFile;
outputFile << "\">";
ReplaceSpecialChars(outputFile, classPtr->GetName());
outputFile << "</a>";
} else
ReplaceSpecialChars(outputFile, classPtr->GetName());
outputFile << "</tt><a name=\"Title:";
outputFile << classPtr->GetName();
outputFile << "\"></a>";
ReplaceSpecialChars(outputFile, classPtr->GetTitle());
outputFile << "</li>" << endl;
} else
Error("MakeIndex", "Unknown class '%s' !",
strchr(fileNames[i], '_') + 1);
char *first = strrchr(fileNames[i], '/');
if (!first)
first=strchr(fileNames[i],'_');
else first=strchr(first,'_');
if (first)
*first = 0;
char *second = 0;
if (i < (numberOfNames - 1)) {
second = strrchr(fileNames[i + 1], '/');
if (!second)
second=strchr(fileNames[i + 1],'_');
else second=strchr(second,'_');
if (second)
*second = 0;
}
if (!first || !second || strcmp(fileNames[i], fileNames[i + 1])) {
if (outputFile.good()) {
outputFile << "</ul>" << endl;
TDatime date;
WriteHtmlFooter(outputFile, "", date.AsString());
outputFile.close();
filename = 0;
} else
Error("MakeIndex", "Corrupted file '%s' !", filename);
}
if (first)
*first = '_';
if (second)
*second = '_';
}
}
void THtml::CreateHierarchy(const char **classNames, Int_t numberOfClasses)
{
Int_t i=0;
gSystem->ExpandPathName(fOutputDir);
char *filename = gSystem->ConcatFileName(fOutputDir, "ClassHierarchy.html");
ofstream out;
out.open(filename, ios::out);
if (out.good()) {
Printf(formatStr, "", fCounter.Data(), filename);
WriteHtmlHeader(out, "Class Hierarchy");
out << "<h1>Class Hierarchy</h1>" << endl;
const char *searchEngine =
gEnv->GetValue("Root.Html.SearchEngine", "");
if (*searchEngine) {
out << "<h2><a href=\"" << searchEngine
<< "\">Search the Class Reference Guide</a></h2>" << endl;
}
for (i = 0; i < numberOfClasses; i++) {
TClass *basePtr = GetClass((const char *) classNames[i]);
if (basePtr == 0) {
Warning("THtml::CreateHierarchy", "skipping class %s\n", classNames[i]);
continue;
}
TList *bases = basePtr->GetListOfBases();
if (bases && bases->IsEmpty()){
out << "<hr>" << endl;
out << "<table><tr><td><ul><li><tt>";
TString htmlFile;
GetHtmlFileName(basePtr, htmlFile);
if (htmlFile.Length()) {
out << "<a name=\"";
out << classNames[i];
out << "\" href=\"";
out << htmlFile;
out << "\">";
ReplaceSpecialChars(out, classNames[i]);
out << "</a>";
} else {
ReplaceSpecialChars(out, classNames[i]);
}
out << "</tt></li></ul></td>";
fHierarchyLines = 0;
DescendHierarchy(out,basePtr,classNames,numberOfClasses);
out << "</tr></table>" << endl;
}
}
TDatime date;
WriteHtmlFooter(out, "", date.AsString());
out.close();
} else
Error("CreateHierarchy", "Can't open file '%s' !", filename);
if (filename)
delete[]filename;
}
void THtml::DescendHierarchy(ofstream & out, TClass* basePtr,
const char **classNames, Int_t numberOfClasses, Int_t maxLines, Int_t depth)
{
if (maxLines)
if (fHierarchyLines >= maxLines) {
out << "<td></td>" << endl;
return;
}
Int_t numClasses=0;
for (Int_t j = 0; j < numberOfClasses && (!maxLines || fHierarchyLines<maxLines); j++) {
TClass *classPtr = GetClass((const char *) classNames[j]);
if (!classPtr) continue;
TList* bases=classPtr->GetListOfBases();
if (!bases) continue;
TBaseClass *inheritFrom=(TBaseClass*)bases->FindObject(basePtr->GetName());
if (!inheritFrom) continue;
if (!numClasses)
out << "<td><-</td><td><table><tr>" << endl;
else
out << "</tr><tr>"<<endl;
fHierarchyLines++;
numClasses++;
UInt_t bgcolor=255-depth*8;
out << "<td bgcolor=\""
<< Form("#%02x%02x%02x", bgcolor, bgcolor, bgcolor)
<< "\">";
out << "<table><tr><td>" << endl;
TString htmlFile;
GetHtmlFileName(classPtr, htmlFile);
if (htmlFile.Length()) {
out << "<center><tt><a name=\"";
out << classNames[j];
out << "\" href=\"";
out << htmlFile;
out << "\">";
ReplaceSpecialChars(out, classNames[j]);
out << "</a></tt></center>";
} else {
ReplaceSpecialChars(out, classNames[j]);
}
out << "</td>" << endl;
DescendHierarchy(out,classPtr,classNames,numberOfClasses,maxLines, depth+1);
out << "</tr></table></td>" << endl;
}
if (numClasses)
out << "</tr></table></td>" << endl;
else
out << "<td></td>" << endl;
}
void THtml::CreateListOfClasses(const char* filter)
{
Int_t totalNumberOfClasses = gClassTable->Classes();
if (fClassNames) delete [] fClassNames;
if (fFileNames) delete [] fFileNames;
fClassNames = new const char *[totalNumberOfClasses];
fFileNames = new char *[totalNumberOfClasses];
gClassTable->Init();
fNumberOfClasses = 0;
fNumberOfFileNames = 0;
TString reg = filter;
TRegexp re(reg, kTRUE);
for (Int_t i = 0; i < totalNumberOfClasses; i++) {
const char *cname = gClassTable->Next();
TString s = cname;
if (filter && filter[0] && strcmp(filter,"*") && s.Index(re) == kNPOS)
continue;
if (strstr(cname, "__gnu_cxx::")) continue;
TClass *classPtr = gROOT->GetClass((const char *) cname, kTRUE);
if (!classPtr) continue;
TString srcGuess;
TString hdrGuess;
const char *impname=GetImplFileName(classPtr);
if (!impname || !impname[0]) {
impname = GetDeclFileName(classPtr);
if (impname && !impname[0]) {
TString impnameString(cname);
TObjArray* arrScopes = impnameString.Tokenize("::");
TIter iScope(arrScopes, kIterBackward);
TObjString *osFile = (TObjString*)iScope();
TObjString *osModule = 0;
if (osFile) osModule = (TObjString*)iScope();
if (osModule) {
hdrGuess = osModule->String();
hdrGuess.ToLower();
hdrGuess += "/inc/";
hdrGuess += osModule->String();
hdrGuess += "/";
hdrGuess += osFile->String();
hdrGuess += ".h";
char* realFile = gSystem->Which(fSourceDir, hdrGuess, kReadPermission);
if (realFile) {
delete realFile;
fGuessedDeclFileNames[classPtr] = hdrGuess.Data();
impname = hdrGuess.Data();
srcGuess = osModule->String();
srcGuess.ToLower();
srcGuess += "/src/";
srcGuess += osFile->String();
srcGuess += ".cxx";
realFile = gSystem->Which(fSourceDir, srcGuess, kReadPermission);
if (realFile) {
delete realFile;
fGuessedImplFileNames[classPtr] = srcGuess.Data();
impname = srcGuess.Data();
}
}
}
delete arrScopes;
}
}
if (!impname || !impname[0]) {
cout << "WARNING class " << cname <<
" has no implementation file name !" << endl;
continue;
}
if (strstr(impname,"prec_stl/")) continue;
if (strstr(cname, "ROOT::") && !strstr(cname,"Math::")
&& !strstr(cname,"Reflex::") && !strstr(cname,"Cintex::"))
continue;
fClassNames[fNumberOfClasses] = cname;
fFileNames[fNumberOfFileNames] = StrDup(impname, strlen(fClassNames[fNumberOfClasses])+2);
char* posSlash = strchr(fFileNames[fNumberOfFileNames], '/');
char *srcdir = 0;
if (posSlash) {
srcdir = strstr(posSlash, "/src/");
if (!srcdir) srcdir=strstr(posSlash, "/inc/");
} else srcdir = 0;
if (srcdir && srcdir == posSlash) {
strcpy(srcdir, "_");
for (char *t = fFileNames[fNumberOfFileNames];
(t[0] = toupper(t[0])); t++);
strcat(srcdir, fClassNames[fNumberOfClasses]);
} else {
if (posSlash && !strncmp(posSlash,"/Math/GenVector/", 16))
strcpy(fFileNames[fNumberOfFileNames], "MATHCORE_");
else if (posSlash && !strncmp(posSlash,"/Math/Matrix", 12))
strcpy(fFileNames[fNumberOfFileNames], "SMATRIX_");
else
strcpy(fFileNames[fNumberOfFileNames], "USER_");
strcat(fFileNames[fNumberOfFileNames], fClassNames[fNumberOfClasses]);
}
fNumberOfFileNames++;
fNumberOfClasses++;
}
SortNames(fClassNames, fNumberOfClasses, kCaseInsensitive);
SortNames((const char **) fFileNames, fNumberOfFileNames);
}
void THtml::CreateListOfTypes()
{
ofstream typesList;
gSystem->ExpandPathName(fOutputDir);
char *outFile = gSystem->ConcatFileName(fOutputDir, "ListOfTypes.html");
typesList.open(outFile, ios::out);
if (typesList.good()) {
Printf(formatStr, "", "", outFile);
WriteHtmlHeader(typesList, "List of data types");
typesList << "<h2> List of data types </h2>" << endl;
typesList << "<dl><dd>" << endl;
TDataType *type;
TIter nextType(gROOT->GetListOfTypes());
std::list<std::string> typeNames;
while ((type = (TDataType *) nextType()))
if (*type->GetTitle() && !strchr(type->GetName(), '(')
&& !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>'))
&& type->GetName())
typeNames.push_back(type->GetName());
sort_strlist_stricmp(typeNames);
std::vector<std::string> indexChars;
if (typeNames.size() > 10) {
typesList << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
GetIndexChars(typeNames, 10 , indexChars);
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
typesList << "<a href=\"#idx" << iIdxEntry << "\">" << indexChars[iIdxEntry]
<< "</a>" << endl;
}
typesList << "</div><br/>" << endl;
}
typesList << "<ul id=\"indx\">" << endl;
nextType.Reset();
int idx = 0;
UInt_t currentIndexEntry = 0;
for (std::list<std::string>::iterator iTypeName = typeNames.begin();
iTypeName != typeNames.end(); ++iTypeName) {
TDataType* type = gROOT->GetType(iTypeName->c_str(), kFALSE);
typesList << "<li class=\"idxl" << idx%2 << "\">";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), iTypeName->c_str(),
indexChars[currentIndexEntry].length()))
typesList << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
typesList << "<a name=\"";
ReplaceSpecialChars(typesList, iTypeName->c_str());
typesList << "\"><tt>";
ReplaceSpecialChars(typesList, iTypeName->c_str());
typesList << "</tt></a>";
typesList << "<a name=\"Title:";
ReplaceSpecialChars(typesList, type->GetTitle());
typesList << "\"></a>";
ReplaceSpecialChars(typesList, type->GetTitle());
typesList << "</li>" << endl;
++idx;
}
typesList << "</ul>" << endl;
TDatime date;
WriteHtmlFooter(typesList, "", date.AsString());
typesList.close();
} else
Error("Make", "Can't open file '%s' !", outFile);
if (outFile)
delete[]outFile;
}
void THtml::CreateStyleSheet() {
ofstream styleSheet;
gSystem->ExpandPathName(fOutputDir);
char *outFile = gSystem->ConcatFileName(fOutputDir, "ROOT.css");
styleSheet.open(outFile, ios::out);
if (styleSheet.good()) {
styleSheet
<< "a {" << std::endl
<< " text-decoration: none;" << std::endl
<< " font-weight: bolder;" << std::endl
<< "}" << std::endl
<< "a:link {" << std::endl
<< " color: #0000ff;" << std::endl
<< " text-decoration: none;" << std::endl
<< "}" << std::endl
<< "a:visited {" << std::endl
<< "" << std::endl
<< " color: #5500cc;" << std::endl
<< "}" << std::endl
<< "a:active {" << std::endl
<< " color: #551a8b;" << std::endl
<< " border: dotted 1px #0000ff;" << std::endl
<< "}" << std::endl
<< "a:hover {" << std::endl
<< " background: #eeeeff;" << std::endl
<< "}" << std::endl
<< "" << std::endl
<< "#indx {" << std::endl
<< " list-style: none;" << std::endl
<< " padding-left: 0em;" << std::endl
<< " margin-left: 0em;" << std::endl
<< "}" << std::endl
<< "#indx li {" << std::endl
<< " margin-top: 1px;" << std::endl
<< " margin-bottom: 1px;" << std::endl
<< " margin-left: 0px;" << std::endl
<< " padding-left: 2em;" << std::endl
<< " padding-bottom: 0.3em;" << std::endl
<< " border-top: 0px hidden #afafaf;" << std::endl
<< " border-left: 0px hidden #afafaf;" << std::endl
<< " border-bottom: 1px hidden #ffffff;" << std::endl
<< " border-right: 1px hidden #ffffff;" << std::endl
<< "}" << std::endl
<< "#indx li:hover {" << std::endl
<< " border-top: 1px solid #afafaf;" << std::endl
<< " border-left: 1px solid #afafaf;" << std::endl
<< " border-bottom: 0px solid #ffffff;" << std::endl
<< " border-right: 0px solid #ffffff;" << std::endl
<< "}" << std::endl
<< "#indx li.idxl0 {" << std::endl
<< " background-color: #e7e7ff;" << std::endl
<< "}" << std::endl
<< "#indx a {" << std::endl
<< " font-weight: bold;" << std::endl
<< " display: block;" << std::endl
<< " margin-left: -1em;" << std::endl
<< "}" << std::endl
<< "#indxShortX {" << std::endl
<< " border: 3px solid gray;" << std::endl
<< " padding: 8pt;" << std::endl
<< " margin-left: 2em;" << std::endl
<< "}" << std::endl
<< "#indxShortX h4 {" << std::endl
<< " margin-top: 0em;" << std::endl
<< " margin-bottom: 0.5em;" << std::endl
<< "}" << std::endl
<< "#indxShortX a {" << std::endl
<< " margin-right: 0.25em;" << std::endl
<< " margin-left: 0.25em;" << std::endl
<< "}" << std::endl
<< "#indxModules {" << std::endl
<< " border: 3px solid gray;" << std::endl
<< " padding: 8pt;" << std::endl
<< " margin-left: 2em;" << std::endl
<< "}" << std::endl
<< "#indxModules h4 {" << std::endl
<< " margin-top: 0em;" << std::endl
<< " margin-bottom: 0.5em;" << std::endl
<< "}" << std::endl
<< "#indxModules a {" << std::endl
<< " margin-right: 0.25em;" << std::endl
<< " margin-left: 0.25em;" << std::endl
<< "}" << std::endl
<< "#searchform {" << std::endl
<< " margin-left: 2em;" << std::endl
<< "}" << std::endl
<< "" << std::endl
<< "div.funcdoc {" << std::endl
<< " width: 100%;" << std::endl
<< " border-bottom: solid 3px #cccccc;" << std::endl
<< " border-left: solid 1px #cccccc;" << std::endl
<< " margin-bottom: 1em;" << std::endl
<< " margin-left: 0.3em;" << std::endl
<< " padding-left: 1em;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "span.funcname {" << std::endl
<< " margin-left: -0.7em;" << std::endl
<< " " << std::endl
<< " font-weight: bolder;" << std::endl
<< "}" << std::endl
<< "" << std::endl
<< "span.comment {" << std::endl
<< " background-color: #eeeeee;" << std::endl
<< " color: Green;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "span.keyword {" << std::endl
<< " color: Maroon;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "span.cpp {" << std::endl
<< " color: Gray;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "span.string {" << std::endl
<< " color: Teal;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "pre.code {" << std::endl
<< " font-weight: bolder;" << std::endl
<< "}" << std::endl
<< "div.classdescr {" << std::endl
<< " width: 100%;" << std::endl
<< " margin-left: 0.3em;" << std::endl
<< " padding-left: 1em;" << std::endl
<< " margin-bottom: 2em;" << std::endl
<< " " << std::endl
<< " border-bottom: solid 3px #cccccc;" << std::endl
<< " border-left: solid 1px #cccccc;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "body {" << std::endl
<< " background-color: #fcfcfc;" << std::endl
<< "}" << std::endl
<< "table.inhtree {" << std::endl
<< " background-color: White;" << std::endl
<< " border: solid 1px Black;" << std::endl
<< " width: 100%;" << std::endl
<< "}" << std::endl
<< "table.libinfo " << std::endl
<< "{" << std::endl
<< " background-color: White;" << std::endl
<< " padding: 2px;" << std::endl
<< " border: solid 1px Gray; " << std::endl
<< " float: right;" << std::endl
<< "}" << std::endl;
}
delete outFile;
}
void THtml::ExpandKeywords(ostream & out, const char *text)
{
TString str(text);
ExpandKeywords(str);
out << str;
}
void THtml::ExpandKeywords(TString& keyword)
{
static Bool_t pre_is_open = kFALSE;
Bool_t commentIsCPP = kFALSE;
TClass* currentType = 0;
enum {
kNada,
kMember,
kScope,
kNumAccesses
} scoping = kNada;
Ssiz_t i;
for (i = 0; i < keyword.Length(); ++i) {
if (!currentType)
scoping = kNada;
if (fParseContext == kCode || fParseContext == kCComment) {
if (!strncmp(keyword.Data() + i, "::", 2)) {
scoping = kScope;
i += 2;
} else if (!strncmp(keyword.Data() + i, "->", 2)) {
scoping = kMember;
i += 2;
} else if (keyword[i] == '.') {
scoping = kMember;
++i;
} else currentType = 0;
if (i >= keyword.Length())
break;
} else currentType = 0;
if (!IsWord(keyword[i])){
if (fParseContext != kBeginEndHtml && fParseContext != kBeginEndHtmlInCComment) {
Bool_t closeString = !fEscFlag && fParseContext == kString &&
( keyword[i] == '"' || keyword[i] == '\'');
if (!fEscFlag)
if (fParseContext == kCode || fParseContext == kCComment) {
if (keyword.Length() > i + 1 && keyword[i] == '"' ||
keyword[i] == '\'' && (
keyword.Length() > i + 2 && keyword[i + 2] == '\'' ||
keyword.Length() > i + 3 && keyword[i + 1] == '\'' && keyword[i + 3] == '\'')) {
keyword.Insert(i, "<span class=\"string\">");
i += 21;
fParseContext = kString;
currentType = 0;
} else if (fParseContext != kCComment &&
keyword.Length() > i + 1 && keyword[i] == '/' &&
(keyword[i+1] == '/' || keyword[i+1] == '*')) {
fParseContext = kCComment;
commentIsCPP = keyword[i+1] == '/';
currentType = 0;
}
} else if (fParseContext == kCComment && !commentIsCPP &&
keyword.Length() > i + 1 &&
keyword[i] == '*' && keyword[i+1] == '/') {
fParseContext = kCode;
currentType = 0;
}
ReplaceSpecialChars(keyword, i);
if (closeString) {
keyword.Insert(i, "</span>");
i += 7;
fParseContext = kCode;
currentType = 0;
}
--i;
} else
if ((unsigned char)keyword[i]>31)
if (keyword[i] == '<'){
if (!strncasecmp(keyword.Data() + i, "<pre>", 5)){
if (pre_is_open) {
keyword.Remove(i, 4);
continue;
} else {
pre_is_open = kTRUE;
i += 3;
}
currentType = 0;
} else
if (!strncasecmp(keyword,"</pre>", 6)) {
if (!pre_is_open) {
keyword.Remove(i, 5);
continue;
} else {
pre_is_open = kFALSE;
i += 4;
}
currentType = 0;
}
}
continue;
}
Ssiz_t endWord = i;
while (endWord < keyword.Length() && IsName(keyword[endWord]))
endWord++;
if (fParseContext != kCode && fParseContext != kCComment &&
fParseContext != kBeginEndHtml && fParseContext != kBeginEndHtmlInCComment) {
i = endWord - 1;
continue;
}
TString word(keyword(i, endWord - i));
if (fParseContext == kBeginEndHtml || fParseContext == kBeginEndHtmlInCComment) {
if (!word.CompareTo("end_html", TString::kIgnoreCase) &&
(i == 0 || keyword[i - 1] != '\"')) {
if (fParseContext == kBeginEndHtmlInCComment) {
fParseContext = kCComment;
commentIsCPP = kFALSE;
} else
fParseContext = kCode;
pre_is_open = kTRUE;
keyword.Replace(i, word.Length(), "<pre>");
i += 4;
}
currentType = 0;
continue;
}
if (!word.CompareTo("begin_html", TString::kIgnoreCase) &&
(i == 0 || keyword[i - 1] != '\"')) {
if (commentIsCPP)
fParseContext = kBeginEndHtml;
else
fParseContext = kBeginEndHtmlInCComment;
pre_is_open = kFALSE;
keyword.Replace(i, word.Length(), "</pre>");
i += 5;
currentType = 0;
continue;
}
if (fParseContext == kCode &&
fgKeywords.find(word.Data()) != fgKeywords.end()) {
keyword.Insert(i, "<span class=\"keyword\">");
i += 22 + word.Length();
keyword.Insert(i, "</span>");
i += 7 - 1;
currentType = 0;
continue;
}
TDataType* subType = 0;
TClass* subClass = 0;
TDataMember *datamem = 0;
TMethod *meth = 0;
TClass* lookupScope = currentType;
if (!lookupScope)
lookupScope = fCurrentClass;
if (scoping == kNada) {
subType = gROOT->GetType(word);
if (!subType)
subClass = GetClass(word);
if (!subType && !subClass) {
TGlobal *global = gROOT->GetGlobal(word);
if (global) {
const char* globalTypeName = global->GetTypeName();
subClass = GetClass(globalTypeName);
if (!subClass)
subType = gROOT->GetType(globalTypeName);
else
if (subClass == THtml::Class() && word != "gHtml")
subClass = 0;
}
}
if (!subType && !subClass) {
}
}
if (lookupScope && !subType && !subClass) {
if (scoping == kScope) {
TString subClassName(lookupScope->GetName());
subClassName += "::";
subClassName += word;
subClass = GetClass(subClassName);
}
if (!subClass)
datamem = lookupScope->GetDataMember(word);
if (!subClass && !datamem)
meth = lookupScope->GetMethodAllAny(word);
}
TString link;
if (subType) {
link = "./ListOfTypes.html";
link += "#";
TString mangledWord(word);
NameSpace2FileName(mangledWord);
link += mangledWord;
currentType = 0;
} else if (subClass) {
GetHtmlFileName(subClass, link);
link.Prepend("./");
currentType = subClass;
} else if (datamem || meth) {
GetHtmlFileName(lookupScope, link);
link.Prepend("./");
link += "#";
TString mangledName(lookupScope->GetName());
NameSpace2FileName(mangledName);
link += mangledName;
link += ":";
if (datamem) {
mangledName = datamem->GetName();
if (datamem->GetDataType())
currentType = 0;
else
currentType = GetClass(datamem->GetTypeName());
} else {
mangledName = meth->GetName();
const char* retTypeName = meth->GetReturnTypeName();
if (retTypeName)
if (gROOT->GetType(retTypeName))
currentType = 0;
else
currentType = GetClass(retTypeName);
}
NameSpace2FileName(mangledName);
link += mangledName;
} else
currentType = 0;
if (link.Length()) {
link.Prepend("<a href=\"");
link += "\">";
keyword.Insert(i, link);
i += link.Length();
}
TString mangledWord(word);
NameSpace2FileName(mangledWord);
keyword.Replace(i, word.Length(), mangledWord);
i += word.Length();
if (link.Length()) {
keyword.Insert(i, "</a>");
i += 4;
}
--i;
}
if (commentIsCPP && fParseContext == kCComment)
fParseContext = kCode;
if (fParseContext == kString) {
keyword += "</span>";
i += 7;
fParseContext = kCode;
currentType = 0;
}
}
void THtml::ExpandPpLine(ostream & out)
{
const char *ptr;
const char *ptrStart;
const char *ptrEnd;
char *fileName;
Bool_t linkExist = kFALSE;
ptrEnd = strstr(fLine.Data(), "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);
fileName[len]=0;
char *tmpstr =
gSystem->Which(fSourceDir, fileName, kReadPermission);
if (tmpstr) {
char *realFileName = StrDup(tmpstr);
if (realFileName) {
CopyHtmlFile(realFileName);
ptr = fLine.Data();
while (ptr < ptrStart)
ReplaceSpecialChars(out, *ptr++);
out << "<a href=\"../" << GetFileName(realFileName) <<
"\">";
out << fileName << "</a>";
out << ptrEnd;
linkExist = kTRUE;
}
if (realFileName)
delete[]realFileName;
if (fileName)
delete[]fileName;
delete[]tmpstr;
}
}
}
}
if (!linkExist)
ReplaceSpecialChars(out, fLine);
}
const char *THtml::GetFileName(const char *filename)
{
return gSystem->BaseName(filename);
}
void THtml::GetSourceFileName(TString& filename)
{
TString found(filename);
if (strchr(filename, '/')
#ifdef WIN32
|| strchr(filename, '\\')
#endif
){
TString found(fSourcePrefix);
if (found.Length())
gSystem->PrependPathName(found, filename);
gSystem->FindFile(fSourceDir, filename, kReadPermission);
if (filename.Length())
return;
}
filename = GetFileName(filename);
if (filename.Length())
gSystem->FindFile(fSourceDir, filename, kReadPermission);
}
void THtml::GetHtmlFileName(TClass * classPtr, TString& filename)
{
filename.Remove(0);
if (!classPtr) return;
const char* cFilename = GetImplFileName(classPtr);
if (!cFilename || !cFilename[0])
cFilename = GetDeclFileName(classPtr);
if (!cFilename || !cFilename[0])
return;
TString varName("Root.Html.");
const char *colon = strchr(cFilename, ':');
if (colon)
varName += TString(cFilename, colon - cFilename);
else
varName += "Root";
filename = cFilename;
TString htmlFileName;
if (!filename.Length() ||
!gSystem->FindFile(fSourceDir, filename, kReadPermission))
htmlFileName = gEnv->GetValue(varName, "");
else
htmlFileName = "./";
if (htmlFileName.Length()) {
filename = htmlFileName;
TString className(classPtr->GetName());
NameSpace2FileName(className);
gSystem->PrependPathName(filename, className);
filename = className;
filename += ".html";
} else filename.Remove(0);
}
TClass *THtml::GetClass(const char *name1, Bool_t load)
{
if(!name1) return 0;
if (strstr(name1,"ROOT::")==name1) {
Bool_t ret = kTRUE;
if (strstr(name1,"Math::")) ret = kFALSE;
if (strstr(name1,"Reflex::")) ret = kFALSE;
if (strstr(name1,"Cintex::")) ret = kFALSE;
if (ret) return 0;
}
Int_t n = strlen(name1);
if (!n) return 0;
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);
if (cl && GetDeclFileName(cl) &&
strstr(GetDeclFileName(cl),"prec_stl/"))
cl = 0;
delete [] name;
if (cl && GetDeclFileName(cl) && GetDeclFileName(cl)[0])
return cl;
return 0;
}
const char* THtml::GetDeclFileName(TClass * cl) const
{
std::map<TClass*,std::string>::const_iterator iClDecl = fGuessedDeclFileNames.find(cl);
if (iClDecl == fGuessedDeclFileNames.end()) return cl->GetDeclFileName();
return iClDecl->second.c_str();
}
const char* THtml::GetImplFileName(TClass * cl) const
{
std::map<TClass*,std::string>::const_iterator iClImpl = fGuessedImplFileNames.find(cl);
if (iClImpl == fGuessedImplFileNames.end()) return cl->GetImplFileName();
return iClImpl->second.c_str();
}
Bool_t THtml::IsModified(TClass * classPtr, const Int_t type)
{
Bool_t ret = kTRUE;
TString sourceFile;
TString classname(classPtr->GetName());
TString filename;
TString dir;
switch (type) {
case kSource:
if (classPtr->GetImplFileLine()) {
sourceFile = GetDeclFileName(classPtr);
GetSourceFileName(sourceFile);
} else {
sourceFile = GetDeclFileName(classPtr);
GetSourceFileName(sourceFile);
}
dir = "src";
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, dir);
filename = classname;
NameSpace2FileName(filename);
gSystem->PrependPathName(dir, filename);
filename += ".cxx.html";
break;
case kInclude:
filename = GetDeclFileName(classPtr);
sourceFile = filename;
GetSourceFileName(sourceFile);
filename = GetFileName(filename);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, filename);
break;
case kTree:
sourceFile = GetDeclFileName(classPtr);
GetSourceFileName(sourceFile);
NameSpace2FileName(classname);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, classname);
filename = classname;
filename += "_Tree.pdf";
break;
default:
Error("IsModified", "Unknown file type !");
}
Long64_t sSize, dSize;
Long_t sId, sFlags, sModtime;
Long_t dId, 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 THtml::IsName(UChar_t c)
{
Bool_t ret = kFALSE;
if (isalnum(c) || c == '_')
ret = kTRUE;
return ret;
}
Bool_t THtml::IsWord(UChar_t c)
{
Bool_t ret = kFALSE;
if (isalpha(c) || c == '_')
ret = kTRUE;
return ret;
}
void THtml::MakeAll(Bool_t force, const char *filter)
{
Int_t i;
TString reg = filter;
TRegexp re(reg, kTRUE);
MakeIndex(filter);
for (i = 0; i < fNumberOfClasses; i++) {
fCounter.Form("%5d", fNumberOfClasses - i);
MakeClass((char *) fClassNames[i], force);
}
fCounter.Remove(0);
}
void THtml::MakeClass(const char *className, Bool_t force)
{
if (!fClassNames) CreateListOfClasses("*");
fCurrentClass = GetClass(className);
if (fCurrentClass) {
TString htmlFile;
GetHtmlFileName(fCurrentClass, htmlFile);
if (htmlFile.Length()
&& (htmlFile.BeginsWith("http:)
|| htmlFile.BeginsWith("https:)
|| gSystem->IsAbsoluteFileName(htmlFile))
) {
htmlFile.Remove(0);
}
if (htmlFile.Length()) {
Class2Html(force);
MakeTree(className, force);
} else
Printf(formatStr, "-skipped-", fCounter.Data(), className);
} else
if (!TClassEdit::IsStdClass(className))
Error("MakeClass", "Unknown class '%s' !", className);
}
void THtml::MakeIndex(const char *filter)
{
CreateListOfClasses(filter);
CreateListOfTypes();
CreateIndexByTopic(fFileNames, fNumberOfFileNames);
CreateIndex(fClassNames, fNumberOfClasses);
CreateHierarchy(fClassNames, fNumberOfClasses);
}
void THtml::MakeTree(const char *className, Bool_t force)
{
TVirtualPad *psCanvas = 0;
TVirtualUtilPad *util = (TVirtualUtilPad*)gROOT->GetListOfSpecials()->FindObject("R__TVirtualUtilPad");
if (!util) {
TPluginHandler *h;
if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualUtilPad"))) {
if (h->LoadPlugin() == -1)
return;
h->ExecPlugin(0);
util = (TVirtualUtilPad*)gROOT->GetListOfSpecials()->FindObject("R__TVirtualUtilPad");
}
}
util->MakeCanvas("","psCanvas",0,0,1000,1200);
psCanvas = gPad->GetVirtCanvas();
TClass *classPtr = GetClass(className);
if (classPtr) {
TString htmlFile;
GetHtmlFileName(classPtr, htmlFile);
if (htmlFile.Length()
&& (htmlFile.BeginsWith("http:)
|| htmlFile.BeginsWith("https:)
|| gSystem->IsAbsoluteFileName(htmlFile))
) {
htmlFile.Remove(0);
}
if (htmlFile.Length()) {
ClassTree(psCanvas, classPtr, force);
htmlFile.Remove(0);
} else
Printf(formatStr, "-skipped-", "", className);
} else
Error("MakeTree", "Unknown class '%s' !", className);
psCanvas->Close();
delete psCanvas;
}
void THtml::ReplaceSpecialChars(ostream & out, const char c)
{
static TString s;
s = c;
Ssiz_t pos = 0;
ReplaceSpecialChars(s, pos);
out << s.Data();
}
void THtml::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
{
const char c = text[pos];
if (fEscFlag) {
fEscFlag = kFALSE;
++pos;
return;
} else if (c == fEsc) {
fEscFlag = kTRUE;
return;
}
switch (c) {
case '<':
text.Replace(pos, 1, "<");
pos += 3;
break;
case '&':
text.Replace(pos, 1, "&");
pos += 4;
break;
case '>':
text.Replace(pos, 1, ">");
pos += 3;
break;
}
++pos;
}
void THtml::ReplaceSpecialChars(ostream & out, const char *string)
{
while (string && *string) {
ReplaceSpecialChars(out, *string);
string++;
}
}
void THtml::SetDeclFileName(TClass* cl, const char* filename)
{
fGuessedDeclFileNames[cl] = filename;
}
void THtml::SetImplFileName(TClass* cl, const char* filename)
{
fGuessedImplFileNames[cl] = filename;
}
void THtml::SortNames(const char **strings, Int_t num, Bool_t type)
{
if (type == kCaseSensitive)
qsort(strings, num, sizeof(strings), CaseSensitiveSort);
else
qsort(strings, num, sizeof(strings), CaseInsensitiveSort);
}
char *THtml::StrDup(const char *s1, Int_t 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 THtml::WriteHtmlHeader(ofstream & out, const char *title,
const char* dir , TClass *cls)
{
// Write HTML header
//
//
// Input: out - output file stream
// title - title for the HTML page
// cls - current class
// dir - relative directory to reach the top
// ("" for html doc, "../" for src/*cxx.html etc)
//
// evaluates the Root.Html.Header setting:
// * if not set, the standard header is written. (ROOT)
const char *addHeader = gEnv->GetValue("Root.Html.Header", "");
const char *charset = gEnv->GetValue("Root.Html.Charset", "ISO-8859-1");
if (addHeader
&& (strlen(addHeader) == 0
|| addHeader[strlen(addHeader) - 1] == '+')) {
TDatime date;
out << "<!DOCTYPE HTML PUBLIC \"-
endl;
out << "<html>" << endl;
out << "<!-- -->" <<
endl;
out << "<!-- Author: ROOT team (rootdev@hpsalo.cern.ch) -->" <<
endl;
out << "<!-- -->" <<
endl;
out << "<!-- Date: " << date.AsString() << " -->" << endl;
out << "<!-- -->" <<
endl;
out << "<head>" << endl;
out << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" <<
charset << "\" />" <<
endl;
out << "<title>";
ReplaceSpecialChars(out, title);
out << "</title>" << endl;
out << "<link rev=made href=\"mailto:rootdev@root.cern.ch\" />" <<
endl;
out << "<meta name=\"rating\" content=\"General\" />" << endl;
out << "<meta name=\"objecttype\" content=\"Manual\" />" << endl;
out <<
"<meta name=\"keywords\" content=\"software development, oo, object oriented, ";
out << "unix, x11, windows, c++, html, rene brun, fons rademakers, cern\" />"
<< endl;
out <<
"<meta name=\"description\" content=\"ROOT - An Object Oriented Framework For Large Scale Data Analysis.\" />"
<< endl;
out << "<link rel=\"stylesheet\" href=\"" << dir << "ROOT.css\" type=\"text/css\" id=\"ROOTstyle\" />" << endl;
out << "</head>" << endl;
out <<
"<body>"
<< endl;
};
if (addHeader && strlen(addHeader) > 0) {
ifstream addHeaderFile;
char *addHeaderTmp = StrDup(addHeader);
if (addHeaderTmp[strlen(addHeaderTmp) - 1] == '+')
addHeaderTmp[strlen(addHeaderTmp) - 1] = 0;
addHeaderFile.open(addHeaderTmp, ios::in);
if (addHeaderFile.good()) {
while (!addHeaderFile.eof()) {
fLine.ReadLine(addHeaderFile, kFALSE);
if (addHeaderFile.eof())
break;
if (fLine) {
TString txt(fLine);
txt.ReplaceAll("%TITLE%", title);
txt.ReplaceAll("%CLASS%", cls?cls->GetName():"");
txt.ReplaceAll("%INCFILE%", cls?GetDeclFileName(cls):"");
txt.ReplaceAll("%SRCFILE%", cls?GetImplFileName(cls):"");
out << txt << endl;
}
}
} else
Warning("THtml::WriteHtmlHeader",
"Can't open user html header file %s\n", addHeaderTmp);
if (addHeaderTmp)
delete[]addHeaderTmp;
}
out << "<a name=\"TopOfPage\"></a>" << endl;
}
void THtml::WriteHtmlFooter(ofstream & out, const char *dir,
const char *lastUpdate, const char *author,
const char *copyright)
{
out << endl;
const char* templateSITags[kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%"};
const char *addFooter = gEnv->GetValue("Root.Html.Footer", "");
if (addFooter && strlen(addFooter) > 0) {
ifstream addFooterFile;
char *addFooterTmp = StrDup(addFooter);
if (addFooterTmp[strlen(addFooterTmp) - 1] == '+')
addFooterTmp[strlen(addFooterTmp) - 1] = 0;
addFooterFile.open(addFooterTmp, ios::in);
if (addFooterFile.good()) {
while (!addFooterFile.eof()) {
fLine.ReadLine(addFooterFile, kFALSE);
if (addFooterFile.eof())
break;
if (fLine) {
for (Int_t siTag = 0; siTag < (Int_t) kNumSourceInfos; ++siTag) {
Ssiz_t siPos = fLine.Index(templateSITags[siTag]);
if (siPos != kNPOS)
fLine.Replace(siPos, strlen(templateSITags[siTag]), fSourceInfo[siTag]);
}
out << fLine;
}
}
} else
Warning("THtml::WriteHtmlFooter",
"Can't open user html footer file %s\n", addFooterTmp);
if (addFooterTmp)
delete[]addFooterTmp;
}
if (addFooter
&& (strlen(addFooter) == 0
|| addFooter[strlen(addFooter) - 1] == '+')) {
if (*author || *lastUpdate || *copyright)
out << "<br>" << endl;
out << "<!--SIGNATURE-->" << endl;
if (*author) {
out << "<em>Author: ";
char *auth = StrDup(author);
char *name = strtok(auth, ",");
Bool_t firstAuthor = kTRUE;
do {
char *ptr = name;
char *cLink = 0;
while (*ptr && isspace((UChar_t)*ptr))
ptr++;
if (!firstAuthor)
out << ", ";
if (!strncmp(ptr, "Nicolas", 7)) {
out << "<a href=http:;
ptr += 12;
} else {
cLink = strchr(ptr, '<');
if (cLink) {
out << "<a href=\"";
ptr = cLink-1;
for (cLink++; *cLink != 0 && *cLink != '>'; cLink++)
if (*cLink != ' ')
out << *cLink;
} else {
out << "<a href=\"" << GetXwho();
while (*ptr && !cLink) {
if (!strncmp(ptr, "Valery", 6)) {
out << "Valeri";
ptr += 6;
} else if (!strncmp(ptr, "Fine", 4)) {
out << "Faine";
ptr += 4;
}
while (*ptr && !isspace((UChar_t)*ptr))
out << *ptr++;
if (isspace((UChar_t)*ptr)) {
while (*ptr && isspace((UChar_t)*ptr))
ptr++;
if (isalpha(*ptr))
out << '+';
else
break;
} else
break;
}
}
}
out << "\">";
char *cCurrentPos = name;
while (*cCurrentPos == ' ')
cCurrentPos++;
Bool_t bBlank = kFALSE;
for (; cCurrentPos != ptr && *cCurrentPos != 0; cCurrentPos++) {
if (*cCurrentPos != ' ') {
if (bBlank) {
out << ' ';
bBlank = kFALSE;
}
out << *cCurrentPos;
} else
bBlank = kTRUE;
}
out << "</a>";
while (ptr && *ptr==' ') ptr++;
if (ptr && *ptr=='<') {
while (*ptr && *ptr!='>') ptr++;
if (ptr && *ptr=='>') ptr++;
}
while (ptr && *ptr==' ') ptr++;
if (ptr && *ptr)
out << ' ' << ptr;
firstAuthor = kFALSE;
name += strlen(name) + 1;
} while ((name - auth) < (int) strlen(author)
&& (name = strtok(name, ",")));
out << "</em><br>" << endl;
delete[]auth;
}
if (*lastUpdate)
out << "<em>Last update: " << lastUpdate << "</em><br>" << endl;
if (*copyright)
out << "<em>Copyright " << copyright << "</em><br>" << endl;
out << "<br>" << endl;
out << "<hr>" << endl;
out << "<center>" << endl;
out << "<address>" << endl;
out <<
"<a href=\"http:
const char *userHomePage = gEnv->GetValue("Root.Html.HomePage", "");
if (*userHomePage) {
out << "<a href=\"";
if (*dir) {
if (strncmp(userHomePage, "http:, 7)
&& strncmp(userHomePage, "https:, 8)
&& !gSystem->IsAbsoluteFileName(userHomePage))
out << dir;
}
out << userHomePage;
out << "\">Home page</a> - ";
}
out << "<a href=\"";
if (*dir)
out << dir;
out << "ClassIndex.html\">Class index</a> - ";
out << "<a href=\"";
if (*dir)
out << dir;
out << "ClassHierarchy.html\">Class Hierarchy</a> - ";
out << "<a href=\"#TopOfPage\">Top of the page</a><br>" << endl;
out << "</address>" << endl;
out << "</center>" << endl;
out << "<hr>" << endl;
out << "<address>" << endl;
out << "This page has been automatically generated. If you have any comments or suggestions ";
out <<
"about the page layout send a mail to <a href=\"mailto:rootdev@root.cern.ch\">ROOT support</a>, or ";
out <<
"contact <a href=\"mailto:rootdev@root.cern.ch\">the developers</a> with any questions or problems regarding ROOT."
<< endl;
out << "</address>" << endl;
out << "</body>" << endl;
out << "</html>" << endl;
}
}
void THtml::NameSpace2FileName(TString& name)
{
const char* replaceWhat = ":<> ,";
for (Ssiz_t i=0; i < name.Length(); ++i)
if (strchr(replaceWhat, name[i]))
name[i] = '_';
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.