diff options
Diffstat (limited to 'src/linguist/shared/ioutils.cpp')
-rw-r--r-- | src/linguist/shared/ioutils.cpp | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/src/linguist/shared/ioutils.cpp b/src/linguist/shared/ioutils.cpp index 921acf025..1a7710827 100644 --- a/src/linguist/shared/ioutils.cpp +++ b/src/linguist/shared/ioutils.cpp @@ -100,11 +100,18 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) } inline static +bool isSpecialChar(ushort c, const uchar (&iqm)[16]) +{ + if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + return true; + return false; +} + +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)))) + if (isSpecialChar(arg.unicode()[x].unicode(), iqm)) return true; } return false; @@ -140,23 +147,38 @@ QString IoUtils::shellQuoteWin(const QString &arg) 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 }; + // Shell meta chars that need escaping. + static const uchar ism[] = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 + }; // &()<>^| if (!arg.length()) return QString::fromLatin1("\"\""); QString ret(arg); 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". - ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - int i = ret.length(); - while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) - --i; - ret.insert(i, QLatin1Char('"')); + // The process-level standard quoting allows escaping quotes with backslashes (note + // that backslashes don't escape themselves, unless they are followed by a quote). + // Consequently, quotes are escaped and their preceding backslashes are doubled. + ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + // Trailing backslashes must be doubled as well, as they are followed by a quote. + ret.replace(QRegExp(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1")); + // However, the shell also interprets the command, and no backslash-escaping exists + // there - a quote always toggles the quoting state, but is nonetheless passed down + // to the called process verbatim. In the unquoted state, the circumflex escapes + // meta chars (including itself and quotes), and is removed from the command. + bool quoted = true; + for (int i = 0; i < ret.length(); i++) { + QChar c = ret.unicode()[i]; + if (c.unicode() == '"') + quoted = !quoted; + else if (!quoted && isSpecialChar(c.unicode(), ism)) + ret.insert(i++, QLatin1Char('^')); + } + if (!quoted) + ret.append(QLatin1Char('^')); + ret.append(QLatin1Char('"')); ret.prepend(QLatin1Char('"')); } return ret; |