Logo ROOT  
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 "TGlobal.h"
23#include "THtml.h"
24#include "TInterpreter.h"
25#include "TMethod.h"
26#include "TMethodArg.h"
27#include "TPRegexp.h"
28#include "TROOT.h"
29#include "TSystem.h"
30#include "TObjString.h"
31#include "TVirtualMutex.h"
32#include <string>
33
34namespace {
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}
121End_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
132testmacro.C END_MACRO
133
134
135and 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
145std::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),
192 fCurrentClass(0), fRecentClass(0), fDirectiveCount(0),
193 fLineNumber(0), fDocContext(kIgnore),
194 fCheckForMethod(kFALSE), fClassDocState(kClassDoc_Uninitialized),
195 fCommentAtBOL(kFALSE), fAllowDirectives(kFALSE)
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) {
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
402void 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()) {
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
450void 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) {
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) {
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()) {
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
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()
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
967void TDocParser::GetCurrentModule(TString& out_module) const {
968 if (fCurrentModule) out_module = fCurrentModule;
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
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);
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())
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...
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) {
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
1573void TDocParser::Parse(std::ostream& out)
1574{
1576
1578
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
1607void 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);
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 }
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);
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()) {
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);
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
1847{
1848 // for Doc++ style
1849 Bool_t useDocxxStyle = (fHtml->GetDocStyle() == "Doc++");
1850
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
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] == '*'))
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
2096void TDocParser::WriteClassDoc(std::ostream& out, Bool_t first /*= kTRUE*/)
2097{
2100 static_cast<TClassDocOutput*>(fDocOutput)->WriteClassDescription(out, classDoc);
2102 }
2103
2104}
2105
2106namespace {
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())) {
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
2242void 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
2294 ret.Remove(0);
2295 name.Remove(0);
2296 params.Remove(0);
2297 anchor.Remove(0);
2298 fComment.Remove(0);
2299
2301}
2302
2303////////////////////////////////////////////////////////////////////////////////
2304/// Write fLineSource to out.
2305/// Adjust relative paths first.
2306
2307void TDocParser::WriteSourceLine(std::ostream& out)
2308{
2310 out << fLineSource << std::endl;
2311
2312}
int Int_t
Definition: CPyCppyy.h:43
unsigned int UInt_t
Definition: CPyCppyy.h:44
unsigned long ULong_t
Definition: CPyCppyy.h:51
void Class()
Definition: Class.C:29
ROOT::R::TRInterface & r
Definition: Object.C:4
#define c(i)
Definition: RSha256.hxx:101
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
unsigned char UChar_t
Definition: RtypesCore.h:38
int Ssiz_t
Definition: RtypesCore.h:67
char Char_t
Definition: RtypesCore.h:33
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:364
@ kInt_t
Definition: TDataType.h:30
@ kIsDestructor
Definition: TDictionary.h:129
@ kIsConstructor
Definition: TDictionary.h:127
@ kIsPublic
Definition: TDictionary.h:75
@ kIsConstant
Definition: TDictionary.h:88
@ kIsConstMethod
Definition: TDictionary.h:96
@ kIsEnum
Definition: TDictionary.h:68
@ kIsPrivate
Definition: TDictionary.h:77
@ kIsStatic
Definition: TDictionary.h:80
@ kIsProtected
Definition: TDictionary.h:76
Int_t gDebug
Definition: TROOT.cxx:589
#define gROOT
Definition: TROOT.h:404
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
#define R__LOCKGUARD(mutex)
Each class (see TClass) has a linked list of its base class(es).
Definition: TBaseClass.h:33
TClass * GetClassPointer(Bool_t load=kTRUE)
Get pointer to the base class TClass.
Definition: TBaseClass.cxx:63
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TBaseClass.cxx:134
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3392
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4971
TList * GetListOfMethods(Bool_t load=kTRUE)
Return list containing the TMethods of a class.
Definition: TClass.cxx:3805
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3763
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3629
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4377
TMethod * GetMethodAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4367
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4867
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:2955
Collection abstract base class.
Definition: TCollection.h:63
virtual void RemoveAll(TCollection *col)
Remove all objects in collection col from this collection.
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
TDataType * GetDataType() const
Definition: TDataMember.h:76
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
Int_t GetType() const
Definition: TDataType.h:68
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:102
virtual const char * GetEndTag() const =0
virtual Bool_t GetResult(TString &result)=0
void SetCounter(Int_t count)
Definition: TDocDirective.h:59
void SetTag(const char *tag)
Definition: TDocDirective.h:58
void SetParameters(const char *params)
Given a string containing parameters in params, we call AddParameter() for each of them.
const char * GetName() const
Returns name of object.
Definition: TDocDirective.h:49
virtual void DeleteOutput() const
Definition: TDocDirective.h:73
void SetParser(TDocParser *parser)
Set the parser, and fDocOutput, fHtml from that.
virtual void AddLine(const TSubString &line)=0
virtual Int_t GetOverloadIdx() const =0
virtual TMethod * GetMethod() const =0
virtual void DecorateEntityBegin(TString &str, Ssiz_t &pos, TDocParser::EParseContext type)
Add some colors etc to a source entity, contained in str.
virtual void NameSpace2FileName(TString &name)
Replace "::" in name by "__" Replace "<", ">", " ", ",", "~", "=" in name by "_" Replace "A::X<A::Y>"...
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 void ReferenceEntity(TSubString &str, TClass *entity, const char *comment=0)
Create a reference to a class documentation page.
Bool_t CopyHtmlFile(const char *sourceName, const char *destName="")
Copy file to HTML directory.
Definition: TDocOutput.cxx:592
void WriteHtmlFooter(std::ostream &out, const char *dir, const char *lastUpdate, const char *author, const char *copyright, const char *footer)
Write HTML footer.
virtual const char * ReplaceSpecialChars(char c)
Replace ampersand, less-than and greater-than character, writing to out.
virtual void DecorateEntityEnd(TString &str, Ssiz_t &pos, TDocParser::EParseContext type)
Add some colors etc to a source entity, contained in str.
virtual void FixupAuthorSourceInfo(TString &authors)
Special author treatment; called when TDocParser::fSourceInfo[kInfoAuthor] is set.
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:296
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
static Bool_t IsWord(UChar_t c)
Check if c is a valid first character for C++ name.
EParseContext Context() const
Definition: TDocParser.h:129
EDocContext fDocContext
Definition: TDocParser.h:104
void LocateMethodsInSource(std::ostream &out)
Given fCurrentClass, look for methods in its source file, and extract documentation to out,...
void WriteClassDoc(std::ostream &out, Bool_t first=kTRUE)
Write the class description depending (among others) on fClassDocState.
TString fCurrentFile
Definition: TDocParser.h:102
TString fCurrentModule
Definition: TDocParser.h:98
std::set< UInt_t > fExtraLinesWithAnchor
Definition: TDocParser.h:120
void LocateMethodsInHeaderClassDecl(std::ostream &out)
Given fCurrentClass, look for methods in its header file's class declaration block,...
virtual void ExpandCPPLine(TString &line, Ssiz_t &pos)
Expand preprocessor statements.
Definition: TDocParser.cxx:911
Long_t fLineNumber
Definition: TDocParser.h:101
THtml * fHtml
Definition: TDocParser.h:86
@ kParseContextMask
Definition: TDocParser.h:77
TString fComment
Definition: TDocParser.h:93
TClass * fRecentClass
Definition: TDocParser.h:97
void LocateMethodsInHeaderInline(std::ostream &out)
Given fCurrentClass, look for methods in its header file, and extract documentation to out.
virtual TClass * IsDirective(const TString &line, Ssiz_t pos, const TString &word, Bool_t &begin) const
return whether word at line's pos is a valid directive, and returns its TDocDirective's TClass object...
TList fDirectiveHandlers
Definition: TDocParser.h:118
static std::set< std::string > fgKeywords
Definition: TDocParser.h:125
static Bool_t Strip(TString &s)
strips ' ', tabs, and newlines from both sides of str
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.
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,...
TClass * fCurrentClass
Definition: TDocParser.h:96
void InitKeywords() const
fill C++ keywords into fgKeywords
void RemoveCommentContext(Bool_t cxxcomment)
remove the top-most comment context that matches cxxcomment,
Bool_t fCommentAtBOL
Definition: TDocParser.h:115
TString fSourceInfoTags[kNumSourceInfos]
Definition: TDocParser.h:117
TDocOutput * GetDocOutput() const
Definition: TDocParser.h:173
@ kParseContextFlagMask
Definition: TDocParser.h:81
TString fLineSource
Definition: TDocParser.h:92
TString fCurrentMethodTag
Definition: TDocParser.h:99
TString fSourceInfo[kNumSourceInfos]
Definition: TDocParser.h:121
TDocParser(TClassDocOutput &docOutput, TClass *cl)
Constructor called for parsing class sources.
Definition: TDocParser.cxx:150
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
virtual Bool_t ProcessComment()
Parse the current line as a comment, handling directives and re-formatting the comment: remove "/*",...
static Bool_t IsName(UChar_t c)
Check if c is a valid C++ name character.
UInt_t fLineNo
Definition: TDocParser.h:88
@ kClassDoc_Written
Definition: TDocParser.h:111
@ kClassDoc_LookingNothingFound
Definition: TDocParser.h:109
@ kClassDoc_LookingHaveSomething
Definition: TDocParser.h:110
@ kNumSourceInfos
Definition: TDocParser.h:60
@ kInfoLastUpdate
Definition: TDocParser.h:55
@ kInfoCopyright
Definition: TDocParser.h:57
virtual ~TDocParser()
destructor, checking whether all methods have been found for gDebug > 3
Definition: TDocParser.cxx:211
void GetCurrentModule(TString &out_module) const
Return the name of module for which sources are currently parsed.
Definition: TDocParser.cxx:967
enum TDocParser::@102 fClassDocState
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
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.
TString fFirstClassDoc
Definition: TDocParser.h:94
std::list< UInt_t > fParseContext
Definition: TDocParser.h:105
THashList fMethods[3]
Definition: TDocParser.h:122
UInt_t InContext(Int_t context) const
checks whether we are in a parse context, return the entry closest to the current context.
void AddClassMethodsRecursively(TBaseClass *bc)
Add accessible (i.e.
Definition: TDocParser.cxx:235
TDocOutput * fDocOutput
Definition: TDocParser.h:87
std::map< std::string, Int_t > fMethodCounts
Definition: TDocParser.h:103
TString fLastClassDoc
Definition: TDocParser.h:95
void WriteSourceLine(std::ostream &out)
Write fLineSource to out.
TString fLineStripped
Definition: TDocParser.h:90
void AddClassDataMembersRecursively(TBaseClass *bc)
Add data members of fCurrentClass and of bc to datamembers, recursively.
Definition: TDocParser.cxx:306
TString fLineRaw
Definition: TDocParser.h:89
TString fClassDescrTag
Definition: TDocParser.h:116
virtual void DecorateKeywords(std::ostream &out, const char *text)
Expand keywords in text, writing to out.
Definition: TDocParser.cxx:450
TString fLineComment
Definition: TDocParser.h:91
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
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
Int_t fDirectiveCount
Definition: TDocParser.h:100
virtual void Parse(std::ostream &out)
Locate methods, starting in the source file, then inline, then immediately inside the class declarati...
TList fDataMembers[6]
Definition: TDocParser.h:123
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Definition: TFunction.cxx:184
const char * GetReturnTypeName() const
Get full type description of function return type, e,g.: "class TDirectory*".
Definition: TFunction.cxx:141
Global variables class (global variables are obtained from CINT).
Definition: TGlobal.h:28
virtual const char * GetTypeName() const
Get type of global variable, e,g.
Definition: TGlobal.cxx:111
void Rehash(Int_t newCapacity)
Rehash the hashlist.
Definition: THashList.cxx:368
const TList * GetListForObject(const char *name) const
Return the THashTable's list (bucket) in which obj can be found based on its hash; see THashTable::Ge...
Definition: THashList.cxx:283
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:621
virtual TClass * GetClass(const char *name) const
Return pointer to class with name.
Definition: THtml.cxx:2076
const TString & GetCopyrightTag() const
Definition: THtml.h:307
TVirtualMutex * GetMakeClassMutex() const
Definition: THtml.h:343
const TString & GetLastUpdateTag() const
Definition: THtml.h:306
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:2105
const TString & GetClassDocTag() const
Definition: THtml.h:304
const TString & GetAuthorTag() const
Definition: THtml.h:305
virtual void GetModuleNameForClass(TString &module, TClass *cl) const
Return the module name for a given class.
Definition: THtml.cxx:1540
virtual bool GetImplFileName(TClass *cl, Bool_t filesys, TString &out_name) const
Return implementation file name.
Definition: THtml.cxx:2113
const TPathDefinition & GetPathDefinition() const
Return the TModuleDefinition (or derived) object as set by SetModuleDefinition(); create and return a...
Definition: THtml.cxx:1339
const TString & GetDocStyle() const
Definition: THtml.h:316
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:822
virtual TObjLink * LastLink() const
Definition: TList.h:111
virtual TObject * At(Int_t idx) const
Returns the object at position idx. Returns 0 if idx is out of range.
Definition: TList.cxx:357
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:693
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:659
virtual void AddLast(TObject *obj)
Add object at the end of the list.
Definition: TList.cxx:152
virtual void Clear(Option_t *option="")
Remove all objects from the list.
Definition: TList.cxx:402
virtual void Sort(Bool_t order=kSortAscending)
Sort linked list.
Definition: TList.cxx:937
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition: TMethodArg.h:36
const char * GetFullTypeName() const
Get full type description of method argument, e.g.: "class TDirectory*".
Definition: TMethodArg.cxx:74
Each ROOT class (see TClass) has a linked list of methods.
Definition: TMethod.h:38
TClass * GetClass() const
Definition: TMethod.h:55
virtual TList * GetListOfMethodArgs()
Returns methodarg list and additionally updates fDataMember in TMethod by calling FindDataMember();.
Definition: TMethod.cxx:307
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Collectable string class.
Definition: TObjString.h:28
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:359
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual Bool_t IsSortable() const
Definition: TObject.h:146
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:879
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:323
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
virtual Int_t Compare(const TObject *obj) const
Compare abstract method.
Definition: TObject.cxx:161
virtual ULong_t Hash() const
Return hash value for this object.
Definition: TObject.cxx:435
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:867
Wrapper for PCRE library (Perl Compatible Regular Expressions).
Definition: TPRegexp.h:97
Int_t Match(const TString &s, UInt_t start=0)
Runs a match on s against the regex 'this' was created with.
Definition: TPRegexp.cxx:706
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1150
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1131
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:523
@ kLeading
Definition: TString.h:267
@ kTrailing
Definition: TString.h:267
@ kBoth
Definition: TString.h:267
@ kIgnoreCase
Definition: TString.h:268
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:615
TString & Prepend(const char *cs)
Definition: TString.h:661
const char * Data() const
Definition: TString.h:369
Int_t CountChar(Int_t c) const
Return number of times character c occurs in the string.
Definition: TString.cxx:500
TString & Remove(Ssiz_t pos)
Definition: TString.h:673
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:639
std::istream & ReadLine(std::istream &str, Bool_t skipWhite=kTRUE)
Read a line from stream upto newline skipping any whitespace.
Definition: Stringio.cxx:65
A zero length substring is legal.
Definition: TString.h:82
Ssiz_t Length() const
Definition: TString.h:119
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition: TSystem.cxx:1081
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:935
TText * text
TLine * line
const Int_t n
Definition: legend1.C:16
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
static const std::string name("name")
static const std::string pattern("pattern")
TClass * GetClass(T *)
Definition: TClass.h:658
static constexpr double s
Definition: first.py:1
const char * String
Definition: TXMLSetup.cxx:94
auto * m
Definition: textangle.C:8
auto * l
Definition: textangle.C:4