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
|
\enum QProcess::ProcessChannelMode
|
||||||
|
|
||||||
This enum describes the process channel modes of QProcess. Pass
|
This enum describes the process output channel modes of QProcess.
|
||||||
one of these values to setProcessChannelMode() to set the
|
Pass one of these values to setProcessChannelMode() to set the
|
||||||
current read channel mode.
|
current read channel mode.
|
||||||
|
|
||||||
\value SeparateChannels QProcess manages the output of the
|
\value SeparateChannels QProcess manages the output of the
|
||||||
@ -651,6 +651,26 @@ void QProcessPrivate::Channel::clear()
|
|||||||
\sa setProcessChannelMode()
|
\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
|
\enum QProcess::ProcessError
|
||||||
|
|
||||||
@ -779,6 +799,7 @@ QProcessPrivate::QProcessPrivate()
|
|||||||
{
|
{
|
||||||
processChannel = QProcess::StandardOutput;
|
processChannel = QProcess::StandardOutput;
|
||||||
processChannelMode = QProcess::SeparateChannels;
|
processChannelMode = QProcess::SeparateChannels;
|
||||||
|
inputChannelMode = QProcess::ManagedInputChannel;
|
||||||
processError = QProcess::UnknownError;
|
processError = QProcess::UnknownError;
|
||||||
processState = QProcess::NotRunning;
|
processState = QProcess::NotRunning;
|
||||||
pid = 0;
|
pid = 0;
|
||||||
@ -1243,6 +1264,34 @@ void QProcess::setProcessChannelMode(ProcessChannelMode mode)
|
|||||||
d->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.
|
Returns the current read channel of the QProcess.
|
||||||
|
|
||||||
|
@ -128,6 +128,10 @@ public:
|
|||||||
ForwardedOutputChannel,
|
ForwardedOutputChannel,
|
||||||
ForwardedErrorChannel
|
ForwardedErrorChannel
|
||||||
};
|
};
|
||||||
|
enum InputChannelMode {
|
||||||
|
ManagedInputChannel,
|
||||||
|
ForwardedInputChannel
|
||||||
|
};
|
||||||
enum ExitStatus {
|
enum ExitStatus {
|
||||||
NormalExit,
|
NormalExit,
|
||||||
CrashExit
|
CrashExit
|
||||||
@ -151,6 +155,8 @@ public:
|
|||||||
void setReadChannelMode(ProcessChannelMode mode);
|
void setReadChannelMode(ProcessChannelMode mode);
|
||||||
ProcessChannelMode processChannelMode() const;
|
ProcessChannelMode processChannelMode() const;
|
||||||
void setProcessChannelMode(ProcessChannelMode mode);
|
void setProcessChannelMode(ProcessChannelMode mode);
|
||||||
|
InputChannelMode inputChannelMode() const;
|
||||||
|
void setInputChannelMode(InputChannelMode mode);
|
||||||
|
|
||||||
ProcessChannel readChannel() const;
|
ProcessChannel readChannel() const;
|
||||||
void setReadChannel(ProcessChannel channel);
|
void setReadChannel(ProcessChannel channel);
|
||||||
|
@ -302,6 +302,7 @@ public:
|
|||||||
|
|
||||||
QProcess::ProcessChannel processChannel;
|
QProcess::ProcessChannel processChannel;
|
||||||
QProcess::ProcessChannelMode processChannelMode;
|
QProcess::ProcessChannelMode processChannelMode;
|
||||||
|
QProcess::InputChannelMode inputChannelMode;
|
||||||
QProcess::ProcessError processError;
|
QProcess::ProcessError processError;
|
||||||
QProcess::ProcessState processState;
|
QProcess::ProcessState processState;
|
||||||
QString workingDirectory;
|
QString workingDirectory;
|
||||||
|
@ -807,29 +807,29 @@ pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **en
|
|||||||
? i : SPAWN_FDCLOSED;
|
? i : SPAWN_FDCLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputChannelMode == QProcess::ManagedInputChannel)
|
||||||
|
fd_map[0] = stdinChannel.pipe[0];
|
||||||
|
else
|
||||||
|
fd_map[0] = QT_FILENO(stdin);
|
||||||
|
|
||||||
switch (processChannelMode) {
|
switch (processChannelMode) {
|
||||||
case QProcess::ForwardedChannels:
|
case QProcess::ForwardedChannels:
|
||||||
fd_map[0] = stdinChannel.pipe[0];
|
|
||||||
fd_map[1] = QT_FILENO(stdout);
|
fd_map[1] = QT_FILENO(stdout);
|
||||||
fd_map[2] = QT_FILENO(stderr);
|
fd_map[2] = QT_FILENO(stderr);
|
||||||
break;
|
break;
|
||||||
case QProcess::ForwardedOutputChannel:
|
case QProcess::ForwardedOutputChannel:
|
||||||
fd_map[0] = stdinChannel.pipe[0];
|
|
||||||
fd_map[1] = QT_FILENO(stdout);
|
fd_map[1] = QT_FILENO(stdout);
|
||||||
fd_map[2] = stderrChannel.pipe[1];
|
fd_map[2] = stderrChannel.pipe[1];
|
||||||
break;
|
break;
|
||||||
case QProcess::ForwardedErrorChannel:
|
case QProcess::ForwardedErrorChannel:
|
||||||
fd_map[0] = stdinChannel.pipe[0];
|
|
||||||
fd_map[1] = stdoutChannel.pipe[1];
|
fd_map[1] = stdoutChannel.pipe[1];
|
||||||
fd_map[2] = QT_FILENO(stderr);
|
fd_map[2] = QT_FILENO(stderr);
|
||||||
break;
|
break;
|
||||||
case QProcess::MergedChannels:
|
case QProcess::MergedChannels:
|
||||||
fd_map[0] = stdinChannel.pipe[0];
|
|
||||||
fd_map[1] = stdoutChannel.pipe[1];
|
fd_map[1] = stdoutChannel.pipe[1];
|
||||||
fd_map[2] = stdoutChannel.pipe[1];
|
fd_map[2] = stdoutChannel.pipe[1];
|
||||||
break;
|
break;
|
||||||
case QProcess::SeparateChannels:
|
case QProcess::SeparateChannels:
|
||||||
fd_map[0] = stdinChannel.pipe[0];
|
|
||||||
fd_map[1] = stdoutChannel.pipe[1];
|
fd_map[1] = stdoutChannel.pipe[1];
|
||||||
fd_map[2] = stderrChannel.pipe[1];
|
fd_map[2] = stderrChannel.pipe[1];
|
||||||
break;
|
break;
|
||||||
@ -855,7 +855,8 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
|||||||
|
|
||||||
Q_Q(QProcess);
|
Q_Q(QProcess);
|
||||||
|
|
||||||
// copy the stdin socket (without closing on exec)
|
// copy the stdin socket if asked to (without closing on exec)
|
||||||
|
if (inputChannelMode != QProcess::ForwardedInputChannel)
|
||||||
qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0);
|
qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0);
|
||||||
|
|
||||||
// copy the stdout and stderr if asked to
|
// copy the stdout and stderr if asked to
|
||||||
|
@ -156,7 +156,15 @@ bool QProcessPrivate::createChannel(Channel &channel)
|
|||||||
if (channel.type == Channel::Normal) {
|
if (channel.type == Channel::Normal) {
|
||||||
// we're piping this channel to our own process
|
// we're piping this channel to our own process
|
||||||
if (&channel == &stdinChannel) {
|
if (&channel == &stdinChannel) {
|
||||||
|
if (inputChannelMode != QProcess::ForwardedInputChannel) {
|
||||||
qt_create_pipe(channel.pipe, true);
|
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 {
|
} else {
|
||||||
QWindowsPipeReader *pipeReader = 0;
|
QWindowsPipeReader *pipeReader = 0;
|
||||||
if (&channel == &stdoutChannel) {
|
if (&channel == &stdoutChannel) {
|
||||||
|
@ -48,7 +48,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 3)
|
||||||
return 13;
|
return 13;
|
||||||
|
|
||||||
#ifndef QT_NO_PROCESS
|
#ifndef QT_NO_PROCESS
|
||||||
@ -59,12 +59,17 @@ int main(int argc, char **argv)
|
|||||||
if (process.processChannelMode() != mode)
|
if (process.processChannelMode() != mode)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
QProcess::InputChannelMode inmode = (QProcess::InputChannelMode)atoi(argv[2]);
|
||||||
|
process.setInputChannelMode(inmode);
|
||||||
|
if (process.inputChannelMode() != inmode)
|
||||||
|
return 11;
|
||||||
|
|
||||||
process.start("testProcessEcho2/testProcessEcho2");
|
process.start("testProcessEcho2/testProcessEcho2");
|
||||||
|
|
||||||
if (!process.waitForStarted(5000))
|
if (!process.waitForStarted(5000))
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
if (process.write("forwarded") != 9)
|
if (inmode == QProcess::ManagedInputChannel && process.write("forwarded") != 9)
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
process.closeWriteChannel();
|
process.closeWriteChannel();
|
||||||
|
@ -1094,33 +1094,40 @@ void tst_QProcess::mergedChannels()
|
|||||||
void tst_QProcess::forwardedChannels_data()
|
void tst_QProcess::forwardedChannels_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<int>("mode");
|
QTest::addColumn<int>("mode");
|
||||||
|
QTest::addColumn<int>("inmode");
|
||||||
QTest::addColumn<QByteArray>("outdata");
|
QTest::addColumn<QByteArray>("outdata");
|
||||||
QTest::addColumn<QByteArray>("errdata");
|
QTest::addColumn<QByteArray>("errdata");
|
||||||
|
|
||||||
QTest::newRow("separate") << int(QProcess::SeparateChannels)
|
QTest::newRow("separate") << int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel)
|
||||||
<< QByteArray() << QByteArray();
|
<< QByteArray() << QByteArray();
|
||||||
QTest::newRow("forwarded") << int(QProcess::ForwardedChannels)
|
QTest::newRow("forwarded") << int(QProcess::ForwardedChannels) << int(QProcess::ManagedInputChannel)
|
||||||
<< QByteArray("forwarded") << QByteArray("forwarded");
|
<< QByteArray("forwarded") << QByteArray("forwarded");
|
||||||
QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel)
|
QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel) << int(QProcess::ManagedInputChannel)
|
||||||
<< QByteArray("forwarded") << QByteArray();
|
<< QByteArray("forwarded") << QByteArray();
|
||||||
QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel)
|
QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ManagedInputChannel)
|
||||||
<< QByteArray() << QByteArray("forwarded");
|
<< QByteArray() << QByteArray("forwarded");
|
||||||
|
QTest::newRow("fwdinput") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ForwardedInputChannel)
|
||||||
|
<< QByteArray() << QByteArray("input");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QProcess::forwardedChannels()
|
void tst_QProcess::forwardedChannels()
|
||||||
{
|
{
|
||||||
QFETCH(int, mode);
|
QFETCH(int, mode);
|
||||||
|
QFETCH(int, inmode);
|
||||||
QFETCH(QByteArray, outdata);
|
QFETCH(QByteArray, outdata);
|
||||||
QFETCH(QByteArray, errdata);
|
QFETCH(QByteArray, errdata);
|
||||||
|
|
||||||
QProcess process;
|
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));
|
QVERIFY(process.waitForStarted(5000));
|
||||||
|
QCOMPARE(process.write("input"), 5);
|
||||||
|
process.closeWriteChannel();
|
||||||
QVERIFY(process.waitForFinished(5000));
|
QVERIFY(process.waitForFinished(5000));
|
||||||
const char *err;
|
const char *err;
|
||||||
switch (process.exitCode()) {
|
switch (process.exitCode()) {
|
||||||
case 0: err = "ok"; break;
|
case 0: err = "ok"; break;
|
||||||
case 1: err = "processChannelMode is wrong"; break;
|
case 1: err = "processChannelMode is wrong"; break;
|
||||||
|
case 11: err = "inputChannelMode is wrong"; break;
|
||||||
case 2: err = "failed to start"; break;
|
case 2: err = "failed to start"; break;
|
||||||
case 3: err = "failed to write"; break;
|
case 3: err = "failed to write"; break;
|
||||||
case 4: err = "did not finish"; break;
|
case 4: err = "did not finish"; break;
|
||||||
|
Loading…
Reference in New Issue
Block a user