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