#include "TDocOutput.h"
#include "Riostream.h"
#include "TClassDocOutput.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TDocInfo.h"
#include "TDocParser.h"
#include "TEnv.h"
#include "TGlobal.h"
#include "THtml.h"
#include "TMethod.h"
#include "TROOT.h"
#include "TSystem.h"
#include <vector>
#include <list>
#include <set>
#include <sstream>
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;
static 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;
}
}
static 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);
}
}
static 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;
}
}
static 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);
}
static 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);
}
}
namespace {
static int CaseInsensitiveSort(const void *name1, const void *name2)
{
return (strcasecmp(*((char **) name1), *((char **) name2)));
}
static 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);
}
}
ClassImp(TDocOutput);
TDocOutput::TDocOutput(THtml& html): fHtml(&html)
{}
TDocOutput::~TDocOutput()
{}
void TDocOutput::AddLink(TSubString& str, TString& link, const char* comment)
{
if (ReferenceIsRelative(link) && !link.BeginsWith("./"))
link.Prepend("./");
link.Prepend("<a href=\"");
link += "\"";
if (comment && strlen(comment)) {
link += " title=\"";
TString description(comment);
ReplaceSpecialChars(description);
description.ReplaceAll("\"", """);
link += description;
link += "\"";
}
link += ">";
str.String().Insert(str.Start() + str.Length(), "</a>");
str.String().Insert(str.Start(), link);
TString &strString = str.String();
TSubString update = strString(str.Start(), str.Length() + link.Length() + 4);
str = update;
}
void TDocOutput::AdjustSourcePath(TString& line, const char* relpath )
{
TString replWithRelPath("=\"");
replWithRelPath += relpath;
line.ReplaceAll("=\"./", replWithRelPath);
}
void TDocOutput::Convert(std::istream& in, const char* outfilename, const char *title,
const char *relpath )
{
TString htmlFilename(outfilename);
htmlFilename += ".html";
std::ofstream out(htmlFilename);
if (!out.good()) {
Error("Convert", "Can't open file '%s' !", htmlFilename.Data());
return;
}
Printf("Convert: %s", htmlFilename.Data());
WriteHtmlHeader(out, title, relpath);
out << "<h1>" << title << "</h1>" << endl;
out << "<pre>" << endl;
TDocParser parser(*this);
parser.Convert(out, in, relpath);
out << "</pre>" << endl;
WriteHtmlFooter(out, relpath);
}
Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName)
{
char *tmp1 = gSystem->Which(fHtml->GetSourceDir(), sourceName, kReadPermission);
if (!tmp1) {
Error("Copy", "Can't copy file '%s' to '%s/%s' - can't find source file!", sourceName,
fHtml->GetOutputDir().Data(), destName);
return kFALSE;
}
TString sourceFile(tmp1);
delete[]tmp1;
if (!sourceFile.Length()) {
Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName,
fHtml->GetOutputDir().Data());
return kFALSE;
}
TString destFile;
if (!destName || !*destName)
destFile = fHtml->GetFileName(sourceFile);
else
destFile = fHtml->GetFileName(destName);
gSystem->PrependPathName(fHtml->GetOutputDir(), destFile);
Long64_t size;
Long_t id, flags, sModtime, dModtime;
sModtime = 0;
dModtime = 0;
if (gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)
|| gSystem->GetPathInfo(destFile, &id, &size, &flags, &dModtime)
|| sModtime > dModtime)
gSystem->CopyFile(sourceFile, destFile, kTRUE);
return kTRUE;
}
void TDocOutput::CreateHierarchy()
{
TString filename("ClassHierarchy.html");
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
std::ofstream out(filename);
if (!out.good()) {
Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
return;
}
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
WriteHtmlHeader(out, "Class Hierarchy");
out << "<h1>Class Hierarchy</h1>" << endl;
WriteSearch(out);
TClassDocInfo* cdi = 0;
TIter iClass(fHtml->GetListOfClasses());
while ((cdi = (TClassDocInfo*)iClass())) {
if (!cdi->HaveSource())
continue;
TClass *basePtr = cdi->GetClass();
if (basePtr == 0) {
Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
continue;
}
TClassDocOutput cdo(*fHtml, basePtr);
cdo.CreateClassHierarchy(out, cdi->GetHtmlFileName());
}
WriteHtmlFooter(out);
}
void TDocOutput::CreateClassIndex()
{
fHtml->CreateAuxiliaryFiles();
TString filename("ClassIndex.html");
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
std::ofstream indexFile(filename.Data());
if (!indexFile.good()) {
Error("CreateClassIndex", "Can't open file '%s' !", filename.Data());
return;
}
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
WriteHtmlHeader(indexFile, "Class Index");
indexFile << "<h1>Index</h1>" << endl;
WriteModuleLinks(indexFile);
std::vector<std::string> indexChars;
if (fHtml->GetListOfClasses()->GetSize() > 10) {
std::vector<std::string> classNames;
{
TIter iClass(fHtml->GetListOfClasses());
TClassDocInfo* cdi = 0;
while ((cdi = (TClassDocInfo*)iClass()))
if (cdi->IsSelected() && cdi->HaveSource())
classNames.push_back(cdi->GetName());
}
if (classNames.size() > 10) {
indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
GetIndexChars(classNames, 50 , indexChars);
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
indexFile << "<a href=\"#idx" << iIdxEntry << "\">";
ReplaceSpecialChars(indexFile, indexChars[iIdxEntry].c_str());
indexFile << "</a>" << endl;
}
indexFile << "</div><br />" << endl;
}
}
WriteSearch(indexFile);
indexFile << "<ul id=\"indx\">" << endl;
UInt_t currentIndexEntry = 0;
TIter iClass(fHtml->GetListOfClasses());
TClassDocInfo* cdi = 0;
Int_t i = 0;
while ((cdi = (TClassDocInfo*)iClass())) {
if (!cdi->IsSelected() || !cdi->HaveSource())
continue;
TClass* currentClass = cdi->GetClass();
if (!currentClass) {
Warning("THtml::CreateClassIndex", "skipping class %s\n", cdi->GetName());
continue;
}
indexFile << "<li class=\"idxl" << (i++)%2 << "\">";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
indexChars[currentIndexEntry].length()))
indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
TString htmlFile(cdi->GetHtmlFileName());
if (htmlFile.Length()) {
indexFile << "<a href=\"";
indexFile << htmlFile;
indexFile << "\"><span class=\"typename\">";
ReplaceSpecialChars(indexFile, cdi->GetName());
indexFile << "</span></a> ";
} else {
indexFile << "<span class=\"typename\">";
ReplaceSpecialChars(indexFile, cdi->GetName());
indexFile << "</span> ";
}
ReplaceSpecialChars(indexFile, currentClass->GetTitle());
indexFile << "</li>" << endl;
}
indexFile << "</ul>" << endl;
WriteHtmlFooter(indexFile);
}
void TDocOutput::CreateModuleIndex()
{
const char* title = "LibraryDependencies";
TString filename(title);
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
std::ofstream libDepDotFile(filename + ".dot");
libDepDotFile << "strict digraph G {" << endl
<< "ratio=auto;" << endl
<< "rankdir=RL;" << endl
<< "compound=true;" << endl
<< "constraint=false;" << endl
<< "ranksep=3;" << endl
<< "nodesep=0.1;" << endl
<< "ratio=compress;" << endl
<< "node [fontsize=10];" << endl
<< "size=\"16,20\";" << endl;
TModuleDocInfo* module = 0;
TIter iModule(fHtml->GetListOfModules());
std::stringstream sstrCluster;
std::stringstream sstrDeps;
while ((module = (TModuleDocInfo*)iModule())) {
if (!module->IsSelected())
continue;
std::vector<std::string> indexChars;
TString filename(module->GetName());
filename += "_Index.html";
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
std::ofstream outputFile(filename.Data());
if (!outputFile.good()) {
Error("MakeIndex", "Can't open file '%s' !", filename.Data());
continue;
}
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
TString htmltitle("Index of ");
htmltitle += module->GetName();
htmltitle += " classes";
WriteHtmlHeader(outputFile, htmltitle);
outputFile << "<h2>" << htmltitle << "</h2>" << endl;
if (GetHtml()->GetModuleDocPath().Length()) {
TString outdir(module->GetName());
gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir);
TString moduleDocDir(GetHtml()->GetModuleDocPath());
if (!gSystem->IsAbsoluteFileName(moduleDocDir))
gSystem->PrependPathName(module->GetSourceDir(), moduleDocDir);
ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName());
}
std::list<std::string> classNames;
{
TIter iClass(module->GetClasses());
TClassDocInfo* cdi = 0;
while ((cdi = (TClassDocInfo*) iClass())) {
if (!cdi->IsSelected() || !cdi->HaveSource())
continue;
classNames.push_back(cdi->GetName());
if (classNames.size() > 1) continue;
TString libs(cdi->GetClass()->GetSharedLibs());
Ssiz_t posDepLibs = libs.Index(' ');
TString thisLib(libs);
if (posDepLibs != kNPOS)
thisLib.Remove(posDepLibs, thisLib.Length());
Ssiz_t posExt = thisLib.First('.');
if (posExt != kNPOS)
thisLib.Remove(posExt, thisLib.Length());
if (!thisLib.Length())
continue;
std::set<std::string>& setDep = fHtml->GetLibraryDependencies()[thisLib.Data()][module->GetName()];
if (posDepLibs != kNPOS) {
std::string lib;
for(Ssiz_t pos = posDepLibs + 1; libs[pos]; ++pos) {
if (libs[pos] == ' ') {
if (thisLib.Length() && lib.length()) {
size_t posExt = lib.find('.');
if (posExt != std::string::npos)
lib.erase(posExt);
setDep.insert(lib);
}
lib.erase();
} else
lib += libs[pos];
}
if (lib.length() && thisLib.Length()) {
size_t posExt = lib.find('.');
if (posExt != std::string::npos)
lib.erase(posExt);
setDep.insert(lib);
}
}
}
}
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 << "\">";
ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str());
outputFile << "</a>" << endl;
}
outputFile << "</div><br />" << endl;
}
outputFile << "<ul id=\"indx\">" << endl;
TIter iClass(module->GetClasses());
TClassDocInfo* cdi = 0;
UInt_t count = 0;
UInt_t currentIndexEntry = 0;
while ((cdi = (TClassDocInfo*) iClass())) {
if (!cdi->IsSelected() || !cdi->HaveSource())
continue;
TClass *classPtr = cdi->GetClass();
if (!classPtr) {
Error("MakeIndex", "Unknown class '%s' !", cdi->GetName());
continue;
}
outputFile << "<li class=\"idxl" << (count++)%2 << "\">";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
indexChars[currentIndexEntry].length()))
outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
TString htmlFile(cdi->GetHtmlFileName());
if (htmlFile.Length()) {
outputFile << "<a href=\"";
outputFile << htmlFile;
outputFile << "\"><span class=\"typename\">";
ReplaceSpecialChars(outputFile, classPtr->GetName());
outputFile << "</span></a> ";
} else {
outputFile << "<span class=\"typename\">";
ReplaceSpecialChars(outputFile, classPtr->GetName());
outputFile << "</span> ";
}
ReplaceSpecialChars(outputFile, classPtr->GetTitle());
outputFile << "</li>" << endl;
}
outputFile << "</ul>" << endl;
WriteHtmlFooter(outputFile);
}
for (THtml::LibDep_t::iterator iLibDep = fHtml->GetLibraryDependencies().begin();
iLibDep != fHtml->GetLibraryDependencies().end(); ++iLibDep) {
if (!iLibDep->first.length())
continue;
sstrCluster << "subgraph cluster" << iLibDep->first << " {" << endl
<< "style=filled;" << endl
<< "color=lightgray;" << endl
<< "label=\"";
if (iLibDep->first == "libCore")
sstrCluster << "Everything depends on ";
sstrCluster << iLibDep->first << "\";" << endl;
for (std::map<std::string, std::set<std::string> >::iterator iModule = iLibDep->second.begin();
iModule != iLibDep->second.end(); ++iModule) {
sstrCluster << "\"" << iModule->first << "\" [style=filled,color=white,URL=\""
<< iModule->first << "_Index.html\",fontsize=10];" << endl;
for (std::set<std::string>::iterator iLib = iModule->second.begin();
iLib != iModule->second.end(); ++iLib) {
const THtml::TMapModuleDepMap& modDep = fHtml->GetLibraryDependencies()[*iLib];
if (modDep.size()) {
THtml::TMapModuleDepMap::const_iterator iModDep = modDep.begin();
const std::string& mod = iModDep->first;
sstrDeps << "\"" << iModule->first << "\" -> \"" << mod << "\" [lhead=cluster" << *iLib << "];" << endl;
}
sstrDeps << "\"" << iModule->first << "\" -> \"CONT\" [style=invis];" << endl;
}
}
sstrCluster << endl
<< "}" << endl;
}
libDepDotFile << sstrCluster.str() << endl
<< sstrDeps.str();
libDepDotFile << "}" << endl;
libDepDotFile.close();
std::ofstream out(filename + ".html");
if (!out.good()) {
Error("CreateModuleIndex", "Can't open file '%s.html' !",
filename.Data());
return;
}
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (filename + ".html").Data());
WriteHtmlHeader(out, "Library Dependencies");
out << "<h1>Library Dependencies</h1>" << endl;
WriteSearch(out);
RunDot(filename, &out);
out << "<img alt=\"Library Dependencies\" class=\"formatsel\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
WriteHtmlFooter(out);
}
void TDocOutput::CreateProductIndex()
{
TString outFile("index.html");
gSystem->PrependPathName(GetHtml()->GetOutputDir(), outFile);
std::ofstream out(outFile);
if (!out.good()) {
Error("CreateProductIndex", "Can't open file '%s' !", outFile.Data());
return;
}
Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide");
out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl;
if (GetHtml()->GetProductDocDir().Length())
ProcessDocInDir(out, GetHtml()->GetProductDocDir(), GetHtml()->GetOutputDir(), "./");
WriteModuleLinks(out);
out << "<h2>Chapters</h2>" << std::endl
<< "<h3><a href=\"./ClassIndex.html\">Class Index</a></h3>" << std::endl
<< "<p>A complete list of all classes defined in " << GetHtml()->GetProductName() << "</p>" << std::endl
<< "<h3><a href=\"./ClassHierarchy.html\">Class Hierarchy</a></h3>" << std::endl
<< "<p>A hierarchy graph of all classes, showing each class's base and derived classes</p>" << std::endl
<< "<h3><a href=\"./ListOfTypes.html\">Type Index</a></h3>" << std::endl
<< "<p>A complete list of all types</p>" << std::endl
<< "<h3><a href=\"./LibraryDependencies.html\">Library Dependency</a></h3>" << std::endl
<< "<p>A diagram showing all of " << GetHtml()->GetProductName() << "'s libraries and their dependencies</p>" << std::endl;
WriteHtmlFooter(out);
}
void TDocOutput::CreateTypeIndex()
{
TString outFile("ListOfTypes.html");
gSystem->PrependPathName(fHtml->GetOutputDir(), outFile);
std::ofstream typesList(outFile);
if (!typesList.good()) {
Error("CreateTypeIndex", "Can't open file '%s' !", outFile.Data());
return;
}
Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
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 << "\">";
ReplaceSpecialChars(typesList, indexChars[iIdxEntry].c_str());
typesList << "</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 << "\"><span class=\"typename\">";
ReplaceSpecialChars(typesList, iTypeName->c_str());
typesList << "</span></a> ";
ReplaceSpecialChars(typesList, type->GetTitle());
typesList << "</li>" << endl;
++idx;
}
typesList << "</ul>" << endl;
WriteHtmlFooter(typesList);
typesList.close();
}
void TDocOutput::DecorateEntityBegin(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
{
Ssiz_t originalLen = str.Length();
switch (type) {
case TDocParser::kCode: break;
case TDocParser::kComment:
str.Insert(pos, "<span class=\"comment\">");
break;
case TDocParser::kDirective:
break;
case TDocParser::kString:
str.Insert(pos, "<span class=\"string\">");
break;
case TDocParser::kKeyword:
str.Insert(pos, "<span class=\"keyword\">");
break;
case TDocParser::kCPP:
str.Insert(pos, "<span class=\"cpp\">");
break;
case TDocParser::kVerbatim:
str.Insert(pos, "<pre>");
break;
default:
Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
return;
}
Ssiz_t addedLen = str.Length() - originalLen;
pos += addedLen;
}
void TDocOutput::DecorateEntityEnd(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
{
Ssiz_t originalLen = str.Length();
switch (type) {
case TDocParser::kCode: break;
case TDocParser::kComment:
str.Insert(pos, "</span>");
break;
case TDocParser::kDirective:
break;
case TDocParser::kString:
str.Insert(pos, "</span>");
break;
case TDocParser::kKeyword:
str.Insert(pos, "</span>");
break;
case TDocParser::kCPP:
str.Insert(pos, "</span>");
break;
case TDocParser::kVerbatim:
str.Insert(pos, "</pre>");
break;
default:
Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
return;
}
Ssiz_t addedLen = str.Length() - originalLen;
pos += addedLen;
}
void TDocOutput::FixupAuthorSourceInfo(TString& authors)
{
TString original(authors);
authors = "";
TString author;
Ssiz_t pos = 0;
Bool_t firstAuthor = kTRUE;
while (original.Tokenize(author, pos, ",")) {
author.Strip(TString::kBoth);
if (!firstAuthor)
authors += ", ";
firstAuthor = kFALSE;
Ssiz_t cLink = author.First('<');
if (cLink != kNPOS) {
Ssiz_t endLink = author.Index(">", cLink + 1);
if(endLink == kNPOS)
endLink = author.Length();
authors += "<a href=\"";
authors += author(cLink + 1, endLink - (cLink + 1));
authors += "\">";
authors += author(0, cLink);
authors += "</a>";
if (endLink != author.Length())
authors += author(endLink + 1, author.Length());
} else {
authors += "<a href=\"";
authors += fHtml->GetXwho();
TString namePart;
Ssiz_t posNamePart = 0;
Bool_t firstNamePart = kTRUE;
while (author.Tokenize(namePart, posNamePart, " ")) {
namePart.Strip(TString::kBoth);
if (!namePart.Length())
continue;
if (!firstNamePart)
authors += '+';
firstNamePart = kFALSE;
authors += namePart;
}
authors += "\">";
authors += author;
authors += "</a>";
}
}
}
Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type)
{
TString sourceFile;
TString classname(classPtr->GetName());
TString filename;
TString dir;
switch (type) {
case kSource:
if (classPtr->GetImplFileLine()) {
sourceFile = fHtml->GetImplFileName(classPtr);
fHtml->GetSourceFileName(sourceFile);
} else {
sourceFile = fHtml->GetDeclFileName(classPtr);
fHtml->GetSourceFileName(sourceFile);
}
dir = "src";
gSystem->PrependPathName(fHtml->GetOutputDir(), dir);
filename = classname;
NameSpace2FileName(filename);
gSystem->PrependPathName(dir, filename);
if (classPtr->GetImplFileLine())
filename += ".cxx.html";
else
filename += ".h.html";
break;
case kInclude:
filename = fHtml->GetDeclFileName(classPtr);
sourceFile = filename;
fHtml->GetSourceFileName(sourceFile);
filename = fHtml->GetFileName(filename);
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
break;
case kTree:
sourceFile = fHtml->GetDeclFileName(classPtr);
fHtml->GetSourceFileName(sourceFile);
NameSpace2FileName(classname);
gSystem->PrependPathName(fHtml->GetOutputDir(), classname);
filename = classname;
filename += "_Tree.pdf";
break;
default:
Error("IsModified", "Unknown file type !");
}
Long64_t size;
Long_t id, flags, sModtime, dModtime;
if (!(gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)))
if (!(gSystem->GetPathInfo(filename, &id, &size, &flags, &dModtime)))
return (sModtime > dModtime);
return kTRUE;
}
void TDocOutput::NameSpace2FileName(TString& name)
{
const char* replaceWhat = ":<> ,~=";
for (Ssiz_t i=0; i < name.Length(); ++i)
if (strchr(replaceWhat, name[i]))
name[i] = '_';
}
void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir,
const char* outdir, const char* linkdir)
{
void * dirHandle = gSystem->OpenDirectory(indir);
if (!dirHandle) return;
const char* entry = 0;
std::list<std::string> files;
while ((entry = gSystem->GetDirEntry(dirHandle))) {
FileStat_t stat;
TString filename(entry);
gSystem->PrependPathName(indir, filename);
if (gSystem->GetPathInfo(filename, stat))
continue;
if (!R_ISREG(stat.fMode)) continue;
if (TString(entry).BeginsWith("index.", TString::kIgnoreCase)) {
if (filename.EndsWith(".txt", TString::kIgnoreCase)) {
std::ifstream in(filename);
if (in) {
out << "<pre>";
TDocParser parser(*this);
parser.Convert(out, in, "../");
out << "</pre>";
}
} else if (filename.EndsWith(".html", TString::kIgnoreCase)) {
std::ifstream in(filename);
TString line;
while (in) {
if (!line.ReadLine(in)) break;
out << line;
}
}
} else
files.push_back(filename.Data());
}
std::stringstream furtherReading;
files.sort();
for (std::list<std::string>::const_iterator iFile = files.begin();
iFile != files.end(); ++iFile) {
TString filename(iFile->c_str());
if (!filename.EndsWith(".txt", TString::kIgnoreCase)
&& !filename.EndsWith(".html", TString::kIgnoreCase))
continue;
if (gSystem->AccessPathName(outdir))
if (gSystem->mkdir(outdir, kTRUE) == -1)
Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
TString outfile(gSystem->BaseName(filename));
gSystem->PrependPathName(outdir, outfile);
if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
outfile.Remove(outfile.Length()-3, 3);
outfile += "html";
std::ifstream in(filename);
std::ofstream out(outfile);
if (in && out) {
out << "<pre>";
TDocParser parser(*this);
parser.Convert(out, in, "../");
out << "</pre>";
}
} else {
if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
continue;
}
TString showname(gSystem->BaseName(outfile));
furtherReading << "<a class=\"linkeddoc\" href=\"" << linkdir << "/" << showname << "\">";
showname.Remove(showname.Length() - 5, 5);
showname.ReplaceAll("_", " ");
ReplaceSpecialChars(furtherReading, showname);
furtherReading << "</a> " << endl;
}
gSystem->FreeDirectory(dirHandle);
if (furtherReading.str().length())
out << "<h3>Further Reading</h3><div id=\"furtherreading\">" << endl
<< furtherReading.str() << "</div><h3>List of Classes</h3>" << endl;
}
void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment )
{
TString link;
fHtml->GetHtmlFileName(entity, link);
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment )
{
TString link;
TClass* scope = entity->GetClass();
fHtml->GetHtmlFileName(scope, link);
link += "#";
TString mangledName(scope->GetName());
NameSpace2FileName(mangledName);
link += mangledName;
link += ":";
mangledName = entity->GetName();
NameSpace2FileName(mangledName);
link += mangledName;
TString description;
if (!comment) {
description = entity->GetFullTypeName();
description += " ";
if (scope) {
description += scope->GetName();
description += "::";
}
description += entity->GetName();
comment = description.Data();
}
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment )
{
TString link("ListOfTypes.html#");
TString mangledEntity(entity->GetName());
NameSpace2FileName(mangledEntity);
link += mangledEntity;
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment )
{
TString link;
TClass* scope = entity->GetClass();
fHtml->GetHtmlFileName(scope, link);
link += "#";
TString mangledName(scope->GetName());
NameSpace2FileName(mangledName);
link += mangledName;
link += ":";
mangledName = entity->GetName();
NameSpace2FileName(mangledName);
link += mangledName;
TString description;
if (!comment && entity->GetClass()) {
TIter iMeth(scope->GetListOfMethods());
TMethod* mCand = 0;
while ((mCand = (TMethod*)iMeth()))
if (!strcmp(mCand->GetName(), entity->GetName())) {
if (description.Length()) {
description += " or overloads";
break;
}
description = mCand->GetPrototype();
}
comment = description.Data();
}
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
{
return !reference ||
strncmp(reference, "http", 4) ||
strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4);
}
const char* TDocOutput::ReplaceSpecialChars(const char c)
{
switch (c) {
case '<': return "<";
case '&': return "&";
case '>': return ">";
};
return 0;
}
void TDocOutput::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
{
const char c = text[pos];
const char* replaced = ReplaceSpecialChars(c);
if (replaced) {
text.Replace(pos, 1, replaced);
pos += strlen(replaced) - 1;
}
++pos;
}
void TDocOutput::ReplaceSpecialChars(TString& text) {
Ssiz_t pos = 0;
while (pos < text.Length())
ReplaceSpecialChars(text, pos);
}
void TDocOutput::ReplaceSpecialChars(std::ostream& out, const char *string)
{
while (string && *string) {
const char* replaced = ReplaceSpecialChars(*string);
if (replaced)
out << replaced;
else
out << *string;
string++;
}
}
Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap ) {
if (!fHtml->HaveDot())
return kFALSE;
TString runDot("dot");
if (fHtml->GetDotDir() && *fHtml->GetDotDir())
gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
runDot += " -q1 -Tgif -o";
runDot += filename;
runDot += ".gif ";
if (outMap) {
runDot += "-Tcmap -o";
runDot += filename;
runDot += ".map ";
}
runDot += filename;
runDot += ".dot";
if (gDebug > 3)
Info("RunDot", "Running: %s", runDot.Data());
Int_t retDot = gSystem->Exec(runDot);
if (gDebug < 4 && !retDot)
gSystem->Unlink(Form("%s.dot", filename));
if (!retDot && outMap) {
ifstream inmap(Form("%s.map", filename));
std::string line;
std::getline(inmap, line);
if (inmap && !inmap.eof()) {
*outMap << "<map name=\"Map" << gSystem->BaseName(filename)
<< "\" id=\"Map" << gSystem->BaseName(filename) << "\">" << endl;
while (inmap && !inmap.eof()) {
if (line.compare(0, 6, "<area ") == 0) {
size_t posEndTag = line.find('>');
if (posEndTag != std::string::npos)
line.replace(posEndTag, 1, "/>");
}
*outMap << line << endl;
std::getline(inmap, line);
}
*outMap << "</map>" << endl;
}
inmap.close();
if (gDebug < 7)
gSystem->Unlink(Form("%s.map", filename));
}
if (retDot) {
Error("RunDot", "Error running %s!", runDot.Data());
fHtml->SetFoundDot(kFALSE);
return kFALSE;
}
return kTRUE;
}
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial,
const char* dir , TClass *cls ,
const char* header)
{
ifstream addHeaderFile(header);
if (!addHeaderFile.good()) {
Warning("THtml::WriteHtmlHeader",
"Can't open html header file %s\n", header);
return;
}
const TString& charset = GetHtml()->GetCharset();
TDatime date;
TString strDate(date.AsString());
TString line;
while (!addHeaderFile.eof()) {
line.ReadLine(addHeaderFile, kFALSE);
if (addHeaderFile.eof())
break;
if (line) {
if (!cls && (
line.Index("%CLASS%") != kNPOS ||
line.Index("%INCFILE%") != kNPOS ||
line.Index("%SRCFILE%") != kNPOS))
continue;
TString txt(line);
txt.ReplaceAll("%TITLE%", titleNoSpecial);
txt.ReplaceAll("%DATE%", strDate);
txt.ReplaceAll("%RELDIR%", dir);
txt.ReplaceAll("%CHARSET%", charset);
if (cls) {
txt.ReplaceAll("%CLASS%", cls->GetName());
txt.ReplaceAll("%INCFILE%", fHtml->GetDeclFileName(cls));
txt.ReplaceAll("%SRCFILE%", fHtml->GetImplFileName(cls));
}
out << txt << endl;
}
}
}
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title,
const char* dir , TClass *cls)
{
TString userHeader = GetHtml()->GetHeader();
TString noSpecialCharTitle(title);
ReplaceSpecialChars(noSpecialCharTitle);
Ssiz_t lenUserHeader = userHeader.Length();
Bool_t bothHeaders = lenUserHeader > 0 && userHeader[lenUserHeader - 1] == '+';
if (lenUserHeader == 0 || bothHeaders) {
TString header("header.html");
gSystem->PrependPathName(fHtml->GetEtcDir(), header);
WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, header);
}
if (lenUserHeader != 0) {
if (bothHeaders)
userHeader.Remove(lenUserHeader - 1);
WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, userHeader);
};
}
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* ,
const char* lastUpdate, const char* author,
const char* copyright, const char* footer)
{
static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%"};
TString datimeString;
if (!lastUpdate) {
TDatime date;
datimeString = date.AsString();
lastUpdate = datimeString.Data();
}
const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright };
ifstream addFooterFile(footer);
if (!addFooterFile.good()) {
Warning("THtml::WriteHtmlFooter",
"Can't open html footer file %s\n", footer);
return;
}
TString line;
while (!addFooterFile.eof()) {
line.ReadLine(addFooterFile, kFALSE);
if (addFooterFile.eof())
break;
if (!line)
continue;
for (Int_t siTag = 0; siTag < (Int_t) TDocParser::kNumSourceInfos; ++siTag) {
Ssiz_t siPos = line.Index(templateSITags[siTag]);
if (siPos != kNPOS)
if (siValues[siTag] && siValues[siTag][0])
line.Replace(siPos, strlen(templateSITags[siTag]), siValues[siTag]);
else
line = "";
}
out << line << std::endl;
}
}
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
const char *lastUpdate, const char *author,
const char *copyright)
{
out << endl;
TString userFooter = GetHtml()->GetFooter();
if (userFooter.Length() != 0) {
TString footer(userFooter);
if (footer.EndsWith("+"))
footer.Remove(footer.Length() - 1);
WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
};
if (userFooter.Length() == 0 || userFooter.EndsWith("+")) {
TString footer("footer.html");
gSystem->PrependPathName(fHtml->GetEtcDir(), footer);
WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
}
}
void TDocOutput::WriteModuleLinks(std::ostream& out)
{
if (fHtml->GetListOfModules()->GetSize()) {
out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
TIter iModule(fHtml->GetListOfModules());
TModuleDocInfo* module = 0;
while ((module = (TModuleDocInfo*) iModule()))
if (module->IsSelected())
out << "<a href=\"" << module->GetName() << "_Index.html\">"
<< module->GetName() << "</a>" << endl;
out<< "</div><br />" << endl;
}
}
void TDocOutput::WriteSearch(std::ostream& out)
{
const TString& searchCmd = GetHtml()->GetSearchStemURL();
if (searchCmd.Length()) {
out << "<script type=\"text/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;
return;
}
const TString& searchEngine = GetHtml()->GetSearchEngine();
if (searchEngine.Length())
out << "<h2><a href=\"" << searchEngine
<< "\">Search the Class Reference Guide</a></h2>" << endl;
}
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.