add QProcess::InputChannelMode
this enables forwarding standard input from the parent process. Change-Id: I7ee72b9842acc96320d4da693b95dd15d9a7b4d4 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Olivier Goffart <ogoffart@woboq.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
This commit is contained in:
parent
fba0a30791
commit
50a8a5e795
@ -608,8 +608,8 @@ void QProcessPrivate::Channel::clear()
|
||||
/*!
|
||||
\enum QProcess::ProcessChannelMode
|
||||
|
||||
This enum describes the process channel modes of QProcess. Pass
|
||||
one of these values to setProcessChannelMode() to set the
|
||||
This enum describes the process output channel modes of QProcess.
|
||||
Pass one of these values to setProcessChannelMode() to set the
|
||||
current read channel mode.
|
||||
|
||||
\value SeparateChannels QProcess manages the output of the
|
||||
@ -651,6 +651,26 @@ void QProcessPrivate::Channel::clear()
|
||||
\sa setProcessChannelMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QProcess::InputChannelMode
|
||||
\since 5.2
|
||||
|
||||
This enum describes the process input channel modes of QProcess.
|
||||
Pass one of these values to setInputChannelMode() to set the
|
||||
current write channel mode.
|
||||
|
||||
\value ManagedInputChannel QProcess manages the input of the running
|
||||
process. This is the default input channel mode of QProcess.
|
||||
|
||||
\value ForwardedInputChannel QProcess forwards the input of the main
|
||||
process onto the running process. The child process reads its standard
|
||||
input from the same source as the main process.
|
||||
Note that the main process must not try to read its standard input
|
||||
while the child process is running.
|
||||
|
||||
\sa setInputChannelMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QProcess::ProcessError
|
||||
|
||||
@ -779,6 +799,7 @@ QProcessPrivate::QProcessPrivate()
|
||||
{
|
||||
processChannel = QProcess::StandardOutput;
|
||||
processChannelMode = QProcess::SeparateChannels;
|
||||
inputChannelMode = QProcess::ManagedInputChannel;
|
||||
processError = QProcess::UnknownError;
|
||||
processState = QProcess::NotRunning;
|
||||
pid = 0;
|
||||
@ -1243,6 +1264,34 @@ void QProcess::setProcessChannelMode(ProcessChannelMode mode)
|
||||
d->processChannelMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.2
|
||||
|
||||
Returns the channel mode of the QProcess standard input channel.
|
||||
|
||||
\sa setInputChannelMode(), InputChannelMode
|
||||
*/
|
||||
QProcess::InputChannelMode QProcess::inputChannelMode() const
|
||||
{
|
||||
Q_D(const QProcess);
|
||||
return d->inputChannelMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.2
|
||||
|
||||
Sets the channel mode of the QProcess standard intput
|
||||
channel to the \a mode specified.
|
||||
This mode will be used the next time start() is called.
|
||||
|
||||
\sa inputChannelMode(), InputChannelMode
|
||||
*/
|
||||
void QProcess::setInputChannelMode(InputChannelMode mode)
|
||||
{
|
||||
Q_D(QProcess);
|
||||
d->inputChannelMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current read channel of the QProcess.
|
||||
|
||||
|
@ -128,6 +128,10 @@ public:
|
||||
ForwardedOutputChannel,
|
||||
ForwardedErrorChannel
|
||||
};
|
||||
enum InputChannelMode {
|
||||
ManagedInputChannel,
|
||||
ForwardedInputChannel
|
||||
};
|
||||
enum ExitStatus {
|
||||
NormalExit,
|
||||
CrashExit
|
||||
@ -151,6 +155,8 @@ public:
|
||||
void setReadChannelMode(ProcessChannelMode mode);
|
||||
ProcessChannelMode processChannelMode() const;
|
||||
void setProcessChannelMode(ProcessChannelMode mode);
|
||||
InputChannelMode inputChannelMode() const;
|
||||
void setInputChannelMode(InputChannelMode mode);
|
||||
|
||||
ProcessChannel readChannel() const;
|
||||
void setReadChannel(ProcessChannel channel);
|
||||
|
@ -302,6 +302,7 @@ public:
|
||||
|
||||
QProcess::ProcessChannel processChannel;
|
||||
QProcess::ProcessChannelMode processChannelMode;
|
||||
QProcess::InputChannelMode inputChannelMode;
|
||||
QProcess::ProcessError processError;
|
||||
QProcess::ProcessState processState;
|
||||
QString workingDirectory;
|
||||
|
@ -807,29 +807,29 @@ pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **en
|
||||
? i : SPAWN_FDCLOSED;
|
||||
}
|
||||
|
||||
if (inputChannelMode == QProcess::ManagedInputChannel)
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
else
|
||||
fd_map[0] = QT_FILENO(stdin);
|
||||
|
||||
switch (processChannelMode) {
|
||||
case QProcess::ForwardedChannels:
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
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];
|
||||
fd_map[2] = stdoutChannel.pipe[1];
|
||||
break;
|
||||
case QProcess::SeparateChannels:
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
fd_map[1] = stdoutChannel.pipe[1];
|
||||
fd_map[2] = stderrChannel.pipe[1];
|
||||
break;
|
||||
@ -855,8 +855,9 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
||||
|
||||
Q_Q(QProcess);
|
||||
|
||||
// copy the stdin socket (without closing on exec)
|
||||
qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0);
|
||||
// copy the stdin socket if asked to (without closing on exec)
|
||||
if (inputChannelMode != QProcess::ForwardedInputChannel)
|
||||
qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0);
|
||||
|
||||
// copy the stdout and stderr if asked to
|
||||
if (processChannelMode != QProcess::ForwardedChannels) {
|
||||
|
@ -156,7 +156,15 @@ bool QProcessPrivate::createChannel(Channel &channel)
|
||||
if (channel.type == Channel::Normal) {
|
||||
// we're piping this channel to our own process
|
||||
if (&channel == &stdinChannel) {
|
||||
qt_create_pipe(channel.pipe, true);
|
||||
if (inputChannelMode != QProcess::ForwardedInputChannel) {
|
||||
qt_create_pipe(channel.pipe, true);
|
||||
} else {
|
||||
channel.pipe[1] = INVALID_Q_PIPE;
|
||||
HANDLE hStdReadChannel = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE hCurrentProcess = GetCurrentProcess();
|
||||
DuplicateHandle(hCurrentProcess, hStdReadChannel, hCurrentProcess,
|
||||
&channel.pipe[0], 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||
}
|
||||
} else {
|
||||
QWindowsPipeReader *pipeReader = 0;
|
||||
if (&channel == &stdoutChannel) {
|
||||
|
@ -48,7 +48,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if (argc < 2)
|
||||
if (argc < 3)
|
||||
return 13;
|
||||
|
||||
#ifndef QT_NO_PROCESS
|
||||
@ -59,12 +59,17 @@ int main(int argc, char **argv)
|
||||
if (process.processChannelMode() != mode)
|
||||
return 1;
|
||||
|
||||
QProcess::InputChannelMode inmode = (QProcess::InputChannelMode)atoi(argv[2]);
|
||||
process.setInputChannelMode(inmode);
|
||||
if (process.inputChannelMode() != inmode)
|
||||
return 11;
|
||||
|
||||
process.start("testProcessEcho2/testProcessEcho2");
|
||||
|
||||
if (!process.waitForStarted(5000))
|
||||
return 2;
|
||||
|
||||
if (process.write("forwarded") != 9)
|
||||
if (inmode == QProcess::ManagedInputChannel && process.write("forwarded") != 9)
|
||||
return 3;
|
||||
|
||||
process.closeWriteChannel();
|
||||
|
@ -1094,33 +1094,40 @@ void tst_QProcess::mergedChannels()
|
||||
void tst_QProcess::forwardedChannels_data()
|
||||
{
|
||||
QTest::addColumn<int>("mode");
|
||||
QTest::addColumn<int>("inmode");
|
||||
QTest::addColumn<QByteArray>("outdata");
|
||||
QTest::addColumn<QByteArray>("errdata");
|
||||
|
||||
QTest::newRow("separate") << int(QProcess::SeparateChannels)
|
||||
QTest::newRow("separate") << int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel)
|
||||
<< QByteArray() << QByteArray();
|
||||
QTest::newRow("forwarded") << int(QProcess::ForwardedChannels)
|
||||
QTest::newRow("forwarded") << int(QProcess::ForwardedChannels) << int(QProcess::ManagedInputChannel)
|
||||
<< QByteArray("forwarded") << QByteArray("forwarded");
|
||||
QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel)
|
||||
QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel) << int(QProcess::ManagedInputChannel)
|
||||
<< QByteArray("forwarded") << QByteArray();
|
||||
QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel)
|
||||
QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ManagedInputChannel)
|
||||
<< QByteArray() << QByteArray("forwarded");
|
||||
QTest::newRow("fwdinput") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ForwardedInputChannel)
|
||||
<< QByteArray() << QByteArray("input");
|
||||
}
|
||||
|
||||
void tst_QProcess::forwardedChannels()
|
||||
{
|
||||
QFETCH(int, mode);
|
||||
QFETCH(int, inmode);
|
||||
QFETCH(QByteArray, outdata);
|
||||
QFETCH(QByteArray, errdata);
|
||||
|
||||
QProcess process;
|
||||
process.start("testForwarding/testForwarding", QStringList() << QString::number(mode));
|
||||
process.start("testForwarding/testForwarding", QStringList() << QString::number(mode) << QString::number(inmode));
|
||||
QVERIFY(process.waitForStarted(5000));
|
||||
QCOMPARE(process.write("input"), 5);
|
||||
process.closeWriteChannel();
|
||||
QVERIFY(process.waitForFinished(5000));
|
||||
const char *err;
|
||||
switch (process.exitCode()) {
|
||||
case 0: err = "ok"; break;
|
||||
case 1: err = "processChannelMode is wrong"; break;
|
||||
case 11: err = "inputChannelMode is wrong"; break;
|
||||
case 2: err = "failed to start"; break;
|
||||
case 3: err = "failed to write"; break;
|
||||
case 4: err = "did not finish"; break;
|
||||
|
Loading…
Reference in New Issue
Block a user