diff options
author | José Fonseca <jose.r.fonseca@gmail.com> | 2011-11-11 14:56:42 +0000 |
---|---|---|
committer | José Fonseca <jose.r.fonseca@gmail.com> | 2011-11-11 20:14:05 +0000 |
commit | 03c5d3d41dc219051cbbb8b84ea505e15ff433c4 (patch) | |
tree | 9d21052f28cde35524cf8cdf2a57ac66435a4811 /common/os_win32.cpp | |
parent | 3984ad2eba8decfcfab3da10964746e0ef8720c7 (diff) |
Abstract execv().
Diffstat (limited to 'common/os_win32.cpp')
-rw-r--r-- | common/os_win32.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/common/os_win32.cpp b/common/os_win32.cpp index 74d911ca..e156c77b 100644 --- a/common/os_win32.cpp +++ b/common/os_win32.cpp @@ -29,6 +29,8 @@ #include <string.h> #include <stdio.h> +#include <string> + #include "os.hpp" #include "os_path.hpp" @@ -97,6 +99,116 @@ Path::exists(void) const return attrs != INVALID_FILE_ATTRIBUTES; } +/** + * Determine whether an argument should be quoted. + */ +static bool +needsQuote(const char *arg) +{ + char c; + while (true) { + c = *arg++; + if (c == '\0') { + break; + } + if (c == ' ' || c == '\t' || c == '\"') { + return true; + } + if (c == '\\') { + c = *arg++; + if (c == '\0') { + break; + } + if (c == '"') { + return true; + } + } + } + return false; +} + +static void +quoteArg(std::string &s, const char *arg) +{ + char c; + unsigned backslashes = 0; + + s.push_back('"'); + while (true) { + c = *arg++; + switch (c) + if (c == '\0') { + break; + } else if (c == '"') { + while (backslashes) { + s.push_back('\\'); + --backslashes; + } + s.push_back('\\'); + } else { + if (c == '\\') { + ++backslashes; + } else { + backslashes = 0; + } + } + s.push_back(c); + } + s.push_back('"'); +} + +int execute(char * const * args) +{ + std::string commandLine; + + const char *arg0 = *args; + const char *arg; + char sep = 0; + while ((arg = *args++) != NULL) { + if (sep) { + commandLine.push_back(sep); + } + + if (needsQuote(arg)) { + quoteArg(commandLine, arg); + } else { + commandLine.append(arg); + } + + sep = ' '; + } + + STARTUPINFO startupInfo; + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + PROCESS_INFORMATION processInformation; + + if (!CreateProcessA(NULL, + const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW + 0, // process attributes + 0, // thread attributes + FALSE, // inherit handles + 0, // creation flags, + NULL, // environment + NULL, // current directory + &startupInfo, + &processInformation + )) { + log("error: failed to execute %s\n", arg0); + } + + WaitForSingleObject(processInformation.hProcess, INFINITE); + + DWORD exitCode = ~0; + GetExitCodeProcess(processInformation.hProcess, &exitCode); + + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + return (int)exitCode; +} + void log(const char *format, ...) { |