diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp | 320 |
1 files changed, 0 insertions, 320 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp deleted file mode 100644 index 2010b05db93..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/************************************************************************* -** Process.cpp ** -** ** -** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2021 Martin Gieseking <martin.gieseking@uos.de> ** -** ** -** This program is free software; you can redistribute it and/or ** -** modify it under the terms of the GNU General Public License as ** -** published by the Free Software Foundation; either version 3 of ** -** the License, or (at your option) any later version. ** -** ** -** This program is distributed in the hope that it will be useful, but ** -** WITHOUT ANY WARRANTY; without even the implied warranty of ** -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** -** GNU General Public License for more details. ** -** ** -** You should have received a copy of the GNU General Public License ** -** along with this program; if not, see <http://www.gnu.org/licenses/>. ** -*************************************************************************/ - -#ifdef _WIN32 - #include "windows.hpp" -#else - #include <csignal> - #include <cstring> - #include <fcntl.h> - #include <sys/wait.h> - #include <unistd.h> -#endif - -#include <cstdlib> -#include "FileSystem.hpp" -#include "Process.hpp" -#include "SignalHandler.hpp" - -using namespace std; - - -/** Helper class that encapsulates the system-specific parts of - * running a subprocess and retrieving its terminal output. */ -class Subprocess { - public: - enum class State {RUNNING, FINISHED, FAILED}; - - public: - Subprocess () =default; - Subprocess (const Subprocess&) =delete; - Subprocess (Subprocess&&) =delete; - ~Subprocess (); - bool run (const string &cmd, string params); - bool readFromPipe (string &out); - State state (); - - private: -#ifdef _WIN32 - HANDLE _pipeReadHandle=NULL; ///< handle of read end of pipe - HANDLE _childProcHandle=NULL; ///< handle of child process -#else - int _readfd=-1; ///< file descriptor of read end of pipe - pid_t _pid=-1; ///< PID of the subprocess -#endif -}; - - -Process::Process (string cmd, string paramstr) - : _cmd(std::move(cmd)), _paramstr(std::move(paramstr)) -{ -} - - -/** Runs the process and waits until it's finished. - * @param[out] out takes the output written to stdout by the executed subprocess - * @return true if process terminated properly - * @throw SignalException if CTRL-C was pressed during execution */ -bool Process::run (string *out) { - Subprocess subprocess; - if (!subprocess.run(_cmd, _paramstr)) - return false; - for (;;) { - if (out) { - out->clear(); - subprocess.readFromPipe(*out); - } - Subprocess::State state = subprocess.state(); - if (state != Subprocess::State::RUNNING) - return state == Subprocess::State::FINISHED; - SignalHandler::instance().check(); - } -} - - -/** Runs the process in the given working directory and waits until it's finished. - * @param[in] dir working directory - * @param[out] out takes the output written to stdout by the executed process - * @return true if process terminated properly - * @throw SignalException if CTRL-C was pressed during execution */ -bool Process::run (const string &dir, string *out) { - bool ret = false; - string cwd = FileSystem::getcwd(); - if (FileSystem::chdir(dir)) { - ret = run(out); - ret &= FileSystem::chdir(cwd); - } - return ret; -} - -// system-specific stuff - -#ifdef _WIN32 - -static inline void close_and_zero_handle (HANDLE &handle) { - CloseHandle(handle); - handle = NULL; -} - - -Subprocess::~Subprocess () { - if (_pipeReadHandle != NULL) - CloseHandle(_pipeReadHandle); - if (_childProcHandle != NULL) { - TerminateProcess(_childProcHandle, 1); - CloseHandle(_childProcHandle); - } -} - - -/** Retrieves output generated by child process. - * @param[out] out read output is appended to this string - * @returns false on errors */ -bool Subprocess::readFromPipe (string &out) { - if (!_pipeReadHandle) - return false; - - bool success=false; - bool processExited=false; - DWORD len=0; - while (PeekNamedPipe(_pipeReadHandle, NULL, 0, NULL, &len, NULL)) { // prevent blocking - if (len == 0) { - if (processExited) - break; - // process still busy - processExited = (!_childProcHandle || WaitForSingleObject(_childProcHandle, 100) != WAIT_TIMEOUT); - } - else { - char buf[4096]; - success = ReadFile(_pipeReadHandle, buf, sizeof(buf), &len, NULL); - if (!success || len == 0) - break; - out.append(buf, len); - } - } - return success; -} - - -/** Starts a child process. - * @param[in] cmd name of command to execute - * @param[in] paramstr parameters required by command - * @returns true if child process started properly */ -bool Subprocess::run (const string &cmd, string paramstr) { - SECURITY_ATTRIBUTES securityAttribs; - ZeroMemory(&securityAttribs, sizeof(SECURITY_ATTRIBUTES)); - securityAttribs.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttribs.bInheritHandle = true; - - HANDLE pipeWriteHandle; // write end of pipe - if (CreatePipe(&_pipeReadHandle, &pipeWriteHandle, &securityAttribs, 0) == ERROR_INVALID_HANDLE) - return false; - - SetHandleInformation(_pipeReadHandle, HANDLE_FLAG_INHERIT, 0); - HANDLE nullFile = CreateFile("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &securityAttribs, OPEN_EXISTING, 0, NULL); - bool success = false; - if (nullFile != INVALID_HANDLE_VALUE) { - STARTUPINFO startupInfo; - ZeroMemory(&startupInfo, sizeof(STARTUPINFO)); - startupInfo.cb = sizeof(STARTUPINFO); - startupInfo.dwFlags = STARTF_USESTDHANDLES; - startupInfo.hStdInput = nullFile; - startupInfo.hStdOutput = pipeWriteHandle; - startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - - PROCESS_INFORMATION processInfo; - ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); - - string cmdline = cmd + " " + paramstr; - // put subprocess in separate process group to prevent its termination in case of CTRL-C - success = CreateProcess(NULL, (LPSTR)cmdline.c_str(), NULL, NULL, true, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &startupInfo, &processInfo); - if (success) { - _childProcHandle = processInfo.hProcess; - CloseHandle(processInfo.hThread); - } - CloseHandle(nullFile); - } - CloseHandle(pipeWriteHandle); // must be closed before reading from pipe to prevent blocking - if (!success) - close_and_zero_handle(_pipeReadHandle); - return success; -} - - -/** Returns the current state of the child process. */ -Subprocess::State Subprocess::state () { - DWORD status; - if (!GetExitCodeProcess(_childProcHandle, &status)) - return State::FAILED; - if (status == STILL_ACTIVE) - return State::RUNNING; - close_and_zero_handle(_childProcHandle); - return status == 0 ? State::FINISHED : State::FAILED; -} - -#else // !_WIN32 - -Subprocess::~Subprocess () { - if (_readfd >= 0) - close(_readfd); - if (_pid > 0) - kill(_pid, SIGKILL); -} - - -/** Retrieves output generated by child process. - * @param[out] out read output is appended to this string - * @returns false on errors */ -bool Subprocess::readFromPipe (string &out) { - if (_readfd < 0 || _pid < 0) - return false; - - char buf[1024]; - ssize_t len; - while ((len = read(_readfd, buf, sizeof(buf))) > 0) - out.append(buf, len); - if (len < 0) { - close(_readfd); - _readfd = -1; - } - return len >= 0; -} - - -/** Extracts whitespace-separated parameters from a string. - * @param[in,out] paramstr the parameter string - * @param[out] params vector holding pointers to the extracted parameters */ -static void split_paramstr (string ¶mstr, vector<const char*> ¶ms) { - size_t left=0, right=0; // index of first and last character of current parameter - char quote=0; // current quote character, 0=none - const size_t len = paramstr.length(); - while (left <= right && right < len) { - while (left < len && isspace(paramstr[left])) - ++left; - if (left < len && (paramstr[left] == '"' || paramstr[left] == '\'')) - quote = paramstr[left++]; - right = left; - while (right < len && (quote || !isspace(paramstr[right]))) { - if (quote && paramstr[right] == quote) { - quote=0; - break; - } - else - ++right; - } - if (right < len) - paramstr[right]=0; - if (left < len) - params.push_back(¶mstr[left]); - left = ++right; - } -} - - -/** Starts a child process. - * @param[in] cmd name of command to execute or absolute path to executable - * @param[in] paramstr parameters required by the command - * @returns true if child process started properly */ -bool Subprocess::run (const string &cmd, string paramstr) { - int pipefd[2]; - if (cmd.empty() || pipe(pipefd) < 0) - return false; - - _pid = fork(); - if (_pid < 0) { - close(pipefd[0]); - close(pipefd[1]); - return false; - } - if (_pid == 0) { // child process - dup2(pipefd[1], STDOUT_FILENO); // redirect stdout to the pipe - dup2(pipefd[1], STDERR_FILENO); // redirect stderr to the pipe - close(pipefd[0]); - close(pipefd[1]); - - vector<const char*> params; - params.push_back(cmd.c_str()); - split_paramstr(paramstr, params); - params.push_back(nullptr); // trailing null pointer marks end of parameter list - signal(SIGINT, SIG_IGN); // child process is supposed to ignore ctrl-c events - if (params[0][0] == '/') // absolute path to executable? - params[0] = strrchr(params[0], '/')+1; // filename of executable - execvp(cmd.c_str(), const_cast<char* const*>(params.data())); - exit(1); - } - _readfd = pipefd[0]; - close(pipefd[1]); // close write end of pipe - return true; -} - - -/** Returns the current state of the child process. */ -Subprocess::State Subprocess::state () { - int status; - pid_t wpid = waitpid(_pid, &status, WNOHANG); - if (wpid == 0) - return State::RUNNING; // still running - _pid = -1; - if (wpid > 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0) - return State::FINISHED; - return State::FAILED; -} - -#endif // !_WIN32 |