1 |
// @(#)root/html:$Id: TDocOutput.cxx 26944 2008-12-16 10:27:55Z brun $
|
2 |
// 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 |
&gClientGetListOfWindows, gclient));
|
421 |
gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGClient*)0x%lx)->GetDefaultRoot();",
|
422 |
&gClientGetDefaultRoot, gclient));
|
423 |
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 |
&winGetParent, win));
|
429 |
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 |
&winGetParent, win));
|
462 |
Bool_t winIsMapped = kFALSE;
|
463 |
if (winGetParent == gClientGetDefaultRoot)
|
464 |
gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TGWindow*)0x%lx)->IsMapped();",
|
465 |
&winIsMapped, win));
|
466 |
if (winIsMapped && previousWindows.find(win) == previousWindows.end()
|
467 |
&& win->InheritsFrom(clGMainFrame)) {
|
468 |
gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->MapRaised();", win));
|
469 |
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 |
&hasEditor, win));
|
474 |
}
|
475 |
if (isRootCanvas && !hasEditor) {
|
476 |
TVirtualPad* pad = 0;
|
477 |
gROOT->ProcessLine(TString::Format("*((TVirtualPad**)0x%lx) = ((TRootCanvas*)0x%lx)->Canvas();",
|
478 |
&pad, win));
|
479 |
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 |
win, outfilename, nCanvases++));
|
485 |
}
|
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 |
}
|