Commit c68ebeed authored by hjk's avatar hjk Committed by Eike Ziller

QtcProcess: Introduce a QtcProcess::Arguments class

This is used to get a platform-agnostic handle on "command line
arguments". It essentially wraps a single QString on Windows,
and a QStringList everywhere else.

As a consequence, several occurrences of #ifdef Q_OS_*
can be removed from the codebase.

Change-Id: Ic93118c1bd0bce0ebb58f416d395dbaebb861772
Reviewed-by: default avatarOswald Buddenhagen <oswald.buddenhagen@digia.com>
parent a0d29eeb
......@@ -75,7 +75,8 @@ bool ConsoleProcess::start(const QString &program, const QString &args)
return false;
QtcProcess::SplitError perr;
QStringList pargs = QtcProcess::prepareArgs(args, &perr, &d->m_environment, &d->m_workingDir);
QtcProcess::Arguments pargs = QtcProcess::prepareArgs(args, &perr, HostOsInfo::hostOs(),
&d->m_environment, &d->m_workingDir);
QString pcmd;
if (perr == QtcProcess::SplitOk) {
pcmd = program;
......@@ -91,12 +92,15 @@ bool ConsoleProcess::start(const QString &program, const QString &args)
return false;
}
pcmd = QLatin1String("/bin/sh");
pargs << QLatin1String("-c") << (QtcProcess::quoteArg(program) + QLatin1Char(' ') + args);
pargs = QtcProcess::Arguments::createUnixArgs(QStringList()
<< QLatin1String("-c")
<< (QtcProcess::quoteArg(program) + QLatin1Char(' ') + args));
}
QtcProcess::SplitError qerr;
QStringList xtermArgs = QtcProcess::prepareArgs(terminalEmulator(d->m_settings), &qerr,
&d->m_environment, &d->m_workingDir);
QtcProcess::Arguments xtermArgs = QtcProcess::prepareArgs(terminalEmulator(d->m_settings), &qerr,
HostOsInfo::hostOs(),
&d->m_environment, &d->m_workingDir);
if (qerr != QtcProcess::SplitOk) {
emit processError(qerr == QtcProcess::BadQuoting
? tr("Quoting error in terminal command.")
......@@ -134,23 +138,23 @@ bool ConsoleProcess::start(const QString &program, const QString &args)
}
}
if (Utils::HostOsInfo::isMacHost()) {
xtermArgs << (QCoreApplication::applicationDirPath()
+ QLatin1String("/../Resources/qtcreator_process_stub"));
} else {
xtermArgs << (QCoreApplication::applicationDirPath()
+ QLatin1String("/qtcreator_process_stub"));
}
xtermArgs
QString stubPath = QCoreApplication::applicationDirPath();
if (Utils::HostOsInfo::isMacHost())
stubPath.append(QLatin1String("/../Resources/qtcreator_process_stub"));
else
stubPath.append(QLatin1String("/qtcreator_process_stub"));
QStringList allArgs = xtermArgs.toUnixArgs();
allArgs << stubPath
<< modeOption(d->m_mode)
<< d->m_stubServer.fullServerName()
<< msgPromptToClose()
<< workingDirectory()
<< (d->m_tempFile ? d->m_tempFile->fileName() : QString())
<< pcmd << pargs;
<< pcmd << pargs.toUnixArgs();
QString xterm = xtermArgs.takeFirst();
d->m_process.start(xterm, xtermArgs);
QString xterm = allArgs.takeFirst();
d->m_process.start(xterm, allArgs);
if (!d->m_process.waitForStarted()) {
stubServerShutdown();
emit processError(tr("Cannot start the terminal emulator '%1', change the setting in the "
......
......@@ -75,7 +75,10 @@ bool ConsoleProcess::start(const QString &program, const QString &args)
pcmd = program;
pargs = args;
} else {
QtcProcess::prepareCommand(program, args, &pcmd, &pargs, &d->m_environment, &d->m_workingDir);
QtcProcess::Arguments outArgs;
QtcProcess::prepareCommand(program, args, &pcmd, &outArgs, OsTypeWindows,
&d->m_environment, &d->m_workingDir);
pargs = outArgs.toWindowsArgs();
}
const QString err = stubServerListen();
......
This diff is collapsed.
......@@ -56,6 +56,22 @@ public:
void terminate();
void interrupt();
class QTCREATOR_UTILS_EXPORT Arguments
{
public:
static Arguments createWindowsArgs(const QString &args);
static Arguments createUnixArgs(const QStringList &args);
QString toWindowsArgs() const;
QStringList toUnixArgs() const;
QString toString() const;
private:
QString m_windowsArgs;
QStringList m_unixArgs;
bool m_isWindows;
};
enum SplitError {
SplitOk = 0, //! All went just fine
BadQuoting, //! Command contains quoting errors
......@@ -64,45 +80,33 @@ public:
//! Quote a single argument for usage in a unix shell command
static QString quoteArgUnix(const QString &arg);
//! Quote a single argument and append it to a unix shell command
static void addArgUnix(QString *args, const QString &arg);
//! Join an argument list into a unix shell command
static QString joinArgsUnix(const QStringList &args);
#ifdef Q_OS_WIN
//! Quote a single argument for usage in a shell command
static QString quoteArg(const QString &arg);
static QString quoteArg(const QString &arg, OsType osType = HostOsInfo::hostOs());
//! Quote a single argument and append it to a shell command
static void addArg(QString *args, const QString &arg);
static void addArg(QString *args, const QString &arg, OsType osType = HostOsInfo::hostOs());
//! Join an argument list into a shell command
static QString joinArgs(const QStringList &args);
static QString joinArgs(const QStringList &args, OsType osType = HostOsInfo::hostOs());
//! Prepare argument of a shell command for feeding into QProcess
static QString prepareArgs(const QString &cmd, SplitError *err,
const Environment *env = 0, const QString *pwd = 0);
static Arguments prepareArgs(const QString &cmd, SplitError *err,
OsType osType = HostOsInfo::hostOs(),
const Environment *env = 0, const QString *pwd = 0);
//! Prepare a shell command for feeding into QProcess
static void prepareCommand(const QString &command, const QString &arguments,
QString *outCmd, QString *outArgs,
const Environment *env = 0, const QString *pwd = 0);
#else
static QString quoteArg(const QString &arg) { return quoteArgUnix(arg); }
static void addArg(QString *args, const QString &arg) { addArgUnix(args, arg); }
static QString joinArgs(const QStringList &args) { return joinArgsUnix(args); }
static QStringList prepareArgs(const QString &cmd, SplitError *err,
const Environment *env = 0, const QString *pwd = 0)
{ return splitArgs(cmd, true, err, env, pwd); }
static bool prepareCommand(const QString &command, const QString &arguments,
QString *outCmd, QStringList *outArgs,
QString *outCmd, Arguments *outArgs, OsType osType = HostOsInfo::hostOs(),
const Environment *env = 0, const QString *pwd = 0);
#endif
//! Quote and append each argument to a shell command
static void addArgs(QString *args, const QStringList &inArgs);
//! Append already quoted arguments to a shell command
static void addArgs(QString *args, const QString &inArgs);
//! Split a shell command into separate arguments. ArgIterator is usually a better choice.
static QStringList splitArgs(const QString &cmd, bool abortOnMeta = false, SplitError *err = 0,
static QStringList splitArgs(const QString &cmd, OsType osType = HostOsInfo::hostOs(),
bool abortOnMeta = false, SplitError *err = 0,
const Environment *env = 0, const QString *pwd = 0);
//! Safely replace the expandos in a shell command
static bool expandMacros(QString *cmd, AbstractMacroExpander *mx);
static QString expandMacros(const QString &str, AbstractMacroExpander *mx);
static bool expandMacros(QString *cmd, AbstractMacroExpander *mx,
OsType osType = HostOsInfo::hostOs());
static QString expandMacros(const QString &str, AbstractMacroExpander *mx,
OsType osType = HostOsInfo::hostOs());
/*! Iterate over arguments from a command line.
* Assumes that the name of the actual command is *not* part of the line.
......@@ -110,7 +114,9 @@ public:
*/
class QTCREATOR_UTILS_EXPORT ArgIterator {
public:
ArgIterator(QString *str) : m_str(str), m_pos(0), m_prev(-1) {}
ArgIterator(QString *str, OsType osType = HostOsInfo::hostOs())
: m_str(str), m_pos(0), m_prev(-1), m_osType(osType)
{}
//! Get the next argument. Returns false on encountering end of first command.
bool next();
//! True iff the argument is a plain string, possibly after unquoting.
......@@ -126,11 +132,14 @@ public:
QString *m_str, m_value;
int m_pos, m_prev;
bool m_simple;
OsType m_osType;
};
class QTCREATOR_UTILS_EXPORT ConstArgIterator {
public:
ConstArgIterator(const QString &str) : m_str(str), m_ait(&m_str) {}
ConstArgIterator(const QString &str, OsType osType = HostOsInfo::hostOs())
: m_str(str), m_ait(&m_str, osType)
{}
bool next() { return m_ait.next(); }
bool isSimple() const { return m_ait.isSimple(); }
QString value() const { return m_ait.value(); }
......
......@@ -121,13 +121,14 @@ void FileUtils::openTerminal(const QString &path)
// Get terminal application
QString terminalEmulator;
QStringList args;
if (HostOsInfo::isWindowsHost()) {
const OsType hostOs = HostOsInfo::hostOs();
if (hostOs == OsTypeWindows) {
terminalEmulator = ConsoleProcess::defaultTerminalEmulator();
} else if (HostOsInfo::isMacHost()) {
} else if (hostOs == OsTypeMac) {
terminalEmulator = ICore::resourcePath()
+ QLatin1String("/scripts/openTerminal.command");
} else {
args = QtcProcess::splitArgs(ConsoleProcess::terminalEmulator(ICore::settings()));
args = QtcProcess::splitArgs(ConsoleProcess::terminalEmulator(ICore::settings()), hostOs);
terminalEmulator = args.takeFirst();
args.append(QString::fromLocal8Bit(qgetenv("SHELL")));
}
......
......@@ -4771,19 +4771,20 @@ void GdbEngine::write(const QByteArray &data)
bool GdbEngine::prepareCommand()
{
#ifdef Q_OS_WIN
Utils::QtcProcess::SplitError perr;
startParameters().processArgs = Utils::QtcProcess::prepareArgs(
startParameters().processArgs, &perr,
&startParameters().environment, &startParameters().workingDirectory);
if (perr != Utils::QtcProcess::SplitOk) {
// perr == BadQuoting is never returned on Windows
// FIXME? QTCREATORBUG-2809
handleAdapterStartFailed(QCoreApplication::translate("DebuggerEngine", // Same message in CdbEngine
"Debugging complex command lines is currently not supported on Windows."), Core::Id());
return false;
if (HostOsInfo::isWindowsHost()) {
DebuggerStartParameters &sp = startParameters();
QtcProcess::SplitError perr;
sp.processArgs = QtcProcess::prepareArgs(sp.processArgs, &perr,
Utils::HostOsInfo::hostOs(),
&sp.environment, &sp.workingDirectory).toWindowsArgs();
if (perr != Utils::QtcProcess::SplitOk) {
// perr == BadQuoting is never returned on Windows
// FIXME? QTCREATORBUG-2809
handleAdapterStartFailed(QCoreApplication::translate("DebuggerEngine", // Same message in CdbEngine
"Debugging complex command lines is currently not supported on Windows."), Core::Id());
return false;
}
}
#endif
return true;
}
......
......@@ -201,11 +201,7 @@ void LldbEngine::setupInferior()
const DebuggerStartParameters &sp = startParameters();
QString executable;
#ifdef Q_OS_WIN
QString args;
#else
QStringList args;
#endif
Utils::QtcProcess::Arguments args;
Utils::QtcProcess::prepareCommand(QFileInfo(sp.executable).absoluteFilePath(),
sp.processArgs, &executable, &args);
......@@ -213,12 +209,8 @@ void LldbEngine::setupInferior()
cmd.arg("executable", executable);
cmd.arg("startMode", sp.startMode); // directly relying on this is brittle wrt. insertions, so check it here
cmd.beginList("processArgs");
#ifdef Q_OS_WIN
// fixme?
#else
foreach (const QString &arg, args)
foreach (const QString &arg, args.toUnixArgs())
cmd.arg(arg.toUtf8().toHex());
#endif
cmd.endList();
// it is better not to check the start mode on the python sid (as we would have to duplicate the
......
......@@ -2990,7 +2990,7 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
VcsBase::VcsBaseOutputWindow *outwin = VcsBase::VcsBaseOutputWindow::instance();
const QString gitkOpts = settings()->stringValue(GitSettings::gitkOptionsKey);
if (!gitkOpts.isEmpty())
arguments.append(Utils::QtcProcess::splitArgs(gitkOpts));
arguments.append(Utils::QtcProcess::splitArgs(gitkOpts, Utils::HostOsInfo::hostOs()));
if (!fileName.isEmpty())
arguments << QLatin1String("--") << fileName;
outwin->appendCommand(workingDirectory, binary, arguments);
......
......@@ -51,6 +51,7 @@
using namespace ProjectExplorer;
using namespace QmakeProjectManager;
using namespace Utils;
namespace Ios {
namespace Internal {
......@@ -341,27 +342,27 @@ QString IosRunConfigurationWidget::argListToString(const QStringList &args) cons
QStringList IosRunConfigurationWidget::stringToArgList(const QString &args) const
{
Utils::QtcProcess::SplitError err;
QStringList res = Utils::QtcProcess::splitArgs(args, false, &err);
QtcProcess::SplitError err;
QStringList res = QtcProcess::splitArgs(args, OsTypeMac, false, &err);
switch (err) {
case Utils::QtcProcess::SplitOk:
case QtcProcess::SplitOk:
break;
case Utils::QtcProcess::BadQuoting:
case QtcProcess::BadQuoting:
if (args.at(args.size()-1) == QLatin1Char('\\')) {
res = Utils::QtcProcess::splitArgs(args + QLatin1Char('\\'), false, &err);
if (err != Utils::QtcProcess::SplitOk)
res = Utils::QtcProcess::splitArgs(args + QLatin1Char('\\') + QLatin1Char('\''),
false, &err);
if (err != Utils::QtcProcess::SplitOk)
res = Utils::QtcProcess::splitArgs(args + QLatin1Char('\\') + QLatin1Char('\"'),
false, &err);
res = QtcProcess::splitArgs(args + QLatin1Char('\\'), OsTypeMac, false, &err);
if (err != QtcProcess::SplitOk)
res = QtcProcess::splitArgs(args + QLatin1Char('\\') + QLatin1Char('\''),
OsTypeMac, false, &err);
if (err != QtcProcess::SplitOk)
res = QtcProcess::splitArgs(args + QLatin1Char('\\') + QLatin1Char('\"'),
OsTypeMac, false, &err);
}
if (err != Utils::QtcProcess::SplitOk)
res = Utils::QtcProcess::splitArgs(args + QLatin1Char('\''), false, &err);
if (err != Utils::QtcProcess::SplitOk)
res = Utils::QtcProcess::splitArgs(args + QLatin1Char('\"'), false, &err);
if (err != QtcProcess::SplitOk)
res = QtcProcess::splitArgs(args + QLatin1Char('\''), OsTypeMac, false, &err);
if (err != QtcProcess::SplitOk)
res = QtcProcess::splitArgs(args + QLatin1Char('\"'), OsTypeMac, false, &err);
break;
case Utils::QtcProcess::FoundMeta:
case QtcProcess::FoundMeta:
qDebug() << "IosRunConfigurationWidget FoundMeta (should not happen)";
break;
}
......
......@@ -928,13 +928,14 @@ void GccToolChainConfigWidget::makeReadOnlyImpl()
QStringList GccToolChainConfigWidget::splitString(const QString &s)
{
QtcProcess::SplitError splitError;
QStringList res = QtcProcess::splitArgs(s, false, &splitError);
const OsType osType = HostOsInfo::hostOs();
QStringList res = QtcProcess::splitArgs(s, osType, false, &splitError);
if (splitError != QtcProcess::SplitOk){
res = QtcProcess::splitArgs(s + QLatin1Char('\\'), false, &splitError);
res = QtcProcess::splitArgs(s + QLatin1Char('\\'), osType, false, &splitError);
if (splitError != QtcProcess::SplitOk){
res = QtcProcess::splitArgs(s + QLatin1Char('"'), false, &splitError);
res = QtcProcess::splitArgs(s + QLatin1Char('"'), osType, false, &splitError);
if (splitError != QtcProcess::SplitOk)
res = QtcProcess::splitArgs(s + QLatin1Char('\''), false, &splitError);
res = QtcProcess::splitArgs(s + QLatin1Char('\''), osType, false, &splitError);
}
}
return res;
......
......@@ -169,20 +169,12 @@ QString ProcessParameters::prettyArguments() const
{
QString margs = effectiveArguments();
QString workDir = effectiveWorkingDirectory();
#ifdef Q_OS_WIN
QString args;
#else
QStringList args;
#endif
Utils::QtcProcess::SplitError err;
args = Utils::QtcProcess::prepareArgs(margs, &err, &m_environment, &workDir);
Utils::QtcProcess::Arguments args =
Utils::QtcProcess::prepareArgs(margs, &err, Utils::HostOsInfo::hostOs(), &m_environment, &workDir);
if (err != Utils::QtcProcess::SplitOk)
return margs; // Sorry, too complex - just fall back.
#ifdef Q_OS_WIN
return args;
#else
return Utils::QtcProcess::joinArgs(args);
#endif
return args.toString();
}
QString ProcessParameters::summary(const QString &displayName) const
......
......@@ -69,7 +69,7 @@ QString LinuxDeviceProcess::fullCommandLine() const
fullCommandLine.append(quote(executable()));
if (!arguments().isEmpty()) {
fullCommandLine.append(QLatin1Char(' '));
fullCommandLine.append(Utils::QtcProcess::joinArgsUnix(arguments()));
fullCommandLine.append(Utils::QtcProcess::joinArgs(arguments(), Utils::OsTypeLinux));
}
return fullCommandLine;
}
......
......@@ -207,7 +207,7 @@ QString RemoteLinuxRunConfiguration::remoteExecutableFilePath() const
void RemoteLinuxRunConfiguration::setArguments(const QString &args)
{
d->arguments = QtcProcess::splitArgs(args); // TODO: Widget should be list-based.
d->arguments = QtcProcess::splitArgs(args, OsTypeLinux); // TODO: Widget should be list-based.
}
QString RemoteLinuxRunConfiguration::workingDirectory() const
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment