TDocOutput.cxx

Go to the documentation of this file.
00001 // @(#)root/html:$Id: TDocOutput.cxx 37576 2010-12-13 16:58:41Z brun $
00002 // Author: Axel Naumann 2007-01-09
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TDocOutput.h"
00013 
00014 #include "Riostream.h"
00015 #include "TClassDocOutput.h"
00016 #include "TClassEdit.h"
00017 #include "TDataMember.h"
00018 #include "TDataType.h"
00019 #include "TDocInfo.h"
00020 #include "TDocParser.h"
00021 #include "TEnv.h"
00022 #include "TGlobal.h"
00023 #include "THtml.h"
00024 #include "TInterpreter.h"
00025 #include "TMethod.h"
00026 #include "TPRegexp.h"
00027 #include "TROOT.h"
00028 #include "TSystem.h"
00029 #include "TUrl.h"
00030 #include "TVirtualMutex.h"
00031 #include "TVirtualPad.h"
00032 #include "TVirtualViewer3D.h"
00033 #include <vector>
00034 #include <list>
00035 #include <set>
00036 #include <sstream>
00037 #include <stdlib.h>
00038 
00039 namespace {
00040 
00041    typedef std::vector<std::string> Words_t;
00042    typedef Words_t::const_iterator SectionStart_t;
00043 
00044    class TSectionInfo {
00045    public:
00046       TSectionInfo(SectionStart_t start, size_t chars, size_t size):
00047          fStart(start), fChars(chars), fSize(size) {};
00048 
00049          SectionStart_t fStart;
00050          size_t fChars;
00051          size_t fSize;
00052    };
00053    typedef std::list<TSectionInfo> SectionStarts_t;
00054 
00055    static void Sections_BuildIndex(SectionStarts_t& sectionStarts,
00056       SectionStart_t begin, SectionStart_t end,
00057       size_t maxPerSection)
00058    {
00059       // for each assumed section border, check that previous entry's
00060       // char[selectionChar] differs, else move section start forward
00061 
00062       SectionStart_t cursor = begin;
00063       if (sectionStarts.empty() || sectionStarts.back().fStart != cursor)
00064          sectionStarts.push_back(TSectionInfo(cursor, 1, 0));
00065 
00066       SectionStarts_t::iterator prevSection = sectionStarts.end();
00067       --prevSection;
00068 
00069       while (cursor != end) {
00070          size_t numLeft = end - cursor;
00071          size_t assumedNumSections = (numLeft + maxPerSection - 1 ) / maxPerSection;
00072          size_t step = ((numLeft + assumedNumSections - 1) / assumedNumSections);
00073          if (!step || step >= numLeft) return;
00074          cursor += step;
00075          if (cursor == end) break;
00076 
00077          SectionStart_t addWhichOne = prevSection->fStart;
00078 
00079          size_t selectionChar=1;
00080          for (; selectionChar <= cursor->length() && addWhichOne == prevSection->fStart;
00081             ++selectionChar) {
00082             SectionStart_t checkPrev = cursor;
00083             while (--checkPrev != prevSection->fStart
00084                && !strncasecmp(checkPrev->c_str(), cursor->c_str(), selectionChar)) { }
00085 
00086             SectionStart_t checkNext = cursor;
00087             while (++checkNext != end
00088                && !strncasecmp(checkNext->c_str(), cursor->c_str(), selectionChar)) { }
00089 
00090             // if the previous matching one is closer but not previous section start, take it!
00091             if (checkPrev != prevSection->fStart) {
00092                if ((cursor - checkPrev) <= (checkNext - cursor))
00093                   addWhichOne = ++checkPrev;
00094                else if (checkNext != end
00095                   && (size_t)(checkNext - cursor) < maxPerSection) {
00096                   addWhichOne = checkNext;
00097                }
00098             }
00099          }
00100          if (addWhichOne == prevSection->fStart)
00101             addWhichOne = cursor;
00102 
00103          selectionChar = 1;
00104          while (selectionChar <= prevSection->fStart->length()
00105             && selectionChar <= addWhichOne->length()
00106             && !strncasecmp(prevSection->fStart->c_str(), addWhichOne->c_str(), selectionChar))
00107             ++selectionChar;
00108 
00109          sectionStarts.push_back(TSectionInfo(addWhichOne, selectionChar, 0));
00110          cursor = addWhichOne;
00111          ++prevSection;
00112       } // while cursor != end
00113    }
00114 
00115    static void Sections_SetSize(SectionStarts_t& sectionStarts, const Words_t &words)
00116    {
00117       // Update the length of the sections
00118       for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
00119          iSectionStart != sectionStarts.end(); ++iSectionStart) {
00120          SectionStarts_t::iterator next = iSectionStart;
00121          ++next;
00122          if (next == sectionStarts.end()) {
00123             iSectionStart->fSize = (words.end() - iSectionStart->fStart);
00124             break;
00125          }
00126          iSectionStart->fSize = (next->fStart - iSectionStart->fStart);
00127       }
00128    }
00129 
00130    static void Sections_PostMerge(SectionStarts_t& sectionStarts, const size_t maxPerSection)
00131    {
00132       // Merge sections that ended up being too small, up to maxPerSection entries
00133       for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
00134          iSectionStart != sectionStarts.end();) {
00135          SectionStarts_t::iterator iNextSectionStart = iSectionStart;
00136          ++iNextSectionStart;
00137          if (iNextSectionStart == sectionStarts.end()) break;
00138          if (iNextSectionStart->fSize + iSectionStart->fSize < maxPerSection) {
00139             iSectionStart->fSize += iNextSectionStart->fSize;
00140             sectionStarts.erase(iNextSectionStart);
00141          } else ++iSectionStart;
00142       }
00143    }
00144 
00145    static void GetIndexChars(const Words_t& words, UInt_t numSectionsIn,
00146       std::vector<std::string> &sectionMarkersOut)
00147    {
00148       // Given a list of words (class names, in this case), this function builds an
00149       // optimal set of about numSectionIn sections (even if almost all words start
00150       // with a "T"...), and returns the significant characters for each section start
00151       // in sectionMarkersOut.
00152 
00153       const size_t maxPerSection = (words.size() + numSectionsIn - 1)/ numSectionsIn;
00154       SectionStarts_t sectionStarts;
00155       Sections_BuildIndex(sectionStarts, words.begin(), words.end(), maxPerSection);
00156       Sections_SetSize(sectionStarts, words);
00157       Sections_PostMerge(sectionStarts, maxPerSection);
00158 
00159       // convert to index markers
00160       sectionMarkersOut.clear();
00161       sectionMarkersOut.resize(sectionStarts.size());
00162       size_t idx = 0;
00163       for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
00164          iSectionStart != sectionStarts.end(); ++iSectionStart)
00165          sectionMarkersOut[idx++] =
00166             iSectionStart->fStart->substr(0, iSectionStart->fChars);
00167    }
00168 
00169    static void GetIndexChars(const std::list<std::string>& wordsIn, UInt_t numSectionsIn,
00170       std::vector<std::string> &sectionMarkersOut)
00171    {
00172       // initialize word vector
00173       Words_t words(wordsIn.size());
00174       size_t idx = 0;
00175       for (std::list<std::string>::const_iterator iWord = wordsIn.begin(); iWord != wordsIn.end(); ++iWord)
00176          words[idx++] = *iWord;
00177       GetIndexChars(words, numSectionsIn, sectionMarkersOut);
00178    }
00179 
00180 }
00181 
00182 extern "C" { // std::qsort on solaris wants the sorter to be extern "C"
00183 
00184    //______________________________________________________________________________
00185    static int CaseInsensitiveSort(const void *name1, const void *name2)
00186    {
00187    // Friend function for sorting strings, case insensitive
00188    //
00189    //
00190    // Input: name1 - pointer to the first string
00191    //        name2 - pointer to the second string
00192    //
00193    //  NOTE: This function compares its arguments and returns an integer less
00194    //        than, equal to, or greater than zero, depending on whether name1
00195    //        is lexicographically less than, equal to, or greater than name2,
00196    //        but characters are forced to lower-case prior to comparison.
00197    //
00198    //
00199 
00200       return (strcasecmp(*((char **) name1), *((char **) name2)));
00201    }
00202 }
00203 
00204 namespace {
00205 
00206    // std::list::sort(with_stricmp_predicate) doesn't work with Solaris CC...
00207    static void sort_strlist_stricmp(std::vector<std::string>& l)
00208    {
00209       // sort strings ignoring case - easier for humans
00210       struct posList {
00211          const char* str;
00212          size_t pos;
00213       };
00214       posList* carr = new posList[l.size()];
00215       size_t idx = 0;
00216       for (size_t iS = 0, iSE = l.size(); iS < iSE; ++iS) {
00217          carr[idx].pos = iS;
00218          carr[idx++].str = l[iS].c_str();
00219       }
00220       qsort(&carr[0].str, idx, sizeof(posList), CaseInsensitiveSort);
00221       std::vector<std::string> lsort(l.size());
00222       for (size_t iS = 0, iSE = l.size(); iS < iSE; ++iS) {
00223          lsort[iS].swap(l[carr[iS].pos]);
00224       }
00225       delete [] carr;
00226       l.swap(lsort);
00227    }
00228 
00229 }
00230 
00231 //______________________________________________________________________________
00232 //
00233 // THtml generated documentation is written to file by TDocOutput. So far only
00234 // output of HTML is implemented. Customization of the output should be done
00235 // with THtml's interfaces - TDocOutput should not be used nor re-implemented
00236 // directly.
00237 //
00238 // TDocOutput generates the index tables:
00239 // * classes (THtml invokes TClassDocOutput for each),
00240 // * inheritance hierarchy,
00241 // * types and typedefs,
00242 // * libraries,
00243 // * the product index, and
00244 // * the module index (including the links to per-module documentation).
00245 // It invokes AT&T's GraphViz tool (dot) if available; charts benefit a lot
00246 // from it.
00247 //
00248 // TDocOutput also writes all pages' header and footer, which can be customized
00249 // by calling THtml::SetHeader(), THtml::SetFooter().
00250 //______________________________________________________________________________
00251 
00252 ClassImp(TDocOutput);
00253 
00254 //______________________________________________________________________________
00255 TDocOutput::TDocOutput(THtml& html): fHtml(&html)
00256 {}
00257 
00258 //______________________________________________________________________________
00259 TDocOutput::~TDocOutput()
00260 {}
00261 
00262 //______________________________________________________________________________
00263 void TDocOutput::AddLink(TSubString& str, TString& link, const char* comment)
00264 {
00265    // Add a link around str, with title comment.
00266    // Update str so it surrounds the link.
00267 
00268    // prepend "./" to allow callers to replace a different relative directory
00269    if (ReferenceIsRelative(link) && !link.BeginsWith("./"))
00270       link.Prepend("./");
00271    link.Prepend("<a href=\"");
00272    link += "\"";
00273    if (comment && strlen(comment)) {
00274       link += " title=\"";
00275       TString description(comment);
00276       ReplaceSpecialChars(description);
00277       description.ReplaceAll("\"", "&quot;");
00278       link += description;
00279       link += "\"";
00280    }
00281    link += ">";
00282 
00283    str.String().Insert(str.Start() + str.Length(), "</a>");
00284    str.String().Insert(str.Start(), link);
00285 
00286    TString &strString = str.String();
00287    TSubString update = strString(str.Start(), str.Length() + link.Length() + 4);
00288    str = update;
00289 }
00290 
00291 //______________________________________________________________________________
00292 void TDocOutput::AdjustSourcePath(TString& line, const char* relpath /*= "../"*/)
00293 {
00294    // adjust the path of links for source files, which are in src/, but need
00295    // to point to relpath (usually "../"). Simply replaces "=\"./" by "=\"../"
00296 
00297    TString replWithRelPath("=\"@!@");
00298    line.ReplaceAll("=\"../", replWithRelPath + "../" + relpath);
00299    line.ReplaceAll("=\"./", replWithRelPath + relpath);
00300    line.ReplaceAll("=\"@!@","=\"");
00301 }
00302 
00303 //______________________________________________________________________________
00304 void TDocOutput::Convert(std::istream& in, const char* infilename,
00305                          const char* outfilename, const char *title,
00306                          const char *relpath /*= "../"*/, Int_t includeOutput /*=0*/,
00307                          const char* context /*= ""*/,
00308                          TGClient* gclient /*= 0*/)
00309 {
00310    // Convert a text file into a html file.
00311    // outfilename doesn't have an extension yet; up to us to decide.
00312    // We generate HTML, so our extension is ".html".
00313    // See THtml::Convert() for the other parameters.
00314 
00315    TString htmlFilename(outfilename);
00316    htmlFilename += ".html";
00317 
00318    std::ofstream out(htmlFilename);
00319 
00320    if (!out.good()) {
00321       Error("Convert", "Can't open file '%s' !", htmlFilename.Data());
00322       return;
00323    }
00324 
00325    // write a HTML header
00326    WriteHtmlHeader(out, title, relpath);
00327 
00328    if (context && context[0])
00329       out << context << endl;
00330    else if (title && title[0])
00331       out << "<h1 class=\"convert\">" << title << "</h1>" << endl;
00332 
00333    Int_t numReuseCanvases = 0;
00334    if (includeOutput && !(includeOutput & THtml::kForceOutput)) {
00335       void* dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
00336       if (dirHandle) {
00337          FileStat_t infile_stat;
00338          if (!gSystem->GetPathInfo(infilename, infile_stat)) {
00339             // can stat.
00340             const char* outfile = 0;
00341             TString firstCanvasFileBase(gSystem->BaseName(outfilename));
00342             firstCanvasFileBase += "_0.png";
00343             // first check whether the firstCanvasFile exists:
00344             Bool_t haveFirstCanvasFile = false;
00345             while ((outfile = gSystem->GetDirEntry(dirHandle))) {
00346                if (firstCanvasFileBase == outfile) {
00347                   haveFirstCanvasFile = true;
00348                   break;
00349                }
00350             }
00351             gSystem->FreeDirectory(dirHandle);
00352 
00353             FileStat_t outfile_stat;
00354             TString firstCanvasFile = outfilename;
00355             firstCanvasFile += "_0.png";
00356             Int_t maxIdx = -1;
00357             if (haveFirstCanvasFile && !gSystem->GetPathInfo(firstCanvasFile, outfile_stat)
00358                 && outfile_stat.fMtime > infile_stat.fMtime) {
00359                // the first canvas file exists and it is newer than the script, so we reuse
00360                // the canvas files. We need to know how many there are:
00361                dirHandle = gSystem->OpenDirectory(gSystem->DirName(htmlFilename));
00362                TString stem(gSystem->BaseName(outfilename));
00363                stem += "_";
00364                TString dir(gSystem->DirName(htmlFilename));
00365                while ((outfile = gSystem->GetDirEntry(dirHandle))) {
00366                   if (strncmp(outfile, stem, stem.Length()))
00367                      continue;
00368                   const char* posext = strrchr(outfile, '.');
00369                   if (!posext || strcmp(posext, ".png"))
00370                      continue;
00371 
00372                   // extract the mod time of the PNG file
00373                   if (gSystem->GetPathInfo(dir + "/" + outfile, outfile_stat))
00374                      // can't stat!
00375                      continue;
00376 
00377                   if (outfile_stat.fMtime > infile_stat.fMtime) {
00378                      ++numReuseCanvases;
00379                      // The canvas PNG is newer than the script, so
00380                      // extract the index of the canvas
00381                      TString idxStr(outfile + stem.Length());
00382                      idxStr.Remove(idxStr.Length() - 4);
00383                      Int_t idx = idxStr.Atoi();
00384                      if (maxIdx < idx)
00385                         maxIdx = idx;
00386                   }
00387                }
00388                gSystem->FreeDirectory(dirHandle);
00389                if (maxIdx + 1 != numReuseCanvases)
00390                   // bad: the number of canvases to reuse noes not correspond to the highest index we saw.
00391                   // we will need to regenerate evrything.
00392                   numReuseCanvases = 0;
00393             }
00394          } // infile can be stat'ed
00395       } // can open output directory
00396    } // canvases wanted
00397 
00398    if (numReuseCanvases)
00399       Printf("Convert: %s (reusing %d saved canvas%s)", htmlFilename.Data(), numReuseCanvases, (numReuseCanvases > 1 ? "es" : ""));
00400    else
00401       Printf("Convert: %s", htmlFilename.Data());
00402 
00403    UInt_t nCanvases = numReuseCanvases;
00404    if (includeOutput) {
00405       if (!numReuseCanvases) {
00406          // need to run the script
00407          if (includeOutput & THtml::kSeparateProcessOutput) {
00408             TString baseInFileName = gSystem->BaseName(infilename);
00409             TPMERegexp reOutFile(baseInFileName + "_[[:digit:]]+\\.png");
00410 
00411             // remove all files matching what saveScriptOutput.C could produce:
00412             void* outdirH = gSystem->OpenDirectory(gSystem->DirName(outfilename));
00413             if (outdirH) {
00414                // the directory exists.
00415                const char* outdirE = 0;
00416                while ((outdirE = gSystem->GetDirEntry(outdirH))) {
00417                   if (reOutFile.Match(outdirE)) {
00418                      gSystem->Unlink(outdirE);
00419                   }
00420                }
00421                gSystem->FreeDirectory(outdirH);
00422             }
00423 
00424             gSystem->Exec(TString::Format("ROOT_HIST=0 root.exe -l -q %s $ROOTSYS/etc/html/saveScriptOutput.C\\(\\\"%s\\\",\\\"%s\\\",%d\\)",
00425                           gROOT->IsBatch() ? "-b" : "",
00426                           infilename,
00427                           gSystem->DirName(outfilename),
00428                           includeOutput & THtml::kCompiledOutput));
00429 
00430             // determine how many output files were created:
00431             outdirH = gSystem->OpenDirectory(gSystem->DirName(outfilename));
00432             if (outdirH) {
00433                // the directory exists.
00434                const char* outdirE = 0;
00435                while ((outdirE = gSystem->GetDirEntry(outdirH))) {
00436                   if (reOutFile.Match(outdirE)) {
00437                      ++nCanvases;
00438                   }
00439                }
00440                gSystem->FreeDirectory(outdirH);
00441             }
00442          } else {
00443             // run in this ROOT process
00444             TString pwd(gSystem->pwd());
00445             gSystem->cd(gSystem->DirName(infilename));
00446 
00447             TList* gClientGetListOfWindows = 0;
00448             TObject* gClientGetDefaultRoot = 0;
00449             std::set<TObject*> previousWindows;
00450             if (gclient) {
00451                gROOT->ProcessLine(TString::Format("*((TList**)0x%lx) = ((TGClient*)0x%lx)->GetListOfWindows();",
00452                                                   (ULong_t)&gClientGetListOfWindows, (ULong_t)gclient));
00453                gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGClient*)0x%lx)->GetDefaultRoot();",
00454                                                   (ULong_t)&gClientGetDefaultRoot, (ULong_t)gclient));
00455                TObject* win = 0;
00456                TIter iWin(gClientGetListOfWindows);
00457                while((win = iWin())) {
00458                   TObject* winGetParent = 0;
00459                   gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
00460                                                      (ULong_t)&winGetParent, (ULong_t)win));
00461                   if (winGetParent == gClientGetDefaultRoot)
00462                      previousWindows.insert(win);
00463                }
00464             } else {
00465                if (gROOT->GetListOfCanvases()->GetSize())
00466                   previousWindows.insert(gROOT->GetListOfCanvases()->Last());
00467             }
00468             TIter iTimer(gSystem->GetListOfTimers());
00469             std::set<TObject*> timersBefore;
00470             TObject* timerOld = 0;
00471             while ((timerOld = iTimer()))
00472                timersBefore.insert(timerOld);
00473 
00474             TString cmd(".x ");
00475             cmd += gSystem->BaseName(infilename);
00476             if (includeOutput & THtml::kCompiledOutput)
00477                cmd += "+";
00478             gInterpreter->SaveContext();
00479             gInterpreter->SaveGlobalsContext();
00480             Int_t err;
00481             gROOT->ProcessLine(cmd, &err);
00482             gSystem->ProcessEvents();
00483             gSystem->cd(pwd);
00484 
00485             if (err == TInterpreter::kNoError) {
00486                if (gclient) {
00487                   TClass* clRootCanvas = TClass::GetClass("TRootCanvas");
00488                   TClass* clGMainFrame = TClass::GetClass("TGMainFrame");
00489                   TObject* win = 0;
00490                   TIter iWin(gClientGetListOfWindows);
00491                   while((win = iWin())) {
00492                      TObject* winGetParent = 0;
00493                      gROOT->ProcessLine(TString::Format("*((TObject**)0x%lx) = ((TGWindow*)0x%lx)->GetParent();",
00494                                                         (ULong_t)&winGetParent, (ULong_t)win));
00495                      Bool_t winIsMapped = kFALSE;
00496                      if (winGetParent == gClientGetDefaultRoot)
00497                         gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TGWindow*)0x%lx)->IsMapped();",
00498                                                            (ULong_t)&winIsMapped, (ULong_t)win));
00499                      if (winIsMapped && previousWindows.find(win) == previousWindows.end()
00500                          && win->InheritsFrom(clGMainFrame)) {
00501                         gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->MapRaised();", (ULong_t)win));
00502                         Bool_t isRootCanvas = win->InheritsFrom(clRootCanvas);
00503                         Bool_t hasEditor = false;
00504                         if (isRootCanvas) {
00505                            gROOT->ProcessLine(TString::Format("*((Bool_t*)0x%lx) = ((TRootCanvas*)0x%lx)->HasEditor();",
00506                                                               (ULong_t)&hasEditor, (ULong_t)win));
00507                         }
00508                         if (isRootCanvas && !hasEditor) {
00509                            TVirtualPad* pad = 0;
00510                            gROOT->ProcessLine(TString::Format("*((TVirtualPad**)0x%lx) = ((TRootCanvas*)0x%lx)->Canvas();",
00511                                                               (ULong_t)&pad, (ULong_t)win));
00512                            if (!pad->HasViewer3D() || pad->GetViewer3D()->InheritsFrom("TViewer3DPad")) {
00513                               pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
00514                            }
00515                         } else
00516                            gROOT->ProcessLine(TString::Format("((TGWindow*)0x%lx)->SaveAs(\"%s_%d.png\");",
00517                                                               (ULong_t)win, outfilename, nCanvases++));
00518                      }
00519                   }
00520                } else {
00521                   // no gClient
00522                   TVirtualPad* pad = 0;
00523                   TVirtualPad* last = 0;
00524                   if (!previousWindows.empty())
00525                      last = (TVirtualPad*) *previousWindows.begin();
00526                   TIter iCanvas(gROOT->GetListOfCanvases());
00527                   while ((pad = (TVirtualPad*) iCanvas())) {
00528                      if (last) {
00529                         if (last == pad) last = 0;
00530                         continue;
00531                      }
00532                      pad->SaveAs(TString::Format("%s_%d.png", outfilename, nCanvases++));
00533                   }
00534                }
00535                gInterpreter->Reset();
00536                gInterpreter->ResetGlobals();
00537                TIter iTimerRemove(gSystem->GetListOfTimers());
00538                TTimer* timer = 0;
00539                while ((timer = (TTimer*) iTimerRemove()))
00540                   if (timersBefore.find(timer) == timersBefore.end())
00541                      gSystem->RemoveTimer(timer);
00542             }
00543          } // run script in this ROOT process
00544       }
00545       out << "<table><tr><td style=\"vertical-align:top;padding-right:2em;\">" << endl;
00546    }
00547    out << "<div class=\"listing\"><pre class=\"listing\">" << endl;
00548 
00549    TDocParser parser(*this);
00550    parser.Convert(out, in, relpath, (includeOutput) /* determines whether it's code or not */,
00551                   kFALSE /*interpretDirectives*/);
00552 
00553    out << "</pre></div>" << endl;
00554 
00555    WriteLineNumbers(out, parser.GetLineNumber(), gSystem->BaseName(infilename));
00556 
00557    if (includeOutput) {
00558       out << "</td><td style=\"vertical-align:top;\">" << endl;
00559       out << "<table>" << endl;
00560       for (UInt_t i = 0; i < nCanvases; ++i) {
00561          TString pngname = TString::Format("%s_%d.png", gSystem->BaseName(outfilename), i);
00562          out << "<tr><td><a href=\"" << pngname << "\">" << endl
00563              << "<img src=\"" << pngname << "\" id=\"canv" << i << "\" alt=\"thumb\" style=\"border:none;width:22em;\" "
00564             "onmouseover=\"javascript:canv" << i << ".style.width='auto';\" />" << endl
00565              << "</a></td></tr>" << endl;
00566          }
00567       out << "</table>" << endl;
00568       out << "</td></tr></table>" << endl;
00569    }
00570 
00571    // write a HTML footer
00572    WriteHtmlFooter(out, relpath);
00573 }
00574 
00575 //______________________________________________________________________________
00576 Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName)
00577 {
00578 // Copy file to HTML directory
00579 //
00580 //
00581 //  Input: sourceName - source file name (fully qualified i.e. file system path)
00582 //         destName   - optional destination name, if not
00583 //                      specified it would be the same
00584 //                      as the source file name
00585 //
00586 // Output: TRUE if file is successfully copied, or
00587 //         FALSE if it's not
00588 //
00589 //
00590 //   NOTE: The destination directory is always fHtml->GetOutputDir()
00591 //
00592 
00593    R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
00594 
00595    TString sourceFile(sourceName);
00596 
00597    if (!sourceFile.Length()) {
00598       Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName,
00599             fHtml->GetOutputDir().Data());
00600       return kFALSE;
00601    }
00602 
00603    // destination file name
00604    TString destFile;
00605    if (!destName || !*destName)
00606       destFile = gSystem->BaseName(sourceFile);
00607    else
00608       destFile = gSystem->BaseName(destName);
00609 
00610    gSystem->PrependPathName(fHtml->GetOutputDir(), destFile);
00611 
00612    // Get info about a file
00613    Long64_t size;
00614    Long_t id, flags, sModtime, dModtime;
00615    sModtime = 0;
00616    dModtime = 0;
00617    if (gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)
00618       || gSystem->GetPathInfo(destFile, &id, &size, &flags, &dModtime)
00619       || sModtime > dModtime)
00620       gSystem->CopyFile(sourceFile, destFile, kTRUE);
00621 
00622    return kTRUE;
00623 }
00624 
00625 
00626 
00627 //______________________________________________________________________________
00628 void TDocOutput::CreateHierarchy()
00629 {
00630 // Create a hierarchical class list
00631 // The algorithm descends from the base classes and branches into
00632 // all derived classes. Mixing classes are displayed several times.
00633 //
00634 //
00635 
00636    // if (CreateHierarchyDot()) return;
00637 
00638    TString filename("ClassHierarchy.html");
00639    gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
00640 
00641    // open out file
00642    std::ofstream out(filename);
00643 
00644    if (!out.good()) {
00645       Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
00646       return;
00647    }
00648 
00649    Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
00650 
00651    // write out header
00652    WriteHtmlHeader(out, "Class Hierarchy");
00653 
00654    WriteTopLinks(out, 0);
00655 
00656    out << "<h1>Class Hierarchy</h1>" << endl;
00657 
00658 
00659    // loop on all classes
00660    TClassDocInfo* cdi = 0;
00661    TIter iClass(fHtml->GetListOfClasses());
00662    while ((cdi = (TClassDocInfo*)iClass())) {
00663       if (!cdi->HaveSource())
00664          continue;
00665 
00666       // get class
00667       TDictionary *dictPtr = cdi->GetClass();
00668       TClass *basePtr = dynamic_cast<TClass*>(dictPtr);
00669       if (basePtr == 0) {
00670          if (!dictPtr)
00671             Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
00672          continue;
00673       }
00674 
00675       TClassDocOutput cdo(*fHtml, basePtr, 0);
00676       cdo.CreateClassHierarchy(out, cdi->GetHtmlFileName());
00677    }
00678 
00679    // write out footer
00680    WriteHtmlFooter(out);
00681 }
00682 
00683 //______________________________________________________________________________
00684 void TDocOutput::CreateClassIndex()
00685 {
00686 // Create index of all classes
00687 //
00688 
00689    // create CSS file, we need it
00690    fHtml->CreateAuxiliaryFiles();
00691 
00692    TString filename("ClassIndex.html");
00693    gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
00694 
00695    // open indexFile file
00696    std::ofstream indexFile(filename.Data());
00697 
00698    if (!indexFile.good()) {
00699       Error("CreateClassIndex", "Can't open file '%s' !", filename.Data());
00700       return;
00701    }
00702 
00703    Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
00704 
00705    // write indexFile header
00706    WriteHtmlHeader(indexFile, "Class Index");
00707 
00708    WriteTopLinks(indexFile, 0);
00709 
00710    indexFile << "<h1>Class Index</h1>" << endl;
00711 
00712    WriteModuleLinks(indexFile);
00713 
00714    std::vector<std::string> indexChars;
00715    if (fHtml->GetListOfClasses()->GetSize() > 10) {
00716       std::vector<std::string> classNames;
00717       {
00718          TIter iClass(fHtml->GetListOfClasses());
00719          TClassDocInfo* cdi = 0;
00720          while ((cdi = (TClassDocInfo*)iClass()))
00721             if (cdi->IsSelected() && cdi->HaveSource())
00722                classNames.push_back(cdi->GetName());
00723       }
00724 
00725       if (classNames.size() > 10) {
00726          indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
00727          // find index chars
00728          GetIndexChars(classNames, 50 /*sections*/, indexChars);
00729          for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
00730             indexFile << "<a href=\"#idx" << iIdxEntry << "\">";
00731             ReplaceSpecialChars(indexFile, indexChars[iIdxEntry].c_str());
00732             indexFile << "</a>" << endl;
00733          }
00734          indexFile << "</div><br />" << endl;
00735       }
00736    }
00737 
00738    indexFile << "<ul id=\"indx\">" << endl;
00739 
00740    // loop on all classes
00741    UInt_t currentIndexEntry = 0;
00742    TIter iClass(fHtml->GetListOfClasses());
00743    TClassDocInfo* cdi = 0;
00744    Int_t i = 0;
00745    while ((cdi = (TClassDocInfo*)iClass())) {
00746       if (!cdi->IsSelected() || !cdi->HaveSource())
00747          continue;
00748 
00749       // get class
00750       TDictionary *currentDict = cdi->GetClass();
00751       TClass* currentClass = dynamic_cast<TClass*>(currentDict);
00752       if (!currentClass) {
00753          if (!currentDict)
00754             Warning("THtml::CreateClassIndex", "skipping class %s\n", cdi->GetName());
00755          continue;
00756       }
00757 
00758       indexFile << "<li class=\"idxl" << (i++)%2 << "\">";
00759       if (currentIndexEntry < indexChars.size()
00760          && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
00761                      indexChars[currentIndexEntry].length()))
00762          indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
00763 
00764       TString htmlFile(cdi->GetHtmlFileName());
00765       if (htmlFile.Length()) {
00766          indexFile << "<a href=\"";
00767          indexFile << htmlFile;
00768          indexFile << "\"><span class=\"typename\">";
00769          ReplaceSpecialChars(indexFile, cdi->GetName());
00770          indexFile << "</span></a> ";
00771       } else {
00772          indexFile << "<span class=\"typename\">";
00773          ReplaceSpecialChars(indexFile, cdi->GetName());
00774          indexFile << "</span> ";
00775       }
00776 
00777       // write title == short doc
00778       ReplaceSpecialChars(indexFile, currentClass->GetTitle());
00779       indexFile << "</li>" << endl;
00780    }
00781 
00782    indexFile << "</ul>" << endl;
00783 
00784    // write indexFile footer
00785    WriteHtmlFooter(indexFile);
00786 }
00787 
00788 
00789 //______________________________________________________________________________
00790 void TDocOutput::CreateModuleIndex()
00791 {
00792    // Create the class index for each module, picking up documentation from the
00793    // module's TModuleDocInfo::GetInputPath() plus the (possibly relative)
00794    // THtml::GetModuleDocPath(). Also creates the library dependency plot if dot
00795    // exists, see THtml::HaveDot().
00796 
00797    const char* title = "LibraryDependencies";
00798    TString dotfilename(title);
00799    gSystem->PrependPathName(fHtml->GetOutputDir(), dotfilename);
00800 
00801    std::ofstream libDepDotFile(dotfilename + ".dot");
00802    libDepDotFile << "digraph G {" << endl
00803                  << "ratio=compress;" << endl
00804                  << "node [fontsize=22,labeldistance=0.1];" << endl
00805                  << "edge [len=0.01];" << endl
00806                  << "fontsize=22;" << endl
00807                  << "size=\"16,16\";" << endl
00808                  << "overlap=false;" << endl
00809                  << "splines=true;" << endl
00810                  << "K=0.1;" << endl;
00811 
00812    TModuleDocInfo* module = 0;
00813    TIter iterModule(fHtml->GetListOfModules());
00814 
00815    std::stringstream sstrCluster;
00816    std::stringstream sstrDeps;
00817    while ((module = (TModuleDocInfo*)iterModule())) {
00818       if (!module->IsSelected())
00819          continue;
00820 
00821       std::vector<std::string> indexChars;
00822       TString filename(module->GetName());
00823       filename.ToUpper();
00824       filename.ReplaceAll("/","_");
00825       filename += "_Index.html";
00826       gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
00827       std::ofstream outputFile(filename.Data());
00828       if (!outputFile.good()) {
00829          Error("CreateModuleIndex", "Can't open file '%s' !", filename.Data());
00830          continue;
00831       }
00832       Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
00833 
00834       TString htmltitle("Index of ");
00835       TString moduletitle(module->GetName());
00836       moduletitle.ToUpper();
00837       htmltitle += moduletitle;
00838       WriteHtmlHeader(outputFile, htmltitle);
00839 
00840       WriteTopLinks(outputFile, module);
00841 
00842       outputFile << "<h2>" << htmltitle << "</h2>" << endl;
00843 
00844       // Module doc
00845       if (GetHtml()->GetModuleDocPath().Length()) {
00846          TString outdir(module->GetName());
00847          gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir);
00848 
00849          TString moduleDocDir;
00850          GetHtml()->GetPathDefinition().GetDocDir(module->GetName(), moduleDocDir);
00851          ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName());
00852       }
00853 
00854       WriteModuleLinks(outputFile, module);
00855 
00856       std::list<std::string> classNames;
00857       {
00858          TIter iClass(module->GetClasses());
00859          TClassDocInfo* cdi = 0;
00860          while ((cdi = (TClassDocInfo*) iClass())) {
00861             if (!cdi->IsSelected() || !cdi->HaveSource())
00862                continue;
00863             classNames.push_back(cdi->GetName());
00864 
00865             if (classNames.size() > 1) continue;
00866 
00867             TClass* cdiClass = dynamic_cast<TClass*>(cdi->GetClass());
00868             if (!cdiClass)
00869                continue;
00870 
00871             TString libs(cdiClass->GetSharedLibs());
00872             Ssiz_t posDepLibs = libs.Index(' ');
00873             TString thisLib(libs);
00874             if (posDepLibs != kNPOS)
00875                thisLib.Remove(posDepLibs, thisLib.Length());
00876 
00877             {
00878                Ssiz_t posExt = thisLib.First('.');
00879                if (posExt != kNPOS)
00880                   thisLib.Remove(posExt, thisLib.Length());
00881             }
00882 
00883             if (!thisLib.Length())
00884                continue;
00885 
00886             // allocate entry, even if no dependencies
00887             TLibraryDocInfo *libdeps =
00888                (TLibraryDocInfo*)fHtml->GetLibraryDependencies()->FindObject(thisLib);
00889             if (!libdeps) {
00890                libdeps = new TLibraryDocInfo(thisLib);
00891                fHtml->GetLibraryDependencies()->Add(libdeps);
00892             }
00893             libdeps->AddModule(module->GetName());
00894             if (posDepLibs != kNPOS) {
00895                std::string lib;
00896                for(Ssiz_t pos = posDepLibs + 1; libs[pos]; ++pos) {
00897                   if (libs[pos] == ' ') {
00898                      if (thisLib.Length() && lib.length()) {
00899                         size_t posExt = lib.find('.');
00900                         if (posExt != std::string::npos)
00901                            lib.erase(posExt);
00902                         libdeps->AddDependency(lib);
00903                      }
00904                      lib.erase();
00905                   } else
00906                      lib += libs[pos];
00907                }
00908                if (lib.length() && thisLib.Length()) {
00909                   size_t posExt = lib.find('.');
00910                   if (posExt != std::string::npos)
00911                      lib.erase(posExt);
00912                   libdeps->AddDependency(lib);
00913                }
00914             } // if dependencies
00915          } // while next class in module
00916       } // just a scope block
00917 
00918       TIter iClass(module->GetClasses());
00919       TClassDocInfo* cdi = 0;
00920       UInt_t count = 0;
00921       UInt_t currentIndexEntry = 0;
00922       while ((cdi = (TClassDocInfo*) iClass())) {
00923          if (!cdi->IsSelected() || !cdi->HaveSource())
00924             continue;
00925 
00926          TDictionary *classPtr = cdi->GetClass();
00927          if (!classPtr) {
00928             Error("CreateModuleIndex", "Unknown class '%s' !", cdi->GetName());
00929             continue;
00930          }
00931 
00932          if (!count) {
00933             outputFile << "<h2>Class Index</h2>" << endl;
00934 
00935             if (classNames.size() > 10) {
00936                outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
00937                UInt_t numSections = classNames.size() / 10;
00938                if (numSections < 10) numSections = 10;
00939                if (numSections > 50) numSections = 50;
00940                // find index chars
00941                GetIndexChars(classNames, numSections, indexChars);
00942                for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
00943                   outputFile << "<a href=\"#idx" << iIdxEntry << "\">";
00944                   ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str());
00945                   outputFile << "</a>" << endl;
00946                }
00947                outputFile << "</div><br />" << endl;
00948             }
00949 
00950             outputFile << "<ul id=\"indx\">" << endl;
00951          }
00952 
00953          // write a classname to an index file
00954          outputFile << "<li class=\"idxl" << (count++)%2 << "\">";
00955          if (currentIndexEntry < indexChars.size()
00956             && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(),
00957                         indexChars[currentIndexEntry].length()))
00958             outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
00959 
00960          TString htmlFile(cdi->GetHtmlFileName());
00961          if (htmlFile.Length()) {
00962             outputFile << "<a href=\"";
00963             outputFile << htmlFile;
00964             outputFile << "\"><span class=\"typename\">";
00965             ReplaceSpecialChars(outputFile, classPtr->GetName());
00966             outputFile << "</span></a> ";
00967          } else {
00968             outputFile << "<span class=\"typename\">";
00969             ReplaceSpecialChars(outputFile, classPtr->GetName());
00970             outputFile << "</span> ";
00971          }
00972 
00973          // write title
00974          ReplaceSpecialChars(outputFile, classPtr->GetTitle());
00975          outputFile << "</li>" << endl;
00976       }
00977 
00978 
00979       if (count)
00980          outputFile << "</ul>" << endl;
00981 
00982       // write outputFile footer
00983       WriteHtmlFooter(outputFile);
00984    } // while next module
00985 
00986    // libCint is missing as we don't have class doc for it
00987    // We need it for dependencies nevertheless, so add it by hand.
00988    /*
00989    sstrCluster << "subgraph clusterlibCint {" << endl
00990       << "style=filled;" << endl
00991       << "color=lightgray;" << endl
00992       << "label=\"libCint\";" << endl
00993       << "\"CINT\" [style=filled,color=white,fontsize=10]" << endl
00994       << "}" << endl;
00995    */
00996 
00997    // simplify the library dependencies, by removing direct links
00998    // that are equivalent to indirect ones, e.g. instead of having both
00999    // A->C, A->B->C, keep only A->B->C.
01000 
01001    TIter iLib(fHtml->GetLibraryDependencies());
01002    TLibraryDocInfo* libinfo = 0;
01003    while ((libinfo = (TLibraryDocInfo*)iLib())) {
01004       if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
01005 
01006       std::set<std::string>& deps = libinfo->GetDependencies();
01007       for (std::set<std::string>::iterator iDep = deps.begin();
01008            iDep != deps.end(); ++iDep) {
01009          Bool_t already_indirect = kFALSE;
01010          for (std::set<std::string>::const_iterator iDep2 = deps.begin();
01011               !already_indirect && iDep2 != deps.end(); ++iDep2) {
01012             if (iDep == iDep2) continue;
01013             TLibraryDocInfo* libinfo2 = (TLibraryDocInfo*)
01014                fHtml->GetLibraryDependencies()->FindObject(iDep2->c_str());
01015             if (!libinfo2) continue;
01016             const std::set<std::string>& deps2 = libinfo2->GetDependencies();
01017             already_indirect |= deps2.find(*iDep) != deps2.end();
01018          }
01019          if (already_indirect) {
01020             std::set<std::string>::iterator iRemove = iDep;
01021             --iDep; // otherwise we cannot do the for loop's ++iDep
01022             deps.erase(*iRemove);
01023          }
01024       } // for library dependencies of module in library
01025    } // for libaries
01026 
01027    iLib.Reset();
01028    while ((libinfo = (TLibraryDocInfo*)iLib())) {
01029       if (!libinfo->GetName() || !libinfo->GetName()[0]) continue;
01030 
01031       const std::set<std::string>& modules = libinfo->GetModules();
01032       if (modules.size() > 1) {
01033          sstrCluster << "subgraph cluster" << libinfo->GetName() << " {" << endl
01034                      << "style=filled;" << endl
01035                      << "color=lightgray;" << endl
01036                      << "label=\"";
01037          if (!strcmp(libinfo->GetName(), "libCore"))
01038             sstrCluster << "Everything depends on ";
01039          sstrCluster << libinfo->GetName() << "\";" << endl;
01040 
01041          for (std::set<std::string>::const_iterator iModule = modules.begin();
01042               iModule != modules.end(); ++iModule) {
01043             sstrCluster << "\"" << *iModule << "\" [style=filled,color=white,URL=\""
01044                         << *iModule << "_Index.html\"];" << endl;
01045          }
01046          sstrCluster << endl
01047                      << "}" << endl;
01048       } else {
01049          // only one module
01050          sstrCluster << "\"" << *modules.begin()
01051                      << "\" [label=\"" << libinfo->GetName()
01052                      << "\",style=filled,color=lightgray,shape=box,URL=\""
01053                      << *modules.begin() << "_Index.html\"];" << endl;
01054       }
01055 
01056       // GetSharedLib doesn't mention libCore or libCint; add them by hand
01057       /*
01058         if (iLibDep->first != "libCore")
01059         sstrDeps << "\"" << iModule->first << "\" -> \"BASE\" [lhead=clusterlibCore];" << endl;
01060         sstrDeps << "\"" << iModule->first << "\" -> \"CINT\" [lhead=clusterlibCint];" << endl;
01061       */
01062 
01063       const std::string& mod = *(modules.begin());
01064       const std::set<std::string>& deps = libinfo->GetDependencies();
01065       for (std::set<std::string>::const_iterator iDep = deps.begin();
01066             iDep != deps.end(); ++iDep) {
01067          // cannot create dependency on iDep directly, use its first module instead.
01068          TLibraryDocInfo* depLibInfo = (TLibraryDocInfo*)
01069             fHtml->GetLibraryDependencies()->FindObject(iDep->c_str());
01070          if (!depLibInfo || depLibInfo->GetModules().empty())
01071             continue; // ouch!
01072 
01073          const std::string& moddep = *(depLibInfo->GetModules().begin());
01074          sstrDeps << "\"" << mod << "\" -> \"" << moddep << "\";" << endl;
01075       }
01076       // make sure libCore ends up at the bottom
01077       sstrDeps << "\"" << mod <<  "\" -> \"CONT\" [style=invis];" << endl;
01078    } // for libs
01079 
01080    libDepDotFile << sstrCluster.str() << endl
01081       << sstrDeps.str();
01082    libDepDotFile << "}" << endl;
01083    libDepDotFile.close();
01084 
01085    std::ofstream out(dotfilename + ".html");
01086    if (!out.good()) {
01087       Error("CreateModuleIndex", "Can't open file '%s.html' !",
01088             dotfilename.Data());
01089       return;
01090    }
01091 
01092    Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (dotfilename + ".html").Data());
01093    // write out header
01094    WriteHtmlHeader(out, "Library Dependencies");
01095 
01096    WriteTopLinks(out, 0);
01097 
01098    out << "<h1>Library Dependencies</h1>" << endl;
01099 
01100    RunDot(dotfilename, &out, kFdp);
01101 
01102    out << "<img alt=\"Library Dependencies\" class=\"classcharts\" usemap=\"#Map" << title << "\" src=\"" << title << ".png\"/>" << endl;
01103 
01104    // write out footer
01105    WriteHtmlFooter(out);
01106 }
01107 
01108 //______________________________________________________________________________
01109 void TDocOutput::CreateProductIndex()
01110 {
01111    // Fetch documentation from THtml::GetProductDocDir() and put it into the
01112    // product index page.
01113 
01114    //TString outFile(GetHtml()->GetProductName());
01115    //outFile += ".html";
01116    TString outFile("index.html");
01117    gSystem->PrependPathName(GetHtml()->GetOutputDir(), outFile);
01118    std::ofstream out(outFile);
01119 
01120    if (!out.good()) {
01121       Error("CreateProductIndex", "Can't open file '%s' !", outFile.Data());
01122       return;
01123    }
01124 
01125    Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
01126 
01127    WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide");
01128 
01129    WriteTopLinks(out, 0);
01130 
01131    out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl;
01132 
01133    TString prodDoc;
01134    if (GetHtml()->GetPathDefinition().GetDocDir("", prodDoc))
01135       ProcessDocInDir(out, prodDoc, GetHtml()->GetOutputDir(), "./");
01136 
01137    WriteModuleLinks(out);
01138 
01139    out << "<h2>Chapters</h2>" << std::endl
01140       << "<h3><a href=\"./ClassIndex.html\">Class Index</a></h3>" << std::endl
01141       << "<p>A complete list of all classes defined in " << GetHtml()->GetProductName() << "</p>" << std::endl
01142       << "<h3><a href=\"./ClassHierarchy.html\">Class Hierarchy</a></h3>" << std::endl
01143       << "<p>A hierarchy graph of all classes, showing each class's base and derived classes</p>" << std::endl
01144       << "<h3><a href=\"./ListOfTypes.html\">Type Index</a></h3>" << std::endl
01145       << "<p>A complete list of all types</p>" << std::endl
01146       << "<h3><a href=\"./LibraryDependencies.html\">Library Dependency</a></h3>" << std::endl
01147       << "<p>A diagram showing all of " << GetHtml()->GetProductName() << "'s libraries and their dependencies</p>" << std::endl;
01148 
01149    WriteHtmlFooter(out);
01150 }
01151 
01152 //______________________________________________________________________________
01153 void TDocOutput::CreateClassTypeDefs()
01154 {
01155    // Create a forwarding page for each typedef pointing to a class.
01156    TDocParser parser(*this);
01157 
01158    TIter iClass(GetHtml()->GetListOfClasses());
01159    TClassDocInfo* cdi = 0;
01160    while ((cdi = (TClassDocInfo*) iClass())) {
01161       if (cdi->GetListOfTypedefs().IsEmpty())
01162          continue;
01163       TIter iTypedefs(&cdi->GetListOfTypedefs());
01164       TDataType* dt = 0;
01165       while ((dt = (TDataType*) iTypedefs())) {
01166          if (gDebug > 0)
01167             Info("CreateClassTypeDefs", "Creating typedef %s to class %s",
01168                  dt->GetName(), cdi->GetName());
01169          // create a filename
01170          TString filename(dt->GetName());
01171          NameSpace2FileName(filename);
01172 
01173          gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
01174 
01175          filename += ".html";
01176 
01177          // open class file
01178          std::ofstream outfile(filename);
01179 
01180          if (!outfile.good()) {
01181             Error("CreateClassTypeDefs", "Can't open file '%s' !", filename.Data());
01182             continue;
01183          }
01184 
01185          WriteHtmlHeader(outfile, dt->GetName());
01186 
01187          outfile << "<a name=\"TopOfPage\"></a>" << endl;
01188 
01189          TString dtName(dt->GetName());
01190          ReplaceSpecialChars(dtName);
01191          TString sTitle("typedef ");
01192          sTitle += dtName;
01193 
01194          TClass* cls = dynamic_cast<TClass*>(cdi->GetClass());
01195          if (cls) {
01196             // show box with lib, include
01197             // needs to go first to allow title on the left
01198             TString sInclude;
01199             TString sLib;
01200             const char* lib=cls->GetSharedLibs();
01201             GetHtml()->GetPathDefinition().GetIncludeAs(cls, sInclude);
01202             if (lib) {
01203                char* libDup=StrDup(lib);
01204                char* libDupSpace=strchr(libDup,' ');
01205                if (libDupSpace) *libDupSpace = 0;
01206                char* libDupEnd=libDup+strlen(libDup);
01207                while (libDupEnd!=libDup)
01208                   if (*(--libDupEnd)=='.') {
01209                      *libDupEnd=0;
01210                      break;
01211                   }
01212                sLib = libDup;
01213                delete[] libDup;
01214             }
01215             outfile << "<script type=\"text/javascript\">WriteFollowPageBox('"
01216                     << sTitle << "','" << sLib << "','" << sInclude << "');</script>" << endl;
01217          }
01218 
01219          TString modulename;
01220          fHtml->GetModuleNameForClass(modulename, cls);
01221          TModuleDocInfo* module = (TModuleDocInfo*) fHtml->GetListOfModules()->FindObject(modulename);
01222          WriteTopLinks(outfile, module, dt->GetName());
01223 
01224          outfile << "<div class=\"dropshadow\"><div class=\"withshadow\">";
01225          outfile << "<h1>" << sTitle << "</h1>" << endl
01226             << "<div class=\"classdescr\">" << endl;
01227 
01228          outfile << dtName << " is a typedef to ";
01229          std::string shortClsName(fHtml->ShortType(cdi->GetName()));
01230          parser.DecorateKeywords(outfile, shortClsName.c_str());
01231          outfile << endl
01232             << "</div>" << std::endl
01233             << "</div></div><div style=\"clear:both;\"></div>" << std::endl;
01234 
01235          // the typedef isn't a data member, but the CSS is applicable nevertheless
01236          outfile << endl << "<div id=\"datamembers\">" << endl
01237             << "<table class=\"data\" cellspacing=\"0\">" << endl;
01238          outfile << "<tr class=\"data";
01239          outfile << "\"><td class=\"datatype\">typedef ";
01240          parser.DecorateKeywords(outfile, dt->GetFullTypeName());
01241          outfile << "</td><td class=\"dataname\">";
01242          ReplaceSpecialChars(outfile, dt->GetName());
01243          if (dt->GetTitle() && dt->GetTitle()[0]) {
01244             outfile << "</td><td class=\"datadesc\">";
01245             ReplaceSpecialChars(outfile, dt->GetTitle());
01246          } else outfile << "</td><td>";
01247          outfile << "</td></tr>" << endl
01248             << "</table></div>" << endl;
01249 
01250          // write footer
01251          WriteHtmlFooter(outfile);
01252 
01253       }
01254    }
01255 }
01256 
01257 //______________________________________________________________________________
01258 void TDocOutput::CreateTypeIndex()
01259 {
01260 // Create index of all data types
01261 
01262    // open file
01263    TString outFile("ListOfTypes.html");
01264    gSystem->PrependPathName(fHtml->GetOutputDir(), outFile);
01265    std::ofstream typesList(outFile);
01266 
01267    if (!typesList.good()) {
01268       Error("CreateTypeIndex", "Can't open file '%s' !", outFile.Data());
01269       return;
01270    }
01271 
01272    Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
01273 
01274    // write typesList header
01275    WriteHtmlHeader(typesList, "List of data types");
01276    typesList << "<h2> List of data types </h2>" << endl;
01277 
01278    typesList << "<dl><dd>" << endl;
01279 
01280    // make loop on data types
01281    std::vector<std::string> typeNames(gROOT->GetListOfTypes()->GetSize());
01282 
01283    {
01284       TDataType *type;
01285       TIter nextType(gROOT->GetListOfTypes());
01286       size_t tnIdx = 0;
01287 
01288       while ((type = (TDataType *) nextType()))
01289          // no templates ('<' and '>'), no idea why the '(' is in here...
01290          if (*type->GetTitle() && !strchr(type->GetName(), '(')
01291              && !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>'))
01292              && type->GetName())
01293             typeNames[tnIdx++] = type->GetName();
01294       typeNames.resize(tnIdx);
01295    }
01296 
01297    sort_strlist_stricmp(typeNames);
01298 
01299    std::vector<std::string> indexChars;
01300    if (typeNames.size() > 10) {
01301       typesList << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
01302       // find index chars
01303       GetIndexChars(typeNames, 10 /*sections*/, indexChars);
01304       for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
01305          typesList << "<a href=\"#idx" << iIdxEntry << "\">";
01306          ReplaceSpecialChars(typesList, indexChars[iIdxEntry].c_str());
01307          typesList << "</a>" << endl;
01308       }
01309       typesList << "</div><br />" << endl;
01310    }
01311 
01312    typesList << "<ul id=\"indx\">" << endl;
01313 
01314    int idx = 0;
01315    UInt_t currentIndexEntry = 0;
01316 
01317    for (std::vector<std::string>::iterator iTypeName = typeNames.begin();
01318       iTypeName != typeNames.end(); ++iTypeName) {
01319       TDataType* type = gROOT->GetType(iTypeName->c_str(), kFALSE);
01320       typesList << "<li class=\"idxl" << idx%2 << "\">";
01321       if (currentIndexEntry < indexChars.size()
01322          && !strncmp(indexChars[currentIndexEntry].c_str(), iTypeName->c_str(),
01323                      indexChars[currentIndexEntry].length()))
01324          typesList << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
01325       typesList << "<a name=\"";
01326       ReplaceSpecialChars(typesList, iTypeName->c_str());
01327       typesList << "\"><span class=\"typename\">";
01328       ReplaceSpecialChars(typesList, iTypeName->c_str());
01329       typesList << "</span></a> ";
01330       ReplaceSpecialChars(typesList, type->GetTitle());
01331       typesList << "</li>" << endl;
01332       ++idx;
01333    }
01334    typesList << "</ul>" << endl;
01335 
01336    // write typesList footer
01337    WriteHtmlFooter(typesList);
01338 
01339    // close file
01340    typesList.close();
01341 
01342 }
01343 
01344 
01345 //______________________________________________________________________________
01346 void TDocOutput::DecorateEntityBegin(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
01347 {
01348    // Add some colors etc to a source entity, contained in str.
01349    // The type of what's contained in str is given by type.
01350    // It's called e.g. by TDocParser::BeautifyLine().
01351    // This function should assume that only str.Begin() is valid.
01352    // When inserting into str.String(), str.Begin() must be updated.
01353 
01354    Ssiz_t originalLen = str.Length();
01355 
01356    switch (type) {
01357       case TDocParser::kCode: break;
01358       case TDocParser::kComment:
01359          str.Insert(pos, "<span class=\"comment\">");
01360          break;
01361       case TDocParser::kDirective:
01362          break;
01363       case TDocParser::kString:
01364          str.Insert(pos, "<span class=\"string\">");
01365          break;
01366       case TDocParser::kKeyword:
01367          str.Insert(pos, "<span class=\"keyword\">");
01368          break;
01369       case TDocParser::kCPP:
01370          str.Insert(pos, "<span class=\"cpp\">");
01371          break;
01372       case TDocParser::kVerbatim:
01373          str.Insert(pos, "<pre>");
01374          break;
01375       default:
01376          Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
01377          return;
01378    }
01379 
01380    Ssiz_t addedLen = str.Length() - originalLen;
01381    pos += addedLen;
01382 }
01383 
01384 //______________________________________________________________________________
01385 void TDocOutput::DecorateEntityEnd(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
01386 {
01387    // Add some colors etc to a source entity, contained in str.
01388    // The type of what's contained in str is given by type.
01389    // It's called e.g. by TDocParser::BeautifyLine().
01390    // This function should assume that only str."End()"
01391    // (i.e. str.Begin()+str.Length()) is valid.
01392    // When inserting into str.String(), str.Length() must be updated.
01393 
01394    Ssiz_t originalLen = str.Length();
01395 
01396    switch (type) {
01397       case TDocParser::kCode: break;
01398       case TDocParser::kComment:
01399          str.Insert(pos, "</span>");
01400          break;
01401       case TDocParser::kDirective:
01402          break;
01403       case TDocParser::kString:
01404          str.Insert(pos, "</span>");
01405          break;
01406       case TDocParser::kKeyword:
01407          str.Insert(pos, "</span>");
01408          break;
01409       case TDocParser::kCPP:
01410          str.Insert(pos, "</span>");
01411          break;
01412       case TDocParser::kVerbatim:
01413          str.Insert(pos, "</pre>");
01414          break;
01415       default:
01416          Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
01417          return;
01418    }
01419    Ssiz_t addedLen = str.Length() - originalLen;
01420    pos += addedLen;
01421 }
01422 
01423 //______________________________________________________________________________
01424 void TDocOutput::FixupAuthorSourceInfo(TString& authors)
01425 {
01426 // Special author treatment; called when TDocParser::fSourceInfo[kInfoAuthor] is set.
01427 // Modifies the author(s) description, which is a comma separated list of tokens
01428 // either in the format
01429 // (i) "FirstName LastName " or
01430 // (ii) "FirstName LastName <link> more stuff"
01431 // The first one generates an XWho link (CERN compatible),
01432 // the second a http link (WORLD compatible), <link> being e.g.
01433 // <mailto:user@host.bla> or <http://www.host.bla/page>.
01434 
01435    TString original(authors);
01436    authors = "";
01437 
01438    TString author;
01439    Ssiz_t pos = 0;
01440    Bool_t firstAuthor = kTRUE;
01441    while (original.Tokenize(author, pos, ",")) {
01442       author.Strip(TString::kBoth);
01443 
01444       if (!firstAuthor)
01445          authors += ", ";
01446       firstAuthor = kFALSE;
01447 
01448       // do we have a link for the current name?
01449       Ssiz_t cLink = author.First('<'); // look for link start tag
01450       if (cLink != kNPOS) {
01451          // split NAME <LINK> POST
01452          // into  <a href="LINK">NAME</a> POST
01453          Ssiz_t endLink = author.Index(">", cLink + 1);
01454          if(endLink == kNPOS)
01455             endLink = author.Length();
01456          authors += "<a href=\"";
01457          authors += author(cLink + 1,  endLink - (cLink + 1));
01458          authors += "\">";
01459          authors += author(0, cLink);
01460          authors += "</a>";
01461          if (endLink != author.Length())
01462             authors += author(endLink + 1, author.Length());
01463       } else {
01464          authors += "<a href=\"";
01465          authors += fHtml->GetXwho();
01466 
01467          // separate Firstname Middlename Lastname by '+'
01468          TString namePart;
01469          Ssiz_t posNamePart = 0;
01470          Bool_t firstNamePart = kTRUE;
01471          while (author.Tokenize(namePart, posNamePart, " ")) {
01472             namePart.Strip(TString::kBoth);
01473             if (!namePart.Length())
01474                continue;
01475             if (isdigit(namePart[0])) continue; //likely a date
01476             if (!firstNamePart)
01477                authors += '+';
01478             firstNamePart = kFALSE;
01479             authors += namePart;
01480          }
01481          authors += "\">";
01482          authors += author;
01483          authors += "</a>";
01484       }
01485    } // while next author
01486 }
01487 
01488 //______________________________________________________________________________
01489 Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type)
01490 {
01491 // Check if file is modified
01492 //
01493 //
01494 //  Input: classPtr - pointer to the class
01495 //         type     - file type to compare with
01496 //                    values: kSource, kInclude, kTree
01497 //
01498 // Output: TRUE     - if file is modified since last time
01499 //         FALSE    - if file is up to date
01500 //
01501 
01502    TString sourceFile;
01503    TString classname(classPtr->GetName());
01504    TString filename;
01505    TString dir;
01506 
01507    switch (type) {
01508    case kSource:
01509       if (classPtr->GetImplFileLine()) {
01510          fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
01511       } else {
01512          fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
01513       }
01514       dir = "src";
01515       gSystem->PrependPathName(fHtml->GetOutputDir(), dir);
01516       filename = classname;
01517       NameSpace2FileName(filename);
01518       gSystem->PrependPathName(dir, filename);
01519       if (classPtr->GetImplFileLine())
01520          filename += ".cxx.html";
01521       else
01522          filename += ".h.html";
01523       break;
01524 
01525    case kInclude:
01526       fHtml->GetDeclFileName(classPtr, kFALSE, filename);
01527       filename = gSystem->BaseName(filename);
01528       fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
01529       gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
01530       break;
01531 
01532    case kTree:
01533       fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
01534       NameSpace2FileName(classname);
01535       gSystem->PrependPathName(fHtml->GetOutputDir(), classname);
01536       filename = classname;
01537       filename += "_Tree.pdf";
01538       break;
01539 
01540    case kDoc:
01541       if (classPtr->GetImplFileLine()) {
01542          fHtml->GetImplFileName(classPtr, kTRUE, sourceFile);
01543       } else {
01544          fHtml->GetDeclFileName(classPtr, kTRUE, sourceFile);
01545       }
01546       filename = classname;
01547       NameSpace2FileName(filename);
01548       gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
01549       filename += ".html";
01550       break;
01551 
01552    default:
01553       Error("IsModified", "Unknown file type !");
01554    }
01555 
01556    R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
01557 
01558    // Get info about a file
01559    Long64_t size;
01560    Long_t id, flags, sModtime, dModtime;
01561 
01562    if (!(gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)))
01563       if (!(gSystem->GetPathInfo(filename, &id, &size, &flags, &dModtime)))
01564          return (sModtime > dModtime);
01565 
01566    return kTRUE;
01567 }
01568 
01569 
01570 //______________________________________________________________________________
01571 void TDocOutput::NameSpace2FileName(TString& name)
01572 {
01573    // Replace "::" in name by "__"
01574    // Replace "<", ">", " ", ",", "~", "=" in name by "_"
01575    // Replace "A::X<A::Y>" by "A::X<-p0Y>",
01576    //         "A::B::X<A::B::Y>" by "A::B::X<-p1Y>", etc
01577 
01578    TString encScope(name);
01579    Ssiz_t posTemplate = encScope.Index('<');
01580    if (posTemplate != kNPOS) {
01581       // strip default template params
01582       name = fHtml->ShortType(name);
01583       TString templateArgs = encScope(posTemplate, encScope.Length());
01584       encScope.Remove(posTemplate, encScope.Length());
01585       // shorten the name a bit:
01586       // convert A::B::X<A::B::Y> to A::X<-p1Y>, i.e.
01587       // the filename A__X_A__Y_ to A__X_-p1Y_
01588       // The rule: if the enclosing scope up to the N-th scope matches,
01589       // the name becomes -pN
01590       Ssiz_t posName = encScope.Last(':');
01591       if (posName != kNPOS) {
01592          Int_t numDblColumn = encScope.CountChar(':');
01593          while (numDblColumn > 1) {
01594             encScope.Remove(posName + 1, encScope.Length());
01595             numDblColumn -= 2;
01596             templateArgs.ReplaceAll(encScope, TString::Format("-p%d", numDblColumn / 2));
01597             encScope.Remove(encScope.Length() - 2, 2);
01598             posName = encScope.Last(':');
01599             if (posName == kNPOS)
01600                break; // should be handled by numDblColumn...
01601          }
01602          name.Replace(posTemplate, name.Length(), templateArgs);
01603       }
01604    }
01605 
01606    if (name.Length() > 240) { // really 240! It might get some extra prefix or extension
01607       // 8.3 is dead, but e.g. ext2 can only hold 255 chars in a file name.
01608       // So mangle name to "beginning_of_name"-h"hash"."extension", where
01609       // beginning_of_name is short enough such that the full name is <255 characters.
01610 
01611       TString hash;
01612       TDocParser::AnchorFromLine(name, hash);
01613       hash.Prepend("-h");
01614       Ssiz_t posDot = name.Last('.');
01615       TString ext;
01616       if (posDot != kNPOS)
01617          ext = name(posDot, name.Length());
01618       Ssiz_t namelen = 240 - hash.Length() - ext.Length();
01619       name = name(0, namelen) + hash + ext;
01620    }
01621 
01622    const char* replaceWhat = ":<> ,~=";
01623    for (Ssiz_t i=0; i < name.Length(); ++i)
01624       if (strchr(replaceWhat, name[i]))
01625          name[i] = '_';
01626 }
01627 
01628 //______________________________________________________________________________
01629 void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir,
01630                                  const char* outdir, const char* linkdir)
01631 {
01632    // Write links to files indir/*.txt, indir/*.html (non-recursive) to out.
01633    // If one of the files is called "index.{html,txt}" it will be
01634    // included in out (instead of copying it to outdir and generating a link
01635    // to linkdir). txt files are passed through Convert().
01636    // The files' links are sorted alphabetically.
01637 
01638    R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
01639 
01640    void * dirHandle = gSystem->OpenDirectory(indir);
01641    if (!dirHandle) return;
01642 
01643    const char* entry = 0;
01644    std::list<std::string> files;
01645    while ((entry = gSystem->GetDirEntry(dirHandle))) {
01646       FileStat_t stat;
01647       TString filename(entry);
01648       gSystem->PrependPathName(indir, filename);
01649       if (gSystem->GetPathInfo(filename, stat)) // funny ret
01650          continue;
01651       if (!R_ISREG(stat.fMode)) continue;
01652 
01653       if (TString(entry).BeginsWith("index.", TString::kIgnoreCase)) {
01654          // This is the part we put directly (verbatim) into the module index.
01655          // If it ends on ".txt" we run Convert first.
01656          if (filename.EndsWith(".txt", TString::kIgnoreCase)) {
01657             std::ifstream in(filename);
01658             if (in) {
01659                out << "<pre>"; // this is what e.g. the html directive expects
01660                TDocParser parser(*this);
01661                parser.Convert(out, in, "./", kFALSE /* no code */, kTRUE /*process Directives*/);
01662                out << "</pre>";
01663             }
01664          } else if (filename.EndsWith(".html", TString::kIgnoreCase)) {
01665             std::ifstream in(filename);
01666             TString line;
01667             while (in) {
01668                if (!line.ReadLine(in)) break;
01669                out << line << endl;
01670             }
01671          } else
01672             files.push_back(filename.Data());
01673       } else
01674          files.push_back(filename.Data());
01675    }
01676 
01677    std::stringstream furtherReading;
01678    files.sort();
01679    for (std::list<std::string>::const_iterator iFile = files.begin();
01680       iFile != files.end(); ++iFile) {
01681       TString filename(iFile->c_str());
01682       if (gSystem->AccessPathName(outdir))
01683          if (gSystem->mkdir(outdir, kTRUE) == -1)
01684             // bad - but let's still try to create the output
01685             Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
01686 
01687       TString outfile(gSystem->BaseName(filename));
01688       gSystem->PrependPathName(outdir, outfile);
01689 
01690       if (!filename.EndsWith(".txt", TString::kIgnoreCase)
01691           && !filename.EndsWith(".html", TString::kIgnoreCase)) {
01692          // copy to outdir, who know whether it's needed...
01693          if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
01694             continue;
01695          continue;
01696       }
01697 
01698       // Just copy and link this page.
01699       if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
01700          // convert first
01701          outfile.Remove(outfile.Length()-3, 3);
01702          outfile += "html";
01703          std::ifstream inFurther(filename);
01704          std::ofstream outFurther(outfile);
01705          if (inFurther && outFurther) {
01706             outFurther << "<pre>"; // this is what e.g. the html directive expects
01707             TDocParser parser(*this);
01708             parser.Convert(outFurther, inFurther, "../", kFALSE /*no code*/, kTRUE /*process Directives*/);
01709             outFurther << "</pre>";
01710          }
01711       } else {
01712          if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
01713             continue;
01714       }
01715       TString showname(gSystem->BaseName(outfile));
01716       furtherReading << "<a class=\"linkeddoc\" href=\"" << linkdir << "/" << showname << "\">";
01717       showname.Remove(showname.Length() - 5, 5); // .html
01718       showname.ReplaceAll("_", " ");
01719       ReplaceSpecialChars(furtherReading, showname);
01720       furtherReading << "</a> " << endl;
01721    }
01722 
01723    gSystem->FreeDirectory(dirHandle);
01724    if (furtherReading.str().length())
01725       out << "<h3>Further Reading</h3><div id=\"furtherreading\">" << endl
01726           << furtherReading.str() << "</div><h3>List of Classes</h3>" << endl;
01727 }
01728 
01729 //______________________________________________________________________________
01730 void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment /*= 0*/)
01731 {
01732    // Create a reference to a class documentation page.
01733    // str encloses the text to create the reference for (e.g. name of instance).
01734    // comment will be added e.g. as tooltip text.
01735    // After the reference is put into str.String(), str will enclose the reference
01736    // and the original text. Example:
01737    // Input:
01738    //  str.String(): "a gHtml test"
01739    //  str.Begin():  2
01740    //  str.Length(): 5
01741    // Output:
01742    //  str.String(): "a <a href="THtml.html">gHtml</a> test"
01743    //  str.Begin():  2
01744    //  str.Length(): 30
01745 
01746    TString link;
01747    fHtml->GetHtmlFileName(entity, link);
01748 
01749    if (comment && !strcmp(comment, entity->GetName()))
01750       comment = "";
01751 
01752    AddLink(str, link, comment);
01753 }
01754 
01755 //______________________________________________________________________________
01756 void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment /*= 0*/)
01757 {
01758    // Create a reference to a data member documentation page.
01759    // str encloses the text to create the reference for (e.g. name of instance).
01760    // comment will be added e.g. as tooltip text.
01761    // After the reference is put into str.String(), str will enclose the reference
01762    // and the original text. Example:
01763    // Input:
01764    //  str.String(): "a gHtml test"
01765    //  str.Begin():  2
01766    //  str.Length(): 5
01767    // Output:
01768    //  str.String(): "a <a href="THtml.html">gHtml</a> test"
01769    //  str.Begin():  2
01770    //  str.Length(): 30
01771    TString link;
01772    TClass* scope = entity->GetClass();
01773    fHtml->GetHtmlFileName(scope, link);
01774    link += "#";
01775 
01776    TString mangledName;
01777    if (scope) {
01778       mangledName = scope->GetName();
01779       NameSpace2FileName(mangledName);
01780       link += mangledName;
01781       link += ":";
01782    }
01783 
01784    mangledName = entity->GetName();
01785    NameSpace2FileName(mangledName);
01786    link += mangledName;
01787 
01788    TString description;
01789    if (!comment) {
01790       description = entity->GetFullTypeName();
01791       description += " ";
01792       if (scope) {
01793          description += scope->GetName();
01794          description += "::";
01795       }
01796       description += entity->GetName();
01797       comment = description.Data();
01798    }
01799 
01800    if (comment && !strcmp(comment, entity->GetName()))
01801       comment = "";
01802 
01803    AddLink(str, link, comment);
01804 }
01805 
01806 //______________________________________________________________________________
01807 void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment /*= 0*/)
01808 {
01809    // Create a reference to a type documentation page.
01810    // str encloses the text to create the reference for (e.g. name of instance).
01811    // comment will be added e.g. as tooltip text.
01812    // After the reference is put into str.String(), str will enclose the reference
01813    // and the original text. Example:
01814    // Input:
01815    //  str.String(): "a gHtml test"
01816    //  str.Begin():  2
01817    //  str.Length(): 5
01818    // Output:
01819    //  str.String(): "a <a href="THtml.html">gHtml</a> test"
01820    //  str.Begin():  2
01821    //  str.Length(): 30
01822 
01823    TString mangledEntity(entity->GetName());
01824    NameSpace2FileName(mangledEntity);
01825 
01826    TString link;
01827    TClassDocInfo* cdi = 0;
01828    bool isClassTypedef = entity->GetType() == -1;
01829    if (isClassTypedef)
01830       /* is class/ struct / union */
01831       isClassTypedef = isClassTypedef && (entity->Property() & 7);
01832    if (isClassTypedef) {
01833       std::string shortTypeName(fHtml->ShortType(entity->GetFullTypeName()));
01834       cdi = (TClassDocInfo*) GetHtml()->GetListOfClasses()->FindObject(shortTypeName.c_str());
01835    }
01836    if (cdi) {
01837       link = mangledEntity + ".html";
01838    } else {
01839       link = "ListOfTypes.html#";
01840       link += mangledEntity;
01841    }
01842 
01843    if (comment && !strcmp(comment, entity->GetName()))
01844       comment = "";
01845 
01846    AddLink(str, link, comment);
01847 }
01848 
01849 //______________________________________________________________________________
01850 void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment /*= 0*/)
01851 {
01852    // Create a reference to a method documentation page.
01853    // str encloses the text to create the reference for (e.g. name of instance).
01854    // comment will be added e.g. as tooltip text.
01855    // After the reference is put into str.String(), str will enclose the reference
01856    // and the original text. Example:
01857    // Input:
01858    //  str.String(): "a gHtml test"
01859    //  str.Begin():  2
01860    //  str.Length(): 5
01861    // Output:
01862    //  str.String(): "a <a href="THtml.html">gHtml</a> test"
01863    //  str.Begin():  2
01864    //  str.Length(): 30
01865 
01866    TString link;
01867    TClass* scope = entity->GetClass();
01868    fHtml->GetHtmlFileName(scope, link);
01869    link += "#";
01870 
01871    TString mangledName(scope->GetName());
01872    NameSpace2FileName(mangledName);
01873    link += mangledName;
01874    link += ":";
01875 
01876    mangledName = entity->GetName();
01877    NameSpace2FileName(mangledName);
01878    link += mangledName;
01879 
01880    TString description;
01881    if (!comment && entity->GetClass()) {
01882       TIter iMeth(scope->GetListOfMethods());
01883       TMethod* mCand = 0;
01884       while ((mCand = (TMethod*)iMeth()))
01885          if (!strcmp(mCand->GetName(), entity->GetName())) {
01886             if (description.Length()) {
01887                description += " or overloads";
01888                break;
01889             }
01890             description = mCand->GetPrototype();
01891          }
01892       comment = description.Data();
01893    }
01894 
01895    if (comment && !strcmp(comment, entity->GetName()))
01896       comment = "";
01897 
01898    AddLink(str, link, comment);
01899 }
01900 
01901 //______________________________________________________________________________
01902 Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
01903 {
01904    // Check whether reference is a relative reference, and can (or should)
01905    // be prependen by relative paths. For HTML, check that it doesn't start
01906    // with "http://" or "https://"
01907 
01908    return !reference ||
01909       strncmp(reference, "http", 4) ||
01910       (strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4));
01911 }
01912 
01913 //______________________________________________________________________________
01914 const char* TDocOutput::ReplaceSpecialChars(char c)
01915 {
01916 // Replace ampersand, less-than and greater-than character, writing to out.
01917 // If 0 is returned, no replacement needs to be done.
01918 
01919    /*
01920    if (fEscFlag) {
01921       fEscFlag = kFALSE;
01922       return buf;
01923    } else if (c == fEsc) {
01924       // text.Remove(pos, 1); - NO! we want to keep it nevertheless!
01925       fEscFlag = kTRUE;
01926       return buf;
01927    }
01928 
01929    */
01930    switch (c) {
01931       case '<': return "&lt;";
01932       case '&': return "&amp;";
01933       case '>': return "&gt;";
01934    };
01935    return 0;
01936 }
01937 
01938 //______________________________________________________________________________
01939 void TDocOutput::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
01940 {
01941 // Replace ampersand, less-than and greater-than character
01942 //
01943 //
01944 // Input: text - text where replacement will happen,
01945 //        pos  - index of char to be replaced; will point to next char to be
01946 //               replaced when function returns
01947 //
01948 
01949    const char c = text[pos];
01950    const char* replaced = ReplaceSpecialChars(c);
01951    if (replaced) {
01952          text.Replace(pos, 1, replaced);
01953          pos += strlen(replaced) - 1;
01954    }
01955    ++pos;
01956 }
01957 
01958 //______________________________________________________________________________
01959 void TDocOutput::ReplaceSpecialChars(TString& text) {
01960 // Replace ampersand, less-than and greater-than character
01961 //
01962 //
01963 // Input: text - text where replacement will happen,
01964 //
01965    Ssiz_t pos = 0;
01966    while (pos < text.Length())
01967          ReplaceSpecialChars(text, pos);
01968 }
01969 
01970 //______________________________________________________________________________
01971 void TDocOutput::ReplaceSpecialChars(std::ostream& out, const char *string)
01972 {
01973 // Replace ampersand, less-than and greater-than characters, writing to out
01974 //
01975 //
01976 // Input: out    - output file stream
01977 //        string - pointer to an array of characters
01978 //
01979 
01980    while (string && *string) {
01981       const char* replaced = ReplaceSpecialChars(*string);
01982       if (replaced)
01983          out << replaced;
01984       else
01985          out << *string;
01986       string++;
01987    }
01988 }
01989 
01990 //______________________________________________________________________________
01991 Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap /* =0 */,
01992                           EGraphvizTool gvwhat /*= kDot*/) {
01993 // Run filename".dot", creating filename".png", and - if outMap is !=0,
01994 // filename".map", which gets then included literally into outMap.
01995 
01996    if (!fHtml->HaveDot())
01997       return kFALSE;
01998 
01999    TString runDot;
02000    switch (gvwhat) {
02001    case kNeato: runDot = "neato"; break;
02002    case kFdp: runDot = "fdp"; break;
02003    case kCirco: runDot = "circo"; break;
02004    default: runDot = "dot";
02005    };
02006    if (fHtml->GetDotDir() && *fHtml->GetDotDir())
02007       gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
02008    runDot += " -q1 -Tpng -o";
02009    runDot += filename;
02010    runDot += ".png ";
02011    if (outMap) {
02012       runDot += "-Tcmap -o";
02013       runDot += filename;
02014       runDot += ".map ";
02015    }
02016    runDot += filename;
02017    runDot += ".dot";
02018 
02019    if (gDebug > 3)
02020       Info("RunDot", "Running: %s", runDot.Data());
02021    Int_t retDot = gSystem->Exec(runDot);
02022    if (gDebug < 4 && !retDot)
02023       gSystem->Unlink(Form("%s.dot", filename));
02024 
02025    if (!retDot && outMap) {
02026       ifstream inmap(Form("%s.map", filename));
02027       std::string line;
02028       std::getline(inmap, line);
02029       if (inmap && !inmap.eof()) {
02030          *outMap << "<map name=\"Map" << gSystem->BaseName(filename)
02031             << "\" id=\"Map" << gSystem->BaseName(filename) << "\">" << endl;
02032          while (inmap && !inmap.eof()) {
02033             if (line.compare(0, 6, "<area ") == 0) {
02034                size_t posEndTag = line.find('>');
02035                if (posEndTag != std::string::npos)
02036                   line.replace(posEndTag, 1, "/>");
02037             }
02038             *outMap << line << endl;
02039             std::getline(inmap, line);
02040          }
02041          *outMap << "</map>" << endl;
02042       }
02043       inmap.close();
02044       if (gDebug < 7)
02045          gSystem->Unlink(Form("%s.map", filename));
02046    }
02047 
02048    if (retDot) {
02049       Error("RunDot", "Error running %s!", runDot.Data());
02050       fHtml->SetFoundDot(kFALSE);
02051       return kFALSE;
02052    }
02053 
02054    return kTRUE;
02055 }
02056 
02057 
02058 //______________________________________________________________________________
02059 void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial,
02060                             const char* dir /*=""*/, TClass *cls /*=0*/,
02061                             const char* header)
02062 {
02063 // Write HTML header
02064 //
02065 // Internal method invoked by the overload
02066 
02067    ifstream addHeaderFile(header);
02068 
02069    if (!addHeaderFile.good()) {
02070       Warning("THtml::WriteHtmlHeader",
02071               "Can't open html header file %s\n", header);
02072       return;
02073    }
02074 
02075    TString declFileName;
02076    if (cls) fHtml->GetDeclFileName(cls, kFALSE, declFileName);
02077    TString implFileName;
02078    if (cls) fHtml->GetImplFileName(cls, kFALSE, implFileName);
02079 
02080    const TString& charset = GetHtml()->GetCharset();
02081    TDatime date;
02082    TString strDate(date.AsString());
02083    TString line;
02084 
02085    while (!addHeaderFile.eof()) {
02086 
02087       line.ReadLine(addHeaderFile, kFALSE);
02088       if (addHeaderFile.eof())
02089          break;
02090 
02091       if (line) {
02092 
02093          if (!cls && (
02094             line.Index("%CLASS%") != kNPOS ||
02095             line.Index("%INCFILE%") != kNPOS ||
02096             line.Index("%SRCFILE%") != kNPOS))
02097             continue; // skip class line for non-class files
02098 
02099          TString txt(line);
02100 
02101          txt.ReplaceAll("%TITLE%", titleNoSpecial);
02102          txt.ReplaceAll("%DATE%", strDate);
02103          txt.ReplaceAll("%RELDIR%", dir);
02104          txt.ReplaceAll("%CHARSET%", charset);
02105 
02106          if (cls) {
02107             txt.ReplaceAll("%CLASS%", cls->GetName());
02108             txt.ReplaceAll("%INCFILE%", declFileName);
02109             txt.ReplaceAll("%SRCFILE%", implFileName);
02110          }
02111 
02112          out << txt << endl;
02113       }
02114    }
02115 }
02116 
02117 //______________________________________________________________________________
02118 void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title,
02119                             const char* dir /*=""*/, TClass *cls/*=0*/)
02120 {
02121 // Write HTML header
02122 //
02123 //
02124 // Input: out   - output file stream
02125 //        title - title for the HTML page
02126 //        cls   - current class
02127 //        dir   - relative directory to reach the top
02128 //                ("" for html doc, "../" for src/*cxx.html etc)
02129 //
02130 // evaluates the Root.Html.Header setting:
02131 // * if not set, the standard header is written. (ROOT)
02132 // * if set, and ends with a "+", the standard header is written and this file
02133 //   included afterwards. (ROOT, USER)
02134 // * if set but doesn't end on "+" the file specified will be written instead
02135 //   of the standard header (USER)
02136 //
02137 // Any occurrence of "%TITLE%" (without the quotation marks) in the user
02138 // provided header file will be replaced by the value of this method's
02139 // parameter "title" before written to the output file. %CLASS% is replaced by
02140 // the class name, %INCFILE% by the header file name as given by
02141 // TClass::GetDeclFileName() and %SRCFILE% by the source file name as given by
02142 // TClass::GetImplFileName(). If the header is written for a non-class page,
02143 // i.e. cls==0, lines containing %CLASS%, %INCFILE%, or %SRCFILE% will be
02144 // skipped.
02145 
02146    TString userHeader = GetHtml()->GetHeader();
02147    TString noSpecialCharTitle(title);
02148    ReplaceSpecialChars(noSpecialCharTitle);
02149 
02150    Ssiz_t lenUserHeader = userHeader.Length();
02151    // standard header output if Root.Html.Header is not set, or it's set and it ends with a "+".
02152    Bool_t bothHeaders = lenUserHeader > 0 && userHeader[lenUserHeader - 1] == '+';
02153    if (lenUserHeader == 0 || bothHeaders) {
02154       TString header("header.html");
02155       gSystem->PrependPathName(fHtml->GetEtcDir(), header);
02156       WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, header);
02157    }
02158 
02159    if (lenUserHeader != 0) {
02160       if (bothHeaders)
02161          userHeader.Remove(lenUserHeader - 1);
02162       WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, userHeader);
02163    };
02164 }
02165 
02166 //______________________________________________________________________________
02167 void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* /*dir*/,
02168                                  const char* lastUpdate, const char* author,
02169                                  const char* copyright, const char* footer)
02170 {
02171 // Write HTML footer
02172 //
02173 // Internal method invoked by the overload
02174 
02175    static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%", "%CHANGED%", "%GENERATED%"};
02176 
02177    TString today;
02178    TDatime dtToday;
02179    today.Form("%d-%02d-%02d %02d:%02d", dtToday.GetYear(), dtToday.GetMonth(), dtToday.GetDay(), dtToday.GetHour(), dtToday.GetMinute());
02180 
02181    TString datimeString;
02182    if (!lastUpdate || !strlen(lastUpdate)) {
02183       lastUpdate = today;
02184    }
02185    const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright, lastUpdate, today };
02186 
02187    ifstream addFooterFile(footer);
02188 
02189    if (!addFooterFile.good()) {
02190       Warning("THtml::WriteHtmlFooter",
02191               "Can't open html footer file %s\n", footer);
02192       return;
02193    }
02194 
02195    TString line;
02196    while (!addFooterFile.eof()) {
02197 
02198       line.ReadLine(addFooterFile, kFALSE);
02199       if (addFooterFile.eof())
02200          break;
02201 
02202       if (!line)
02203          continue;
02204 
02205       for (Int_t siTag = 0; siTag < (Int_t) TDocParser::kNumSourceInfos; ++siTag) {
02206          Ssiz_t siPos = line.Index(templateSITags[siTag]);
02207          if (siPos != kNPOS) {
02208             if (siValues[siTag] && siValues[siTag][0])
02209                line.Replace(siPos, strlen(templateSITags[siTag]), siValues[siTag]);
02210             else
02211                line = ""; // skip e.g. %AUTHOR% lines if no author is set
02212          }
02213       }
02214 
02215       out << line << std::endl;
02216    }
02217 
02218 }
02219 
02220 //______________________________________________________________________________
02221 void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
02222                             const char *lastUpdate, const char *author,
02223                             const char *copyright)
02224 {
02225 // Write HTML footer
02226 //
02227 //
02228 // Input: out        - output file stream
02229 //        dir        - usually equal to "" or "../", depends of
02230 //                     current file directory position, i.e. if
02231 //                     file is in the fHtml->GetOutputDir(), then dir will be ""
02232 //        lastUpdate - last update string
02233 //        author     - author's name
02234 //        copyright  - copyright note
02235 //
02236 // Allows optional user provided footer to be written. Root.Html.Footer holds
02237 // the file name for this footer. For details see THtml::WriteHtmlHeader (here,
02238 // the "+" means the user's footer is written in front of Root's!) Occurences
02239 // of %AUTHOR%, %CHANGED%, %GENERATED%, and %COPYRIGHT% in the user's file are replaced by
02240 // their corresponding values (author, lastUpdate, today, and copyright) before
02241 // written to out.
02242 // If no author is set (author == "", e.g. for ClassIndex.html") skip the whole
02243 // line of the footer template containing %AUTHOR%. Accordingly for %COPYRIGHT%.
02244 
02245    out << endl;
02246 
02247    TString userFooter = GetHtml()->GetFooter();
02248 
02249    if (userFooter.Length() != 0) {
02250       TString footer(userFooter);
02251       if (footer.EndsWith("+"))
02252          footer.Remove(footer.Length() - 1);
02253       WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
02254    };
02255 
02256    if (userFooter.Length() == 0 || userFooter.EndsWith("+")) {
02257       TString footer("footer.html");
02258       gSystem->PrependPathName(fHtml->GetEtcDir(), footer);
02259       WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
02260    }
02261 }
02262 
02263 //______________________________________________________________________________
02264 void TDocOutput::WriteModuleLinks(std::ostream& out)
02265 {
02266    // Create a div containing links to all topmost modules
02267 
02268    if (fHtml->GetListOfModules()->GetSize()) {
02269       out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
02270       // find index chars
02271       fHtml->SortListOfModules();
02272       TIter iModule(fHtml->GetListOfModules());
02273       TModuleDocInfo* module = 0;
02274       while ((module = (TModuleDocInfo*) iModule())) {
02275          if (!module->GetName() || strchr(module->GetName(), '/'))
02276             continue;
02277          if (module->IsSelected()) {
02278             TString name(module->GetName());
02279             name.ToUpper();
02280             out << "<a href=\"" << name << "_Index.html\">"
02281                 << name << "</a>" << endl;
02282          }
02283       }
02284       out<< "</div><br />" << endl;
02285    }
02286 }
02287 
02288 //______________________________________________________________________________
02289 void TDocOutput::WriteLineNumbers(std::ostream& out, Long_t nLines, const TString& infileBase) const
02290 {
02291    // Create a div containing the line numbers (for a source listing) 1 to nLines.
02292    // Create links to the source file's line number and anchors, such that one can
02293    // jump to SourceFile.cxx.html#27 (using the anchor), and one can copy and paste
02294    // the link into e.g. gdb to get the text "SourceFile.cxx:27".
02295 
02296    out << "<div id=\"linenums\">";
02297    for (Long_t i = 0; i < nLines; ++i) {
02298       // &nbsp; to force correct line height
02299       out << "<div class=\"ln\">&nbsp;<span class=\"lnfile\">" << infileBase
02300           << ":</span><a name=\"" << i + 1 << "\" href=\"#" << i + 1
02301           << "\" class=\"ln\">" << i + 1 << "</a></div>";
02302    }
02303    out << "</div>" << std::endl;
02304 
02305 }
02306 
02307 //______________________________________________________________________________
02308 void TDocOutput::WriteModuleLinks(std::ostream& out, TModuleDocInfo* super)
02309 {
02310    // Create a div containing links to all modules
02311 
02312    if (super->GetSub().GetSize()) {
02313       TString superName(super->GetName());
02314       superName.ToUpper();
02315       out << "<div id=\"indxModules\"><h4>" << superName << " Modules</h4>" << endl;
02316       // find index chars
02317       super->GetSub().Sort();
02318       TIter iModule(&super->GetSub());
02319       TModuleDocInfo* module = 0;
02320       while ((module = (TModuleDocInfo*) iModule())) {
02321          if (module->IsSelected()) {
02322             TString name(module->GetName());
02323             name.ToUpper();
02324             TString link(name);
02325             link.ReplaceAll("/", "_");
02326             Ssiz_t posSlash = name.Last('/');
02327             if (posSlash != kNPOS)
02328                name.Remove(0, posSlash + 1);
02329             out << "<a href=\"" << link << "_Index.html\">" << name << "</a>" << endl;
02330          }
02331       }
02332       out<< "</div><br />" << endl;
02333    }
02334 }
02335 
02336 //______________________________________________________________________________
02337 void TDocOutput::WriteSearch(std::ostream& out)
02338 {
02339    // Write a search link or a search box, based on THtml::GetSearchStemURL()
02340    // and THtml::GetSearchEngine(). The first one is preferred.
02341 
02342    // e.g. searchCmd = "http://www.google.com/search?q=%s+site%3A%u+-site%3A%u%2Fsrc%2F+-site%3A%u%2Fexamples%2F";
02343    const TString& searchCmd = GetHtml()->GetSearchStemURL();
02344    const TString& searchEngine = GetHtml()->GetSearchEngine();
02345 
02346    if (!searchCmd.Length() && !searchEngine.Length())
02347       return;
02348 
02349    if (searchCmd.Length()) {
02350       TUrl url(searchCmd);
02351       TString serverName(url.GetHost());
02352       if (serverName.Length()) {
02353          serverName.Prepend(" title=\"");
02354          serverName += "\" ";
02355       }
02356       // create search input
02357       out << "<script type=\"text/javascript\">" << endl
02358           << "function onSearch() {" << endl
02359           << "var s='" << searchCmd <<"';" << endl
02360           << "var ref=String(document.location.href).replace(/https?:\\/\\//,'').replace(/\\/[^\\/]*$/,'').replace(/\\//g,'%2F');" << endl
02361           << "window.location.href=s.replace(/%u/ig,ref).replace(/%s/ig,escape(document.searchform.t.value));" << endl
02362           << "return false;}" << endl
02363           << "</script>" << endl
02364           << "<form id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\" action=\"javascript:onSearch();\" method=\"post\">" << endl
02365           << "<input name=\"t\" size=\"30\" value=\"Search documentation...\" onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input>" << endl
02366           << "<a id=\"searchlink\" " << serverName << " href=\"javascript:onSearch();\" onclick=\"return onSearch()\">Search</a></form>" << endl;
02367    } else if (searchEngine.Length())
02368       // create link to search engine page
02369       out << "<a class=\"descrheadentry\" href=\"" << searchEngine
02370           << "\">Search the Class Reference Guide</a>" << endl;
02371 }
02372 
02373 
02374 //______________________________________________________________________________
02375 void TDocOutput::WriteLocation(std::ostream& out, TModuleDocInfo* module, const char* classname)
02376 {
02377    // make a link to the description
02378    out << "<div class=\"location\">" << endl; // location
02379    const char *productName = fHtml->GetProductName();
02380    out << "<a class=\"locationlevel\" href=\"index.html\">" << productName << "</a>" << endl;
02381 
02382    if (module) {
02383       TString modulename(module->GetName());
02384       modulename.ToUpper();
02385       TString modulePart;
02386       TString modulePath;
02387       Ssiz_t pos = 0;
02388       while (modulename.Tokenize(modulePart, pos, "/")) {
02389          if (pos == kNPOS && !classname)
02390             // we are documenting the module itself, no need to link it:
02391             break;
02392          if (modulePath.Length()) modulePath += "_";
02393          modulePath += modulePart;
02394          out << " &#187; <a class=\"locationlevel\" href=\"./" << modulePath << "_Index.html\">" << modulePart << "</a>" << endl;
02395       }
02396    }
02397 
02398    TString entityName;
02399    if (classname) entityName = classname;
02400    else if (module) {
02401       entityName = module->GetName();
02402       Ssiz_t posSlash = entityName.Last('/');
02403       if (posSlash != kNPOS)
02404          entityName.Remove(0, posSlash + 1);
02405       entityName.ToUpper();
02406    }
02407    if (entityName.Length()) {
02408       out << " &#187; <a class=\"locationlevel\" href=\"#TopOfPage\">";
02409       ReplaceSpecialChars(out, entityName);
02410       out << "</a>" << endl;
02411    }
02412    out << "</div>" << endl; // location
02413 }
02414 
02415 
02416 //______________________________________________________________________________
02417 void TDocOutput::WriteTopLinks(std::ostream& out, TModuleDocInfo* module, const char* classname,
02418                                Bool_t withLocation)
02419 {
02420    // Write the first part of the links shown ontop of each doc page;
02421    // one <div> has to be closed by caller so additional items can still
02422    // be added.
02423 
02424    out << "<div id=\"toplinks\">" << endl;
02425 
02426    out << "<div class=\"descrhead\"><div class=\"descrheadcontent\">" << endl // descrhead line 1
02427       << "<span class=\"descrtitle\">Quick Links:</span>" << endl;
02428 
02429    // link to the user home page (if exist)
02430    const char* userHomePage = GetHtml()->GetHomepage();
02431    const char* productName = fHtml->GetProductName();
02432    if (!productName) {
02433       productName = "";
02434    } else if (!strcmp(productName, "ROOT")) {
02435       userHomePage = "";
02436    }
02437    if (userHomePage && *userHomePage)
02438       out << "<a class=\"descrheadentry\" href=\"" << userHomePage << "\">" << productName << "</a>" << endl;
02439    out << "<a class=\"descrheadentry\" href=\"http://root.cern.ch\">ROOT Homepage</a>" << endl
02440       << "<a class=\"descrheadentry\" href=\"./ClassIndex.html\">Class Index</a>" << endl
02441       << "<a class=\"descrheadentry\" href=\"./ClassHierarchy.html\">Class Hierarchy</a></div>" << endl;
02442    WriteSearch(out);
02443    out << "</div>" << endl; // descrhead, line 1
02444 
02445    if (withLocation) {
02446       out << "</div>" << endl; //toplinks
02447       WriteLocation(out, module, classname); // descrhead line 2
02448    }
02449    // else {
02450    //    Closed by caller!
02451    //    out << "</div>" << endl; // toplinks
02452    // }
02453 
02454 }

Generated on Tue Jul 5 14:24:55 2011 for ROOT_528-00b_version by  doxygen 1.5.1