From 3d629b1a2bec3c336cbb59fe8ed8aaf35b9b27cc Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 25 Jul 2012 20:02:23 +0200 Subject: [PATCH] add $$system_quote() & $$shell_quote() functions follow suit with qmake ... Change-Id: I3db37ba73cb709d8baf200600ae29241bc26bee5 Reviewed-by: Daniel Teske Reviewed-by: Oswald Buddenhagen --- src/shared/proparser/ioutils.cpp | 63 ++++++++++++++------------ src/shared/proparser/ioutils.h | 9 +++- src/shared/proparser/qmakebuiltins.cpp | 23 +++++++++- 3 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index b85ed95378c..cd8923a32ca 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -91,11 +91,40 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); } -#ifdef QT_BOOTSTRAPPED -inline static bool isSpecialChar(ushort c) +inline static +bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) +{ + for (int x = arg.length() - 1; x >= 0; --x) { + ushort c = arg.unicode()[x].unicode(); + if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + return true; + } + return false; +} + +QString IoUtils::shellQuoteUnix(const QString &arg) +{ + // Chars that should be quoted (TM). This includes: + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, + 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 + }; // 0-32 \'"$`<>|;&(){}*?#!~[] + + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + if (hasSpecialChars(ret, iqm)) { + ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); + ret.prepend(QLatin1Char('\'')); + ret.append(QLatin1Char('\'')); + } + return ret; +} + +QString IoUtils::shellQuoteWin(const QString &arg) { // Chars that should be quoted (TM). This includes: -#ifdef Q_OS_WIN // - control chars & space // - the shell meta chars "&()<>^| // - the potential separators ,;= @@ -103,32 +132,12 @@ inline static bool isSpecialChar(ushort c) 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 }; -#else - static const uchar iqm[] = { - 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, - 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 - }; // 0-32 \'"$`<>|;&(){}*?#!~[] -#endif - return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); -} - -inline static bool hasSpecialChars(const QString &arg) -{ - for (int x = arg.length() - 1; x >= 0; --x) - if (isSpecialChar(arg.unicode()[x].unicode())) - return true; - return false; -} - -QString IoUtils::shellQuote(const QString &arg) -{ if (!arg.length()) return QString::fromLatin1("\"\""); QString ret(arg); - if (hasSpecialChars(ret)) { -#ifdef Q_OS_WIN + if (hasSpecialChars(ret, iqm)) { // Quotes are escaped and their preceding backslashes are doubled. // It's impossible to escape anything inside a quoted string on cmd // level, so the outer quoting must be "suspended". @@ -141,14 +150,8 @@ QString IoUtils::shellQuote(const QString &arg) --i; ret.insert(i, QLatin1Char('"')); ret.prepend(QLatin1Char('"')); -#else // Q_OS_WIN - ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); - ret.prepend(QLatin1Char('\'')); - ret.append(QLatin1Char('\'')); -#endif // Q_OS_WIN } return ret; } -#endif QT_END_NAMESPACE diff --git a/src/shared/proparser/ioutils.h b/src/shared/proparser/ioutils.h index 0482f7628e2..8f1fadb7d73 100644 --- a/src/shared/proparser/ioutils.h +++ b/src/shared/proparser/ioutils.h @@ -55,8 +55,13 @@ public: static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } static QStringRef fileName(const QString &fileName); // Requires normalized path static QString resolvePath(const QString &baseDir, const QString &fileName); -#ifdef QT_BOOTSTRAPPED - static QString shellQuote(const QString &arg); + static QString shellQuoteUnix(const QString &arg); + static QString shellQuoteWin(const QString &arg); + static QString shellQuote(const QString &arg) +#ifdef Q_OS_UNIX + { return shellQuoteUnix(arg); } +#else + { return shellQuoteWin(arg); } #endif }; diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 1e26c90af86..83d3cf36045 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -78,7 +78,7 @@ enum ExpandFunc { E_UPPER, E_LOWER, 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, - E_SYSTEM_PATH, E_SHELL_PATH + E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE }; enum TestFunc { @@ -131,6 +131,8 @@ void QMakeEvaluator::initFunctionStatics() { "clean_path", E_CLEAN_PATH }, { "system_path", E_SYSTEM_PATH }, { "shell_path", E_SHELL_PATH }, + { "system_quote", E_SYSTEM_QUOTE }, + { "shell_quote", E_SHELL_QUOTE }, }; for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) statics.expands.insert(ProString(expandInits[i].name), expandInits[i].func); @@ -890,6 +892,25 @@ ProStringList QMakeEvaluator::evaluateExpandFunction( ret << ProString(rstr, NoHash).setSource(args.at(0)); } break; + case E_SYSTEM_QUOTE: + if (args.count() != 1) + evalError(fL1S("system_quote(arg) requires one argument.")); + else + ret << ProString(IoUtils::shellQuote(args.at(0).toQString(m_tmp1)), + NoHash).setSource(args.at(0)); + break; + case E_SHELL_QUOTE: + if (args.count() != 1) { + evalError(fL1S("shell_quote(arg) requires one argument.")); + } else { + QString rstr = args.at(0).toQString(m_tmp1); + if (m_option->dir_sep.at(0) != QLatin1Char('/')) + rstr = IoUtils::shellQuoteWin(rstr); + else + rstr = IoUtils::shellQuoteUnix(rstr); + ret << ProString(rstr, NoHash).setSource(args.at(0)); + } + break; case E_INVALID: evalError(fL1S("'%1' is not a recognized replace function.") .arg(func.toQString(m_tmp1)));