src/corelib/io/qprocess.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 //#define QPROCESS_DEBUG
00025 
00026 #if defined QPROCESS_DEBUG
00027 #include <qdebug.h>
00028 #include <qstring.h>
00029 #include <ctype.h>
00030 
00031 /*
00032     Returns a human readable representation of the first \a len
00033     characters in \a data.
00034 */
00035 static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
00036 {
00037     if (!data) return "(null)";
00038     QByteArray out;
00039     for (int i = 0; i < len && i < maxSize; ++i) {
00040         char c = data[i];
00041         if (isprint(c)) {
00042             out += c;
00043         } else switch (c) {
00044         case '\n': out += "\\n"; break;
00045         case '\r': out += "\\r"; break;
00046         case '\t': out += "\\t"; break;
00047         default:
00048             char buf[5];
00049             qsnprintf(buf, sizeof(buf), "\\%3o", c);
00050             buf[4] = '\0';
00051             out += QString::fromLatin1(buf);
00052         }
00053     }
00054 
00055     if (len < maxSize)
00056         out += "...";
00057 
00058     return out;
00059 }
00060 #endif
00061 
00062 #include "qprocess.h"
00063 #include "qprocess_p.h"
00064 
00065 #include <qbytearray.h>
00066 #include <qdatetime.h>
00067 #include <qcoreapplication.h>
00068 #include <qsocketnotifier.h>
00069 #include <qtimer.h>
00070 
00071 #ifdef Q_WS_WIN
00072 #include <private/qwineventnotifier_p.h>
00073 #endif
00074 
00075 #ifndef QT_NO_PROCESS
00076 
00353 QProcessPrivate::QProcessPrivate()
00354 {
00355     processChannel = QProcess::StandardOutput;
00356     processChannelMode = QProcess::SeparateChannels;
00357     processError = QProcess::UnknownError;
00358     processState = QProcess::NotRunning;
00359     pid = 0;
00360     sequenceNumber = 0;
00361     exitCode = 0;
00362     exitStatus = QProcess::NormalExit;
00363     startupSocketNotifier = 0;
00364     deathNotifier = 0;
00365     notifier = 0;
00366     pipeWriter = 0;
00367     childStartedPipe[0] = INVALID_Q_PIPE;
00368     childStartedPipe[1] = INVALID_Q_PIPE;
00369     deathPipe[0] = INVALID_Q_PIPE;
00370     deathPipe[1] = INVALID_Q_PIPE;
00371     exitCode = 0;
00372     crashed = false;
00373     emittedReadyRead = false;
00374     emittedBytesWritten = false;
00375 #ifdef Q_WS_WIN
00376     pipeWriter = 0;
00377     processFinishedNotifier = 0;
00378 #endif // Q_WS_WIN
00379 #ifdef Q_OS_UNIX
00380     serial = 0;
00381 #endif
00382 }
00383 
00386 QProcessPrivate::~QProcessPrivate()
00387 {
00388     if (stdinChannel.process)
00389         stdinChannel.process->stdoutChannel.clear();
00390     if (stdoutChannel.process)
00391         stdoutChannel.process->stdinChannel.clear();
00392 }
00393 
00396 void QProcessPrivate::cleanup()
00397 {
00398     processState = QProcess::NotRunning;
00399 #ifdef Q_OS_WIN
00400     if (pid) {
00401         CloseHandle(pid->hThread);
00402         CloseHandle(pid->hProcess);
00403         delete pid;
00404         pid = 0;
00405     }
00406     if (processFinishedNotifier) {
00407         processFinishedNotifier->setEnabled(false);
00408         delete processFinishedNotifier;
00409         processFinishedNotifier = 0;
00410     }
00411 
00412 #endif
00413     pid = 0;
00414     sequenceNumber = 0;
00415 
00416     if (stdoutChannel.notifier) {
00417         stdoutChannel.notifier->setEnabled(false);
00418         delete stdoutChannel.notifier;
00419         stdoutChannel.notifier = 0;
00420     }
00421     if (stderrChannel.notifier) {
00422         stderrChannel.notifier->setEnabled(false);
00423         delete stderrChannel.notifier;
00424         stderrChannel.notifier = 0;
00425     }
00426     if (stdinChannel.notifier) {
00427         stdinChannel.notifier->setEnabled(false);
00428         delete stdinChannel.notifier;
00429         stdinChannel.notifier = 0;
00430     }
00431     if (startupSocketNotifier) {
00432         startupSocketNotifier->setEnabled(false);
00433         delete startupSocketNotifier;
00434         startupSocketNotifier = 0;
00435     }
00436     if (deathNotifier) {
00437         deathNotifier->setEnabled(false);
00438         delete deathNotifier;
00439         deathNotifier = 0;
00440     }
00441     if (notifier) {
00442         delete notifier;
00443         notifier = 0;
00444     }
00445     destroyPipe(stdoutChannel.pipe);
00446     destroyPipe(stderrChannel.pipe);
00447     destroyPipe(stdinChannel.pipe);
00448     destroyPipe(childStartedPipe);
00449     destroyPipe(deathPipe);
00450 #ifdef Q_OS_UNIX
00451     serial = 0;
00452 #endif
00453 }
00454 
00457 bool QProcessPrivate::_q_canReadStandardOutput()
00458 {
00459     Q_Q(QProcess);
00460     qint64 available = bytesAvailableFromStdout();
00461     if (available == 0) {
00462         if (stdoutChannel.notifier)
00463             stdoutChannel.notifier->setEnabled(false);
00464         destroyPipe(stdoutChannel.pipe);
00465 #if defined QPROCESS_DEBUG
00466         qDebug("QProcessPrivate::canReadStandardOutput(), 0 bytes available");
00467 #endif
00468         return false;
00469     }
00470 
00471     char *ptr = outputReadBuffer.reserve(available);
00472     qint64 readBytes = readFromStdout(ptr, available);
00473     if (readBytes == -1) {
00474         processError = QProcess::ReadError;
00475         q->setErrorString(QT_TRANSLATE_NOOP(QProcess, QLatin1String("Error reading from process")));
00476         emit q->error(processError);
00477 #if defined QPROCESS_DEBUG
00478         qDebug("QProcessPrivate::canReadStandardOutput(), failed to read from the process");
00479 #endif
00480         return false;
00481     }
00482 #if defined QPROCESS_DEBUG
00483     qDebug("QProcessPrivate::canReadStandardOutput(), read %d bytes from the process' output",
00484             int(readBytes));
00485 #endif
00486 
00487     if (stdoutChannel.closed) {
00488         outputReadBuffer.chop(readBytes);
00489         return false;
00490     }
00491 
00492     outputReadBuffer.chop(available - readBytes);
00493 
00494     bool didRead = false;
00495     if (readBytes == 0) {
00496         if (stdoutChannel.notifier)
00497             stdoutChannel.notifier->setEnabled(false);
00498     } else if (processChannel == QProcess::StandardOutput) {
00499         didRead = true;
00500         if (!emittedReadyRead) {
00501             emittedReadyRead = true;
00502             emit q->readyRead();
00503             emittedReadyRead = false;
00504         }
00505     }
00506     emit q->readyReadStandardOutput();
00507     return didRead;
00508 }
00509 
00512 bool QProcessPrivate::_q_canReadStandardError()
00513 {
00514     Q_Q(QProcess);
00515     qint64 available = bytesAvailableFromStderr();
00516     if (available == 0) {
00517         if (stderrChannel.notifier)
00518             stderrChannel.notifier->setEnabled(false);
00519         destroyPipe(stderrChannel.pipe);
00520         return false;
00521     }
00522 
00523     char *ptr = errorReadBuffer.reserve(available);
00524     qint64 readBytes = readFromStderr(ptr, available);
00525     if (readBytes == -1) {
00526         processError = QProcess::ReadError;
00527         q->setErrorString(QT_TRANSLATE_NOOP(QProcess, QLatin1String("Error reading from process")));
00528         emit q->error(processError);
00529         return false;
00530     }
00531     if (stderrChannel.closed) {
00532         errorReadBuffer.chop(readBytes);
00533         return false;
00534     }
00535 
00536     errorReadBuffer.chop(available - readBytes);
00537 
00538     bool didRead = false;
00539     if (readBytes == 0) {
00540         if (stderrChannel.notifier)
00541             stderrChannel.notifier->setEnabled(false);
00542     } else if (processChannel == QProcess::StandardError) {
00543         didRead = true;
00544         if (!emittedReadyRead) {
00545             emittedReadyRead = true;
00546             emit q->readyRead();
00547             emittedReadyRead = false;
00548         }
00549     }
00550     emit q->readyReadStandardError();
00551     return didRead;
00552 }
00553 
00556 bool QProcessPrivate::_q_canWrite()
00557 {
00558     Q_Q(QProcess);
00559     if (stdinChannel.notifier)
00560         stdinChannel.notifier->setEnabled(false);
00561 
00562     if (writeBuffer.isEmpty()) {
00563 #if defined QPROCESS_DEBUG
00564         qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
00565 #endif
00566         return false;
00567     }
00568 
00569     qint64 written = writeToStdin(writeBuffer.readPointer(),
00570                                       writeBuffer.nextDataBlockSize());
00571     if (written < 0) {
00572         destroyPipe(stdinChannel.pipe);
00573         processError = QProcess::WriteError;
00574         q->setErrorString(QT_TRANSLATE_NOOP(QProcess, QLatin1String("Error writing to process")));
00575 #if defined QPROCESS_DEBUG
00576         qDebug("QProcessPrivate::canWrite(), failed to write (%s)", strerror(errno));
00577 #endif
00578         emit q->error(processError);
00579         return false;
00580     }
00581 
00582 #if defined QPROCESS_DEBUG
00583     qDebug("QProcessPrivate::canWrite(), wrote %d bytes to the process input", int(written));
00584 #endif
00585 
00586     writeBuffer.free(written);
00587     if (!emittedBytesWritten) {
00588         emittedBytesWritten = true;
00589         emit q->bytesWritten(written);
00590         emittedBytesWritten = false;
00591     }
00592     if (stdinChannel.notifier && !writeBuffer.isEmpty())
00593         stdinChannel.notifier->setEnabled(true);
00594     if (writeBuffer.isEmpty() && stdinChannel.closed)
00595         closeWriteChannel();
00596     return true;
00597 }
00598 
00601 bool QProcessPrivate::_q_processDied()
00602 {
00603     Q_Q(QProcess);
00604 #if defined QPROCESS_DEBUG
00605     qDebug("QProcessPrivate::_q_processDied()");
00606 #endif
00607 #ifdef Q_OS_UNIX
00608     if (!waitForDeadChild())
00609         return false;
00610 #endif
00611 #ifdef Q_OS_WIN
00612     if (processFinishedNotifier)
00613         processFinishedNotifier->setEnabled(false);
00614 #endif
00615 
00616     // the process may have died before it got a chance to report that it was
00617     // either running or stopped, so we will call _q_startupNotification() and
00618     // give it a chance to emit started() or error(FailedToStart).
00619     if (processState == QProcess::Starting) {
00620         if (!_q_startupNotification())
00621             return true;
00622     }
00623 
00624     // in case there is data in the pipe line and this slot by chance
00625     // got called before the read notifications, call these two slots
00626     // so the data is made available before the process dies.
00627     _q_canReadStandardOutput();
00628     _q_canReadStandardError();
00629 
00630     findExitCode();
00631 
00632     if (crashed) {
00633         exitStatus = QProcess::CrashExit;
00634         processError = QProcess::Crashed;
00635         q->setErrorString(QT_TRANSLATE_NOOP(QProcess, QLatin1String("Process crashed")));
00636         emit q->error(processError);
00637     }
00638 
00639     cleanup();
00640 
00641     processState = QProcess::NotRunning;
00642     emit q->stateChanged(processState);
00643     emit q->finished(exitCode);
00644     emit q->finished(exitCode, exitStatus);
00645 #if defined QPROCESS_DEBUG
00646     qDebug("QProcessPrivate::_q_processDied() process is dead");
00647 #endif
00648     return true;
00649 }
00650 
00653 bool QProcessPrivate::_q_startupNotification()
00654 {
00655     Q_Q(QProcess);
00656 #if defined QPROCESS_DEBUG
00657     qDebug("QProcessPrivate::startupNotification()");
00658 #endif
00659 
00660     if (startupSocketNotifier)
00661         startupSocketNotifier->setEnabled(false);
00662     if (processStarted()) {
00663         processState = QProcess::Running;
00664         emit q->started();
00665         return true;
00666     }
00667 
00668     processState = QProcess::NotRunning;
00669     processError = QProcess::FailedToStart;
00670     emit q->error(processError);
00671 #ifdef Q_OS_UNIX
00672     // make sure the process manager removes this entry
00673     waitForDeadChild();
00674     findExitCode();
00675 #endif
00676     cleanup();
00677     return false;
00678 }
00679 
00682 void QProcessPrivate::closeWriteChannel()
00683 {
00684 #if defined QPROCESS_DEBUG
00685     qDebug("QProcessPrivate::closeWriteChannel()");
00686 #endif
00687     if (stdinChannel.notifier) {
00688         stdinChannel.notifier->setEnabled(false);
00689         delete stdinChannel.notifier;
00690         stdinChannel.notifier = 0;
00691     }
00692 #ifdef Q_OS_WIN
00693     // ### Find a better fix, feeding the process little by little
00694     // instead.
00695     flushPipeWriter();
00696 #endif
00697     destroyPipe(stdinChannel.pipe);
00698 }
00699 
00703 QProcess::QProcess(QObject *parent)
00704     : QIODevice(*new QProcessPrivate, parent)
00705 {
00706 #if defined QPROCESS_DEBUG
00707     qDebug("QProcess::QProcess(%p)", parent);
00708 #endif
00709 }
00710 
00717 QProcess::~QProcess()
00718 {
00719     Q_D(QProcess);
00720     if (d->processState != NotRunning) {
00721         qWarning("QProcess: Destroyed while process is still running.");
00722         kill();
00723         waitForFinished();
00724     }
00725 #ifdef Q_OS_UNIX
00726     // make sure the process manager removes this entry
00727     d->findExitCode();
00728 #endif
00729     d->cleanup();
00730 }
00731 
00739 QProcess::ProcessChannelMode QProcess::readChannelMode() const
00740 {
00741     return processChannelMode();
00742 }
00743 
00751 void QProcess::setReadChannelMode(ProcessChannelMode mode)
00752 {
00753     setProcessChannelMode(mode);
00754 }
00755 
00764 QProcess::ProcessChannelMode QProcess::processChannelMode() const
00765 {
00766     Q_D(const QProcess);
00767     return d->processChannelMode;
00768 }
00769 
00790 void QProcess::setProcessChannelMode(ProcessChannelMode mode)
00791 {
00792     Q_D(QProcess);
00793     d->processChannelMode = mode;
00794 }
00795 
00801 QProcess::ProcessChannel QProcess::readChannel() const
00802 {
00803     Q_D(const QProcess);
00804     return d->processChannel;
00805 }
00806 
00817 void QProcess::setReadChannel(ProcessChannel channel)
00818 {
00819     Q_D(QProcess);
00820     if (d->processChannel != channel)
00821         d->buffer.clear();
00822     d->processChannel = channel;
00823 }
00824 
00835 void QProcess::closeReadChannel(ProcessChannel channel)
00836 {
00837     Q_D(QProcess);
00838 
00839     if (channel == StandardOutput)
00840         d->stdoutChannel.closed = true;
00841     else
00842         d->stderrChannel.closed = true;
00843 }
00844 
00869 void QProcess::closeWriteChannel()
00870 {
00871     Q_D(QProcess);
00872     d->stdinChannel.closed = true; // closing
00873     if (d->writeBuffer.isEmpty())
00874         d->closeWriteChannel();
00875 }
00876 
00894 void QProcess::setStandardInputFile(const QString &fileName)
00895 {
00896     Q_D(QProcess);
00897     d->stdinChannel = fileName;
00898 }
00899 
00922 void QProcess::setStandardOutputFile(const QString &fileName, OpenMode mode)
00923 {
00924     Q_ASSERT(mode == Append || mode == Truncate);
00925     Q_D(QProcess);
00926 
00927     d->stdoutChannel = fileName;
00928     d->stdoutChannel.append = mode == Append;
00929 }
00930 
00949 void QProcess::setStandardErrorFile(const QString &fileName, OpenMode mode)
00950 {
00951     Q_ASSERT(mode == Append || mode == Truncate);
00952     Q_D(QProcess);
00953 
00954     d->stderrChannel = fileName;
00955     d->stderrChannel.append = mode == Append;
00956 }
00957 
00980 void QProcess::setStandardOutputProcess(QProcess *destination)
00981 {
00982     QProcessPrivate *dfrom = d_func();
00983     QProcessPrivate *dto = destination->d_func();
00984     dfrom->stdoutChannel.pipeTo(dto);
00985     dto->stdinChannel.pipeFrom(dfrom);
00986 }
00987 
00994 QString QProcess::workingDirectory() const
00995 {
00996     Q_D(const QProcess);
00997     return d->workingDirectory;
00998 }
00999 
01007 void QProcess::setWorkingDirectory(const QString &dir)
01008 {
01009     Q_D(QProcess);
01010     d->workingDirectory = dir;
01011 }
01012 
01017 Q_PID QProcess::pid() const
01018 {
01019     Q_D(const QProcess);
01020     return d->pid;
01021 }
01022 
01029 bool QProcess::canReadLine() const
01030 {
01031     Q_D(const QProcess);
01032     const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
01033                                     ? &d->errorReadBuffer
01034                                     : &d->outputReadBuffer;
01035     return readBuffer->canReadLine() || QIODevice::canReadLine();
01036 }
01037 
01043 void QProcess::close()
01044 {
01045     emit aboutToClose();
01046     while (waitForBytesWritten(-1))
01047         ;
01048     kill();
01049     waitForFinished(-1);
01050     setOpenMode(QIODevice::NotOpen);
01051 }
01052 
01058 bool QProcess::atEnd() const
01059 {
01060     Q_D(const QProcess);
01061     const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
01062                                     ? &d->errorReadBuffer
01063                                     : &d->outputReadBuffer;
01064     return QIODevice::atEnd() && (!isOpen() || readBuffer->isEmpty());
01065 }
01066 
01069 bool QProcess::isSequential() const
01070 {
01071     return true;
01072 }
01073 
01076 qint64 QProcess::bytesAvailable() const
01077 {
01078     Q_D(const QProcess);
01079     const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
01080                                     ? &d->errorReadBuffer
01081                                     : &d->outputReadBuffer;
01082 #if defined QPROCESS_DEBUG
01083     qDebug("QProcess::bytesAvailable() == %i (%s)", readBuffer->size(),
01084            (d->processChannel == QProcess::StandardError) ? "stderr" : "stdout");
01085 #endif
01086     return readBuffer->size() + QIODevice::bytesAvailable();
01087 }
01088 
01091 qint64 QProcess::bytesToWrite() const
01092 {
01093     Q_D(const QProcess);
01094     return d->writeBuffer.size();
01095 }
01096 
01102 QProcess::ProcessError QProcess::error() const
01103 {
01104     Q_D(const QProcess);
01105     return d->processError;
01106 }
01107 
01113 QProcess::ProcessState QProcess::state() const
01114 {
01115     Q_D(const QProcess);
01116     return d->processState;
01117 }
01118 
01132 void QProcess::setEnvironment(const QStringList &environment)
01133 {
01134     Q_D(QProcess);
01135     d->environment = environment;
01136 }
01137 
01146 QStringList QProcess::environment() const
01147 {
01148     Q_D(const QProcess);
01149     return d->environment;
01150 }
01151 
01171 bool QProcess::waitForStarted(int msecs)
01172 {
01173     Q_D(QProcess);
01174     if (d->processState == QProcess::Starting) {
01175         if (!d->waitForStarted(msecs))
01176             return false;
01177         d->processState = QProcess::Running;
01178         emit started();
01179     }
01180     return d->processState == QProcess::Running;
01181 }
01182 
01185 bool QProcess::waitForReadyRead(int msecs)
01186 {
01187     Q_D(QProcess);
01188 
01189     if (d->processState == QProcess::NotRunning)
01190         return false;
01191     if (d->processChannel == QProcess::StandardOutput && d->stdoutChannel.closed)
01192         return false;
01193     if (d->processChannel == QProcess::StandardError && d->stderrChannel.closed)
01194         return false;
01195     return d->waitForReadyRead(msecs);
01196 }
01197 
01200 bool QProcess::waitForBytesWritten(int msecs)
01201 {
01202     Q_D(QProcess);
01203     if (d->processState == QProcess::NotRunning)
01204         return false;
01205     if (d->processState == QProcess::Starting) {
01206         QTime stopWatch;
01207         stopWatch.start();
01208         bool started = waitForStarted(msecs);
01209         if (!started)
01210             return false;
01211         if (msecs != -1)
01212             msecs -= stopWatch.elapsed();
01213     }
01214 
01215     return d->waitForBytesWritten(msecs);
01216 }
01217 
01236 bool QProcess::waitForFinished(int msecs)
01237 {
01238     Q_D(QProcess);
01239     if (d->processState == QProcess::NotRunning)
01240         return false;
01241     if (d->processState == QProcess::Starting) {
01242         QTime stopWatch;
01243         stopWatch.start();
01244         bool started = waitForStarted(msecs);
01245         if (!started)
01246             return false;
01247         if (msecs != -1)
01248             msecs -= stopWatch.elapsed();
01249     }
01250 
01251     return d->waitForFinished(msecs);
01252 }
01253 
01259 void QProcess::setProcessState(ProcessState state)
01260 {
01261     Q_D(QProcess);
01262     d->processState = state;
01263 }
01264 
01299 void QProcess::setupChildProcess()
01300 {
01301 }
01302 
01305 qint64 QProcess::readData(char *data, qint64 maxlen)
01306 {
01307     Q_D(QProcess);
01308     QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
01309                               ? &d->errorReadBuffer
01310                               : &d->outputReadBuffer;
01311 
01312     if (maxlen == 1) {
01313         int c = readBuffer->getChar();
01314         if (c == -1) {
01315 #if defined QPROCESS_DEBUG
01316             qDebug("QProcess::readData(%p \"%s\", %d) == -1",
01317                    data, qt_prettyDebug(data, 1, maxlen).constData(), 1);
01318 #endif
01319             return -1;
01320         }
01321         *data = (char) c;
01322 #if defined QPROCESS_DEBUG
01323         qDebug("QProcess::readData(%p \"%s\", %d) == 1",
01324                data, qt_prettyDebug(data, 1, maxlen).constData(), 1);
01325 #endif
01326         return 1;
01327     }
01328 
01329     qint64 bytesToRead = qint64(qMin(readBuffer->size(), (int)maxlen));
01330     qint64 readSoFar = 0;
01331     while (readSoFar < bytesToRead) {
01332         const char *ptr = readBuffer->readPointer();
01333         int bytesToReadFromThisBlock = qMin<qint64>(bytesToRead - readSoFar,
01334                                             readBuffer->nextDataBlockSize());
01335         memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
01336         readSoFar += bytesToReadFromThisBlock;
01337         readBuffer->free(bytesToReadFromThisBlock);
01338     }
01339 
01340 #if defined QPROCESS_DEBUG
01341     qDebug("QProcess::readData(%p \"%s\", %lld) == %lld",
01342            data, qt_prettyDebug(data, readSoFar, 16).constData(), maxlen, readSoFar);
01343 #endif
01344     return readSoFar;
01345 }
01346 
01349 qint64 QProcess::writeData(const char *data, qint64 len)
01350 {
01351     Q_D(QProcess);
01352 
01353     if (d->stdinChannel.closed) {
01354 #if defined QPROCESS_DEBUG
01355     qDebug("QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
01356            data, qt_prettyDebug(data, len, 16).constData(), len);
01357 #endif
01358         return 0;
01359     }
01360 
01361     if (len == 1) {
01362         d->writeBuffer.putChar(*data);
01363         if (d->stdinChannel.notifier)
01364             d->stdinChannel.notifier->setEnabled(true);
01365 #if defined QPROCESS_DEBUG
01366     qDebug("QProcess::writeData(%p \"%s\", %lld) == 1 (written to buffer)",
01367            data, qt_prettyDebug(data, len, 16).constData(), len);
01368 #endif
01369         return 1;
01370     }
01371 
01372     char *dest = d->writeBuffer.reserve(len);
01373     memcpy(dest, data, len);
01374     if (d->stdinChannel.notifier)
01375         d->stdinChannel.notifier->setEnabled(true);
01376 #if defined QPROCESS_DEBUG
01377     qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
01378            data, qt_prettyDebug(data, len, 16).constData(), len, len);
01379 #endif
01380     return len;
01381 }
01382 
01390 QByteArray QProcess::readAllStandardOutput()
01391 {
01392     ProcessChannel tmp = readChannel();
01393     setReadChannel(StandardOutput);
01394     QByteArray data = readAll();
01395     setReadChannel(tmp);
01396     return data;
01397 }
01398 
01406 QByteArray QProcess::readAllStandardError()
01407 {
01408     ProcessChannel tmp = readChannel();
01409     setReadChannel(StandardError);
01410     QByteArray data = readAll();
01411     setReadChannel(tmp);
01412     return data;
01413 }
01414 
01431 void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
01432 {
01433     Q_D(QProcess);
01434     if (d->processState != NotRunning) {
01435         qWarning("QProcess::start: Process is already running");
01436         return;
01437     }
01438 
01439 #if defined QPROCESS_DEBUG
01440     qDebug() << "QProcess::start(" << program << "," << arguments << "," << mode << ")";
01441 #endif
01442 
01443     d->outputReadBuffer.clear();
01444     d->errorReadBuffer.clear();
01445 
01446     if (d->stdinChannel.type != QProcessPrivate::Channel::Normal)
01447         mode &= ~WriteOnly;     // not open for writing
01448     if (d->stdoutChannel.type != QProcessPrivate::Channel::Normal &&
01449         (d->stderrChannel.type != QProcessPrivate::Channel::Normal ||
01450          d->processChannelMode == MergedChannels))
01451         mode &= ~ReadOnly;      // not open for reading
01452     if (mode == 0)
01453         mode = Unbuffered;
01454     setOpenMode(mode);
01455 
01456     d->stdinChannel.closed = false;
01457     d->stdoutChannel.closed = false;
01458     d->stderrChannel.closed = false;
01459 
01460     d->program = program;
01461     d->arguments = arguments;
01462 
01463     d->exitCode = 0;
01464     d->exitStatus = NormalExit;
01465     d->processError = QProcess::UnknownError;
01466     d->errorString.clear();
01467     d->startProcess();
01468 }
01469 
01470 
01471 static QStringList parseCombinedArgString(const QString &program)
01472 {
01473     QStringList args;
01474     QString tmp;
01475     int quoteCount = 0;
01476     bool inQuote = false;
01477 
01478     // handle quoting. tokens can be surrounded by double quotes
01479     // "hello world". three consecutive double quotes represent
01480     // the quote character itself.
01481     for (int i = 0; i < program.size(); ++i) {
01482         if (program.at(i) == QLatin1Char('"')) {
01483             ++quoteCount;
01484             if (quoteCount == 3) {
01485                 // third consecutive quote
01486                 quoteCount = 0;
01487                 tmp += program.at(i);
01488             }
01489             continue;
01490         }
01491         if (quoteCount) {
01492             if (quoteCount == 1)
01493                 inQuote = !inQuote;
01494             quoteCount = 0;
01495         }
01496         if (!inQuote && program.at(i).isSpace()) {
01497             if (!tmp.isEmpty()) {
01498                 args += tmp;
01499                 tmp.clear();
01500             }
01501         } else {
01502             tmp += program.at(i);
01503         }
01504     }
01505     if (!tmp.isEmpty())
01506         args += tmp;
01507 
01508     return args;
01509 }
01510 
01546 void QProcess::start(const QString &program, OpenMode mode)
01547 {
01548     QStringList args = parseCombinedArgString(program);
01549 
01550     QString prog = args.first();
01551     args.removeFirst();
01552 
01553     start(prog, args, mode);
01554 }
01555 
01567 void QProcess::terminate()
01568 {
01569     Q_D(QProcess);
01570     d->terminateProcess();
01571 }
01572 
01581 void QProcess::kill()
01582 {
01583     Q_D(QProcess);
01584     d->killProcess();
01585 }
01586 
01590 int QProcess::exitCode() const
01591 {
01592     Q_D(const QProcess);
01593     return d->exitCode;
01594 }
01595 
01605 QProcess::ExitStatus QProcess::exitStatus() const
01606 {
01607     Q_D(const QProcess);
01608     return d->exitStatus;
01609 }
01610 
01622 int QProcess::execute(const QString &program, const QStringList &arguments)
01623 {
01624     QProcess process;
01625     process.setReadChannelMode(ForwardedChannels);
01626     process.start(program, arguments);
01627     process.waitForFinished(-1);
01628     return process.exitCode();
01629 }
01630 
01638 int QProcess::execute(const QString &program)
01639 {
01640     QProcess process;
01641     process.setReadChannelMode(ForwardedChannels);
01642     process.start(program);
01643     process.waitForFinished(-1);
01644     return process.exitCode();
01645 }
01646 
01659 bool QProcess::startDetached(const QString &program, const QStringList &arguments)
01660 {
01661     return QProcessPrivate::startDetached(program, arguments);
01662 }
01663 
01674 bool QProcess::startDetached(const QString &program)
01675 {
01676     QStringList args = parseCombinedArgString(program);
01677 
01678     QString prog = args.first();
01679     args.removeFirst();
01680 
01681     return QProcessPrivate::startDetached(prog, args);
01682 }
01683 
01684 #ifdef Q_OS_MAC
01685 # include <crt_externs.h>
01686 # define environ (*_NSGetEnviron())
01687 #elif !defined(Q_OS_WIN)
01688   extern char **environ;
01689 #endif
01690 
01705 QStringList QProcess::systemEnvironment()
01706 {
01707     QStringList tmp;
01708     char *entry = 0;
01709     int count = 0;
01710     while ((entry = environ[count++]))
01711         tmp << QString::fromLocal8Bit(entry);
01712     return tmp;
01713 }
01714 
01726 #include "moc_qprocess.cpp"
01727 
01728 #endif // QT_NO_PROCESS

Generated on Thu Mar 15 11:53:15 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1