示例#1
0
RegExp::RegExp(const UString &p, int flags)
  : _flags(flags), _numSubPatterns(0)
{
#ifdef HAVE_PCREPOSIX

  int options = PCRE_UTF8;
  // Note: the Global flag is already handled by RegExpProtoFunc::execute.
  if (flags & IgnoreCase)
    options |= PCRE_CASELESS;
  if (flags & Multiline)
    options |= PCRE_MULTILINE;

  const char *errorMessage;
  int errorOffset;
  UString nullTerminated(p);
  char null(0);
  nullTerminated.append(null);
  _regex = pcre_compile(reinterpret_cast<const uint16_t *>(nullTerminated.data()), options, &errorMessage, &errorOffset, NULL);
  if (!_regex) {
#ifndef NDEBUG
    fprintf(stderr, "KJS: pcre_compile() failed with '%s'\n", errorMessage);
#endif
    return;
  }

#ifdef PCRE_INFO_CAPTURECOUNT
  // Get number of subpatterns that will be returned.
  pcre_fullinfo(_regex, NULL, PCRE_INFO_CAPTURECOUNT, &_numSubPatterns);
#endif

#else /* HAVE_PCREPOSIX */

  int regflags = 0;
#ifdef REG_EXTENDED
  regflags |= REG_EXTENDED;
#endif
#ifdef REG_ICASE
  if ( f & IgnoreCase )
    regflags |= REG_ICASE;
#endif

  //NOTE: Multiline is not feasible with POSIX regex.
  //if ( f & Multiline )
  //    ;
  // Note: the Global flag is already handled by RegExpProtoFunc::execute

  regcomp(&_regex, p.ascii(), regflags);
  /* TODO check for errors */

#endif
}
// DecodeUTF8
// decodes the specified *unterminated* UTF-8 byte array
wxWCharBuffer DecodeUTF8(
    const void* data, // an unterminated UTF-8 encoded byte array
    size_t size       // the byte length of data
    )
{
    // the decoder requires a null terminated buffer.
    // the input data is not null terminated.
    // copy to null terminated buffer

    wxCharBuffer nullTerminated( size+1 );
    memcpy( nullTerminated.data(), data, size );
    nullTerminated.data()[size] = 0;
    return wxConvUTF8.cMB2WC(nullTerminated.data());
}
示例#3
0
Process::ExecState Process::startInternal(const Path &command, const List<String> &a, const List<String> &environment,
                                          int timeout, unsigned int execFlags)
{
    mErrorString.clear();

    const char *path = 0;
    for (const auto &it : environment) {
        if (it.startsWith("PATH=")) {
            path = it.constData() + 5;
            break;
        }
    }
    Path cmd = findCommand(command, path);
    if (cmd.isEmpty()) {
        mErrorString = "Command not found";
        return Error;
    }
    List<String> arguments = a;
    int err;

    int closePipe[2];
    eintrwrap(err, ::pipe(closePipe));
#ifdef HAVE_CLOEXEC
    if (!SocketClient::setFlags(closePipe[1], FD_CLOEXEC, F_GETFD, F_SETFD)) {
        mErrorString = "Unable to set FD_CLOEXEC";
        eintrwrap(err, ::close(closePipe[0]));
        eintrwrap(err, ::close(closePipe[1]));
        return Error;
    }
#else
#warning No CLOEXEC, Process might have problematic behavior
#endif

    eintrwrap(err, ::pipe(mStdIn));
    eintrwrap(err, ::pipe(mStdOut));
    eintrwrap(err, ::pipe(mStdErr));
    if (mMode == Sync)
        eintrwrap(err, ::pipe(mSync));

    const char **args = new const char*[arguments.size() + 2];
    // const char* args[arguments.size() + 2];
    args[arguments.size() + 1] = 0;
    args[0] = cmd.nullTerminated();
    int pos = 1;
    for (List<String>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) {
        args[pos] = it->nullTerminated();
        // printf("arg: '%s'\n", args[pos]);
        ++pos;
    }

    const bool hasEnviron = !environment.empty();

    const char **env = new const char*[environment.size() + 1];
    env[environment.size()] = 0;

    if (hasEnviron) {
        pos = 0;
        //printf("fork, about to exec '%s'\n", cmd.nullTerminated());
        for (List<String>::const_iterator it = environment.begin(); it != environment.end(); ++it) {
            env[pos] = it->nullTerminated();
            //printf("env: '%s'\n", env[pos]);
            ++pos;
        }
    }

    ProcessThread::setPending(1);

    mPid = ::fork();
    if (mPid == -1) {
        //printf("fork, something horrible has happened %d\n", errno);
        // bail out

        ProcessThread::setPending(-1);

        eintrwrap(err, ::close(mStdIn[1]));
        eintrwrap(err, ::close(mStdIn[0]));
        eintrwrap(err, ::close(mStdOut[1]));
        eintrwrap(err, ::close(mStdOut[0]));
        eintrwrap(err, ::close(mStdErr[1]));
        eintrwrap(err, ::close(mStdErr[0]));
        eintrwrap(err, ::close(closePipe[1]));
        eintrwrap(err, ::close(closePipe[0]));
        mErrorString = "Fork failed";
        delete[] env;
        delete[] args;
        return Error;
    } else if (mPid == 0) {
        //printf("fork, in child\n");
        // child, should do some error checking here really
        eintrwrap(err, ::close(closePipe[0]));
        eintrwrap(err, ::close(mStdIn[1]));
        eintrwrap(err, ::close(mStdOut[0]));
        eintrwrap(err, ::close(mStdErr[0]));

        eintrwrap(err, ::close(STDIN_FILENO));
        eintrwrap(err, ::close(STDOUT_FILENO));
        eintrwrap(err, ::close(STDERR_FILENO));

        eintrwrap(err, ::dup2(mStdIn[0], STDIN_FILENO));
        eintrwrap(err, ::close(mStdIn[0]));
        eintrwrap(err, ::dup2(mStdOut[1], STDOUT_FILENO));
        eintrwrap(err, ::close(mStdOut[1]));
        eintrwrap(err, ::dup2(mStdErr[1], STDERR_FILENO));
        eintrwrap(err, ::close(mStdErr[1]));

        int ret;
        if (!mChRoot.isEmpty() && ::chroot(mChRoot.constData())) {
            goto error;
        }
        if (!mCwd.isEmpty() && ::chdir(mCwd.constData())) {
            goto error;
        }
        if (hasEnviron) {
            ret = ::execve(cmd.nullTerminated(), const_cast<char* const*>(args), const_cast<char* const*>(env));
        } else {
            ret = ::execv(cmd.nullTerminated(), const_cast<char* const*>(args));
        }
        // notify the parent process
  error:
        const char c = 'c';
        eintrwrap(err, ::write(closePipe[1], &c, 1));
        eintrwrap(err, ::close(closePipe[1]));
        ::_exit(1);
        (void)ret;
        //printf("fork, exec seemingly failed %d, %d %s\n", ret, errno, Rct::strerror().constData());
    } else {
        delete[] env;
        delete[] args;

        // parent
        eintrwrap(err, ::close(closePipe[1]));
        eintrwrap(err, ::close(mStdIn[0]));
        eintrwrap(err, ::close(mStdOut[1]));
        eintrwrap(err, ::close(mStdErr[1]));

        //printf("fork, in parent\n");

        int flags;
        eintrwrap(flags, fcntl(mStdIn[1], F_GETFL, 0));
        eintrwrap(flags, fcntl(mStdIn[1], F_SETFL, flags | O_NONBLOCK));
        eintrwrap(flags, fcntl(mStdOut[0], F_GETFL, 0));
        eintrwrap(flags, fcntl(mStdOut[0], F_SETFL, flags | O_NONBLOCK));
        eintrwrap(flags, fcntl(mStdErr[0], F_GETFL, 0));
        eintrwrap(flags, fcntl(mStdErr[0], F_SETFL, flags | O_NONBLOCK));

        // block until exec is called in the child or until exec fails
        {
            char c;
            eintrwrap(err, ::read(closePipe[0], &c, 1));
            (void)c;

            if (err == -1) {
                // bad
                eintrwrap(err, ::close(closePipe[0]));
                mErrorString = "Failed to read from closePipe during process start";
                mPid = -1;
                ProcessThread::setPending(-1);
                mReturn = ReturnCrashed;
                return Error;
            } else if (err == 0) {
                // process has started successfully
                eintrwrap(err, ::close(closePipe[0]));
            } else if (err == 1) {
                // process start failed
                eintrwrap(err, ::close(closePipe[0]));
                mErrorString = "Process failed to start";
                mReturn = ReturnCrashed;
                mPid = -1;
                ProcessThread::setPending(-1);
                return Error;
            }
        }

        ProcessThread::addPid(mPid, this, (mMode == Async));

        //printf("fork, about to add fds: stdin=%d, stdout=%d, stderr=%d\n", mStdIn[1], mStdOut[0], mStdErr[0]);
        if (mMode == Async) {
            if (EventLoop::SharedPtr loop = EventLoop::eventLoop()) {
                loop->registerSocket(mStdOut[0], EventLoop::SocketRead, std::bind(&Process::processCallback, this, std::placeholders::_1, std::placeholders::_2));
                loop->registerSocket(mStdErr[0], EventLoop::SocketRead, std::bind(&Process::processCallback, this, std::placeholders::_1, std::placeholders::_2));
            }
        } else {
            // select and stuff
            timeval started, now, timeoutForSelect;
            if (timeout > 0) {
                Rct::gettime(&started);
                timeoutForSelect.tv_sec = timeout / 1000;
                timeoutForSelect.tv_usec = (timeout % 1000) * 1000;
            }
            if (!(execFlags & NoCloseStdIn)) {
                closeStdIn(CloseForce);
                mWantStdInClosed = false;
            }
            for (;;) {
                // set up all the select crap
                fd_set rfds, wfds;
                FD_ZERO(&rfds);
                FD_ZERO(&wfds);
                int max = 0;
                FD_SET(mStdOut[0], &rfds);
                max = std::max(max, mStdOut[0]);
                FD_SET(mStdErr[0], &rfds);
                max = std::max(max, mStdErr[0]);
                FD_SET(mSync[0], &rfds);
                max = std::max(max, mSync[0]);
                if (mStdIn[1] != -1) {
                    FD_SET(mStdIn[1], &wfds);
                    max = std::max(max, mStdIn[1]);
                }
                int ret;
                eintrwrap(ret, ::select(max + 1, &rfds, &wfds, 0, timeout > 0 ? &timeoutForSelect : 0));
                if (ret == -1) { // ow
                    mErrorString = "Sync select failed: ";
                    mErrorString += Rct::strerror();
                    return Error;
                }
                // check fds and stuff
                if (FD_ISSET(mStdOut[0], &rfds))
                    handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut);
                if (FD_ISSET(mStdErr[0], &rfds))
                    handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr);
                if (mStdIn[1] != -1 && FD_ISSET(mStdIn[1], &wfds))
                    handleInput(mStdIn[1]);
                if (FD_ISSET(mSync[0], &rfds)) {
                    // we're done
                    {
                        std::lock_guard<std::mutex> lock(mMutex);
                        assert(mSync[1] == -1);

                        // try to read all remaining data on stdout and stderr
                        handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut);
                        handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr);

                        closeStdOut();
                        closeStdErr();

                        int w;
                        eintrwrap(w, ::close(mSync[0]));
                        mSync[0] = -1;
                    }
                    mFinished(this);
                    return Done;
                }
                if (timeout) {
                    Rct::gettime(&now);

                    // lasted is the amount of time we spent until now in ms
                    const int lasted = Rct::timevalDiff(&now, &started);
                    if (lasted >= timeout) {
                        // timeout, we're done
                        kill(); // attempt to kill

                        // we need to remove this Process object from
                        // ProcessThread, because ProcessThread will try to
                        // finish() this object. However, this object may
                        // already have been deleted *before* ProcessThread
                        // runs, creating a segfault.
                        ProcessThread::removePid(mPid);

                        mErrorString = "Timed out";
                        return TimedOut;
                    }

                    // (timeout - lasted) is guaranteed to be > 0 because of
                    // the check above.
                    timeoutForSelect.tv_sec = (timeout - lasted) / 1000;
                    timeoutForSelect.tv_usec = ((timeout - lasted) % 1000) * 1000;
                }
            }
        }
    }
    return Done;
}