1 /*****************************************************************************
3 * Copyright (C) 1997-2015 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.
16 %option never-interactive
17 %option prefix="commentscanYY"
43 #include "outputlist.h"
44 #include "membergroup.h"
47 #include "parserintf.h"
50 #include "condparser.h"
54 #define YY_NO_UNISTD_H 1
56 // forward declarations
57 static bool handleBrief(const QCString &);
58 static bool handleFn(const QCString &);
59 static bool handleDef(const QCString &);
60 static bool handleOverload(const QCString &);
61 static bool handleEnum(const QCString &);
62 static bool handleDefGroup(const QCString &);
63 static bool handleAddToGroup(const QCString &);
64 static bool handleWeakGroup(const QCString &);
65 static bool handleNamespace(const QCString &);
66 static bool handlePackage(const QCString &);
67 static bool handleClass(const QCString &);
68 static bool handleHeaderFile(const QCString &);
69 static bool handleProtocol(const QCString &);
70 static bool handleCategory(const QCString &);
71 static bool handleUnion(const QCString &);
72 static bool handleStruct(const QCString &);
73 static bool handleInterface(const QCString &);
74 static bool handleIdlException(const QCString &);
75 static bool handlePage(const QCString &);
76 static bool handleMainpage(const QCString &);
77 static bool handleFile(const QCString &);
78 static bool handleDir(const QCString &);
79 static bool handleExample(const QCString &);
80 static bool handleDetails(const QCString &);
81 static bool handleName(const QCString &);
82 static bool handleTodo(const QCString &);
83 static bool handleTest(const QCString &);
84 static bool handleBug(const QCString &);
85 static bool handleSubpage(const QCString &s);
86 static bool handleDeprecated(const QCString &);
87 static bool handleXRefItem(const QCString &);
88 static bool handleRelated(const QCString &);
89 static bool handleRelatedAlso(const QCString &);
90 static bool handleMemberOf(const QCString &);
91 static bool handleRefItem(const QCString &);
92 static bool handleSection(const QCString &);
93 static bool handleAnchor(const QCString &);
94 static bool handleCite(const QCString &);
95 static bool handleFormatBlock(const QCString &);
96 static bool handleAddIndex(const QCString &);
97 static bool handleIf(const QCString &);
98 static bool handleIfNot(const QCString &);
99 static bool handleElseIf(const QCString &);
100 static bool handleElse(const QCString &);
101 static bool handleEndIf(const QCString &);
102 static bool handleIngroup(const QCString &);
103 static bool handleNoSubGrouping(const QCString &);
104 static bool handleShowInitializer(const QCString &);
105 static bool handleHideInitializer(const QCString &);
106 static bool handleCallgraph(const QCString &);
107 static bool handleHideCallgraph(const QCString &);
108 static bool handleCallergraph(const QCString &);
109 static bool handleHideCallergraph(const QCString &);
110 static bool handleInternal(const QCString &);
111 static bool handleLineBr(const QCString &);
112 static bool handleStatic(const QCString &);
113 static bool handlePure(const QCString &);
114 static bool handlePrivate(const QCString &);
115 static bool handlePrivateSection(const QCString &);
116 static bool handleProtected(const QCString &);
117 static bool handleProtectedSection(const QCString &);
118 static bool handlePublic(const QCString &s);
119 static bool handlePublicSection(const QCString &s);
120 static bool handleToc(const QCString &s);
121 static bool handleInherit(const QCString &);
122 static bool handleExtends(const QCString &);
123 static bool handleCopyDoc(const QCString &);
124 static bool handleCopyBrief(const QCString &);
125 static bool handleCopyDetails(const QCString &);
126 static bool handleParBlock(const QCString &);
127 static bool handleEndParBlock(const QCString &);
128 static bool handleParam(const QCString &);
129 static bool handleRetval(const QCString &);
131 typedef bool (*DocCmdFunc)(const QCString &name);
140 // map of command to handler function
141 static DocCmdMap docCmdMap[] =
143 // command name handler function ends brief description
144 { "brief", &handleBrief, FALSE },
145 { "short", &handleBrief, FALSE },
146 { "fn", &handleFn, FALSE },
147 { "var", &handleFn, FALSE },
148 { "typedef", &handleFn, FALSE },
149 { "property", &handleFn, FALSE },
150 { "def", &handleDef, FALSE },
151 { "overload", &handleOverload, FALSE },
152 { "enum", &handleEnum, FALSE },
153 { "defgroup", &handleDefGroup, FALSE },
154 { "addtogroup", &handleAddToGroup, FALSE },
155 { "weakgroup", &handleWeakGroup, FALSE },
156 { "namespace", &handleNamespace, FALSE },
157 { "package", &handlePackage, FALSE },
158 { "class", &handleClass, FALSE },
159 { "headerfile", &handleHeaderFile, FALSE },
160 { "protocol", &handleProtocol, FALSE },
161 { "category", &handleCategory, FALSE },
162 { "union", &handleUnion, FALSE },
163 { "struct", &handleStruct, FALSE },
164 { "interface", &handleInterface, FALSE },
165 { "idlexcept", &handleIdlException, FALSE },
166 { "page", &handlePage, FALSE },
167 { "mainpage", &handleMainpage, FALSE },
168 { "file", &handleFile, FALSE },
169 { "dir", &handleDir, FALSE },
170 { "example", &handleExample, FALSE },
171 { "details", &handleDetails, TRUE },
172 { "name", &handleName, FALSE },
173 { "todo", &handleTodo, FALSE }, // end brief will be done differently
174 { "test", &handleTest, FALSE }, // end brief will be done differently
175 { "bug", &handleBug, FALSE }, // end brief will be done differently
176 { "deprecated", &handleDeprecated, FALSE }, // end brief will be done differently
177 { "xrefitem", &handleXRefItem, FALSE }, // end brief will be done differently
178 { "related", &handleRelated, TRUE },
179 { "relates", &handleRelated, TRUE },
180 { "relatedalso", &handleRelatedAlso, TRUE },
181 { "relatesalso", &handleRelatedAlso, TRUE },
182 { "parblock", &handleParBlock, TRUE },
183 { "endparblock", &handleEndParBlock, TRUE },
184 { "refitem", &handleRefItem, TRUE },
185 { "cite", &handleCite, FALSE },
186 { "subpage", &handleSubpage, TRUE },
187 { "section", &handleSection, TRUE },
188 { "subsection", &handleSection, TRUE },
189 { "subsubsection", &handleSection, TRUE },
190 { "paragraph", &handleSection, TRUE },
191 { "anchor", &handleAnchor, TRUE },
192 { "verbatim", &handleFormatBlock, TRUE },
193 { "latexonly", &handleFormatBlock, FALSE },
194 { "htmlonly", &handleFormatBlock, FALSE },
195 { "xmlonly", &handleFormatBlock, FALSE },
196 { "docbookonly", &handleFormatBlock, FALSE },
197 { "rtfonly", &handleFormatBlock, FALSE },
198 { "manonly", &handleFormatBlock, FALSE },
199 { "dot", &handleFormatBlock, TRUE },
200 { "msc", &handleFormatBlock, TRUE },
201 { "startuml", &handleFormatBlock, TRUE },
202 { "code", &handleFormatBlock, TRUE },
203 { "addindex", &handleAddIndex, FALSE },
204 { "if", &handleIf, FALSE },
205 { "ifnot", &handleIfNot, FALSE },
206 { "elseif", &handleElseIf, FALSE },
207 { "else", &handleElse, FALSE },
208 { "endif", &handleEndIf, FALSE },
209 { "ingroup", &handleIngroup, FALSE },
210 { "nosubgrouping", &handleNoSubGrouping, FALSE },
211 { "showinitializer", &handleShowInitializer, FALSE },
212 { "hideinitializer", &handleHideInitializer, FALSE },
213 { "callgraph", &handleCallgraph, FALSE },
214 { "hidecallgraph", &handleHideCallgraph, FALSE },
215 { "callergraph", &handleCallergraph, FALSE },
216 { "hidecallergraph", &handleHideCallergraph, FALSE },
217 { "internal", &handleInternal, TRUE },
218 { "_linebr", &handleLineBr, FALSE },
219 { "static", &handleStatic, FALSE },
220 { "pure", &handlePure, FALSE },
221 { "private", &handlePrivate, FALSE },
222 { "privatesection", &handlePrivateSection, FALSE },
223 { "protected", &handleProtected, FALSE },
224 { "protectedsection",&handleProtectedSection, FALSE },
225 { "public", &handlePublic, FALSE },
226 { "publicsection", &handlePublicSection, FALSE },
227 { "tableofcontents", &handleToc, FALSE },
228 { "inherit", &handleInherit, TRUE },
229 { "extends", &handleExtends, TRUE },
230 { "implements", &handleExtends, TRUE },
231 { "memberof", &handleMemberOf, TRUE },
233 { "attention", 0, TRUE },
234 { "author", 0, TRUE },
235 { "authors", 0, TRUE },
236 { "copydoc", &handleCopyDoc, TRUE },
237 { "copybrief", &handleCopyBrief, FALSE },
238 { "copydetails", &handleCopyDetails, TRUE },
239 { "copyright", 0, TRUE },
241 { "dotfile", 0, TRUE },
242 { "htmlinclude", 0, FALSE },
243 { "image", 0, TRUE },
244 { "include", 0, TRUE },
245 { "includelineno", 0, TRUE },
246 { "invariant", 0, TRUE },
247 { "latexinclude", 0, FALSE },
252 { "param", &handleParam, TRUE },
253 { "tparam", 0, TRUE },
256 { "remark", 0, TRUE },
257 { "remarks", 0, TRUE },
258 { "result", 0, TRUE },
259 { "return", 0, TRUE },
260 { "returns", 0, TRUE },
261 { "exception", 0, TRUE },
262 { "retval", &handleRetval, TRUE },
265 { "since", 0, TRUE },
266 { "throw", 0, TRUE },
267 { "throws", 0, TRUE },
268 { "until", 0, TRUE },
269 { "verbinclude", 0, FALSE },
270 { "version", 0, TRUE },
271 { "warning", 0, TRUE },
275 /** @brief Command mapper.
277 * Maps a command name (as found in a comment block) onto a
278 * specific handler function.
289 /** maps a command name to a handler function */
290 static Cmd *map(const char *name)
292 return instance()->find(name);
295 /** release the singleton */
296 static void freeInstance()
298 delete s_instance; s_instance=0;
302 static DocCmdMapper *instance()
304 if (s_instance==0) s_instance = new DocCmdMapper;
308 DocCmdMapper() : m_map(113)
310 m_map.setAutoDelete(TRUE);
311 DocCmdMap *p = docCmdMap;
314 if (m_map.find(p->cmdName)!=0)
316 err("DocCmdMapper: command %s already added\n",p->cmdName);
320 cmd->func = p->handler;
321 cmd->endsBrief = p->endsBrief;
322 m_map.insert(p->cmdName,cmd);
327 Cmd *find(const char *name)
329 return m_map.find(name);
332 static DocCmdMapper *s_instance;
335 DocCmdMapper *DocCmdMapper::s_instance=0;
337 bool inInternalDocs = FALSE;
339 #define YY_NEVER_INTERACTIVE 1
369 GuardedSection(bool enabled,bool parentVisible)
370 : m_enabled(enabled),m_parentVisible(parentVisible) {}
371 bool isEnabled() const { return m_enabled; }
372 bool parentVisible() const { return m_parentVisible; }
376 bool m_parentVisible;
379 void openGroup(Entry *e,const char *file,int line);
380 void closeGroup(Entry *e,const char *file,int line,bool foundInline=FALSE);
381 void initGroupInfo(Entry *e);
382 static void groupAddDocs(Entry *e);
384 /* -----------------------------------------------------------------
389 static ParserInterface *langParser; // the language parser that is calling us
390 static QCString inputString; // input string
391 static int inputPosition; // read pointer
392 static QCString yyFileName; // file name that is read from
393 static int yyLineNr; // line number in the input
394 static bool inBody; // was the comment found inside the body of a function?
395 static OutputContext inContext; // are we inside the brief, details or xref part
396 static bool briefEndsAtDot; // does the brief description stop at a dot?
397 static QCString formulaText; // Running text of a formula
398 static QCString formulaEnv; // environment name
399 static int formulaNewLines; // amount of new lines in the formula
400 static QCString *pOutputString; // pointer to string to which the output is appended.
401 static QCString outputXRef; // temp argument of todo/test/../xrefitem commands
402 static QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...)
403 static XRefKind xrefKind; // kind of cross-reference command
404 static XRefKind newXRefKind; //
405 static GuardType guardType; // kind of guard for conditional section
406 static bool enabledSectionFound;
407 static QCString functionProto; // function prototype
408 static QStack<GuardedSection> guards; // tracks nested conditional sections (if,ifnot,..)
409 static Entry* current = 0 ; // working entry
410 //static Entry* current_root = 0 ; // parent of working entry
413 //static Entry* previous = 0 ; // TODO: remove need for this
414 static bool needNewEntry;
416 static QCString g_sectionLabel;
417 static QCString g_sectionTitle;
418 static int g_sectionLevel;
419 static QCString xrefItemKey;
420 static QCString newXRefItemKey;
421 static QCString xrefItemTitle;
422 static QCString xrefListTitle;
423 static Protection protection;
425 static bool xrefAppendFlag;
426 static bool inGroupParamFound;
427 static int braceCount;
428 static bool insidePre;
429 static bool parseMore;
430 static int g_condCount;
432 static int g_commentCount;
433 static QCString g_spaceBeforeCmd;
434 static QCString g_spaceBeforeIf;
435 static QCString g_copyDocArg;
437 static QCString g_guardExpr;
438 static int g_roundCount;
440 static bool g_insideParBlock;
442 //-----------------------------------------------------------------------------
444 static QStack<Grouping> g_autoGroupStack;
445 static int g_memberGroupId = DOX_NOGROUP;
446 static QCString g_memberGroupHeader;
447 static QCString g_memberGroupDocs;
448 static QCString g_memberGroupRelates;
449 static QCString g_compoundName;
451 //-----------------------------------------------------------------------------
453 static void initParser()
455 g_sectionLabel.resize(0);
456 g_sectionTitle.resize(0);
457 g_memberGroupHeader.resize(0);
458 g_insideParBlock = FALSE;
461 //-----------------------------------------------------------------------------
463 static bool getDocSectionName(int s)
467 case Entry::CLASSDOC_SEC:
468 case Entry::STRUCTDOC_SEC:
469 case Entry::UNIONDOC_SEC:
470 case Entry::EXCEPTIONDOC_SEC:
471 case Entry::NAMESPACEDOC_SEC:
472 case Entry::PROTOCOLDOC_SEC:
473 case Entry::CATEGORYDOC_SEC:
474 case Entry::ENUMDOC_SEC:
475 case Entry::PAGEDOC_SEC:
476 case Entry::VARIABLEDOC_SEC:
477 case Entry::MEMBERDOC_SEC:
478 case Entry::OVERLOADDOC_SEC:
479 case Entry::FILEDOC_SEC:
480 case Entry::DEFINEDOC_SEC:
481 case Entry::GROUPDOC_SEC:
482 case Entry::MAINPAGEDOC_SEC:
483 case Entry::PACKAGEDOC_SEC:
484 case Entry::DIRDOC_SEC:
485 case Entry::EXAMPLE_SEC:
486 case Entry::MEMBERGRP_SEC:
493 //-----------------------------------------------------------------------------
495 static bool makeStructuralIndicator(Entry::Sections s)
497 //printf("current->section=%x\n",current->section);
498 if (getDocSectionName(current->section))
505 current->section = s;
506 current->fileName = yyFileName;
507 current->startLine = yyLineNr;
512 static void lineCount()
514 for( const char* c = yytext ; *c ; ++c )
515 yyLineNr += (*c == '\n') ;
519 static QCString stripQuotes(const char *s)
522 if (s==0 || *s==0) return name;
524 if (name.at(0)=='"' && name.at(name.length()-1)=='"')
526 name=name.mid(1,name.length()-2);
531 //-----------------------------------------------------------------
533 static void addXRefItem(const char *listName,const char *itemTitle,
534 const char *listTitle,bool append)
536 Entry *docEntry = current; // inBody && previous ? previous : current;
537 if (listName==0) return;
538 //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append);
541 RefList *refList = Doxygen::xrefLists->find(listName);
542 if (refList==0) // new list
544 refList = new RefList(listName,listTitle,itemTitle);
545 Doxygen::xrefLists->insert(listName,refList);
546 //printf("new list!\n");
550 QListIterator<ListItemInfo> slii(*docEntry->sli);
551 for (slii.toFirst();(lii=slii.current());++slii)
553 if (qstrcmp(lii->type,listName)==0)
555 //printf("found %s lii->type=%s\n",listName,lii->type);
560 if (lii && append) // already found item of same type just before this one
562 //printf("listName=%s item id = %d existing\n",listName,lii->itemId);
563 RefItem *item = refList->getRefItem(lii->itemId);
565 item->text += " <p>";
566 if (Doxygen::markdownSupport)
568 item->text += processMarkdown(yyFileName,yyLineNr,current,outputXRef);
572 item->text += outputXRef;
574 //printf("%s: text +=%s\n",listName,item->text.data());
578 int itemId = refList->addRefItem();
579 //printf("listName=%s item id = %d new current=%p\n",listName,itemId,current);
581 // if we have already an item from the same list type (e.g. a second @todo)
582 // in the same Entry (i.e. lii!=0) then we reuse its link anchor.
583 char anchorLabel[1024];
584 //sprintf(anchorLabel,"_%s%06d",listName,lii ? lii->itemId : itemId);
585 sprintf(anchorLabel,"_%s%06d",listName,itemId);
586 RefItem *item = refList->getRefItem(itemId);
588 if (Doxygen::markdownSupport)
590 item->text = processMarkdown(yyFileName,yyLineNr,current,outputXRef);
594 item->text = outputXRef;
596 item->listAnchor = anchorLabel;
597 docEntry->addSpecialListItem(listName,itemId);
599 cmdString.sprintf("\\xrefitem %s %d.",listName,itemId);
602 docEntry->inbodyDocs += cmdString;
606 docEntry->doc += cmdString;
608 SectionInfo *si = Doxygen::sectionDict->find(anchorLabel);
611 if (si->lineNr != -1)
613 warn(listName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel,si->fileName.data(),si->lineNr);
617 warn(listName,yyLineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel,si->fileName.data());
622 si=new SectionInfo(listName,yyLineNr,anchorLabel,
623 g_sectionTitle,SectionInfo::Anchor,
625 Doxygen::sectionDict->append(anchorLabel,si);
626 docEntry->anchors->append(si);
629 outputXRef.resize(0);
632 //-----------------------------------------------------------------------------
634 // Adds a formula text to the list/dictionary of formulas if it was
635 // not already added. Returns the label of the formula.
636 static QCString addFormula()
639 QCString fText=formulaText.simplifyWhiteSpace();
641 if ((f=Doxygen::formulaDict->find(fText))==0)
643 f = new Formula(fText);
644 Doxygen::formulaList->append(f);
645 Doxygen::formulaDict->insert(fText,f);
646 formLabel.sprintf("\\form#%d",f->getId());
647 Doxygen::formulaNameDict->insert(formLabel,f);
651 formLabel.sprintf("\\form#%d",f->getId());
654 for (i=0;i<formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to
656 // correctly aligned.
660 //-----------------------------------------------------------------------------
662 static void checkFormula();
663 //-----------------------------------------------------------------------------
665 static SectionInfo::SectionType sectionLevelToType(int level)
667 if (level>=0 && level<5) return (SectionInfo::SectionType)level;
668 return SectionInfo::Anchor;
671 static void addSection()
673 SectionInfo *si = Doxygen::sectionDict->find(g_sectionLabel);
676 if (si->lineNr != -1)
678 warn(yyFileName,yyLineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s, line %d)",g_sectionLabel.data(),si->fileName.data(),si->lineNr);
682 warn(yyFileName,yyLineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s)",g_sectionLabel.data(),si->fileName.data());
687 // create a new section element
688 g_sectionTitle+=yytext;
689 g_sectionTitle=g_sectionTitle.stripWhiteSpace();
690 si = new SectionInfo(yyFileName,yyLineNr,g_sectionLabel,
691 g_sectionTitle,sectionLevelToType(g_sectionLevel),g_sectionLevel);
693 // add section to this entry
694 current->anchors->append(si);
696 // add section to the global dictionary
697 Doxygen::sectionDict->append(g_sectionLabel,si);
701 //-----------------------------------------------------------------------------
703 static void addCite()
705 Doxygen::citeDict->insert(yytext);
708 //-----------------------------------------------------------------------------
710 // strip trailing whitespace (excluding newlines) from string s
711 static void stripTrailingWhiteSpace(QCString &s)
713 uint len = s.length();
716 while (i>=0 && ((c = s.at(i))==' ' || c=='\t' || c=='\r')) i--;
719 s.resize(i+2); // string up to and including char at pos i and \0 terminator
723 // selects the output to write to
724 static inline void setOutput(OutputContext ctx)
726 bool xrefAppendToPrev = xrefAppendFlag;
727 // determine append flag for the next item (i.e. the end of this item)
728 xrefAppendFlag = !inBody &&
729 inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items
730 newXRefKind==xrefKind && // of the same kind
731 (xrefKind!=XRef_Item ||
732 newXRefItemKey==xrefItemKey); // with the same key if \xrefitem
733 //printf("%d && %d && %d && (%d || %d)\n",
734 // inContext==OutputXRef,
736 // newXRefKind==xrefKind,
737 // xrefKind!=XRef_Item,
738 // newXRefItemKey==xrefItemKey);
740 //printf("refKind=%d newXRefKind=%d xrefAppendToPrev=%d xrefAppendFlag=%d\n",
741 // xrefKind,newXRefKind,xrefAppendToPrev,xrefAppendFlag);
743 //printf("setOutput(inContext=%d ctx=%d)\n",inContext,ctx);
744 if (inContext==OutputXRef) // end of XRef section => add the item
746 // See if we can append this new xref item to the previous one.
747 // We know this at the start of the next item of the same
748 // type and need to remember this until the end of that item.
753 theTranslator->trTodo(),
754 theTranslator->trTodoList(),
760 theTranslator->trTest(),
761 theTranslator->trTestList(),
767 theTranslator->trBug(),
768 theTranslator->trBugList(),
772 case XRef_Deprecated:
773 addXRefItem("deprecated",
774 theTranslator->trDeprecated(),
775 theTranslator->trDeprecatedList(),
779 case XRef_Item: // user defined list
780 addXRefItem(xrefItemKey,
791 xrefItemKey = newXRefItemKey;
793 int oldContext = inContext;
795 if (inContext!=OutputXRef && inBody) inContext=OutputInbody;
799 if (oldContext!=inContext)
801 stripTrailingWhiteSpace(current->doc);
802 if (current->docFile.isEmpty())
804 current->docFile = yyFileName;
805 current->docLine = yyLineNr;
808 pOutputString = ¤t->doc;
811 if (oldContext!=inContext)
813 if (current->briefFile.isEmpty())
815 current->briefFile = yyFileName;
816 current->briefLine = yyLineNr;
819 if (current->brief.stripWhiteSpace().isEmpty()) // we only want one brief
820 // description even if multiple
823 pOutputString = ¤t->brief;
827 pOutputString = ¤t->doc;
828 inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
832 pOutputString = &outputXRef;
833 // first item found, so can't append to previous
834 //xrefAppendFlag = FALSE;
837 pOutputString = ¤t->inbodyDocs;
843 static void addAnchor(const char *anchor)
845 SectionInfo *si = Doxygen::sectionDict->find(anchor);
848 if (si->lineNr != -1)
850 warn(yyFileName,yyLineNr,"multiple use of section label '%s' while adding anchor, (first occurrence: %s, line %d)",anchor,si->fileName.data(),si->lineNr);
854 warn(yyFileName,yyLineNr,"multiple use of section label '%s' while adding anchor, (first occurrence: %s)",anchor,si->fileName.data());
859 si = new SectionInfo(yyFileName,yyLineNr,anchor,0,SectionInfo::Anchor,0);
860 Doxygen::sectionDict->append(anchor,si);
861 current->anchors->append(si);
865 // add a string to the output
866 static inline void addOutput(const char *s)
868 //printf("addOutput(%s)\n",s);
872 // add a character to the output
873 static inline void addOutput(char c)
878 static void endBrief(bool addToOutput=TRUE)
880 if (!current->brief.stripWhiteSpace().isEmpty())
881 { // only go to the detailed description if we have
882 // found some brief description and not just whitespace
883 briefEndsAtDot=FALSE;
884 setOutput(OutputDoc);
885 if (addToOutput) addOutput(yytext);
889 static void handleGuard(const QCString &expr);
890 /* ----------------------------------------------------------------- */
892 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
894 static int prevPosition=0;
896 static int yyread(char *buf,int max_size)
898 prevPosition=inputPosition;
900 while( c < max_size && inputString[inputPosition] )
902 *buf = inputString[inputPosition++] ;
903 //printf("%d (%c)\n",*buf,*buf);
911 /* start command character */
913 DCMD1 ("arg"|"attention"|"author"|"cite"|"code")
914 DCMD2 ("date"|"dot"|"msc"|"dotfile"|"example"|"startuml")
915 DCMD3 ("htmlinclude"|"htmlonly"|"image"|"include")
916 DCMD4 ("includelineno"|"internal"|"invariant")
917 DCMD5 ("latexinclude"|"latexonly"|"li"|"line"|"manonly"|"name")
918 DCMD6 ("note"|"par"|"paragraph"|"param"|"post")
919 DCMD7 ("pre"|"remarks"|(("relate"[sd])("also")?))
920 DCMD8 ("remarks"|("return"[s]?)|"retval"|"sa"|"section")
921 DCMD9 ("see"|"since"|"subsection"|"subsubsection")
922 DCMD10 ("throw"|"until"|"verbatim")
923 DCMD11 ("verbinclude"|"version"|"warning")
924 DETAILEDCMD {CMD}({DCMD1}|{DCMD2}|{DCMD3}|{DCMD4}|{DCMD5}|{DCMD6}|{DCMD7}|{DCMD8}|{DCMD9}|{DCMD10}|{DCMD11})
925 XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem")
927 TABLE [tT][aA][bB][lL][eE]
934 PARA [pP][aA][rR][aA]
935 CODE [cC][oO][dD][eE]
936 CAPTION [cC][aA][pP][tT][iI][oO][nN]
937 DETAILEDHTML {PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA}
938 DETAILEDHTMLOPT {CODE}
942 BS ^(({B}*"//")?)(({B}*"*"+)?){B}*
944 DOCNL "\n"|"\\_linebr"
947 FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+@&#]
948 FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+@&#]
949 FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"")
950 ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
951 LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
952 CITESCHAR [a-z_A-Z0-9\x80-\xFF]
953 CITEECHAR [a-z_A-Z0-9\x80-\xFF\-\+:\/]*
954 CITEID {CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*
955 SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
956 SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID})
957 TMPLSPEC "<"{BN}*[^>]+{BN}*">"
958 MAILADDR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
959 RCSTAG "$"{ID}":"[^\n$]+"$"
963 /* comment parsing states. */
990 %x SkipGuardedSection
1009 /* What can happen in while parsing a comment block:
1010 * commands (e.g. @page, or \page)
1011 * escaped commands (e.g. @@page or \\page).
1012 * formulas (e.g. \f$ \f[ \f{..)
1013 * directories (e.g. \doxygen\src\)
1014 * autolist end. (e.g. a dot on an otherwise empty line)
1016 * end of brief description due to blank line.
1017 * end of brief description due to some command (@command, or <command>).
1018 * words and whitespace and other characters (#,?!, etc).
1019 * grouping commands (e.g. @{ and @})
1020 * language switch (e.g. \~english or \~).
1021 * mail address (e.g. dimitri@stack.nl).
1022 * quoted text, such as "foo@bar"
1023 * XML commands, <summary></summary><remarks></remarks>
1026 <Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command
1029 <Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command
1032 <Comment>{MAILADDR} { // mail address
1035 <Comment>"\""[^"\n]*"\"" { // quoted text
1038 <Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!)
1041 <Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description
1042 setOutput(OutputDoc);
1043 // continue with the same input
1046 <Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description
1047 if (current->lang==SrcLangExt_CSharp)
1049 setOutput(OutputDoc);
1051 // continue with the same input
1054 <Comment>"<summary>" { // start of a .NET XML style brief description
1055 setOutput(OutputBrief);
1058 <Comment>"<remarks>" { // start of a .NET XML style detailed description
1059 setOutput(OutputDoc);
1062 <Comment>"</summary>" { // start of a .NET XML style detailed description
1064 setOutput(OutputDoc);
1066 <Comment>"</remarks>" { // end of a brief or detailed description
1069 <Comment>"<"{CAPTION}{ATTR}">" {
1070 QCString tag=yytext;
1071 int s=tag.find("id=");
1072 if (s!=-1) // command has id attribute
1075 if (c=='\'' || c=='"') // valid start
1077 int e=tag.find(c,s+4);
1078 if (e!=-1) // found matching end
1080 QCString id=tag.mid(s+4,e-s-4); // extract id
1087 <Comment>"<"{PRE}{ATTR}">" {
1091 <Comment>"</"{PRE}">" {
1095 <Comment>{RCSTAG} { // RCS tag which end a brief description
1096 setOutput(OutputDoc);
1102 <Comment>{B}*{CMD}"endinternal"{B}* {
1103 addOutput("\\endinternal ");
1104 if (!inInternalDocs)
1105 warn(yyFileName,yyLineNr,
1106 "found \\endinternal without matching \\internal"
1108 inInternalDocs = FALSE;
1110 <Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command
1111 // the {B}* in the front was added for bug620924
1112 QCString cmdName = QCString(yytext).stripWhiteSpace().data()+1;
1113 DocCmdMapper::Cmd *cmdPtr = DocCmdMapper::map(cmdName);
1114 if (cmdPtr) // special action is required
1117 while (yytext[i]==' ' || yytext[i]=='\t') i++;
1118 g_spaceBeforeCmd = QCString(yytext).left(i);
1119 if (cmdPtr->endsBrief && !(inContext==OutputXRef && cmdName=="parblock"))
1121 briefEndsAtDot=FALSE;
1122 // this command forces the end of brief description
1123 setOutput(OutputDoc);
1125 //if (i>0) addOutput(QCString(yytext).left(i)); // removed for bug 689341
1126 if (cmdPtr->func && cmdPtr->func(cmdName))
1128 // implicit split of the comment block into two
1129 // entries. Restart the next block at the start
1133 // yuk, this is probably not very portable across lex implementations,
1134 // but we need to know the position in the input buffer where this
1136 // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE
1137 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
1138 inputPosition=prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);
1140 inputPosition=prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf);
1144 else if (cmdPtr->func==0)
1146 // command without handler, to be processed
1147 // later by parsedoc.cpp
1151 else // command not relevant
1156 <Comment>{B}*("\\\\"|"@@")"f"[$\[{] { // escaped formula command
1159 <Comment>{B}*{CMD}"~"[a-z_A-Z-]* { // language switch command
1160 QCString langId = QString(yytext).stripWhiteSpace().data()+2;
1161 if (!langId.isEmpty() &&
1162 qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)!=0)
1163 { // enable language specific section
1167 <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment
1168 formulaText="\\begin";
1169 formulaEnv=QString(yytext).stripWhiteSpace().data()+2;
1170 if (formulaEnv.at(formulaEnv.length()-1)=='{')
1172 // remove trailing open brace
1173 formulaEnv=formulaEnv.left(formulaEnv.length()-1);
1175 formulaText+=formulaEnv;
1177 BEGIN(ReadFormulaLong);
1179 <Comment>{B}*{CMD}"f$" { // start of a inline formula
1182 BEGIN(ReadFormulaShort);
1184 <Comment>{B}*{CMD}"f[" { // start of a block formula
1187 BEGIN(ReadFormulaLong);
1189 <Comment>{B}*{CMD}"{" { // begin of a group
1190 //langParser->handleGroupStartCommand(g_memberGroupHeader);
1191 openGroup(current,yyFileName,yyLineNr);
1193 <Comment>{B}*{CMD}"}" { // end of a group
1194 //langParser->handleGroupEndCommand();
1195 closeGroup(current,yyFileName,yyLineNr,TRUE);
1196 g_memberGroupHeader.resize(0);
1198 needNewEntry = TRUE;
1199 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
1200 inputPosition=prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + strlen(yytext);
1202 inputPosition=prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + strlen(yytext);
1206 <Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character
1209 <Comment>[a-z_A-Z]+ { // normal word
1212 <Comment>^{B}*"."{B}*/\n { // explicit end autolist: e.g " ."
1215 <Comment>^{B}*[1-9][0-9]*"."{B}+ |
1216 <Comment>^{B}*[*+]{B}+ { // start of autolist
1217 if (!Doxygen::markdownSupport)
1223 if (inContext!=OutputXRef)
1225 briefEndsAtDot=FALSE;
1226 setOutput(OutputDoc);
1231 <Comment>^{B}*"-"{B}+ { // start of autolist
1232 if (inContext!=OutputXRef)
1234 briefEndsAtDot=FALSE;
1235 setOutput(OutputDoc);
1239 <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{B}*/\n { // horizontal line (dashed)
1242 <Comment>{CMD}"---" { // escaped mdash
1245 <Comment>{CMD}"--" { // escaped mdash
1248 <Comment>"---" { // mdash
1249 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "—");
1251 <Comment>"--" { // ndash
1252 addOutput(insidePre || Doxygen::markdownSupport ? yytext : "–");
1254 <Comment>"-#"{B}+ { // numbered item
1257 <Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis
1260 <Comment>".\\"[ \t] { // . with escaped space.
1261 addOutput(yytext[0]);
1262 addOutput(yytext[2]);
1264 <Comment>".," { // . with comma such as "e.g.,"
1267 <Comment>"...\\"[ \t] { // ellipsis with escaped space.
1270 <Comment>".."[\.]?/[^ \t\n] { // internal ellipsis
1273 <Comment>(\n|\\_linebr)({B}*(\n|\\_linebr))+ { // at least one blank line (or blank line command)
1274 if (inContext==OutputXRef)
1276 // see bug 613024, we need to put the newlines after ending the XRef section.
1277 if (!g_insideParBlock) setOutput(OutputDoc);
1281 if (yytext[i]=='\n') addOutput('\n'),i++;
1282 else if (strcmp(yytext+i,"\\_linebr")==0) addOutput('\n'),i+=8;
1286 else if (inContext!=OutputBrief)
1291 if (yytext[i]=='\n') addOutput('\n'),i++;
1292 else if (strcmp(yytext+i,"\\_linebr")==0) addOutput('\n'),i+=8;
1295 setOutput(OutputDoc);
1297 else // inContext==OutputBrief
1298 { // only go to the detailed description if we have
1299 // found some brief description and not just whitespace
1304 <Comment>"." { // potential end of a JavaDoc style comment
1308 setOutput(OutputDoc);
1309 briefEndsAtDot=FALSE;
1312 <Comment>\n { // newline
1316 <Comment>. { // catch-all for anything else
1321 /* -------------- Rules for handling HTML comments ----------- */
1323 <HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); }
1324 <HtmlComment>{DOCNL} {
1325 if (*yytext=='\n') yyLineNr++;
1327 <HtmlComment>[^\\\n\-]+ { // ignore unimportant characters
1329 <HtmlComment>. { // ignore every else
1332 /* -------------- Rules for handling formulas ---------------- */
1334 <ReadFormulaShort>{CMD}"f$" { // end of inline formula
1336 addOutput(" "+addFormula());
1339 <ReadFormulaLong>{CMD}"f]" { // end of block formula
1341 addOutput(" "+addFormula());
1344 <ReadFormulaLong>{CMD}"f}" { // end of custom env formula
1345 formulaText+="\\end";
1346 formulaText+=formulaEnv;
1347 addOutput(" "+addFormula());
1350 <ReadFormulaLong,ReadFormulaShort>[^\\@\n]+ { // any non-special character
1351 formulaText+=yytext;
1353 <ReadFormulaLong,ReadFormulaShort>\n { // new line
1355 formulaText+=*yytext;
1358 <ReadFormulaLong,ReadFormulaShort>. { // any othe character
1359 formulaText+=*yytext;
1362 /* ------------ handle argument of enum command --------------- */
1364 <EnumDocArg1>{SCOPEID} { // handle argument
1365 current->name = yytext;
1368 <EnumDocArg1>{LC} { // line continuation
1372 <EnumDocArg1>{DOCNL} { // missing argument
1373 warn(yyFileName,yyLineNr,
1374 "missing argument after \\enum."
1377 if (*yytext=='\n') yyLineNr++;
1380 <EnumDocArg1>. { // ignore other stuff
1383 /* ------------ handle argument of namespace command --------------- */
1385 <NameSpaceDocArg1>{SCOPENAME} { // handle argument
1386 current->name = substitute(yytext,".","::");
1389 <NameSpaceDocArg1>{LC} { // line continuation
1393 <NameSpaceDocArg1>{DOCNL} { // missing argument
1394 warn(yyFileName,yyLineNr,
1395 "missing argument after "
1399 if (*yytext=='\n') yyLineNr++;
1402 <NameSpaceDocArg1>. { // ignore other stuff
1405 /* ------------ handle argument of package command --------------- */
1407 <PackageDocArg1>{ID}("."{ID})* { // handle argument
1408 current->name = yytext;
1411 <PackageDocArg1>{LC} { // line continuation
1415 <PackageDocArg1>{DOCNL} { // missing argument
1416 warn(yyFileName,yyLineNr,
1417 "missing argument after "
1421 if (*yytext=='\n') yyLineNr++;
1424 <PackageDocArg1>. { // ignore other stuff
1427 /* ------ handle argument of class/struct/union command --------------- */
1429 <ClassDocArg1>{SCOPENAME}{TMPLSPEC} {
1430 current->name = substitute(removeRedundantWhiteSpace(yytext),".","::");
1431 BEGIN( ClassDocArg2 );
1433 <ClassDocArg1>{SCOPENAME} { // first argument
1434 current->name = substitute(yytext,".","::");
1435 if (current->section==Entry::PROTOCOLDOC_SEC)
1437 current->name+="-p";
1439 // prepend outer scope name
1440 BEGIN( ClassDocArg2 );
1442 <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" {
1443 current->name = substitute(yytext,".","::");
1444 BEGIN( ClassDocArg2 );
1446 <ClassDocArg1,CategoryDocArg1>{LC} { // line continuation
1450 <ClassDocArg1,CategoryDocArg1>{DOCNL} {
1451 warn(yyFileName,yyLineNr,
1452 "missing argument after "
1453 "\\%s.",YY_START==ClassDocArg1?"class":"category"
1456 if (*yytext=='\n') yyLineNr++;
1459 <ClassDocArg1,CategoryDocArg1>. { // ignore other stuff
1462 <ClassDocArg2>{FILE}|"<>" { // second argument; include file
1463 current->includeFile = yytext;
1464 BEGIN( ClassDocArg3 );
1466 <ClassDocArg2>{LC} { // line continuation
1470 <ClassDocArg2>{DOCNL} {
1472 if (*yytext=='\n') yyLineNr++;
1475 <ClassDocArg2>. { // ignore other stuff
1478 <ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name
1479 current->includeName = yytext;
1482 <ClassDocArg3>{LC} { // line continuation
1486 <ClassDocArg3>{DOCNL} {
1487 if (*yytext=='\n') yyLineNr++;
1490 <ClassDocArg3>. { // ignore other stuff
1493 /* --------- handle arguments of {def,add,weak}group commands --------- */
1495 <GroupDocArg1>{LABELID}(".html"?) { // group name
1496 current->name = yytext;
1497 //lastDefGroup.groupname = yytext;
1498 //lastDefGroup.pri = current->groupingPri();
1499 // the .html stuff is for Qt compatibility
1500 if (current->name.right(5)==".html")
1502 current->name=current->name.left(current->name.length()-5);
1504 current->type.resize(0);
1505 BEGIN(GroupDocArg2);
1507 <GroupDocArg1>"\\"{B}*"\n" { // line continuation
1511 <GroupDocArg1>{DOCNL} { // missing argument!
1512 warn(yyFileName,yyLineNr,
1513 "missing group name after %s",
1514 current->groupDocCmd()
1517 if (*yytext=='\n') yyLineNr++;
1520 <GroupDocArg2>"\\"{B}*"\n" { // line continuation
1524 <GroupDocArg2>[^\n\\\*]+ { // title (stored in type)
1525 current->type += yytext;
1526 current->type = current->type.stripWhiteSpace();
1528 <GroupDocArg2>{DOCNL} {
1529 if ( current->groupDocType==Entry::GROUPDOC_NORMAL &&
1530 current->type.isEmpty()
1531 ) // defgroup requires second argument
1533 warn(yyFileName,yyLineNr,
1534 "missing title after "
1535 "\\defgroup %s", current->name.data()
1538 if (*yytext=='\n') yyLineNr++;
1543 /* --------- handle arguments of page/mainpage command ------------------- */
1545 <PageDocArg1>{FILE} { // first argument; page name
1546 current->name = stripQuotes(yytext);
1547 BEGIN( PageDocArg2 );
1549 <PageDocArg1>{LC} { yyLineNr++;
1552 <PageDocArg1>{DOCNL} {
1553 warn(yyFileName,yyLineNr,
1554 "missing argument after "
1557 if (*yytext=='\n') yyLineNr++;
1561 <PageDocArg1>. { // ignore other stuff
1563 <PageDocArg2>.*"\n" { // second argument; page title
1565 current->args = yytext;
1570 /* --------- handle arguments of the param command ------------ */
1571 <ParamArg1>{ID}/{B}*"," {
1572 if (yytext[0]=='_' && Config_getBool(MARKDOWN_SUPPORT))
1582 if (yytext[0]=='_' && Config_getBool(MARKDOWN_SUPPORT))
1594 /* --------- handle arguments of the file/dir/example command ------------ */
1596 <FileDocArg1>{DOCNL} { // no file name specified
1597 if (*yytext=='\n') yyLineNr++;
1601 <FileDocArg1>{FILE} { // first argument; name
1602 current->name = stripQuotes(yytext);
1605 <FileDocArg1>{LC} { yyLineNr++;
1608 <FileDocArg1>. { // ignore other stuff
1611 /* --------- handle arguments of the xrefitem command ------------ */
1613 <XRefItemParam1>{LABELID} { // first argument
1614 newXRefItemKey=yytext;
1615 setOutput(OutputXRef);
1616 BEGIN(XRefItemParam2);
1618 <XRefItemParam1>{LC} { // line continuation
1622 <XRefItemParam1>{DOCNL} { // missing arguments
1623 warn(yyFileName,yyLineNr,
1624 "Missing first argument of \\xrefitem"
1626 if (*yytext=='\n') yyLineNr++;
1628 inContext = OutputDoc;
1631 <XRefItemParam1>. { // ignore other stuff
1634 <XRefItemParam2>"\""[^\n\"]*"\"" { // second argument
1635 xrefItemTitle = stripQuotes(yytext);
1636 BEGIN(XRefItemParam3);
1638 <XRefItemParam2>{LC} { // line continuation
1642 <XRefItemParam2>{DOCNL} { // missing argument
1643 warn(yyFileName,yyLineNr,
1644 "Missing second argument of \\xrefitem"
1646 if (*yytext=='\n') yyLineNr++;
1648 inContext = OutputDoc;
1651 <XRefItemParam2>. { // ignore other stuff
1654 <XRefItemParam3>"\""[^\n\"]*"\"" { // third argument
1655 xrefListTitle = stripQuotes(yytext);
1656 xrefKind = XRef_Item;
1659 <XRefItemParam2,XRefItemParam3>{LC} { // line continuation
1663 <XRefItemParam3>{DOCNL} { // missing argument
1664 warn(yyFileName,yyLineNr,
1665 "Missing third argument of \\xrefitem"
1667 if (*yytext=='\n') yyLineNr++;
1669 inContext = OutputDoc;
1672 <XRefItemParam3>. { // ignore other stuff
1676 /* ----- handle arguments of the relates(also)/memberof command ------- */
1678 <RelatesParam1>({ID}("::"|"."))*{ID} { // argument
1679 current->relates = yytext;
1680 //if (current->mGrpId!=DOX_NOGROUP)
1682 // memberGroupRelates = yytext;
1686 <RelatesParam1>{LC} { // line continuation
1690 <RelatesParam1>{DOCNL} { // missing argument
1691 warn(yyFileName,yyLineNr,
1692 "Missing argument of \\relates or \\memberof command"
1694 if (*yytext=='\n') yyLineNr++;
1698 <RelatesParam1>. { // ignore other stuff
1702 /* ----- handle arguments of the relates(also)/addindex commands ----- */
1704 <LineParam>{DOCNL} { // end of argument
1705 if (*yytext=='\n') yyLineNr++;
1709 <LineParam>{LC} { // line continuation
1713 <LineParam>. { // ignore other stuff
1717 /* ----- handle arguments of the section/subsection/.. commands ------- */
1719 <SectionLabel>{LABELID} { // first argyment
1720 g_sectionLabel=yytext;
1722 g_sectionTitle.resize(0);
1723 BEGIN(SectionTitle);
1725 <SectionLabel>{DOCNL} { // missing argument
1726 warn(yyFileName,yyLineNr,
1727 "\\section command has no label"
1729 if (*yytext=='\n') yyLineNr++;
1733 <SectionLabel>. { // invalid character for section label
1734 warn(yyFileName,yyLineNr,
1735 "Invalid or missing section label"
1739 <SectionTitle>[^\n@\\*]*/"\n" { // end of section title
1744 <SectionTitle>[^\n@\\]*/"\\_linebr" { // end of section title
1749 <SectionTitle>{LC} { // line continuation
1753 <SectionTitle>[^\n@\\]* { // any character without special meaning
1754 g_sectionTitle+=yytext;
1757 <SectionTitle>("\\\\"|"@@"){ID} { // unescape escaped command
1758 g_sectionTitle+=&yytext[1];
1761 <SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character
1762 g_sectionTitle+=yytext[1];
1765 <SectionTitle>. { // anything else
1766 g_sectionTitle+=yytext;
1770 /* ----- handle arguments of the subpage command ------- */
1772 <SubpageLabel>{LABELID} { // first argument
1774 // we add subpage labels as a kind of "inheritance" relation to prevent
1775 // needing to add another list to the Entry class.
1776 current->extends->append(new BaseInfo(yytext,Public,Normal));
1777 BEGIN(SubpageTitle);
1779 <SubpageLabel>{DOCNL} { // missing argument
1780 warn(yyFileName,yyLineNr,
1781 "\\subpage command has no label"
1783 if (*yytext=='\n') yyLineNr++;
1787 <SubpageTitle>{DOCNL} { // no title, end command
1791 <SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command
1795 <SubpageTitle>. { // no title, end of command
1800 /* ----- handle arguments of the anchor command ------- */
1802 <AnchorLabel>{LABELID} { // found argument
1807 <AnchorLabel>{DOCNL} { // missing argument
1808 warn(yyFileName,yyLineNr,
1809 "\\anchor command has no label"
1811 if (*yytext=='\n') yyLineNr++;
1815 <AnchorLabel>. { // invalid character for anchor label
1816 warn(yyFileName,yyLineNr,
1817 "Invalid or missing anchor label"
1823 /* ----- handle arguments of the preformatted block commands ------- */
1825 <FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc"|"endvhdlflow")/{NW} { // possible ends
1827 if (&yytext[4]==blockName) // found end of the block
1832 <FormatBlock>{CMD}"enduml" {
1834 if (blockName=="startuml") // found end of the block
1839 <FormatBlock>[^ \@\*\/\\\n]* { // some word
1842 <FormatBlock>{DOCNL} { // new line
1843 if (*yytext=='\n') yyLineNr++;
1846 <FormatBlock>"/*" { // start of a C-comment
1850 <FormatBlock>"*/" { // end of a C-comment
1853 if (g_commentCount<0 && blockName!="verbatim")
1855 warn(yyFileName,yyLineNr,
1856 "found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",blockName.data(),blockName.data());
1862 <FormatBlock><<EOF>> {
1863 QCString endTag = "@end"+blockName;
1864 if (blockName=="startuml") endTag="enduml";
1865 warn(yyFileName,yyLineNr,
1866 "reached end of comment while inside a @%s block; check for missing @%s tag!",
1867 blockName.data(),endTag.data()
1872 /* ----- handle arguments of if/ifnot commands ------- */
1874 <GuardParam>{B}*"(" {
1880 g_guardExpr+=yytext;
1883 g_guardExpr+=yytext;
1887 g_guardExpr+=yytext;
1889 if (g_roundCount==0)
1891 handleGuard(g_guardExpr);
1895 warn(yyFileName,yyLineNr,
1896 "invalid expression '%s' for guard",g_guardExpr.data());
1900 <GuardParam>{B}*[a-z_A-Z0-9.\-]+ { // parameter of if/ifnot guard
1901 handleGuard(yytext);
1903 <GuardParam>{DOCNL} { // end of argument
1904 if (*yytext=='\n') yyLineNr++;
1905 //next line is commented out due to bug620924
1909 <GuardParam>{LC} { // line continuation
1913 <GuardParam>. { // ignore other stuff
1916 <GuardParamEnd>{B}*{DOCNL} {
1917 g_spaceBeforeIf.resize(0);
1920 <GuardParamEnd>{B}* {
1921 if (!g_spaceBeforeIf.isEmpty()) // needed for 665313 in combation with bug620924
1923 addOutput(g_spaceBeforeIf);
1925 g_spaceBeforeIf.resize(0);
1933 /* ----- handle skipping of conditional sections ------- */
1935 <SkipGuardedSection>{CMD}"ifnot"/{NW} {
1936 guardType = Guard_IfNot;
1937 BEGIN( GuardParam );
1939 <SkipGuardedSection>{CMD}"if"/{NW} {
1940 guardType = Guard_If;
1941 BEGIN( GuardParam );
1943 <SkipGuardedSection>{CMD}"endif"/{NW} {
1944 if (guards.isEmpty())
1946 warn(yyFileName,yyLineNr,
1947 "found @endif without matching start command");
1951 GuardedSection *s = guards.pop();
1952 bool parentVisible = s->parentVisible();
1956 enabledSectionFound=TRUE;
1957 BEGIN( GuardParamEnd );
1961 <SkipGuardedSection>{CMD}"else"/{NW} {
1962 if (guards.isEmpty())
1964 warn(yyFileName,yyLineNr,
1965 "found @else without matching start command");
1969 if (!enabledSectionFound && guards.top()->parentVisible())
1971 delete guards.pop();
1972 guards.push(new GuardedSection(TRUE,TRUE));
1973 enabledSectionFound=TRUE;
1974 BEGIN( GuardParamEnd );
1978 <SkipGuardedSection>{CMD}"elseif"/{NW} {
1979 if (guards.isEmpty())
1981 warn(yyFileName,yyLineNr,
1982 "found @elseif without matching start command");
1986 if (!enabledSectionFound && guards.top()->parentVisible())
1989 delete guards.pop();
1990 BEGIN( GuardParam );
1994 <SkipGuardedSection>{DOCNL} { // skip line
1995 if (*yytext=='\n') yyLineNr++;
1998 <SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters
2000 <SkipGuardedSection>. { // any other character
2004 /* ----- handle skipping of internal section ------- */
2006 <SkipInternal>{DOCNL} { // skip line
2007 if (*yytext=='\n') yyLineNr++;
2010 <SkipInternal>[@\\]"if"/[ \t] {
2013 <SkipInternal>[@\\]"ifnot"/[ \t] {
2016 <SkipInternal>[@\\]/"endif" {
2018 if (g_condCount<0) // handle conditional section around of \internal, see bug607743
2024 <SkipInternal>[@\\]/"section"[ \t] {
2025 if (g_sectionLevel>0)
2031 <SkipInternal>[@\\]/"subsection"[ \t] {
2032 if (g_sectionLevel>1)
2038 <SkipInternal>[@\\]/"subsubsection"[ \t] {
2039 if (g_sectionLevel>2)
2045 <SkipInternal>[@\\]/"paragraph"[ \t] {
2046 if (g_sectionLevel>3)
2052 <SkipInternal>[@\\]"endinternal"[ \t]* {
2053 addOutput("\\endinternal ");
2056 <SkipInternal>[^ \\@\n]+ { // skip non-special characters
2058 <SkipInternal>. { // any other character
2062 /* ----- handle argument of name command ------- */
2064 <NameParam>{DOCNL} { // end of argument
2065 if (*yytext=='\n') yyLineNr++;
2069 <NameParam>{LC} { // line continuation
2072 g_memberGroupHeader+=' ';
2074 <NameParam>. { // ignore other stuff
2075 g_memberGroupHeader+=*yytext;
2076 current->name+=*yytext;
2079 /* ----- handle argument of ingroup command ------- */
2081 <InGroupParam>{LABELID} { // group id
2082 current->groups->append(
2083 new Grouping(yytext, Grouping::GROUPING_INGROUP)
2085 inGroupParamFound=TRUE;
2087 <InGroupParam>{DOCNL} { // missing argument
2088 if (!inGroupParamFound)
2090 warn(yyFileName,yyLineNr,
2091 "Missing group name for \\ingroup command"
2094 if (*yytext=='\n') yyLineNr++;
2098 <InGroupParam>{LC} { // line continuation
2102 <InGroupParam>. { // ignore other stuff
2106 /* ----- handle argument of fn command ------- */
2108 <FnParam>{DOCNL} { // end of argument
2111 if (*yytext=='\n') yyLineNr++;
2113 langParser->parsePrototype(functionProto);
2117 <FnParam>{LC} { // line continuation
2121 <FnParam>[^@\\\n()]+ { // non-special characters
2122 functionProto+=yytext;
2125 functionProto+=yytext;
2129 functionProto+=yytext;
2132 <FnParam>. { // add other stuff
2133 functionProto+=*yytext;
2137 /* ----- handle argument of overload command ------- */
2140 <OverloadParam>{DOCNL} { // end of argument
2141 if (*yytext=='\n') yyLineNr++;
2142 if (functionProto.stripWhiteSpace().isEmpty())
2143 { // plain overload command
2144 addOutput(getOverloadDocs());
2147 else // overload declaration
2149 makeStructuralIndicator(Entry::OVERLOADDOC_SEC);
2150 langParser->parsePrototype(functionProto);
2154 <OverloadParam>{LC} { // line continuation
2158 <OverloadParam>. { // add other stuff
2159 functionProto+=*yytext;
2162 /* ----- handle argument of inherit command ------- */
2164 <InheritParam>({ID}("::"|"."))*{ID} { // found argument
2165 current->extends->append(
2166 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2170 <InheritParam>{DOCNL} { // missing argument
2171 warn(yyFileName,yyLineNr,
2172 "\\inherit command has no argument"
2174 if (*yytext=='\n') yyLineNr++;
2178 <InheritParam>. { // invalid character for anchor label
2179 warn(yyFileName,yyLineNr,
2180 "Invalid or missing name for \\inherit command"
2185 /* ----- handle argument of extends and implements commands ------- */
2187 <ExtendsParam>({ID}("::"|"."))*{ID} { // found argument
2188 current->extends->append(
2189 new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal)
2193 <ExtendsParam>{DOCNL} { // missing argument
2194 warn(yyFileName,yyLineNr,
2195 "\\extends or \\implements command has no argument"
2197 if (*yytext=='\n') yyLineNr++;
2201 <ExtendsParam>. { // ignore other stuff
2204 /* ----- handle language specific sections ------- */
2206 <SkipLang>[\\@]"~"[a-zA-Z-]* { /* language switch */
2207 QCString langId = &yytext[2];
2208 if (langId.isEmpty() ||
2209 qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)==0)
2210 { // enable language specific section
2214 <SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
2216 <SkipLang>{DOCNL} { /* new line in verbatim block */
2217 if (*yytext=='\n') yyLineNr++;
2219 <SkipLang>. { /* any other character */
2222 /* ----- handle arguments of the cite command ------- */
2224 <CiteLabel>{CITEID} { // found argyment
2229 <CiteLabel>{DOCNL} { // missing argument
2230 warn(yyFileName,yyLineNr,
2231 "\\cite command has no label"
2233 if (*yytext=='\n') yyLineNr++;
2237 <CiteLabel>. { // invalid character for cite label
2238 warn(yyFileName,yyLineNr,
2239 "Invalid or missing cite label"
2244 /* ----- handle argument of the copydoc command ------- */
2248 if (*yytext=='\n') yyLineNr++;
2250 setOutput(OutputDoc);
2251 addOutput("\\copydetails ");
2252 addOutput(g_copyDocArg);
2257 g_copyDocArg+=yytext;
2261 g_copyDocArg+=yytext;
2268 //----------------------------------------------------------------------------
2270 static bool handleBrief(const QCString &)
2272 //printf("handleBrief\n");
2273 setOutput(OutputBrief);
2277 static bool handleFn(const QCString &)
2279 bool stop=makeStructuralIndicator(Entry::MEMBERDOC_SEC);
2280 functionProto.resize(0);
2286 static bool handleDef(const QCString &)
2288 bool stop=makeStructuralIndicator(Entry::DEFINEDOC_SEC);
2289 functionProto.resize(0);
2294 static bool handleOverload(const QCString &)
2296 functionProto.resize(0);
2297 BEGIN(OverloadParam);
2301 static bool handleEnum(const QCString &)
2303 bool stop=makeStructuralIndicator(Entry::ENUMDOC_SEC);
2308 static bool handleDefGroup(const QCString &)
2310 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2311 current->groupDocType = Entry::GROUPDOC_NORMAL;
2312 BEGIN( GroupDocArg1 );
2316 static bool handleAddToGroup(const QCString &)
2318 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2319 current->groupDocType = Entry::GROUPDOC_ADD;
2320 BEGIN( GroupDocArg1 );
2324 static bool handleWeakGroup(const QCString &)
2326 bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
2327 current->groupDocType = Entry::GROUPDOC_WEAK;
2328 BEGIN( GroupDocArg1 );
2332 static bool handleNamespace(const QCString &)
2334 bool stop=makeStructuralIndicator(Entry::NAMESPACEDOC_SEC);
2335 BEGIN( NameSpaceDocArg1 );
2339 static bool handlePackage(const QCString &)
2341 bool stop=makeStructuralIndicator(Entry::PACKAGEDOC_SEC);
2342 BEGIN( PackageDocArg1 );
2346 static bool handleClass(const QCString &)
2348 bool stop=makeStructuralIndicator(Entry::CLASSDOC_SEC);
2349 BEGIN( ClassDocArg1 );
2353 static bool handleHeaderFile(const QCString &)
2355 BEGIN( ClassDocArg2 );
2359 static bool handleProtocol(const QCString &)
2361 bool stop=makeStructuralIndicator(Entry::PROTOCOLDOC_SEC);
2362 BEGIN( ClassDocArg1 );
2366 static bool handleCategory(const QCString &)
2368 bool stop=makeStructuralIndicator(Entry::CATEGORYDOC_SEC);
2369 BEGIN( CategoryDocArg1 );
2373 static bool handleUnion(const QCString &)
2375 bool stop=makeStructuralIndicator(Entry::UNIONDOC_SEC);
2376 BEGIN( ClassDocArg1 );
2380 static bool handleStruct(const QCString &)
2382 bool stop=makeStructuralIndicator(Entry::STRUCTDOC_SEC);
2383 BEGIN( ClassDocArg1 );
2387 static bool handleInterface(const QCString &)
2389 bool stop=makeStructuralIndicator(Entry::INTERFACEDOC_SEC);
2390 BEGIN( ClassDocArg1 );
2394 static bool handleIdlException(const QCString &)
2396 bool stop=makeStructuralIndicator(Entry::EXCEPTIONDOC_SEC);
2397 BEGIN( ClassDocArg1 );
2401 static bool handlePage(const QCString &)
2403 bool stop=makeStructuralIndicator(Entry::PAGEDOC_SEC);
2404 BEGIN( PageDocArg1 );
2408 static bool handleMainpage(const QCString &)
2410 bool stop=makeStructuralIndicator(Entry::MAINPAGEDOC_SEC);
2413 current->name = "mainpage";
2415 BEGIN( PageDocArg2 );
2419 static bool handleFile(const QCString &)
2421 bool stop=makeStructuralIndicator(Entry::FILEDOC_SEC);
2424 current->name = yyFileName;
2426 BEGIN( FileDocArg1 );
2430 static bool handleParam(const QCString &)
2432 // we need process param and retval arguments to escape leading underscores in case of
2433 // markdown processing, see bug775493
2434 addOutput("@param ");
2439 static bool handleRetval(const QCString &)
2441 addOutput("@retval ");
2446 static bool handleDir(const QCString &)
2448 bool stop=makeStructuralIndicator(Entry::DIRDOC_SEC);
2449 if (!stop) current->name = yyFileName;
2450 BEGIN( FileDocArg1 );
2454 static bool handleExample(const QCString &)
2456 bool stop=makeStructuralIndicator(Entry::EXAMPLE_SEC);
2457 if (!stop) current->name = yyFileName;
2458 BEGIN( FileDocArg1 );
2462 static bool handleDetails(const QCString &)
2464 if (inContext!=OutputBrief)
2466 addOutput("\n\n"); // treat @details outside brief description
2467 // as a new paragraph
2469 setOutput(OutputDoc);
2473 static bool handleName(const QCString &)
2475 bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC);
2478 g_memberGroupHeader.resize(0);
2480 if (g_memberGroupId!=DOX_NOGROUP) // end of previous member group
2482 closeGroup(current,yyFileName,yyLineNr,TRUE);
2488 static bool handleTodo(const QCString &)
2490 newXRefKind = XRef_Todo;
2491 setOutput(OutputXRef);
2492 xrefKind = XRef_Todo;
2496 static bool handleTest(const QCString &)
2498 newXRefKind = XRef_Test;
2499 setOutput(OutputXRef);
2500 xrefKind = XRef_Test;
2504 static bool handleBug(const QCString &)
2506 newXRefKind = XRef_Bug;
2507 setOutput(OutputXRef);
2508 xrefKind = XRef_Bug;
2512 static bool handleDeprecated(const QCString &)
2514 newXRefKind = XRef_Deprecated;
2515 setOutput(OutputXRef);
2516 xrefKind = XRef_Deprecated;
2520 static bool handleXRefItem(const QCString &)
2522 newXRefKind = XRef_Item;
2523 BEGIN(XRefItemParam1);
2527 static bool handleParBlock(const QCString &)
2529 if (g_insideParBlock)
2531 warn(yyFileName,yyLineNr,
2532 "found \\parblock command while already in a parblock!");
2534 if (!g_spaceBeforeCmd.isEmpty())
2536 addOutput(g_spaceBeforeCmd);
2537 g_spaceBeforeCmd.resize(0);
2539 addOutput("@parblock ");
2540 g_insideParBlock = TRUE;
2544 static bool handleEndParBlock(const QCString &)
2546 if (!g_insideParBlock)
2548 warn(yyFileName,yyLineNr,
2549 "found \\endparblock command without matching \\parblock!");
2551 addOutput("@endparblock");
2552 setOutput(OutputDoc); // to end a parblock inside a xrefitem like context
2553 g_insideParBlock = FALSE;
2557 static bool handleRelated(const QCString &)
2559 BEGIN(RelatesParam1);
2563 static bool handleRelatedAlso(const QCString &)
2565 current->relatesType = Duplicate;
2566 BEGIN(RelatesParam1);
2570 static bool handleMemberOf(const QCString &)
2572 current->relatesType = MemberOf;
2573 BEGIN(RelatesParam1);
2577 static bool handleRefItem(const QCString &)
2579 addOutput("@refitem ");
2584 static bool handleSection(const QCString &s)
2586 setOutput(OutputDoc);
2587 addOutput("@"+s+" ");
2588 BEGIN(SectionLabel);
2589 if (s=="section") g_sectionLevel=1;
2590 else if (s=="subsection") g_sectionLevel=2;
2591 else if (s=="subsubsection") g_sectionLevel=3;
2592 else if (s=="paragraph") g_sectionLevel=4;
2596 static bool handleSubpage(const QCString &s)
2598 if (current->section!=Entry::EMPTY_SEC &&
2599 current->section!=Entry::PAGEDOC_SEC &&
2600 current->section!=Entry::MAINPAGEDOC_SEC
2603 warn(yyFileName,yyLineNr,
2604 "found \\subpage command in a comment block that is not marked as a page!");
2606 if (!g_spaceBeforeCmd.isEmpty())
2608 addOutput(g_spaceBeforeCmd);
2609 g_spaceBeforeCmd.resize(0);
2611 addOutput("@"+s+" ");
2612 BEGIN(SubpageLabel);
2616 static bool handleAnchor(const QCString &s)
2618 addOutput("@"+s+" ");
2623 static bool handleCite(const QCString &s)
2625 if (!g_spaceBeforeCmd.isEmpty())
2627 addOutput(g_spaceBeforeCmd);
2628 g_spaceBeforeCmd.resize(0);
2630 addOutput("@"+s+" ");
2635 static bool handleFormatBlock(const QCString &s)
2637 addOutput("@"+s+" ");
2638 //printf("handleFormatBlock(%s)\n",s.data());
2645 static bool handleAddIndex(const QCString &)
2647 addOutput("@addindex ");
2652 static bool handleIf(const QCString &)
2654 enabledSectionFound=FALSE;
2655 guardType = Guard_If;
2656 g_spaceBeforeIf = g_spaceBeforeCmd;
2661 static bool handleIfNot(const QCString &)
2663 enabledSectionFound=FALSE;
2664 guardType = Guard_IfNot;
2665 g_spaceBeforeIf = g_spaceBeforeCmd;
2670 static bool handleElseIf(const QCString &)
2672 if (guards.isEmpty())
2674 warn(yyFileName,yyLineNr,
2675 "found \\else without matching start command");
2679 guardType = enabledSectionFound ? Guard_Skip : Guard_If;
2685 static bool handleElse(const QCString &)
2687 if (guards.isEmpty())
2689 warn(yyFileName,yyLineNr,
2690 "found \\else without matching start command");
2694 BEGIN( SkipGuardedSection );
2699 static bool handleEndIf(const QCString &)
2701 if (guards.isEmpty())
2703 warn(yyFileName,yyLineNr,
2704 "found \\endif without matching start command");
2708 delete guards.pop();
2710 enabledSectionFound=FALSE;
2711 if (!g_spaceBeforeCmd.isEmpty())
2713 addOutput(g_spaceBeforeCmd);
2714 g_spaceBeforeCmd.resize(0);
2716 BEGIN( GuardParamEnd );
2720 static bool handleIngroup(const QCString &)
2722 inGroupParamFound=FALSE;
2723 BEGIN( InGroupParam );
2727 static bool handleNoSubGrouping(const QCString &)
2729 current->subGrouping = FALSE;
2733 static bool handleShowInitializer(const QCString &)
2735 current->initLines = 100000; // ON
2739 static bool handleHideInitializer(const QCString &)
2741 current->initLines = 0; // OFF
2745 static bool handleCallgraph(const QCString &)
2747 current->callGraph = TRUE; // ON
2751 static bool handleHideCallgraph(const QCString &)
2753 current->callGraph = FALSE; // OFF
2757 static bool handleCallergraph(const QCString &)
2759 current->callerGraph = TRUE; // ON
2763 static bool handleHideCallergraph(const QCString &)
2765 current->callerGraph = FALSE; // OFF
2769 static bool handleInternal(const QCString &)
2771 if (!Config_getBool(INTERNAL_DOCS))
2773 // make sure some whitespace before a \internal command
2774 // is not treated as "documentation"
2775 if (current->doc.stripWhiteSpace().isEmpty())
2777 current->doc.resize(0);
2780 BEGIN( SkipInternal );
2784 // re-enabled for bug640828
2785 addOutput("\\internal ");
2786 inInternalDocs = TRUE;
2791 static bool handleLineBr(const QCString &)
2797 static bool handleStatic(const QCString &)
2800 current->stat = TRUE;
2804 static bool handlePure(const QCString &)
2807 current->virt = Pure;
2811 static bool handlePrivate(const QCString &)
2813 current->protection = Private;
2817 static bool handlePrivateSection(const QCString &)
2819 current->protection = protection = Private;
2823 static bool handleProtected(const QCString &)
2825 current->protection = Protected;
2829 static bool handleProtectedSection(const QCString &)
2831 current->protection = protection = Protected ;
2835 static bool handlePublic(const QCString &)
2837 current->protection = Public;
2841 static bool handlePublicSection(const QCString &)
2843 current->protection = protection = Public;
2847 static bool handleToc(const QCString &)
2849 if (current->section==Entry::PAGEDOC_SEC ||
2850 current->section==Entry::MAINPAGEDOC_SEC)
2852 current->stat=TRUE; // we 'abuse' stat to pass whether or the TOC is enabled
2857 static bool handleInherit(const QCString &)
2859 BEGIN(InheritParam);
2863 static bool handleExtends(const QCString &)
2865 BEGIN(ExtendsParam);
2869 static bool handleCopyBrief(const QCString &)
2871 if (current->brief.isEmpty() && current->doc.isEmpty())
2872 { // if we don't have a brief or detailed description yet,
2873 // then the @copybrief should end up in the brief description.
2874 // otherwise it will be copied inline (see bug691315 & bug700788)
2875 setOutput(OutputBrief);
2877 if (!g_spaceBeforeCmd.isEmpty())
2879 addOutput(g_spaceBeforeCmd);
2880 g_spaceBeforeCmd.resize(0);
2882 addOutput("\\copybrief ");
2886 static bool handleCopyDetails(const QCString &)
2888 setOutput(OutputDoc);
2889 if (!g_spaceBeforeCmd.isEmpty())
2891 addOutput(g_spaceBeforeCmd);
2892 g_spaceBeforeCmd.resize(0);
2894 addOutput("\\copydetails ");
2898 static bool handleCopyDoc(const QCString &)
2900 setOutput(OutputBrief);
2901 if (!g_spaceBeforeCmd.isEmpty())
2903 addOutput(g_spaceBeforeCmd);
2904 g_spaceBeforeCmd.resize(0);
2906 addOutput("\\copybrief ");
2907 g_copyDocArg.resize(0);
2912 //----------------------------------------------------------------------------
2914 static void checkFormula()
2916 if (YY_START==ReadFormulaShort || YY_START==ReadFormulaLong)
2918 warn(yyFileName,yyLineNr,"End of comment block while inside formula.");
2922 //----------------------------------------------------------------------------
2924 bool parseCommentBlock(/* in */ ParserInterface *parser,
2925 /* in */ Entry *curEntry,
2926 /* in */ const QCString &comment,
2927 /* in */ const QCString &fileName,
2928 /* in,out */ int &lineNr,
2929 /* in */ bool isBrief,
2930 /* in */ bool isAutoBriefOn,
2931 /* in */ bool isInbody,
2932 /* in,out */ Protection &prot,
2933 /* in,out */ int &position,
2934 /* out */ bool &newEntryNeeded
2937 //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n",
2938 // isBrief,isAutoBriefOn,lineNr);
2941 guards.setAutoDelete(TRUE);
2943 langParser = parser;
2945 if (comment.isEmpty()) return FALSE; // avoid empty strings
2946 inputString = comment;
2947 inputString.append(" ");
2948 inputPosition = position;
2950 yyFileName = fileName;
2952 needNewEntry = FALSE;
2953 xrefKind = XRef_None;
2954 xrefAppendFlag = FALSE;
2958 outputXRef.resize(0);
2959 setOutput( isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
2960 briefEndsAtDot = isAutoBriefOn;
2963 g_spaceBeforeCmd.resize(0);
2964 g_spaceBeforeIf.resize(0);
2966 printlex(yy_flex_debug, TRUE, __FILE__, fileName ? fileName.data(): NULL);
2967 if (!current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments
2969 current->inbodyDocs+="\n\n";
2972 Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n"
2973 "input=[\n%s]\n",qPrint(fileName),lineNr,qPrint(comment)
2976 commentscanYYrestart( commentscanYYin );
2979 setOutput( OutputDoc );
2981 if (YY_START==OverloadParam) // comment ended with \overload
2983 addOutput(getOverloadDocs());
2986 if (!guards.isEmpty())
2988 warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
2991 if (g_insideParBlock)
2993 warn(yyFileName,yyLineNr,
2994 "Documentation block ended while inside a \\parblock. Missing \\endparblock");
2997 current->doc=stripLeadingAndTrailingEmptyLines(current->doc,current->docLine);
2999 if (current->section==Entry::FILEDOC_SEC && current->doc.isEmpty())
3001 // to allow a comment block with just a @file command.
3002 current->doc="\n\n";
3005 if (current->section==Entry::MEMBERGRP_SEC &&
3006 g_memberGroupId==DOX_NOGROUP) // @name section but no group started yet
3008 openGroup(current,yyFileName,yyLineNr);
3011 if (Doxygen::markdownSupport)
3013 current->brief = processMarkdown(fileName,lineNr,current,current->brief);
3014 current->doc = processMarkdown(fileName,lineNr,current,current->doc);
3015 current->inbodyDocs = processMarkdown(fileName,lineNr,current,current->inbodyDocs);
3018 Debug::print(Debug::CommentScan,0,
3019 "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n===========\n",
3020 current->briefLine,qPrint(current->brief),
3021 current->docLine,qPrint(current->doc),
3022 current->inbodyLine,qPrint(current->inbodyDocs)
3028 groupAddDocs(curEntry);
3030 newEntryNeeded = needNewEntry;
3032 // if we did not proceed during this call, it does not make
3033 // sense to continue, since we get stuck. See bug 567346 for situations
3034 // were this happens
3035 if (parseMore && position==inputPosition) parseMore=FALSE;
3037 if (parseMore) position=inputPosition; else position=0;
3040 //printf("position=%d parseMore=%d newEntryNeeded=%d\n",
3041 // position,parseMore,newEntryNeeded);
3043 printlex(yy_flex_debug, FALSE, __FILE__, fileName ? fileName.data(): NULL);
3047 //---------------------------------------------------------------------------
3049 void groupEnterFile(const char *fileName,int)
3051 g_autoGroupStack.setAutoDelete(TRUE);
3052 g_autoGroupStack.clear();
3053 g_memberGroupId = DOX_NOGROUP;
3054 g_memberGroupDocs.resize(0);
3055 g_memberGroupRelates.resize(0);
3056 g_compoundName=fileName;
3059 void groupLeaveFile(const char *fileName,int line)
3061 //if (g_memberGroupId!=DOX_NOGROUP)
3063 // warn(fileName,line,"end of file while inside a member group\n");
3065 g_memberGroupId=DOX_NOGROUP;
3066 g_memberGroupRelates.resize(0);
3067 g_memberGroupDocs.resize(0);
3068 if (!g_autoGroupStack.isEmpty())
3070 warn(fileName,line,"end of file while inside a group\n");
3074 void groupEnterCompound(const char *fileName,int line,const char *name)
3076 if (g_memberGroupId!=DOX_NOGROUP)
3078 warn(fileName,line,"try to put compound %s inside a member group\n",name);
3080 g_memberGroupId=DOX_NOGROUP;
3081 g_memberGroupRelates.resize(0);
3082 g_memberGroupDocs.resize(0);
3083 g_compoundName = name;
3084 int i = g_compoundName.find('(');
3087 g_compoundName=g_compoundName.left(i); // strip category (Obj-C)
3089 if (g_compoundName.isEmpty())
3091 g_compoundName=fileName;
3093 //printf("groupEnterCompound(%s)\n",name);
3096 void groupLeaveCompound(const char *,int,const char * /*name*/)
3098 //printf("groupLeaveCompound(%s)\n",name);
3099 //if (g_memberGroupId!=DOX_NOGROUP)
3101 // warn(fileName,line,"end of compound %s while inside a member group\n",name);
3103 g_memberGroupId=DOX_NOGROUP;
3104 g_memberGroupRelates.resize(0);
3105 g_memberGroupDocs.resize(0);
3106 g_compoundName.resize(0);
3109 static int findExistingGroup(int &groupId,const MemberGroupInfo *info)
3111 //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data());
3112 QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict);
3113 MemberGroupInfo *mi;
3114 for (di.toFirst();(mi=di.current());++di)
3116 if (g_compoundName==mi->compoundName && // same file or scope
3117 !mi->header.isEmpty() && // not a nameless group
3118 qstricmp(mi->header,info->header)==0 // same header name
3121 //printf("Found it!\n");
3122 return (int)di.currentKey(); // put the item in this group
3125 groupId++; // start new group
3129 void openGroup(Entry *e,const char *,int)
3131 //printf("==> openGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
3132 // e->name.data(),e->section,g_autoGroupStack.count());
3133 if (e->section==Entry::GROUPDOC_SEC) // auto group
3135 g_autoGroupStack.push(new Grouping(e->name,e->groupingPri()));
3137 else // start of a member group
3139 //printf(" membergroup id=%d %s\n",g_memberGroupId,g_memberGroupHeader.data());
3140 if (g_memberGroupId==DOX_NOGROUP) // no group started yet
3142 static int curGroupId=0;
3144 MemberGroupInfo *info = new MemberGroupInfo;
3145 info->header = g_memberGroupHeader.stripWhiteSpace();
3146 info->compoundName = g_compoundName;
3147 g_memberGroupId = findExistingGroup(curGroupId,info);
3148 //printf(" use membergroup %d\n",g_memberGroupId);
3149 Doxygen::memGrpInfoDict.insert(g_memberGroupId,info);
3151 g_memberGroupRelates = e->relates;
3152 e->mGrpId = g_memberGroupId;
3157 void closeGroup(Entry *e,const char *fileName,int line,bool foundInline)
3159 //printf("==> closeGroup(name=%s,sec=%x,file=%s,line=%d) g_autoGroupStack=%d\n",
3160 // e->name.data(),e->section,fileName,line,g_autoGroupStack.count());
3161 if (g_memberGroupId!=DOX_NOGROUP) // end of member group
3163 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
3164 if (info) // known group
3166 info->doc = g_memberGroupDocs;
3167 info->docFile = fileName;
3168 info->docLine = line;
3170 g_memberGroupId=DOX_NOGROUP;
3171 g_memberGroupRelates.resize(0);
3172 g_memberGroupDocs.resize(0);
3173 if (!foundInline) e->mGrpId=DOX_NOGROUP;
3174 //printf("new group id=%d\n",g_memberGroupId);
3176 else if (!g_autoGroupStack.isEmpty()) // end of auto group
3178 Grouping *grp = g_autoGroupStack.pop();
3179 // see bug577005: we should not remove the last group for e
3180 if (!foundInline) e->groups->removeLast();
3181 //printf("Removing %s e=%p\n",grp->groupname.data(),e);
3183 if (!foundInline) initGroupInfo(e);
3187 void initGroupInfo(Entry *e)
3189 //printf("==> initGroup(id=%d,related=%s,e=%p)\n",g_memberGroupId,
3190 // g_memberGroupRelates.data(),e);
3191 e->mGrpId = g_memberGroupId;
3192 e->relates = g_memberGroupRelates;
3193 if (!g_autoGroupStack.isEmpty())
3195 //printf("Appending group %s to %s: count=%d entry=%p\n",
3196 // g_autoGroupStack.top()->groupname.data(),
3197 // e->name.data(),e->groups->count(),e);
3198 e->groups->append(new Grouping(*g_autoGroupStack.top()));
3202 static void groupAddDocs(Entry *e)
3204 if (e->section==Entry::MEMBERGRP_SEC)
3206 g_memberGroupDocs=e->brief.stripWhiteSpace();
3207 e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine);
3208 if (!g_memberGroupDocs.isEmpty() && !e->doc.isEmpty())
3210 g_memberGroupDocs+="\n\n";
3212 g_memberGroupDocs+=e->doc;
3213 MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
3216 info->doc = g_memberGroupDocs;
3217 info->docFile = e->docFile;
3218 info->docLine = e->docLine;
3219 info->setRefItems(e->sli);
3226 static void handleGuard(const QCString &expr)
3229 bool sectionEnabled=prs.parse(yyFileName,yyLineNr,expr.stripWhiteSpace());
3230 bool parentEnabled = TRUE;
3231 if (!guards.isEmpty()) parentEnabled = guards.top()->isEnabled();
3235 (sectionEnabled && guardType==Guard_If) ||
3236 (!sectionEnabled && guardType==Guard_IfNot)
3237 ) // section is visible
3239 guards.push(new GuardedSection(TRUE,TRUE));
3240 enabledSectionFound=TRUE;
3241 BEGIN( GuardParamEnd );
3243 else // section is invisible
3245 if (guardType!=Guard_Skip)
3247 guards.push(new GuardedSection(FALSE,TRUE));
3249 BEGIN( SkipGuardedSection );
3252 else // invisible because of parent
3254 guards.push(new GuardedSection(FALSE,FALSE));
3255 BEGIN( SkipGuardedSection );
3261 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3262 //----------------------------------------------------------------------------
3263 extern "C" { // some bogus code to keep the compiler happy
3264 void commentscanYYdummy() { yy_flex_realloc(0,0); }