forked from qt-creator/qt-creator
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: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
This commit is contained in:
@@ -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();
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user