summaryrefslogtreecommitdiffstats
path: root/addon/doxywizard/config_doxyw.l
diff options
context:
space:
mode:
Diffstat (limited to 'addon/doxywizard/config_doxyw.l')
-rw-r--r--addon/doxywizard/config_doxyw.l458
1 files changed, 318 insertions, 140 deletions
diff --git a/addon/doxywizard/config_doxyw.l b/addon/doxywizard/config_doxyw.l
index 59fa427..b93a79d 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.
*
@@ -12,6 +12,10 @@
%option never-interactive
%option prefix="config_doxywYY"
+%top{
+#include <stdint.h>
+}
+
%{
/*
@@ -19,6 +23,8 @@
*/
#include "config.h"
#include "input.h"
+#include "inputstring.h"
+#include "config_msg.h"
#include <QString>
#include <QVariant>
@@ -29,6 +35,7 @@
#include <QStringList>
#include <QRegExp>
#include <QTextStream>
+#include <QMessageBox>
#define YY_NO_UNISTD_H 1
@@ -47,22 +54,22 @@ struct ConfigFileState
YY_BUFFER_STATE oldState;
YY_BUFFER_STATE newState;
QString fileName;
-};
+};
static const QHash<QString,Input*> *g_options;
static FILE *g_file;
static QString g_yyFileName;
static QString g_includeName;
static QVariant g_includePathList;
-static QStack<ConfigFileState*> g_includeStack;
+static QStack<ConfigFileState*> 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 bool g_isEnum;
static const char *stateToString(int state);
@@ -71,41 +78,19 @@ static const char *stateToString(int state);
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
-static int yyread(char *buf,int maxSize)
+static yy_size_t yyread(char *buf,yy_size_t 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);
}
}
-static QString warning_str = QString::fromLatin1("warning: ");
-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);
- 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);
- va_end(args);
-}
-
static void substEnvVarsInStrList(QStringList &sl);
static void substEnvVarsInString(QString &s);
@@ -123,6 +108,191 @@ 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<l;i++)
+ {
+ char c = s.at(i);
+ if (c=='\\') // skip over escaped characters
+ {
+ i++;
+ }
+ else if (c=='"') // toggle inside/outside quotation
+ {
+ insideQuote=!insideQuote;
+ }
+ else if (!insideQuote && c=='#') // found start of a comment
+ {
+ return s.left(i).trimmed();
+ }
+ }
+ return s;
+}
+
+
+static void processString()
+{
+ // strip leading and trailing whitespace
+ QByteArray s = stripComment(g_str.trimmed());
+ int l = s.length();
+
+ // remove surrounding quotes if present (and not escaped)
+ if (l>=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();
+ }
+
+ // check for invalid and/or escaped quotes
+ bool warned=false;
+ QByteArray result;
+ for (int i=0;i<l;i++)
+ {
+ char c = s.at(i);
+ if (c=='\\') // escaped character
+ {
+ if (i<l-1 && s.at(i+1)=='"') // unescape the quote character
+ {
+ result+='"';
+ }
+ else // keep other escaped characters in escaped form
+ {
+ result+=c;
+ if (i<l-1)
+ {
+ result+=s.at(i+1);
+ }
+ }
+ i++; // skip over the escaped character
+ }
+ else if (c=='"') // unescaped quote
+ {
+ if (!warned)
+ {
+ std::string str = g_str.trimmed().data();
+ config_warn("Invalid value for '%s' tag at line %d, file %s: Value '%s' is not properly quoted\n",
+ qPrintable(g_cmd),yylineno-1,qPrintable(g_yyFileName),str.c_str());
+ }
+ warned=true;
+ }
+ else // normal character
+ {
+ result+=c;
+ }
+ }
+
+ // recode the string
+ if (g_isEnum)
+ {
+ InputString *cur = dynamic_cast<InputString *>(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<l;i++)
+ {
+ char c = s.at(i);
+ if (!needsSeparator && c=='\\') // escaped character
+ {
+ if (i<l-1 && s.at(i+1)=='"') // unescape the quote character
+ {
+ elemStr+='"';
+ }
+ else // keep other escaped characters in escaped form
+ {
+ elemStr+=c;
+ if (i<l-1)
+ {
+ elemStr+=s.at(i+1);
+ }
+ }
+ i++; // skip over the escaped character
+ }
+ else if (!needsSeparator && c=='"') // quote character
+ {
+ if (!insideQuote)
+ {
+ insideQuote=true;
+ }
+ else // this quote ends an element
+ {
+ insideQuote=false;
+ needsSeparator=true;
+ }
+ }
+ else if (!insideQuote && ((c==',' && allowCommaAsSeparator) || isspace(c))) // separator
+ {
+ needsSeparator=false;
+ addElem();
+ }
+ else // normal content character
+ {
+ if (needsSeparator)
+ {
+ if (!warned)
+ {
+ std::string str = g_str.trimmed().data();
+ config_warn("Invalid value for '%s' tag at line %d, file %s: Values in list '%s' are not properly space %sseparated\n",
+ qPrintable(g_cmd),yylineno-1,qPrintable(g_yyFileName),str.c_str(),allowCommaAsSeparator?"or comma ":"");
+ warned=true;
+ }
+ needsSeparator=false;
+ i--; // try the character again as part of a new element
+ addElem();
+ }
+ else
+ {
+ elemStr+=c;
+ }
+ }
+ }
+ // add last part
+ addElem();
+ if (insideQuote)
+ {
+ std::string str = g_str.trimmed().data();
+ config_warn("Invalid value for '%s' tag at line %d, file %s: Values in list '%s' are not properly quoted\n",
+ qPrintable(g_cmd),yylineno-1,qPrintable(g_yyFileName),str.c_str());
+ }
+}
+
+
static FILE *tryPath(const QString &path,const QString &fileName)
{
QString absName=!path.isEmpty() ? path+QString::fromLatin1("/")+fileName : fileName;
@@ -132,7 +302,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;
@@ -148,7 +318,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;
@@ -159,18 +329,17 @@ 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",
+ config_err("maximum include depth (%d) reached, %s is not included.",
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);
@@ -185,7 +354,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;
@@ -197,11 +366,10 @@ 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));
- exit(1);
}
}
@@ -213,40 +381,46 @@ static void readIncludeFile(const QString &incName)
%option yylineno
%x Start
-%x SkipComment
%x SkipInvalid
%x GetString
+%x GetEnum
%x GetStrList
%x GetQuotedString
-%x GetEnvVar
%x Include
%%
<*>\0x0d
-<Start,GetString,GetStrList,SkipInvalid>"#" { BEGIN(SkipComment); }
-<Start>[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);
+
+ /*-------------- Comments ---------------*/
+
+<Start>"#".*\n { /* Skip comment */ }
+
+ /*-------------- TAG start ---------------*/
+
+<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { g_cmd = g_codec->toUnicode(yytext);
+ 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
{
- //option->setEncoding(encoding);
g_arg = &g_curOption->value();
+ g_str = QByteArray();
+ g_isEnum = false;
switch(g_curOption->kind())
{
case Input::StrList:
- g_elemStr = QString();
*g_arg = QStringList();
BEGIN(GetStrList);
break;
case Input::String:
- BEGIN(GetString);
+ g_isEnum = dynamic_cast<InputString *>(g_curOption)->stringMode() == InputString::StringFixed;
+ BEGIN(GetString);
break;
case Input::Int:
BEGIN(GetString);
@@ -257,20 +431,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;
}
}
}
-<Start>[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);
+<Start>[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
@@ -279,31 +453,34 @@ 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:
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;
}
}
}
-<Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); }
+
+ /*-------------- INCLUDE* ---------------*/
+
+<Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_str=QByteArray(); }
/* include a config file */
<Start>"@INCLUDE"[ \t]*"=" { BEGIN(Include);}
-<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") {
- readIncludeFile(g_codec->toUnicode(yytext));
+<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") {
+ readIncludeFile(g_codec->toUnicode(yytext));
BEGIN(Start);
}
<<EOF>> {
@@ -322,69 +499,66 @@ 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--;
}
}
<Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); }
-<GetString,SkipInvalid>\n { BEGIN(Start); }
-<GetStrList>\n {
- if (!g_elemStr.isEmpty())
- {
- //printf("elemStr1='%s'\n",qPrintable(elemStr));
- *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
- }
- BEGIN(Start);
- }
-<GetStrList>[ \t]+ {
- if (!g_elemStr.isEmpty())
- {
- //printf("elemStr2='%s'\n",qPrintable(elemStr));
- *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
- }
- g_elemStr = QString();
- }
-<GetString>[^ \"\t\r\n]+ {
- *g_arg = QVariant(g_codec->toUnicode(yytext));
- checkEncoding();
+
+ /*-------------- GetString ---------------*/
+
+<GetString>\n { // end of string
+ processString();
+ BEGIN(Start);
}
-<GetString,GetStrList,SkipInvalid>"\"" { g_lastState=YY_START;
- BEGIN(GetQuotedString);
- g_tmpString="";
- }
-<GetQuotedString>"\""|"\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();
- }
- else
- {
- g_elemStr+=g_codec->toUnicode(g_tmpString);
- }
- if (*yytext=='\n')
- {
- config_warn("Missing end quote (\") on line %d, file %s\n",yylineno,
- qPrintable(g_yyFileName));
- }
- BEGIN(g_lastState);
- }
-<GetQuotedString>"\\\"" {
- g_tmpString+='"';
- }
-<GetQuotedString>. { g_tmpString+=*yytext; }
-<GetStrList>[^ \#\"\t\r\n]+ {
- g_elemStr+=g_codec->toUnicode(yytext);
- }
-<SkipComment>\n { BEGIN(Start); }
-<SkipComment>\\[ \r\t]*\n { BEGIN(Start); }
+<GetString>\\[ \r\t]*\n { // line continuation
+ g_str+=' ';
+ }
+<GetString>"\\" { // escape character
+ g_str+=yytext;
+ }
+<GetString>[^\n\\]+ { // string part without escape characters
+ g_str+=yytext;
+ }
+
+ /*-------------- GetStrList ---------------*/
+
+<GetStrList>\n { // end of list
+ processList();
+ BEGIN(Start);
+ }
+<GetStrList>\\[ \r\t]*\n { // line continuation
+ g_str+=' ';
+ }
+<GetStrList>"\\" { // escape character
+ g_str+=yytext;
+ }
+<GetStrList>[^\n\\]+ { // string part without escape characters
+ g_str+=yytext;
+ }
+
+ /*-------------- SkipInvalid ---------------*/
+
+<SkipInvalid>\n { // end of skipped part
+ BEGIN(Start);
+ }
+<SkipInvalid>\\[ \r\t]*\n { // line continuation
+ g_str+=' ';
+ }
+<SkipInvalid>"\\" { // escape character
+ g_str+=yytext;
+ }
+<SkipInvalid>[^\n\\]+ { // string part without escape characters
+ g_str+=yytext;
+ }
+
+ /*-------------- fall through -------------*/
+
<*>\\[ \r\t]*\n { }
+<*>[ \r\t] { }
<*>\n
-<*>.
+<*>. { config_warn("ignoring unknown character '%c' at line %d, file %s\n",yytext[0],yylineno,qPrintable(g_yyFileName)); }
%%
@@ -419,7 +593,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);
@@ -429,7 +603,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();
@@ -440,11 +614,11 @@ static void substEnvVarsInStrList(QStringList &sl)
{
QChar c=0;
// skip until start of new word
- while (i<l && ((c=result.at(i))==QChar::fromLatin1(' ') || c==QChar::fromLatin1('\t'))) i++;
+ while (i<l && ((c=result.at(i))==QChar::fromLatin1(' ') || c==QChar::fromLatin1('\t'))) i++;
p=i; // p marks the start index of the word
// skip until end of a word
- while (i<l && ((c=result.at(i))!=QChar::fromLatin1(' ') &&
- c!=QChar::fromLatin1('\t') &&
+ while (i<l && ((c=result.at(i))!=QChar::fromLatin1(' ') &&
+ c!=QChar::fromLatin1('\t') &&
c!=QChar::fromLatin1('"'))) i++;
if (i<l) // not at the end of the string
{
@@ -458,7 +632,7 @@ static void substEnvVarsInStrList(QStringList &sl)
{
out += result.mid(p,i-p);
p=i+1;
- break;
+ break;
}
else if (c==QChar::fromLatin1('\\')) // skip escaped stuff
{
@@ -493,13 +667,15 @@ bool parseConfig(
const QHash<QString,Input *> &options
)
{
+ yylineno = 1;
+ config_open();
QHashIterator<QString, Input*> 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())
@@ -519,7 +695,7 @@ bool parseConfig(
// update the values in the UI
i.toFront();
- while (i.hasNext())
+ while (i.hasNext())
{
i.next();
if (i.value())
@@ -531,8 +707,9 @@ bool parseConfig(
{
printf("Invalid option: %s\n",qPrintable(i.key()));
}
- }
+ }
fclose(g_file);
+ config_finish();
return true;
}
@@ -549,29 +726,30 @@ 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(',') ||
+ 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++;
@@ -582,7 +760,7 @@ void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s)
t << s;
}
if (needsHashEscaping || needsEscaping)
- {
+ {
t << "\"";
}
}