~reviczky/luatex/texlive-bin-git

« back to all changes in this revision

Viewing changes to texk/dvisvgm/dvisvgm-1.8.1/src/Process.cpp

  • Committer: Adam Reviczky
  • Date: 2015-04-26 22:40:47 UTC
  • Revision ID: adam.reviczky@kclalumni.net-20150426224047-i2p26n3wqphupq6z
TeX Live 2015 import (rev. 37052)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*************************************************************************
2
 
** Process.cpp                                                          **
3
 
**                                                                      **
4
 
** This file is part of dvisvgm -- the DVI to SVG converter             **
5
 
** Copyright (C) 2005-2014 Martin Gieseking <martin.gieseking@uos.de>   **
6
 
**                                                                      **
7
 
** This program is free software; you can redistribute it and/or        **
8
 
** modify it under the terms of the GNU General Public License as       **
9
 
** published by the Free Software Foundation; either version 3 of       **
10
 
** the License, or (at your option) any later version.                  **
11
 
**                                                                      **
12
 
** This program is distributed in the hope that it will be useful, but  **
13
 
** WITHOUT ANY WARRANTY; without even the implied warranty of           **
14
 
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         **
15
 
** GNU General Public License for more details.                         **
16
 
**                                                                      **
17
 
** You should have received a copy of the GNU General Public License    **
18
 
** along with this program; if not, see <http://www.gnu.org/licenses/>. **
19
 
*************************************************************************/
20
 
 
21
 
#include <config.h>
22
 
 
23
 
#ifdef __WIN32__
24
 
        #include <windows.h>
25
 
#else
26
 
        #include <fcntl.h>
27
 
        #include <sys/wait.h>
28
 
        #include <unistd.h>
29
 
        #include <signal.h>
30
 
#endif
31
 
 
32
 
#include <cstdlib>
33
 
#include "FileSystem.h"
34
 
#include "Process.h"
35
 
#include "SignalHandler.h"
36
 
#include "macros.h"
37
 
 
38
 
using namespace std;
39
 
 
40
 
Process::Process (const string &cmd, const string &paramstr)
41
 
        : _cmd(cmd), _paramstr(paramstr)
42
 
{
43
 
}
44
 
 
45
 
 
46
 
#ifdef __WIN32__
47
 
static void pipe_read (HANDLE handle, string &out) {
48
 
        char buf[4096];
49
 
        out.clear();
50
 
        for (;;) {
51
 
                DWORD num_chars;
52
 
                bool success = ReadFile(handle, buf, 1024, &num_chars, NULL);
53
 
                if (!success || num_chars == 0)
54
 
                        break;
55
 
                out.append(buf, num_chars);
56
 
        }
57
 
        // remove trailing space
58
 
        if (!out.empty()) {
59
 
                int pos = out.size()-1;
60
 
                while (pos >= 0 && isspace(out[pos]))
61
 
                        pos--;
62
 
                out.erase(pos+1);
63
 
        }
64
 
}
65
 
 
66
 
 
67
 
static inline void close_handle (HANDLE handle) {
68
 
        if (handle != NULL)
69
 
                CloseHandle(handle);
70
 
}
71
 
 
72
 
#else
73
 
 
74
 
/** Extracts whitespace-sparated parameters from a string.
75
 
 *  @param[in] paramstr the parameter string
76
 
 *  @param[out] params vector holding the extracted parameters */
77
 
static void split_paramstr (string paramstr, vector<const char*> &params) {
78
 
        size_t left=0, right=0;  // index of first and last character of current parameter
79
 
        char quote=0;            // current quote character, 0=none
80
 
        const size_t len = paramstr.length();
81
 
        while (left <= right && right < len) {
82
 
                while (left < len && isspace(paramstr[left]))
83
 
                        ++left;
84
 
                if (left < len && (paramstr[left] == '"' || paramstr[left] == '\''))
85
 
                        quote = paramstr[left++];
86
 
                right = left;
87
 
                while (right < len && (quote || !isspace(paramstr[right]))) {
88
 
                        if (quote && paramstr[right] == quote) {
89
 
                                quote=0;
90
 
                                break;
91
 
                        }
92
 
                        else
93
 
                                ++right;
94
 
                }
95
 
                if (right < len)
96
 
                        paramstr[right]=0;
97
 
                if (left < len)
98
 
                        params.push_back(&paramstr[left]);
99
 
                left = ++right;
100
 
        }
101
 
}
102
 
 
103
 
#endif
104
 
 
105
 
 
106
 
/** Runs the process and waits until it's finished.
107
 
 *  @param[out] out takes the output written to stdout by the executed process
108
 
 *  @return true if process terminated properly
109
 
 *  @throw SignalException if CTRL-C was pressed during execution */
110
 
bool Process::run (string *out) {
111
 
#ifdef __WIN32__
112
 
        SECURITY_ATTRIBUTES sa;
113
 
        ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
114
 
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
115
 
        sa.bInheritHandle = true;
116
 
 
117
 
        STARTUPINFO si;
118
 
        ZeroMemory(&si, sizeof(STARTUPINFO));
119
 
        si.cb = sizeof(STARTUPINFO);
120
 
        si.dwFlags = STARTF_USESTDHANDLES;
121
 
        HANDLE devnull = NULL;
122
 
        HANDLE proc_read_handle = NULL;
123
 
        HANDLE proc_write_handle = NULL;
124
 
        if (out) {
125
 
                CreatePipe(&proc_read_handle, &proc_write_handle, &sa, 0);
126
 
                SetHandleInformation(proc_read_handle, HANDLE_FLAG_INHERIT, 0);
127
 
                si.hStdOutput = proc_write_handle;
128
 
        }
129
 
        else {
130
 
                devnull = CreateFile("nul", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
131
 
                si.hStdOutput = devnull;
132
 
        }
133
 
        si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
134
 
        si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
135
 
 
136
 
        PROCESS_INFORMATION pi;
137
 
        ZeroMemory(&pi, sizeof(pi));
138
 
        DWORD exitcode = DWORD(-1);
139
 
        string cmdline = _cmd+" "+_paramstr;
140
 
        bool success = CreateProcess(NULL, (LPSTR)cmdline.c_str(), NULL, NULL, true, 0, NULL, NULL, &si, &pi);
141
 
        if (success) {
142
 
                WaitForSingleObject(pi.hProcess, INFINITE);
143
 
                GetExitCodeProcess(pi.hProcess, &exitcode);
144
 
                CloseHandle(pi.hProcess);
145
 
                CloseHandle(pi.hThread);
146
 
        }
147
 
        close_handle(proc_write_handle);  // must be closed before reading from pipe to prevent blocking
148
 
        if (success && out)
149
 
                pipe_read(proc_read_handle, *out);
150
 
        close_handle(proc_read_handle);
151
 
        close_handle(devnull);
152
 
        return exitcode == 0;
153
 
#else
154
 
        pid_t pid = fork();
155
 
        if (pid == 0) {   // child process
156
 
                if (!out) {
157
 
                        int devnull = open(FileSystem::DEVNULL, O_WRONLY);
158
 
                        if (devnull >= 0) {
159
 
                                dup2(devnull, STDOUT_FILENO);
160
 
                                dup2(devnull, STDERR_FILENO);
161
 
                                close(devnull);
162
 
                        }
163
 
                }
164
 
                vector<const char*> params;
165
 
                params.push_back(_cmd.c_str());
166
 
                split_paramstr(_paramstr, params);
167
 
                params.push_back(0);     // trailing NULL marks end
168
 
                execvp(_cmd.c_str(), const_cast<char* const*>(&params[0]));
169
 
                exit(1);
170
 
        }
171
 
        if (pid > 0) {    // main process
172
 
                int status;
173
 
                for (;;) {
174
 
                        waitpid(pid, &status, WNOHANG);
175
 
                        if (WIFEXITED(status)) // child process exited normally
176
 
                                return WEXITSTATUS(status) == 0;
177
 
 
178
 
                        try {
179
 
                                SignalHandler::instance().check();
180
 
                        }
181
 
                        catch (SignalException &e) { // caught ctrl-c
182
 
                                kill(pid, SIGKILL);
183
 
                                throw;
184
 
                        }
185
 
                }
186
 
        }
187
 
        return false;
188
 
#endif
189
 
}
190