// This script generates the html pages for the ROOT tutorials hierarchy. // It creates $ROOTSYS/htmldoc if not already there // It creates $ROOTSYS/htmldoc/tutorials if not already there // It creates $ROOTSYS/htmldoc/tutorials/index.html (index to all directory tutorials) // It creates $ROOTSYS/htmldoc/tutorials/dir/index.html with index of tutorials in dir // It creates $ROOTSYS/htmldoc/tutorials/dir/*.C.html with one html file for each tutorial // Author: Rene Brun #include "THtml.h" #include "TDocOutput.h" #include "TROOT.h" #include "TSystem.h" #include "TEnv.h" #include "TDatime.h" #include "TStyle.h" #include "TList.h" #include #include using namespace std; void scandir(THtml& html, const char *dir, const char *title, TObjLink* toplnk); void AppendLink(TString& links, int id, const TNamed* n) { // Used to construct the context links (prev/up/next) at the top of each html page. // "links" contains the html code that AppendLink() adds to. // "id" contains the pass (id == 0: prev, 1: up, 2: next) // "n" points to a TNamed that has the URL (without trailing ".html") as the name // and the title as the title. static const char* tag[] = {"<", "^", ">"}; // "<" "^" ">" static const char* name[] = {"prev", "up", "next"}; // for CSS static const TNamed emptyName; // for CSS TString arrowid("contextheadarrow_"); arrowid += name[id]; TString entryid("contextheadentry_"); entryid += name[id]; TString ardivid("divcontextheadar_"); ardivid += name[id]; if (!n) n = &emptyName; TString title; // format for prev, next: script: title (if not empty) // format for up: title if (id != 1) title = n->GetName(); if (title.Length()) title += ": "; title += n->GetTitle(); const char* mytag = tag[id]; // if we don't have a link we don't write <^> if (!n->GetName()[0]) mytag = ""; // td for "<" "^" ">" TString arrow = TString::Format("
" "%s
", arrowid.Data(), ardivid.Data(), n->GetName(), mytag); // td for the text TString entry = TString::Format("" "%s", entryid.Data(), n->GetName(), title.Data()); if (id == 2) // "next" has the text first links += entry + arrow; else links += arrow + entry; } void MakeTopLinks(TString &links, const char* name, const char* title, const char* upLink, const char* upTitle, TObjLink *lnk, const char* dir) { // Create the html code for the navigation box at the top of each page, // showing a link to the previous and next tutorial and to the upper level. // "links" will hold the html code after the function returns, // "title" is the title for the page, displayed below the naviation links // "upLink" is the URL for the up link, // "upTitle" is the text to display for the link. // "lnk" has TNamed as prev and next, with name as URL and title as // title for the previous and next links. links = "
" ""; TObjLink *prevlnk = lnk ? lnk->Prev() : 0; TObjLink *nextlnk = lnk ? lnk->Next() : 0; TNamed* prevname = prevlnk ? (TNamed*)prevlnk->GetObject() : 0; AppendLink(links, 0, prevname); TNamed upname; if (upLink && upLink[0]) upname.SetNameTitle(upLink, upTitle); AppendLink(links, 1, &upname); TNamed* nextname = nextlnk ? (TNamed*)nextlnk->GetObject() : 0; AppendLink(links, 2, nextname); links += TString("

") + title + "

\n"; TString suburl = dir; TString subtitle = dir; if (name) { if (!subtitle.EndsWith("/")) { subtitle += '/'; } subtitle += TString(name); suburl = subtitle + "?view=markup"; } links += TString::Format("", suburl.Data(), subtitle.Data()); } void writeHeader(THtml& html, ostream& out, const char *title, const char* relPath="../") { // Write the html file header // "html" THtml object to use // "out" where to write to // "title" title to display in the browser's bar // "relPath" relative path to the root of the documentation output, // i.e. where to find ROOT.css generated below by THtml::CreateAuxiliaryFiles() TDocOutput docout(html); docout.WriteHtmlHeader(out, title, relPath); } void writeTrailer(THtml& html, ostream& out) { // Write the html file trailer // "html" THtml object to use // "out" where to write to TDocOutput docout(html); docout.WriteHtmlFooter(out); } void writeItem(ostream& out, Int_t numb, const char *ref, const char *name, const char *title, Bool_t isnew) { // Write a list entry in the directory index. // "out" where to write to // "numb" number of the current line // "ref" URL of the line's page // "name" name to display for the link // const char *imagenew = ""; cout << "writingItem: " << numb << ", ref=" << ref << ", name=" << name << ", title=" << title << endl; if (isnew) imagenew = " \"new\""; out << "
  • "; out << "" << numb << ". " << name << " " << title << imagenew << "
  • " << endl; } void writeItemDir(THtml& html, ostream& out, TObjLink* lnk) { // Process a tutorial directory: add a list entry for it in the // topmost index and add all tutorials in this directory. // "html" THtml object to use // "out" where to write the html code to // "lnk" a TObjLink with Prev() and Next() pointing to TNamed that // hold the URL (name) and the title (title) for the previous // and next tutorial directory. static int n=0; const char *dir = lnk->GetObject()->GetName(); const char *title = lnk->GetObject()->GetTitle(); out << "
  • " << "" << dir << "" << title << "
  • " << endl; scandir(html, dir, title, lnk); } void writeTutorials(THtml& html) { // Process all tutorials by looking over the directories in // $ROOTSYS/tutorials, generating index pages showing them // and index pages for each directory showing its tutorials, // and by converting all tutorials to html code, including // the graphics output where possible. The latter is done // using THtml::Convert(). // tutorials and their titles; ordered by "significance" const char* tutorials[][2] = { {"hist", "Histograms"}, {"graphics", "Basic Graphics"}, {"graphs", "TGraph, TGraphErrors, etc"}, {"gui", "Graphics User Interface"}, {"fit", "Fitting tutorials"}, {"fitsio", "CFITSIO interface"}, {"io", "Input/Output"}, {"tree", "Trees I/O, Queries, Graphics"}, {"math", "Math tutorials"}, {"matrix", "Matrix packages tutorials"}, {"geom", "Geometry package"}, {"gl", "OpenGL examples"}, {"eve", "Event Display"}, {"fft", "Fast Fourier Transforms"}, {"foam", "TFoam example"}, {"image", "Image Processing"}, {"mlp", "Neural Networks"}, {"net", "Network, Client/server"}, {"physics", "Physics misc"}, {"proof", "PROOF tutorials"}, {"pyroot", "Python-ROOT"}, {"pythia", "Pythia event generator"}, {"quadp", "Quadratic Programming package"}, {"roofit", "RooFit tutorials"}, {"roostats", "Roostats tutorials"}, {"spectrum", "Peak Finder, Deconvolutions"}, {"splot", "TSPlot example"}, {"sql", "SQL Data Bases interfaces"}, {"thread", "Multi-Threading examples"}, {"unuran", "The Unuran package"}, {"xml", "XML tools"}, {0, 0} }; // the output file for the directory index ofstream fptop("htmldoc/tutorials/index.html"); writeHeader(html, fptop,"ROOT Tutorials"); TString topLinks; MakeTopLinks(topLinks, 0, "ROOT Tutorials", "../index", "ROOT", 0, ""); fptop << topLinks << endl; fptop << "" << endl; fptop << "

    Download ROOT and run the tutorials in $ROOTSYS/tutorials yourself!

    " << endl; writeTrailer(html, fptop); } void GetMacroTitle(const char *fullpath, TString &comment, Bool_t &compile) { // Find the best line with a title by scanning the first 50 lines of a macro. // "fullpath" location of the macro // "comment" is set to the comment (i.e. title) found in the macro // "compile" is set to true if the macro should be compiled, i.e. the // title line starts with "//+ " (note the space) compile = kFALSE; FILE *fp = fopen(fullpath,"r"); char line[250]; int nlines = 0; while (fgets(line,240,fp)) { nlines++; char *com = strstr(line,"//"); if (com) { if (strstr(line,"Author")) continue; if (strstr(line,"@(#)")) continue; if (strstr(line,"****")) continue; if (strstr(line,"////")) continue; if (strstr(line,"====")) continue; if (strstr(line,"....")) continue; if (strstr(line,"----")) continue; if (strstr(line,"____")) continue; if (strlen(com+1) < 5) continue; if (!strncmp(com,"//+ ", 4)) { compile = kTRUE; com += 2; // skip "+ ", too. } comment = com+2; break; } if (nlines > 50) break; } fclose(fp); } Bool_t IsNew(const char *filename) { // Check if filename in SVN is newer than 6 months gSystem->Exec(Form("svn info %s > MakeTutorials-tmp.log",filename)); FILE *fpdate = fopen("MakeTutorials-tmp.log","r"); char line[250]; Bool_t isnew = kFALSE; TDatime today; Int_t now = 365*(today.GetYear()-1)+12*(today.GetMonth()-1) + today.GetDay(); Int_t year,month,day; while (fgets(line,240,fpdate)) { const char *com = strstr(line,"Last Changed Date: "); if (com) { sscanf(&com[19],"%d-%d-%d",&year,&month,&day); Int_t filedate = 365*(year-1) + 12*(month-1) + day; //see TDatime::GetDate if (now-filedate< 6*30) isnew = kTRUE; break; } } fclose(fpdate); gSystem->Unlink("MakeTutorials-tmp.log"); return isnew; } Bool_t CreateOutput_Dir(const char* dir) { // Whether THtml::Convert() should run the tutorials in the // directory "dir" and store their output if (strstr(dir,"net")) return kFALSE; if (strstr(dir,"xml")) return kFALSE; if (strstr(dir,"sql")) return kFALSE; if (strstr(dir,"proof")) return kFALSE; if (strstr(dir,"foam")) return kFALSE; if (strstr(dir,"unuran")) return kFALSE; if (strstr(dir,"roofit")) return kFALSE; if (strstr(dir,"thread")) return kFALSE; return kTRUE; } Bool_t CreateOutput_Tutorial(const char* tut) { // Whether THtml::Convert() should run the tutorial "tut" // and store its output static const char* vetoed[] = { "geodemo", "peaks2", "testUnfold", "readCode", "importCode", "hadd", "line3Dfit", "gtime", "games", "guiWithCINT", "Qt", "rs401d_FeldmanCousins", "graph_edit_playback", "fitpanel_playback", "guitest_playback", "geom_cms_playback", "gviz3d.C", 0 }; for (const char** iVetoed = vetoed; *iVetoed; ++iVetoed) if (strstr(tut, *iVetoed)) return kFALSE; return kTRUE; } void scandir(THtml& html, const char *dir, const char *title, TObjLink* toplnk) { // Process a directory containing tutorials by converting all tutorials to // html and creating an index of all tutorials in the directory. TString fullpath("htmldoc/tutorials/"); fullpath += dir; if (!gSystem->OpenDirectory(fullpath)) gSystem->MakeDirectory(fullpath); fullpath += "/index.html"; // The index for the current directory ofstream fpind(fullpath); writeHeader(html, fpind, title, "../../"); TString topLinks; // Creates links to prev: "hist.html", up: ".html", next: "graph.html". MakeTopLinks(topLinks, 0, title, ".", "ROOT Tutorials", toplnk, dir); // But we need links to prev: "../hist/index.html", up: "../index.html", next: "graph/index.html", // so the following works: topLinks.ReplaceAll("href=\"", "href=\"../"); topLinks.ReplaceAll("href=\"../http://", "href=\"http://"); topLinks.ReplaceAll("href=\"../https://", "href=\"https://"); topLinks.ReplaceAll(".html\"", "/index.html\""); // Also prepend "ROOT Tutorials" to the current title: topLinks.ReplaceAll("

    ", "

    ROOT Tutorials: "); fpind << topLinks << endl; fpind << "
      " << endl; TString outpath("htmldoc/tutorials/"); outpath += dir; TString inpath("$ROOTSYS/tutorials/"); inpath += dir; inpath += "/"; gSystem->ExpandPathName(inpath); void *thedir = gSystem->OpenDirectory(inpath); if (!thedir) { printf("MakeTutorials.C: error opening directory %s", inpath.Data()); return; } const char *direntry; THashList h; while ((direntry = gSystem->GetDirEntry(thedir))) { if(*direntry =='.') continue; const char *CC = strstr(direntry,".C"); // must end on ".C" if (!CC || *(CC+2)) continue; // do not even document these; they are part of another tutorial: if(strstr(direntry,"h1anal")) continue; if(strstr(direntry,"hsimpleProxy")) continue; if(strstr(direntry,"tv3")) continue; if(strstr(direntry,"tvdemo")) continue; if(strstr(direntry,"na49")) continue; if(strstr(direntry,"fit1_C")) continue; if(strstr(direntry,"c1.C")) continue; if(strstr(direntry,"MDF.C")) continue; if(strstr(direntry,"cms_calo_detail")) continue; TString atut(inpath + direntry); TString comment; Bool_t compile; GetMacroTitle(atut,comment, compile); TNamed *named = new TNamed(direntry,comment.Data()); if (compile) named->SetBit(BIT(14)); h.Add(named); } h.Sort(); int numb = 0; TObjLink *lnk = h.FirstLink(); while (lnk) { TNamed* named = (TNamed*)lnk->GetObject(); Bool_t compile = named->TestBit(BIT(14)); direntry = named->GetName(); TString atut(inpath + direntry); numb++; TString iname(direntry); iname += ".html"; writeItem(fpind, numb, iname, direntry, named->GetTitle(), IsNew(atut)); Int_t includeOutput = THtml::kNoOutput; if (!gROOT->IsBatch()) { if (compile) includeOutput = THtml::kCompiledOutput; else includeOutput = THtml::kInterpretedOutput; includeOutput |= THtml::kSeparateProcessOutput; } if (!CreateOutput_Dir(dir) || !CreateOutput_Tutorial(direntry)) includeOutput = THtml::kNoOutput; TString links; TString tutTitle(named->GetName()); tutTitle += ": "; tutTitle += named->GetTitle(); MakeTopLinks(links,named->GetName(),tutTitle,"index",title,lnk, dir); html.Convert(atut,named->GetTitle(),outpath,"../../",includeOutput,links); gROOT->GetListOfCanvases()->Delete(); gROOT->CloseFiles(); gROOT->GetListOfFunctions()->Delete(); gROOT->GetListOfBrowsers()->Delete(); gROOT->GetListOfGeometries()->Delete(); //gROOT->GetListOfSpecials()->Delete(); // Create some styles gStyle = 0; TStyle::BuildStyles(); gROOT->SetStyle("Default"); lnk = lnk->Next(); } fpind << "
    " << endl; writeTrailer(html, fpind); } void MakeTutorials() { // Bring the ROOT tutorials on the web, see http://root.cern.ch/root/html/tutorials/. // Demonstrates the use of THtml:Convert() in a realistic context. if (!gSystem->OpenDirectory("htmldoc")) gSystem->MakeDirectory("htmldoc"); if (!gSystem->OpenDirectory("htmldoc/tutorials")) gSystem->MakeDirectory("htmldoc/tutorials"); gEnv->SetValue("Unix.*.Root.Html.SourceDir", "$(ROOTSYS)"); gEnv->SetValue("Root.Html.ViewCVS","http://root.cern.ch/viewcvs/trunk/%f?view=log"); gEnv->SetValue("Root.Html.Search", "http://www.google.com/search?q=%s+site%3A%u"); THtml html; html.LoadAllLibs(); //gROOT->ProcessLine(".x htmlLoadlibs.C"); html.CreateAuxiliaryFiles(); writeTutorials(html); }