Obsolete command-string parsing QProcess::start/execute overloads

The command string parsing covers only simple quoting
patterns, while users tend to expect something that is in line with
their shell.
The overloads that take a QStringList are the recommended APIs to use
anyway, so exposing the splitting  method as a static function for
which we document the exact behavior allows callers to post-process
the QStringList, before calling the preferred overloads.

[ChangeLog][QtCore][QProcess] Overloads of start/execute/startDatached
that parse a single command string into program and arguments have
been marked as deprecated. A static helper splitCommand has
been added to construct a QStringList from a command string.

Change-Id: Ie91fcfb5eae6a52e5065efc60d2d9e068d20869d
Fixes: QTBUG-80640
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
Volker Hilsheimer 2020-02-07 14:12:57 +01:00
parent adfd0914e3
commit 92eea63349
2 changed files with 41 additions and 11 deletions

View File

@ -2246,8 +2246,16 @@ void QProcessPrivate::start(QIODevice::OpenMode mode)
startProcess();
}
/*!
\since 5.15
static QStringList parseCombinedArgString(const QString &program)
Splits the string \a command into a list of tokens, and returns
the list.
Tokens with spaces can be surrounded by double quotes; three
consecutive double quotes represent the quote character itself.
*/
QStringList QProcess::splitCommand(const QString &command)
{
QStringList args;
QString tmp;
@ -2257,13 +2265,13 @@ static QStringList parseCombinedArgString(const QString &program)
// handle quoting. tokens can be surrounded by double quotes
// "hello world". three consecutive double quotes represent
// the quote character itself.
for (int i = 0; i < program.size(); ++i) {
if (program.at(i) == QLatin1Char('"')) {
for (int i = 0; i < command.size(); ++i) {
if (command.at(i) == QLatin1Char('"')) {
++quoteCount;
if (quoteCount == 3) {
// third consecutive quote
quoteCount = 0;
tmp += program.at(i);
tmp += command.at(i);
}
continue;
}
@ -2272,13 +2280,13 @@ static QStringList parseCombinedArgString(const QString &program)
inQuote = !inQuote;
quoteCount = 0;
}
if (!inQuote && program.at(i).isSpace()) {
if (!inQuote && command.at(i).isSpace()) {
if (!tmp.isEmpty()) {
args += tmp;
tmp.clear();
}
} else {
tmp += program.at(i);
tmp += command.at(i);
}
}
if (!tmp.isEmpty())
@ -2288,6 +2296,7 @@ static QStringList parseCombinedArgString(const QString &program)
}
/*!
\obsolete
\overload
Starts the command \a command in a new process.
@ -2324,11 +2333,13 @@ static QStringList parseCombinedArgString(const QString &program)
list-based API. In these rare cases you need to use setProgram() and
setNativeArguments() instead of this function.
\sa splitCommand()
*/
#if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START)
void QProcess::start(const QString &command, OpenMode mode)
{
QStringList args = parseCombinedArgString(command);
QStringList args = splitCommand(command);
if (args.isEmpty()) {
Q_D(QProcess);
d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
@ -2493,6 +2504,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments)
}
/*!
\obsolete
\overload
Starts the program \a command in a new process, waits for it to finish,
@ -2503,7 +2515,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments)
After the \a command string has been split and unquoted, this function
behaves like the overload which takes the arguments as a string list.
\sa start()
\sa start(), splitCommand()
*/
int QProcess::execute(const QString &command)
{
@ -2559,6 +2571,7 @@ bool QProcess::startDetached(const QString &program,
}
/*!
\obsolete
\overload startDetached()
Starts the command \a command in a new process, and detaches from it.
@ -2569,11 +2582,11 @@ bool QProcess::startDetached(const QString &program,
After the \a command string has been split and unquoted, this function
behaves like the overload which takes the arguments as a string list.
\sa start(const QString &command, QIODevice::OpenMode mode)
\sa start(const QString &command, QIODevice::OpenMode mode), splitCommand()
*/
bool QProcess::startDetached(const QString &command)
{
QStringList args = parseCombinedArgString(command);
QStringList args = splitCommand(command);
if (args.isEmpty())
return false;

View File

@ -160,7 +160,13 @@ public:
void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite);
#if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START)
#if QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X(
"Use QProcess::start(const QString &program, const QStringList &arguments,"
"OpenMode mode = ReadWrite) instead"
)
void start(const QString &command, OpenMode mode = ReadWrite);
#endif
#endif
void start(OpenMode mode = ReadWrite);
bool startDetached(qint64 *pid = nullptr);
@ -250,8 +256,12 @@ public:
bool atEnd() const override; // ### Qt6: remove trivial override
static int execute(const QString &program, const QStringList &arguments);
#if QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X(
"Use QProcess::execute(const QString &program, const QStringList &arguments) instead"
)
static int execute(const QString &command);
#endif
static bool startDetached(const QString &program, const QStringList &arguments,
const QString &workingDirectory
#if defined(Q_QDOC)
@ -261,12 +271,19 @@ public:
#if !defined(Q_QDOC)
static bool startDetached(const QString &program, const QStringList &arguments); // ### Qt6: merge overloads
#endif
#if QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X(
"Use QProcess::startDetached(const QString &program, const QStringList &arguments) instead"
)
static bool startDetached(const QString &command);
#endif
static QStringList systemEnvironment();
static QString nullDevice();
static QStringList splitCommand(const QString &command);
public Q_SLOTS:
void terminate();
void kill();