1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef SHELLQUOTE_SHARED_H
5#define SHELLQUOTE_SHARED_H
6
7#include <QDir>
8#include <QRegularExpression>
9#include <QString>
10
11// Copy-pasted from qmake/library/ioutil.cpp
12inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
13{
14 for (int x = arg.size() - 1; x >= 0; --x) {
15 ushort c = arg.unicode()[x].unicode();
16 if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
17 return true;
18 }
19 return false;
20}
21
22static QString shellQuoteUnix(const QString &arg)
23{
24 // Chars that should be quoted (TM). This includes:
25 static const uchar iqm[] = {
26 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
27 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
28 }; // 0-32 \'"$`<>|;&(){}*?#!~[]
29
30 if (!arg.size())
31 return QLatin1String("\"\"");
32
33 QString ret(arg);
34 if (hasSpecialChars(arg: ret, iqm)) {
35 ret.replace(c: QLatin1Char('\''), after: QLatin1String("'\\''"));
36 ret.prepend(c: QLatin1Char('\''));
37 ret.append(c: QLatin1Char('\''));
38 }
39 return ret;
40}
41
42static QString shellQuoteWin(const QString &arg)
43{
44 // Chars that should be quoted (TM). This includes:
45 // - control chars & space
46 // - the shell meta chars "&()<>^|
47 // - the potential separators ,;=
48 static const uchar iqm[] = {
49 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
50 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
51 };
52
53 if (!arg.size())
54 return QLatin1String("\"\"");
55
56 QString ret(arg);
57 if (hasSpecialChars(arg: ret, iqm)) {
58 // Quotes are escaped and their preceding backslashes are doubled.
59 // It's impossible to escape anything inside a quoted string on cmd
60 // level, so the outer quoting must be "suspended".
61 ret.replace(re: QRegularExpression(QLatin1String("(\\\\*)\"")), after: QLatin1String("\"\\1\\1\\^\"\""));
62 // The argument must not end with a \ since this would be interpreted
63 // as escaping the quote -- rather put the \ behind the quote: e.g.
64 // rather use "foo"\ than "foo\"
65 int i = ret.size();
66 while (i > 0 && ret.at(i: i - 1) == QLatin1Char('\\'))
67 --i;
68 ret.insert(i, c: QLatin1Char('"'));
69 ret.prepend(c: QLatin1Char('"'));
70 }
71 return ret;
72}
73
74static QString shellQuote(const QString &arg)
75{
76 if (QDir::separator() == QLatin1Char('\\'))
77 return shellQuoteWin(arg);
78 else
79 return shellQuoteUnix(arg);
80}
81
82#endif // SHELLQUOTE_SHARED_H
83

source code of qtbase/src/tools/shared/shellquote_shared.h