Doxygen
commentscan.l
浏览该文件的文档.
1 /*****************************************************************************
2  *
3  * Copyright (C) 1997-2020 by Dimitri van Heesch.
4  *
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.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 %option never-interactive
17 %option prefix="commentscanYY"
18 %option reentrant
19 %option extra-type="struct commentscanYY_state *"
20 %top{
21 #include <stdint.h>
22 // forward declare yyscan_t to improve typesafety
23 #define YY_TYPEDEF_YY_SCANNER_T
24 struct yyguts_t;
25 typedef yyguts_t *yyscan_t;
26 }
27 
28 %{
29 
30 /*
31  * includes
32  */
33 
34 #include <map>
35 #include <stack>
36 #include <string>
37 #include <mutex>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <assert.h>
42 #include <ctype.h>
43 
44 #include "qcstring.h"
45 #include "cite.h"
46 #include "commentscan.h"
47 #include "condparser.h"
48 #include "config.h"
49 #include "debug.h"
50 #include "docgroup.h"
51 #include "doxygen.h"
52 #include "entry.h"
53 #include "formula.h"
54 #include "language.h"
55 #include "message.h"
56 #include "parserintf.h"
57 #include "reflist.h"
58 #include "section.h"
59 #include "util.h"
60 #include "reflist.h"
61 
62 #define USE_STATE2STRING 0
63 
64 // forward declarations
65 static bool handleBrief(yyscan_t yyscanner,const QCString &, const StringVector &);
66 static bool handleFn(yyscan_t yyscanner,const QCString &, const StringVector &);
67 static bool handleDef(yyscan_t yyscanner,const QCString &, const StringVector &);
68 static bool handleOverload(yyscan_t yyscanner,const QCString &, const StringVector &);
69 static bool handleEnum(yyscan_t yyscanner,const QCString &, const StringVector &);
70 static bool handleDefGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
71 static bool handleAddToGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
72 static bool handleWeakGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
73 static bool handleNamespace(yyscan_t yyscanner,const QCString &, const StringVector &);
74 static bool handlePackage(yyscan_t yyscanner,const QCString &, const StringVector &);
75 static bool handleConcept(yyscan_t yyscanner,const QCString &, const StringVector &);
76 static bool handleClass(yyscan_t yyscanner,const QCString &, const StringVector &);
77 static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &);
78 static bool handleProtocol(yyscan_t yyscanner,const QCString &, const StringVector &);
79 static bool handleCategory(yyscan_t yyscanner,const QCString &, const StringVector &);
80 static bool handleUnion(yyscan_t yyscanner,const QCString &, const StringVector &);
81 static bool handleStruct(yyscan_t yyscanner,const QCString &, const StringVector &);
82 static bool handleInterface(yyscan_t yyscanner,const QCString &, const StringVector &);
83 static bool handleIdlException(yyscan_t yyscanner,const QCString &, const StringVector &);
84 static bool handlePage(yyscan_t yyscanner,const QCString &, const StringVector &);
85 static bool handleMainpage(yyscan_t yyscanner,const QCString &, const StringVector &);
86 static bool handleFile(yyscan_t yyscanner,const QCString &, const StringVector &);
87 static bool handleDir(yyscan_t yyscanner,const QCString &, const StringVector &);
88 static bool handleExample(yyscan_t yyscanner,const QCString &, const StringVector &);
89 static bool handleDetails(yyscan_t yyscanner,const QCString &, const StringVector &);
90 static bool handleNoop(yyscan_t yyscanner,const QCString &, const StringVector &);
91 static bool handleName(yyscan_t yyscanner,const QCString &, const StringVector &);
92 static bool handleTodo(yyscan_t yyscanner,const QCString &, const StringVector &);
93 static bool handleTest(yyscan_t yyscanner,const QCString &, const StringVector &);
94 static bool handleBug(yyscan_t yyscanner,const QCString &, const StringVector &);
95 static bool handleSubpage(yyscan_t yyscanner,const QCString &s, const StringVector &);
96 static bool handleDeprecated(yyscan_t yyscanner,const QCString &, const StringVector &);
97 static bool handleXRefItem(yyscan_t yyscanner,const QCString &, const StringVector &);
98 static bool handleRelated(yyscan_t yyscanner,const QCString &, const StringVector &);
99 static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &, const StringVector &);
100 static bool handleMemberOf(yyscan_t yyscanner,const QCString &, const StringVector &);
101 static bool handleRefItem(yyscan_t yyscanner,const QCString &, const StringVector &);
102 static bool handleSection(yyscan_t yyscanner,const QCString &, const StringVector &);
103 static bool handleAnchor(yyscan_t yyscanner,const QCString &, const StringVector &);
104 static bool handleImage(yyscan_t yyscanner,const QCString &, const StringVector &);
105 static bool handleCite(yyscan_t yyscanner,const QCString &, const StringVector &);
106 static bool handleFormatBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
107 static bool handleAddIndex(yyscan_t yyscanner,const QCString &, const StringVector &);
108 static bool handleIf(yyscan_t yyscanner,const QCString &, const StringVector &);
109 static bool handleIfNot(yyscan_t yyscanner,const QCString &, const StringVector &);
110 static bool handleElseIf(yyscan_t yyscanner,const QCString &, const StringVector &);
111 static bool handleElse(yyscan_t yyscanner,const QCString &, const StringVector &);
112 static bool handleEndIf(yyscan_t yyscanner,const QCString &, const StringVector &);
113 static bool handleIngroup(yyscan_t yyscanner,const QCString &, const StringVector &);
114 static bool handleNoSubGrouping(yyscan_t yyscanner,const QCString &, const StringVector &);
115 static bool handleShowInitializer(yyscan_t yyscanner,const QCString &, const StringVector &);
116 static bool handleHideInitializer(yyscan_t yyscanner,const QCString &, const StringVector &);
117 static bool handleCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &);
118 static bool handleHideCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &);
119 static bool handleCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &);
120 static bool handleHideCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &);
121 static bool handleReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
122 static bool handleHideReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
123 static bool handleReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
124 static bool handleHideReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
125 static bool handleInternal(yyscan_t yyscanner,const QCString &, const StringVector &);
126 static bool handleStatic(yyscan_t yyscanner,const QCString &, const StringVector &);
127 static bool handlePure(yyscan_t yyscanner,const QCString &, const StringVector &);
128 static bool handlePrivate(yyscan_t yyscanner,const QCString &, const StringVector &);
129 static bool handlePrivateSection(yyscan_t yyscanner,const QCString &, const StringVector &);
130 static bool handleProtected(yyscan_t yyscanner,const QCString &, const StringVector &);
131 static bool handleProtectedSection(yyscan_t yyscanner,const QCString &, const StringVector &);
132 static bool handlePublic(yyscan_t yyscanner,const QCString &s, const StringVector &);
133 static bool handlePublicSection(yyscan_t yyscanner,const QCString &s, const StringVector &);
134 static bool handleToc(yyscan_t yyscanner,const QCString &s, const StringVector &);
135 static bool handleInherit(yyscan_t yyscanner,const QCString &, const StringVector &);
136 static bool handleExtends(yyscan_t yyscanner,const QCString &, const StringVector &);
137 static bool handleCopyDoc(yyscan_t yyscanner,const QCString &, const StringVector &);
138 static bool handleCopyBrief(yyscan_t yyscanner,const QCString &, const StringVector &);
139 static bool handleCopyDetails(yyscan_t yyscanner,const QCString &, const StringVector &);
140 static bool handleParBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
141 static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
142 static bool handleParam(yyscan_t yyscanner,const QCString &, const StringVector &);
143 static bool handleRetval(yyscan_t yyscanner,const QCString &, const StringVector &);
144 
145 #if USE_STATE2STRING
146 static const char *stateToString(int state);
147 #endif
148 
149 typedef bool (*DocCmdFunc)(yyscan_t yyscanner,const QCString &name, const StringVector &optList);
150 
151 enum class CommandSpacing
152 {
153  Invisible, // command sets some property but does not appear in the output.
154  Inline, // command appears inline in the output which can be a brief description.
155  Block, // command starts a new paragraphs / ends a brief description.
156  XRef // command is a cross reference (todo, bug, test, xrefitem).
157 };
158 
159 struct DocCmdMap
160 {
161  DocCmdMap(DocCmdFunc h,CommandSpacing s) : handler(h), spacing(s) {}
162  DocCmdFunc handler;
163  CommandSpacing spacing;
164 };
165 
166 // map of command to handler function
167 static const std::map< std::string, DocCmdMap > docCmdMap =
168 {
169  // command name handler function command spacing
170  { "addindex", { &handleAddIndex, CommandSpacing::Invisible }},
171  { "addtogroup", { &handleAddToGroup, CommandSpacing::Invisible }},
172  { "anchor", { &handleAnchor, CommandSpacing::Invisible }},
173  { "arg", { 0, CommandSpacing::Block }},
174  { "attention", { 0, CommandSpacing::Block }},
175  { "author", { 0, CommandSpacing::Block }},
176  { "authors", { 0, CommandSpacing::Block }},
177  { "brief", { &handleBrief, CommandSpacing::Invisible }},
178  { "bug", { &handleBug, CommandSpacing::XRef }},
179  { "callergraph", { &handleCallergraph, CommandSpacing::Invisible }},
180  { "callgraph", { &handleCallgraph, CommandSpacing::Invisible }},
181  { "category", { &handleCategory, CommandSpacing::Invisible }},
182  { "cite", { &handleCite, CommandSpacing::Inline }},
183  { "class", { &handleClass, CommandSpacing::Invisible }},
184  { "code", { &handleFormatBlock, CommandSpacing::Block }},
185  { "concept", { &handleConcept, CommandSpacing::Invisible }},
186  { "copybrief", { &handleCopyBrief, CommandSpacing::Invisible }},
187  { "copydetails", { &handleCopyDetails, CommandSpacing::Block }},
188  { "copydoc", { &handleCopyDoc, CommandSpacing::Block }},
189  { "copyright", { 0, CommandSpacing::Block }},
190  { "date", { 0, CommandSpacing::Block }},
191  { "def", { &handleDef, CommandSpacing::Invisible }},
192  { "defgroup", { &handleDefGroup, CommandSpacing::Invisible }},
193  { "deprecated", { &handleDeprecated, CommandSpacing::XRef }},
194  { "details", { &handleDetails, CommandSpacing::Block }},
195  { "dir", { &handleDir, CommandSpacing::Invisible }},
196  { "docbookinclude", { 0, CommandSpacing::Inline }},
197  { "docbookonly", { &handleFormatBlock, CommandSpacing::Invisible }},
198  { "dot", { &handleFormatBlock, CommandSpacing::Block }},
199  { "dotfile", { 0, CommandSpacing::Block }},
200  { "else", { &handleElse, CommandSpacing::Inline }},
201  { "elseif", { &handleElseIf, CommandSpacing::Inline }},
202  { "endif", { &handleEndIf, CommandSpacing::Inline }},
203  { "endparblock", { &handleEndParBlock, CommandSpacing::Block }},
204  { "enum", { &handleEnum, CommandSpacing::Invisible }},
205  { "example", { &handleExample, CommandSpacing::Invisible }},
206  { "exception", { 0, CommandSpacing::Block }},
207  { "extends", { &handleExtends, CommandSpacing::Invisible }},
208  { "file", { &handleFile, CommandSpacing::Invisible }},
209  { "fn", { &handleFn, CommandSpacing::Invisible }},
210  { "headerfile", { &handleHeaderFile, CommandSpacing::Invisible }},
211  { "hidecallergraph", { &handleHideCallergraph, CommandSpacing::Invisible }},
212  { "hidecallgraph", { &handleHideCallgraph, CommandSpacing::Invisible }},
213  { "hideinitializer", { &handleHideInitializer, CommandSpacing::Invisible }},
214  { "hiderefby", { &handleHideReferencedByRelation, CommandSpacing::Invisible }},
215  { "hiderefs", { &handleHideReferencesRelation, CommandSpacing::Invisible }},
216  { "htmlinclude", { 0, CommandSpacing::Inline }},
217  { "htmlonly", { &handleFormatBlock, CommandSpacing::Invisible }},
218  { "idlexcept", { &handleIdlException, CommandSpacing::Invisible }},
219  { "if", { &handleIf, CommandSpacing::Inline }},
220  { "ifnot", { &handleIfNot, CommandSpacing::Inline }},
221  { "image", { &handleImage, CommandSpacing::Block }},
222  { "implements", { &handleExtends, CommandSpacing::Invisible }},
223  { "include", { 0, CommandSpacing::Block }},
224  { "includelineno", { 0, CommandSpacing::Block }},
225  { "ingroup", { &handleIngroup, CommandSpacing::Invisible }},
226  { "inherit", { &handleInherit, CommandSpacing::Invisible }},
227  { "interface", { &handleInterface, CommandSpacing::Invisible }},
228  { "internal", { &handleInternal, CommandSpacing::Block }},
229  { "invariant", { 0, CommandSpacing::Block }},
230  { "latexinclude", { 0, CommandSpacing::Inline }},
231  { "latexonly", { &handleFormatBlock, CommandSpacing::Invisible }},
232  { "li", { 0, CommandSpacing::Block }},
233  { "line", { 0, CommandSpacing::Invisible }},
234  { "mainpage", { &handleMainpage, CommandSpacing::Invisible }},
235  { "maninclude", { 0, CommandSpacing::Inline }},
236  { "manonly", { &handleFormatBlock, CommandSpacing::Invisible }},
237  { "memberof", { &handleMemberOf, CommandSpacing::Invisible }},
238  { "msc", { &handleFormatBlock, CommandSpacing::Block }},
239  { "name", { &handleName, CommandSpacing::Invisible }},
240  { "namespace", { &handleNamespace, CommandSpacing::Invisible }},
241  { "noop", { &handleNoop, CommandSpacing::Invisible }},
242  { "nosubgrouping", { &handleNoSubGrouping, CommandSpacing::Invisible }},
243  { "note", { 0, CommandSpacing::Block }},
244  { "overload", { &handleOverload, CommandSpacing::Invisible }},
245  { "package", { &handlePackage, CommandSpacing::Invisible }},
246  { "page", { &handlePage, CommandSpacing::Invisible }},
247  { "par", { 0, CommandSpacing::Block }},
248  { "paragraph", { &handleSection, CommandSpacing::Block }},
249  { "param", { &handleParam, CommandSpacing::Block }},
250  { "parblock", { &handleParBlock, CommandSpacing::Block }},
251  { "post", { 0, CommandSpacing::Block }},
252  { "pre", { 0, CommandSpacing::Block }},
253  { "private", { &handlePrivate, CommandSpacing::Invisible }},
254  { "privatesection", { &handlePrivateSection, CommandSpacing::Invisible }},
255  { "property", { &handleFn, CommandSpacing::Invisible }},
256  { "protected", { &handleProtected, CommandSpacing::Invisible }},
257  { "protectedsection",{ &handleProtectedSection, CommandSpacing::Invisible }},
258  { "protocol", { &handleProtocol, CommandSpacing::Invisible }},
259  { "public", { &handlePublic, CommandSpacing::Invisible }},
260  { "publicsection", { &handlePublicSection, CommandSpacing::Invisible }},
261  { "pure", { &handlePure, CommandSpacing::Invisible }},
262  { "refitem", { &handleRefItem, CommandSpacing::Inline }},
263  { "related", { &handleRelated, CommandSpacing::Invisible }},
264  { "relatedalso", { &handleRelatedAlso, CommandSpacing::Invisible }},
265  { "relates", { &handleRelated, CommandSpacing::Invisible }},
266  { "relatesalso", { &handleRelatedAlso, CommandSpacing::Invisible }},
267  { "remark", { 0, CommandSpacing::Block }},
268  { "remarks", { 0, CommandSpacing::Block }},
269  { "result", { 0, CommandSpacing::Block }},
270  { "return", { 0, CommandSpacing::Block }},
271  { "returns", { 0, CommandSpacing::Block }},
272  { "retval", { &handleRetval, CommandSpacing::Block }},
273  { "rtfinclude", { 0, CommandSpacing::Inline }},
274  { "rtfonly", { &handleFormatBlock, CommandSpacing::Invisible }},
275  { "sa", { 0, CommandSpacing::Block }},
276  { "section", { &handleSection, CommandSpacing::Block }},
277  { "see", { 0, CommandSpacing::Block }},
278  { "short", { &handleBrief, CommandSpacing::Invisible }},
279  { "showinitializer", { &handleShowInitializer, CommandSpacing::Invisible }},
280  { "showrefby", { &handleReferencedByRelation, CommandSpacing::Invisible }},
281  { "showrefs", { &handleReferencesRelation, CommandSpacing::Invisible }},
282  { "since", { 0, CommandSpacing::Block }},
283  { "snippet", { 0, CommandSpacing::Block }},
284  { "snippetlineno", { 0, CommandSpacing::Block }},
285  { "startuml", { &handleFormatBlock, CommandSpacing::Block }},
286  { "static", { &handleStatic, CommandSpacing::Invisible }},
287  { "struct", { &handleStruct, CommandSpacing::Invisible }},
288  { "subpage", { &handleSubpage, CommandSpacing::Inline }},
289  { "subsection", { &handleSection, CommandSpacing::Block }},
290  { "subsubsection", { &handleSection, CommandSpacing::Block }},
291  { "tableofcontents", { &handleToc, CommandSpacing::Invisible }},
292  { "test", { &handleTest, CommandSpacing::XRef }},
293  { "throw", { 0, CommandSpacing::Block }},
294  { "throws", { 0, CommandSpacing::Block }},
295  { "todo", { &handleTodo, CommandSpacing::XRef }},
296  { "tparam", { 0, CommandSpacing::Block }},
297  { "typedef", { &handleFn, CommandSpacing::Invisible }},
298  { "union", { &handleUnion, CommandSpacing::Invisible }},
299  { "until", { 0, CommandSpacing::Block }},
300  { "var", { &handleFn, CommandSpacing::Invisible }},
301  { "verbatim", { &handleFormatBlock, CommandSpacing::Block }},
302  { "verbinclude", { 0, CommandSpacing::Inline }},
303  { "version", { 0, CommandSpacing::Block }},
304  { "warning", { 0, CommandSpacing::Block }},
305  { "weakgroup", { &handleWeakGroup, CommandSpacing::Invisible }},
306  { "xmlinclude", { 0, CommandSpacing::Inline }},
307  { "xmlonly", { &handleFormatBlock, CommandSpacing::Invisible }},
308  { "xrefitem", { &handleXRefItem, CommandSpacing::XRef }}
309 };
310 
311 #define YY_NO_INPUT 1
312 #define YY_NO_UNISTD_H 1
313 #define YY_NEVER_INTERACTIVE 1
314 
315 
316 enum XRefKind
317 {
318  XRef_Item,
319  XRef_Todo,
320  XRef_Test,
321  XRef_Bug,
322  XRef_Deprecated,
323  XRef_None
324 };
325 
326 enum OutputContext
327 {
328  OutputDoc,
329  OutputBrief,
330  OutputXRef,
331  OutputInbody
332 };
333 
334 enum GuardType
335 {
336  Guard_If,
337  Guard_IfNot,
338  Guard_Skip
339 };
340 
341 class GuardedSection
342 {
343  public:
344  GuardedSection(bool enabled,bool parentVisible)
345  : m_enabled(enabled),m_parentVisible(parentVisible) {}
346  bool isEnabled() const { return m_enabled; }
347  bool parentVisible() const { return m_parentVisible; }
348 
349  private:
350  bool m_enabled;
351  bool m_parentVisible;
352 };
353 
354 /* -----------------------------------------------------------------
355  *
356  * statics
357  */
358 
359 struct commentscanYY_state
360 {
361  OutlineParserInterface *langParser = 0; // the language parser that is calling us
362  QCString inputString; // input string
363  QCString currentCmd; // the command used
364  int inputPosition = 0; // read pointer
365  QCString fileName; // file name that is read from
366  int lineNr = 0; // line number in the input
367  bool inBody = FALSE; // was the comment found inside the body of a function?
368  OutputContext inContext; // are we inside the brief, details or xref part
369  bool briefEndsAtDot = FALSE; // does the brief description stop at a dot?
370  QCString formulaText; // Running text of a formula
371  QCString formulaEnv; // environment name
372  int formulaNewLines = 0; // amount of new lines in the formula
373  QCString *pOutputString = 0; // pointer to string to which the output is appended.
374  QCString outputXRef; // temp argument of todo/test/../xrefitem commands
375  QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...)
376  XRefKind xrefKind = XRef_Item; // kind of cross-reference command
377  XRefKind newXRefKind = XRef_Item; //
378  GuardType guardType = Guard_If; // kind of guards for conditional section
379  bool enabledSectionFound = FALSE;
380  QCString functionProto; // function prototype
381  std::stack<GuardedSection> guards; // tracks nested conditional sections (if,ifnot,..)
382  Entry *current = 0; // working entry
383 
384  bool needNewEntry = FALSE;
385 
386  QCString sectionLabel;
387  QCString sectionTitle;
388  int sectionLevel = 0;
389  QCString xrefItemKey;
390  QCString newXRefItemKey;
391  QCString xrefItemTitle;
392  QCString xrefListTitle;
393  Protection protection = Public;
394 
395  bool xrefAppendFlag = FALSE;
396  bool inGroupParamFound = FALSE;
397  int braceCount = 0;
398  bool insidePre = FALSE;
399  bool parseMore = FALSE;
400  int condCount = 0;
401 
402  int commentCount = 0;
403  QCString spaceBeforeCmd;
404  QCString spaceBeforeIf;
405  QCString copyDocArg;
406 
407  QCString guardExpr;
408  int roundCount = 0;
409 
410  bool insideParBlock = FALSE;
411  bool inInternalDocs = FALSE;
412  int prevPosition = 0;
413  DocGroup docGroup;
414  bool markdownSupport = TRUE;
415 };
416 
417 
418 static std::mutex g_sectionMutex;
419 static std::mutex g_formulaMutex;
420 static std::mutex g_citeMutex;
421 
422 //-----------------------------------------------------------------------------
423 
424 static QCString stripQuotes(const char *s);
425 static bool getDocSectionName(int s);
426 static SectionType sectionLevelToType(int level);
427 static void stripTrailingWhiteSpace(QCString &s);
428 
429 static void initParser(yyscan_t yyscanner);
430 static bool makeStructuralIndicator(yyscan_t yyscanner,Entry::Sections s);
431 static void lineCount(yyscan_t yyscanner);
432 static void addXRefItem(yyscan_t yyscanner,
433  const QCString &listName,const QCString &itemTitle,
434  const QCString &listTitle,bool append);
435 static QCString addFormula(yyscan_t yyscanner);
436 static void checkFormula(yyscan_t yyscanner);
437 static void addSection(yyscan_t yyscanner);
438 static inline void setOutput(yyscan_t yyscanner,OutputContext ctx);
439 static void addAnchor(yyscan_t yyscanner,const QCString &anchor);
440 static inline void addOutput(yyscan_t yyscanner,const char *s);
441 static inline void addOutput(yyscan_t yyscanner,const QCString &s);
442 static inline void addOutput(yyscan_t yyscanner,char c);
443 static void endBrief(yyscan_t yyscanner,bool addToOutput=TRUE);
444 static void handleGuard(yyscan_t yyscanner,const QCString &expr);
445 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
446 static void addCite(yyscan_t yyscanner);
447 static void addIline(yyscan_t yyscanner,int lineNr);
448 
449 #define unput_string(yytext,yyleng) do { for (int i=(int)yyleng-1;i>=0;i--) unput(yytext[i]); } while(0)
450 
451 //-----------------------------------------------------------------------------
452 
453 #undef YY_INPUT
454 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
455 
456 %}
457 
458  /* start command character */
459 CMD ("\\"|"@")
460 XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem")
461 PRE [pP][rR][eE]
462 TABLE [tT][aA][bB][lL][eE]
463 P [pP]
464 UL [uU][lL]
465 OL [oO][lL]
466 DL [dD][lL]
467 IMG [iI][mM][gG]
468 HR [hH][rR]
469 PARA [pP][aA][rR][aA]
470 CODE [cC][oO][dD][eE]
471 CAPTION [cC][aA][pP][tT][iI][oO][nN]
472 CENTER [cC][eE][nN][tT][eE][rR]
473 DIV [dD][iI][vV]
474 DETAILEDHTML {CENTER}|{DIV}|{PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA}
475 DETAILEDHTMLOPT {CODE}
476 BN [ \t\n\r]
477 BL [ \t\r]*"\n"
478 B [ \t]
479 Bopt {B}*
480 BS ^(({B}*"/""/")?)(({B}*"*"+)?){B}*
481 ATTR ({B}+[^>\n]*)?
482 DOCNL "\n"|"\\ilinebr"
483 LC "\\"{B}*"\n"
484 NW [^a-z_A-Z0-9]
485 FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+@&#]
486 FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+@&#]
487 FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"")
488 ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
489 LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
490 CITESCHAR [a-z_A-Z0-9\x80-\xFF\-\?]
491 CITEECHAR [a-z_A-Z0-9\x80-\xFF\-\+:\/\?]*
492 CITEID {CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*|"\""{CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*"\""
493 SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
494 SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID})
495 TMPLSPEC "<"{BN}*[^>]+{BN}*">"
496 MAILADDR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
497 RCSTAG "$"{ID}":"[^\n$]+"$"
498 
499  // C start comment
500 CCS "/\*"
501  // C end comment
502 CCE "*\/"
503  // Cpp comment
504 CPPC "/\/"
505 
506  // end of section title with asterisk
507 STAopt [^\n@\\*]*
508  // end of section title without asterisk
509 STopt [^\n@\\]*
510 
511 %option noyywrap
512 
513  /* comment parsing states. */
514 %x Comment
515 %x PageDocArg1
516 %x PageDocArg2
517 %x RelatesParam1
518 %x ClassDocArg1
519 %x ClassDocArg2
520 %x ClassDocArg3
521 %x CategoryDocArg1
522 %x XRefItemParam1
523 %x XRefItemParam2
524 %x XRefItemParam3
525 %x FileDocArg1
526 %x ParamArg1
527 %x EnumDocArg1
528 %x NameSpaceDocArg1
529 %x PackageDocArg1
530 %x ConceptDocArg1
531 %x GroupDocArg1
532 %x GroupDocArg2
533 %x SectionLabel
534 %x SectionTitle
535 %x SubpageLabel
536 %x SubpageTitle
537 %x FormatBlock
538 %x LineParam
539 %x GuardParam
540 %x GuardParamEnd
541 %x SkipGuardedSection
542 %x SkipInternal
543 %x NameParam
544 %x InGroupParam
545 %x FnParam
546 %x OverloadParam
547 %x InheritParam
548 %x ExtendsParam
549 %x ReadFormulaShort
550 %x ReadFormulaRound
551 %x ReadFormulaLong
552 %x AnchorLabel
553 %x HtmlComment
554 %x SkipLang
555 %x CiteLabel
556 %x CopyDoc
557 %x GuardExpr
558 %x CdataSection
559 %x Noop
560 
561 %%
562 
563  /* What can happen in while parsing a comment block:
564  * commands (e.g. @page, or \page)
565  * escaped commands (e.g. @@page or \\page).
566  * formulas (e.g. \f$...\f$ \f[...\f] \f{...\f} \f(...\f) )
567  * directories (e.g. \doxygen\src\)
568  * autolist end. (e.g. a dot on an otherwise empty line)
569  * newlines.
570  * end of brief description due to blank line.
571  * end of brief description due to some command (@command, or <command>).
572  * words and whitespace and other characters (#,?!, etc).
573  * grouping commands (e.g. @{ and @})
574  * language switch (e.g. \~english or \~).
575  * mail address (e.g. doxygen@gmail.com).
576  * quoted text, such as "foo@bar"
577  * XML commands, <summary></summary><remarks></remarks>
578  */
579 
580 <Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command
581  addOutput(yyscanner,yytext);
582  }
583 <Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command
584  addOutput(yyscanner,yytext);
585  }
586 <Comment>{MAILADDR} { // mail address
587  addOutput(yyscanner,yytext);
588  }
589 <Comment>"\""[^"\n]*"\"" { // quoted text
590  addOutput(yyscanner,yytext);
591  }
592 <Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!)
593  addOutput(yyscanner,yytext);
594  }
595 <Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description
596  setOutput(yyscanner,OutputDoc);
597  // continue with the same input
598  REJECT;
599  }
600 <Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description
601  if (yyextra->current->lang==SrcLangExt_CSharp)
602  {
603  setOutput(yyscanner,OutputDoc);
604  }
605  // continue with the same input
606  REJECT;
607  }
608 <Comment>"<summary>" { // start of a .NET XML style brief description
609  setOutput(yyscanner,OutputBrief);
610  addOutput(yyscanner,yytext);
611  }
612 <Comment>"<remarks>" { // start of a .NET XML style detailed description
613  setOutput(yyscanner,OutputDoc);
614  addOutput(yyscanner,yytext);
615  }
616 <Comment>"</summary>" { // start of a .NET XML style detailed description
617  addOutput(yyscanner,yytext);
618  setOutput(yyscanner,OutputDoc);
619  }
620 <Comment>"</remarks>" { // end of a brief or detailed description
621  setOutput(yyscanner,OutputDoc);
622  addOutput(yyscanner,yytext);
623  }
624 <Comment>"<"{CAPTION}{ATTR}">" {
625  QCString tag(yytext);
626  int s=tag.find("id=");
627  if (s!=-1) // command has id attribute
628  {
629  char c=tag[s+3];
630  if (c=='\'' || c=='"') // valid start
631  {
632  int e=tag.find(c,s+4);
633  if (e!=-1) // found matching end
634  {
635  QCString id=tag.mid(s+4,e-s-4); // extract id
636  addAnchor(yyscanner,id);
637  }
638  }
639  }
640  addOutput(yyscanner,yytext);
641  }
642 <Comment>"<"{PRE}{ATTR}">" {
643  yyextra->insidePre=TRUE;
644  addOutput(yyscanner,yytext);
645  }
646 <Comment>"</"{PRE}">" {
647  yyextra->insidePre=FALSE;
648  addOutput(yyscanner,yytext);
649  }
650 <Comment>{RCSTAG} { // RCS tag which end a brief description
651  setOutput(yyscanner,OutputDoc);
652  REJECT;
653  }
654 <Comment>"<!--" {
655  BEGIN(HtmlComment);
656  }
657 <Comment>"<!\[CDATA\[" {
658  BEGIN(CdataSection);
659  }
660 <Comment>{B}*{CMD}"endinternal"{B}* {
661  addOutput(yyscanner," \\endinternal ");
662  if (!yyextra->inInternalDocs)
663  warn(yyextra->fileName,yyextra->lineNr,
664  "found \\endinternal without matching \\internal"
665  );
666  yyextra->inInternalDocs = FALSE;
667  }
668 <Comment>{B}*"\\ilinebr"{B}* { // preserve spacing around \\ilinebr
669  addOutput(yyscanner,yytext);
670  }
671 <Comment>{B}*{CMD}[a-z_A-Z]+"{"[a-zA-Z_,:0-9\. ]*"}"{B}* |
672 <Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command
673  // the {B}* in the front was added for bug620924
674  QCString fullMatch = QCString(yytext);
675  int idx = fullMatch.find('{');
676  /* handle `\f{` and `@f{` as special cases */
677  if ((idx > 1) && (yytext[idx-1] == 'f') && (yytext[idx-2] == '\\' || yytext[idx-2] =='@')) REJECT;
678  int idxEnd = fullMatch.find("}",idx+1);
679  QCString cmdName;
680  StringVector optList;
681  if (idx == -1) // no options
682  {
683  cmdName = QCString(yytext).stripWhiteSpace().mid(1); // to remove {CMD}
684  }
685  else // options present
686  {
687  cmdName = fullMatch.left(idx).stripWhiteSpace().mid(1); // to remove {CMD}
688  QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
689  optList = split(optStr.str(),",");
690  }
691  auto it = docCmdMap.find(cmdName.str());
692  //printf("lookup command '%s' found=%d\n",qPrint(cmdName),it!=docCmdMap.end());
693  if (it!=docCmdMap.end()) // special action is required
694  {
695  int i=0;
696  while (yytext[i]==' ' || yytext[i]=='\t') i++;
697  yyextra->spaceBeforeCmd = QCString(yytext).left(i);
698  CommandSpacing spacing = it->second.spacing;
699  if ((spacing==CommandSpacing::Block || spacing==CommandSpacing::XRef) &&
700  !(yyextra->inContext==OutputXRef && cmdName=="parblock"))
701  {
702  yyextra->briefEndsAtDot=FALSE;
703  bool insideXRef = yyextra->inContext==OutputXRef && spacing==CommandSpacing::XRef;
704  // this command forces the end of brief description
705  setOutput(yyscanner,insideXRef ? OutputXRef : OutputDoc);
706  }
707  //if (i>0) addOutput(yyscanner,QCString(yytext).left(i)); // removed for bug 689341
708  if (it->second.handler && it->second.handler(yyscanner, cmdName, optList))
709  {
710  // implicit split of the comment block into two
711  // entries. Restart the next block at the start
712  // of this command.
713  yyextra->parseMore=TRUE;
714 
715  // yuk, this is probably not very portable across lex implementations,
716  // but we need to know the position in the input buffer where this
717  // rule matched.
718  // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE
719 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
720  yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);
721 #else
722  yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf);
723 #endif
724  yyterminate();
725  }
726  else if (it->second.handler==0)
727  {
728  // command without handler, to be processed
729  // later by parsedoc.cpp
730  addOutput(yyscanner,yytext);
731  }
732  }
733  else // command not relevant
734  {
735  addOutput(yyscanner,yytext);
736  }
737  }
738 <Comment>{B}*({CMD}{CMD})"f"[$\[{] { // escaped formula command
739  addOutput(yyscanner,yytext);
740  }
741 <Comment>{B}*{CMD}"~"[a-z_A-Z-]* { // language switch command
742  QCString langId = QCString(yytext).stripWhiteSpace().mid(2);
743  if (!langId.isEmpty() &&
744  qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE).data(),langId.data())!=0)
745  { // enable language specific section
746  BEGIN(SkipLang);
747  }
748  }
749 <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment
750  setOutput(yyscanner,OutputDoc);
751  yyextra->formulaText="\\begin";
752  yyextra->formulaEnv=QCString(yytext).stripWhiteSpace().mid(2);
753  if (yyextra->formulaEnv.at(yyextra->formulaEnv.length()-1)=='{')
754  {
755  // remove trailing open brace
756  yyextra->formulaEnv=yyextra->formulaEnv.left(yyextra->formulaEnv.length()-1);
757  }
758  yyextra->formulaText+=yyextra->formulaEnv;
759  yyextra->formulaNewLines=0;
760  BEGIN(ReadFormulaLong);
761  }
762 <Comment>{B}*{CMD}"f$" { // start of a inline formula
763  yyextra->formulaText="$";
764  yyextra->formulaNewLines=0;
765  BEGIN(ReadFormulaShort);
766  }
767 <Comment>{B}*{CMD}"f(" { // start of a inline formula
768  yyextra->formulaText="";
769  yyextra->formulaNewLines=0;
770  BEGIN(ReadFormulaRound);
771  }
772 <Comment>{B}*{CMD}"f[" { // start of a block formula
773  setOutput(yyscanner,OutputDoc);
774  yyextra->formulaText="\\[";
775  yyextra->formulaNewLines=0;
776  BEGIN(ReadFormulaLong);
777  }
778 <Comment>{B}*{CMD}"{" { // begin of a group
779  //yyextra->langParser->handleGroupStartCommand(yyextra->memberGroupHeader);
780  yyextra->docGroup.open(yyextra->current,yyextra->fileName,yyextra->lineNr);
781  }
782 <Comment>{B}*{CMD}"}" { // end of a group
783  //yyextra->langParser->handleGroupEndCommand();
784  yyextra->docGroup.close(yyextra->current,yyextra->fileName,yyextra->lineNr,TRUE);
785  yyextra->docGroup.clearHeader();
786  yyextra->parseMore=TRUE;
787  yyextra->needNewEntry = TRUE;
788 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
789  yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + (int)strlen(yytext);
790 #else
791  yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + (int)strlen(yytext);
792 #endif
793  yyterminate();
794  }
795 <Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character
796  addOutput(yyscanner,yytext);
797  }
798 <Comment>[a-z_A-Z]+ { // normal word
799  addOutput(yyscanner,yytext);
800  }
801 <Comment>^{B}*"."{Bopt}/\n { // explicit end autolist: e.g " ."
802  addOutput(yyscanner,yytext);
803  }
804 <Comment>^{B}*[1-9][0-9]*"."{B}+ |
805 <Comment>^{B}*[*+]{B}+ { // start of autolist
806  if (!yyextra->markdownSupport)
807  {
808  REJECT;
809  }
810  else
811  {
812  if (yyextra->inContext!=OutputXRef)
813  {
814  yyextra->briefEndsAtDot=FALSE;
815  setOutput(yyscanner,OutputDoc);
816  }
817  addOutput(yyscanner,yytext);
818  }
819  }
820 <Comment>^{B}*"-"{B}+ { // start of autolist
821  if (yyextra->inContext!=OutputXRef)
822  {
823  yyextra->briefEndsAtDot=FALSE;
824  setOutput(yyscanner,OutputDoc);
825  }
826  addOutput(yyscanner,yytext);
827  }
828 <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{Bopt}/\n { // horizontal line (dashed)
829  addOutput(yyscanner,yytext);
830  }
831 <Comment>{CMD}"---" { // escaped mdash
832  addOutput(yyscanner,yytext);
833  }
834 <Comment>{CMD}"--" { // escaped mdash
835  addOutput(yyscanner,yytext);
836  }
837 <Comment>"---" { // mdash
838  addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "&mdash;");
839  }
840 <Comment>"--" { // ndash
841  addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "&ndash;");
842  }
843 <Comment>"-#"{B}+ { // numbered item
844  if (yyextra->inContext!=OutputXRef)
845  {
846  yyextra->briefEndsAtDot=FALSE;
847  setOutput(yyscanner,OutputDoc);
848  }
849  addOutput(yyscanner,yytext);
850  }
851 <Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis
852  addOutput(yyscanner,yytext);
853  }
854 <Comment>".\\"[ \t] { // . with escaped space.
855  addOutput(yyscanner,yytext[0]);
856  addOutput(yyscanner,yytext[2]);
857  }
858 <Comment>".," { // . with comma such as "e.g.,"
859  addOutput(yyscanner,yytext);
860  }
861 <Comment>"...\\"[ \t] { // ellipsis with escaped space.
862  addOutput(yyscanner,"... ");
863  }
864 <Comment>"..."/[^\.] { // ellipsis
865  addOutput(yyscanner,"...");
866  }
867 <Comment>".."[\.]?/[^ \t\n] { // internal ellipsis
868  addOutput(yyscanner,yytext);
869  }
870 <Comment>(\n|\\ilinebr)({B}*(\n|\\ilinebr))+ { // at least one blank line (or blank line command)
871  if (yyextra->inContext==OutputXRef)
872  {
873  // see bug 613024, we need to put the newlines after ending the XRef section.
874  if (!yyextra->insideParBlock) setOutput(yyscanner,OutputDoc);
875  yy_size_t i;
876  for (i=0;i<(yy_size_t)yyleng;)
877  {
878  if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++;
879  else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8;
880  else i++;
881  }
882  }
883  else if (yyextra->inContext!=OutputBrief)
884  {
885  yy_size_t i;
886  for (i=0;i<(yy_size_t)yyleng;)
887  {
888  if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++;
889  else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8;
890  else i++;
891  }
892  setOutput(yyscanner,OutputDoc);
893  }
894  else // yyextra->inContext==OutputBrief
895  { // only go to the detailed description if we have
896  // found some brief description and not just whitespace
897  endBrief(yyscanner,TRUE);
898  }
899  lineCount(yyscanner);
900  }
901 <Comment>"." { // potential end of a JavaDoc style comment
902  addOutput(yyscanner,*yytext);
903  if (yyextra->briefEndsAtDot)
904  {
905  setOutput(yyscanner,OutputDoc);
906  yyextra->briefEndsAtDot=FALSE;
907  }
908  }
909 <Comment>{DOCNL} { // newline
910  addOutput(yyscanner,yytext);
911  if (*yytext == '\n') yyextra->lineNr++;
912  }
913 <Comment>. { // catch-all for anything else
914  addOutput(yyscanner,*yytext);
915  }
916 
917 
918  /* -------------- Rules for handling HTML comments ----------- */
919 
920 <HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); }
921 <HtmlComment>{DOCNL} {
922  if (*yytext=='\n')
923  {
924  addOutput(yyscanner,*yytext);
925  yyextra->lineNr++;
926  }
927  }
928 <HtmlComment>[^\\\n\-]+ { // ignore unimportant characters
929  }
930 <HtmlComment>. { // ignore every else
931  }
932 
933 <CdataSection>"\]\]>" {
934  BEGIN( Comment );
935  }
936 <CdataSection>{DOCNL} {
937  addOutput(yyscanner,'\n');
938  if (*yytext=='\n') yyextra->lineNr++;
939  }
940 <CdataSection>[<>&] { // the special XML characters for iwhich the CDATA section is especially used
941  addOutput(yyscanner,'\\');
942  addOutput(yyscanner,*yytext);
943  }
944 <CdataSection>[^\\\n\]<>&]+ {
945  addOutput(yyscanner,yytext);
946  }
947 <CdataSection>. {
948  addOutput(yyscanner,*yytext);
949  }
950 
951  /* -------------- Rules for handling formulas ---------------- */
952 
953 <ReadFormulaShort>{CMD}"f$" { // end of inline formula
954  yyextra->formulaText+="$";
955  addOutput(yyscanner," "+addFormula(yyscanner));
956  BEGIN(Comment);
957  }
958 <ReadFormulaRound>{CMD}"f)" { // end of inline formula
959  addOutput(yyscanner," "+addFormula(yyscanner));
960  BEGIN(Comment);
961  }
962 <ReadFormulaLong>{CMD}"f]" { // end of block formula
963  yyextra->formulaText+="\\]";
964  addOutput(yyscanner," "+addFormula(yyscanner));
965  BEGIN(Comment);
966  }
967 <ReadFormulaLong>{CMD}"f}" { // end of custom env formula
968  yyextra->formulaText+="\\end";
969  yyextra->formulaText+=yyextra->formulaEnv;
970  addOutput(yyscanner," "+addFormula(yyscanner));
971  BEGIN(Comment);
972  }
973 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>[^\\@\n]+ { // any non-special character
974  yyextra->formulaText+=yytext;
975  }
976 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>\n { // new line
977  yyextra->formulaNewLines++;
978  yyextra->formulaText+=*yytext;
979  yyextra->lineNr++;
980  }
981 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>. { // any other character
982  yyextra->formulaText+=*yytext;
983  }
984 
985  /* ------------ handle argument of enum command --------------- */
986 
987 <EnumDocArg1>{SCOPEID} { // handle argument
988  yyextra->current->name = yytext;
989  BEGIN( Comment );
990  }
991 <EnumDocArg1>{LC} { // line continuation
992  yyextra->lineNr++;
993  addOutput(yyscanner,'\n');
994  }
995 <EnumDocArg1>{DOCNL} { // missing argument
996  warn(yyextra->fileName,yyextra->lineNr,
997  "missing argument after \\enum."
998  );
999  unput_string(yytext,yyleng);
1000  //addOutput(yyscanner,'\n');
1001  //if (*yytext=='\n') yyextra->lineNr++;
1002  BEGIN( Comment );
1003  }
1004 <EnumDocArg1>. { // ignore other stuff
1005  }
1006 
1007  /* ------------ handle argument of namespace command --------------- */
1008 
1009 <NameSpaceDocArg1>{SCOPENAME} { // handle argument
1010  yyextra->current->name = substitute(QCString(yytext),QCString("."),QCString("::"));
1011  BEGIN( Comment );
1012  }
1013 <NameSpaceDocArg1>{LC} { // line continuation
1014  yyextra->lineNr++;
1015  addOutput(yyscanner,'\n');
1016  }
1017 <NameSpaceDocArg1>{DOCNL} { // missing argument
1018  warn(yyextra->fileName,yyextra->lineNr,
1019  "missing argument after "
1020  "\\namespace."
1021  );
1022  unput_string(yytext,yyleng);
1023  //addOutput(yyscanner,'\n');
1024  //if (*yytext=='\n') yyextra->lineNr++;
1025  BEGIN( Comment );
1026  }
1027 <NameSpaceDocArg1>. { // ignore other stuff
1028  }
1029 
1030  /* ------------ handle argument of package command --------------- */
1031 
1032 <PackageDocArg1>{ID}("."{ID})* { // handle argument
1033  yyextra->current->name = yytext;
1034  BEGIN( Comment );
1035  }
1036 <PackageDocArg1>{LC} { // line continuation
1037  yyextra->lineNr++;
1038  addOutput(yyscanner,'\n');
1039  }
1040 <PackageDocArg1>{DOCNL} { // missing argument
1041  warn(yyextra->fileName,yyextra->lineNr,
1042  "missing argument after "
1043  "\\package."
1044  );
1045  unput_string(yytext,yyleng);
1046  //addOutput(yyscanner,'\n');
1047  //if (*yytext=='\n') yyextra->lineNr++;
1048  BEGIN( Comment );
1049  }
1050 <PackageDocArg1>. { // ignore other stuff
1051  }
1052 
1053  /* ------------ handle argument of concept command --------------- */
1054 
1055 <ConceptDocArg1>{SCOPEID} { // handle argument
1056  yyextra->current->name = yytext;
1057  BEGIN( Comment );
1058  }
1059 <ConceptDocArg1>{LC} { // line continuation
1060  yyextra->lineNr++;
1061  addOutput(yyscanner,'\n');
1062  }
1063 <ConceptDocArg1>{DOCNL} { // missing argument
1064  warn(yyextra->fileName,yyextra->lineNr,
1065  "missing argument after "
1066  "\\concept."
1067  );
1068  unput_string(yytext,yyleng);
1069  BEGIN( Comment );
1070  }
1071 <ConceptDocArg1>. { // ignore other stuff
1072  }
1073 
1074 
1075  /* ------ handle argument of class/struct/union command --------------- */
1076 
1077 <ClassDocArg1>{SCOPENAME}{TMPLSPEC} {
1078  yyextra->current->name = substitute(removeRedundantWhiteSpace(QCString(yytext)),".","::");
1079  BEGIN( ClassDocArg2 );
1080  }
1081 <ClassDocArg1>{SCOPENAME} { // first argument
1082  yyextra->current->name = substitute(QCString(yytext),".","::");
1083  if (yyextra->current->section==Entry::PROTOCOLDOC_SEC)
1084  {
1085  yyextra->current->name+="-p";
1086  }
1087  // prepend outer scope name
1088  BEGIN( ClassDocArg2 );
1089  }
1090 <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" {
1091  yyextra->current->name = substitute(QCString(yytext),".","::");
1092  BEGIN( ClassDocArg2 );
1093  }
1094 <ClassDocArg1,CategoryDocArg1>{LC} { // line continuation
1095  yyextra->lineNr++;
1096  addOutput(yyscanner,'\n');
1097  }
1098 <ClassDocArg1,CategoryDocArg1>{DOCNL} {
1099  warn(yyextra->fileName,yyextra->lineNr,
1100  "missing argument after "
1101  "'\\%s'.",qPrint(yyextra->currentCmd)
1102  );
1103  //addOutput(yyscanner,'\n');
1104  //if (*yytext=='\n') yyextra->lineNr++;
1105  unput_string(yytext,yyleng);
1106  BEGIN( Comment );
1107  }
1108 <ClassDocArg1,CategoryDocArg1>. { // ignore other stuff
1109  }
1110 
1111 <ClassDocArg2>{DOCNL} {
1112  //addOutput(yyscanner,'\n');
1113  //if (*yytext=='\n') yyextra->lineNr++;
1114  unput_string(yytext,yyleng);
1115  BEGIN( Comment );
1116  }
1117 <ClassDocArg2>{FILE}|"<>" { // second argument; include file
1118  yyextra->current->includeFile = yytext;
1119  BEGIN( ClassDocArg3 );
1120  }
1121 <ClassDocArg2>{LC} { // line continuation
1122  yyextra->lineNr++;
1123  addOutput(yyscanner,'\n');
1124  }
1125 <ClassDocArg2>. { // ignore other stuff
1126  }
1127 
1128 <ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name
1129  yyextra->current->includeName = yytext;
1130  BEGIN( Comment );
1131  }
1132 <ClassDocArg3>{LC} { // line continuation
1133  yyextra->lineNr++;
1134  addOutput(yyscanner,'\n');
1135  }
1136 <ClassDocArg3>{DOCNL} {
1137  //if (*yytext=='\n') yyextra->lineNr++;
1138  unput_string(yytext,yyleng);
1139  BEGIN( Comment );
1140  }
1141 <ClassDocArg3>. { // ignore other stuff
1142  }
1143 
1144  /* --------- handle arguments of {def,add,weak}group commands --------- */
1145 
1146 <GroupDocArg1>{LABELID}(".html"?) { // group name
1147  yyextra->current->name = yytext;
1148  //lastDefGroup.groupname = yytext;
1149  //lastDefGroup.pri = yyextra->current->groupingPri();
1150  // the .html stuff is for Qt compatibility
1151  if (yyextra->current->name.right(5)==".html")
1152  {
1153  yyextra->current->name=yyextra->current->name.left(yyextra->current->name.length()-5);
1154  }
1155  yyextra->current->type.resize(0);
1156  BEGIN(GroupDocArg2);
1157  }
1158 <GroupDocArg1>"\\"{B}*"\n" { // line continuation
1159  yyextra->lineNr++;
1160  addOutput(yyscanner,'\n');
1161  }
1162 <GroupDocArg1>{DOCNL} { // missing argument!
1163  warn(yyextra->fileName,yyextra->lineNr,
1164  "missing group name after %s",
1165  yyextra->current->groupDocCmd()
1166  );
1167  //addOutput(yyscanner,'\n');
1168  //if (*yytext=='\n') yyextra->lineNr++;
1169  unput_string(yytext,yyleng);
1170  BEGIN( Comment );
1171  }
1172 <GroupDocArg1>. { // ignore other stuff
1173  }
1174 <GroupDocArg2>"\\"{B}*"\n" { // line continuation
1175  yyextra->lineNr++;
1176  addOutput(yyscanner,'\n');
1177  }
1178 <GroupDocArg2>[^\n\\]+ { // title (stored in type)
1179  yyextra->current->type += yytext;
1180  yyextra->current->type = yyextra->current->type.stripWhiteSpace();
1181  }
1182 <GroupDocArg2>{DOCNL} {
1183  if ( yyextra->current->groupDocType==Entry::GROUPDOC_NORMAL &&
1184  yyextra->current->type.isEmpty()
1185  ) // defgroup requires second argument
1186  {
1187  warn(yyextra->fileName,yyextra->lineNr,
1188  "missing title after "
1189  "\\defgroup %s", qPrint(yyextra->current->name)
1190  );
1191  }
1192  unput_string(yytext,yyleng);
1193  //if (*yytext=='\n') yyextra->lineNr++;
1194  //addOutput(yyscanner,'\n');
1195  BEGIN( Comment );
1196  }
1197 <GroupDocArg2>. { // title (stored in type)
1198  yyextra->current->type += yytext;
1199  yyextra->current->type = yyextra->current->type.stripWhiteSpace();
1200  }
1201 
1202  /* --------- handle arguments of page/mainpage command ------------------- */
1203 
1204 <PageDocArg1>{FILE} { // first argument; page name
1205  yyextra->current->name = stripQuotes(yytext);
1206  yyextra->current->args = "";
1207  BEGIN( PageDocArg2 );
1208  }
1209 <PageDocArg1>{LC} { yyextra->lineNr++;
1210  addOutput(yyscanner,'\n');
1211  }
1212 <PageDocArg1>{DOCNL} {
1213  warn(yyextra->fileName,yyextra->lineNr,
1214  "missing argument after "
1215  "\\page."
1216  );
1217  unput_string(yytext,yyleng);
1218  //if (*yytext=='\n') yyextra->lineNr++;
1219  //addOutput(yyscanner,'\n');
1220  BEGIN( Comment );
1221  }
1222 <PageDocArg1>. { // ignore other stuff
1223  }
1224 <PageDocArg2>{DOCNL} { // second argument; page title
1225  unput_string(yytext,yyleng);
1226  //if (*yytext=='\n') yyextra->lineNr++;
1227  //addOutput(yyscanner,'\n');
1228  BEGIN( Comment );
1229  }
1230 <PageDocArg2>{CMD}[<>] {
1231  // bug 748927
1232  QCString tmp(yytext);
1233  tmp = substitute(substitute(tmp,"@<","&lt;"),"@>","&gt;");
1234  tmp = substitute(substitute(tmp,"\<","&lt;"),"\>","&gt;");
1235  yyextra->current->args += tmp;
1236  }
1237 <PageDocArg2>. {
1238  yyextra->current->args += yytext;
1239  }
1240  /* --------- handle arguments of the param command ------------ */
1241 <ParamArg1>{ID}/{B}*"," {
1242  addOutput(yyscanner,yytext);
1243  }
1244 <ParamArg1>"," {
1245  addOutput(yyscanner," , ");
1246  }
1247 <ParamArg1>{DOCNL} {
1248  if (*yytext=='\n') yyextra->lineNr++;
1249  addOutput(yyscanner," ");
1250  }
1251 <ParamArg1>{ID} {
1252  addOutput(yyscanner,yytext);
1253  BEGIN( Comment );
1254  }
1255 <ParamArg1>. {
1256  unput(yytext[0]);
1257  BEGIN( Comment );
1258  }
1259 
1260  /* --------- handle arguments of the file/dir/example command ------------ */
1261 
1262 <FileDocArg1>{DOCNL} { // no file name specified
1263  unput_string(yytext,yyleng);
1264  //if (*yytext=='\n') yyextra->lineNr++;
1265  //addOutput(yyscanner,'\n');
1266  BEGIN( Comment );
1267  }
1268 <FileDocArg1>{FILE} { // first argument; name
1269  yyextra->current->name = stripQuotes(yytext);
1270  BEGIN( Comment );
1271  }
1272 <FileDocArg1>{LC} { yyextra->lineNr++;
1273  addOutput(yyscanner,'\n');
1274  }
1275 <FileDocArg1>. { // ignore other stuff
1276  }
1277 
1278  /* --------- handle arguments of the xrefitem command ------------ */
1279 
1280 <XRefItemParam1>{LABELID} { // first argument
1281  yyextra->newXRefItemKey=yytext;
1282  setOutput(yyscanner,OutputXRef);
1283  BEGIN(XRefItemParam2);
1284  }
1285 <XRefItemParam1>{LC} { // line continuation
1286  yyextra->lineNr++;
1287  addOutput(yyscanner,'\n');
1288  }
1289 <XRefItemParam1>{DOCNL} { // missing arguments
1290  warn(yyextra->fileName,yyextra->lineNr,
1291  "Missing first argument of \\xrefitem"
1292  );
1293  if (*yytext=='\n') yyextra->lineNr++;
1294  addOutput(yyscanner,'\n');
1295  yyextra->inContext = OutputDoc;
1296  BEGIN( Comment );
1297  }
1298 <XRefItemParam1>. { // ignore other stuff
1299  }
1300 
1301 <XRefItemParam2>"\""[^\n\"]*"\"" { // second argument
1302  yyextra->xrefItemTitle = stripQuotes(yytext);
1303  BEGIN(XRefItemParam3);
1304  }
1305 <XRefItemParam2>{LC} { // line continuation
1306  yyextra->lineNr++;
1307  addOutput(yyscanner,'\n');
1308  }
1309 <XRefItemParam2>{DOCNL} { // missing argument
1310  warn(yyextra->fileName,yyextra->lineNr,
1311  "Missing second argument of \\xrefitem"
1312  );
1313  if (*yytext=='\n') yyextra->lineNr++;
1314  addOutput(yyscanner,'\n');
1315  yyextra->inContext = OutputDoc;
1316  BEGIN( Comment );
1317  }
1318 <XRefItemParam2>. { // ignore other stuff
1319  }
1320 
1321 <XRefItemParam3>"\""[^\n\"]*"\"" { // third argument
1322  yyextra->xrefListTitle = stripQuotes(yytext);
1323  yyextra->xrefKind = XRef_Item;
1324  BEGIN( Comment );
1325  }
1326 <XRefItemParam2,XRefItemParam3>{LC} { // line continuation
1327  yyextra->lineNr++;
1328  addOutput(yyscanner,'\n');
1329  }
1330 <XRefItemParam3>{DOCNL} { // missing argument
1331  warn(yyextra->fileName,yyextra->lineNr,
1332  "Missing third argument of \\xrefitem"
1333  );
1334  if (*yytext=='\n') yyextra->lineNr++;
1335  addOutput(yyscanner,'\n');
1336  yyextra->inContext = OutputDoc;
1337  BEGIN( Comment );
1338  }
1339 <XRefItemParam3>. { // ignore other stuff
1340  }
1341 
1342 
1343  /* ----- handle arguments of the relates(also)/memberof command ------- */
1344 
1345 <RelatesParam1>({ID}("::"|"."))*{ID} { // argument
1346  yyextra->current->relates = yytext;
1347  //if (yyextra->current->mGrpId!=DOX_NOGROUP)
1348  //{
1349  // memberGroupRelates = yytext;
1350  //}
1351  BEGIN( Comment );
1352  }
1353 <RelatesParam1>{LC} { // line continuation
1354  yyextra->lineNr++;
1355  addOutput(yyscanner,'\n');
1356  }
1357 <RelatesParam1>{DOCNL} { // missing argument
1358  warn(yyextra->fileName,yyextra->lineNr,
1359  "Missing argument of '\\%s' command",qPrint(yyextra->currentCmd)
1360  );
1361  unput_string(yytext,yyleng);
1362  //if (*yytext=='\n') yyextra->lineNr++;
1363  //addOutput(yyscanner,'\n');
1364  BEGIN( Comment );
1365  }
1366 <RelatesParam1>. { // ignore other stuff
1367  }
1368 
1369 
1370  /* ----- handle arguments of the relates(also)/addindex commands ----- */
1371 
1372 <LineParam>{DOCNL} { // end of argument
1373  //if (*yytext=='\n') yyextra->lineNr++;
1374  //addOutput(yyscanner,'\n');
1375  unput_string(yytext,yyleng);
1376  BEGIN( Comment );
1377  }
1378 <LineParam>{LC} { // line continuation
1379  yyextra->lineNr++;
1380  addOutput(yyscanner,'\n');
1381  }
1382 <LineParam>. { // ignore other stuff
1383  addOutput(yyscanner,*yytext);
1384  }
1385 
1386  /* ----- handle arguments of the section/subsection/.. commands ------- */
1387 
1388 <SectionLabel>{LABELID} { // first argument
1389  yyextra->sectionLabel=yytext;
1390  addOutput(yyscanner,yytext);
1391  yyextra->sectionTitle.resize(0);
1392  BEGIN(SectionTitle);
1393  }
1394 <SectionLabel>{DOCNL} { // missing argument
1395  warn(yyextra->fileName,yyextra->lineNr,
1396  "\\section command has no label"
1397  );
1398  if (*yytext=='\n') yyextra->lineNr++;
1399  addOutput(yyscanner,'\n');
1400  BEGIN( Comment );
1401  }
1402 <SectionLabel>. { // invalid character for section label
1403  warn(yyextra->fileName,yyextra->lineNr,
1404  "Invalid or missing section label"
1405  );
1406  BEGIN(Comment);
1407  }
1408 <SectionTitle>{STAopt}/"\n" { // end of section title
1409  addSection(yyscanner);
1410  addOutput(yyscanner,yytext);
1411  BEGIN( Comment );
1412  }
1413 <SectionTitle>{STopt}/"\\ilinebr" { // end of section title
1414  addSection(yyscanner);
1415  addOutput(yyscanner,yytext);
1416  BEGIN( Comment );
1417  }
1418 <SectionTitle>{LC} { // line continuation
1419  yyextra->lineNr++;
1420  addOutput(yyscanner,'\n');
1421  }
1422 <SectionTitle>[^\n@\\]* { // any character without special meaning
1423  yyextra->sectionTitle+=yytext;
1424  addOutput(yyscanner,yytext);
1425  }
1426 <SectionTitle>({CMD}{CMD}){ID} { // unescape escaped command
1427  yyextra->sectionTitle+=&yytext[1];
1428  addOutput(yyscanner,yytext);
1429  }
1430 <SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character
1431  yyextra->sectionTitle+=yytext[1];
1432  addOutput(yyscanner,yytext);
1433  }
1434 <SectionTitle>. { // anything else
1435  yyextra->sectionTitle+=yytext;
1436  addOutput(yyscanner,*yytext);
1437  }
1438 
1439  /* ----- handle arguments of the subpage command ------- */
1440 
1441 <SubpageLabel>{LABELID} { // first argument
1442  addOutput(yyscanner,yytext);
1443  // we add subpage labels as a kind of "inheritance" relation to prevent
1444  // needing to add another list to the Entry class.
1445  yyextra->current->extends.push_back(BaseInfo(QCString(yytext),Public,Normal));
1446  BEGIN(SubpageTitle);
1447  }
1448 <SubpageLabel>{DOCNL} { // missing argument
1449  warn(yyextra->fileName,yyextra->lineNr,
1450  "\\subpage command has no label"
1451  );
1452  if (*yytext=='\n') yyextra->lineNr++;
1453  addOutput(yyscanner,'\n');
1454  BEGIN( Comment );
1455  }
1456 <SubpageTitle>{DOCNL} { // no title, end command
1457  addOutput(yyscanner,yytext);
1458  BEGIN( Comment );
1459  }
1460 <SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command
1461  addOutput(yyscanner,yytext);
1462  BEGIN( Comment );
1463  }
1464 <SubpageTitle>. { // no title, end of command
1465  unput(*yytext);
1466  BEGIN( Comment );
1467  }
1468 
1469  /* ----- handle arguments of the anchor command ------- */
1470 
1471 <AnchorLabel>{LABELID} { // found argument
1472  addAnchor(yyscanner,QCString(yytext));
1473  addOutput(yyscanner,yytext);
1474  BEGIN( Comment );
1475  }
1476 <AnchorLabel>{DOCNL} { // missing argument
1477  warn(yyextra->fileName,yyextra->lineNr,
1478  "\\anchor command has no label"
1479  );
1480  if (*yytext=='\n') yyextra->lineNr++;
1481  addOutput(yyscanner,'\n');
1482  BEGIN( Comment );
1483  }
1484 <AnchorLabel>. { // invalid character for anchor label
1485  warn(yyextra->fileName,yyextra->lineNr,
1486  "Invalid or missing anchor label"
1487  );
1488  BEGIN(Comment);
1489  }
1490 
1491 
1492  /* ----- handle arguments of the preformatted block commands ------- */
1493 
1494 <FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc")/{NW} { // possible ends
1495  addOutput(yyscanner,yytext);
1496  if (&yytext[4]==yyextra->blockName) // found end of the block
1497  {
1498  BEGIN(Comment);
1499  }
1500  }
1501 <FormatBlock>{CMD}"enduml" {
1502  addOutput(yyscanner,yytext);
1503  if (yyextra->blockName=="startuml") // found end of the block
1504  {
1505  BEGIN(Comment);
1506  }
1507  }
1508 <FormatBlock>[^ \@\*\/\\\n]* { // some word
1509  addOutput(yyscanner,yytext);
1510  }
1511 <FormatBlock>{DOCNL} { // new line
1512  if (*yytext=='\n') yyextra->lineNr++;
1513  addOutput(yyscanner,'\n');
1514  }
1515 <FormatBlock>{CCS} { // start of a C-comment
1516  if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim")) yyextra->commentCount++;
1517  addOutput(yyscanner,yytext);
1518  }
1519 <FormatBlock>{CCE} { // end of a C-comment
1520  addOutput(yyscanner,yytext);
1521  if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim"))
1522  {
1523  yyextra->commentCount--;
1524  if (yyextra->commentCount<0)
1525  {
1526  QCString endTag = "end"+yyextra->blockName;
1527  if (yyextra->blockName=="startuml") endTag="enduml";
1528  warn(yyextra->fileName,yyextra->lineNr,
1529  "found */ without matching /* while inside a \\%s block! Perhaps a missing \\%s?\n",qPrint(yyextra->blockName),qPrint(endTag));
1530  }
1531  }
1532  }
1533 <FormatBlock>. {
1534  addOutput(yyscanner,*yytext);
1535  }
1536 <FormatBlock><<EOF>> {
1537  QCString endTag = "end"+yyextra->blockName;
1538  if (yyextra->blockName=="startuml") endTag="enduml";
1539  warn(yyextra->fileName,yyextra->lineNr,
1540  "reached end of comment while inside a \\%s block; check for missing \\%s tag!",
1541  qPrint(yyextra->blockName),qPrint(endTag)
1542  );
1543  yyterminate();
1544  }
1545 
1546  /* ----- handle arguments of if/ifnot commands ------- */
1547 
1548 <GuardParam>{B}*"(" {
1549  yyextra->guardExpr=yytext;
1550  yyextra->roundCount=1;
1551  BEGIN(GuardExpr);
1552  }
1553 <GuardExpr>[^()]* {
1554  yyextra->guardExpr+=yytext;
1555  lineCount(yyscanner);
1556  }
1557 <GuardExpr>"(" {
1558  yyextra->guardExpr+=yytext;
1559  yyextra->roundCount++;
1560  }
1561 <GuardExpr>")" {
1562  yyextra->guardExpr+=yytext;
1563  yyextra->roundCount--;
1564  if (yyextra->roundCount==0)
1565  {
1566  handleGuard(yyscanner,yyextra->guardExpr);
1567  }
1568  }
1569 <GuardExpr>\n {
1570  warn(yyextra->fileName,yyextra->lineNr,
1571  "invalid expression '%s' for yyextra->guards",qPrint(yyextra->guardExpr));
1572  unput(*yytext);
1573  BEGIN(GuardParam);
1574  }
1575 <GuardParam>{B}*[a-z_A-Z0-9.\-]+ { // parameter of if/ifnot yyextra->guards
1576  handleGuard(yyscanner,QCString(yytext));
1577  }
1578 <GuardParam>{DOCNL} { // end of argument
1579  if (*yytext=='\n') yyextra->lineNr++;
1580  //next line is commented out due to bug620924
1581  //addOutput(yyscanner,'\n');
1582  addIline(yyscanner,yyextra->lineNr);
1583  BEGIN( Comment );
1584  }
1585 <GuardParam>{LC} { // line continuation
1586  yyextra->lineNr++;
1587  addOutput(yyscanner,'\n');
1588  }
1589 <GuardParam>. { // ignore other stuff
1590  addOutput(yyscanner,*yytext);
1591  }
1592 <GuardParamEnd>{B}*{DOCNL} {
1593  lineCount(yyscanner);
1594  yyextra->spaceBeforeIf.resize(0);
1595  addIline(yyscanner,yyextra->lineNr);
1596  BEGIN(Comment);
1597  }
1598 <GuardParamEnd>{B}* {
1599  if (!yyextra->spaceBeforeIf.isEmpty()) // needed for 665313 in combination with bug620924
1600  {
1601  addOutput(yyscanner,yyextra->spaceBeforeIf);
1602  }
1603  yyextra->spaceBeforeIf.resize(0);
1604  addIline(yyscanner,yyextra->lineNr);
1605  BEGIN(Comment);
1606  }
1607 <GuardParamEnd>. {
1608  unput(*yytext);
1609  addIline(yyscanner,yyextra->lineNr);
1610  BEGIN(Comment);
1611  }
1612 
1613  /* ----- handle skipping of conditional sections ------- */
1614 
1615 <SkipGuardedSection>{CMD}"ifnot"/{NW} {
1616  yyextra->guardType = Guard_IfNot;
1617  BEGIN( GuardParam );
1618  }
1619 <SkipGuardedSection>{CMD}"if"/{NW} {
1620  yyextra->guardType = Guard_If;
1621  BEGIN( GuardParam );
1622  }
1623 <SkipGuardedSection>{CMD}"endif"/{NW} {
1624  if (yyextra->guards.empty())
1625  {
1626  warn(yyextra->fileName,yyextra->lineNr,
1627  "found \\endif without matching start command");
1628  }
1629  else
1630  {
1631  GuardedSection s = yyextra->guards.top();
1632  yyextra->guards.pop();
1633  bool parentVisible = s.parentVisible();
1634  if (parentVisible)
1635  {
1636  yyextra->enabledSectionFound=TRUE;
1637  BEGIN( GuardParamEnd );
1638  }
1639  }
1640  }
1641 <SkipGuardedSection>{CMD}"else"/{NW} {
1642  if (yyextra->guards.empty())
1643  {
1644  warn(yyextra->fileName,yyextra->lineNr,
1645  "found \\else without matching start command");
1646  }
1647  else
1648  {
1649  if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible())
1650  {
1651  yyextra->guards.pop();
1652  yyextra->guards.push(GuardedSection(TRUE,TRUE));
1653  yyextra->enabledSectionFound=TRUE;
1654  BEGIN( GuardParamEnd );
1655  }
1656  }
1657  }
1658 <SkipGuardedSection>{CMD}"elseif"/{NW} {
1659  if (yyextra->guards.empty())
1660  {
1661  warn(yyextra->fileName,yyextra->lineNr,
1662  "found \\elseif without matching start command");
1663  }
1664  else
1665  {
1666  if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible())
1667  {
1668  yyextra->guardType=Guard_If;
1669  yyextra->guards.pop();
1670  BEGIN( GuardParam );
1671  }
1672  }
1673  }
1674 <SkipGuardedSection>{DOCNL} { // skip line
1675  if (*yytext=='\n') yyextra->lineNr++;
1676  //addOutput(yyscanner,'\n');
1677  }
1678 <SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters
1679  }
1680 <SkipGuardedSection>. { // any other character
1681  }
1682 
1683 
1684  /* ----- handle skipping of internal section ------- */
1685 
1686 <SkipInternal>{DOCNL} { // skip line
1687  if (*yytext=='\n') yyextra->lineNr++;
1688  addOutput(yyscanner,'\n');
1689  }
1690 <SkipInternal>[@\\]"if"/[ \t] {
1691  yyextra->condCount++;
1692  }
1693 <SkipInternal>[@\\]"ifnot"/[ \t] {
1694  yyextra->condCount++;
1695  }
1696 <SkipInternal>[@\\]/"endif" {
1697  yyextra->condCount--;
1698  if (yyextra->condCount<0) // handle conditional section around of \internal, see bug607743
1699  {
1700  unput('\\');
1701  BEGIN(Comment);
1702  }
1703  }
1704 <SkipInternal>[@\\]/"section"[ \t] {
1705  if (yyextra->sectionLevel>0)
1706  {
1707  unput('\\');
1708  BEGIN(Comment);
1709  }
1710  }
1711 <SkipInternal>[@\\]/"subsection"[ \t] {
1712  if (yyextra->sectionLevel>1)
1713  {
1714  unput('\\');
1715  BEGIN(Comment);
1716  }
1717  }
1718 <SkipInternal>[@\\]/"subsubsection"[ \t] {
1719  if (yyextra->sectionLevel>2)
1720  {
1721  unput('\\');
1722  BEGIN(Comment);
1723  }
1724  }
1725 <SkipInternal>[@\\]/"paragraph"[ \t] {
1726  if (yyextra->sectionLevel>3)
1727  {
1728  unput('\\');
1729  BEGIN(Comment);
1730  }
1731  }
1732 <SkipInternal>[@\\]"endinternal"[ \t]* {
1733  BEGIN(Comment);
1734  }
1735 <SkipInternal>[^ \\@\n]+ { // skip non-special characters
1736  }
1737 <SkipInternal>. { // any other character
1738  }
1739 
1740 
1741  /* ----- handle argument of name command ------- */
1742 
1743 <NameParam>{DOCNL} { // end of argument
1744  //if (*yytext=='\n') yyextra->lineNr++;
1745  //addOutput(yyscanner,'\n');
1746  unput_string(yytext,yyleng);
1747  BEGIN( Comment );
1748  }
1749 <NameParam>{LC} { // line continuation
1750  yyextra->lineNr++;
1751  addOutput(yyscanner,'\n');
1752  yyextra->docGroup.appendHeader(' ');
1753  }
1754 <NameParam>. { // ignore other stuff
1755  yyextra->docGroup.appendHeader(*yytext);
1756  yyextra->current->name+=*yytext;
1757  }
1758 
1759  /* ----- handle argument of noop command ------- */
1760 <Noop>{DOCNL} { // end of argument
1761  if (*yytext=='\n') yyextra->lineNr++;
1762  addOutput(yyscanner,'\n');
1763  BEGIN( Comment );
1764  }
1765 <Noop>. { // ignore other stuff
1766  }
1767  /* ----- handle argument of ingroup command ------- */
1768 
1769 <InGroupParam>{LABELID} { // group id
1770  yyextra->current->groups.push_back(
1771  Grouping(QCString(yytext), Grouping::GROUPING_INGROUP)
1772  );
1773  yyextra->inGroupParamFound=TRUE;
1774  }
1775 <InGroupParam>{DOCNL} { // missing argument
1776  if (!yyextra->inGroupParamFound)
1777  {
1778  warn(yyextra->fileName,yyextra->lineNr,
1779  "Missing group name for \\ingroup command"
1780  );
1781  }
1782  //if (*yytext=='\n') yyextra->lineNr++;
1783  //addOutput(yyscanner,'\n');
1784  unput_string(yytext,yyleng);
1785  BEGIN( Comment );
1786  }
1787 <InGroupParam>{LC} { // line continuation
1788  yyextra->lineNr++;
1789  addOutput(yyscanner,'\n');
1790  }
1791 <InGroupParam>. { // ignore other stuff
1792  addOutput(yyscanner,*yytext);
1793  }
1794 
1795  /* ----- handle argument of fn command ------- */
1796 
1797 <FnParam>{DOCNL} { // end of argument
1798  if (yyextra->braceCount==0)
1799  {
1800  //if (*yytext=='\n') yyextra->lineNr++;
1801  //addOutput(yyscanner,'\n');
1802  unput_string(yytext,yyleng);
1803  yyextra->langParser->parsePrototype(yyextra->functionProto);
1804  BEGIN( Comment );
1805  }
1806  }
1807 <FnParam>{LC} { // line continuation
1808  yyextra->lineNr++;
1809  yyextra->functionProto+=' ';
1810  }
1811 <FnParam>[^@\\\n()]+ { // non-special characters
1812  yyextra->functionProto+=yytext;
1813  }
1814 <FnParam>"(" {
1815  yyextra->functionProto+=yytext;
1816  yyextra->braceCount++;
1817  }
1818 <FnParam>")" {
1819  yyextra->functionProto+=yytext;
1820  yyextra->braceCount--;
1821  }
1822 <FnParam>. { // add other stuff
1823  yyextra->functionProto+=*yytext;
1824  }
1825 
1826 
1827  /* ----- handle argument of overload command ------- */
1828 
1829 
1830 <OverloadParam>{DOCNL} { // end of argument
1831  if (*yytext=='\n') yyextra->lineNr++;
1832  if (yyextra->functionProto.stripWhiteSpace().isEmpty())
1833  { // plain overload command
1834  addOutput(yyscanner,getOverloadDocs());
1835  addOutput(yyscanner,'\n');
1836  }
1837  else // overload declaration
1838  {
1839  makeStructuralIndicator(yyscanner,Entry::OVERLOADDOC_SEC);
1840  yyextra->langParser->parsePrototype(yyextra->functionProto);
1841  }
1842  BEGIN( Comment );
1843  }
1844 <OverloadParam>{LC} { // line continuation
1845  yyextra->lineNr++;
1846  yyextra->functionProto+=' ';
1847  }
1848 <OverloadParam>. { // add other stuff
1849  yyextra->functionProto+=*yytext;
1850  }
1851 
1852  /* ----- handle argument of inherit command ------- */
1853 
1854 <InheritParam>({ID}("::"|"."))*{ID} { // found argument
1855  yyextra->current->extends.push_back(
1856  BaseInfo(removeRedundantWhiteSpace(QCString(yytext)),Public,Normal)
1857  );
1858  BEGIN( Comment );
1859  }
1860 <InheritParam>{DOCNL} { // missing argument
1861  warn(yyextra->fileName,yyextra->lineNr,
1862  "\\inherit command has no argument"
1863  );
1864  if (*yytext=='\n') yyextra->lineNr++;
1865  addOutput(yyscanner,'\n');
1866  BEGIN( Comment );
1867  }
1868 <InheritParam>. { // invalid character for anchor label
1869  warn(yyextra->fileName,yyextra->lineNr,
1870  "Invalid or missing name for \\inherit command"
1871  );
1872  BEGIN(Comment);
1873  }
1874 
1875  /* ----- handle argument of extends and implements commands ------- */
1876 
1877 <ExtendsParam>({ID}("::"|"."))*{ID} { // found argument
1878  yyextra->current->extends.push_back(
1879  BaseInfo(removeRedundantWhiteSpace(QCString(yytext)),Public,Normal)
1880  );
1881  BEGIN( Comment );
1882  }
1883 <ExtendsParam>{DOCNL} { // missing argument
1884  warn(yyextra->fileName,yyextra->lineNr,
1885  "'\\%s' command has no argument",qPrint(yyextra->currentCmd)
1886  );
1887  //if (*yytext=='\n') yyextra->lineNr++;
1888  //addOutput(yyscanner,'\n');
1889  unput_string(yytext,yyleng);
1890  BEGIN( Comment );
1891  }
1892 <ExtendsParam>. { // ignore other stuff
1893  }
1894 
1895  /* ----- handle language specific sections ------- */
1896 
1897 <SkipLang>[\\@]"~"[a-zA-Z-]* { /* language switch */
1898  QCString langId(&yytext[2]);
1899  if (langId.isEmpty() ||
1900  qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE).data(),langId.data())==0)
1901  { // enable language specific section
1902  BEGIN(Comment);
1903  }
1904  }
1905 <SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
1906  }
1907 <SkipLang>{DOCNL} { /* new line in verbatim block */
1908  if (*yytext=='\n') yyextra->lineNr++;
1909  }
1910 <SkipLang>. { /* any other character */
1911  }
1912 
1913  /* ----- handle arguments of the cite command ------- */
1914 
1915 <CiteLabel>{CITEID} { // found argument
1916  addCite(yyscanner);
1917  addOutput(yyscanner,yytext);
1918  BEGIN(Comment);
1919  }
1920 <CiteLabel>{DOCNL} { // missing argument
1921  warn(yyextra->fileName,yyextra->lineNr,
1922  "\\cite command has no label"
1923  );
1924  //if (*yytext=='\n') yyextra->lineNr++;
1925  //addOutput(yyscanner,'\n');
1926  unput_string(yytext,yyleng);
1927  BEGIN( Comment );
1928  }
1929 <CiteLabel>. { // invalid character for cite label
1930  warn(yyextra->fileName,yyextra->lineNr,
1931  "Invalid or missing cite label"
1932  );
1933  BEGIN(Comment);
1934  }
1935 
1936  /* ----- handle argument of the copydoc command ------- */
1937 
1938 <CopyDoc><<EOF>> |
1939 <CopyDoc>{DOCNL} {
1940  if (*yytext=='\n') yyextra->lineNr++;
1941  addOutput(yyscanner,'\n');
1942  setOutput(yyscanner,OutputDoc);
1943  addOutput(yyscanner," \\copydetails ");
1944  addOutput(yyscanner,yyextra->copyDocArg);
1945  addOutput(yyscanner,"\n");
1946  BEGIN(Comment);
1947  }
1948 <CopyDoc>[^\n\\]+ {
1949  yyextra->copyDocArg+=yytext;
1950  addOutput(yyscanner,yytext);
1951  }
1952 <CopyDoc>. {
1953  yyextra->copyDocArg+=yytext;
1954  addOutput(yyscanner,yytext);
1955  }
1956 
1957  /*
1958 <*>. { fprintf(stderr,"Lex scanner %s %sdefault rule for state %s: #%s#\n", __FILE__,yyextra->fileName ? ("(" + yyextra->fileName +") ").data(): "",stateToString(YY_START),yytext);}
1959 <*>\n { fprintf(stderr,"Lex scanner %s %sdefault rule newline for state %s.\n", __FILE__, yyextra->fileName ? ("(" + yyextra->fileName +") ").data(): "",stateToString(YY_START));}
1960  */
1961 
1962 %%
1963 
1964 //----------------------------------------------------------------------------
1965 
1966 static bool handleBrief(yyscan_t yyscanner,const QCString &, const StringVector &)
1967 {
1968  //printf("handleBrief\n");
1969  setOutput(yyscanner,OutputBrief);
1970  return FALSE;
1971 }
1972 
1973 static bool handleFn(yyscan_t yyscanner,const QCString &, const StringVector &)
1974 {
1975  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1976  bool stop=makeStructuralIndicator(yyscanner,Entry::MEMBERDOC_SEC);
1977  yyextra->functionProto.resize(0);
1978  yyextra->braceCount=0;
1979  BEGIN(FnParam);
1980  return stop;
1981 }
1982 
1983 static bool handleDef(yyscan_t yyscanner,const QCString &, const StringVector &)
1984 {
1985  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1986  bool stop=makeStructuralIndicator(yyscanner,Entry::DEFINEDOC_SEC);
1987  yyextra->functionProto.resize(0);
1988  BEGIN(FnParam);
1989  return stop;
1990 }
1991 
1992 static bool handleOverload(yyscan_t yyscanner,const QCString &, const StringVector &)
1993 {
1994  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1995  yyextra->functionProto.resize(0);
1996  BEGIN(OverloadParam);
1997  return FALSE;
1998 }
1999 
2000 static bool handleEnum(yyscan_t yyscanner,const QCString &, const StringVector &)
2001 {
2002  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2003  bool stop=makeStructuralIndicator(yyscanner,Entry::ENUMDOC_SEC);
2004  BEGIN(EnumDocArg1);
2005  return stop;
2006 }
2007 
2008 static bool handleDefGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2009 {
2010  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2011  bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2012  yyextra->current->groupDocType = Entry::GROUPDOC_NORMAL;
2013  BEGIN( GroupDocArg1 );
2014  return stop;
2015 }
2016 
2017 static bool handleAddToGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2018 {
2019  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2020  bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2021  yyextra->current->groupDocType = Entry::GROUPDOC_ADD;
2022  BEGIN( GroupDocArg1 );
2023  return stop;
2024 }
2025 
2026 static bool handleWeakGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2027 {
2028  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2029  bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2030  yyextra->current->groupDocType = Entry::GROUPDOC_WEAK;
2031  BEGIN( GroupDocArg1 );
2032  return stop;
2033 }
2034 
2035 static bool handleNamespace(yyscan_t yyscanner,const QCString &, const StringVector &)
2036 {
2037  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2038  bool stop=makeStructuralIndicator(yyscanner,Entry::NAMESPACEDOC_SEC);
2039  BEGIN( NameSpaceDocArg1 );
2040  return stop;
2041 }
2042 
2043 static bool handlePackage(yyscan_t yyscanner,const QCString &, const StringVector &)
2044 {
2045  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2046  bool stop=makeStructuralIndicator(yyscanner,Entry::PACKAGEDOC_SEC);
2047  BEGIN( PackageDocArg1 );
2048  return stop;
2049 }
2050 
2051 static bool handleClass(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2052 {
2053  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2054  bool stop=makeStructuralIndicator(yyscanner,Entry::CLASSDOC_SEC);
2055  yyextra->currentCmd = cmd;
2056  BEGIN( ClassDocArg1 );
2057  return stop;
2058 }
2059 
2060 static bool handleConcept(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2061 {
2062  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2063  bool stop=makeStructuralIndicator(yyscanner,Entry::CONCEPTDOC_SEC);
2064  yyextra->currentCmd = cmd;
2065  BEGIN( ConceptDocArg1 );
2066  return stop;
2067 }
2068 
2069 static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &)
2070 {
2071  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2072  BEGIN( ClassDocArg2 );
2073  return FALSE;
2074 }
2075 
2076 static bool handleProtocol(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2077 { // Obj-C protocol
2078  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2079  bool stop=makeStructuralIndicator(yyscanner,Entry::PROTOCOLDOC_SEC);
2080  yyextra->currentCmd = cmd;
2081  BEGIN( ClassDocArg1 );
2082  return stop;
2083 }
2084 
2085 static bool handleCategory(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2086 { // Obj-C category
2087  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2088  bool stop=makeStructuralIndicator(yyscanner,Entry::CATEGORYDOC_SEC);
2089  yyextra->currentCmd = cmd;
2090  BEGIN( CategoryDocArg1 );
2091  return stop;
2092 }
2093 
2094 static bool handleUnion(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2095 {
2096  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2097  bool stop=makeStructuralIndicator(yyscanner,Entry::UNIONDOC_SEC);
2098  yyextra->currentCmd = cmd;
2099  BEGIN( ClassDocArg1 );
2100  return stop;
2101 }
2102 
2103 static bool handleStruct(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2104 {
2105  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2106  bool stop=makeStructuralIndicator(yyscanner,Entry::STRUCTDOC_SEC);
2107  yyextra->currentCmd = cmd;
2108  BEGIN( ClassDocArg1 );
2109  return stop;
2110 }
2111 
2112 static bool handleInterface(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2113 {
2114  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2115  bool stop=makeStructuralIndicator(yyscanner,Entry::INTERFACEDOC_SEC);
2116  yyextra->currentCmd = cmd;
2117  BEGIN( ClassDocArg1 );
2118  return stop;
2119 }
2120 
2121 static bool handleIdlException(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2122 {
2123  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2124  bool stop=makeStructuralIndicator(yyscanner,Entry::EXCEPTIONDOC_SEC);
2125  yyextra->currentCmd = cmd;
2126  BEGIN( ClassDocArg1 );
2127  return stop;
2128 }
2129 
2130 static bool handlePage(yyscan_t yyscanner,const QCString &, const StringVector &)
2131 {
2132  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2133  bool stop=makeStructuralIndicator(yyscanner,Entry::PAGEDOC_SEC);
2134  BEGIN( PageDocArg1 );
2135  return stop;
2136 }
2137 
2138 static bool handleMainpage(yyscan_t yyscanner,const QCString &, const StringVector &)
2139 {
2140  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2141  bool stop=makeStructuralIndicator(yyscanner,Entry::MAINPAGEDOC_SEC);
2142  if (!stop)
2143  {
2144  yyextra->current->name = "mainpage";
2145  }
2146  BEGIN( PageDocArg2 );
2147  return stop;
2148 }
2149 
2150 static bool handleFile(yyscan_t yyscanner,const QCString &, const StringVector &)
2151 {
2152  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2153  bool stop=makeStructuralIndicator(yyscanner,Entry::FILEDOC_SEC);
2154  if (!stop)
2155  {
2156  yyextra->current->name = yyextra->fileName;
2157  }
2158  BEGIN( FileDocArg1 );
2159  return stop;
2160 }
2161 
2162 static bool handleParam(yyscan_t yyscanner,const QCString &, const StringVector &)
2163 {
2164  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2165  // we need process param and retval arguments to escape leading underscores in case of
2166  // markdown processing, see bug775493
2167  addOutput(yyscanner,"@param ");
2168  BEGIN( ParamArg1 );
2169  return FALSE;
2170 }
2171 
2172 static bool handleRetval(yyscan_t yyscanner,const QCString &, const StringVector &)
2173 {
2174  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2175  addOutput(yyscanner,"@retval ");
2176  BEGIN( ParamArg1 );
2177  return FALSE;
2178 }
2179 
2180 static bool handleDir(yyscan_t yyscanner,const QCString &, const StringVector &)
2181 {
2182  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2183  bool stop=makeStructuralIndicator(yyscanner,Entry::DIRDOC_SEC);
2184  if (!stop) yyextra->current->name = yyextra->fileName;
2185  BEGIN( FileDocArg1 );
2186  return stop;
2187 }
2188 
2189 static bool handleExample(yyscan_t yyscanner,const QCString &cmd, const StringVector &optList)
2190 {
2191  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2192  Entry::Sections section=Entry::EXAMPLE_SEC;
2193  for (const auto &opt : optList)
2194  {
2195  if (opt=="lineno")
2196  {
2197  section=Entry::EXAMPLE_LINENO_SEC;
2198  }
2199  else
2200  {
2201  warn(yyextra->fileName,yyextra->lineNr,
2202  "unsupported option '%s' for command '\\%s'",opt.c_str(),qPrint(cmd));
2203  }
2204  }
2205  bool stop=makeStructuralIndicator(yyscanner,section);
2206  if (!stop) yyextra->current->name = yyextra->fileName;
2207  BEGIN( FileDocArg1 );
2208  return stop;
2209 }
2210 
2211 static bool handleDetails(yyscan_t yyscanner,const QCString &, const StringVector &)
2212 {
2213  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2214  if (yyextra->inContext!=OutputBrief)
2215  {
2216  addOutput(yyscanner,"\\ilinebr\\ilinebr "); // treat @details outside brief description
2217  // as a new paragraph
2218  }
2219  setOutput(yyscanner,OutputDoc);
2220  return FALSE;
2221 }
2222 
2223 static bool handleNoop(yyscan_t yyscanner,const QCString &, const StringVector &)
2224 {
2225  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2226  BEGIN( Noop );
2227  return FALSE;
2228 }
2229 
2230 static bool handleName(yyscan_t yyscanner,const QCString &, const StringVector &)
2231 {
2232  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2233  bool stop=makeStructuralIndicator(yyscanner,Entry::MEMBERGRP_SEC);
2234  if (!stop)
2235  {
2236  yyextra->docGroup.clearHeader();
2237  BEGIN( NameParam );
2238  if (!yyextra->docGroup.isEmpty()) // end of previous member group
2239  {
2240  yyextra->docGroup.close(yyextra->current,yyextra->fileName,yyextra->lineNr,TRUE,true);
2241  }
2242  }
2243  return stop;
2244 }
2245 
2246 static bool handleTodo(yyscan_t yyscanner,const QCString &, const StringVector &)
2247 {
2248  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2249  yyextra->newXRefKind = XRef_Todo;
2250  setOutput(yyscanner,OutputXRef);
2251  yyextra->xrefKind = XRef_Todo;
2252  return FALSE;
2253 }
2254 
2255 static bool handleTest(yyscan_t yyscanner,const QCString &, const StringVector &)
2256 {
2257  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2258  yyextra->newXRefKind = XRef_Test;
2259  setOutput(yyscanner,OutputXRef);
2260  yyextra->xrefKind = XRef_Test;
2261  return FALSE;
2262 }
2263 
2264 static bool handleBug(yyscan_t yyscanner,const QCString &, const StringVector &)
2265 {
2266  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2267  yyextra->newXRefKind = XRef_Bug;
2268  setOutput(yyscanner,OutputXRef);
2269  yyextra->xrefKind = XRef_Bug;
2270  return FALSE;
2271 }
2272 
2273 static bool handleDeprecated(yyscan_t yyscanner,const QCString &, const StringVector &)
2274 {
2275  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2276  yyextra->newXRefKind = XRef_Deprecated;
2277  setOutput(yyscanner,OutputXRef);
2278  yyextra->xrefKind = XRef_Deprecated;
2279  return FALSE;
2280 }
2281 
2282 static bool handleXRefItem(yyscan_t yyscanner,const QCString &, const StringVector &)
2283 {
2284  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2285  yyextra->newXRefKind = XRef_Item;
2286  BEGIN(XRefItemParam1);
2287  return FALSE;
2288 }
2289 
2290 static bool handleParBlock(yyscan_t yyscanner,const QCString &, const StringVector &)
2291 {
2292  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2293  if (yyextra->insideParBlock)
2294  {
2295  warn(yyextra->fileName,yyextra->lineNr,
2296  "found \\parblock command while already in a parblock!");
2297  }
2298  if (!yyextra->spaceBeforeCmd.isEmpty())
2299  {
2300  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2301  yyextra->spaceBeforeCmd.resize(0);
2302  }
2303  addOutput(yyscanner,"@parblock ");
2304  yyextra->insideParBlock = TRUE;
2305  return FALSE;
2306 }
2307 
2308 static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const StringVector &)
2309 {
2310  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2311  if (!yyextra->insideParBlock)
2312  {
2313  warn(yyextra->fileName,yyextra->lineNr,
2314  "found \\endparblock command without matching \\parblock!");
2315  }
2316  addOutput(yyscanner,"@endparblock");
2317  setOutput(yyscanner,OutputDoc); // to end a parblock inside a xrefitem like context
2318  yyextra->insideParBlock = FALSE;
2319  return FALSE;
2320 }
2321 
2322 static bool handleRelated(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2323 {
2324  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2325  if (!yyextra->current->relates.isEmpty())
2326  {
2327  warn(yyextra->fileName,yyextra->lineNr,
2328  "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2329  }
2330  yyextra->current->relatesType = Simple;
2331  BEGIN(RelatesParam1);
2332  return FALSE;
2333 }
2334 
2335 static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2336 {
2337  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2338  if (!yyextra->current->relates.isEmpty())
2339  {
2340  warn(yyextra->fileName,yyextra->lineNr,
2341  "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2342  }
2343  yyextra->current->relatesType = Duplicate;
2344  yyextra->currentCmd = cmd;
2345  BEGIN(RelatesParam1);
2346  return FALSE;
2347 }
2348 
2349 static bool handleMemberOf(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2350 {
2351  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2352  if (!yyextra->current->relates.isEmpty())
2353  {
2354  warn(yyextra->fileName,yyextra->lineNr,
2355  "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2356  }
2357  yyextra->current->relatesType = MemberOf;
2358  yyextra->currentCmd = cmd;
2359  BEGIN(RelatesParam1);
2360  return FALSE;
2361 }
2362 
2363 static bool handleRefItem(yyscan_t yyscanner,const QCString &, const StringVector &)
2364 {
2365  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2366  addOutput(yyscanner,"@refitem ");
2367  BEGIN(LineParam);
2368  return FALSE;
2369 }
2370 
2371 static bool handleSection(yyscan_t yyscanner,const QCString &s, const StringVector &)
2372 {
2373  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2374  setOutput(yyscanner,OutputDoc);
2375  addOutput(yyscanner,"@"+s+" ");
2376  BEGIN(SectionLabel);
2377  if (s=="section") yyextra->sectionLevel=1;
2378  else if (s=="subsection") yyextra->sectionLevel=2;
2379  else if (s=="subsubsection") yyextra->sectionLevel=3;
2380  else if (s=="paragraph") yyextra->sectionLevel=4;
2381  return FALSE;
2382 }
2383 
2384 static bool handleSubpage(yyscan_t yyscanner,const QCString &s, const StringVector &)
2385 {
2386  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2387  if (yyextra->current->section!=Entry::EMPTY_SEC &&
2388  yyextra->current->section!=Entry::PAGEDOC_SEC &&
2389  yyextra->current->section!=Entry::MAINPAGEDOC_SEC
2390  )
2391  {
2392  warn(yyextra->fileName,yyextra->lineNr,
2393  "found \\subpage command in a comment block that is not marked as a page!");
2394  }
2395  if (!yyextra->spaceBeforeCmd.isEmpty())
2396  {
2397  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2398  yyextra->spaceBeforeCmd.resize(0);
2399  }
2400  addOutput(yyscanner,"@"+s+" ");
2401  BEGIN(SubpageLabel);
2402  return FALSE;
2403 }
2404 
2405 static bool handleAnchor(yyscan_t yyscanner,const QCString &s, const StringVector &)
2406 {
2407  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2408  addOutput(yyscanner,"@"+s+" ");
2409  BEGIN(AnchorLabel);
2410  return FALSE;
2411 }
2412 
2413 static bool handleImage(yyscan_t yyscanner,const QCString &s, const StringVector &optList)
2414 {
2415  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2416  for (const auto &opt : optList)
2417  {
2418  QCString locOpt(opt);
2419  locOpt = locOpt.stripWhiteSpace();
2420  if (locOpt.lower().startsWith("anchor:"))
2421  {
2422  addAnchor(yyscanner,locOpt.mid(7));
2423  break; // real option handling will be done later on
2424  }
2425  }
2426  if (optList.empty())
2427  {
2428  addOutput(yyscanner,"@"+s+" ");
2429  }
2430  else
2431  {
2432  addOutput(yyscanner,"@"+s+"{"+QCString(join(optList,","))+"} ");
2433  }
2434  BEGIN(Comment);
2435  return FALSE;
2436 }
2437 
2438 static bool handleCite(yyscan_t yyscanner,const QCString &s, const StringVector &)
2439 {
2440  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2441  if (!yyextra->spaceBeforeCmd.isEmpty())
2442  {
2443  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2444  yyextra->spaceBeforeCmd.resize(0);
2445  }
2446  addOutput(yyscanner,"@"+s+" ");
2447  BEGIN(CiteLabel);
2448  return FALSE;
2449 }
2450 
2451 static bool handleFormatBlock(yyscan_t yyscanner,const QCString &s, const StringVector &optList)
2452 {
2453  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2454  if (!yyextra->spaceBeforeCmd.isEmpty())
2455  {
2456  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2457  yyextra->spaceBeforeCmd.resize(0);
2458  }
2459  if (optList.empty())
2460  {
2461  addOutput(yyscanner,"@"+s+" ");
2462  }
2463  else
2464  {
2465  addOutput(yyscanner,"@"+s+"{"+QCString(join(optList,","))+"} ");
2466  }
2467  //printf("handleFormatBlock(%s) with option(%s)\n",qPrint(s),qPrint(opt));
2468  yyextra->blockName=s;
2469  yyextra->commentCount=0;
2470  BEGIN(FormatBlock);
2471  return FALSE;
2472 }
2473 
2474 static bool handleAddIndex(yyscan_t yyscanner,const QCString &, const StringVector &)
2475 {
2476  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2477  addOutput(yyscanner,"@addindex ");
2478  BEGIN(LineParam);
2479  return FALSE;
2480 }
2481 
2482 static bool handleIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2483 {
2484  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2485  yyextra->enabledSectionFound=FALSE;
2486  yyextra->guardType = Guard_If;
2487  yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2488  BEGIN(GuardParam);
2489  return FALSE;
2490 }
2491 
2492 static bool handleIfNot(yyscan_t yyscanner,const QCString &, const StringVector &)
2493 {
2494  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2495  yyextra->enabledSectionFound=FALSE;
2496  yyextra->guardType = Guard_IfNot;
2497  yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2498  BEGIN(GuardParam);
2499  return FALSE;
2500 }
2501 
2502 static bool handleElseIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2503 {
2504  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2505  if (yyextra->guards.empty())
2506  {
2507  warn(yyextra->fileName,yyextra->lineNr,
2508  "found \\else without matching start command");
2509  }
2510  else
2511  {
2512  yyextra->guardType = yyextra->enabledSectionFound ? Guard_Skip : Guard_If;
2513  yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2514  BEGIN(GuardParam);
2515  }
2516  return FALSE;
2517 }
2518 
2519 static bool handleElse(yyscan_t yyscanner,const QCString &, const StringVector &)
2520 {
2521  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2522  if (yyextra->guards.empty())
2523  {
2524  warn(yyextra->fileName,yyextra->lineNr,
2525  "found \\else without matching start command");
2526  }
2527  else
2528  {
2529  yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2530  BEGIN( SkipGuardedSection );
2531  }
2532  return FALSE;
2533 }
2534 
2535 static bool handleEndIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2536 {
2537  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2538  if (yyextra->guards.empty())
2539  {
2540  warn(yyextra->fileName,yyextra->lineNr,
2541  "found \\endif without matching start command");
2542  }
2543  else
2544  {
2545  yyextra->guards.pop();
2546  }
2547  yyextra->enabledSectionFound=FALSE;
2548  if (!yyextra->spaceBeforeCmd.isEmpty())
2549  {
2550  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2551  yyextra->spaceBeforeCmd.resize(0);
2552  }
2553  BEGIN( GuardParamEnd );
2554  return FALSE;
2555 }
2556 
2557 static bool handleIngroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2558 {
2559  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2560  yyextra->inGroupParamFound=FALSE;
2561  BEGIN( InGroupParam );
2562  return FALSE;
2563 }
2564 
2565 static bool handleNoSubGrouping(yyscan_t yyscanner,const QCString &, const StringVector &)
2566 {
2567  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2568  yyextra->current->subGrouping = FALSE;
2569  return FALSE;
2570 }
2571 
2572 static bool handleShowInitializer(yyscan_t yyscanner,const QCString &, const StringVector &)
2573 {
2574  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2575  yyextra->current->initLines = 100000; // ON
2576  return FALSE;
2577 }
2578 
2579 static bool handleHideInitializer(yyscan_t yyscanner,const QCString &, const StringVector &)
2580 {
2581  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2582  yyextra->current->initLines = 0; // OFF
2583  return FALSE;
2584 }
2585 
2586 static bool handleCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2587 {
2588  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2589  yyextra->current->callGraph = TRUE; // ON
2590  return FALSE;
2591 }
2592 
2593 static bool handleHideCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2594 {
2595  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2596  yyextra->current->callGraph = FALSE; // OFF
2597  return FALSE;
2598 }
2599 
2600 static bool handleCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2601 {
2602  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2603  yyextra->current->callerGraph = TRUE; // ON
2604  return FALSE;
2605 }
2606 
2607 static bool handleHideCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2608 {
2609  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2610  yyextra->current->callerGraph = FALSE; // OFF
2611  return FALSE;
2612 }
2613 
2614 static bool handleReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2615 {
2616  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2617  yyextra->current->referencedByRelation = TRUE; // ON
2618  return FALSE;
2619 }
2620 
2621 static bool handleHideReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2622 {
2623  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2624  yyextra->current->referencedByRelation = FALSE; // OFF
2625  return FALSE;
2626 }
2627 
2628 static bool handleReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2629 {
2630  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2631  yyextra->current->referencesRelation = TRUE; // ON
2632  return FALSE;
2633 }
2634 
2635 static bool handleHideReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2636 {
2637  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2638  yyextra->current->referencesRelation = FALSE; // OFF
2639  return FALSE;
2640 }
2641 
2642 static bool handleInternal(yyscan_t yyscanner,const QCString &, const StringVector &)
2643 {
2644  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2645  if (!Config_getBool(INTERNAL_DOCS))
2646  {
2647  // make sure some whitespace before a \internal command
2648  // is not treated as "documentation"
2649  if (yyextra->current->doc.stripWhiteSpace().isEmpty())
2650  {
2651  yyextra->current->doc.resize(0);
2652  }
2653  yyextra->condCount=0;
2654  BEGIN( SkipInternal );
2655  }
2656  else
2657  {
2658  // re-enabled for bug640828
2659  addOutput(yyscanner," \\internal ");
2660  yyextra->inInternalDocs = TRUE;
2661  }
2662  return FALSE;
2663 }
2664 
2665 static bool handleStatic(yyscan_t yyscanner,const QCString &, const StringVector &)
2666 {
2667  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2668  yyextra->current->stat = TRUE;
2669  return FALSE;
2670 }
2671 
2672 static bool handlePure(yyscan_t yyscanner,const QCString &, const StringVector &)
2673 {
2674  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2675  yyextra->current->virt = Pure;
2676  return FALSE;
2677 }
2678 
2679 static bool handlePrivate(yyscan_t yyscanner,const QCString &, const StringVector &)
2680 {
2681  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2682  yyextra->current->protection = Private;
2683  return FALSE;
2684 }
2685 
2686 static bool handlePrivateSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2687 {
2688  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2689  yyextra->current->protection = yyextra->protection = Private;
2690  return FALSE;
2691 }
2692 
2693 static bool handleProtected(yyscan_t yyscanner,const QCString &, const StringVector &)
2694 {
2695  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2696  yyextra->current->protection = Protected;
2697  return FALSE;
2698 }
2699 
2700 static bool handleProtectedSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2701 {
2702  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2703  yyextra->current->protection = yyextra->protection = Protected ;
2704  return FALSE;
2705 }
2706 
2707 static bool handlePublic(yyscan_t yyscanner,const QCString &, const StringVector &)
2708 {
2709  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2710  yyextra->current->protection = Public;
2711  return FALSE;
2712 }
2713 
2714 static bool handlePublicSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2715 {
2716  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2717  yyextra->current->protection = yyextra->protection = Public;
2718  return FALSE;
2719 }
2720 
2721 static bool handleToc(yyscan_t yyscanner,const QCString &, const StringVector &optList)
2722 {
2723  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2724  if (yyextra->current->section==Entry::PAGEDOC_SEC ||
2725  yyextra->current->section==Entry::MAINPAGEDOC_SEC)
2726  {
2727  for (const auto &opt_ : optList)
2728  {
2729  QCString opt = QCString(opt_).stripWhiteSpace().lower();
2730  char dum;
2731  int level = 5;
2732  int i = opt.find(':');
2733  if (i>0) // found ':' but not on position 0 what would mean just a level
2734  {
2735  if (sscanf(opt.right(opt.length() - i - 1).data(),"%d%c",&level,&dum) != 1)
2736  {
2737  warn(yyextra->fileName,yyextra->lineNr,"Unknown option:level specified with \\tableofcontents: '%s'", qPrint(QCString(opt_).stripWhiteSpace()));
2738  opt = "";
2739  }
2740  else
2741  {
2742  level = (level > 5 ? 5 : level);
2743  level = (level <= 0 ? 5 : level);
2744  opt = opt.left(i).stripWhiteSpace();
2745  }
2746  }
2747  if (!opt.isEmpty())
2748  {
2749  if (opt == "html")
2750  {
2751  yyextra->current->localToc.enableHtml(level);
2752  }
2753  else if (opt == "latex")
2754  {
2755  yyextra->current->localToc.enableLatex(level);
2756  }
2757  else if (opt == "xml")
2758  {
2759  yyextra->current->localToc.enableXml(level);
2760  }
2761  else if (opt == "docbook")
2762  {
2763  yyextra->current->localToc.enableDocbook(level);
2764  }
2765  else
2766  {
2767  warn(yyextra->fileName,yyextra->lineNr,"Unknown option specified with \\tableofcontents: '%s'", qPrint(QCString(opt_).stripWhiteSpace()));
2768  }
2769  }
2770  }
2771  if (yyextra->current->localToc.nothingEnabled())
2772  {
2773  // for backward compatibility
2774  yyextra->current->localToc.enableHtml(5);
2775  yyextra->current->localToc.enableXml(5);
2776  }
2777  }
2778  return FALSE;
2779 }
2780 
2781 static bool handleInherit(yyscan_t yyscanner,const QCString &, const StringVector &)
2782 {
2783  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2784  BEGIN(InheritParam);
2785  return FALSE;
2786 }
2787 
2788 static bool handleExtends(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2789 {
2790  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2791  yyextra->currentCmd = cmd;
2792  BEGIN(ExtendsParam);
2793  return FALSE;
2794 }
2795 
2796 static bool handleCopyBrief(yyscan_t yyscanner,const QCString &, const StringVector &)
2797 {
2798  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2799  if (yyextra->current->brief.isEmpty() && yyextra->current->doc.isEmpty())
2800  { // if we don't have a brief or detailed description yet,
2801  // then the @copybrief should end up in the brief description.
2802  // otherwise it will be copied inline (see bug691315 & bug700788)
2803  setOutput(yyscanner,OutputBrief);
2804  }
2805  if (!yyextra->spaceBeforeCmd.isEmpty())
2806  {
2807  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2808  yyextra->spaceBeforeCmd.resize(0);
2809  }
2810  addOutput(yyscanner,"\\copybrief ");
2811  return FALSE;
2812 }
2813 
2814 static bool handleCopyDetails(yyscan_t yyscanner,const QCString &, const StringVector &)
2815 {
2816  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2817  setOutput(yyscanner,OutputDoc);
2818  if (!yyextra->spaceBeforeCmd.isEmpty())
2819  {
2820  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2821  yyextra->spaceBeforeCmd.resize(0);
2822  }
2823  addOutput(yyscanner,"\\copydetails ");
2824  return FALSE;
2825 }
2826 
2827 static bool handleCopyDoc(yyscan_t yyscanner,const QCString &, const StringVector &)
2828 {
2829  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2830  setOutput(yyscanner,OutputBrief);
2831  if (!yyextra->spaceBeforeCmd.isEmpty())
2832  {
2833  addOutput(yyscanner,yyextra->spaceBeforeCmd);
2834  yyextra->spaceBeforeCmd.resize(0);
2835  }
2836  addOutput(yyscanner,"\\copybrief ");
2837  yyextra->copyDocArg.resize(0);
2838  BEGIN(CopyDoc);
2839  return FALSE;
2840 }
2841 
2842 //-----------------------------------------------------------------------------------------
2843 
2844 static void initParser(yyscan_t yyscanner)
2845 {
2846  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2847  yyextra->sectionLabel.resize(0);
2848  yyextra->sectionTitle.resize(0);
2849  yyextra->docGroup.clearHeader();
2850  yyextra->insideParBlock = FALSE;
2851 }
2852 
2853 
2854 static bool getDocSectionName(int s)
2855 {
2856  switch(s)
2857  {
2858  case Entry::CLASSDOC_SEC:
2859  case Entry::STRUCTDOC_SEC:
2860  case Entry::UNIONDOC_SEC:
2861  case Entry::EXCEPTIONDOC_SEC:
2862  case Entry::NAMESPACEDOC_SEC:
2863  case Entry::PROTOCOLDOC_SEC:
2864  case Entry::CATEGORYDOC_SEC:
2865  case Entry::ENUMDOC_SEC:
2866  case Entry::PAGEDOC_SEC:
2867  case Entry::VARIABLEDOC_SEC:
2868  case Entry::MEMBERDOC_SEC:
2869  case Entry::OVERLOADDOC_SEC:
2870  case Entry::FILEDOC_SEC:
2871  case Entry::DEFINEDOC_SEC:
2872  case Entry::GROUPDOC_SEC:
2873  case Entry::MAINPAGEDOC_SEC:
2874  case Entry::PACKAGEDOC_SEC:
2875  case Entry::DIRDOC_SEC:
2876  case Entry::EXAMPLE_SEC:
2877  case Entry::MEMBERGRP_SEC:
2878  case Entry::CONCEPTDOC_SEC:
2879  return TRUE;
2880  default:
2881  return FALSE;
2882  }
2883 }
2884 
2885 //-----------------------------------------------------------------------------
2886 
2887 static bool makeStructuralIndicator(yyscan_t yyscanner,Entry::Sections s)
2888 {
2889  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2890  //printf("yyextra->current->section=%x\n",yyextra->current->section);
2891  if (getDocSectionName(yyextra->current->section))
2892  {
2893  return TRUE;
2894  }
2895  else
2896  {
2897  yyextra->needNewEntry = TRUE;
2898  yyextra->current->section = s;
2899  yyextra->current->fileName = yyextra->fileName;
2900  yyextra->current->startLine = yyextra->lineNr;
2901  yyextra->current->docLine = yyextra->lineNr;
2902  return FALSE;
2903  }
2904 }
2905 
2906 //-----------------------------------------------------------------
2907 
2908 static void lineCount(yyscan_t yyscanner)
2909 {
2910  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2911  for( const char* c = yytext ; *c ; ++c )
2912  yyextra->lineNr += (*c == '\n') ;
2913 }
2914 
2915 //-----------------------------------------------------------------
2916 
2917 static QCString stripQuotes(const char *s)
2918 {
2919  QCString name;
2920  if (s==0 || *s==0) return name;
2921  name=s;
2922  if (name.at(0)=='"' && name.at(name.length()-1)=='"')
2923  {
2924  name=name.mid(1,name.length()-2);
2925  }
2926  return name;
2927 }
2928 
2929 //-----------------------------------------------------------------
2930 
2931 static void addXRefItem(yyscan_t yyscanner,
2932  const QCString &listName,const QCString &itemTitle,
2933  const QCString &listTitle,bool append)
2934 {
2935  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2936  if (listName.isEmpty()) return;
2937  //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append);
2938 
2939  std::unique_lock<std::mutex> lock(g_sectionMutex);
2940 
2941  RefList *refList = RefListManager::instance().add(listName,listTitle,itemTitle);
2942  RefItem *item = 0;
2943  for (auto it = yyextra->current->sli.rbegin(); it != yyextra->current->sli.rend(); ++it)
2944  {
2945  RefItem *i = *it;
2946  if (i && i->list()->listName()==listName)
2947  {
2948  //printf("found %s lii->type=%s\n",listName,qPrint(i->list()->listName()));
2949  item = i;
2950  break;
2951  }
2952  }
2953  if (item && append) // already found item of same type just before this one
2954  {
2955  //printf("listName=%s item id = %d existing\n",listName,item->id());
2956  item->setText(item->text() + " <p>" + yyextra->outputXRef);
2957  //printf("%s: text +=%s\n",listName,qPrint(item->text));
2958  }
2959  else // new item
2960  {
2961 
2962  // if we have already an item from the same list type (e.g. a second @todo)
2963  // in the same Entry (i.e. lii!=0) then we reuse its link anchor.
2964  item = refList->add();
2965  //printf("listName=%s item id = %d new yyextra->current=%p\n",listName,item->id(),yyextra->current);
2966  QCString anchorLabel;
2967  anchorLabel.sprintf("_%s%06d",listName.data(),item->id());
2968  item->setText(yyextra->outputXRef);
2969  item->setAnchor(anchorLabel);
2970  yyextra->current->sli.push_back(item);
2971  QCString cmdString;
2972  cmdString.sprintf(" \\xrefitem %s %d.",qPrint(listName),item->id());
2973  if (yyextra->inBody)
2974  {
2975  yyextra->current->inbodyDocs += cmdString;
2976  }
2977  else
2978  {
2979  yyextra->current->doc += cmdString;
2980  }
2981 
2982  {
2983  SectionManager &sm = SectionManager::instance();
2984  const SectionInfo *si = sm.find(anchorLabel);
2985  if (si)
2986  {
2987  if (!si->ref().isEmpty()) // we are from a tag file
2988  {
2989  si = sm.replace(anchorLabel,listName,yyextra->lineNr,
2990  yyextra->sectionTitle,SectionType::Anchor,
2991  yyextra->sectionLevel);
2992  yyextra->current->anchors.push_back(si);
2993  }
2994  else if (si->lineNr() != -1)
2995  {
2996  warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",qPrint(anchorLabel),qPrint(si->fileName()),si->lineNr());
2997  }
2998  else
2999  {
3000  warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",qPrint(anchorLabel),qPrint(si->fileName()));
3001  }
3002  }
3003  else
3004  {
3005  si = sm.add(anchorLabel,listName,yyextra->lineNr,
3006  yyextra->sectionTitle,SectionType::Anchor,
3007  yyextra->sectionLevel);
3008  yyextra->current->anchors.push_back(si);
3009  }
3010  }
3011  }
3012  yyextra->outputXRef.resize(0);
3013 }
3014 
3015 //-----------------------------------------------------------------------------
3016 
3017 // Adds a formula text to the list/dictionary of formulas if it was
3018 // not already added. Returns the label of the formula.
3019 static QCString addFormula(yyscan_t yyscanner)
3020 {
3021  std::unique_lock<std::mutex> lock(g_formulaMutex);
3022  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3023  QCString formLabel;
3024  QCString fText=yyextra->formulaText.simplifyWhiteSpace();
3025  int id = FormulaManager::instance().addFormula(fText.str());
3026  formLabel.sprintf("\\_form#%d",id);
3027  for (int i=0;i<yyextra->formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to
3028  // keep the warnings
3029  // correctly aligned.
3030  return formLabel;
3031 }
3032 
3033 //-----------------------------------------------------------------------------
3034 
3035 static SectionType sectionLevelToType(int level)
3036 {
3037  if (level>=0 && level<5) return (SectionType)level;
3038  return SectionType::Anchor;
3039 }
3040 
3041 static void addSection(yyscan_t yyscanner)
3042 {
3043  std::unique_lock<std::mutex> lock(g_sectionMutex);
3044  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3045  SectionManager &sm = SectionManager::instance();
3046  const SectionInfo *si = sm.find(yyextra->sectionLabel);
3047  if (si)
3048  {
3049  if (!si->ref().isEmpty()) // we are from a tag file
3050  {
3051  // create a new section element
3052  yyextra->sectionTitle+=yytext;
3053  yyextra->sectionTitle=yyextra->sectionTitle.stripWhiteSpace();
3054  si = sm.replace(yyextra->sectionLabel,yyextra->fileName,yyextra->lineNr,
3055  yyextra->sectionTitle,sectionLevelToType(yyextra->sectionLevel),
3056  yyextra->sectionLevel);
3057 
3058  // add section to this entry
3059  yyextra->current->anchors.push_back(si);
3060  }
3061  else if (si->lineNr() != -1)
3062  {
3063  warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s, line %d)",qPrint(yyextra->sectionLabel),qPrint(si->fileName()),si->lineNr());
3064  }
3065  else
3066  {
3067  warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s)",qPrint(yyextra->sectionLabel),qPrint(si->fileName()));
3068  }
3069  }
3070  else
3071  {
3072  // create a new section element
3073  yyextra->sectionTitle+=yytext;
3074  yyextra->sectionTitle=yyextra->sectionTitle.stripWhiteSpace();
3075  si = sm.add(yyextra->sectionLabel,yyextra->fileName,yyextra->lineNr,
3076  yyextra->sectionTitle,sectionLevelToType(yyextra->sectionLevel),
3077  yyextra->sectionLevel);
3078 
3079  // add section to this entry
3080  yyextra->current->anchors.push_back(si);
3081  }
3082 }
3083 
3084 //-----------------------------------------------------------------------------
3085 
3086 static void addCite(yyscan_t yyscanner)
3087 {
3088  std::unique_lock<std::mutex> lock(g_citeMutex);
3089  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3090  QCString name(yytext);
3091  if (yytext[0] =='"')
3092  {
3093  name=yytext+1;
3094  name=name.left((int)yyleng-2);
3095  }
3096  CitationManager::instance().insert(name);
3097 }
3098 
3099 //-----------------------------------------------------------------------------
3100 
3101 // strip trailing whitespace (excluding newlines) from string s
3102 static void stripTrailingWhiteSpace(QCString &s)
3103 {
3104  uint len = s.length();
3105  int i = (int)len-1;
3106  char c;
3107  while (i>=0)
3108  {
3109  c = s.at(i);
3110  if (c==' ' || c=='\t' || c=='\r') // normal whitespace
3111  {
3112  i--;
3113  }
3114  else if (c=='r' && i>=7 && qstrncmp("\\ilinebr",s.data()+i-7,8)==0) // special line break marker
3115  {
3116  i-=8;
3117  }
3118  else // non-whitespace
3119  {
3120  break;
3121  }
3122  }
3123  //printf("stripTrailingWhitespace(%s) i=%d len=%d\n",qPrint(s),i,len);
3124  if (i!=(int)len-1)
3125  {
3126  s.resize(i+2); // string up to and including char at pos i and \0 terminator
3127  }
3128 }
3129 
3130 // selects the output to write to
3131 static inline void setOutput(yyscan_t yyscanner,OutputContext ctx)
3132 {
3133  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3134  bool xrefAppendToPrev = yyextra->xrefAppendFlag;
3135  // determine append flag for the next item (i.e. the end of this item)
3136  yyextra->xrefAppendFlag = !yyextra->inBody &&
3137  yyextra->inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items
3138  yyextra->newXRefKind==yyextra->xrefKind && // of the same kind
3139  (yyextra->xrefKind!=XRef_Item ||
3140  yyextra->newXRefItemKey==yyextra->xrefItemKey); // with the same key if \xrefitem
3141  //printf("%d && %d && %d && (%d || %d)\n",
3142  // yyextra->inContext==OutputXRef,
3143  // ctx==OutputXRef,
3144  // yyextra->newXRefKind==yyextra->xrefKind,
3145  // yyextra->xrefKind!=XRef_Item,
3146  // yyextra->newXRefItemKey==yyextra->xrefItemKey);
3147  //printf("refKind=%d yyextra->newXRefKind=%d xrefAppendToPrev=%d yyextra->xrefAppendFlag=%d\n",
3148  // yyextra->xrefKind,yyextra->newXRefKind,xrefAppendToPrev,yyextra->xrefAppendFlag);
3149 
3150  //printf("setOutput(yyscanner,yyextra->inContext=%d ctx=%d)\n",yyextra->inContext,ctx);
3151  if (yyextra->inContext==OutputXRef) // end of XRef section => add the item
3152  {
3153  // See if we can append this new xref item to the previous one.
3154  // We know this at the start of the next item of the same
3155  // type and need to remember this until the end of that item.
3156  switch(yyextra->xrefKind)
3157  {
3158  case XRef_Todo:
3159  addXRefItem(yyscanner,QCString("todo"),
3160  theTranslator->trTodo(),
3161  theTranslator->trTodoList(),
3162  xrefAppendToPrev
3163  );
3164  break;
3165  case XRef_Test:
3166  addXRefItem(yyscanner,QCString("test"),
3167  theTranslator->trTest(),
3168  theTranslator->trTestList(),
3169  xrefAppendToPrev
3170  );
3171  break;
3172  case XRef_Bug:
3173  addXRefItem(yyscanner,QCString("bug"),
3174  theTranslator->trBug(),
3175  theTranslator->trBugList(),
3176  xrefAppendToPrev
3177  );
3178  break;
3179  case XRef_Deprecated:
3180  addXRefItem(yyscanner,QCString("deprecated"),
3181  theTranslator->trDeprecated(),
3182  theTranslator->trDeprecatedList(),
3183  xrefAppendToPrev
3184  );
3185  break;
3186  case XRef_Item: // user defined list
3187  addXRefItem(yyscanner,yyextra->xrefItemKey,
3188  yyextra->xrefItemTitle,
3189  yyextra->xrefListTitle,
3190  xrefAppendToPrev
3191  );
3192  break;
3193  case XRef_None:
3194  ASSERT(0);
3195  break;
3196  }
3197  }
3198  yyextra->xrefItemKey = yyextra->newXRefItemKey;
3199 
3200  int oldContext = yyextra->inContext;
3201  yyextra->inContext = ctx;
3202  if (yyextra->inContext!=OutputXRef && yyextra->inBody) yyextra->inContext=OutputInbody;
3203  switch(yyextra->inContext)
3204  {
3205  case OutputDoc:
3206  if (oldContext!=yyextra->inContext)
3207  {
3208  stripTrailingWhiteSpace(yyextra->current->doc);
3209  if (yyextra->current->doc.isEmpty()) yyextra->current->docLine = yyextra->lineNr;
3210  if (yyextra->current->docFile.isEmpty())
3211  {
3212  yyextra->current->docFile = yyextra->fileName;
3213  yyextra->current->docLine = yyextra->lineNr;
3214  }
3215  }
3216  yyextra->pOutputString = &yyextra->current->doc;
3217  break;
3218  case OutputBrief:
3219  if (oldContext!=yyextra->inContext)
3220  {
3221  if (yyextra->current->brief.isEmpty()) yyextra->current->briefLine = yyextra->lineNr;
3222  if (yyextra->current->briefFile.isEmpty())
3223  {
3224  yyextra->current->briefFile = yyextra->fileName;
3225  yyextra->current->briefLine = yyextra->lineNr;
3226  }
3227  }
3228  if (yyextra->current->brief.stripWhiteSpace().isEmpty()) // we only want one brief
3229  // description even if multiple
3230  // are given...
3231  {
3232  yyextra->pOutputString = &yyextra->current->brief;
3233  }
3234  else
3235  {
3236  if (!yyextra->current->doc.isEmpty()) // when appending parts add a new line
3237  {
3238  yyextra->current->doc += "\n";
3239  }
3240  yyextra->pOutputString = &yyextra->current->doc;
3241  yyextra->inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
3242  }
3243  break;
3244  case OutputXRef:
3245  yyextra->pOutputString = &yyextra->outputXRef;
3246  // first item found, so can't append to previous
3247  //yyextra->xrefAppendFlag = FALSE;
3248  break;
3249  case OutputInbody:
3250  yyextra->pOutputString = &yyextra->current->inbodyDocs;
3251  break;
3252  }
3253 }
3254 
3255 
3256 static void addAnchor(yyscan_t yyscanner,const QCString &anchor)
3257 {
3258  std::unique_lock<std::mutex> lock(g_sectionMutex);
3259  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3260  SectionManager &sm = SectionManager::instance();
3261  const SectionInfo *si = sm.find(anchor);
3262  if (si)
3263  {
3264  if (!si->ref().isEmpty()) // we are from a tag file
3265  {
3266  si = sm.replace(anchor,yyextra->fileName,yyextra->lineNr,QCString(),SectionType::Anchor,0);
3267  yyextra->current->anchors.push_back(si);
3268  }
3269  else if (si->lineNr() != -1)
3270  {
3271  warn(yyextra->fileName,yyextra->lineNr,
3272  "multiple use of section label '%s' while adding anchor, (first occurrence: %s, line %d)",
3273  qPrint(anchor),qPrint(si->fileName()),si->lineNr());
3274  }
3275  else
3276  {
3277  warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding anchor, (first occurrence: %s)",
3278  qPrint(anchor),qPrint(si->fileName()));
3279  }
3280  }
3281  else
3282  {
3283  si = sm.add(anchor,yyextra->fileName,yyextra->lineNr,QCString(),SectionType::Anchor,0);
3284  yyextra->current->anchors.push_back(si);
3285  }
3286 }
3287 
3288 // add a string to the output
3289 static inline void addOutput(yyscan_t yyscanner,const char *s)
3290 {
3291  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3292  //printf("addOutput(yyscanner,%s)\n",s);
3293  *yyextra->pOutputString+=s;
3294 }
3295 
3296 // add a string to the output
3297 static inline void addOutput(yyscan_t yyscanner,const QCString &s)
3298 {
3299  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3300  //printf("addOutput(yyscanner,%s)\n",s);
3301  *yyextra->pOutputString+=s;
3302 }
3303 
3304 // add a character to the output
3305 static inline void addOutput(yyscan_t yyscanner,char c)
3306 {
3307  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3308  *yyextra->pOutputString+=c;
3309 }
3310 
3311 static void addIline(yyscan_t yyscanner,int lineNr)
3312 {
3313  char cmd[20];
3314  sprintf(cmd,"\\iline %d ",lineNr);
3315  addOutput(yyscanner, cmd);
3316 }
3317 
3318 static void endBrief(yyscan_t yyscanner,bool addToOutput)
3319 {
3320  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3321  if (!yyextra->current->brief.stripWhiteSpace().isEmpty())
3322  { // only go to the detailed description if we have
3323  // found some brief description and not just whitespace
3324  yyextra->briefEndsAtDot=FALSE;
3325  setOutput(yyscanner,OutputDoc);
3326  if (addToOutput) addOutput(yyscanner,yytext);
3327  }
3328 }
3329 
3330 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
3331 {
3332  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3333  yyextra->prevPosition=yyextra->inputPosition;
3334  yy_size_t c=0;
3335  while( c < max_size && yyextra->inputString[yyextra->inputPosition] )
3336  {
3337  *buf = yyextra->inputString[yyextra->inputPosition++] ;
3338  //printf("%d (%c)\n",*buf,*buf);
3339  c++; buf++;
3340  }
3341  return c;
3342 }
3343 
3344 //----------------------------------------------------------------------------
3345 
3346 static void checkFormula(yyscan_t yyscanner)
3347 {
3348  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3349  if (YY_START==ReadFormulaShort || YY_START==ReadFormulaRound || YY_START==ReadFormulaLong)
3350  {
3351  warn(yyextra->fileName,yyextra->lineNr,"End of comment block while inside formula.");
3352  }
3353 }
3354 
3355 //----------------------------------------------------------------------------
3356 
3357 struct CommentScanner::Private
3358 {
3359  yyscan_t yyscanner;
3360  commentscanYY_state extra;
3361 };
3362 
3363 CommentScanner::CommentScanner() : p(std::make_unique<Private>())
3364 {
3365  commentscanYYlex_init_extra(&p->extra,&p->yyscanner);
3366 #ifdef FLEX_DEBUG
3367  commentscanYYset_debug(1,p->yyscanner);
3368 #endif
3369 }
3370 
3371 CommentScanner::~CommentScanner()
3372 {
3373  commentscanYYlex_destroy(p->yyscanner);
3374 }
3375 
3376 bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *parser,
3377  /* in */ Entry *curEntry,
3378  /* in */ const QCString &comment,
3379  /* in */ const QCString &fileName,
3380  /* in,out */ int &lineNr,
3381  /* in */ bool isBrief,
3382  /* in */ bool isAutoBriefOn,
3383  /* in */ bool isInbody,
3384  /* in,out */ Protection &prot,
3385  /* in,out */ int &position,
3386  /* out */ bool &newEntryNeeded,
3387  /* in */ bool markdownSupport
3388  )
3389 {
3390  yyscan_t yyscanner = p->yyscanner;
3391  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3392  //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n",
3393  // isBrief,isAutoBriefOn,lineNr);
3394 
3395  initParser(yyscanner);
3396  yyextra->guards = std::stack<GuardedSection>();
3397  yyextra->langParser = parser;
3398  yyextra->current = curEntry;
3399  yyextra->current->docLine = (lineNr > 1 ? lineNr : 1);
3400  if (comment.isEmpty()) return FALSE; // avoid empty strings
3401  yyextra->inputString = comment;
3402  yyextra->inputString.append(" ");
3403  yyextra->inputPosition = position;
3404  yyextra->lineNr = lineNr;
3405  yyextra->fileName = fileName;
3406  yyextra->protection = prot;
3407  yyextra->needNewEntry = FALSE;
3408  yyextra->xrefKind = XRef_None;
3409  yyextra->xrefAppendFlag = FALSE;
3410  yyextra->insidePre = FALSE;
3411  yyextra->parseMore = FALSE;
3412  yyextra->inBody = isInbody;
3413  yyextra->markdownSupport= markdownSupport;
3414  yyextra->outputXRef.resize(0);
3415  if (!isBrief && !isAutoBriefOn && !yyextra->current->doc.isEmpty())
3416  { // add newline separator between detailed comment blocks
3417  yyextra->current->doc += '\n';
3418  }
3419  setOutput(yyscanner, isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
3420  yyextra->briefEndsAtDot = isAutoBriefOn;
3421  yyextra->condCount = 0;
3422  yyextra->sectionLevel = 0;
3423  yyextra->spaceBeforeCmd.resize(0);
3424  yyextra->spaceBeforeIf.resize(0);
3425 
3426  printlex(yy_flex_debug, TRUE, __FILE__, !fileName.isEmpty() ? qPrint(fileName): NULL);
3427  if (!yyextra->current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments
3428  {
3429  yyextra->current->inbodyDocs+="\n\n";
3430  }
3431 
3432  Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n"
3433  "input=[\n%s]\n",qPrint(fileName),lineNr,qPrint(yyextra->inputString)
3434  );
3435 
3436  commentscanYYrestart( 0, yyscanner );
3437  BEGIN( Comment );
3438  commentscanYYlex(yyscanner);
3439  setOutput(yyscanner, OutputDoc );
3440 
3441  if (YY_START==OverloadParam) // comment ended with \overload
3442  {
3443  addOutput(yyscanner,getOverloadDocs());
3444  }
3445 
3446  if (!yyextra->guards.empty())
3447  {
3448  warn(yyextra->fileName,yyextra->lineNr,"Documentation block ended in the middle of a conditional section!");
3449  }
3450 
3451  if (yyextra->insideParBlock)
3452  {
3453  warn(yyextra->fileName,yyextra->lineNr,
3454  "Documentation block ended while inside a \\parblock. Missing \\endparblock");
3455  }
3456 
3457  yyextra->current->doc=stripLeadingAndTrailingEmptyLines(yyextra->current->doc,yyextra->current->docLine);
3458 
3459  if (yyextra->current->section==Entry::FILEDOC_SEC && yyextra->current->doc.isEmpty())
3460  {
3461  // to allow a comment block with just a @file command.
3462  yyextra->current->doc="\n\n";
3463  }
3464 
3465  if (yyextra->current->section==Entry::MEMBERGRP_SEC &&
3466  yyextra->docGroup.isEmpty()) // @name section but no group started yet
3467  {
3468  yyextra->docGroup.open(yyextra->current,yyextra->fileName,yyextra->lineNr,true);
3469  }
3470 
3471  Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\noutput=[\n"
3472  "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n]\n===========\n",
3473  qPrint(fileName),lineNr,
3474  yyextra->current->briefLine,qPrint(yyextra->current->brief),
3475  yyextra->current->docLine,qPrint(yyextra->current->doc),
3476  yyextra->current->inbodyLine,qPrint(yyextra->current->inbodyDocs)
3477  );
3478 
3479  checkFormula(yyscanner);
3480  prot = yyextra->protection;
3481 
3482  yyextra->docGroup.addDocs(curEntry);
3483 
3484  newEntryNeeded = yyextra->needNewEntry;
3485 
3486  // if we did not proceed during this call, it does not make
3487  // sense to continue, since we get stuck. See bug 567346 for situations
3488  // were this happens
3489  if (yyextra->parseMore && position==yyextra->inputPosition) yyextra->parseMore=FALSE;
3490 
3491  if (yyextra->parseMore) position=yyextra->inputPosition; else position=0;
3492 
3493  lineNr = yyextra->lineNr;
3494  //printf("position=%d yyextra->parseMore=%d newEntryNeeded=%d\n",
3495  // position,yyextra->parseMore,newEntryNeeded);
3496 
3497  printlex(yy_flex_debug, FALSE, __FILE__, !fileName.isEmpty() ? qPrint(fileName): NULL);
3498  return yyextra->parseMore;
3499 }
3500 
3501 static void handleGuard(yyscan_t yyscanner,const QCString &expr)
3502 {
3503  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3504  CondParser prs;
3505  bool sectionEnabled=prs.parse(yyextra->fileName,yyextra->lineNr,expr.stripWhiteSpace());
3506  bool parentEnabled = TRUE;
3507  if (!yyextra->guards.empty()) parentEnabled = yyextra->guards.top().isEnabled();
3508  if (parentEnabled)
3509  {
3510  if (
3511  (sectionEnabled && yyextra->guardType==Guard_If) ||
3512  (!sectionEnabled && yyextra->guardType==Guard_IfNot)
3513  ) // section is visible
3514  {
3515  yyextra->guards.push(GuardedSection(TRUE,TRUE));
3516  yyextra->enabledSectionFound=TRUE;
3517  BEGIN( GuardParamEnd );
3518  }
3519  else // section is invisible
3520  {
3521  if (yyextra->guardType!=Guard_Skip)
3522  {
3523  yyextra->guards.push(GuardedSection(FALSE,TRUE));
3524  }
3525  BEGIN( SkipGuardedSection );
3526  }
3527  }
3528  else // invisible because of parent
3529  {
3530  yyextra->guards.push(GuardedSection(FALSE,FALSE));
3531  BEGIN( SkipGuardedSection );
3532  }
3533 }
3534 
3535 void CommentScanner::initGroupInfo(Entry *entry)
3536 {
3537  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3538  yyextra->docGroup.initGroupInfo(entry);
3539 }
3540 
3541 void CommentScanner::enterFile(const QCString &fileName,int lineNr)
3542 {
3543  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3544  yyextra->docGroup.enterFile(fileName,lineNr);
3545 }
3546 
3547 void CommentScanner::leaveFile(const QCString &fileName,int lineNr)
3548 {
3549  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3550  yyextra->docGroup.leaveFile(fileName,lineNr);
3551 }
3552 
3553 void CommentScanner::enterCompound(const QCString &fileName,int lineNr,const QCString &name)
3554 {
3555  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3556  yyextra->docGroup.enterCompound(fileName,lineNr,name);
3557 }
3558 
3559 void CommentScanner::leaveCompound(const QCString &fileName,int lineNr,const QCString &name)
3560 {
3561  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3562  yyextra->docGroup.leaveCompound(fileName,lineNr,name);
3563 }
3564 
3565 void CommentScanner::open(Entry *e,const QCString &fileName,int lineNr,bool implicit)
3566 {
3567  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3568  yyextra->docGroup.open(e,fileName,lineNr,implicit);
3569 }
3570 
3571 void CommentScanner::close(Entry *e,const QCString &fileName,int lineNr,bool foundInline,bool implicit)
3572 {
3573  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3574  yyextra->docGroup.close(e,fileName,lineNr,foundInline,implicit);
3575 }
3576 
3577 #if USE_STATE2STRING
3578 #include "commentscan.l.h"
3579 #endif