summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@digia.com>2013-09-03 21:52:22 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-05 21:17:39 +0200
commitfba0a307914772b286e8f315e0d1dec5ce7935f8 (patch)
tree10908de0f4da40445ff5db2072a7e7ccc532a0ef
parentdd9d6b3d5b21281707440db4413707e1d818889e (diff)
add QProcess::Forwarded{Output,Error}Channel
Change-Id: Ifc5ed20c38f3228ef25c28681f296d0456b61abe Reviewed-by: Simon Hausmann <simon.hausmann@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
-rw-r--r--src/corelib/io/qprocess.cpp17
-rw-r--r--src/corelib/io/qprocess.h4
-rw-r--r--src/corelib/io/qprocess_unix.cpp15
-rw-r--r--src/corelib/io/qprocess_win.cpp6
-rw-r--r--tests/auto/corelib/io/qprocess/testForwarding/main.cpp21
-rw-r--r--tests/auto/corelib/io/qprocess/tst_qprocess.cpp31
6 files changed, 79 insertions, 15 deletions
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index d473281acc..27a8bce3fe 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -533,7 +533,11 @@ void QProcessPrivate::Channel::clear()
MergedChannels before starting the process to activative
this feature. You also have the option of forwarding the output of
the running process to the calling, main process, by passing
- ForwardedChannels as the argument.
+ ForwardedChannels as the argument. It is also possible to forward
+ only one of the output channels - typically one would use
+ ForwardedErrorChannel, but ForwardedOutputChannel also exists.
+ Note that using channel forwarding is typically a bad idea in GUI
+ applications - you should present errors graphically instead.
Certain processes need special environment settings in order to
operate. You can set environment variables for your process by
@@ -625,6 +629,17 @@ void QProcessPrivate::Channel::clear()
writes to its standard output and standard error will be written
to the standard output and standard error of the main process.
+ \value ForwardedErrorChannel QProcess manages the standard output
+ of the running process, but forwards its standard error onto the
+ main process. This reflects the typical use of command line tools
+ as filters, where the standard output is redirected to another
+ process or a file, while standard error is printed to the console
+ for diagnostic purposes.
+ (This value was introduced in Qt 5.2.)
+
+ \value ForwardedOutputChannel Complementary to ForwardedErrorChannel.
+ (This value was introduced in Qt 5.2.)
+
\note Windows intentionally suppresses output from GUI-only
applications to inherited consoles.
This does \e not apply to output redirected to files or pipes.
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 2919788e34..0984d501fd 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -124,7 +124,9 @@ public:
enum ProcessChannelMode {
SeparateChannels,
MergedChannels,
- ForwardedChannels
+ ForwardedChannels,
+ ForwardedOutputChannel,
+ ForwardedErrorChannel
};
enum ExitStatus {
NormalExit,
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index bc0ae5a382..0e0ead5897 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -813,6 +813,16 @@ pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **en
fd_map[1] = QT_FILENO(stdout);
fd_map[2] = QT_FILENO(stderr);
break;
+ case QProcess::ForwardedOutputChannel:
+ fd_map[0] = stdinChannel.pipe[0];
+ fd_map[1] = QT_FILENO(stdout);
+ fd_map[2] = stderrChannel.pipe[1];
+ break;
+ case QProcess::ForwardedErrorChannel:
+ fd_map[0] = stdinChannel.pipe[0];
+ fd_map[1] = stdoutChannel.pipe[1];
+ fd_map[2] = QT_FILENO(stderr);
+ break;
case QProcess::MergedChannels:
fd_map[0] = stdinChannel.pipe[0];
fd_map[1] = stdoutChannel.pipe[1];
@@ -850,12 +860,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
// copy the stdout and stderr if asked to
if (processChannelMode != QProcess::ForwardedChannels) {
- qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0);
+ if (processChannelMode != QProcess::ForwardedOutputChannel)
+ qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0);
// merge stdout and stderr if asked to
if (processChannelMode == QProcess::MergedChannels) {
qt_safe_dup2(fileno(stdout), fileno(stderr), 0);
- } else {
+ } else if (processChannelMode != QProcess::ForwardedErrorChannel) {
qt_safe_dup2(stderrChannel.pipe[1], fileno(stderr), 0);
}
}
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 880cbf659d..f545386f56 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -160,7 +160,8 @@ bool QProcessPrivate::createChannel(Channel &channel)
} else {
QWindowsPipeReader *pipeReader = 0;
if (&channel == &stdoutChannel) {
- if (processChannelMode != QProcess::ForwardedChannels) {
+ if (processChannelMode != QProcess::ForwardedChannels
+ && processChannelMode != QProcess::ForwardedOutputChannel) {
if (!stdoutReader) {
stdoutReader = new QWindowsPipeReader(q);
q->connect(stdoutReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput()));
@@ -170,7 +171,8 @@ bool QProcessPrivate::createChannel(Channel &channel)
duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE);
}
} else /* if (&channel == &stderrChannel) */ {
- if (processChannelMode != QProcess::ForwardedChannels) {
+ if (processChannelMode != QProcess::ForwardedChannels
+ && processChannelMode != QProcess::ForwardedErrorChannel) {
if (!stderrReader) {
stderrReader = new QWindowsPipeReader(q);
q->connect(stderrReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
diff --git a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
index 3122232ee1..deff2b95ad 100644
--- a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
+++ b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
@@ -42,30 +42,41 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
+#include <stdlib.h>
+
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
+ if (argc < 2)
+ return 13;
+
#ifndef QT_NO_PROCESS
QProcess process;
- process.setProcessChannelMode(QProcess::ForwardedChannels);
- if (process.processChannelMode() != QProcess::ForwardedChannels)
+
+ QProcess::ProcessChannelMode mode = (QProcess::ProcessChannelMode)atoi(argv[1]);
+ process.setProcessChannelMode(mode);
+ if (process.processChannelMode() != mode)
return 1;
- process.start("testProcessEcho/testProcessEcho");
+ process.start("testProcessEcho2/testProcessEcho2");
if (!process.waitForStarted(5000))
return 2;
- if (process.write("forwarded\n") != 10)
+ if (process.write("forwarded") != 9)
return 3;
process.closeWriteChannel();
if (!process.waitForFinished(5000))
return 4;
- if (process.bytesAvailable() != 0)
+ if ((mode == QProcess::ForwardedOutputChannel || mode == QProcess::ForwardedChannels)
+ && !process.readAllStandardOutput().isEmpty())
return 5;
+ if ((mode == QProcess::ForwardedErrorChannel || mode == QProcess::ForwardedChannels)
+ && !process.readAllStandardError().isEmpty())
+ return 6;
#endif
return 0;
}
diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
index 183f827836..e03c1fb75e 100644
--- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
+++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
@@ -107,6 +107,7 @@ private slots:
void softExitInSlots_data();
void softExitInSlots();
void mergedChannels();
+ void forwardedChannels_data();
void forwardedChannels();
void atEnd();
void atEnd2();
@@ -1089,10 +1090,31 @@ void tst_QProcess::mergedChannels()
//-----------------------------------------------------------------------------
#ifndef Q_OS_WINCE
// Reading and writing to a process is not supported on Qt/CE
+
+void tst_QProcess::forwardedChannels_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<QByteArray>("outdata");
+ QTest::addColumn<QByteArray>("errdata");
+
+ QTest::newRow("separate") << int(QProcess::SeparateChannels)
+ << QByteArray() << QByteArray();
+ QTest::newRow("forwarded") << int(QProcess::ForwardedChannels)
+ << QByteArray("forwarded") << QByteArray("forwarded");
+ QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel)
+ << QByteArray("forwarded") << QByteArray();
+ QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel)
+ << QByteArray() << QByteArray("forwarded");
+}
+
void tst_QProcess::forwardedChannels()
{
+ QFETCH(int, mode);
+ QFETCH(QByteArray, outdata);
+ QFETCH(QByteArray, errdata);
+
QProcess process;
- process.start("testForwarding/testForwarding");
+ process.start("testForwarding/testForwarding", QStringList() << QString::number(mode));
QVERIFY(process.waitForStarted(5000));
QVERIFY(process.waitForFinished(5000));
const char *err;
@@ -1103,12 +1125,13 @@ void tst_QProcess::forwardedChannels()
case 3: err = "failed to write"; break;
case 4: err = "did not finish"; break;
case 5: err = "unexpected stdout"; break;
+ case 6: err = "unexpected stderr"; break;
+ case 13: err = "parameter error"; break;
default: err = "unknown exit code"; break;
}
QVERIFY2(!process.exitCode(), err);
- QByteArray data = process.readAll();
- QVERIFY(!data.isEmpty());
- QVERIFY(data.contains("forwarded"));
+ QCOMPARE(process.readAllStandardOutput(), outdata);
+ QCOMPARE(process.readAllStandardError(), errdata);
}
#endif