-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsystem.cpp
More file actions
164 lines (160 loc) · 4.75 KB
/
Copy pathsystem.cpp
File metadata and controls
164 lines (160 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "system.hpp"
#include <iostream>
#include <filesystem>
#if defined(__APPLE__) && defined(__MACH__)
#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE
#define OS_MACOS
#else
static_assert(false, "Failed to detect an acceptable OS (iOS is not supported)."
);
#endif
#elif defined(_WIN32) || defined(_WIN64)
#define OS_WINDOWS
#elif defined(__linux__)
#define OS_LINUX
#else
static_assert(false, "Failed to detect an acceptable OS (no valid macros define"
"d).");
#endif
#if defined(OS_MACOS) || defined(OS_LINUX)
#define OS_UNIX
#endif
#ifdef OS_WINDOWS
#include <windows.h>
#else
#include <unistd.h>
#include <sys/wait.h>
#include <sys/fcntl.h>
#include <cstring>
#endif
void pgfplotter::system_call(const std::string& file, const std::vector<std::
string>& args)
{
#ifdef OS_WINDOWS
std::string cmd = file;
for(const auto& n : args)
{
cmd += " \"" + n + "\"";
}
STARTUPINFOA si = {};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = nullptr;
HANDLE g_hChildStd_IN_Rd = nullptr;
HANDLE g_hChildStd_IN_Wr = nullptr;
HANDLE g_hChildStd_OUT_Rd = nullptr;
HANDLE g_hChildStd_OUT_Wr = nullptr;
if(!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0))
{
throw std::runtime_error("Failed to create output pipe: Error " + std::
to_string(GetLastError()) + ".");
}
if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
{
throw std::runtime_error("Failed to set output pipe to inherit: Error "
+ std::to_string(GetLastError()) + ".");
}
if(!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &sa, 0))
{
throw std::runtime_error("Failed to create input pipe: Error " + std::
to_string(GetLastError()) + ".");
}
if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
{
throw std::runtime_error("Failed to set input pipe to inherit: Error " +
std::to_string(GetLastError()) + ".");
}
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdInput = g_hChildStd_IN_Rd;
si.dwFlags |= STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
if(!CreateProcessA(nullptr, const_cast<char*>(cmd.c_str()), nullptr,
nullptr, true, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi))
{
throw std::runtime_error("Failed to create process: Error " + std::
to_string(GetLastError()) + ".");
}
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitCode;
if(!GetExitCodeProcess(pi.hProcess, &exitCode))
{
throw std::runtime_error("Failed to get exit code: Error " + std::
to_string(GetLastError()) + ".");
}
if(exitCode == STILL_ACTIVE)
{
throw std::runtime_error("Wait returned before process completed.");
}
if(exitCode)
{
throw std::runtime_error("System call returned " + std::to_string(
exitCode) + ".");
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(g_hChildStd_OUT_Wr);
g_hChildStd_OUT_Wr = nullptr;
CloseHandle(g_hChildStd_IN_Rd);
g_hChildStd_OUT_Wr = nullptr;
#else
const auto pid = fork();
if(pid > 0)
{
int status;
if(waitpid(pid, &status, 0) < 0)
{
throw std::runtime_error("Wait failed.");
}
if(!WIFEXITED(status))
{
throw std::runtime_error("System call did not exit normally.");
}
const auto exitCode = WEXITSTATUS(status);
if(exitCode)
{
throw std::runtime_error("System call returned " + std::to_string(
exitCode) + ".");
}
}
else if(pid == 0)
{
std::vector<const char*> argv = {file.c_str()};
for(const auto& n : args)
{
argv.push_back(n.c_str());
}
argv.push_back(nullptr);
const auto fd = open("/dev/null", O_WRONLY);
if(fd < 0)
{
std::cerr << "Warning: Failed to open \"/dev/null\": " << std::
strerror(errno) << std::endl;
}
else
{
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
const int status = execvp(argv[0], const_cast<char**>(argv.data()));
std::exit(status);
}
else
{
throw std::runtime_error("Fork failed: " + std::string(std::strerror(
errno)) + ".");
}
#endif
}
void pgfplotter::split_path(const std::string& path, std::string& dir, std::
string& name)
{
const std::filesystem::path p(path);
dir = p.parent_path().string();
name = p.filename().string();
}