⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qprocess_unix.cpp

📁 奇趣公司比较新的qt/emd版本
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        QByteArray fname = QFile::encodeName(channel.file);        if (&channel == &stdinChannel) {            // try to open in read-only mode            channel.pipe[1] = -1;            if ( (channel.pipe[0] = open(fname, O_RDONLY)) != -1)                return true;    // success            q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Could not open input redirection for reading")));        } else {            int mode = O_WRONLY | O_CREAT;            if (channel.append)                mode |= O_APPEND;            else                mode |= O_TRUNC;            channel.pipe[0] = -1;            if ( (channel.pipe[1] = open(fname, mode, 0666)) != -1)                return true; // success            q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Could not open output redirection for writing")));        }        // could not open file        processError = QProcess::FailedToStart;        emit q->error(processError);        cleanup();        return false;    } else {        Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");        Channel *source;        Channel *sink;        if (channel.type == Channel::PipeSource) {            // we are the source            source = &channel;            sink = &channel.process->stdinChannel;            Q_ASSERT(source == &stdoutChannel);            Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);        } else {            // we are the sink;            source = &channel.process->stdoutChannel;            sink = &channel;            Q_ASSERT(sink == &stdinChannel);            Q_ASSERT(source->process == this && source->type == Channel::PipeSource);        }        if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {            // already created, do nothing            return true;        } else {            Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE);            Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);            Q_PIPE pipe[2] = { -1, -1 };            qt_create_pipe(pipe);            sink->pipe[0] = pipe[0];            source->pipe[1] = pipe[1];            return true;        }    }}static char **_q_dupEnvironment(const QStringList &environment, int *envc){    // if LD_LIBRARY_PATH exists in the current environment, but    // not in the environment list passed by the programmer, then    // copy it over.#if defined(Q_OS_MAC)    static const char libraryPath[] = "DYLD_LIBRARY_PATH";#else    static const char libraryPath[] = "LD_LIBRARY_PATH";#endif    const QString libraryPathString = QLatin1String(libraryPath);    QStringList env = environment;    QStringList matches = env.filter(        QRegExp(QLatin1Char('^') + libraryPathString + QLatin1Char('=')));    const QString envLibraryPath = QString::fromLocal8Bit(::getenv(libraryPath));    if (matches.isEmpty() && !envLibraryPath.isEmpty()) {        QString entry = libraryPathString;        entry += QLatin1Char('=');        entry += envLibraryPath;        env << libraryPathString + QLatin1Char('=') + envLibraryPath;    }    char **envp = new char *[env.count() + 1];    envp[env.count()] = 0;    for (int j = 0; j < env.count(); ++j) {        QString item = env.at(j);        envp[j] = ::strdup(item.toLocal8Bit().constData());    }    *envc = env.count();    return envp;}void QProcessPrivate::startProcess(){    Q_Q(QProcess);#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::startProcess()");#endif    processManager()->start();    // Initialize pipes    qt_create_pipe(childStartedPipe);    if (threadData->eventDispatcher) {        startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],                                                    QSocketNotifier::Read, q);        QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),                         q, SLOT(_q_startupNotification()));    }    qt_create_pipe(deathPipe);    ::fcntl(deathPipe[0], F_SETFD, FD_CLOEXEC);    ::fcntl(deathPipe[1], F_SETFD, FD_CLOEXEC);    if (threadData->eventDispatcher) {        deathNotifier = new QSocketNotifier(deathPipe[0],                                            QSocketNotifier::Read, q);        QObject::connect(deathNotifier, SIGNAL(activated(int)),                         q, SLOT(_q_processDied()));    }    if (!createChannel(stdinChannel) ||        !createChannel(stdoutChannel) ||        !createChannel(stderrChannel))        return;    // Start the process (platform dependent)    processState = QProcess::Starting;    emit q->stateChanged(processState);    // Create argument list with right number of elements, and set the final    // one to 0.    char **argv = new char *[arguments.count() + 2];    argv[arguments.count() + 1] = 0;    // Encode the program name.    QByteArray encodedProgramName = QFile::encodeName(program);#ifdef Q_OS_MAC    // allow invoking of .app bundles on the Mac.    QFileInfo fileInfo(QString::fromUtf8(encodedProgramName.constData()));    if (encodedProgramName.endsWith(".app") && fileInfo.isDir()) {        QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,                                                          QCFString(fileInfo.absoluteFilePath()),                                                          kCFURLPOSIXPathStyle, true);        QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);        url = CFBundleCopyExecutableURL(bundle);        if (url) {            QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);            encodedProgramName += "/Contents/MacOS/" + static_cast<QString>(str).toUtf8();        }    }#endif    // Add the program name to the argument list.    char *dupProgramName = ::strdup(encodedProgramName.constData());    argv[0] = dupProgramName;    // Add every argument to the list    for (int i = 0; i < arguments.count(); ++i) {        QString arg = arguments.at(i);#ifdef Q_OS_MAC        // Mac OS X uses UTF8 for exec, regardless of the system locale.        argv[i + 1] = ::strdup(arg.toUtf8().constData());#else        argv[i + 1] = ::strdup(arg.toLocal8Bit().constData());#endif    }    // Duplicate the environment.    int envc = 0;    char **envp = _q_dupEnvironment(environment, &envc);    // Encode the working directory if it's non-empty, otherwise just pass 0.    const char *workingDirPtr = 0;    QByteArray encodedWorkingDirectory;    if (!workingDirectory.isEmpty()) {        encodedWorkingDirectory = QFile::encodeName(workingDirectory);        workingDirPtr = encodedWorkingDirectory.constData();    }    // If the program does not specify a path, generate a list of possible    // locations for the binary using the PATH environment variable.    char **path = 0;    int pathc = 0;    if (!program.contains(QLatin1Char('/'))) {        const QString pathEnv = QString::fromLocal8Bit(::getenv("PATH"));        if (!pathEnv.isEmpty()) {            QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);            if (!pathEntries.isEmpty()) {                pathc = pathEntries.size();                path = new char *[pathc + 1];                path[pathc] = 0;                                for (int k = 0; k < pathEntries.size(); ++k) {                    QByteArray tmp = QFile::encodeName(pathEntries.at(k));                    if (!tmp.endsWith('/')) tmp += '/';                    tmp += encodedProgramName;                    path[k] = ::strdup(tmp.constData());                }            }        }    }    // Start the process manager, and fork off the child process.    processManager()->lock();    pid_t childPid = fork();    if (childPid != 0) {        // Clean up duplicated memory.        free(dupProgramName);        for (int i = 1; i <= arguments.count(); ++i)            free(argv[i]);        for (int i = 0; i < envc; ++i)            free(envp[i]);        for (int i = 0; i < pathc; ++i)            free(path[i]);        delete [] argv;        delete [] envp;        delete [] path;    }    if (childPid < 0) {        // Cleanup, report error and return        processManager()->unlock();        processState = QProcess::NotRunning;        emit q->stateChanged(processState);        processError = QProcess::FailedToStart;        q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Resource error (fork failure)")));        emit q->error(processError);        cleanup();        return;    }    // Start the child.    if (childPid == 0) {        execChild(workingDirPtr, path, argv, envp);        ::_exit(-1);    }    // Register the child. In the mean time, we can get a SIGCHLD, so we need    // to keep the lock held to avoid a race to catch the child.    processManager()->add(childPid, q);    pid = Q_PID(childPid);    processManager()->unlock();    // parent    // close the ends we don't use and make all pipes non-blocking    ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);    qt_native_close(childStartedPipe[1]);    childStartedPipe[1] = -1;    if (stdinChannel.pipe[0] != -1) {        qt_native_close(stdinChannel.pipe[0]);        stdinChannel.pipe[0] = -1;    }    if (stdinChannel.pipe[1] != -1)        ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);    if (stdoutChannel.pipe[1] != -1) {        qt_native_close(stdoutChannel.pipe[1]);        stdoutChannel.pipe[1] = -1;    }    if (stdoutChannel.pipe[0] != -1)        ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);    if (stderrChannel.pipe[1] != -1) {        qt_native_close(stderrChannel.pipe[1]);        stderrChannel.pipe[1] = -1;    }    if (stderrChannel.pipe[0] != -1)        ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);}void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp){    ::signal(SIGPIPE, SIG_DFL);         // reset the signal that we ignored    Q_Q(QProcess);    // copy the stdin socket    qt_native_dup2(stdinChannel.pipe[0], fileno(stdin));    // copy the stdout and stderr if asked to    if (processChannelMode != QProcess::ForwardedChannels) {        qt_native_dup2(stdoutChannel.pipe[1], fileno(stdout));        // merge stdout and stderr if asked to        if (processChannelMode == QProcess::MergedChannels) {            qt_native_dup2(fileno(stdout), fileno(stderr));        } else {            qt_native_dup2(stderrChannel.pipe[1], fileno(stderr));        }    }    // make sure this fd is closed if execvp() succeeds    qt_native_close(childStartedPipe[0]);    ::fcntl(childStartedPipe[1], F_SETFD, FD_CLOEXEC);    // enter the working directory    if (workingDir)        qt_native_chdir(workingDir);    // this is a virtual call, and it base behavior is to do nothing.    q->setupChildProcess();    // execute the process    if (environment.isEmpty()) {        qt_native_execvp(argv[0], argv);    } else {        if (path) {            char **arg = path;            while (*arg) {                argv[0] = *arg;#if defined (QPROCESS_DEBUG)                fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);#endif                qt_native_execve(argv[0], argv, envp);                ++arg;            }        } else {#if defined (QPROCESS_DEBUG)            fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);#endif            qt_native_execve(argv[0], argv, envp);        }    }    // notify failure#if defined (QPROCESS_DEBUG)    fprintf(stderr, "QProcessPrivate::execChild() failed, notifying parent process\n");#endif    qt_native_write(childStartedPipe[1], "", 1);    qt_native_close(childStartedPipe[1]);    childStartedPipe[1] = -1;}bool QProcessPrivate::processStarted(){    char c;    int i = qt_native_read(childStartedPipe[0], &c, 1);    if (startupSocketNotifier) {        startupSocketNotifier->setEnabled(false);        delete startupSocketNotifier;        startupSocketNotifier = 0;    }    qt_native_close(childStartedPipe[0]);    childStartedPipe[0] = -1;#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::processStarted() == %s", i <= 0 ? "true" : "false");#endif    return i <= 0;}qint64 QProcessPrivate::bytesAvailableFromStdout() const{    size_t nbytes = 0;    qint64 available = 0;    if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)        available = (qint64) *((int *) &nbytes);#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld", available);#endif    return available;}qint64 QProcessPrivate::bytesAvailableFromStderr() const{    size_t nbytes = 0;    qint64 available = 0;    if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)        available = (qint64) *((int *) &nbytes);#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld", available);#endif    return available;}qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen){    qint64 bytesRead = qt_native_read(stdoutChannel.pipe[0], data, maxlen);#if defined QPROCESS_DEBUG    qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld",           data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);#endif    return bytesRead;}qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen){    qint64 bytesRead = qt_native_read(stderrChannel.pipe[0], data, maxlen);#if defined QPROCESS_DEBUG    qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld",           data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);#endif    return bytesRead;}static void qt_ignore_sigpipe(){    // Set to ignore SIGPIPE once only.    static QBasicAtomic atom = Q_ATOMIC_INIT(0);    if (atom.testAndSet(0, 1)) {        struct sigaction noaction;        memset(&noaction, 0, sizeof(noaction));        noaction.sa_handler = SIG_IGN;        qt_native_sigaction(SIGPIPE, &noaction, 0);    }}qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen){    qt_ignore_sigpipe();    qint64 written = qt_native_write(stdinChannel.pipe[1], data, maxlen);#if defined QPROCESS_DEBUG    qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld",           data, qt_prettyDebug(data, maxlen, 16).constData(), maxlen, written);#endif    return written;}void QProcessPrivate::terminateProcess(){#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::killProcess()");#endif    if (pid)        ::kill(pid_t(pid), SIGTERM);}void QProcessPrivate::killProcess(){#if defined (QPROCESS_DEBUG)    qDebug("QProcessPrivate::killProcess()");#endif    if (pid)        ::kill(pid_t(pid), SIGKILL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -