::const_iterator iFile = files.begin();
iFile != files.end(); ++iFile) {
TString filename(iFile->c_str());
if (gSystem->AccessPathName(outdir))
if (gSystem->mkdir(outdir, kTRUE) == -1)
// bad - but let's still try to create the output
Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
TString outfile(gSystem->BaseName(filename));
gSystem->PrependPathName(outdir, outfile);
if (!filename.EndsWith(".txt", TString::kIgnoreCase)
&& !filename.EndsWith(".html", TString::kIgnoreCase)) {
// copy to outdir, who know whether it's needed...
if (gSystem->CopyFile(filename, outfile, kTRUE) == -1) {
Error("CreateModuleIndex", "Cannot copy file %s to %s",
filename.Data(), outfile.Data());
continue;
}
continue;
}
// Just copy and link this page.
if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
// convert first
outfile.Remove(outfile.Length()-3, 3);
outfile += "html";
std::ifstream inFurther(filename);
std::ofstream outFurther(outfile);
if (inFurther && outFurther) {
outFurther << ""; // this is what e.g. the html directive expects
TDocParser parser(*this);
parser.Convert(outFurther, inFurther, "../", kFALSE /*no code*/, kTRUE /*process Directives*/);
outFurther << "
";
}
} else {
if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
continue;
}
TString showname(gSystem->BaseName(outfile));
furtherReading << "";
showname.Remove(showname.Length() - 5, 5); // .html
showname.ReplaceAll("_", " ");
ReplaceSpecialChars(furtherReading, showname);
furtherReading << " " << std::endl;
}
gSystem->FreeDirectory(dirHandle);
if (furtherReading.str().length())
out << "Further Reading
" << std::endl
<< furtherReading.str() << "
List of Classes
" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
/// Create a reference to a class documentation page.
/// str encloses the text to create the reference for (e.g. name of instance).
/// comment will be added e.g. as tooltip text.
/// After the reference is put into str.String(), str will enclose the reference
/// and the original text. Example:
/// Input:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 5
/// Output:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 30
void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment /*= 0*/)
{
TString link;
fHtml->GetHtmlFileName(entity, link);
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
////////////////////////////////////////////////////////////////////////////////
/// Create a reference to a data member documentation page.
/// str encloses the text to create the reference for (e.g. name of instance).
/// comment will be added e.g. as tooltip text.
/// After the reference is put into str.String(), str will enclose the reference
/// and the original text. Example:
/// Input:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 5
/// Output:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 30
void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment /*= 0*/)
{
TString link;
TClass* scope = entity->GetClass();
fHtml->GetHtmlFileName(scope, link);
link += "#";
TString mangledName;
if (scope) {
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);
}
////////////////////////////////////////////////////////////////////////////////
/// Create a reference to a type documentation page.
/// str encloses the text to create the reference for (e.g. name of instance).
/// comment will be added e.g. as tooltip text.
/// After the reference is put into str.String(), str will enclose the reference
/// and the original text. Example:
/// Input:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 5
/// Output:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 30
void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment /*= 0*/)
{
TString mangledEntity(entity->GetName());
NameSpace2FileName(mangledEntity);
TString link;
TClassDocInfo* cdi = 0;
bool isClassTypedef = entity->GetType() == -1;
if (isClassTypedef)
/* is class/ struct / union */
isClassTypedef = isClassTypedef && (entity->Property() & 7);
if (isClassTypedef) {
std::string shortTypeName(fHtml->ShortType(entity->GetFullTypeName()));
cdi = (TClassDocInfo*) GetHtml()->GetListOfClasses()->FindObject(shortTypeName.c_str());
}
if (cdi) {
link = mangledEntity + ".html";
} else {
link = "ListOfTypes.html#";
link += mangledEntity;
}
if (comment && !strcmp(comment, entity->GetName()))
comment = "";
AddLink(str, link, comment);
}
////////////////////////////////////////////////////////////////////////////////
/// Create a reference to a method documentation page.
/// str encloses the text to create the reference for (e.g. name of instance).
/// comment will be added e.g. as tooltip text.
/// After the reference is put into str.String(), str will enclose the reference
/// and the original text. Example:
/// Input:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 5
/// Output:
/// str.String(): "a gHtml test"
/// str.Begin(): 2
/// str.Length(): 30
void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment /*= 0*/)
{
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);
}
////////////////////////////////////////////////////////////////////////////////
/// Check whether reference is a relative reference, and can (or should)
/// be prependen by relative paths. For HTML, check that it doesn't start
/// with "http://" or "https://"
Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
{
return !reference ||
strncmp(reference, "http", 4) ||
(strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4));
}
////////////////////////////////////////////////////////////////////////////////
/// Replace ampersand, less-than and greater-than character, writing to out.
/// If 0 is returned, no replacement needs to be done.
const char* TDocOutput::ReplaceSpecialChars(char c)
{
/*
if (fEscFlag) {
fEscFlag = kFALSE;
return buf;
} else if (c == fEsc) {
// text.Remove(pos, 1); - NO! we want to keep it nevertheless!
fEscFlag = kTRUE;
return buf;
}
*/
switch (c) {
case '<': return "<";
case '&': return "&";
case '>': return ">";
};
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// Replace ampersand, less-than and greater-than character
///
///
/// Input: text - text where replacement will happen,
/// pos - index of char to be replaced; will point to next char to be
/// replaced when function returns
///
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;
}
////////////////////////////////////////////////////////////////////////////////
/// Replace ampersand, less-than and greater-than character
///
///
/// Input: text - text where replacement will happen,
///
void TDocOutput::ReplaceSpecialChars(TString& text) {
Ssiz_t pos = 0;
while (pos < text.Length())
ReplaceSpecialChars(text, pos);
}
////////////////////////////////////////////////////////////////////////////////
/// Replace ampersand, less-than and greater-than characters, writing to out
///
///
/// Input: out - output file stream
/// string - pointer to an array of characters
///
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++;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Run filename".dot", creating filename".png", and - if outMap is !=0,
/// filename".map", which gets then included literally into outMap.
Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap /* =0 */,
EGraphvizTool gvwhat /*= kDot*/) {
if (!fHtml->HaveDot())
return kFALSE;
TString runDot;
switch (gvwhat) {
case kNeato: runDot = "neato"; break;
case kFdp: runDot = "fdp"; break;
case kCirco: runDot = "circo"; break;
default: runDot = "dot";
};
if (fHtml->GetDotDir() && *fHtml->GetDotDir())
gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
runDot += " -q1 -Tpng -o";
runDot += filename;
runDot += ".png ";
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) {
std::ifstream inmap(Form("%s.map", filename));
std::string line;
std::getline(inmap, line);
if (inmap && !inmap.eof()) {
*outMap << "" << std::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;
}
////////////////////////////////////////////////////////////////////////////////
/// Write HTML header
///
/// Internal method invoked by the overload
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial,
const char* dir /*=""*/, TClass *cls /*=0*/,
const char* header)
{
std::ifstream addHeaderFile(header);
if (!addHeaderFile.good()) {
Warning("THtml::WriteHtmlHeader",
"Can't open html header file %s\n", header);
return;
}
TString declFileName;
if (cls) fHtml->GetDeclFileName(cls, kFALSE, declFileName);
TString implFileName;
if (cls) fHtml->GetImplFileName(cls, kFALSE, implFileName);
const TString& charset = GetHtml()->GetCharset();
TDatime date;
TString strDate(date.AsString());
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; // skip class line for non-class files
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%", declFileName);
txt.ReplaceAll("%SRCFILE%", implFileName);
}
out << txt << std::endl;
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// 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)
/// * if set, and ends with a "+", the standard header is written and this file
/// included afterwards. (ROOT, USER)
/// * if set but doesn't end on "+" the file specified will be written instead
/// of the standard header (USER)
///
/// Any occurrence of "%TITLE%" (without the quotation marks) in the user
/// provided header file will be replaced by the value of this method's
/// parameter "title" before written to the output file. %CLASS% is replaced by
/// the class name, %INCFILE% by the header file name as given by
/// TClass::GetDeclFileName() and %SRCFILE% by the source file name as given by
/// TClass::GetImplFileName(). If the header is written for a non-class page,
/// i.e. cls==0, lines containing %CLASS%, %INCFILE%, or %SRCFILE% will be
/// skipped.
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title,
const char* dir /*=""*/, TClass *cls/*=0*/)
{
TString userHeader = GetHtml()->GetHeader();
TString noSpecialCharTitle(title);
ReplaceSpecialChars(noSpecialCharTitle);
Ssiz_t lenUserHeader = userHeader.Length();
// standard header output if Root.Html.Header is not set, or it's set and it ends with a "+".
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);
};
}
////////////////////////////////////////////////////////////////////////////////
/// Write HTML footer
///
/// Internal method invoked by the overload
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/,
const char* lastUpdate, const char* author,
const char* copyright, const char* footer)
{
static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%", "%CHANGED%", "%GENERATED%"};
TString today;
TDatime dtToday;
today.Form("%d-%02d-%02d %02d:%02d", dtToday.GetYear(), dtToday.GetMonth(), dtToday.GetDay(), dtToday.GetHour(), dtToday.GetMinute());
TString datimeString;
if (!lastUpdate || !lastUpdate[0]) {
lastUpdate = today;
}
const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright, lastUpdate, today };
std::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 = ""; // skip e.g. %AUTHOR% lines if no author is set
}
}
out << line << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Write HTML footer
///
///
/// Input: out - output file stream
/// dir - usually equal to "" or "../", depends of
/// current file directory position, i.e. if
/// file is in the fHtml->GetOutputDir(), then dir will be ""
/// lastUpdate - last update string
/// author - author's name
/// copyright - copyright note
///
/// Allows optional user provided footer to be written. Root.Html.Footer holds
/// the file name for this footer. For details see THtml::WriteHtmlHeader (here,
/// the "+" means the user's footer is written in front of Root's!) Occurences
/// of %AUTHOR%, %CHANGED%, %GENERATED%, and %COPYRIGHT% in the user's file are replaced by
/// their corresponding values (author, lastUpdate, today, and copyright) before
/// written to out.
/// If no author is set (author == "", e.g. for ClassIndex.html") skip the whole
/// line of the footer template containing %AUTHOR%. Accordingly for %COPYRIGHT%.
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
const char *lastUpdate, const char *author,
const char *copyright)
{
out << std::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);
}
}
////////////////////////////////////////////////////////////////////////////////
/// Create a div containing links to all topmost modules
void TDocOutput::WriteModuleLinks(std::ostream& out)
{
if (fHtml->GetListOfModules()->GetSize()) {
out << "Modules
" << std::endl;
// find index chars
fHtml->SortListOfModules();
TIter iModule(fHtml->GetListOfModules());
TModuleDocInfo* module = 0;
while ((module = (TModuleDocInfo*) iModule())) {
if (!module->GetName() || strchr(module->GetName(), '/'))
continue;
if (module->IsSelected()) {
TString name(module->GetName());
name.ToUpper();
out << "
"
<< name << "" << std::endl;
}
}
out<< "
" << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Create a div containing the line numbers (for a source listing) 1 to nLines.
/// Create links to the source file's line number and anchors, such that one can
/// jump to SourceFile.cxx.html#27 (using the anchor), and one can copy and paste
/// the link into e.g. gdb to get the text "SourceFile.cxx:27".
void TDocOutput::WriteLineNumbers(std::ostream& out, Long_t nLines, const TString& infileBase) const
{
out << "";
for (Long_t i = 0; i < nLines; ++i) {
// to force correct line height
out << "
";
}
out << "
" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
/// Create a div containing links to all modules
void TDocOutput::WriteModuleLinks(std::ostream& out, TModuleDocInfo* super)
{
if (super->GetSub().GetSize()) {
TString superName(super->GetName());
superName.ToUpper();
out << "" << superName << " Modules
" << std::endl;
// find index chars
super->GetSub().Sort();
TIter iModule(&super->GetSub());
TModuleDocInfo* module = 0;
while ((module = (TModuleDocInfo*) iModule())) {
if (module->IsSelected()) {
TString name(module->GetName());
name.ToUpper();
TString link(name);
link.ReplaceAll("/", "_");
Ssiz_t posSlash = name.Last('/');
if (posSlash != kNPOS)
name.Remove(0, posSlash + 1);
out << "
" << name << "" << std::endl;
}
}
out<< "
" << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Write a search link or a search box, based on THtml::GetSearchStemURL()
/// and THtml::GetSearchEngine(). The first one is preferred.
void TDocOutput::WriteSearch(std::ostream& out)
{
// e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u+-site%3A%u%2Fsrc%2F+-site%3A%u%2Fexamples%2F";
const TString& searchCmd = GetHtml()->GetSearchStemURL();
const TString& searchEngine = GetHtml()->GetSearchEngine();
if (!searchCmd.Length() && !searchEngine.Length())
return;
if (searchCmd.Length()) {
TUrl url(searchCmd);
TString serverName(url.GetHost());
if (serverName.Length()) {
serverName.Prepend(" title=\"");
serverName += "\" ";
}
// create search input
out << "" << std::endl
<< "" << std::endl;
} else if (searchEngine.Length())
// create link to search engine page
out << "Search the Class Reference Guide" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
/// make a link to the description
void TDocOutput::WriteLocation(std::ostream& out, TModuleDocInfo* module, const char* classname)
{
out << "" << std::endl; // location
const char *productName = fHtml->GetProductName();
out << "
" << productName << "" << std::endl;
if (module) {
TString modulename(module->GetName());
modulename.ToUpper();
TString modulePart;
TString modulePath;
Ssiz_t pos = 0;
while (modulename.Tokenize(modulePart, pos, "/")) {
if (pos == kNPOS && !classname)
// we are documenting the module itself, no need to link it:
break;
if (modulePath.Length()) modulePath += "_";
modulePath += modulePart;
out << " »
" << modulePart << "" << std::endl;
}
}
TString entityName;
if (classname) entityName = classname;
else if (module) {
entityName = module->GetName();
Ssiz_t posSlash = entityName.Last('/');
if (posSlash != kNPOS)
entityName.Remove(0, posSlash + 1);
entityName.ToUpper();
}
if (entityName.Length()) {
out << " »
";
ReplaceSpecialChars(out, entityName);
out << "" << std::endl;
}
out << "
" << std::endl; // location
}
////////////////////////////////////////////////////////////////////////////////
/// Write the first part of the links shown ontop of each doc page;
/// one has to be closed by caller so additional items can still
/// be added.
void TDocOutput::WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname,
Bool_t withLocation)
{
out << "
" << std::endl;
out << "
" << std::endl // descrhead line 1
<< "
Quick Links:" << std::endl;
// link to the user home page (if exist)
const char* userHomePage = GetHtml()->GetHomepage();
const char* productName = fHtml->GetProductName();
if (!productName) {
productName = "";
} else if (!strcmp(productName, "ROOT")) {
userHomePage = "";
}
if (userHomePage && *userHomePage)
out << "
" << productName << "" << std::endl;
out << "
ROOT Homepage" << std::endl
<< "
Class Index" << std::endl
<< "
Class Hierarchy" << std::endl;
WriteSearch(out);
out << "
" << std::endl; // descrhead, line 1
if (withLocation) {
out << "
" << std::endl; //toplinks
WriteLocation(out, module, classname); // descrhead line 2
}
// else {
// Closed by caller!
// out << "
" << std::endl; // toplinks
// }
}