1 |
bendavid |
1.2 |
// @(#)root/html:$Id: TDocOutput.cxx,v 1.1 2009/08/11 23:09:28 loizides Exp $
|
2 |
loizides |
1.1 |
// Author: Axel Naumann 2007-01-09
|
3 |
|
|
|
4 |
|
|
/*************************************************************************
|
5 |
|
|
* Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
|
6 |
|
|
* All rights reserved. *
|
7 |
|
|
* *
|
8 |
|
|
* For the licensing terms see $ROOTSYS/LICENSE. *
|
9 |
|
|
* For the list of contributors see $ROOTSYS/README/CREDITS. *
|
10 |
|
|
*************************************************************************/
|
11 |
|
|
|
12 |
|
|
#include "MitAna/Utils/interface/TDocOutput.h"
|
13 |
|
|
|
14 |
|
|
#include "Riostream.h"
|
15 |
|
|
#include "MitAna/Utils/interface/TClassDocOutput.h"
|
16 |
|
|
#include "TDataMember.h"
|
17 |
|
|
#include "TDataType.h"
|
18 |
|
|
#include "MitAna/Utils/interface/TDocInfo.h"
|
19 |
|
|
#include "MitAna/Utils/interface/TDocParser.h"
|
20 |
|
|
#include "TEnv.h"
|
21 |
|
|
#include "TGlobal.h"
|
22 |
|
|
#include "MitAna/Utils/interface/THtml.h"
|
23 |
|
|
#include "TInterpreter.h"
|
24 |
|
|
#include "TMethod.h"
|
25 |
|
|
#include "TROOT.h"
|
26 |
|
|
#include "TSystem.h"
|
27 |
|
|
#include "TUrl.h"
|
28 |
|
|
#include "TVirtualMutex.h"
|
29 |
|
|
#include "TVirtualPad.h"
|
30 |
|
|
#include "TVirtualViewer3D.h"
|
31 |
|
|
#include <vector>
|
32 |
|
|
#include <list>
|
33 |
|
|
#include <set>
|
34 |
|
|
#include <sstream>
|
35 |
|
|
#include <stdlib.h>
|
36 |
|
|
|
37 |
|
|
namespace {
|
38 |
|
|
|
39 |
|
|
typedef std::vector<std::string> Words_t;
|
40 |
|
|
typedef Words_t::const_iterator SectionStart_t;
|
41 |
|
|
|
42 |
|
|
class TSectionInfo {
|
43 |
|
|
public:
|
44 |
|
|
TSectionInfo(SectionStart_t start, size_t chars, size_t size):
|
45 |
|
|
fStart(start), fChars(chars), fSize(size) {};
|
46 |
|
|
|
47 |
|
|
SectionStart_t fStart;
|
48 |
|
|
size_t fChars;
|
49 |
|
|
size_t fSize;
|
50 |
|
|
};
|
51 |
|
|
typedef std::list<TSectionInfo> SectionStarts_t;
|
52 |
|
|
|
53 |
|
|
static void Sections_BuildIndex(SectionStarts_t& sectionStarts,
|
54 |
|
|
SectionStart_t begin, SectionStart_t end,
|
55 |
|
|
size_t maxPerSection)
|
56 |
|
|
{
|
57 |
|
|
// for each assumed section border, check that previous entry's
|
58 |
|
|
// char[selectionChar] differs, else move section start forward
|
59 |
|
|
|
60 |
|
|
SectionStart_t cursor = begin;
|
61 |
|
|
if (sectionStarts.empty() || sectionStarts.back().fStart != cursor)
|
62 |
|
|
sectionStarts.push_back(TSectionInfo(cursor, 1, 0));
|
63 |
|
|
|
64 |
|
|
SectionStarts_t::iterator prevSection = sectionStarts.end();
|
65 |
|
|
--prevSection;
|
66 |
|
|
|
67 |
|
|
while (cursor != end) {
|
68 |
|
|
size_t numLeft = end - cursor;
|
69 |
|
|
size_t assumedNumSections = (numLeft + maxPerSection - 1 ) / maxPerSection;
|
70 |
|
|
size_t step = ((numLeft + assumedNumSections - 1) / assumedNumSections);
|
71 |
|
|
if (!step || step >= numLeft) return;
|
72 |
|
|
cursor += step;
|
73 |
|
|
if (cursor == end) break;
|
74 |
|
|
|
75 |
|
|
SectionStart_t addWhichOne = prevSection->fStart;
|
76 |
|
|
|
77 |
|
|
size_t selectionChar=1;
|
78 |
|
|
for (; selectionChar <= cursor->length() && addWhichOne == prevSection->fStart;
|
79 |
|
|
++selectionChar) {
|
80 |
|
|
SectionStart_t checkPrev = cursor;
|
81 |
|
|
while (--checkPrev != prevSection->fStart
|
82 |
|
|
&& !strncasecmp(checkPrev->c_str(), cursor->c_str(), selectionChar)) { }
|
83 |
|
|
|
84 |
|
|
SectionStart_t checkNext = cursor;
|
85 |
|
|
while (++checkNext != end
|
86 |
|
|
&& !strncasecmp(checkNext->c_str(), cursor->c_str(), selectionChar)) { }
|
87 |
|
|
|
88 |
|
|
// if the previous matching one is closer but not previous section start, take it!
|
89 |
|
|
if (checkPrev != prevSection->fStart) {
|
90 |
|
|
if ((cursor - checkPrev) <= (checkNext - cursor))
|
91 |
|
|
addWhichOne = ++checkPrev;
|
92 |
|
|
else if (checkNext != end
|
93 |
|
|
&& (size_t)(checkNext - cursor) < maxPerSection) {
|
94 |
|
|
addWhichOne = checkNext;
|
95 |
|
|
}
|
96 |
|
|
}
|
97 |
|
|
}
|
98 |
|
|
if (addWhichOne == prevSection->fStart)
|
99 |
|
|
addWhichOne = cursor;
|
100 |
|
|
|
101 |
|
|
selectionChar = 1;
|
102 |
|
|
while (selectionChar <= prevSection->fStart->length()
|
103 |
|
|
&& selectionChar <= addWhichOne->length()
|
104 |
|
|
&& !strncasecmp(prevSection->fStart->c_str(), addWhichOne->c_str(), selectionChar))
|
105 |
|
|
++selectionChar;
|
106 |
|
|
|
107 |
|
|
sectionStarts.push_back(TSectionInfo(addWhichOne, selectionChar, 0));
|
108 |
|
|
cursor = addWhichOne;
|
109 |
|
|
++prevSection;
|
110 |
|
|
} // while cursor != end
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
static void Sections_SetSize(SectionStarts_t& sectionStarts, const Words_t &words)
|
114 |
|
|
{
|
115 |
|
|
// Update the length of the sections
|
116 |
|
|
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
|
117 |
|
|
iSectionStart != sectionStarts.end(); ++iSectionStart) {
|
118 |
|
|
SectionStarts_t::iterator next = iSectionStart;
|
119 |
|
|
++next;
|
120 |
|
|
if (next == sectionStarts.end()) {
|
121 |
|
|
iSectionStart->fSize = (words.end() - iSectionStart->fStart);
|
122 |
|
|
break;
|
123 |
|
|
}
|
124 |
|
|
iSectionStart->fSize = (next->fStart - iSectionStart->fStart);
|
125 |
|
|
}
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
static void Sections_PostMerge(SectionStarts_t& sectionStarts, const size_t maxPerSection)
|
129 |
|
|
{
|
130 |
|
|
// Merge sections that ended up being too small, up to maxPerSection entries
|
131 |
|
|
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
|
132 |
|
|
iSectionStart != sectionStarts.end();) {
|
133 |
|
|
SectionStarts_t::iterator iNextSectionStart = iSectionStart;
|
134 |
|
|
++iNextSectionStart;
|
135 |
|
|
if (iNextSectionStart == sectionStarts.end()) break;
|
136 |
|
|
if (iNextSectionStart->fSize + iSectionStart->fSize < maxPerSection) {
|
137 |
|
|
iSectionStart->fSize += iNextSectionStart->fSize;
|
138 |
|
|
sectionStarts.erase(iNextSectionStart);
|
139 |
|
|
} else ++iSectionStart;
|
140 |
|
|
}
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
static void GetIndexChars(const Words_t& words, UInt_t numSectionsIn,
|
144 |
|
|
std::vector<std::string> §ionMarkersOut)
|
145 |
|
|
{
|
146 |
|
|
// Given a list of words (class names, in this case), this function builds an
|
147 |
|
|
// optimal set of about numSectionIn sections (even if almost all words start
|
148 |
|
|
// with a "T"...), and returns the significant characters for each section start
|
149 |
|
|
// in sectionMarkersOut.
|
150 |
|
|
|
151 |
|
|
const size_t maxPerSection = (words.size() + numSectionsIn - 1)/ numSectionsIn;
|
152 |
|
|
SectionStarts_t sectionStarts;
|
153 |
|
|
Sections_BuildIndex(sectionStarts, words.begin(), words.end(), maxPerSection);
|
154 |
|
|
Sections_SetSize(sectionStarts, words);
|
155 |
|
|
Sections_PostMerge(sectionStarts, maxPerSection);
|
156 |
|
|
|
157 |
|
|
// convert to index markers
|
158 |
|
|
sectionMarkersOut.clear();
|
159 |
|
|
sectionMarkersOut.resize(sectionStarts.size());
|
160 |
|
|
size_t idx = 0;
|
161 |
|
|
for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
|
162 |
|
|
iSectionStart != sectionStarts.end(); ++iSectionStart)
|
163 |
|
|
sectionMarkersOut[idx++] =
|
164 |
|
|
iSectionStart->fStart->substr(0, iSectionStart->fChars);
|
165 |
|
|
}
|
166 |
|
|
|
167 |
|
|
static void GetIndexChars(const std::list<std::string>& wordsIn, UInt_t numSectionsIn,
|
168 |
|
|
std::vector<std::string> §ionMarkersOut)
|
169 |
|
|
{
|
170 |
|
|
// initialize word vector
|
171 |
|
|
Words_t words(wordsIn.size());
|
172 |
|
|
size_t idx = 0;
|
173 |
|
|
for (std::list<std::string>::const_iterator iWord = wordsIn.begin(); iWord != wordsIn.end(); ++iWord)
|
174 |
|
|
words[idx++] = *iWord;
|
175 |
|
|
GetIndexChars(words, numSectionsIn, sectionMarkersOut);
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
extern "C" { // std::qsort on solaris wants the sorter to be extern "C"
|
181 |
|
|
|
182 |
|
|
//______________________________________________________________________________
|
183 |
|
|
static int CaseInsensitiveSort(const void *name1, const void *name2)
|
184 |
|
|
{
|
185 |
|
|
// Friend function for sorting strings, case insensitive
|
186 |
|
|
//
|
187 |
|
|
//
|
188 |
|
|
// Input: name1 - pointer to the first string
|
189 |
|
|
// name2 - pointer to the second string
|
190 |
|
|
//
|
191 |
|
|
// NOTE: This function compares its arguments and returns an integer less
|
192 |
|
|
// than, equal to, or greater than zero, depending on whether name1
|
193 |
|
|
// is lexicographically less than, equal to, or greater than name2,
|
194 |
|
|
// but characters are forced to lower-case prior to comparison.
|
195 |
|
|
//
|
196 |
|
|
//
|
197 |
|
|
|
198 |
|
|
return (strcasecmp(*((char **) name1), *((char **) name2)));
|
199 |
|
|
}
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
namespace {
|
203 |
|
|
|
204 |
|
|
// std::list::sort(with_stricmp_predicate) doesn't work with Solaris CC...
|
205 |
|
|
static void sort_strlist_stricmp(std::list<std::string>& l)
|
206 |
|
|
{
|
207 |
|
|
// sort strings ignoring case - easier for humans
|
208 |
|
|
struct posList {
|
209 |
|
|
const char* str;
|
210 |
|
|
std::list<std::string>::const_iterator pos;
|
211 |
|
|
};
|
212 |
|
|
posList* carr = new posList[l.size()];
|
213 |
|
|
size_t idx = 0;
|
214 |
|
|
for (std::list<std::string>::const_iterator iS = l.begin(); iS != l.end(); ++iS) {
|
215 |
|
|
carr[idx].pos = iS;
|
216 |
|
|
carr[idx++].str = iS->c_str();
|
217 |
|
|
}
|
218 |
|
|
qsort(&carr[0].str, idx, sizeof(posList), CaseInsensitiveSort);
|
219 |
|
|
std::list<std::string> lsort;
|
220 |
|
|
for (idx = 0; idx < l.size(); ++idx) {
|
221 |
|
|
lsort.push_back(*carr[idx].pos);
|
222 |
|
|
}
|
223 |
|
|
delete [] carr;
|
224 |
|
|
l.swap(lsort);
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
}
|
228 |
|
|
|
229 |
|
|
//______________________________________________________________________________
|
230 |
|
|
//
|
231 |
|
|
// THtml generated documentation is written to file by TDocOutput. So far only
|
232 |
|
|
// output of HTML is implemented. Customization of the output should be done
|
233 |
|
|
// with THtml's interfaces - TDocOutput should not be used nor re-implemented
|
234 |
|
|
// directly.
|
235 |
|
|
//
|
236 |
|
|
// TDocOutput generates the index tables:
|
237 |
|
|
// * classes (THtml invokes TClassDocOutput for each),
|
238 |
|
|
// * inheritance hierarchy,
|
239 |
|
|
// * types and typedefs,
|
240 |
|
|
// * libraries,
|
241 |
|
|
// * the product index, and
|
242 |
|
|
// * the module index (including the links to per-module documentation).
|
243 |
|
|
// It invokes AT&T's GraphViz tool (dot) if available; charts benefit a lot
|
244 |
|
|
// from it.
|
245 |
|
|
//
|
246 |
|
|
// TDocOutput also writes all pages' header and footer, which can be customized
|
247 |
|
|
// by calling THtml::SetHeader(), THtml::SetFooter().
|
248 |
|
|
//______________________________________________________________________________
|
249 |
|
|
|
250 |
|
|
ClassImp(TDocOutput)
|
251 |
|
|
|
252 |
|
|
//______________________________________________________________________________
|
253 |
|
|
TDocOutput::TDocOutput(THtml& html): fHtml(&html)
|
254 |
|
|
{}
|
255 |
|
|
|
256 |
|
|
//______________________________________________________________________________
|
257 |
|
|
TDocOutput::~TDocOutput()
|
258 |
|
|
{}
|
259 |
|
|
|
260 |
|
|
//______________________________________________________________________________
|
261 |
|
|
void TDocOutput::AddLink(TSubString& str, TString& link, const char* comment)
|
262 |
|
|
{
|
263 |
|
|
// Add a link around str, with title comment.
|
264 |
|
|
// Update str so it surrounds the link.
|
265 |
|
|
|
266 |
|
|
// prepend "./" to allow callers to replace a different relative directory
|
267 |
|
|
if (ReferenceIsRelative(link) && !link.BeginsWith("./"))
|
268 |
|
|
link.Prepend("./");
|
269 |
|
|
link.Prepend("<a href=\"");
|
270 |
|
|
link += "\"";
|
271 |
|
|
if (comment && strlen(comment)) {
|
272 |
|
|
link += " title=\"";
|
273 |
|
|
TString description(comment);
|
274 |
|
|
ReplaceSpecialChars(description);
|
275 |
|
|
description.ReplaceAll("\"", """);
|
276 |
|
|
link += description;
|
277 |
|
|
link += "\"";
|
278 |
|
|
}
|
279 |
|
|
link += ">";
|
280 |
|
|
|
281 |
|
|
str.String().Insert(str.Start() + str.Length(), "</a>");
|
282 |
|
|
str.String().Insert(str.Start(), link);
|
283 |
|
|
|
284 |
|
|
TString &strString = str.String();
|
285 |
|
|
TSubString update = strString(str.Start(), str.Length() + link.Length() + 4);
|
286 |
|
|
str = update;
|
287 |
|
|
}
|
288 |
|
|
|
289 |
|
|
//______________________________________________________________________________
|
290 |
|
|
void TDocOutput::AdjustSourcePath(TString& line, const char* relpath /*= "../"*/)
|
291 |
|
|
{
|
292 |
|
|
// adjust the path of links for source files, which are in src/, but need
|
293 |
|
|
// to point to relpath (usually "../"). Simply replaces "=\"./" by "=\"../"
|
294 |
|
|
|
295 |
|
|
TString replWithRelPath("=\"");
|
296 |
|
|
replWithRelPath += relpath;
|
297 |
|
|
line.ReplaceAll("=\"./", replWithRelPath);
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
//______________________________________________________________________________
|
301 |
|
|
void TDocOutput::Convert(std::istream& in, const char* infilename,
|
302 |
|
|
const char* outfilename, const char *title,
|
303 |
|
|
const char *relpath /*= "../"*/, Int_t includeOutput /*=0*/,
|
304 |
|
|
const char* context /*= ""*/,
|
305 |
|
|
TGClient* gclient /*= 0*/)
|
306 |
|
|
{
|
307 |
|
|
// Convert a text file into a html file.
|
308 |
|
|
// outfilename doesn't have an extension yet; up to us to decide.
|
309 |
|
|
// We generate HTML, so our extension is ".html".
|
310 |
|
|
// See THtml::Convert() for the other parameters.
|
311 |
|
|
|
312 |
|
|
TString htmlFilename(outfilename);
|
313 |
|
|
htmlFilename += ".html";
|
314 |
|
|
|
315 |
|
|
std::ofstream out(htmlFilename);
|
316 |
|
|
|
317 |
|
|
if (!out.good()) {
|
318 |
|
|
Error("Convert", "Can't open file '%s' !", htmlFilename.Data());
|
319 |
|
|
return;
|
320 |
|
|
}
|
321 |
|
|
|
322 |
|
|
// write a HTML header
|
323 |
|
|
WriteHtmlHeader(out, title, relpath);
|
324 |
|
|
|
325 |
|
|
if (context || context[0])
|
326 |
|
|
out << context << endl;
|
327 |
|
|
else if (title && title[0])
|
328 |
|
|
out << "<h1 class=\"convert\">" << title << "</h1>" << endl;
|
329 |
|
|
|
330 |
|
|
Int_t numReuseCanvases = 0;
|
331 |
|
|
if (includeOutput && !(includeOutput & THtml::kForceOutput)) {
|
332 |
|
|
void* dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
|
333 |
|
|
if (dirHandle) {
|
334 |
|
|
FileStat_t infile_stat;
|
335 |
|
|
if (!gSystem->GetPathInfo(infilename, infile_stat)) {
|
336 |
|
|
// can stat.
|
337 |
|
|
const char* outfile = 0;
|
338 |
|
|
TString firstCanvasFileBase(gSystem->BaseName(outfilename));
|
339 |
|
|
firstCanvasFileBase += "_0.png";
|
340 |
|
|
// first check whether the firstCanvasFile exists:
|
341 |
|
|
Bool_t haveFirstCanvasFile = false;
|
342 |
|
|
while ((outfile = gSystem->GetDirEntry(dirHandle))) {
|
343 |
|
|
if (firstCanvasFileBase == outfile) {
|
344 |
|
|
haveFirstCanvasFile = true;
|
345 |
|
|
break;
|
346 |
|
|
}
|
347 |
|
|
}
|
348 |
|
|
gSystem->FreeDirectory(dirHandle);
|
349 |
|
|
|
350 |
|
|
FileStat_t outfile_stat;
|
351 |
|
|
TString firstCanvasFile = outfilename;
|
352 |
|
|
firstCanvasFile += "_0.png";
|
353 |
|
|
Int_t maxIdx = -1;
|
354 |
|
|
if (haveFirstCanvasFile && !gSystem->GetPathInfo(firstCanvasFile, outfile_stat)
|
355 |
|
|
&& outfile_stat.fMtime > infile_stat.fMtime) {
|
356 |
|
|
// the first canvas file exists and it is newer than the script, so we reuse
|
357 |
|
|
// the canvas files. We need to know how many there are:
|
358 |
|
|
dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
|
359 |
|
|
TString stem(gSystem->BaseName(outfilename));
|
360 |
|
|
stem += "_";
|
361 |
|
|
TString dir(gSystem->DirName(htmlFilename));
|
362 |
|
|
while ((outfile = gSystem->GetDirEntry(dirHandle))) {
|
363 |
|
|
if (strncmp(outfile, stem, stem.Length()))
|
364 |
|
|
continue;
|
365 |
|
|
const char* posext = strrchr(outfile, '.');
|
366 |
|
|
if (!posext || strcmp(posext, ".png"))
|
367 |
|
|
continue;
|
368 |
|
|
|
369 |
|
|
// extract the mod time of the PNG file
|
370 |
|
|
if (gSystem->GetPathInfo(dir + "/" + outfile, outfile_stat))
|
371 |
|
|
// can't stat!
|
372 |
|
|
continue;
|
373 |
|
|
|
374 |
|
|
if (outfile_stat.fMtime > infile_stat.fMtime) {
|
375 |
|
|
++numReuseCanvases;
|
376 |
|
|
// The canvas PNG is newer than the script, so
|
377 |
|
|
// extract the index of the canvas
|
378 |
|
|
TString idxStr(outfile + stem.Length());
|
379 |
|
|
idxStr.Remove(idxStr.Length() - 4);
|
380 |
|
|
Int_t idx = idxStr.Atoi();
|
381 |
|
|
if (maxIdx < idx)
|
382 |
|
|
maxIdx = idx;
|
383 |
|
|
}
|
384 |
|
|
}
|
385 |
|
|
gSystem->FreeDirectory(dirHandle);
|
386 |
|
|
if (maxIdx + 1 != numReuseCanvases)
|
387 |
|
|
// bad: the number of canvases to reuse noes not correspond to the highest index we saw.
|
388 |
|
|
// we will need to regenerate evrything.
|
389 |
|
|
numReuseCanvases = 0;
|
390 |
|
|
}
|
391 |
|
|
} // infile can be stat'ed
|
392 |
|
|
} // can open output directory
|
393 |
|
|
} // canvases wanted
|
394 |
|
|
|
395 |
|
|
if (numReuseCanvases)
|
396 |
|
|
Printf("Convert: %s (reusing %d saved canvas%s)", htmlFilename.Data(), numReuseCanvases, (numReuseCanvases > 1 ? "es" : ""));
|
397 |
|
|
else
|
398 |
|
|
Printf("Convert: %s", htmlFilename.Data());
|
399 |
|
|
|
400 |
|
|
UInt_t nCanvases = numReuseCanvases;
|
401 |
|
|
if (includeOutput) {
|
402 |
|
|
if (!numReuseCanvases) {
|
403 |
|
|
// need to run the script
|
404 |
|
|
if (includeOutput & THtml::kSeparateProcessOutput) {
|
405 |
|
|
gSystem->Exec(TString::Format("ROOT_HIST=0 root.exe -l -q %s $ROOTSYS/etc/html/saveScriptOutput.C\\(\\\"%s\\\",\\\"%s\\\",%d\\)",
|
406 |
|
|
gROOT->IsBatch() ? "-b" : "",
|
407 |
|
|
infilename,
|
408 |
|
|
gSystem->DirName(outfilename),
|
409 |
|
|
includeOutput & THtml::kCompiledOutput));
|
410 |
|
|
} else {
|
411 |
|
|
// run in this ROOT process
|
412 |
|
|
TString pwd(gSystem->pwd());
|
413 |
|
|
gSystem->cd(gSystem->DirName(infilename));
|
414 |
|
|
|
415 |
|
|
TList* gClientGetListOfWindows = 0;
|
416 |
|
|
TObject* gClientGetDefaultRoot = 0;
|
417 |
|
|
std::set<TObject*> previousWindows;
|
418 |
|
|
if (gclient) {
|
419 |
|
|
gROOT->ProcessLine(TString::Format("*((TList**)0x%lx) = ((TGClient*)0x%lx)->GetListOfWindows();",
|
420 |
bendavid |
1.2 |
(ULong_t)&gClientGetListOfWindows, (ULong_t)gclient));
|
421 |
loizides |
1.1 |
gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGClient*)0x%lx)->GetDefaultRoot();",
|
422 |
bendavid |
1.2 |
(ULong_t)&gClientGetDefaultRoot, (ULong_t)gclient));
|
423 |
loizides |
1.1 |
TObject* win = 0;
|
424 |
|
|
TIter iWin(gClientGetListOfWindows);
|
425 |
|
|
while((win = iWin())) {
|
426 |
|
|
TObject* winGetParent = 0;
|
427 |
|
|
gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
|
428 |
bendavid |
1.2 |
(ULong_t)&winGetParent, (ULong_t)win));
|
429 |
loizides |
1.1 |
if (winGetParent == gClientGetDefaultRoot)
|
430 |
|
|
previousWindows.insert(win);
|
431 |
|
|
}
|
432 |
|
|
} else {
|
433 |
|
|
if (gROOT->GetListOfCanvases()->GetSize())
|
434 |
|
|
previousWindows.insert(gROOT->GetListOfCanvases()->Last());
|
435 |
|
|
}
|
436 |
|
|
TIter iTimer(gSystem->GetListOfTimers());
|
437 |
|
|
std::set<TObject*> timersBefore;
|
438 |
|
|
TObject* timerOld = 0;
|
439 |
|
|
while ((timerOld = iTimer()))
|
440 |
|
|
timersBefore.insert(timerOld);
|
441 |
|
|
|
442 |
|
|
TString cmd(".x ");
|
443 |
|
|
cmd += gSystem->BaseName(infilename);
|
444 |
|
|
if (includeOutput & THtml::kCompiledOutput)
|
445 |
|
|
cmd += "+";
|
446 |
|
|
gInterpreter->SaveContext();
|
447 |
|
|
gInterpreter->SaveGlobalsContext();
|
448 |
|
|
Int_t err;
|
449 |
|
|
gROOT->ProcessLine(cmd, &err);
|
450 |
|
|
gSystem->cd(pwd);
|
451 |
|
|
|
452 |
|
|
if (err == TInterpreter::kNoError) {
|
453 |
|
|
if (gclient) {
|
454 |
|
|
TClass* clRootCanvas = TClass::GetClass("TRootCanvas");
|
455 |
|
|
TClass* clGMainFrame = TClass::GetClass("TGMainFrame");
|
456 |
|
|
TObject* win = 0;
|
457 |
|
|
TIter iWin(gClientGetListOfWindows);
|
458 |
|
|
while((win = iWin())) {
|
459 |
|
|
TObject* winGetParent = 0;
|
460 |
|
|
gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
|
461 |
bendavid |
1.2 |
(ULong_t)&winGetParent, (ULong_t)win));
|
462 |
loizides |
1.1 |
Bool_t winIsMapped = kFALSE;
|
463 |
|
|
if (winGetParent == gClientGetDefaultRoot)
|
464 |
|
|
gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TGWindow*)0x%lx)->IsMapped();",
|
465 |
bendavid |
1.2 |
(ULong_t)&winIsMapped, (ULong_t)win));
|
466 |
loizides |
1.1 |
if (winIsMapped && previousWindows.find(win) == previousWindows.end()
|
467 |
|
|
&& win->InheritsFrom(clGMainFrame)) {
|
468 |
bendavid |
1.2 |
gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->MapRaised();", (ULong_t)win));
|
469 |
loizides |
1.1 |
Bool_t isRootCanvas = win->InheritsFrom(clRootCanvas);
|
470 |
|
|
Bool_t hasEditor = false;
|
471 |
|
|
if (isRootCanvas) {
|
472 |
|
|
gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TRootCanvas*)0x%lx)->HasEditor();",
|
473 |
bendavid |
1.2 |
(ULong_t)&hasEditor, (ULong_t)win));
|
474 |
loizides |
1.1 |
}
|
475 |
|
|
if (isRootCanvas && !hasEditor) {
|
476 |
|
|
TVirtualPad* pad = 0;
|
477 |
|
|
gROOT->ProcessLine(TString::Format("*((TVirtualPad**)0x%lx) = ((TRootCanvas*)0x%lx)->Canvas();",
|
478 |
bendavid |
1.2 |
(ULong_t)&pad, (ULong_t)win));
|
479 |
loizides |
1.1 |
if (!pad->HasViewer3D() || pad->GetViewer3D()->InheritsFrom("TViewer3DPad")) {
|
480 |
|
|
pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
|
481 |
|
|
}
|
482 |
|
|
} else
|
483 |
|
|
gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->SaveAs(\"%s_%d.png\");",
|
484 |
bendavid |
1.2 |
(ULong_t)win, outfilename, nCanvases++));
|
485 |
loizides |
1.1 |
}
|
486 |
|
|
}
|
487 |
|
|
} else {
|
488 |
|
|
// no gClient
|
489 |
|
|
TVirtualPad* pad = 0;
|
490 |
|
|
TVirtualPad* last = 0;
|
491 |
|
|
if (!previousWindows.empty())
|
492 |
|
|
last = (TVirtualPad*) *previousWindows.begin();
|
493 |
|
|
TIter iCanvas(gROOT->GetListOfCanvases());
|
494 |
|
|
while ((pad = (TVirtualPad*) iCanvas())) {
|
495 |
|
|
if (last) {
|
496 |
|
|
if (last == pad) last = 0;
|
497 |
|
|
continue;
|
498 |
|
|
}
|
499 |
|
|
pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
|
500 |
|
|
}
|
501 |
|
|
}
|
502 |
|
|
gInterpreter->Reset();
|
503 |
|
|
gInterpreter->ResetGlobals();
|
504 |
|
|
TIter iTimerRemove(gSystem->GetListOfTimers());
|
505 |
|
|
TTimer* timer = 0;
|
506 |
|
|
while ((timer = (TTimer*) iTimerRemove()))
|
507 |
|
|
if (timersBefore.find(timer) == timersBefore.end())
|
508 |
|
|
gSystem->RemoveTimer(timer);
|
509 |
|
|
}
|
510 |
|
|
} // run script in this ROOT process
|
511 |
|
|
}
|
512 |
|
|
out << "<table><tr><td style=\"vertical-align:top;padding-right:2em;\">" << endl;
|
513 |
|
|
}
|
514 |
|
|
out << "<pre>" << endl;
|
515 |
|
|
|
516 |
|
|
TDocParser parser(*this);
|
517 |
|
|
parser.Convert(out, in, relpath, (includeOutput) /* determines whether it's code or not */);
|
518 |
|
|
|
519 |
|
|
out << "</pre>" << endl;
|
520 |
|
|
|
521 |
|
|
if (includeOutput) {
|
522 |
|
|
out << "</td><td style=\"vertical-align:top;\">" << endl;
|
523 |
|
|
out << "<table>" << endl;
|
524 |
|
|
for (UInt_t i = 0; i < nCanvases; ++i) {
|
525 |
|
|
TString pngname = TString::Format("%s_%d.png", gSystem->BaseName(outfilename), i);
|
526 |
|
|
out << "<tr><td><a href=\"" << pngname << "\">" << endl
|
527 |
|
|
<< "<img src=\"" << pngname << "\" id=\"canv" << i << "\" alt=\"thumb\" style=\"border:none;width:22em;\" "
|
528 |
|
|
"onmouseover=\"javascript:canv" << i << ".style.width='auto';\" />" << endl
|
529 |
|
|
<< "</a></td></tr>" << endl;
|
530 |
|
|
}
|
531 |
|
|
out << "</table>" << endl;
|
532 |
|
|
out << "</td></tr></table>" << endl;
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
// write a HTML footer
|
536 |
|
|
WriteHtmlFooter(out, relpath);
|
537 |
|
|
}
|
538 |
|
|
|
539 |
|
|
//______________________________________________________________________________
|
540 |
|
|
Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName)
|
541 |
|
|
{
|
542 |
|
|
// Copy file to HTML directory
|
543 |
|
|
//
|
544 |
|
|
//
|
545 |
|
|
// Input: sourceName - source file name (fully qualified i.e. file system path)
|
546 |
|
|
// destName - optional destination name, if not
|
547 |
|
|
// specified it would be the same
|
548 |
|
|
// as the source file name
|
549 |
|
|
//
|
550 |
|
|
// Output: TRUE if file is successfully copied, or
|
551 |
|
|
// FALSE if it's not
|
552 |
|
|
//
|
553 |
|
|
//
|
554 |
|
|
// NOTE: The destination directory is always fHtml->GetOutputDir()
|
555 |
|
|
//
|
556 |
|
|
|
557 |
|
|
R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
|
558 |
|
|
|
559 |
|
|
TString sourceFile(sourceName);
|
560 |
|
|
|
561 |
|
|
if (!sourceFile.Length()) {
|
562 |
|
|
Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName,
|
563 |
|
|
fHtml->GetOutputDir().Data());
|
564 |
|
|
return kFALSE;
|
565 |
|
|
}
|
566 |
|
|
|
567 |
|
|
// destination file name
|
568 |
|
|
TString destFile;
|
569 |
|
|
if (!destName || !*destName)
|
570 |
|
|
destFile = gSystem->BaseName(sourceFile);
|
571 |
|
|
else
|
572 |
|
|
destFile = gSystem->BaseName(destName);
|
573 |
|
|
|
574 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), destFile);
|
575 |
|
|
|
576 |
|
|
// Get info about a file
|
577 |
|
|
Long64_t size;
|
578 |
|
|
Long_t id, flags, sModtime, dModtime;
|
579 |
|
|
sModtime = 0;
|
580 |
|
|
dModtime = 0;
|
581 |
|
|
if (gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)
|
582 |
|
|
|| gSystem->GetPathInfo(destFile, &id, &size, &flags, &dModtime)
|
583 |
|
|
|| sModtime > dModtime)
|
584 |
|
|
gSystem->CopyFile(sourceFile, destFile, kTRUE);
|
585 |
|
|
|
586 |
|
|
return kTRUE;
|
587 |
|
|
}
|
588 |
|
|
|
589 |
|
|
|
590 |
|
|
|
591 |
|
|
//______________________________________________________________________________
|
592 |
|
|
void TDocOutput::CreateHierarchy()
|
593 |
|
|
{
|
594 |
|
|
// Create a hierarchical class list
|
595 |
|
|
// The algorithm descends from the base classes and branches into
|
596 |
|
|
// all derived classes. Mixing classes are displayed several times.
|
597 |
|
|
//
|
598 |
|
|
//
|
599 |
|
|
|
600 |
|
|
// if (CreateHierarchyDot()) return;
|
601 |
|
|
|
602 |
|
|
TString filename("ClassHierarchy.html");
|
603 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
604 |
|
|
|
605 |
|
|
// open out file
|
606 |
|
|
std::ofstream out(filename);
|
607 |
|
|
|
608 |
|
|
if (!out.good()) {
|
609 |
|
|
Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
|
610 |
|
|
return;
|
611 |
|
|
}
|
612 |
|
|
|
613 |
|
|
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
|
614 |
|
|
|
615 |
|
|
// write out header
|
616 |
|
|
WriteHtmlHeader(out, "Class Hierarchy");
|
617 |
|
|
|
618 |
|
|
WriteTopLinks(out, 0);
|
619 |
|
|
out << "</div></div>" << endl;
|
620 |
|
|
|
621 |
|
|
out << "<h1>Class Hierarchy</h1>" << endl;
|
622 |
|
|
|
623 |
|
|
|
624 |
|
|
// loop on all classes
|
625 |
|
|
TClassDocInfo* cdi = 0;
|
626 |
|
|
TIter iClass(fHtml->GetListOfClasses());
|
627 |
|
|
while ((cdi = (TClassDocInfo*)iClass())) {
|
628 |
|
|
if (!cdi->HaveSource())
|
629 |
|
|
continue;
|
630 |
|
|
|
631 |
|
|
// get class
|
632 |
|
|
TDictionary *dictPtr = cdi->GetClass();
|
633 |
|
|
TClass *basePtr = dynamic_cast<TClass*>(dictPtr);
|
634 |
|
|
if (basePtr == 0) {
|
635 |
|
|
if (!dictPtr)
|
636 |
|
|
Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
|
637 |
|
|
continue;
|
638 |
|
|
}
|
639 |
|
|
|
640 |
|
|
TClassDocOutput cdo(*fHtml, basePtr, 0);
|
641 |
|
|
cdo.CreateClassHierarchy(out, cdi->GetHtmlFileName());
|
642 |
|
|
}
|
643 |
|
|
|
644 |
|
|
// write out footer
|
645 |
|
|
WriteHtmlFooter(out);
|
646 |
|
|
}
|
647 |
|
|
|
648 |
|
|
//______________________________________________________________________________
|
649 |
|
|
void TDocOutput::CreateClassIndex()
|
650 |
|
|
{
|
651 |
|
|
// Create index of all classes
|
652 |
|
|
//
|
653 |
|
|
|
654 |
|
|
// create CSS file, we need it
|
655 |
|
|
fHtml->CreateAuxiliaryFiles();
|
656 |
|
|
|
657 |
|
|
TString filename("ClassIndex.html");
|
658 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
659 |
|
|
|
660 |
|
|
// open indexFile file
|
661 |
|
|
std::ofstream indexFile(filename.Data());
|
662 |
|
|
|
663 |
|
|
if (!indexFile.good()) {
|
664 |
|
|
Error("CreateClassIndex", "Can't open file '%s' !", filename.Data());
|
665 |
|
|
return;
|
666 |
|
|
}
|
667 |
|
|
|
668 |
|
|
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
|
669 |
|
|
|
670 |
|
|
// write indexFile header
|
671 |
|
|
WriteHtmlHeader(indexFile, "Class Index");
|
672 |
|
|
|
673 |
|
|
WriteTopLinks(indexFile, 0);
|
674 |
|
|
indexFile << "</div></div>" << endl;
|
675 |
|
|
|
676 |
|
|
indexFile << "<h1>Class Index</h1>" << endl;
|
677 |
|
|
|
678 |
|
|
WriteModuleLinks(indexFile);
|
679 |
|
|
|
680 |
|
|
std::vector<std::string> indexChars;
|
681 |
|
|
if (fHtml->GetListOfClasses()->GetSize() > 10) {
|
682 |
|
|
std::vector<std::string> classNames;
|
683 |
|
|
{
|
684 |
|
|
TIter iClass(fHtml->GetListOfClasses());
|
685 |
|
|
TClassDocInfo* cdi = 0;
|
686 |
|
|
while ((cdi = (TClassDocInfo*)iClass()))
|
687 |
|
|
if (cdi->IsSelected() && cdi->HaveSource())
|
688 |
|
|
classNames.push_back(cdi->GetName());
|
689 |
|
|
}
|
690 |
|
|
|
691 |
|
|
if (classNames.size() > 10) {
|
692 |
|
|
indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
|
693 |
|
|
// find index chars
|
694 |
|
|
GetIndexChars(classNames, 50 /*sections*/, indexChars);
|
695 |
|
|
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
|
696 |
|
|
indexFile << "<a href=\"#idx" << iIdxEntry << "\">";
|
697 |
|
|
ReplaceSpecialChars(indexFile, indexChars[iIdxEntry].c_str());
|
698 |
|
|
indexFile << "</a>" << endl;
|
699 |
|
|
}
|
700 |
|
|
indexFile << "</div><br />" << endl;
|
701 |
|
|
}
|
702 |
|
|
}
|
703 |
|
|
|
704 |
|
|
indexFile << "<ul id=\"indx\">" << endl;
|
705 |
|
|
|
706 |
|
|
// loop on all classes
|
707 |
|
|
UInt_t currentIndexEntry = 0;
|
708 |
|
|
TIter iClass(fHtml->GetListOfClasses());
|
709 |
|
|
TClassDocInfo* cdi = 0;
|
710 |
|
|
Int_t i = 0;
|
711 |
|
|
while ((cdi = (TClassDocInfo*)iClass())) {
|
712 |
|
|
if (!cdi->IsSelected() || !cdi->HaveSource())
|
713 |
|
|
continue;
|
714 |
|
|
|
715 |
|
|
// get class
|
716 |
|
|
TDictionary *currentDict = cdi->GetClass();
|
717 |
|
|
TClass* currentClass = dynamic_cast<TClass*>(currentDict);
|
718 |
|
|
if (!currentClass) {
|
719 |
|
|
if (!currentDict)
|
720 |
|
|
Warning("THtml::CreateClassIndex", "skipping class %s\n", cdi->GetName());
|
721 |
|
|
continue;
|
722 |
|
|
}
|
723 |
|
|
|
724 |
|
|
indexFile << "<li class=\"idxl" << (i++)%2 << "\">";
|
725 |
|
|
if (currentIndexEntry < indexChars.size()
|
726 |
|
|
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
|
727 |
|
|
indexChars[currentIndexEntry].length()))
|
728 |
|
|
indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
|
729 |
|
|
|
730 |
|
|
TString htmlFile(cdi->GetHtmlFileName());
|
731 |
|
|
if (htmlFile.Length()) {
|
732 |
|
|
indexFile << "<a href=\"";
|
733 |
|
|
indexFile << htmlFile;
|
734 |
|
|
indexFile << "\"><span class=\"typename\">";
|
735 |
|
|
ReplaceSpecialChars(indexFile, cdi->GetName());
|
736 |
|
|
indexFile << "</span></a> ";
|
737 |
|
|
} else {
|
738 |
|
|
indexFile << "<span class=\"typename\">";
|
739 |
|
|
ReplaceSpecialChars(indexFile, cdi->GetName());
|
740 |
|
|
indexFile << "</span> ";
|
741 |
|
|
}
|
742 |
|
|
|
743 |
|
|
// write title == short doc
|
744 |
|
|
ReplaceSpecialChars(indexFile, currentClass->GetTitle());
|
745 |
|
|
indexFile << "</li>" << endl;
|
746 |
|
|
}
|
747 |
|
|
|
748 |
|
|
indexFile << "</ul>" << endl;
|
749 |
|
|
|
750 |
|
|
// write indexFile footer
|
751 |
|
|
WriteHtmlFooter(indexFile);
|
752 |
|
|
}
|
753 |
|
|
|
754 |
|
|
|
755 |
|
|
//______________________________________________________________________________
|
756 |
|
|
void TDocOutput::CreateModuleIndex()
|
757 |
|
|
{
|
758 |
|
|
// Create the class index for each module, picking up documentation from the
|
759 |
|
|
// module's TModuleDocInfo::GetInputPath() plus the (possibly relative)
|
760 |
|
|
// THtml::GetModuleDocPath(). Also creates the library dependency plot if dot
|
761 |
|
|
// exists, see THtml::HaveDot().
|
762 |
|
|
|
763 |
|
|
const char* title = "LibraryDependencies";
|
764 |
|
|
TString dotfilename(title);
|
765 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), dotfilename);
|
766 |
|
|
|
767 |
|
|
std::ofstream libDepDotFile(dotfilename + ".dot");
|
768 |
|
|
libDepDotFile << "digraph G {" << endl
|
769 |
|
|
<< "ratio=compress;" << endl
|
770 |
|
|
<< "node [fontsize=22,labeldistance=0.1];" << endl
|
771 |
|
|
<< "edge [len=0.01];" << endl
|
772 |
|
|
<< "fontsize=22;" << endl
|
773 |
|
|
<< "size=\"16,16\";" << endl
|
774 |
|
|
<< "overlap=false;" << endl
|
775 |
|
|
<< "splines=true;" << endl
|
776 |
|
|
<< "K=0.1;" << endl;
|
777 |
|
|
|
778 |
|
|
TModuleDocInfo* module = 0;
|
779 |
|
|
TIter iterModule(fHtml->GetListOfModules());
|
780 |
|
|
|
781 |
|
|
std::stringstream sstrCluster;
|
782 |
|
|
std::stringstream sstrDeps;
|
783 |
|
|
while ((module = (TModuleDocInfo*)iterModule())) {
|
784 |
|
|
if (!module->IsSelected())
|
785 |
|
|
continue;
|
786 |
|
|
|
787 |
|
|
std::vector<std::string> indexChars;
|
788 |
|
|
TString filename(module->GetName());
|
789 |
|
|
filename.ToUpper();
|
790 |
|
|
filename.ReplaceAll("/","_");
|
791 |
|
|
filename += "_Index.html";
|
792 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
793 |
|
|
std::ofstream outputFile(filename.Data());
|
794 |
|
|
if (!outputFile.good()) {
|
795 |
|
|
Error("CreateModuleIndex", "Can't open file '%s' !", filename.Data());
|
796 |
|
|
continue;
|
797 |
|
|
}
|
798 |
|
|
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
|
799 |
|
|
|
800 |
|
|
TString htmltitle("Index of ");
|
801 |
|
|
TString moduletitle(module->GetName());
|
802 |
|
|
moduletitle.ToUpper();
|
803 |
|
|
htmltitle += moduletitle;
|
804 |
|
|
WriteHtmlHeader(outputFile, htmltitle);
|
805 |
|
|
|
806 |
|
|
WriteTopLinks(outputFile, module);
|
807 |
|
|
outputFile << "</div></div>" << endl;
|
808 |
|
|
|
809 |
|
|
outputFile << "<h2>" << htmltitle << "</h2>" << endl;
|
810 |
|
|
|
811 |
|
|
// Module doc
|
812 |
|
|
if (GetHtml()->GetModuleDocPath().Length()) {
|
813 |
|
|
TString outdir(module->GetName());
|
814 |
|
|
gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir);
|
815 |
|
|
|
816 |
|
|
TString moduleDocDir;
|
817 |
|
|
GetHtml()->GetPathDefinition().GetDocDir(module->GetName(), moduleDocDir);
|
818 |
|
|
ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName());
|
819 |
|
|
}
|
820 |
|
|
|
821 |
|
|
WriteModuleLinks(outputFile, module);
|
822 |
|
|
|
823 |
|
|
std::list<std::string> classNames;
|
824 |
|
|
{
|
825 |
|
|
TIter iClass(module->GetClasses());
|
826 |
|
|
TClassDocInfo* cdi = 0;
|
827 |
|
|
while ((cdi = (TClassDocInfo*) iClass())) {
|
828 |
|
|
if (!cdi->IsSelected() || !cdi->HaveSource())
|
829 |
|
|
continue;
|
830 |
|
|
classNames.push_back(cdi->GetName());
|
831 |
|
|
|
832 |
|
|
if (classNames.size() > 1) continue;
|
833 |
|
|
|
834 |
|
|
TClass* cdiClass = dynamic_cast<TClass*>(cdi->GetClass());
|
835 |
|
|
if (!cdiClass)
|
836 |
|
|
continue;
|
837 |
|
|
|
838 |
|
|
TString libs(cdiClass->GetSharedLibs());
|
839 |
|
|
Ssiz_t posDepLibs = libs.Index(' ');
|
840 |
|
|
TString thisLib(libs);
|
841 |
|
|
if (posDepLibs != kNPOS)
|
842 |
|
|
thisLib.Remove(posDepLibs, thisLib.Length());
|
843 |
|
|
|
844 |
|
|
{
|
845 |
|
|
Ssiz_t posExt = thisLib.First('.');
|
846 |
|
|
if (posExt != kNPOS)
|
847 |
|
|
thisLib.Remove(posExt, thisLib.Length());
|
848 |
|
|
}
|
849 |
|
|
|
850 |
|
|
if (!thisLib.Length())
|
851 |
|
|
continue;
|
852 |
|
|
|
853 |
|
|
// allocate entry, even if no dependencies
|
854 |
|
|
TLibraryDocInfo *libdeps =
|
855 |
|
|
(TLibraryDocInfo*)fHtml->GetLibraryDependencies()->FindObject(thisLib);
|
856 |
|
|
if (!libdeps) {
|
857 |
|
|
libdeps = new TLibraryDocInfo(thisLib);
|
858 |
|
|
fHtml->GetLibraryDependencies()->Add(libdeps);
|
859 |
|
|
}
|
860 |
|
|
libdeps->AddModule(module->GetName());
|
861 |
|
|
if (posDepLibs != kNPOS) {
|
862 |
|
|
std::string lib;
|
863 |
|
|
for(Ssiz_t pos = posDepLibs + 1; libs[pos]; ++pos) {
|
864 |
|
|
if (libs[pos] == ' ') {
|
865 |
|
|
if (thisLib.Length() && lib.length()) {
|
866 |
|
|
size_t posExt = lib.find('.');
|
867 |
|
|
if (posExt != std::string::npos)
|
868 |
|
|
lib.erase(posExt);
|
869 |
|
|
libdeps->AddDependency(lib);
|
870 |
|
|
}
|
871 |
|
|
lib.erase();
|
872 |
|
|
} else
|
873 |
|
|
lib += libs[pos];
|
874 |
|
|
}
|
875 |
|
|
if (lib.length() && thisLib.Length()) {
|
876 |
|
|
size_t posExt = lib.find('.');
|
877 |
|
|
if (posExt != std::string::npos)
|
878 |
|
|
lib.erase(posExt);
|
879 |
|
|
libdeps->AddDependency(lib);
|
880 |
|
|
}
|
881 |
|
|
} // if dependencies
|
882 |
|
|
} // while next class in module
|
883 |
|
|
} // just a scope block
|
884 |
|
|
|
885 |
|
|
TIter iClass(module->GetClasses());
|
886 |
|
|
TClassDocInfo* cdi = 0;
|
887 |
|
|
UInt_t count = 0;
|
888 |
|
|
UInt_t currentIndexEntry = 0;
|
889 |
|
|
while ((cdi = (TClassDocInfo*) iClass())) {
|
890 |
|
|
if (!cdi->IsSelected() || !cdi->HaveSource())
|
891 |
|
|
continue;
|
892 |
|
|
|
893 |
|
|
TDictionary *classPtr = cdi->GetClass();
|
894 |
|
|
if (!classPtr) {
|
895 |
|
|
Error("CreateModuleIndex", "Unknown class '%s' !", cdi->GetName());
|
896 |
|
|
continue;
|
897 |
|
|
}
|
898 |
|
|
|
899 |
|
|
if (!count) {
|
900 |
|
|
outputFile << "<h2>Class Index</h2>" << endl;
|
901 |
|
|
|
902 |
|
|
if (classNames.size() > 10) {
|
903 |
|
|
outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
|
904 |
|
|
UInt_t numSections = classNames.size() / 10;
|
905 |
|
|
if (numSections < 10) numSections = 10;
|
906 |
|
|
if (numSections > 50) numSections = 50;
|
907 |
|
|
// find index chars
|
908 |
|
|
GetIndexChars(classNames, numSections, indexChars);
|
909 |
|
|
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
|
910 |
|
|
outputFile << "<a href=\"#idx" << iIdxEntry << "\">";
|
911 |
|
|
ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str());
|
912 |
|
|
outputFile << "</a>" << endl;
|
913 |
|
|
}
|
914 |
|
|
outputFile << "</div><br />" << endl;
|
915 |
|
|
}
|
916 |
|
|
|
917 |
|
|
outputFile << "<ul id=\"indx\">" << endl;
|
918 |
|
|
}
|
919 |
|
|
|
920 |
|
|
// write a classname to an index file
|
921 |
|
|
outputFile << "<li class=\"idxl" << (count++)%2 << "\">";
|
922 |
|
|
if (currentIndexEntry < indexChars.size()
|
923 |
|
|
&& !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
|
924 |
|
|
indexChars[currentIndexEntry].length()))
|
925 |
|
|
outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
|
926 |
|
|
|
927 |
|
|
TString htmlFile(cdi->GetHtmlFileName());
|
928 |
|
|
if (htmlFile.Length()) {
|
929 |
|
|
outputFile << "<a href=\"";
|
930 |
|
|
outputFile << htmlFile;
|
931 |
|
|
outputFile << "\"><span class=\"typename\">";
|
932 |
|
|
ReplaceSpecialChars(outputFile, classPtr->GetName());
|
933 |
|
|
outputFile << "</span></a> ";
|
934 |
|
|
} else {
|
935 |
|
|
outputFile << "<span class=\"typename\">";
|
936 |
|
|
ReplaceSpecialChars(outputFile, classPtr->GetName());
|
937 |
|
|
outputFile << "</span> ";
|
938 |
|
|
}
|
939 |
|
|
|
940 |
|
|
// write title
|
941 |
|
|
ReplaceSpecialChars(outputFile, classPtr->GetTitle());
|
942 |
|
|
outputFile << "</li>" << endl;
|
943 |
|
|
}
|
944 |
|
|
|
945 |
|
|
|
946 |
|
|
if (count)
|
947 |
|
|
outputFile << "</ul>" << endl;
|
948 |
|
|
|
949 |
|
|
// write outputFile footer
|
950 |
|
|
WriteHtmlFooter(outputFile);
|
951 |
|
|
} // while next module
|
952 |
|
|
|
953 |
|
|
// libCint is missing as we don't have class doc for it
|
954 |
|
|
// We need it for dependencies nevertheless, so add it by hand.
|
955 |
|
|
/*
|
956 |
|
|
sstrCluster << "subgraph clusterlibCint {" << endl
|
957 |
|
|
<< "style=filled;" << endl
|
958 |
|
|
<< "color=lightgray;" << endl
|
959 |
|
|
<< "label=\"libCint\";" << endl
|
960 |
|
|
<< "\"CINT\" [style=filled,color=white,fontsize=10]" << endl
|
961 |
|
|
<< "}" << endl;
|
962 |
|
|
*/
|
963 |
|
|
|
964 |
|
|
// simplify the library dependencies, by removing direct links
|
965 |
|
|
// that are equivalent to indirect ones, e.g. instead of having both
|
966 |
|
|
// A->C, A->B->C, keep only A->B->C.
|
967 |
|
|
|
968 |
|
|
TIter iLib(fHtml->GetLibraryDependencies());
|
969 |
|
|
TLibraryDocInfo* libinfo = 0;
|
970 |
|
|
while ((libinfo = (TLibraryDocInfo*)iLib())) {
|
971 |
|
|
if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
|
972 |
|
|
|
973 |
|
|
std::set<std::string>& deps = libinfo->GetDependencies();
|
974 |
|
|
for (std::set<std::string>::iterator iDep = deps.begin();
|
975 |
|
|
iDep != deps.end(); ++iDep) {
|
976 |
|
|
Bool_t already_indirect = kFALSE;
|
977 |
|
|
for (std::set<std::string>::const_iterator iDep2 = deps.begin();
|
978 |
|
|
!already_indirect && iDep2 != deps.end(); ++iDep2) {
|
979 |
|
|
if (iDep == iDep2) continue;
|
980 |
|
|
TLibraryDocInfo* libinfo2 = (TLibraryDocInfo*)
|
981 |
|
|
fHtml->GetLibraryDependencies()->FindObject(iDep2->c_str());
|
982 |
|
|
if (!libinfo2) continue;
|
983 |
|
|
const std::set<std::string>& deps2 = libinfo2->GetDependencies();
|
984 |
|
|
already_indirect |= deps2.find(*iDep) != deps2.end();
|
985 |
|
|
}
|
986 |
|
|
if (already_indirect) {
|
987 |
|
|
std::set<std::string>::iterator iRemove = iDep;
|
988 |
|
|
--iDep; // otherwise we cannot do the for loop's ++iDep
|
989 |
|
|
deps.erase(*iRemove);
|
990 |
|
|
}
|
991 |
|
|
} // for library dependencies of module in library
|
992 |
|
|
} // for libaries
|
993 |
|
|
|
994 |
|
|
iLib.Reset();
|
995 |
|
|
while ((libinfo = (TLibraryDocInfo*)iLib())) {
|
996 |
|
|
if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
|
997 |
|
|
|
998 |
|
|
const std::set<std::string>& modules = libinfo->GetModules();
|
999 |
|
|
if (modules.size() > 1) {
|
1000 |
|
|
sstrCluster << "subgraph cluster" << libinfo->GetName() << " {" << endl
|
1001 |
|
|
<< "style=filled;" << endl
|
1002 |
|
|
<< "color=lightgray;" << endl
|
1003 |
|
|
<< "label=\"";
|
1004 |
|
|
if (!strcmp(libinfo->GetName(), "libCore"))
|
1005 |
|
|
sstrCluster << "Everything depends on ";
|
1006 |
|
|
sstrCluster << libinfo->GetName() << "\";" << endl;
|
1007 |
|
|
|
1008 |
|
|
for (std::set<std::string>::const_iterator iModule = modules.begin();
|
1009 |
|
|
iModule != modules.end(); ++iModule) {
|
1010 |
|
|
sstrCluster << "\"" << *iModule << "\" [style=filled,color=white,URL=\""
|
1011 |
|
|
<< *iModule << "_Index.html\"];" << endl;
|
1012 |
|
|
}
|
1013 |
|
|
sstrCluster << endl
|
1014 |
|
|
<< "}" << endl;
|
1015 |
|
|
} else {
|
1016 |
|
|
// only one module
|
1017 |
|
|
sstrCluster << "\"" << *modules.begin()
|
1018 |
|
|
<< "\" [label=\"" << libinfo->GetName()
|
1019 |
|
|
<< "\",style=filled,color=lightgray,shape=box,URL=\""
|
1020 |
|
|
<< *modules.begin() << "_Index.html\"];" << endl;
|
1021 |
|
|
}
|
1022 |
|
|
|
1023 |
|
|
// GetSharedLib doesn't mention libCore or libCint; add them by hand
|
1024 |
|
|
/*
|
1025 |
|
|
if (iLibDep->first != "libCore")
|
1026 |
|
|
sstrDeps << "\"" << iModule->first << "\" -> \"BASE\" [lhead=clusterlibCore];" << endl;
|
1027 |
|
|
sstrDeps << "\"" << iModule->first << "\" -> \"CINT\" [lhead=clusterlibCint];" << endl;
|
1028 |
|
|
*/
|
1029 |
|
|
|
1030 |
|
|
const std::string& mod = *(modules.begin());
|
1031 |
|
|
const std::set<std::string>& deps = libinfo->GetDependencies();
|
1032 |
|
|
for (std::set<std::string>::const_iterator iDep = deps.begin();
|
1033 |
|
|
iDep != deps.end(); ++iDep) {
|
1034 |
|
|
// cannot create dependency on iDep directly, use its first module instead.
|
1035 |
|
|
TLibraryDocInfo* depLibInfo = (TLibraryDocInfo*)
|
1036 |
|
|
fHtml->GetLibraryDependencies()->FindObject(iDep->c_str());
|
1037 |
|
|
if (!depLibInfo || depLibInfo->GetModules().empty())
|
1038 |
|
|
continue; // ouch!
|
1039 |
|
|
|
1040 |
|
|
const std::string& moddep = *(depLibInfo->GetModules().begin());
|
1041 |
|
|
sstrDeps << "\"" << mod << "\" -> \"" << moddep << "\";" << endl;
|
1042 |
|
|
}
|
1043 |
|
|
// make sure libCore ends up at the bottom
|
1044 |
|
|
sstrDeps << "\"" << mod << "\" -> \"CONT\" [style=invis];" << endl;
|
1045 |
|
|
} // for libs
|
1046 |
|
|
|
1047 |
|
|
libDepDotFile << sstrCluster.str() << endl
|
1048 |
|
|
<< sstrDeps.str();
|
1049 |
|
|
libDepDotFile << "}" << endl;
|
1050 |
|
|
libDepDotFile.close();
|
1051 |
|
|
|
1052 |
|
|
std::ofstream out(dotfilename + ".html");
|
1053 |
|
|
if (!out.good()) {
|
1054 |
|
|
Error("CreateModuleIndex", "Can't open file '%s.html' !",
|
1055 |
|
|
dotfilename.Data());
|
1056 |
|
|
return;
|
1057 |
|
|
}
|
1058 |
|
|
|
1059 |
|
|
Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (dotfilename + ".html").Data());
|
1060 |
|
|
// write out header
|
1061 |
|
|
WriteHtmlHeader(out, "Library Dependencies");
|
1062 |
|
|
|
1063 |
|
|
WriteTopLinks(out, 0);
|
1064 |
|
|
out << "</div></div>" << endl;
|
1065 |
|
|
|
1066 |
|
|
out << "<h1>Library Dependencies</h1>" << endl;
|
1067 |
|
|
|
1068 |
|
|
RunDot(dotfilename, &out, kFdp);
|
1069 |
|
|
|
1070 |
|
|
out << "<img alt=\"Library Dependencies\" class=\"classcharts\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
|
1071 |
|
|
|
1072 |
|
|
// write out footer
|
1073 |
|
|
WriteHtmlFooter(out);
|
1074 |
|
|
}
|
1075 |
|
|
|
1076 |
|
|
//______________________________________________________________________________
|
1077 |
|
|
void TDocOutput::CreateProductIndex()
|
1078 |
|
|
{
|
1079 |
|
|
// Fetch documentation from THtml::GetProductDocDir() and put it into the
|
1080 |
|
|
// product index page.
|
1081 |
|
|
|
1082 |
|
|
//TString outFile(GetHtml()->GetProductName());
|
1083 |
|
|
//outFile += ".html";
|
1084 |
|
|
TString outFile("index.html");
|
1085 |
|
|
gSystem->PrependPathName(GetHtml()->GetOutputDir(), outFile);
|
1086 |
|
|
std::ofstream out(outFile);
|
1087 |
|
|
|
1088 |
|
|
if (!out.good()) {
|
1089 |
|
|
Error("CreateProductIndex", "Can't open file '%s' !", outFile.Data());
|
1090 |
|
|
return;
|
1091 |
|
|
}
|
1092 |
|
|
|
1093 |
|
|
Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
|
1094 |
|
|
|
1095 |
|
|
WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide");
|
1096 |
|
|
|
1097 |
|
|
WriteTopLinks(out, 0);
|
1098 |
|
|
out << "</div></div>" << endl;
|
1099 |
|
|
|
1100 |
|
|
out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl;
|
1101 |
|
|
|
1102 |
|
|
TString prodDoc;
|
1103 |
|
|
if (GetHtml()->GetPathDefinition().GetDocDir("", prodDoc))
|
1104 |
|
|
ProcessDocInDir(out, prodDoc, GetHtml()->GetOutputDir(), "./");
|
1105 |
|
|
|
1106 |
|
|
WriteModuleLinks(out);
|
1107 |
|
|
|
1108 |
|
|
out << "<h2>Chapters</h2>" << std::endl
|
1109 |
|
|
<< "<h3><a href=\"./ClassIndex.html\">Class Index</a></h3>" << std::endl
|
1110 |
|
|
<< "<p>A complete list of all classes defined in " << GetHtml()->GetProductName() << "</p>" << std::endl
|
1111 |
|
|
<< "<h3><a href=\"./ClassHierarchy.html\">Class Hierarchy</a></h3>" << std::endl
|
1112 |
|
|
<< "<p>A hierarchy graph of all classes, showing each class's base and derived classes</p>" << std::endl
|
1113 |
|
|
<< "<h3><a href=\"./ListOfTypes.html\">Type Index</a></h3>" << std::endl
|
1114 |
|
|
<< "<p>A complete list of all types</p>" << std::endl
|
1115 |
|
|
<< "<h3><a href=\"./LibraryDependencies.html\">Library Dependency</a></h3>" << std::endl
|
1116 |
|
|
<< "<p>A diagram showing all of " << GetHtml()->GetProductName() << "'s libraries and their dependencies</p>" << std::endl;
|
1117 |
|
|
|
1118 |
|
|
WriteHtmlFooter(out);
|
1119 |
|
|
}
|
1120 |
|
|
|
1121 |
|
|
//______________________________________________________________________________
|
1122 |
|
|
void TDocOutput::CreateClassTypeDefs()
|
1123 |
|
|
{
|
1124 |
|
|
// Create a forwarding page for each typedef pointing to a class.
|
1125 |
|
|
TDocParser parser(*this);
|
1126 |
|
|
|
1127 |
|
|
TIter iClass(GetHtml()->GetListOfClasses());
|
1128 |
|
|
TClassDocInfo* cdi = 0;
|
1129 |
|
|
while ((cdi = (TClassDocInfo*) iClass())) {
|
1130 |
|
|
if (cdi->GetListOfTypedefs().IsEmpty())
|
1131 |
|
|
continue;
|
1132 |
|
|
TIter iTypedefs(&cdi->GetListOfTypedefs());
|
1133 |
|
|
TDataType* dt = 0;
|
1134 |
|
|
while ((dt = (TDataType*) iTypedefs())) {
|
1135 |
|
|
if (gDebug > 0)
|
1136 |
|
|
Info("CreateClassTypeDefs", "Creating typedef %s to class %s",
|
1137 |
|
|
dt->GetName(), cdi->GetName());
|
1138 |
|
|
// create a filename
|
1139 |
|
|
TString filename(dt->GetName());
|
1140 |
|
|
NameSpace2FileName(filename);
|
1141 |
|
|
|
1142 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
1143 |
|
|
|
1144 |
|
|
filename += ".html";
|
1145 |
|
|
|
1146 |
|
|
// open class file
|
1147 |
|
|
std::ofstream outfile(filename);
|
1148 |
|
|
|
1149 |
|
|
if (!outfile.good()) {
|
1150 |
|
|
Error("CreateClassTypeDefs", "Can't open file '%s' !", filename.Data());
|
1151 |
|
|
continue;
|
1152 |
|
|
}
|
1153 |
|
|
|
1154 |
|
|
WriteHtmlHeader(outfile, dt->GetName());
|
1155 |
|
|
|
1156 |
|
|
outfile << "<a name=\"TopOfPage\"></a>" << endl;
|
1157 |
|
|
|
1158 |
|
|
TString dtName(dt->GetName());
|
1159 |
|
|
ReplaceSpecialChars(dtName);
|
1160 |
|
|
TString sTitle("typedef ");
|
1161 |
|
|
sTitle += dtName;
|
1162 |
|
|
|
1163 |
|
|
TClass* cls = dynamic_cast<TClass*>(cdi->GetClass());
|
1164 |
|
|
if (cls) {
|
1165 |
|
|
// show box with lib, include
|
1166 |
|
|
// needs to go first to allow title on the left
|
1167 |
|
|
TString sInclude;
|
1168 |
|
|
TString sLib;
|
1169 |
|
|
const char* lib=cls->GetSharedLibs();
|
1170 |
|
|
GetHtml()->GetPathDefinition().GetIncludeAs(cls, sInclude);
|
1171 |
|
|
if (lib) {
|
1172 |
|
|
char* libDup=StrDup(lib);
|
1173 |
|
|
char* libDupSpace=strchr(libDup,' ');
|
1174 |
|
|
if (libDupSpace) *libDupSpace = 0;
|
1175 |
|
|
char* libDupEnd=libDup+strlen(libDup);
|
1176 |
|
|
while (libDupEnd!=libDup)
|
1177 |
|
|
if (*(--libDupEnd)=='.') {
|
1178 |
|
|
*libDupEnd=0;
|
1179 |
|
|
break;
|
1180 |
|
|
}
|
1181 |
|
|
sLib = libDup;
|
1182 |
|
|
delete[] libDup;
|
1183 |
|
|
}
|
1184 |
|
|
outfile << "<script type=\"text/javascript\">WriteFollowPageBox('"
|
1185 |
|
|
<< sTitle << "','" << sLib << "','" << sInclude << "');</script>" << endl;
|
1186 |
|
|
}
|
1187 |
|
|
|
1188 |
|
|
TString modulename;
|
1189 |
|
|
fHtml->GetModuleNameForClass(modulename, cls);
|
1190 |
|
|
TModuleDocInfo* module = (TModuleDocInfo*) fHtml->GetListOfModules()->FindObject(modulename);
|
1191 |
|
|
WriteTopLinks(outfile, module, dt->GetName());
|
1192 |
|
|
|
1193 |
|
|
outfile << "</div><div class=\"dropshadow\"><div class=\"withshadow\">";
|
1194 |
|
|
outfile << "<h1>" << sTitle << "</h1>" << endl
|
1195 |
|
|
<< "<div class=\"classdescr\">" << endl;
|
1196 |
|
|
|
1197 |
|
|
outfile << dtName << " is a typedef to ";
|
1198 |
|
|
parser.DecorateKeywords(outfile, cls->GetName());
|
1199 |
|
|
outfile << endl
|
1200 |
|
|
<< "</div>" << std::endl
|
1201 |
|
|
<< "</div></div><div style=\"clear:both;\"></div>" << std::endl;
|
1202 |
|
|
|
1203 |
|
|
// the typedef isn't a data member, but the CSS is applicable nevertheless
|
1204 |
|
|
outfile << endl << "<div id=\"datamembers\">" << endl
|
1205 |
|
|
<< "<table class=\"data\" cellspacing=\"0\">" << endl;
|
1206 |
|
|
outfile << "<tr class=\"data";
|
1207 |
|
|
outfile << "\"><td class=\"datatype\">typedef ";
|
1208 |
|
|
parser.DecorateKeywords(outfile, dt->GetFullTypeName());
|
1209 |
|
|
outfile << "</td><td class=\"dataname\">";
|
1210 |
|
|
ReplaceSpecialChars(outfile, dt->GetName());
|
1211 |
|
|
if (dt->GetTitle() && dt->GetTitle()[0]) {
|
1212 |
|
|
outfile << "</td><td class=\"datadesc\">";
|
1213 |
|
|
ReplaceSpecialChars(outfile, dt->GetTitle());
|
1214 |
|
|
} else outfile << "</td><td>";
|
1215 |
|
|
outfile << "</td></tr>" << endl
|
1216 |
|
|
<< "</table></div>" << endl;
|
1217 |
|
|
|
1218 |
|
|
// write footer
|
1219 |
|
|
WriteHtmlFooter(outfile);
|
1220 |
|
|
|
1221 |
|
|
}
|
1222 |
|
|
}
|
1223 |
|
|
}
|
1224 |
|
|
|
1225 |
|
|
//______________________________________________________________________________
|
1226 |
|
|
void TDocOutput::CreateTypeIndex()
|
1227 |
|
|
{
|
1228 |
|
|
// Create index of all data types
|
1229 |
|
|
|
1230 |
|
|
// open file
|
1231 |
|
|
TString outFile("ListOfTypes.html");
|
1232 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), outFile);
|
1233 |
|
|
std::ofstream typesList(outFile);
|
1234 |
|
|
|
1235 |
|
|
if (!typesList.good()) {
|
1236 |
|
|
Error("CreateTypeIndex", "Can't open file '%s' !", outFile.Data());
|
1237 |
|
|
return;
|
1238 |
|
|
}
|
1239 |
|
|
|
1240 |
|
|
Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
|
1241 |
|
|
|
1242 |
|
|
// write typesList header
|
1243 |
|
|
WriteHtmlHeader(typesList, "List of data types");
|
1244 |
|
|
typesList << "<h2> List of data types </h2>" << endl;
|
1245 |
|
|
|
1246 |
|
|
typesList << "<dl><dd>" << endl;
|
1247 |
|
|
|
1248 |
|
|
// make loop on data types
|
1249 |
|
|
std::list<std::string> typeNames;
|
1250 |
|
|
|
1251 |
|
|
{
|
1252 |
|
|
TDataType *type;
|
1253 |
|
|
TIter nextType(gROOT->GetListOfTypes());
|
1254 |
|
|
|
1255 |
|
|
while ((type = (TDataType *) nextType()))
|
1256 |
|
|
// no templates ('<' and '>'), no idea why the '(' is in here...
|
1257 |
|
|
if (*type->GetTitle() && !strchr(type->GetName(), '(')
|
1258 |
|
|
&& !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>'))
|
1259 |
|
|
&& type->GetName())
|
1260 |
|
|
typeNames.push_back(type->GetName());
|
1261 |
|
|
}
|
1262 |
|
|
|
1263 |
|
|
sort_strlist_stricmp(typeNames);
|
1264 |
|
|
|
1265 |
|
|
std::vector<std::string> indexChars;
|
1266 |
|
|
if (typeNames.size() > 10) {
|
1267 |
|
|
typesList << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
|
1268 |
|
|
// find index chars
|
1269 |
|
|
GetIndexChars(typeNames, 10 /*sections*/, indexChars);
|
1270 |
|
|
for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
|
1271 |
|
|
typesList << "<a href=\"#idx" << iIdxEntry << "\">";
|
1272 |
|
|
ReplaceSpecialChars(typesList, indexChars[iIdxEntry].c_str());
|
1273 |
|
|
typesList << "</a>" << endl;
|
1274 |
|
|
}
|
1275 |
|
|
typesList << "</div><br />" << endl;
|
1276 |
|
|
}
|
1277 |
|
|
|
1278 |
|
|
typesList << "<ul id=\"indx\">" << endl;
|
1279 |
|
|
|
1280 |
|
|
int idx = 0;
|
1281 |
|
|
UInt_t currentIndexEntry = 0;
|
1282 |
|
|
|
1283 |
|
|
for (std::list<std::string>::iterator iTypeName = typeNames.begin();
|
1284 |
|
|
iTypeName != typeNames.end(); ++iTypeName) {
|
1285 |
|
|
TDataType* type = gROOT->GetType(iTypeName->c_str(), kFALSE);
|
1286 |
|
|
typesList << "<li class=\"idxl" << idx%2 << "\">";
|
1287 |
|
|
if (currentIndexEntry < indexChars.size()
|
1288 |
|
|
&& !strncmp(indexChars[currentIndexEntry].c_str(), iTypeName->c_str(),
|
1289 |
|
|
indexChars[currentIndexEntry].length()))
|
1290 |
|
|
typesList << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
|
1291 |
|
|
typesList << "<a name=\"";
|
1292 |
|
|
ReplaceSpecialChars(typesList, iTypeName->c_str());
|
1293 |
|
|
typesList << "\"><span class=\"typename\">";
|
1294 |
|
|
ReplaceSpecialChars(typesList, iTypeName->c_str());
|
1295 |
|
|
typesList << "</span></a> ";
|
1296 |
|
|
ReplaceSpecialChars(typesList, type->GetTitle());
|
1297 |
|
|
typesList << "</li>" << endl;
|
1298 |
|
|
++idx;
|
1299 |
|
|
}
|
1300 |
|
|
typesList << "</ul>" << endl;
|
1301 |
|
|
|
1302 |
|
|
// write typesList footer
|
1303 |
|
|
WriteHtmlFooter(typesList);
|
1304 |
|
|
|
1305 |
|
|
// close file
|
1306 |
|
|
typesList.close();
|
1307 |
|
|
|
1308 |
|
|
}
|
1309 |
|
|
|
1310 |
|
|
|
1311 |
|
|
//______________________________________________________________________________
|
1312 |
|
|
void TDocOutput::DecorateEntityBegin(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
|
1313 |
|
|
{
|
1314 |
|
|
// Add some colors etc to a source entity, contained in str.
|
1315 |
|
|
// The type of what's contained in str is given by type.
|
1316 |
|
|
// It's called e.g. by TDocParser::BeautifyLine().
|
1317 |
|
|
// This function should assume that only str.Begin() is valid.
|
1318 |
|
|
// When inserting into str.String(), str.Begin() must be updated.
|
1319 |
|
|
|
1320 |
|
|
Ssiz_t originalLen = str.Length();
|
1321 |
|
|
|
1322 |
|
|
switch (type) {
|
1323 |
|
|
case TDocParser::kCode: break;
|
1324 |
|
|
case TDocParser::kComment:
|
1325 |
|
|
str.Insert(pos, "<span class=\"comment\">");
|
1326 |
|
|
break;
|
1327 |
|
|
case TDocParser::kDirective:
|
1328 |
|
|
break;
|
1329 |
|
|
case TDocParser::kString:
|
1330 |
|
|
str.Insert(pos, "<span class=\"string\">");
|
1331 |
|
|
break;
|
1332 |
|
|
case TDocParser::kKeyword:
|
1333 |
|
|
str.Insert(pos, "<span class=\"keyword\">");
|
1334 |
|
|
break;
|
1335 |
|
|
case TDocParser::kCPP:
|
1336 |
|
|
str.Insert(pos, "<span class=\"cpp\">");
|
1337 |
|
|
break;
|
1338 |
|
|
case TDocParser::kVerbatim:
|
1339 |
|
|
str.Insert(pos, "<pre>");
|
1340 |
|
|
break;
|
1341 |
|
|
default:
|
1342 |
|
|
Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
|
1343 |
|
|
return;
|
1344 |
|
|
}
|
1345 |
|
|
|
1346 |
|
|
Ssiz_t addedLen = str.Length() - originalLen;
|
1347 |
|
|
pos += addedLen;
|
1348 |
|
|
}
|
1349 |
|
|
|
1350 |
|
|
//______________________________________________________________________________
|
1351 |
|
|
void TDocOutput::DecorateEntityEnd(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
|
1352 |
|
|
{
|
1353 |
|
|
// Add some colors etc to a source entity, contained in str.
|
1354 |
|
|
// The type of what's contained in str is given by type.
|
1355 |
|
|
// It's called e.g. by TDocParser::BeautifyLine().
|
1356 |
|
|
// This function should assume that only str."End()"
|
1357 |
|
|
// (i.e. str.Begin()+str.Length()) is valid.
|
1358 |
|
|
// When inserting into str.String(), str.Length() must be updated.
|
1359 |
|
|
|
1360 |
|
|
Ssiz_t originalLen = str.Length();
|
1361 |
|
|
|
1362 |
|
|
switch (type) {
|
1363 |
|
|
case TDocParser::kCode: break;
|
1364 |
|
|
case TDocParser::kComment:
|
1365 |
|
|
str.Insert(pos, "</span>");
|
1366 |
|
|
break;
|
1367 |
|
|
case TDocParser::kDirective:
|
1368 |
|
|
break;
|
1369 |
|
|
case TDocParser::kString:
|
1370 |
|
|
str.Insert(pos, "</span>");
|
1371 |
|
|
break;
|
1372 |
|
|
case TDocParser::kKeyword:
|
1373 |
|
|
str.Insert(pos, "</span>");
|
1374 |
|
|
break;
|
1375 |
|
|
case TDocParser::kCPP:
|
1376 |
|
|
str.Insert(pos, "</span>");
|
1377 |
|
|
break;
|
1378 |
|
|
case TDocParser::kVerbatim:
|
1379 |
|
|
str.Insert(pos, "</pre>");
|
1380 |
|
|
break;
|
1381 |
|
|
default:
|
1382 |
|
|
Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
|
1383 |
|
|
return;
|
1384 |
|
|
}
|
1385 |
|
|
Ssiz_t addedLen = str.Length() - originalLen;
|
1386 |
|
|
pos += addedLen;
|
1387 |
|
|
}
|
1388 |
|
|
|
1389 |
|
|
//______________________________________________________________________________
|
1390 |
|
|
void TDocOutput::FixupAuthorSourceInfo(TString& authors)
|
1391 |
|
|
{
|
1392 |
|
|
// Special author treatment; called when TDocParser::fSourceInfo[kInfoAuthor] is set.
|
1393 |
|
|
// Modifies the author(s) description, which is a comma separated list of tokens
|
1394 |
|
|
// either in the format
|
1395 |
|
|
// (i) "FirstName LastName " or
|
1396 |
|
|
// (ii) "FirstName LastName <link> more stuff"
|
1397 |
|
|
// The first one generates an XWho link (CERN compatible),
|
1398 |
|
|
// the second a http link (WORLD compatible), <link> being e.g.
|
1399 |
|
|
// <mailto:user@host.bla> or <http://www.host.bla/page>.
|
1400 |
|
|
|
1401 |
|
|
TString original(authors);
|
1402 |
|
|
authors = "";
|
1403 |
|
|
|
1404 |
|
|
TString author;
|
1405 |
|
|
Ssiz_t pos = 0;
|
1406 |
|
|
Bool_t firstAuthor = kTRUE;
|
1407 |
|
|
while (original.Tokenize(author, pos, ",")) {
|
1408 |
|
|
author.Strip(TString::kBoth);
|
1409 |
|
|
|
1410 |
|
|
if (!firstAuthor)
|
1411 |
|
|
authors += ", ";
|
1412 |
|
|
firstAuthor = kFALSE;
|
1413 |
|
|
|
1414 |
|
|
// do we have a link for the current name?
|
1415 |
|
|
Ssiz_t cLink = author.First('<'); // look for link start tag
|
1416 |
|
|
if (cLink != kNPOS) {
|
1417 |
|
|
// split NAME <LINK> POST
|
1418 |
|
|
// into <a href="LINK">NAME</a> POST
|
1419 |
|
|
Ssiz_t endLink = author.Index(">", cLink + 1);
|
1420 |
|
|
if(endLink == kNPOS)
|
1421 |
|
|
endLink = author.Length();
|
1422 |
|
|
authors += "<a href=\"";
|
1423 |
|
|
authors += author(cLink + 1, endLink - (cLink + 1));
|
1424 |
|
|
authors += "\">";
|
1425 |
|
|
authors += author(0, cLink);
|
1426 |
|
|
authors += "</a>";
|
1427 |
|
|
if (endLink != author.Length())
|
1428 |
|
|
authors += author(endLink + 1, author.Length());
|
1429 |
|
|
} else {
|
1430 |
|
|
authors += "<a href=\"";
|
1431 |
|
|
authors += fHtml->GetXwho();
|
1432 |
|
|
|
1433 |
|
|
// separate Firstname Middlename Lastname by '+'
|
1434 |
|
|
TString namePart;
|
1435 |
|
|
Ssiz_t posNamePart = 0;
|
1436 |
|
|
Bool_t firstNamePart = kTRUE;
|
1437 |
|
|
while (author.Tokenize(namePart, posNamePart, " ")) {
|
1438 |
|
|
namePart.Strip(TString::kBoth);
|
1439 |
|
|
if (!namePart.Length())
|
1440 |
|
|
continue;
|
1441 |
|
|
if (isdigit(namePart[0])) continue; //likely a date
|
1442 |
|
|
if (!firstNamePart)
|
1443 |
|
|
authors += '+';
|
1444 |
|
|
firstNamePart = kFALSE;
|
1445 |
|
|
authors += namePart;
|
1446 |
|
|
}
|
1447 |
|
|
authors += "\">";
|
1448 |
|
|
authors += author;
|
1449 |
|
|
authors += "</a>";
|
1450 |
|
|
}
|
1451 |
|
|
} // while next author
|
1452 |
|
|
}
|
1453 |
|
|
|
1454 |
|
|
//______________________________________________________________________________
|
1455 |
|
|
Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type)
|
1456 |
|
|
{
|
1457 |
|
|
// Check if file is modified
|
1458 |
|
|
//
|
1459 |
|
|
//
|
1460 |
|
|
// Input: classPtr - pointer to the class
|
1461 |
|
|
// type - file type to compare with
|
1462 |
|
|
// values: kSource, kInclude, kTree
|
1463 |
|
|
//
|
1464 |
|
|
// Output: TRUE - if file is modified since last time
|
1465 |
|
|
// FALSE - if file is up to date
|
1466 |
|
|
//
|
1467 |
|
|
|
1468 |
|
|
TString sourceFile;
|
1469 |
|
|
TString classname(classPtr->GetName());
|
1470 |
|
|
TString filename;
|
1471 |
|
|
TString dir;
|
1472 |
|
|
|
1473 |
|
|
switch (type) {
|
1474 |
|
|
case kSource:
|
1475 |
|
|
if (classPtr->GetImplFileLine()) {
|
1476 |
|
|
fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
|
1477 |
|
|
} else {
|
1478 |
|
|
fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
|
1479 |
|
|
}
|
1480 |
|
|
dir = "src";
|
1481 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), dir);
|
1482 |
|
|
filename = classname;
|
1483 |
|
|
NameSpace2FileName(filename);
|
1484 |
|
|
gSystem->PrependPathName(dir, filename);
|
1485 |
|
|
if (classPtr->GetImplFileLine())
|
1486 |
|
|
filename += ".cxx.html";
|
1487 |
|
|
else
|
1488 |
|
|
filename += ".h.html";
|
1489 |
|
|
break;
|
1490 |
|
|
|
1491 |
|
|
case kInclude:
|
1492 |
|
|
fHtml->GetDeclFileName(classPtr, kFALSE, filename);
|
1493 |
|
|
filename = gSystem->BaseName(filename);
|
1494 |
|
|
fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
|
1495 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
1496 |
|
|
break;
|
1497 |
|
|
|
1498 |
|
|
case kTree:
|
1499 |
|
|
fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
|
1500 |
|
|
NameSpace2FileName(classname);
|
1501 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), classname);
|
1502 |
|
|
filename = classname;
|
1503 |
|
|
filename += "_Tree.pdf";
|
1504 |
|
|
break;
|
1505 |
|
|
|
1506 |
|
|
case kDoc:
|
1507 |
|
|
if (classPtr->GetImplFileLine()) {
|
1508 |
|
|
fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
|
1509 |
|
|
} else {
|
1510 |
|
|
fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
|
1511 |
|
|
}
|
1512 |
|
|
filename = classname;
|
1513 |
|
|
NameSpace2FileName(filename);
|
1514 |
|
|
gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
|
1515 |
|
|
filename += ".html";
|
1516 |
|
|
break;
|
1517 |
|
|
|
1518 |
|
|
default:
|
1519 |
|
|
Error("IsModified", "Unknown file type !");
|
1520 |
|
|
}
|
1521 |
|
|
|
1522 |
|
|
R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
|
1523 |
|
|
|
1524 |
|
|
// Get info about a file
|
1525 |
|
|
Long64_t size;
|
1526 |
|
|
Long_t id, flags, sModtime, dModtime;
|
1527 |
|
|
|
1528 |
|
|
if (!(gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)))
|
1529 |
|
|
if (!(gSystem->GetPathInfo(filename, &id, &size, &flags, &dModtime)))
|
1530 |
|
|
return (sModtime > dModtime);
|
1531 |
|
|
|
1532 |
|
|
return kTRUE;
|
1533 |
|
|
}
|
1534 |
|
|
|
1535 |
|
|
|
1536 |
|
|
//______________________________________________________________________________
|
1537 |
|
|
void TDocOutput::NameSpace2FileName(TString& name)
|
1538 |
|
|
{
|
1539 |
|
|
// Replace "::" in name by "__"
|
1540 |
|
|
// Replace "<", ">", " ", ",", "~", "=" in name by "_"
|
1541 |
|
|
// Replace "A::X<A::Y>" by "A::X<-p0Y>",
|
1542 |
|
|
// "A::B::X<A::B::Y>" by "A::B::X<-p1Y>", etc
|
1543 |
|
|
|
1544 |
|
|
TString encScope(name);
|
1545 |
|
|
Ssiz_t posTemplate = encScope.Index('<');
|
1546 |
|
|
if (posTemplate != kNPOS) {
|
1547 |
|
|
TString templateArgs = encScope(posTemplate, encScope.Length());
|
1548 |
|
|
encScope.Remove(posTemplate, encScope.Length());
|
1549 |
|
|
// shorten the name a bit:
|
1550 |
|
|
// convert A::B::X<A::B::Y> to A::X<-p1Y>, i.e.
|
1551 |
|
|
// the filename A__X_A__Y_ to A__X_-p1Y_
|
1552 |
|
|
// The rule: if the enclosing scope up to the N-th scope matches,
|
1553 |
|
|
// the name becomes -pN
|
1554 |
|
|
Ssiz_t posName = encScope.Last(':');
|
1555 |
|
|
if (posName != kNPOS) {
|
1556 |
|
|
Int_t numDblColumn = encScope.CountChar(':');
|
1557 |
|
|
while (numDblColumn > 1) {
|
1558 |
|
|
encScope.Remove(posName + 1, encScope.Length());
|
1559 |
|
|
numDblColumn -= 2;
|
1560 |
|
|
templateArgs.ReplaceAll(encScope, TString::Format("-p%d", numDblColumn / 2));
|
1561 |
|
|
encScope.Remove(encScope.Length() - 2, 2);
|
1562 |
|
|
posName = encScope.Last(':');
|
1563 |
|
|
if (posName == kNPOS)
|
1564 |
|
|
break; // should be handled by numDblColumn...
|
1565 |
|
|
}
|
1566 |
|
|
name.Replace(posTemplate, name.Length(), templateArgs);
|
1567 |
|
|
}
|
1568 |
|
|
}
|
1569 |
|
|
|
1570 |
|
|
if (name.Length() > 240) { // really 240! It might get some extra prefix or extension
|
1571 |
|
|
// 8.3 is dead, but e.g. ext2 can only hold 255 chars in a file name.
|
1572 |
|
|
// So mangle name to "beginning_of_name"-h"hash"."extension", where
|
1573 |
|
|
// beginning_of_name is short enough such that the full name is <255 characters.
|
1574 |
|
|
|
1575 |
|
|
TString hash;
|
1576 |
|
|
TDocParser::AnchorFromLine(name, hash);
|
1577 |
|
|
hash.Prepend("-h");
|
1578 |
|
|
Ssiz_t posDot = name.Last('.');
|
1579 |
|
|
TString ext;
|
1580 |
|
|
if (posDot != kNPOS)
|
1581 |
|
|
ext = name(posDot, name.Length());
|
1582 |
|
|
Ssiz_t namelen = 240 - hash.Length() - ext.Length();
|
1583 |
|
|
name = name(0, namelen) + hash + ext;
|
1584 |
|
|
}
|
1585 |
|
|
|
1586 |
|
|
const char* replaceWhat = ":<> ,~=";
|
1587 |
|
|
for (Ssiz_t i=0; i < name.Length(); ++i)
|
1588 |
|
|
if (strchr(replaceWhat, name[i]))
|
1589 |
|
|
name[i] = '_';
|
1590 |
|
|
}
|
1591 |
|
|
|
1592 |
|
|
//______________________________________________________________________________
|
1593 |
|
|
void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir,
|
1594 |
|
|
const char* outdir, const char* linkdir)
|
1595 |
|
|
{
|
1596 |
|
|
// Write links to files indir/*.txt, indir/*.html (non-recursive) to out.
|
1597 |
|
|
// If one of the files is called "index.{html,txt}" it will be
|
1598 |
|
|
// included in out (instead of copying it to outdir and generating a link
|
1599 |
|
|
// to linkdir). txt files are passed through Convert().
|
1600 |
|
|
// The files' links are sorted alphabetically.
|
1601 |
|
|
|
1602 |
|
|
R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
|
1603 |
|
|
|
1604 |
|
|
void * dirHandle = gSystem->OpenDirectory(indir);
|
1605 |
|
|
if (!dirHandle) return;
|
1606 |
|
|
|
1607 |
|
|
const char* entry = 0;
|
1608 |
|
|
std::list<std::string> files;
|
1609 |
|
|
while ((entry = gSystem->GetDirEntry(dirHandle))) {
|
1610 |
|
|
FileStat_t stat;
|
1611 |
|
|
TString filename(entry);
|
1612 |
|
|
gSystem->PrependPathName(indir, filename);
|
1613 |
|
|
if (gSystem->GetPathInfo(filename, stat)) // funny ret
|
1614 |
|
|
continue;
|
1615 |
|
|
if (!R_ISREG(stat.fMode)) continue;
|
1616 |
|
|
|
1617 |
|
|
if (TString(entry).BeginsWith("index.", TString::kIgnoreCase)) {
|
1618 |
|
|
// This is the part we put directly (verbatim) into the module index.
|
1619 |
|
|
// If it ends on ".txt" we run Convert first.
|
1620 |
|
|
if (filename.EndsWith(".txt", TString::kIgnoreCase)) {
|
1621 |
|
|
std::ifstream in(filename);
|
1622 |
|
|
if (in) {
|
1623 |
|
|
out << "<pre>"; // this is what e.g. the html directive expects
|
1624 |
|
|
TDocParser parser(*this);
|
1625 |
|
|
parser.Convert(out, in, "./", kFALSE /* no code */);
|
1626 |
|
|
out << "</pre>";
|
1627 |
|
|
}
|
1628 |
|
|
} else if (filename.EndsWith(".html", TString::kIgnoreCase)) {
|
1629 |
|
|
std::ifstream in(filename);
|
1630 |
|
|
TString line;
|
1631 |
|
|
while (in) {
|
1632 |
|
|
if (!line.ReadLine(in)) break;
|
1633 |
|
|
out << line << endl;
|
1634 |
|
|
}
|
1635 |
|
|
}
|
1636 |
|
|
} else
|
1637 |
|
|
files.push_back(filename.Data());
|
1638 |
|
|
}
|
1639 |
|
|
|
1640 |
|
|
std::stringstream furtherReading;
|
1641 |
|
|
files.sort();
|
1642 |
|
|
for (std::list<std::string>::const_iterator iFile = files.begin();
|
1643 |
|
|
iFile != files.end(); ++iFile) {
|
1644 |
|
|
TString filename(iFile->c_str());
|
1645 |
|
|
if (!filename.EndsWith(".txt", TString::kIgnoreCase)
|
1646 |
|
|
&& !filename.EndsWith(".html", TString::kIgnoreCase))
|
1647 |
|
|
continue;
|
1648 |
|
|
|
1649 |
|
|
// Just copy and link this page.
|
1650 |
|
|
if (gSystem->AccessPathName(outdir))
|
1651 |
|
|
if (gSystem->mkdir(outdir, kTRUE) == -1)
|
1652 |
|
|
// bad - but let's still try to create the output
|
1653 |
|
|
Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
|
1654 |
|
|
|
1655 |
|
|
TString outfile(gSystem->BaseName(filename));
|
1656 |
|
|
gSystem->PrependPathName(outdir, outfile);
|
1657 |
|
|
if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
|
1658 |
|
|
// convert first
|
1659 |
|
|
outfile.Remove(outfile.Length()-3, 3);
|
1660 |
|
|
outfile += "html";
|
1661 |
|
|
std::ifstream inFurther(filename);
|
1662 |
|
|
std::ofstream outFurther(outfile);
|
1663 |
|
|
if (inFurther && outFurther) {
|
1664 |
|
|
outFurther << "<pre>"; // this is what e.g. the html directive expects
|
1665 |
|
|
TDocParser parser(*this);
|
1666 |
|
|
parser.Convert(outFurther, inFurther, "../", kFALSE /*no code*/);
|
1667 |
|
|
outFurther << "</pre>";
|
1668 |
|
|
}
|
1669 |
|
|
} else {
|
1670 |
|
|
if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
|
1671 |
|
|
continue;
|
1672 |
|
|
}
|
1673 |
|
|
TString showname(gSystem->BaseName(outfile));
|
1674 |
|
|
furtherReading << "<a class=\"linkeddoc\" href=\"" << linkdir << "/" << showname << "\">";
|
1675 |
|
|
showname.Remove(showname.Length() - 5, 5); // .html
|
1676 |
|
|
showname.ReplaceAll("_", " ");
|
1677 |
|
|
ReplaceSpecialChars(furtherReading, showname);
|
1678 |
|
|
furtherReading << "</a> " << endl;
|
1679 |
|
|
}
|
1680 |
|
|
|
1681 |
|
|
gSystem->FreeDirectory(dirHandle);
|
1682 |
|
|
if (furtherReading.str().length())
|
1683 |
|
|
out << "<h3>Further Reading</h3><div id=\"furtherreading\">" << endl
|
1684 |
|
|
<< furtherReading.str() << "</div><h3>List of Classes</h3>" << endl;
|
1685 |
|
|
}
|
1686 |
|
|
|
1687 |
|
|
//______________________________________________________________________________
|
1688 |
|
|
void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment /*= 0*/)
|
1689 |
|
|
{
|
1690 |
|
|
// Create a reference to a class documentation page.
|
1691 |
|
|
// str encloses the text to create the reference for (e.g. name of instance).
|
1692 |
|
|
// comment will be added e.g. as tooltip text.
|
1693 |
|
|
// After the reference is put into str.String(), str will enclose the reference
|
1694 |
|
|
// and the original text. Example:
|
1695 |
|
|
// Input:
|
1696 |
|
|
// str.String(): "a gHtml test"
|
1697 |
|
|
// str.Begin(): 2
|
1698 |
|
|
// str.Length(): 5
|
1699 |
|
|
// Output:
|
1700 |
|
|
// str.String(): "a <a href="THtml.html">gHtml</a> test"
|
1701 |
|
|
// str.Begin(): 2
|
1702 |
|
|
// str.Length(): 30
|
1703 |
|
|
|
1704 |
|
|
TString link;
|
1705 |
|
|
fHtml->GetHtmlFileName(entity, link);
|
1706 |
|
|
|
1707 |
|
|
if (comment && !strcmp(comment, entity->GetName()))
|
1708 |
|
|
comment = "";
|
1709 |
|
|
|
1710 |
|
|
AddLink(str, link, comment);
|
1711 |
|
|
}
|
1712 |
|
|
|
1713 |
|
|
//______________________________________________________________________________
|
1714 |
|
|
void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment /*= 0*/)
|
1715 |
|
|
{
|
1716 |
|
|
// Create a reference to a data member documentation page.
|
1717 |
|
|
// str encloses the text to create the reference for (e.g. name of instance).
|
1718 |
|
|
// comment will be added e.g. as tooltip text.
|
1719 |
|
|
// After the reference is put into str.String(), str will enclose the reference
|
1720 |
|
|
// and the original text. Example:
|
1721 |
|
|
// Input:
|
1722 |
|
|
// str.String(): "a gHtml test"
|
1723 |
|
|
// str.Begin(): 2
|
1724 |
|
|
// str.Length(): 5
|
1725 |
|
|
// Output:
|
1726 |
|
|
// str.String(): "a <a href="THtml.html">gHtml</a> test"
|
1727 |
|
|
// str.Begin(): 2
|
1728 |
|
|
// str.Length(): 30
|
1729 |
|
|
TString link;
|
1730 |
|
|
TClass* scope = entity->GetClass();
|
1731 |
|
|
fHtml->GetHtmlFileName(scope, link);
|
1732 |
|
|
link += "#";
|
1733 |
|
|
|
1734 |
|
|
TString mangledName(scope->GetName());
|
1735 |
|
|
NameSpace2FileName(mangledName);
|
1736 |
|
|
link += mangledName;
|
1737 |
|
|
link += ":";
|
1738 |
|
|
|
1739 |
|
|
mangledName = entity->GetName();
|
1740 |
|
|
NameSpace2FileName(mangledName);
|
1741 |
|
|
link += mangledName;
|
1742 |
|
|
|
1743 |
|
|
TString description;
|
1744 |
|
|
if (!comment) {
|
1745 |
|
|
description = entity->GetFullTypeName();
|
1746 |
|
|
description += " ";
|
1747 |
|
|
if (scope) {
|
1748 |
|
|
description += scope->GetName();
|
1749 |
|
|
description += "::";
|
1750 |
|
|
}
|
1751 |
|
|
description += entity->GetName();
|
1752 |
|
|
comment = description.Data();
|
1753 |
|
|
}
|
1754 |
|
|
|
1755 |
|
|
if (comment && !strcmp(comment, entity->GetName()))
|
1756 |
|
|
comment = "";
|
1757 |
|
|
|
1758 |
|
|
AddLink(str, link, comment);
|
1759 |
|
|
}
|
1760 |
|
|
|
1761 |
|
|
//______________________________________________________________________________
|
1762 |
|
|
void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment /*= 0*/)
|
1763 |
|
|
{
|
1764 |
|
|
// Create a reference to a type documentation page.
|
1765 |
|
|
// str encloses the text to create the reference for (e.g. name of instance).
|
1766 |
|
|
// comment will be added e.g. as tooltip text.
|
1767 |
|
|
// After the reference is put into str.String(), str will enclose the reference
|
1768 |
|
|
// and the original text. Example:
|
1769 |
|
|
// Input:
|
1770 |
|
|
// str.String(): "a gHtml test"
|
1771 |
|
|
// str.Begin(): 2
|
1772 |
|
|
// str.Length(): 5
|
1773 |
|
|
// Output:
|
1774 |
|
|
// str.String(): "a <a href="THtml.html">gHtml</a> test"
|
1775 |
|
|
// str.Begin(): 2
|
1776 |
|
|
// str.Length(): 30
|
1777 |
|
|
|
1778 |
|
|
TString mangledEntity(entity->GetName());
|
1779 |
|
|
NameSpace2FileName(mangledEntity);
|
1780 |
|
|
|
1781 |
|
|
TString link;
|
1782 |
|
|
TClassDocInfo* cdi = 0;
|
1783 |
|
|
bool isClassTypedef = entity->GetType() == -1;
|
1784 |
|
|
if (isClassTypedef)
|
1785 |
|
|
/* is class/ struct / union */
|
1786 |
|
|
isClassTypedef = isClassTypedef && (entity->Property() & 7);
|
1787 |
|
|
if (isClassTypedef)
|
1788 |
|
|
cdi = (TClassDocInfo*) GetHtml()->GetListOfClasses()->FindObject(entity->GetFullTypeName());
|
1789 |
|
|
if (cdi) {
|
1790 |
|
|
link = mangledEntity + ".html";
|
1791 |
|
|
} else {
|
1792 |
|
|
link = "ListOfTypes.html#";
|
1793 |
|
|
link += mangledEntity;
|
1794 |
|
|
}
|
1795 |
|
|
|
1796 |
|
|
if (comment && !strcmp(comment, entity->GetName()))
|
1797 |
|
|
comment = "";
|
1798 |
|
|
|
1799 |
|
|
AddLink(str, link, comment);
|
1800 |
|
|
}
|
1801 |
|
|
|
1802 |
|
|
//______________________________________________________________________________
|
1803 |
|
|
void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment /*= 0*/)
|
1804 |
|
|
{
|
1805 |
|
|
// Create a reference to a method documentation page.
|
1806 |
|
|
// str encloses the text to create the reference for (e.g. name of instance).
|
1807 |
|
|
// comment will be added e.g. as tooltip text.
|
1808 |
|
|
// After the reference is put into str.String(), str will enclose the reference
|
1809 |
|
|
// and the original text. Example:
|
1810 |
|
|
// Input:
|
1811 |
|
|
// str.String(): "a gHtml test"
|
1812 |
|
|
// str.Begin(): 2
|
1813 |
|
|
// str.Length(): 5
|
1814 |
|
|
// Output:
|
1815 |
|
|
// str.String(): "a <a href="THtml.html">gHtml</a> test"
|
1816 |
|
|
// str.Begin(): 2
|
1817 |
|
|
// str.Length(): 30
|
1818 |
|
|
|
1819 |
|
|
TString link;
|
1820 |
|
|
TClass* scope = entity->GetClass();
|
1821 |
|
|
fHtml->GetHtmlFileName(scope, link);
|
1822 |
|
|
link += "#";
|
1823 |
|
|
|
1824 |
|
|
TString mangledName(scope->GetName());
|
1825 |
|
|
NameSpace2FileName(mangledName);
|
1826 |
|
|
link += mangledName;
|
1827 |
|
|
link += ":";
|
1828 |
|
|
|
1829 |
|
|
mangledName = entity->GetName();
|
1830 |
|
|
NameSpace2FileName(mangledName);
|
1831 |
|
|
link += mangledName;
|
1832 |
|
|
|
1833 |
|
|
TString description;
|
1834 |
|
|
if (!comment && entity->GetClass()) {
|
1835 |
|
|
TIter iMeth(scope->GetListOfMethods());
|
1836 |
|
|
TMethod* mCand = 0;
|
1837 |
|
|
while ((mCand = (TMethod*)iMeth()))
|
1838 |
|
|
if (!strcmp(mCand->GetName(), entity->GetName())) {
|
1839 |
|
|
if (description.Length()) {
|
1840 |
|
|
description += " or overloads";
|
1841 |
|
|
break;
|
1842 |
|
|
}
|
1843 |
|
|
description = mCand->GetPrototype();
|
1844 |
|
|
}
|
1845 |
|
|
comment = description.Data();
|
1846 |
|
|
}
|
1847 |
|
|
|
1848 |
|
|
if (comment && !strcmp(comment, entity->GetName()))
|
1849 |
|
|
comment = "";
|
1850 |
|
|
|
1851 |
|
|
AddLink(str, link, comment);
|
1852 |
|
|
}
|
1853 |
|
|
|
1854 |
|
|
//______________________________________________________________________________
|
1855 |
|
|
Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
|
1856 |
|
|
{
|
1857 |
|
|
// Check whether reference is a relative reference, and can (or should)
|
1858 |
|
|
// be prependen by relative paths. For HTML, check that it doesn't start
|
1859 |
|
|
// with "http://" or "https://"
|
1860 |
|
|
|
1861 |
|
|
return !reference ||
|
1862 |
|
|
strncmp(reference, "http", 4) ||
|
1863 |
|
|
(strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4));
|
1864 |
|
|
}
|
1865 |
|
|
|
1866 |
|
|
//______________________________________________________________________________
|
1867 |
|
|
const char* TDocOutput::ReplaceSpecialChars(char c)
|
1868 |
|
|
{
|
1869 |
|
|
// Replace ampersand, less-than and greater-than character, writing to out.
|
1870 |
|
|
// If 0 is returned, no replacement needs to be done.
|
1871 |
|
|
|
1872 |
|
|
/*
|
1873 |
|
|
if (fEscFlag) {
|
1874 |
|
|
fEscFlag = kFALSE;
|
1875 |
|
|
return buf;
|
1876 |
|
|
} else if (c == fEsc) {
|
1877 |
|
|
// text.Remove(pos, 1); - NO! we want to keep it nevertheless!
|
1878 |
|
|
fEscFlag = kTRUE;
|
1879 |
|
|
return buf;
|
1880 |
|
|
}
|
1881 |
|
|
|
1882 |
|
|
*/
|
1883 |
|
|
switch (c) {
|
1884 |
|
|
case '<': return "<";
|
1885 |
|
|
case '&': return "&";
|
1886 |
|
|
case '>': return ">";
|
1887 |
|
|
};
|
1888 |
|
|
return 0;
|
1889 |
|
|
}
|
1890 |
|
|
|
1891 |
|
|
//______________________________________________________________________________
|
1892 |
|
|
void TDocOutput::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
|
1893 |
|
|
{
|
1894 |
|
|
// Replace ampersand, less-than and greater-than character
|
1895 |
|
|
//
|
1896 |
|
|
//
|
1897 |
|
|
// Input: text - text where replacement will happen,
|
1898 |
|
|
// pos - index of char to be replaced; will point to next char to be
|
1899 |
|
|
// replaced when function returns
|
1900 |
|
|
//
|
1901 |
|
|
|
1902 |
|
|
const char c = text[pos];
|
1903 |
|
|
const char* replaced = ReplaceSpecialChars(c);
|
1904 |
|
|
if (replaced) {
|
1905 |
|
|
text.Replace(pos, 1, replaced);
|
1906 |
|
|
pos += strlen(replaced) - 1;
|
1907 |
|
|
}
|
1908 |
|
|
++pos;
|
1909 |
|
|
}
|
1910 |
|
|
|
1911 |
|
|
//______________________________________________________________________________
|
1912 |
|
|
void TDocOutput::ReplaceSpecialChars(TString& text) {
|
1913 |
|
|
// Replace ampersand, less-than and greater-than character
|
1914 |
|
|
//
|
1915 |
|
|
//
|
1916 |
|
|
// Input: text - text where replacement will happen,
|
1917 |
|
|
//
|
1918 |
|
|
Ssiz_t pos = 0;
|
1919 |
|
|
while (pos < text.Length())
|
1920 |
|
|
ReplaceSpecialChars(text, pos);
|
1921 |
|
|
}
|
1922 |
|
|
|
1923 |
|
|
//______________________________________________________________________________
|
1924 |
|
|
void TDocOutput::ReplaceSpecialChars(std::ostream& out, const char *string)
|
1925 |
|
|
{
|
1926 |
|
|
// Replace ampersand, less-than and greater-than characters, writing to out
|
1927 |
|
|
//
|
1928 |
|
|
//
|
1929 |
|
|
// Input: out - output file stream
|
1930 |
|
|
// string - pointer to an array of characters
|
1931 |
|
|
//
|
1932 |
|
|
|
1933 |
|
|
while (string && *string) {
|
1934 |
|
|
const char* replaced = ReplaceSpecialChars(*string);
|
1935 |
|
|
if (replaced)
|
1936 |
|
|
out << replaced;
|
1937 |
|
|
else
|
1938 |
|
|
out << *string;
|
1939 |
|
|
string++;
|
1940 |
|
|
}
|
1941 |
|
|
}
|
1942 |
|
|
|
1943 |
|
|
//______________________________________________________________________________
|
1944 |
|
|
Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap /* =0 */,
|
1945 |
|
|
EGraphvizTool gvwhat /*= kDot*/) {
|
1946 |
|
|
// Run filename".dot", creating filename".gif", and - if outMap is !=0,
|
1947 |
|
|
// filename".map", which gets then included literally into outMap.
|
1948 |
|
|
|
1949 |
|
|
if (!fHtml->HaveDot())
|
1950 |
|
|
return kFALSE;
|
1951 |
|
|
|
1952 |
|
|
TString runDot;
|
1953 |
|
|
switch (gvwhat) {
|
1954 |
|
|
case kNeato: runDot = "neato"; break;
|
1955 |
|
|
case kFdp: runDot = "fdp"; break;
|
1956 |
|
|
case kCirco: runDot = "circo"; break;
|
1957 |
|
|
default: runDot = "dot";
|
1958 |
|
|
};
|
1959 |
|
|
if (fHtml->GetDotDir() && *fHtml->GetDotDir())
|
1960 |
|
|
gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
|
1961 |
|
|
runDot += " -q1 -Tgif -o";
|
1962 |
|
|
runDot += filename;
|
1963 |
|
|
runDot += ".gif ";
|
1964 |
|
|
if (outMap) {
|
1965 |
|
|
runDot += "-Tcmap -o";
|
1966 |
|
|
runDot += filename;
|
1967 |
|
|
runDot += ".map ";
|
1968 |
|
|
}
|
1969 |
|
|
runDot += filename;
|
1970 |
|
|
runDot += ".dot";
|
1971 |
|
|
|
1972 |
|
|
if (gDebug > 3)
|
1973 |
|
|
Info("RunDot", "Running: %s", runDot.Data());
|
1974 |
|
|
Int_t retDot = gSystem->Exec(runDot);
|
1975 |
|
|
if (gDebug < 4 && !retDot)
|
1976 |
|
|
gSystem->Unlink(Form("%s.dot", filename));
|
1977 |
|
|
|
1978 |
|
|
if (!retDot && outMap) {
|
1979 |
|
|
ifstream inmap(Form("%s.map", filename));
|
1980 |
|
|
std::string line;
|
1981 |
|
|
std::getline(inmap, line);
|
1982 |
|
|
if (inmap && !inmap.eof()) {
|
1983 |
|
|
*outMap << "<map name=\"Map" << gSystem->BaseName(filename)
|
1984 |
|
|
<< "\" id=\"Map" << gSystem->BaseName(filename) << "\">" << endl;
|
1985 |
|
|
while (inmap && !inmap.eof()) {
|
1986 |
|
|
if (line.compare(0, 6, "<area ") == 0) {
|
1987 |
|
|
size_t posEndTag = line.find('>');
|
1988 |
|
|
if (posEndTag != std::string::npos)
|
1989 |
|
|
line.replace(posEndTag, 1, "/>");
|
1990 |
|
|
}
|
1991 |
|
|
*outMap << line << endl;
|
1992 |
|
|
std::getline(inmap, line);
|
1993 |
|
|
}
|
1994 |
|
|
*outMap << "</map>" << endl;
|
1995 |
|
|
}
|
1996 |
|
|
inmap.close();
|
1997 |
|
|
if (gDebug < 7)
|
1998 |
|
|
gSystem->Unlink(Form("%s.map", filename));
|
1999 |
|
|
}
|
2000 |
|
|
|
2001 |
|
|
if (retDot) {
|
2002 |
|
|
Error("RunDot", "Error running %s!", runDot.Data());
|
2003 |
|
|
fHtml->SetFoundDot(kFALSE);
|
2004 |
|
|
return kFALSE;
|
2005 |
|
|
}
|
2006 |
|
|
|
2007 |
|
|
return kTRUE;
|
2008 |
|
|
}
|
2009 |
|
|
|
2010 |
|
|
|
2011 |
|
|
//______________________________________________________________________________
|
2012 |
|
|
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial,
|
2013 |
|
|
const char* dir /*=""*/, TClass *cls /*=0*/,
|
2014 |
|
|
const char* header)
|
2015 |
|
|
{
|
2016 |
|
|
// Write HTML header
|
2017 |
|
|
//
|
2018 |
|
|
// Internal method invoked by the overload
|
2019 |
|
|
|
2020 |
|
|
ifstream addHeaderFile(header);
|
2021 |
|
|
|
2022 |
|
|
if (!addHeaderFile.good()) {
|
2023 |
|
|
Warning("THtml::WriteHtmlHeader",
|
2024 |
|
|
"Can't open html header file %s\n", header);
|
2025 |
|
|
return;
|
2026 |
|
|
}
|
2027 |
|
|
|
2028 |
|
|
TString declFileName;
|
2029 |
|
|
if (cls) fHtml->GetDeclFileName(cls, kFALSE, declFileName);
|
2030 |
|
|
TString implFileName;
|
2031 |
|
|
if (cls) fHtml->GetImplFileName(cls, kFALSE, implFileName);
|
2032 |
|
|
|
2033 |
|
|
const TString& charset = GetHtml()->GetCharset();
|
2034 |
|
|
TDatime date;
|
2035 |
|
|
TString strDate(date.AsString());
|
2036 |
|
|
TString line;
|
2037 |
|
|
|
2038 |
|
|
while (!addHeaderFile.eof()) {
|
2039 |
|
|
|
2040 |
|
|
line.ReadLine(addHeaderFile, kFALSE);
|
2041 |
|
|
if (addHeaderFile.eof())
|
2042 |
|
|
break;
|
2043 |
|
|
|
2044 |
|
|
if (line) {
|
2045 |
|
|
|
2046 |
|
|
if (!cls && (
|
2047 |
|
|
line.Index("%CLASS%") != kNPOS ||
|
2048 |
|
|
line.Index("%INCFILE%") != kNPOS ||
|
2049 |
|
|
line.Index("%SRCFILE%") != kNPOS))
|
2050 |
|
|
continue; // skip class line for non-class files
|
2051 |
|
|
|
2052 |
|
|
TString txt(line);
|
2053 |
|
|
|
2054 |
|
|
txt.ReplaceAll("%TITLE%", titleNoSpecial);
|
2055 |
|
|
txt.ReplaceAll("%DATE%", strDate);
|
2056 |
|
|
txt.ReplaceAll("%RELDIR%", dir);
|
2057 |
|
|
txt.ReplaceAll("%CHARSET%", charset);
|
2058 |
|
|
|
2059 |
|
|
if (cls) {
|
2060 |
|
|
txt.ReplaceAll("%CLASS%", cls->GetName());
|
2061 |
|
|
txt.ReplaceAll("%INCFILE%", declFileName);
|
2062 |
|
|
txt.ReplaceAll("%SRCFILE%", implFileName);
|
2063 |
|
|
}
|
2064 |
|
|
|
2065 |
|
|
out << txt << endl;
|
2066 |
|
|
}
|
2067 |
|
|
}
|
2068 |
|
|
}
|
2069 |
|
|
|
2070 |
|
|
//______________________________________________________________________________
|
2071 |
|
|
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title,
|
2072 |
|
|
const char* dir /*=""*/, TClass *cls/*=0*/)
|
2073 |
|
|
{
|
2074 |
|
|
// Write HTML header
|
2075 |
|
|
//
|
2076 |
|
|
//
|
2077 |
|
|
// Input: out - output file stream
|
2078 |
|
|
// title - title for the HTML page
|
2079 |
|
|
// cls - current class
|
2080 |
|
|
// dir - relative directory to reach the top
|
2081 |
|
|
// ("" for html doc, "../" for src/*cxx.html etc)
|
2082 |
|
|
//
|
2083 |
|
|
// evaluates the Root.Html.Header setting:
|
2084 |
|
|
// * if not set, the standard header is written. (ROOT)
|
2085 |
|
|
// * if set, and ends with a "+", the standard header is written and this file
|
2086 |
|
|
// included afterwards. (ROOT, USER)
|
2087 |
|
|
// * if set but doesn't end on "+" the file specified will be written instead
|
2088 |
|
|
// of the standard header (USER)
|
2089 |
|
|
//
|
2090 |
|
|
// Any occurrence of "%TITLE%" (without the quotation marks) in the user
|
2091 |
|
|
// provided header file will be replaced by the value of this method's
|
2092 |
|
|
// parameter "title" before written to the output file. %CLASS% is replaced by
|
2093 |
|
|
// the class name, %INCFILE% by the header file name as given by
|
2094 |
|
|
// TClass::GetDeclFileName() and %SRCFILE% by the source file name as given by
|
2095 |
|
|
// TClass::GetImplFileName(). If the header is written for a non-class page,
|
2096 |
|
|
// i.e. cls==0, lines containing %CLASS%, %INCFILE%, or %SRCFILE% will be
|
2097 |
|
|
// skipped.
|
2098 |
|
|
|
2099 |
|
|
TString userHeader = GetHtml()->GetHeader();
|
2100 |
|
|
TString noSpecialCharTitle(title);
|
2101 |
|
|
ReplaceSpecialChars(noSpecialCharTitle);
|
2102 |
|
|
|
2103 |
|
|
Ssiz_t lenUserHeader = userHeader.Length();
|
2104 |
|
|
// standard header output if Root.Html.Header is not set, or it's set and it ends with a "+".
|
2105 |
|
|
Bool_t bothHeaders = lenUserHeader > 0 && userHeader[lenUserHeader - 1] == '+';
|
2106 |
|
|
if (lenUserHeader == 0 || bothHeaders) {
|
2107 |
|
|
TString header("header.html");
|
2108 |
|
|
gSystem->PrependPathName(fHtml->GetEtcDir(), header);
|
2109 |
|
|
WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, header);
|
2110 |
|
|
}
|
2111 |
|
|
|
2112 |
|
|
if (lenUserHeader != 0) {
|
2113 |
|
|
if (bothHeaders)
|
2114 |
|
|
userHeader.Remove(lenUserHeader - 1);
|
2115 |
|
|
WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, userHeader);
|
2116 |
|
|
};
|
2117 |
|
|
}
|
2118 |
|
|
|
2119 |
|
|
//______________________________________________________________________________
|
2120 |
|
|
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/,
|
2121 |
|
|
const char* lastUpdate, const char* author,
|
2122 |
|
|
const char* copyright, const char* footer)
|
2123 |
|
|
{
|
2124 |
|
|
// Write HTML footer
|
2125 |
|
|
//
|
2126 |
|
|
// Internal method invoked by the overload
|
2127 |
|
|
|
2128 |
|
|
static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%", "%CHANGED%", "%GENERATED%"};
|
2129 |
|
|
|
2130 |
|
|
TString datimeString;
|
2131 |
|
|
if (!lastUpdate || !strlen(lastUpdate)) {
|
2132 |
|
|
TDatime date;
|
2133 |
|
|
datimeString = date.AsString();
|
2134 |
|
|
lastUpdate = datimeString.Data();
|
2135 |
|
|
}
|
2136 |
|
|
TString today;
|
2137 |
|
|
TDatime dtToday;
|
2138 |
|
|
today.Form("%d-%02d-%02d %02d:%02d", dtToday.GetYear(), dtToday.GetMonth(), dtToday.GetDay(), dtToday.GetHour(), dtToday.GetMinute());
|
2139 |
|
|
const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright, lastUpdate, today };
|
2140 |
|
|
|
2141 |
|
|
ifstream addFooterFile(footer);
|
2142 |
|
|
|
2143 |
|
|
if (!addFooterFile.good()) {
|
2144 |
|
|
Warning("THtml::WriteHtmlFooter",
|
2145 |
|
|
"Can't open html footer file %s\n", footer);
|
2146 |
|
|
return;
|
2147 |
|
|
}
|
2148 |
|
|
|
2149 |
|
|
TString line;
|
2150 |
|
|
while (!addFooterFile.eof()) {
|
2151 |
|
|
|
2152 |
|
|
line.ReadLine(addFooterFile, kFALSE);
|
2153 |
|
|
if (addFooterFile.eof())
|
2154 |
|
|
break;
|
2155 |
|
|
|
2156 |
|
|
if (!line)
|
2157 |
|
|
continue;
|
2158 |
|
|
|
2159 |
|
|
for (Int_t siTag = 0; siTag < (Int_t) TDocParser::kNumSourceInfos; ++siTag) {
|
2160 |
|
|
Ssiz_t siPos = line.Index(templateSITags[siTag]);
|
2161 |
|
|
if (siPos != kNPOS) {
|
2162 |
|
|
if (siValues[siTag] && siValues[siTag][0])
|
2163 |
|
|
line.Replace(siPos, strlen(templateSITags[siTag]), siValues[siTag]);
|
2164 |
|
|
else
|
2165 |
|
|
line = ""; // skip e.g. %AUTHOR% lines if no author is set
|
2166 |
|
|
}
|
2167 |
|
|
}
|
2168 |
|
|
|
2169 |
|
|
out << line << std::endl;
|
2170 |
|
|
}
|
2171 |
|
|
|
2172 |
|
|
}
|
2173 |
|
|
|
2174 |
|
|
//______________________________________________________________________________
|
2175 |
|
|
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
|
2176 |
|
|
const char *lastUpdate, const char *author,
|
2177 |
|
|
const char *copyright)
|
2178 |
|
|
{
|
2179 |
|
|
// Write HTML footer
|
2180 |
|
|
//
|
2181 |
|
|
//
|
2182 |
|
|
// Input: out - output file stream
|
2183 |
|
|
// dir - usually equal to "" or "../", depends of
|
2184 |
|
|
// current file directory position, i.e. if
|
2185 |
|
|
// file is in the fHtml->GetOutputDir(), then dir will be ""
|
2186 |
|
|
// lastUpdate - last update string
|
2187 |
|
|
// author - author's name
|
2188 |
|
|
// copyright - copyright note
|
2189 |
|
|
//
|
2190 |
|
|
// Allows optional user provided footer to be written. Root.Html.Footer holds
|
2191 |
|
|
// the file name for this footer. For details see THtml::WriteHtmlHeader (here,
|
2192 |
|
|
// the "+" means the user's footer is written in front of Root's!) Occurences
|
2193 |
|
|
// of %AUTHOR%, %CHANGED%, %GENERATED%, and %COPYRIGHT% in the user's file are replaced by
|
2194 |
|
|
// their corresponding values (author, lastUpdate, today, and copyright) before
|
2195 |
|
|
// written to out.
|
2196 |
|
|
// If no author is set (author == "", e.g. for ClassIndex.html") skip the whole
|
2197 |
|
|
// line of the footer template containing %AUTHOR%. Accordingly for %COPYRIGHT%.
|
2198 |
|
|
|
2199 |
|
|
out << endl;
|
2200 |
|
|
|
2201 |
|
|
TString userFooter = GetHtml()->GetFooter();
|
2202 |
|
|
|
2203 |
|
|
if (userFooter.Length() != 0) {
|
2204 |
|
|
TString footer(userFooter);
|
2205 |
|
|
if (footer.EndsWith("+"))
|
2206 |
|
|
footer.Remove(footer.Length() - 1);
|
2207 |
|
|
WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
|
2208 |
|
|
};
|
2209 |
|
|
|
2210 |
|
|
if (userFooter.Length() == 0 || userFooter.EndsWith("+")) {
|
2211 |
|
|
TString footer("footer.html");
|
2212 |
|
|
gSystem->PrependPathName(fHtml->GetEtcDir(), footer);
|
2213 |
|
|
WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
|
2214 |
|
|
}
|
2215 |
|
|
}
|
2216 |
|
|
|
2217 |
|
|
//______________________________________________________________________________
|
2218 |
|
|
void TDocOutput::WriteModuleLinks(std::ostream& out)
|
2219 |
|
|
{
|
2220 |
|
|
// Create a div containing links to all topmost modules
|
2221 |
|
|
|
2222 |
|
|
if (fHtml->GetListOfModules()->GetSize()) {
|
2223 |
|
|
out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
|
2224 |
|
|
// find index chars
|
2225 |
|
|
fHtml->SortListOfModules();
|
2226 |
|
|
TIter iModule(fHtml->GetListOfModules());
|
2227 |
|
|
TModuleDocInfo* module = 0;
|
2228 |
|
|
while ((module = (TModuleDocInfo*) iModule())) {
|
2229 |
|
|
if (!module->GetName() || strchr(module->GetName(), '/'))
|
2230 |
|
|
continue;
|
2231 |
|
|
if (module->IsSelected()) {
|
2232 |
|
|
TString name(module->GetName());
|
2233 |
|
|
name.ToUpper();
|
2234 |
|
|
out << "<a href=\"" << name << "_Index.html\">"
|
2235 |
|
|
<< name << "</a>" << endl;
|
2236 |
|
|
}
|
2237 |
|
|
}
|
2238 |
|
|
out<< "</div><br />" << endl;
|
2239 |
|
|
}
|
2240 |
|
|
}
|
2241 |
|
|
|
2242 |
|
|
//______________________________________________________________________________
|
2243 |
|
|
void TDocOutput::WriteModuleLinks(std::ostream& out, TModuleDocInfo* super)
|
2244 |
|
|
{
|
2245 |
|
|
// Create a div containing links to all modules
|
2246 |
|
|
|
2247 |
|
|
if (super->GetSub().GetSize()) {
|
2248 |
|
|
TString superName(super->GetName());
|
2249 |
|
|
superName.ToUpper();
|
2250 |
|
|
out << "<div id=\"indxModules\"><h4>" << superName << " Modules</h4>" << endl;
|
2251 |
|
|
// find index chars
|
2252 |
|
|
super->GetSub().Sort();
|
2253 |
|
|
TIter iModule(&super->GetSub());
|
2254 |
|
|
TModuleDocInfo* module = 0;
|
2255 |
|
|
while ((module = (TModuleDocInfo*) iModule())) {
|
2256 |
|
|
if (module->IsSelected()) {
|
2257 |
|
|
TString name(module->GetName());
|
2258 |
|
|
name.ToUpper();
|
2259 |
|
|
TString link(name);
|
2260 |
|
|
link.ReplaceAll("/", "_");
|
2261 |
|
|
Ssiz_t posSlash = name.Last('/');
|
2262 |
|
|
if (posSlash != kNPOS)
|
2263 |
|
|
name.Remove(0, posSlash + 1);
|
2264 |
|
|
out << "<a href=\"" << link << "_Index.html\">" << name << "</a>" << endl;
|
2265 |
|
|
}
|
2266 |
|
|
}
|
2267 |
|
|
out<< "</div><br />" << endl;
|
2268 |
|
|
}
|
2269 |
|
|
}
|
2270 |
|
|
|
2271 |
|
|
//______________________________________________________________________________
|
2272 |
|
|
void TDocOutput::WriteSearch(std::ostream& out)
|
2273 |
|
|
{
|
2274 |
|
|
// Write a search link or a search box, based on THtml::GetSearchStemURL()
|
2275 |
|
|
// and THtml::GetSearchEngine(). The first one is preferred.
|
2276 |
|
|
|
2277 |
|
|
// e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u+-site%3A%u%2Fsrc%2F+-site%3A%u%2Fexamples%2F";
|
2278 |
|
|
const TString& searchCmd = GetHtml()->GetSearchStemURL();
|
2279 |
|
|
const TString& searchEngine = GetHtml()->GetSearchEngine();
|
2280 |
|
|
|
2281 |
|
|
if (!searchCmd.Length() && !searchEngine.Length())
|
2282 |
|
|
return;
|
2283 |
|
|
|
2284 |
|
|
if (searchCmd.Length()) {
|
2285 |
|
|
TUrl url(searchCmd);
|
2286 |
|
|
TString serverName(url.GetHost());
|
2287 |
|
|
if (serverName.Length()) {
|
2288 |
|
|
serverName.Prepend(" title=\"");
|
2289 |
|
|
serverName += "\" ";
|
2290 |
|
|
}
|
2291 |
|
|
// create search input
|
2292 |
|
|
out << "<script type=\"text/javascript\">" << endl
|
2293 |
|
|
<< "function onSearch() {" << endl
|
2294 |
|
|
<< "var s='" << searchCmd <<"';" << endl
|
2295 |
|
|
<< "var ref=String(document.location.href).replace(/https?:\\/\\//,'').replace(/\\/[^\\/]*$/,'').replace(/\\//g,'%2F');" << endl
|
2296 |
|
|
<< "window.location.href=s.replace(/%u/ig,ref).replace(/%s/ig,escape(document.searchform.t.value));" << endl
|
2297 |
|
|
<< "return false;}" << endl
|
2298 |
|
|
<< "</script>" << endl
|
2299 |
|
|
<< "<a class=\"descrheadentry\"> </a>" << endl
|
2300 |
|
|
<< "<form id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\" action=\"javascript:onSearch();\" method=\"post\">" << endl
|
2301 |
|
|
<< "<input name=\"t\" size=\"30\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input></form>" << endl
|
2302 |
|
|
<< "<a id=\"searchlink\" " << serverName << " href=\"javascript:onSearch();\" onclick=\"return onSearch()\">Search</a>" << endl;
|
2303 |
|
|
} else if (searchEngine.Length())
|
2304 |
|
|
// create link to search engine page
|
2305 |
|
|
out << "<a class=\"descrheadentry\" href=\"" << searchEngine
|
2306 |
|
|
<< "\">Search the Class Reference Guide</a>" << endl;
|
2307 |
|
|
}
|
2308 |
|
|
|
2309 |
|
|
//______________________________________________________________________________
|
2310 |
|
|
void TDocOutput::WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname)
|
2311 |
|
|
{
|
2312 |
|
|
// Write the first part of the links shown ontop of each doc page;
|
2313 |
|
|
// two <div>s have to be closed by caller so additional items can still
|
2314 |
|
|
// be added.
|
2315 |
|
|
|
2316 |
|
|
out << "<div id=\"toplinks\">" << endl;
|
2317 |
|
|
|
2318 |
|
|
// make a link to the description
|
2319 |
|
|
out << "<div class=\"descrhead\">" << endl
|
2320 |
|
|
<< "<span class=\"descrtitle\">Location:</span>" << endl;
|
2321 |
|
|
const char *productName = fHtml->GetProductName();
|
2322 |
|
|
out << "<a class=\"descrheadentry\" href=\"index.html\">" << productName << "</a>" << endl;
|
2323 |
|
|
|
2324 |
|
|
if (module) {
|
2325 |
|
|
TString modulename(module->GetName());
|
2326 |
|
|
modulename.ToUpper();
|
2327 |
|
|
TString modulePart;
|
2328 |
|
|
TString modulePath;
|
2329 |
|
|
Ssiz_t pos = 0;
|
2330 |
|
|
while (modulename.Tokenize(modulePart, pos, "/")) {
|
2331 |
|
|
if (pos == kNPOS && !classname)
|
2332 |
|
|
// we are documenting the module itself, no need to link it:
|
2333 |
|
|
break;
|
2334 |
|
|
if (modulePath.Length()) modulePath += "_";
|
2335 |
|
|
modulePath += modulePart;
|
2336 |
|
|
out << " » <a class=\"descrheadentry\" href=\"./" << modulePath << "_Index.html\">" << modulePart << "</a>" << endl;
|
2337 |
|
|
}
|
2338 |
|
|
}
|
2339 |
|
|
|
2340 |
|
|
TString entityName;
|
2341 |
|
|
if (classname) entityName = classname;
|
2342 |
|
|
else if (module) {
|
2343 |
|
|
entityName = module->GetName();
|
2344 |
|
|
Ssiz_t posSlash = entityName.Last('/');
|
2345 |
|
|
if (posSlash != kNPOS)
|
2346 |
|
|
entityName.Remove(0, posSlash + 1);
|
2347 |
|
|
entityName.ToUpper();
|
2348 |
|
|
}
|
2349 |
|
|
if (entityName.Length()) {
|
2350 |
|
|
out << " » <a class=\"descrheadentry\" href=\"#TopOfPage\">";
|
2351 |
|
|
ReplaceSpecialChars(out, entityName);
|
2352 |
|
|
out << "</a>" << endl;
|
2353 |
|
|
}
|
2354 |
|
|
out << "</div>" << endl;
|
2355 |
|
|
|
2356 |
|
|
out << "<div class=\"descrhead\">" << endl
|
2357 |
|
|
<< "<span class=\"descrtitle\">Quick Links:</span>" << endl;
|
2358 |
|
|
|
2359 |
|
|
// link to the user home page (if exist)
|
2360 |
|
|
const char* userHomePage = GetHtml()->GetHomepage();
|
2361 |
|
|
if (productName && !strcmp(productName, "ROOT"))
|
2362 |
|
|
userHomePage = "";
|
2363 |
|
|
if (userHomePage && *userHomePage)
|
2364 |
|
|
out << "<a class=\"descrheadentry\" href=\"" << userHomePage << "\">" << productName << "</a>" << endl;
|
2365 |
|
|
out << "<a class=\"descrheadentry\" href=\"http://root.cern.ch\">ROOT Homepage</a>" << endl
|
2366 |
|
|
<< "<a class=\"descrheadentry\" href=\"./ClassIndex.html\">Class Index</a>" << endl
|
2367 |
|
|
<< "<a class=\"descrheadentry\" href=\"./ClassHierarchy.html\">Class Hierarchy</a>" << endl;
|
2368 |
|
|
WriteSearch(out);
|
2369 |
|
|
out << "</div>" << endl;
|
2370 |
|
|
|
2371 |
|
|
}
|