Commit 027b52a2 authored by Oswald Buddenhagen's avatar Oswald Buddenhagen

sync variable expansion and list splitting with qmake

parent 5bc97eb1
......@@ -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(&current);
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(&current);
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(&current);
if (!replaced)
ret = QStringList(str);
else if (!current.isEmpty())
ret.append(current);
} else if (!current.isEmpty()) {
unquote(&current);
ret.append(current);
}
return ret;
}
......
......@@ -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 {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment