1 /*****************************************************************************
3 * Copyright (C) 1997-2012 by Dimitri van Heesch.
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
42 #include "outputlist.h"
43 #include "membergroup.h"
46 #include "parserintf.h"
52 // forward declarations
53 static bool handleBrief(const QCString &);
54 static bool handleFn(const QCString &);
55 static bool handleDef(const QCString &);
56 static bool handleOverload(const QCString &);
57 static bool handleEnum(const QCString &);
58 static bool handleDefGroup(const QCString &);
59 static bool handleAddToGroup(const QCString &);
60 static bool handleWeakGroup(const QCString &);
61 static bool handleNamespace(const QCString &);
62 static bool handlePackage(const QCString &);
63 static bool handleClass(const QCString &);
64 static bool handleHeaderFile(const QCString &);
65 static bool handleProtocol(const QCString &);
66 static bool handleCategory(const QCString &);
67 static bool handleUnion(const QCString &);
68 static bool handleStruct(const QCString &);
69 static bool handleInterface(const QCString &);
70 static bool handleIdlException(const QCString &);
71 static bool handlePage(const QCString &);
72 static bool handleMainpage(const QCString &);
73 static bool handleFile(const QCString &);
74 static bool handleDir(const QCString &);
75 static bool handleExample(const QCString &);
76 static bool handleDetails(const QCString &);
77 static bool handleName(const QCString &);
78 static bool handleTodo(const QCString &);
79 static bool handleTest(const QCString &);
80 static bool handleBug(const QCString &);
81 static bool handleSubpage(const QCString &s);
82 static bool handleDeprecated(const QCString &);
83 static bool handleXRefItem(const QCString &);
84 static bool handleRelated(const QCString &);
85 static bool handleRelatedAlso(const QCString &);
86 static bool handleMemberOf(const QCString &);
87 static bool handleRefItem(const QCString &);
88 static bool handleSection(const QCString &);
89 static bool handleAnchor(const QCString &);
90 static bool handleCite(const QCString &);
91 static bool handleFormatBlock(const QCString &);
92 static bool handleAddIndex(const QCString &);
93 static bool handleIf(const QCString &);
94 static bool handleIfNot(const QCString &);
95 static bool handleElseIf(const QCString &);
96 static bool handleElse(const QCString &);
97 static bool handleEndIf(const QCString &);
98 static bool handleIngroup(const QCString &);
99 static bool handleNoSubGrouping(const QCString &);
100 static bool handleShowInitializer(const QCString &);
101 static bool handleHideInitializer(const QCString &);
102 static bool handleCallgraph(const QCString &);
103 static bool handleCallergraph(const QCString &);
104 static bool handleInternal(const QCString &);
105 static bool handleLineBr(const QCString &);
106 static bool handleStatic(const QCString &);
107 static bool handlePure(const QCString &);
108 static bool handlePrivate(const QCString &);
109 static bool handlePrivateSection(const QCString &);
110 static bool handleProtected(const QCString &);
111 static bool handleProtectedSection(const QCString &);
112 static bool handlePublic(const QCString &s);
113 static bool handlePublicSection(const QCString &s);
114 static bool handleToc(const QCString &s);
115 static bool handleInherit(const QCString &);
116 static bool handleExtends(const QCString &);
117 static bool handleCopyDoc(const QCString &);
119 typedef bool (*DocCmdFunc)(const QCString &name);
128 // map of command to handler function
129 static DocCmdMap docCmdMap[] =
131 // command name handler function ends brief description
132 { "brief", &handleBrief, FALSE },
133 { "short", &handleBrief, FALSE },
134 { "fn", &handleFn, FALSE },
135 { "var", &handleFn, FALSE },
136 { "typedef", &handleFn, FALSE },
137 { "property", &handleFn, FALSE },
138 { "def", &handleDef, FALSE },
139 { "overload", &handleOverload, FALSE },
140 { "enum", &handleEnum, FALSE },
141 { "defgroup", &handleDefGroup, FALSE },
142 { "addtogroup", &handleAddToGroup, FALSE },
143 { "weakgroup", &handleWeakGroup, FALSE },
144 { "namespace", &handleNamespace, FALSE },
145 { "package", &handlePackage, FALSE },
146 { "class", &handleClass, FALSE },
147 { "headerfile", &handleHeaderFile, FALSE },
148 { "protocol", &handleProtocol, FALSE },
149 { "category", &handleCategory, FALSE },
150 { "union", &handleUnion, FALSE },
151 { "struct", &handleStruct, FALSE },
152 { "interface", &handleInterface, FALSE },
153 { "idlexcept", &handleIdlException, FALSE },
154 { "page", &handlePage, FALSE },
155 { "mainpage", &handleMainpage, FALSE },
156 { "file", &handleFile, FALSE },
157 { "dir", &handleDir, FALSE },
158 { "example", &handleExample, FALSE },
159 { "details", &handleDetails, TRUE },
160 { "name", &handleName, FALSE },
161 { "todo", &handleTodo, FALSE }, // end brief will be done differently
162 { "test", &handleTest, FALSE }, // end brief will be done differently
163 { "bug", &handleBug, FALSE }, // end brief will be done differently
164 { "deprecated", &handleDeprecated, FALSE }, // end brief will be done differently
165 { "xrefitem", &handleXRefItem, FALSE }, // end brief will be done differently
166 { "related", &handleRelated, TRUE },
167 { "relates", &handleRelated, TRUE },
168 { "relatedalso", &handleRelatedAlso, TRUE },
169 { "relatesalso", &handleRelatedAlso, TRUE },
170 { "refitem", &handleRefItem, TRUE },
171 { "cite", &handleCite, TRUE },
172 { "subpage", &handleSubpage, TRUE },
173 { "section", &handleSection, TRUE },
174 { "subsection", &handleSection, TRUE },
175 { "subsubsection", &handleSection, TRUE },
176 { "paragraph", &handleSection, TRUE },
177 { "anchor", &handleAnchor, TRUE },
178 { "verbatim", &handleFormatBlock, TRUE },
179 { "latexonly", &handleFormatBlock, FALSE },
180 { "htmlonly", &handleFormatBlock, FALSE },
181 { "xmlonly", &handleFormatBlock, FALSE },
182 { "rtfonly", &handleFormatBlock, FALSE },
183 { "manonly", &handleFormatBlock, FALSE },
184 { "dot", &handleFormatBlock, TRUE },
185 { "msc", &handleFormatBlock, TRUE },
186 { "code", &handleFormatBlock, TRUE },
187 { "addindex", &handleAddIndex, FALSE },
188 { "if", &handleIf, FALSE },
189 { "ifnot", &handleIfNot, FALSE },
190 { "elseif", &handleElseIf, FALSE },
191 { "else", &handleElse, FALSE },
192 { "endif", &handleEndIf, FALSE },
193 { "ingroup", &handleIngroup, FALSE },
194 { "nosubgrouping", &handleNoSubGrouping, FALSE },
195 { "showinitializer", &handleShowInitializer, FALSE },
196 { "hideinitializer", &handleHideInitializer, FALSE },
197 { "callgraph", &handleCallgraph, FALSE },
198 { "callergraph", &handleCallergraph, FALSE },
199 { "internal", &handleInternal, TRUE },
200 { "_linebr", &handleLineBr, FALSE },
201 { "static", &handleStatic, FALSE },
202 { "pure", &handlePure, FALSE },
203 { "private", &handlePrivate, FALSE },
204 { "privatesection", &handlePrivateSection, FALSE },
205 { "protected", &handleProtected, FALSE },
206 { "protectedsection",&handleProtectedSection, FALSE },
207 { "public", &handlePublic, FALSE },
208 { "publicsection", &handlePublicSection, FALSE },
209 { "tableofcontents", &handleToc, FALSE },
210 { "inherit", &handleInherit, TRUE },
211 { "extends", &handleExtends, TRUE },
212 { "implements", &handleExtends, TRUE },
213 { "memberof", &handleMemberOf, TRUE },
215 { "attention", 0, TRUE },
216 { "author", 0, TRUE },
217 { "authors", 0, TRUE },
218 { "copydoc", &handleCopyDoc, TRUE },
219 { "copybrief", 0, FALSE },
220 { "copydetails", 0, TRUE },
222 { "dotfile", 0, TRUE },
223 { "htmlinclude", 0, FALSE },
224 { "image", 0, TRUE },
225 { "include", 0, TRUE },
226 { "includelineno", 0, TRUE },
227 { "invariant", 0, TRUE },
232 { "param", 0, TRUE },
233 { "tparam", 0, TRUE },
236 { "remark", 0, TRUE },
237 { "remarks", 0, TRUE },
238 { "result", 0, TRUE },
239 { "return", 0, TRUE },
240 { "returns", 0, TRUE },
241 { "retval", 0, TRUE },
244 { "since", 0, TRUE },
245 { "throw", 0, TRUE },
246 { "throws", 0, TRUE },
247 { "until", 0, TRUE },
248 { "verbinclude", 0, FALSE },
249 { "version", 0, TRUE },
250 { "warning", 0, TRUE },
254 /** @brief Command mapper.
256 * Maps a command name (as found in a comment block) onto a
257 * specific handler function.
268 /** maps a command name to a handler function */
269 static Cmd *map(const char *name)
271 return instance()->find(name);
274 /** release the singleton */
275 static void freeInstance()
277 delete s_instance; s_instance=0;
281 static DocCmdMapper *instance()
283 if (s_instance==0) s_instance = new DocCmdMapper;
287 DocCmdMapper() : m_map(113)
289 m_map.setAutoDelete(TRUE);
290 DocCmdMap *p = docCmdMap;
293 if (m_map.find(p->cmdName)!=0)
295 printf("Error: DocCmdMapper: command %s already added\n",p->cmdName);
299 cmd->func = p->handler;
300 cmd->endsBrief = p->endsBrief;
301 m_map.insert(p->cmdName,cmd);
306 Cmd *find(const char *name)
308 return m_map.find(name);
311 static DocCmdMapper *s_instance;
314 DocCmdMapper *DocCmdMapper::s_instance=0;
317 #define YY_NEVER_INTERACTIVE 1
347 GuardedSection(bool enabled,bool parentVisible)
348 : m_enabled(enabled),m_parentVisible(parentVisible) {}
349 bool isEnabled() const { return m_enabled; }
350 bool parentVisible() const { return m_parentVisible; }
354 bool m_parentVisible;
357 void openGroup(Entry *e,const char *file,int line);
358 void closeGroup(Entry *e,const char *file,int line,bool foundInline=FALSE);
359 void initGroupInfo(Entry *e);
360 static void groupAddDocs(Entry *e,const char *fileName);
362 /* -----------------------------------------------------------------
367 static ParserInterface *langParser; // the language parser that is calling us
368 static QCString inputString; // input string
369 static int inputPosition; // read pointer
370 static QCString yyFileName; // file name that is read from
371 static int yyLineNr; // line number in the input
372 static bool inBody; // was the comment found inside the body of a function?
373 static OutputContext inContext; // are we inside the brief, details or xref part
374 static bool briefEndsAtDot; // does the brief description stop at a dot?
375 static QCString formulaText; // Running text of a formula
376 static QCString formulaEnv; // environment name
377 static int formulaNewLines; // amount of new lines in the formula
378 static QCString *pOutputString; // pointer to string to which the output is appended.
379 static QCString outputXRef; // temp argument of todo/test/../xrefitem commands
380 static QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...)
381 static XRefKind xrefKind; // kind of cross-reference command
382 static XRefKind newXRefKind; //
383 static GuardType guardType; // kind of guard for conditional section
384 static bool enabledSectionFound;
385 static QCString functionProto; // function prototype
386 static QStack<GuardedSection> guards; // tracks nested conditional sections (if,ifnot,..)
387 static Entry* current = 0 ; // working entry
388 //static Entry* current_root = 0 ; // parent of working entry
391 //static Entry* previous = 0 ; // TODO: remove need for this
392 static bool needNewEntry;
394 static QCString g_sectionLabel;
395 static QCString g_sectionTitle;
396 static int g_sectionLevel;
397 static QCString xrefItemKey;
398 static QCString newXRefItemKey;
399 static QCString xrefItemTitle;
400 static QCString xrefListTitle;
401 static Protection protection;
403 static bool xrefAppendFlag;
404 static bool inGroupParamFound;
405 static int braceCount;
406 static bool insidePre;
407 static bool parseMore;
408 static int g_condCount;
410 static int g_commentCount;
411 static bool g_spaceBeforeCmd;
412 static bool g_spaceBeforeIf;
413 static QCString g_copyDocArg;
415 //-----------------------------------------------------------------------------
417 static QStack<Grouping> g_autoGroupStack;
418 static int g_memberGroupId = DOX_NOGROUP;
419 static QCString g_memberGroupHeader;
420 static QCString g_memberGroupDocs;
421 static QCString g_memberGroupRelates;
422 static QCString g_compoundName;
424 //-----------------------------------------------------------------------------
426 static void initParser()
428 g_sectionLabel.resize(0);
429 g_sectionTitle.resize(0);
430 g_memberGroupHeader.resize(0);
433 //-----------------------------------------------------------------------------
435 static bool getDocSectionName(int s)
439 case Entry::CLASSDOC_SEC:
440 case Entry::STRUCTDOC_SEC:
441 case Entry::UNIONDOC_SEC:
442 case Entry::EXCEPTIONDOC_SEC:
443 case Entry::NAMESPACEDOC_SEC:
444 case Entry::PROTOCOLDOC_SEC:
445 case Entry::CATEGORYDOC_SEC:
446 case Entry::ENUMDOC_SEC:
447 case Entry::PAGEDOC_SEC:
448 case Entry::VARIABLEDOC_SEC:
449 case Entry::MEMBERDOC_SEC:
450 case Entry::OVERLOADDOC_SEC:
451 case Entry::FILEDOC_SEC:
452 case Entry::DEFINEDOC_SEC:
453 case Entry::GROUPDOC_SEC:
454 case Entry::MAINPAGEDOC_SEC:
455 case Entry::PACKAGEDOC_SEC:
456 case Entry::DIRDOC_SEC:
457 case Entry::EXAMPLE_SEC:
458 case Entry::MEMBERGRP_SEC:
465 //-----------------------------------------------------------------------------
467 static bool makeStructuralIndicator(Entry::Sections s)
469 //printf("current->section=%x\n",current->section);
470 if (getDocSectionName(current->section))
477 current->section = s;
478 current->fileName = yyFileName;
479 current->startLine = yyLineNr;
484 static void lineCount()
486 for( const char* c = yytext ; *c ; ++c )
487 yyLineNr += (*c == '\n') ;
491 static QCString stripQuotes(const char *s)
494 if (s==0 || *s==0) return name;
496 if (name.at(0)=='"' && name.at(name.length()-1)=='"')
498 name=name.mid(1,name.length()-2);
503 //-----------------------------------------------------------------
505 static void addXRefItem(const char *listName,const char *itemTitle,
506 const char *listTitle,bool append)
508 Entry *docEntry = current; // inBody && previous ? previous : current;
509 if (listName==0) return;
510 //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append);
513 RefList *refList = Doxygen::xrefLists->find(listName);
514 if (refList==0) // new list
516 refList = new RefList(listName,listTitle,itemTitle);
517 Doxygen::xrefLists->insert(listName,refList);
518 //printf("new list!\n");
522 QListIterator<ListItemInfo> slii(*docEntry->sli);
523 for (slii.toFirst();(lii=slii.current());++slii)
525 if (strcmp(lii->type,listName)==0)
527 //printf("found %s lii->type=%s\n",listName,lii->type);
532 if (lii && append) // already found item of same type just before this one
534 //printf("listName=%s item id = %d existing\n",listName,lii->itemId);
535 RefItem *item = refList->getRefItem(lii->itemId);
537 item->text += " <p>";
538 if (Doxygen::markdownSupport)
540 item->text += processMarkdown(yyFileName,current,outputXRef);
544 item->text += outputXRef;
546 //printf("%s: text +=%s\n",listName,item->text.data());
550 int itemId = refList->addRefItem();
551 //printf("listName=%s item id = %d new current=%p\n",listName,itemId,current);
553 // if we have already an item from the same list type (e.g. a second @todo)
554 // in the same Entry (i.e. lii!=0) then we reuse its link anchor.
555 char anchorLabel[1024];
556 //sprintf(anchorLabel,"_%s%06d",listName,lii ? lii->itemId : itemId);
557 sprintf(anchorLabel,"_%s%06d",listName,itemId);
558 RefItem *item = refList->getRefItem(itemId);
560 if (Doxygen::markdownSupport)
562 item->text = processMarkdown(yyFileName,current,outputXRef);
566 item->text = outputXRef;
568 item->listAnchor = anchorLabel;
569 docEntry->addSpecialListItem(listName,itemId);
571 cmdString.sprintf("\\xrefitem %s %d.",listName,itemId);
574 docEntry->inbodyDocs += cmdString;
578 docEntry->doc += cmdString;
580 SectionInfo *si=new SectionInfo(listName,anchorLabel,
581 g_sectionTitle,SectionInfo::Anchor,
583 Doxygen::sectionDict.append(anchorLabel,si);
584 docEntry->anchors->append(si);
586 outputXRef.resize(0);
589 //-----------------------------------------------------------------------------
591 // Adds a formula text to the list/dictionary of formulas if it was
592 // not already added. Returns the label of the formula.
593 static QCString addFormula()
596 QCString fText=formulaText.simplifyWhiteSpace();
598 if ((f=Doxygen::formulaDict[fText])==0)
600 f = new Formula(fText);
601 Doxygen::formulaList.append(f);
602 Doxygen::formulaDict.insert(fText,f);
603 formLabel.sprintf("\\form#%d",f->getId());
604 Doxygen::formulaNameDict.insert(formLabel,f);
608 formLabel.sprintf("\\form#%d",f->getId());
611 for (i=0;i<formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to
613 // correctly aligned.
617 //-----------------------------------------------------------------------------
619 static void checkFormula();
620 //-----------------------------------------------------------------------------
622 static SectionInfo::SectionType sectionLevelToType(int level)
624 if (level>=0 && level<5) return (SectionInfo::SectionType)level;
625 return SectionInfo::Anchor;
628 static void addSection()
630 // create a new section element
631 g_sectionTitle+=yytext;
632 g_sectionTitle=g_sectionTitle.stripWhiteSpace();
633 SectionInfo *si = new SectionInfo(yyFileName,g_sectionLabel,
634 g_sectionTitle,sectionLevelToType(g_sectionLevel),g_sectionLevel);
636 // add section to this entry
637 current->anchors->append(si);
639 // add section to the global dictionary
640 Doxygen::sectionDict.append(g_sectionLabel,si);
644 //-----------------------------------------------------------------------------
646 static void addCite()
648 Doxygen::citeDict->insert(yytext);
651 //-----------------------------------------------------------------------------
653 // strip trailing whitespace (excluding newlines) from string s
654 static void stripTrailingWhiteSpace(QCString &s)
656 uint len = s.length();
659 while (i>=0 && ((c = s.at(i))==' ' || c=='\t' || c=='\r')) i--;
662 s.resize(i+2); // string upto and including char at pos i and \0 terminator
666 // selects the output to write to
667 static inline void setOutput(OutputContext ctx)
669 bool xrefAppendToPrev = xrefAppendFlag;
670 // determine append flag for the next item (i.e. the end of this item)
671 xrefAppendFlag = !inBody &&
672 inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items
673 newXRefKind==xrefKind && // of the same kind
674 (xrefKind!=XRef_Item ||
675 newXRefItemKey==xrefItemKey); // with the same key if \xrefitem
676 //printf("%d && %d && %d && (%d || %d)\n",
677 // inContext==OutputXRef,
679 // newXRefKind==xrefKind,
680 // xrefKind!=XRef_Item,
681 // newXRefItemKey==xrefItemKey);
683 //printf("refKind=%d newXRefKind=%d xrefAppendToPrev=%d xrefAppendFlag=%d\n",
684 // xrefKind,newXRefKind,xrefAppendToPrev,xrefAppendFlag);
686 //printf("setOutput(inContext=%d ctx=%d)\n",inContext,ctx);
687 if (inContext==OutputXRef) // end of XRef section => add the item
689 // See if we can append this new xref item to the previous one.
690 // We know this at the start of the next item of the same
691 // type and need to remember this until the end of that item.
696 theTranslator->trTodo(),
697 theTranslator->trTodoList(),
703 theTranslator->trTest(),
704 theTranslator->trTestList(),
710 theTranslator->trBug(),
711 theTranslator->trBugList(),
715 case XRef_Deprecated:
716 addXRefItem("deprecated",
717 theTranslator->trDeprecated(),
718 theTranslator->trDeprecatedList(),
722 case XRef_Item: // user defined list
723 addXRefItem(xrefItemKey,
734 xrefItemKey = newXRefItemKey;
736 int oldContext = inContext;
738 if (inContext!=OutputXRef && inBody) inContext=OutputInbody;
742 if (oldContext!=inContext)
744 stripTrailingWhiteSpace(current->doc);
745 if (current->docFile.isEmpty())
747 current->docFile = yyFileName;
748 current->docLine = yyLineNr;
751 pOutputString = ¤t->doc;
754 if (oldContext!=inContext)
756 if (current->briefFile.isEmpty())
758 current->briefFile = yyFileName;
759 current->briefLine = yyLineNr;
762 if (current->brief.stripWhiteSpace().isEmpty()) // we only want one brief
763 // description even if multiple
766 pOutputString = ¤t->brief;
770 pOutputString = ¤t->doc;
771 inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
775 pOutputString = &outputXRef;
776 // first item found, so can't append to previous
777 //xrefAppendFlag = FALSE;
780 pOutputString = ¤t->inbodyDocs;
785 // add a string to the output
786 static inline void addOutput(const char *s)
788 //printf("addOutput(%s)\n",s);
792 // add a character to the output
793 static inline void addOutput(char c)
798 static void endBrief(bool addToOutput=TRUE)
800 if (!current->brief.stripWhiteSpace().isEmpty())
801 { // only go to the detailed description if we have
802 // found some brief description and not just whitespace
803 briefEndsAtDot=FALSE;
804 setOutput(OutputDoc);
805 if (addToOutput) addOutput(yytext);
809 /* ----------------------------------------------------------------- */
811 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
813 static int prevPosition=0;
815 static int yyread(char *buf,int max_size)
817 prevPosition=inputPosition;
819 while( c < max_size && inputString[inputPosition] )
821 *buf = inputString[inputPosition++] ;
822 //printf("%d (%c)\n",*buf,*buf);
830 /* start command character */
832 DCMD1 ("arg"|"attention"|"author"|"cite"|"code")
833 DCMD2 ("date"|"dot"|"msc"|"dotfile"|"example")
834 DCMD3 ("htmlinclude"|"htmlonly"|"image"|"include")
835 DCMD4 ("includelineno"|"internal"|"invariant")
836 DCMD5 ("latexonly"|"li"|"line"|"manonly"|"name")
837 DCMD6 ("note"|"par"|"paragraph"|"param"|"post")
838 DCMD7 ("pre"|"remarks"|(("relate"[sd])("also")?))
839 DCMD8 ("remarks"|("return"[s]?)|"retval"|"sa"|"section")
840 DCMD9 ("see"|"since"|"subsection"|"subsubsection")
841 DCMD10 ("throw"|"until"|"verbatim")
842 DCMD11 ("verbinclude"|"version"|"warning")
843 DETAILEDCMD {CMD}({DCMD1}|{DCMD2}|{DCMD3}|{DCMD4}|{DCMD5}|{DCMD6}|{DCMD7}|{DCMD8}|{DCMD9}|{DCMD10}|{DCMD11})
844 XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem")
846 TABLE [tT][aA][bB][lL][eE]
853 PARA [pP][aA][rR][aA]
854 CODE [cC][oO][dD][eE]
855 DETAILEDHTML {PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA}
856 DETAILEDHTMLOPT {CODE}
860 BS ^(({B}*"//")?)(({B}*"*"+)?){B}*
862 DOCNL "\n"|"\\_linebr"
865 FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+]
866 FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+]
867 FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"")
868 ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
869 LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
870 CITEID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-:/]*
871 SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
872 SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID})
873 MAILADR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
874 RCSTAG "$"{ID}":"[^\n$]+"$"
878 /* comment parsing states. */
904 %x SkipGuardedSection
922 /* What can happen in while parsing a comment block:
923 * commands (e.g. @page, or \page)
924 * escaped commands (e.g. @@page or \\page).
925 * formulas (e.g. \f$ \f[ \f{..)
926 * directories (e.g. \doxygen\src\)
927 * autolist end. (e.g. a dot on an otherwise empty line)
929 * end of brief description due to blank line.
930 * end of brief description due to some command (@command, or <command>).
931 * words and whitespace and other characters (#,?!, etc).
932 * grouping commands (e.g. @{ and @})
933 * language switch (e.g. \~english or \~).
934 * mail adress (e.g. dimitri@stack.nl).
935 * quoted text, such as "foo@bar"
936 * XML commands, <summary></summary><remarks></remarks>
939 <Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command
942 <Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command
945 <Comment>{MAILADR} { // mail adress
948 <Comment>"\""[^"\n]*"\"" { // quoted text
951 <Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!)
954 <Comment>{XREFCMD}/[^a-z_A-Z]* { // xref command
955 if (inContext!=OutputXRef)
957 briefEndsAtDot=FALSE;
958 setOutput(OutputDoc);
960 // continue with the same input
964 <Comment>{DETAILEDCMD}/[^a-z_A-Z]* { // command that can end a brief description
965 briefEndsAtDot=FALSE;
966 setOutput(OutputDoc);
967 // continue with the same input
971 <Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description
972 setOutput(OutputDoc);
973 // continue with the same input
976 <Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description
977 if (current->lang==SrcLangExt_CSharp)
979 setOutput(OutputDoc);
981 // continue with the same input
984 <Comment>"<summary>" { // start of a .NET XML style brief description
985 setOutput(OutputBrief);
988 <Comment>"<remarks>" { // start of a .NET XML style detailed description
989 setOutput(OutputDoc);
992 <Comment>"</summary>" { // start of a .NET XML style detailed description
994 setOutput(OutputDoc);
996 <Comment>"</remarks>" { // end of a brief or detailed description
999 <Comment>"<"{PRE}{ATTR}">" {
1003 <Comment>"</"{PRE}">" {
1007 <Comment>{RCSTAG} { // RCS tag which end a brief description
1008 setOutput(OutputDoc);
1014 <Comment>{B}*{CMD}"endinternal"{B}* {
1015 warn(yyFileName,yyLineNr,
1016 "warning: found \\endinternal without matching \\internal"
1019 <Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command
1020 // the {B}* in the front was added for bug620924
1021 QCString cmdName = QCString(yytext).stripWhiteSpace().data()+1;
1022 DocCmdMapper::Cmd *cmdPtr = DocCmdMapper::map(cmdName);
1023 g_spaceBeforeCmd = yytext[0]==' ' || yytext[0]=='\t';
1024 if (cmdPtr) // special action is required
1026 if (cmdPtr->endsBrief)
1028 briefEndsAtDot=FALSE;
1029 // this command forces the end of brief description
1030 setOutput(OutputDoc);
1033 while (yytext[i]==' ' || yytext[i]=='\t') i++;
1034 if (i>0) addOutput(QCString(yytext).left(i));
1035 if (cmdPtr->func && cmdPtr->func(cmdName))
1037 // implicit split of the comment block into two
1038 // entries. Restart the next block at the start
1042 // yuk, this is probably not very portable across lex implementations,
1043 // but we need to know the position in the input buffer where this
1045 // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE
1046 #if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33
1047 inputPosition=prevPosition + yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
1049 inputPosition=prevPosition + yy_bp - yy_current_buffer->yy_ch_buf;
1053 else if (cmdPtr->func==0)
1055 // command without handler, to be processed
1056 // later by parsedoc.cpp
1057 addOutput(yytext+i);
1060 else // command not relevant
1065 <Comment>{B}*("\\\\"|"@@")"f"[$\[{] { // escaped formula command
1068 <Comment>{B}*{CMD}"~"[a-z_A-Z]* { // language switch command
1069 QCString langId = QString(yytext).stripWhiteSpace().data()+2;
1070 if (!langId.isEmpty() &&
1071 stricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)!=0)
1072 { // enable language specific section
1076 <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment
1077 formulaText="\\begin";
1078 formulaEnv=QString(yytext).stripWhiteSpace().data()+2;
1079 if (formulaEnv.at(formulaEnv.length()-1)=='{')
1081 // remove trailing open brace
1082 formulaEnv=formulaEnv.left(formulaEnv.length()-1);
1084 formulaText+=formulaEnv;
1086 BEGIN(ReadFormulaLong);
1088 <Comment>{B}*{CMD}"f$" { // start of a inline formula
1091 BEGIN(ReadFormulaShort);
1093 <Comment>{B}*{CMD}"f[" { // start of a block formula
1096 BEGIN(ReadFormulaLong);
1098 <Comment>{B}*{CMD}"{" { // begin of a group
1099 //langParser->handleGroupStartCommand(g_memberGroupHeader);
1100 openGroup(current,yyFileName,yyLineNr);
1102 <Comment>{B}*{CMD}"}" { // end of a group
1103 //langParser->handleGroupEndCommand();
1104 closeGroup(current,yyFileName,yyLineNr,TRUE);
1105 g_memberGroupHeader.resize(0);
1107 needNewEntry = TRUE;
1108 #if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33
1109 inputPosition=prevPosition + yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + strlen(yytext);
1111 inputPosition=prevPosition + yy_bp - yy_current_buffer->yy_ch_buf + strlen(yytext);
1115 <Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character
1118 <Comment>[a-z_A-Z]+ { // normal word
1121 <Comment>^{B}*"."{B}*/\n { // explicit end autolist: e.g " ."
1124 <Comment>^{B}*[1-9][0-9]*"."{B}+ |
1125 <Comment>^{B}*[*+]{B}+ { // start of autolist
1126 if (!Doxygen::markdownSupport)
1132 if (inContext!=OutputXRef)
1134 briefEndsAtDot=FALSE;
1135 setOutput(OutputDoc);
1140 <Comment>^{B}*"-"{B}+ { // start of autolist
1141 if (inContext!=OutputXRef)
1143 briefEndsAtDot=FALSE;
1144 setOutput(OutputDoc);
1148 <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{B}*/\n { // horizontal line (dashed)
1151 <Comment>"---" { // mdash
1152 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "—");
1154 <Comment>"--" { // ndash
1155 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "–");
1157 <Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis
1160 <Comment>".\\"[ \t] { // . with escaped space.
1161 addOutput(yytext[0]);
1162 addOutput(yytext[2]);
1164 <Comment>".," { // . with comma such as "e.g.,"
1167 <Comment>"...\\"[ \t] { // ellipsis with escaped space.
1170 <Comment>".."[\.]?/[^ \t\n] { // internal ellipsis
1173 <Comment>(\n|\\_linebr)({B}*(\n|\\_linebr))+ { // at least one blank line (or blank line command)
1174 if (inContext==OutputXRef)
1176 // see bug 613024, we need to put the newlines after ending the XRef section.
1177 setOutput(OutputDoc);
1180 else if (inContext!=OutputBrief)
1183 setOutput(OutputDoc);
1185 else // inContext==OutputBrief
1186 { // only go to the detailed description if we have
1187 // found some brief description and not just whitespace
1192 <Comment>"." { // potential end of a JavaDoc style comment
1196 setOutput(OutputDoc);
1197 briefEndsAtDot=FALSE;
1200 <Comment>\n { // newline
1204 <Comment>. { // catch-all for anything else
1209 /* -------------- Rules for handling HTML comments ----------- */
1211 <HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); }
1212 <HtmlComment>{DOCNL} {
1213 if (*yytext=='\n') yyLineNr++;
1215 <HtmlComment>[^\\\n\-]+ { // ignore unimportant characters
1217 <HtmlComment>. { // ignore every else
1220 /* -------------- Rules for handling formulas ---------------- */
1222 <ReadFormulaShort>{CMD}"f$" { // end of inline formula
1224 addOutput(" "+addFormula());
1227 <ReadFormulaLong>{CMD}"f]" { // end of block formula
1229 addOutput(" "+addFormula());
1232 <ReadFormulaLong>{CMD}"f}" { // end of custom env formula
1233 formulaText+="\\end";
1234 formulaText+=formulaEnv;
1235 addOutput(" "+addFormula());
1238 <ReadFormulaLong,ReadFormulaShort>[^\\@\n]+ { // any non-special character
1239 formulaText+=yytext;
1241 <ReadFormulaLong,ReadFormulaShort>\n { // new line
1243 formulaText+=*yytext;
1246 <ReadFormulaLong,ReadFormulaShort>. { // any othe character
1247 formulaText+=*yytext;
1250 /* ------------ handle argument of enum command --------------- */
1252 <EnumDocArg1>{SCOPEID} { // handle argument
1253 current->name = yytext;
1256 <EnumDocArg1>{LC} { // line continuation
1260 <EnumDocArg1>{DOCNL} { // missing argument
1261 warn(yyFileName,yyLineNr,
1262 "warning: missing argument after \\enum."
1265 if (*yytext=='\n') yyLineNr++;
1268 <EnumDocArg1>. { // ignore other stuff
1271 /* ------------ handle argument of namespace command --------------- */
1273 <NameSpaceDocArg1>{SCOPENAME} { // handle argument
1274 current->name = substitute(yytext,".","::");
1277 <NameSpaceDocArg1>{LC} { // line continuation
1281 <NameSpaceDocArg1>{DOCNL} { // missing argument
1282 warn(yyFileName,yyLineNr,
1283 "warning: missing argument after "
1287 if (*yytext=='\n') yyLineNr++;
1290 <NameSpaceDocArg1>. { // ignore other stuff
1293 /* ------------ handle argument of package command --------------- */
1295 <PackageDocArg1>{ID}("."{ID})* { // handle argument
1296 current->name = yytext;
1299 <PackageDocArg1>{LC} { // line continuation
1303 <PackageDocArg1>{DOCNL} { // missing argument
1304 warn(yyFileName,yyLineNr,
1305 "warning: missing argument after "
1309 if (*yytext=='\n') yyLineNr++;
1312 <PackageDocArg1>. { // ignore other stuff
1315 /* ------ handle argument of class/struct/union command --------------- */
1317 <ClassDocArg1>{SCOPENAME} { // first argument
1318 current->name = substitute(yytext,".","::");
1319 if (current->section==Entry::PROTOCOLDOC_SEC)
1321 current->name+="-p";
1323 // prepend outer scope name
1324 BEGIN( ClassDocArg2 );
1326 <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" {
1327 current->name = substitute(yytext,".","::");
1328 BEGIN( ClassDocArg2 );
1330 <ClassDocArg1,CategoryDocArg1>{LC} { // line continuation
1334 <ClassDocArg1,CategoryDocArg1>{DOCNL} {
1335 warn(yyFileName,yyLineNr,
1336 "warning: missing argument after "
1337 "\\%s.",YY_START==ClassDocArg1?"class":"category"
1340 if (*yytext=='\n') yyLineNr++;
1343 <ClassDocArg1,CategoryDocArg1>. { // ignore other stuff
1346 <ClassDocArg2>{FILE}|"<>" { // second argument; include file
1347 current->includeFile = yytext;
1348 BEGIN( ClassDocArg3 );
1350 <ClassDocArg2>{LC} { // line continuation
1354 <ClassDocArg2>{DOCNL} {
1356 if (*yytext=='\n') yyLineNr++;
1359 <ClassDocArg2>. { // ignore other stuff
1362 <ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name
1363 current->includeName = yytext;
1366 <ClassDocArg3>{LC} { // line continuation
1370 <ClassDocArg3>{DOCNL} {
1371 if (*yytext=='\n') yyLineNr++;
1374 <ClassDocArg3>. { // ignore other stuff
1377 /* --------- handle arguments of {def,add,weak}group commands --------- */
1379 <GroupDocArg1>{LABELID}(".html"?) { // group name
1380 current->name = yytext;
1381 //lastDefGroup.groupname = yytext;
1382 //lastDefGroup.pri = current->groupingPri();
1383 // the .html stuff is for Qt compatibility
1384 if (current->name.right(5)==".html")
1386 current->name=current->name.left(current->name.length()-5);
1388 current->type.resize(0);
1389 BEGIN(GroupDocArg2);
1391 <GroupDocArg1>"\\"{B}*"\n" { // line continuation
1395 <GroupDocArg1>{DOCNL} { // missing argument!
1396 warn(yyFileName,yyLineNr,
1397 "warning: missing group name after %s",
1398 current->groupDocCmd()
1401 if (*yytext=='\n') yyLineNr++;
1404 <GroupDocArg2>"\\"{B}*"\n" { // line continuation
1408 <GroupDocArg2>[^\n\\\*]+ { // title (stored in type)
1409 current->type += yytext;
1410 current->type = current->type.stripWhiteSpace();
1412 <GroupDocArg2>{DOCNL} {
1413 if ( current->groupDocType==Entry::GROUPDOC_NORMAL &&
1414 current->type.isEmpty()
1415 ) // defgroup requires second argument
1417 warn(yyFileName,yyLineNr,
1418 "warning: missing title after "
1419 "\\defgroup %s", current->name.data()
1422 if (*yytext=='\n') yyLineNr++;
1427 /* --------- handle arguments of page/mainpage command ------------------- */
1429 <PageDocArg1>{FILE} { // first argument; page name
1430 current->name = stripQuotes(yytext);
1431 BEGIN( PageDocArg2 );
1433 <PageDocArg1>{LC} { yyLineNr++;
1436 <PageDocArg1>{DOCNL} {
1437 warn(yyFileName,yyLineNr,
1438 "warning: missing argument after "
1441 if (*yytext=='\n') yyLineNr++;
1445 <PageDocArg1>. { // ignore other stuff
1447 <PageDocArg2>.*"\n" { // second argument; page title
1449 current->args = yytext;
1454 /* --------- handle arguments of the file/dir/example command ------------ */
1456 <FileDocArg1>{DOCNL} { // no file name specfied
1457 if (*yytext=='\n') yyLineNr++;
1461 <FileDocArg1>{FILE} { // first argument; name
1462 current->name = stripQuotes(yytext);
1465 <FileDocArg1>{LC} { yyLineNr++;
1468 <FileDocArg1>. { // ignore other stuff
1471 /* --------- handle arguments of the xrefitem command ------------ */
1473 <XRefItemParam1>{LABELID} { // first argument
1474 newXRefItemKey=yytext;
1475 setOutput(OutputXRef);
1476 BEGIN(XRefItemParam2);
1478 <XRefItemParam1>{LC} { // line continuation
1482 <XRefItemParam1>{DOCNL} { // missing arguments
1483 warn(yyFileName,yyLineNr,
1484 "warning: Missing first argument of \\xrefitem"
1486 if (*yytext=='\n') yyLineNr++;
1488 inContext = OutputDoc;
1491 <XRefItemParam1>. { // ignore other stuff
1494 <XRefItemParam2>"\""[^\n\"]*"\"" { // second argument
1495 xrefItemTitle = stripQuotes(yytext);
1496 BEGIN(XRefItemParam3);
1498 <XRefItemParam2>{LC} { // line continuation
1502 <XRefItemParam2>{DOCNL} { // missing argument
1503 warn(yyFileName,yyLineNr,
1504 "warning: Missing second argument of \\xrefitem"
1506 if (*yytext=='\n') yyLineNr++;
1508 inContext = OutputDoc;
1511 <XRefItemParam2>. { // ignore other stuff
1514 <XRefItemParam3>"\""[^\n\"]*"\"" { // third argument
1515 xrefListTitle = stripQuotes(yytext);
1516 xrefKind = XRef_Item;
1519 <XRefItemParam2,XRefItemParam3>{LC} { // line continuation
1523 <XRefItemParam3>{DOCNL} { // missing argument
1524 warn(yyFileName,yyLineNr,
1525 "warning: Missing third argument of \\xrefitem"
1527 if (*yytext=='\n') yyLineNr++;
1529 inContext = OutputDoc;
1532 <XRefItemParam3>. { // ignore other stuff
1536 /* ----- handle arguments of the relates(also)/memberof command ------- */
1538 <RelatesParam1>({ID}("::"|"."))*{ID} { // argument
1539 current->relates = yytext;
1540 //if (current->mGrpId!=DOX_NOGROUP)
1542 // memberGroupRelates = yytext;
1546 <RelatesParam1>{LC} { // line continuation
1550 <RelatesParam1>{DOCNL} { // missing argument
1551 warn(yyFileName,yyLineNr,
1552 "warning: Missing argument of \\relates or \\memberof command"
1554 if (*yytext=='\n') yyLineNr++;
1558 <RelatesParam1>. { // ignore other stuff
1562 /* ----- handle arguments of the relates(also)/addindex commands ----- */
1564 <LineParam>{DOCNL} { // end of argument
1565 if (*yytext=='\n') yyLineNr++;
1569 <LineParam>{LC} { // line continuation
1573 <LineParam>. { // ignore other stuff
1577 /* ----- handle arguments of the section/subsection/.. commands ------- */
1579 <SectionLabel>{LABELID} { // first argyment
1580 g_sectionLabel=yytext;
1582 g_sectionTitle.resize(0);
1583 BEGIN(SectionTitle);
1585 <SectionLabel>{DOCNL} { // missing argument
1586 warn(yyFileName,yyLineNr,
1587 "warning: \\section command has no label"
1589 if (*yytext=='\n') yyLineNr++;
1593 <SectionLabel>. { // invalid character for section label
1594 warn(yyFileName,yyLineNr,
1595 "warning: Invalid or missing section label"
1599 <SectionTitle>[^\n@\\*]*/"\n" { // end of section title
1604 <SectionTitle>[^\n@\\]*/"\\_linebr" { // end of section title
1609 <SectionTitle>{LC} { // line continuation
1613 <SectionTitle>[^\n@\\]* { // any character without special meaning
1614 g_sectionTitle+=yytext;
1617 <SectionTitle>("\\\\"|"@@"){ID} { // unescape escaped command
1618 g_sectionTitle+=&yytext[1];
1621 <SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character
1622 g_sectionTitle+=yytext[1];
1625 <SectionTitle>. { // anything else
1626 g_sectionTitle+=yytext;
1630 /* ----- handle arguments of the subpage command ------- */
1632 <SubpageLabel>{LABELID} { // first argument
1634 // we add subpage labels as a kind of "inheritance" relation to prevent
1635 // needing to add another list to the Entry class.
1636 current->extends->append(new BaseInfo(yytext,Public,Normal));
1637 BEGIN(SubpageTitle);
1639 <SubpageLabel>{DOCNL} { // missing argument
1640 warn(yyFileName,yyLineNr,
1641 "warning: \\subpage command has no label"
1643 if (*yytext=='\n') yyLineNr++;
1647 <SubpageTitle>{DOCNL} { // no title, end command
1651 <SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command
1655 <SubpageTitle>. { // no title, end of command
1660 /* ----- handle arguments of the anchor command ------- */
1662 <AnchorLabel>{LABELID} { // found argument
1663 SectionInfo *si = new SectionInfo(yyFileName,yytext,0,SectionInfo::Anchor,0);
1664 Doxygen::sectionDict.append(yytext,si);
1665 current->anchors->append(si);
1669 <AnchorLabel>{DOCNL} { // missing argument
1670 warn(yyFileName,yyLineNr,
1671 "warning: \\anchor command has no label"
1673 if (*yytext=='\n') yyLineNr++;
1677 <AnchorLabel>. { // invalid character for anchor label
1678 warn(yyFileName,yyLineNr,
1679 "warning: Invalid or missing anchor label"
1685 /* ----- handle arguments of the preformatted block commands ------- */
1687 <FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc")/{NW} { // possible ends
1689 if (&yytext[4]==blockName) // found end of the block
1694 <FormatBlock>[^ \@\*\/\\\n]* { // some word
1697 <FormatBlock>{DOCNL} { // new line
1698 if (*yytext=='\n') yyLineNr++;
1701 <FormatBlock>"/*" { // start of a C-comment
1705 <FormatBlock>"*/" { // end of a C-comment
1708 if (g_commentCount<0 && blockName!="verbatim")
1710 warn(yyFileName,yyLineNr,
1711 "warning: found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",blockName.data(),blockName.data());
1717 <FormatBlock><<EOF>> {
1718 warn(yyFileName,yyLineNr,
1719 "warning: reached end of comment while inside a @%s block; check for missing @end%s tag!",
1720 blockName.data(),blockName.data()
1725 /* ----- handle arguments of if/ifnot commands ------- */
1727 <GuardParam>{LABELID} { // parameter of if/ifnot guard
1728 bool sectionEnabled = Config_getList("ENABLED_SECTIONS").find(yytext)!=-1;
1729 bool parentEnabled = TRUE;
1730 if (!guards.isEmpty()) parentEnabled = guards.top()->isEnabled();
1734 (sectionEnabled && guardType==Guard_If) ||
1735 (!sectionEnabled && guardType==Guard_IfNot)
1736 ) // section is visible
1738 guards.push(new GuardedSection(TRUE,TRUE));
1739 enabledSectionFound=TRUE;
1740 BEGIN( GuardParamEnd );
1742 else // section is invisible
1744 if (guardType!=Guard_Skip)
1746 guards.push(new GuardedSection(FALSE,TRUE));
1748 BEGIN( SkipGuardedSection );
1751 else // invisible because of parent
1753 guards.push(new GuardedSection(FALSE,FALSE));
1754 BEGIN( SkipGuardedSection );
1757 <GuardParam>{DOCNL} { // end of argument
1758 if (*yytext=='\n') yyLineNr++;
1759 //next line is commented out due to bug620924
1763 <GuardParam>{LC} { // line continuation
1767 <GuardParam>. { // ignore other stuff
1770 <GuardParamEnd>{B}*{DOCNL} {
1771 g_spaceBeforeIf=FALSE;
1774 <GuardParamEnd>{B}* {
1775 if (g_spaceBeforeIf) // needed for 665313 in combation with bug620924
1779 g_spaceBeforeIf=FALSE;
1787 /* ----- handle skipping of conditional sections ------- */
1789 <SkipGuardedSection>{CMD}"ifnot"/{NW} {
1790 guardType = Guard_IfNot;
1791 BEGIN( GuardParam );
1793 <SkipGuardedSection>{CMD}"if"/{NW} {
1794 guardType = Guard_If;
1795 BEGIN( GuardParam );
1797 <SkipGuardedSection>{CMD}"endif"/{NW} {
1798 if (guards.isEmpty())
1800 warn(yyFileName,yyLineNr,
1801 "warning: found @endif without matching start command");
1805 delete guards.pop();
1806 BEGIN( GuardParamEnd );
1809 <SkipGuardedSection>{CMD}"else"/{NW} {
1810 if (guards.isEmpty())
1812 warn(yyFileName,yyLineNr,
1813 "warning: found @else without matching start command");
1817 if (!enabledSectionFound && guards.top()->parentVisible())
1819 delete guards.pop();
1820 guards.push(new GuardedSection(TRUE,TRUE));
1821 enabledSectionFound=TRUE;
1822 BEGIN( GuardParamEnd );
1826 <SkipGuardedSection>{CMD}"elseif"/{NW} {
1827 if (guards.isEmpty())
1829 warn(yyFileName,yyLineNr,
1830 "warning: found @elseif without matching start command");
1834 if (!enabledSectionFound && guards.top()->parentVisible())
1836 delete guards.pop();
1837 BEGIN( GuardParam );
1841 <SkipGuardedSection>{DOCNL} { // skip line
1842 if (*yytext=='\n') yyLineNr++;
1845 <SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters
1847 <SkipGuardedSection>. { // any other character
1851 /* ----- handle skipping of internal section ------- */
1853 <SkipInternal>{DOCNL} { // skip line
1854 if (*yytext=='\n') yyLineNr++;
1857 <SkipInternal>[@\\]"if"/[ \t] {
1860 <SkipInternal>[@\\]"ifnot"/[ \t] {
1863 <SkipInternal>[@\\]/"endif" {
1865 if (g_condCount<0) // handle conditional section around of \internal, see bug607743
1871 <SkipInternal>[@\\]/"section"[ \t] {
1872 if (g_sectionLevel>0)
1878 <SkipInternal>[@\\]/"subsection"[ \t] {
1879 if (g_sectionLevel>1)
1885 <SkipInternal>[@\\]/"subsubsection"[ \t] {
1886 if (g_sectionLevel>2)
1892 <SkipInternal>[@\\]/"paragraph"[ \t] {
1893 if (g_sectionLevel>3)
1899 <SkipInternal>[@\\]"endinternal"[ \t]* {
1902 <SkipInternal>[^ \\@\n]+ { // skip non-special characters
1904 <SkipInternal>. { // any other character
1908 /* ----- handle argument of name command ------- */
1910 <NameParam>{DOCNL} { // end of argument
1911 if (*yytext=='\n') yyLineNr++;
1915 <NameParam>{LC} { // line continuation
1918 g_memberGroupHeader+=' ';
1920 <NameParam>. { // ignore other stuff
1921 g_memberGroupHeader+=*yytext;
1922 current->name+=*yytext;
1925 /* ----- handle argument of ingroup command ------- */
1927 <InGroupParam>{LABELID} { // group id
1928 current->groups->append(
1929 new Grouping(yytext, Grouping::GROUPING_INGROUP)
1931 inGroupParamFound=TRUE;
1933 <InGroupParam>{DOCNL} { // missing argument
1934 if (!inGroupParamFound)
1936 warn(yyFileName,yyLineNr,
1937 "warning: Missing group name for \\ingroup command"
1940 if (*yytext=='\n') yyLineNr++;
1944 <InGroupParam>{LC} { // line continuation
1948 <InGroupParam>. { // ignore other stuff
1952 /* ----- handle argument of fn command ------- */
1954 <FnParam>{DOCNL} { // end of argument
1957 if (*yytext=='\n') yyLineNr++;
1959 langParser->parsePrototype(functionProto);
1963 <FnParam>{LC} { // line continuation
1967 <FnParam>[^@\\\n()]+ { // non-special characters
1968 functionProto+=yytext;
1971 functionProto+=yytext;
1975 functionProto+=yytext;
1978 <FnParam>. { // add other stuff
1979 functionProto+=*yytext;
1983 /* ----- handle argument of overload command ------- */
1986 <OverloadParam>{DOCNL} { // end of argument
1987 if (*yytext=='\n') yyLineNr++;
1989 if (functionProto.stripWhiteSpace().isEmpty())
1990 { // plain overload command
1991 addOutput(getOverloadDocs());
1993 else // overload declaration
1995 makeStructuralIndicator(Entry::OVERLOADDOC_SEC);
1996 langParser->parsePrototype(functionProto);
2000 <OverloadParam>{LC} { // line continuation
2004 <OverloadParam>. { // add other stuff
2005 functionProto+=*yytext;
2008 /* ----- handle argument of inherit command ------- */
2010 <InheritParam>({ID}("::"|"."))*{ID} { // found argument
2011 current->extends->append(
2012 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2016 <InheritParam>{DOCNL} { // missing argument
2017 warn(yyFileName,yyLineNr,
2018 "warning: \\inherit command has no argument"
2020 if (*yytext=='\n') yyLineNr++;
2024 <InheritParam>. { // invalid character for anchor label
2025 warn(yyFileName,yyLineNr,
2026 "warning: Invalid or missing name for \\inherit command"
2031 /* ----- handle argument of extends and implements commands ------- */
2033 <ExtendsParam>({ID}("::"|"."))*{ID} { // found argument
2034 current->extends->append(
2035 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2039 <ExtendsParam>{DOCNL} { // missing argument
2040 warn(yyFileName,yyLineNr,
2041 "warning: \\extends or \\implements command has no argument"
2043 if (*yytext=='\n') yyLineNr++;
2047 <ExtendsParam>. { // ignore other stuff
2050 /* ----- handle language specific sections ------- */
2052 <SkipLang>[\\@]"~"[a-zA-Z]* { /* language switch */
2053 QCString langId = &yytext[2];
2054 if (langId.isEmpty() ||
2055 stricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)==0)
2056 { // enable language specific section
2060 <SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
2062 <SkipLang>{DOCNL} { /* new line in verbatim block */
2063 if (*yytext=='\n') yyLineNr++;
2065 <SkipLang>. { /* any other character */
2068 /* ----- handle arguments of the cite command ------- */
2070 <CiteLabel>{CITEID} { // found argyment
2075 <CiteLabel>{DOCNL} { // missing argument
2076 warn(yyFileName,yyLineNr,
2077 "warning: \\cite command has no label"
2079 if (*yytext=='\n') yyLineNr++;
2083 <CiteLabel>. { // invalid character for cite label
2084 warn(yyFileName,yyLineNr,
2085 "warning: Invalid or missing cite label"
2090 /* ----- handle argument of the copydoc command ------- */
2094 if (*yytext=='\n') yyLineNr++;
2096 setOutput(OutputDoc);
2097 addOutput("\\copydetails ");
2098 addOutput(g_copyDocArg);
2103 g_copyDocArg+=yytext;
2107 g_copyDocArg+=yytext;
2114 //----------------------------------------------------------------------------
2116 static bool handleBrief(const QCString &)
2118 //printf("handleBrief\n");
2119 setOutput(OutputBrief);
2123 static bool handleFn(const QCString &)
2125 bool stop=makeStructuralIndicator(Entry::MEMBERDOC_SEC);
2126 functionProto.resize(0);
2132 static bool handleDef(const QCString &)
2134 bool stop=makeStructuralIndicator(Entry::DEFINEDOC_SEC);
2135 functionProto.resize(0);
2140 static bool handleOverload(const QCString &)
2142 functionProto.resize(0);
2143 BEGIN(OverloadParam);
2147 static bool handleEnum(const QCString &)
2149 bool stop=makeStructuralIndicator(Entry::ENUMDOC_SEC);
2154 static bool handleDefGroup(const QCString &)
2156 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2157 current->groupDocType = Entry::GROUPDOC_NORMAL;
2158 BEGIN( GroupDocArg1 );
2162 static bool handleAddToGroup(const QCString &)
2164 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2165 current->groupDocType = Entry::GROUPDOC_ADD;
2166 BEGIN( GroupDocArg1 );
2170 static bool handleWeakGroup(const QCString &)
2172 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2173 current->groupDocType = Entry::GROUPDOC_WEAK;
2174 BEGIN( GroupDocArg1 );
2178 static bool handleNamespace(const QCString &)
2180 bool stop=makeStructuralIndicator(Entry::NAMESPACEDOC_SEC);
2181 BEGIN( NameSpaceDocArg1 );
2185 static bool handlePackage(const QCString &)
2187 bool stop=makeStructuralIndicator(Entry::PACKAGEDOC_SEC);
2188 BEGIN( PackageDocArg1 );
2192 static bool handleClass(const QCString &)
2194 bool stop=makeStructuralIndicator(Entry::CLASSDOC_SEC);
2195 BEGIN( ClassDocArg1 );
2199 static bool handleHeaderFile(const QCString &)
2201 BEGIN( ClassDocArg2 );
2205 static bool handleProtocol(const QCString &)
2207 bool stop=makeStructuralIndicator(Entry::PROTOCOLDOC_SEC);
2208 BEGIN( ClassDocArg1 );
2212 static bool handleCategory(const QCString &)
2214 bool stop=makeStructuralIndicator(Entry::CATEGORYDOC_SEC);
2215 BEGIN( CategoryDocArg1 );
2219 static bool handleUnion(const QCString &)
2221 bool stop=makeStructuralIndicator(Entry::UNIONDOC_SEC);
2222 BEGIN( ClassDocArg1 );
2226 static bool handleStruct(const QCString &)
2228 bool stop=makeStructuralIndicator(Entry::STRUCTDOC_SEC);
2229 BEGIN( ClassDocArg1 );
2233 static bool handleInterface(const QCString &)
2235 bool stop=makeStructuralIndicator(Entry::INTERFACEDOC_SEC);
2236 BEGIN( ClassDocArg1 );
2240 static bool handleIdlException(const QCString &)
2242 bool stop=makeStructuralIndicator(Entry::EXCEPTIONDOC_SEC);
2243 BEGIN( ClassDocArg1 );
2247 static bool handlePage(const QCString &)
2249 bool stop=makeStructuralIndicator(Entry::PAGEDOC_SEC);
2250 BEGIN( PageDocArg1 );
2254 static bool handleMainpage(const QCString &)
2256 bool stop=makeStructuralIndicator(Entry::MAINPAGEDOC_SEC);
2259 current->name = "mainpage";
2261 BEGIN( PageDocArg2 );
2265 static bool handleFile(const QCString &)
2267 bool stop=makeStructuralIndicator(Entry::FILEDOC_SEC);
2270 current->name = yyFileName;
2272 BEGIN( FileDocArg1 );
2276 static bool handleDir(const QCString &)
2278 bool stop=makeStructuralIndicator(Entry::DIRDOC_SEC);
2279 if (!stop) current->name = yyFileName;
2280 BEGIN( FileDocArg1 );
2284 static bool handleExample(const QCString &)
2286 bool stop=makeStructuralIndicator(Entry::EXAMPLE_SEC);
2287 if (!stop) current->name = yyFileName;
2288 BEGIN( FileDocArg1 );
2292 static bool handleDetails(const QCString &)
2294 if (inContext!=OutputBrief)
2296 addOutput("\n\n"); // treat @details outside brief description
2297 // as a new paragraph
2299 setOutput(OutputDoc);
2303 static bool handleName(const QCString &)
2305 bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC);
2308 g_memberGroupHeader.resize(0);
2310 if (g_memberGroupId!=DOX_NOGROUP) // end of previous member group
2312 closeGroup(current,yyFileName,yyLineNr,TRUE);
2318 static bool handleTodo(const QCString &)
2320 newXRefKind = XRef_Todo;
2321 setOutput(OutputXRef);
2322 xrefKind = XRef_Todo;
2326 static bool handleTest(const QCString &)
2328 newXRefKind = XRef_Test;
2329 setOutput(OutputXRef);
2330 xrefKind = XRef_Test;
2334 static bool handleBug(const QCString &)
2336 newXRefKind = XRef_Bug;
2337 setOutput(OutputXRef);
2338 xrefKind = XRef_Bug;
2342 static bool handleDeprecated(const QCString &)
2344 newXRefKind = XRef_Deprecated;
2345 setOutput(OutputXRef);
2346 xrefKind = XRef_Deprecated;
2350 static bool handleXRefItem(const QCString &)
2352 newXRefKind = XRef_Item;
2353 BEGIN(XRefItemParam1);
2357 static bool handleRelated(const QCString &)
2359 BEGIN(RelatesParam1);
2363 static bool handleRelatedAlso(const QCString &)
2365 current->relatesType = Duplicate;
2366 BEGIN(RelatesParam1);
2370 static bool handleMemberOf(const QCString &)
2372 current->relatesType = MemberOf;
2373 BEGIN(RelatesParam1);
2377 static bool handleRefItem(const QCString &)
2379 addOutput("@refitem ");
2384 static bool handleSection(const QCString &s)
2386 setOutput(OutputDoc);
2387 addOutput("@"+s+" ");
2388 BEGIN(SectionLabel);
2389 if (s=="section") g_sectionLevel=1;
2390 else if (s=="subsection") g_sectionLevel=2;
2391 else if (s=="subsubsection") g_sectionLevel=3;
2392 else if (s=="paragraph") g_sectionLevel=4;
2396 static bool handleSubpage(const QCString &s)
2398 if (current->section!=Entry::EMPTY_SEC &&
2399 current->section!=Entry::PAGEDOC_SEC &&
2400 current->section!=Entry::MAINPAGEDOC_SEC
2403 warn(yyFileName,yyLineNr,
2404 "warning: found \\subpage command in a comment block that is not marked as a page!");
2406 addOutput("@"+s+" ");
2407 BEGIN(SubpageLabel);
2411 static bool handleAnchor(const QCString &s)
2413 addOutput("@"+s+" ");
2418 static bool handleCite(const QCString &s)
2420 addOutput("@"+s+" ");
2425 static bool handleFormatBlock(const QCString &s)
2427 addOutput("@"+s+" ");
2428 //printf("handleFormatBlock(%s)\n",s.data());
2435 static bool handleAddIndex(const QCString &)
2437 addOutput("@addindex ");
2442 static bool handleIf(const QCString &)
2444 enabledSectionFound=FALSE;
2445 guardType = Guard_If;
2446 g_spaceBeforeIf = g_spaceBeforeCmd;
2451 static bool handleIfNot(const QCString &)
2453 enabledSectionFound=FALSE;
2454 guardType = Guard_IfNot;
2455 g_spaceBeforeIf = g_spaceBeforeCmd;
2460 static bool handleElseIf(const QCString &)
2462 if (guards.isEmpty())
2464 warn(yyFileName,yyLineNr,
2465 "warning: found \\else without matching start command");
2469 guardType = enabledSectionFound ? Guard_Skip : Guard_If;
2475 static bool handleElse(const QCString &)
2477 if (guards.isEmpty())
2479 warn(yyFileName,yyLineNr,
2480 "warning: found \\else without matching start command");
2484 BEGIN( SkipGuardedSection );
2489 static bool handleEndIf(const QCString &)
2491 if (guards.isEmpty())
2493 warn(yyFileName,yyLineNr,
2494 "warning: found \\endif without matching start command");
2498 delete guards.pop();
2500 enabledSectionFound=FALSE;
2501 BEGIN( GuardParamEnd );
2505 static bool handleIngroup(const QCString &)
2507 inGroupParamFound=FALSE;
2508 BEGIN( InGroupParam );
2512 static bool handleNoSubGrouping(const QCString &)
2514 current->subGrouping = FALSE;
2518 static bool handleShowInitializer(const QCString &)
2520 current->initLines = 100000; // ON
2524 static bool handleHideInitializer(const QCString &)
2526 current->initLines = 0; // OFF
2530 static bool handleCallgraph(const QCString &)
2532 current->callGraph = TRUE; // ON
2536 static bool handleCallergraph(const QCString &)
2538 current->callerGraph = TRUE; // ON
2542 static bool handleInternal(const QCString &)
2544 if (!Config_getBool("INTERNAL_DOCS"))
2546 // make sure some whitespace before a \internal command
2547 // is not treated as "documentation"
2548 if (current->doc.stripWhiteSpace().isEmpty())
2550 current->doc.resize(0);
2553 BEGIN( SkipInternal );
2557 // re-enabled for bug640828
2558 addOutput("\\internal ");
2563 static bool handleLineBr(const QCString &)
2569 static bool handleStatic(const QCString &)
2572 current->stat = TRUE;
2576 static bool handlePure(const QCString &)
2579 current->virt = Pure;
2583 static bool handlePrivate(const QCString &)
2585 current->protection = Private;
2589 static bool handlePrivateSection(const QCString &)
2591 current->protection = protection = Private;
2595 static bool handleProtected(const QCString &)
2597 current->protection = Protected;
2601 static bool handleProtectedSection(const QCString &)
2603 current->protection = protection = Protected ;
2607 static bool handlePublic(const QCString &)
2609 current->protection = Public;
2613 static bool handlePublicSection(const QCString &)
2615 current->protection = protection = Public;
2619 static bool handleToc(const QCString &)
2621 if (current->section==Entry::PAGEDOC_SEC ||
2622 current->section==Entry::MAINPAGEDOC_SEC)
2624 current->stat=TRUE; // we 'abuse' stat to pass whether or the TOC is enabled
2629 static bool handleInherit(const QCString &)
2631 BEGIN(InheritParam);
2635 static bool handleExtends(const QCString &)
2637 BEGIN(ExtendsParam);
2641 static bool handleCopyDoc(const QCString &)
2643 setOutput(OutputBrief);
2644 addOutput("\\copybrief ");
2645 g_copyDocArg.resize(0);
2650 //----------------------------------------------------------------------------
2652 static void checkFormula()
2654 if (YY_START==ReadFormulaShort || YY_START==ReadFormulaLong)
2656 warn(yyFileName,yyLineNr,"warning: End of comment block while inside formula.");
2660 //----------------------------------------------------------------------------
2662 bool parseCommentBlock(/* in */ ParserInterface *parser,
2663 /* in */ Entry *curEntry,
2664 /* in */ const QCString &comment,
2665 /* in */ const QCString &fileName,
2666 /* in,out */ int &lineNr,
2667 /* in */ bool isBrief,
2668 /* in */ bool isAutoBriefOn,
2669 /* in */ bool isInbody,
2670 /* in,out */ Protection &prot,
2671 /* in,out */ int &position,
2672 /* out */ bool &newEntryNeeded
2675 //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n",
2676 // isBrief,isAutoBriefOn,lineNr);
2679 guards.setAutoDelete(TRUE);
2681 langParser = parser;
2683 if (comment.isEmpty()) return FALSE; // avoid empty strings
2684 inputString = comment;
2685 inputString.append(" ");
2686 inputPosition = position;
2688 yyFileName = fileName;
2690 needNewEntry = FALSE;
2691 xrefKind = XRef_None;
2692 xrefAppendFlag = FALSE;
2696 outputXRef.resize(0);
2697 setOutput( isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
2698 briefEndsAtDot = isAutoBriefOn;
2701 g_spaceBeforeCmd = FALSE;
2702 g_spaceBeforeIf = FALSE;
2704 if (!current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments
2706 current->inbodyDocs+="\n\n";
2709 Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n"
2710 "input=[\n%s]\n",fileName.data(),lineNr,comment.data()
2713 commentScanYYrestart( commentScanYYin );
2716 setOutput( OutputDoc );
2718 if (YY_START==OverloadParam) // comment ended with \overload
2720 addOutput(getOverloadDocs());
2723 if (!guards.isEmpty())
2725 warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
2728 current->doc=stripLeadingAndTrailingEmptyLines(current->doc,current->docLine);
2730 if (current->section==Entry::FILEDOC_SEC && current->doc.isEmpty())
2732 // to allow a comment block with just a @file command.
2733 current->doc="\n\n";
2736 if (current->section==Entry::MEMBERGRP_SEC &&
2737 g_memberGroupId==DOX_NOGROUP) // @name section but no group started yet
2739 openGroup(current,yyFileName,yyLineNr);
2742 if (Doxygen::markdownSupport)
2744 current->brief = processMarkdown(fileName,current,current->brief);
2745 current->doc = processMarkdown(fileName,current,current->doc);
2746 current->inbodyDocs = processMarkdown(fileName,current,current->inbodyDocs);
2749 Debug::print(Debug::CommentScan,0,
2750 "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n===========\n",
2751 current->briefLine,current->brief.data(),
2752 current->docLine,current->doc.data(),
2753 current->inbodyLine,current->inbodyDocs.data()
2759 groupAddDocs(curEntry,fileName);
2761 newEntryNeeded = needNewEntry;
2763 // if we did not proceed during this call, it does not make
2764 // sense to continue, since we get stuck. See bug 567346 for situations
2765 // were this happens
2766 if (parseMore && position==inputPosition) parseMore=FALSE;
2768 if (parseMore) position=inputPosition; else position=0;
2771 //printf("position=%d parseMore=%d\n",position,parseMore);
2776 //---------------------------------------------------------------------------
2778 void groupEnterFile(const char *fileName,int)
2780 g_autoGroupStack.setAutoDelete(TRUE);
2781 g_autoGroupStack.clear();
2782 g_memberGroupId = DOX_NOGROUP;
2783 g_memberGroupDocs.resize(0);
2784 g_memberGroupRelates.resize(0);
2785 g_compoundName=fileName;
2788 void groupLeaveFile(const char *fileName,int line)
2790 //if (g_memberGroupId!=DOX_NOGROUP)
2792 // warn(fileName,line,"warning: end of file while inside a member group\n");
2794 g_memberGroupId=DOX_NOGROUP;
2795 g_memberGroupRelates.resize(0);
2796 g_memberGroupDocs.resize(0);
2797 if (!g_autoGroupStack.isEmpty())
2799 warn(fileName,line,"warning: end of file while inside a group\n");
2803 void groupEnterCompound(const char *fileName,int line,const char *name)
2805 if (g_memberGroupId!=DOX_NOGROUP)
2807 warn(fileName,line,"warning: try to put compound %s inside a member group\n",name);
2809 g_memberGroupId=DOX_NOGROUP;
2810 g_memberGroupRelates.resize(0);
2811 g_memberGroupDocs.resize(0);
2812 g_compoundName = name;
2813 int i = g_compoundName.find('(');
2816 g_compoundName=g_compoundName.left(i); // strip category (Obj-C)
2818 if (g_compoundName.isEmpty())
2820 g_compoundName=fileName;
2822 //printf("groupEnterCompound(%s)\n",name);
2825 void groupLeaveCompound(const char *,int,const char * /*name*/)
2827 //printf("groupLeaveCompound(%s)\n",name);
2828 //if (g_memberGroupId!=DOX_NOGROUP)
2830 // warn(fileName,line,"warning: end of compound %s while inside a member group\n",name);
2832 g_memberGroupId=DOX_NOGROUP;
2833 g_memberGroupRelates.resize(0);
2834 g_memberGroupDocs.resize(0);
2835 g_compoundName.resize(0);
2838 static int findExistingGroup(int &groupId,const MemberGroupInfo *info)
2840 //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data());
2841 QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict);
2842 MemberGroupInfo *mi;
2843 for (di.toFirst();(mi=di.current());++di)
2845 if (g_compoundName==mi->compoundName && // same file or scope
2846 !mi->header.isEmpty() && // not a nameless group
2847 stricmp(mi->header,info->header)==0 // same header name
2850 //printf("Found it!\n");
2851 return di.currentKey(); // put the item in this group
2854 groupId++; // start new group
2858 void openGroup(Entry *e,const char *,int)
2860 //printf("==> openGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
2861 // e->name.data(),e->section,g_autoGroupStack.count());
2862 if (e->section==Entry::GROUPDOC_SEC) // auto group
2864 g_autoGroupStack.push(new Grouping(e->name,e->groupingPri()));
2866 else // start of a member group
2868 //printf(" membergroup id=%d %s\n",g_memberGroupId,g_memberGroupHeader.data());
2869 if (g_memberGroupId==DOX_NOGROUP) // no group started yet
2871 static int curGroupId=0;
2873 MemberGroupInfo *info = new MemberGroupInfo;
2874 info->header = g_memberGroupHeader.stripWhiteSpace();
2875 info->compoundName = g_compoundName;
2876 g_memberGroupId = findExistingGroup(curGroupId,info);
2877 //printf(" use membergroup %d\n",g_memberGroupId);
2878 Doxygen::memGrpInfoDict.insert(g_memberGroupId,info);
2880 g_memberGroupRelates = e->relates;
2881 e->mGrpId = g_memberGroupId;
2886 void closeGroup(Entry *e,const char *fileName,int,bool foundInline)
2888 //printf("==> closeGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
2889 // e->name.data(),e->section,g_autoGroupStack.count());
2890 if (g_memberGroupId!=DOX_NOGROUP) // end of member group
2892 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
2893 if (info) // known group
2895 info->doc = g_memberGroupDocs;
2896 info->docFile = fileName;
2898 g_memberGroupId=DOX_NOGROUP;
2899 g_memberGroupRelates.resize(0);
2900 g_memberGroupDocs.resize(0);
2901 e->mGrpId=DOX_NOGROUP;
2902 //printf("new group id=%d\n",g_memberGroupId);
2904 else if (!g_autoGroupStack.isEmpty()) // end of auto group
2906 Grouping *grp = g_autoGroupStack.pop();
2907 // see bug577005: we should not remove the last group for e
2908 if (!foundInline) e->groups->removeLast();
2909 //printf("Removing %s e=%p\n",grp->groupname.data(),e);
2911 if (!foundInline) initGroupInfo(e);
2915 void initGroupInfo(Entry *e)
2917 //printf("==> initGroup(id=%d,related=%s,e=%p)\n",g_memberGroupId,
2918 // g_memberGroupRelates.data(),e);
2919 e->mGrpId = g_memberGroupId;
2920 e->relates = g_memberGroupRelates;
2921 if (!g_autoGroupStack.isEmpty())
2923 //printf("Appending group %s to %s: count=%d entry=%p\n",
2924 // g_autoGroupStack.top()->groupname.data(),
2925 // e->name.data(),e->groups->count(),e);
2926 e->groups->append(new Grouping(*g_autoGroupStack.top()));
2930 static void groupAddDocs(Entry *e,const char *fileName)
2932 if (e->section==Entry::MEMBERGRP_SEC)
2934 g_memberGroupDocs=e->brief.stripWhiteSpace();
2935 e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine);
2936 if (!g_memberGroupDocs.isEmpty() && !e->doc.isEmpty())
2938 g_memberGroupDocs+="\n\n";
2940 g_memberGroupDocs+=e->doc;
2941 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
2944 info->doc = g_memberGroupDocs;
2945 info->docFile = fileName;
2946 info->setRefItems(e->sli);
2954 #if !defined(YY_FLEX_SUBMINOR_VERSION)
2955 //----------------------------------------------------------------------------
2956 extern "C" { // some bogus code to keep the compiler happy
2957 void commentScanYYdummy() { yy_flex_realloc(0,0); }