From 4fe7291edcac2688f042a11ff5c23374c6c0375d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 6 Jul 2010 13:56:38 +0200 Subject: add setNativeArguments() and nativeArguments() this function enables starting subprocesses which need command lines which cannot be constructed via the portable list-based api. such cases would be programs which need quoting rules which diverge from the msvc runtime. Reviewed-by: joerg Task-number: QTBUG-7620 (and various others which boil down to that) --- src/corelib/io/qprocess.cpp | 44 ++++++++++++++++++ src/corelib/io/qprocess.h | 5 +++ src/corelib/io/qprocess_p.h | 3 ++ src/corelib/io/qprocess_symbian.cpp | 17 ++++--- src/corelib/io/qprocess_win.cpp | 5 +++ src/s60installs/bwins/QtCoreu.def | 2 + src/s60installs/eabi/QtCoreu.def | 2 + tests/auto/qprocess/testProcessSpacesArgs/main.cpp | 7 ++- tests/auto/qprocess/tst_qprocess.cpp | 52 ++++++++++++++++++++++ 9 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 4c21a40..9bc4063 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1377,6 +1377,50 @@ void QProcess::setStandardOutputProcess(QProcess *destination) dto->stdinChannel.pipeFrom(dfrom); } +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + +/*! + \since 4.7 + + Returns the additional native command line arguments for the program. + + \note This function is available only on the Windows and Symbian + platforms. + + \sa setNativeArguments() +*/ +QString QProcess::nativeArguments() const +{ + Q_D(const QProcess); + return d->nativeArguments; +} + +/*! + \since 4.7 + \overload + + Sets additional native command line arguments for the program. + + On operating systems where the system API for passing command line + arguments to a subprocess natively uses a single string, one can + conceive command lines which cannot be passed via QProcess's portable + list-based API. In such cases this function must be used to set a + string which is \e appended to the string composed from the usual + argument list, with a delimiting space. + + \note This function is available only on the Windows and Symbian + platforms. + + \sa nativeArguments() +*/ +void QProcess::setNativeArguments(const QString &arguments) +{ + Q_D(QProcess); + d->nativeArguments = arguments; +} + +#endif + /*! If QProcess has been assigned a working directory, this function returns the working directory that the QProcess will enter before the program has diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index f84b855..b07d742 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -148,6 +148,11 @@ public: void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate); void setStandardOutputProcess(QProcess *destination); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QString nativeArguments() const; + void setNativeArguments(const QString &arguments); +#endif + QString workingDirectory() const; void setWorkingDirectory(const QString &dir); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 60b7b5a..8b7e3ff 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -181,6 +181,9 @@ public: QString program; QStringList arguments; +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QString nativeArguments; +#endif QProcessEnvironment environment; QRingBuffer outputReadBuffer; diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp index 92212fe..af657b2 100644 --- a/src/corelib/io/qprocess_symbian.cpp +++ b/src/corelib/io/qprocess_symbian.cpp @@ -219,7 +219,8 @@ static bool qt_rprocess_running(RProcess *proc) return false; } -static void qt_create_symbian_commandline(const QStringList &arguments, QString &commandLine) +static void qt_create_symbian_commandline( + const QStringList &arguments, const QString &nativeArguments, QString &commandLine) { for (int i = 0; i < arguments.size(); ++i) { QString tmp = arguments.at(i); @@ -243,12 +244,14 @@ static void qt_create_symbian_commandline(const QStringList &arguments, QString } } - // Chop the extra trailing space if any arguments were appended - if (arguments.size()) + if (!nativeArguments.isEmpty()) + commandLine += nativeArguments; + else if (!commandLine.isEmpty()) // Chop the extra trailing space if any arguments were appended commandLine.chop(1); } -static TInt qt_create_symbian_process(RProcess **proc, const QString &programName, const QStringList &arguments) +static TInt qt_create_symbian_process(RProcess **proc, + const QString &programName, const QStringList &arguments, const QString &nativeArguments) { RProcess *newProc = NULL; newProc = new RProcess(); @@ -257,7 +260,7 @@ static TInt qt_create_symbian_process(RProcess **proc, const QString &programNam return KErrNoMemory; QString commandLine; - qt_create_symbian_commandline(arguments, commandLine); + qt_create_symbian_commandline(arguments, nativeArguments, commandLine); TPtrC program_ptr(reinterpret_cast(programName.constData())); TPtrC cmdline_ptr(reinterpret_cast(commandLine.constData())); @@ -794,7 +797,7 @@ void QProcessPrivate::startProcess() q, SLOT(_q_processDied())); } - TInt err = qt_create_symbian_process(&symbianProcess, program, arguments); + TInt err = qt_create_symbian_process(&symbianProcess, program, arguments, nativeArguments); if (err == KErrNone) { pid = symbianProcess->Id().Id(); @@ -1030,7 +1033,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a RProcess *newProc = NULL; - TInt err = qt_create_symbian_process(&newProc, program, arguments); + TInt err = qt_create_symbian_process(&newProc, program, arguments, QString()); if (err == KErrNone) { if (pid) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index cb25a58..702349f 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -366,6 +366,11 @@ void QProcessPrivate::startProcess() if (environment.d.constData()) envlist = qt_create_environment(environment.d.constData()->hash); #endif + if (!nativeArguments.isEmpty()) { + if (!args.isEmpty()) + args += QLatin1Char(' '); + args += nativeArguments; + } #if defined QPROCESS_DEBUG qDebug("Creating process"); diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 101c6a8..94be1bb 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4482,4 +4482,6 @@ EXPORTS ?textDirection@QLocale@@QBE?AW4LayoutDirection@Qt@@XZ @ 4481 NONAME ; enum Qt::LayoutDirection QLocale::textDirection(void) const ?peek@QIODevicePrivate@@UAE_JPAD_J@Z @ 4482 NONAME ; long long QIODevicePrivate::peek(char *, long long) ?peek@QIODevicePrivate@@UAE?AVQByteArray@@_J@Z @ 4483 NONAME ; class QByteArray QIODevicePrivate::peek(long long) + ?nativeArguments@QProcess@@QBE?AVQString@@XZ @ 4484 NONAME ; class QString QProcess::nativeArguments(void) const + ?setNativeArguments@QProcess@@QAEXABVQString@@@Z @ 4485 NONAME ; void QProcess::setNativeArguments(class QString const &) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index 7b9e777..46c4885 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3709,4 +3709,6 @@ EXPORTS _ZNK7QString13isRightToLeftEv @ 3708 NONAME _ZN16QIODevicePrivate4peekEPcx @ 3709 NONAME _ZN16QIODevicePrivate4peekEx @ 3710 NONAME + _ZN8QProcess18setNativeArgumentsERK7QString @ 3711 NONAME + _ZNK8QProcess15nativeArgumentsEv @ 3712 NONAME diff --git a/tests/auto/qprocess/testProcessSpacesArgs/main.cpp b/tests/auto/qprocess/testProcessSpacesArgs/main.cpp index d842934..ae5d3ae 100644 --- a/tests/auto/qprocess/testProcessSpacesArgs/main.cpp +++ b/tests/auto/qprocess/testProcessSpacesArgs/main.cpp @@ -44,9 +44,14 @@ int main(int argc, char ** argv) { -#if defined(__SYMBIAN32__) +#if defined(__SYMBIAN32__) || defined(WINCE) || defined(_WIN32_WCE) +# if defined(__SYMBIAN32__) // Printing to stdout messes up the out.txt, so open a file and print there. FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","w+"); +# else + // No pipes on this "OS" + FILE* file = fopen("\\temp\\qprocess_args_test.txt","w+"); +# endif for (int i = 0; i < argc; ++i) { if (i) fprintf(file, "|"); diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index 8242d30..fd310f4 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -132,6 +132,9 @@ private slots: void waitForBytesWrittenInABytesWrittenSlot(); void spaceArgsTest_data(); void spaceArgsTest(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + void nativeArguments(); +#endif void exitCodeTest(); void setEnvironment_data(); void setEnvironment(); @@ -1630,6 +1633,55 @@ void tst_QProcess::spaceArgsTest() process = 0; } +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + +//----------------------------------------------------------------------------- +void tst_QProcess::nativeArguments() +{ + QProcess proc; + + // This doesn't actually need special quoting, so it is pointless to use + // native arguments here, but that's not the point of this test. + proc.setNativeArguments("hello kitty, \"*\"!"); + + proc.start(QString::fromLatin1("testProcessSpacesArgs/nospace"), QStringList()); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(proc.waitForStarted(5000)); + QVERIFY(proc.waitForFinished(5000)); +#else + QVERIFY(proc.waitForStarted(10000)); + QVERIFY(proc.waitForFinished(10000)); +#endif + +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + // Symbian test outputs to a file, so check that +# ifdef Q_OS_SYMBIAN + FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","r"); +# else + FILE* file = fopen("\\temp\\qprocess_args_test.txt","r"); +# endif + char buf[256]; + fgets(buf, 256, file); + fclose(file); + QStringList actual = QString::fromLatin1(buf).split("|"); +#else + QStringList actual = QString::fromLatin1(proc.readAll()).split("|"); +#endif + QVERIFY(!actual.isEmpty()); + // not interested in the program name, it might be different. + actual.removeFirst(); + QStringList expected; +#if defined(Q_OS_WINCE) + expected << "hello" << "kitty," << "\"*\"!"; // Weird, weird ... +#else + expected << "hello" << "kitty," << "*!"; +#endif + QCOMPARE(actual, expected); +} + +#endif + //----------------------------------------------------------------------------- void tst_QProcess::exitCodeTest() { -- cgit v0.12