<p dir="ltr"><br>
在 2013年9月11日 上午3:51,"Rui Ueyama" <<a href="mailto:ruiu@google.com">ruiu@google.com</a>>写道:<br>
><br>
> Author: ruiu<br>
> Date: Tue Sep 10 14:45:51 2013<br>
> New Revision: 190423<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=190423&view=rev">http://llvm.org/viewvc/llvm-project?rev=190423&view=rev</a><br>
> Log:<br>
> Add getenv() wrapper that works on multibyte environment variable.<br>
><br>
> On Windows, character encoding of multibyte environment variable varies<br>
> depending on settings. The only reliable way to handle it I think is to use<br>
> GetEnvironmentVariableW().<br>
><br>
> GetEnvironmentVariableW() works on wchar_t string, which is on Windows UTF16<br>
> string. That's not ideal because we use UTF-8 as the internal encoding in LLVM.<br>
> This patch defines a wrapper function which takes and returns UTF-8 string for<br>
> GetEnvironmentVariableW().<br>
><br>
> The wrapper function does not do any conversion and just forwards the argument<br>
> to getenv() on Unix.<br>
><br>
> Differential Revision: <a href="http://llvm-reviews.chandlerc.com/D1612">http://llvm-reviews.chandlerc.com/D1612</a><br>
><br>
> Modified:<br>
> llvm/trunk/include/llvm/Support/Process.h<br>
> llvm/trunk/lib/Support/Unix/Process.inc<br>
> llvm/trunk/lib/Support/Windows/Path.inc<br>
> llvm/trunk/lib/Support/Windows/Process.inc<br>
> llvm/trunk/lib/Support/Windows/Windows.h<br>
> llvm/trunk/unittests/Support/ProcessTest.cpp<br>
><br>
> Modified: llvm/trunk/include/llvm/Support/Process.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Process.h?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Process.h?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/include/llvm/Support/Process.h (original)<br>
> +++ llvm/trunk/include/llvm/Support/Process.h Tue Sep 10 14:45:51 2013<br>
> @@ -25,11 +25,14 @@<br>
> #ifndef LLVM_SUPPORT_PROCESS_H<br>
> #define LLVM_SUPPORT_PROCESS_H<br>
><br>
> +#include "llvm/ADT/Optional.h"<br>
> #include "llvm/Config/llvm-config.h"<br>
> #include "llvm/Support/DataTypes.h"<br>
> #include "llvm/Support/TimeValue.h"<br>
><br>
> namespace llvm {<br>
> +class StringRef;<br>
> +<br>
> namespace sys {<br>
><br>
> class self_process;<br>
> @@ -161,6 +164,10 @@ public:<br>
> /// @brief Prevent core file generation.<br>
> static void PreventCoreFiles();<br>
><br>
> + // This function returns the environment variable \arg name's value as a UTF-8<br>
> + // string. \arg Name is assumed to be in UTF-8 encoding too.<br>
> + static Optional<std::string> GetEnv(StringRef name);<br>
> +<br>
> /// This function determines if the standard input is connected directly<br>
> /// to a user's input (keyboard probably), rather than coming from a file<br>
> /// or pipe.<br>
><br>
> Modified: llvm/trunk/lib/Support/Unix/Process.inc<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Process.inc?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Process.inc?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/Support/Unix/Process.inc (original)<br>
> +++ llvm/trunk/lib/Support/Unix/Process.inc Tue Sep 10 14:45:51 2013<br>
> @@ -13,6 +13,7 @@<br>
><br>
> #include "Unix.h"<br>
> #include "llvm/ADT/Hashing.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> #include "llvm/Support/Mutex.h"<br>
> #include "llvm/Support/MutexGuard.h"<br>
> #include "llvm/Support/TimeValue.h"<br>
> @@ -181,6 +182,14 @@ void Process::PreventCoreFiles() {<br>
> #endif<br>
> }<br>
><br>
> +Optional<std::string> Process::GetEnv(StringRef Name) {<br>
> + std::string NameStr = Name.str();<br>
> + const char *Val = ::getenv(NameStr.c_str());<br>
> + if (!Val)<br>
> + return None;<br>
> + return std::string(Val);<br>
> +}<br>
> +<br>
> bool Process::StandardInIsUserInput() {<br>
> return FileDescriptorIsDisplayed(STDIN_FILENO);<br>
> }<br>
><br>
> Modified: llvm/trunk/lib/Support/Windows/Path.inc<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/Support/Windows/Path.inc (original)<br>
> +++ llvm/trunk/lib/Support/Windows/Path.inc Tue Sep 10 14:45:51 2013<br>
> @@ -37,6 +37,9 @@ typedef int errno_t;<br>
><br>
> using namespace llvm;<br>
><br>
> +using llvm::sys::windows::UTF8ToUTF16;<br>
> +using llvm::sys::windows::UTF16ToUTF8;<br>
> +<br>
> namespace {<br>
> typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(<br>
> /*__in*/ LPCWSTR lpSymlinkFileName,<br>
> @@ -47,61 +50,6 @@ namespace {<br>
> ::GetProcAddress(::GetModuleHandleA("kernel32.dll"),<br>
> "CreateSymbolicLinkW"));<br>
><br>
> - error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) {<br>
> - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,<br>
> - utf8.begin(), utf8.size(),<br>
> - utf16.begin(), 0);<br>
> -<br>
> - if (len == 0)<br>
> - return windows_error(::GetLastError());<br>
> -<br>
> - utf16.reserve(len + 1);<br>
> - utf16.set_size(len);<br>
> -<br>
> - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,<br>
> - utf8.begin(), utf8.size(),<br>
> - utf16.begin(), utf16.size());<br>
> -<br>
> - if (len == 0)<br>
> - return windows_error(::GetLastError());<br>
> -<br>
> - // Make utf16 null terminated.<br>
> - utf16.push_back(0);<br>
> - utf16.pop_back();<br>
> -<br>
> - return error_code::success();<br>
> - }<br>
> -<br>
> - error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,<br>
> - SmallVectorImpl<char> &utf8) {<br>
> - // Get length.<br>
> - int len = ::WideCharToMultiByte(CP_UTF8, 0,<br>
> - utf16, utf16_len,<br>
> - utf8.begin(), 0,<br>
> - NULL, NULL);<br>
> -<br>
> - if (len == 0)<br>
> - return windows_error(::GetLastError());<br>
> -<br>
> - utf8.reserve(len);<br>
> - utf8.set_size(len);<br>
> -<br>
> - // Now do the actual conversion.<br>
> - len = ::WideCharToMultiByte(CP_UTF8, 0,<br>
> - utf16, utf16_len,<br>
> - utf8.data(), utf8.size(),<br>
> - NULL, NULL);<br>
> -<br>
> - if (len == 0)<br>
> - return windows_error(::GetLastError());<br>
> -<br>
> - // Make utf8 null terminated.<br>
> - utf8.push_back(0);<br>
> - utf8.pop_back();<br>
> -<br>
> - return error_code::success();<br>
> - }<br>
> -<br>
> error_code TempDir(SmallVectorImpl<wchar_t> &result) {<br>
> retry_temp_dir:<br>
> DWORD len = ::GetTempPathW(result.capacity(), result.begin());<br>
> @@ -1092,7 +1040,64 @@ error_code openFileForWrite(const Twine<br>
> ResultFD = FD;<br>
> return error_code::success();<br>
> }<br>
> -<br>
> } // end namespace fs<br>
> +<br>
> +namespace windows {<br>
> +llvm::error_code UTF8ToUTF16(llvm::StringRef utf8,<br>
> + llvm::SmallVectorImpl<wchar_t> &utf16) {<br>
> + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,<br>
> + utf8.begin(), utf8.size(),<br>
> + utf16.begin(), 0);<br>
> +<br>
> + if (len == 0)<br>
> + return llvm::windows_error(::GetLastError());<br>
> +<br>
> + utf16.reserve(len + 1);<br>
> + utf16.set_size(len);<br>
> +<br>
> + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,<br>
> + utf8.begin(), utf8.size(),<br>
> + utf16.begin(), utf16.size());<br>
> +<br>
> + if (len == 0)<br>
> + return llvm::windows_error(::GetLastError());<br>
> +<br>
> + // Make utf16 null terminated.<br>
> + utf16.push_back(0);<br>
> + utf16.pop_back();<br>
> +<br>
> + return llvm::error_code::success();<br>
> +}<br>
> +<br>
> +llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,<br>
> + llvm::SmallVectorImpl<char> &utf8) {<br>
> + // Get length.<br>
> + int len = ::WideCharToMultiByte(CP_UTF8, 0,<br>
> + utf16, utf16_len,<br>
> + utf8.begin(), 0,<br>
> + NULL, NULL);<br>
> +<br>
> + if (len == 0)<br>
> + return llvm::windows_error(::GetLastError());<br>
> +<br>
> + utf8.reserve(len);<br>
> + utf8.set_size(len);<br>
> +<br>
> + // Now do the actual conversion.<br>
> + len = ::WideCharToMultiByte(CP_UTF8, 0,<br>
> + utf16, utf16_len,<br>
> + utf8.data(), utf8.size(),<br>
> + NULL, NULL);<br>
> +<br>
> + if (len == 0)<br>
> + return llvm::windows_error(::GetLastError());<br>
> +<br>
> + // Make utf8 null terminated.<br>
> + utf8.push_back(0);<br>
> + utf8.pop_back();<br>
> +<br>
> + return llvm::error_code::success();<br>
> +}<br>
> +} // end namespace windows<br>
> } // end namespace sys<br>
> } // end namespace llvm<br>
><br>
> Modified: llvm/trunk/lib/Support/Windows/Process.inc<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Process.inc?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Process.inc?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/Support/Windows/Process.inc (original)<br>
> +++ llvm/trunk/lib/Support/Windows/Process.inc Tue Sep 10 14:45:51 2013<br>
> @@ -140,6 +140,36 @@ void Process::PreventCoreFiles() {<br>
> SEM_NOOPENFILEERRORBOX);<br>
> }<br>
><br>
> +/// Returns the environment variable \arg Name's value as a string encoded in<br>
> +/// UTF-8. \arg Name is assumed to be in UTF-8 encoding.<br>
> +Optional<std::string> Process::GetEnv(StringRef Name) {<br>
> + // Convert the argument to UTF-16 to pass it to _wgetenv().<br>
comment shiukd be GetEnvironmentVariableW</p>
<p dir="ltr">> + SmallVector<wchar_t, 128> NameUTF16;<br>
> + if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16))<br>
> + return None;<br>
> +<br>
> + // Environment variable can be encoded in non-UTF8 encoding, and there's no<br>
> + // way to know what the encoding is. The only reliable way to look up<br>
> + // multibyte environment variable is to use GetEnvironmentVariableW().<br>
> + std::vector<wchar_t> Buf(16);<br>
> + size_t Size = 0;<br>
> + for (;;) {<br>
> + Size = GetEnvironmentVariableW(&NameUTF16[0], &Buf[0], Buf.size());<br>
> + if (Size < Buf.size())<br>
> + break;<br>
> + // Try again with larger buffer.<br>
> + Buf.resize(Size + 1);<br>
> + }<br>
> + if (Size == 0)<br>
> + return None;<br>
> +<br>
> + // Convert the result from UTF-16 to UTF-8.<br>
> + SmallVector<char, 128> Res;<br>
> + if (error_code ec = windows::UTF16ToUTF8(&Buf[0], Size, Res))<br>
> + return None;<br>
> + return std::string(&Res[0]);<br>
> +}<br>
> +<br>
> bool Process::StandardInIsUserInput() {<br>
> return FileDescriptorIsDisplayed(0);<br>
> }<br>
><br>
> Modified: llvm/trunk/lib/Support/Windows/Windows.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Windows.h?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Windows.h?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/Support/Windows/Windows.h (original)<br>
> +++ llvm/trunk/lib/Support/Windows/Windows.h Tue Sep 10 14:45:51 2013<br>
> @@ -24,13 +24,17 @@<br>
> #define _WIN32_IE 0x0600 // MinGW at it again.<br>
> #define WIN32_LEAN_AND_MEAN<br>
><br>
> +#include "llvm/ADT/SmallVector.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> #include "llvm/Config/config.h" // Get build system configuration settings<br>
> #include "llvm/Support/Compiler.h"<br>
> +#include "llvm/Support/system_error.h"<br>
> #include <windows.h><br>
> #include <wincrypt.h><br>
> #include <shlobj.h><br>
> #include <cassert><br>
> #include <string><br>
> +#include <vector><br>
><br>
> inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) {<br>
> if (!ErrMsg)<br>
> @@ -148,4 +152,13 @@ c_str(SmallVectorImpl<T> &str) {<br>
> str.pop_back();<br>
> return str.data();<br>
> }<br>
> +<br>
> +namespace sys {<br>
> +namespace windows {<br>
> +error_code UTF8ToUTF16(StringRef utf8,<br>
> + SmallVectorImpl<wchar_t> &utf16);<br>
> +error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,<br>
> + SmallVectorImpl<char> &utf8);<br>
> +} // end namespace windows<br>
> +} // end namespace sys<br>
> } // end namespace llvm.<br>
><br>
> Modified: llvm/trunk/unittests/Support/ProcessTest.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProcessTest.cpp?rev=190423&r1=190422&r2=190423&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProcessTest.cpp?rev=190423&r1=190422&r2=190423&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/unittests/Support/ProcessTest.cpp (original)<br>
> +++ llvm/trunk/unittests/Support/ProcessTest.cpp Tue Sep 10 14:45:51 2013<br>
> @@ -39,4 +39,32 @@ TEST(ProcessTest, SelfProcess) {<br>
> EXPECT_GT(TimeValue::MaxTime, process::get_self()->get_wall_time());<br>
> }<br>
><br>
> +#ifdef LLVM_ON_WIN32<br>
> +#define setenv(name, var, ignore) _putenv_s(name, var)<br>
> +#endif<br>
> +<br>
> +#if HAVE_SETENV || defined(LLVM_ON_WIN32)<br>
> +TEST(ProcessTest, Basic) {<br>
> + setenv("__LLVM_TEST_ENVIRON_VAR__", "abc", true);<br>
> + Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));<br>
> + EXPECT_TRUE(val.hasValue());<br>
> + EXPECT_STREQ("abc", val->c_str());<br>
> +}<br>
> +<br>
> +TEST(ProcessTest, None) {<br>
> + Optional<std::string> val(<br>
> + Process::GetEnv("__LLVM_TEST_ENVIRON_NO_SUCH_VAR__"));<br>
> + EXPECT_FALSE(val.hasValue());<br>
> +}<br>
> +#endif<br>
> +<br>
> +#ifdef LLVM_ON_WIN32<br>
> +TEST(ProcessTest, Wchar) {<br>
> + SetEnvironmentVariableW(L"__LLVM_TEST_ENVIRON_VAR__", L"abcdefghijklmnopqrs");<br>
> + Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));<br>
> + EXPECT_TRUE(val.hasValue());<br>
> + EXPECT_STREQ("abcdefghijklmnopqrs", val->c_str());<br>
> +}<br>
> +#endif<br>
> +<br>
> } // end anonymous namespace<br>
><br>
><br>
> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</p>