diff options
author | David Majnemer <david.majnemer@gmail.com> | 2013-10-07 01:00:07 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2013-10-07 01:00:07 +0000 |
commit | 6a971bb8f59f4e20c953a2cc360cab7bae8642e4 (patch) | |
tree | f3784bd1d13b1987a65df2b1d1a06830e9eeed88 /lib/Support/Windows | |
parent | 32e3150faba95187c76b211e27d6496a21bee360 (diff) | |
download | llvm-6a971bb8f59f4e20c953a2cc360cab7bae8642e4.tar.gz llvm-6a971bb8f59f4e20c953a2cc360cab7bae8642e4.tar.bz2 llvm-6a971bb8f59f4e20c953a2cc360cab7bae8642e4.tar.xz |
Revert "Revert "Windows: Add support for unicode command lines""
This reverts commit r192070 which reverted r192069, I forgot to
regenerate the configure scripts.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192079 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support/Windows')
-rw-r--r-- | lib/Support/Windows/DynamicLibrary.inc | 9 | ||||
-rw-r--r-- | lib/Support/Windows/Path.inc | 29 | ||||
-rw-r--r-- | lib/Support/Windows/Process.inc | 62 | ||||
-rw-r--r-- | lib/Support/Windows/Program.inc | 126 | ||||
-rw-r--r-- | lib/Support/Windows/Signals.inc | 2 | ||||
-rw-r--r-- | lib/Support/Windows/Windows.h | 1 |
6 files changed, 147 insertions, 82 deletions
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc index 2edaf74fa5..5a7b21920a 100644 --- a/lib/Support/Windows/DynamicLibrary.inc +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -83,8 +83,15 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, // This is mostly to ensure that the return value still shows up as "valid". return DynamicLibrary(&OpenedHandles); } + + SmallVector<wchar_t, MAX_PATH> filenameUnicode; + if (error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) { + SetLastError(ec.value()); + MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16: "); + return DynamicLibrary(); + } - HMODULE a_handle = LoadLibrary(filename); + HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); if (a_handle == 0) { MakeErrMsg(errMsg, std::string(filename) + ": Can't open : "); diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 94a501b39a..998ec422ec 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -128,7 +128,7 @@ retry_random_path: BYTE val = 0; if (!::CryptGenRandom(CryptoProvider, 1, &val)) return windows_error(::GetLastError()); - random_path_utf16.push_back("0123456789abcdef"[val & 15]); + random_path_utf16.push_back(L"0123456789abcdef"[val & 15]); } else random_path_utf16.push_back(*i); @@ -241,22 +241,23 @@ TimeValue file_status::getLastModificationTime() const { } error_code current_path(SmallVectorImpl<char> &result) { - SmallVector<wchar_t, 128> cur_path; - cur_path.reserve(128); -retry_cur_dir: - DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + SmallVector<wchar_t, MAX_PATH> cur_path; + DWORD len = MAX_PATH; - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return windows_error(::GetLastError()); - - // If there's insufficient space, the len returned is larger than the len - // given. - if (len > cur_path.capacity()) { + do { cur_path.reserve(len); - goto retry_cur_dir; - } + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); + + // If there's insufficient space, the len returned is larger than the len + // given. + } while (len > cur_path.capacity()); + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. cur_path.set_size(len); return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 5d776504fb..4d801492e8 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -11,18 +11,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Allocator.h" + #include "Windows.h" #include <direct.h> #include <io.h> #include <malloc.h> #include <psapi.h> +#include <shellapi.h> #ifdef __MINGW32__ #if (HAVE_LIBPSAPI != 1) #error "libpsapi.a should be present" #endif + #if (HAVE_LIBSHELL32 != 1) + #error "libshell32.a should be present" + #endif #else #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "shell32.lib") #endif //===----------------------------------------------------------------------===// @@ -151,25 +158,58 @@ Optional<std::string> Process::GetEnv(StringRef Name) { // Environment variable can be encoded in non-UTF8 encoding, and there's no // way to know what the encoding is. The only reliable way to look up // multibyte environment variable is to use GetEnvironmentVariableW(). - std::vector<wchar_t> Buf(16); - size_t Size = 0; - for (;;) { - Size = GetEnvironmentVariableW(&NameUTF16[0], &Buf[0], Buf.size()); - if (Size < Buf.size()) - break; + SmallVector<wchar_t, MAX_PATH> Buf; + size_t Size = MAX_PATH; + do { + Buf.reserve(Size); + Size = GetEnvironmentVariableW(&NameUTF16[0], &Buf[0], Buf.capacity()); + if (Size == 0) + return None; + // Try again with larger buffer. - Buf.resize(Size + 1); - } - if (Size == 0) - return None; + } while (Size > Buf.capacity()); + Buf.set_size(Size); // Convert the result from UTF-16 to UTF-8. - SmallVector<char, 128> Res; + SmallVector<char, MAX_PATH> Res; if (error_code ec = windows::UTF16ToUTF8(&Buf[0], Size, Res)) return None; return std::string(&Res[0]); } +error_code +Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, + ArrayRef<const char *>, + SpecificBumpPtrAllocator<char> &ArgAllocator) { + int NewArgCount; + error_code ec; + + wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(), + &NewArgCount); + if (!UnicodeCommandLine) + return windows_error(::GetLastError()); + + Args.reserve(NewArgCount); + + for (int i = 0; i < NewArgCount; ++i) { + SmallVector<char, MAX_PATH> NewArgString; + ec = windows::UTF16ToUTF8(UnicodeCommandLine[i], + wcslen(UnicodeCommandLine[i]), + NewArgString); + if (ec) + break; + + char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1); + ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1); + Args.push_back(Buffer); + } + LocalFree(UnicodeCommandLine); + if (ec) + return ec; + + return error_code::success(); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(0); } diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 28690852b0..e464e2f687 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -42,42 +42,39 @@ std::string sys::FindProgramByName(const std::string &progName) { // At this point, the file name is valid and does not contain slashes. // Let Windows search for it. - std::string buffer; - buffer.resize(MAX_PATH); - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - &buffer[0], &dummy); - - // See if it wasn't found. - if (len == 0) + SmallVector<wchar_t, MAX_PATH> progNameUnicode; + if (windows::UTF8ToUTF16(progName, progNameUnicode)) return ""; - // See if we got the entire path. - if (len < MAX_PATH) - return buffer; + SmallVector<wchar_t, MAX_PATH> buffer; + DWORD len = MAX_PATH; + do { + buffer.reserve(len); + len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe", + buffer.capacity(), buffer.data(), NULL); - // Buffer was too small; grow and retry. - while (true) { - buffer.resize(len+1); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, &buffer[0], &dummy); - - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) + // See if it wasn't found. + if (len == 0) return ""; - else if (len2 <= len) - return buffer; - len = len2; - } + // Buffer was too small; grow and retry. + } while (len > buffer.capacity()); + + buffer.set_size(len); + SmallVector<char, MAX_PATH> result; + if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) + return ""; + + return std::string(result.data(), result.size()); } static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { HANDLE h; if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; return h; } @@ -92,9 +89,13 @@ static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; - h = CreateFile(fname.c_str(), fd ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); + SmallVector<wchar_t, 128> fnameUnicode; + if (windows::UTF8ToUTF16(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + + h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + (fd ? "input: " : "output: ")); @@ -218,34 +219,28 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, *p = 0; // The pointer to the environment block for the new process. - OwningArrayPtr<char> envblock; + std::vector<wchar_t> EnvBlock; if (envp) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. + for (unsigned i = 0; envp[i]; ++i) { + SmallVector<wchar_t, MAX_PATH> EnvString; + if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); + return false; + } - // First, determine the length of the environment block. - len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock.reset(new char[len+1]); - p = envblock.get(); - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; + EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); + EnvBlock.push_back(0); } - - *p = 0; + EnvBlock.push_back(0); } // Create a child process. - STARTUPINFO si; + STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; @@ -269,9 +264,14 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); + return false; + } } else { // Just redirect stderr si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); @@ -289,9 +289,27 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, fflush(stdout); fflush(stderr); - std::string ProgramStr = Program; - BOOL rc = CreateProcess(ProgramStr.c_str(), command.get(), NULL, NULL, TRUE, - 0, envblock.get(), NULL, &si, &pi); + + SmallVector<wchar_t, MAX_PATH> ProgramUtf16; + if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert application name to UTF-16")); + return false; + } + + SmallVector<wchar_t, MAX_PATH> CommandUtf16; + if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert command-line to UTF-16")); + return false; + } + + BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, + TRUE, CREATE_UNICODE_ENVIRONMENT, + EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, + &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with @@ -304,7 +322,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - ProgramStr + "'"); + Program.str() + "'"); return false; } diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index bce83b9686..2b4a66d008 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -135,7 +135,7 @@ typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); static fpSymFunctionTableAccess64 SymFunctionTableAccess64; static bool load64BitDebugHelp(void) { - HMODULE hLib = ::LoadLibrary("Dbghelp.dll"); + HMODULE hLib = ::LoadLibrary(TEXT("Dbghelp.dll")); if (hLib) { StackWalk64 = (fpStackWalk64) ::GetProcAddress(hLib, "StackWalk64"); diff --git a/lib/Support/Windows/Windows.h b/lib/Support/Windows/Windows.h index 1236fe5652..657ae4fc83 100644 --- a/lib/Support/Windows/Windows.h +++ b/lib/Support/Windows/Windows.h @@ -31,7 +31,6 @@ #include "llvm/Support/system_error.h" #include <windows.h> #include <wincrypt.h> -#include <shlobj.h> #include <cassert> #include <string> #include <vector> |