diff options
author | Stephen Hines <srhines@google.com> | 2014-12-01 14:51:49 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-12-02 16:08:10 -0800 |
commit | 37ed9c199ca639565f6ce88105f9e39e898d82d0 (patch) | |
tree | 8fb36d3910e3ee4c4e1b7422f4f017108efc52f5 /lib/Support/Windows/Program.inc | |
parent | d2327b22152ced7bc46dc629fc908959e8a52d03 (diff) | |
download | external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.zip external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.gz external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.bz2 |
Update aosp/master LLVM for rebase to r222494.
Change-Id: Ic787f5e0124df789bd26f3f24680f45e678eef2d
Diffstat (limited to 'lib/Support/Windows/Program.inc')
-rw-r--r-- | lib/Support/Windows/Program.inc | 184 |
1 files changed, 130 insertions, 54 deletions
diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index b2f71ae..72c2a58 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -12,7 +12,11 @@ //===----------------------------------------------------------------------===// #include "WindowsSupport.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/WindowsError.h" #include <cstdio> #include <fcntl.h> #include <io.h> @@ -28,43 +32,67 @@ using namespace sys; ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} -// This function just uses the PATH environment variable to find the program. -std::string sys::FindProgramByName(const std::string &progName) { - // Check some degenerate cases - if (progName.length() == 0) // no program - return ""; - std::string temp = progName; - // Return paths with slashes verbatim. - if (progName.find('\\') != std::string::npos || - progName.find('/') != std::string::npos) - return temp; - - // At this point, the file name is valid and does not contain slashes. - // Let Windows search for it. - SmallVector<wchar_t, MAX_PATH> progNameUnicode; - if (windows::UTF8ToUTF16(progName, progNameUnicode)) - return ""; - - 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); - - // See if it wasn't found. - if (len == 0) - return ""; - - // 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()); +ErrorOr<std::string> sys::findProgramByName(StringRef Name, + ArrayRef<StringRef> Paths) { + assert(!Name.empty() && "Must have a name!"); + + if (Name.find_first_of("/\\") != StringRef::npos) + return std::string(Name); + + const wchar_t *Path = nullptr; + std::wstring PathStorage; + if (!Paths.empty()) { + PathStorage.reserve(Paths.size() * MAX_PATH); + for (unsigned i = 0; i < Paths.size(); ++i) { + if (i) + PathStorage.push_back(L';'); + StringRef P = Paths[i]; + SmallVector<wchar_t, MAX_PATH> TmpPath; + if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath)) + return EC; + PathStorage.append(TmpPath.begin(), TmpPath.end()); + } + Path = PathStorage.c_str(); + } + + SmallVector<wchar_t, MAX_PATH> U16Name; + if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name)) + return EC; + + SmallVector<StringRef, 12> PathExts; + PathExts.push_back(""); + PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%. + SplitString(std::getenv("PATHEXT"), PathExts, ";"); + + SmallVector<wchar_t, MAX_PATH> U16Result; + DWORD Len = MAX_PATH; + for (StringRef Ext : PathExts) { + SmallVector<wchar_t, MAX_PATH> U16Ext; + if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext)) + return EC; + + do { + U16Result.reserve(Len); + Len = ::SearchPathW(Path, c_str(U16Name), + U16Ext.empty() ? nullptr : c_str(U16Ext), + U16Result.capacity(), U16Result.data(), nullptr); + } while (Len > U16Result.capacity()); + + if (Len != 0) + break; // Found it. + } + + if (Len == 0) + return mapWindowsError(::GetLastError()); + + U16Result.set_size(Len); + + SmallVector<char, MAX_PATH> U8Result; + if (std::error_code EC = + windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result)) + return EC; + + return std::string(U8Result.begin(), U8Result.end()); } static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { @@ -166,19 +194,7 @@ static unsigned int ArgLenWithQuotes(const char *Str) { } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, - const char **envp, const StringRef **redirects, - unsigned memoryLimit, std::string *ErrMsg) { - if (!sys::fs::can_execute(Program)) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces (or are empty). - +static std::unique_ptr<char[]> flattenArgs(const char **args) { // First, determine the length of the command line. unsigned len = 0; for (unsigned i = 0; args[i]; i++) { @@ -216,6 +232,22 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } *p = 0; + return command; +} + +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg) { + if (!sys::fs::can_execute(Program)) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // Windows wants a command line, not an array of args, to pass to the new + // process. We have to concatenate them all, while quoting the args that + // have embedded spaces (or are empty). + std::unique_ptr<char[]> command = flattenArgs(args); // The pointer to the environment block for the new process. std::vector<wchar_t> EnvBlock; @@ -422,20 +454,64 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, return WaitResult; } - std::error_code sys::ChangeStdinToBinary(){ - int result = _setmode( _fileno(stdin), _O_BINARY ); +std::error_code sys::ChangeStdinToBinary() { + int result = _setmode(_fileno(stdin), _O_BINARY); if (result == -1) return std::error_code(errno, std::generic_category()); return std::error_code(); } - std::error_code sys::ChangeStdoutToBinary(){ - int result = _setmode( _fileno(stdout), _O_BINARY ); +std::error_code sys::ChangeStdoutToBinary() { + int result = _setmode(_fileno(stdout), _O_BINARY); if (result == -1) return std::error_code(errno, std::generic_category()); return std::error_code(); } +std::error_code +llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, + WindowsEncodingMethod Encoding) { + std::error_code EC; + llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text); + if (EC) + return EC; + + if (Encoding == WEM_UTF8) { + OS << Contents; + } else if (Encoding == WEM_CurrentCodePage) { + SmallVector<wchar_t, 1> ArgsUTF16; + SmallVector<char, 1> ArgsCurCP; + + if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) + return EC; + + if ((EC = windows::UTF16ToCurCP( + ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP))) + return EC; + + OS.write(ArgsCurCP.data(), ArgsCurCP.size()); + } else if (Encoding == WEM_UTF16) { + SmallVector<wchar_t, 1> ArgsUTF16; + + if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) + return EC; + + // Endianness guessing + char BOM[2]; + uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE; + memcpy(BOM, &src, 2); + OS.write(BOM, 2); + OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1); + } else { + llvm_unreachable("Unknown encoding"); + } + + if (OS.has_error()) + return std::make_error_code(std::errc::io_error); + + return EC; +} + bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { // The documented max length of the command line passed to CreateProcess. static const size_t MaxCommandStringLength = 32768; |