Logo ROOT   6.14/05
Reference Guide
TDocParser.cxx
Go to the documentation of this file.
1 // @(#)root/html:$Id$
2 // Author: Axel Naumann 2007-01-09
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TDocParser.h"
13 
14 #include "Riostream.h"
15 #include "TBaseClass.h"
16 #include "TClass.h"
17 #include "TClassDocOutput.h"
18 #include "TDataMember.h"
19 #include "TDataType.h"
20 #include "TDatime.h"
21 #include "TDocDirective.h"
22 #include "TEnv.h"
23 #include "TGlobal.h"
24 #include "THtml.h"
25 #include "TInterpreter.h"
26 #include "TMethod.h"
27 #include "TMethodArg.h"
28 #include "TPRegexp.h"
29 #include "TROOT.h"
30 #include "TSystem.h"
31 #include "TVirtualMutex.h"
32 #include <string>
33 
34 namespace {
35 
36  class TMethodWrapperImpl: public TDocMethodWrapper {
37  public:
38  TMethodWrapperImpl(TMethod* m, int overloadIdx):
39  fMeth(m), fOverloadIdx(overloadIdx) {}
40 
41  static void SetClass(const TClass* cl) { fgClass = cl; }
42 
43  const char* GetName() const { return fMeth->GetName(); }
44  ULong_t Hash() const { return fMeth->Hash();}
45  Int_t GetNargs() const { return fMeth->GetNargs(); }
46  virtual TMethod* GetMethod() const { return fMeth; }
47  Bool_t IsSortable() const { return kTRUE; }
48 
49  Int_t GetOverloadIdx() const { return fOverloadIdx; }
50 
51  Int_t Compare(const TObject *obj) const {
52  const TMethodWrapperImpl* m = dynamic_cast<const TMethodWrapperImpl*>(obj);
53  if (!m) return 1;
54 
55  Int_t ret = strcasecmp(GetName(), m->GetName());
56  if (ret == 0) {
57  if (GetNargs() < m->GetNargs()) return -1;
58  else if (GetNargs() > m->GetNargs()) return 1;
59  if (GetMethod()->GetClass()->InheritsFrom(m->GetMethod()->GetClass()))
60  return -1;
61  else
62  return 1;
63  }
64 
65  const char* l(GetName());
66  const char* r(m->GetName());
67  if (l[0] == '~' && r[0] == '~') {
68  ++l;
69  ++r;
70  }
71  TClass *lcl = 0;
72  TClass *rcl = 0;
73  if (fMeth->Property() & (kIsConstructor|kIsDestructor)) {
74  lcl = TClass::GetClass(l);
75  }
76  if (m->fMeth->Property() & (kIsConstructor|kIsDestructor)) {
77  rcl = TClass::GetClass(r);
78  }
79  if (lcl && fgClass->InheritsFrom(lcl)) {
80  if (rcl && fgClass->InheritsFrom(rcl)) {
81  if (lcl->InheritsFrom(rcl))
82  return -1;
83  else return 1;
84  } else return -1;
85  } else if (rcl && fgClass->InheritsFrom(rcl))
86  return 1;
87 
88  if (l[0] == '~') return -1;
89  if (r[0] == '~') return 1;
90  return (ret < 0) ? -1 : 1;
91  }
92 
93  private:
94  static const TClass* fgClass; // current class, defining inheritance sort order
95  TMethod* fMeth; // my method
96  Int_t fOverloadIdx; // this is the n-th overload
97  };
98 
99  const TClass* TMethodWrapperImpl::fgClass = 0;
100 }
101 
102 
103 //______________________________________________________________________________
104 ////////////////////////////////////////////////////////////////////////////////
105 //
106 // Parse C++ source or header, and extract documentation.
107 //
108 // Also handles special macros like
109 /* Begin_Macro(GUI, source)
110 {
111  TGMainFrame* f = new TGMainFrame(0, 100, 100);
112  f->SetName("testMainFrame"); // that's part of the name of the image
113  TGButton* b = new TGTextButton(f, "Test Button");
114  f->AddFrame(b);
115  f->MapSubwindows();
116  f->Resize(f->GetDefaultSize());
117 
118  f->MapWindow();
119  return f; // *HIDE*
120 }
121 End_Macro */
122 // or multiline Latex aligned at =:
123 /* Begin_Latex(separator='=',align=rcl) C = d #sqrt{#frac{2}{#lambdaD}} #int^{x}_{0}cos(#frac{#pi}{2}t^{2})dt
124  D(x) = d End_Latex */
125 // even without alignment: Begin_Latex
126 // x=sin^2(y)
127 // y = #sqrt{sin(x)}
128 // End_Latex and what about running an external macro?
129 /* BEGIN_MACRO(source)
130 
131 
132 testmacro.C END_MACRO
133 
134 
135 and some nested stuff which doesn't work yet: */
136 // BEGIN_HTML
137 /* BEGIN_LATEX Wow,^{an}_{image}^{inside}_{a}^{html}_{block}
138  END_LATEX
139 */
140 // END_HTML
141 ////////////////////////////////////////////////////////////////////////////////
142 
144 
145 std::set<std::string> TDocParser::fgKeywords;
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Constructor called for parsing class sources
149 
151  fHtml(docOutput.GetHtml()), fDocOutput(&docOutput), fLineNo(0),
152  fCurrentClass(cl), fRecentClass(0), fCurrentModule(0),
153  fDirectiveCount(0), fLineNumber(0), fDocContext(kIgnore),
154  fCheckForMethod(kFALSE), fClassDocState(kClassDoc_Uninitialized),
155  fCommentAtBOL(kFALSE), fAllowDirectives(kTRUE)
156 {
157  InitKeywords();
158 
162 
164 
165  TMethodWrapperImpl::SetClass(cl);
166 
167  for (int ia = 0; ia < 3; ++ia) {
168  fMethods[ia].Rehash(101);
169  }
170 
173 
174  // needed for list of methods,...
175  fParseContext.push_back(kCode);
176 
177  // create an array of method names
178  TMethod *method;
179  TIter nextMethod(fCurrentClass->GetListOfMethods());
180  fMethodCounts.clear();
181  while ((method = (TMethod *) nextMethod())) {
182  ++fMethodCounts[method->GetName()];
183  }
184 
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// constructor called for parsing text files with Convert()
189 
191  fHtml(docOutput.GetHtml()), fDocOutput(&docOutput), fLineNo(0),
196 {
197  InitKeywords();
198 
202 
204 
205  TMethodWrapperImpl::SetClass(0);
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// destructor, checking whether all methods have been found for gDebug > 3
210 
212 {
213  if (gDebug > 3) {
214  for (std::map<std::string, Int_t>::const_iterator iMethod = fMethodCounts.begin();
215  iMethod != fMethodCounts.end(); ++iMethod)
216  if (iMethod->second)
217  Info("~TDocParser", "Implementation of method %s::%s could not be found.",
219  iMethod->first.c_str());
220  TIter iDirective(&fDirectiveHandlers);
221  TDocDirective* directive = 0;
222  while ((directive = (TDocDirective*) iDirective())) {
223  TString directiveName;
224  directive->GetName(directiveName);
225  Warning("~TDocParser", "Missing \"%s\" for macro %s", directive->GetEndTag(), directiveName.Data());
226  }
227  }
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Add accessible (i.e. non-private) methods of base class bc
232 /// and its base classes' methods to methodNames.
233 /// If bc==0, we add fCurrentClass's methods (and also private functions).
234 
236 {
237  // make a loop on member functions
238  TClass *cl = fCurrentClass;
239  if (bc)
240  cl = bc->GetClassPointer(kFALSE);
241  if (!cl) return;
242 
243  TMethod *method;
244  TIter nextMethod(cl->GetListOfMethods());
245  std::map<std::string, int> methOverloads;
246 
247  while ((method = (TMethod *) nextMethod())) {
248 
249  if (!strcmp(method->GetName(), "Dictionary") ||
250  !strcmp(method->GetName(), "Class_Version") ||
251  !strcmp(method->GetName(), "Class_Name") ||
252  !strcmp(method->GetName(), "DeclFileName") ||
253  !strcmp(method->GetName(), "DeclFileLine") ||
254  !strcmp(method->GetName(), "ImplFileName") ||
255  !strcmp(method->GetName(), "ImplFileLine") ||
256  (bc && (method->GetName()[0] == '~' // d'tor
257  || !strcmp(method->GetName(), method->GetReturnTypeName()))) // c'tor
258  )
259  continue;
260 
261 
262  Int_t mtype = 0;
263  if (kIsPrivate & method->Property())
264  mtype = 0;
265  else if (kIsProtected & method->Property())
266  mtype = 1;
267  else if (kIsPublic & method->Property())
268  mtype = 2;
269 
270  if (bc) {
271  if (mtype == 0) continue;
272  if (bc->Property() & kIsPrivate)
273  mtype = 0;
274  else if ((bc->Property() & kIsProtected) && mtype == 2)
275  mtype = 1;
276  }
277 
278  Bool_t hidden = kFALSE;
279  for (Int_t access = 0; !hidden && access < 3; ++access) {
280  TMethodWrapperImpl* other = (TMethodWrapperImpl*) fMethods[access].FindObject(method->GetName());
281  hidden |= (other) && (other->GetMethod()->GetClass() != method->GetClass());
282  }
283  if (!hidden) {
284  fMethods[mtype].Add(new TMethodWrapperImpl(method, methOverloads[method->GetName()]));
285  ++methOverloads[method->GetName()];
286  }
287  }
288 
289  TIter iBase(cl->GetListOfBases());
290  TBaseClass* base = 0;
291  while ((base = (TBaseClass*)iBase()))
293 
294  if (!bc)
295  for (Int_t access = 0; access < 3; ++access) {
296  fMethods[access].SetOwner();
297  fMethods[access].Sort();
298  }
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Add data members of fCurrentClass and of bc to datamembers, recursively.
303 /// Real data members are in idx 0..2 (public, protected, private access),
304 /// enum constants in idx 3..5.
305 
307  // make a loop on member functions
308  TClass *cl = fCurrentClass;
309  if (bc)
310  cl = bc->GetClassPointer(kFALSE);
311  if (!cl) return;
312 
313  TDataMember *dm;
314  TIter nextDM(cl->GetListOfDataMembers());
315 
316  while ((dm = (TDataMember *) nextDM())) {
317  if (!strcmp(dm->GetName(), "fgIsA"))
318  continue;
319  Int_t mtype = 0;
320  if (kIsPrivate & dm->Property())
321  mtype = 0;
322  else if (kIsProtected & dm->Property())
323  mtype = 1;
324  else if (kIsPublic & dm->Property())
325  mtype = 2;
326 
327  if (bc) {
328  if (mtype == 0) continue;
329  if (bc->Property() & kIsPrivate)
330  mtype = 0;
331  else if ((bc->Property() & kIsProtected) && mtype == 2)
332  mtype = 1;
333  }
334 
335  const Int_t flagEnumConst = kIsEnum | kIsConstant | kIsStatic;
336  if ((dm->Property() & flagEnumConst) == flagEnumConst
337  && dm->GetDataType() && dm->GetDataType()->GetType() == kInt_t) {
338  mtype = 5;
339  // The access of the enum constant is defined by the access of the enum:
340  // for CINT, all enum constants are public.
341  // There is no TClass or TDataType for enum types; instead, use CINT:
342  /*
343  No - CINT does not know their access restriction.
344  With CINT5 we have no way of determining it...
345 
346  ClassInfo_t* enumCI = gInterpreter->ClassInfo_Factory(dm->GetTypeName());
347  if (enumCI) {
348  Long_t prop = gInterpreter->ClassInfo_Property(enumCI);
349  if (kIsPrivate & prop)
350  mtype = 3;
351  else if (kIsProtected & prop)
352  mtype = 4;
353  else if (kIsPublic & prop)
354  mtype = 5;
355  gInterpreter->ClassInfo_Delete(enumCI);
356  }
357  */
358  }
359 
360  fDataMembers[mtype].Add(dm);
361  }
362 
363  TIter iBase(cl->GetListOfBases());
364  TBaseClass* base = 0;
365  while ((base = (TBaseClass*)iBase()))
367 
368  if (!bc)
369  for (Int_t access = 0; access < 6; ++access) {
370  fDataMembers[access].SetOwner(kFALSE);
371  if (access < 3) // don't sort enums; we keep them in enum tag order
372  fDataMembers[access].Sort();
373  }
374 }
375 
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 /// Create an anchor from the given line, by hashing it and
379 /// convertig the hash into a custom base64 string.
380 
382  const char base64String[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
383 
384  // use hash of line instead of e.g. line number.
385  // advantages: more stable (lines can move around, we still find them back),
386  // no need for keeping a line number context
387  UInt_t hash = ::Hash(line);
388  anchor.Remove(0);
389  // force first letter to be [A-Za-z], to be id compatible
390  anchor += base64String[hash % 52];
391  hash /= 52;
392  while (hash) {
393  anchor += base64String[hash % 64];
394  hash /= 64;
395  }
396 }
397 
398 ////////////////////////////////////////////////////////////////////////////////
399 /// Parse text file "in", add links etc, and write output to "out".
400 /// If "isCode", "in" is assumed to be C++ code.
401 
402 void TDocParser::Convert(std::ostream& out, std::istream& in, const char* relpath,
403  Bool_t isCode, Bool_t interpretDirectives)
404 {
405  fLineNumber = 0;
406  fParseContext.clear();
407  if (isCode) fParseContext.push_back(kCode);
408  else fParseContext.push_back(kComment); // so we can find "BEGIN_HTML"/"END_HTML" in plain text
409 
410  while (!in.eof()) {
411  fLineRaw.ReadLine(in, kFALSE);
412  ++fLineNumber;
413  if (in.eof())
414  break;
415 
416  // remove leading spaces
417  fLineComment = "";
421 
423 
424  // Changes in this bit of code have consequences for:
425  // * module index,
426  // * source files,
427  // * THtml::Convert() e.g. in tutorials/html/MakeTutorials.C
428  if (!interpretDirectives) {
429  // Only write the raw, uninterpreted directive code:
430  if (!InContext(kDirective)) {
432  out << fLineSource << std::endl;
433  }
434  } else {
435  // Write source for source and interpreted directives if they exist.
436  if (fLineComment.Length() ) {
438  out << fLineComment << std::endl;
439  } else if (!InContext(kDirective)) {
441  out << fLineSource << std::endl;
442  }
443  }
444  }
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Expand keywords in text, writing to out.
449 
450 void TDocParser::DecorateKeywords(std::ostream& out, const char *text)
451 {
452  TString str(text);
453  DecorateKeywords(str);
454  out << str;
455 }
456 
457 ////////////////////////////////////////////////////////////////////////////////
458 /// Find keywords in line and create URLs around them. Escape characters with a
459 /// special meaning for HTML. Protect "Begin_Html"/"End_Html" pairs, and set the
460 /// parsing context. Evaluate sequences like a::b->c.
461 /// Skip regions where directives are active.
462 
464 {
465  std::list<TClass*> currentType;
466 
467  enum {
468  kNada,
469  kMember,
470  kScope,
471  kNumAccesses
472  } scoping = kNada;
473 
474  currentType.push_back(0);
475 
476  Ssiz_t i = 0;
477  while (isspace((UChar_t)line[i]))
478  ++i;
479 
480  Ssiz_t startOfLine = i;
481 
482  // changed when the end of a directive is encountered, i.e.
483  // from where fLineSource needs to be appended to fLineComment
484  Ssiz_t copiedToCommentUpTo = 0;
485 
487  // we're only waiting for an "End_Whatever" and ignoring everything else
489  const char* endTag = directive->GetEndTag();
490  Ssiz_t posEndTag = i;
491  while (kNPOS != (posEndTag = line.Index(endTag, posEndTag, TString::kIgnoreCase)))
492  if (posEndTag == 0 || line[posEndTag - 1] != '"') // escaping '"'
493  break;
494  if (posEndTag != kNPOS)
495  i = posEndTag;
496  else {
497  Ssiz_t start = 0;
499  // means we are in a C++ comment
500  while (isspace((UChar_t)fLineRaw[start])) ++start;
501  if (fLineRaw[start] == '/' && fLineRaw[start + 1] == '/')
502  start += 2;
503  else start = 0;
504  }
505  directive->AddLine(fLineRaw(start, fLineRaw.Length()));
506  while(i < line.Length())
508  copiedToCommentUpTo = i;
509  }
510  }
511 
512  for (; i < line.Length(); ++i) {
513 
514  if (!currentType.back())
515  scoping = kNada;
516 
517  // evaluate scope relation
518  if (Context() == kCode
519  || Context() == kComment) {
520  if (currentType.back())
521  switch (line[i]) {
522  case ':':
523  if (line[i + 1] == ':') {
524  scoping = kScope;
525  i += 1;
526  continue;
527  }
528  break;
529  case '-':
530  if (line[i + 1] == '>') {
531  scoping = kMember;
532  i += 1;
533  continue;
534  }
535  break;
536  case '.':
537  if (line[i + 1] != '.') {
538  // prevent "..."
539  scoping = kMember;
540  continue;
541  }
542  break;
543  }
544  switch (line[i]) {
545  case '(':
546  currentType.push_back(0);
547  scoping = kNada;
548  continue;
549  break;
550  case ')':
551  if (currentType.size() > 1)
552  currentType.pop_back();
553  scoping = kMember;
554  continue;
555  break;
556  }
557  if (i >= line.Length())
558  break;
559  } else // code or comment
560  currentType.back() = 0;
561 
562 
563  if (!IsWord(line[i])){
564 
565  Bool_t haveHtmlEscapedChar = Context() == kString
566  && i > 2 && line[i] == '\'' && line[i-1] == ';';
567  if (haveHtmlEscapedChar) {
568  Ssiz_t posBegin = i - 2;
569  while (posBegin > 0 && IsWord(line[posBegin]))
570  --posBegin;
571  haveHtmlEscapedChar = posBegin > 0 &&
572  line[posBegin] == '&' && line[posBegin - 1] == '\'';
573  }
574  EParseContext context = Context();
575  Bool_t closeString = context == kString
576  && ( line[i] == '"'
577  || (line[i] == '\''
578  && ( (i > 1 && line[i - 2] == '\'')
579  || (i > 3 && line[i - 2] == '\\' && line[i - 3] == '\'')))
580  || haveHtmlEscapedChar)
581  && (i == 0 || line[i - 1] != '\\'); // but not "foo \"str...
582  if (context == kCode || context == kComment) {
583  if (line[i] == '"' || (line[i] == '\'' && (
584  // 'a'
585  (line.Length() > i + 2 && line[i + 2] == '\'') ||
586  // '\a'
587  (line.Length() > i + 3 && line[i + 1] == '\'' && line[i + 3] == '\'')))) {
588 
590  fParseContext.push_back(kString);
591  currentType.back() = 0;
592  closeString = kFALSE;
593  } else if (context == kCode
594  && line[i] == '/' && (line[i+1] == '/' || line[i+1] == '*')) {
595  fParseContext.push_back(kComment);
596  if (line[i+1] == '/')
597  fParseContext.back() |= kCXXComment;
598  currentType.back() = 0;
600  ++i;
601  } else if (context == kComment
602  && !(fParseContext.back() & kCXXComment)
603  && line.Length() > i + 1
604  && line[i] == '*' && line[i+1] == '/') {
605  if (fParseContext.size()>1)
606  fParseContext.pop_back();
607 
608  currentType.back() = 0;
609  i += 2;
611  if (!fCommentAtBOL) {
612  if (InContext(kDirective))
613  ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(line(copiedToCommentUpTo, i));
614  else
615  fLineComment += line(copiedToCommentUpTo, i);
616  copiedToCommentUpTo = i;
617  }
618  } else if (startOfLine == i
619  && line[i] == '#'
620  && context == kCode) {
621  ExpandCPPLine(line, i);
622  }
623  } // if context is comment or code
624 
625  if (i < line.Length())
627 
628  if (closeString) {
630  if (fParseContext.size()>1)
631  fParseContext.pop_back();
632 
633  currentType.back() = 0;
634  }
635  --i; // i already moved by ReplaceSpecialChar
636 
637  continue;
638  } // end of "not a word"
639 
640  // get the word
641  Ssiz_t endWord = i;
642  while (endWord < line.Length() && IsName(line[endWord]))
643  endWord++;
644 
645  if (Context() == kString || Context() == kCPP) {
646  // don't replace in strings, cpp, etc
647  i = endWord - 1;
648  continue;
649  }
650 
651  TString word(line(i, endWord - i));
652 
653  // '"' escapes handling of "Begin_..."/"End_..."
654  if ((i == 0 || (i > 0 && line[i - 1] != '"'))
655  && HandleDirective(line, i, word, copiedToCommentUpTo)) {
656  // something special happened; the currentType is gone.
657  currentType.back() = 0;
658  continue;
659  }
660 
661  // don't replace keywords in comments
662  if (Context() == kCode
663  && fgKeywords.find(word.Data()) != fgKeywords.end()) {
665  i += word.Length();
667  --i; // -1 for ++i
668  currentType.back() = 0;
669  continue;
670  }
671 
672  // Now decorate scopes and member, referencing their documentation:
673 
674  // generic layout:
675  // A::B::C::member[arr]->othermember
676  // we iterate through this, first scope is A, and currentType will be set toA,
677  // next we see ::B, "::" signals to use currentType,...
678 
679  TDataType* subType = 0;
680  TClass* subClass = 0;
681  TDataMember *datamem = 0;
682  TMethod *meth = 0;
683  const char* globalTypeName = 0;
684  if (currentType.empty()) {
685  Warning("DecorateKeywords", "type context is empty!");
686  currentType.push_back(0);
687  }
688  TClass* lookupScope = currentType.back();
689 
690  if (scoping == kNada) {
691  if (fCurrentClass)
692  lookupScope = fCurrentClass;
693  else
694  lookupScope = fRecentClass;
695  }
696 
697  if (scoping == kNada) {
698  subType = gROOT->GetType(word);
699  if (!subType)
700  subClass = fHtml->GetClass(word);
701  if (!subType && !subClass) {
702  TGlobal *global = gROOT->GetGlobal(word);
703  if (global) {
704  // cannot doc globals; take at least their type...
705  globalTypeName = global->GetTypeName();
706  subClass = fHtml->GetClass(globalTypeName);
707  if (!subClass)
708  subType = gROOT->GetType(globalTypeName);
709  else // hack to prevent current THtml obj from showing up - we only want gHtml
710  if (subClass == THtml::Class() && word != "gHtml")
711  subClass = 0;
712  }
713  }
714  if (!subType && !subClass) {
715  // too bad - cannot doc yet...
716  //TFunction *globFunc = gROOT->GetGlobalFunctionWithPrototype(word);
717  //globFunc = 0;
718  }
719  if (!subType && !subClass) {
720  // also try template
721  while (isspace(line[endWord])) ++endWord;
722  if (line[endWord] == '<' || line[endWord] == '>') {
723  // check for possible template
724  Ssiz_t endWordT = endWord + 1;
725  int templateLevel = 1;
726  while (endWordT < line.Length()
727  && (templateLevel
728  || IsName(line[endWordT])
729  || line[endWordT] == '<'
730  || line[endWordT] == '>')) {
731  if (line[endWordT] == '<')
732  ++templateLevel;
733  else if (line[endWordT] == '>')
734  --templateLevel;
735  endWordT++;
736  }
737  subClass = fHtml->GetClass(line(i, endWordT - i).Data());
738  if (subClass)
739  word = line(i, endWordT - i);
740  }
741  }
742  }
743 
744  if (lookupScope && !subType && !subClass) {
745  if (scoping == kScope) {
746  TString subClassName(lookupScope->GetName());
747  subClassName += "::";
748  subClassName += word;
749  subClass = fHtml->GetClass(subClassName);
750  if (!subClass)
751  subType = gROOT->GetType(subClassName);
752  }
753  if (!subClass && !subType) {
754  // also try A::B::c()
755  datamem = lookupScope->GetDataMember(word);
756  if (!datamem)
757  meth = lookupScope->GetMethodAllAny(word);
758  }
759  if (!subClass && !subType && !datamem && !meth) {
760  // also try template
761  while (isspace(line[endWord])) ++endWord;
762  if (line[endWord] == '<' || line[endWord] == '>') {
763  // check for possible template
764  Ssiz_t endWordT = endWord + 1;
765  int templateLevel = 1;
766  while (endWordT < line.Length()
767  && (templateLevel
768  || IsName(line[endWordT])
769  || line[endWordT] == '<'
770  || line[endWordT] == '>')) {
771  if (line[endWordT] == '<')
772  ++templateLevel;
773  else if (line[endWordT] == '>')
774  --templateLevel;
775  endWordT++;
776  }
777  TString subClassName(lookupScope->GetName());
778  subClassName += "::";
779  subClassName += line(i, endWordT - i);
780  subClass = fHtml->GetClass(subClassName);
781  if (subClass)
782  word = line(i, endWordT - i);
783  }
784  }
785  }
786  // create the link
787  TString mangledWord(word);
788  fDocOutput->ReplaceSpecialChars(mangledWord);
789  line.Replace(i, word.Length(), mangledWord);
790 
791  TSubString substr(line(i, mangledWord.Length()));
792  if (subType) {
793  fDocOutput->ReferenceEntity(substr, subType,
794  globalTypeName ? globalTypeName : subType->GetName());
795  currentType.back() = 0;
796  } else if (subClass) {
797  fDocOutput->ReferenceEntity(substr, subClass,
798  globalTypeName ? globalTypeName : subClass->GetName());
799 
800  currentType.back() = subClass;
801  fRecentClass = subClass;
802  } else if (datamem || meth) {
803  if (datamem) {
804  fDocOutput->ReferenceEntity(substr, datamem);
805 
806  if (datamem->GetTypeName())
807  currentType.back() = fHtml->GetClass(datamem->GetTypeName());
808  } else {
809  fDocOutput->ReferenceEntity(substr, meth);
810 
811  TString retTypeName = meth->GetReturnTypeName();
812  if (retTypeName.BeginsWith("const "))
813  retTypeName.Remove(0,6);
814  Ssiz_t pos=0;
815  while (IsWord(retTypeName[pos]) || retTypeName[pos]=='<' || retTypeName[pos]=='>' || retTypeName[pos]==':')
816  ++pos;
817  retTypeName.Remove(pos, retTypeName.Length());
818  if (retTypeName.Length())
819  currentType.back() = fHtml->GetClass(retTypeName);
820  }
821  } else
822  currentType.back() = 0;
823 
824  //i += mangledWord.Length();
825  i += substr.Length();
826 
827  --i; // due to ++i
828  } // while i < line.Length()
829  if (i > line.Length())
830  i = line.Length();
831 
832  // clean up, no strings across lines
833  if (Context() == kString) {
835  if (fParseContext.size()>1)
836  fParseContext.pop_back();
837  currentType.back() = 0;
838  }
839 
840  // HandleDirective already copied the chunk before the directive
841  // from fLineSource to fLineComment. So we're done up to "i" in
842  // fLineSource; next time we encounter a directive we just need
843  // to copy from startOfComment on.
844  if ((InContext(kComment) || fCommentAtBOL) && copiedToCommentUpTo < line.Length()) {
845  if (InContext(kDirective))
846  ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(line(copiedToCommentUpTo, line.Length()));
847  else
848  fLineComment += line(copiedToCommentUpTo, line.Length());
849  }
850 
851  // Do this after we append to fLineComment, otherwise the closing
852  // </span> gets sent to the directive.
853  // clean up, no CPP comment across lines
854  if (InContext(kComment) & kCXXComment) {
856  if (fLineComment.Length()) {
857  Ssiz_t pos = fLineComment.Length();
859  }
861  currentType.back() = 0;
862  }
863 }
864 
865 ////////////////////////////////////////////////////////////////////////////////
866 /// reduce method count for method called name,
867 /// removing it from fMethodCounts once the count reaches 0.
868 
870 {
871  typedef std::map<std::string /*method name*/, Int_t > MethodCount_t;
872  MethodCount_t::iterator iMethodName = fMethodCounts.find(name);
873  if (iMethodName != fMethodCounts.end()) {
874  --(iMethodName->second);
875  if (iMethodName->second <= 0)
876  fMethodCounts.erase(iMethodName);
877  }
878 }
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 /// Delete output generated by prior runs of all known directives;
882 /// the output file names might have changes.
883 
885 {
886  TIter iClass(gROOT->GetListOfClasses());
887  TClass* cl = 0;
888  while ((cl = (TClass*) iClass()))
889  if (cl != TDocDirective::Class()
890  && cl->InheritsFrom(TDocDirective::Class())) {
891  TDocDirective* directive = (TDocDirective*) cl->New();
892  if (!directive) continue;
893  directive->SetParser(const_cast<TDocParser*>(this));
894  directive->DeleteOutput();
895  delete directive;
896  }
897 }
898 
899 ////////////////////////////////////////////////////////////////////////////////
900 /// Expand preprocessor statements
901 ///
902 ///
903 /// Input: line - line containing the CPP statement,
904 /// pos - position of '#'
905 ///
906 /// NOTE: Looks for the #include statements and
907 /// creates link to the corresponding file
908 /// if such file exists
909 ///
910 
912 {
913  Bool_t linkExist = kFALSE;
914  Ssiz_t posEndOfLine = line.Length();
915  Ssiz_t posHash = pos;
916 
917  Ssiz_t posInclude = line.Index("include", pos);
918  if (posInclude != kNPOS) {
919  TString filename;
920  Ssiz_t posStartFilename = posInclude + 7;
921  if (line.Tokenize(filename, posStartFilename, "[<\"]")) {
922  Ssiz_t posEndFilename = posStartFilename;
923  if (line.Tokenize(filename, posEndFilename, "[>\"]")) {
925 
926  TString filesysFileName;
927  if (fHtml->GetPathDefinition().GetFileNameFromInclude(filename, filesysFileName)) {
928  fDocOutput->CopyHtmlFile(filesysFileName);
929 
930  TString endOfLine(line(posEndFilename - 1, line.Length()));
931  line.Remove(posStartFilename, line.Length());
932  for (Ssiz_t i = pos; i < line.Length();)
934 
935  line += "<a href=\"./";
936  line += gSystem->BaseName(filename);
937  line += "\">";
938  line += filename + "</a>" + endOfLine[0]; // add include file's closing '>' or '"'
939  posEndOfLine = line.Length() - 1; // set the "processed up to" to it
940  fDocOutput->ReplaceSpecialChars(line, posEndOfLine); // and run replace-special-char on it
941 
942  line += endOfLine(1, endOfLine.Length()); // add the unprocessed part of the line back
943 
944  linkExist = kTRUE;
945  }
946  }
947  }
948  }
949 
950  if (!linkExist) {
952  posEndOfLine = line.Length();
953  }
954 
955  Ssiz_t posHashAfterDecoration = posHash;
956  fDocOutput->DecorateEntityBegin(line, posHashAfterDecoration, kCPP);
957  posEndOfLine += posHashAfterDecoration - posHash;
958 
959  fDocOutput->DecorateEntityEnd(line, posEndOfLine, kCPP);
960  pos = posEndOfLine;
961 }
962 
963 
964 ////////////////////////////////////////////////////////////////////////////////
965 /// Return the name of module for which sources are currently parsed.
966 
967 void TDocParser::GetCurrentModule(TString& out_module) const {
968  if (fCurrentModule) out_module = fCurrentModule;
969  else if (fCurrentClass) fHtml->GetModuleNameForClass(out_module, fCurrentClass);
970  else out_module = "(UNKNOWN MODULE WHILE PARSING)";
971 }
972 
973 ////////////////////////////////////////////////////////////////////////////////
974 /// Process directives to the documentation engine, like "Begin_Html" / "End_Html",
975 /// "Begin_Macro" / "End_Macro", and "Begin_Latex" / "End_Latex".
976 
978  Ssiz_t& copiedToCommentUpTo)
979 {
980  Bool_t begin = kTRUE;
981  TClass* clDirective = IsDirective(line, pos, word, begin);
982  if (!clDirective)
983  return kFALSE;
984 
985  // we'll need end later on: afer the begin block, both end _and_ begin can be true.
986  Bool_t end = !begin;
987 
988  TDocDirective* directive = 0; // allow re-use of object from begin block in end
989 
990  if (begin) {
991  // copy from fLineSource to fLineComment, starting at copiedToCommentUpTo
992  if (InContext(kDirective))
993  ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(fLineSource(copiedToCommentUpTo, pos - copiedToCommentUpTo));
994  else
995  fLineComment += fLineSource(copiedToCommentUpTo, pos - copiedToCommentUpTo);
996  copiedToCommentUpTo = pos;
997 
998  pos += word.Length(); // skip the keyword
999 
1000  directive = (TDocDirective*) clDirective->New();
1001  if (!directive)
1002  return kFALSE;
1003 
1004  directive->SetParser(this);
1005  if (fCurrentMethodTag.Length())
1006  directive->SetTag(fCurrentMethodTag);
1007  directive->SetCounter(fDirectiveCount++);
1008 
1009  // parse parameters
1010  TString params;
1011  if (begin && line[pos] == '(') {
1012  std::list<char> waitForClosing;
1013  Ssiz_t endParam = pos + 1;
1014  for (; endParam < line.Length()
1015  && (line[endParam] != ')' || !waitForClosing.empty()); ++endParam) {
1016  const char c = line[endParam];
1017  if (!waitForClosing.empty() && waitForClosing.back() == c) {
1018  waitForClosing.pop_back();
1019  continue;
1020  }
1021  switch (c) {
1022  case '"':
1023  if (waitForClosing.empty() || waitForClosing.back() != '\'')
1024  waitForClosing.push_back('"');
1025  break;
1026  case '\'':
1027  if (waitForClosing.empty() || waitForClosing.back() != '"')
1028  waitForClosing.push_back('\'');
1029  break;
1030  case '(':
1031  if (waitForClosing.empty() || (waitForClosing.back() != '"' && waitForClosing.back() != '\''))
1032  waitForClosing.push_back(')');
1033  break;
1034  case '\\':
1035  ++endParam; // skip next char
1036  default:
1037  break;
1038  };
1039  }
1040  if (waitForClosing.empty()) {
1041  params = line(pos + 1, endParam - (pos + 1));
1042  pos += params.Length() + 2; // params + parentheses
1043  }
1044  directive->SetParameters(params);
1045  }
1046 
1047  // check for end tag in current line
1048  Ssiz_t posEndTag = pos;
1049  const char* endTag = directive->GetEndTag();
1050  Ssiz_t lenEndTag = strlen(endTag);
1051  while (kNPOS != (posEndTag = line.Index(endTag, posEndTag, TString::kIgnoreCase))) {
1052  if (line[posEndTag - 1] == '"') {
1053  posEndTag += lenEndTag;
1054  continue; // escaping '"'
1055  }
1056  break;
1057  }
1058  if (posEndTag != kNPOS) {
1059  end = kTRUE; // we just continue below!
1060  } else {
1061  fDirectiveHandlers.AddLast(directive);
1062 
1063  fParseContext.push_back(kDirective);
1065  fParseContext.back() |= kCXXComment;
1066 
1067  posEndTag = line.Length();
1068  }
1069 
1070  directive->AddLine(line(pos, posEndTag - pos));
1071  TString remainder(line(posEndTag, line.Length()));
1072  line.Remove(posEndTag, line.Length());
1073 
1074  while (pos < line.Length())
1075  fDocOutput->ReplaceSpecialChars(line, pos);
1076 
1077  pos = line.Length();
1078  // skip the remainder of the line
1079  copiedToCommentUpTo = line.Length();
1080  line += remainder;
1081  }
1082 
1083  // no else - "end" can also be set by begin having an end tag!
1084  if (end) {
1085 
1086  if (!begin)
1087  pos += word.Length(); // skip the keyword
1088  else pos += word.Length() - 2; // "Begin" is 2 chars longer than "End"
1089 
1090  if (!directive) directive = (TDocDirective*) fDirectiveHandlers.Last();
1091 
1092  if (!directive) {
1093  Warning("HandleDirective", "Cannot find directive handler object %s !",
1094  fLineRaw.Data());
1095  return kFALSE;
1096  }
1097 
1098  if (!begin) {
1099  Ssiz_t start = 0;
1101  // means we are in a C++ comment
1102  while (isspace((UChar_t)fLineRaw[start])) ++start;
1103  if (fLineRaw[start] == '/' && fLineRaw[start + 1] == '/')
1104  start += 2;
1105  else start = 0;
1106  }
1107  directive->AddLine(line(start, pos - word.Length() - start));
1108 
1109  TString remainder(line(pos, line.Length()));
1110  line.Remove(pos, line.Length());
1112  pos = line.Length();
1113  line += remainder;
1114  }
1115  copiedToCommentUpTo = pos;
1116 
1117  TString result;
1118  directive->GetResult(result);
1119 
1120  if (!begin)
1122  delete directive;
1123 
1124  if (!begin) {
1125  // common to all directives: pop context
1126  Bool_t isInCxxComment = InContext(kDirective) & kCXXComment;
1127  if (fParseContext.size()>1)
1128  fParseContext.pop_back();
1129  if (isInCxxComment && !InContext(kComment)) {
1130  fParseContext.push_back(kComment | kCXXComment);
1132  }
1133  }
1134 
1136  ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(result(0, result.Length()));
1137  else
1138  fLineComment += result;
1139 
1140  /* NO - this can happen e.g. for "BEGIN_HTML / *..." (see doc in this class)
1141  if (Context() != kComment) {
1142  Warning("HandleDirective", "Popping back a directive context, but enclosing context is not a comment! At:\n%s",
1143  fLineRaw.Data());
1144  fParseContext.push_back(kComment);
1145  }
1146  */
1147  }
1148 
1149  return kTRUE;
1150 }
1151 
1152 ////////////////////////////////////////////////////////////////////////////////
1153 /// checks whether we are in a parse context, return the entry closest
1154 /// to the current context.
1155 /// If context is a EParseContextFlag just look for the first match in
1156 /// the flags
1157 
1159 {
1160  UInt_t lowerContext = context & kParseContextMask;
1161  UInt_t contextFlag = context & kParseContextFlagMask;
1162 
1163  for (std::list<UInt_t>::const_reverse_iterator iPC = fParseContext.rbegin();
1164  iPC != fParseContext.rend(); ++iPC)
1165  if (!lowerContext || ((lowerContext && ((*iPC & kParseContextMask) == lowerContext))
1166  && (!contextFlag || (contextFlag && (*iPC & contextFlag)))))
1167  return *iPC;
1168 
1169  return 0;
1170 }
1171 
1172 ////////////////////////////////////////////////////////////////////////////////
1173 /// fill C++ keywords into fgKeywords
1174 
1176 {
1177  if (!fgKeywords.empty())
1178  return;
1179 
1180  fgKeywords.insert("asm");
1181  fgKeywords.insert("auto");
1182  fgKeywords.insert("bool");
1183  fgKeywords.insert("break");
1184  fgKeywords.insert("case");
1185  fgKeywords.insert("catch");
1186  fgKeywords.insert("char");
1187  fgKeywords.insert("class");
1188  fgKeywords.insert("const");
1189  fgKeywords.insert("const_cast");
1190  fgKeywords.insert("continue");
1191  fgKeywords.insert("default");
1192  fgKeywords.insert("delete");
1193  fgKeywords.insert("do");
1194  fgKeywords.insert("double");
1195  fgKeywords.insert("dynamic_cast");
1196  fgKeywords.insert("else");
1197  fgKeywords.insert("enum");
1198  fgKeywords.insert("explicit");
1199  fgKeywords.insert("export");
1200  fgKeywords.insert("extern");
1201  fgKeywords.insert("false");
1202  fgKeywords.insert("float");
1203  fgKeywords.insert("for");
1204  fgKeywords.insert("friend");
1205  fgKeywords.insert("goto");
1206  fgKeywords.insert("if");
1207  fgKeywords.insert("inline");
1208  fgKeywords.insert("int");
1209  fgKeywords.insert("long");
1210  fgKeywords.insert("mutable");
1211  fgKeywords.insert("namespace");
1212  fgKeywords.insert("new");
1213  fgKeywords.insert("operator");
1214  fgKeywords.insert("private");
1215  fgKeywords.insert("protected");
1216  fgKeywords.insert("public");
1217  fgKeywords.insert("register");
1218  fgKeywords.insert("reinterpret_cast");
1219  fgKeywords.insert("return");
1220  fgKeywords.insert("short");
1221  fgKeywords.insert("signed");
1222  fgKeywords.insert("sizeof");
1223  fgKeywords.insert("static");
1224  fgKeywords.insert("static_cast");
1225  fgKeywords.insert("struct");
1226  fgKeywords.insert("switch");
1227  fgKeywords.insert("template");
1228  fgKeywords.insert("this");
1229  fgKeywords.insert("throw");
1230  fgKeywords.insert("true");
1231  fgKeywords.insert("try");
1232  fgKeywords.insert("typedef");
1233  fgKeywords.insert("typeid");
1234  fgKeywords.insert("typename");
1235  fgKeywords.insert("union");
1236  fgKeywords.insert("unsigned");
1237  fgKeywords.insert("using");
1238  fgKeywords.insert("virtual");
1239  fgKeywords.insert("void");
1240  fgKeywords.insert("volatile");
1241  fgKeywords.insert("wchar_t");
1242  fgKeywords.insert("while");
1243 }
1244 
1245 ////////////////////////////////////////////////////////////////////////////////
1246 /// return whether word at line's pos is a valid directive, and returns its
1247 /// TDocDirective's TClass object, or 0 if it's not a directive. Set begin
1248 /// to kTRUE for "Begin_..."
1249 /// You can implement your own handlers by implementing a class deriving
1250 /// from TDocHandler, and calling it TDocTagDirective for "BEGIN_TAG",
1251 /// "END_TAG" blocks.
1252 
1254  const TString& word, Bool_t& begin) const
1255 {
1256  // '"' serves as escape char
1257  if (pos > 0 && line[pos - 1] == '"')
1258  return 0;
1259 
1260  begin = word.BeginsWith("begin_", TString::kIgnoreCase);
1261  Bool_t end = word.BeginsWith("end_", TString::kIgnoreCase);
1262 
1263  if (!begin && !end)
1264  return 0;
1265 
1266  /* NO - we can have "BEGIN_HTML / * ..."
1267  if (!InContext(kComment))
1268  return 0;
1269  */
1270 
1271  TString tag = word( begin ? 6 : 4, word.Length());
1272 
1273  if (!tag.Length())
1274  return 0;
1275 
1276  tag.ToLower();
1277  tag[0] -= 'a' - 'A'; // first char is caps
1278  tag.Prepend("TDoc");
1279  tag += "Directive";
1280 
1281  TClass* clDirective = TClass::GetClass(tag, kFALSE);
1282 
1283  if (gDebug > 0 && !clDirective)
1284  Warning("IsDirective", "Unknown THtml directive %s in line %d!", word.Data(), fLineNo);
1285 
1286  return clDirective;
1287 }
1288 
1289 ////////////////////////////////////////////////////////////////////////////////
1290 /// Check if c is a valid C++ name character
1291 ///
1292 ///
1293 /// Input: c - a single character
1294 ///
1295 /// Output: TRUE if c is a valid C++ name character
1296 /// and FALSE if it's not.
1297 ///
1298 /// NOTE: Valid name characters are [a..zA..Z0..9_~],
1299 ///
1300 
1302 {
1303  Bool_t ret = kFALSE;
1304 
1305  if (isalnum(c) || c == '_' || c == '~')
1306  ret = kTRUE;
1307 
1308  return ret;
1309 }
1310 
1311 
1312 ////////////////////////////////////////////////////////////////////////////////
1313 /// Check if c is a valid first character for C++ name
1314 ///
1315 ///
1316 /// Input: c - a single character
1317 ///
1318 /// Output: TRUE if c is a valid first character for C++ name,
1319 /// and FALSE if it's not.
1320 ///
1321 /// NOTE: Valid first characters are [a..zA..Z_~]
1322 ///
1323 
1325 {
1326  Bool_t ret = kFALSE;
1327 
1328  if (isalpha(c) || c == '_' || c == '~')
1329  ret = kTRUE;
1330 
1331  return ret;
1332 }
1333 
1334 
1335 ////////////////////////////////////////////////////////////////////////////////
1336 /// Search for a method starting at posMethodName, and return its return type,
1337 /// its name, and its arguments. If the end of arguments is not found in the
1338 /// current line, get a new line from sourceFile, beautify it to srcOut, creating
1339 /// an anchor as necessary. When this function returns, posMethodName points to the
1340 /// end of the function declaration, i.e. right after the arguments' closing bracket.
1341 /// If posMethodName == kNPOS, we look for the first matching method in fMethodCounts.
1342 
1344  TString& name, TString& params,
1345  Bool_t& isconst, std::ostream &srcOut,
1346  TString &anchor, std::ifstream& sourceFile,
1347  Bool_t allowPureVirtual)
1348 {
1349  typedef std::map<std::string /*method name*/, Int_t > MethodCount_t;
1350  isconst = false;
1351 
1352  if (posMethodName == kNPOS) {
1353  name.Remove(0);
1354  TMethod * meth = 0;
1355  Ssiz_t posBlock = fLineRaw.Index('{');
1356  Ssiz_t posQuote = fLineRaw.Index('"');
1357  if (posQuote != kNPOS && (posBlock == kNPOS || posQuote < posBlock))
1358  posBlock = posQuote;
1359  if (posBlock == kNPOS)
1360  posBlock = fLineRaw.Length();
1361  for (MethodCount_t::iterator iMethodName = fMethodCounts.begin();
1362  !name.Length() && iMethodName != fMethodCounts.end(); ++iMethodName) {
1363  TString lookFor(iMethodName->first);
1364  posMethodName = fLineRaw.Index(lookFor);
1365  if (posMethodName != kNPOS && posMethodName < posBlock
1366  && (posMethodName == 0 || !IsWord(fLineRaw[posMethodName - 1]))) {
1367  // check whether the method name is followed by optional spaces and
1368  // an opening parathesis
1369  Ssiz_t posMethodEnd = posMethodName + lookFor.Length();
1370  while (isspace((UChar_t)fLineRaw[posMethodEnd])) ++posMethodEnd;
1371  if (fLineRaw[posMethodEnd] == '(') {
1372  meth = LocateMethodInCurrentLine(posMethodName, ret, name, params, isconst,
1373  srcOut, anchor, sourceFile, allowPureVirtual);
1374  if (name.Length())
1375  return meth;
1376  }
1377  }
1378  }
1379  return 0;
1380  }
1381 
1382  name = fLineRaw(posMethodName, fLineRaw.Length() - posMethodName);
1383 
1384  // extract return type
1385  ret = fLineRaw(0, posMethodName);
1386  if (ret.Length()) {
1387  while (ret.Length() && (IsName(ret[ret.Length() - 1]) || ret[ret.Length()-1] == ':'))
1388  ret.Remove(ret.Length() - 1, 1);
1389  Strip(ret);
1390  Bool_t didSomething = kTRUE;
1391  while (didSomething) {
1392  didSomething = kFALSE;
1393  if (ret.BeginsWith("inline ")) {
1394  didSomething = kTRUE;
1395  ret.Remove(0, 7);
1396  }
1397  if (ret.BeginsWith("static ")) {
1398  didSomething = kTRUE;
1399  ret.Remove(0, 7);
1400  }
1401  if (ret.BeginsWith("virtual ")) {
1402  didSomething = kTRUE;
1403  ret.Remove(0, 8);
1404  }
1405  } // while replacing static, virtual, inline
1406  Strip(ret);
1407  }
1408 
1409  // extract parameters
1410  Ssiz_t posParam = name.First('(');
1411  if (posParam == kNPOS ||
1412  // no strange return types, please
1413  ret.Contains("{") || ret.Contains("}") || ret.Contains("(") || ret.Contains(")")
1414  || ret.Contains("=")) {
1415  ret.Remove(0);
1416  name.Remove(0);
1417  params.Remove(0);
1418  return 0;
1419  }
1420 
1421  if (name.BeginsWith("operator")) {
1422  // op () (...)
1423  Ssiz_t checkOpBracketParam = posParam + 1;
1424  while (isspace((UChar_t)name[checkOpBracketParam]))
1425  ++checkOpBracketParam;
1426  if (name[checkOpBracketParam] == ')') {
1427  ++checkOpBracketParam;
1428  while (isspace((UChar_t)name[checkOpBracketParam]))
1429  ++checkOpBracketParam;
1430  if (name[checkOpBracketParam] == '(')
1431  posParam = checkOpBracketParam;
1432  }
1433  } // check for op () (...)
1434 
1435  if (posParam == kNPOS) {
1436  ret.Remove(0);
1437  name.Remove(0);
1438  params.Remove(0);
1439  return 0;
1440  }
1441 
1442  params = name(posParam, name.Length() - posParam);
1443  name.Remove(posParam);
1444  while (name.Length() && isspace((UChar_t)name[name.Length() - 1]))
1445  name.Remove(name.Length() - 1);
1446  if (!name.Length()) {
1447  ret.Remove(0);
1448  name.Remove(0);
1449  params.Remove(0);
1450  return 0;
1451  }
1452 
1453  MethodCount_t::const_iterator iMethodName = fMethodCounts.find(name.Data());
1454  if (iMethodName == fMethodCounts.end() || iMethodName->second <= 0) {
1455  ret.Remove(0);
1456  name.Remove(0);
1457  params.Remove(0);
1458  return 0;
1459  }
1460 
1461  // find end of param
1462  Ssiz_t posParamEnd = 1;
1463  Int_t bracketLevel = 1;
1464  while (bracketLevel) {
1465  const char* paramEnd = strpbrk(params.Data() + posParamEnd, ")(\"'");
1466  if (!paramEnd) {
1467  // func with params over multiple lines
1468  // gotta write out this line before it gets lost
1469  if (!anchor.Length()) {
1470  // request an anchor, just in case...
1471  AnchorFromLine(fLineStripped, anchor);
1472  if (srcOut)
1473  srcOut << "<a name=\"" << anchor << "\"></a>";
1474  }
1475  ++fLineNumber;
1476  if (srcOut)
1477  WriteSourceLine(srcOut);
1478 
1479  fLineRaw.ReadLine(sourceFile, kFALSE);
1480  if (sourceFile.eof()) {
1481  Error("LocateMethodInCurrentLine",
1482  "Cannot find end of signature for function %s!",
1483  name.Data());
1484  break;
1485  }
1486 
1488 
1489  // replace class names etc
1492 
1495 
1496  posParamEnd = params.Length();
1497  params += fLineRaw;
1498  } else
1499  posParamEnd = paramEnd - params.Data();
1500  switch (params[posParamEnd]) {
1501  case '(': ++bracketLevel; ++posParamEnd; break;
1502  case ')': --bracketLevel; ++posParamEnd; break;
1503  case '"': // skip ")"
1504  ++posParamEnd;
1505  while (params.Length() > posParamEnd && params[posParamEnd] != '"') {
1506  // skip '\"'
1507  if (params[posParamEnd] == '\\') ++posParamEnd;
1508  ++posParamEnd;
1509  }
1510  if (params.Length() <= posParamEnd) {
1511  // something is seriously wrong - skip :-/
1512  ret.Remove(0);
1513  name.Remove(0);
1514  params.Remove(0);
1515  return 0;
1516  }
1517  ++posParamEnd; // skip trailing '"'
1518  break;
1519  case '\'': // skip ')'
1520  ++posParamEnd;
1521  if (params[posParamEnd] == '\\') ++posParamEnd;
1522  posParamEnd += 2;
1523  break;
1524  default:
1525  ++posParamEnd;
1526  }
1527  } // while bracketlevel, i.e. (...(..)...)
1528 
1529  {
1530  TString pastParams(params(posParamEnd, params.Length()));
1531  pastParams = pastParams.Strip(TString::kLeading);
1532  isconst = pastParams.BeginsWith("const") && !(isalnum(pastParams[5]) || pastParams[5] == '_');
1533  }
1534 
1535  Ssiz_t posBlock = params.Index('{', posParamEnd);
1536  Ssiz_t posSemicolon = params.Index(';', posParamEnd);
1537  Ssiz_t posPureVirt = params.Index('=', posParamEnd);
1538  if (posSemicolon != kNPOS)
1539  if ((posBlock == kNPOS || (posSemicolon < posBlock)) &&
1540  (posPureVirt == kNPOS || !allowPureVirtual)
1541  && !allowPureVirtual) // allow any "func();" if pv is allowed
1542  params.Remove(0);
1543 
1544  if (params.Length())
1545  params.Remove(posParamEnd);
1546 
1547  if (!params.Length()) {
1548  ret.Remove(0);
1549  name.Remove(0);
1550  return 0;
1551  }
1552  // update posMethodName to point behind the method
1553  posMethodName = posParam + posParamEnd;
1554  if (fCurrentClass) {
1555  TMethod* meth = fCurrentClass->GetMethodAny(name);
1556  if (meth) {
1557  fDirectiveCount = 0;
1558  fCurrentMethodTag = name + "_";
1560  return meth;
1561  }
1562  }
1563 
1564  return 0;
1565 }
1566 
1567 
1568 ////////////////////////////////////////////////////////////////////////////////
1569 /// Locate methods, starting in the source file, then inline, then
1570 /// immediately inside the class declaration. While doing that also
1571 /// find the class description and special tags like the macro tag etc.
1572 
1573 void TDocParser::Parse(std::ostream& out)
1574 {
1576 
1578 
1579  LocateMethodsInSource(out);
1582 
1583  if (!fSourceInfo[kInfoLastUpdate].Length()) {
1584  TDatime date;
1586  }
1587 }
1588 
1589 ////////////////////////////////////////////////////////////////////////////////
1590 /// Collect methods from the source or header file called filename.
1591 /// It generates a beautified version of the source file on the fly;
1592 /// the output file is given by the fCurrentClass's name, and sourceExt.
1593 /// Documentation is extracted to out.
1594 /// lookForSourceInfo: if set, author, lastUpdate, and copyright are
1595 /// extracted (i.e. the values contained in fSourceInfo)
1596 /// useDocxxStyle: if set, documentation can be in front of the method
1597 /// name, not only inside the method. Useful doc Doc++/Doxygen style,
1598 /// and inline methods.
1599 /// lookForClassDescr: if set, the first line matching the class description
1600 /// rules is assumed to be the class description for fCurrentClass; the
1601 /// description is written to out.
1602 /// methodPattern: if set, methods have to be prepended by this tag. Usually
1603 /// the class name + "::". In header files, looking for in-place function
1604 /// definitions, this should be 0. In that case, only functions in
1605 /// fMethodCounts are searched for.
1606 
1607 void TDocParser::LocateMethods(std::ostream& out, const char* filename,
1608  Bool_t lookForSourceInfo /*= kTRUE*/,
1609  Bool_t useDocxxStyle /*= kFALSE*/,
1610  Bool_t allowPureVirtual /*= kFALSE*/,
1611  const char* methodPattern /*= 0*/,
1612  const char* sourceExt /*= 0 */)
1613 {
1614  TString sourceFileName(filename);
1615  fCurrentFile = filename;
1616  if (!sourceFileName.Length()) {
1617  fHtml->GetImplFileName(fCurrentClass, kFALSE, sourceFileName);
1618  Error("LocateMethods", "Can't find source file '%s' for class %s!",
1619  sourceFileName.Data(), fCurrentClass->GetName());
1620  return;
1621  }
1622  std::ifstream sourceFile(sourceFileName.Data());
1623  if (!sourceFile || !sourceFile.good()) {
1624  Error("LocateMethods", "Can't open file '%s' for reading!", sourceFileName.Data());
1625  return;
1626  }
1627 
1628  TPMERegexp patternRE(methodPattern ? methodPattern : "");
1629 
1630  TString codeOneLiner;
1631  TString methodRet;
1632  TString methodName;
1633  TString methodParam;
1634  Bool_t methodIsConst = kFALSE;
1635  TString anchor;
1636  TString docxxComment;
1637 
1638  Bool_t wroteMethodNowWaitingForOpenBlock = kFALSE;
1639 
1640  std::ofstream srcHtmlOut;
1641  TString srcHtmlOutName;
1642  if (sourceExt && sourceExt[0]) {
1643  static_cast<TClassDocOutput*>(fDocOutput)->CreateSourceOutputStream(srcHtmlOut, sourceExt, srcHtmlOutName);
1644  fLineNumber = 0;
1645  } else {
1646  sourceExt = 0;
1647  srcHtmlOutName = fCurrentClass->GetName();
1648  fDocOutput->NameSpace2FileName(srcHtmlOutName);
1649  gSystem->PrependPathName("src", srcHtmlOutName);
1650  srcHtmlOutName += ".h.html";
1651  }
1652 
1653  fParseContext.clear();
1654  fParseContext.push_back(kCode);
1655  fDocContext = kIgnore;
1656  fLineNo = 0;
1657 
1658  while (!sourceFile.eof()) {
1659  Bool_t needAnchor = kFALSE;
1660 
1661  ++fLineNo; // we count fortrany
1662 
1663  fLineRaw.ReadLine(sourceFile, kFALSE);
1664  if (sourceFile.eof()) break;
1665 
1667 
1668  // replace class names etc
1671 
1673  fLineComment = "";
1675 
1676  if (!ProcessComment()) {
1677  // not a commented line
1678 
1680  TString strippedComment(fComment);
1681  Strip(strippedComment);
1682  if (strippedComment.Length() > 0) {
1687  }
1688  }
1689  fDocContext = kIgnore;
1690  }
1691 
1692  Ssiz_t impIdx = fLineStripped.Index("ClassImp(");
1693  if (impIdx == 0 && fClassDocState == kClassDoc_LookingHaveSomething) {
1695  // take unscoped version
1696  Ssiz_t posLastScope = kNPOS;
1697  while ((posLastScope = name.Index("::")) != kNPOS)
1698  name.Remove(0, posLastScope + 2);
1699 
1700  Ssiz_t posName = fLineStripped.Index(name, impIdx);
1701  if (posName != kNPOS) {
1702  Ssiz_t posClosingParen = posName + name.Length();
1703  while (isspace(fLineStripped[posClosingParen])) ++posClosingParen;
1704  if (fLineStripped[posClosingParen] == ')') {
1705  WriteClassDoc(out, kFALSE);
1706  fDocContext = kIgnore;
1707  }
1708  }
1709  }
1710 
1711  if (fLineStripped.Length())
1712  // remove last class doc if it not followed by ClassImp
1713  // (with optional empty lines in between)
1714  fLastClassDoc = "";
1715 
1716  // write previous method
1717  if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
1718  TString savedComment;
1719  if (useDocxxStyle && docxxComment.Length()) {
1720  savedComment = fComment;
1721  fComment = docxxComment;
1722  }
1723  WriteMethod(out, methodRet, methodName, methodParam, methodIsConst,
1724  gSystem->BaseName(srcHtmlOutName), anchor, codeOneLiner);
1725  docxxComment.Remove(0);
1726  if (savedComment[0]) {
1727  fComment = savedComment;
1728  }
1729  }
1730 
1731  if (!wroteMethodNowWaitingForOpenBlock) {
1732  // check for method
1733  Ssiz_t posPattern = kNPOS;
1734  if (methodPattern) {
1735  posPattern = fLineRaw.Index((TPRegexp&)patternRE);
1736  }
1737  if (posPattern != kNPOS && methodPattern) {
1738  // no strings, no blocks in front of function declarations / implementations
1739  static const char vetoChars[] = "{\"";
1740  for (int ich = 0; posPattern != kNPOS && vetoChars[ich]; ++ich) {
1741  Ssiz_t posVeto = fLineRaw.Index(vetoChars[ich]);
1742  if (posVeto != kNPOS && posVeto < posPattern)
1743  posPattern = kNPOS;
1744  }
1745  }
1746  if (posPattern != kNPOS || !methodPattern) {
1747  if (methodPattern) {
1748  patternRE.Match(fLineRaw);
1749  posPattern += patternRE[0].Length();
1750  }
1751  LocateMethodInCurrentLine(posPattern, methodRet, methodName,
1752  methodParam, methodIsConst, srcHtmlOut,
1753  anchor, sourceFile, allowPureVirtual);
1754  if (methodName.Length()) {
1756  needAnchor = !anchor.Length();
1757  if (useDocxxStyle)
1758  docxxComment = fComment;
1759  fComment.Remove(0);
1760  codeOneLiner.Remove(0);
1761 
1762  wroteMethodNowWaitingForOpenBlock = fLineRaw.Index("{", posPattern) == kNPOS;
1763  wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index(";", posPattern) == kNPOS;
1764  } else if (fLineRaw.First("{};") != kNPOS)
1765  // these chars reset the preceding comment
1766  fComment.Remove(0);
1767  } // pattern matches - could be a method
1768  else
1769  fComment.Remove(0);
1770  } else {
1771  wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index("{") == kNPOS;
1772  wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index(";") == kNPOS;
1773  } // if !wroteMethodNowWaitingForOpenBlock
1774 
1775  if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
1776  // make sure we don't have more '{' in commentLine than in fLineRaw
1777  if (!codeOneLiner.Length() &&
1778  fLineSource.CountChar('{') == 1 &&
1779  fLineSource.CountChar('}') == 1) {
1780  // a one-liner
1781  codeOneLiner = fLineSource;
1782  codeOneLiner.Remove(0, codeOneLiner.Index('{'));
1783  codeOneLiner.Remove(codeOneLiner.Index('}') + 1);
1784  }
1785  } // if method name and '{'
1786  // else not a comment, and we don't need the previous one:
1787  else if (!methodName.Length() && !useDocxxStyle)
1788  fComment.Remove(0);
1789 
1790  if (needAnchor || fExtraLinesWithAnchor.find(fLineNo) != fExtraLinesWithAnchor.end()) {
1791  AnchorFromLine(fLineStripped, anchor);
1792  if (sourceExt)
1793  srcHtmlOut << "<a name=\"" << anchor << "\"></a>";
1794  }
1795  // else anchor.Remove(0); - NO! WriteMethod will need it later!
1796  } // if !comment
1797 
1798  // check for last update,...
1799  Ssiz_t posTag = kNPOS;
1800  if (lookForSourceInfo)
1801  for (Int_t si = 0; si < (Int_t) kNumSourceInfos; ++si)
1802  if (!fSourceInfo[si].Length() && (posTag = fLineRaw.Index(fSourceInfoTags[si])) != kNPOS) {
1803  fSourceInfo[si] = fLineRaw(posTag + strlen(fSourceInfoTags[si]), fLineRaw.Length() - posTag);
1804  if (si == kInfoAuthor)
1806  }
1807 
1808 
1809  // write to .cxx.html
1810  ++fLineNumber;
1811  if (srcHtmlOut)
1812  WriteSourceLine(srcHtmlOut);
1813  else if (needAnchor)
1815  } // while !sourceFile.eof()
1816 
1817  // deal with last func
1818  if (methodName.Length()) {
1819  if (useDocxxStyle && docxxComment.Length())
1820  fComment = docxxComment;
1821  WriteMethod(out, methodRet, methodName, methodParam, methodIsConst,
1822  gSystem->BaseName(srcHtmlOutName), anchor, codeOneLiner);
1823  docxxComment.Remove(0);
1824  } else
1825  WriteClassDoc(out);
1826 
1827  srcHtmlOut << "</pre>" << std::endl;
1828 
1830 
1831  srcHtmlOut << "</div>" << std::endl;
1832 
1833  fDocOutput->WriteHtmlFooter(srcHtmlOut, "../");
1834 
1835  fParseContext.clear();
1836  fParseContext.push_back(kCode);
1837  fDocContext = kIgnore;
1838  fCurrentFile = "";
1839 }
1840 
1841 ////////////////////////////////////////////////////////////////////////////////
1842 /// Given fCurrentClass, look for methods in its source file,
1843 /// and extract documentation to out, while beautifying the source
1844 /// file in parallel.
1845 
1846 void TDocParser::LocateMethodsInSource(std::ostream& out)
1847 {
1848  // for Doc++ style
1849  Bool_t useDocxxStyle = (fHtml->GetDocStyle() == "Doc++");
1850 
1851  TString pattern(fCurrentClass->GetName());
1852  // take unscoped version
1853  Ssiz_t posLastScope = kNPOS;
1854  while ((posLastScope = pattern.Index("::")) != kNPOS)
1855  pattern.Remove(0, posLastScope + 2);
1856  pattern += "::";
1857 
1858  TString implFileName;
1859  if (fHtml->GetImplFileName(fCurrentClass, kTRUE, implFileName)) {
1860  LocateMethods(out, implFileName, kFALSE /*source info*/, useDocxxStyle,
1861  kFALSE /*allowPureVirtual*/, pattern, ".cxx.html");
1862  Ssiz_t posGt = pattern.Index('>');
1863  if (posGt != kNPOS) {
1864  // template! Re-run with pattern '...<.*>::'
1865  Ssiz_t posLt = pattern.Index('<');
1866  if (posLt != kNPOS && posLt < posGt) {
1867  pattern.Replace(posLt + 1, posGt - posLt - 1, ".*");
1868  LocateMethods(out, implFileName, kFALSE /*source info*/, useDocxxStyle,
1869  kFALSE /*allowPureVirtual*/, pattern, ".cxx.html");
1870  }
1871  }
1872  }
1873 }
1874 
1875 ////////////////////////////////////////////////////////////////////////////////
1876 /// Given fCurrentClass, look for methods in its header file,
1877 /// and extract documentation to out.
1878 
1880 {
1881  // for inline methods, always allow doc before func
1882  Bool_t useDocxxStyle = kTRUE;
1883 
1884  TString pattern(fCurrentClass->GetName());
1885  // take unscoped version
1886  Ssiz_t posLastScope = kNPOS;
1887  while ((posLastScope = pattern.Index("::")) != kNPOS)
1888  pattern.Remove(0, posLastScope + 1);
1889  pattern += "::";
1890 
1891  TString declFileName;
1892  if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, declFileName)) {
1893  LocateMethods(out, declFileName, kTRUE /*source info*/, useDocxxStyle,
1894  kFALSE /*allowPureVirtual*/, pattern, 0);
1895  Ssiz_t posGt = pattern.Index('>');
1896  if (posGt != kNPOS) {
1897  // template! Re-run with pattern '...<.*>::'
1898  Ssiz_t posLt = pattern.Index('<');
1899  if (posLt != kNPOS && posLt < posGt) {
1900  pattern.Replace(posLt + 1, posGt - posLt - 1, ".*");
1901  LocateMethods(out, declFileName, kTRUE /*source info*/, useDocxxStyle,
1902  kFALSE /*allowPureVirtual*/, pattern, 0);
1903  }
1904  }
1905  }
1906 }
1907 
1908 ////////////////////////////////////////////////////////////////////////////////
1909 /// Given fCurrentClass, look for methods in its header file's
1910 /// class declaration block, and extract documentation to out,
1911 /// while beautifying the header file in parallel.
1912 
1914 {
1915  TString declFileName;
1916  if (fHtml->GetDeclFileName(fCurrentClass, kTRUE, declFileName))
1917  LocateMethods(out, declFileName, kTRUE/*source info*/, kTRUE /*useDocxxStyle*/,
1918  kTRUE /*allowPureVirtual*/, 0, ".h.html");
1919 }
1920 
1921 ////////////////////////////////////////////////////////////////////////////////
1922 /// Parse the current line as a comment, handling directives and re-formatting
1923 /// the comment: remove "/*", "*/", "//", similar characters surrounding lines,
1924 /// etc.
1925 ///
1926 /// Return kFALSE if the line is not a comment.
1927 
1929 {
1930  if (!fCommentAtBOL
1931  && !(fLineStripped[0] == '/'
1932  && (fLineStripped[1] == '/' || fLineStripped[1] == '*'))
1933  && !InContext(kComment) && !InContext(kDirective)) {
1934  fLineComment = "";
1935  return kFALSE;
1936  }
1937 
1938  //if (InContext(kDirective))
1939  // return kTRUE; - NO! we might have a comment from a previous directive!
1940 
1941  // don't write out empty lines if the current directive is eating the line
1943  return kTRUE;
1944 
1945  TString commentLine(fLineComment.Strip());
1946 
1947  // remove all <span class="comment"> tags
1948  Bool_t mustDealWithCommentAtBOL = fCommentAtBOL; // whether we had a closing "*/"
1949  Ssiz_t posComment = kNPOS;
1950  if (!fCommentAtBOL)
1951  posComment = commentLine.Index("<span class=\"comment\">", 0, TString::kIgnoreCase);
1952  Ssiz_t posSpanEnd = commentLine.Index("</span>", posComment == kNPOS?0:posComment, TString::kIgnoreCase);
1953  while ((mustDealWithCommentAtBOL && posSpanEnd != kNPOS) || posComment != kNPOS) {
1954  Int_t spanLevel = 1;
1955  Ssiz_t posSpan = commentLine.Index("<span", posComment + 1, TString::kIgnoreCase);
1956  while (spanLevel > 1 || (posSpan != kNPOS && posSpan < posSpanEnd)) {
1957  // another span was opened, take the next </span>
1958  if (posSpan != kNPOS && posSpan < posSpanEnd) {
1959  ++spanLevel;
1960  posSpan = commentLine.Index("<span", posSpan + 1, TString::kIgnoreCase);
1961  // posSpanEnd doesn't change
1962  continue;
1963  } // else
1964  --spanLevel;
1965  // posSpan doesn't change
1966  posSpanEnd = commentLine.Index("</span>", posSpanEnd + 1, TString::kIgnoreCase);
1967  }
1968  if (posSpanEnd != kNPOS) {
1969  // only remove span if </span> if it exists (or we end up with unbalanced spans)
1970  commentLine.Remove(posSpanEnd, 7);
1971  if (posComment != kNPOS)
1972  commentLine.Remove(posComment, 22);
1973  else {
1974  mustDealWithCommentAtBOL = kFALSE;
1975  // now remove C comments
1976  posComment = 0;
1977  }
1978  posComment = commentLine.Index("<span class=\"comment\">", posComment, TString::kIgnoreCase);
1979  } else break;
1980  }
1981  if (posComment != kNPOS)
1982  commentLine.Remove(posComment, 22);
1983 
1984  // don't strip in C comments, do strip if opening:
1986  || (fLineStripped[0] == '/' && fLineStripped[1] == '*'))
1987  Strip(commentLine);
1988 
1989  // look for start tag of class description
1992  && !fComment.Length()
1993  && fDocContext == kIgnore && commentLine.Contains(fClassDescrTag)) {
1995  }
1996 
1997  char start_or_end = 0;
1998  // remove leading /*, //
1999  if (commentLine.Length()>1 && commentLine[0] == '/'
2000  && (commentLine[1] == '/' || commentLine[1] == '*')) {
2001  start_or_end = commentLine[1];
2002  commentLine.Remove(0, 2);
2003  }
2004  // remove trailing */
2005  if (start_or_end != '/' && commentLine.Length()>1
2006  && commentLine[commentLine.Length() - 2] == '*'
2007  && commentLine[commentLine.Length() - 1] == '/') {
2008  start_or_end = commentLine[commentLine.Length() - 2];
2009  commentLine.Remove(commentLine.Length()-2);
2010  }
2011 
2012  // remove repeating characters from the end of the line
2013  if (start_or_end && commentLine.Length() > 3) {
2014  TString lineAllOneChar(commentLine.Strip());
2015 
2016  Ssiz_t len = lineAllOneChar.Length();
2017  if (len > 2) {
2018  Char_t c = lineAllOneChar[len - 1];
2019  if (c == lineAllOneChar[len - 2] && c == lineAllOneChar[len - 3]) {
2020  TString lineAllOneCharStripped = lineAllOneChar.Strip(TString::kTrailing, c);
2021  Strip(lineAllOneCharStripped);
2022  if (!lineAllOneCharStripped.Length()) {
2023  commentLine.Remove(0);
2024 
2025  // also a class doc signature: line consists of ////
2028  && !fComment.Length()
2029  && fDocContext == kIgnore && start_or_end=='/') {
2031  }
2032  }
2033  }
2034  }
2035  }
2036 
2037  // remove leading and trailing chars from e.g. // some doc //
2038  if (commentLine.Length() > 0 && start_or_end == commentLine[commentLine.Length() - 1])
2039  // we already removed it as part of // or / *; also remove the trailing
2040  commentLine = commentLine.Strip(TString::kTrailing, start_or_end);
2041 
2042  if (commentLine.Length() > 2 && Context() != kDirective)
2043  while (commentLine.Length() > 2
2044  && !IsWord(commentLine[0])
2045  && commentLine[0] == commentLine[commentLine.Length() - 1])
2046  commentLine = commentLine.Strip(TString::kBoth, commentLine[0]);
2047 
2048  // remove leading '/' if we had // or '*' if we had / *
2049  while (start_or_end && commentLine[0] == start_or_end)
2050  commentLine.Remove(0, 1);
2051 
2052  fComment += commentLine + "\n";
2053 
2054  return kTRUE;
2055 }
2056 
2057 ////////////////////////////////////////////////////////////////////////////////
2058 /// remove the top-most comment context that matches cxxcomment,
2059 
2061 {
2062  UInt_t lookFor = kComment;
2063  if (cxxcomment) lookFor |= kCXXComment;
2064  std::list<UInt_t>::iterator iComment = fParseContext.end();
2065  for (std::list<UInt_t>::iterator iContext = fParseContext.begin();
2066  iContext != fParseContext.end(); ++ iContext)
2067  if (*iContext == lookFor) iComment =iContext;
2068  if (iComment != fParseContext.end())
2069  fParseContext.erase(iComment);
2070 }
2071 
2072 ////////////////////////////////////////////////////////////////////////////////
2073 /// strips ' ', tabs, and newlines from both sides of str
2074 
2076 {
2077  Bool_t changed = str[0] == ' ' || str[0] == '\t' || str[0] == '\n';
2078  changed |= str.Length()
2079  && (str[str.Length() - 1] == ' ' || str[str.Length() - 1] == '\t'
2080  || str[str.Length() - 1] == '\n');
2081  if (!changed) return kFALSE;
2082  Ssiz_t i = 0;
2083  while (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2084  ++i;
2085  str.Remove(0,i);
2086  i = str.Length() - 1;
2087  while (i >= 0 && (str[i] == ' ' || str[i] == '\t' || str[i] == '\n'))
2088  --i;
2089  str.Remove(i + 1, str.Length());
2090  return kTRUE;
2091 }
2092 
2093 ////////////////////////////////////////////////////////////////////////////////
2094 /// Write the class description depending (among others) on fClassDocState.
2095 
2096 void TDocParser::WriteClassDoc(std::ostream& out, Bool_t first /*= kTRUE*/)
2097 {
2099  TString& classDoc = first || !fLastClassDoc.Length() ? fFirstClassDoc : fLastClassDoc;
2100  static_cast<TClassDocOutput*>(fDocOutput)->WriteClassDescription(out, classDoc);
2102  }
2103 
2104 }
2105 
2106 namespace {
2107  static void RemoveUnneededSpaces(TString& s) {
2108  // Remove spaces except between identifier characters.
2109  // Assumes s is stripped (does not start nor end with space).
2110  for (Ssiz_t i = 1; i < s.Length() - 1; ++i) {
2111  if (s[i] == ' ') {
2112  char p = s[i - 1];
2113  char n = s[i + 1];
2114  if (((isalnum(p) || p == '_') && (isalnum(n) || n == '_'))
2115  || (p == '>' && n == '>')) {
2116  // "id id" or "> >": keep space
2117  } else {
2118  while (isspace(s[i])) {
2119  s.Remove(i, 1);
2120  }
2121  }
2122  }
2123  }
2124  }
2125 
2126  static void ParseParameters(TString& strippedParams, TList& paramArr) {
2127  // Extract a list of strings (the parameters without initializers) from
2128  // the signature.
2129  int nest = 0;
2130  bool init = false;
2131  bool quoted = false;
2132  Ssiz_t len = strippedParams.Length();
2133  TString arg;
2134  for (Ssiz_t i = 0; i < len; ++i) {
2135  switch (strippedParams[i]) {
2136  case '<': // fallthrough
2137  case '(': // fallthrough
2138  case '[': ++nest; break;
2139  case '>': // fallthrough
2140  case ')': // fallthrough
2141  case ']': --nest; break;
2142  case '=': init = true; break;
2143  case '\'': ++i; if (strippedParams[i] == '\\') ++i; ++i; continue;
2144  case '\\': ++i; continue; break;
2145  case '"': quoted = !quoted; break;
2146  case ',': {
2147  if (!quoted && !nest) {
2148  TString strippedArg(arg.Strip(TString::kBoth));
2149  paramArr.AddLast(new TObjString(strippedArg));
2150  init = false;
2151  arg.Remove(0);
2152  continue;
2153  }
2154  }
2155  }
2156  if (!init) {
2157  arg += strippedParams[i];
2158  }
2159  }
2160  TString strippedLastArg(arg.Strip(TString::kBoth));
2161  if (strippedLastArg.Length()) {
2162  paramArr.AddLast(new TObjString(strippedLastArg));
2163  }
2164  }
2165 
2166  void MatchOverloadSignatures(TCollection* candidates, TList* paramArr)
2167  {
2168  // Check type identity of candidate signatures. For each argument, check whether it
2169  // reduces the list of candidates to > 0 elements.
2170  TList suppressed;
2171  TIter iCandidate(candidates);
2172  int nparams = paramArr->GetSize();
2173  for (int iparam = 0; iparam < nparams && candidates->GetSize() > 1; ++iparam) {
2174  TString& srcArg = ((TObjString*)paramArr->At(iparam))->String();
2175  TString noParName(srcArg);
2176  while (noParName.Length()
2177  && (isalnum(noParName[noParName.Length() - 1]) || noParName[noParName.Length() - 1] == '_'))
2178  noParName.Remove(noParName.Length() - 1);
2179  noParName = noParName.Strip(TString::kTrailing);
2180 
2181  if (noParName.Length()) {
2182  RemoveUnneededSpaces(noParName);
2183  }
2184  RemoveUnneededSpaces(srcArg);
2185  // comparison:
2186  // 0: strcmp
2187  // 1: source's parameter has last identifier (parameter name?) removed
2188  // 2: candidate type name contained in source parameter
2189  for (int comparison = 0; comparison < 5; ++comparison) {
2190  if (comparison == 1 && noParName == srcArg)
2191  // there is no parameter name to ignore
2192  continue;
2193  suppressed.Clear();
2194  iCandidate.Reset();
2195  TDocMethodWrapper* method = 0;
2196  while ((method = (TDocMethodWrapper*) iCandidate())) {
2197  TMethodArg* methArg = (TMethodArg*) method->GetMethod()->GetListOfMethodArgs()->At(iparam);
2198  TString sMethArg = methArg->GetFullTypeName();
2199  RemoveUnneededSpaces(sMethArg);
2200  bool matches = false;
2201  switch (comparison) {
2202  case 0: matches = (srcArg == sMethArg); break;
2203  case 1: matches = (noParName == sMethArg); break;
2204  case 2: matches = srcArg.Contains(sMethArg) || sMethArg.Contains(srcArg); break;
2205  }
2206  if (!matches) {
2207  suppressed.Add(method);
2208  }
2209  }
2210  if (suppressed.GetSize()
2211  && suppressed.GetSize() < candidates->GetSize()) {
2212  candidates->RemoveAll(&suppressed);
2213  break;
2214  }
2215  if (!suppressed.GetSize()) {
2216  // we have a match, no point in trying a looser matching
2217  break;
2218  }
2219  }
2220  }
2221  if (candidates->GetSize() > 1) {
2222  // use TDocMethodWrapper::kDocumented bit
2223  suppressed.Clear();
2224  iCandidate.Reset();
2225  TDocMethodWrapper* method = 0;
2226  while ((method = (TDocMethodWrapper*) iCandidate())) {
2227  if (method->TestBit(TDocMethodWrapper::kDocumented)) {
2228  suppressed.AddLast(method);
2229  }
2230  }
2231  if (suppressed.GetSize()
2232  && suppressed.GetSize() < candidates->GetSize()) {
2233  candidates->RemoveAll(&suppressed);
2234  }
2235  }
2236  }
2237 }
2238 
2239 ////////////////////////////////////////////////////////////////////////////////
2240 /// Write a method, forwarding to TClassDocOutput
2241 
2242 void TDocParser::WriteMethod(std::ostream& out, TString& ret,
2243  TString& name, TString& params, Bool_t isconst,
2244  const char* filename, TString& anchor,
2245  TString& codeOneLiner)
2246 {
2247  // if we haven't found the class description until now it's too late.
2249  WriteClassDoc(out);
2250 
2251  TString strippedParams(params);
2252  if (strippedParams[0] == '(') {
2253  strippedParams.Remove(0, 1);
2254  strippedParams.Remove(strippedParams.Length() - 1);
2255  strippedParams = strippedParams.Strip(TString::kBoth);
2256  }
2257 
2258  TList paramArr;
2259  paramArr.SetOwner();
2260  ParseParameters(strippedParams, paramArr);
2261  int nparams = paramArr.GetSize();
2262 
2263  // Collect overload candidates
2264  TList candidates;
2265  for (int access = 0; access < 3; ++access) {
2266  const TList* methList = fMethods[access].GetListForObject(name);
2267  if (!methList) continue;
2268 
2269  TIter nextMethod(methList);
2270  TDocMethodWrapper* method = 0;
2271  while ((method = (TDocMethodWrapper *) nextMethod())) {
2272  if (name == method->GetName()
2273  && isconst == ((method->GetMethod()->Property() & kIsConstMethod) > 0)
2274  && method->GetMethod()->GetListOfMethodArgs()->GetSize() == nparams) {
2275  candidates.Add(method);
2276  }
2277  }
2278  }
2279 
2280  if (nparams && candidates.GetSize() > 1) {
2281  MatchOverloadSignatures(&candidates, &paramArr);
2282  }
2283 
2284  TDocMethodWrapper* guessedMethod = 0;
2285  if (candidates.GetSize() == 1) {
2286  guessedMethod = (TDocMethodWrapper*) candidates.First();
2287  guessedMethod->SetBit(TDocMethodWrapper::kDocumented);
2288  }
2289 
2290  static_cast<TClassDocOutput*>(fDocOutput)->WriteMethod(out, ret, name, params, filename, anchor,
2291  fComment, codeOneLiner, guessedMethod);
2292 
2293  DecrementMethodCount(name);
2294  ret.Remove(0);
2295  name.Remove(0);
2296  params.Remove(0);
2297  anchor.Remove(0);
2298  fComment.Remove(0);
2299 
2300  fDocContext = kIgnore;
2301 }
2302 
2303 ////////////////////////////////////////////////////////////////////////////////
2304 /// Write fLineSource to out.
2305 /// Adjust relative paths first.
2306 
2307 void TDocParser::WriteSourceLine(std::ostream& out)
2308 {
2310  out << fLineSource << std::endl;
2311 
2312 }
A zero length substring is legal.
Definition: TString.h:77
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:932
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
TDocParser(TClassDocOutput &docOutput, TClass *cl)
Constructor called for parsing class sources.
Definition: TDocParser.cxx:150
THtml * fHtml
Definition: TDocParser.h:86
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3507
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
void WriteLineNumbers(std::ostream &out, Long_t nLines, const TString &infileBase) const
Create a div containing the line numbers (for a source listing) 1 to nLines.
virtual bool GetImplFileName(TClass *cl, Bool_t filesys, TString &out_name) const
Return implementation file name.
Definition: THtml.cxx:2105
virtual ULong_t Hash() const
Return hash value for this object.
Definition: TObject.cxx:433
auto * m
Definition: textangle.C:8
TLine * line
Collectable string class.
Definition: TObjString.h:28
TMethod * LocateMethodInCurrentLine(Ssiz_t &posMethodName, TString &ret, TString &name, TString &params, Bool_t &isconst, std::ostream &srcOut, TString &anchor, std::ifstream &sourcefile, Bool_t allowPureVirtual)
Search for a method starting at posMethodName, and return its return type, its name, and its arguments.
const char * GetReturnTypeName() const
Get full type description of function return type, e,g.: "class TDirectory*".
Definition: TFunction.cxx:140
virtual void DeleteDirectiveOutput() const
Delete output generated by prior runs of all known directives; the output file names might have chang...
Definition: TDocParser.cxx:884
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
TClass * GetClassPointer(Bool_t load=kTRUE)
Get pointer to the base class TClass.
Definition: TBaseClass.cxx:63
std::istream & ReadLine(std::istream &str, Bool_t skipWhite=kTRUE)
Read a line from stream upto newline skipping any whitespace.
Definition: Stringio.cxx:65
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
void SetTag(const char *tag)
Definition: TDocDirective.h:58
UInt_t fLineNo
Definition: TDocParser.h:88
virtual Bool_t GetResult(TString &result)=0
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:689
TString fSourceInfoTags[kNumSourceInfos]
Definition: TDocParser.h:117
TString fComment
Definition: TDocParser.h:93
void AddClassDataMembersRecursively(TBaseClass *bc)
Add data members of fCurrentClass and of bc to datamembers, recursively.
Definition: TDocParser.cxx:306
const TString & GetLastUpdateTag() const
Definition: THtml.h:306
#define gROOT
Definition: TROOT.h:410
UInt_t InContext(Int_t context) const
checks whether we are in a parse context, return the entry closest to the current context...
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3617
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
Basic string class.
Definition: TString.h:131
void DecrementMethodCount(const char *name)
reduce method count for method called name, removing it from fMethodCounts once the count reaches 0...
Definition: TDocParser.cxx:869
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1100
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Ssiz_t Length() const
Definition: TString.h:114
Bool_t CopyHtmlFile(const char *sourceName, const char *destName="")
Copy file to HTML directory.
Definition: TDocOutput.cxx:593
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition: TMethodArg.h:31
void GetCurrentModule(TString &out_module) const
Return the name of module for which sources are currently parsed.
Definition: TDocParser.cxx:967
const TString & GetDocStyle() const
Definition: THtml.h:316
TString & Prepend(const char *cs)
Definition: TString.h:656
const char * GetFullTypeName() const
Get full type description of method argument, e.g.: "class TDirectory*".
Definition: TMethodArg.cxx:75
THashList fMethods[3]
Definition: TDocParser.h:122
void WriteClassDoc(std::ostream &out, Bool_t first=kTRUE)
Write the class description depending (among others) on fClassDocState.
virtual Int_t GetOverloadIdx() const =0
Long_t fLineNumber
Definition: TDocParser.h:101
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4205
virtual void DecorateEntityBegin(TString &str, Ssiz_t &pos, TDocParser::EParseContext type)
Add some colors etc to a source entity, contained in str.
void Reset()
Definition: TCollection.h:252
virtual void AddLast(TObject *obj)
Add object at the end of the list.
Definition: TList.cxx:149
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
const TString & GetClassDocTag() const
Definition: THtml.h:304
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:677
virtual void Sort(Bool_t order=kSortAscending)
Sort linked list.
Definition: TList.cxx:933
virtual void DecorateEntityEnd(TString &str, Ssiz_t &pos, TDocParser::EParseContext type)
Add some colors etc to a source entity, contained in str.
const char * String
Definition: TXMLSetup.cxx:93
void RemoveCommentContext(Bool_t cxxcomment)
remove the top-most comment context that matches cxxcomment,
TString fLastClassDoc
Definition: TDocParser.h:95
virtual Bool_t ProcessComment()
void Class()
Definition: Class.C:29
virtual void ExpandCPPLine(TString &line, Ssiz_t &pos)
Expand preprocessor statements.
Definition: TDocParser.cxx:911
void WriteSourceLine(std::ostream &out)
Write fLineSource to out.
void SetCounter(Int_t count)
Definition: TDocDirective.h:59
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
void Convert(std::ostream &out, std::istream &in, const char *relpath, Bool_t isCode, Bool_t interpretDirectives)
Parse text file "in", add links etc, and write output to "out".
Definition: TDocParser.cxx:402
virtual ~TDocParser()
destructor, checking whether all methods have been found for gDebug > 3
Definition: TDocParser.cxx:211
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition: TSystem.cxx:1062
static Bool_t Strip(TString &s)
strips &#39; &#39;, tabs, and newlines from both sides of str
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TFunction.cxx:183
virtual bool GetFileNameFromInclude(const char *included, TString &out_fsname) const
Set out_fsname to the full pathname corresponding to a file included as "included".
Definition: THtml.cxx:620
TList fDataMembers[6]
Definition: TDocParser.h:123
TDataType * GetDataType() const
Definition: TDataMember.h:74
Bool_t fCheckForMethod
Definition: TDocParser.h:106
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:487
void WriteHtmlFooter(std::ostream &out, const char *dir, const char *lastUpdate, const char *author, const char *copyright, const char *footer)
Write HTML footer.
TList fDirectiveHandlers
Definition: TDocParser.h:118
const TList * GetListForObject(const char *name) const
Return the THashTable&#39;s list (bucket) in which obj can be found based on its hash; see THashTable::Ge...
Definition: THashList.cxx:283
virtual void GetModuleNameForClass(TString &module, TClass *cl) const
Return the module name for a given class.
Definition: THtml.cxx:1530
TDocOutput * fDocOutput
Definition: TDocParser.h:87
void SetParser(TDocParser *parser)
Set the parser, and fDocOutput, fHtml from that.
TString fClassDescrTag
Definition: TDocParser.h:116
virtual void Parse(std::ostream &out)
Locate methods, starting in the source file, then inline, then immediately inside the class declarati...
static Bool_t IsWord(UChar_t c)
Check if c is a valid first character for C++ name.
A doubly linked list.
Definition: TList.h:44
virtual TClass * IsDirective(const TString &line, Ssiz_t pos, const TString &word, Bool_t &begin) const
return whether word at line&#39;s pos is a valid directive, and returns its TDocDirective&#39;s TClass object...
Bool_t fAllowDirectives
Definition: TDocParser.h:119
virtual void AdjustSourcePath(TString &line, const char *relpath="../")
adjust the path of links for source files, which are in src/, but need to point to relpath (usually "...
Definition: TDocOutput.cxx:297
Int_t GetType() const
Definition: TDataType.h:68
const TString & GetAuthorTag() const
Definition: THtml.h:305
TClass * fCurrentClass
Definition: TDocParser.h:96
virtual TList * GetListOfMethodArgs()
Returns methodarg list and additionally updates fDataMember in TMethod by calling FindDataMember();...
Definition: TMethod.cxx:305
void WriteMethod(std::ostream &out, TString &ret, TString &name, TString &params, Bool_t isconst, const char *file, TString &anchor, TString &codeOneLiner)
Write a method, forwarding to TClassDocOutput.
virtual void ReferenceEntity(TSubString &str, TClass *entity, const char *comment=0)
Create a reference to a class documentation page.
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:321
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:655
ROOT::R::TRInterface & r
Definition: Object.C:4
virtual Bool_t IsSortable() const
Definition: TObject.h:131
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
TString fCurrentMethodTag
Definition: TDocParser.h:99
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
virtual const char * ReplaceSpecialChars(char c)
Replace ampersand, less-than and greater-than character, writing to out.
static void AnchorFromLine(const TString &line, TString &anchor)
Create an anchor from the given line, by hashing it and convertig the hash into a custom base64 strin...
Definition: TDocParser.cxx:381
virtual void NameSpace2FileName(TString &name)
Replace "::" in name by "__" Replace "<", ">", " ", ",", "~", "=" in name by "_" Replace "A::X<A::Y>"...
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:818
virtual Bool_t HandleDirective(TString &keyword, Ssiz_t &pos, TString &word, Ssiz_t &copiedToCommentUpTo)
Process directives to the documentation engine, like "Begin_Html" / "End_Html", "Begin_Macro" / "End_...
Definition: TDocParser.cxx:977
Bool_t fCommentAtBOL
Definition: TDocParser.h:115
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:610
Collection abstract base class.
Definition: TCollection.h:63
const char * GetName() const
Returns name of object.
Definition: TDocDirective.h:49
static Bool_t IsName(UChar_t c)
Check if c is a valid C++ name character.
TClass * fRecentClass
Definition: TDocParser.h:97
unsigned int UInt_t
Definition: RtypesCore.h:42
TString fCurrentModule
Definition: TDocParser.h:98
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
Ssiz_t Length() const
Definition: TString.h:405
std::map< std::string, Int_t > fMethodCounts
Definition: TDocParser.h:103
Int_t fDirectiveCount
Definition: TDocParser.h:100
TVirtualMutex * GetMakeClassMutex() const
Definition: THtml.h:343
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1081
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
void LocateMethodsInHeaderInline(std::ostream &out)
Given fCurrentClass, look for methods in its header file, and extract documentation to out...
enum TDocParser::@86 fClassDocState
virtual Int_t Compare(const TObject *obj) const
Compare abstract method.
Definition: TObject.cxx:159
virtual TObject * At(Int_t idx) const
Returns the object at position idx. Returns 0 if idx is out of range.
Definition: TList.cxx:354
Global variables class (global variables are obtained from CINT).
Definition: TGlobal.h:27
virtual TMethod * GetMethod() const =0
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4688
virtual bool GetDeclFileName(TClass *cl, Bool_t filesys, TString &out_name) const
Return declaration file name; return the full path if filesys is true.
Definition: THtml.cxx:2097
Each class (see TClass) has a linked list of its base class(es).
Definition: TBaseClass.h:33
void LocateMethodsInHeaderClassDecl(std::ostream &out)
Given fCurrentClass, look for methods in its header file&#39;s class declaration block, and extract documentation to out, while beautifying the header file in parallel.
const Bool_t kFALSE
Definition: RtypesCore.h:88
void Rehash(Int_t newCapacity)
Rehash the hashlist.
Definition: THashList.cxx:368
virtual void FixupAuthorSourceInfo(TString &authors)
Special author treatment; called when TDocParser::fSourceInfo[kInfoAuthor] is set.
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
int Ssiz_t
Definition: RtypesCore.h:63
TString fSourceInfo[kNumSourceInfos]
Definition: TDocParser.h:121
void SetParameters(const char *params)
Given a string containing parameters in params, we call AddParameter() for each of them...
TString fLineRaw
Definition: TDocParser.h:89
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2172
std::set< UInt_t > fExtraLinesWithAnchor
Definition: TDocParser.h:120
TString fLineComment
Definition: TDocParser.h:91
virtual const char * GetTypeName() const
Get type of global variable, e,g.
Definition: TGlobal.cxx:111
#define ClassImp(name)
Definition: Rtypes.h:359
TString fCurrentFile
Definition: TDocParser.h:102
static Int_t init()
TText * text
virtual void DecorateKeywords(std::ostream &out, const char *text)
Expand keywords in text, writing to out.
Definition: TDocParser.cxx:450
TString fFirstClassDoc
Definition: TDocParser.h:94
unsigned long ULong_t
Definition: RtypesCore.h:51
static std::set< std::string > fgKeywords
Definition: TDocParser.h:125
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
static constexpr double s
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:101
#define R__LOCKGUARD(mutex)
EParseContext Context() const
Definition: TDocParser.h:129
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TBaseClass.cxx:134
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2887
virtual void Clear(Option_t *option="")
Remove all objects from the list.
Definition: TList.cxx:399
std::list< UInt_t > fParseContext
Definition: TDocParser.h:105
Int_t Match(const TString &s, UInt_t start=0)
Runs a match on s against the regex &#39;this&#39; was created with.
Definition: TPRegexp.cxx:708
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetEndTag() const =0
virtual TClass * GetClass(const char *name) const
Return pointer to class with name.
Definition: THtml.cxx:2066
char Char_t
Definition: RtypesCore.h:29
TString fLineStripped
Definition: TDocParser.h:90
const TString & GetCopyrightTag() const
Definition: THtml.h:307
virtual void Add(TObject *obj)
Definition: TList.h:87
auto * l
Definition: textangle.C:4
Wrapper for PCRE library (Perl Compatible Regular Expressions).
Definition: TPRegexp.h:97
EDocContext fDocContext
Definition: TDocParser.h:104
virtual void RemoveAll(TCollection *col)
Remove all objects in collection col from this collection.
TDocOutput * GetDocOutput() const
Definition: TDocParser.h:173
Each ROOT class (see TClass) has a linked list of methods.
Definition: TMethod.h:38
virtual void InitKeywords() const
fill C++ keywords into fgKeywords
TClass * GetClass() const
Definition: TMethod.h:55
void LocateMethods(std::ostream &out, const char *filename, Bool_t lookForSourceInfo=kTRUE, Bool_t useDocxxStyle=kFALSE, Bool_t allowPureVirtual=kFALSE, const char *methodPattern=0, const char *sourceExt=0)
Collect methods from the source or header file called filename.
Int_t CountChar(Int_t c) const
Return number of times character c occurs in the string.
Definition: TString.cxx:464
R__EXTERN Int_t gDebug
Definition: Rtypes.h:86
#define c(i)
Definition: RSha256.hxx:101
virtual TObjLink * LastLink() const
Definition: TList.h:111
void AddClassMethodsRecursively(TBaseClass *bc)
Add accessible (i.e.
Definition: TDocParser.cxx:235
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3280
unsigned char UChar_t
Definition: RtypesCore.h:34
TMethod * GetMethodAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4195
Definition: first.py:1
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
const TPathDefinition & GetPathDefinition() const
Return the TModuleDefinition (or derived) object as set by SetModuleDefinition(); create and return a...
Definition: THtml.cxx:1331
TList * GetListOfMethods(Bool_t load=kTRUE)
Return list containing the TMethods of a class.
Definition: TClass.cxx:3666
const Bool_t kTRUE
Definition: RtypesCore.h:87
const Int_t n
Definition: legend1.C:16
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
void LocateMethodsInSource(std::ostream &out)
Given fCurrentClass, look for methods in its source file, and extract documentation to out...
virtual void DeleteOutput() const
Definition: TDocDirective.h:73
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
virtual void AddLine(const TSubString &line)=0
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4792
const char * Data() const
Definition: TString.h:364
TString fLineSource
Definition: TDocParser.h:92