qmake: make access to raw data temporaries safe
make sure the access is properly scoped and does not recurse. Change-Id: Iaa345cd2771811281b9ed6f634c70235a78c3c33 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
parent
d68016c739
commit
d550ba4e96
@ -229,6 +229,55 @@ inline bool operator!=(const QString &that, const ProString &other)
|
|||||||
|
|
||||||
QTextStream &operator<<(QTextStream &t, const ProString &str);
|
QTextStream &operator<<(QTextStream &t, const ProString &str);
|
||||||
|
|
||||||
|
// This class manages read-only access to a ProString via a raw data QString
|
||||||
|
// temporary, ensuring that the latter is accessed exclusively.
|
||||||
|
class ProStringRoUser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProStringRoUser(QString &rs)
|
||||||
|
{
|
||||||
|
Q_ASSERT(rs.isDetached() || rs.isEmpty());
|
||||||
|
m_rs = &rs;
|
||||||
|
}
|
||||||
|
ProStringRoUser(const ProString &ps, QString &rs)
|
||||||
|
: ProStringRoUser(rs)
|
||||||
|
{
|
||||||
|
ps.toQString(rs);
|
||||||
|
}
|
||||||
|
// No destructor, as a RAII pattern cannot be used: references to the
|
||||||
|
// temporary string can legitimately outlive instances of this class
|
||||||
|
// (if they are held by Qt, e.g. in QRegExp).
|
||||||
|
QString &set(const ProString &ps) { return ps.toQString(*m_rs); }
|
||||||
|
QString &str() { return *m_rs; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString *m_rs;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class manages read-write access to a ProString via a raw data QString
|
||||||
|
// temporary, ensuring that the latter is accessed exclusively, and that raw
|
||||||
|
// data does not leak outside its source's refcounting.
|
||||||
|
class ProStringRwUser : public ProStringRoUser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProStringRwUser(QString &rs)
|
||||||
|
: ProStringRoUser(rs), m_ps(0) {}
|
||||||
|
ProStringRwUser(const ProString &ps, QString &rs)
|
||||||
|
: ProStringRoUser(ps, rs), m_ps(&ps) {}
|
||||||
|
QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); }
|
||||||
|
ProString extract(const QString &s) const
|
||||||
|
{ return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); }
|
||||||
|
ProString extract(const QString &s, const ProStringRwUser &other) const
|
||||||
|
{
|
||||||
|
if (other.m_ps && s.isSharedWith(*other.m_rs))
|
||||||
|
return *other.m_ps;
|
||||||
|
return extract(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ProString *m_ps;
|
||||||
|
};
|
||||||
|
|
||||||
class ProStringList : public QVector<ProString> {
|
class ProStringList : public QVector<ProString> {
|
||||||
public:
|
public:
|
||||||
ProStringList() {}
|
ProStringList() {}
|
||||||
|
@ -263,8 +263,9 @@ QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
evalError(fL1S("%1() argument 2 (start) '%2' invalid.")
|
ProStringRoUser u1(func, m_tmp1);
|
||||||
.arg(func.toQString(m_tmp1), start_str.toQString(m_tmp2)));
|
ProStringRoUser u2(start_str, m_tmp2);
|
||||||
|
evalError(fL1S("%1() argument 2 (start) '%2' invalid.").arg(u1.str(), u2.str()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -272,8 +273,9 @@ QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringLis
|
|||||||
if (args.count() == 3)
|
if (args.count() == 3)
|
||||||
*end = args.at(2).toInt(&ok);
|
*end = args.at(2).toInt(&ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
evalError(fL1S("%1() argument 3 (end) '%2' invalid.")
|
ProStringRoUser u1(func, m_tmp1);
|
||||||
.arg(func.toQString(m_tmp1), args.at(2).toQString(m_tmp2)));
|
ProStringRoUser u2(args.at(2), m_tmp2);
|
||||||
|
evalError(fL1S("%1() argument 3 (end) '%2' invalid.").arg(u1.str(), u2.str()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -581,14 +583,16 @@ void QMakeEvaluator::populateDeps(
|
|||||||
|
|
||||||
QString QMakeEvaluator::filePathArg0(const ProStringList &args)
|
QString QMakeEvaluator::filePathArg0(const ProStringList &args)
|
||||||
{
|
{
|
||||||
QString fn = resolvePath(args.at(0).toQString(m_tmp1));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
QString fn = resolvePath(u1.str());
|
||||||
fn.detach();
|
fn.detach();
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QMakeEvaluator::filePathEnvArg0(const ProStringList &args)
|
QString QMakeEvaluator::filePathEnvArg0(const ProStringList &args)
|
||||||
{
|
{
|
||||||
QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
QString fn = resolvePath(m_option->expandEnvVars(u1.str()));
|
||||||
fn.detach();
|
fn.detach();
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
@ -633,23 +637,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
if (regexp) {
|
if (regexp) {
|
||||||
QRegExp sepRx(sep);
|
QRegExp sepRx(sep);
|
||||||
for (const ProString &str : strings) {
|
for (const ProString &str : strings) {
|
||||||
const QString &rstr = str.toQString(m_tmp[m_toggle ^= 1]).section(sepRx, beg, end);
|
ProStringRwUser u1(str, m_tmp[m_toggle ^= 1]);
|
||||||
ret << (rstr.isSharedWith(m_tmp[m_toggle]) ? str : ProString(rstr).setSource(str));
|
ret << u1.extract(u1.str().section(sepRx, beg, end));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const ProString &str : strings) {
|
for (const ProString &str : strings) {
|
||||||
const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
|
ProStringRwUser u1(str, m_tmp1);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
|
ret << u1.extract(u1.str().section(sep, beg, end));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SPRINTF: {
|
case E_SPRINTF: {
|
||||||
QString tmp = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
QString tmp = u1.str();
|
||||||
for (int i = 1; i < args.count(); ++i)
|
for (int i = 1; i < args.count(); ++i)
|
||||||
tmp = tmp.arg(args.at(i).toQStringView());
|
tmp = tmp.arg(args.at(i).toQStringView());
|
||||||
ret << (tmp.isSharedWith(m_tmp1) ? args.at(0) : ProString(tmp).setSource(args.at(0)));
|
ret << u1.extract(tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_FORMAT_NUMBER: {
|
case E_FORMAT_NUMBER: {
|
||||||
@ -758,7 +763,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SPLIT: {
|
case E_SPLIT: {
|
||||||
const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
|
ProStringRoUser u1(m_tmp1);
|
||||||
|
const QString &sep = (args.count() == 2) ? u1.set(args.at(1)) : statics.field_sep;
|
||||||
const auto vars = values(map(args.at(0)));
|
const auto vars = values(map(args.at(0)));
|
||||||
for (const ProString &var : vars) {
|
for (const ProString &var : vars) {
|
||||||
// FIXME: this is inconsistent with the "there are no empty strings" dogma.
|
// FIXME: this is inconsistent with the "there are no empty strings" dogma.
|
||||||
@ -884,7 +890,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
QRegExp regx(args.at(1).toQString());
|
QRegExp regx(args.at(1).toQString());
|
||||||
const auto vals = values(map(args.at(0)));
|
const auto vals = values(map(args.at(0)));
|
||||||
for (const ProString &val : vals) {
|
for (const ProString &val : vals) {
|
||||||
if (regx.indexIn(val.toQString(m_tmp[m_toggle ^= 1])) != -1)
|
ProStringRoUser u1(val, m_tmp[m_toggle ^= 1]);
|
||||||
|
if (regx.indexIn(u1.str()) != -1)
|
||||||
ret += val;
|
ret += val;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -979,8 +986,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
break;
|
break;
|
||||||
case E_RE_ESCAPE:
|
case E_RE_ESCAPE:
|
||||||
for (int i = 0; i < args.size(); ++i) {
|
for (int i = 0; i < args.size(); ++i) {
|
||||||
const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1));
|
ProStringRwUser u1(args.at(i), m_tmp1);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
|
ret << u1.extract(QRegExp::escape(u1.str()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case E_VAL_ESCAPE: {
|
case E_VAL_ESCAPE: {
|
||||||
@ -994,7 +1001,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
case E_LOWER:
|
case E_LOWER:
|
||||||
case E_TITLE:
|
case E_TITLE:
|
||||||
for (int i = 0; i < args.count(); ++i) {
|
for (int i = 0; i < args.count(); ++i) {
|
||||||
QString rstr = args.at(i).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(i), m_tmp1);
|
||||||
|
QString rstr = u1.str();
|
||||||
if (func_t == E_UPPER) {
|
if (func_t == E_UPPER) {
|
||||||
rstr = rstr.toUpper();
|
rstr = rstr.toUpper();
|
||||||
} else {
|
} else {
|
||||||
@ -1002,7 +1010,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
if (func_t == E_TITLE && rstr.length() > 0)
|
if (func_t == E_TITLE && rstr.length() > 0)
|
||||||
rstr[0] = rstr.at(0).toTitleCase();
|
rstr[0] = rstr.at(0).toTitleCase();
|
||||||
}
|
}
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
|
ret << u1.extract(rstr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case E_FILES: {
|
case E_FILES: {
|
||||||
@ -1010,7 +1018,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
if (args.count() == 2)
|
if (args.count() == 2)
|
||||||
recursive = isTrue(args.at(1));
|
recursive = isTrue(args.at(1));
|
||||||
QStringList dirs;
|
QStringList dirs;
|
||||||
QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1))
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
QString r = m_option->expandEnvVars(u1.str())
|
||||||
.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
||||||
QString pfx;
|
QString pfx;
|
||||||
if (IoUtils::isRelativePath(r)) {
|
if (IoUtils::isRelativePath(r)) {
|
||||||
@ -1047,7 +1056,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
}
|
}
|
||||||
#ifdef PROEVALUATOR_FULL
|
#ifdef PROEVALUATOR_FULL
|
||||||
case E_PROMPT: {
|
case E_PROMPT: {
|
||||||
QString msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp1));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
QString msg = m_option->expandEnvVars(u1.str());
|
||||||
bool decorate = true;
|
bool decorate = true;
|
||||||
if (args.count() == 2)
|
if (args.count() == 2)
|
||||||
decorate = isTrue(args.at(1));
|
decorate = isTrue(args.at(1));
|
||||||
@ -1074,17 +1084,15 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
#endif
|
#endif
|
||||||
case E_REPLACE: {
|
case E_REPLACE: {
|
||||||
const QRegExp before(args.at(1).toQString());
|
const QRegExp before(args.at(1).toQString());
|
||||||
const QString &after(args.at(2).toQString(m_tmp2));
|
ProStringRwUser u2(args.at(2), m_tmp2);
|
||||||
|
const QString &after = u2.str();
|
||||||
const auto vals = values(map(args.at(0)));
|
const auto vals = values(map(args.at(0)));
|
||||||
for (const ProString &val : vals) {
|
for (const ProString &val : vals) {
|
||||||
QString rstr = val.toQString(m_tmp1);
|
ProStringRwUser u1(val, m_tmp1);
|
||||||
|
QString rstr = u1.str();
|
||||||
QString copy = rstr; // Force a detach on modify
|
QString copy = rstr; // Force a detach on modify
|
||||||
rstr.replace(before, after);
|
rstr.replace(before, after);
|
||||||
ret << (rstr.isSharedWith(m_tmp1)
|
ret << u1.extract(rstr, u2);
|
||||||
? val
|
|
||||||
: rstr.isSharedWith(m_tmp2)
|
|
||||||
? args.at(2)
|
|
||||||
: ProString(rstr).setSource(val));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1125,52 +1133,52 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
ret << key;
|
ret << key;
|
||||||
break; }
|
break; }
|
||||||
case E_SHADOWED: {
|
case E_SHADOWED: {
|
||||||
QString rstr = m_option->shadowedPath(resolvePath(args.at(0).toQString(m_tmp1)));
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
if (rstr.isEmpty())
|
QString rstr = m_option->shadowedPath(resolvePath(u1.str()));
|
||||||
break;
|
if (!rstr.isEmpty())
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(rstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_ABSOLUTE_PATH: {
|
case E_ABSOLUTE_PATH: {
|
||||||
QString arg = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
ProStringRwUser u2(m_tmp2);
|
||||||
QString baseDir = args.count() > 1
|
QString baseDir = args.count() > 1
|
||||||
? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
|
? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
|
||||||
: currentDirectory();
|
: currentDirectory();
|
||||||
QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
|
QString rstr = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
|
||||||
ret << (rstr.isSharedWith(m_tmp1)
|
ret << u1.extract(rstr, u2);
|
||||||
? args.at(0)
|
|
||||||
: args.count() > 1 && rstr.isSharedWith(m_tmp2)
|
|
||||||
? args.at(1)
|
|
||||||
: ProString(rstr).setSource(args.at(0)));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_RELATIVE_PATH: {
|
case E_RELATIVE_PATH: {
|
||||||
QString arg = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
ProStringRoUser u2(m_tmp2);
|
||||||
QString baseDir = args.count() > 1
|
QString baseDir = args.count() > 1
|
||||||
? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
|
? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
|
||||||
: currentDirectory();
|
: currentDirectory();
|
||||||
QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
|
QString absArg = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
|
||||||
QString rstr = QDir(baseDir).relativeFilePath(absArg);
|
QString rstr = QDir(baseDir).relativeFilePath(absArg);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(rstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_CLEAN_PATH: {
|
case E_CLEAN_PATH: {
|
||||||
QString rstr = QDir::cleanPath(args.at(0).toQString(m_tmp1));
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(QDir::cleanPath(u1.str()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SYSTEM_PATH: {
|
case E_SYSTEM_PATH: {
|
||||||
QString rstr = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
QString rstr = u1.str();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
||||||
#else
|
#else
|
||||||
rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
||||||
#endif
|
#endif
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(rstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SHELL_PATH: {
|
case E_SHELL_PATH: {
|
||||||
QString rstr = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
QString rstr = u1.str();
|
||||||
if (m_dirSep.startsWith(QLatin1Char('\\'))) {
|
if (m_dirSep.startsWith(QLatin1Char('\\'))) {
|
||||||
rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
||||||
} else {
|
} else {
|
||||||
@ -1183,27 +1191,27 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(rstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SYSTEM_QUOTE: {
|
case E_SYSTEM_QUOTE: {
|
||||||
QString rstr = IoUtils::shellQuote(args.at(0).toQString(m_tmp1));
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(IoUtils::shellQuote(u1.str()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_SHELL_QUOTE: {
|
case E_SHELL_QUOTE: {
|
||||||
QString rstr = args.at(0).toQString(m_tmp1);
|
ProStringRwUser u1(args.at(0), m_tmp1);
|
||||||
|
QString rstr = u1.str();
|
||||||
if (m_dirSep.startsWith(QLatin1Char('\\')))
|
if (m_dirSep.startsWith(QLatin1Char('\\')))
|
||||||
rstr = IoUtils::shellQuoteWin(rstr);
|
rstr = IoUtils::shellQuoteWin(rstr);
|
||||||
else
|
else
|
||||||
rstr = IoUtils::shellQuoteUnix(rstr);
|
rstr = IoUtils::shellQuoteUnix(rstr);
|
||||||
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
|
ret << u1.extract(rstr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case E_GETENV: {
|
case E_GETENV: {
|
||||||
const ProString &var = args.at(0);
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1)));
|
ret << ProString(m_option->getEnv(u1.str()));
|
||||||
ret << val;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1270,7 +1278,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
evalError(fL1S("discard_from() cannot be called from functions."));
|
evalError(fL1S("discard_from() cannot be called from functions."));
|
||||||
return ReturnFalse;
|
return ReturnFalse;
|
||||||
}
|
}
|
||||||
QString fn = resolvePath(args.at(0).toQString(m_tmp1));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
QString fn = resolvePath(u1.str());
|
||||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||||
int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
|
int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
|
||||||
if (!pro)
|
if (!pro)
|
||||||
@ -1318,7 +1327,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
if (args.count() == 2)
|
if (args.count() == 2)
|
||||||
return returnBool(vars.contains(map(args.at(1))));
|
return returnBool(vars.contains(map(args.at(1))));
|
||||||
QRegExp regx;
|
QRegExp regx;
|
||||||
const QString &qry = args.at(2).toQString(m_tmp1);
|
ProStringRoUser u1(args.at(2), m_tmp1);
|
||||||
|
const QString &qry = u1.str();
|
||||||
if (qry != QRegExp::escape(qry)) {
|
if (qry != QRegExp::escape(qry)) {
|
||||||
QString copy = qry;
|
QString copy = qry;
|
||||||
copy.detach();
|
copy.detach();
|
||||||
@ -1326,8 +1336,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
}
|
}
|
||||||
const auto strings = vars.value(map(args.at(1)));
|
const auto strings = vars.value(map(args.at(1)));
|
||||||
for (const ProString &s : strings) {
|
for (const ProString &s : strings) {
|
||||||
if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[m_toggle ^= 1]))) || s == qry)
|
if (s == qry)
|
||||||
return ReturnTrue;
|
return ReturnTrue;
|
||||||
|
if (!regx.isEmpty()) {
|
||||||
|
ProStringRoUser u2(s, m_tmp[m_toggle ^= 1]);
|
||||||
|
if (regx.exactMatch(u2.str()))
|
||||||
|
return ReturnTrue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ReturnFalse;
|
return ReturnFalse;
|
||||||
}
|
}
|
||||||
@ -1371,7 +1386,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
return ReturnFalse;
|
return ReturnFalse;
|
||||||
}
|
}
|
||||||
case T_CONTAINS: {
|
case T_CONTAINS: {
|
||||||
const QString &qry = args.at(1).toQString(m_tmp1);
|
ProStringRoUser u1(args.at(1), m_tmp1);
|
||||||
|
const QString &qry = u1.str();
|
||||||
QRegExp regx;
|
QRegExp regx;
|
||||||
if (qry != QRegExp::escape(qry)) {
|
if (qry != QRegExp::escape(qry)) {
|
||||||
QString copy = qry;
|
QString copy = qry;
|
||||||
@ -1382,19 +1398,29 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
if (args.count() == 2) {
|
if (args.count() == 2) {
|
||||||
for (int i = 0; i < l.size(); ++i) {
|
for (int i = 0; i < l.size(); ++i) {
|
||||||
const ProString &val = l[i];
|
const ProString &val = l[i];
|
||||||
if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1]))) || val == qry)
|
if (val == qry)
|
||||||
return ReturnTrue;
|
return ReturnTrue;
|
||||||
|
if (!regx.isEmpty()) {
|
||||||
|
ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]);
|
||||||
|
if (regx.exactMatch(u2.str()))
|
||||||
|
return ReturnTrue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|'),
|
const auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|'),
|
||||||
QString::SkipEmptyParts);
|
QString::SkipEmptyParts);
|
||||||
for (int i = l.size() - 1; i >= 0; i--) {
|
for (int i = l.size() - 1; i >= 0; i--) {
|
||||||
const ProString val = l[i];
|
const ProString &val = l[i];
|
||||||
for (int mut = 0; mut < mutuals.count(); mut++) {
|
for (int mut = 0; mut < mutuals.count(); mut++) {
|
||||||
if (val.toQStringRef() == mutuals[mut].trimmed()) {
|
if (val.toQStringRef() == mutuals[mut].trimmed()) {
|
||||||
return returnBool((!regx.isEmpty()
|
if (val == qry)
|
||||||
&& regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1])))
|
return ReturnTrue;
|
||||||
|| val == qry);
|
if (!regx.isEmpty()) {
|
||||||
|
ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]);
|
||||||
|
if (regx.exactMatch(u2.str()))
|
||||||
|
return ReturnTrue;
|
||||||
|
}
|
||||||
|
return ReturnFalse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1482,7 +1508,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
case T_PARSE_JSON: {
|
case T_PARSE_JSON: {
|
||||||
QByteArray json = values(args.at(0).toKey()).join(QLatin1Char(' ')).toUtf8();
|
QByteArray json = values(args.at(0).toKey()).join(QLatin1Char(' ')).toUtf8();
|
||||||
QString parseInto = args.at(1).toQString(m_tmp2);
|
ProStringRoUser u1(args.at(1), m_tmp2);
|
||||||
|
QString parseInto = u1.str();
|
||||||
return parseJsonInto(json, parseInto, &m_valuemapStack.top());
|
return parseJsonInto(json, parseInto, &m_valuemapStack.top());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1537,7 +1564,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
#ifdef PROEVALUATOR_DEBUG
|
#ifdef PROEVALUATOR_DEBUG
|
||||||
int level = args.at(0).toInt();
|
int level = args.at(0).toInt();
|
||||||
if (level <= m_debugLevel) {
|
if (level <= m_debugLevel) {
|
||||||
const QString &msg = m_option->expandEnvVars(args.at(1).toQString(m_tmp2));
|
ProStringRoUser u1(args.at(1), m_tmp1);
|
||||||
|
const QString &msg = m_option->expandEnvVars(u1.str());
|
||||||
debugMsg(level, "Project DEBUG: %s", qPrintable(msg));
|
debugMsg(level, "Project DEBUG: %s", qPrintable(msg));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1547,19 +1575,21 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
case T_ERROR:
|
case T_ERROR:
|
||||||
case T_WARNING:
|
case T_WARNING:
|
||||||
case T_MESSAGE: {
|
case T_MESSAGE: {
|
||||||
const QString &msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp2));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
|
const QString &msg = m_option->expandEnvVars(u1.str());
|
||||||
if (!m_skipLevel) {
|
if (!m_skipLevel) {
|
||||||
if (func_t == T_LOG) {
|
if (func_t == T_LOG) {
|
||||||
#ifdef PROEVALUATOR_FULL
|
#ifdef PROEVALUATOR_FULL
|
||||||
fputs(msg.toLatin1().constData(), stderr);
|
fputs(msg.toLatin1().constData(), stderr);
|
||||||
#endif
|
#endif
|
||||||
} else if (!msg.isEmpty() || func_t != T_ERROR) {
|
} else if (!msg.isEmpty() || func_t != T_ERROR) {
|
||||||
|
ProStringRoUser u2(function, m_tmp2);
|
||||||
m_handler->fileMessage(
|
m_handler->fileMessage(
|
||||||
(func_t == T_ERROR ? QMakeHandler::ErrorMessage :
|
(func_t == T_ERROR ? QMakeHandler::ErrorMessage :
|
||||||
func_t == T_WARNING ? QMakeHandler::WarningMessage :
|
func_t == T_WARNING ? QMakeHandler::WarningMessage :
|
||||||
QMakeHandler::InfoMessage)
|
QMakeHandler::InfoMessage)
|
||||||
| (m_cumulative ? QMakeHandler::CumulativeEvalMessage : 0),
|
| (m_cumulative ? QMakeHandler::CumulativeEvalMessage : 0),
|
||||||
fL1S("Project %1: %2").arg(function.toQString(m_tmp1).toUpper(), msg));
|
fL1S("Project %1: %2").arg(u2.str().toUpper(), msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue;
|
return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue;
|
||||||
@ -1645,8 +1675,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
|||||||
}
|
}
|
||||||
case T_TOUCH: {
|
case T_TOUCH: {
|
||||||
#ifdef PROEVALUATOR_FULL
|
#ifdef PROEVALUATOR_FULL
|
||||||
const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1));
|
ProStringRoUser u1(args.at(0), m_tmp1);
|
||||||
const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2));
|
ProStringRoUser u2(args.at(1), m_tmp2);
|
||||||
|
const QString &tfn = resolvePath(u1.str());
|
||||||
|
const QString &rfn = resolvePath(u2.str());
|
||||||
QString error;
|
QString error;
|
||||||
if (!IoUtils::touchFile(tfn, rfn, &error)) {
|
if (!IoUtils::touchFile(tfn, rfn, &error)) {
|
||||||
evalError(error);
|
evalError(error);
|
||||||
|
@ -337,7 +337,8 @@ static void replaceInList(ProStringList *varlist,
|
|||||||
const QRegExp ®exp, const QString &replace, bool global, QString &tmp)
|
const QRegExp ®exp, const QString &replace, bool global, QString &tmp)
|
||||||
{
|
{
|
||||||
for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
|
for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
|
||||||
QString val = varit->toQString(tmp);
|
ProStringRoUser u1(*varit, tmp);
|
||||||
|
QString val = u1.str();
|
||||||
QString copy = val; // Force detach and have a reference value
|
QString copy = val; // Force detach and have a reference value
|
||||||
val.replace(regexp, replace);
|
val.replace(regexp, replace);
|
||||||
if (!val.isSharedWith(copy) && val != copy) {
|
if (!val.isSharedWith(copy) && val != copy) {
|
||||||
@ -1336,7 +1337,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConfigFeatures()
|
|||||||
bool finished = true;
|
bool finished = true;
|
||||||
ProStringList configs = values(statics.strCONFIG);
|
ProStringList configs = values(statics.strCONFIG);
|
||||||
for (int i = configs.size() - 1; i >= 0; --i) {
|
for (int i = configs.size() - 1; i >= 0; --i) {
|
||||||
QString config = configs.at(i).toQString(m_tmp1).toLower();
|
ProStringRoUser u1(configs.at(i), m_tmp1);
|
||||||
|
QString config = u1.str().toLower();
|
||||||
if (!processed.contains(config)) {
|
if (!processed.contains(config)) {
|
||||||
config.detach();
|
config.detach();
|
||||||
processed.insert(config);
|
processed.insert(config);
|
||||||
@ -1640,7 +1642,8 @@ bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex)
|
|||||||
// CONFIG variable
|
// CONFIG variable
|
||||||
const auto configValues = values(statics.strCONFIG);
|
const auto configValues = values(statics.strCONFIG);
|
||||||
for (const ProString &configValue : configValues) {
|
for (const ProString &configValue : configValues) {
|
||||||
if (re.exactMatch(configValue.toQString(m_tmp[m_toggle ^= 1])))
|
ProStringRoUser u1(configValue, m_tmp[m_toggle ^= 1]);
|
||||||
|
if (re.exactMatch(u1.str()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1749,9 +1752,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
|
|||||||
if (val)
|
if (val)
|
||||||
return ReturnTrue;
|
return ReturnTrue;
|
||||||
} else {
|
} else {
|
||||||
|
ProStringRoUser u1(function, m_tmp1);
|
||||||
evalError(fL1S("Unexpected return value from test '%1': %2.")
|
evalError(fL1S("Unexpected return value from test '%1': %2.")
|
||||||
.arg(function.toQString(m_tmp1))
|
.arg(u1.str(), ret.join(QLatin1String(" :: "))));
|
||||||
.arg(ret.join(QLatin1String(" :: "))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ReturnFalse;
|
return ReturnFalse;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user