diff options
author | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2016-08-05 11:59:28 +0300 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2016-08-05 11:40:07 +0200 |
commit | 1853f01a5b0955a28e9c321cd36f45d5f17651bf (patch) | |
tree | 5d357de37f3c2ef93e38bbc79ef96b6f8982cd6f /src/shared/proparser | |
parent | 713bc04ad4560123d97bb469d109a0885cf36373 (diff) | |
parent | d004203b13fa17d1258ee62d5eb4f681adf32398 (diff) |
Merge remote-tracking branch 'origin/4.1'
Change-Id: Ia442f30f387fe9292217582260bbe79e54608810
Diffstat (limited to 'src/shared/proparser')
-rw-r--r-- | src/shared/proparser/proitems.cpp | 15 | ||||
-rw-r--r-- | src/shared/proparser/proitems.h | 21 | ||||
-rw-r--r-- | src/shared/proparser/prowriter.cpp | 2 | ||||
-rw-r--r-- | src/shared/proparser/qmakebuiltins.cpp | 340 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.cpp | 230 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.h | 27 | ||||
-rw-r--r-- | src/shared/proparser/qmakeglobals.cpp | 29 | ||||
-rw-r--r-- | src/shared/proparser/qmakeglobals.h | 3 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.cpp | 54 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.h | 6 | ||||
-rw-r--r-- | src/shared/proparser/qmakevfs.cpp | 18 | ||||
-rw-r--r-- | src/shared/proparser/qmakevfs.h | 2 |
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); |