Doxygen
Loading...
Searching...
No Matches
commentcnv.l
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 1997-2023 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%{
17 // redefine buffer size (defaults to 16Kb) to avoid a 'flex scanner push-back overflow' error
18 #undef YY_BUF_SIZE
19 #define YY_BUF_SIZE 10*1024*1024 // 10Mb should be sufficient for a source file
20%}
21
22%option never-interactive
23%option prefix="commentcnvYY"
24%option reentrant
25%option extra-type="struct commentcnvYY_state *"
26%top{
27#include <stdint.h>
28// forward declare yyscan_t to improve type safety
29#define YY_TYPEDEF_YY_SCANNER_T
30struct yyguts_t;
31typedef yyguts_t *yyscan_t;
yyguts_t * yyscan_t
Definition code.l:24
32}
33
34%{
35
36// own header
37#include "commentcnv.h"
38
39// standard includes
40#include <algorithm>
41#include <deque>
42#include <stack>
43#include <string>
44#include <string_view>
45#include <vector>
46
47// other includes
48#include "aliases.h"
49#include "condparser.h"
50#include "config.h"
51#include "debug.h"
52#include "doxygen.h"
53#include "filedef.h"
54#include "fileinfo.h"
55#include "filename.h"
56#include "fortranscanner.h"
57#include "message.h"
58#include "section.h"
59#include "stringutil.h"
60#include "util.h"
61
62#define YY_NO_INPUT 1
63#define YY_NO_UNISTD_H 1
64
66{
67 commentcnvYY_CondCtx(int line,const DString &id,bool b)
68 : lineNr(line),sectionId(id), skip(b) {}
69 int lineNr;
71 bool skip;
72};
73
75{
76 CommentCtx(int line)
77 : lineNr(line) {}
78 int lineNr;
79};
80
97
99{
100 commentcnvYY_state(const std::string *i,std::string &o) : inBuf(i), outBuf(o) {}
101 const std::string *inBuf;
102 std::string &outBuf;
103 int inBufPos = 0;
104 size_t col = 0;
105 size_t blockHeadCol = 0; // column at which the start of a special comment block was found
106 size_t blockHeadPos = 0; // position in outBuf at which the start of a C++ special comment block was written
107 size_t insertCommentCol = 0; // column at which an include or snippet command was found
108 bool mlBrief = false;
109 int readLineCtx = 0;
110 int includeCtx = 0;
111 int raiseLevel = 0;
115 bool skip = false;
117 int lineNr = 0;
118 int condCtx = 0;
119 std::stack<commentcnvYY_CondCtx> condStack;
120 std::stack<int> commentStack;
123 bool inSpecialComment = false;
124 bool inRoseComment= false;
126 int charContext = 0;
127 int javaBlock = 0;
128 bool specialComment = false;
129 bool inVerbatim = false;
132 bool firstIncludeLine = false;
136 int blockCount = 0;
137 bool lastEscaped = false;
139 bool pythonDocString = false;
142 bool vhdl = false; // for VHDL old style --! comment
143 SrcLangExt lang = SrcLangExt::Unknown;
144 bool isFixedForm = false; // For Fortran
145 std::deque<std::unique_ptr<commentcnv_FileState>> includeStack;
146 std::vector<std::string> expandedAliases;
150};
151
152[[maybe_unused]] static const char *stateToString(int state);
153static inline int computeIndent(const char *s);
154
155static void replaceCommentMarker(yyscan_t yyscanner,std::string_view s);
156static inline void copyToOutput(yyscan_t yyscanner,std::string_view s);
157static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len);
158static void startCondSection(yyscan_t yyscanner,const DString &sectId);
159static void endCondSection(yyscan_t yyscanner);
160static void handleCondSectionId(yyscan_t yyscanner,const char *expression);
161static void replaceAliases(yyscan_t yyscanner,std::string_view s,bool replaceCppComment=false,bool replaceCComment=false);
162static int yyread(yyscan_t yyscanner,char *buf,int max_size);
163static void replaceComment(yyscan_t yyscanner,int offset);
164static void clearCommentStack(yyscan_t yyscanner);
165static bool readIncludeFile(yyscan_t yyscanner,const DString &inc,const DString &blockId);
166static void insertCommentStart(yyscan_t yyscanner);
167static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s);
168
169#undef YY_INPUT
170#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
171
172// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
173static inline const char *getLexerFILE() {return __FILE__;}
174#include "doxygen_lex.h"
175
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
First pass comment processing.
static void copyToOutput(yyscan_t yyscanner, std::string_view s)
static int computeIndent(const char *s)
static void handleCondSectionId(yyscan_t yyscanner, const char *expression)
static void endCondSection(yyscan_t yyscanner)
static void replaceComment(yyscan_t yyscanner, int offset)
static void insertCommentStart(yyscan_t yyscanner)
static bool readIncludeFile(yyscan_t yyscanner, const DString &inc, const DString &blockId)
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
static const char * stateToString(int state)
static void replaceAliases(yyscan_t yyscanner, std::string_view s, bool replaceCppComment=false, bool replaceCComment=false)
copies string s with length len to the output, while replacing any alias commands found in the string...
static void replaceCommentMarker(yyscan_t yyscanner, std::string_view s)
static void startCondSection(yyscan_t yyscanner, const DString &sectId)
static void clearCommentStack(yyscan_t yyscanner)
static const char * getLexerFILE()
Definition commentcnv.l:173
static bool parseIncludeOptions(yyscan_t yyscanner, std::string_view s)
Token literal values and constants.
Definition CharStream.h:12
Some helper functions for std::string.
CommentCtx(int line)
Definition commentcnv.l:76
std::string fileBuf
Definition commentcnv.l:90
YY_BUFFER_STATE bufState
Definition commentcnv.l:84
const std::string * oldFileBuf
Definition commentcnv.l:91
commentcnvYY_CondCtx(int line, const DString &id, bool b)
Definition commentcnv.l:67
std::string & outBuf
Definition commentcnv.l:102
std::deque< std::unique_ptr< commentcnv_FileState > > includeStack
Definition commentcnv.l:145
std::vector< std::string > expandedAliases
Definition commentcnv.l:146
std::stack< commentcnvYY_CondCtx > condStack
Definition commentcnv.l:119
const std::string * inBuf
Definition commentcnv.l:101
commentcnvYY_state(const std::string *i, std::string &o)
Definition commentcnv.l:100
std::stack< int > commentStack
Definition commentcnv.l:120
DString snippetFileName
Definition commentcnv.l:147
SrcLangExt
Definition types.h:207
A bunch of utility functions.
176%}
177
178MAILADDR ("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\-]+
179
180%option noyywrap
181
182%x Scan
183%x SkipString
184%x SkipVerbString
185%x SkipChar
186%x SkipLang
187%x SComment
188%x CComment
189%x CNComment
190%x Verbatim
191%x VerbatimCode
192%x ReadLine
193%x CopyLine
194%x CondLine
195%x ReadAliasArgs
196%x IncludeDoc
197%x SnippetDoc
198%x SnippetDocTag
199%x RawString
200%x IncludeFile
201
202CMD [\\@]
203 //- start: NUMBER -------------------------------------------------------------------------
204 // Note same defines in code.l: keep in sync
205DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
206HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
207OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
208BINARY_INTEGER "0"[bB][01][01']*[01]?
209INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
210
211FP_SUF [fFlL]
212
213DIGIT_SEQ [0-9][0-9']*[0-9]?
214FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
215FP_EXP [eE][+-]?{DIGIT_SEQ}
216DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
217DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
218
219HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
220HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
221BIN_EXP [pP][+-]?{DIGIT_SEQ}
222HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
223HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
224
225FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
226FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
227FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
228NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
229
230RAWBEGIN (u|U|L|u8)?R\"[^ \t\‍(\‍)\\‍]{0,16}"("
231RAWEND ")"[^ \t\‍(\‍)\\‍]{0,16}\"
232
233FILEICHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+=&#@]
234FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+=&#@]
235FILECHARS {FILEICHAR}*{FILEECHAR}+
236HFILEMASK {FILEICHAR}*("."{FILEICHAR}+)+{FILECHARS}*
237VFILEMASK {FILECHARS}("."{FILECHARS})*
238FILEMASK {VFILEMASK}|{HFILEMASK}
239
240DOXYCFG [A-Z][A-Z_0-9]*
241
242B [ \t]
243
244OPTS "{"[^}]*"}"{B}*
245
246 //- end: NUMBER ---------------------------------------------------------------------------
247
248 // C start comment
249CCS "/\*"
250 // C end comment
251CCE "*\/"
252 // Cpp comment
253CPPC "/\/"
254
255 // Optional any character
256ANYopt .*
257 // Optional white space
258WSopt [ \t\r]*
259 // readline non special
260RLopt [^\\@<\n\*\/`]*
261RL [^\\@<\n\*\/`]+
262 // Optional slash
263SLASHopt [/]*
264
266
267<Scan>{NUMBER} { //Note similar code in code.l
268 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
269 copyToOutput(yyscanner,yytext,yyleng);
270 }
271<Scan>{RAWBEGIN} {
272 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
273 copyToOutput(yyscanner,yytext,yyleng);
274 BEGIN(RawString);
275 }
276<Scan>[^"'!\/\n\\#,\-=; \t@$]* { /* eat anything that is not " / , or \n */
277 copyToOutput(yyscanner,yytext,yyleng);
278 }
279<Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
280 copyToOutput(yyscanner,yytext,yyleng);
281 }
282<Scan>"'''"! |
283<Scan>"\"\"\""! { /* start of python long comment */
284 if (yyextra->lang!=SrcLangExt::Python)
285 {
286 REJECT;
287 }
288 else
289 {
290 yyextra->pythonDocString = true;
291 yyextra->pythonDocStringChar = yytext[0];
292 yyextra->nestingCount=1;
293 clearCommentStack(yyscanner); /* to be on the save side */
294 copyToOutput(yyscanner,yytext,yyleng);
295 BEGIN(CComment);
296 yyextra->commentStack.push(yyextra->lineNr);
297 }
298 }
299<Scan>"'''" |
300<Scan>"\"\"\"" { /* start of python long comment */
301 if (yyextra->lang!=SrcLangExt::Python)
302 {
303 REJECT;
304 }
305 else if (Config_getBool(PYTHON_DOCSTRING))
306 {
307 REJECT;
308 }
309 else
310 { /* handle as if """! */
311 yyextra->pythonDocString = true;
312 yyextra->pythonDocStringChar = yytext[0];
313 yyextra->nestingCount=1;
314 clearCommentStack(yyscanner); /* to be on the save side */
315 copyToOutput(yyscanner,yytext,yyleng);
316 BEGIN(CComment);
317 yyextra->commentStack.push(yyextra->lineNr);
318 }
319 }
#define Config_getBool(name)
Definition config.h:33
320<Scan>{B}*![><!]/.*\n {
321 if (yyextra->lang!=SrcLangExt::Fortran)
322 {
323 REJECT;
324 }
325 else
326 {
327 yyextra->nestingCount=0; // Fortran doesn't have an end comment
328 clearCommentStack(yyscanner); /* to be on the save side */
329 yyextra->specialComment=true;
330 copyToOutput(yyscanner,yytext,yyleng);
331 yyextra->blockHeadCol=yyextra->col-2;
332 BEGIN(CComment);
333 yyextra->commentStack.push(yyextra->lineNr);
334 }
335 }
336<Scan>[Cc\*][><!]/.*\n {
337 if (yyextra->lang!=SrcLangExt::Fortran)
338 {
339 REJECT;
340 }
341 else
342 {
343 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
344 if (yyextra->isFixedForm && (yyextra->col == 0))
345 {
346 yyextra->nestingCount=0; // Fortran doesn't have an end comment
347 clearCommentStack(yyscanner); /* to be on the save side */
348 yyextra->specialComment=true;
349 copyToOutput(yyscanner,yytext,yyleng);
350 yyextra->blockHeadCol=yyextra->col-1;
351 BEGIN(CComment);
352 yyextra->commentStack.push(yyextra->lineNr);
353 }
354 else
355 {
356 REJECT;
357 }
358 }
359 }
360<Scan>!.*\n {
361 if (yyextra->lang!=SrcLangExt::Fortran)
362 {
363 REJECT;
364 }
365 else
366 {
367 copyToOutput(yyscanner,yytext,yyleng);
368 }
369 }
370<Scan>[Cc\*].*\n {
371 if (yyextra->lang!=SrcLangExt::Fortran)
372 {
373 REJECT;
374 }
375 else
376 {
377 if (yyextra->col == 0)
378 {
379 copyToOutput(yyscanner,yytext,yyleng);
380 }
381 else
382 {
383 REJECT;
384 }
385 }
386 }
387<Scan>[$]?"@\"" { /* start of an interpolated verbatim C# string */
388 if (yyextra->lang!=SrcLangExt::CSharp) REJECT
389 copyToOutput(yyscanner,yytext,yyleng);
390 yyextra->stringContext = YY_START;
391 BEGIN(SkipVerbString);
392 }
393<Scan>"\"" { /* start of a string */
394 copyToOutput(yyscanner,yytext,yyleng);
395 yyextra->stringContext = YY_START;
396 BEGIN(SkipString);
397 }
398<Scan>' {
399 copyToOutput(yyscanner,yytext,yyleng);
400 yyextra->charContext = YY_START;
401 if (yyextra->lang!=SrcLangExt::VHDL)
402 {
403 BEGIN(SkipChar);
404 }
405 }
406<Scan>\n { /* new line */
407 copyToOutput(yyscanner,yytext,yyleng);
408 }
409<Scan>{CPPC}[!/]/.*\n[ \t]*{CPPC}[!/][ \t]*{CMD}"}" { // see bug #8731, don't treat multiline C++ comment as detailed description
410 // if the next line is an end of group marker.
411 yyextra->inSpecialComment=true;
412 yyextra->blockHeadCol=yyextra->col+1;
413 yyextra->insertCppCommentMarker=true;
414 copyToOutput(yyscanner,yytext,yyleng);
415 yyextra->readLineCtx=YY_START;
416 BEGIN(ReadLine);
417 }
418<Scan>{CPPC}"!"/.*\n[ \t]*{CPPC}[\/!][^\/] | /* start C++ style special comment block */
419<Scan>({CPPC}"/"[/]*)/[^/].*\n[ \t]*{CPPC}[\/!][^\/] { /* start C++ style special comment block */
420 if (yyextra->mlBrief)
421 {
422 REJECT; // bail out if we do not need to convert
423 }
424 else
425 {
426 int i=3;
427 if (yytext[2]=='/')
428 {
429 while (i<(int)yyleng && yytext[i]=='/') i++;
430 }
431 yyextra->blockHeadCol=yyextra->col+1;
432 yyextra->blockHeadPos=yyextra->skip ? std::string::npos : yyextra->outBuf.size(); // see replaceComment()
433 if (yytext[2] == '!')
434 {
435 copyToOutput(yyscanner,"/*!");
436 }
437 else
438 {
439 copyToOutput(yyscanner,"/**");
440 }
441 if (i<yyleng) replaceAliases(yyscanner,yytext+i);
442 yyextra->inSpecialComment=true;
443 //BEGIN(SComment);
444 yyextra->readLineCtx=SComment;
445 BEGIN(ReadLine);
446 }
447 }
448<Scan>{CPPC}"##Documentation"{ANYopt}/\n { /* Start of Rational Rose ANSI C++ comment block */
449 if (yyextra->mlBrief) REJECT;
450 int i=17; //=strlen("//##Documentation");
451 yyextra->blockHeadCol=yyextra->col+1;
452 yyextra->blockHeadPos=yyextra->skip ? std::string::npos : yyextra->outBuf.size(); // see replaceComment()
453 copyToOutput(yyscanner,"/**");
454 if (i<yyleng) replaceAliases(yyscanner,yytext+i);
455 yyextra->inRoseComment=true;
456 BEGIN(SComment);
457 }
458<Scan>{CPPC}[!\/]/.*\n[ \t]*{CPPC}[|\/][ \t]*{CMD}"}" { // next line contains an end marker, see bug 752712
459 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
460 if (yyextra->inSpecialComment)
461 {
462 yyextra->blockHeadCol=yyextra->col+1;
463 }
464 copyToOutput(yyscanner,yytext,yyleng);
465 yyextra->readLineCtx=YY_START;
466 BEGIN(ReadLine);
467 }
468<Scan>{CPPC}[!/]/.*\n { /* one line special C++ comment */
469 yyextra->inSpecialComment=true;
470 yyextra->blockHeadCol=yyextra->col+1;
471 yyextra->insertCppCommentMarker=true;
472 copyToOutput(yyscanner,yytext,yyleng);
473 yyextra->readLineCtx=YY_START;
474 BEGIN(ReadLine);
475 }
476<Scan>{CPPC}/.*\n { /* one line normal C++ comment */
477 yyextra->inSpecialComment=false;
478 copyToOutput(yyscanner,yytext,yyleng);
479 yyextra->readLineCtx=YY_START;
480 BEGIN(CopyLine);
481 }
482<Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
483 copyToOutput(yyscanner,yytext,yyleng);
484 }
485<Scan>{CCS}[*!]? { /* start of a C comment */
486 if (yyextra->lang==SrcLangExt::Python)
487 {
488 REJECT;
489 }
490 yyextra->specialComment=(int)yyleng==3;
491 yyextra->nestingCount=1;
492 clearCommentStack(yyscanner); /* to be on the save side */
493 copyToOutput(yyscanner,yytext,yyleng);
494 if (yyextra->specialComment)
495 {
496 yyextra->blockHeadCol=0;
497 BEGIN(CComment);
498 }
499 else
500 {
501 BEGIN(CNComment);
502 }
503 yyextra->commentStack.push(yyextra->lineNr);
504 }
505<Scan>"#"[^\n]*\n {
506 if (yyextra->lang!=SrcLangExt::PHP)
507 {
508 REJECT;
509 }
510 copyToOutput(yyscanner,yytext,yyleng);
511 }
512<Scan>"#"("#")? {
513 if (yyextra->lang!=SrcLangExt::Python)
514 {
515 REJECT;
516 }
517 else
518 {
519 yyextra->nestingCount=0; // Python doesn't have an end comment for #
520 clearCommentStack(yyscanner); /* to be on the save side */
521 yyextra->specialComment=(int)yyleng==2;
522 if (yyextra->specialComment)
523 {
524 yyextra->blockHeadCol=yyextra->col;
525 }
526 yyextra->commentStack.push(yyextra->lineNr);
527 copyToOutput(yyscanner,yytext,yyleng);
528 BEGIN(CComment);
529 }
530 }
531<Scan>"--"[^!][^\n]* {
532 if (yyextra->lang!=SrcLangExt::VHDL)
533 {
534 REJECT;
535 }
536 else
537 {
538 copyToOutput(yyscanner,yytext,yyleng);
539 }
540 }
541<Scan>"--!" {
542 if (yyextra->lang!=SrcLangExt::VHDL)
543 {
544 REJECT;
545 }
546 else
547 {
548 yyextra->specialComment=true;
549 yyextra->blockHeadCol=yyextra->col;
550 yyextra->vhdl = true;
551 yyextra->nestingCount=0; // VHDL doesn't have an end comment
552 clearCommentStack(yyscanner); /* to be on the save side */
553 yyextra->commentStack.push(yyextra->lineNr);
554 copyToOutput(yyscanner,yytext,yyleng);
555 BEGIN(CComment);
556 }
557 }
558<Scan>{B}*![><!] {
559 if (yyextra->lang!=SrcLangExt::Fortran)
560 {
561 REJECT;
562 }
563 else
564 {
565 yyextra->nestingCount=0; // Fortran doesn't have an end comment
566 clearCommentStack(yyscanner); /* to be on the save side */
567 yyextra->specialComment=true;
568 yyextra->blockHeadCol=yyextra->col;
569 yyextra->commentStack.push(yyextra->lineNr);
570 copyToOutput(yyscanner,yytext,yyleng);
571 BEGIN(CComment);
572 }
573 }
574<RawString>{RAWEND} {
575 copyToOutput(yyscanner,yytext,yyleng);
576 if (extractEndRawStringDelimiter(yytext)==yyextra->delimiter)
577 {
578 BEGIN(Scan);
579 }
580 }
DString extractEndRawStringDelimiter(const char *rawEnd)
Definition util.cpp:5395
581<RawString>[^)\n]+ { copyToOutput(yyscanner,yytext,yyleng); }
582<RawString>\n { copyToOutput(yyscanner,yytext,yyleng); }
583<RawString>. { copyToOutput(yyscanner,yytext,yyleng); }
584
585<CComment,CNComment,ReadLine,IncludeFile>{MAILADDR} |
586<CComment,CNComment,ReadLine,IncludeFile>"<"{MAILADDR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
587 copyToOutput(yyscanner,yytext,yyleng);
588 }
589<CComment,IncludeFile>"{"[ \t]*"@code"/[ \t\n] {
590 copyToOutput(yyscanner,"@iliteral{code}");
591 yyextra->lastCommentContext = YY_START;
592 yyextra->javaBlock=1;
593 yyextra->blockName=DString("end")+&yytext[1];
594 yyextra->inVerbatim=true;
595 yyextra->verbatimLine=yyextra->lineNr;
596 BEGIN(VerbatimCode);
597 }
598<CComment,IncludeFile>"{"[ \t]*"@literal"/[ \t\n] {
599 copyToOutput(yyscanner,"@iliteral");
600 yyextra->lastCommentContext = YY_START;
601 yyextra->javaBlock=1;
602 yyextra->blockName=DString("end")+&yytext[1];
603 yyextra->inVerbatim=true;
604 yyextra->verbatimLine=yyextra->lineNr;
605 BEGIN(VerbatimCode);
606 }
607<CComment,ReadLine,IncludeFile>{CMD}"ilinebr"[ \t]+("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
608 if (!Config_getBool(MARKDOWN_SUPPORT))
609 {
610 REJECT;
611 }
612 copyToOutput(yyscanner,yytext,yyleng);
613 yyextra->lastCommentContext = YY_START;
614 yyextra->javaBlock=0;
615 yyextra->blockName=DString(yytext).stripWhiteSpace().right(3); // take the ``` or ~~~ part
616 yyextra->inVerbatim=true;
617 yyextra->verbatimLine=yyextra->lineNr;
618 BEGIN(VerbatimCode);
619 }
DString right(size_t len) const
Definition dstring.h:311
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:337
620<CComment,ReadLine,IncludeFile>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
621 if (!Config_getBool(MARKDOWN_SUPPORT))
622 {
623 REJECT;
624 }
625 copyToOutput(yyscanner,yytext,yyleng);
626 yyextra->lastCommentContext = YY_START;
627 yyextra->javaBlock=0;
628 yyextra->blockName=DString(yytext).stripWhiteSpace().left(3); // take the ``` or ~~~ part
629 yyextra->inVerbatim=true;
630 yyextra->verbatimLine=yyextra->lineNr;
631 BEGIN(VerbatimCode);
632 }
DString left(size_t len) const
Definition dstring.h:306
633<CComment,ReadLine,IncludeFile>{CMD}("dot"|"code"|"msc"|"startuml"|"mermaid")/[^a-z_A-Z0-9] { /* start of a verbatim block */
634 copyToOutput(yyscanner,yytext,yyleng);
635 if (yyextra->inSpecialComment || yyextra->specialComment || yyextra->lang==SrcLangExt::Markdown)
636 {
637 yyextra->lastCommentContext = YY_START;
638 yyextra->javaBlock=0;
639 if (dstrcmp(&yytext[1],"startuml")==0)
640 {
641 yyextra->blockName="enduml";
642 }
643 else
644 {
645 yyextra->blockName=DString("end")+&yytext[1];
646 }
647 yyextra->inVerbatim=true;
648 yyextra->verbatimLine=yyextra->lineNr;
649 BEGIN(VerbatimCode);
650 }
651 }
int dstrcmp(const char *str1, const char *str2)
Definition dstring.h:50
652<CComment,ReadLine,IncludeFile>"\\`" {
653 copyToOutput(yyscanner,yytext,yyleng);
654 }
655<CComment,ReadLine,IncludeFile>"```" { // skip ``` if not at the start of the line
656 copyToOutput(yyscanner,yytext,yyleng);
657 }
658<CComment,ReadLine,IncludeFile>"`"{1,2} {
659 if (!Config_getBool(MARKDOWN_SUPPORT))
660 {
661 REJECT;
662 }
663 copyToOutput(yyscanner,yytext,yyleng);
664 if (yyextra->inSpecialComment || yyextra->specialComment || yyextra->lang==SrcLangExt::Markdown)
665 {
666 yyextra->lastCommentContext = YY_START;
667 yyextra->javaBlock=0;
668 yyextra->blockName=yytext;
669 yyextra->inVerbatim=true;
670 yyextra->verbatimLine=yyextra->lineNr;
671 BEGIN(VerbatimCode);
672 }
673 }
674<CComment,ReadLine,IncludeFile>{CMD}("f$"|"f["|"f{"|"f(") {
675 copyToOutput(yyscanner,yytext,yyleng);
676 if (yyextra->inSpecialComment || yyextra->specialComment || yyextra->lang==SrcLangExt::Markdown)
677 {
678 yyextra->blockName=&yytext[1];
679 if (yyextra->blockName.at(1)=='[')
680 {
681 yyextra->blockName.at(1)=']';
682 }
683 else if (yyextra->blockName.at(1)=='{')
684 {
685 yyextra->blockName.at(1)='}';
686 }
687 else if (yyextra->blockName.at(1)=='(')
688 {
689 yyextra->blockName.at(1)=')';
690 }
691 yyextra->lastCommentContext = YY_START;
692 yyextra->inVerbatim=true;
693 yyextra->verbatimLine=yyextra->lineNr;
694 BEGIN(Verbatim);
695 }
696 }
697<CComment,ReadLine,IncludeFile>"<!--!" { /* HTML comment doxygen command*/
698 if (yyextra->inVerbatim) REJECT;
699 //copyToOutput(yyscanner," ",5);
700 yyextra->inHtmlDoxygenCommand=true;
701 }
702<CComment,ReadLine,IncludeFile>"-->" { /* potential end HTML comment doxygen command*/
703 if (yyextra->inHtmlDoxygenCommand)
704 {
705 yyextra->inHtmlDoxygenCommand=false;
706 }
707 else
708 {
709 copyToOutput(yyscanner,yytext,yyleng);
710 }
711 }
712<CComment,ReadLine,IncludeFile>"<!--" { /* HTML comment */
713 copyToOutput(yyscanner,yytext,yyleng);
714 if (yyextra->inSpecialComment || yyextra->specialComment || yyextra->lang==SrcLangExt::Markdown)
715 {
716 yyextra->blockName="-->";
717 yyextra->lastCommentContext = YY_START;
718 yyextra->inVerbatim=true;
719 yyextra->verbatimLine=yyextra->lineNr;
720 BEGIN(Verbatim);
721 }
722 }
723<CComment,ReadLine,IncludeFile>{CMD}("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
724 copyToOutput(yyscanner,yytext,yyleng);
725 if (yyextra->inSpecialComment || yyextra->specialComment || yyextra->lang==SrcLangExt::Markdown)
726 {
727 yyextra->blockName=DString("end")+&yytext[1];
728 yyextra->lastCommentContext = YY_START;
729 yyextra->inVerbatim=true;
730 yyextra->verbatimLine=yyextra->lineNr;
731 BEGIN(Verbatim);
732 }
733 }
734<Scan>"\\\"" { /* escaped double quote */
735 copyToOutput(yyscanner,yytext,yyleng);
736 }
737<Scan>"\\\\" { /* escaped backslash */
738 copyToOutput(yyscanner,yytext,yyleng);
739 }
740<Scan>. { /* any other character */
741 copyToOutput(yyscanner,yytext,yyleng);
742 }
743<Verbatim>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
744 copyToOutput(yyscanner,yytext,yyleng);
745 if (&yytext[1]==yyextra->blockName) // end of command or formula
746 {
747 yyextra->inVerbatim=false;
748 BEGIN(yyextra->lastCommentContext);
749 }
750 }
751<Verbatim>"-->" {
752 copyToOutput(yyscanner,yytext,yyleng);
753 if (yytext==yyextra->blockName)
754 {
755 yyextra->inVerbatim=false;
756 BEGIN(yyextra->lastCommentContext);
757 }
758 }
759<VerbatimCode>"{" {
760 if (yyextra->javaBlock==0)
761 {
762 REJECT;
763 }
764 else
765 {
766 yyextra->javaBlock++;
767 copyToOutput(yyscanner,yytext,yyleng);
768 }
769 }
770<VerbatimCode>"}" {
771 if (yyextra->javaBlock==0)
772 {
773 REJECT;
774 }
775 else
776 {
777 yyextra->javaBlock--;
778 if (yyextra->javaBlock==0)
779 {
780 copyToOutput(yyscanner," @endiliteral ");
781 yyextra->inVerbatim=false;
782 BEGIN(yyextra->lastCommentContext);
783 }
784 else
785 {
786 copyToOutput(yyscanner,yytext,yyleng);
787 }
788 }
789 }
790<VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
791 if (yytext[0]=='`' && (yyextra->blockName=="`" || yyextra->blockName=="``")) // ``` type block inside single or double backtick "block"
792 {
793 // copy the end block marker
794 copyToOutput(yyscanner,yytext,yyleng);
795 }
796 else
797 {
798 copyToOutput(yyscanner,yytext,yyleng);
799 if (yytext[0]==yyextra->blockName[0])
800 {
801 yyextra->inVerbatim=false;
802 BEGIN(yyextra->lastCommentContext);
803 }
804 }
805 }
806<VerbatimCode>"''" {
807 copyToOutput(yyscanner,yytext,yyleng);
808 if (!Config_getBool(MARKDOWN_STRICT) && yyextra->blockName=="``") // support for ``text''
809 {
810 yyextra->inVerbatim=false;
811 BEGIN(yyextra->lastCommentContext);
812 }
813 }
814<VerbatimCode>"'" {
815 copyToOutput(yyscanner,yytext,yyleng);
816 if (!Config_getBool(MARKDOWN_STRICT) && yyextra->blockName=="`") // support for `text'
817 {
818 yyextra->inVerbatim=false;
819 BEGIN(yyextra->lastCommentContext);
820 }
821 }
822<VerbatimCode>"`"{1,2} {
823 copyToOutput(yyscanner,yytext,yyleng);
824 if (yytext==yyextra->blockName)
825 {
826 yyextra->inVerbatim=false;
827 BEGIN(yyextra->lastCommentContext);
828 }
829 }
830<VerbatimCode>{CMD}("enddot"|"endcode"|"endmsc"|"enduml"|"endmermaid")/("{")? { // end of verbatim block
831 copyToOutput(yyscanner,yytext,yyleng);
832 if (&yytext[1]==yyextra->blockName)
833 {
834 yyextra->inVerbatim=false;
835 BEGIN(yyextra->lastCommentContext);
836 }
837 }
838<VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
839 if (!yyextra->inSpecialComment || yyextra->mlBrief)
840 {
841 copyToOutput(yyscanner,yytext,yyleng);
842 }
843 else
844 {
845 int l=0;
846 while (yytext[l]==' ' || yytext[l]=='\t')
847 {
848 l++;
849 }
850 copyToOutput(yyscanner,yytext,l);
851 if (yyleng-l==3) // ends with //! or ///
852 {
853 copyToOutput(yyscanner," * ");
854 }
855 else // ends with //
856 {
857 copyToOutput(yyscanner,"//");
858 }
859 }
860 }
861<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
862 copyToOutput(yyscanner,yytext,yyleng);
863 }
864<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]+/\n{B}*"//" {
865 if (yyextra->lastCommentContext!=ReadLine)
866 {
867 REJECT;
868 }
869 else
870 {
871 copyToOutput(yyscanner,yytext,yyleng);
872 }
873 }
874<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]+/\n { /* premature end of comment block */
875 if (yyextra->lastCommentContext==ReadLine)
876 {
877 yyextra->inVerbatim=false;
878 BEGIN(yyextra->lastCommentContext);
879 }
880 copyToOutput(yyscanner,yytext,yyleng);
881 }
882<Verbatim,VerbatimCode>\n { /* new line in verbatim block */
883 copyToOutput(yyscanner,yytext,yyleng);
884 if (yyextra->lastCommentContext == IncludeFile)
885 {
886 insertCommentStart(yyscanner);
887 }
888 }
889<Verbatim>^[ \t]*{CPPC}[/!] {
890 if (yyextra->blockName=="enddot" || yyextra->blockName=="endmsc" || yyextra->blockName=="enduml" || yyextra->blockName.at(0)=='f')
891 {
892 // see bug 487871, strip /// from dot images and formulas.
893 int l=0;
894 while (yytext[l]==' ' || yytext[l]=='\t')
895 {
896 l++;
897 }
898 copyToOutput(yyscanner,yytext,l);
899 copyToOutput(yyscanner," ");
900 }
901 else // even slashes are verbatim (e.g. \verbatim, \code)
902 {
903 REJECT;
904 }
905 }
906<Verbatim,VerbatimCode>. { /* any other character */
907 copyToOutput(yyscanner,yytext,yyleng);
908 }
909<SkipString>\\. { /* escaped character in string */
910 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
911 {
912 unput(yytext[1]);
913 copyToOutput(yyscanner,yytext,1);
914 }
915 else
916 {
917 copyToOutput(yyscanner,yytext,yyleng);
918 }
919 }
920<SkipString>"\"" { /* end of string */
921 copyToOutput(yyscanner,yytext,yyleng);
922 BEGIN(yyextra->stringContext);
923 }
924<SkipString>. { /* any other string character */
925 copyToOutput(yyscanner,yytext,yyleng);
926 }
927<SkipString>\n { /* new line inside string (illegal for some compilers) */
928 copyToOutput(yyscanner,yytext,yyleng);
929 }
930<SkipVerbString>[^"\n]+ {
931 copyToOutput(yyscanner,yytext,yyleng);
932 }
933<SkipVerbString>\"\" { // escaped quote
934 copyToOutput(yyscanner,yytext,yyleng);
935 }
936<SkipVerbString>"\"" { /* end of string */
937 copyToOutput(yyscanner,yytext,yyleng);
938 BEGIN(yyextra->stringContext);
939 }
940<SkipVerbString>. {
941 copyToOutput(yyscanner,yytext,yyleng);
942 }
943<SkipVerbString>\n {
944 copyToOutput(yyscanner,yytext,yyleng);
945 }
946<SkipChar>\\. { /* escaped character */
947 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
948 {
949 unput(yytext[1]);
950 copyToOutput(yyscanner,yytext,1);
951 }
952 else
953 {
954 copyToOutput(yyscanner,yytext,yyleng);
955 }
956 }
957<SkipChar>' { /* end of character literal */
958 copyToOutput(yyscanner,yytext,yyleng);
959 BEGIN(yyextra->charContext);
960 }
961<SkipChar>. { /* any other string character */
962 copyToOutput(yyscanner,yytext,yyleng);
963 }
964<SkipChar>\n { /* new line character */
965 copyToOutput(yyscanner,yytext,yyleng);
966 }
967
968<CComment,CNComment>[^ `~<\\!@*\n{\"'\/-`]* { /* anything that is not a '*' or command */
969 copyToOutput(yyscanner,yytext,yyleng);
970 }
971<CComment,CNComment>^{B}*"*"+[^*\/<\\@\n{\"`]* { /* stars without slashes */
972 if (yyextra->lang==SrcLangExt::Markdown) REJECT;
973 yyextra->col = computeIndent(yytext);
974 if (yyextra->col>yyextra->blockHeadCol)
975 {
976 //printf("new blockHeadCol=%d\n",yyextra->blockHeadCol);
977 yyextra->blockHeadCol=yyextra->col;
978 }
979 copyToOutput(yyscanner,yytext,yyleng);
980 }
981<CComment>"'''" |
982<CComment>"\"\"\"" { /* end of Python docstring */
983 if (yyextra->lang!=SrcLangExt::Python)
984 {
985 REJECT;
986 }
987 else if (yyextra->pythonDocStringChar != yytext[0])
988 {
989 copyToOutput(yyscanner,yytext,yyleng);
990 }
991 else
992 {
993 yyextra->nestingCount--;
994 yyextra->pythonDocString = false;
995 yyextra->pythonDocStringChar = '\0';
996 copyToOutput(yyscanner,yytext,yyleng);
997 BEGIN(Scan);
998 }
999 }
1000<CComment,CNComment>\n { /* new line in comment */
1001 copyToOutput(yyscanner,yytext,yyleng);
1002 /* in case of Fortran always end of comment */
1003 if (yyextra->lang==SrcLangExt::Fortran)
1004 {
1005 BEGIN(Scan);
1006 }
1007 }
1008<CComment,CNComment>"/""/"+/"*/" { /* we are already in C-comment so not a start of a nested comment but
1009 * just the end of the comment (the end part is handled later). */
1010 copyToOutput(yyscanner,yytext,yyleng);
1011 }
1012<CComment,CNComment>"/"+"*" { /* nested C comment */
1013 if (yyextra->lang==SrcLangExt::Python ||
1014 yyextra->lang==SrcLangExt::Markdown)
1015 {
1016 REJECT;
1017 }
1018 yyextra->nestingCount++;
1019 yyextra->commentStack.push(yyextra->lineNr);
1020 copyToOutput(yyscanner,yytext,yyleng);
1021 }
1022<CComment,CNComment>^{B}*"*"+"/" |
1023<CComment,CNComment>"*"+"/" { /* end of C comment */
1024 if (yyextra->lang==SrcLangExt::Python ||
1025 yyextra->lang==SrcLangExt::Markdown)
1026 {
1027 REJECT;
1028 }
1029 else
1030 {
1031 copyToOutput(yyscanner,yytext,yyleng);
1032 yyextra->nestingCount--;
1033 if (yyextra->nestingCount<=0)
1034 {
1035 BEGIN(Scan);
1036 }
1037 else
1038 {
1039 //yyextra->nestingCount--;
1040 yyextra->commentStack.pop();
1041 }
1042 }
1043 }
1044 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
1045<CComment,CNComment>"\n"/[ \t]*"#" {
1046 if (yyextra->lang!=SrcLangExt::VHDL)
1047 {
1048 REJECT;
1049 }
1050 else
1051 {
1052 if (yyextra->vhdl) // inside --! comment
1053 {
1054 yyextra->vhdl = false;
1055 copyToOutput(yyscanner,yytext,yyleng);
1056 BEGIN(Scan);
1057 }
1058 else // C-type comment
1059 {
1060 REJECT;
1061 }
1062 }
1063 }
1064<CComment,CNComment>"\n"/[ \t]*"-" {
1065 if (yyextra->lang!=SrcLangExt::Python || yyextra->pythonDocString)
1066 {
1067 REJECT;
1068 }
1069 else
1070 {
1071 copyToOutput(yyscanner,yytext,yyleng);
1072 BEGIN(Scan);
1073 }
1074 }
1075<CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
1076 if (yyextra->lang==SrcLangExt::Python)
1077 {
1078 if (yyextra->pythonDocString)
1079 {
1080 REJECT;
1081 }
1082 else
1083 {
1084 copyToOutput(yyscanner,yytext,yyleng);
1085 BEGIN(Scan);
1086 }
1087 }
1088 else if (yyextra->lang==SrcLangExt::VHDL)
1089 {
1090 if (yyextra->vhdl) // inside --! comment
1091 {
1092 yyextra->vhdl = false;
1093 copyToOutput(yyscanner,yytext,yyleng);
1094 BEGIN(Scan);
1095 }
1096 else // C-type comment
1097 {
1098 REJECT;
1099 }
1100 }
1101 else
1102 {
1103 REJECT;
1104 }
1105 }
1106 /* removed for bug 674842 (bug was introduced in rev 768)
1107<CComment,CNComment>"'" {
1108 yyextra->charContext = YY_START;
1109 copyToOutput(yyscanner,yytext,yyleng);
1110 BEGIN(SkipChar);
1111 }
1112<CComment,CNComment>"\"" {
1113 yyextra->stringContext = YY_START;
1114 copyToOutput(yyscanner,yytext,yyleng);
1115 BEGIN(SkipString);
1116 }
1117 */
1118<CComment,CNComment>{CMD}"~"[a-z_A-Z-]* { // language switch command
1119 if (yyextra->lang!=SrcLangExt::Markdown) REJECT;
1120 DString langId = DString(yytext).mid(2);
1121 if (!langId.empty() &&
1122 dstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)!=0)
1123 { // enable language specific section
1124 if (!Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
1125 {
1126 warn(yyextra->fileName,yyextra->lineNr,
1127 "non supported language '{}' specified in '{}'",langId,DString(yytext).stripWhiteSpace());
1128 }
1129 BEGIN(SkipLang);
1130 }
1131 }
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
#define Config_getEnumAsString(name)
Definition config.h:36
#define Config_isAvailableEnum(name, value)
Definition config.h:45
int dstricmp(const char *s1, const char *s2)
Definition dstring.cpp:444
#define warn(file, line, fmt,...)
Definition message.h:97
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:75
1132<CComment,CNComment>{CMD}{CMD} |
1133<CComment,CNComment>. {
1134 copyToOutput(yyscanner,yytext,yyleng);
1135 }
1136<SkipLang>{CMD}"~"[a-zA-Z-]* { /* language switch */
1137 DString langId(&yytext[2]);
1138 if (!langId.empty() && !Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
1139 {
1140 warn(yyextra->fileName,yyextra->lineNr,
1141 "non supported language '{}' specified in '{}'",langId,DString(yytext).stripWhiteSpace());
1142 }
1143 else if (langId.empty() ||
1144 dstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)==0)
1145 { // enable language specific section
1146 BEGIN(CComment);
1147 }
1148 }
1149<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
1150 }
1151<SkipLang>\n { /* new line in language block, needed for keeping track of line numbers */
1152 copyToOutput(yyscanner,yytext,yyleng);
1153 }
1154<SkipLang>. { /* any other character */
1155 }
1156<SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
1157 replaceComment(yyscanner,0);
1158 }
1159<SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
1160 replaceComment(yyscanner,1);
1161 }
1162<SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
1163 replaceComment(yyscanner,0);
1164 yyextra->readLineCtx=YY_START;
1165 YY_CURRENT_BUFFER->yy_at_bol=1;
1166 BEGIN(ReadLine);
1167 }
1168<SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*{CMD}"}".*\n {
1169 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
1170 copyToOutput(yyscanner," */");
1171 copyToOutput(yyscanner,yytext,yyleng);
1172 yyextra->inSpecialComment=false;
1173 yyextra->inRoseComment=false;
1174 BEGIN(Scan);
1175 }
1176<SComment>\n[ \t]*{CPPC}"/"[^\\@\/\n]/.*\n {
1177 replaceComment(yyscanner,1);
1178 yyextra->readLineCtx=YY_START;
1179 YY_CURRENT_BUFFER->yy_at_bol=1;
1180 BEGIN(ReadLine);
1181 }
1182<SComment>^[ \t]*{CPPC}"!" | // just //!
1183<SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
1184<SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
1185 replaceComment(yyscanner,0);
1186 yyextra->readLineCtx=YY_START;
1187 YY_CURRENT_BUFFER->yy_at_bol=1;
1188 BEGIN(ReadLine);
1189 }
1190<SComment>\n[ \t]*{CPPC}"!" |
1191<SComment>\n[ \t]*{CPPC}"!<"/.*\n |
1192<SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
1193 replaceComment(yyscanner,1);
1194 yyextra->readLineCtx=YY_START;
1195 YY_CURRENT_BUFFER->yy_at_bol=1;
1196 BEGIN(ReadLine);
1197 }
1198<SComment>^[ \t]*{CPPC}"##"/.*\n {
1199 if (!yyextra->inRoseComment)
1200 {
1201 REJECT;
1202 }
1203 else
1204 {
1205 replaceComment(yyscanner,0);
1206 yyextra->readLineCtx=YY_START;
1207 YY_CURRENT_BUFFER->yy_at_bol=1;
1208 BEGIN(ReadLine);
1209 }
1210 }
1211<SComment>\n[ \t]*{CPPC}"##"/.*\n {
1212 if (!yyextra->inRoseComment)
1213 {
1214 REJECT;
1215 }
1216 else
1217 {
1218 replaceComment(yyscanner,1);
1219 yyextra->readLineCtx=YY_START;
1220 YY_CURRENT_BUFFER->yy_at_bol=1;
1221 BEGIN(ReadLine);
1222 }
1223 }
1224<SComment>\n { /* end of special comment */
1225 copyToOutput(yyscanner," */");
1226 copyToOutput(yyscanner,yytext,yyleng);
1227 yyextra->inSpecialComment=false;
1228 yyextra->inRoseComment=false;
1229 yyextra->insertCppCommentMarker=false;
1230 yyextra->readLineCtx = Scan; // reset, otherwise there will be problems with:
1231 // static void handleCondSectionId
1232 BEGIN(Scan);
1233 }
1234<ReadLine,CopyLine>{CCS}"*" {
1235 copyToOutput(yyscanner,"/&zwj;**");
1236 }
1237<ReadLine,CopyLine>{CCE} {
1238 copyToOutput(yyscanner,"*&zwj;/");
1239 }
1240<ReadLine,CopyLine>"*" {
1241 copyToOutput(yyscanner,yytext,yyleng);
1242 }
1243<ReadLine,CopyLine>{RL} {
1244 copyToOutput(yyscanner,yytext,yyleng);
1245 }
1246<ReadLine,CopyLine>{RL}/{B}{CMD}"ilinebr"{B} {
1247 copyToOutput(yyscanner,yytext,yyleng);
1248 }
1249<ReadLine,CopyLine>{RLopt}/\n {
1250 copyToOutput(yyscanner,yytext,yyleng);
1251 yyextra->insertCppCommentMarker=false;
1252 BEGIN(yyextra->readLineCtx);
1253 }
1254<CComment,CNComment,ReadLine>"\<" { /* escaped html comment */
1255 copyToOutput(yyscanner,yytext,yyleng);
1256 }
1257<CComment,CNComment,ReadLine>{CMD}{CMD}[~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
1258 copyToOutput(yyscanner,yytext,yyleng);
1259 }
1260
1261<CComment,ReadLine,IncludeFile>{CMD}("include"{OPTS}|"includedoc"{OPTS}*) {
1262 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1263 yyextra->includeCtx = YY_START;
1264 yyextra->firstIncludeLine = true;
1265 yyextra->insertCommentCol = yyextra->col;
1266 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1267 {
1268 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1269 }
1270 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1271 BEGIN(IncludeDoc);
1272 }
1273<CComment,ReadLine,IncludeFile>{CMD}("snippet"{OPTS}|"snippetdoc"{OPTS}*) {
1274 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1275 yyextra->includeCtx = YY_START;
1276 yyextra->firstIncludeLine = true;
1277 yyextra->insertCommentCol = yyextra->col;
1278 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1279 {
1280 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1281 }
1282 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1283 BEGIN(SnippetDoc);
1284 }
1285<IncludeDoc,SnippetDoc>{B}*
1286<IncludeDoc>{FILEMASK}|"\""[^\n\"]+"\"" {
1287 DString fileName=yytext;
1288 if (yytext[0]=='"')
1289 {
1290 fileName=fileName.mid(1,fileName.length()-2); // strip quotes
1291 }
1292 if (readIncludeFile(yyscanner,fileName,""))
1293 {
1294 BEGIN(IncludeFile);
1295 }
1296 else
1297 {
1298 BEGIN(yyextra->includeCtx);
1299 }
1300 }
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:151
1301<SnippetDoc>({FILEMASK}|"\""[^\n\"]+"\""){B}+ {
1302 yyextra->snippetFileName=yytext;
1303 yyextra->snippetFileName=yyextra->snippetFileName.stripWhiteSpace();
1304 if (yyextra->snippetFileName == "this") yyextra->snippetFileName=yyextra->fileName;
1305 yyextra->snippetName = "";
1306 BEGIN(SnippetDocTag);
1307 }
1308<SnippetDocTag>[^\\@\n]+ {
1309 yyextra->snippetName += yytext;
1310 }
1311<SnippetDocTag>{CMD} {
1312 yyextra->snippetName += yytext;
1313 }
1314<SnippetDocTag>(\n|{CMD}"ilinebr") {
1315 for (int i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1316 yyextra->snippetName = yyextra->snippetName.stripWhiteSpace();
1317 DString blockId = "["+yyextra->snippetName+"]";
1318 if (readIncludeFile(yyscanner,yyextra->snippetFileName,blockId))
1319 {
1320 BEGIN(IncludeFile);
1321 }
1322 else
1323 {
1324 BEGIN(yyextra->includeCtx);
1325 }
1326 }
1327
1328<IncludeDoc,SnippetDoc>\n {
1329 copyToOutput(yyscanner,yytext,yyleng);
1330 insertCommentStart(yyscanner);
1331 // missing file name
1332 //warn(yyextra->fileName,yyextra->lineNr,"Found \\include{{doc}} command without valid file name argument");
1333 BEGIN(yyextra->includeCtx);
1334 }
1335<IncludeDoc,SnippetDoc>. { // invalid character
1336 copyToOutput(yyscanner,yytext,yyleng);
1337 BEGIN(yyextra->includeCtx);
1338 }
1339<CComment,ReadLine,IncludeFile>{CMD}"cond"/[^a-z_A-Z0-9] { // conditional section
1340 yyextra->condCtx = YY_START;
1341 BEGIN(CondLine);
1342 }
1343<CComment,ReadLine,IncludeFile>{CMD}"endcond"/[^a-z_A-Z0-9] { // end of conditional section
1344 bool oldSkip=yyextra->skip;
1345 endCondSection(yyscanner);
1346 if (YY_START==CComment && oldSkip && !yyextra->skip)
1347 {
1348 //printf("** Adding start of comment!\n");
1349 if (yyextra->lang!=SrcLangExt::Python &&
1350 yyextra->lang!=SrcLangExt::VHDL &&
1351 yyextra->lang!=SrcLangExt::Markdown &&
1352 yyextra->lang!=SrcLangExt::Fortran)
1353 {
1354 yyextra->outBuf+='/';
1355 yyextra->outBuf+='*';
1356 yyextra->col+=2;
1357 if (yyextra->specialComment)
1358 {
1359 yyextra->outBuf+='*';
1360 yyextra->col++;
1361 }
1362 }
1363 }
1364 }
1365<CondLine>{B}*{CMD}doxyconfig{B}+{DOXYCFG} {
1366 handleCondSectionId(yyscanner,yytext);
1367 }
1368<CondLine>([!()&| \ta-z_A-Z0-9.\-]|{CMD}"doxyconfig")+ {
1369 handleCondSectionId(yyscanner,yytext);
1370 }
1371<CComment,ReadLine,IncludeFile>{CMD}"cond"{WSopt}/\n {
1372 yyextra->condCtx=YY_START;
1373 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1374 }
1375<CondLine>\n |
1376<CondLine>. { // forgot section id?
1377 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1378 if (*yytext=='\n') { copyToOutput(yyscanner,"\n");}
1379 }
1380<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{CMD}[a-z_A-Z][a-z_A-Z0-9-]* { // expand alias without arguments
1381 bool inCppComment = YY_START==ReadLine && yyextra->readLineCtx==SComment;
1382 bool inCComment = YY_START==CComment && yyextra->blockHeadCol>0;
1383 replaceAliases(yyscanner,yytext,inCppComment,inCComment);
1384 }
1385<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{B}?{CMD}"ilinebr"{B}{CMD}"ialias{" { // expand alias with arguments
1386 yyextra->lastBlockContext=YY_START;
1387 yyextra->blockCount=1;
1388 int extraSpace = (yytext[0]==' '? 1:0);
1389 yyextra->aliasString=yytext+9+extraSpace;
1390 yyextra->aliasCmd=yytext+9+extraSpace;
1391 yyextra->lastEscaped=0;
1392 BEGIN( ReadAliasArgs );
1393 }
1394<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{CMD}[a-z_A-Z][a-z_A-Z0-9-]*"{" { // expand alias with arguments
1395 yyextra->lastBlockContext=YY_START;
1396 yyextra->blockCount=1;
1397 yyextra->aliasString=yytext;
1398 yyextra->aliasCmd=yytext;
1399 yyextra->lastEscaped=0;
1400 BEGIN( ReadAliasArgs );
1401 }
1402<ReadAliasArgs>^[ \t]*"*" {
1403 size_t indent=computeIndent(yytext)-1;
1404 if (indent>yyextra->blockHeadCol) // assume part of block marker
1405 {
1406 yyextra->aliasString+=yytext;
1407 }
1408 else
1409 {
1410 // skip leading *
1411 }
1412 }
1413<ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]* { // skip leading special comments (see bug 618079)
1414 }
1415<ReadAliasArgs>[^{}\n\\\*]+ {
1416 yyextra->aliasString+=yytext;
1417 yyextra->lastEscaped=false;
1418 }
1419<ReadAliasArgs>"\\" {
1420 if (yyextra->lastEscaped) yyextra->lastEscaped=false;
1421 else yyextra->lastEscaped=true;
1422 yyextra->aliasString+=yytext;
1423 }
1424<ReadAliasArgs>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
1425 yyextra->aliasString+=yytext;
1426 if (yyextra->inVerbatim && &yytext[1]==yyextra->blockName)
1427 // For verbatim sections we do not support matching end block markers inside
1428 // alias arguments. Instead this will end the verbatim block.
1429 // This is needed to support an alias definition
1430 // like startalign=" \latexonly\noalign{\endlatexonly" were otherwise
1431 // the scanner would try to find a matching closing brace for noalign and then
1432 // skip over the \endlatexonly command.
1433 {
1434 copyToOutput(yyscanner,yyextra->aliasString.view());
1435 yyextra->inVerbatim=false;
1436 BEGIN(yyextra->lastCommentContext);
1437 }
1438 }
1439<ReadAliasArgs>\n {
1440 yyextra->aliasString+=yytext;
1441 yyextra->lastEscaped=false;
1442 if (yyextra->inVerbatim) // for verbatim sections we do not support multi-line
1443 // alias arguments.
1444 {
1445 copyToOutput(yyscanner,yyextra->aliasString.view());
1446 BEGIN( yyextra->lastBlockContext );
1447 }
1448 }
1449<ReadAliasArgs>"{" {
1450 yyextra->aliasString+=yytext;
1451 if (!yyextra->lastEscaped) yyextra->blockCount++;
1452 yyextra->lastEscaped=false;
1453 }
1454<ReadAliasArgs>"}" {
1455 yyextra->aliasString+=yytext;
1456 if (!yyextra->lastEscaped) yyextra->blockCount--;
1457 if (yyextra->blockCount==0)
1458 {
1459 bool inCppComment = yyextra->lastBlockContext==ReadLine && yyextra->readLineCtx==SComment;
1460 bool inCComment = yyextra->lastBlockContext==CComment && yyextra->blockHeadCol>0;
1461 replaceAliases(yyscanner,yyextra->aliasString.view(),inCppComment,inCComment);
1462 BEGIN( yyextra->lastBlockContext );
1463 }
1464 yyextra->lastEscaped=false;
1465 }
1466<ReadAliasArgs>. {
1467 yyextra->aliasString+=yytext;
1468 yyextra->lastEscaped=false;
1469 }
1470<CopyLine>. {
1471 copyToOutput(yyscanner,yytext,yyleng);
1472 }
1473<CopyLine>\n {
1474 copyToOutput(yyscanner,yytext,yyleng);
1475 yyextra->insertCppCommentMarker=false;
1476 BEGIN(yyextra->readLineCtx);
1477 }
1478<ReadLine>{CMD}{CMD} |
1479<ReadLine>. {
1480 copyToOutput(yyscanner,yytext,yyleng);
1481 }
1482<IncludeFile>. {
1483 copyToOutput(yyscanner,yytext,yyleng);
1484 }
1485<IncludeFile>\n {
1486 copyToOutput(yyscanner,yytext,yyleng);
1487 insertCommentStart(yyscanner);
1488 }
1489<*>. {
1490 copyToOutput(yyscanner,yytext,yyleng);
1491 }
1492<<EOF>> {
1493 if (YY_START == ReadAliasArgs)
1494 {
1495 warn(yyextra->fileName,yyextra->lineNr,
1496 "Reached end of file while still searching closing '}}' of an alias argument (probable start: '{}')",
1497 yyextra->aliasCmd);
1498 }
1499 else if (YY_START==Verbatim || YY_START==VerbatimCode)
1500 {
1501 warn(yyextra->fileName,yyextra->lineNr,
1502 "Reached end of file while still searching closing '{}' of a verbatim block starting at line {}",
1503 yyextra->blockName,yyextra->verbatimLine);
1504 }
1505 if (yyextra->includeStack.empty())
1506 {
1507 yyextra->insertCppCommentMarker=false;
1508 yyterminate();
1509 }
1510 else // switch back to parent file
1511 {
1512 std::unique_ptr<commentcnv_FileState> &fs = yyextra->includeStack.back();
1513 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
1514 yy_switch_to_buffer(fs->bufState, yyscanner);
1515 yy_delete_buffer(oldBuf, yyscanner);
1516 BEGIN(fs->oldState);
1517 yyextra->fileName = fs->oldFileName;
1518 yyextra->lineNr = fs->oldLineNr;
1519 yyextra->inBuf = fs->oldFileBuf;
1520 yyextra->inBufPos = fs->oldFileBufPos;
1521 yyextra->includeCtx = fs->oldIncludeCtx;
1522 DString lineStr= " \\ifile \""+yyextra->fileName+"\" \\iline "+DString().setNum(yyextra->lineNr)+" ";
1523 if (fs->oldRaiseLvl!=yyextra->raiseLevel)
1524 {
1525 lineStr+="\\iraise " + std::to_string(fs->oldRaiseLvl)+ " ";
1526 }
1527 if (fs->oldRaiseLbl!=yyextra->raiseLabel)
1528 {
1529 lineStr+="\\iprefix \"" + fs->oldRaiseLbl + "\" ";
1530 }
1531 lineStr+="\\ilinebr ";
1532 yyextra->raiseLevel = fs->oldRaiseLvl;
1533 yyextra->raiseLabel = fs->oldRaiseLbl;
1534 copyToOutput(yyscanner,lineStr.view());
1535 yyextra->includeStack.pop_back();
1536 //printf("<<EOF>> switch back to %s line %d inbufPos=%d outbufPos=%d\n",
1537 // qPrint(yyextra->fileName),yyextra->lineNr,yyextra->inBufPos,yyextra->outBuf.curPos());
1538 }
1539 }
DString & setNum(short n)
Definition dstring.h:552
std::string_view view() const
Definition dstring.h:162
#define yyterminate()
1540 /*
1541<*>\n { fprintf(stderr,"Lex scanner %s (%s) default rule newline for state %s.\n", __FILE__, qPrint(yyextra->fileName),stateToString(YY_START));}
1542 */
1543%%
1544
1545static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
1546{
1547 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1548
1549 //printf("parseIncludeOptions=%s\n",qPrint(s));
1550 size_t optIdxStart = s.find('{');
1551 size_t optIdxEnd = optIdxStart!=std::string::npos ? s.find("}",optIdxStart+1) : std::string::npos;
1552 std::string cmdName;
1553 StringVector optList;
1554 if (optIdxStart == std::string::npos) // no options
1555 {
1556 cmdName = stripWhiteSpace(s.substr(1)); // to remove {CMD}
1557 }
1558 else // options present
1559 {
1560 cmdName = stripWhiteSpace(s.substr(1,optIdxStart-1)); // to remove {CMD}
1561 optList = split(std::string{s.substr(optIdxStart+1,optIdxEnd-optIdxStart-1)},",");
1562 }
1563 bool isDoc = cmdName=="includedoc" || cmdName=="snippetdoc";
1564 for (const auto &opt : optList)
1565 {
1566 if (stripWhiteSpace(opt)==std::string_view{"doc"})
1567 {
1568 isDoc=true;
1569 break;
1570 }
1571 }
1572
1573 if (isDoc)
1574 {
1575 for (const auto &opt : optList)
1576 {
1577 std::string_view locOpt = stripWhiteSpace(opt);
1578 size_t posEqual = locOpt.find('=');
1579 std::string_view option = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(0,posEqual)) : locOpt;
1580 std::string_view value = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(posEqual+1)) : std::string_view();
1581
1582 if (option==std::string_view{"doc"} && value.empty())
1583 {
1584 }
1585 else if (option==std::string_view{"raise"} && !value.empty())
1586 {
1587 yyextra->raiseIncrement = atoi(value.data());
1588 if (yyextra->raiseLevel+yyextra->raiseIncrement>=SectionType::MaxLevel) // check range
1589 {
1590 warn(yyextra->fileName,yyextra->lineNr,"Raising section level from {} to {}, exceeds allowed range [0-{}], adjusting",
1591 yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,SectionType::MaxLevel-1);
1592 yyextra->raiseIncrement = std::max(0,SectionType::MaxLevel-1-yyextra->raiseLevel);
1593 }
1594 }
1595 else if (option==std::string_view{"prefix"} && !value.empty())
1596 {
1597 yyextra->raisePrefix = value;
1598 }
1599 else
1600 {
1601 warn(yyextra->fileName,yyextra->lineNr,"Unsupported option '{}' for {} command",option, cmdName);
1602 }
1603 }
1604 }
1605
1606 return isDoc;
1607}
1608
1609
1610static void replaceCommentMarker(yyscan_t yyscanner,std::string_view s)
1611{
1612 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1613 if (s.empty()) return;
1614 size_t p = 0;
1615 size_t len = s.length();
1616 char c = 0;
1617 // copy leading blanks
1618 while (p<len && (c=s[p]) && (c==' ' || c=='\t' || c=='\n'))
1619 {
1620 yyextra->outBuf+=c;
1621 if (c=='\n') { yyextra->lineNr++; yyextra->col=0; } else { yyextra->col++; }
1622 p++;
1623 }
1624 // replace start of comment marker by blanks and the last character by a *
1625 int blanks=0;
1626 while (p<len && (c=s[p]) && (c=='/' || c=='!' || c=='#'))
1627 {
1628 blanks++;
1629 p++;
1630 if (p<len && s[p]=='<') // comment-after-item marker
1631 {
1632 blanks++;
1633 p++;
1634 }
1635 if (c=='!') // end after first !
1636 {
1637 break;
1638 }
1639 }
1640 if (blanks>0)
1641 {
1642 while (blanks>2)
1643 {
1644 yyextra->outBuf+=' ';
1645 yyextra->col++;
1646 blanks--;
1647 }
1648 if (blanks>1) { yyextra->outBuf+='*'; yyextra->col++; }
1649 yyextra->outBuf+=' ';
1650 yyextra->col++;
1651 }
1652 // copy comment line to output
1653 yyextra->outBuf+=s.substr(p);
1654 yyextra->col+=static_cast<int>(s.substr(p).length());
1655}
1656
1657static inline int computeIndent(const char *s)
1658{
1659 int col=0;
1660 int tabSize=Config_getInt(TAB_SIZE);
1661 const char *p=s;
1662 char c = 0;
1663 while ((c=*p++))
1664 {
1665 if (c==' ') col++;
1666 else if (c=='\t') col+=tabSize-(col%tabSize);
1667 else break;
1668 }
1669 return col;
1670}
1671
1672static inline void copyToOutput(yyscan_t yyscanner,std::string_view s)
1673{
1674 int tabSize=Config_getInt(TAB_SIZE);
1675 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1676 size_t len = s.length();
1677 if (yyextra->skip) // only add newlines.
1678 {
1679 for (size_t i=0;i<len;i++)
1680 {
1681 switch(s[i])
1682 {
1683 case '\n':
1684 yyextra->outBuf+='\n';
1685 yyextra->lineNr++;
1686 yyextra->col=0;
1687 break;
1688 case '\t':
1689 yyextra->col+=tabSize-(yyextra->col%tabSize);
1690 break;
1691 default:
1692 yyextra->col++;
1693 break;
1694 }
1695 }
1696 }
1697 else if (len>0)
1698 {
1699 yyextra->outBuf+=s;
1700 for (size_t i=0;i<len;i++)
1701 {
1702 switch (s[i])
1703 {
1704 case '\n': yyextra->col=0;
1705 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1706 yyextra->lineNr++; break;
1707 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1708 default: yyextra->col++; break;
1709 }
1710 }
1711 }
1712}
1713
1714static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1715{
1716 copyToOutput(yyscanner,std::string_view{s,(size_t)len});
1717}
1718
1719static void clearCommentStack(yyscan_t yyscanner)
1720{
1721 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1722 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1723}
1724
1725static void startCondSection(yyscan_t yyscanner,const DString &sectId)
1726{
1727 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1728 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1729 CondParser prs;
1730 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1731 yyextra->condStack.emplace(yyextra->lineNr,sectId,yyextra->skip);
1732 if (!expResult) // not enabled
1733 {
1734 yyextra->skip=true;
1735 }
1736}
1737
1738static void endCondSection(yyscan_t yyscanner)
1739{
1740 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1741 if (yyextra->condStack.empty())
1742 {
1743 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1744 yyextra->skip=false;
1745 }
1746 else
1747 {
1748 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1749 yyextra->skip=ctx.skip;
1750 yyextra->condStack.pop();
1751 }
1752 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1753}
1754
1755static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1756{
1757 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1758 bool oldSkip=yyextra->skip;
1759 startCondSection(yyscanner,expression);
1760 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1761 !oldSkip && yyextra->skip)
1762 {
1763 if (yyextra->lang!=SrcLangExt::Python &&
1764 yyextra->lang!=SrcLangExt::VHDL &&
1765 yyextra->lang!=SrcLangExt::Markdown &&
1766 yyextra->lang!=SrcLangExt::Fortran)
1767 {
1768 yyextra->outBuf+='*';
1769 yyextra->outBuf+='/';
1770 yyextra->col+=2;
1771 }
1772 }
1773 if (yyextra->readLineCtx==SComment)
1774 {
1775 BEGIN(SComment);
1776 }
1777 else
1778 {
1779 BEGIN(yyextra->condCtx);
1780 }
1781}
1782
1783/** Returns the line number of the line following the line with the marker.
1784 * \sa routine extractBlock
1785 */
1786static int lineBlock(const DString &text,const DString &marker)
1787{
1788 int result = 1;
1789
1790 // find the character positions of the first marker
1791 size_t m1 = text.find(marker);
1792 if (m1==DString::npos) return result;
1793
1794 // find start line positions for the markers
1795 bool found=false;
1796 size_t p=0, i=0;
1797 while (!found && (i=text.find('\n',p))!=DString::npos)
1798 {
1799 found = (p<=m1 && m1<i); // found the line with the start marker
1800 p=i+1;
1801 result++;
1802 }
1803 return result;
1804}
1805
1806
1807/** Returns the section of text, in between a pair of markers.
1808 * Full lines are returned, excluding the lines on which the markers appear.
1809 * \sa routine lineBlock
1810 */
1811static DString extractBlock(const DString &text,const DString &marker,size_t &blockPos)
1812{
1813 DString result;
1814 size_t p=0, i = DString::npos;
1815 bool found = false;
1816
1817 // find the character positions of the markers
1818 size_t m1 = text.find(marker);
1819 if (m1==DString::npos) return result;
1820 size_t m2 = text.find(marker,m1+marker.length());
1821 if (m2==DString::npos) return result;
1822
1823 // find start and end line positions for the markers
1824 size_t l1=DString::npos, l2=DString::npos;
1825 while (!found && (i=text.find('\n',p))!=DString::npos)
1826 {
1827 found = (p<=m1 && m1<i); // found the line with the start marker
1828 p=i+1;
1829 }
1830 l1=p;
1831 blockPos=p;
1832 size_t lp=i;
1833 if (found)
1834 {
1835 while ((i=text.find('\n',p))!=DString::npos)
1836 {
1837 if (p<=m2 && m2<i) // found the line with the end marker
1838 {
1839 l2=p;
1840 break;
1841 }
1842 p=i+1;
1843 lp=i;
1844 }
1845 }
1846 if (l2==DString::npos) // marker at last line without newline (see bug706874)
1847 {
1848 l2=lp;
1849 }
1850 return l1!=DString::npos && l2!=DString::npos && l2>l1 ? text.mid(l1,l2-l1) : DString();
1851}
1852
1853static void insertCommentStart(yyscan_t yyscanner)
1854{
1855 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1856 size_t startCol=yyextra->blockHeadCol;
1857 size_t contentCol=yyextra->insertCommentCol;
1858 size_t markerSpace=contentCol-startCol;
1859 //printf("insertCommentStart startCol=%d contentCol=%d mlBrief=%d insertCppCommentMarker=%d\n",
1860 // yyextra->blockHeadCol,yyextra->insertCommentCol,yyextra->mlBrief,yyextra->insertCppCommentMarker);
1861 std::string marker;
1862 if (yyextra->lang==SrcLangExt::Python) // need to insert # or space
1863 {
1864 if (yyextra->pythonDocString) // """! style comment
1865 {
1866 marker=" ";
1867 }
1868 else
1869 {
1870 marker="# ";
1871 }
1872 }
1873 else if (yyextra->lang==SrcLangExt::Fortran) // need to insert !!
1874 {
1875 marker="!! ";
1876 }
1877 else if (yyextra->lang==SrcLangExt::Markdown)
1878 {
1879 marker=" ";
1880 }
1881 else if (yyextra->insertCppCommentMarker) // need to insert ///
1882 {
1883 marker="/// ";
1884 if (startCol>0)
1885 {
1886 // insert `///` instead of '* '
1887 startCol--;
1888 markerSpace++;
1889 }
1890 }
1891 else // need to insert *
1892 {
1893 marker="* ";
1894 }
1895 size_t i=0;
1896 for (;i<startCol;i++)
1897 {
1898 copyToOutput(yyscanner," ");
1899 }
1900 if (marker.length()<=markerSpace && !yyextra->firstIncludeLine)
1901 {
1902 copyToOutput(yyscanner,marker);
1903 i+=static_cast<int>(marker.length());
1904 }
1905 for (;i<contentCol;i++)
1906 {
1907 copyToOutput(yyscanner," ");
1908 }
1909 yyextra->firstIncludeLine = false;
1910}
1911
1912static bool readIncludeFile(yyscan_t yyscanner,const DString &inc,const DString &blockId)
1913{
1914 //printf("readIncludeFile(inc=%s,blockId=%s)\n",qPrint(inc),qPrint(blockId));
1915 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1916 bool ambig = false;
1917 DString absFileName = findExampleFilePath(inc,ambig);
1918 FileInfo fi(absFileName.str());
1919 if (!absFileName.empty() && fi.exists() && fi.isFile())
1920 {
1921 if (ambig)
1922 {
1923 warn_doc_error(yyextra->fileName,yyextra->lineNr,"included file name '{}' is ambiguous"
1924 "Possible candidates:\n{}",inc, Doxygen::exampleNameLinkedMap->showFileDefMatches(inc));
1925 }
1926 bool alreadyProcessed = std::any_of(
1927 yyextra->includeStack.begin(),
1928 yyextra->includeStack.end(),
1929 [&absFileName,&blockId](const auto &lfs)
1930 { return lfs->fileName==absFileName && lfs->blockId==blockId; }
1931 );
1932
1933 if (alreadyProcessed)
1934 {
1935 if (!blockId.empty())
1936 {
1937 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\snippet{{doc}}' block with name '{}' and file name '{}', skipping",
1938 blockId,absFileName);
1939 }
1940 else
1941 {
1942 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\include{{doc}}' with file name '{}', skipping", absFileName);
1943 }
1944 return false;
1945 }
1946
1947 auto fs = std::make_unique<commentcnv_FileState>();
1948 if (!readInputFile(absFileName,fs->fileBuf,false))
1949 {
1950 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' could not be read",blockId.empty()?"include":"snippet",absFileName);
1951 fs.reset();
1952 return false;
1953 }
1954 int lineNr=1;
1955 if (!blockId.empty())
1956 {
1957 DString incText { fs->fileBuf };
1958 int count = incText.contains(blockId.data());
1959 if (count!=2)
1960 {
1961 warn_doc_error(yyextra->fileName,yyextra->lineNr,"block marked with {} for \\snippet{{doc}} should appear twice in file {}, found it {:d} times, skipping",
1962 blockId,absFileName,count);
1963 return false;
1964 }
1965 lineNr = lineBlock(incText, blockId);
1966 size_t blockPos = 0;
1967 incText = extractBlock(incText, blockId, blockPos);
1968 fs->fileBuf.clear();
1969 if (!incText.empty())
1970 {
1971 fs->fileBuf.append(incText.str());
1972 }
1973 }
1974 int oldRaiseLevel = yyextra->raiseLevel;
1975 DString oldRaiseLabel = yyextra->raiseLabel;
1976 yyextra->raiseLevel+=yyextra->raiseIncrement;
1977 yyextra->raiseLabel+=yyextra->raisePrefix;
1978 DString lineStr=" \\ifile \""+absFileName+"\" \\iline " + std::to_string(lineNr)+" ";
1979 if (yyextra->raiseLevel>0)
1980 {
1981 lineStr+="\\iraise " + std::to_string(yyextra->raiseLevel)+" ";
1982 }
1983 if (!yyextra->raiseLabel.empty())
1984 {
1985 lineStr+="\\iprefix \"" + yyextra->raiseLabel + "\" ";
1986 }
1987 lineStr+="\\ilinebr ";
1988 copyToOutput(yyscanner,lineStr.view());
1989
1990 fs->fileName = absFileName;
1991 fs->bufState = YY_CURRENT_BUFFER;
1992 fs->oldLineNr = yyextra->lineNr;
1993 fs->oldFileName = yyextra->fileName;
1994 fs->oldState = yyextra->includeCtx;
1995 fs->oldFileBuf = yyextra->inBuf;
1996 fs->oldFileBufPos = yyextra->inBufPos;
1997 fs->oldIncludeCtx = yyextra->includeCtx;
1998 fs->oldRaiseLvl = oldRaiseLevel;
1999 fs->oldRaiseLbl = oldRaiseLabel;
2000 fs->blockId = blockId;
2001 yy_switch_to_buffer(yy_create_buffer(nullptr, YY_BUF_SIZE, yyscanner),yyscanner);
2002 yyextra->fileName = absFileName;
2003 yyextra->lineNr = lineNr;
2004 yyextra->inBuf = &fs->fileBuf;
2005 yyextra->inBufPos = 0;
2006 yyextra->includeStack.push_back(std::move(fs));
2007 insertCommentStart(yyscanner);
2008 //printf("switched to %s\n",qPrint(fileName));
2009 }
2010 else
2011 {
2012 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' not found",blockId.empty()?"include":"snippet",inc);
2013 return false;
2014 }
2015 return true;
2016}
2017
2018/** copies string \a s with length \a len to the output, while
2019 * replacing any alias commands found in the string.
2020 */
2021static void replaceAliases(yyscan_t yyscanner,std::string_view s,bool replaceCppComment,bool replaceCComment)
2022{
2023 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2024 if (s.empty()) return;
2025 size_t pos = s.find('{');
2026 std::string cmd { s.substr(1, pos!=std::string::npos ? pos-1 : s.length()-1) };
2027 auto &expAlias = yyextra->expandedAliases;
2028 if (std::find(expAlias.begin(),expAlias.end(),cmd)!=std::end(expAlias))
2029 {
2030 copyToOutput(yyscanner,s);
2031 return; // prevent recursive expansion
2032 }
2033 else if (cmd=="ialias")
2034 {
2035 if (s.length()>cmd.length()+3) // \cmd{value}
2036 {
2037 std::string value { s.substr(cmd.length()+2,s.length()-cmd.length()-3) };
2038 //printf("removing value '%s'\n",qPrint(value));
2039 expAlias.erase(std::remove(expAlias.begin(),expAlias.end(),value),expAlias.end());
2040 }
2041 return;
2042 }
2043 std::string result = resolveAliasCmd(s);
2044 if (yyextra->inVerbatim) // inside verbatim blocks (like @code...@endcode) only expand aliases if
2045 // their expansion contains the matching end block marker.
2046 {
2047 std::string blk = yyextra->blockName.str();
2048 ASSERT(!blk.empty());
2049 bool isNamedCommand=isId(blk[0]); // true for e.g. @endcode, false for e.g. ~~~
2050 size_t i=0,p=0;
2051 bool found=false;
2052 while ((i=result.find(blk,p))!=std::string::npos && !found) // for each match of blk in result
2053 {
2054 found = !isNamedCommand || // e.g. '~~~' or '-->'
2055 (i>0 && (result[i-1]=='\\' || result[i-1]=='@') && !isId(result[i+blk.length()])); // e.g. '@endcode' but not ~endcode or @endcodex
2056 p = i+yyextra->blockName.length();
2057 }
2058 //printf("blk=%s result=%s found=%d\n",qPrint(blk),qPrint(result),found);
2059 if (!found) // treat alias as part of the verbatim block
2060 {
2061 copyToOutput(yyscanner,s);
2062 return;
2063 }
2064 }
2065 //printf("replaceAliases(%s)->'%s' replaceCppComment=%d replaceCComment=%d\n",qPrint(s),qPrint(result),replaceCppComment,replaceCComment);
2066 if (result!=s)
2067 {
2068 size_t numSpaces = yyextra->blockHeadCol>1 ? yyextra->blockHeadCol-1 : 0;
2069 std::string spaces(numSpaces,' ');
2070 if (replaceCppComment) // In case we are replacing a multiline /// comment by a C style comment
2071 // and we have new lines in the alias argument, we need to place back a /// for each new line
2072 // to prevent breaking the multiline comment into multiple C style comments
2073 {
2074 std::string replacement = "\n"+spaces+"///";
2075 result = substituteStringView(result,"\n",replacement);
2076 }
2077 else if (replaceCComment)
2078 {
2079 std::string replacement = "\n"+spaces+" * ";
2080 result = substituteStringView(result,"\n",replacement);
2081 }
2082 expAlias.push_back(cmd);
2083 // add a ialias command to allow expansion of cmd again
2084 result += " \\ilinebr \\ialias{";
2085 result += cmd;
2086 result += "}";
2087 for (int i=(int)result.length()-1; i>=0; i--)
2088 {
2089 unput(result[i]);
2090 }
2091 }
2092 else
2093 {
2094 copyToOutput(yyscanner,result);
2095 }
2096}
2097
2098
2099static int yyread(yyscan_t yyscanner,char *buf,int max_size)
2100{
2101 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2102 int bytesInBuf = static_cast<int>(yyextra->inBuf->size())-yyextra->inBufPos;
2103 int bytesToCopy = std::min(max_size,bytesInBuf);
2104 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
2105 yyextra->inBufPos+=bytesToCopy;
2106 return bytesToCopy;
2107}
2108
2109static void replaceComment(yyscan_t yyscanner,int offset)
2110{
2111 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2112 if (yyextra->mlBrief || yyextra->skip)
2113 {
2114 copyToOutput(yyscanner,yytext,yyleng);
2115 }
2116 else
2117 {
2118 size_t i=computeIndent(&yytext[offset]);
2119 // A line in another column starts a new block, since it may document something
2120 // else. If both the block and the line have a marker ending in '<' (//!< or ///<),
2121 // they both document the member in front of them. The line then still starts a new
2122 // block, but a C style one: handed back to the scanner as a single //!< line it
2123 // would become the brief description, ahead of the lines that come before it
2124 // (see issue #5266).
2125 bool afterMember = yyleng>0 && yytext[yyleng-1]=='<';
2126 // The '<' of the line that started the block is not part of the text matched at that
2127 // point, so look at what was written for it: "/*!" or "/**", then '<' if it had one.
2128 bool headAfterMember = yyextra->blockHeadPos!=std::string::npos &&
2129 yyextra->blockHeadPos+3<yyextra->outBuf.size() &&
2130 yyextra->outBuf[yyextra->blockHeadPos+3]=='<';
2131 bool sameEntity = afterMember && headAfterMember;
2132 //printf("i=%d blockHeadCol=%d\n",i,yyextra->blockHeadCol);
2133 if (i==yyextra->blockHeadCol || i+1==yyextra->blockHeadCol)
2134 {
2135 replaceCommentMarker(yyscanner,std::string_view(yytext,yyleng));
2136 }
2137 else if (sameEntity)
2138 {
2139 // start the new block on this line, after the newline and the indentation
2140 size_t p=offset;
2141 while (p<(size_t)yyleng && (yytext[p]==' ' || yytext[p]=='\t')) p++;
2142 bool javadoc = yytext[p+2]=='/';
2143 copyToOutput(yyscanner," */");
2144 copyToOutput(yyscanner,std::string_view(yytext,p));
2145 yyextra->blockHeadCol=i+1;
2146 yyextra->blockHeadPos=yyextra->outBuf.size();
2147 // With AUTOBRIEF the first sentence of this block would become the brief description
2148 // when the lines before it did not give one, so use the style AUTOBRIEF does not apply to.
2149 bool qtAuto = Config_getBool(QT_AUTOBRIEF);
2150 bool jdAuto = Config_getBool(JAVADOC_AUTOBRIEF);
2151 if (javadoc && jdAuto && !qtAuto) javadoc=false;
2152 else if (!javadoc && qtAuto && !jdAuto) javadoc=true;
2153 copyToOutput(yyscanner,javadoc ? "/**<" : "/*!<");
2154 }
2155 else
2156 {
2157 copyToOutput(yyscanner," */");
2158 for (i = yyleng; i>0; )
2159 {
2160 --i;
2161 unput(yytext[i]);
2162 }
2163 yyextra->inSpecialComment=false;
2164 BEGIN(Scan);
2165 }
2166 }
2167}
2168
2169/*! This function does three things:
2170 * -# It converts multi-line C++ style comment blocks (that are aligned)
2171 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
2172 * -# It replaces aliases with their definition (see ALIASES)
2173 * -# It handles conditional sections (cond...endcond blocks)
2174 */
2175void convertCppComments(const std::string &inBuf,std::string &outBuf,const std::string &fn)
2176{
2177 DString fileName { fn };
2178 yyscan_t yyscanner;
2179 commentcnvYY_state extra(&inBuf,outBuf);
2180 commentcnvYYlex_init_extra(&extra,&yyscanner);
2181#ifdef FLEX_DEBUG
2182 commentcnvYYset_debug(Debug::isFlagSet(Debug::Lex_commentcnv)?1:0,yyscanner);
2183#endif
2184 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2185 //printf("convertCppComments(%s)\n",qPrint(fileName));
2186 yyextra->inBufPos = 0;
2187 yyextra->col = 0;
2188 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
2189 yyextra->skip = false;
2190 yyextra->fileName = fileName;
2191 yyextra->lang = getLanguageFromFileName(fileName);
2192 yyextra->pythonDocString = false;
2193 yyextra->lineNr = 1;
2194 yyextra->raiseLevel = 0;
2195 yyextra->raiseLabel = "";
2196 yyextra->raiseIncrement = 0;
2197 yyextra->raisePrefix = "";
2198 yyextra->insertCppCommentMarker=false;
2199 yyextra->expandedAliases.clear();
2200 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
2201 clearCommentStack(yyscanner);
2202 yyextra->vhdl = false;
2203
2204 DebugLex debugLex(Debug::Lex_commentcnv,__FILE__, qPrint(fileName));
2205 yyextra->isFixedForm = false;
2206 if (yyextra->lang==SrcLangExt::Fortran)
2207 {
2209 yyextra->isFixedForm = recognizeFixedForm(inBuf,fmt);
2210 }
2211
2212 if (yyextra->lang==SrcLangExt::Markdown)
2213 {
2214 yyextra->nestingCount=0;
2215 BEGIN(CComment);
2216 yyextra->commentStack.push(yyextra->lineNr);
2217 }
2218 else
2219 {
2220 BEGIN(Scan);
2221 }
2222 yylex(yyscanner);
2223 while (!yyextra->condStack.empty())
2224 {
2225 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
2226 DString sectionInfo(" ");
2227 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
2228 warn(yyextra->fileName,ctx.lineNr,"Conditional section{}does not have "
2229 "a corresponding \\endcond command within this file.",sectionInfo.data());
2230 yyextra->condStack.pop();
2231 }
2232 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt::Markdown && yyextra->lang!=SrcLangExt::Fortran)
2233 {
2234 DString lines;
2235 bool first = true;
2236 while (!yyextra->commentStack.empty())
2237 {
2238 int lineNr = yyextra->commentStack.top();
2239 if (!first) lines += ", ";
2240 lines += DString().setNum(lineNr);
2241 first = false;
2242 yyextra->commentStack.pop();
2243 }
2244 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
2245 "Nesting level {} (possible line reference(s): {})",yyextra->nestingCount,lines);
2246 }
2247 yyextra->nestingCount = 0;
2249 {
2250 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: {}\n"
2251 "output=[\n{}]\n-----------\n",fileName,yyextra->outBuf
2252 );
2253 }
2254 commentcnvYYlex_destroy(yyscanner);
2255}
2256
2257
2258//----------------------------------------------------------------------------
2259
2260#include "commentcnv.l.h"
std::string resolveAliasCmd(std::string_view aliasCmd)
Definition aliases.cpp:495
Copyright (C) 1997-2026 by Dimitri van Heesch.
Definition condparser.h:29
bool parse(const DString &fileName, int lineNr, const DString &expr)
parses and evaluates the given expression.
void push_back(char c)
Definition dstring.h:202
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
int contains(char c, bool cs=true) const
Definition dstring.cpp:85
size_t find(char c, size_t pos=0) const
Definition dstring.h:239
DString & sprintf(const char *format,...)
Definition dstring.cpp:34
const std::string & str() const
Definition dstring.h:645
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:157
@ Lex_commentcnv
Definition debug.h:55
@ CommentCnv
Definition debug.h:32
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:78
static FileNameLinkedMap * exampleNameLinkedMap
Definition doxygen.h:95
Minimal replacement for QFileInfo.
Definition fileinfo.h:26
bool exists() const
Definition fileinfo.cpp:34
bool isFile() const
Definition fileinfo.cpp:67
DString showFileDefMatches(const DString &n) const
Returns a list of file definitions in fnMap that match the file name n.
Definition filename.cpp:131
static constexpr int MaxLevel
Definition section.h:39
void convertCppComments(const std::string &inBuf, std::string &outBuf, const std::string &fn)
Converts the comments in a file.
static DString extractBlock(const DString &text, const DString &marker, size_t &blockPos)
Returns the section of text, in between a pair of markers.
static int lineBlock(const DString &text, const DString &marker)
Returns the line number of the line following the line with the marker.
#define YY_BUF_SIZE
Definition commentcnv.l:19
#define Config_getInt(name)
Definition config.h:34
int yylex(void)
std::vector< std::string > StringVector
Definition containers.h:33
bool isId(char c)
Returns true if c is a valid character for an identifier.
Definition dstring.h:895
const char * qPrint(const char *s)
Definition dstring.h:783
bool recognizeFixedForm(const DString &contents, FortranFormat format)
FortranFormat convertFileNameFortranParserCode(const DString &fn)
#define ASSERT(x)
Definition message.h:142
#define warn_doc_error(file, line, fmt,...)
Definition message.h:112
Definition message.h:146
std::string substituteStringView(std::string_view s, std::string_view toReplace, std::string_view replaceWith)
Returns a new string where occurrences of substring toReplace in string s are replaced by string repl...
Definition stringutil.h:53
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition stringutil.h:117
FortranFormat
Definition types.h:612
bool readInputFile(const DString &fileName, std::string &contents, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition util.cpp:4383
SrcLangExt getLanguageFromFileName(const DString &fileName, SrcLangExt defLang)
Definition util.cpp:4177
DString findExampleFilePath(const DString &file, bool &ambig)
Definition util.cpp:2460