#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 "TPaveText.h"
#include "TClassEdit.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <list>
#include <vector>
#include <algorithm>
#include <sstream>
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;
// BEGIN_HTML <!--
/* --><p>The THtml class is designed to easily document
classes, code, and code related text files (like change logs). It generates HTML
pages conforming to the XHTML 1.0 transitional specifications; an example of
these pages is ROOT's own <a href="http://root.cern.ch/root/html/ClassIndex.html">
reference guide</a>. This page was verified to be valid XHTML 1.0 transitional,
which proves that all pages generated by THtml can be valid, as long as the user
provided XHTML (documentation, header, etc) is valid. You can check the current
THtml by clicking this icon:
<a href="http://validator.w3.org/check?uri=referer"><img
src="http://www.w3.org/Icons/valid-xhtml10"
alt="Valid XHTML 1.0 Transitional" height="31" width="88" style="border: none;"/></a></p>
Overview:
<ol style="list-style-type: upper-roman;"><li><a href="#conf">Configuration</a>
<ol><li><a href="#conf:input">Input files</a></li>
<li><a href="#conf:output">Output directory</a></li>
<li><a href="#conf:liblink">Linking other documentation</a></li>
<li><a href="#conf:classdoc">Recognizing class documentation</a></li>
<li><a href="#conf:tags">Author, copyright, etc.</a></li>
<li><a href="#conf:header">Header and footer</a></li>
<li><a href="#conf:search">Links to searches, home page, ViewCVS</a></li>
<li><a href="#conf:charset">HTML Charset</a></li>
</ol></li>
<li><a href="#syntax">Documentation syntax</a>
<ol><li><a href="#syntax:classdesc">Class description</a></li>
<li><a href="#syntax:classidx">Class index</a></li>
<li><a href="#syntax:meth">Method documentation</a></li>
<li><a href="#syntax:datamem">Data member documentation</a></li>
<li><a href="#syntax:beginhtml"><tt>BEGIN<!-- -->_HTML</tt> <tt>END<!-- -->_HTML</tt>: include 'raw' HTML</a></li>
</ol></li>
<li><a href="#CSSJS">Style sheet, JavaScript</a></li>
<li><a href="#charts">Class Charts</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#confvar">Configuration variables</a></li>
</ol>
<h3><a name="conf">I. Configuration</a></h3>
<h4><a name="conf:input">I.1 Input files</a></h4>
<p>In your .rootrc, define Root.Html.SourceDir to point to directories containing
.cxx and .h files (see: <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>)
of the classes you want to document.</p>
<p>Example:</p><pre>
Root.Html.SourceDir: .:src:include
Root.Html.Root: http://root.cern.ch/root/html</pre>
<h4><a name="conf:output">I.2 Output directory</a></h4>
<p>The output directory can be specified using the Root.Html.OutputDir
configuration variable (default value: "htmldoc"). If that directory
doesn't exist <a href="http://root.cern.ch/root/html/THtml.html">THtml</a>
will create it.</p>
<p>Example:</p><pre>
Root.Html.OutputDir: htmldoc</pre>
<h4><a name="conf:liblink">I.3 Linking other documentation</a></h4>
<p>When trying to document a class, THtml searches for a source file in
the directories set via SetSourceDir(). If it cannot find it, it assumes
that this class must have been documented before. Based on the library
this class is defined in, it checks the configuration variable
<tt>Root.Html.LibName</tt>, and creates a link using its value.</p>
<p>Example:<br/>
If a class MyClass is defined in class mylibs/libMyLib.so, and .rootrc
contains</p><pre>
Root.Html.MyLib: ../mylib/</pre>
<p>THtml will create a link to "../mylib/MyClass.html".</p>
<p>The library name association can be set up using the rootmap facility.
For the library in the example above, which contains a dictionary
generated from the linkdef MyLinkdef.h, the command to generate the
rootmap file is</p>
<pre> $ rlibmap -f -r rootmap -l mylib/libMyLib.so -d libCore.so -c MyLinkdef.h</pre>
<p>Here, <tt>-r</tt> specifies that the entries for libMyLib should be updated,
<tt>-l</tt> specifies the library we're dealing with, <tt>-d</tt> its
dependencies, and <tt>-c</tt> its linkdef. The rootmap file must be within
one of the <tt>LD_LIBRARY_PATH</tt> (or <tt>PATH</tt> for Windows) directories
when ROOT is started, otherwise ROOT will not use it.</p>
<h4><a name="conf:classdoc">I.4 Recognizing class documentation</a></h4>
<p>The class documentation has to appear in the header file containing the
class, right in front of its declaration. It is introduced by a string
defined by Root.Html.Description. See the section on
<a href="#syntax">documentation syntax</a> for further details.</p>
<p>Example:</p><pre>
Root.Html.Description: //____________________</pre>
<h4><a name="conf:tags">I.5 Author, copyright, etc.</a></h4>
<p>During the conversion,
<a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will look for
some strings ("tags") in the source file, which have to appear right in
front of e.g. the author's name, copyright notice, etc. These tags can be
defined with the following environment variables: Root.Html.Author,
Root.Html.LastUpdate and Root.Html.Copyright.</p>
<p>If the LastUpdate tag is not found, the current date and time are used.
This is useful when using
<a href="http://root.cern.ch/root/html/THtml.html#THtml:MakeAll">THtml::MakeAll()</a>'s
default option force=kFALSE, in which case
<a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates
documentation only for changed classes.</p>
Authors can be a comma separated list of author entries. Each entry has
one of the following two formats
<ul><li><tt>Name (non-alpha)</tt>.
<p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate an
HTML link for <tt>Name</tt>, taking the Root.Html.XWho configuration
variable (defaults to "http://consult.cern.ch/xwho/people?") and adding
all parts of the name with spaces replaces by '+'. Non-alphanumerical
characters are printed out behind <tt>Name</tt>.</p>
<p>Example:</p>
<tt>// Author: Enrico Fermi</tt> appears in the source file.
<a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate the link
<tt>http://consult.cern.ch/xwho/people?Enrico+Fermi</tt>. This works well for
people at CERN.</li>
<li><tt>Name <link> Info</tt>.
<p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will generate
an HTML link for <tt>Name</tt> as specified by <tt>link</tt> and print
<tt>Info</tt> behind <tt>Name</tt>.</p>
<p>Example:</p>
<tt>// Author: Enrico Fermi <http://www.enricos-home.it></tt> or<br/>
<tt>// Author: Enrico Fermi <mailto:enrico@fnal.gov></tt> in the
source file. That's world compatible.</li>
</ul>
<p>Example (with defaults given):</p><pre>
Root.Html.Author: // Author:
Root.Html.LastUpdate: // @(#)
Root.Html.Copyright: * Copyright
Root.Html.XWho: http://consult.cern.ch/xwho/people?</pre>
<h4><a name="conf:header">I.6 Header and footer</a></h4>
<p><a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates
a default header and footer for all pages. You can
specify your own versions with the configuration variables Root.Html.Header
and Root.Html.Footer. Both variables default to "", using the standard Root
versions. If it has a "+" appended, <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will
write both versions (user and root) to a file, for the header in the order
1st root, 2nd user, and for the footer 1st user, 2nd root (the root
versions containing "<html>" and </html> tags, resp).</p>
<p>If you want to replace root's header you have to write a file containing
all HTML elements necessary starting with the <doctype> tag and ending with
(and including) the <body> tag. If you add your header it will be added
directly after Root's <body> tag. Any occurrence of the string <tt>%TITLE%</tt>
in the user's header file will be replaced by
a sensible, automatically generated title. If the header is generated for a
class, occurrences of <tt>%CLASS%</tt> will be replaced by the current class's name,
<tt>%SRCFILE%</tt> and <tt>%INCFILE%</tt> by the name of the source and header file, resp.
(as given by <a href="http://root.cern.ch/root/html/TClass.html#TClass:GetImplFileLine">TClass::GetImplFileName()</a>,
<a href="http://root.cern.ch/root/html/TClass.html#TClass:GetImplFileLine">TClass::GetDeclFileName()</a>).
If the header is not generated for a class, they will be replaced by "".</p>
<p>Root's footer starts with the tag <!--SIGNATURE-->. It includes the
author(s), last update, copyright, the links to the Root home page, to the
user home page, to the index file (ClassIndex.html), to the top of the page
and <tt>this page is automatically generated</tt> infomation. It ends with the
tags <tt></body></html></tt>. If you want to replace it,
<a href="http://root.cern.ch/root/html/THtml.html">THtml</a> will search for some
tags in your footer: Occurrences of the strings <tt>%AUTHOR%</tt>, <tt>%UPDATE%</tt>, and
<tt>%COPYRIGHT%</tt> are replaced by their
corresponding values before writing the html file. The <tt>%AUTHOR%</tt> tag will be
replaced by the exact string that follows Root.Html.Author, no link
generation will occur.</p>
<h4><a name="conf:search">I.7 Links to searches, home page, ViewCVS</a></h4>
<p>Additional parameters can be set by Root.Html.Homepage (address of the
user's home page), Root.Html.SearchEngine (search engine for the class
documentation), Root.Html.Search (search URL), and a ViewCVS base URL
Root.Html.ViewCVS. All default to "".</p>
<p>Examples:</p><pre>
Root.Html.Homepage: http://www.enricos-home.it
Root.Html.SearchEngine: http://root.cern.ch/root/Search.phtml
Root.Html.Search: http://www.google.com/search?q=%s+site%3Aroot.cern.ch%2Froot%2Fhtml</pre>
<h4><a name="conf:charset">I.8 HTML Charset</a></h4>
<p>XHTML 1.0 transitional recommends the specification of the charset in the
content type meta tag, see e.g. <a href="http://www.w3.org/TR/2002/REC-xhtml1-20020801/">http://www.w3.org/TR/2002/REC-xhtml1-20020801/</a>
<a href="http://root.cern.ch/root/html/THtml.html">THtml</a> generates it for the HTML output files. It defaults to ISO-8859-1, and
can be changed using Root.Html.Charset.</p>
<p>Example:</p><pre>
Root.Html.Charset: EUC-JP</pre>
<h3><a name="syntax">II. Documentation syntax</a></h3>
<h4><a name="syntax:classdesc">II.1 Class description</a></h4>
<p>A class description block, which must be placed before the first
member function, has a following form:</p>
<pre>
////////////////////////////////////////////////////////////////
// //
// TMyClass //
// //
// This is the description block. //
// //
////////////////////////////////////////////////////////////////
</pre>
<p>The environment variable Root.Html.Description
(see: <a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>) contains
the delimiter string (default value: <tt>//_________________</tt>). It means
that you can also write your class description block like this:</p>
<pre>
//_____________________________________________________________
// A description of the class starts with the line above, and
// will take place here !
//
</pre>
<p>Note that <b><i>everything</i></b> until the first non-commented line is considered
as a valid class description block.</p>
<h4><a name="syntax:classidx">II.2 Class index</a></h4>
<p>All classes to be documented will have an entry in the ClassIndex.html,
showing their name with a link to their documentation page and a miniature
description. This discription for e.g. the class MyClass has to be given
in MyClass's header as a comment right after ClassDef(MyClass, n).</p>
<h4><a name="syntax:meth">II.3 Method documentation</a></h4>
<p>A member function description block starts immediately after '{'
and looks like this:</p>
<pre>
void TWorld::HelloWorldFunc(string *text)
{
// This is an example of description for the
// TWorld member function
helloWorld.Print( text );
}
</pre>
Like in a class description block, <b><i>everything</i></b> until the first
non-commented line is considered as a valid member function
description block.
<h4><a name="syntax:datamem">II.4 Data member documentation</a></h4>
<p>Data members are documented by putting a C++ comment behind their
declaration in the header file, e.g.</p>
<pre>
int fIAmADataMember; // this is a data member
</pre>
<h4><a name="syntax:beginhtml">II.5 <tt>BEGIN<!-- -->_HTML</tt> <tt>END<!-- -->_HTML</tt>: include 'raw' HTML</a></h4>
<p>You can insert pure html code into your documentation comments. During the
generation of the documentation, this code will be inserted as is
into the html file.</p>
<p>Pure html code must be surrounded by the keywords
<tt>BEGIN<!-- -->_HTML</tt> and <tt>END<!-- -->_HTML</tt>, where the
case is ignored.
Examples of pure html code are given e.g. in
<a href="http://root.cern.ch/root/html/TDataMember.html">TDataMember</a>
and <a href="http://root.cern.ch/root/html/TMinuit.html">TMinuit</a>. The
following trick can be used to hide
the surrounding <tt>/<!-- -->*</tt> <tt>*<!-- -->/</tt> from the documentation:</p>
<pre>
// start doc
// BEGIN<!-- -->_HTML <!--
/<!-- -->* -->
We can now write HTML code, like <a href="something">something</a>
<!-- *<!-- -->/
// --> END<!-- -->_HTML
// end doc
</pre>
<h3><a name="CSSJS">III. Style sheet, JavaScript</a></h3>
<p>The documentation pages share a common set of javascript and CSS files. They
are generated automatically when running <a href="#THtml:MakeAll">MakeAll()</a>;
they can be generated on
demand by calling <a href="#THtml:CreateJavascript">CreateJavascript()</a>
and <a href="#THtml:CreateStyleSheet">CreateStyleSheet()</a>, respectively.</p>
<h3><a name="charts">IV. Class Charts</a></h3>
THtml can generate a number of graphical representations for a class, which
are displayed as a tabbed set of imaged ontop of the class description.
It can show the inheritance, inherited and hidden members, directly and
indirectly included files, and library dependencies.
These graphs are generated using the <a href="http://www.graphviz.org/">Graphviz</a>
package. You can install it from <a href="http://www.graphviz.org">http://www.graphviz.org</a>.
You can either put it into your $PATH, or tell THtml where to find it by calling
<a href="#THtml:SetDotDir">SetDotDir()</a>.
<h3><a name="usage">V. Usage</a></h3>
These are typical things people do with THtml:
<pre>
root[] <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> html; // create a <a href="http://root.cern.ch/root/html/THtml.html">THtml</a> object
root[] html.MakeAll() // generate documentation for all changed classes
root[] html.MakeClass("TMyClass") // create documentation for TMyClass only
</pre>
To "beautify" (i.e. create links to documentation for class names etc) some text
file or macro, use:
<pre>
root[] html.Convert( "hsimple.C", "Histogram example" )
</pre>
<h3><a name="confvar">VI. Configuration variables</a></h3>
<p>Here is a list of all configuration variables that are known to THtml.
You can set them in your .rootrc file, see
<a href="http://root.cern.ch/root/html/TEnv.html">TEnv</a>.</p>
<pre>
Root.Html.OutputDir (default: htmldoc)
Root.Html.SourceDir (default: .:src/:include/)
Root.Html.Author (default: // Author:) - start tag for authors
Root.Html.LastUpdate (default: // @(#)) - start tag for last update
Root.Html.Copyright (default: * Copyright) - start tag for copyright notice
Root.Html.Description (default: //____________________ ) - start tag for class descr
Root.Html.HomePage (default: ) - URL to the user defined home page
Root.Html.Header (default: ) - location of user defined header
Root.Html.Footer (default: ) - location of user defined footer
Root.Html.Root (default: ) - URL of Root's class documentation
Root.Html.SearchEngine (default: ) - link to the search engine
Root.Html.Search (defualt: ) - link to search by replacing "%s" with user input
Root.Html.ViewCVS (default: ) - URL of ViewCVS base
Root.Html.XWho (default: http://consult.cern.ch/xwho/people?) - URL of CERN's xWho
Root.Html.Charset (default: ISO-8859-1) - HTML character set
</pre><!--
*/
// --> END_HTML
ClassImp(THtml)
THtml::THtml(): fFoundDot(-1), fCurrentClass(0), fDocContext(kIgnore),
fEscFlag(kFALSE), fHierarchyLines(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://consult.cern.ch/xwho/people?");
fClasses.SetOwner();
fModules.SetOwner();
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()
{
fClasses.Clear();
fModules.Clear();
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);
}
class TMethodWrapper: public TObject {
public:
TMethodWrapper(const TMethod* m): fMeth(m) {}
static void SetClass(const TClass* cl) { fgClass = cl; }
const char* GetName() const { return fMeth->GetName(); }
Int_t GetNargs() const { return fMeth->GetNargs(); }
const TMethod* GetMethod() const { return fMeth; }
Bool_t IsSortable() const { return kTRUE; }
Int_t Compare(const TObject *obj) const {
const TMethodWrapper* m = dynamic_cast<const TMethodWrapper*>(obj);
if (!m) return 1;
Int_t ret = strcasecmp(GetName(), m->GetName());
if (ret == 0) {
if (GetNargs() < m->GetNargs()) return -1;
else if (GetNargs() > m->GetNargs()) return 1;
if (GetMethod()->GetClass()->InheritsFrom(m->GetMethod()->GetClass()))
return -1;
else
return 1;
}
const char* l(GetName());
const char* r(m->GetName());
if (l[0] == '~' && r[0] == '~') {
++l;
++r;
}
if (fgClass->InheritsFrom(l)) {
if (fgClass->InheritsFrom(r)) {
if (gROOT->GetClass(l)->InheritsFrom(r))
return -1;
else return 1;
} else return -1;
} else if (fgClass->InheritsFrom(r))
return 1;
if (l[0] == '~') return -1;
if (r[0] == '~') return 1;
return (ret < 0) ? -1 : 1;
}
private:
static const TClass* fgClass;
const TMethod* fMeth;
};
const TClass* TMethodWrapper::fgClass = 0;
class TModuleDocInfo;
class TClassDocInfo: public TObject {
public:
TClassDocInfo(TClass* cl, const char* filename):
fClass(cl), fModule(0), fHtmlFileName(filename), fSelected(kTRUE) { }
virtual ~TClassDocInfo() {}
TClass* GetClass() const { return fClass; }
virtual const char* GetName() const { return fClass ? fClass->GetName() : "(UNKNOWN)"; }
const char* GetHtmlFileName() const { return fHtmlFileName; }
void SetModule(TModuleDocInfo* module) { fModule = module; }
TModuleDocInfo* GetModule() const { return fModule; }
void SetSelected(Bool_t sel = kTRUE) { fSelected = sel; }
Bool_t IsSelected() const { return fSelected; }
ULong_t Hash() const { return fClass ? fClass->Hash() : (ULong_t)-1; }
Bool_t IsSortable() const { return kTRUE; }
Int_t Compare(const TObject* obj) const { return fClass ? fClass->Compare(obj) : obj < this; }
private:
TClassDocInfo();
TClass* fClass;
TModuleDocInfo* fModule;
TString fHtmlFileName;
Bool_t fSelected;
};
class TModuleDocInfo: public TNamed {
public:
TModuleDocInfo(const char* name, const char* doc = ""):
TNamed(name, doc) {}
virtual ~TModuleDocInfo() {}
void SetDoc(const char* doc) { SetTitle(doc); }
const char* GetDoc() const { return GetTitle(); }
void AddClass(TClassDocInfo* cl) { fClasses.Add(cl); }
TList* GetClasses() { return &fClasses; }
std::ostringstream& Stream() { return fStream; }
private:
TList fClasses;
std::ostringstream fStream;
};
class MapModuleDepMap: public std::map<std::string, std::set<std::string> > {
public:
MapModuleDepMap() {}
};
typedef std::map<std::string, MapModuleDepMap > LibDep_t;
LibDep_t setLibDeps;
}
void THtml::AddClassMethodsRecursive(TBaseClass* bc, TList methodNames[3])
{
TClass *cl = fCurrentClass;
if (bc)
cl = bc->GetClassPointer(kFALSE);
if (!cl) return;
TMethod *method;
TIter nextMethod(cl->GetListOfMethods());
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") ||
bc && (method->GetName()[0] == '~'
|| !strcmp(method->GetName(), method->GetReturnTypeName()))
)
continue;
Int_t mtype = 0;
if (kIsPrivate & method->Property())
mtype = 0;
else if (kIsProtected & method->Property())
mtype = 1;
else if (kIsPublic & method->Property())
mtype = 2;
if (bc) {
if (mtype == 0) continue;
if (bc->Property() & kIsPrivate)
mtype = 0;
else if ((bc->Property() & kIsProtected) && mtype == 2)
mtype = 1;
}
Bool_t hidden = kFALSE;
for (Int_t access = 0; !hidden && access < 3; ++access) {
TMethodWrapper* other = (TMethodWrapper*) methodNames[access].FindObject(method->GetName());
hidden |= (other) && (other->GetMethod()->GetClass() != method->GetClass());
}
if (!hidden)
methodNames[mtype].Add(new TMethodWrapper(method));
}
TIter iBase(cl->GetListOfBases());
TBaseClass* base = 0;
while ((base = (TBaseClass*)iBase()))
AddClassMethodsRecursive(base, methodNames);
}
void THtml::AddClassDataMembersRecursive(TBaseClass* bc, TList datamembers[6]) {
TClass *cl = fCurrentClass;
if (bc)
cl = bc->GetClassPointer(kFALSE);
if (!cl) return;
TDataMember *dm;
TIter nextDM(cl->GetListOfDataMembers());
while ((dm = (TDataMember *) nextDM())) {
if (!strcmp(dm->GetName(), "fgIsA"))
continue;
Int_t mtype = 0;
if (kIsPrivate & dm->Property())
mtype = 0;
else if (kIsProtected & dm->Property())
mtype = 1;
else if (kIsPublic & dm->Property())
mtype = 2;
if (bc) {
if (mtype == 0) continue;
if (bc->Property() & kIsPrivate)
mtype = 0;
else if ((bc->Property() & kIsProtected) && mtype == 2)
mtype = 1;
}
const Int_t flagEnumConst = G__BIT_ISENUM | G__BIT_ISCONSTANT | G__BIT_ISSTATIC;
if ((dm->Property() & flagEnumConst) == flagEnumConst
&& dm->GetDataType() && dm->GetDataType()->GetType() == kInt_t)
mtype += 3;
datamembers[mtype].Add(dm);
}
TIter iBase(cl->GetListOfBases());
TBaseClass* base = 0;
while ((base = (TBaseClass*)iBase()))
AddClassDataMembersRecursive(base, datamembers);
}
void THtml::Class2Html(Bool_t force)
{
gROOT->GetListOfGlobals(kTRUE);
TString filename(fCurrentClass->GetName());
NameSpace2FileName(filename);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, filename);
filename += ".html";
fParseContext.clear();
fParseContext.push_back(kCode);
fDocContext = kIgnore;
if (force || IsModified(fCurrentClass, kSource)) {
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;
TString currClassNameMangled(fCurrentClass->GetName());
NameSpace2FileName(currClassNameMangled);
classFile << "<!--SDL--><em><a href=\"#" << currClassNameMangled;
if (IsNamespace(fCurrentClass)) {
classFile << ":description\">namespace description</a>";
} else {
classFile << ":description\">class description</a>";
}
TString classFileName(fCurrentClass->GetName());
NameSpace2FileName(classFileName);
const char* headerFileName = GetDeclFileName(fCurrentClass);
if (headerFileName && !headerFileName[0])
headerFileName = 0;
const char* sourceFileName = GetImplFileName(fCurrentClass);
if (sourceFileName && !sourceFileName[0])
sourceFileName = 0;
if (headerFileName)
classFile << " - <a href=\"src/" << classFileName
<< ".h.html\">header file</a>";
if (sourceFileName)
classFile << " - <a href=\"src/" << classFileName
<< ".cxx.html\">source file</a>";
if (!IsNamespace(fCurrentClass) && !HaveDot()) {
classFile << " - <a href=\"" << classFileName << "_Tree.pdf\"";
classFile << ">inheritance tree (.pdf)</a>";
}
const char* viewCVSLink = gEnv->GetValue("Root.Html.ViewCVS","");
if (viewCVSLink && !viewCVSLink[0])
viewCVSLink = 0;
if (viewCVSLink && (headerFileName || sourceFileName)) {
classFile << "<br />";
if (headerFileName)
classFile << "<a href=\"" << viewCVSLink << headerFileName << "\">viewCVS header</a>";
if (headerFileName && sourceFileName)
classFile << " - ";
if (sourceFileName)
classFile << "<a href=\"" << viewCVSLink << sourceFileName << "\">viewCVS source</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 ";
ReplaceSpecialChars(classFile, fCurrentClass->GetName());
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))
if (!ClassDotCharts(classFile))
ClassHtmlTree(classFile, fCurrentClass);
TList methodNames[3];
AddClassMethodsRecursive(0, methodNames);
TMethodWrapper::SetClass(fCurrentClass);
classFile << endl << "<div id=\"functions\">" << endl;
classFile << "<h3><a name=\"" << fCurrentClass->GetName()
<< ":Function_Members\"></a>Function Members (Methods)</h3>" << endl;
classFile << "<div id=\"dispopt\">Display options:<br /><form id=\"formdispopt\" action=\"#\">" << endl
<< "<input id=\"dispoptCBInh\" type=\"checkbox\" "
"onclick=\"javascript:CBChanged(this);\" "
"title=\"Select to display inherited members\" />Show inherited<br />" << endl
<< "<input id=\"dispoptCBPub\" type=\"checkbox\" checked=\"checked\" "
"onclick=\"javascript:CBChanged(this);\" "
"title=\"Select to display protected and private members\" />Show non-public<br />"
<< "</form></div>";
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;
for (Int_t access = 2; access >=0 && !IsNamespace(fCurrentClass); --access) {
if (methodNames[access].GetEntries() == 0)
continue;
methodNames[access].SetOwner();
methodNames[access].Sort();
classFile << "<div class=\"access\" ";
const char* accessID [] = {"priv", "prot", "publ"};
const char* accesstxt[] = {"private", "protected", "public"};
classFile << "id=\"func" << accessID[access] << "\"><b>"
<< accesstxt[access] << ":</b>" << endl
<< "<table class=\"func\" id=\"tabfunc" << accessID[access] << "\">" << endl;
TIter iMethWrap(&methodNames[access]);
TMethodWrapper *methWrap = 0;
while ((methWrap = (TMethodWrapper*) iMethWrap())) {
const TMethod* method = methWrap->GetMethod();
Bool_t isctor = (!strcmp(method->GetName(), method->GetReturnTypeName()));
Bool_t isdtor = (!isctor && method->GetName()[0] == '~');
classFile << "<tr class=\"func";
if (method->GetClass() != fCurrentClass)
classFile << "inh";
classFile << "\"><td class=\"funcret\">";
if (kIsVirtual & method->Property())
if (!isdtor)
classFile << "virtual ";
else
classFile << " virtual";
if (kIsStatic & method->Property())
classFile << "static ";
if (!isctor && !isdtor)
ExpandKeywords(classFile, method->GetReturnTypeName());
TString mangled(method->GetClass()->GetName());
NameSpace2FileName(mangled);
classFile << "</td><td class=\"funcname\"><a href=\"";
if (method->GetClass() != fCurrentClass) {
TString htmlFile;
GetHtmlFileName(method->GetClass(), htmlFile);
classFile << htmlFile;
}
classFile << "#" << mangled;
classFile << ":";
mangled = method->GetName();
NameSpace2FileName(mangled);
classFile << mangled << "\">";
if (method->GetClass() != fCurrentClass) {
classFile << "<span class=\"baseclass\">";
ReplaceSpecialChars(classFile, method->GetClass()->GetName());
classFile << "::</span>";
}
ReplaceSpecialChars(classFile, method->GetName());
classFile << "</a>";
ExpandKeywords(classFile, const_cast<TMethod*>(method)->GetSignature());
classFile << "</td></tr>" << endl;
}
classFile << endl << "</table></div>" << endl;
}
classFile << "</div>" << endl;
TList datamembers[6];
AddClassDataMembersRecursive(0, datamembers);
Bool_t haveDataMembers = (datamembers[0].GetEntries() ||
datamembers[1].GetEntries() ||
datamembers[2].GetEntries() ||
datamembers[3].GetEntries() ||
datamembers[4].GetEntries() ||
datamembers[5].GetEntries());
if (haveDataMembers) {
classFile << endl << "<div id=\"datamembers\">" << endl;
classFile << "<h3><a name=\"" << fCurrentClass->GetName()
<< ":Data_Members\"></a>Data Members</h3>" << endl;
}
for (Int_t access = 5; access >= 0 && !IsNamespace(fCurrentClass); --access) {
if (datamembers[access].GetEntries() == 0)
continue;
classFile << "<div class=\"access\" ";
const char* what = "data";
if (access > 2) what = "enum";
const char* accessID [] = {"priv", "prot", "publ"};
const char* accesstxt[] = {"private", "protected", "public"};
classFile << "id=\"" << what << accessID[access%3] << "\"><b>"
<< accesstxt[access%3] << ":</b>" << endl
<< "<table class=\"data\" id=\"tab" << what << accessID[access%3] << "\">" << endl;
TIter iDM(&datamembers[access]);
TDataMember *member = 0;
TString prevEnumName;
Bool_t prevIsInh = kTRUE;
while ((member = (TDataMember*) iDM())) {
Bool_t haveNewEnum = access > 2 && prevEnumName != member->GetTypeName();
if (haveNewEnum) {
if (prevEnumName.Length()) {
classFile << "<tr class=\"data";
if (prevIsInh)
classFile << "inh";
classFile << "\"><td class=\"datatype\">};</td><td></td><td></td></tr>" << endl;
}
prevEnumName = member->GetTypeName();
}
classFile << "<tr class=\"data";
prevIsInh = (member->GetClass() != fCurrentClass);
if (prevIsInh)
classFile << "inh";
classFile << "\"><td class=\"datatype\">";
if (haveNewEnum) {
TString enumName(member->GetTypeName());
TString myScope(fCurrentClass->GetName());
myScope += "::";
enumName.ReplaceAll(myScope, "");
if (enumName.EndsWith("::"))
enumName += "<i>[unnamed]</i>";
if (!enumName.BeginsWith("enum "))
classFile << "enum ";
classFile << enumName;
classFile << " { ";
} else
if (access < 3) {
if (member->Property() & G__BIT_ISSTATIC)
classFile << "static ";
ExpandKeywords(classFile, member->GetFullTypeName());
}
TString mangled(member->GetClass()->GetName());
NameSpace2FileName(mangled);
classFile << "</td><td class=\"dataname\"><a ";
if (member->GetClass() != fCurrentClass) {
classFile << "href=\"";
TString htmlFile;
GetHtmlFileName(member->GetClass(), htmlFile);
classFile << htmlFile << "#";
} else
classFile << "name=\"";
classFile << mangled;
classFile << ":";
mangled = member->GetName();
NameSpace2FileName(mangled);
classFile << mangled << "\">";
if (member->GetClass() == fCurrentClass)
classFile << "</a>";
if (access < 3 && member->GetClass() != fCurrentClass) {
classFile << "<span class=\"baseclass\">";
ReplaceSpecialChars(classFile, member->GetClass()->GetName());
classFile << "::</span>";
}
ReplaceSpecialChars(classFile, member->GetName());
for (Int_t indx = 0; indx < member->GetArrayDim(); ++indx)
if (member->GetMaxIndex(indx) <= 0)
break;
else
classFile << "[" << member->GetMaxIndex(indx) << "]";
if (member->GetClass() != fCurrentClass)
classFile << "</a>";
classFile << "</td><td class=\"datadesc\">";
ReplaceSpecialChars(classFile, member->GetTitle());
classFile << "</td></tr>" << endl;
}
if (prevEnumName.Length()) {
classFile << "<tr class=\"data";
if (prevIsInh)
classFile << "inh";
classFile << "\"><td class=\"datatype\">};</td><td></td><td></td></tr>" << endl;
}
classFile << endl << "</table></div>" << endl;
}
if (haveDataMembers)
classFile << "</div>" << 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::AnchorFromLine(TString& anchor) {
const char base64String[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
UInt_t hash = ::Hash(fLineStripped);
anchor.Remove(0);
anchor += base64String[hash % 52];
hash /= 52;
while (hash) {
anchor += base64String[hash % 64];
hash /= 64;
}
}
void THtml::BeautifyLine(std::ostream &sOut, const char* relpath )
{
enum EBeautifyContext {
kNothingSpecialMoveOn,
kCommentC,
kCommentCXX,
kPreProc,
kDontTouch,
kNumBeautifyContexts
};
EBeautifyContext context = kNothingSpecialMoveOn;
switch (fParseContext.back()) {
case kCode:
context = kNothingSpecialMoveOn;
if (fLineStripped.Length() && fLineStripped[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 (context == kDontTouch
|| kNPOS != fLine.Index("End_Html", 0, TString::kIgnoreCase)
&& kNPOS == fLine.Index("\"End_Html", 0, TString::kIgnoreCase)) {
ReplaceSpecialChars(sOut, fLine);
sOut << std::endl;
return;
}
TString stripSubExpanded(fLineExpanded);
Bool_t stripped = Strip(stripSubExpanded);
TString lineExpandedDotDot(stripSubExpanded);
TString replWithRelPath("=\"");
replWithRelPath += relpath;
lineExpandedDotDot.ReplaceAll("=\"./", replWithRelPath);
if (stripped)
sOut << fLineExpanded(0, fLineExpanded.Index(stripSubExpanded));
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;
}
sOut << lineExpandedDotDot.Data() + i;
i = lineExpandedDotDot.Length();
} else if (lineExpandedDotDot[i + 1] == '*') {
if (context == kPreProc) {
sOut << "</span>";
context = kNothingSpecialMoveOn;
}
if (context == kNothingSpecialMoveOn || context == kCommentC) {
context = kCommentC;
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 << "*/";
context = kNothingSpecialMoveOn;
if (fParseContext.size()>1)
fParseContext.pop_back();
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)
{
typedef std::map<std::string , Int_t > MethodCount_t;
if (posMethodName == kNPOS) {
name.Remove(0);
TMethod * meth = 0;
Ssiz_t posBlock = fLine.Index('{');
if (posBlock == kNPOS)
posBlock = fLine.Length();
for (MethodCount_t::iterator iMethodName = fMethodNames.begin();
!name.Length() && iMethodName != fMethodNames.end(); ++iMethodName) {
TString lookFor(iMethodName->first);
lookFor += "(";
posMethodName = fLine.Index(lookFor);
if (posMethodName != kNPOS && posMethodName < posBlock
&& (posMethodName == 0 || !IsWord(fLine[posMethodName - 1]))) {
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);
Strip(ret);
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);
}
}
Strip(ret);
}
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);
MethodCount_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()) {
AnchorFromLine(anchor);
if (srcOut)
srcOut << "<a name=\"" << anchor << "\"></a>";
}
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::WriteMethod(std::ostream & out, TString& ret,
TString& name, TString& params,
const char* filename, TString& anchor,
TString& comment, TString& codeOneLiner)
{
ExpandKeywords(ret);
ExpandKeywords(params);
out << "<div class=\"funcdoc\"><span class=\"funcname\">";
out << ret << " <a name=\"";
TString mangled(fCurrentClass->GetName());
NameSpace2FileName(mangled);
out << mangled << ":";
mangled = name;
NameSpace2FileName(mangled);
out << mangled << "\" href=\"src/" << filename;
if (anchor.Length())
out << "#" << anchor;
out << "\">";
ReplaceSpecialChars(out, name);
out << "</a>" << params << "</span><br />" << std::endl;
if (comment.Length())
out << "<pre>" << comment << "</pre>" << std::endl;
if (codeOneLiner.Length()) {
out << std::endl << "<div class=\"inlinecode\"><code class=\"inlinecode\">"
<< codeOneLiner << "</code></div>" << std::endl;
codeOneLiner.Remove(0);
}
out << "</div>" << std::endl;
typedef std::map<std::string , Int_t > MethodCount_t;
MethodCount_t::iterator iMethodName = fMethodNames.find(name.Data());
if (iMethodName != fMethodNames.end()) {
--(iMethodName->second);
if (iMethodName->second <= 0)
fMethodNames.erase(iMethodName);
}
ret.Remove(0);
name.Remove(0);
params.Remove(0);
anchor.Remove(0);
comment.Remove(0);
fDocContext = kIgnore;
}
Bool_t THtml::ExtractComments(const TString &lineExpandedStripped,
Bool_t &foundClassDescription,
const char* classDescrTag,
TString& comment) {
if (fParseContext.back() != kBeginEndHtml &&
fParseContext.back() != kBeginEndHtmlInCComment &&
fParseContext.back() != kCComment &&
!lineExpandedStripped.BeginsWith("<span class=\"comment\">"))
return kFALSE;
if ((fParseContext.back() == kBeginEndHtml
|| fParseContext.back() == kBeginEndHtmlInCComment)
&& (kNPOS == fLine.Index("Begin_Html", 0, TString::kIgnoreCase)
|| kNPOS != fLine.Index("\"Begin_Html", 0, TString::kIgnoreCase))
&& (kNPOS == fLine.Index("End_Html", 0, TString::kIgnoreCase)
|| kNPOS != fLine.Index("\"End_Html", 0, TString::kIgnoreCase))) {
comment += fLine + "\n";
return kTRUE;
}
TString commentLine(lineExpandedStripped);
if (commentLine.BeginsWith("<span class=\"comment\">/")) {
if (commentLine[23] == '/')
if (!commentLine.EndsWith("</span>"))
return kFALSE;
else
commentLine.Remove(commentLine.Length()-7, 7);
commentLine.Remove(0,22);
}
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]) {
TString lineAllOneCharStripped(lineAllOneChar.Strip(TString::kTrailing, c));
if (lineAllOneCharStripped.BeginsWith("//") || lineAllOneCharStripped.BeginsWith("/*"))
lineAllOneCharStripped.Remove(0, 2);
Strip(lineAllOneCharStripped);
if (!lineAllOneCharStripped.Length())
commentLine.Remove(0);
}
}
if (!foundClassDescription && !comment.Length() && fDocContext == kIgnore &&
(!commentLine.Length() || classDescrTag && lineExpandedStripped.Contains(classDescrTag))) {
fDocContext = kDocClass;
foundClassDescription = kTRUE;
}
while (fParseContext.back() != kBeginEndHtml && fParseContext.back() != 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.Remove(0, 2);
if (commentLine.Length()>1 && commentLine[commentLine.Length() - 2] == '*' &&
commentLine[commentLine.Length() - 1] == '/')
commentLine.Remove(commentLine.Length()-2);
comment += commentLine + "\n";
return kTRUE;
}
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 )
{
TString sourceFileName(filename);
fCurrentFile = 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", "// 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;
TString codeOneLiner;
TString methodRet;
TString methodName;
TString methodParam;
TString anchor;
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.clear();
fParseContext.push_back(kCode);
fDocContext = kIgnore;
fLineNo = 0;
while (!sourceFile.eof()) {
Bool_t needAnchor = kFALSE;
++fLineNo;
fLine.ReadLine(sourceFile, kFALSE);
if (sourceFile.eof()) break;
fLineExpanded = fLine;
ExpandKeywords(fLineExpanded);
fLineStripped = fLine;
Strip(fLineStripped);
TString lineExpandedStripped(fLineExpanded);
Strip(lineExpandedStripped);
if (!ExtractComments(lineExpandedStripped, foundClassDescription,
descriptionStr, prevComment)) {
if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
if (!foundClassDescription && lookForClassDescr) {
out << "</div>" << std::endl;
lookForClassDescr = kFALSE;
}
WriteMethod(out, methodRet, methodName, methodParam,
gSystem->BaseName(srcHtmlOutName), anchor,
prevComment, codeOneLiner);
} else if (fDocContext == kDocClass) {
out << "<pre>" << prevComment << "</pre></div>" << std::endl;
prevComment.Remove(0);
fDocContext = kIgnore;
}
if (!wroteMethodNowWaitingForOpenBlock) {
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);
codeOneLiner.Remove(0);
wroteMethodNowWaitingForOpenBlock = fLine.Index("{", posPattern) == kNPOS;
wroteMethodNowWaitingForOpenBlock &= fLine.Index(";", posPattern) == kNPOS;
} else
prevComment.Remove(0);
}
else
prevComment.Remove(0);
} else {
wroteMethodNowWaitingForOpenBlock &= fLine.Index("{") == kNPOS;
wroteMethodNowWaitingForOpenBlock &= fLine.Index(";") == kNPOS;
}
if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
if (!codeOneLiner.Length() &&
lineExpandedStripped.CountChar('{') == 1 &&
lineExpandedStripped.CountChar('}') == 1) {
codeOneLiner = lineExpandedStripped;
codeOneLiner.Remove(0, codeOneLiner.Index('{'));
codeOneLiner.Remove(codeOneLiner.Index('}') + 1);
}
}
}
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 (needAnchor || fExtraLinesWithAnchor.find(fLineNo) != fExtraLinesWithAnchor.end()) {
AnchorFromLine(anchor);
if (sourceExt)
srcHtmlOut << "<a name=\"" << anchor << "\"></a>";
}
if (sourceExt)
BeautifyLine(srcHtmlOut);
else if (needAnchor)
fExtraLinesWithAnchor.insert(fLineNo);
}
if (methodName.Length()) {
WriteMethod(out, methodRet, methodName, methodParam,
gSystem->BaseName(srcHtmlOutName), anchor,
prevComment, codeOneLiner);
} else if (fDocContext == kDocClass) {
out << prevComment << "</div>" << std::endl;
} else if (!foundClassDescription && lookForClassDescr)
out << "</div>" << std::endl;
srcHtmlOut << "</pre>" << std::endl;
WriteHtmlFooter(srcHtmlOut, "../");
fParseContext.clear();
fParseContext.push_back(kCode);
fDocContext = kIgnore;
fCurrentFile = "";
}
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");
else out << "</div>" << endl;
}
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\">";
TString anchor(fCurrentClass->GetName());
NameSpace2FileName(anchor);
out << "<h2><a name=\"" << anchor;
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);
fExtraLinesWithAnchor.clear();
LocateMethodsInSource(out);
LocateMethodsInHeaderInline(out);
LocateMethodsInHeaderClassDecl(out);
fExtraLinesWithAnchor.clear();
TDatime date;
if (!fSourceInfo[kInfoLastUpdate].Length())
fSourceInfo[kInfoLastUpdate] = date.AsString();
WriteHtmlFooter(out, "", fSourceInfo[kInfoLastUpdate],
fSourceInfo[kInfoAuthor], fSourceInfo[kInfoCopyright]);
}
Bool_t THtml::HaveDot() {
if (fFoundDot != -1)
return (Bool_t)fFoundDot;
Info("HaveDot", "Checking for Graphviz (dot)...");
TString runDot("dot");
if (fDotDir.Length())
gSystem->PrependPathName(fDotDir, runDot);
runDot += " -V";
if (gDebug > 3)
Info("HaveDot", "Running: %s", runDot.Data());
if (gSystem->Exec(runDot)) {
fFoundDot = 0;
return kFALSE;
}
fFoundDot = 1;
return kTRUE;
}
Bool_t THtml::RunDot(const char* filename, std::ostream* outMap ) {
if (!HaveDot())
return kFALSE;
TString runDot("dot");
if (fDotDir.Length())
gSystem->PrependPathName(fDotDir, 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());
fFoundDot = 0;
return kFALSE;
}
return kTRUE;
}
Bool_t THtml::CreateDotClassChartInh(const char* filename) {
ofstream outdot(filename);
outdot << "strict digraph G {" << endl
<< "rankdir=RL;" << endl
<< "compound=true;" << endl
<< "constraint=false;" << endl
<< "ranksep=0.1;" << endl
<< "nodesep=0;" << endl
<< "size=\"16,20\";" << endl
<< "ratio=compress;" << endl
<< "\"" << fCurrentClass->GetName() << "\";" << endl;
std::stringstream ssDep;
std::list<TClass*> writeBasesFor;
writeBasesFor.push_back(fCurrentClass);
Bool_t haveBases = fCurrentClass->GetListOfBases() &&
fCurrentClass->GetListOfBases()->GetSize();
if (haveBases) {
outdot << "{" << endl
<< " node [shape=plaintext,fontsize=10];" << endl;
while (!writeBasesFor.empty()) {
TClass* cl = writeBasesFor.front();
writeBasesFor.pop_front();
if (cl != fCurrentClass) {
outdot << " \"" << cl->GetName() << "\"";
TClassDocInfo* cdi = (TClassDocInfo*) fClasses.FindObject(cl->GetName());
if (cdi)
outdot << " [URL=\"" << cdi->GetHtmlFileName() << "\"]";
outdot << ";" << endl;
}
if (cl->GetListOfBases() && cl->GetListOfBases()->GetSize()) {
ssDep << " \"" << cl->GetName() << "\" -> {";
TIter iBase(cl->GetListOfBases());
TBaseClass* base = 0;
while ((base = (TBaseClass*)iBase())) {
ssDep << " \"" << base->GetName() << "\";";
writeBasesFor.push_back(base->GetClassPointer());
}
ssDep << "}" << endl;
}
}
outdot << "}" << endl;
}
std::set<TClass*> derivesFromMe;
TIter iClass(&fClasses);
TClassDocInfo* cdi = 0;
while ((cdi = (TClassDocInfo*) iClass())) {
TClass* cl = cdi->GetClass();
if (!cl) continue;
if (cl != fCurrentClass && cl->InheritsFrom(fCurrentClass))
derivesFromMe.insert(cl);
}
outdot << "{" << endl
<< " node [shape=plaintext,fontsize=10];" << endl;
for (std::set<TClass*>::iterator iDerived = derivesFromMe.begin();
iDerived != derivesFromMe.end(); ++iDerived) {
TClassDocInfo* cdi = (TClassDocInfo*) fClasses.FindObject((*iDerived)->GetName());
if (cdi)
outdot << " node [URL=\"" << cdi->GetHtmlFileName() << "\"];" << endl;
outdot << " \"" << (*iDerived)->GetName() << "\";" << endl;
TIter iBaseOfDerived((*iDerived)->GetListOfBases());
TBaseClass* baseDerived = 0;
while ((baseDerived = (TBaseClass*) iBaseOfDerived())) {
TClass* clBaseDerived = baseDerived->GetClassPointer();
if (clBaseDerived->InheritsFrom(fCurrentClass))
ssDep << "\"" << (*iDerived)->GetName() << "\" -> \""
<< clBaseDerived->GetName() << "\";" << endl;
}
}
outdot << "}" << endl;
outdot << ssDep.str();
outdot << "}" << endl;
return kTRUE;
}
Bool_t THtml::CreateDotClassChartInhMem(const char* filename) {
ofstream outdot(filename);
outdot << "strict digraph G {" << endl
<< "ratio=auto;" << endl
<< "rankdir=RL;" << endl
<< "compound=true;" << endl
<< "constraint=false;" << endl
<< "ranksep=0.1;" << endl
<< "nodesep=0;" << endl;
std::stringstream ssDep;
std::list<TClass*> writeBasesFor;
writeBasesFor.push_back(fCurrentClass);
while (!writeBasesFor.empty()) {
TClass* cl = writeBasesFor.front();
writeBasesFor.pop_front();
TString htmlFileName;
TClassDocInfo* cdi = (TClassDocInfo*) fClasses.FindObject(cl->GetName());
if (cdi)
htmlFileName = cdi->GetHtmlFileName();
outdot << "subgraph \"cluster" << cl->GetName() << "\" {" << endl
<< " color=lightgray;" << endl
<< " label=\"" << cl->GetName() << "\";" << endl;
if (cl != fCurrentClass)
outdot << " URL=\"" << htmlFileName << "\"" << endl;
outdot << " node [style=filled,width=0.7,height=0.15,shape=plaintext,fixedsize=true,fontsize=10];" << endl;
Bool_t haveMembers = (cl->GetListOfDataMembers() && cl->GetListOfDataMembers()->GetSize());
Bool_t haveFuncs = cl->GetListOfMethods() && cl->GetListOfMethods()->GetSize();
if (haveMembers) {
outdot << "subgraph \"clusterData" << cl->GetName() << "\" {" << endl
<< " color=white;" << endl
<< " label=\"\";" << endl
<< " \"nodeToCluster" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl;
if (!haveFuncs)
outdot << "\"nodeFromCluster" << cl->GetName() << "\" [style=invis,width=0,height=0];" << endl;
TIter iDM(cl->GetListOfDataMembers());
TDataMember* dm = 0;
while ((dm = (TDataMember*) iDM())) {
TString name(dm->GetName());
NameSpace2FileName(name);
outdot << "\"" << cl->GetName() << "::" << dm->GetName() << "\" [label=\""
<< dm->GetName() << "\"";
if (dm->Property() & kIsPrivate)
outdot << ",color=\"#FFCCCC\"";
else if (dm->Property() & kIsProtected)
outdot << ",color=\"#FFFF77\"";
else
outdot << ",color=\"#CCFFCC\"";
outdot << "];" << endl;
}
outdot << "}" << endl;
}
if (haveFuncs) {
outdot << "subgraph \"clusterFunc" << cl->GetName() << "\" {" << endl
<< " color=white;" << endl
<< " label=\"\";" << endl;
if (!haveMembers)
outdot << " \"nodeToCluster" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl;
outdot << "\"nodeFromCluster" << cl->GetName() << "\" [style=invis,width=0,height=0];" << endl;
TIter iMeth(cl->GetListOfMethods());
TMethod* meth = 0;
while ((meth = (TMethod*) iMeth())) {
TString name(meth->GetName());
NameSpace2FileName(name);
outdot << "\"" << cl->GetName() << "::" << meth->GetName() << "\" [label=\""
<< meth->GetName() << "\"";
if (cl != fCurrentClass &&
fCurrentClass->GetMethodAny(meth->GetName()))
outdot << ",color=\"#777777\"";
else if (meth->Property() & kIsPrivate)
outdot << ",color=\"#FFCCCC\"";
else if (meth->Property() & kIsProtected)
outdot << ",color=\"#FFFF77\"";
else
outdot << ",color=\"#CCFFCC\"";
outdot << "];" << endl;
}
if (haveMembers)
ssDep << " \"nodeToCluster" << cl->GetName() << "\" -> \"nodeFromCluster"
<< cl->GetName() << "\" [style=invis];" << endl;
outdot << "}" << endl;
} else if (!haveMembers) {
outdot << " \"nodeToCluster" << cl->GetName() << "\" [height=0,width=0,style=invis];" << endl;
outdot << "\"nodeFromCluster" << cl->GetName() << "\" [style=invis,width=0,height=0];" << endl;
}
outdot << "}" << endl;
if (cl->GetListOfBases() && cl->GetListOfBases()->GetSize()) {
TIter iBase(cl->GetListOfBases());
TBaseClass* base = 0;
while ((base = (TBaseClass*)iBase())) {
ssDep << " \"nodeFromCluster" << cl->GetName() << "\" -> "
<< " \"nodeToCluster" << base->GetName() << "\" [ltail=\"cluster" << cl->GetName()
<< "\",lhead=\"cluster" << base->GetName() << "\"";
if (base != cl->GetListOfBases()->First())
ssDep << ",weight=0";
ssDep << "];" << endl;
writeBasesFor.push_back(base->GetClassPointer());
}
}
}
outdot << ssDep.str();
outdot << "}" << endl;
return kTRUE;
}
Bool_t THtml::CreateDotClassChartIncl(const char* filename) {
std::map<std::string, std::string> filesToParse;
std::list<std::string> listFilesToParse;
const char* declFileName = GetDeclFileName(fCurrentClass);
const char* implFileName = GetImplFileName(fCurrentClass);
if (declFileName && strlen(declFileName)) {
char* real = gSystem->Which(fSourceDir, declFileName, kReadPermission);
if (real) {
filesToParse[declFileName] = real;
listFilesToParse.push_back(declFileName);
delete real;
}
}
if (implFileName && strlen(implFileName)) {
char* real = gSystem->Which(fSourceDir, implFileName, kReadPermission);
if (real) {
filesToParse[implFileName] = real;
listFilesToParse.push_back(implFileName);
delete real;
}
}
ofstream outdot(filename);
outdot << "strict digraph G {" << endl
<< "ratio=compress;" << endl
<< "rankdir=TB;" << endl
<< "concentrate=true;" << endl
<< "ranksep=0;" << endl
<< "nodesep=0;" << endl
<< "size=\"8,10\";" << endl
<< "node [fontsize=20,shape=plaintext];" << endl;
for (std::list<std::string>::iterator iFile = listFilesToParse.begin();
iFile != listFilesToParse.end(); ++iFile) {
ifstream in(filesToParse[*iFile].c_str());
std::string line;
while (in && !in.eof()) {
std::getline(in, line);
size_t pos = 0;
while (line[pos] == ' ' || line[pos] == '\t') ++pos;
if (line[pos] != '#') continue;
++pos;
while (line[pos] == ' ' || line[pos] == '\t') ++pos;
if (line.compare(pos, 8, "include ") != 0) continue;
pos += 8;
while (line[pos] == ' ' || line[pos] == '\t') ++pos;
if (line[pos] != '"' && line[pos] != '<')
continue;
char delim = line[pos];
if (delim == '<') delim = '>';
++pos;
line.erase(0, pos);
pos = 0;
pos = line.find(delim);
if (pos == std::string::npos) continue;
line.erase(pos);
if (filesToParse.find(line) == filesToParse.end()) {
char* filename = gSystem->Which(fSourceDir, line.c_str(), kReadPermission);
if (!filename) continue;
listFilesToParse.push_back(line);
filesToParse[line] = filename;
delete filename;
if (*iFile == implFileName || *iFile == declFileName)
outdot << "\"" << *iFile << "\" [style=filled,fillcolor=lightgray];" << endl;
}
outdot << "\"" << *iFile << "\" -> \"" << line << "\";" << endl;
}
}
outdot << "}" << endl;
return kTRUE;
}
Bool_t THtml::CreateDotClassChartLib(const char* filename) {
ofstream outdot(filename);
outdot << "strict digraph G {" << endl
<< "ratio=auto;" << endl
<< "rankdir=RL;" << endl
<< "compound=true;" << endl
<< "constraint=false;" << endl
<< "ranksep=0.7;" << endl
<< "nodesep=0.3;" << endl
<< "size=\"8,8\";" << endl
<< "ratio=compress;" << endl;
TString libs(fCurrentClass->GetSharedLibs());
outdot << "\"All Libraries\" [URL=\"LibraryDependencies.html\",shape=box,rank=max,fillcolor=lightgray,style=filled];" << endl;
if (libs.Length()) {
TString firstLib(libs);
Ssiz_t end = firstLib.Index(' ');
if (end != kNPOS) {
firstLib.Remove(end, firstLib.Length());
libs.Remove(0, end + 1);
} else libs = "";
Ssiz_t posExt = firstLib.First(".");
if (posExt != kNPOS)
firstLib.Remove(posExt, firstLib.Length());
outdot << "\"All Libraries\" -> \"" << firstLib << "\" [style=invis];" << endl;
outdot << "\"" << firstLib << "\" -> {" << endl;
if (firstLib != "libCore")
libs += " libCore";
if (firstLib != "libCint")
libs += " libCint";
TString thisLib;
for (Ssiz_t pos = 0; pos < libs.Length(); ++pos)
if (libs[pos] != ' ')
thisLib += libs[pos];
else if (thisLib.Length()) {
Ssiz_t posExt = thisLib.First(".");
if (posExt != kNPOS)
thisLib.Remove(posExt, thisLib.Length());
outdot << " \"" << thisLib << "\";";
thisLib = "";
}
if (thisLib.Length()) {
Ssiz_t posExt = thisLib.First(".");
if (posExt != kNPOS)
thisLib.Remove(posExt, thisLib.Length());
outdot << " \"" << thisLib << "\";";
thisLib = "";
}
outdot << "}" << endl;
} else
outdot << "\"No rlibmap information avaliable.\"" << endl;
outdot << "}" << endl;
return kTRUE;
}
Bool_t THtml::ClassDotCharts(ofstream & out)
{
if (!HaveDot())
return kFALSE;
TString title(fCurrentClass->GetName());
NameSpace2FileName(title);
gSystem->ExpandPathName(fOutputDir);
TString dir("inh");
gSystem->PrependPathName(fOutputDir, dir);
gSystem->MakeDirectory(dir);
dir = "inhmem";
gSystem->PrependPathName(fOutputDir, dir);
gSystem->MakeDirectory(dir);
dir = "incl";
gSystem->PrependPathName(fOutputDir, dir);
gSystem->MakeDirectory(dir);
dir = "lib";
gSystem->PrependPathName(fOutputDir, dir);
gSystem->MakeDirectory(dir);
TString filenameInh(title);
gSystem->PrependPathName("inh", filenameInh);
gSystem->PrependPathName(fOutputDir, filenameInh);
filenameInh += "_Inh";
if (!CreateDotClassChartInh(filenameInh + ".dot") ||
!RunDot(filenameInh, &out))
return kFALSE;
TString filenameInhMem(title);
gSystem->PrependPathName("inhmem", filenameInhMem);
gSystem->PrependPathName(fOutputDir, filenameInhMem);
filenameInhMem += "_InhMem";
if (CreateDotClassChartInhMem(filenameInhMem + ".dot"))
RunDot(filenameInhMem, &out);
TString filenameIncl(title);
gSystem->PrependPathName("incl", filenameIncl);
gSystem->PrependPathName(fOutputDir, filenameIncl);
filenameIncl += "_Incl";
if (CreateDotClassChartIncl(filenameIncl + ".dot"))
RunDot(filenameIncl, &out);
TString filenameLib(title);
gSystem->PrependPathName("lib", filenameLib);
gSystem->PrependPathName(fOutputDir, filenameLib);
filenameLib += "_Lib";
if (CreateDotClassChartLib(filenameLib + ".dot"))
RunDot(filenameLib, &out);
out << "<div class=\"imgformattabs\">" << endl
<< "<a id=\"img" << title << "_Inh\" class=\"imgformattabsel\" href=\"javascript:SetImg('Charts','inh/" << title << "_Inh.gif');\">Inheritance</a>" << endl
<< "<a id=\"img" << title << "_InhMem\" class=\"imgformattab\" href=\"javascript:SetImg('Charts','inhmem/" << title << "_InhMem.gif');\">Inherited Members</a>" << endl
<< "<a id=\"img" << title << "_Incl\" class=\"imgformattab\" href=\"javascript:SetImg('Charts','incl/" << title << "_Incl.gif');\">Includes</a>" << endl
<< "<a id=\"img" << title << "_Lib\" class=\"imgformattab\" href=\"javascript:SetImg('Charts','lib/" << title << "_Lib.gif');\">Libraries</a><br/>" << endl
<< "</div><div class=\"formatsel\"><div class=\"formatselwidth\"></div>" << endl
<< "<img id=\"Charts\" alt=\"Class Charts\" class=\"formatsel\" usemap=\"#Map" << title << "_Inh\" src=\"inh/" << title << "_Inh.gif\"/></div>" << endl;
return kTRUE;
}
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%\">"
<< "<a href=\"ClassHierarchy.html\">Inheritance Chart</a>:</td></tr>";
out << "<tr class=\"inhtree\"><td width=\"10%\"></td><td width=\"70%\">";
out << "<table class=\"inhtree\"><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);
TString anchor(className);
NameSpace2FileName(anchor);
if (dir == kUp) {
if (htmlFile) {
out << "<center><tt><a name=\"" << anchor;
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=\"" << anchor;
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,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");
Int_t saveErrorIgnoreLevel = gErrorIgnoreLevel;
gErrorIgnoreLevel = kWarning;
psCanvas->SaveAs(filename);
gErrorIgnoreLevel = saveErrorIgnoreLevel;
} else
Printf(formatStr, "-no change-", "", filename.Data());
}
}
void THtml::Convert(const char *filename, const char *title,
const char *dirname , const char *relpath )
{
gROOT->GetListOfGlobals(kTRUE);
CreateListOfClasses("*");
const char *dir;
if (!*dirname) {
gSystem->ExpandPathName(fOutputDir);
dir = gSystem->ConcatFileName(fOutputDir, "examples");
} else
dir = dirname;
if (gSystem->AccessPathName(dir))
gSystem->MakeDirectory(dir);
char *realFilename =
gSystem->Which(fSourceDir, filename, kReadPermission);
if (!realFilename) {
Error("Convert", "Can't find file '%s' !", filename);
return;
}
ifstream sourceFile;
sourceFile.open(realFilename, ios::in);
delete[]realFilename;
realFilename = 0;
if (!sourceFile.good()) {
Error("Convert", "Can't open file '%s' !", realFilename);
return;
}
if (gSystem->AccessPathName(dir)) {
Error("Convert",
"Directory '%s' doesn't exist, or it's write protected !", dir);
return;
}
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()) {
Error("Convert", "Can't open file '%s' !", htmlFilename);
if (htmlFilename)
delete[]htmlFilename;
return;
}
Printf("Convert: %s", htmlFilename);
WriteHtmlHeader(tempFile, title, relpath);
tempFile << "<h1>" << title << "</h1>" << endl;
tempFile << "<pre>" << endl;
fParseContext.clear();
fParseContext.push_back(kCComment);
fDocContext = kIgnore;
fLineNo = 0;
while (!sourceFile.eof()) {
fLine.ReadLine(sourceFile, kFALSE);
if (sourceFile.eof())
break;
fLineExpanded = fLine;
ExpandKeywords(fLineExpanded);
fLineStripped = fLine;
Strip(fLineStripped);
if ((fParseContext.back() == kBeginEndHtml
|| fParseContext.back() == kBeginEndHtmlInCComment))
if (kNPOS == fLine.Index("Begin_Html", 0, TString::kIgnoreCase)
|| kNPOS != fLine.Index("\"Begin_Html", 0, TString::kIgnoreCase))
tempFile << fLine << std::endl;
else {
fParseContext.push_back(kCode);
BeautifyLine(tempFile, relpath);
fParseContext.pop_back();
}
else
if (kNPOS == fLine.Index("End_Html", 0, TString::kIgnoreCase)
|| kNPOS != fLine.Index("\"End_Html", 0, TString::kIgnoreCase))
BeautifyLine(tempFile, relpath);
else {
Ssiz_t posEndHtml = fLine.Index("End_Html", 0, TString::kIgnoreCase);
fLine.Remove(posEndHtml,8);
BeautifyLine(tempFile, relpath);
}
}
tempFile << "</pre>" << endl;
WriteHtmlFooter(tempFile, relpath);
tempFile.close();
sourceFile.close();
if (htmlFilename)
delete[]htmlFilename;
}
Bool_t THtml::CopyHtmlFile(const char *sourceName, const char *destName)
{
char *tmp1 = gSystem->Which(fSourceDir, sourceName, kReadPermission);
if (!tmp1) {
Error("Copy", "Can't copy file '%s' to '%s/%s' - can't find source file!", sourceName,
fOutputDir.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,
fOutputDir.Data());
return kFALSE;
}
TString destFile;
if (!destName || !*destName)
destFile = GetFileName(sourceFile);
else
destFile = GetFileName(destName);
gSystem->ExpandPathName(fOutputDir);
gSystem->PrependPathName(fOutputDir, 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 THtml::CreateIndex()
{
CreateStyleSheet();
CreateJavascript();
gSystem->ExpandPathName(fOutputDir);
TString filename("ClassIndex.html");
gSystem->PrependPathName(fOutputDir, filename);
ofstream indexFile;
indexFile.open(filename.Data(), ios::out);
if (indexFile.good()) {
Printf(formatStr, "", fCounter.Data(), filename.Data());
WriteHtmlHeader(indexFile, "Class Index");
indexFile << "<h1>Index</h1>" << endl;
if (fModules.GetSize()) {
indexFile << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
fModules.Sort();
TIter iModule(&fModules);
TModuleDocInfo* module = 0;
while ((module = (TModuleDocInfo*) iModule()))
indexFile << "<a href=\"" << module->GetName() << "_Index.html\">"
<< module->GetName() << "</a>" << endl;
indexFile << "</div><br />" << endl;
}
std::vector<std::string> indexChars;
if (fClasses.GetSize() > 10) {
std::vector<std::string> classNames;
{
TIter iClass(&fClasses);
TClassDocInfo* cdi = 0;
while ((cdi = (TClassDocInfo*)iClass()))
classNames.push_back(cdi->GetName());
}
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 << "\">" << 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;
TIter iClass(&fClasses);
TClassDocInfo* cdi = 0;
Int_t i = 0;
while ((cdi = (TClassDocInfo*)iClass())) {
fCurrentClass = cdi->GetClass();
if (fCurrentClass == 0) {
Warning("THtml::CreateIndex", "skipping class %s\n", cdi->GetName());
continue;
}
indexFile << "<li class=\"idxl" << (i++)%2 << "\"><tt>";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
indexChars[currentIndexEntry].length()))
indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
TString htmlFile(cdi->GetHtmlFileName());
if (htmlFile.Length()) {
indexFile << "<a name=\"";
indexFile << cdi->GetName();
indexFile << "\" href=\"";
indexFile << htmlFile;
indexFile << "\">";
ReplaceSpecialChars(indexFile, cdi->GetName());
indexFile << "</a>";
} else
ReplaceSpecialChars(indexFile, cdi->GetName());
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.Data());
fCurrentClass = 0;
}
void THtml::CreateIndexByTopic()
{
gSystem->ExpandPathName(fOutputDir);
const char* title = "LibraryDependencies";
TString filename(title);
gSystem->PrependPathName(fOutputDir, filename);
std::ofstream libDepDotFile(filename + ".dot");
libDepDotFile << "strict digraph G {" << endl
<< "ratio=auto;" << endl
<< "rankdir=TB;" << endl
<< "compound=true;" << endl
<< "constraint=false;" << endl
<< "ranksep=1;" << endl
<< "nodesep=0.3;" << endl
<< "ratio=compress;" << endl;
TModuleDocInfo* module = 0;
TIter iModule(&fModules);
fModules.Sort();
std::stringstream sstrCluster;
std::stringstream sstrDeps;
while ((module = (TModuleDocInfo*)iModule())) {
std::vector<std::string> indexChars;
TString filename(module->GetName());
filename += "_Index.html";
gSystem->PrependPathName(fOutputDir, filename);
ofstream outputFile(filename.Data());
if (!outputFile.good()) {
Error("MakeIndex", "Can't open file '%s' !", filename.Data());
continue;
}
Printf(formatStr, "", fCounter.Data(), filename.Data());
TString htmltitle("Index of ");
htmltitle += module->GetName();
htmltitle += " classes";
WriteHtmlHeader(outputFile, htmltitle);
outputFile << "<h2>" << htmltitle << "</h2>" << endl;
std::list<std::string> classNames;
{
TIter iClass(module->GetClasses());
TClassDocInfo* cdi = 0;
while ((cdi = (TClassDocInfo*) iClass())) {
classNames.push_back(cdi->GetName());
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 = setLibDeps[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 << "\">" << indexChars[iIdxEntry]
<< "</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())) {
TClass *classPtr = cdi->GetClass();
if (!classPtr) {
Error("MakeIndex", "Unknown class '%s' !", cdi->GetName());
continue;
}
outputFile << "<li class=\"idxl" << (count++)%2 << "\"><tt>";
if (currentIndexEntry < indexChars.size()
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
indexChars[currentIndexEntry].length()))
outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
TString htmlFile(cdi->GetHtmlFileName());
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;
}
outputFile << "</ul>" << endl;
TDatime date;
WriteHtmlFooter(outputFile, "", date.AsString());
}
sstrCluster << "subgraph clusterlibCint {" << endl
<< "style=filled;" << endl
<< "color=lightgray;" << endl
<< "label=\"libCint\";" << endl
<< "\"CINT\" [style=filled,color=white,fontsize=10]" << endl
<< "}" << endl;
for (LibDep_t::iterator iLibDep = setLibDeps.begin(); iLibDep != setLibDeps.end(); ++iLibDep) {
if (!iLibDep->first.length())
continue;
sstrCluster << "subgraph cluster" << iLibDep->first << " {" << endl
<< "style=filled;" << endl
<< "color=lightgray;" << endl
<< "label=\"" << 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;
if (iLibDep->first != "libCore")
sstrDeps << "\"" << iModule->first << "\" -> \"BASE\" [lhead=clusterlibCore];" << endl;
sstrDeps << "\"" << iModule->first << "\" -> \"CINT\" [lhead=clusterlibCint];" << endl;
for (std::set<std::string>::iterator iLib = iModule->second.begin();
iLib != iModule->second.end(); ++iLib) {
const std::map<std::string, std::set<std::string> >& modDep = setLibDeps[*iLib];
std::map<std::string, std::set<std::string> >::const_iterator iModDep = modDep.begin();
const std::string& mod = iModDep->first;
sstrDeps << "\"" << iModule->first << "\" -> \"" << mod << "\" [lhead=cluster" << *iLib << "];" << endl;
}
}
sstrCluster << endl
<< "}" << endl;
}
libDepDotFile << sstrCluster.str() << endl
<< sstrDeps.str();
libDepDotFile << "}" << endl;
libDepDotFile.close();
ofstream out(filename + ".html");
if (!out.good()) {
Error("CreateIndexByTopic", "Can't open file '%s.html' !",
filename.Data());
return;
}
Printf(formatStr, "", fCounter.Data(), (filename + ".html").Data());
WriteHtmlHeader(out, "Library Dependencies");
out << "<h1>Library Dependencies</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;
}
RunDot(filename, &out);
out << "<img alt=\"Library Dependencies\" class=\"formatsel\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
TDatime date;
WriteHtmlFooter(out, "", date.AsString());
}
Bool_t THtml::CreateHierarchyDot()
{
const char* title = "ClassHierarchy";
gSystem->ExpandPathName(fOutputDir);
TString filename(title);
gSystem->PrependPathName(fOutputDir, filename);
ofstream dotout(filename + ".dot");
if (!dotout.good()) {
Error("CreateHierarchy", "Can't open file '%s.dot' !",
filename.Data());
return kFALSE;
}
dotout << "digraph G {" << endl
<< "ratio=auto;" << endl
<< "rankdir=RL;" << endl;
TClassDocInfo* cdi = 0;
TIter iClass(&fClasses);
while ((cdi = (TClassDocInfo*)iClass())) {
TClass *cl = cdi->GetClass();
if (cl == 0) {
Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
continue;
}
TList *bases = cl->GetListOfBases();
if (bases && !bases->IsEmpty()) {
dotout << "\"" << cdi->GetName() << "\" -> { ";
TIter iBase(bases);
TBaseClass* base = 0;
while ((base = (TBaseClass*) iBase())) {
if (base != bases->First())
dotout << "; ";
dotout << "\"" << base->GetName() << "\"";
}
dotout << "};" << endl;
} else
dotout << "\"" << cdi->GetName() << "\";" << endl;
}
dotout << "}";
dotout.close();
ofstream out(filename + ".html");
if (!out.good()) {
Error("CreateHierarchy", "Can't open file '%s.html' !",
filename.Data());
return kFALSE;
}
Printf(formatStr, "", fCounter.Data(), (filename + ".html").Data());
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;
}
RunDot(filename, &out);
out << "<img usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
TDatime date;
WriteHtmlFooter(out, "", date.AsString());
return kTRUE;
}
void THtml::CreateHierarchy()
{
gSystem->ExpandPathName(fOutputDir);
TString filename("ClassHierarchy.html");
gSystem->PrependPathName(fOutputDir, filename);
ofstream out(filename);
if (!out.good()) {
Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
return;
}
Printf(formatStr, "", fCounter.Data(), filename.Data());
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;
}
TClassDocInfo* cdi = 0;
TIter iClass(&fClasses);
while ((cdi = (TClassDocInfo*)iClass())) {
TClass *basePtr = cdi->GetClass();
if (basePtr == 0) {
Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
continue;
}
TList *bases = basePtr->GetListOfBases();
if (bases && !bases->IsEmpty()) {
out << "<hr />" << endl;
out << "<table><tr><td><ul><li><tt>";
if (cdi->GetHtmlFileName()) {
out << "<a name=\"" << cdi->GetName() << "\" href=\""
<< cdi->GetHtmlFileName() << "\">";
ReplaceSpecialChars(out, cdi->GetName());
out << "</a>";
} else {
ReplaceSpecialChars(out, cdi->GetName());
}
out << "</tt></li></ul></td>";
fHierarchyLines = 0;
DescendHierarchy(out,basePtr);
out << "</tr></table>" << endl;
}
}
TDatime date;
WriteHtmlFooter(out, "", date.AsString());
}
void THtml::DescendHierarchy(ofstream & out, TClass* basePtr, Int_t maxLines, Int_t depth)
{
if (maxLines)
if (fHierarchyLines >= maxLines) {
out << "<td></td>" << endl;
return;
}
UInt_t numClasses = 0;
TClassDocInfo* cdi = 0;
TIter iClass(&fClasses);
while ((cdi = (TClassDocInfo*)iClass()) && (!maxLines || fHierarchyLines<maxLines)) {
TClass *classPtr = cdi->GetClass();
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(cdi->GetHtmlFileName());
if (htmlFile.Length()) {
out << "<center><tt><a name=\"" << cdi->GetName() << "\" href=\""
<< htmlFile << "\">";
ReplaceSpecialChars(out, cdi->GetName());
out << "</a></tt></center>";
} else {
ReplaceSpecialChars(out, cdi->GetName());
}
out << "</td>" << endl;
DescendHierarchy(out,classPtr,maxLines, depth+1);
out << "</tr></table></td>" << endl;
}
if (numClasses)
out << "</tr></table></td>" << endl;
else
out << "<td></td>" << endl;
}
void THtml::GetModuleName(TString& modulename, const char* filename) const
{
modulename = filename;
const char* posSlash = strchr(filename, '/');
const char *srcdir = 0;
if (posSlash) {
srcdir = strstr(posSlash, "/src/");
if (!srcdir) srcdir=strstr(posSlash, "/inc/");
} else srcdir = 0;
if (srcdir && srcdir == posSlash) {
modulename.Remove(srcdir - filename, modulename.Length());
modulename.ToUpper();
} else {
if (posSlash && !strncmp(posSlash,"/Math/GenVector/", 16))
modulename = "MATHCORE";
else if (posSlash && !strncmp(posSlash,"/Math/Matrix", 12))
modulename = "SMATRIX";
else
modulename = "USER_";
}
}
void THtml::CreateListOfClasses(const char* filter)
{
if (fClassFilter == filter)
return;
Info("CreateListOfClasses", "Initializing list of known classes - this might take a while...");
Int_t totalNumberOfClasses = gClassTable->Classes();
fClasses.Clear();
fModules.Clear();
fClassFilter = filter;
gClassTable->Init();
TString reg = filter;
TRegexp re(reg, kTRUE);
for (Int_t i = 0; i < totalNumberOfClasses; i++) {
const char *cname = gClassTable->Next();
TString s = cname;
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;
TString htmlfilename;
GetHtmlFileName(classPtr, htmlfilename);
TClassDocInfo* cdi = new TClassDocInfo(classPtr, htmlfilename.Data());
cdi->SetSelected(!(filter && filter[0] && strcmp(filter,"*") && s.Index(re) == kNPOS));
fClasses.Add(cdi);
TString modulename;
GetModuleName(modulename, impname);
TModuleDocInfo* module = (TModuleDocInfo*) fModules.FindObject(modulename);
if (!module) {
module = new TModuleDocInfo(modulename);
fModules.Add(module);
}
if (module) {
module->AddClass(cdi);
cdi->SetModule(module);
}
}
fClasses.Sort();
Info("CreateListOfClasses", "Initializing list of known classes - DONE.");
}
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::CreateJavascript() {
ofstream js;
gSystem->ExpandPathName(fOutputDir);
char *outFile = gSystem->ConcatFileName(fOutputDir, "ROOT.js");
js.open(outFile, ios::out);
if (!js.good()) {
delete []outFile;
return;
}
js << "function SetCSSValue(where,what,to){" << endl
<< " var r='cssRules';" << endl
<< " if(document.all && navigator.appName.indexOf('Opera')==-1)" << endl
<< " r='rules';" << endl
<< " var i;" << endl
<< " for(i=0;i<document.styleSheets.length;++i) {" << endl
<< " var cssrules=document.styleSheets[i][r];" << endl
<< " for(j=0;j<cssrules.length;++j)" << endl
<< " if(cssrules[j].selectorText.toUpperCase()==where.toUpperCase()) {" << endl
<< " cssrules[j].style[what]=to;" << endl
<< " return;" << endl
<< " }" << endl
<< " }" << endl
<< "}" << endl
<< "var elements=new Array('dispoptCBInh.checked','dispoptCBPub.checked');" << endl
<< "function SetValuesFromCookie() {" << endl
<< " var i;" << endl
<< " var arrcookie=document.cookie.split(\";\");" << endl
<< " for(i=0; i<arrcookie.length; ++i) {" << endl
<< " while(arrcookie[i].charAt(0)==' ') " << endl
<< " arrcookie[i]=arrcookie[i].substring(1,arrcookie[i].length);" << endl
<< " if (arrcookie[i].indexOf(\"ROOT\")==0) {" << endl
<< " var arrval=arrcookie[i].substring(5).split(':');" << endl
<< " for (i=0; i<arrval.length; ++i) {" << endl
<< " var posdelim=elements[i].indexOf(\".\");" << endl
<< " var what=elements[i].substring(0,posdelim);" << endl
<< " var mem =elements[i].substring(posdelim+1);" << endl
<< " var val=arrval[i];" << endl
<< " if (val=='false') val=false;" << endl
<< " else if (val=='true') val=true;" << endl
<< " var el=document.getElementById(what);" << endl
<< " if (!el) return;" << endl
<< " el[mem]=val;" << endl
<< " CBChanged(el);" << endl
<< " }" << endl
<< " return;" << endl
<< " }" << endl
<< " }" << endl
<< "}" << endl
<< "function UpdateCookie() {" << endl
<< " var cookietxt=\"ROOT=\";" << endl
<< " var i;" << endl
<< " for (i=0; i<elements.length; ++i) {" << endl
<< " var posdelim=elements[i].indexOf(\".\");" << endl
<< " var what=elements[i].substring(0,posdelim);" << endl
<< " var mem =elements[i].substring(posdelim+1);" << endl
<< " var val=document.getElementById(what)[mem];" << endl
<< " if (i>0) cookietxt+=':';" << endl
<< " cookietxt+=val;" << endl
<< " }" << endl
<< " var ayear=new Date();" << endl
<< " ayear.setTime(ayear.getTime()+31536000000);" << endl
<< " cookietxt+=\";path=/;expires=\"+ayear.toUTCString();" << endl
<< " document.cookie=cookietxt;" << endl
<< "}" << endl
<< "function CBChanged(cb){" << endl
<< " if(cb.id=='dispoptCBInh') {" << endl
<< " SetCSSValue('tr.funcinh','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('tr.datainh','display',cb.checked?'':'none');" << endl
<< " } else if(cb.id=='dispoptCBPub') {" << endl
<< " SetCSSValue('#funcprot','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('#funcpriv','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('#dataprot','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('#datapriv','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('#enumprot','display',cb.checked?'':'none');" << endl
<< " SetCSSValue('#enumpriv','display',cb.checked?'':'none');" << endl
<< " }" << endl
<< " UpdateCookie();" << endl
<< "}" << endl
<< "function SetImg(name, file) {" << std::endl
<< " var img=document.getElementById(name);" << std::endl
<< " var src=img.src;" << std::endl
<< " var posFile=src.lastIndexOf('/');" << std::endl
<< " var numSlashes=file.split('/').length - 1;" << std::endl
<< " for (var i=0; i<numSlashes; i++)" << std::endl
<< " posFile=src.lastIndexOf('/',posFile - 1);" << std::endl
<< " var oldFile=src.substr(posFile+1);" << std::endl
<< " src=src.substr(0,posFile+1);" << std::endl
<< " src+=file;" << std::endl
<< " img.src=src;" << std::endl
<< " if (img.useMap) {" << std::endl
<< " var usemapFile=file;" << std::endl
<< " var posUsemapExt=usemapFile.lastIndexOf('.');" << std::endl
<< " if (posUsemapExt!=-1) usemapFile=usemapFile.substr(0,posUsemapExt);" << std::endl
<< " var posUsemapDir=usemapFile.lastIndexOf('/');" << std::endl
<< " if (posUsemapDir!=-1) usemapFile=usemapFile.substr(posUsemapDir+1);" << std::endl
<< " img.useMap=\"#Map\"+usemapFile;" << std::endl
<< " }" << std::endl
<< " var posExt=oldFile.lastIndexOf('.');" << std::endl
<< " oldFile=oldFile.substr(0,posExt);" << std::endl
<< " var posDir=oldFile.lastIndexOf('/');" << std::endl
<< " if (posDir!=-1) oldFile=oldFile.substr(posDir + 1);" << std::endl
<< " document.getElementById(\"img\"+oldFile).className=\"imgformattab\";" << std::endl
<< " posExt=file.lastIndexOf('.');" << std::endl
<< " file=file.substr(0,posExt);" << std::endl
<< " posDir=file.lastIndexOf('/');" << std::endl
<< " if (posDir!=-1) file=file.substr(posDir + 1);" << std::endl
<< " document.getElementById(\"img\"+file).className=\"imgformattabsel\";" << std::endl
<< "}" << std::endl;
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
<< " background-color: inherit;" << std::endl
<< " text-decoration: none;" << std::endl
<< "}" << std::endl
<< "a:visited {" << std::endl
<< " color: #5500cc;" << std::endl
<< " background-color: inherit;" << std::endl
<< "}" << std::endl
<< "a:active {" << std::endl
<< " color: #551a8b;" << std::endl
<< " background-color: inherit;" << std::endl
<< " border: dotted 1px #0000ff;" << std::endl
<< "}" << std::endl
<< "a:hover {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: #eeeeff;" << 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
<< " color: inherit;" << 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: 97%;" << 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
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "span.funcname {" << std::endl
<< " margin-left: -0.7em;" << std::endl
<< " font-weight: bolder;" << 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: Black;" << std::endl
<< " background-color: inherit;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "span.cpp {" << std::endl
<< " color: Gray;" << std::endl
<< " background-color: inherit;" << std::endl
<< " font-weight: normal;" << std::endl
<< "}" << std::endl
<< "span.string {" << std::endl
<< " color: Teal;" << std::endl
<< " background-color: inherit;" << 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: 97%;" << std::endl
<< " margin-left: 0.3em;" << std::endl
<< " padding-left: 1em;" << std::endl
<< " margin-bottom: 2em;" << std::endl
<< " border-bottom: solid 3px #cccccc;" << std::endl
<< " border-left: solid 1px #cccccc;" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "div.inlinecode {" << std::endl
<< " margin-bottom: 0.5em;" << std::endl
<< " padding: 0.5em;" << std::endl
<< "}" << std::endl
<< "code.inlinecode {" << std::endl
<< " padding: 0.5em;" << std::endl
<< " border: solid 1px #ffff77;" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: #ffffdd;" << std::endl
<< "}" << std::endl
<< "body {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: #fcfcfc;" << std::endl
<< "}" << std::endl
<< "table.inhtree {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< " border: solid 1px Black;" << std::endl
<< " width: 97%;" << std::endl
<< "}" << std::endl
<< "table.libinfo {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< " padding: 2px;" << std::endl
<< " border: solid 1px Gray; " << std::endl
<< " float: right;" << std::endl
<< "}" << std::endl
<< "#functions {" << std::endl
<< " margin-top: 4em;" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "#datamembers {" << std::endl
<< " margin-top: 4em;" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "div.access {" << std::endl
<< " border-left: solid 3pt black;" << std::endl
<< " padding-left: 1em;" << std::endl
<< " margin-left: 1em;" << std::endl
<< " margin-bottom: 1em;" << std::endl
<< "}" << std::endl
<< "#funcpubl {" << std::endl
<< " border-left-color: #77ff77;" << std::endl
<< "}" << std::endl
<< "#funcprot {" << std::endl
<< " border-left-color: #ffff00;" << std::endl
<< "}" << std::endl
<< "#funcpriv {" << std::endl
<< " border-left-color: #ff7777;" << std::endl
<< "}" << std::endl
<< "#datapubl {" << std::endl
<< " border-left-color: #77ff77;" << std::endl
<< "}" << std::endl
<< "#dataprot {" << std::endl
<< " border-left-color: #ffff00;" << std::endl
<< "}" << std::endl
<< "#datapriv {" << std::endl
<< " border-left-color: #ff7777;" << std::endl
<< "}" << std::endl
<< "#enumpubl {" << std::endl
<< " border-left-color: #77ff77;" << std::endl
<< "}" << std::endl
<< "#enumprot {" << std::endl
<< " border-left-color: #ffff00;" << std::endl
<< "}" << std::endl
<< "#enumpriv {" << std::endl
<< " border-left-color: #ff7777;" << std::endl
<< "}" << std::endl
<< "tr.func {" << std::endl
<< " white-space: nowrap;" << std::endl
<< "}" << std::endl
<< "tr.data {" << std::endl
<< " white-space: nowrap;" << std::endl
<< "}" << std::endl
<< "tr.funcinh {" << std::endl
<< " display: none;" << std::endl
<< " white-space: nowrap;" << std::endl
<< "}" << std::endl
<< "tr.datainh {" << std::endl
<< " display: none;" << std::endl
<< " white-space: nowrap;" << std::endl
<< "}" << std::endl
<< "span.baseclass {" << std::endl
<< " font-size:x-small;" << std::endl
<< "}" << std::endl
<< "td.funcret {" << std::endl
<< " float: right;" << std::endl
<< " padding-right: 0.5em;" << std::endl
<< "}" << std::endl
<< "td.funcname {" << std::endl
<< " font-weight: bolder;" << std::endl
<< " white-space: normal;" << std::endl
<< " text-indent: -2em;" << std::endl
<< " padding-left: 2em;" << std::endl
<< "}" << std::endl
<< "td.datatype {" << std::endl
<< " float: right;" << std::endl
<< " padding-right: 0.5em;" << std::endl
<< "}" << std::endl
<< "td.dataname {" << std::endl
<< " font-weight: bolder;" << std::endl
<< " vertical-align: top;" << std::endl
<< "}" << std::endl
<< "td.datadesc {" << std::endl
<< " font-style: italic;" << std::endl
<< " padding-left: 0.5em;" << std::endl
<< " white-space: normal;" << std::endl
<< "}" << std::endl
<< "#dispopt {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< " padding: 2px;" << std::endl
<< " border: solid 1px Gray; " << std::endl
<< " float: right;" << std::endl
<< " position: relative;" << std::endl
<< " top: -5em;" << std::endl
<< " z-index: 2;" << std::endl
<< "}" << std::endl
<< "#formdispopt {" << std::endl
<< " margin: 0px 0px 0px 0px;" << std::endl
<< "}" << std::endl
<< "div.imgformattabs {" << std::endl
<< " padding-left: 1em;" << std::endl
<< "}" << std::endl
<< "div.formatsel {" << std::endl
<< " border: solid 2px Black;" << std::endl
<< " margin-right: auto;" << std::endl
<< " display: table;" << std::endl
<< "}" << std::endl
<< "div.formatselwidth {" << std::endl
<< " width: 28em;" << std::endl
<< " height: 0pt;" << std::endl
<< "}" << std::endl
<< "img.formatsel {" << std::endl
<< " display: block;" << std::endl
<< " border: none;" << std::endl
<< " margin-left: auto;" << std::endl
<< " margin-right: auto;" << std::endl
<< "}" << std::endl
<< "a.imgformattab {" << std::endl
<< " border-top: solid 1px Gray;" << std::endl
<< " border-left: solid 1px Gray;" << std::endl
<< " border-right: solid 1px Gray;" << std::endl
<< " border-bottom: solid 0px Black;" << std::endl
<< " color: #777777;" << std::endl
<< " background-color: #dddddd;" << std::endl
<< " padding: 0px 0.4em 1px 0.4em;" << std::endl
<< " position: relative;" << std::endl
<< " top: +0px;" << std::endl
<< "}" << std::endl
<< "* html a.imgformattab { /* IE only, fix pos bug */" << std::endl
<< " top: -1px;" << std::endl
<< "}" << std::endl
<< "a.imgformattab:hover {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "a.imgformattabsel {" << std::endl
<< " border-top: solid 2px Black;" << std::endl
<< " border-left: solid 2px Black;" << std::endl
<< " border-right: solid 2px Black;" << std::endl
<< " border-bottom: solid 3px White;" << std::endl
<< " padding: 2px 0.4em 1px 0.4em;" << std::endl
<< " position: relative;" << std::endl
<< " top: 0px;" << std::endl
<< " background-color: White;" << std::endl
<< " color: Black;" << std::endl
<< "}" << std::endl
<< "* html a.imgformattabsel { /* IE only, fix pos bug */" << std::endl
<< " top: -1px;" << std::endl
<< "}" << std::endl
<< "a.imgformattabsel:hover {" << std::endl
<< " color: inherit;" << std::endl
<< " background-color: White;" << std::endl
<< "}" << std::endl
<< "a.imgformattabsel:active {" << std::endl
<< " color: Black;" << std::endl
<< " background-color: inherit;" << std::endl
<< " border-left: solid 2px Black;" << std::endl
<< " border-right: solid 2px Black;" << std::endl
<< " border-top: solid 2px Black;" << std::endl
<< " border-bottom: solid 3px White;" << 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;
std::list<TClass*> currentType;
enum {
kNada,
kMember,
kScope,
kNumAccesses
} scoping = kNada;
Ssiz_t i;
currentType.push_back(0);
for (i = 0; i < keyword.Length(); ++i) {
if (!currentType.back())
scoping = kNada;
if (fParseContext.back() == kCode || fParseContext.back() == kCComment) {
if (currentType.back())
switch (keyword[i]) {
case ':':
if (keyword[i + 1] == ':') {
scoping = kScope;
i += 1;
continue;
}
break;
case '-':
if (keyword[i + 1] == '>') {
scoping = kMember;
i += 1;
continue;
}
break;
case '.':
if (keyword[i + 1] != '.') {
scoping = kMember;
continue;
}
break;
}
switch (keyword[i]) {
case '(':
currentType.push_back(0);
scoping = kNada;
continue;
break;
case ')':
if (currentType.size() > 1)
currentType.pop_back();
scoping = kMember;
continue;
break;
}
if (i >= keyword.Length())
break;
} else
currentType.back() = 0;
if (!IsWord(keyword[i])){
if (fParseContext.back() != kBeginEndHtml && fParseContext.back() != kBeginEndHtmlInCComment) {
Bool_t haveHtmlEscapedChar = fParseContext.back() == kString && i > 2 &&
keyword[i] == '\'' && keyword[i-1] == ';';
if (haveHtmlEscapedChar) {
Ssiz_t posBegin = i - 2;
while (posBegin > 0 && IsWord(keyword[posBegin]))
--posBegin;
haveHtmlEscapedChar = posBegin > 0 &&
keyword[posBegin] == '&' && keyword[posBegin - 1] == '\'';
}
Bool_t closeString = fParseContext.back() == kString &&
( keyword[i] == '"' || keyword[i] == '\''
&& (i > 1 && keyword[i - 2] == '\''
|| i > 2 && keyword[i - 2] == '\\' && (i > 1 && keyword[i - 3] == '\''))
|| haveHtmlEscapedChar);
if (!fEscFlag)
if (fParseContext.back() == kCode || fParseContext.back() == 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.push_back(kString);
currentType.back() = 0;
closeString = kFALSE;
} else if (fParseContext.back() != kCComment &&
keyword.Length() > i + 1 && keyword[i] == '/' &&
(keyword[i+1] == '/' || keyword[i+1] == '*')) {
fParseContext.push_back(kCComment);
commentIsCPP = keyword[i+1] == '/';
currentType.back() = 0;
keyword.Insert(i, "<span class=\"comment\">");
i += 23;
} else if (fParseContext.back() == kCComment && !commentIsCPP
&& keyword.Length() > i + 1
&& keyword[i] == '*' && keyword[i+1] == '/') {
if (fParseContext.size()>1)
fParseContext.pop_back();
currentType.back() = 0;
keyword.Insert(i + 2, "</span>");
i += 9;
}
ReplaceSpecialChars(keyword, i);
if (closeString) {
keyword.Insert(i, "</span>");
i += 7;
if (fParseContext.size()>1)
fParseContext.pop_back();
currentType.back() = 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, 5);
continue;
} else {
pre_is_open = kTRUE;
i += 5;
}
currentType.back() = 0;
} else
if (!strncasecmp(keyword.Data() + i,"</pre>", 6)) {
if (!pre_is_open) {
keyword.Remove(i, 6);
continue;
} else {
pre_is_open = kFALSE;
i += 6;
}
currentType.back() = 0;
}
}
continue;
}
Ssiz_t endWord = i;
while (endWord < keyword.Length() && IsName(keyword[endWord]))
endWord++;
if (fParseContext.back() != kCode && fParseContext.back() != kCComment &&
fParseContext.back() != kBeginEndHtml && fParseContext.back() != kBeginEndHtmlInCComment) {
i = endWord - 1;
continue;
}
TString word(keyword(i, endWord - i));
if (fParseContext.back() == kBeginEndHtml || fParseContext.back() == kBeginEndHtmlInCComment) {
if (!word.CompareTo("end_html", TString::kIgnoreCase) &&
(i == 0 || keyword[i - 1] != '\"')) {
if (fParseContext.back() == kBeginEndHtmlInCComment)
commentIsCPP = kFALSE;
else {
commentIsCPP = kTRUE;
if (keyword.BeginsWith("//")) {
keyword.Prepend("<span class=\"comment\">");
i += 22;
}
}
if (fParseContext.size()>1)
fParseContext.pop_back();
if (fParseContext.back() != kCComment)
fParseContext.push_back(kCComment);
pre_is_open = kTRUE;
keyword.Replace(i, word.Length(), "<pre>");
i += 4;
}
// we're in a begin/end_html block, just keep what we have
currentType.back() = 0;
continue;
}
if (fParseContext.back() == kCComment
&& !word.CompareTo("begin_html", TString::kIgnoreCase)
&& (i == 0 || keyword[i - 1] != '\"')) {
if (commentIsCPP)
fParseContext.push_back(kBeginEndHtml);
else
fParseContext.push_back(kBeginEndHtmlInCComment);
pre_is_open = kFALSE;
keyword.Replace(i, word.Length(), "</pre>");
i += 5;
currentType.back() = 0;
continue;
}
if (fParseContext.back() == 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.back() = 0;
continue;
}
TDataType* subType = 0;
TClass* subClass = 0;
TDataMember *datamem = 0;
TMethod *meth = 0;
const char* globalTypeName = 0;
if (!currentType.size()) {
Warning("ExpandKeywords", "type context is empty!");
currentType.push_back(0);
}
TClass* lookupScope = currentType.back();
Bool_t describe = kFALSE;
TString description;
if (!lookupScope && scoping == kNada)
lookupScope = fCurrentClass;
if (scoping == kNada) {
subType = gROOT->GetType(word);
if (!subType)
subClass = GetClass(word);
if (!subType && !subClass) {
TGlobal *global = gROOT->GetGlobal(word);
if (global) {
globalTypeName = global->GetTypeName();
subClass = GetClass(globalTypeName);
if (!subClass)
subType = gROOT->GetType(globalTypeName);
else
if (subClass == THtml::Class() && word != "gHtml")
subClass = 0;
describe = (subClass || subType);
}
}
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 (!datamem)
meth = lookupScope->GetMethodAllAny(word);
describe = (datamem || meth);
}
}
TString link;
if (subType) {
link = "./ListOfTypes.html";
link += "#";
TString mangledWord;
if (!globalTypeName)
mangledWord = word;
else
mangledWord = globalTypeName;
if (describe)
description = mangledWord;
NameSpace2FileName(mangledWord);
link += mangledWord;
currentType.back() = 0;
} else if (subClass) {
GetHtmlFileName(subClass, link);
if (link.Length() && !link.BeginsWith("http://") && !link.BeginsWith("https://"))
link.Prepend("./");
currentType.back() = subClass;
if (describe)
description = subClass->GetName();
} else if (datamem || meth) {
TClass* scope = datamem ? datamem->GetClass() : meth->GetClass();
GetHtmlFileName(scope, link);
if (link.Length()) {
if (!link.BeginsWith("http://") && !link.BeginsWith("https://"))
link.Prepend("./");
link += "#";
TString mangledName(scope->GetName());
NameSpace2FileName(mangledName);
link += mangledName;
link += ":";
if (datamem) {
mangledName = datamem->GetName();
if (datamem->GetTypeName())
currentType.back() = GetClass(datamem->GetTypeName());
if (describe) {
description = datamem->GetFullTypeName();
description += " ";
if (datamem->GetClass()) {
description += datamem->GetClass()->GetName();
description += "::";
}
description += datamem->GetName();
}
} else {
mangledName = meth->GetName();
TString retTypeName = meth->GetReturnTypeName();
if (retTypeName.BeginsWith("const "))
retTypeName.Remove(0,6);
Ssiz_t pos=0;
while (IsWord(retTypeName[pos])) ++pos;
retTypeName.Remove(pos, retTypeName.Length());
if (retTypeName.Length())
currentType.back() = GetClass(retTypeName);
if (describe && meth->GetClass()) {
TIter iMeth(meth->GetClass()->GetListOfMethods());
TMethod* mCand = 0;
description = "";
while ((mCand = (TMethod*)iMeth()))
if (!strcmp(mCand->GetName(), meth->GetName())) {
if (description.Length()) {
description += " or overloads";
break;
}
description = mCand->GetPrototype();
}
}
}
NameSpace2FileName(mangledName);
link += mangledName;
}
} else
currentType.back() = 0;
if (link.Length()) {
link.Prepend("<a href=\"");
link += "\"";
if (description.Length()) {
link += " title=\"";
Ssiz_t pos = 0;
while (pos < description.Length())
ReplaceSpecialChars(description, pos);
link += description;
link += "\"";
}
link += ">";
keyword.Insert(i, link);
i += link.Length();
}
TString mangledWord(word);
Ssiz_t posReplace = 0;
ReplaceSpecialChars(mangledWord, posReplace);
keyword.Replace(i, word.Length(), mangledWord);
i += mangledWord.Length();
if (link.Length()) {
keyword.Insert(i, "</a>");
i += 4;
}
--i;
}
if (fParseContext.back() == kString) {
keyword += "</span>";
i += 7;
if (fParseContext.size()>1)
fParseContext.pop_back();
currentType.back() = 0;
}
if (commentIsCPP) {
keyword += "</span>";
i += 7;
if (fParseContext.back() == kCComment) {
if (fParseContext.size()>1)
fParseContext.pop_back();
}
currentType.back() = 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)
{
if (!filename || !filename[0]) return "";
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
if (classPtr->GetSharedLibs()) {
TString libname(classPtr->GetSharedLibs());
Ssiz_t posSpace = libname.First(' ');
if (posSpace != kNPOS)
libname.Remove(posSpace, libname.Length());
TString libnameBase = gSystem->BaseName(libname);
if (libnameBase.BeginsWith("lib"))
libnameBase.Remove(0, 3);
Ssiz_t posExt = libnameBase.First('.');
if (posExt != '.')
libnameBase.Remove(posExt, libnameBase.Length());
if (libnameBase.Length())
varName += libnameBase;
else
varName += "Root";
} else
varName += "Root";
filename = cFilename;
TString htmlFileName;
if (!filename.Length() ||
!gSystem->FindFile(fSourceDir, filename, kReadPermission)) {
htmlFileName = gEnv->GetValue(varName, "");
if ((!htmlFileName || !htmlFileName[0]) && varName != "Root.Html.Root")
htmlFileName = gEnv->GetValue("Root.Html.Root", "");
} else
htmlFileName = "./";
if (htmlFileName.Length()) {
filename = htmlFileName;
TString className(classPtr->GetName());
NameSpace2FileName(className);
gSystem->PrependPathName(filename, className);
filename = className;
filename.ReplaceAll("\\", "/");
filename += ".html";
} else filename.Remove(0);
}
TClass *THtml::GetClass(const char *name1)
{
if(!name1 || !name1[0]) 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;
}
TClassDocInfo* cdi = (TClassDocInfo*)fClasses.FindObject(name1);
if (!cdi) return 0;
TClass *cl=cdi->GetClass();
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)
{
TString sourceFile;
TString classname(classPtr->GetName());
TString filename;
TString dir;
switch (type) {
case kSource:
if (classPtr->GetImplFileLine()) {
sourceFile = GetImplFileName(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);
if (classPtr->GetImplFileLine())
filename += ".cxx.html";
else
filename += ".h.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 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;
}
Bool_t THtml::IsName(UChar_t c)
{
Bool_t ret = kFALSE;
if (isalnum(c) || c == '_' || c == '~')
ret = kTRUE;
return ret;
}
Bool_t THtml::IsWord(UChar_t c)
{
Bool_t ret = kFALSE;
if (isalpha(c) || c == '_' || c == '~')
ret = kTRUE;
return ret;
}
void THtml::MakeAll(Bool_t force, const char *filter)
{
MakeIndex(filter);
TClassDocInfo* classinfo = 0;
TIter iClassInfo(&fClasses);
UInt_t count = 0;
while ((classinfo = (TClassDocInfo*)iClassInfo())) {
if (!classinfo->IsSelected())
continue;
fCounter.Form("%5d", fClasses.GetSize() - count++);
MakeClass(classinfo, force);
}
fCounter.Remove(0);
}
void THtml::MakeClass(const char *className, Bool_t force)
{
if (!fClasses.GetSize())
CreateListOfClasses("*");
TClassDocInfo* cdi = (TClassDocInfo*)fClasses.FindObject(className);
if (!cdi) {
if (!TClassEdit::IsStdClass(className))
Error("MakeClass", "Unknown class '%s' !", className);
return;
}
MakeClass(cdi, force);
}
void THtml::MakeClass(void *cdi_void, Bool_t force)
{
if (!fClasses.GetSize())
CreateListOfClasses("*");
TClassDocInfo* cdi = (TClassDocInfo*) cdi_void;
fCurrentClass = cdi->GetClass();
if (!fCurrentClass) {
if (!TClassEdit::IsStdClass(cdi->GetName()))
Error("MakeClass", "Unknown class '%s' !", cdi->GetName());
return;
}
TString htmlFile(cdi->GetHtmlFileName());
if (htmlFile.Length()
&& (htmlFile.BeginsWith("http://")
|| htmlFile.BeginsWith("https://")
|| gSystem->IsAbsoluteFileName(htmlFile))
) {
htmlFile.Remove(0);
}
if (htmlFile.Length()) {
Class2Html(force);
MakeTree(cdi->GetName(), force);
} else
Printf(formatStr, "-skipped-", fCounter.Data(), cdi->GetName());
}
void THtml::MakeIndex(const char *filter)
{
CreateListOfClasses(filter);
CreateListOfTypes();
CreateIndexByTopic();
CreateIndex();
CreateHierarchy();
}
void THtml::MakeTree(const char *className, Bool_t force)
{
Bool_t wasBatch = gROOT->IsBatch();
if (!wasBatch)
gROOT->SetBatch();
TVirtualPad *psCanvas = (TVirtualPad*)gROOT->ProcessLineFast("new TCanvas(\"R__THtml\",\"psCanvas\",0,0,1000,1200);");
if (!wasBatch)
gROOT->SetBatch(kFALSE);
if (!psCanvas) {
Error("MakeTree", "Cannot create a TCanvas!");
return;
}
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 (!HaveDot())
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);
}
Bool_t THtml::Strip(TString& str) {
Bool_t changed = str[0] == ' ' || str[0] == '\t';
changed |= str[str.Length()] == ' ' || str[str.Length()] == '\t';
if (!changed) return kFALSE;
Ssiz_t i = 0;
while (str[i] == ' ' || str[i] == '\t')
++i;
str.Remove(0,i);
i = str.Length() - 1;
while (i >= 0 && (str[i] == ' ' || str[i] == '\t'))
--i;
str.Remove(i + 1, str.Length());
return kTRUE;
}
void THtml::WriteHtmlHeader(ofstream & out, const char *title,
const char* dir , TClass *cls)
{
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 << "<?xml version=\"1.0\"?>" << endl;
out << "<!DOCTYPE html PUBLIC \"-
<< "\"http:
out << "<html xmlns=\"http:
out << "<!-- -->" <<
endl;
out << "<!-- Author: ROOT team (rootdev@pcroot.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 << "<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\" type=\"text/css\" href=\"" << dir << "ROOT.css\" id=\"ROOTstyle\" />" << endl;
out << "<script type=\"text/javascript\" src=\"" << dir << "ROOT.js\"></script>" << endl;
out << "</head>" << endl;
out << "<body onload=\"javascript:SetValuesFromCookie();\">" << 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://pcbrun.cern.ch/nicolas/index.html";
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 << "<em>" << 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 << "</em>" << 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.