Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
MakeTutorials.C
Go to the documentation of this file.
1 // This script generates the html pages for the ROOT tutorials hierarchy.
2 // It creates $ROOTSYS/htmldoc if not already there
3 // It creates $ROOTSYS/htmldoc/tutorials if not already there
4 // It creates $ROOTSYS/htmldoc/tutorials/index.html (index to all directory tutorials)
5 // It creates $ROOTSYS/htmldoc/tutorials/dir/index.html with index of tutorials in dir
6 // It creates $ROOTSYS/htmldoc/tutorials/dir/*.C.html with one html file for each tutorial
7 // Author: Rene Brun
8 
9 #include "THtml.h"
10 #include "TDocOutput.h"
11 #include "TROOT.h"
12 #include "TSystem.h"
13 #include "TEnv.h"
14 #include "TDatime.h"
15 #include "TStyle.h"
16 #include "TList.h"
17 #include <iostream>
18 #include <fstream>
19 
20 using namespace std;
21 
22 void scandir(THtml& html, const char *dir, const char *title, TObjLink* toplnk);
23 
24 
25 void AppendLink(TString& links, int id, const TNamed* n)
26 {
27  // Used to construct the context links (prev/up/next) at the top of each html page.
28  // "links" contains the html code that AppendLink() adds to.
29  // "id" contains the pass (id == 0: prev, 1: up, 2: next)
30  // "n" points to a TNamed that has the URL (without trailing ".html") as the name
31  // and the title as the title.
32 
33  static const char* tag[] = {"&lt;", "^", "&gt;"}; // "<" "^" ">"
34  static const char* name[] = {"prev", "up", "next"}; // for CSS
35  static const TNamed emptyName;
36 
37  // for CSS
38  TString arrowid("contextheadarrow_"); arrowid += name[id];
39  TString entryid("contextheadentry_"); entryid += name[id];
40  TString ardivid("divcontextheadar_"); ardivid += name[id];
41  if (!n) n = &emptyName;
42 
43  TString title;
44  // format for prev, next: script: title (if not empty)
45  // format for up: title
46  if (id != 1) title = n->GetName();
47  if (title.Length()) title += ": ";
48  title += n->GetTitle();
49  const char* mytag = tag[id];
50  // if we don't have a link we don't write <^>
51  if (!n->GetName()[0]) mytag = "";
52  // td for "<" "^" ">"
53  TString arrow = TString::Format("<td id=\"%s\"><div id=\"%s\">"
54  "<a class=\"contextheadarrow\" href=\"%s.html\">%s</a></div></td>",
55  arrowid.Data(), ardivid.Data(), n->GetName(), mytag);
56  // td for the text
57  TString entry = TString::Format("<td class=\"contextheadentry\" id=\"%s\">"
58  "<a class=\"contextheadentry\" href=\"%s.html\">%s</a></td>",
59  entryid.Data(), n->GetName(), title.Data());
60  if (id == 2)
61  // "next" has the text first
62  links += entry + arrow;
63  else
64  links += arrow + entry;
65 }
66 
67 
68 void MakeTopLinks(TString &links, const char* name, const char* title, const char* upLink, const char* upTitle,
69  TObjLink *lnk, const char* dir)
70 {
71 // Create the html code for the navigation box at the top of each page,
72 // showing a link to the previous and next tutorial and to the upper level.
73 // "links" will hold the html code after the function returns,
74 // "title" is the title for the page, displayed below the naviation links
75 // "upLink" is the URL for the up link,
76 // "upTitle" is the text to display for the link.
77 // "lnk" has TNamed as prev and next, with name as URL and title as
78 // title for the previous and next links.
79 
80  links = "<div id=\"toplinks\"><div class=\"descrhead\">"
81  "<table class=\"descrtitle\" id=\"contexttitle\"><tr class=\"descrtitle\">";
82  TObjLink *prevlnk = lnk ? lnk->Prev() : 0;
83  TObjLink *nextlnk = lnk ? lnk->Next() : 0;
84 
85  TNamed* prevname = prevlnk ? (TNamed*)prevlnk->GetObject() : 0;
86  AppendLink(links, 0, prevname);
87 
88  TNamed upname;
89  if (upLink && upLink[0])
90  upname.SetNameTitle(upLink, upTitle);
91  AppendLink(links, 1, &upname);
92 
93  TNamed* nextname = nextlnk ? (TNamed*)nextlnk->GetObject() : 0;
94  AppendLink(links, 2, nextname);
95 
96  links += TString("</tr></table></div><h1 class=\"convert\">") + title + "</h1></div>\n";
97  TString suburl = dir;
98  TString subtitle = dir;
99  if (name) {
100  if (!subtitle.EndsWith("/")) {
101  subtitle += '/';
102  }
103  subtitle += TString(name);
104  suburl = subtitle + "?view=markup";
105  }
106  links += TString::Format("<div class=\"location\"><h2>From <a href=\"http://root.cern.ch/viewvc/trunk/tutorials/%s\">$ROOTSYS/tutorials/%s</a></h2></div>",
107  suburl.Data(), subtitle.Data());
108 }
109 
110 void writeHeader(THtml& html, ostream& out, const char *title, const char* relPath="../") {
111  // Write the html file header
112  // "html" THtml object to use
113  // "out" where to write to
114  // "title" title to display in the browser's bar
115  // "relPath" relative path to the root of the documentation output,
116  // i.e. where to find ROOT.css generated below by THtml::CreateAuxiliaryFiles()
117 
118  TDocOutput docout(html);
119  docout.WriteHtmlHeader(out, title, relPath);
120 }
121 
122 void writeTrailer(THtml& html, ostream& out) {
123  // Write the html file trailer
124  // "html" THtml object to use
125  // "out" where to write to
126 
127  TDocOutput docout(html);
128  docout.WriteHtmlFooter(out);
129 }
130 
131 void writeItem(ostream& out, Int_t numb, const char *ref, const char *name, const char *title, Bool_t isnew) {
132  // Write a list entry in the directory index.
133  // "out" where to write to
134  // "numb" number of the current line
135  // "ref" URL of the line's page
136  // "name" name to display for the link
137  //
138  const char *imagenew = "";
139  cout << "writingItem: " << numb << ", ref=" << ref << ", name=" << name << ", title=" << title << endl;
140  if (isnew) imagenew = " <img src=\"http://root.cern.ch/root/images/new01.gif\" alt=\"new\" align=\"top\" />";
141  out << "<li class=\"idxl" << numb%2 << "\">";
142  out << "<a href=\"" << ref << "\"><span class=\"typename\">" << numb << ". " << name << "</span></a> "
143  << title << imagenew << "</li>" << endl;
144 }
145 
146 void writeItemDir(THtml& html, ostream& out, TObjLink* lnk) {
147  // Process a tutorial directory: add a list entry for it in the
148  // topmost index and add all tutorials in this directory.
149  // "html" THtml object to use
150  // "out" where to write the html code to
151  // "lnk" a TObjLink with Prev() and Next() pointing to TNamed that
152  // hold the URL (name) and the title (title) for the previous
153  // and next tutorial directory.
154 
155  static int n=0;
156  const char *dir = lnk->GetObject()->GetName();
157  const char *title = lnk->GetObject()->GetTitle();
158  out << "<li class=\"idxl" << (n++)%2 << "\"><a href=\"" << dir << "/index.html\">"
159  << "<span class=\"typename\">" << dir << "</span></a>" << title << "</li>" << endl;
160 
161  scandir(html, dir, title, lnk);
162 }
163 
164 void writeTutorials(THtml& html) {
165  // Process all tutorials by looking over the directories in
166  // $ROOTSYS/tutorials, generating index pages showing them
167  // and index pages for each directory showing its tutorials,
168  // and by converting all tutorials to html code, including
169  // the graphics output where possible. The latter is done
170  // using THtml::Convert().
171 
172  // tutorials and their titles; ordered by "significance"
173  const char* tutorials[][2] = {
174  {"hist", "Histograms"},
175  {"graphics", "Basic Graphics"},
176  {"graphs", "TGraph, TGraphErrors, etc"},
177  {"gui", "Graphics User Interface"},
178  {"fit", "Fitting tutorials"},
179  {"fitsio", "CFITSIO interface"},
180  {"io", "Input/Output"},
181  {"tree", "Trees I/O, Queries, Graphics"},
182  {"math", "Math tutorials"},
183  {"matrix", "Matrix packages tutorials"},
184  {"geom", "Geometry package"},
185  {"gl", "OpenGL examples"},
186  {"eve", "Event Display"},
187  {"fft", "Fast Fourier Transforms"},
188  {"foam", "TFoam example"},
189  {"image", "Image Processing"},
190  {"mlp", "Neural Networks"},
191  {"net", "Network, Client/server"},
192  {"physics", "Physics misc"},
193  {"proof", "PROOF tutorials"},
194  {"pyroot", "Python-ROOT"},
195  {"pythia", "Pythia event generator"},
196  {"quadp", "Quadratic Programming package"},
197  {"roofit", "RooFit tutorials"},
198  {"roostats", "Roostats tutorials"},
199  {"spectrum", "Peak Finder, Deconvolutions"},
200  {"splot", "TSPlot example"},
201  {"sql", "SQL Data Bases interfaces"},
202  {"thread", "Multi-Threading examples"},
203  {"unuran", "The Unuran package"},
204  {"xml", "XML tools"},
205  {0, 0}
206  };
207 
208  // the output file for the directory index
209  ofstream fptop("htmldoc/tutorials/index.html");
210  writeHeader(html, fptop,"ROOT Tutorials");
211  TString topLinks;
212  MakeTopLinks(topLinks, 0, "ROOT Tutorials", "../index", "ROOT", 0, "");
213  fptop << topLinks << endl;
214  fptop << "<ul id=\"indx\">" << endl;
215 
216  // Iterate over all tutorial directories.
217  // We need prev and next, so keep prev, curr, and next
218  // in a TList containing three TNamed, and sweep through
219  // the char array tutorials.
220  TList contextList;
221  TNamed prev;
222  TNamed curr(tutorials[0][0], tutorials[0][1]);
223  TNamed next(tutorials[1][0], tutorials[1][1]);
224  contextList.AddLast(&prev);
225  contextList.AddLast(&curr);
226  contextList.AddLast(&next);
227  TObjLink* lnk = contextList.FirstLink();
228  lnk = lnk->Next(); // "curr" is the second link
229  const char** iTut = tutorials[2];
230  while (iTut[0]) {
231  writeItemDir(html, fptop, lnk);
232  prev = curr;
233  curr = next;
234  next.SetNameTitle(iTut[0], iTut[1]);
235  ++iTut; // skip name
236  ++iTut; // skip title
237  }
238 
239  fptop << "</ul>" << endl;
240  fptop << "<p><a href=\"http://root.cern.ch/drupal/content/downloading-root\">Download ROOT</a> and run the tutorials in $ROOTSYS/tutorials yourself!</p>" << endl;
241  writeTrailer(html, fptop);
242 }
243 
244 void GetMacroTitle(const char *fullpath, TString &comment, Bool_t &compile) {
245  // Find the best line with a title by scanning the first 50 lines of a macro.
246  // "fullpath" location of the macro
247  // "comment" is set to the comment (i.e. title) found in the macro
248  // "compile" is set to true if the macro should be compiled, i.e. the
249  // title line starts with "//+ " (note the space)
250  compile = kFALSE;
251  FILE *fp = fopen(fullpath,"r");
252  char line[250];
253  int nlines = 0;
254  while (fgets(line,240,fp)) {
255  nlines++;
256  char *com = strstr(line,"//");
257  if (com) {
258  if (strstr(line,"Author")) continue;
259  if (strstr(line,"@(#)")) continue;
260  if (strstr(line,"****")) continue;
261  if (strstr(line,"////")) continue;
262  if (strstr(line,"====")) continue;
263  if (strstr(line,"....")) continue;
264  if (strstr(line,"----")) continue;
265  if (strstr(line,"____")) continue;
266  if (strlen(com+1) < 5) continue;
267  if (!strncmp(com,"//+ ", 4)) {
268  compile = kTRUE;
269  com += 2; // skip "+ ", too.
270  }
271  comment = com+2;
272  break;
273  }
274  if (nlines > 50) break;
275  }
276  fclose(fp);
277 }
278 
279 Bool_t IsNew(const char *filename) {
280  // Check if filename in SVN is newer than 6 months
281  gSystem->Exec(Form("svn info %s > MakeTutorials-tmp.log",filename));
282  FILE *fpdate = fopen("MakeTutorials-tmp.log","r");
283  char line[250];
284  Bool_t isnew = kFALSE;
285  TDatime today;
286  Int_t now = 365*(today.GetYear()-1)+12*(today.GetMonth()-1) + today.GetDay();
287  Int_t year,month,day;
288  while (fgets(line,240,fpdate)) {
289  const char *com = strstr(line,"Last Changed Date: ");
290  if (com) {
291  sscanf(&com[19],"%d-%d-%d",&year,&month,&day);
292  Int_t filedate = 365*(year-1) + 12*(month-1) + day; //see TDatime::GetDate
293  if (now-filedate< 6*30) isnew = kTRUE;
294  break;
295  }
296  }
297  fclose(fpdate);
298  gSystem->Unlink("MakeTutorials-tmp.log");
299  return isnew;
300 }
301 
302 Bool_t CreateOutput_Dir(const char* dir) {
303  // Whether THtml::Convert() should run the tutorials in the
304  // directory "dir" and store their output
305 
306  if (strstr(dir,"net")) return kFALSE;
307  if (strstr(dir,"xml")) return kFALSE;
308  if (strstr(dir,"sql")) return kFALSE;
309  if (strstr(dir,"proof")) return kFALSE;
310  if (strstr(dir,"foam")) return kFALSE;
311  if (strstr(dir,"unuran")) return kFALSE;
312  if (strstr(dir,"roofit")) return kFALSE;
313  if (strstr(dir,"thread")) return kFALSE;
314  return kTRUE;
315 }
316 Bool_t CreateOutput_Tutorial(const char* tut) {
317  // Whether THtml::Convert() should run the tutorial "tut"
318  // and store its output
319 
320  static const char* vetoed[] = {
321  "geodemo",
322  "peaks2",
323  "testUnfold",
324  "readCode",
325  "importCode",
326  "hadd",
327  "line3Dfit",
328  "gtime",
329  "games",
330  "guiWithCINT",
331  "Qt",
332  "rs401d_FeldmanCousins",
333  "graph_edit_playback",
334  "fitpanel_playback",
335  "guitest_playback",
336  "geom_cms_playback",
337  "gviz3d.C",
338  0
339  };
340 
341  for (const char** iVetoed = vetoed; *iVetoed; ++iVetoed)
342  if (strstr(tut, *iVetoed))
343  return kFALSE;
344 
345  return kTRUE;
346 }
347 
348 void scandir(THtml& html, const char *dir, const char *title, TObjLink* toplnk) {
349  // Process a directory containing tutorials by converting all tutorials to
350  // html and creating an index of all tutorials in the directory.
351 
352  TString fullpath("htmldoc/tutorials/");
353  fullpath += dir;
354  if (!gSystem->OpenDirectory(fullpath)) gSystem->MakeDirectory(fullpath);
355  fullpath += "/index.html";
356  // The index for the current directory
357  ofstream fpind(fullpath);
358  writeHeader(html, fpind, title, "../../");
359 
360  TString topLinks;
361  // Creates links to prev: "hist.html", up: ".html", next: "graph.html".
362  MakeTopLinks(topLinks, 0, title, ".", "ROOT Tutorials", toplnk, dir);
363  // But we need links to prev: "../hist/index.html", up: "../index.html", next: "graph/index.html",
364  // so the following works:
365  topLinks.ReplaceAll("href=\"", "href=\"../");
366  topLinks.ReplaceAll("href=\"../http://", "href=\"http://");
367  topLinks.ReplaceAll("href=\"../https://", "href=\"https://");
368  topLinks.ReplaceAll(".html\"", "/index.html\"");
369  // Also prepend "ROOT Tutorials" to the current title:
370  topLinks.ReplaceAll("<h1 class=\"convert\">", "<h1 class=\"convert\">ROOT Tutorials: ");
371  fpind << topLinks << endl;
372  fpind << "<ul id=\"indx\">" << endl;
373 
374  TString outpath("htmldoc/tutorials/");
375  outpath += dir;
376  TString inpath("$ROOTSYS/tutorials/");
377  inpath += dir;
378  inpath += "/";
379  gSystem->ExpandPathName(inpath);
380  void *thedir = gSystem->OpenDirectory(inpath);
381  if (!thedir) {
382  printf("MakeTutorials.C: error opening directory %s", inpath.Data());
383  return;
384  }
385  const char *direntry;
386  THashList h;
387  while ((direntry = gSystem->GetDirEntry(thedir))) {
388  if(*direntry =='.') continue;
389  const char *CC = strstr(direntry,".C");
390  // must end on ".C"
391  if (!CC || *(CC+2)) continue;
392  // do not even document these; they are part of another tutorial:
393  if(strstr(direntry,"h1anal")) continue;
394  if(strstr(direntry,"hsimpleProxy")) continue;
395  if(strstr(direntry,"tv3")) continue;
396  if(strstr(direntry,"tvdemo")) continue;
397  if(strstr(direntry,"na49")) continue;
398  if(strstr(direntry,"fit1_C")) continue;
399  if(strstr(direntry,"c1.C")) continue;
400  if(strstr(direntry,"MDF.C")) continue;
401  if(strstr(direntry,"cms_calo_detail")) continue;
402  TString atut(inpath + direntry);
403  TString comment;
404  Bool_t compile;
405  GetMacroTitle(atut,comment, compile);
406  TNamed *named = new TNamed(direntry,comment.Data());
407  if (compile) named->SetBit(BIT(14));
408  h.Add(named);
409  }
410  h.Sort();
411  int numb = 0;
412  TObjLink *lnk = h.FirstLink();
413  while (lnk) {
414  TNamed* named = (TNamed*)lnk->GetObject();
415  Bool_t compile = named->TestBit(BIT(14));
416  direntry = named->GetName();
417  TString atut(inpath + direntry);
418  numb++;
419  TString iname(direntry);
420  iname += ".html";
421  writeItem(fpind, numb, iname, direntry, named->GetTitle(), IsNew(atut));
422  Int_t includeOutput = THtml::kNoOutput;
423  if (!gROOT->IsBatch()) {
424  if (compile)
425  includeOutput = THtml::kCompiledOutput;
426  else
427  includeOutput = THtml::kInterpretedOutput;
428  includeOutput |= THtml::kSeparateProcessOutput;
429  }
430  if (!CreateOutput_Dir(dir) || !CreateOutput_Tutorial(direntry))
431  includeOutput = THtml::kNoOutput;
432 
433  TString links;
434  TString tutTitle(named->GetName());
435  tutTitle += ": ";
436  tutTitle += named->GetTitle();
437  MakeTopLinks(links,named->GetName(),tutTitle,"index",title,lnk, dir);
438  html.Convert(atut,named->GetTitle(),outpath,"../../",includeOutput,links);
439  gROOT->GetListOfCanvases()->Delete();
440  gROOT->CloseFiles();
441  gROOT->GetListOfFunctions()->Delete();
442  gROOT->GetListOfBrowsers()->Delete();
443  gROOT->GetListOfGeometries()->Delete();
444  //gROOT->GetListOfSpecials()->Delete();
445  // Create some styles
446  gStyle = 0;
447  TStyle::BuildStyles();
448  gROOT->SetStyle("Default");
449  lnk = lnk->Next();
450  }
451  fpind << "</ul>" << endl;
452  writeTrailer(html, fpind);
453 }
454 
455 void MakeTutorials() {
456  // Bring the ROOT tutorials on the web, see http://root.cern.ch/root/html/tutorials/.
457  // Demonstrates the use of THtml:Convert() in a realistic context.
458 
459  if (!gSystem->OpenDirectory("htmldoc")) gSystem->MakeDirectory("htmldoc");
460  if (!gSystem->OpenDirectory("htmldoc/tutorials")) gSystem->MakeDirectory("htmldoc/tutorials");
461  gEnv->SetValue("Unix.*.Root.Html.SourceDir", "$(ROOTSYS)");
462  gEnv->SetValue("Root.Html.ViewCVS","http://root.cern.ch/viewcvs/trunk/%f?view=log");
463  gEnv->SetValue("Root.Html.Search", "http://www.google.com/search?q=%s+site%3A%u");
464  THtml html;
465  html.LoadAllLibs();
466  //gROOT->ProcessLine(".x htmlLoadlibs.C");
467  html.CreateAuxiliaryFiles();
468  writeTutorials(html);
469 }