From ef91bacb7a69bbf7bccb4a864698cc003aabac66 Mon Sep 17 00:00:00 2001 From: albert-github Date: Sun, 25 Oct 2020 18:42:43 +0100 Subject: Incorrect handling of string with spaces and no quotes During some tests on the documentation of LLVM the (CMake generated) doxygen configuration file contained the line: ``` DOT_PATH=D:\Program Files (x86)\Graphviz2.38\bin\dot.exe ``` and this was interpreted by doxygen as ``` DOT_PATH = D:\ProgramFiles(x86)\Graphviz2.38\bin\dot.exe ``` without any message other than that later on the `dot` executable could not be found. It is clear that here the double quotes were missing. This problem has been solved by giving a warning and setting the value to the default value. - configimpl.l - config_doxyw.l during the checking some debug facilities for the doxywizard were required and this has been implemented: - config_doxyw.l - doxywizard.h - doxywizard.cpp it was also discovered that in case of none existing int or bool values were specified the wrong "defaults" were taken (it was set to `0` / `false`), now the correct defaults are taken - inputbool.cpp - inputint.cpp --- addon/doxywizard/config_doxyw.l | 222 ++++++++++++++++++++++++++++------------ addon/doxywizard/doxywizard.cpp | 32 +++++- addon/doxywizard/doxywizard.h | 13 +++ addon/doxywizard/inputbool.cpp | 35 ++++--- addon/doxywizard/inputint.cpp | 19 ++-- src/configimpl.l | 101 ++++++++++-------- 6 files changed, 294 insertions(+), 128 deletions(-) diff --git a/addon/doxywizard/config_doxyw.l b/addon/doxywizard/config_doxyw.l index 554571f..db7b05a 100644 --- a/addon/doxywizard/config_doxyw.l +++ b/addon/doxywizard/config_doxyw.l @@ -3,8 +3,8 @@ * Copyright (C) 1997-2019 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -24,6 +24,7 @@ #include "config.h" #include "input.h" #include "inputstring.h" +#include "doxywizard.h" #include #include @@ -53,14 +54,14 @@ struct ConfigFileState YY_BUFFER_STATE oldState; YY_BUFFER_STATE newState; QString fileName; -}; +}; static const QHash *g_options; static FILE *g_file; static QString g_yyFileName; static QString g_includeName; static QVariant g_includePathList; -static QStack g_includeStack; +static QStack g_includeStack; static int g_includeDepth; static QVariant *g_arg; static Input *g_curOption=0; @@ -69,6 +70,8 @@ static QTextCodec *g_codec = QTextCodec::codecForName("UT 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 const char *stateToString(int state); @@ -80,11 +83,11 @@ static const char *stateToString(int state); static yy_size_t yyread(char *buf,int maxSize) { // no file included - if (g_includeStack.isEmpty()) + if (g_includeStack.isEmpty()) { return fread(buf,1,maxSize,g_file); - } - else + } + else { return fread(buf,1,maxSize,g_includeStack.top()->file); } @@ -96,19 +99,39 @@ static QString error_str = QString::fromLatin1("error: "); void config_err(const char *fmt, ...) { QString msg = error_str; + msg.append(QString::fromLatin1(fmt)); va_list args; va_start(args, fmt); - vfprintf(stderr, qPrintable(msg), args); + if (DoxygenWizard::debugFlag) + { + char debugOut[1000]; // this size should be sufficient + vsnprintf(debugOut, 1000,qPrintable(msg), args); + MainWindow::instance().outputLogText(QString::fromLatin1(debugOut)); + } + else + { + vfprintf(stderr, qPrintable(msg), args); + } va_end(args); } void config_warn(const char *fmt, ...) { QString msg = warning_str; + msg.append(QString::fromLatin1(fmt)); va_list args; va_start(args, fmt); - vfprintf(stderr, qPrintable(msg), args); + if (DoxygenWizard::debugFlag) + { + char debugOut[1000]; + vsnprintf(debugOut, 1000,qPrintable(msg), args); + MainWindow::instance().outputLogText(QString::fromLatin1(debugOut)); + } + else + { + vfprintf(stderr, qPrintable(msg), args); + } va_end(args); } @@ -138,7 +161,7 @@ static FILE *tryPath(const QString &path,const QString &fileName) FILE *f = fopen(absName.toLocal8Bit(),"r"); if (f==NULL) config_err("could not open file %s for reading\n",qPrintable(absName)); - else + else return f; } return NULL; @@ -154,7 +177,7 @@ static FILE *findFile(const QString &fileName) // relative path, try with include paths in the list QStringList sl = g_includePathList.toStringList(); substEnvVarsInStrList(sl); - foreach (QString s, sl) + foreach (QString s, sl) { FILE *f = tryPath(s,fileName); if (f) return f; @@ -165,18 +188,18 @@ static FILE *findFile(const QString &fileName) static void readIncludeFile(const QString &incName) { - if (g_includeDepth==MAX_INCLUDE_DEPTH) + if (g_includeDepth==MAX_INCLUDE_DEPTH) { config_err("maximum include depth (%d) reached, %s is not included. Aborting...\n", MAX_INCLUDE_DEPTH,qPrintable(incName)); exit(1); - } + } QString inc = incName; substEnvVarsInString(inc); inc = inc.trimmed(); uint incLen = inc.length(); - if (inc.at(0)==QChar::fromLatin1('"') && + if (inc.at(0)==QChar::fromLatin1('"') && inc.at(incLen-1)==QChar::fromLatin1('"')) // strip quotes { inc=inc.mid(1,incLen-2); @@ -191,7 +214,7 @@ static void readIncludeFile(const QString &incName) msg("@INCLUDE = %s: parsing...\n",qPrintable(inc)); #endif - // store the state of the old file + // store the state of the old file ConfigFileState *fs=new ConfigFileState; fs->oldState=YY_CURRENT_BUFFER; fs->fileName=g_yyFileName; @@ -203,7 +226,7 @@ static void readIncludeFile(const QString &incName) fs->newState=YY_CURRENT_BUFFER; g_yyFileName=inc; g_includeDepth++; - } + } else { config_err("@INCLUDE = %s: not found!\n",qPrintable(inc)); @@ -225,20 +248,20 @@ static void readIncludeFile(const QString &incName) %x GetEnum %x GetStrList %x GetQuotedString -%x GetEnvVar %x Include %% <*>\0x0d "#" { BEGIN(SkipComment); } -[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QString cmd = g_codec->toUnicode(yytext); - cmd=cmd.left(cmd.length()-1).trimmed(); - g_curOption = g_options->value(cmd); +[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(); + g_curOption = g_options->value(g_cmd); if (g_curOption==0) // oops not known { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); BEGIN(SkipInvalid); } else // known tag @@ -271,20 +294,20 @@ static void readIncludeFile(const QString &incName) case Input::Obsolete: config_warn("Tag '%s' at line %d of file %s has become obsolete.\n" "To avoid this warning please update your configuration " - "file using \"doxygen -u\"\n", qPrintable(cmd), - yylineno,qPrintable(g_yyFileName)); + "file using \"doxygen -u\"\n", qPrintable(g_cmd), + yylineno,qPrintable(g_yyFileName)); BEGIN(SkipInvalid); break; } } } -[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QString cmd=g_codec->toUnicode(yytext); - cmd=cmd.left(cmd.length()-2).trimmed(); - g_curOption = g_options->value(cmd); +[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { g_cmd=g_codec->toUnicode(yytext); + g_cmd=g_cmd.left(g_cmd.length()-2).trimmed(); + g_curOption = g_options->value(g_cmd); if (g_curOption==0) // oops not known { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - yytext,yylineno,qPrintable(g_yyFileName)); + yytext,yylineno,qPrintable(g_yyFileName)); BEGIN(SkipInvalid); } else // known tag @@ -299,15 +322,15 @@ static void readIncludeFile(const QString &incName) case Input::String: case Input::Int: case Input::Bool: - config_warn("operator += not supported for '%s'. Ignoring line at line %d, file %s\n", - yytext,yylineno,qPrintable(g_yyFileName)); + config_warn("operator += not supported for '%s'. Ignoring line %d, file %s\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); BEGIN(SkipInvalid); break; case Input::Obsolete: config_warn("Tag '%s' at line %d of file %s has become obsolete.\n" "To avoid this warning please update your configuration " - "file using \"doxygen -u\"\n", - qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); + "file using \"doxygen -u\"\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); BEGIN(SkipInvalid); break; } @@ -316,8 +339,8 @@ static void readIncludeFile(const QString &incName) "@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); } /* include a config file */ "@INCLUDE"[ \t]*"=" { BEGIN(Include);} -([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { - readIncludeFile(g_codec->toUnicode(yytext)); +([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { + readIncludeFile(g_codec->toUnicode(yytext)); BEGIN(Start); } <> { @@ -336,20 +359,20 @@ static void readIncludeFile(const QString &incName) yy_switch_to_buffer( fs->oldState ); yy_delete_buffer( oldBuf ); g_yyFileName=fs->fileName; - delete fs; + delete fs; g_includeDepth--; } } [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); } -\n { +\n { if (!g_elemStr.isEmpty()) { //printf("elemStr1='%s'\n",qPrintable(elemStr)); *g_arg = QVariant(g_arg->toStringList() << g_elemStr); } - BEGIN(Start); + BEGIN(Start); } [ \t]+ { if (!g_elemStr.isEmpty()) @@ -360,30 +383,94 @@ static void readIncludeFile(const QString &incName) g_elemStr = QString(); } [^ \"\t\r\n]+ { - *g_arg = QVariant(g_codec->toUnicode(yytext)); - checkEncoding(); + if (g_part == 1) // multiple unquoted parts, reset to default + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); + *g_arg=QVariant(g_codec->toUnicode("")); + } + else if (g_part > 1) // multiple unquoted parts, reset to default + { + *g_arg=QVariant(g_codec->toUnicode("")); + } + else + { + *g_arg = QVariant(g_codec->toUnicode(yytext)); + checkEncoding(); + } + g_part++; } [^ \"\t\r\n]+ { InputString *cur = dynamic_cast(g_curOption); - *g_arg = cur->checkEnumVal(g_codec->toUnicode(yytext)); + if (g_part == 1) // multiple unquoted parts, reset to default + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); + *g_arg=QVariant(g_codec->toUnicode("")); + } + else if (g_part > 1) // multiple unquoted parts, reset to default + { + *g_arg=QVariant(g_codec->toUnicode("")); + } + else + { + *g_arg = cur->checkEnumVal(g_codec->toUnicode(yytext)); + } + g_part++; } "\"" { g_lastState=YY_START; - BEGIN(GetQuotedString); + BEGIN(GetQuotedString); g_tmpString=""; } -"\""|"\n" { +"\""|"\n" { // we add a bogus space to signal that the string was quoted. This space will be stripped later on. g_tmpString+=" "; //printf("Quoted String = '%s'\n",qPrintable(tmpString)); if (g_lastState==GetString) { - *g_arg = g_codec->toUnicode(g_tmpString); - checkEncoding(); + if (g_part == 1) // multiple unquoted parts, reset to default + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); + *g_arg=g_codec->toUnicode(""); + } + else if (g_part > 1) // multiple unquoted parts, reset to default + { + *g_arg=g_codec->toUnicode(""); + } + else + { + *g_arg = g_codec->toUnicode(g_tmpString); + checkEncoding(); + } + g_part++; } else if (g_lastState==GetEnum) { - InputString *cur = dynamic_cast(g_curOption); - *g_arg = cur->checkEnumVal(g_codec->toUnicode(g_tmpString)); + if (g_part == 1) // multiple unquoted parts, reset to default + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default\n", + qPrintable(g_cmd),yylineno,qPrintable(g_yyFileName)); + *g_arg=g_codec->toUnicode(""); + } + else if (g_part > 1) // multiple unquoted parts, reset to default + { + *g_arg=g_codec->toUnicode(""); + } + else + { + InputString *cur = dynamic_cast(g_curOption); + *g_arg = cur->checkEnumVal(g_codec->toUnicode(g_tmpString)); + } + g_part++; } else { @@ -442,7 +529,7 @@ static void substEnvVarsInStrList(QStringList &sl) foreach (QString result, sl) { // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE. - bool wasQuoted = (result.indexOf(QChar::fromLatin1(' '))!=-1) || + bool wasQuoted = (result.indexOf(QChar::fromLatin1(' '))!=-1) || (result.indexOf(QChar::fromLatin1('\t'))!=-1); // here we strip the quote again substEnvVarsInString(result); @@ -452,7 +539,7 @@ static void substEnvVarsInStrList(QStringList &sl) if (!wasQuoted) /* as a result of the expansion, a single string may have expanded into a list, which we'll add to sl. If the original string already - contained multiple elements no further + contained multiple elements no further splitting is done to allow quoted items with spaces! */ { int l=result.length(); @@ -463,11 +550,11 @@ static void substEnvVarsInStrList(QStringList &sl) { QChar c=0; // skip until start of new word - while (i &options ) { + yylineno = 1; + if (DoxygenWizard::debugFlag) + { + MainWindow::instance().outputLogStart(); + } QHashIterator i(options); g_file = fopen(fileName.toLocal8Bit(),"r"); if (g_file==NULL) return false; // reset all values i.toFront(); - while (i.hasNext()) + while (i.hasNext()) { i.next(); if (i.value()) @@ -542,7 +634,7 @@ bool parseConfig( // update the values in the UI i.toFront(); - while (i.hasNext()) + while (i.hasNext()) { i.next(); if (i.value()) @@ -554,8 +646,12 @@ bool parseConfig( { printf("Invalid option: %s\n",qPrintable(i.key())); } - } + } fclose(g_file); + if (DoxygenWizard::debugFlag) + { + MainWindow::instance().outputLogFinish(); + } return true; } @@ -572,29 +668,29 @@ void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s) { if (*p != QChar::fromLatin1('"')) { - while (!(c=*p++).isNull() && !needsEscaping) + while (!(c=*p++).isNull() && !needsEscaping) { - needsEscaping = (c==QChar::fromLatin1(' ') || - c==QChar::fromLatin1('\n') || - c==QChar::fromLatin1('\t') || + needsEscaping = (c==QChar::fromLatin1(' ') || + c==QChar::fromLatin1('\n') || + c==QChar::fromLatin1('\t') || c==QChar::fromLatin1('"')); } p=s.data(); - while (!(c=*p++).isNull() && !needsHashEscaping) + while (!(c=*p++).isNull() && !needsHashEscaping) { needsHashEscaping = (c==QChar::fromLatin1('#')); } } if (needsHashEscaping || needsEscaping) - { + { t << "\""; } if (needsEscaping) - { + { p=s.data(); while (!p->isNull()) { - if (*p ==QChar::fromLatin1(' ') && + if (*p ==QChar::fromLatin1(' ') && *(p+1)==QChar::fromLatin1('\0')) break; // skip inserted space at the end if (*p ==QChar::fromLatin1('"')) t << "\\"; // escape quotes t << *p++; @@ -605,7 +701,7 @@ void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s) t << s; } if (needsHashEscaping || needsEscaping) - { + { t << "\""; } } diff --git a/addon/doxywizard/doxywizard.cpp b/addon/doxywizard/doxywizard.cpp index e621e0b..5b0becc 100755 --- a/addon/doxywizard/doxywizard.cpp +++ b/addon/doxywizard/doxywizard.cpp @@ -42,6 +42,9 @@ #define MAX_RECENT_FILES 10 +// globally accessible variables +bool DoxygenWizard::debugFlag = false; + const int messageTimeout = 5000; //!< status bar message timeout in milliseconds. #define APPQT(x) QString::fromLatin1("
") + x + QString::fromLatin1("
") @@ -725,11 +728,26 @@ bool MainWindow::discardUnsavedChanges(bool saveOption) return true; } +void MainWindow::outputLogStart() +{ + m_outputLog->clear(); +} +void MainWindow::outputLogText(QString text) +{ + m_outputLog->append(APPQT(text)); +} +void MainWindow::outputLogFinish() +{ + m_outputLog->ensureCursorVisible(); + m_saveLog->setEnabled(true); +} //----------------------------------------------------------------------- int main(int argc,char **argv) { QApplication a(argc,argv); - if (argc == 2) + int locArgc = argc; + + if (locArgc == 2) { if (!qstrcmp(argv[1],"--help")) { @@ -746,7 +764,13 @@ int main(int argc,char **argv) exit(0); } } - if (argc > 2) + if (!qstrcmp(argv[1],"--debug") && ((locArgc == 2) || (locArgc == 3))) + { + DoxygenWizard::debugFlag = true; + locArgc--; + } + + if (locArgc > 2) { QMessageBox msgBox; msgBox.setText(QString::fromLatin1("Too many arguments specified\n\nUsage: %1 [config file]").arg(QString::fromLatin1(argv[0]))); @@ -756,9 +780,9 @@ int main(int argc,char **argv) else { MainWindow &main = MainWindow::instance(); - if (argc==2 && argv[1][0]!='-') // name of config file as an argument + if (locArgc==2 && argv[argc-1][0]!='-') // name of config file as an argument { - main.loadConfigFromFile(QString::fromLocal8Bit(argv[1])); + main.loadConfigFromFile(QString::fromLocal8Bit(argv[argc-1])); } main.show(); return a.exec(); diff --git a/addon/doxywizard/doxywizard.h b/addon/doxywizard/doxywizard.h index 3fc2b65..eadd51b 100755 --- a/addon/doxywizard/doxywizard.h +++ b/addon/doxywizard/doxywizard.h @@ -41,6 +41,10 @@ class MainWindow : public QMainWindow void closeEvent(QCloseEvent *event); QString configFileName() const { return m_fileName; } void updateTitle(); + // access routines for outputLog pane + void MainWindow::outputLogStart(); + void MainWindow::outputLogText(QString text); + void MainWindow::outputLogFinish(); public slots: void manual(); @@ -101,4 +105,13 @@ class MainWindow : public QMainWindow bool m_modified; }; +/*! \brief This class serves as a namespace for global variables used by the doxygen wizard. + * + * All fields in this class are public and static, so they can be used directly. + */ +class DoxygenWizard +{ + public: + static bool debugFlag; +}; #endif diff --git a/addon/doxywizard/inputbool.cpp b/addon/doxywizard/inputbool.cpp index 3c917a8..65e1d26 100644 --- a/addon/doxywizard/inputbool.cpp +++ b/addon/doxywizard/inputbool.cpp @@ -3,8 +3,8 @@ * Copyright (C) 1997-2019 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -18,7 +18,7 @@ #include #include -InputBool::InputBool( QGridLayout *layout, int &row, +InputBool::InputBool( QGridLayout *layout, int &row, const QString &id, bool checked, const QString &docs ) : m_default(checked), m_docs(docs), m_id(id) @@ -42,10 +42,10 @@ void InputBool::help() } void InputBool::setEnabled(bool b) -{ +{ m_enabled = b; - m_cb->setEnabled(b); - m_lab->setEnabled(b); + m_cb->setEnabled(b); + m_lab->setEnabled(b); updateDefault(); updateDependencies(); } @@ -60,7 +60,7 @@ void InputBool::updateDependencies() void InputBool::setValue( bool s ) { - if (m_state!=s) + if (m_state!=s) { m_state=s; updateDefault(); @@ -91,9 +91,18 @@ QVariant &InputBool::value() void InputBool::update() { QString v = m_value.toString().toLower(); - m_state = (v==QString::fromLatin1("yes") || - v==QString::fromLatin1("true") || - v==QString::fromLatin1("1")); + if (v==QString::fromLatin1("yes") || v==QString::fromLatin1("true") || v==QString::fromLatin1("1")) + { + m_state = true; + } + else if (v==QString::fromLatin1("no") || v==QString::fromLatin1("false") || v==QString::fromLatin1("0")) + { + m_state = false; + } + else + { + m_state = m_default; + } m_cb->setChecked( m_state ); updateDefault(); updateDependencies(); @@ -106,9 +115,9 @@ void InputBool::reset() void InputBool::writeValue(QTextStream &t,QTextCodec *codec) { - if (m_state) - t << codec->fromUnicode(QString::fromLatin1("YES")); - else + if (m_state) + t << codec->fromUnicode(QString::fromLatin1("YES")); + else t << codec->fromUnicode(QString::fromLatin1("NO")); } diff --git a/addon/doxywizard/inputint.cpp b/addon/doxywizard/inputint.cpp index bcba86a..d97f1b0 100644 --- a/addon/doxywizard/inputint.cpp +++ b/addon/doxywizard/inputint.cpp @@ -3,8 +3,8 @@ * Copyright (C) 1997-2019 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -28,7 +28,7 @@ class NoWheelSpinBox : public QSpinBox }; InputInt::InputInt( QGridLayout *layout,int &row, - const QString & id, + const QString & id, int defVal, int minVal,int maxVal, const QString & docs ) : m_default(defVal), m_minVal(minVal), m_maxVal(maxVal), m_docs(docs), m_id(id) @@ -44,7 +44,7 @@ InputInt::InputInt( QGridLayout *layout,int &row, layout->addWidget( m_lab, row, 0 ); layout->addWidget( m_sp, row, 1 ); - connect(m_sp, SIGNAL(valueChanged(int)), + connect(m_sp, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)) ); connect( m_lab, SIGNAL(enter()), SLOT(help()) ); connect( m_lab, SIGNAL(reset()), SLOT(reset()) ); @@ -61,7 +61,7 @@ void InputInt::setValue(int val) { val = qMax(m_minVal,val); val = qMin(m_maxVal,val); - if (val!=m_val) + if (val!=m_val) { m_val = val; m_sp->setValue(val); @@ -81,7 +81,7 @@ void InputInt::updateDefault() { m_lab->setText(QString::fromLatin1("")+m_id+QString::fromLatin1("")); } - emit changed(); + emit changed(); } } @@ -92,14 +92,17 @@ void InputInt::setEnabled(bool state) updateDefault(); } -QVariant &InputInt::value() +QVariant &InputInt::value() { return m_value; } void InputInt::update() { - setValue(m_value.toInt()); + bool ok; + int newVal = m_value.toInt(&ok); + if (!ok) newVal = m_default; + setValue(newVal); } void InputInt::reset() diff --git a/src/configimpl.l b/src/configimpl.l index ed23a12..d7fcdf1 100644 --- a/src/configimpl.l +++ b/src/configimpl.l @@ -512,6 +512,7 @@ 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 bool *g_bool=0; static StringVector *g_list=0; @@ -523,6 +524,7 @@ static int g_includeDepth; static bool g_configUpdate = FALSE; static QCString g_encoding; static ConfigImpl *g_config; +static int g_part; /* ----------------------------------------------------------------- */ @@ -686,11 +688,9 @@ static void readIncludeFile(const char *incName) %x SkipComment %x SkipInvalid %x GetString -%x GetBool %x GetStrList %x GetStrList1 %x GetQuotedString -%x GetEnvVar %x Include %% @@ -701,15 +701,16 @@ static void readIncludeFile(const char *incName) BEGIN(Start); unput(*yytext); } -"##".*"\n" { g_config->appendUserComment(yytext);g_yyLineNr++;} -"#" { BEGIN(SkipComment); } -[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()-1).stripWhiteSpace(); - ConfigOption *option = g_config->get(cmd); +"##".*"\n" { g_config->appendUserComment(yytext);g_yyLineNr++;} +"#" { BEGIN(SkipComment); } +[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 { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - cmd.data(),g_yyLineNr,g_yyFileName.data()); + g_cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); } else // known tag @@ -726,7 +727,7 @@ static void readIncludeFile(const char *incName) g_list = ((ConfigList *)option)->valueRef(); g_list->clear(); g_elemStr=""; - if (cmd == "PREDEFINED") + if (g_cmd == "PREDEFINED") { BEGIN(GetStrList1); } @@ -759,13 +760,13 @@ static void readIncludeFile(const char *incName) if (g_configUpdate) { config_warn("Tag '%s' at line %d of file '%s' has become obsolete.\n" - " This tag has been removed.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + " This tag has been removed.\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); } else { config_warn("Tag '%s' at line %d of file '%s' has become obsolete.\n" " To avoid this warning please remove this line from your configuration " - "file or upgrade it using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file or upgrade it using \"doxygen -u\"\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); } BEGIN(SkipInvalid); break; @@ -773,26 +774,26 @@ static void readIncludeFile(const char *incName) if (g_configUpdate) { config_warn("Tag '%s' at line %d of file '%s' belongs to an option that was not enabled at compile time.\n" - " This tag has been removed.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + " This tag has been removed.\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); } else { config_warn("Tag '%s' at line %d of file '%s' belongs to an option that was not enabled at compile time.\n" " To avoid this warning please remove this line from your configuration " - "file or upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file or upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); } BEGIN(SkipInvalid); break; } } } -[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()-2).stripWhiteSpace(); - ConfigOption *option = g_config->get(cmd); +[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { g_cmd=yytext; + g_cmd=g_cmd.left(g_cmd.length()-2).stripWhiteSpace(); + ConfigOption *option = g_config->get(g_cmd); if (option==0) // oops not known { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - cmd.data(),g_yyLineNr,g_yyFileName.data()); + g_cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); } else // known tag @@ -807,7 +808,7 @@ static void readIncludeFile(const char *incName) case ConfigOption::O_List: g_list = ((ConfigList *)option)->valueRef(); g_elemStr=""; - if (cmd == "PREDEFINED") + if (g_cmd == "PREDEFINED") { BEGIN(GetStrList1); } @@ -827,13 +828,13 @@ static void readIncludeFile(const char *incName) case ConfigOption::O_Obsolete: config_warn("Tag '%s' at line %d of file %s has become obsolete.\n" "To avoid this warning please update your configuration " - "file using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file using \"doxygen -u\"\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); break; case ConfigOption::O_Disabled: config_warn("Tag '%s' at line %d of file %s belongs to an option that was not enabled at compile time.\n" "To avoid this warning please remove this line from your configuration " - "file, upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file, upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", g_cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); break; } @@ -869,7 +870,7 @@ 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()); } -\n { g_yyLineNr++; BEGIN(Start); } +\n { g_yyLineNr++; BEGIN(Start); } \n { g_yyLineNr++; if (!g_elemStr.isEmpty()) @@ -895,8 +896,26 @@ static void readIncludeFile(const char *incName) } g_elemStr.resize(0); } -[^ \"\t\r\n]+ { (*g_string)+=configStringRecode(yytext,g_encoding,"UTF-8"); - checkEncoding(); +[^ \"\t\r\n]+ { + // for each command we only want 1 warning + if (g_part==1) + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default.\n", + g_cmd.data(),g_yyLineNr,g_yyFileName.data()); + (*g_string)=""; + } + else if (g_part > 1) + { + (*g_string)=""; + } + else + { + (*g_string)+=configStringRecode(yytext,g_encoding,"UTF-8"); + checkEncoding(); + } + g_part++; } "\"" { g_lastState=YY_START; BEGIN(GetQuotedString); @@ -908,8 +927,25 @@ static void readIncludeFile(const char *incName) //printf("Quoted String = '%s'\n",g_tmpString.data()); if (g_lastState==GetString) { - (*g_string)+=configStringRecode(g_tmpString,g_encoding,"UTF-8"); - checkEncoding(); + // for each command we only want 1 warning + if (g_part==1) + { + config_warn("Invalid value for '%s' tag in line %d, file %s\n" + "Value should not contain unquoted whitespace, " + "using the default.\n", + g_cmd.data(),g_yyLineNr,g_yyFileName.data()); + (*g_string)=""; + } + else if (g_part > 1) + { + (*g_string)=""; + } + else + { + (*g_string)+=configStringRecode(g_tmpString,g_encoding,"UTF-8"); + checkEncoding(); + } + g_part++; } else { @@ -926,21 +962,6 @@ static void readIncludeFile(const char *incName) g_tmpString+='"'; } . { g_tmpString+=*yytext; } -[a-zA-Z]+ { - QCString bs=yytext; - bs=bs.upper(); - if (bs=="YES" || bs=="1") - *g_bool=TRUE; - else if (bs=="NO" || bs=="0") - *g_bool=FALSE; - else - { - *g_bool=FALSE; - config_warn("Invalid value '%s' for " - "boolean tag in line %d, file %s; use YES or NO\n", - bs.data(),g_yyLineNr,g_yyFileName.data()); - } - } [^ \#\"\t\r\n]+ { g_elemStr+=configStringRecode(yytext,g_encoding,"UTF-8"); } -- cgit v0.12