summaryrefslogtreecommitdiffstats
path: root/qmake/library/qmakebuiltins.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qmake/library/qmakebuiltins.cpp')
-rw-r--r--qmake/library/qmakebuiltins.cpp250
1 files changed, 170 insertions, 80 deletions
diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp
index 80569e503a..6f93b655b4 100644
--- a/qmake/library/qmakebuiltins.cpp
+++ b/qmake/library/qmakebuiltins.cpp
@@ -80,9 +80,10 @@ QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s)
enum ExpandFunc {
- E_INVALID = 0, E_MEMBER, E_FIRST, E_LAST, E_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
- E_SPRINTF, E_FORMAT_NUMBER, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
- E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
+ E_INVALID = 0, E_MEMBER, E_STR_MEMBER, E_FIRST, E_TAKE_FIRST, E_LAST, E_TAKE_LAST,
+ E_SIZE, E_STR_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST, E_SPRINTF, E_FORMAT_NUMBER,
+ E_NUM_ADD, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
+ E_FIND, E_SYSTEM, E_UNIQUE, E_SORTED, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE,
E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
@@ -104,15 +105,20 @@ void QMakeEvaluator::initFunctionStatics()
const ExpandFunc func;
} expandInits[] = {
{ "member", E_MEMBER },
+ { "str_member", E_STR_MEMBER },
{ "first", E_FIRST },
+ { "take_first", E_TAKE_FIRST },
{ "last", E_LAST },
+ { "take_last", E_TAKE_LAST },
{ "size", E_SIZE },
+ { "str_size", E_STR_SIZE },
{ "cat", E_CAT },
{ "fromfile", E_FROMFILE },
{ "eval", E_EVAL },
{ "list", E_LIST },
{ "sprintf", E_SPRINTF },
{ "format_number", E_FORMAT_NUMBER },
+ { "num_add", E_NUM_ADD },
{ "join", E_JOIN },
{ "split", E_SPLIT },
{ "basename", E_BASENAME },
@@ -121,6 +127,7 @@ void QMakeEvaluator::initFunctionStatics()
{ "find", E_FIND },
{ "system", E_SYSTEM },
{ "unique", E_UNIQUE },
+ { "sorted", E_SORTED },
{ "reverse", E_REVERSE },
{ "quote", E_QUOTE },
{ "escape_expand", E_ESCAPE_EXPAND },
@@ -197,6 +204,49 @@ static bool isTrue(const ProString &str)
return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
}
+bool
+QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringList &args,
+ int *start, int *end)
+{
+ *start = 0, *end = 0;
+ if (args.count() >= 2) {
+ bool ok = true;
+ const ProString &start_str = args.at(1);
+ *start = start_str.toInt(&ok);
+ if (!ok) {
+ if (args.count() == 2) {
+ int dotdot = start_str.indexOf(statics.strDotDot);
+ if (dotdot != -1) {
+ *start = start_str.left(dotdot).toInt(&ok);
+ if (ok)
+ *end = start_str.mid(dotdot+2).toInt(&ok);
+ }
+ }
+ if (!ok) {
+ evalError(fL1S("%1() argument 2 (start) '%2' invalid.")
+ .arg(func.toQString(m_tmp1), start_str.toQString(m_tmp2)));
+ return false;
+ }
+ } else {
+ *end = *start;
+ if (args.count() == 3)
+ *end = args.at(2).toInt(&ok);
+ if (!ok) {
+ evalError(fL1S("%1() argument 3 (end) '%2' invalid.")
+ .arg(func.toQString(m_tmp1), args.at(2).toQString(m_tmp2)));
+ return false;
+ }
+ }
+ }
+ if (*start < 0)
+ *start += srclen;
+ if (*end < 0)
+ *end += srclen;
+ if (*start < 0 || *start >= srclen || *end < 0 || *end >= srclen)
+ return false;
+ return true;
+}
+
#if defined(Q_OS_WIN) && defined(PROEVALUATOR_FULL)
static QString windowsErrorCode()
{
@@ -532,31 +582,30 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
bool leftalign = false;
enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
if (args.count() >= 2) {
- const auto opts = split_value_list(args.at(1).toQString(m_tmp2));
+ const auto opts = split_value_list(args.at(1).toQStringRef());
for (const ProString &opt : opts) {
- opt.toQString(m_tmp3);
- if (m_tmp3.startsWith(QLatin1String("ibase="))) {
- ibase = m_tmp3.mid(6).toInt();
- } else if (m_tmp3.startsWith(QLatin1String("obase="))) {
- obase = m_tmp3.mid(6).toInt();
- } else if (m_tmp3.startsWith(QLatin1String("width="))) {
- width = m_tmp3.mid(6).toInt();
- } else if (m_tmp3 == QLatin1String("zeropad")) {
+ if (opt.startsWith(QLatin1String("ibase="))) {
+ ibase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("obase="))) {
+ obase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("width="))) {
+ width = opt.mid(6).toInt();
+ } else if (opt == QLatin1String("zeropad")) {
zeropad = true;
- } else if (m_tmp3 == QLatin1String("padsign")) {
+ } else if (opt == QLatin1String("padsign")) {
sign = PadSign;
- } else if (m_tmp3 == QLatin1String("alwayssign")) {
+ } else if (opt == QLatin1String("alwayssign")) {
sign = AlwaysSign;
- } else if (m_tmp3 == QLatin1String("leftalign")) {
+ } else if (opt == QLatin1String("leftalign")) {
leftalign = true;
} else {
- evalError(fL1S("format_number(): invalid format option %1.").arg(m_tmp3));
+ evalError(fL1S("format_number(): invalid format option %1.")
+ .arg(opt.toQString(m_tmp3)));
goto formfail;
}
}
}
- args.at(0).toQString(m_tmp3);
- if (m_tmp3.contains(QLatin1Char('.'))) {
+ if (args.at(0).contains(QLatin1Char('.'))) {
evalError(fL1S("format_number(): floats are currently not supported."));
break;
}
@@ -564,7 +613,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
qlonglong num = args.at(0).toLongLong(&ok, ibase);
if (!ok) {
evalError(fL1S("format_number(): malformed number %2 for base %1.")
- .arg(ibase).arg(m_tmp3));
+ .arg(ibase).arg(args.at(0).toQString(m_tmp3)));
break;
}
QString outstr;
@@ -592,14 +641,36 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
}
formfail:
break;
+ case E_NUM_ADD:
+ if (args.count() < 1 || args.at(0).isEmpty()) {
+ evalError(fL1S("num_add(num, ...) requires at least one argument."));
+ } else {
+ qlonglong sum = 0;
+ for (const ProString &arg : qAsConst(args)) {
+ if (arg.contains(QLatin1Char('.'))) {
+ evalError(fL1S("num_add(): floats are currently not supported."));
+ goto nafail;
+ }
+ bool ok;
+ qlonglong num = arg.toLongLong(&ok);
+ if (!ok) {
+ evalError(fL1S("num_add(): malformed number %1.")
+ .arg(arg.toQString(m_tmp3)));
+ goto nafail;
+ }
+ sum += num;
+ }
+ ret += ProString(QString::number(sum));
+ }
+ nafail:
+ break;
case E_JOIN: {
if (args.count() < 1 || args.count() > 4) {
evalError(fL1S("join(var, glue, before, after) requires one to four arguments."));
} else {
- QString glue;
- ProString before, after;
+ ProString glue, before, after;
if (args.count() >= 2)
- glue = args.at(1).toQString(m_tmp1);
+ glue = args.at(1);
if (args.count() >= 3)
before = args[2];
if (args.count() == 4)
@@ -634,47 +705,37 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
if (args.count() < 1 || args.count() > 3) {
evalError(fL1S("member(var, start, end) requires one to three arguments."));
} else {
- bool ok = true;
- const ProStringList &var = values(map(args.at(0)));
- int start = 0, end = 0;
- if (args.count() >= 2) {
- const ProString &start_str = args.at(1);
- start = start_str.toInt(&ok);
- if (!ok) {
- if (args.count() == 2) {
- int dotdot = start_str.indexOf(statics.strDotDot);
- if (dotdot != -1) {
- start = start_str.left(dotdot).toInt(&ok);
- if (ok)
- end = start_str.mid(dotdot+2).toInt(&ok);
- }
- }
- if (!ok)
- evalError(fL1S("member() argument 2 (start) '%2' invalid.")
- .arg(start_str.toQString(m_tmp1)));
+ const ProStringList &src = values(map(args.at(0)));
+ int start, end;
+ if (getMemberArgs(func, src.size(), args, &start, &end)) {
+ ret.reserve(qAbs(end - start) + 1);
+ if (start < end) {
+ for (int i = start; i <= end && src.size() >= i; i++)
+ ret += src.at(i);
} else {
- end = start;
- if (args.count() == 3)
- end = args.at(2).toInt(&ok);
- if (!ok)
- evalError(fL1S("member() argument 3 (end) '%2' invalid.")
- .arg(args.at(2).toQString(m_tmp1)));
+ for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
+ ret += src.at(i);
}
}
- if (ok) {
- if (start < 0)
- start += var.count();
- if (end < 0)
- end += var.count();
- if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
- //nothing
- } else if (start < end) {
- for (int i = start; i <= end && var.count() >= i; i++)
- ret.append(var[i]);
+ }
+ break;
+ case E_STR_MEMBER:
+ if (args.count() < 1 || args.count() > 3) {
+ evalError(fL1S("str_member(str, start, end) requires one to three arguments."));
+ } else {
+ const ProString &src = args.at(0);
+ int start, end;
+ if (getMemberArgs(func, src.size(), args, &start, &end)) {
+ QString res;
+ res.reserve(qAbs(end - start) + 1);
+ if (start < end) {
+ for (int i = start; i <= end && src.size() >= i; i++)
+ res += src.at(i);
} else {
- for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
- ret += var[i];
+ for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
+ res += src.at(i);
}
+ ret += ProString(res);
}
}
break;
@@ -692,12 +753,32 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
}
}
break;
+ case E_TAKE_FIRST:
+ case E_TAKE_LAST:
+ if (args.count() != 1) {
+ evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
+ } else {
+ ProStringList &var = valuesRef(map(args.at(0)));
+ if (!var.isEmpty()) {
+ if (func_t == E_TAKE_FIRST)
+ ret.append(var.takeFirst());
+ else
+ ret.append(var.takeLast());
+ }
+ }
+ break;
case E_SIZE:
if (args.count() != 1)
evalError(fL1S("size(var) requires one argument."));
else
ret.append(ProString(QString::number(values(map(args.at(0))).size())));
break;
+ case E_STR_SIZE:
+ if (args.count() != 1)
+ evalError(fL1S("str_size(str) requires one argument."));
+ else
+ ret.append(ProString(QString::number(args.at(0).size())));
+ break;
case E_CAT:
if (args.count() < 1 || args.count() > 2) {
evalError(fL1S("cat(file, singleline=true) requires one or two arguments."));
@@ -708,12 +789,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
bool lines = false;
bool singleLine = true;
if (args.count() > 1) {
- args.at(1).toQString(m_tmp2);
- if (!m_tmp2.compare(QLatin1String("false"), Qt::CaseInsensitive))
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
singleLine = false;
- else if (!m_tmp2.compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
blob = true;
- else if (!m_tmp2.compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
lines = true;
}
@@ -727,7 +807,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
if (lines) {
ret += ProString(stream.readLine());
} else {
- ret += split_value_list(stream.readLine().trimmed());
+ const QString &line = stream.readLine();
+ ret += split_value_list(QStringRef(&line).trimmed());
if (!singleLine)
ret += ProString("\n");
}
@@ -759,7 +840,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
ret = ProStringList(ProString(tmp));
ProStringList lst;
for (const ProString &arg : args)
- lst += split_value_list(arg.toQString(m_tmp1), arg.sourceFile()); // Relies on deep copy
+ lst += split_value_list(arg.toQStringRef(), arg.sourceFile()); // Relies on deep copy
m_valuemapStack.top()[ret.at(0).toKey()] = lst;
break; }
case E_FIND:
@@ -785,12 +866,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
bool lines = false;
bool singleLine = true;
if (args.count() > 1) {
- args.at(1).toQString(m_tmp2);
- if (!m_tmp2.compare(QLatin1String("false"), Qt::CaseInsensitive))
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
singleLine = false;
- else if (!m_tmp2.compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
blob = true;
- else if (!m_tmp2.compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
lines = true;
}
QByteArray bytes = getCommandOutput(args.at(0).toQString(m_tmp2));
@@ -806,7 +886,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
output.replace(QLatin1Char('\t'), QLatin1Char(' '));
if (singleLine)
output.replace(QLatin1Char('\n'), QLatin1Char(' '));
- ret += split_value_list(output);
+ ret += split_value_list(QStringRef(&output));
}
}
}
@@ -820,6 +900,14 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
ret.removeDuplicates();
}
break;
+ case E_SORTED:
+ if (args.count() != 1) {
+ evalError(fL1S("sorted(var) requires one argument."));
+ } else {
+ ret = values(map(args.at(0)));
+ std::sort(ret.begin(), ret.end());
+ }
+ break;
case E_REVERSE:
if (args.count() != 1) {
evalError(fL1S("reverse(var) requires one argument."));
@@ -955,7 +1043,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
QFile qfile;
if (qfile.open(stdin, QIODevice::ReadOnly)) {
QTextStream t(&qfile);
- ret = split_value_list(t.readLine());
+ const QString &line = t.readLine();
+ ret = split_value_list(QStringRef(&line));
}
}
break; }
@@ -989,7 +1078,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3);
populateDeps(orgList, prefix,
args.count() < 3 ? ProStringList(ProString(".depends"))
- : split_value_list(args.at(2).toQString(m_tmp2)),
+ : split_value_list(args.at(2).toQStringRef()),
priosfx, dependencies, dependees, rootSet);
while (!rootSet.isEmpty()) {
QMultiMap<int, ProString>::iterator it = rootSet.begin();
@@ -1211,7 +1300,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse; // Another qmake breakage
case T_EVAL: {
VisitReturn ret = ReturnFalse;
- ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep),
+ QString contents = args.join(statics.field_sep);
+ ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents),
m_current.pro->fileName(), m_current.line);
if (m_cumulative || pro->isOk()) {
m_locationStack.push(m_current);
@@ -1227,7 +1317,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("if(condition) requires one argument."));
return ReturnFalse;
}
- return returnBool(evaluateConditional(args.at(0).toQString(),
+ return returnBool(evaluateConditional(args.at(0).toQStringRef(),
m_current.pro->fileName(), m_current.line));
}
case T_CONFIG: {
@@ -1236,7 +1326,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
}
if (args.count() == 1)
- return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2)));
+ return returnBool(isActiveConfig(args.at(0).toQStringRef()));
const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|'));
const ProStringList &configs = values(statics.strCONFIG);
@@ -1319,8 +1409,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
.arg(function.toQString(m_tmp1)));
return ReturnFalse;
}
- const QString &rhs(args.at(1).toQString(m_tmp1)),
- &lhs(values(map(args.at(0))).join(statics.field_sep));
+ const ProString &rhs = args.at(1);
+ const QString &lhs = values(map(args.at(0))).join(statics.field_sep);
bool ok;
int rhs_int = rhs.toInt(&ok);
if (ok) { // do integer compare
@@ -1332,8 +1422,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
}
if (func_t == T_GREATERTHAN)
- return returnBool(lhs > rhs);
- return returnBool(lhs < rhs);
+ return returnBool(lhs > rhs.toQStringRef());
+ return returnBool(lhs < rhs.toQStringRef());
}
case T_EQUALS:
if (args.count() != 2) {
@@ -1569,7 +1659,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (!vals.isEmpty())
contents = vals.join(QLatin1Char('\n')) + QLatin1Char('\n');
if (args.count() >= 3) {
- const auto opts = split_value_list(args.at(2).toQString(m_tmp2));
+ const auto opts = split_value_list(args.at(2).toQStringRef());
for (const ProString &opt : opts) {
opt.toQString(m_tmp3);
if (m_tmp3 == QLatin1String("append")) {
@@ -1642,7 +1732,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
ProKey srcvar;
if (args.count() >= 2) {
- const auto opts = split_value_list(args.at(1).toQString(m_tmp2));
+ const auto opts = split_value_list(args.at(1).toQStringRef());
for (const ProString &opt : opts) {
opt.toQString(m_tmp3);
if (m_tmp3 == QLatin1String("transient")) {