aboutsummaryrefslogtreecommitdiffstats
path: root/src/shared/proparser
diff options
context:
space:
mode:
authorOrgad Shaneh <orgad.shaneh@audiocodes.com>2016-08-05 11:59:28 +0300
committerUlf Hermann <ulf.hermann@qt.io>2016-08-05 11:40:07 +0200
commit1853f01a5b0955a28e9c321cd36f45d5f17651bf (patch)
tree5d357de37f3c2ef93e38bbc79ef96b6f8982cd6f /src/shared/proparser
parent713bc04ad4560123d97bb469d109a0885cf36373 (diff)
parentd004203b13fa17d1258ee62d5eb4f681adf32398 (diff)
Merge remote-tracking branch 'origin/4.1'
Diffstat (limited to 'src/shared/proparser')
-rw-r--r--src/shared/proparser/proitems.cpp15
-rw-r--r--src/shared/proparser/proitems.h21
-rw-r--r--src/shared/proparser/prowriter.cpp2
-rw-r--r--src/shared/proparser/qmakebuiltins.cpp340
-rw-r--r--src/shared/proparser/qmakeevaluator.cpp230
-rw-r--r--src/shared/proparser/qmakeevaluator.h27
-rw-r--r--src/shared/proparser/qmakeglobals.cpp29
-rw-r--r--src/shared/proparser/qmakeglobals.h3
-rw-r--r--src/shared/proparser/qmakeparser.cpp54
-rw-r--r--src/shared/proparser/qmakeparser.h6
-rw-r--r--src/shared/proparser/qmakevfs.cpp18
-rw-r--r--src/shared/proparser/qmakevfs.h2
12 files changed, 506 insertions, 241 deletions
diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp
index 1a22a3c50b..795b8b4564 100644
--- a/src/shared/proparser/proitems.cpp
+++ b/src/shared/proparser/proitems.cpp
@@ -362,6 +362,11 @@ static QString ProStringList_join(const ProStringList &this_, const QChar *sep,
return res;
}
+QString ProStringList::join(const ProString &sep) const
+{
+ return ProStringList_join(*this, sep.constData(), sep.size());
+}
+
QString ProStringList::join(const QString &sep) const
{
return ProStringList_join(*this, sep.constData(), sep.size());
@@ -388,7 +393,7 @@ void ProStringList::removeAll(const char *str)
void ProStringList::removeEach(const ProStringList &value)
{
- foreach (const ProString &str, value)
+ for (const ProString &str : value)
if (!str.isEmpty())
removeAll(str);
}
@@ -421,7 +426,7 @@ void ProStringList::removeDuplicates()
void ProStringList::insertUnique(const ProStringList &value)
{
- foreach (const ProString &str, value)
+ for (const ProString &str : value)
if (!str.isEmpty() && !contains(str))
append(str);
}
@@ -429,7 +434,7 @@ void ProStringList::insertUnique(const ProStringList &value)
ProStringList::ProStringList(const QStringList &list)
{
reserve(list.size());
- foreach (const QString &str, list)
+ for (const QString &str : list)
*this << ProString(str);
}
@@ -437,8 +442,8 @@ QStringList ProStringList::toQStringList() const
{
QStringList ret;
ret.reserve(size());
- for (int i = 0; i < size(); i++) // foreach causes MSVC2010 ICE
- ret << at(i).toQString();
+ for (const auto &e : *this)
+ ret.append(e.toQString());
return ret;
}
diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h
index d6bc4fe1cb..31e662bcf0 100644
--- a/src/shared/proparser/proitems.h
+++ b/src/shared/proparser/proitems.h
@@ -96,6 +96,7 @@ public:
bool operator!=(const QString &other) const { return !(*this == other); }
bool operator!=(QLatin1String other) const { return !(*this == other); }
bool operator!=(const char *other) const { return !(*this == other); }
+ bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); }
bool isNull() const { return m_string.isNull(); }
bool isEmpty() const { return !m_length; }
int length() const { return m_length; }
@@ -126,8 +127,9 @@ public:
bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; }
bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; }
bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; }
- int toInt(bool *ok = 0, int base = 10) const { return toQString().toInt(ok, base); } // XXX optimize
- short toShort(bool *ok = 0, int base = 10) const { return toQString().toShort(ok, base); } // XXX optimize
+ int toLongLong(bool *ok = 0, int base = 10) const { return toQStringRef().toLongLong(ok, base); }
+ int toInt(bool *ok = 0, int base = 10) const { return toQStringRef().toInt(ok, base); }
+ short toShort(bool *ok = 0, int base = 10) const { return toQStringRef().toShort(ok, base); }
uint hash() const { return m_hash; }
static uint hash(const QChar *p, int n);
@@ -228,6 +230,7 @@ public:
int length() const { return size(); }
+ QString join(const ProString &sep) const;
QString join(const QString &sep) const;
QString join(QChar sep) const;
@@ -360,6 +363,8 @@ class ProFunctionDef {
public:
ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); }
ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); }
+ ProFunctionDef(ProFunctionDef &&other) Q_DECL_NOTHROW
+ : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; }
~ProFunctionDef() { m_pro->deref(); }
ProFunctionDef &operator=(const ProFunctionDef &o)
{
@@ -371,6 +376,18 @@ public:
}
return *this;
}
+ ProFunctionDef &operator=(ProFunctionDef &&other) Q_DECL_NOTHROW
+ {
+ ProFunctionDef moved(std::move(other));
+ swap(moved);
+ return *this;
+ }
+ void swap(ProFunctionDef &other) Q_DECL_NOTHROW
+ {
+ qSwap(m_pro, other.m_pro);
+ qSwap(m_offset, other.m_offset);
+ }
+
ProFile *pro() const { return m_pro; }
const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; }
private:
diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp
index 700e134c1b..d49c3aa864 100644
--- a/src/shared/proparser/prowriter.cpp
+++ b/src/shared/proparser/prowriter.cpp
@@ -175,7 +175,7 @@ QString ProWriter::compileScope(const QString &scope)
if (scope.isEmpty())
return QString();
QMakeParser parser(0, 0, 0);
- ProFile *includeFile = parser.parsedProBlock(scope, QLatin1String("no-file"), 1);
+ ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), QLatin1String("no-file"), 1);
if (!includeFile)
return QString();
QString result = includeFile->items();
diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp
index f5868c5de0..8ceebd9cf0 100644
--- a/src/shared/proparser/qmakebuiltins.cpp
+++ b/src/shared/proparser/qmakebuiltins.cpp
@@ -52,6 +52,8 @@
#include <utime.h>
#include <errno.h>
#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#else
@@ -62,9 +64,11 @@
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
+#define QT_POPEN_READ "rb"
#define QT_PCLOSE _pclose
#else
#define QT_POPEN popen
+#define QT_POPEN_READ "r"
#define QT_PCLOSE pclose
#endif
@@ -75,9 +79,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,
@@ -99,15 +104,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 },
@@ -116,6 +126,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 },
@@ -140,6 +151,7 @@ void QMakeEvaluator::initFunctionStatics()
{ "shell_quote", E_SHELL_QUOTE },
{ "getenv", E_GETENV },
};
+ statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0])));
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func);
@@ -179,16 +191,59 @@ void QMakeEvaluator::initFunctionStatics()
{ "touch", T_TOUCH },
{ "cache", T_CACHE },
};
+ statics.functions.reserve((int)(sizeof(testInits)/sizeof(testInits[0])));
for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
statics.functions.insert(ProKey(testInits[i].name), testInits[i].func);
}
-static bool isTrue(const ProString &_str, QString &tmp)
+static bool isTrue(const ProString &str)
{
- const QString &str = _str.toQString(tmp);
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()
{
@@ -285,19 +340,26 @@ static void insertJsonKeyValue(const QString &key, const QStringList &values, Pr
static void addJsonArray(const QJsonArray &array, const QString &keyPrefix, ProValueMap *map)
{
QStringList keys;
- for (int i = 0; i < array.count(); ++i) {
- keys.append(QString::number(i));
- addJsonValue(array.at(i), keyPrefix + QString::number(i), map);
+ const int size = array.count();
+ keys.reserve(size);
+ for (int i = 0; i < size; ++i) {
+ const QString number = QString::number(i);
+ keys.append(number);
+ addJsonValue(array.at(i), keyPrefix + number, map);
}
insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), keys, map);
}
static void addJsonObject(const QJsonObject &object, const QString &keyPrefix, ProValueMap *map)
{
- foreach (const QString &key, object.keys())
- addJsonValue(object.value(key), keyPrefix + key, map);
-
- insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), object.keys(), map);
+ QStringList keys;
+ keys.reserve(object.size());
+ for (auto it = object.begin(), end = object.end(); it != end; ++it) {
+ const QString key = it.key();
+ keys.append(key);
+ addJsonValue(it.value(), keyPrefix + key, map);
+ }
+ insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), keys, map);
}
static void addJsonValue(const QJsonValue &value, const QString &keyPrefix, ProValueMap *map)
@@ -323,11 +385,16 @@ static void addJsonValue(const QJsonValue &value, const QString &keyPrefix, ProV
}
}
-static QMakeEvaluator::VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value)
+QMakeEvaluator::VisitReturn QMakeEvaluator::parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value)
{
- QJsonDocument document = QJsonDocument::fromJson(json);
- if (document.isNull())
+ QJsonParseError error;
+ QJsonDocument document = QJsonDocument::fromJson(json, &error);
+ if (document.isNull()) {
+ if (error.error != QJsonParseError::NoError)
+ evalError(fL1S("Error parsing json at offset %1: %2")
+ .arg(error.offset).arg(error.errorString()));
return QMakeEvaluator::ReturnFalse;
+ }
QString currentKey = into + QLatin1Char('.');
@@ -344,10 +411,10 @@ static QMakeEvaluator::VisitReturn parseJsonInto(const QByteArray &json, const Q
QMakeEvaluator::VisitReturn
QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
- const QString &contents)
+ bool exe, const QString &contents)
{
QString errStr;
- if (!m_vfs->writeFile(fn, mode, contents, &errStr)) {
+ if (!m_vfs->writeFile(fn, mode, exe, contents, &errStr)) {
evalError(fL1S("Cannot write %1file %2: %3")
.arg(ctx, QDir::toNativeSeparators(fn), errStr));
return ReturnFalse;
@@ -401,7 +468,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const
#else
if (FILE *proc = QT_POPEN(QString(QLatin1String("cd ")
+ IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
- + QLatin1String(" && ") + args).toLocal8Bit().constData(), "r")) {
+ + QLatin1String(" && ") + args).toLocal8Bit().constData(), QT_POPEN_READ)) {
while (!feof(proc)) {
char buff[10 * 1024];
int read_in = int(fread(buff, 1, sizeof(buff), proc));
@@ -411,6 +478,9 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const
}
QT_PCLOSE(proc);
}
+# ifdef Q_OS_WIN
+ out.replace("\r\n", "\n");
+# endif
#endif
return out;
}
@@ -421,11 +491,11 @@ void QMakeEvaluator::populateDeps(
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
QMultiMap<int, ProString> &rootSet) const
{
- foreach (const ProString &item, deps)
+ for (const ProString &item : deps)
if (!dependencies.contains(item.toKey())) {
QSet<ProKey> &dset = dependencies[item.toKey()]; // Always create entry
ProStringList depends;
- foreach (const ProString &suffix, suffixes)
+ for (const ProString &suffix : suffixes)
depends += values(ProKey(prefix + item + suffix));
if (depends.isEmpty()) {
rootSet.insert(first(ProKey(prefix + item + priosfx)).toInt(), item);
@@ -462,9 +532,9 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
} else {
var = args[0];
sep = args.at(1).toQString();
- beg = args.at(2).toQString(m_tmp2).toInt();
+ beg = args.at(2).toInt();
if (args.count() == 4)
- end = args.at(3).toQString(m_tmp2).toInt();
+ end = args.at(3).toInt();
}
} else {
if (args.count() != 1) {
@@ -480,14 +550,15 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
}
}
if (!var.isEmpty()) {
+ const auto strings = values(map(var));
if (regexp) {
QRegExp sepRx(sep);
- foreach (const ProString &str, values(map(var))) {
+ for (const ProString &str : strings) {
const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end);
ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
}
} else {
- foreach (const ProString &str, values(map(var))) {
+ for (const ProString &str : strings) {
const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
}
@@ -516,7 +587,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
bool leftalign = false;
enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
if (args.count() >= 2) {
- foreach (const ProString &opt, 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();
@@ -544,7 +616,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
break;
}
bool ok;
- qlonglong num = m_tmp3.toLongLong(&ok, ibase);
+ 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));
@@ -575,14 +647,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;
+ foreach (const ProString &arg, 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)
@@ -590,7 +684,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
const ProStringList &var = values(map(args.at(0)));
if (!var.isEmpty()) {
const ProFile *src = currentProFile();
- foreach (const ProString &v, var)
+ for (const ProString &v : var)
if (const ProFile *s = v.sourceFile()) {
src = s;
break;
@@ -605,56 +699,49 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
evalError(fL1S("split(var, sep) requires one or two arguments."));
} else {
const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
- foreach (const ProString &var, values(map(args.at(0))))
- foreach (const QString &splt, var.toQString(m_tmp2).split(sep))
+ const auto vars = values(map(args.at(0)));
+ for (const ProString &var : vars) {
+ const auto splits = var.toQString(m_tmp2).split(sep);
+ for (const QString &splt : splits)
ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt).setSource(var));
+ }
}
break;
case E_MEMBER:
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 QString &start_str = args.at(1).toQString(m_tmp1);
- 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));
+ 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).toQString(m_tmp1).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;
@@ -672,12 +759,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."));
@@ -707,7 +814,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");
}
@@ -738,8 +846,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++);
ret = ProStringList(ProString(tmp));
ProStringList lst;
- foreach (const ProString &arg, args)
- lst += split_value_list(arg.toQString(m_tmp1), arg.sourceFile()); // Relies on deep copy
+ for (const ProString &arg : args)
+ lst += split_value_list(arg.toQStringRef(), arg.sourceFile()); // Relies on deep copy
m_valuemapStack.top()[ret.at(0).toKey()] = lst;
break; }
case E_FIND:
@@ -748,7 +856,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
} else {
QRegExp regx(args.at(1).toQString());
int t = 0;
- foreach (const ProString &val, values(map(args.at(0)))) {
+ const auto vals = values(map(args.at(0)));
+ for (const ProString &val : vals) {
if (regx.indexIn(val.toQString(m_tmp[t])) != -1)
ret += val;
t ^= 1;
@@ -785,7 +894,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));
}
}
}
@@ -799,6 +908,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."));
@@ -857,7 +974,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
} else {
const ProStringList &vals = values(args.at(0).toKey());
ret.reserve(vals.size());
- foreach (const ProString &str, vals)
+ for (const ProString &str : vals)
ret += ProString(quoteValue(str));
}
break;
@@ -882,7 +999,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
} else {
bool recursive = false;
if (args.count() == 2)
- recursive = isTrue(args.at(1), m_tmp2);
+ recursive = isTrue(args.at(1));
QStringList dirs;
QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1))
.replace(QLatin1Char('\\'), QLatin1Char('/'));
@@ -934,7 +1051,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; }
@@ -945,7 +1063,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
} else {
const QRegExp before(args.at(1).toQString());
const QString &after(args.at(2).toQString(m_tmp2));
- foreach (const ProString &val, values(map(args.at(0)))) {
+ const auto vals = values(map(args.at(0)));
+ for (const ProString &val : vals) {
QString rstr = val.toQString(m_tmp1);
QString copy = rstr; // Force a detach on modify
rstr.replace(before, after);
@@ -967,7 +1086,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();
@@ -1010,7 +1129,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
QString rstr = QDir::cleanPath(
QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory())
.absoluteFilePath(args.at(0).toQString(m_tmp1)));
- ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
+ ret << (rstr.isSharedWith(m_tmp1)
+ ? args.at(0)
+ : args.count() > 1 && rstr.isSharedWith(m_tmp2)
+ ? args.at(1)
+ : ProString(rstr).setSource(args.at(0)));
}
break;
case E_RELATIVE_PATH:
@@ -1174,7 +1297,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
regx.setPattern(copy);
}
int t = 0;
- foreach (const ProString &s, vars.value(map(args.at(1)))) {
+ const auto strings = vars.value(map(args.at(1)));
+ for (const ProString &s : strings) {
if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry)
return ReturnTrue;
t ^= 1;
@@ -1183,12 +1307,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
case T_REQUIRES:
#ifdef PROEVALUATOR_FULL
- checkRequirements(args);
+ if (checkRequirements(args) == ReturnError)
+ return ReturnError;
#endif
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);
@@ -1204,8 +1330,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("if(condition) requires one argument."));
return ReturnFalse;
}
- return returnBool(evaluateConditional(args.at(0).toQString(),
- m_current.pro->fileName(), m_current.line));
+ return evaluateConditional(args.at(0).toQStringRef(),
+ m_current.pro->fileName(), m_current.line);
}
case T_CONFIG: {
if (args.count() < 1 || args.count() > 2) {
@@ -1268,7 +1394,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
}
int cnt = values(map(args.at(0))).count();
- int val = args.at(1).toQString(m_tmp1).toInt();
+ int val = args.at(1).toInt();
if (args.count() == 3) {
const ProString &comp = args.at(2);
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
@@ -1377,7 +1503,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
flags = LoadSilent;
if (args.count() >= 2) {
parseInto = args.at(1).toQString(m_tmp2);
- if (args.count() >= 3 && isTrue(args.at(2), m_tmp3))
+ if (args.count() >= 3 && isTrue(args.at(2)))
flags = LoadSilent;
}
QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
@@ -1415,7 +1541,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
case T_LOAD: {
bool ignore_error = false;
if (args.count() == 2) {
- ignore_error = isTrue(args.at(1), m_tmp2);
+ ignore_error = isTrue(args.at(1));
} else if (args.count() != 1) {
evalError(fL1S("load(feature) requires one or two arguments."));
return ReturnFalse;
@@ -1480,9 +1606,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
runProcess(&proc, args.at(0).toQString(m_tmp2));
return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0);
#else
- return returnBool(system((QLatin1String("cd ")
- + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
- + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0);
+ int ec = system((QLatin1String("cd ")
+ + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
+ + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData());
+# ifdef Q_OS_UNIX
+ if (ec != -1 && WIFSIGNALED(ec) && (WTERMSIG(ec) == SIGQUIT || WTERMSIG(ec) == SIGINT))
+ raise(WTERMSIG(ec));
+# endif
+ return returnBool(ec == 0);
#endif
#else
return ReturnTrue;
@@ -1533,22 +1664,34 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
case T_WRITE_FILE: {
if (args.count() > 3) {
- evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments."));
+ evalError(fL1S("write_file(name, [content var, [append] [exe]]) requires one to three arguments."));
return ReturnFalse;
}
QIODevice::OpenMode mode = QIODevice::Truncate;
+ bool exe = false;
QString contents;
if (args.count() >= 2) {
const ProStringList &vals = values(args.at(1).toKey());
if (!vals.isEmpty())
contents = vals.join(QLatin1Char('\n')) + QLatin1Char('\n');
- if (args.count() >= 3)
- if (!args.at(2).toQString(m_tmp1).compare(fL1S("append"), Qt::CaseInsensitive))
- mode = QIODevice::Append;
+ if (args.count() >= 3) {
+ const auto opts = split_value_list(args.at(2).toQStringRef());
+ for (const ProString &opt : opts) {
+ opt.toQString(m_tmp3);
+ if (m_tmp3 == QLatin1String("append")) {
+ mode = QIODevice::Append;
+ } else if (m_tmp3 == QLatin1String("exe")) {
+ exe = true;
+ } else {
+ evalError(fL1S("write_file(): invalid flag %1.").arg(m_tmp3));
+ return ReturnFalse;
+ }
+ }
+ }
}
QString path = resolvePath(args.at(0).toQString(m_tmp1));
path.detach(); // make sure to not leak m_tmp1 into the map of written files.
- return writeFile(QString(), path, mode, contents);
+ return writeFile(QString(), path, mode, exe, contents);
}
case T_TOUCH: {
if (args.count() != 2) {
@@ -1605,7 +1748,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
ProKey srcvar;
if (args.count() >= 2) {
- foreach (const ProString &opt, 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")) {
persist = false;
@@ -1723,7 +1867,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
varstr += QLatin1Char(' ');
varstr += quoteValue(diffval.at(0));
} else if (!diffval.isEmpty()) {
- foreach (const ProString &vval, diffval) {
+ for (const ProString &vval : diffval) {
varstr += QLatin1String(" \\\n ");
varstr += quoteValue(vval);
}
@@ -1759,7 +1903,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn);
}
}
- return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr);
+ return writeFile(fL1S("cache "), fn, QIODevice::Append, false, varstr);
}
default:
evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1)));
diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp
index dafb56244a..7d43610a31 100644
--- a/src/shared/proparser/qmakeevaluator.cpp
+++ b/src/shared/proparser/qmakeevaluator.cpp
@@ -183,6 +183,7 @@ void QMakeEvaluator::initStatics()
{ "IN_PWD", "PWD" },
{ "DEPLOYMENT", "INSTALLS" }
};
+ statics.varMap.reserve((int)(sizeof(mapInits)/sizeof(mapInits[0])));
for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname));
}
@@ -266,7 +267,7 @@ void QMakeEvaluator::skipHashStr(const ushort *&tokPtr)
// FIXME: this should not build new strings for direct sections.
// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
-ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFile *source)
+ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, const ProFile *source)
{
QString build;
ProStringList ret;
@@ -401,7 +402,7 @@ static ALWAYS_INLINE void addStrList(
}
}
-void QMakeEvaluator::evaluateExpression(
+QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpression(
const ushort *&tokPtr, ProStringList *ret, bool joined)
{
debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression");
@@ -451,12 +452,15 @@ void QMakeEvaluator::evaluateExpression(
case TokFuncName: {
const ProKey &func = pro->getHashStr(tokPtr);
debugMsg(2, "function %s", dbgKey(func));
- addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
+ ProStringList val;
+ if (evaluateExpandFunction(func, tokPtr, &val) == ReturnError)
+ return ReturnError;
+ addStrList(val, tok, ret, pending, joined);
break; }
default:
debugMsg(2, "evaluated expression => %s", dbgStrList(*ret));
tokPtr--;
- return;
+ return ReturnTrue;
}
}
}
@@ -528,7 +532,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
case TokAppendUnique:
case TokRemove:
case TokReplace:
- visitProVariable(tok, curr, tokPtr);
+ ret = visitProVariable(tok, curr, tokPtr);
+ if (ret == ReturnError)
+ break;
curr.clear();
continue;
case TokBranch:
@@ -688,9 +694,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
continue;
default: {
const ushort *oTokPtr = --tokPtr;
- evaluateExpression(tokPtr, &curr, false);
- if (tokPtr != oTokPtr)
- continue;
+ ret = evaluateExpression(tokPtr, &curr, false);
+ if (ret == ReturnError || tokPtr != oTokPtr)
+ break;
}
Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
continue;
@@ -723,7 +729,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
int index = 0;
ProKey variable;
ProStringList oldVarVal;
- ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
+ ProStringList it_list_out;
+ if (expandVariableReferences(exprPtr, 0, &it_list_out, true) == ReturnError)
+ return ReturnError;
+ ProString it_list = it_list_out.at(0);
if (_variable.isEmpty()) {
if (it_list != statics.strever) {
evalError(fL1S("Invalid loop expression."));
@@ -752,12 +761,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
if (ok) {
int end = itl.mid(dotdot+2).toInt(&ok);
if (ok) {
- if (m_cumulative && qAbs(end - start) > 100) {
+ const int absDiff = qAbs(end - start);
+ if (m_cumulative && absDiff > 100) {
// Such a loop is unlikely to contribute something useful to the
// file collection, and may cause considerable delay.
traceMsg("skipping excessive loop in cumulative mode");
return ReturnFalse;
}
+ list.reserve(absDiff + 1);
if (start < end) {
for (int i = start; i <= end; i++)
list << ProString(QString::number(i));
@@ -820,7 +831,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
return ret;
}
-void QMakeEvaluator::visitProVariable(
+QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable(
ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{
int sizeHint = *tokPtr++;
@@ -829,24 +840,26 @@ void QMakeEvaluator::visitProVariable(
skipExpression(tokPtr);
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
- return;
+ return ReturnTrue;
}
const ProKey &varName = map(curr.first());
if (tok == TokReplace) { // ~=
// DEFINES ~= s/a/b/?[gqi]
- const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
+ ProStringList varVal;
+ if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError)
+ return ReturnError;
const QString &val = varVal.at(0).toQString(m_tmp1);
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
evalError(fL1S("The ~= operator can handle only the s/// function."));
- return;
+ return ReturnTrue;
}
QChar sep = val.at(1);
QStringList func = val.split(sep);
if (func.count() < 3 || func.count() > 4) {
evalError(fL1S("The s/// function expects 3 or 4 arguments."));
- return;
+ return ReturnTrue;
}
bool global = false, quote = false, case_sense = false;
@@ -867,7 +880,9 @@ void QMakeEvaluator::visitProVariable(
replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace));
} else {
- ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
+ ProStringList varVal;
+ if (expandVariableReferences(tokPtr, sizeHint, &varVal, false) == ReturnError)
+ return ReturnError;
switch (tok) {
default: // whatever - cannot happen
case TokAssign: // =
@@ -913,8 +928,10 @@ void QMakeEvaluator::visitProVariable(
}
#ifdef PROEVALUATOR_FULL
else if (varName == statics.strREQUIRES)
- checkRequirements(values(varName));
+ return checkRequirements(values(varName));
#endif
+
+ return ReturnTrue;
}
void QMakeEvaluator::setTemplate()
@@ -949,7 +966,7 @@ static ProString msvcBinDirToQMakeArch(QString subdir)
if (idx >= 0)
subdir.remove(0, idx + 1);
subdir = subdir.toLower();
- if (subdir == QStringLiteral("amd64"))
+ if (subdir == QLatin1String("amd64"))
return ProString("x86_64");
return ProString(subdir);
}
@@ -970,7 +987,8 @@ static ProString msvcArchitecture(const QString &vcInstallDir, const QString &pa
QString vcBinDir = vcInstallDir;
if (vcBinDir.endsWith(QLatin1Char('\\')))
vcBinDir.chop(1);
- foreach (const QString &dir, pathVar.split(QLatin1Char(';'))) {
+ const auto dirs = pathVar.split(QLatin1Char(';'));
+ for (const QString &dir : dirs) {
if (!dir.startsWith(vcBinDir, Qt::CaseInsensitive))
continue;
const ProString arch = msvcBinDirToQMakeArch(dir.mid(vcBinDir.length() + 1));
@@ -992,6 +1010,8 @@ void QMakeEvaluator::loadDefaults()
vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation);
if (!m_option->qmake_args.isEmpty())
vars[ProKey("QMAKE_ARGS")] = ProStringList(m_option->qmake_args);
+ if (!m_option->qtconf.isEmpty())
+ vars[ProKey("QMAKE_QTCONF")] = ProString(m_option->qtconf);
vars[ProKey("QMAKE_HOST.cpu_count")] = ProString(QString::number(idealThreadCount()));
#if defined(Q_OS_WIN32)
vars[ProKey("QMAKE_HOST.os")] << ProString("Windows");
@@ -1268,7 +1288,7 @@ void QMakeEvaluator::setupProject()
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
{
if (!cmds.isEmpty()) {
- ProFile *pro = m_parser->parsedProBlock(cmds, where, -1);
+ ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1);
if (pro->isOk()) {
m_locationStack.push(m_current);
visitProBlock(pro, pro->tokPtr());
@@ -1442,7 +1462,8 @@ void QMakeEvaluator::updateMkspecPaths()
QStringList ret;
const QString concat = QLatin1String("/mkspecs");
- foreach (const QString &it, m_option->getPathListEnv(QLatin1String("QMAKEPATH")))
+ const auto paths = m_option->getPathListEnv(QLatin1String("QMAKEPATH"));
+ for (const QString &it : paths)
ret << it + concat;
foreach (const QString &it, m_qmakepath)
@@ -1467,11 +1488,8 @@ void QMakeEvaluator::updateFeaturePaths()
QStringList feature_roots;
- foreach (const QString &f, m_option->getPathListEnv(QLatin1String("QMAKEFEATURES")))
- feature_roots += f;
-
+ feature_roots += m_option->getPathListEnv(QLatin1String("QMAKEFEATURES"));
feature_roots += m_qmakefeatures;
-
feature_roots += m_option->splitPathList(
m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString(m_mtmp));
@@ -1485,7 +1503,8 @@ void QMakeEvaluator::updateFeaturePaths()
feature_bases << m_sourceRoot;
}
- foreach (const QString &item, m_option->getPathListEnv(QLatin1String("QMAKEPATH")))
+ const auto items = m_option->getPathListEnv(QLatin1String("QMAKEPATH"));
+ for (const QString &item : items)
feature_bases << (item + mkspecs_concat);
foreach (const QString &item, m_qmakepath)
@@ -1511,7 +1530,8 @@ void QMakeEvaluator::updateFeaturePaths()
feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + mkspecs_concat);
foreach (const QString &fb, feature_bases) {
- foreach (const ProString &sfx, values(ProKey("QMAKE_PLATFORM")))
+ const auto sfxs = values(ProKey("QMAKE_PLATFORM"));
+ for (const ProString &sfx : sfxs)
feature_roots << (fb + features_concat + sfx + QLatin1Char('/'));
feature_roots << (fb + features_concat);
}
@@ -1584,7 +1604,8 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
// CONFIG variable
int t = 0;
- foreach (const ProString &configValue, values(statics.strCONFIG)) {
+ const auto configValues = values(statics.strCONFIG);
+ for (const ProString &configValue : configValues) {
if (re.exactMatch(configValue.toQString(m_tmp[t])))
return true;
t ^= 1;
@@ -1602,18 +1623,18 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
return false;
}
-ProStringList QMakeEvaluator::expandVariableReferences(
- const ushort *&tokPtr, int sizeHint, bool joined)
+QMakeEvaluator::VisitReturn QMakeEvaluator::expandVariableReferences(
+ const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined)
{
- ProStringList ret;
- ret.reserve(sizeHint);
+ ret->reserve(sizeHint);
forever {
- evaluateExpression(tokPtr, &ret, joined);
+ if (evaluateExpression(tokPtr, ret, joined) == ReturnError)
+ return ReturnError;
switch (*tokPtr) {
case TokValueTerminator:
case TokFuncTerminator:
tokPtr++;
- return ret;
+ return ReturnTrue;
case TokArgSeparator:
if (joined) {
tokPtr++;
@@ -1627,28 +1648,28 @@ ProStringList QMakeEvaluator::expandVariableReferences(
}
}
-QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr)
+QMakeEvaluator::VisitReturn QMakeEvaluator::prepareFunctionArgs(
+ const ushort *&tokPtr, QList<ProStringList> *ret)
{
- QList<ProStringList> args_list;
if (*tokPtr != TokFuncTerminator) {
for (;; tokPtr++) {
ProStringList arg;
- evaluateExpression(tokPtr, &arg, false);
- args_list << arg;
+ if (evaluateExpression(tokPtr, &arg, false) == ReturnError)
+ return ReturnError;
+ *ret << arg;
if (*tokPtr == TokFuncTerminator)
break;
Q_ASSERT(*tokPtr == TokArgSeparator);
}
}
tokPtr++;
- return args_list;
+ return ReturnTrue;
}
-ProStringList QMakeEvaluator::evaluateFunction(
- const ProFunctionDef &func, const QList<ProStringList> &argumentsList, VisitReturn *ok)
+QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction(
+ const ProFunctionDef &func, const QList<ProStringList> &argumentsList, ProStringList *ret)
{
VisitReturn vr;
- ProStringList ret;
if (m_valuemapStack.count() >= 100) {
evalError(fL1S("Ran into infinite recursion (depth > 100)."));
@@ -1667,25 +1688,22 @@ ProStringList QMakeEvaluator::evaluateFunction(
vr = visitProBlock(func.pro(), func.tokPtr());
if (vr == ReturnReturn)
vr = ReturnTrue;
- ret = m_returnValue;
+ if (vr == ReturnTrue)
+ *ret = m_returnValue;
m_returnValue.clear();
m_current = m_locationStack.pop();
m_valuemapStack.pop();
}
- if (ok)
- *ok = vr;
- if (vr == ReturnTrue)
- return ret;
- return ProStringList();
+ return vr;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
const ProFunctionDef &func, const QList<ProStringList> &argumentsList,
const ProString &function)
{
- VisitReturn vr;
- ProStringList ret = evaluateFunction(func, argumentsList, &vr);
+ ProStringList ret;
+ VisitReturn vr = evaluateFunction(func, argumentsList, &ret);
if (vr == ReturnTrue) {
if (ret.isEmpty())
return ReturnTrue;
@@ -1713,13 +1731,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
{
if (int func_t = statics.functions.value(func)) {
//why don't the builtin functions just use args_list? --Sam
- return evaluateBuiltinConditional(func_t, func, expandVariableReferences(tokPtr, 5, true));
+ ProStringList args;
+ if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
+ return ReturnError;
+ return evaluateBuiltinConditional(func_t, func, args);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.testFunctions.constFind(func);
if (it != m_functionDefs.testFunctions.constEnd()) {
- const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
+ QList<ProStringList> args;
+ if (prepareFunctionArgs(tokPtr, &args) == ReturnError)
+ return ReturnError;
traceMsg("calling %s(%s)", dbgKey(func), dbgStrListList(args));
return evaluateBoolFunction(*it, args, func);
}
@@ -1729,34 +1752,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
return ReturnFalse;
}
-ProStringList QMakeEvaluator::evaluateExpandFunction(
- const ProKey &func, const ushort *&tokPtr)
+QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction(
+ const ProKey &func, const ushort *&tokPtr, ProStringList *ret)
{
if (int func_t = statics.expands.value(func)) {
//why don't the builtin functions just use args_list? --Sam
- return evaluateBuiltinExpand(func_t, func, expandVariableReferences(tokPtr, 5, true));
+ ProStringList args;
+ if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
+ return ReturnError;
+ *ret = evaluateBuiltinExpand(func_t, func, args);
+ return ReturnTrue;
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.replaceFunctions.constFind(func);
if (it != m_functionDefs.replaceFunctions.constEnd()) {
- const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
+ QList<ProStringList> args;
+ if (prepareFunctionArgs(tokPtr, &args) == ReturnError)
+ return ReturnError;
traceMsg("calling $$%s(%s)", dbgKey(func), dbgStrListList(args));
- return evaluateFunction(*it, args, 0);
+ return evaluateFunction(*it, args, ret);
}
skipExpression(tokPtr);
evalError(fL1S("'%1' is not a recognized replace function.").arg(func.toQString(m_tmp1)));
- return ProStringList();
+ return ReturnFalse;
}
-bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line)
+QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional(
+ const QStringRef &cond, const QString &where, int line)
{
- bool ret = false;
+ VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
if (pro->isOk()) {
m_locationStack.push(m_current);
- ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue;
+ ret = visitProBlock(pro, pro->tokPtr());
m_current = m_locationStack.pop();
}
pro->deref();
@@ -1764,28 +1794,49 @@ bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &whe
}
#ifdef PROEVALUATOR_FULL
-void QMakeEvaluator::checkRequirements(const ProStringList &deps)
+QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringList &deps)
{
ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS"));
- foreach (const ProString &dep, deps)
- if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line))
+ for (const ProString &dep : deps) {
+ VisitReturn vr = evaluateConditional(dep.toQStringRef(), m_current.pro->fileName(), m_current.line);
+ if (vr == ReturnError)
+ return ReturnError;
+ if (vr != ReturnTrue)
failed << dep;
+ }
+ return ReturnTrue;
}
#endif
+static bool isFunctParam(const ProKey &variableName)
+{
+ const int len = variableName.size();
+ const QChar *data = variableName.constData();
+ for (int i = 0; i < len; i++) {
+ ushort c = data[i].unicode();
+ if (c < '0' || c > '9')
+ return false;
+ }
+ return true;
+}
+
ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap::Iterator *rit)
{
ProValueMapStack::Iterator vmi = m_valuemapStack.end();
- do {
+ for (bool first = true; ; first = false) {
--vmi;
ProValueMap::Iterator it = (*vmi).find(variableName);
if (it != (*vmi).end()) {
if (it->constBegin() == statics.fakeValue.constBegin())
- return 0;
+ break;
*rit = it;
return &(*vmi);
}
- } while (vmi != m_valuemapStack.begin());
+ if (vmi == m_valuemapStack.begin())
+ break;
+ if (first && isFunctParam(variableName))
+ break;
+ }
return 0;
}
@@ -1797,18 +1848,20 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName)
it->clear();
return *it;
}
- ProValueMapStack::Iterator vmi = m_valuemapStack.end();
- if (--vmi != m_valuemapStack.begin()) {
- do {
- --vmi;
- ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
- if (it != (*vmi).constEnd()) {
- ProStringList &ret = m_valuemapStack.top()[variableName];
- if (it->constBegin() != statics.fakeValue.constBegin())
- ret = *it;
- return ret;
- }
- } while (vmi != m_valuemapStack.begin());
+ if (!isFunctParam(variableName)) {
+ ProValueMapStack::Iterator vmi = m_valuemapStack.end();
+ if (--vmi != m_valuemapStack.begin()) {
+ do {
+ --vmi;
+ ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
+ if (it != (*vmi).constEnd()) {
+ ProStringList &ret = m_valuemapStack.top()[variableName];
+ if (it->constBegin() != statics.fakeValue.constBegin())
+ ret = *it;
+ return ret;
+ }
+ } while (vmi != m_valuemapStack.begin());
+ }
}
return m_valuemapStack.top()[variableName];
}
@@ -1816,7 +1869,7 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName)
ProStringList QMakeEvaluator::values(const ProKey &variableName) const
{
ProValueMapStack::ConstIterator vmi = m_valuemapStack.constEnd();
- do {
+ for (bool first = true; ; first = false) {
--vmi;
ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
if (it != (*vmi).constEnd()) {
@@ -1824,7 +1877,11 @@ ProStringList QMakeEvaluator::values(const ProKey &variableName) const
break;
return *it;
}
- } while (vmi != m_valuemapStack.constBegin());
+ if (vmi == m_valuemapStack.constBegin())
+ break;
+ if (first && isFunctParam(variableName))
+ break;
+ }
return ProStringList();
}
@@ -1864,9 +1921,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileChecked(
{
if (fileName.isEmpty())
return ReturnFalse;
- QMakeEvaluator *ref = this;
+ const QMakeEvaluator *ref = this;
do {
- foreach (const ProFile *pf, ref->m_profileStack)
+ for (const ProFile *pf : ref->m_profileStack)
if (pf->fileName() == fileName) {
evalError(fL1S("Circular inclusion of %1.").arg(fileName));
return ReturnFalse;
@@ -1967,7 +2024,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto(
*values = visitor.m_valuemapStack.top();
ProKey qiif("QMAKE_INTERNAL_INCLUDED_FILES");
ProStringList &iif = m_valuemapStack.first()[qiif];
- foreach (const ProString &ifn, values->value(qiif))
+ const auto ifns = values->value(qiif);
+ for (const ProString &ifn : ifns)
if (!iif.contains(ifn))
iif << ifn;
return ReturnTrue;
@@ -2066,7 +2124,7 @@ QString QMakeEvaluator::formatValueList(const ProStringList &vals, bool commas)
{
QString ret;
- foreach (const ProString &str, vals) {
+ for (const ProString &str : vals) {
if (!ret.isEmpty()) {
if (commas)
ret += QLatin1Char(',');
@@ -2081,7 +2139,7 @@ QString QMakeEvaluator::formatValueListList(const QList<ProStringList> &lists)
{
QString ret;
- foreach (const ProStringList &list, lists) {
+ for (const ProStringList &list : lists) {
if (!ret.isEmpty())
ret += QLatin1String(", ");
ret += formatValueList(list);
diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h
index 7bb673cb89..e9cff77c67 100644
--- a/src/shared/proparser/qmakeevaluator.h
+++ b/src/shared/proparser/qmakeevaluator.h
@@ -144,7 +144,7 @@ public:
{ return b ? ReturnTrue : ReturnFalse; }
static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
- void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
+ VisitReturn evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
void skipExpression(const ushort *&tokPtr);
@@ -164,7 +164,7 @@ public:
VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr,
const ushort *tokPtr);
void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr);
- void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
+ VisitReturn visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var.toKey()); }
const ProKey &map(const ProKey &var);
@@ -172,9 +172,8 @@ public:
void setTemplate();
- ProStringList split_value_list(const QString &vals, const ProFile *source = 0);
- ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
- ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
+ ProStringList split_value_list(const QStringRef &vals, const ProFile *source = 0);
+ VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined);
QString currentFileName() const;
QString currentDirectory() const;
@@ -199,22 +198,22 @@ public:
void deprecationWarning(const QString &msg) const
{ message(QMakeHandler::EvalWarnDeprecated, msg); }
- QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
- ProStringList evaluateFunction(const ProFunctionDef &func,
- const QList<ProStringList> &argumentsList, VisitReturn *ok);
+ VisitReturn prepareFunctionArgs(const ushort *&tokPtr, QList<ProStringList> *ret);
+ VisitReturn evaluateFunction(const ProFunctionDef &func,
+ const QList<ProStringList> &argumentsList, ProStringList *ret);
VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList,
const ProString &function);
- ProStringList evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr);
+ VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args);
VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
- bool evaluateConditional(const QString &cond, const QString &where, int line = -1);
+ VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL
- void checkRequirements(const ProStringList &deps);
+ VisitReturn checkRequirements(const ProStringList &deps);
#endif
void updateMkspecPaths();
@@ -228,8 +227,12 @@ public:
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
QMultiMap<int, ProString> &rootSet) const;
+ bool getMemberArgs(const ProKey &name, int srclen, const ProStringList &args,
+ int *start, int *end);
+ VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value);
+
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
- const QString &contents);
+ bool exe, const QString &contents);
#ifndef QT_BOOTSTRAPPED
void runProcess(QProcess *proc, const QString &command) const;
#endif
diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp
index 2231391f9a..f3600b33e0 100644
--- a/src/shared/proparser/qmakeglobals.cpp
+++ b/src/shared/proparser/qmakeglobals.cpp
@@ -56,9 +56,11 @@
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
+#define QT_POPEN_READ "rb"
#define QT_PCLOSE _pclose
#else
#define QT_POPEN popen
+#define QT_POPEN_READ "r"
#define QT_PCLOSE pclose
#endif
@@ -101,7 +103,7 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s
QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
QMakeCmdLineParserState &state, QStringList &args, int *pos)
{
- enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache } argState = ArgNone;
+ enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache, ArgQtConf } argState = ArgNone;
for (; *pos < args.count(); (*pos)++) {
QString arg = args.at(*pos);
switch (argState) {
@@ -126,8 +128,16 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
case ArgCache:
cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
break;
+ case ArgQtConf:
+ qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
+ break;
default:
if (arg.startsWith(QLatin1Char('-'))) {
+ if (arg == QLatin1String("--")) {
+ state.extraargs = args.mid(*pos + 1);
+ *pos = args.size();
+ return ArgumentsOk;
+ }
if (arg == QLatin1String("-after"))
state.after = true;
else if (arg == QLatin1String("-config"))
@@ -136,6 +146,8 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
do_cache = false;
else if (arg == QLatin1String("-cache"))
argState = ArgCache;
+ else if (arg == QLatin1String("-qtconf"))
+ argState = ArgQtConf;
else if (arg == QLatin1String("-platform") || arg == QLatin1String("-spec"))
argState = ArgSpec;
else if (arg == QLatin1String("-xplatform") || arg == QLatin1String("-xspec"))
@@ -171,6 +183,12 @@ void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state)
{
if (!state.preconfigs.isEmpty())
state.precmds << (fL1S("CONFIG += ") + state.preconfigs.join(QLatin1Char(' ')));
+ if (!state.extraargs.isEmpty()) {
+ QString extra = fL1S("QMAKE_EXTRA_ARGS =");
+ foreach (const QString &ea, state.extraargs)
+ extra += QLatin1Char(' ') + QMakeEvaluator::quoteValue(ProString(ea));
+ state.precmds << extra;
+ }
precmds = state.precmds.join(QLatin1Char('\n'));
if (!state.postconfigs.isEmpty())
state.postcmds << (fL1S("CONFIG += ") + state.postconfigs.join(QLatin1Char(' ')));
@@ -240,9 +258,9 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const
QStringList ret;
if (!val.isEmpty()) {
QDir bdir;
- QStringList vals = val.split(dirlist_sep);
+ const QStringList vals = val.split(dirlist_sep);
ret.reserve(vals.length());
- foreach (const QString &it, vals)
+ for (const QString &it : vals)
ret << QDir::cleanPath(bdir.absoluteFilePath(it));
}
return ret;
@@ -299,14 +317,15 @@ bool QMakeGlobals::initProperties()
data = proc.readAll();
#else
if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation)
- + QLatin1String(" -query")).toLocal8Bit(), "r")) {
+ + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) {
char buff[1024];
while (!feof(proc))
data.append(buff, int(fread(buff, 1, 1023, proc)));
QT_PCLOSE(proc);
}
#endif
- foreach (QByteArray line, data.split('\n')) {
+ const auto lines = data.split('\n');
+ for (QByteArray line : lines) {
int off = line.indexOf(':');
if (off < 0) // huh?
continue;
diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h
index 33a5bdb831..9942113681 100644
--- a/src/shared/proparser/qmakeglobals.h
+++ b/src/shared/proparser/qmakeglobals.h
@@ -81,7 +81,7 @@ class QMAKE_EXPORT QMakeCmdLineParserState
public:
QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), after(false) {}
QString pwd;
- QStringList precmds, preconfigs, postcmds, postconfigs;
+ QStringList precmds, preconfigs, postcmds, postconfigs, extraargs;
bool after;
void flush() { after = false; }
@@ -103,6 +103,7 @@ public:
QString qmake_abslocation;
QStringList qmake_args;
+ QString qtconf;
QString qmakespec, xqmakespec;
QString user_template, user_template_prefix;
QString precmds, postcmds;
diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp
index 59dc289548..7751265e91 100644
--- a/src/shared/proparser/qmakeparser.cpp
+++ b/src/shared/proparser/qmakeparser.cpp
@@ -221,7 +221,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
}
ProFile *QMakeParser::parsedProBlock(
- const QString &contents, const QString &name, int line, SubGrammar grammar)
+ const QStringRef &contents, const QString &name, int line, SubGrammar grammar)
{
ProFile *pro = new ProFile(name);
read(pro, contents, line, grammar);
@@ -244,7 +244,7 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags)
fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr));
return false;
}
- read(pro, content, 1, FullGrammar);
+ read(pro, QStringRef(&content), 1, FullGrammar);
return true;
}
@@ -272,7 +272,8 @@ void QMakeParser::putHashStr(ushort *&pTokPtr, const ushort *buf, uint len)
*tokPtr++ = (ushort)hash;
*tokPtr++ = (ushort)(hash >> 16);
*tokPtr++ = (ushort)len;
- memcpy(tokPtr, buf, len * 2);
+ if (len) // buf may be nullptr; don't pass that to memcpy (-> undefined behavior)
+ memcpy(tokPtr, buf, len * 2);
pTokPtr = tokPtr + len;
}
@@ -285,7 +286,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len)
buf[-2] = (ushort)(hash >> 16);
}
-void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar)
+void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar)
{
m_proFile = pro;
m_lineNo = line;
@@ -295,27 +296,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
// Worst-case size calculations:
// - line marker adds 1 (2-nl) to 1st token of each line
// - empty assignment "A=":2 =>
- // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 0(1) +
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) +
// TokValueTerminator(1) == 8 (9)
// - non-empty assignment "A=B C":5 =>
- // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 2(1) +
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) +
// TokLiteral(1) + len(1) + "B"(1) +
// TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 14 (15)
// - variable expansion: "$$f":3 =>
// TokVariable(1) + hash(2) + len(1) + "f"(1) = 5
// - function expansion: "$$f()":5 =>
// TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6
+ // - test literal: "X":1 =>
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) = 6 (7)
// - scope: "X:":2 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) +
- // TokBranch(1) + len(2) + ... + len(2) + ... == 10
- // - test: "X():":4 =>
+ // TokBranch(1) + len(2) + ... + len(2) + ... == 11 (12)
+ // - test call: "X():":4 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) +
- // TokBranch(1) + len(2) + ... + len(2) + ... == 11
+ // TokBranch(1) + len(2) + ... + len(2) + ... == 12 (13)
// - "for(A,B):":9 =>
// TokForLoop(1) + hash(2) + len(1) + "A"(1) +
// len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) +
// len(2) + ... + TokTerminator(1) == 14 (15)
- tokBuff.reserve((in.size() + 1) * 5);
+ // One extra for possibly missing trailing newline.
+ tokBuff.reserve((in.size() + 1) * 7);
ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position
// Expression precompiler buffer.
@@ -330,8 +334,8 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
QStack<ParseCtx> xprStack;
xprStack.reserve(10);
- // We rely on QStrings being null-terminated, so don't maintain a global end pointer.
const ushort *cur = (const ushort *)in.unicode();
+ const ushort *inend = cur + in.length();
m_canElse = false;
freshLine:
m_state = StNew;
@@ -414,7 +418,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
int indent;
if (context == CtxPureValue) {
- end = (const ushort *)in.unicode() + in.length();
+ end = inend;
cptr = 0;
lineCont = false;
indent = 0; // just gcc being stupid
@@ -426,24 +430,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
// First, skip leading whitespace
for (indent = 0; ; ++cur, ++indent) {
+ if (cur == inend) {
+ cur = 0;
+ goto flushLine;
+ }
c = *cur;
if (c == '\n') {
++cur;
goto flushLine;
- } else if (!c) {
- cur = 0;
- goto flushLine;
- } else if (c != ' ' && c != '\t' && c != '\r') {
- break;
}
+ if (c != ' ' && c != '\t' && c != '\r')
+ break;
}
// Then strip comments. Yep - no escaping is possible.
for (cptr = cur;; ++cptr) {
+ if (cptr == inend) {
+ end = cptr;
+ break;
+ }
c = *cptr;
if (c == '#') {
- for (end = cptr; (c = *++cptr);) {
- if (c == '\n') {
+ end = cptr;
+ while (++cptr < inend) {
+ if (*cptr == '\n') {
++cptr;
break;
}
@@ -456,10 +466,6 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
}
break;
}
- if (!c) {
- end = cptr;
- break;
- }
if (c == '\n') {
end = cptr++;
break;
@@ -1211,7 +1217,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
ushort **buf, QString *xprBuff,
ushort **tokPtr, QString *tokBuff,
- const ushort *cur, const QString &in)
+ const ushort *cur, const QStringRef &in)
{
QString out;
m_tmp.setRawData((const QChar *)xprPtr, tlen);
diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h
index d44523d024..d370d17cbb 100644
--- a/src/shared/proparser/qmakeparser.h
+++ b/src/shared/proparser/qmakeparser.h
@@ -83,7 +83,7 @@ public:
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
// fileName is expected to be absolute and cleanPath()ed.
ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault);
- ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0,
+ ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0,
SubGrammar grammar = FullGrammar);
void discardFileFromCache(const QString &fileName);
@@ -126,7 +126,7 @@ private:
};
bool read(ProFile *pro, ParseFlags flags);
- void read(ProFile *pro, const QString &content, int line, SubGrammar grammar);
+ void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar);
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
@@ -137,7 +137,7 @@ private:
ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
ushort **buf, QString *xprBuff,
ushort **tokPtr, QString *tokBuff,
- const ushort *cur, const QString &in);
+ const ushort *cur, const QStringRef &in);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void warnOperator(const char *msg);
diff --git a/src/shared/proparser/qmakevfs.cpp b/src/shared/proparser/qmakevfs.cpp
index 7eb35bebca..0231fa9a46 100644
--- a/src/shared/proparser/qmakevfs.cpp
+++ b/src/shared/proparser/qmakevfs.cpp
@@ -44,8 +44,8 @@ QMakeVfs::QMakeVfs()
{
}
-bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents,
- QString *errStr)
+bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe,
+ const QString &contents, QString *errStr)
{
#ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE
@@ -57,6 +57,7 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr
else
*cont = contents;
Q_UNUSED(errStr)
+ Q_UNUSED(exe)
return true;
#else
QFileInfo qfi(fn);
@@ -67,8 +68,16 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr
QByteArray bytes = contents.toLocal8Bit();
QFile cfile(fn);
if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- if (cfile.readAll() == bytes)
+ if (cfile.readAll() == bytes) {
+ if (exe) {
+ cfile.setPermissions(cfile.permissions()
+ | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
+ } else {
+ cfile.setPermissions(cfile.permissions()
+ & ~(QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther));
+ }
return true;
+ }
cfile.close();
}
if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
@@ -81,6 +90,9 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr
*errStr = cfile.errorString();
return false;
}
+ if (exe)
+ cfile.setPermissions(cfile.permissions()
+ | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
return true;
#endif
}
diff --git a/src/shared/proparser/qmakevfs.h b/src/shared/proparser/qmakevfs.h
index 8c387fe29d..3ffe67c1ba 100644
--- a/src/shared/proparser/qmakevfs.h
+++ b/src/shared/proparser/qmakevfs.h
@@ -43,7 +43,7 @@ class QMAKE_EXPORT QMakeVfs
public:
QMakeVfs();
- bool writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, QString *errStr);
+ bool writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe, const QString &contents, QString *errStr);
bool readFile(const QString &fn, QString *contents, QString *errStr);
bool exists(const QString &fn);