From e0c4e9f3a5416d53aa4da381ce6804022106fa83 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Fri, 25 Dec 2020 13:50:15 +0100 Subject: Refactoring: better processing of (un)quoted values for tags in the configuration file (part 2) --- addon/doxywizard/config_doxyw.l | 290 ++++++++++++++++++++++++++++++++++++---- src/configimpl.l | 92 ++++++------- src/doxygen.cpp | 2 +- src/layout.cpp | 2 +- 4 files changed, 314 insertions(+), 72 deletions(-) diff --git a/addon/doxywizard/config_doxyw.l b/addon/doxywizard/config_doxyw.l index 38d9f38..cde4e8e 100644 --- a/addon/doxywizard/config_doxyw.l +++ b/addon/doxywizard/config_doxyw.l @@ -65,13 +65,13 @@ static QStack g_includeStack; static int g_includeDepth; static QVariant *g_arg; static Input *g_curOption=0; -static QString g_elemStr; +static QByteArray g_str; static QTextCodec *g_codec = QTextCodec::codecForName("UTF-8"); static QString g_codecName = QString::fromLatin1("UTF-8"); static int g_lastState; -static QByteArray g_tmpString; static QString g_cmd; static int g_part; +static bool g_isEnum; static const char *stateToString(int state); @@ -110,6 +110,193 @@ static void checkEncoding() } } +static QByteArray stripComment(const QByteArray &s) +{ + // check if there is a comment at the end of the string + bool insideQuote=false; + int l = s.length(); + for (int i=0;i=2 && s.at(0)=='"' && s.at(l-1)=='"' && // remove quotes + (s.at(l-2)!='\\' || (s.at(l-2)=='\\' && s.at(l-3)=='\\'))) + { + s=s.mid(1,s.length()-2); + l=s.length(); + quotedString=true; + } + + // check for invalid and/or escaped quotes + bool warned=false; + QByteArray result; + for (int i=0;i(g_curOption); + *g_arg = cur->checkEnumVal(g_codec->toUnicode(result)); + } + else + { + *g_arg = QVariant(g_codec->toUnicode(result)); + } + + // update encoding + checkEncoding(); + + //printf("Processed string '%s'\n",g_string->data()); +} + +static void processList() +{ + bool allowCommaAsSeparator = g_cmd!=QString::fromLatin1("PREDEFINED"); + + const QByteArray s = stripComment(g_str.trimmed()); + int l = s.length(); + + QByteArray elemStr; + + // helper to push elemStr to the list and clear it + auto addElem = [&elemStr]() + { + if (!elemStr.isEmpty()) + { + //printf("Processed list element '%s'\n",e.data()); + *g_arg = QVariant(g_arg->toStringList() << g_codec->toUnicode(elemStr)); + elemStr=""; + } + }; + + bool needsSeparator=false; + int insideQuote=false; + bool warned=false; + for (int i=0;i\0x0d -"#" { BEGIN(SkipComment); } + + /*-------------- Comments ---------------*/ + +"#".*\n { /* Skip comment */ } + + /*-------------- TAG start ---------------*/ + [a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { g_cmd = g_codec->toUnicode(yytext); g_part = 0; g_cmd=g_cmd.left(g_cmd.length()-1).trimmed(); @@ -222,24 +414,17 @@ static void readIncludeFile(const QString &incName) } else // known tag { - //option->setEncoding(encoding); g_arg = &g_curOption->value(); + g_str = QByteArray(); switch(g_curOption->kind()) { case Input::StrList: - g_elemStr = QString(); *g_arg = QStringList(); BEGIN(GetStrList); break; case Input::String: - if (dynamic_cast(g_curOption)->stringMode() == InputString::StringFixed) - { - BEGIN(GetEnum); - } - else - { - BEGIN(GetString); - } + g_isEnum = dynamic_cast(g_curOption)->stringMode() == InputString::StringFixed; + BEGIN(GetString); break; case Input::Int: BEGIN(GetString); @@ -272,7 +457,7 @@ static void readIncludeFile(const QString &incName) { case Input::StrList: g_arg = &g_curOption->value(); - g_elemStr=QString(); + g_str=QByteArray(); BEGIN(GetStrList); break; case Input::String: @@ -292,7 +477,10 @@ static void readIncludeFile(const QString &incName) } } } -"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); } + + /*-------------- INCLUDE* ---------------*/ + +"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_str=QByteArray(); } /* include a config file */ "@INCLUDE"[ \t]*"=" { BEGIN(Include);} ([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { @@ -321,22 +509,72 @@ static void readIncludeFile(const QString &incName) } [a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); } -\n { BEGIN(Start); } + + /*-------------- GetString ---------------*/ + +\n { // end of string + processString(); + BEGIN(Start); + } +\\[ \r\t]*\n { // line continuation + g_str+=' '; + } +"\\" { // escape character + g_str+=yytext; + } +[^\n\\]+ { // string part without escape characters + g_str+=yytext; + } + + /*-------------- GetStrList ---------------*/ + +\n { // end of list + processList(); + BEGIN(Start); + } +\\[ \r\t]*\n { // line continuation + g_str+=' '; + } +"\\" { // escape character + g_str+=yytext; + } +[^\n\\]+ { // string part without escape characters + g_str+=yytext; + } + + /*-------------- SkipInvalid ---------------*/ + +\n { // end of skipped part + BEGIN(Start); + } +\\[ \r\t]*\n { // line continuation + g_str+=' '; + } +"\\" { // escape character + g_str+=yytext; + } +[^\n\\]+ { // string part without escape characters + g_str+=yytext; + } + + /* + +\n { BEGIN(Start); } \n { - if (!g_elemStr.isEmpty()) + if (!g_str.isEmpty()) { //printf("elemStr1='%s'\n",qPrintable(elemStr)); - *g_arg = QVariant(g_arg->toStringList() << g_elemStr); + *g_arg = QVariant(g_arg->toStringList() << g_str); } BEGIN(Start); } [ \t]+ { - if (!g_elemStr.isEmpty()) + if (!g_str.isEmpty()) { //printf("elemStr2='%s'\n",qPrintable(elemStr)); - *g_arg = QVariant(g_arg->toStringList() << g_elemStr); + *g_arg = QVariant(g_arg->toStringList() << g_str); } - g_elemStr = QString(); + g_str = QString(); } [^ \"\t\r\n]+ { if (g_part == 1) // multiple unquoted parts, reset to default @@ -430,7 +668,7 @@ static void readIncludeFile(const QString &incName) } else { - g_elemStr+=g_codec->toUnicode(g_tmpString); + g_str+=g_codec->toUnicode(g_tmpString); } if (*yytext=='\n') { @@ -447,11 +685,15 @@ static void readIncludeFile(const QString &incName) } . { g_tmpString+=*yytext; } [^ \#\"\t\r\n]+ { - g_elemStr+=g_codec->toUnicode(yytext); + g_str+=g_codec->toUnicode(yytext); } \n { BEGIN(Start); } \\[ \r\t]*\n { BEGIN(Start); } . { } + */ + + /*-------------- fall through -------------*/ + <*>\\[ \r\t]*\n { } <*>[ \r\t] { } <*>\n diff --git a/src/configimpl.l b/src/configimpl.l index d856c35..d256c06 100644 --- a/src/configimpl.l +++ b/src/configimpl.l @@ -511,7 +511,6 @@ static const char *g_inputString; static int g_inputPosition; static int g_yyLineNr; static QCString g_yyFileName; -static QCString g_tmpString; static QCString g_cmd; static QCString *g_string=0; static StringVector *g_list=0; @@ -522,7 +521,6 @@ static int g_includeDepth; static bool g_configUpdate = FALSE; static QCString g_encoding; static ConfigImpl *g_config; -static int g_part; /* ----------------------------------------------------------------- */ @@ -594,10 +592,38 @@ static void checkEncoding() g_encoding = *option->valueRef(); } +static QCString stripComment(const QCString &s) +{ + // check if there is a comment at the end of the string + bool insideQuote=false; + int l = s.length(); + for (int i=0;i user comment + { + g_config->appendUserComment(s.mid(i)+"\n"); + } + return s.left(i).stripWhiteSpace(); + } + } + return s; +} + static void processString() { // strip leading and trailing whitespace - QCString s = g_string->stripWhiteSpace(); + QCString s = stripComment(g_string->stripWhiteSpace()); int l = s.length(); // remove surrounding quotes if present (and not escaped) @@ -637,19 +663,10 @@ static void processString() if (!warned) { config_warn("Invalid value for '%s' tag at line %d, file %s: Value '%s' is not properly quoted\n", - g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_string->data()); + g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_string->stripWhiteSpace().data()); } warned=true; } - else if (c=='#' && !quotedString) // found comment - { - if (iappendUserComment(s.mid(i)+"\n"); - } - result=result.stripWhiteSpace(); - break; - } else // normal character { result+=c; @@ -669,7 +686,7 @@ static void processList() { bool allowCommaAsSeparator = g_cmd!="PREDEFINED"; - const QCString s = g_listStr.stripWhiteSpace(); + const QCString s = stripComment(g_listStr.stripWhiteSpace()); int l = s.length(); QCString elemStr; @@ -725,15 +742,6 @@ static void processList() needsSeparator=false; addElem(); } - else if (!insideQuote && c=='#') // found comment - { - if (iappendUserComment(s.mid(i)+"\n"); - } - addElem(); - break; - } else // normal content character { if (needsSeparator) @@ -741,7 +749,7 @@ static void processList() if (!warned) { config_warn("Invalid value for '%s' tag at line %d, file %s: Values in list '%s' are not properly space %sseparated\n", - g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_listStr.data(),allowCommaAsSeparator?"or comma ":""); + g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_listStr.stripWhiteSpace().data(),allowCommaAsSeparator?"or comma ":""); warned=true; } needsSeparator=false; @@ -759,7 +767,7 @@ static void processList() if (insideQuote) { config_warn("Invalid value for '%s' tag at line %d, file %s: Values in list '%s' are not properly quoted\n", - g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_listStr.data()); + g_cmd.data(),g_yyLineNr,g_yyFileName.data(),g_listStr.stripWhiteSpace().data()); } } @@ -849,10 +857,9 @@ static void readIncludeFile(const char *incName) %} %option noyywrap +%option nounput -%x PreStart %x Start -%x SkipComment %x SkipInvalid %x GetString %x GetStrList @@ -864,19 +871,18 @@ static void readIncludeFile(const char *incName) /*-------------- Comments ---------------*/ -"##".*"\n" { g_config->appendStartComment(yytext);g_yyLineNr++;} -. { - BEGIN(Start); - unput(*yytext); +"##".*"\n" { + g_config->appendUserComment(yytext); + g_yyLineNr++; + } +"#"[^#].*"\n" { /* normal comment */ + g_yyLineNr++; } -"##".*"\n" { g_config->appendUserComment(yytext);g_yyLineNr++;} -"#"[^#].*"\n" { /* normal comment */ } /*-------------- TAG start ---------------*/ [a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { g_cmd=yytext; g_cmd=g_cmd.left(g_cmd.length()-1).stripWhiteSpace(); - g_part=0; ConfigOption *option = g_config->get(g_cmd); if (option==0) // oops not known { @@ -1032,8 +1038,8 @@ static void readIncludeFile(const char *incName) [a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,g_yyLineNr,g_yyFileName.data()); } /*-------------- GetString ---------------*/ -\n { g_yyLineNr++; // end of string - processString(); +\n { processString(); + g_yyLineNr++; // end of string BEGIN(Start); } \\[ \r\t]*\n { g_yyLineNr++; // line continuation @@ -1048,8 +1054,8 @@ static void readIncludeFile(const char *incName) /*-------------- GetStrList --------------*/ -\n { g_yyLineNr++; // end of list - processList(); +\n { processList(); + g_yyLineNr++; // end of list BEGIN(Start); } \\[ \r\t]*\n { g_yyLineNr++; // line continuation @@ -1074,18 +1080,12 @@ static void readIncludeFile(const char *incName) [^\n\\]+ { // string part without escape characters } - /*-------------- SkipComment --------------*/ - -\n { g_yyLineNr++; BEGIN(Start); } -\\[ \r\t]*\n { g_yyLineNr++; BEGIN(Start); } -. - /*-------------- fall through -------------*/ <*>\\[ \r\t]*\n { g_yyLineNr++; } <*>[ \t\r] -<*>. { config_warn("ignoring unknown character '%c' at line %d, file %s\n",yytext[0],g_yyLineNr,g_yyFileName.data()); } <*>\n { g_yyLineNr++ ; } +<*>. { config_warn("ignoring unknown character '%c' at line %d, file %s\n",yytext[0],g_yyLineNr,g_yyFileName.data()); } %% @@ -1380,7 +1380,7 @@ bool ConfigImpl::parseString(const char *fn,const char *str,bool update) g_includeStack.clear(); g_includeDepth = 0; configimplYYrestart( configimplYYin ); - BEGIN( PreStart ); + BEGIN( Start ); g_configUpdate = update; configimplYYlex(); g_configUpdate = FALSE; diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 9b3dcb0..4abc9bc 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -4229,7 +4229,7 @@ static int findEndOfTemplate(const QCString &s,int startPos) static int findTemplateSpecializationPosition(const char *name) { if (name==0 || name[0]=='\0') return 0; - int l = strlen(name); + int l = static_cast(strlen(name)); if (name[l-1]=='>') // search backward to find the matching <, allowing nested <...> and strings. { int count=1; diff --git a/src/layout.cpp b/src/layout.cpp index f241bd8..5cac7e1 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -1460,7 +1460,7 @@ void LayoutParser::endElement( const std::string &name ) //printf("endElement [%s]::[%s]\n",m_scope.data(),name.data()); auto it=g_elementHandlers.end(); - if (!m_scope.isEmpty() && m_scope.right(name.length()+1)==name+"/") + if (!m_scope.isEmpty() && m_scope.right(static_cast(name.length())+1)==name+"/") { // element ends current scope it = g_elementHandlers.find(m_scope.left(m_scope.length()-1).str()); } -- cgit v0.12