<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>