forked from qt-creator/qt-creator
sync variable expansion and list splitting with qmake
This commit is contained in:
@@ -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,13 +1009,120 @@ 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) {
|
||||
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;
|
||||
unicode = str_data[++i].unicode();
|
||||
if (unicode == LSQUARE) {
|
||||
unicode = str_data[++i].unicode();
|
||||
term = RSQUARE;
|
||||
var_type = PROPERTY;
|
||||
} else if (unicode == LCURLY) {
|
||||
unicode = str_data[++i].unicode();
|
||||
var_type = VAR;
|
||||
term = RCURLY;
|
||||
} else if (unicode == LPAREN) {
|
||||
unicode = str_data[++i].unicode();
|
||||
var_type = ENVIRON;
|
||||
term = RPAREN;
|
||||
}
|
||||
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(unicode));
|
||||
if (++i == str_len)
|
||||
break;
|
||||
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 && unicode == LPAREN) {
|
||||
var_type = FUNCTION;
|
||||
int depth = 0;
|
||||
forever {
|
||||
if (++i == str_len)
|
||||
break;
|
||||
unicode = str_data[i].unicode();
|
||||
if (unicode == LPAREN) {
|
||||
depth++;
|
||||
} else if (unicode == RPAREN) {
|
||||
if (!depth)
|
||||
break;
|
||||
--depth;
|
||||
}
|
||||
args.append(QChar(unicode));
|
||||
}
|
||||
if (++i < str_len)
|
||||
unicode = str_data[i].unicode();
|
||||
else
|
||||
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 (unicode != term) {
|
||||
q->logMessage(format("Missing %1 terminator [found %2]")
|
||||
.arg(QChar(term))
|
||||
.arg(unicode ? QString(unicode) : QString::fromLatin1(("end-of-line"))));
|
||||
// if (ok)
|
||||
// *ok = false;
|
||||
return QStringList();
|
||||
}
|
||||
} 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 = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLatin1().constData())));
|
||||
} else if (var_type == PROPERTY) {
|
||||
replacement << propertyValue(var);
|
||||
} else if (var_type == FUNCTION) {
|
||||
replacement << evaluateExpandFunction(var, args);
|
||||
} else if (var_type == VAR) {
|
||||
replacement = values(var);
|
||||
}
|
||||
if (!(replaced++) && start_var)
|
||||
current = str.left(start_var);
|
||||
if (!replacement.isEmpty()) {
|
||||
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 {
|
||||
if (replaced)
|
||||
current.append(QLatin1Char('$'));
|
||||
}
|
||||
}
|
||||
if (quote && unicode == quote) {
|
||||
unicode = 0;
|
||||
quote = 0;
|
||||
} else if (unicode == BACKSLASH) {
|
||||
bool escape = false;
|
||||
const char *symbols = "[]{}()$\\";
|
||||
const char *symbols = "[]{}()$\\'\"";
|
||||
for (const char *s = symbols; *s; ++s) {
|
||||
if (str_data[i+1] == (ushort)*s) {
|
||||
if (str_data[i+1].unicode() == (ushort)*s) {
|
||||
i++;
|
||||
escape = true;
|
||||
if (!(replaced++))
|
||||
@@ -1023,129 +1131,27 @@ QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &s
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!escape && replaced)
|
||||
current.append(QChar(c));
|
||||
continue;
|
||||
}
|
||||
if (c == SPACE || c == TAB) {
|
||||
c = 0;
|
||||
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()) {
|
||||
unquote(¤t);
|
||||
ret.append(current);
|
||||
current.clear();
|
||||
}
|
||||
} else if (c == DOLLAR && str_len > i+2) {
|
||||
c = str_data[++i].unicode();
|
||||
if (c == 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();
|
||||
term = RSQUARE;
|
||||
var_type = PROPERTY;
|
||||
} else if (c == LCURLY) {
|
||||
c = str_data[++i].unicode();
|
||||
var_type = VAR;
|
||||
term = RCURLY;
|
||||
} else if (c == LPAREN) {
|
||||
c = 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'))
|
||||
break;
|
||||
var.append(QChar(c));
|
||||
if (++i == str_len)
|
||||
break;
|
||||
c = str_data[i].unicode();
|
||||
}
|
||||
if (var_type == VAR && c == LPAREN) {
|
||||
var_type = FUNCTION;
|
||||
int depth = 0;
|
||||
while (1) {
|
||||
if (++i == str_len)
|
||||
break;
|
||||
c = str_data[i].unicode();
|
||||
if (c == LPAREN) {
|
||||
depth++;
|
||||
} else if (c == RPAREN) {
|
||||
if (!depth)
|
||||
break;
|
||||
--depth;
|
||||
}
|
||||
args.append(QChar(c));
|
||||
}
|
||||
if (i < str_len-1)
|
||||
c = str_data[++i].unicode();
|
||||
else
|
||||
c = 0;
|
||||
}
|
||||
if (term) {
|
||||
if (c != term) {
|
||||
q->logMessage(format("Missing %1 terminator [found %2]")
|
||||
.arg(QChar(term)).arg(QChar(c)));
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return QStringList();
|
||||
}
|
||||
c = 0;
|
||||
} else if (i > str_len-1) {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
QStringList replacement;
|
||||
if (var_type == ENVIRON) {
|
||||
replacement << QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (replaced)
|
||||
current.append(QLatin1Char('$'));
|
||||
}
|
||||
}
|
||||
if (replaced && c != 0)
|
||||
current.append(QChar(c));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user