1 /*****************************************************************************
3 * Copyright (C) 1997-2014 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.
41 #include "outputlist.h"
42 #include "membergroup.h"
45 #include "parserintf.h"
48 #include "condparser.h"
53 // forward declarations
54 static bool handleBrief(const QCString &);
55 static bool handleFn(const QCString &);
56 static bool handleDef(const QCString &);
57 static bool handleOverload(const QCString &);
58 static bool handleEnum(const QCString &);
59 static bool handleDefGroup(const QCString &);
60 static bool handleAddToGroup(const QCString &);
61 static bool handleWeakGroup(const QCString &);
62 static bool handleNamespace(const QCString &);
63 static bool handlePackage(const QCString &);
64 static bool handleClass(const QCString &);
65 static bool handleHeaderFile(const QCString &);
66 static bool handleProtocol(const QCString &);
67 static bool handleCategory(const QCString &);
68 static bool handleUnion(const QCString &);
69 static bool handleStruct(const QCString &);
70 static bool handleInterface(const QCString &);
71 static bool handleIdlException(const QCString &);
72 static bool handlePage(const QCString &);
73 static bool handleMainpage(const QCString &);
74 static bool handleFile(const QCString &);
75 static bool handleDir(const QCString &);
76 static bool handleExample(const QCString &);
77 static bool handleDetails(const QCString &);
78 static bool handleName(const QCString &);
79 static bool handleTodo(const QCString &);
80 static bool handleTest(const QCString &);
81 static bool handleBug(const QCString &);
82 static bool handleSubpage(const QCString &s);
83 static bool handleDeprecated(const QCString &);
84 static bool handleXRefItem(const QCString &);
85 static bool handleRelated(const QCString &);
86 static bool handleRelatedAlso(const QCString &);
87 static bool handleMemberOf(const QCString &);
88 static bool handleRefItem(const QCString &);
89 static bool handleSection(const QCString &);
90 static bool handleAnchor(const QCString &);
91 static bool handleCite(const QCString &);
92 static bool handleFormatBlock(const QCString &);
93 static bool handleAddIndex(const QCString &);
94 static bool handleIf(const QCString &);
95 static bool handleIfNot(const QCString &);
96 static bool handleElseIf(const QCString &);
97 static bool handleElse(const QCString &);
98 static bool handleEndIf(const QCString &);
99 static bool handleIngroup(const QCString &);
100 static bool handleNoSubGrouping(const QCString &);
101 static bool handleShowInitializer(const QCString &);
102 static bool handleHideInitializer(const QCString &);
103 static bool handleCallgraph(const QCString &);
104 static bool handleCallergraph(const QCString &);
105 static bool handleInternal(const QCString &);
106 static bool handleLineBr(const QCString &);
107 static bool handleStatic(const QCString &);
108 static bool handlePure(const QCString &);
109 static bool handlePrivate(const QCString &);
110 static bool handlePrivateSection(const QCString &);
111 static bool handleProtected(const QCString &);
112 static bool handleProtectedSection(const QCString &);
113 static bool handlePublic(const QCString &s);
114 static bool handlePublicSection(const QCString &s);
115 static bool handleToc(const QCString &s);
116 static bool handleInherit(const QCString &);
117 static bool handleExtends(const QCString &);
118 static bool handleCopyDoc(const QCString &);
119 static bool handleCopyBrief(const QCString &);
120 static bool handleCopyDetails(const QCString &);
121 static bool handleParBlock(const QCString &);
122 static bool handleEndParBlock(const QCString &);
124 typedef bool (*DocCmdFunc)(const QCString &name);
133 // map of command to handler function
134 static DocCmdMap docCmdMap[] =
136 // command name handler function ends brief description
137 { "brief", &handleBrief, FALSE },
138 { "short", &handleBrief, FALSE },
139 { "fn", &handleFn, FALSE },
140 { "var", &handleFn, FALSE },
141 { "typedef", &handleFn, FALSE },
142 { "property", &handleFn, FALSE },
143 { "def", &handleDef, FALSE },
144 { "overload", &handleOverload, FALSE },
145 { "enum", &handleEnum, FALSE },
146 { "defgroup", &handleDefGroup, FALSE },
147 { "addtogroup", &handleAddToGroup, FALSE },
148 { "weakgroup", &handleWeakGroup, FALSE },
149 { "namespace", &handleNamespace, FALSE },
150 { "package", &handlePackage, FALSE },
151 { "class", &handleClass, FALSE },
152 { "headerfile", &handleHeaderFile, FALSE },
153 { "protocol", &handleProtocol, FALSE },
154 { "category", &handleCategory, FALSE },
155 { "union", &handleUnion, FALSE },
156 { "struct", &handleStruct, FALSE },
157 { "interface", &handleInterface, FALSE },
158 { "idlexcept", &handleIdlException, FALSE },
159 { "page", &handlePage, FALSE },
160 { "mainpage", &handleMainpage, FALSE },
161 { "file", &handleFile, FALSE },
162 { "dir", &handleDir, FALSE },
163 { "example", &handleExample, FALSE },
164 { "details", &handleDetails, TRUE },
165 { "name", &handleName, FALSE },
166 { "todo", &handleTodo, FALSE }, // end brief will be done differently
167 { "test", &handleTest, FALSE }, // end brief will be done differently
168 { "bug", &handleBug, FALSE }, // end brief will be done differently
169 { "deprecated", &handleDeprecated, FALSE }, // end brief will be done differently
170 { "xrefitem", &handleXRefItem, FALSE }, // end brief will be done differently
171 { "related", &handleRelated, TRUE },
172 { "relates", &handleRelated, TRUE },
173 { "relatedalso", &handleRelatedAlso, TRUE },
174 { "relatesalso", &handleRelatedAlso, TRUE },
175 { "parblock", &handleParBlock, TRUE },
176 { "endparblock", &handleEndParBlock, TRUE },
177 { "refitem", &handleRefItem, TRUE },
178 { "cite", &handleCite, FALSE },
179 { "subpage", &handleSubpage, TRUE },
180 { "section", &handleSection, TRUE },
181 { "subsection", &handleSection, TRUE },
182 { "subsubsection", &handleSection, TRUE },
183 { "paragraph", &handleSection, TRUE },
184 { "anchor", &handleAnchor, TRUE },
185 { "verbatim", &handleFormatBlock, TRUE },
186 { "latexonly", &handleFormatBlock, FALSE },
187 { "htmlonly", &handleFormatBlock, FALSE },
188 { "xmlonly", &handleFormatBlock, FALSE },
189 { "docbookonly", &handleFormatBlock, FALSE },
190 { "rtfonly", &handleFormatBlock, FALSE },
191 { "manonly", &handleFormatBlock, FALSE },
192 { "dot", &handleFormatBlock, TRUE },
193 { "msc", &handleFormatBlock, TRUE },
194 { "code", &handleFormatBlock, TRUE },
195 { "addindex", &handleAddIndex, FALSE },
196 { "if", &handleIf, FALSE },
197 { "ifnot", &handleIfNot, FALSE },
198 { "elseif", &handleElseIf, FALSE },
199 { "else", &handleElse, FALSE },
200 { "endif", &handleEndIf, FALSE },
201 { "ingroup", &handleIngroup, FALSE },
202 { "nosubgrouping", &handleNoSubGrouping, FALSE },
203 { "showinitializer", &handleShowInitializer, FALSE },
204 { "hideinitializer", &handleHideInitializer, FALSE },
205 { "callgraph", &handleCallgraph, FALSE },
206 { "callergraph", &handleCallergraph, FALSE },
207 { "internal", &handleInternal, TRUE },
208 { "_linebr", &handleLineBr, FALSE },
209 { "static", &handleStatic, FALSE },
210 { "pure", &handlePure, FALSE },
211 { "private", &handlePrivate, FALSE },
212 { "privatesection", &handlePrivateSection, FALSE },
213 { "protected", &handleProtected, FALSE },
214 { "protectedsection",&handleProtectedSection, FALSE },
215 { "public", &handlePublic, FALSE },
216 { "publicsection", &handlePublicSection, FALSE },
217 { "tableofcontents", &handleToc, FALSE },
218 { "inherit", &handleInherit, TRUE },
219 { "extends", &handleExtends, TRUE },
220 { "implements", &handleExtends, TRUE },
221 { "memberof", &handleMemberOf, TRUE },
223 { "attention", 0, TRUE },
224 { "author", 0, TRUE },
225 { "authors", 0, TRUE },
226 { "copydoc", &handleCopyDoc, TRUE },
227 { "copybrief", &handleCopyBrief, FALSE },
228 { "copydetails", &handleCopyDetails, TRUE },
229 { "copyright", 0, TRUE },
231 { "dotfile", 0, TRUE },
232 { "htmlinclude", 0, FALSE },
233 { "image", 0, TRUE },
234 { "include", 0, TRUE },
235 { "includelineno", 0, TRUE },
236 { "invariant", 0, TRUE },
237 { "latexinclude", 0, FALSE },
242 { "param", 0, TRUE },
243 { "tparam", 0, TRUE },
246 { "remark", 0, TRUE },
247 { "remarks", 0, TRUE },
248 { "result", 0, TRUE },
249 { "return", 0, TRUE },
250 { "returns", 0, TRUE },
251 { "retval", 0, TRUE },
254 { "since", 0, TRUE },
255 { "throw", 0, TRUE },
256 { "throws", 0, TRUE },
257 { "until", 0, TRUE },
258 { "verbinclude", 0, FALSE },
259 { "version", 0, TRUE },
260 { "warning", 0, TRUE },
264 /** @brief Command mapper.
266 * Maps a command name (as found in a comment block) onto a
267 * specific handler function.
278 /** maps a command name to a handler function */
279 static Cmd *map(const char *name)
281 return instance()->find(name);
284 /** release the singleton */
285 static void freeInstance()
287 delete s_instance; s_instance=0;
291 static DocCmdMapper *instance()
293 if (s_instance==0) s_instance = new DocCmdMapper;
297 DocCmdMapper() : m_map(113)
299 m_map.setAutoDelete(TRUE);
300 DocCmdMap *p = docCmdMap;
303 if (m_map.find(p->cmdName)!=0)
305 err("DocCmdMapper: command %s already added\n",p->cmdName);
309 cmd->func = p->handler;
310 cmd->endsBrief = p->endsBrief;
311 m_map.insert(p->cmdName,cmd);
316 Cmd *find(const char *name)
318 return m_map.find(name);
321 static DocCmdMapper *s_instance;
324 DocCmdMapper *DocCmdMapper::s_instance=0;
326 bool inInternalDocs = FALSE;
328 #define YY_NEVER_INTERACTIVE 1
358 GuardedSection(bool enabled,bool parentVisible)
359 : m_enabled(enabled),m_parentVisible(parentVisible) {}
360 bool isEnabled() const { return m_enabled; }
361 bool parentVisible() const { return m_parentVisible; }
365 bool m_parentVisible;
368 void openGroup(Entry *e,const char *file,int line);
369 void closeGroup(Entry *e,const char *file,int line,bool foundInline=FALSE);
370 void initGroupInfo(Entry *e);
371 static void groupAddDocs(Entry *e,const char *fileName);
373 /* -----------------------------------------------------------------
378 static ParserInterface *langParser; // the language parser that is calling us
379 static QCString inputString; // input string
380 static int inputPosition; // read pointer
381 static QCString yyFileName; // file name that is read from
382 static int yyLineNr; // line number in the input
383 static bool inBody; // was the comment found inside the body of a function?
384 static OutputContext inContext; // are we inside the brief, details or xref part
385 static bool briefEndsAtDot; // does the brief description stop at a dot?
386 static QCString formulaText; // Running text of a formula
387 static QCString formulaEnv; // environment name
388 static int formulaNewLines; // amount of new lines in the formula
389 static QCString *pOutputString; // pointer to string to which the output is appended.
390 static QCString outputXRef; // temp argument of todo/test/../xrefitem commands
391 static QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...)
392 static XRefKind xrefKind; // kind of cross-reference command
393 static XRefKind newXRefKind; //
394 static GuardType guardType; // kind of guard for conditional section
395 static bool enabledSectionFound;
396 static QCString functionProto; // function prototype
397 static QStack<GuardedSection> guards; // tracks nested conditional sections (if,ifnot,..)
398 static Entry* current = 0 ; // working entry
399 //static Entry* current_root = 0 ; // parent of working entry
402 //static Entry* previous = 0 ; // TODO: remove need for this
403 static bool needNewEntry;
405 static QCString g_sectionLabel;
406 static QCString g_sectionTitle;
407 static int g_sectionLevel;
408 static QCString xrefItemKey;
409 static QCString newXRefItemKey;
410 static QCString xrefItemTitle;
411 static QCString xrefListTitle;
412 static Protection protection;
414 static bool xrefAppendFlag;
415 static bool inGroupParamFound;
416 static int braceCount;
417 static bool insidePre;
418 static bool parseMore;
419 static int g_condCount;
421 static int g_commentCount;
422 static QCString g_spaceBeforeCmd;
423 static QCString g_spaceBeforeIf;
424 static QCString g_copyDocArg;
426 static QCString g_guardExpr;
427 static int g_roundCount;
429 static bool g_insideParBlock;
431 //-----------------------------------------------------------------------------
433 static QStack<Grouping> g_autoGroupStack;
434 static int g_memberGroupId = DOX_NOGROUP;
435 static QCString g_memberGroupHeader;
436 static QCString g_memberGroupDocs;
437 static QCString g_memberGroupRelates;
438 static QCString g_compoundName;
440 //-----------------------------------------------------------------------------
442 static void initParser()
444 g_sectionLabel.resize(0);
445 g_sectionTitle.resize(0);
446 g_memberGroupHeader.resize(0);
447 g_insideParBlock = FALSE;
450 //-----------------------------------------------------------------------------
452 static bool getDocSectionName(int s)
456 case Entry::CLASSDOC_SEC:
457 case Entry::STRUCTDOC_SEC:
458 case Entry::UNIONDOC_SEC:
459 case Entry::EXCEPTIONDOC_SEC:
460 case Entry::NAMESPACEDOC_SEC:
461 case Entry::PROTOCOLDOC_SEC:
462 case Entry::CATEGORYDOC_SEC:
463 case Entry::ENUMDOC_SEC:
464 case Entry::PAGEDOC_SEC:
465 case Entry::VARIABLEDOC_SEC:
466 case Entry::MEMBERDOC_SEC:
467 case Entry::OVERLOADDOC_SEC:
468 case Entry::FILEDOC_SEC:
469 case Entry::DEFINEDOC_SEC:
470 case Entry::GROUPDOC_SEC:
471 case Entry::MAINPAGEDOC_SEC:
472 case Entry::PACKAGEDOC_SEC:
473 case Entry::DIRDOC_SEC:
474 case Entry::EXAMPLE_SEC:
475 case Entry::MEMBERGRP_SEC:
482 //-----------------------------------------------------------------------------
484 static bool makeStructuralIndicator(Entry::Sections s)
486 //printf("current->section=%x\n",current->section);
487 if (getDocSectionName(current->section))
494 current->section = s;
495 current->fileName = yyFileName;
496 current->startLine = yyLineNr;
501 static void lineCount()
503 for( const char* c = yytext ; *c ; ++c )
504 yyLineNr += (*c == '\n') ;
508 static QCString stripQuotes(const char *s)
511 if (s==0 || *s==0) return name;
513 if (name.at(0)=='"' && name.at(name.length()-1)=='"')
515 name=name.mid(1,name.length()-2);
520 //-----------------------------------------------------------------
522 static void addXRefItem(const char *listName,const char *itemTitle,
523 const char *listTitle,bool append)
525 Entry *docEntry = current; // inBody && previous ? previous : current;
526 if (listName==0) return;
527 //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append);
530 RefList *refList = Doxygen::xrefLists->find(listName);
531 if (refList==0) // new list
533 refList = new RefList(listName,listTitle,itemTitle);
534 Doxygen::xrefLists->insert(listName,refList);
535 //printf("new list!\n");
539 QListIterator<ListItemInfo> slii(*docEntry->sli);
540 for (slii.toFirst();(lii=slii.current());++slii)
542 if (qstrcmp(lii->type,listName)==0)
544 //printf("found %s lii->type=%s\n",listName,lii->type);
549 if (lii && append) // already found item of same type just before this one
551 //printf("listName=%s item id = %d existing\n",listName,lii->itemId);
552 RefItem *item = refList->getRefItem(lii->itemId);
554 item->text += " <p>";
555 if (Doxygen::markdownSupport)
557 item->text += processMarkdown(yyFileName,yyLineNr,current,outputXRef);
561 item->text += outputXRef;
563 //printf("%s: text +=%s\n",listName,item->text.data());
567 int itemId = refList->addRefItem();
568 //printf("listName=%s item id = %d new current=%p\n",listName,itemId,current);
570 // if we have already an item from the same list type (e.g. a second @todo)
571 // in the same Entry (i.e. lii!=0) then we reuse its link anchor.
572 char anchorLabel[1024];
573 //sprintf(anchorLabel,"_%s%06d",listName,lii ? lii->itemId : itemId);
574 sprintf(anchorLabel,"_%s%06d",listName,itemId);
575 RefItem *item = refList->getRefItem(itemId);
577 if (Doxygen::markdownSupport)
579 item->text = processMarkdown(yyFileName,yyLineNr,current,outputXRef);
583 item->text = outputXRef;
585 item->listAnchor = anchorLabel;
586 docEntry->addSpecialListItem(listName,itemId);
588 cmdString.sprintf("\\xrefitem %s %d.",listName,itemId);
591 docEntry->inbodyDocs += cmdString;
595 docEntry->doc += cmdString;
597 SectionInfo *si = Doxygen::sectionDict->find(anchorLabel);
600 if (si->lineNr != -1)
602 warn(listName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel,si->fileName.data(),si->lineNr);
606 warn(listName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel,si->fileName.data());
611 si=new SectionInfo(listName,yyLineNr,anchorLabel,
612 g_sectionTitle,SectionInfo::Anchor,
614 Doxygen::sectionDict->append(anchorLabel,si);
615 docEntry->anchors->append(si);
618 outputXRef.resize(0);
621 //-----------------------------------------------------------------------------
623 // Adds a formula text to the list/dictionary of formulas if it was
624 // not already added. Returns the label of the formula.
625 static QCString addFormula()
628 QCString fText=formulaText.simplifyWhiteSpace();
630 if ((f=Doxygen::formulaDict->find(fText))==0)
632 f = new Formula(fText);
633 Doxygen::formulaList->append(f);
634 Doxygen::formulaDict->insert(fText,f);
635 formLabel.sprintf("\\form#%d",f->getId());
636 Doxygen::formulaNameDict->insert(formLabel,f);
640 formLabel.sprintf("\\form#%d",f->getId());
643 for (i=0;i<formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to
645 // correctly aligned.
649 //-----------------------------------------------------------------------------
651 static void checkFormula();
652 //-----------------------------------------------------------------------------
654 static SectionInfo::SectionType sectionLevelToType(int level)
656 if (level>=0 && level<5) return (SectionInfo::SectionType)level;
657 return SectionInfo::Anchor;
660 static void addSection()
662 SectionInfo *si = Doxygen::sectionDict->find(g_sectionLabel);
665 if (si->lineNr != -1)
667 warn(yyFileName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",g_sectionLabel.data(),si->fileName.data(),si->lineNr);
671 warn(yyFileName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s)",g_sectionLabel.data(),si->fileName.data());
676 // create a new section element
677 g_sectionTitle+=yytext;
678 g_sectionTitle=g_sectionTitle.stripWhiteSpace();
679 si = new SectionInfo(yyFileName,yyLineNr,g_sectionLabel,
680 g_sectionTitle,sectionLevelToType(g_sectionLevel),g_sectionLevel);
682 // add section to this entry
683 current->anchors->append(si);
685 // add section to the global dictionary
686 Doxygen::sectionDict->append(g_sectionLabel,si);
690 //-----------------------------------------------------------------------------
692 static void addCite()
694 Doxygen::citeDict->insert(yytext);
697 //-----------------------------------------------------------------------------
699 // strip trailing whitespace (excluding newlines) from string s
700 static void stripTrailingWhiteSpace(QCString &s)
702 uint len = s.length();
705 while (i>=0 && ((c = s.at(i))==' ' || c=='\t' || c=='\r')) i--;
708 s.resize(i+2); // string up to and including char at pos i and \0 terminator
712 // selects the output to write to
713 static inline void setOutput(OutputContext ctx)
715 bool xrefAppendToPrev = xrefAppendFlag;
716 // determine append flag for the next item (i.e. the end of this item)
717 xrefAppendFlag = !inBody &&
718 inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items
719 newXRefKind==xrefKind && // of the same kind
720 (xrefKind!=XRef_Item ||
721 newXRefItemKey==xrefItemKey); // with the same key if \xrefitem
722 //printf("%d && %d && %d && (%d || %d)\n",
723 // inContext==OutputXRef,
725 // newXRefKind==xrefKind,
726 // xrefKind!=XRef_Item,
727 // newXRefItemKey==xrefItemKey);
729 //printf("refKind=%d newXRefKind=%d xrefAppendToPrev=%d xrefAppendFlag=%d\n",
730 // xrefKind,newXRefKind,xrefAppendToPrev,xrefAppendFlag);
732 //printf("setOutput(inContext=%d ctx=%d)\n",inContext,ctx);
733 if (inContext==OutputXRef) // end of XRef section => add the item
735 // See if we can append this new xref item to the previous one.
736 // We know this at the start of the next item of the same
737 // type and need to remember this until the end of that item.
742 theTranslator->trTodo(),
743 theTranslator->trTodoList(),
749 theTranslator->trTest(),
750 theTranslator->trTestList(),
756 theTranslator->trBug(),
757 theTranslator->trBugList(),
761 case XRef_Deprecated:
762 addXRefItem("deprecated",
763 theTranslator->trDeprecated(),
764 theTranslator->trDeprecatedList(),
768 case XRef_Item: // user defined list
769 addXRefItem(xrefItemKey,
780 xrefItemKey = newXRefItemKey;
782 int oldContext = inContext;
784 if (inContext!=OutputXRef && inBody) inContext=OutputInbody;
788 if (oldContext!=inContext)
790 stripTrailingWhiteSpace(current->doc);
791 if (current->docFile.isEmpty())
793 current->docFile = yyFileName;
794 current->docLine = yyLineNr;
797 pOutputString = ¤t->doc;
800 if (oldContext!=inContext)
802 if (current->briefFile.isEmpty())
804 current->briefFile = yyFileName;
805 current->briefLine = yyLineNr;
808 if (current->brief.stripWhiteSpace().isEmpty()) // we only want one brief
809 // description even if multiple
812 pOutputString = ¤t->brief;
816 pOutputString = ¤t->doc;
817 inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
821 pOutputString = &outputXRef;
822 // first item found, so can't append to previous
823 //xrefAppendFlag = FALSE;
826 pOutputString = ¤t->inbodyDocs;
831 // add a string to the output
832 static inline void addOutput(const char *s)
834 //printf("addOutput(%s)\n",s);
838 // add a character to the output
839 static inline void addOutput(char c)
844 static void endBrief(bool addToOutput=TRUE)
846 if (!current->brief.stripWhiteSpace().isEmpty())
847 { // only go to the detailed description if we have
848 // found some brief description and not just whitespace
849 briefEndsAtDot=FALSE;
850 setOutput(OutputDoc);
851 if (addToOutput) addOutput(yytext);
855 static void handleGuard(const QCString &expr);
856 /* ----------------------------------------------------------------- */
858 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
860 static int prevPosition=0;
862 static int yyread(char *buf,int max_size)
864 prevPosition=inputPosition;
866 while( c < max_size && inputString[inputPosition] )
868 *buf = inputString[inputPosition++] ;
869 //printf("%d (%c)\n",*buf,*buf);
877 /* start command character */
879 DCMD1 ("arg"|"attention"|"author"|"cite"|"code")
880 DCMD2 ("date"|"dot"|"msc"|"dotfile"|"example")
881 DCMD3 ("htmlinclude"|"htmlonly"|"image"|"include")
882 DCMD4 ("includelineno"|"internal"|"invariant")
883 DCMD5 ("latexinclude"|"latexonly"|"li"|"line"|"manonly"|"name")
884 DCMD6 ("note"|"par"|"paragraph"|"param"|"post")
885 DCMD7 ("pre"|"remarks"|(("relate"[sd])("also")?))
886 DCMD8 ("remarks"|("return"[s]?)|"retval"|"sa"|"section")
887 DCMD9 ("see"|"since"|"subsection"|"subsubsection")
888 DCMD10 ("throw"|"until"|"verbatim")
889 DCMD11 ("verbinclude"|"version"|"warning")
890 DETAILEDCMD {CMD}({DCMD1}|{DCMD2}|{DCMD3}|{DCMD4}|{DCMD5}|{DCMD6}|{DCMD7}|{DCMD8}|{DCMD9}|{DCMD10}|{DCMD11})
891 XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem")
893 TABLE [tT][aA][bB][lL][eE]
900 PARA [pP][aA][rR][aA]
901 CODE [cC][oO][dD][eE]
902 DETAILEDHTML {PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA}
903 DETAILEDHTMLOPT {CODE}
907 BS ^(({B}*"//")?)(({B}*"*"+)?){B}*
909 DOCNL "\n"|"\\_linebr"
912 FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+@&#]
913 FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+@&#]
914 FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"")
915 ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
916 LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
917 CITEID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-:/]*
918 SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
919 SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID})
920 TMPLSPEC "<"{BN}*[^>]+{BN}*">"
921 MAILADDR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
922 RCSTAG "$"{ID}":"[^\n$]+"$"
926 /* comment parsing states. */
952 %x SkipGuardedSection
971 /* What can happen in while parsing a comment block:
972 * commands (e.g. @page, or \page)
973 * escaped commands (e.g. @@page or \\page).
974 * formulas (e.g. \f$ \f[ \f{..)
975 * directories (e.g. \doxygen\src\)
976 * autolist end. (e.g. a dot on an otherwise empty line)
978 * end of brief description due to blank line.
979 * end of brief description due to some command (@command, or <command>).
980 * words and whitespace and other characters (#,?!, etc).
981 * grouping commands (e.g. @{ and @})
982 * language switch (e.g. \~english or \~).
983 * mail address (e.g. dimitri@stack.nl).
984 * quoted text, such as "foo@bar"
985 * XML commands, <summary></summary><remarks></remarks>
988 <Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command
991 <Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command
994 <Comment>{MAILADDR} { // mail address
997 <Comment>"\""[^"\n]*"\"" { // quoted text
1000 <Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!)
1003 <Comment>{XREFCMD}/[^a-z_A-Z]* { // xref command
1004 if (inContext!=OutputXRef)
1006 briefEndsAtDot=FALSE;
1007 setOutput(OutputDoc);
1009 // continue with the same input
1013 <Comment>{DETAILEDCMD}/[^a-z_A-Z]* { // command that can end a brief description
1014 briefEndsAtDot=FALSE;
1015 setOutput(OutputDoc);
1016 // continue with the same input
1020 <Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description
1021 setOutput(OutputDoc);
1022 // continue with the same input
1025 <Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description
1026 if (current->lang==SrcLangExt_CSharp)
1028 setOutput(OutputDoc);
1030 // continue with the same input
1033 <Comment>"<summary>" { // start of a .NET XML style brief description
1034 setOutput(OutputBrief);
1037 <Comment>"<remarks>" { // start of a .NET XML style detailed description
1038 setOutput(OutputDoc);
1041 <Comment>"</summary>" { // start of a .NET XML style detailed description
1043 setOutput(OutputDoc);
1045 <Comment>"</remarks>" { // end of a brief or detailed description
1048 <Comment>"<"{PRE}{ATTR}">" {
1052 <Comment>"</"{PRE}">" {
1056 <Comment>{RCSTAG} { // RCS tag which end a brief description
1057 setOutput(OutputDoc);
1063 <Comment>{B}*{CMD}"endinternal"{B}* {
1064 addOutput("\\endinternal ");
1065 if (!inInternalDocs)
1066 warn(yyFileName,yyLineNr,
1067 "found \\endinternal without matching \\internal"
1069 inInternalDocs = FALSE;
1071 <Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command
1072 // the {B}* in the front was added for bug620924
1073 QCString cmdName = QCString(yytext).stripWhiteSpace().data()+1;
1074 DocCmdMapper::Cmd *cmdPtr = DocCmdMapper::map(cmdName);
1075 if (cmdPtr) // special action is required
1078 while (yytext[i]==' ' || yytext[i]=='\t') i++;
1079 g_spaceBeforeCmd = QCString(yytext).left(i);
1080 if (cmdPtr->endsBrief && inContext!=OutputXRef)
1082 briefEndsAtDot=FALSE;
1083 // this command forces the end of brief description
1084 setOutput(OutputDoc);
1086 //if (i>0) addOutput(QCString(yytext).left(i)); // removed for bug 689341
1087 if (cmdPtr->func && cmdPtr->func(cmdName))
1089 // implicit split of the comment block into two
1090 // entries. Restart the next block at the start
1094 // yuk, this is probably not very portable across lex implementations,
1095 // but we need to know the position in the input buffer where this
1097 // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE
1098 #if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33
1099 inputPosition=prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);
1101 inputPosition=prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf);
1105 else if (cmdPtr->func==0)
1107 // command without handler, to be processed
1108 // later by parsedoc.cpp
1112 else // command not relevant
1117 <Comment>{B}*("\\\\"|"@@")"f"[$\[{] { // escaped formula command
1120 <Comment>{B}*{CMD}"~"[a-z_A-Z]* { // language switch command
1121 QCString langId = QString(yytext).stripWhiteSpace().data()+2;
1122 if (!langId.isEmpty() &&
1123 qstricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)!=0)
1124 { // enable language specific section
1128 <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment
1129 formulaText="\\begin";
1130 formulaEnv=QString(yytext).stripWhiteSpace().data()+2;
1131 if (formulaEnv.at(formulaEnv.length()-1)=='{')
1133 // remove trailing open brace
1134 formulaEnv=formulaEnv.left(formulaEnv.length()-1);
1136 formulaText+=formulaEnv;
1138 BEGIN(ReadFormulaLong);
1140 <Comment>{B}*{CMD}"f$" { // start of a inline formula
1143 BEGIN(ReadFormulaShort);
1145 <Comment>{B}*{CMD}"f[" { // start of a block formula
1148 BEGIN(ReadFormulaLong);
1150 <Comment>{B}*{CMD}"{" { // begin of a group
1151 //langParser->handleGroupStartCommand(g_memberGroupHeader);
1152 openGroup(current,yyFileName,yyLineNr);
1154 <Comment>{B}*{CMD}"}" { // end of a group
1155 //langParser->handleGroupEndCommand();
1156 closeGroup(current,yyFileName,yyLineNr,TRUE);
1157 g_memberGroupHeader.resize(0);
1159 needNewEntry = TRUE;
1160 #if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33
1161 inputPosition=prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + strlen(yytext);
1163 inputPosition=prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + strlen(yytext);
1167 <Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character
1170 <Comment>[a-z_A-Z]+ { // normal word
1173 <Comment>^{B}*"."{B}*/\n { // explicit end autolist: e.g " ."
1176 <Comment>^{B}*[1-9][0-9]*"."{B}+ |
1177 <Comment>^{B}*[*+]{B}+ { // start of autolist
1178 if (!Doxygen::markdownSupport)
1184 if (inContext!=OutputXRef)
1186 briefEndsAtDot=FALSE;
1187 setOutput(OutputDoc);
1192 <Comment>^{B}*"-"{B}+ { // start of autolist
1193 if (inContext!=OutputXRef)
1195 briefEndsAtDot=FALSE;
1196 setOutput(OutputDoc);
1200 <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{B}*/\n { // horizontal line (dashed)
1203 <Comment>{CMD}"---" { // escaped mdash
1206 <Comment>{CMD}"--" { // escaped mdash
1209 <Comment>"---" { // mdash
1210 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "—");
1212 <Comment>"--" { // ndash
1213 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "–");
1215 <Comment>"-#"{B}+ { // numbered item
1218 <Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis
1221 <Comment>".\\"[ \t] { // . with escaped space.
1222 addOutput(yytext[0]);
1223 addOutput(yytext[2]);
1225 <Comment>".," { // . with comma such as "e.g.,"
1228 <Comment>"...\\"[ \t] { // ellipsis with escaped space.
1231 <Comment>".."[\.]?/[^ \t\n] { // internal ellipsis
1234 <Comment>(\n|\\_linebr)({B}*(\n|\\_linebr))+ { // at least one blank line (or blank line command)
1235 if (inContext==OutputXRef)
1237 // see bug 613024, we need to put the newlines after ending the XRef section.
1238 if (!g_insideParBlock) setOutput(OutputDoc);
1242 if (yytext[i]=='\n') addOutput('\n'),i++;
1243 else if (strcmp(yytext+i,"\\_linebr")==0) addOutput('\n'),i+=8;
1247 else if (inContext!=OutputBrief)
1252 if (yytext[i]=='\n') addOutput('\n'),i++;
1253 else if (strcmp(yytext+i,"\\_linebr")==0) addOutput('\n'),i+=8;
1256 setOutput(OutputDoc);
1258 else // inContext==OutputBrief
1259 { // only go to the detailed description if we have
1260 // found some brief description and not just whitespace
1265 <Comment>"." { // potential end of a JavaDoc style comment
1269 setOutput(OutputDoc);
1270 briefEndsAtDot=FALSE;
1273 <Comment>\n { // newline
1277 <Comment>. { // catch-all for anything else
1282 /* -------------- Rules for handling HTML comments ----------- */
1284 <HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); }
1285 <HtmlComment>{DOCNL} {
1286 if (*yytext=='\n') yyLineNr++;
1288 <HtmlComment>[^\\\n\-]+ { // ignore unimportant characters
1290 <HtmlComment>. { // ignore every else
1293 /* -------------- Rules for handling formulas ---------------- */
1295 <ReadFormulaShort>{CMD}"f$" { // end of inline formula
1297 addOutput(" "+addFormula());
1300 <ReadFormulaLong>{CMD}"f]" { // end of block formula
1302 addOutput(" "+addFormula());
1305 <ReadFormulaLong>{CMD}"f}" { // end of custom env formula
1306 formulaText+="\\end";
1307 formulaText+=formulaEnv;
1308 addOutput(" "+addFormula());
1311 <ReadFormulaLong,ReadFormulaShort>[^\\@\n]+ { // any non-special character
1312 formulaText+=yytext;
1314 <ReadFormulaLong,ReadFormulaShort>\n { // new line
1316 formulaText+=*yytext;
1319 <ReadFormulaLong,ReadFormulaShort>. { // any othe character
1320 formulaText+=*yytext;
1323 /* ------------ handle argument of enum command --------------- */
1325 <EnumDocArg1>{SCOPEID} { // handle argument
1326 current->name = yytext;
1329 <EnumDocArg1>{LC} { // line continuation
1333 <EnumDocArg1>{DOCNL} { // missing argument
1334 warn(yyFileName,yyLineNr,
1335 "missing argument after \\enum."
1338 if (*yytext=='\n') yyLineNr++;
1341 <EnumDocArg1>. { // ignore other stuff
1344 /* ------------ handle argument of namespace command --------------- */
1346 <NameSpaceDocArg1>{SCOPENAME} { // handle argument
1347 current->name = substitute(yytext,".","::");
1350 <NameSpaceDocArg1>{LC} { // line continuation
1354 <NameSpaceDocArg1>{DOCNL} { // missing argument
1355 warn(yyFileName,yyLineNr,
1356 "missing argument after "
1360 if (*yytext=='\n') yyLineNr++;
1363 <NameSpaceDocArg1>. { // ignore other stuff
1366 /* ------------ handle argument of package command --------------- */
1368 <PackageDocArg1>{ID}("."{ID})* { // handle argument
1369 current->name = yytext;
1372 <PackageDocArg1>{LC} { // line continuation
1376 <PackageDocArg1>{DOCNL} { // missing argument
1377 warn(yyFileName,yyLineNr,
1378 "missing argument after "
1382 if (*yytext=='\n') yyLineNr++;
1385 <PackageDocArg1>. { // ignore other stuff
1388 /* ------ handle argument of class/struct/union command --------------- */
1390 <ClassDocArg1>{SCOPENAME}{TMPLSPEC} {
1391 current->name = substitute(removeRedundantWhiteSpace(yytext),".","::");
1392 BEGIN( ClassDocArg2 );
1394 <ClassDocArg1>{SCOPENAME} { // first argument
1395 current->name = substitute(yytext,".","::");
1396 if (current->section==Entry::PROTOCOLDOC_SEC)
1398 current->name+="-p";
1400 // prepend outer scope name
1401 BEGIN( ClassDocArg2 );
1403 <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" {
1404 current->name = substitute(yytext,".","::");
1405 BEGIN( ClassDocArg2 );
1407 <ClassDocArg1,CategoryDocArg1>{LC} { // line continuation
1411 <ClassDocArg1,CategoryDocArg1>{DOCNL} {
1412 warn(yyFileName,yyLineNr,
1413 "missing argument after "
1414 "\\%s.",YY_START==ClassDocArg1?"class":"category"
1417 if (*yytext=='\n') yyLineNr++;
1420 <ClassDocArg1,CategoryDocArg1>. { // ignore other stuff
1423 <ClassDocArg2>{FILE}|"<>" { // second argument; include file
1424 current->includeFile = yytext;
1425 BEGIN( ClassDocArg3 );
1427 <ClassDocArg2>{LC} { // line continuation
1431 <ClassDocArg2>{DOCNL} {
1433 if (*yytext=='\n') yyLineNr++;
1436 <ClassDocArg2>. { // ignore other stuff
1439 <ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name
1440 current->includeName = yytext;
1443 <ClassDocArg3>{LC} { // line continuation
1447 <ClassDocArg3>{DOCNL} {
1448 if (*yytext=='\n') yyLineNr++;
1451 <ClassDocArg3>. { // ignore other stuff
1454 /* --------- handle arguments of {def,add,weak}group commands --------- */
1456 <GroupDocArg1>{LABELID}(".html"?) { // group name
1457 current->name = yytext;
1458 //lastDefGroup.groupname = yytext;
1459 //lastDefGroup.pri = current->groupingPri();
1460 // the .html stuff is for Qt compatibility
1461 if (current->name.right(5)==".html")
1463 current->name=current->name.left(current->name.length()-5);
1465 current->type.resize(0);
1466 BEGIN(GroupDocArg2);
1468 <GroupDocArg1>"\\"{B}*"\n" { // line continuation
1472 <GroupDocArg1>{DOCNL} { // missing argument!
1473 warn(yyFileName,yyLineNr,
1474 "missing group name after %s",
1475 current->groupDocCmd()
1478 if (*yytext=='\n') yyLineNr++;
1481 <GroupDocArg2>"\\"{B}*"\n" { // line continuation
1485 <GroupDocArg2>[^\n\\\*]+ { // title (stored in type)
1486 current->type += yytext;
1487 current->type = current->type.stripWhiteSpace();
1489 <GroupDocArg2>{DOCNL} {
1490 if ( current->groupDocType==Entry::GROUPDOC_NORMAL &&
1491 current->type.isEmpty()
1492 ) // defgroup requires second argument
1494 warn(yyFileName,yyLineNr,
1495 "missing title after "
1496 "\\defgroup %s", current->name.data()
1499 if (*yytext=='\n') yyLineNr++;
1504 /* --------- handle arguments of page/mainpage command ------------------- */
1506 <PageDocArg1>{FILE} { // first argument; page name
1507 current->name = stripQuotes(yytext);
1508 BEGIN( PageDocArg2 );
1510 <PageDocArg1>{LC} { yyLineNr++;
1513 <PageDocArg1>{DOCNL} {
1514 warn(yyFileName,yyLineNr,
1515 "missing argument after "
1518 if (*yytext=='\n') yyLineNr++;
1522 <PageDocArg1>. { // ignore other stuff
1524 <PageDocArg2>.*"\n" { // second argument; page title
1526 current->args = yytext;
1531 /* --------- handle arguments of the file/dir/example command ------------ */
1533 <FileDocArg1>{DOCNL} { // no file name specfied
1534 if (*yytext=='\n') yyLineNr++;
1538 <FileDocArg1>{FILE} { // first argument; name
1539 current->name = stripQuotes(yytext);
1542 <FileDocArg1>{LC} { yyLineNr++;
1545 <FileDocArg1>. { // ignore other stuff
1548 /* --------- handle arguments of the xrefitem command ------------ */
1550 <XRefItemParam1>{LABELID} { // first argument
1551 newXRefItemKey=yytext;
1552 setOutput(OutputXRef);
1553 BEGIN(XRefItemParam2);
1555 <XRefItemParam1>{LC} { // line continuation
1559 <XRefItemParam1>{DOCNL} { // missing arguments
1560 warn(yyFileName,yyLineNr,
1561 "Missing first argument of \\xrefitem"
1563 if (*yytext=='\n') yyLineNr++;
1565 inContext = OutputDoc;
1568 <XRefItemParam1>. { // ignore other stuff
1571 <XRefItemParam2>"\""[^\n\"]*"\"" { // second argument
1572 xrefItemTitle = stripQuotes(yytext);
1573 BEGIN(XRefItemParam3);
1575 <XRefItemParam2>{LC} { // line continuation
1579 <XRefItemParam2>{DOCNL} { // missing argument
1580 warn(yyFileName,yyLineNr,
1581 "Missing second argument of \\xrefitem"
1583 if (*yytext=='\n') yyLineNr++;
1585 inContext = OutputDoc;
1588 <XRefItemParam2>. { // ignore other stuff
1591 <XRefItemParam3>"\""[^\n\"]*"\"" { // third argument
1592 xrefListTitle = stripQuotes(yytext);
1593 xrefKind = XRef_Item;
1596 <XRefItemParam2,XRefItemParam3>{LC} { // line continuation
1600 <XRefItemParam3>{DOCNL} { // missing argument
1601 warn(yyFileName,yyLineNr,
1602 "Missing third argument of \\xrefitem"
1604 if (*yytext=='\n') yyLineNr++;
1606 inContext = OutputDoc;
1609 <XRefItemParam3>. { // ignore other stuff
1613 /* ----- handle arguments of the relates(also)/memberof command ------- */
1615 <RelatesParam1>({ID}("::"|"."))*{ID} { // argument
1616 current->relates = yytext;
1617 //if (current->mGrpId!=DOX_NOGROUP)
1619 // memberGroupRelates = yytext;
1623 <RelatesParam1>{LC} { // line continuation
1627 <RelatesParam1>{DOCNL} { // missing argument
1628 warn(yyFileName,yyLineNr,
1629 "Missing argument of \\relates or \\memberof command"
1631 if (*yytext=='\n') yyLineNr++;
1635 <RelatesParam1>. { // ignore other stuff
1639 /* ----- handle arguments of the relates(also)/addindex commands ----- */
1641 <LineParam>{DOCNL} { // end of argument
1642 if (*yytext=='\n') yyLineNr++;
1646 <LineParam>{LC} { // line continuation
1650 <LineParam>. { // ignore other stuff
1654 /* ----- handle arguments of the section/subsection/.. commands ------- */
1656 <SectionLabel>{LABELID} { // first argyment
1657 g_sectionLabel=yytext;
1659 g_sectionTitle.resize(0);
1660 BEGIN(SectionTitle);
1662 <SectionLabel>{DOCNL} { // missing argument
1663 warn(yyFileName,yyLineNr,
1664 "\\section command has no label"
1666 if (*yytext=='\n') yyLineNr++;
1670 <SectionLabel>. { // invalid character for section label
1671 warn(yyFileName,yyLineNr,
1672 "Invalid or missing section label"
1676 <SectionTitle>[^\n@\\*]*/"\n" { // end of section title
1681 <SectionTitle>[^\n@\\]*/"\\_linebr" { // end of section title
1686 <SectionTitle>{LC} { // line continuation
1690 <SectionTitle>[^\n@\\]* { // any character without special meaning
1691 g_sectionTitle+=yytext;
1694 <SectionTitle>("\\\\"|"@@"){ID} { // unescape escaped command
1695 g_sectionTitle+=&yytext[1];
1698 <SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character
1699 g_sectionTitle+=yytext[1];
1702 <SectionTitle>. { // anything else
1703 g_sectionTitle+=yytext;
1707 /* ----- handle arguments of the subpage command ------- */
1709 <SubpageLabel>{LABELID} { // first argument
1711 // we add subpage labels as a kind of "inheritance" relation to prevent
1712 // needing to add another list to the Entry class.
1713 current->extends->append(new BaseInfo(yytext,Public,Normal));
1714 BEGIN(SubpageTitle);
1716 <SubpageLabel>{DOCNL} { // missing argument
1717 warn(yyFileName,yyLineNr,
1718 "\\subpage command has no label"
1720 if (*yytext=='\n') yyLineNr++;
1724 <SubpageTitle>{DOCNL} { // no title, end command
1728 <SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command
1732 <SubpageTitle>. { // no title, end of command
1737 /* ----- handle arguments of the anchor command ------- */
1739 <AnchorLabel>{LABELID} { // found argument
1740 SectionInfo *si = Doxygen::sectionDict->find(yytext);
1743 if (si->lineNr != -1)
1745 warn(yyFileName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",yytext,si->fileName.data(),si->lineNr);
1749 warn(yyFileName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s)",yytext,si->fileName.data());
1754 si = new SectionInfo(yyFileName,yyLineNr,yytext,0,SectionInfo::Anchor,0);
1755 Doxygen::sectionDict->append(yytext,si);
1756 current->anchors->append(si);
1761 <AnchorLabel>{DOCNL} { // missing argument
1762 warn(yyFileName,yyLineNr,
1763 "\\anchor command has no label"
1765 if (*yytext=='\n') yyLineNr++;
1769 <AnchorLabel>. { // invalid character for anchor label
1770 warn(yyFileName,yyLineNr,
1771 "Invalid or missing anchor label"
1777 /* ----- handle arguments of the preformatted block commands ------- */
1779 <FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc"|"endvhdlflow")/{NW} { // possible ends
1781 if (&yytext[4]==blockName) // found end of the block
1786 <FormatBlock>[^ \@\*\/\\\n]* { // some word
1789 <FormatBlock>{DOCNL} { // new line
1790 if (*yytext=='\n') yyLineNr++;
1793 <FormatBlock>"/*" { // start of a C-comment
1797 <FormatBlock>"*/" { // end of a C-comment
1800 if (g_commentCount<0 && blockName!="verbatim")
1802 warn(yyFileName,yyLineNr,
1803 "found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",blockName.data(),blockName.data());
1809 <FormatBlock><<EOF>> {
1810 warn(yyFileName,yyLineNr,
1811 "reached end of comment while inside a @%s block; check for missing @end%s tag!",
1812 blockName.data(),blockName.data()
1817 /* ----- handle arguments of if/ifnot commands ------- */
1819 <GuardParam>{B}*"(" {
1825 g_guardExpr+=yytext;
1828 g_guardExpr+=yytext;
1832 g_guardExpr+=yytext;
1834 if (g_roundCount==0)
1836 handleGuard(g_guardExpr);
1840 warn(yyFileName,yyLineNr,
1841 "invalid expression '%s' for guard",g_guardExpr.data());
1845 <GuardParam>{B}*[a-z_A-Z0-9.\-]+ { // parameter of if/ifnot guard
1846 handleGuard(yytext);
1848 <GuardParam>{DOCNL} { // end of argument
1849 if (*yytext=='\n') yyLineNr++;
1850 //next line is commented out due to bug620924
1854 <GuardParam>{LC} { // line continuation
1858 <GuardParam>. { // ignore other stuff
1861 <GuardParamEnd>{B}*{DOCNL} {
1862 g_spaceBeforeIf.resize(0);
1865 <GuardParamEnd>{B}* {
1866 if (!g_spaceBeforeIf.isEmpty()) // needed for 665313 in combation with bug620924
1868 addOutput(g_spaceBeforeIf);
1870 g_spaceBeforeIf.resize(0);
1878 /* ----- handle skipping of conditional sections ------- */
1880 <SkipGuardedSection>{CMD}"ifnot"/{NW} {
1881 guardType = Guard_IfNot;
1882 BEGIN( GuardParam );
1884 <SkipGuardedSection>{CMD}"if"/{NW} {
1885 guardType = Guard_If;
1886 BEGIN( GuardParam );
1888 <SkipGuardedSection>{CMD}"endif"/{NW} {
1889 if (guards.isEmpty())
1891 warn(yyFileName,yyLineNr,
1892 "found @endif without matching start command");
1896 GuardedSection *s = guards.pop();
1897 bool parentVisible = s->parentVisible();
1901 enabledSectionFound=TRUE;
1902 BEGIN( GuardParamEnd );
1906 <SkipGuardedSection>{CMD}"else"/{NW} {
1907 if (guards.isEmpty())
1909 warn(yyFileName,yyLineNr,
1910 "found @else without matching start command");
1914 if (!enabledSectionFound && guards.top()->parentVisible())
1916 delete guards.pop();
1917 guards.push(new GuardedSection(TRUE,TRUE));
1918 enabledSectionFound=TRUE;
1919 BEGIN( GuardParamEnd );
1923 <SkipGuardedSection>{CMD}"elseif"/{NW} {
1924 if (guards.isEmpty())
1926 warn(yyFileName,yyLineNr,
1927 "found @elseif without matching start command");
1931 if (!enabledSectionFound && guards.top()->parentVisible())
1934 delete guards.pop();
1935 BEGIN( GuardParam );
1939 <SkipGuardedSection>{DOCNL} { // skip line
1940 if (*yytext=='\n') yyLineNr++;
1943 <SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters
1945 <SkipGuardedSection>. { // any other character
1949 /* ----- handle skipping of internal section ------- */
1951 <SkipInternal>{DOCNL} { // skip line
1952 if (*yytext=='\n') yyLineNr++;
1955 <SkipInternal>[@\\]"if"/[ \t] {
1958 <SkipInternal>[@\\]"ifnot"/[ \t] {
1961 <SkipInternal>[@\\]/"endif" {
1963 if (g_condCount<0) // handle conditional section around of \internal, see bug607743
1969 <SkipInternal>[@\\]/"section"[ \t] {
1970 if (g_sectionLevel>0)
1976 <SkipInternal>[@\\]/"subsection"[ \t] {
1977 if (g_sectionLevel>1)
1983 <SkipInternal>[@\\]/"subsubsection"[ \t] {
1984 if (g_sectionLevel>2)
1990 <SkipInternal>[@\\]/"paragraph"[ \t] {
1991 if (g_sectionLevel>3)
1997 <SkipInternal>[@\\]"endinternal"[ \t]* {
1998 addOutput("\\endinternal ");
2001 <SkipInternal>[^ \\@\n]+ { // skip non-special characters
2003 <SkipInternal>. { // any other character
2007 /* ----- handle argument of name command ------- */
2009 <NameParam>{DOCNL} { // end of argument
2010 if (*yytext=='\n') yyLineNr++;
2014 <NameParam>{LC} { // line continuation
2017 g_memberGroupHeader+=' ';
2019 <NameParam>. { // ignore other stuff
2020 g_memberGroupHeader+=*yytext;
2021 current->name+=*yytext;
2024 /* ----- handle argument of ingroup command ------- */
2026 <InGroupParam>{LABELID} { // group id
2027 current->groups->append(
2028 new Grouping(yytext, Grouping::GROUPING_INGROUP)
2030 inGroupParamFound=TRUE;
2032 <InGroupParam>{DOCNL} { // missing argument
2033 if (!inGroupParamFound)
2035 warn(yyFileName,yyLineNr,
2036 "Missing group name for \\ingroup command"
2039 if (*yytext=='\n') yyLineNr++;
2043 <InGroupParam>{LC} { // line continuation
2047 <InGroupParam>. { // ignore other stuff
2051 /* ----- handle argument of fn command ------- */
2053 <FnParam>{DOCNL} { // end of argument
2056 if (*yytext=='\n') yyLineNr++;
2058 langParser->parsePrototype(functionProto);
2062 <FnParam>{LC} { // line continuation
2066 <FnParam>[^@\\\n()]+ { // non-special characters
2067 functionProto+=yytext;
2070 functionProto+=yytext;
2074 functionProto+=yytext;
2077 <FnParam>. { // add other stuff
2078 functionProto+=*yytext;
2082 /* ----- handle argument of overload command ------- */
2085 <OverloadParam>{DOCNL} { // end of argument
2086 if (*yytext=='\n') yyLineNr++;
2087 if (functionProto.stripWhiteSpace().isEmpty())
2088 { // plain overload command
2089 addOutput(getOverloadDocs());
2092 else // overload declaration
2094 makeStructuralIndicator(Entry::OVERLOADDOC_SEC);
2095 langParser->parsePrototype(functionProto);
2099 <OverloadParam>{LC} { // line continuation
2103 <OverloadParam>. { // add other stuff
2104 functionProto+=*yytext;
2107 /* ----- handle argument of inherit command ------- */
2109 <InheritParam>({ID}("::"|"."))*{ID} { // found argument
2110 current->extends->append(
2111 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2115 <InheritParam>{DOCNL} { // missing argument
2116 warn(yyFileName,yyLineNr,
2117 "\\inherit command has no argument"
2119 if (*yytext=='\n') yyLineNr++;
2123 <InheritParam>. { // invalid character for anchor label
2124 warn(yyFileName,yyLineNr,
2125 "Invalid or missing name for \\inherit command"
2130 /* ----- handle argument of extends and implements commands ------- */
2132 <ExtendsParam>({ID}("::"|"."))*{ID} { // found argument
2133 current->extends->append(
2134 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2138 <ExtendsParam>{DOCNL} { // missing argument
2139 warn(yyFileName,yyLineNr,
2140 "\\extends or \\implements command has no argument"
2142 if (*yytext=='\n') yyLineNr++;
2146 <ExtendsParam>. { // ignore other stuff
2149 /* ----- handle language specific sections ------- */
2151 <SkipLang>[\\@]"~"[a-zA-Z]* { /* language switch */
2152 QCString langId = &yytext[2];
2153 if (langId.isEmpty() ||
2154 qstricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)==0)
2155 { // enable language specific section
2159 <SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
2161 <SkipLang>{DOCNL} { /* new line in verbatim block */
2162 if (*yytext=='\n') yyLineNr++;
2164 <SkipLang>. { /* any other character */
2167 /* ----- handle arguments of the cite command ------- */
2169 <CiteLabel>{CITEID} { // found argyment
2174 <CiteLabel>{DOCNL} { // missing argument
2175 warn(yyFileName,yyLineNr,
2176 "\\cite command has no label"
2178 if (*yytext=='\n') yyLineNr++;
2182 <CiteLabel>. { // invalid character for cite label
2183 warn(yyFileName,yyLineNr,
2184 "Invalid or missing cite label"
2189 /* ----- handle argument of the copydoc command ------- */
2193 if (*yytext=='\n') yyLineNr++;
2195 setOutput(OutputDoc);
2196 addOutput("\\copydetails ");
2197 addOutput(g_copyDocArg);
2202 g_copyDocArg+=yytext;
2206 g_copyDocArg+=yytext;
2213 //----------------------------------------------------------------------------
2215 static bool handleBrief(const QCString &)
2217 //printf("handleBrief\n");
2218 setOutput(OutputBrief);
2222 static bool handleFn(const QCString &)
2224 bool stop=makeStructuralIndicator(Entry::MEMBERDOC_SEC);
2225 functionProto.resize(0);
2231 static bool handleDef(const QCString &)
2233 bool stop=makeStructuralIndicator(Entry::DEFINEDOC_SEC);
2234 functionProto.resize(0);
2239 static bool handleOverload(const QCString &)
2241 functionProto.resize(0);
2242 BEGIN(OverloadParam);
2246 static bool handleEnum(const QCString &)
2248 bool stop=makeStructuralIndicator(Entry::ENUMDOC_SEC);
2253 static bool handleDefGroup(const QCString &)
2255 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2256 current->groupDocType = Entry::GROUPDOC_NORMAL;
2257 BEGIN( GroupDocArg1 );
2261 static bool handleAddToGroup(const QCString &)
2263 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2264 current->groupDocType = Entry::GROUPDOC_ADD;
2265 BEGIN( GroupDocArg1 );
2269 static bool handleWeakGroup(const QCString &)
2271 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2272 current->groupDocType = Entry::GROUPDOC_WEAK;
2273 BEGIN( GroupDocArg1 );
2277 static bool handleNamespace(const QCString &)
2279 bool stop=makeStructuralIndicator(Entry::NAMESPACEDOC_SEC);
2280 BEGIN( NameSpaceDocArg1 );
2284 static bool handlePackage(const QCString &)
2286 bool stop=makeStructuralIndicator(Entry::PACKAGEDOC_SEC);
2287 BEGIN( PackageDocArg1 );
2291 static bool handleClass(const QCString &)
2293 bool stop=makeStructuralIndicator(Entry::CLASSDOC_SEC);
2294 BEGIN( ClassDocArg1 );
2298 static bool handleHeaderFile(const QCString &)
2300 BEGIN( ClassDocArg2 );
2304 static bool handleProtocol(const QCString &)
2306 bool stop=makeStructuralIndicator(Entry::PROTOCOLDOC_SEC);
2307 BEGIN( ClassDocArg1 );
2311 static bool handleCategory(const QCString &)
2313 bool stop=makeStructuralIndicator(Entry::CATEGORYDOC_SEC);
2314 BEGIN( CategoryDocArg1 );
2318 static bool handleUnion(const QCString &)
2320 bool stop=makeStructuralIndicator(Entry::UNIONDOC_SEC);
2321 BEGIN( ClassDocArg1 );
2325 static bool handleStruct(const QCString &)
2327 bool stop=makeStructuralIndicator(Entry::STRUCTDOC_SEC);
2328 BEGIN( ClassDocArg1 );
2332 static bool handleInterface(const QCString &)
2334 bool stop=makeStructuralIndicator(Entry::INTERFACEDOC_SEC);
2335 BEGIN( ClassDocArg1 );
2339 static bool handleIdlException(const QCString &)
2341 bool stop=makeStructuralIndicator(Entry::EXCEPTIONDOC_SEC);
2342 BEGIN( ClassDocArg1 );
2346 static bool handlePage(const QCString &)
2348 bool stop=makeStructuralIndicator(Entry::PAGEDOC_SEC);
2349 BEGIN( PageDocArg1 );
2353 static bool handleMainpage(const QCString &)
2355 bool stop=makeStructuralIndicator(Entry::MAINPAGEDOC_SEC);
2358 current->name = "mainpage";
2360 BEGIN( PageDocArg2 );
2364 static bool handleFile(const QCString &)
2366 bool stop=makeStructuralIndicator(Entry::FILEDOC_SEC);
2369 current->name = yyFileName;
2371 BEGIN( FileDocArg1 );
2375 static bool handleDir(const QCString &)
2377 bool stop=makeStructuralIndicator(Entry::DIRDOC_SEC);
2378 if (!stop) current->name = yyFileName;
2379 BEGIN( FileDocArg1 );
2383 static bool handleExample(const QCString &)
2385 bool stop=makeStructuralIndicator(Entry::EXAMPLE_SEC);
2386 if (!stop) current->name = yyFileName;
2387 BEGIN( FileDocArg1 );
2391 static bool handleDetails(const QCString &)
2393 if (inContext!=OutputBrief)
2395 addOutput("\n\n"); // treat @details outside brief description
2396 // as a new paragraph
2398 setOutput(OutputDoc);
2402 static bool handleName(const QCString &)
2404 bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC);
2407 g_memberGroupHeader.resize(0);
2409 if (g_memberGroupId!=DOX_NOGROUP) // end of previous member group
2411 closeGroup(current,yyFileName,yyLineNr,TRUE);
2417 static bool handleTodo(const QCString &)
2419 newXRefKind = XRef_Todo;
2420 setOutput(OutputXRef);
2421 xrefKind = XRef_Todo;
2425 static bool handleTest(const QCString &)
2427 newXRefKind = XRef_Test;
2428 setOutput(OutputXRef);
2429 xrefKind = XRef_Test;
2433 static bool handleBug(const QCString &)
2435 newXRefKind = XRef_Bug;
2436 setOutput(OutputXRef);
2437 xrefKind = XRef_Bug;
2441 static bool handleDeprecated(const QCString &)
2443 newXRefKind = XRef_Deprecated;
2444 setOutput(OutputXRef);
2445 xrefKind = XRef_Deprecated;
2449 static bool handleXRefItem(const QCString &)
2451 newXRefKind = XRef_Item;
2452 BEGIN(XRefItemParam1);
2456 static bool handleParBlock(const QCString &)
2458 if (g_insideParBlock)
2460 warn(yyFileName,yyLineNr,
2461 "found \\parblock command while already in a parblock!");
2463 if (!g_spaceBeforeCmd.isEmpty())
2465 addOutput(g_spaceBeforeCmd);
2466 g_spaceBeforeCmd.resize(0);
2468 addOutput("@parblock ");
2469 g_insideParBlock = TRUE;
2473 static bool handleEndParBlock(const QCString &)
2475 if (!g_insideParBlock)
2477 warn(yyFileName,yyLineNr,
2478 "found \\endparblock command without matching \\parblock!");
2480 addOutput("@endparblock");
2481 setOutput(OutputDoc); // to end a parblock inside a xrefitem like context
2482 g_insideParBlock = FALSE;
2486 static bool handleRelated(const QCString &)
2488 BEGIN(RelatesParam1);
2492 static bool handleRelatedAlso(const QCString &)
2494 current->relatesType = Duplicate;
2495 BEGIN(RelatesParam1);
2499 static bool handleMemberOf(const QCString &)
2501 current->relatesType = MemberOf;
2502 BEGIN(RelatesParam1);
2506 static bool handleRefItem(const QCString &)
2508 addOutput("@refitem ");
2513 static bool handleSection(const QCString &s)
2515 setOutput(OutputDoc);
2516 addOutput("@"+s+" ");
2517 BEGIN(SectionLabel);
2518 if (s=="section") g_sectionLevel=1;
2519 else if (s=="subsection") g_sectionLevel=2;
2520 else if (s=="subsubsection") g_sectionLevel=3;
2521 else if (s=="paragraph") g_sectionLevel=4;
2525 static bool handleSubpage(const QCString &s)
2527 if (current->section!=Entry::EMPTY_SEC &&
2528 current->section!=Entry::PAGEDOC_SEC &&
2529 current->section!=Entry::MAINPAGEDOC_SEC
2532 warn(yyFileName,yyLineNr,
2533 "found \\subpage command in a comment block that is not marked as a page!");
2535 if (!g_spaceBeforeCmd.isEmpty())
2537 addOutput(g_spaceBeforeCmd);
2538 g_spaceBeforeCmd.resize(0);
2540 addOutput("@"+s+" ");
2541 BEGIN(SubpageLabel);
2545 static bool handleAnchor(const QCString &s)
2547 addOutput("@"+s+" ");
2552 static bool handleCite(const QCString &s)
2554 if (!g_spaceBeforeCmd.isEmpty())
2556 addOutput(g_spaceBeforeCmd);
2557 g_spaceBeforeCmd.resize(0);
2559 addOutput("@"+s+" ");
2564 static bool handleFormatBlock(const QCString &s)
2566 addOutput("@"+s+" ");
2567 //printf("handleFormatBlock(%s)\n",s.data());
2574 static bool handleAddIndex(const QCString &)
2576 addOutput("@addindex ");
2581 static bool handleIf(const QCString &)
2583 enabledSectionFound=FALSE;
2584 guardType = Guard_If;
2585 g_spaceBeforeIf = g_spaceBeforeCmd;
2590 static bool handleIfNot(const QCString &)
2592 enabledSectionFound=FALSE;
2593 guardType = Guard_IfNot;
2594 g_spaceBeforeIf = g_spaceBeforeCmd;
2599 static bool handleElseIf(const QCString &)
2601 if (guards.isEmpty())
2603 warn(yyFileName,yyLineNr,
2604 "found \\else without matching start command");
2608 guardType = enabledSectionFound ? Guard_Skip : Guard_If;
2614 static bool handleElse(const QCString &)
2616 if (guards.isEmpty())
2618 warn(yyFileName,yyLineNr,
2619 "found \\else without matching start command");
2623 BEGIN( SkipGuardedSection );
2628 static bool handleEndIf(const QCString &)
2630 if (guards.isEmpty())
2632 warn(yyFileName,yyLineNr,
2633 "found \\endif without matching start command");
2637 delete guards.pop();
2639 enabledSectionFound=FALSE;
2640 if (!g_spaceBeforeCmd.isEmpty())
2642 addOutput(g_spaceBeforeCmd);
2643 g_spaceBeforeCmd.resize(0);
2645 BEGIN( GuardParamEnd );
2649 static bool handleIngroup(const QCString &)
2651 inGroupParamFound=FALSE;
2652 BEGIN( InGroupParam );
2656 static bool handleNoSubGrouping(const QCString &)
2658 current->subGrouping = FALSE;
2662 static bool handleShowInitializer(const QCString &)
2664 current->initLines = 100000; // ON
2668 static bool handleHideInitializer(const QCString &)
2670 current->initLines = 0; // OFF
2674 static bool handleCallgraph(const QCString &)
2676 current->callGraph = TRUE; // ON
2680 static bool handleCallergraph(const QCString &)
2682 current->callerGraph = TRUE; // ON
2686 static bool handleInternal(const QCString &)
2688 if (!Config_getBool("INTERNAL_DOCS"))
2690 // make sure some whitespace before a \internal command
2691 // is not treated as "documentation"
2692 if (current->doc.stripWhiteSpace().isEmpty())
2694 current->doc.resize(0);
2697 BEGIN( SkipInternal );
2701 // re-enabled for bug640828
2702 addOutput("\\internal ");
2703 inInternalDocs = TRUE;
2708 static bool handleLineBr(const QCString &)
2714 static bool handleStatic(const QCString &)
2717 current->stat = TRUE;
2721 static bool handlePure(const QCString &)
2724 current->virt = Pure;
2728 static bool handlePrivate(const QCString &)
2730 current->protection = Private;
2734 static bool handlePrivateSection(const QCString &)
2736 current->protection = protection = Private;
2740 static bool handleProtected(const QCString &)
2742 current->protection = Protected;
2746 static bool handleProtectedSection(const QCString &)
2748 current->protection = protection = Protected ;
2752 static bool handlePublic(const QCString &)
2754 current->protection = Public;
2758 static bool handlePublicSection(const QCString &)
2760 current->protection = protection = Public;
2764 static bool handleToc(const QCString &)
2766 if (current->section==Entry::PAGEDOC_SEC ||
2767 current->section==Entry::MAINPAGEDOC_SEC)
2769 current->stat=TRUE; // we 'abuse' stat to pass whether or the TOC is enabled
2774 static bool handleInherit(const QCString &)
2776 BEGIN(InheritParam);
2780 static bool handleExtends(const QCString &)
2782 BEGIN(ExtendsParam);
2786 static bool handleCopyBrief(const QCString &)
2788 if (current->brief.isEmpty() && current->doc.isEmpty())
2789 { // if we don't have a brief or detailed description yet,
2790 // then the @copybrief should end up in the brief description.
2791 // otherwise it will be copied inline (see bug691315 & bug700788)
2792 setOutput(OutputBrief);
2794 if (!g_spaceBeforeCmd.isEmpty())
2796 addOutput(g_spaceBeforeCmd);
2797 g_spaceBeforeCmd.resize(0);
2799 addOutput("\\copybrief ");
2803 static bool handleCopyDetails(const QCString &)
2805 setOutput(OutputDoc);
2806 if (!g_spaceBeforeCmd.isEmpty())
2808 addOutput(g_spaceBeforeCmd);
2809 g_spaceBeforeCmd.resize(0);
2811 addOutput("\\copydetails ");
2815 static bool handleCopyDoc(const QCString &)
2817 setOutput(OutputBrief);
2818 if (!g_spaceBeforeCmd.isEmpty())
2820 addOutput(g_spaceBeforeCmd);
2821 g_spaceBeforeCmd.resize(0);
2823 addOutput("\\copybrief ");
2824 g_copyDocArg.resize(0);
2829 //----------------------------------------------------------------------------
2831 static void checkFormula()
2833 if (YY_START==ReadFormulaShort || YY_START==ReadFormulaLong)
2835 warn(yyFileName,yyLineNr,"End of comment block while inside formula.");
2839 //----------------------------------------------------------------------------
2841 bool parseCommentBlock(/* in */ ParserInterface *parser,
2842 /* in */ Entry *curEntry,
2843 /* in */ const QCString &comment,
2844 /* in */ const QCString &fileName,
2845 /* in,out */ int &lineNr,
2846 /* in */ bool isBrief,
2847 /* in */ bool isAutoBriefOn,
2848 /* in */ bool isInbody,
2849 /* in,out */ Protection &prot,
2850 /* in,out */ int &position,
2851 /* out */ bool &newEntryNeeded
2854 //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n",
2855 // isBrief,isAutoBriefOn,lineNr);
2858 guards.setAutoDelete(TRUE);
2860 langParser = parser;
2862 if (comment.isEmpty()) return FALSE; // avoid empty strings
2863 inputString = comment;
2864 inputString.append(" ");
2865 inputPosition = position;
2867 yyFileName = fileName;
2869 needNewEntry = FALSE;
2870 xrefKind = XRef_None;
2871 xrefAppendFlag = FALSE;
2875 outputXRef.resize(0);
2876 setOutput( isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
2877 briefEndsAtDot = isAutoBriefOn;
2880 g_spaceBeforeCmd.resize(0);
2881 g_spaceBeforeIf.resize(0);
2883 printlex(yy_flex_debug, TRUE, __FILE__, fileName ? fileName.data(): NULL);
2884 if (!current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments
2886 current->inbodyDocs+="\n\n";
2889 Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n"
2890 "input=[\n%s]\n",fileName.data(),lineNr,comment.data()
2893 commentscanYYrestart( commentscanYYin );
2896 setOutput( OutputDoc );
2898 if (YY_START==OverloadParam) // comment ended with \overload
2900 addOutput(getOverloadDocs());
2903 if (!guards.isEmpty())
2905 warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
2908 if (g_insideParBlock)
2910 warn(yyFileName,yyLineNr,
2911 "Documentation block ended while inside a \\parblock. Missing \\endparblock");
2914 current->doc=stripLeadingAndTrailingEmptyLines(current->doc,current->docLine);
2916 if (current->section==Entry::FILEDOC_SEC && current->doc.isEmpty())
2918 // to allow a comment block with just a @file command.
2919 current->doc="\n\n";
2922 if (current->section==Entry::MEMBERGRP_SEC &&
2923 g_memberGroupId==DOX_NOGROUP) // @name section but no group started yet
2925 openGroup(current,yyFileName,yyLineNr);
2928 if (Doxygen::markdownSupport)
2930 current->brief = processMarkdown(fileName,lineNr,current,current->brief);
2931 current->doc = processMarkdown(fileName,lineNr,current,current->doc);
2932 current->inbodyDocs = processMarkdown(fileName,lineNr,current,current->inbodyDocs);
2935 Debug::print(Debug::CommentScan,0,
2936 "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n===========\n",
2937 current->briefLine,current->brief.data(),
2938 current->docLine,current->doc.data(),
2939 current->inbodyLine,current->inbodyDocs.data()
2945 groupAddDocs(curEntry,fileName);
2947 newEntryNeeded = needNewEntry;
2949 // if we did not proceed during this call, it does not make
2950 // sense to continue, since we get stuck. See bug 567346 for situations
2951 // were this happens
2952 if (parseMore && position==inputPosition) parseMore=FALSE;
2954 if (parseMore) position=inputPosition; else position=0;
2957 //printf("position=%d parseMore=%d newEntryNeeded=%d\n",
2958 // position,parseMore,newEntryNeeded);
2960 printlex(yy_flex_debug, FALSE, __FILE__, fileName ? fileName.data(): NULL);
2964 //---------------------------------------------------------------------------
2966 void groupEnterFile(const char *fileName,int)
2968 g_autoGroupStack.setAutoDelete(TRUE);
2969 g_autoGroupStack.clear();
2970 g_memberGroupId = DOX_NOGROUP;
2971 g_memberGroupDocs.resize(0);
2972 g_memberGroupRelates.resize(0);
2973 g_compoundName=fileName;
2976 void groupLeaveFile(const char *fileName,int line)
2978 //if (g_memberGroupId!=DOX_NOGROUP)
2980 // warn(fileName,line,"end of file while inside a member group\n");
2982 g_memberGroupId=DOX_NOGROUP;
2983 g_memberGroupRelates.resize(0);
2984 g_memberGroupDocs.resize(0);
2985 if (!g_autoGroupStack.isEmpty())
2987 warn(fileName,line,"end of file while inside a group\n");
2991 void groupEnterCompound(const char *fileName,int line,const char *name)
2993 if (g_memberGroupId!=DOX_NOGROUP)
2995 warn(fileName,line,"try to put compound %s inside a member group\n",name);
2997 g_memberGroupId=DOX_NOGROUP;
2998 g_memberGroupRelates.resize(0);
2999 g_memberGroupDocs.resize(0);
3000 g_compoundName = name;
3001 int i = g_compoundName.find('(');
3004 g_compoundName=g_compoundName.left(i); // strip category (Obj-C)
3006 if (g_compoundName.isEmpty())
3008 g_compoundName=fileName;
3010 //printf("groupEnterCompound(%s)\n",name);
3013 void groupLeaveCompound(const char *,int,const char * /*name*/)
3015 //printf("groupLeaveCompound(%s)\n",name);
3016 //if (g_memberGroupId!=DOX_NOGROUP)
3018 // warn(fileName,line,"end of compound %s while inside a member group\n",name);
3020 g_memberGroupId=DOX_NOGROUP;
3021 g_memberGroupRelates.resize(0);
3022 g_memberGroupDocs.resize(0);
3023 g_compoundName.resize(0);
3026 static int findExistingGroup(int &groupId,const MemberGroupInfo *info)
3028 //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data());
3029 QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict);
3030 MemberGroupInfo *mi;
3031 for (di.toFirst();(mi=di.current());++di)
3033 if (g_compoundName==mi->compoundName && // same file or scope
3034 !mi->header.isEmpty() && // not a nameless group
3035 qstricmp(mi->header,info->header)==0 // same header name
3038 //printf("Found it!\n");
3039 return (int)di.currentKey(); // put the item in this group
3042 groupId++; // start new group
3046 void openGroup(Entry *e,const char *,int)
3048 //printf("==> openGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
3049 // e->name.data(),e->section,g_autoGroupStack.count());
3050 if (e->section==Entry::GROUPDOC_SEC) // auto group
3052 g_autoGroupStack.push(new Grouping(e->name,e->groupingPri()));
3054 else // start of a member group
3056 //printf(" membergroup id=%d %s\n",g_memberGroupId,g_memberGroupHeader.data());
3057 if (g_memberGroupId==DOX_NOGROUP) // no group started yet
3059 static int curGroupId=0;
3061 MemberGroupInfo *info = new MemberGroupInfo;
3062 info->header = g_memberGroupHeader.stripWhiteSpace();
3063 info->compoundName = g_compoundName;
3064 g_memberGroupId = findExistingGroup(curGroupId,info);
3065 //printf(" use membergroup %d\n",g_memberGroupId);
3066 Doxygen::memGrpInfoDict.insert(g_memberGroupId,info);
3068 g_memberGroupRelates = e->relates;
3069 e->mGrpId = g_memberGroupId;
3074 void closeGroup(Entry *e,const char *fileName,int,bool foundInline)
3076 //printf("==> closeGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
3077 // e->name.data(),e->section,g_autoGroupStack.count());
3078 if (g_memberGroupId!=DOX_NOGROUP) // end of member group
3080 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
3081 if (info) // known group
3083 info->doc = g_memberGroupDocs;
3084 info->docFile = fileName;
3086 g_memberGroupId=DOX_NOGROUP;
3087 g_memberGroupRelates.resize(0);
3088 g_memberGroupDocs.resize(0);
3089 e->mGrpId=DOX_NOGROUP;
3090 //printf("new group id=%d\n",g_memberGroupId);
3092 else if (!g_autoGroupStack.isEmpty()) // end of auto group
3094 Grouping *grp = g_autoGroupStack.pop();
3095 // see bug577005: we should not remove the last group for e
3096 if (!foundInline) e->groups->removeLast();
3097 //printf("Removing %s e=%p\n",grp->groupname.data(),e);
3099 if (!foundInline) initGroupInfo(e);
3103 void initGroupInfo(Entry *e)
3105 //printf("==> initGroup(id=%d,related=%s,e=%p)\n",g_memberGroupId,
3106 // g_memberGroupRelates.data(),e);
3107 e->mGrpId = g_memberGroupId;
3108 e->relates = g_memberGroupRelates;
3109 if (!g_autoGroupStack.isEmpty())
3111 //printf("Appending group %s to %s: count=%d entry=%p\n",
3112 // g_autoGroupStack.top()->groupname.data(),
3113 // e->name.data(),e->groups->count(),e);
3114 e->groups->append(new Grouping(*g_autoGroupStack.top()));
3118 static void groupAddDocs(Entry *e,const char *fileName)
3120 if (e->section==Entry::MEMBERGRP_SEC)
3122 g_memberGroupDocs=e->brief.stripWhiteSpace();
3123 e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine);
3124 if (!g_memberGroupDocs.isEmpty() && !e->doc.isEmpty())
3126 g_memberGroupDocs+="\n\n";
3128 g_memberGroupDocs+=e->doc;
3129 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
3132 info->doc = g_memberGroupDocs;
3133 info->docFile = fileName;
3134 info->setRefItems(e->sli);
3141 static void handleGuard(const QCString &expr)
3144 bool sectionEnabled=prs.parse(yyFileName,yyLineNr,expr.stripWhiteSpace());
3145 bool parentEnabled = TRUE;
3146 if (!guards.isEmpty()) parentEnabled = guards.top()->isEnabled();
3150 (sectionEnabled && guardType==Guard_If) ||
3151 (!sectionEnabled && guardType==Guard_IfNot)
3152 ) // section is visible
3154 guards.push(new GuardedSection(TRUE,TRUE));
3155 enabledSectionFound=TRUE;
3156 BEGIN( GuardParamEnd );
3158 else // section is invisible
3160 if (guardType!=Guard_Skip)
3162 guards.push(new GuardedSection(FALSE,TRUE));
3164 BEGIN( SkipGuardedSection );
3167 else // invisible because of parent
3169 guards.push(new GuardedSection(FALSE,FALSE));
3170 BEGIN( SkipGuardedSection );
3176 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3177 //----------------------------------------------------------------------------
3178 extern "C" { // some bogus code to keep the compiler happy
3179 void commentscanYYdummy() { yy_flex_realloc(0,0); }