13 #ifndef __STOUT_OS_WINDOWS_SHELL_HPP__
14 #define __STOUT_OS_WINDOWS_SHELL_HPP__
44 std::map<std::wstring, std::wstring> system_env;
45 wchar_t* env_entry =
nullptr;
50 if (!::CreateEnvironmentBlock((LPVOID*)&env_entry,
nullptr, FALSE)) {
55 wchar_t* env_block = env_entry;
57 while (*env_entry != L
'\0') {
68 std::wstring entry(env_entry);
69 std::wstring::size_type separator = entry.find(L
"=");
70 std::wstring var_name(entry.substr(0, separator));
71 std::wstring varVal(entry.substr(separator + 1));
77 var_name.begin(), var_name.end(), var_name.begin(), ::towupper);
80 system_env.insert_or_assign(var_name.data(), varVal.data());
83 env_entry += entry.length() + 1;
86 ::DestroyEnvironmentBlock(env_block);
105 const Option<std::map<std::string, std::string>>& env)
107 if (env.isNone() || (env.isSome() && env.get().size() == 0)) {
115 CHECK(system_env.
isSome() && system_env.
get().size() > 0);
117 std::map<std::wstring, std::wstring> combined_env;
121 const std::wstring& value,
123 combined_env[key] = value;
128 const std::string& value,
130 combined_env[wide_stringify(key)] = wide_stringify(value);
133 std::wstring env_string;
135 const std::wstring& value,
137 env_string += key + L
'=' + value + L
'\0';
141 env_string.push_back(L
'\0');
165 std::wstring command;
166 for (
auto argit = argv.cbegin(); argit != argv.cend(); ++argit) {
167 std::wstring arg = wide_stringify(*argit);
169 if (!arg.empty() && arg.find_first_of(L
" \t\n\v\"") == arg.npos) {
173 command.push_back(L
'"');
174 for (
auto it = arg.cbegin(); it != arg.cend(); ++it) {
176 unsigned int backslashes = 0;
177 while (it != arg.cend() && *it == L
'\\') {
182 if (it == arg.cend()) {
185 command.append(backslashes * 2, L
'\\');
187 }
else if (*it == L
'"') {
189 command.append(backslashes * 2 + 1, L
'\\');
190 command.push_back(*it);
193 command.append(backslashes, L
'\\');
194 command.push_back(*it);
199 command.push_back(L
'"');
202 if (argit != argv.cend() - 1) {
203 command.push_back(L
' ');
207 command.push_back(L
'\0');
234 const std::string& command,
235 const std::vector<std::string>& argv,
237 const bool create_suspended =
false,
238 const Option<std::tuple<int_fd, int_fd, int_fd>> pipes =
None())
242 std::vector<wchar_t> arg_buffer(arg_string.begin(), arg_string.end());
243 arg_buffer.push_back(L
'\0');
246 DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
247 if (create_suspended) {
248 creation_flags |= CREATE_SUSPENDED;
253 std::vector<wchar_t> env_buffer;
254 if (env_string.
isSome()) {
256 env_buffer.assign(env_string.
get().begin(), env_string.
get().end());
259 wchar_t* process_env = env_buffer.empty() ?
nullptr : env_buffer.data();
261 PROCESS_INFORMATION process_info;
262 memset(&process_info, 0,
sizeof(PROCESS_INFORMATION));
264 STARTUPINFOW startup_info;
265 memset(&startup_info, 0,
sizeof(STARTUPINFOW));
266 startup_info.cb =
sizeof(STARTUPINFOW);
274 if (pipes.isSome()) {
275 startup_info.hStdInput = std::get<0>(pipes.get());
276 startup_info.hStdOutput = std::get<1>(pipes.get());
277 startup_info.hStdError = std::get<2>(pipes.get());
278 startup_info.dwFlags |= STARTF_USESTDHANDLES;
281 BOOL create_process_result = ::CreateProcessW(
283 static_cast<LPCWSTR>(
nullptr),
284 static_cast<LPWSTR>(arg_buffer.data()),
285 static_cast<LPSECURITY_ATTRIBUTES>(
nullptr),
286 static_cast<LPSECURITY_ATTRIBUTES
>(
nullptr),
289 static_cast<LPVOID>(process_env),
290 static_cast<LPCWSTR
>(
nullptr),
294 if (!create_process_result) {
296 "Failed to call `CreateProcess`: " +
stringify(arg_string));
302 static_cast<pid_t>(process_info.dwProcessId)};
317 constexpr
const char*
name =
"cmd.exe";
318 constexpr
const char*
arg0 =
"cmd.exe";
319 constexpr
const char*
arg1 =
"/c";
323 template <
typename... T>
327 template<
typename... T>
328 inline int execlp(
const char*
file, T... t) =
delete;
335 const std::string& command,
336 const std::vector<std::string>& arguments,
343 LOG(WARNING) << process_data.
error();
348 ::WaitForSingleObject(
352 if (!::GetExitCodeProcess(
355 LOG(WARNING) <<
"Failed to `GetExitCodeProcess`: " << command;
360 return static_cast<int>(
status);
373 inline int system(
const std::string& command)
383 const std::string& command,
384 const std::vector<std::string>& argv)
395 const std::string& command,
396 const std::vector<std::string>& argv,
397 const std::map<std::string, std::string>& envp)
405 #endif // __STOUT_OS_WINDOWS_SHELL_HPP__
std::wstring stringify_args(const std::vector< std::string > &argv)
Definition: shell.hpp:163
constexpr const char * arg1
Definition: shell.hpp:43
Definition: option.hpp:28
HANDLE get_handle() const
Definition: windows.hpp:96
Definition: windows.hpp:78
int spawn(const std::string &command, const std::vector< std::string > &arguments)
Definition: shell.hpp:159
int execlp(const char *file, T...t)
Definition: shell.hpp:186
Definition: shell.hpp:211
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: error.hpp:106
UPID spawn(ProcessBase *process, bool manage=false)
Spawn a new process.
bool isSome() const
Definition: option.hpp:115
constexpr const char * arg0
Definition: shell.hpp:42
int execvp(const char *file, char *const argv[])
Definition: shell.hpp:192
Environment * environment
DWORD pid_t
Definition: windows.hpp:187
URI file(const std::string &path)
Creates a file URI with the given path on the local host.
Definition: file.hpp:33
SharedHandle process_handle
Definition: shell.hpp:212
SharedHandle thread_handle
Definition: shell.hpp:213
const T & get() const &
Definition: option.hpp:118
#define foreachpair(KEY, VALUE, ELEMS)
Definition: foreach.hpp:51
static Try error(const E &e)
Definition: try.hpp:42
process::Future< Nothing > transform(process::Owned< Reader< T >> &&reader, const std::function< std::string(const T &)> &func, process::http::Pipe::Writer writer)
This is a helper function that reads records from a Reader, applies a transformation to the records a...
Definition: recordio.hpp:112
Try< std::string > shell(const std::string &fmt, const T &...t)
Runs a shell command with optional arguments.
Definition: shell.hpp:71
Option< std::map< std::wstring, std::wstring > > get_system_env()
Definition: shell.hpp:42
bool isError() const
Definition: try.hpp:71
int execvpe(const std::string &command, const std::vector< std::string > &argv, const std::map< std::string, std::string > &envp)
Definition: shell.hpp:394
Option< std::wstring > create_process_env(const Option< std::map< std::string, std::string >> &env)
Definition: shell.hpp:104
pid_t pid
Definition: shell.hpp:214
std::string stringify(int flags)
const T & get() const
Definition: try.hpp:73
constexpr const char * name
Definition: shell.hpp:41
Try< ProcessData > create_process(const std::string &command, const std::vector< std::string > &argv, const Option< std::map< std::string, std::string >> &environment, const bool create_suspended=false, const Option< std::tuple< int_fd, int_fd, int_fd >> pipes=None())
Definition: shell.hpp:233
int system(const std::string &command)
Definition: shell.hpp:130