Skip to content

Commit 9defcc3

Browse files
committed
issue doxygen#11621 Markdown code handling ` gets confused by unterminated ` within (introduced by 1.11)
1 parent c21f339 commit 9defcc3

File tree

4 files changed

+93
-13
lines changed

4 files changed

+93
-13
lines changed

doc/autolink.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
\tableofcontents{html,latex}
2020

21-
Most documentation systems have special `see also' sections where links
21+
Most documentation systems have special 'see also' sections where links
2222
to other pieces of documentation can be inserted.
2323
Although Doxygen also has a command to start such a section (See section
2424
\ref cmdsa "\\sa"), it does allow you to put these kind of links anywhere in the

doc/features.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Although Doxygen can now be used in any project written in a language that is
101101
supported by Doxygen, initially it was specifically designed to be used for projects
102102
that make use of Qt Software's
103103
<A HREF="https://doc.qt.io">Qt toolkit</A>. I have tried to
104-
make Doxygen `Qt-compatible'. That is: Doxygen can read the documentation contained in
104+
make Doxygen 'Qt-compatible'. That is: Doxygen can read the documentation contained in
105105
the Qt source code and create a class browser that looks quite similar to the
106106
one that is generated by Qt Software. Doxygen understands the C++ extensions
107107
used by Qt such as signals and slots and many of the markup commands used in the Qt sources.

src/commentcnv.l

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ struct commentcnvYY_state
122122
int javaBlock = 0;
123123
bool specialComment = FALSE;
124124
bool inVerbatim = false;
125+
int verbatimLine = 1;
125126
bool inHtmlDoxygenCommand = false;
126127
bool firstIncludeLine = false;
127128
bool insertCppCommentMarker = false;
@@ -561,6 +562,7 @@ SLASHopt [/]*
561562
yyextra->javaBlock=1;
562563
yyextra->blockName=QCString("end")+&yytext[1];
563564
yyextra->inVerbatim=true;
565+
yyextra->verbatimLine=yyextra->lineNr;
564566
BEGIN(VerbatimCode);
565567
}
566568
<CComment,IncludeFile>"{"[ \t]*"@literal"/[ \t\n] {
@@ -569,6 +571,7 @@ SLASHopt [/]*
569571
yyextra->javaBlock=1;
570572
yyextra->blockName=QCString("end")+&yytext[1];
571573
yyextra->inVerbatim=true;
574+
yyextra->verbatimLine=yyextra->lineNr;
572575
BEGIN(VerbatimCode);
573576
}
574577
<CComment,ReadLine,IncludeFile>{CMD}"ilinebr"[ \t]+("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
@@ -581,6 +584,7 @@ SLASHopt [/]*
581584
yyextra->javaBlock=0;
582585
yyextra->blockName=QCString(yytext).stripWhiteSpace().right(3); // take the ``` or ~~~ part
583586
yyextra->inVerbatim=true;
587+
yyextra->verbatimLine=yyextra->lineNr;
584588
BEGIN(VerbatimCode);
585589
}
586590
<CComment,ReadLine,IncludeFile>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
@@ -593,6 +597,7 @@ SLASHopt [/]*
593597
yyextra->javaBlock=0;
594598
yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3); // take the ``` or ~~~ part
595599
yyextra->inVerbatim=true;
600+
yyextra->verbatimLine=yyextra->lineNr;
596601
BEGIN(VerbatimCode);
597602
}
598603
<CComment,ReadLine,IncludeFile>{CMD}("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
@@ -608,8 +613,25 @@ SLASHopt [/]*
608613
yyextra->blockName=QCString("end")+&yytext[1];
609614
}
610615
yyextra->inVerbatim=true;
616+
yyextra->verbatimLine=yyextra->lineNr;
611617
BEGIN(VerbatimCode);
612618
}
619+
<CComment,ReadLine,IncludeFile>"```" { // skip ``` if not at the start of the line
620+
copyToOutput(yyscanner,yytext,yyleng);
621+
}
622+
<CComment,ReadLine,IncludeFile>"`"{1,2} {
623+
if (!Config_getBool(MARKDOWN_SUPPORT))
624+
{
625+
REJECT;
626+
}
627+
copyToOutput(yyscanner,yytext,yyleng);
628+
yyextra->lastCommentContext = YY_START;
629+
yyextra->javaBlock=0;
630+
yyextra->blockName=yytext;
631+
yyextra->inVerbatim=true;
632+
yyextra->verbatimLine=yyextra->lineNr;
633+
BEGIN(VerbatimCode);
634+
}
613635
<CComment,ReadLine,IncludeFile>{CMD}("f$"|"f["|"f{"|"f(") {
614636
copyToOutput(yyscanner,yytext,yyleng);
615637
yyextra->blockName=&yytext[1];
@@ -627,6 +649,7 @@ SLASHopt [/]*
627649
}
628650
yyextra->lastCommentContext = YY_START;
629651
yyextra->inVerbatim=true;
652+
yyextra->verbatimLine=yyextra->lineNr;
630653
BEGIN(Verbatim);
631654
}
632655
<CComment,ReadLine,IncludeFile>"<!--!" { /* HTML comment doxygen command*/
@@ -649,13 +672,15 @@ SLASHopt [/]*
649672
yyextra->blockName="-->";
650673
yyextra->lastCommentContext = YY_START;
651674
yyextra->inVerbatim=true;
675+
yyextra->verbatimLine=yyextra->lineNr;
652676
BEGIN(Verbatim);
653677
}
654678
<CComment,ReadLine,IncludeFile>{CMD}("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
655679
copyToOutput(yyscanner,yytext,yyleng);
656680
yyextra->blockName=QCString("end")+&yytext[1];
657681
yyextra->lastCommentContext = YY_START;
658682
yyextra->inVerbatim=true;
683+
yyextra->verbatimLine=yyextra->lineNr;
659684
BEGIN(Verbatim);
660685
}
661686
<Scan>"\\\"" { /* escaped double quote */
@@ -715,8 +740,26 @@ SLASHopt [/]*
715740
}
716741
}
717742
<VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
743+
if (yyextra->blockName=="`" || yyextra->blockName=="``") // ``` inside single quote block
744+
{
745+
// copy the end block marker
746+
copyToOutput(yyscanner,yytext,yyleng);
747+
yyextra->inVerbatim=false;
748+
BEGIN(yyextra->lastCommentContext);
749+
}
750+
else
751+
{
752+
copyToOutput(yyscanner,yytext,yyleng);
753+
if (yytext[0]==yyextra->blockName[0])
754+
{
755+
yyextra->inVerbatim=false;
756+
BEGIN(yyextra->lastCommentContext);
757+
}
758+
}
759+
}
760+
<VerbatimCode>"`"{1,2} {
718761
copyToOutput(yyscanner,yytext,yyleng);
719-
if (yytext[0]==yyextra->blockName[0])
762+
if (yytext==yyextra->blockName)
720763
{
721764
yyextra->inVerbatim=false;
722765
BEGIN(yyextra->lastCommentContext);
@@ -756,6 +799,14 @@ SLASHopt [/]*
756799
<Verbatim,VerbatimCode>[^`~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
757800
copyToOutput(yyscanner,yytext,yyleng);
758801
}
802+
<Verbatim,VerbatimCode>[^`~@\/\-\\\n{}]+/\n { /* premature end of comment block */
803+
if (yyextra->lastCommentContext==ReadLine)
804+
{
805+
yyextra->inVerbatim=false;
806+
BEGIN(yyextra->lastCommentContext);
807+
}
808+
copyToOutput(yyscanner,yytext,yyleng);
809+
}
759810
<Verbatim,VerbatimCode>\n { /* new line in verbatim block */
760811
copyToOutput(yyscanner,yytext,yyleng);
761812
if (yyextra->lastCommentContext == IncludeFile)
@@ -842,10 +893,10 @@ SLASHopt [/]*
842893
copyToOutput(yyscanner,yytext,yyleng);
843894
}
844895
845-
<CComment,CNComment>[^ `~<\\!@*\n{\"'\/-]* { /* anything that is not a '*' or command */
896+
<CComment,CNComment>[^ `~<\\!@*\n{\"'\/-`]* { /* anything that is not a '*' or command */
846897
copyToOutput(yyscanner,yytext,yyleng);
847898
}
848-
<CComment,CNComment>^{B}*"*"+[^*\/<\\@\n{\"]* { /* stars without slashes */
899+
<CComment,CNComment>^{B}*"*"+[^*\/<\\@\n{\"`]* { /* stars without slashes */
849900
if (yyextra->lang==SrcLangExt::Markdown) REJECT;
850901
yyextra->col = computeIndent(yytext);
851902
if (yyextra->col>yyextra->blockHeadCol)
@@ -1039,6 +1090,7 @@ SLASHopt [/]*
10391090
<SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
10401091
replaceComment(yyscanner,0);
10411092
yyextra->readLineCtx=YY_START;
1093+
YY_CURRENT_BUFFER->yy_at_bol=1;
10421094
BEGIN(ReadLine);
10431095
}
10441096
<SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*{CMD}"}".*\n {
@@ -1052,20 +1104,23 @@ SLASHopt [/]*
10521104
<SComment>\n[ \t]*{CPPC}"/"[^\\@\/\n]/.*\n {
10531105
replaceComment(yyscanner,1);
10541106
yyextra->readLineCtx=YY_START;
1107+
YY_CURRENT_BUFFER->yy_at_bol=1;
10551108
BEGIN(ReadLine);
10561109
}
10571110
<SComment>^[ \t]*{CPPC}"!" | // just //!
10581111
<SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
10591112
<SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
10601113
replaceComment(yyscanner,0);
10611114
yyextra->readLineCtx=YY_START;
1115+
YY_CURRENT_BUFFER->yy_at_bol=1;
10621116
BEGIN(ReadLine);
10631117
}
10641118
<SComment>\n[ \t]*{CPPC}"!" |
10651119
<SComment>\n[ \t]*{CPPC}"!<"/.*\n |
10661120
<SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
10671121
replaceComment(yyscanner,1);
10681122
yyextra->readLineCtx=YY_START;
1123+
YY_CURRENT_BUFFER->yy_at_bol=1;
10691124
BEGIN(ReadLine);
10701125
}
10711126
<SComment>^[ \t]*{CPPC}"##"/.*\n {
@@ -1077,6 +1132,7 @@ SLASHopt [/]*
10771132
{
10781133
replaceComment(yyscanner,0);
10791134
yyextra->readLineCtx=YY_START;
1135+
YY_CURRENT_BUFFER->yy_at_bol=1;
10801136
BEGIN(ReadLine);
10811137
}
10821138
}
@@ -1089,6 +1145,7 @@ SLASHopt [/]*
10891145
{
10901146
replaceComment(yyscanner,1);
10911147
yyextra->readLineCtx=YY_START;
1148+
YY_CURRENT_BUFFER->yy_at_bol=1;
10921149
BEGIN(ReadLine);
10931150
}
10941151
}
@@ -1331,12 +1388,6 @@ SLASHopt [/]*
13311388
yyextra->insertCppCommentMarker=false;
13321389
BEGIN(yyextra->readLineCtx);
13331390
}
1334-
<ReadLine>``` {
1335-
copyToOutput(yyscanner,yytext,yyleng);
1336-
}
1337-
<ReadLine>`[^`\n]+` {
1338-
copyToOutput(yyscanner,yytext,yyleng);
1339-
}
13401391
<ReadLine>{CMD}{CMD} |
13411392
<ReadLine>. {
13421393
copyToOutput(yyscanner,yytext,yyleng);
@@ -1358,6 +1409,12 @@ SLASHopt [/]*
13581409
"Reached end of file while still searching closing '}}' of an alias argument (probable start: '{}')",
13591410
yyextra->aliasCmd);
13601411
}
1412+
else if (YY_START==Verbatim || YY_START==VerbatimCode)
1413+
{
1414+
warn(yyextra->fileName,yyextra->lineNr,
1415+
"Reached end of file while still searching closing '{}' of a verbatim block starting at line {}",
1416+
yyextra->blockName,yyextra->verbatimLine);
1417+
}
13611418
if (yyextra->includeStack.empty())
13621419
{
13631420
yyextra->insertCppCommentMarker=false;

src/scanner.l

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7189,6 +7189,14 @@ NONLopt [^\n]*
71897189
startVerbatimBlock(yyscanner,"```",pat.stripWhiteSpace().length(),true);
71907190
BEGIN(DocCopyBlock);
71917191
}
7192+
<DocBlock>"```" { // skip ``` if not at the start of a line
7193+
yyextra->docBlock << yytext;
7194+
}
7195+
<DocBlock>"`"{1,2} {
7196+
yyextra->docBlock << yytext;
7197+
startVerbatimBlock(yyscanner,yytext,yyleng,true);
7198+
BEGIN(DocCopyBlock);
7199+
}
71927200
<DocBlock>{B}*"<"{CODE}">" {
71937201
if (yyextra->insideCS)
71947202
{
@@ -7201,7 +7209,7 @@ NONLopt [^\n]*
72017209
REJECT;
72027210
}
72037211
}
7204-
<DocBlock>[^@*~\/\\\n]+ { // any character that isn't special
7212+
<DocBlock>[^@*~`\/\\\n]+ { // any character that isn't special
72057213
yyextra->docBlock << yytext;
72067214
}
72077215
<DocBlock>\n { // newline
@@ -7314,7 +7322,21 @@ NONLopt [^\n]*
73147322
}
73157323
yyextra->docBlock << pat;
73167324
}
7317-
<DocCopyBlock>[^\<@/\*\]~"\$\\\n]+ { // any character that is not special
7325+
<DocCopyBlock>"```" { // backtick + end marker
7326+
if (yyextra->docBlockName=="``" && endVerbatimBlock(yyscanner,"``",2))
7327+
{
7328+
BEGIN(DocBlock);
7329+
}
7330+
yyextra->docBlock << yytext;
7331+
}
7332+
<DocCopyBlock>"`"{1,2} {
7333+
if (endVerbatimBlock(yyscanner,yytext,yyleng))
7334+
{
7335+
BEGIN(DocBlock);
7336+
}
7337+
yyextra->docBlock << yytext;
7338+
}
7339+
<DocCopyBlock>[^\<@/\*\]`~"\$\\\n]+ { // any character that is not special
73187340
yyextra->docBlock << yytext;
73197341
}
73207342
<DocCopyBlock>\" {
@@ -7344,6 +7366,7 @@ NONLopt [^\n]*
73447366
"Found end of C comment inside a '{}' block without matching start of the comment!"
73457367
" Maybe the end marker for the block is missing?",
73467368
yyextra->docBlockName);
7369+
BEGIN(DocBlock);
73477370
}
73487371
yyextra->docBlock << yytext;
73497372
}

0 commit comments

Comments
 (0)