@@ -177,6 +177,8 @@ static bool handleIPrefix(yyscan_t yyscanner,const QCString &, const StringVecto
177177
178178[[maybe_unused]] static const char *stateToString (int state);
179179
180+ static QCString fileInfoLookup (const FileInfo &fi,const std::string &name);
181+
180182typedef bool (*DocCmdFunc)(yyscan_t yyscanner,const QCString &name, const StringVector &optList);
181183typedef EntryType (*MakeEntryType)();
182184
@@ -554,6 +556,7 @@ static int yyread(yyscan_t yyscanner,char *buf,int max_size);
554556static void addCite (yyscan_t yyscanner);
555557static void addIline (yyscan_t yyscanner,int lineNr);
556558static void addIlineBreak (yyscan_t yyscanner,int lineNr);
559+ static void escapeLabel (QCString &label);
557560
558561#define unput_string (yytext,yyleng ) do { for (int i=(int )yyleng-1 ;i>=0 ;i--) unput (yytext[i]); } while (0 )
559562
@@ -1918,25 +1921,93 @@ STopt [^\n@\\]*
19181921
19191922 /* ----- handle arguments of the section/subsection/.. commands ------- */
19201923
1921- <SectionLabel>{LABELID} { // first argument
1922- yyextra->sectionLabel=yyextra->raisePrefix+yytext;
1923- addOutput(yyscanner,yyextra->sectionLabel.data());
1924- yyextra->sectionTitle.clear();
1925- BEGIN(SectionTitle);
1924+ <SectionLabel>{LABELID} {
1925+ yyextra->sectionLabel+=yytext;
19261926 }
1927- <SectionLabel>{DOCNL} { // missing argument
1928- warn(yyextra->fileName,yyextra->lineNr,
1927+ <SectionLabel>{CMD}" lineinfo" (" {}" )? {
1928+ yyextra->sectionLabel += QCString().setNum(yyextra->lineNr);
1929+ }
1930+ <SectionLabel>{CMD}" fileinfo" (" {" [^}]*" }" )? {
1931+ FileInfo fi(yyextra->fileName.str());
1932+ bool hasOption = false;
1933+ QCString label;
1934+ if (yytext[yyleng-1] == '}') // has parameters
1935+ {
1936+ StringVector optList;
1937+ QCString txt = yytext;
1938+ QCString optStr = txt.mid(10,yyleng-11).stripWhiteSpace();
1939+ optList = split(optStr.str()," ," );
1940+ for (const auto &opt_ : optList)
1941+ {
1942+ QCString optStripped = QCString(opt_).stripWhiteSpace();
1943+ std::string opt = optStripped.lower().str();
1944+ QCString result = fileInfoLookup(fi,opt);
1945+ if (!result.isEmpty())
1946+ {
1947+ if (hasOption) // oops: already found an option
1948+ {
1949+ warn(yyextra->fileName,yyextra->lineNr," Multiple options specified with \\fileinfo, discarding ' {}' " , optStripped);
1950+ }
1951+ else
1952+ {
1953+ label = result;
1954+ }
1955+ hasOption = true;
1956+ }
1957+ else
1958+ {
1959+ warn(yyextra->fileName,yyextra->lineNr," Unknown option specified with \\fileinfo: ' {}' " , optStripped);
1960+ }
1961+ }
1962+ }
1963+ if (!hasOption)
1964+ {
1965+ if (Config_getBool(FULL_PATH_NAMES))
1966+ {
1967+ label=stripFromPath(yyextra->fileName);
1968+ }
1969+ else
1970+ {
1971+ label=yyextra->fileName;
1972+ }
1973+ }
1974+ escapeLabel(label);
1975+ yyextra->sectionLabel+=label;
1976+ }
1977+ <SectionLabel>{DOCNL} {
1978+ yyextra->sectionTitle.clear();
1979+ if (yyextra->sectionLabel.isEmpty())
1980+ { // missing argument
1981+ warn(yyextra->fileName,yyextra->lineNr,
19291982 " \\section command has no label"
19301983 );
1984+ }
1985+ else
1986+ {
1987+ yyextra->sectionLabel=yyextra->raisePrefix+yyextra->sectionLabel;
1988+ addOutput(yyscanner,yyextra->sectionLabel.data());
1989+ addSection(yyscanner);
1990+ }
19311991 if (*yytext=='\n ') yyextra->lineNr++;
19321992 addOutput(yyscanner,'\n ');
19331993 BEGIN( Comment );
19341994 }
19351995<SectionLabel>. { // invalid character for section label
1936- warn(yyextra->fileName,yyextra->lineNr,
1996+ if (yyextra->sectionLabel.isEmpty())
1997+ {
1998+ warn(yyextra->fileName,yyextra->lineNr,
19371999 " Invalid or missing section label"
19382000 );
1939- BEGIN(Comment);
2001+ BEGIN(Comment);
2002+ }
2003+ else
2004+ {
2005+ yyextra->sectionLabel=yyextra->raisePrefix+yyextra->sectionLabel;
2006+ addOutput(yyscanner,yyextra->sectionLabel.data());
2007+ yyextra->sectionTitle.clear();
2008+ unput_string(yytext,yyleng);
2009+ BEGIN(SectionTitle);
2010+ }
19402011 }
19412012<SectionTitle>{STAopt}/" \n" { // end of section title
19422013 addSection(yyscanner);
@@ -3292,6 +3363,7 @@ static bool handleSection(yyscan_t yyscanner,const QCString &s, const StringVect
32923363 setOutput(yyscanner,OutputDoc);
32933364 // printf("handleSection(%s) raiseLevel=%d\n",qPrint(s),yyextra->raiseLevel);
32943365 BEGIN(SectionLabel);
3366+ yyextra->sectionLabel.clear();
32953367 // determine natural section level
32963368 if (s==" section" ) yyextra->sectionLevel=SectionType::Section;
32973369 else if (s==" subsection" ) yyextra->sectionLevel=SectionType::Subsection;
@@ -3436,48 +3508,25 @@ static bool handleFileInfoSection(yyscan_t yyscanner,const QCString &cmdName, co
34363508{
34373509 return handleFileInfoResult(yyscanner,cmdName, optList, true );
34383510}
3439- static bool handleFileInfoResult (yyscan_t yyscanner,const QCString &, const StringVector &optList, bool isSection)
3511+
3512+ static QCString fileInfoLookup (const FileInfo &fi,const std::string &optionName)
34403513{
3441- using OutputWriter = std::function<void (yyscan_t ,FileInfo &,bool )>;
3442- static std::unordered_map<std::string,OutputWriter> options =
3443- { // name, writer
3444- { " name" , [](yyscan_t s,FileInfo &fi,bool isSect) { addOutput (s,fi.baseName ());
3445- if (isSect)
3446- {
3447- struct yyguts_t *yyg = (struct yyguts_t *)s;
3448- yyextra->sectionTitle +=fi.baseName ();
3449- }
3450- } },
3451- { " extension" , [](yyscan_t s,FileInfo &fi,bool isSect) { addOutput (s,fi.extension (true ));
3452- if (isSect)
3453- {
3454- struct yyguts_t *yyg = (struct yyguts_t *)s;
3455- yyextra->sectionTitle +=fi.extension (true );
3456- }
3457- } },
3458- { " filename" , [](yyscan_t s,FileInfo &fi,bool isSect) { addOutput (s,fi.fileName ());
3459- if (isSect)
3460- {
3461- struct yyguts_t *yyg = (struct yyguts_t *)s;
3462- yyextra->sectionTitle +=fi.fileName ();
3463- }
3464- } },
3465- { " directory" , [](yyscan_t s,FileInfo &fi,bool isSect) { addOutput (s,fi.dirPath ());
3466- if (isSect)
3467- {
3468- struct yyguts_t *yyg = (struct yyguts_t *)s;
3469- yyextra->sectionTitle +=fi.dirPath ();
3470- }
3471- } },
3472- { " full" , [](yyscan_t s,FileInfo &fi,bool isSect) { addOutput (s,fi.absFilePath ());
3473- if (isSect)
3474- {
3475- struct yyguts_t *yyg = (struct yyguts_t *)s;
3476- yyextra->sectionTitle +=fi.absFilePath ();
3477- }
3478- } },
3514+ using OptionFunc = std::function<QCString(const FileInfo &)>;
3515+ static std::unordered_map<std::string,OptionFunc> options =
3516+ {
3517+ // name, function producing the value
3518+ { " name" , [](const FileInfo &fi_) { return fi_.baseName (); } },
3519+ { " extension" , [](const FileInfo &fi_) { return fi_.extension (true ); } },
3520+ { " filename" , [](const FileInfo &fi_) { return fi_.fileName (); } },
3521+ { " directory" , [](const FileInfo &fi_) { return fi_.dirPath (); } },
3522+ { " full" , [](const FileInfo &fi_) { return fi_.absFilePath (); } }
34793523 };
3524+ auto it = options.find(optionName);
3525+ return (it!=options.end()) ? it->second (fi) : QCString();
3526+ }
34803527
3528+ static bool handleFileInfoResult (yyscan_t yyscanner,const QCString &, const StringVector &optList, bool isSection)
3529+ {
34813530 struct yyguts_t *yyg = (struct yyguts_t *)yyscanner;
34823531 if (!yyextra->spaceBeforeCmd.isEmpty())
34833532 {
@@ -3491,16 +3540,20 @@ static bool handleFileInfoResult(yyscan_t yyscanner,const QCString &, const Stri
34913540 {
34923541 QCString optStripped = QCString (opt_).stripWhiteSpace ();
34933542 std::string opt = optStripped.lower ().str ();
3494- auto it = options. find ( opt);
3495- if (it != options. end ())
3543+ QCString result = fileInfoLookup (fi, opt);
3544+ if (!result. isEmpty ())
34963545 {
34973546 if (!first)
34983547 {
34993548 warn (yyextra->fileName ,yyextra->lineNr ," Multiple options specified with \\ fileinfo, discarding '{}'" , optStripped);
35003549 }
35013550 else
35023551 {
3503- it->second (yyscanner,fi,isSection);
3552+ addOutput (yyscanner,result);
3553+ if (isSection)
3554+ {
3555+ yyextra->sectionTitle +=result;
3556+ }
35043557 }
35053558 first = false ;
35063559 }
@@ -4299,6 +4352,28 @@ static void addXRefItem(yyscan_t yyscanner,
42994352 yyextra->outputXRef.clear();
43004353}
43014354
4355+ // -----------------------------------------------------------------------------
4356+
4357+ // make label match LABELID pattern
4358+ static void escapeLabel (QCString &label)
4359+ {
4360+ if (label.isEmpty()) return ;
4361+ char c = label[0 ];
4362+ if (!((c>=' a' && c<=' z' ) || (c>=' A' && c<=' Z' ) || c==' _' || c<0 ))
4363+ {
4364+ label[0 ]=' _' ; // replace invalid starting char by _
4365+ }
4366+ for (size_t i=1 ; i<label.size(); i++)
4367+ {
4368+ c = label[i];
4369+ if (!((c>=' a' && c<=' z' ) || (c>=' A' && c<=' Z' ) || (c>=' 0' && c<=' 9' ) || c==' _' || c<0 ))
4370+ {
4371+ label[i]=' _' ; // replace invalid char by _
4372+ }
4373+ }
4374+ }
4375+
4376+
43024377// -----------------------------------------------------------------------------
43034378
43044379// Adds a formula text to the list/dictionary of formulas if it was
0 commit comments