diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 79b93d21b74aa0e9f2a77cff46e65d098946da71..e1c067eee5e61225432376ce2ff6c318294fe0c8 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -978,11 +978,9 @@ QString ProFileEvaluator::Private::currentDirectory() const QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &str) { - bool fOK; - bool *ok = &fOK; QStringList ret; - if (ok) - *ok = true; +// if (ok) +// *ok = true; if (str.isEmpty()) return ret; @@ -998,7 +996,10 @@ QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &s const ushort DOT = '.'; const ushort SPACE = ' '; const ushort TAB = '\t'; + const ushort SINGLEQUOTE = '\''; + const ushort DOUBLEQUOTE = '"'; + ushort unicode, quote = 0; const QChar *str_data = str.data(); const int str_len = str.length(); @@ -1008,126 +1009,105 @@ QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &s int replaced = 0; QString current; for (int i = 0; i < str_len; ++i) { - ushort c = str_data[i].unicode(); + unicode = str_data[i].unicode(); const int start_var = i; - if (c == BACKSLASH) { - bool escape = false; - const char *symbols = "[]{}()$\\"; - for (const char *s = symbols; *s; ++s) { - if (str_data[i+1] == (ushort)*s) { - i++; - escape = true; - if (!(replaced++)) - current = str.left(start_var); - current.append(str.at(i)); - break; - } - } - if (!escape && replaced) - current.append(QChar(c)); - continue; - } - if (c == SPACE || c == TAB) { - c = 0; - if (!current.isEmpty()) { - unquote(¤t); - ret.append(current); - current.clear(); - } - } else if (c == DOLLAR && str_len > i+2) { - c = str_data[++i].unicode(); - if (c == DOLLAR) { + if (unicode == DOLLAR && str_len > i+2) { + unicode = str_data[++i].unicode(); + if (unicode == DOLLAR) { term = 0; var.clear(); args.clear(); enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR; - c = str_data[++i].unicode(); - if (c == LSQUARE) { - c = str_data[++i].unicode(); + unicode = str_data[++i].unicode(); + if (unicode == LSQUARE) { + unicode = str_data[++i].unicode(); term = RSQUARE; var_type = PROPERTY; - } else if (c == LCURLY) { - c = str_data[++i].unicode(); + } else if (unicode == LCURLY) { + unicode = str_data[++i].unicode(); var_type = VAR; term = RCURLY; - } else if (c == LPAREN) { - c = str_data[++i].unicode(); + } else if (unicode == LPAREN) { + unicode = str_data[++i].unicode(); var_type = ENVIRON; term = RPAREN; } - while (1) { - if (!(c & (0xFF<<8)) && - c != DOT && c != UNDERSCORE && - (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9')) + forever { + if (!(unicode & (0xFF<<8)) && + unicode != DOT && unicode != UNDERSCORE && + //unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE && + (unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') && + (unicode < '0' || unicode > '9')) break; - var.append(QChar(c)); + var.append(QChar(unicode)); if (++i == str_len) break; - c = str_data[i].unicode(); + unicode = str_data[i].unicode(); + // at this point, i points to either the 'term' or 'next' character (which is in unicode) } - if (var_type == VAR && c == LPAREN) { + if (var_type == VAR && unicode == LPAREN) { var_type = FUNCTION; int depth = 0; - while (1) { + forever { if (++i == str_len) break; - c = str_data[i].unicode(); - if (c == LPAREN) { + unicode = str_data[i].unicode(); + if (unicode == LPAREN) { depth++; - } else if (c == RPAREN) { + } else if (unicode == RPAREN) { if (!depth) break; --depth; } - args.append(QChar(c)); + args.append(QChar(unicode)); } - if (i < str_len-1) - c = str_data[++i].unicode(); + if (++i < str_len) + unicode = str_data[i].unicode(); else - c = 0; + unicode = 0; + // at this point i is pointing to the 'next' character (which is in unicode) + // this might actually be a term character since you can do $${func()} } if (term) { - if (c != term) { + if (unicode != term) { q->logMessage(format("Missing %1 terminator [found %2]") - .arg(QChar(term)).arg(QChar(c))); - if (ok) - *ok = false; + .arg(QChar(term)) + .arg(unicode ? QString(unicode) : QString::fromLatin1(("end-of-line")))); +// if (ok) +// *ok = false; return QStringList(); } - c = 0; - } else if (i > str_len-1) { - c = 0; + } else { + // move the 'cursor' back to the last char of the thing we were looking at + --i; } + // since i never points to the 'next' character, there is no reason for this to be set + unicode = 0; QStringList replacement; if (var_type == ENVIRON) { - replacement << QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData())); + replacement = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLatin1().constData()))); } else if (var_type == PROPERTY) { replacement << propertyValue(var); - //if (prop) - // replacement = QStringList(prop->value(var)); } else if (var_type == FUNCTION) { replacement << evaluateExpandFunction(var, args); } else if (var_type == VAR) { - replacement += values(var); + replacement = values(var); } if (!(replaced++) && start_var) current = str.left(start_var); if (!replacement.isEmpty()) { - /* If a list is beteen two strings make sure it expands in such a way - * that the string to the left is prepended to the first string and - * the string to the right is appended to the last string, example: - * LIST = a b c - * V3 = x/$$LIST/f.cpp - * message($$member(V3,0)) # Outputs "x/a" - * message($$member(V3,1)) # Outputs "b" - * message($$member(V3,2)) # Outputs "c/f.cpp" - */ - current.append(replacement.at(0)); - for (int i = 1; i < replacement.count(); ++i) { - unquote(¤t); - ret.append(current); - current = replacement.at(i); + if (quote) { + current += replacement.join(QString(Option::field_sep)); + } else { + current += replacement.takeFirst(); + if (!replacement.isEmpty()) { + if (!current.isEmpty()) + ret.append(current); + current = replacement.takeLast(); + if (!replacement.isEmpty()) + ret += replacement; + } } } } else { @@ -1135,17 +1115,43 @@ QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &s current.append(QLatin1Char('$')); } } - if (replaced && c != 0) - current.append(QChar(c)); + if (quote && unicode == quote) { + unicode = 0; + quote = 0; + } else if (unicode == BACKSLASH) { + bool escape = false; + const char *symbols = "[]{}()$\\'\""; + for (const char *s = symbols; *s; ++s) { + if (str_data[i+1].unicode() == (ushort)*s) { + i++; + escape = true; + if (!(replaced++)) + current = str.left(start_var); + current.append(str.at(i)); + break; + } + } + if (escape || !replaced) + unicode =0; + } else if (!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) { + quote = unicode; + unicode = 0; + if (!(replaced++) && i) + current = str.left(i); + } else if (!quote && (unicode == SPACE || unicode == TAB)) { + unicode = 0; + if (!current.isEmpty()) { + ret.append(current); + current.clear(); + } + } + if (replaced && unicode) + current.append(QChar(unicode)); } - if (!replaced) { - current = str; - unquote(¤t); + if (!replaced) + ret = QStringList(str); + else if (!current.isEmpty()) ret.append(current); - } else if (!current.isEmpty()) { - unquote(¤t); - ret.append(current); - } return ret; } diff --git a/src/shared/proparser/proparserutils.h b/src/shared/proparser/proparserutils.h index 97889be597195fe96c2968324cad15521492959c..05754860386505fe243f2c783157d47797c58628 100644 --- a/src/shared/proparser/proparserutils.h +++ b/src/shared/proparser/proparserutils.h @@ -116,17 +116,6 @@ QString Option::dirlist_sep; QString Option::dir_sep; QChar Option::field_sep; -static void unquote(QString *string) -{ - PRE(string); - if ( (string->startsWith(QLatin1Char('\"')) && string->endsWith(QLatin1Char('\"'))) - || (string->startsWith(QLatin1Char('\'')) && string->endsWith(QLatin1Char('\''))) ) - { - string->remove(0,1); - string->remove(string->length() - 1,1); - } -} - static void insertUnique(QHash<QString, QStringList> *map, const QString &key, const QStringList &value) { @@ -221,7 +210,8 @@ static QStringList split_arg_list(QString params) quote = 0; } else if (!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) { quote = unicode; - } else if (!parens && !quote && unicode == COMMA) { + } + if (!parens && !quote && unicode == COMMA) { QString mid = params.mid(last, x - last).trimmed(); args << mid; last = x+1; @@ -230,8 +220,6 @@ static QStringList split_arg_list(QString params) ++last; } } - for (int i = 0; i < args.count(); i++) - unquote(&args[i]); return args; } @@ -239,34 +227,35 @@ static QStringList split_value_list(const QString &vals, bool do_semicolon=false { QString build; QStringList ret; - QStack<QChar> quote; + QStack<char> quote; - const QChar LPAREN = QLatin1Char('('); - const QChar RPAREN = QLatin1Char(')'); - const QChar SINGLEQUOTE = QLatin1Char('\''); - const QChar DOUBLEQUOTE = QLatin1Char('"'); - const QChar BACKSLASH = QLatin1Char('\\'); - const QChar SEMICOLON = QLatin1Char(';'); + const ushort LPAREN = '('; + const ushort RPAREN = ')'; + const ushort SINGLEQUOTE = '\''; + const ushort DOUBLEQUOTE = '"'; + const ushort BACKSLASH = '\\'; + const ushort SEMICOLON = ';'; + ushort unicode; const QChar *vals_data = vals.data(); const int vals_len = vals.length(); for (int x = 0, parens = 0; x < vals_len; x++) { - QChar c = vals_data[x]; - if (x != vals_len-1 && c == BACKSLASH && - vals_data[x+1].unicode() == '\'' || vals_data[x+1] == DOUBLEQUOTE) { - build += vals_data[x++]; // get that 'escape' - } else if (!quote.isEmpty() && c == quote.top()) { + unicode = vals_data[x].unicode(); + if (x != (int)vals_len-1 && unicode == BACKSLASH && + (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) { + build += vals_data[x++]; //get that 'escape' + } else if (!quote.isEmpty() && unicode == quote.top()) { quote.pop(); - } else if (c == SINGLEQUOTE || c == DOUBLEQUOTE) { - quote.push(c); - } else if (c == RPAREN) { + } else if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) { + quote.push(unicode); + } else if (unicode == RPAREN) { --parens; - } else if (c == LPAREN) { + } else if (unicode == LPAREN) { ++parens; } - if (!parens && quote.isEmpty() && ((do_semicolon && c == SEMICOLON) || - vals_data[x] == Option::field_sep)) { + if (!parens && quote.isEmpty() && ((do_semicolon && unicode == SEMICOLON) || + vals_data[x] == Option::field_sep)) { ret << build; build.clear(); } else {