diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 81285259acc..e19eafa4c15 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -1429,16 +1429,20 @@ CommandLine::CommandLine(const FilePath &exe, const QString &args, RawType) CommandLine CommandLine::fromUserInput(const QString &cmdline, MacroExpander *expander) { - CommandLine cmd; - const int pos = cmdline.indexOf(' '); - if (pos == -1) { - cmd.m_executable = FilePath::fromString(cmdline); - } else { - cmd.m_executable = FilePath::fromString(cmdline.left(pos)); - cmd.m_arguments = cmdline.right(cmdline.length() - pos - 1); - if (expander) - cmd.m_arguments = expander->expand(cmd.m_arguments); - } + if (cmdline.isEmpty()) + return {}; + + QString input = cmdline.trimmed(); + + QStringList result = ProcessArgs::splitArgs(cmdline, HostOsInfo::hostOs()); + + if (result.isEmpty()) + return {}; + + auto cmd = CommandLine(FilePath::fromUserInput(result.value(0)), result.mid(1)); + if (expander) + cmd.m_arguments = expander->expand(cmd.m_arguments); + return cmd; } diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index 05357d2526e..6972ae6ba39 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,82 @@ private slots: QString actual = run(shell); QCOMPARE(actual, expected); } + + void testFromUserInput_data() + { + QTest::addColumn("input"); + QTest::addColumn("executable"); + QTest::addColumn("arguments"); + + QTest::newRow("empty") << "" + << "" + << ""; + QTest::newRow("command") << "command" + << "command" + << ""; + QTest::newRow("command-with-args") << "command and args" + << "command" + << "and args"; + + if (!HostOsInfo::isWindowsHost()) { + QTest::newRow("command-with-space-slash") << "command\\ with-space and args" + << "command with-space" + << "and args"; + QTest::newRow("command-with-space-single-quote") << "'command with-space' and args" + << "command with-space" + << "and args"; + } + QTest::newRow("command-with-space-double-quote") << "\"command with-space\" and args" + << "command with-space" + << "and args"; + + QTest::newRow("command-with-space-double-quote-in-name") + << "\"command\\\"with-quote\" and args" + << "command\"with-quote" + << "and args"; + + QTest::newRow("inside-space-quoted") << "command\" \"withspace args here" + << "command withspace" + << "args here"; + } + + void testFromUserInput() + { + QFETCH(QString, input); + QFETCH(QString, executable); + QFETCH(QString, arguments); + + CommandLine cmd = CommandLine::fromUserInput(input); + QCOMPARE(cmd.executable(), FilePath::fromUserInput(executable)); + QCOMPARE(cmd.arguments(), arguments); + } + + void testFromInputFails() + { + if (HostOsInfo::isWindowsHost()) + QSKIP("The test does not work on Windows."); + + CommandLine cmd = CommandLine::fromUserInput("command\\\\\\ with-space and args"); + QEXPECT_FAIL("", + "CommandLine::fromUserInput (and FilePath::fromUserInput) does not handle " + "backslashes correctly", + Continue); + QCOMPARE(cmd.executable().fileName(), "command\\ with-space"); + QCOMPARE(cmd.arguments(), "and args"); + } + + void testFromInputWithMacro() + { + MacroExpander expander; + expander.registerVariable("hello", "world var", [] { return "hello world"; }); + CommandLine cmd = CommandLine::fromUserInput("command macroarg: %{hello}", &expander); + QCOMPARE(cmd.executable(), "command"); + + if (HostOsInfo::isWindowsHost()) + QEXPECT_FAIL("", "Windows does not correctly quote macro arguments", Continue); + + QCOMPARE(cmd.arguments(), "macroarg: 'hello world'"); + } }; int main(int argc, char *argv[])