llvm.org GIT mirror llvm / f42d424
Add getenv() wrapper that works on multibyte environment variable. On Windows, character encoding of multibyte environment variable varies depending on settings. The only reliable way to handle it I think is to use GetEnvironmentVariableW(). GetEnvironmentVariableW() works on wchar_t string, which is on Windows UTF16 string. That's not ideal because we use UTF-8 as the internal encoding in LLVM. This patch defines a wrapper function which takes and returns UTF-8 string for GetEnvironmentVariableW(). The wrapper function does not do any conversion and just forwards the argument to getenv() on Unix. Differential Revision: http://llvm-reviews.chandlerc.com/D1612 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190423 91177308-0d34-0410-b5e6-96231b3b80d8 Rui Ueyama 6 years ago
6 changed file(s) with 148 addition(s) and 56 deletion(s). Raw diff Collapse all Expand all
2424 #ifndef LLVM_SUPPORT_PROCESS_H
2525 #define LLVM_SUPPORT_PROCESS_H
2626
27 #include "llvm/ADT/Optional.h"
2728 #include "llvm/Config/llvm-config.h"
2829 #include "llvm/Support/DataTypes.h"
2930 #include "llvm/Support/TimeValue.h"
3031
3132 namespace llvm {
33 class StringRef;
34
3235 namespace sys {
3336
3437 class self_process;
160163 /// @brief Prevent core file generation.
161164 static void PreventCoreFiles();
162165
166 // This function returns the environment variable \arg name's value as a UTF-8
167 // string. \arg Name is assumed to be in UTF-8 encoding too.
168 static Optional GetEnv(StringRef name);
169
163170 /// This function determines if the standard input is connected directly
164171 /// to a user's input (keyboard probably), rather than coming from a file
165172 /// or pipe.
1212
1313 #include "Unix.h"
1414 #include "llvm/ADT/Hashing.h"
15 #include "llvm/ADT/StringRef.h"
1516 #include "llvm/Support/Mutex.h"
1617 #include "llvm/Support/MutexGuard.h"
1718 #include "llvm/Support/TimeValue.h"
180181 #endif
181182 }
182183
184 Optional Process::GetEnv(StringRef Name) {
185 std::string NameStr = Name.str();
186 const char *Val = ::getenv(NameStr.c_str());
187 if (!Val)
188 return None;
189 return std::string(Val);
190 }
191
183192 bool Process::StandardInIsUserInput() {
184193 return FileDescriptorIsDisplayed(STDIN_FILENO);
185194 }
3636
3737 using namespace llvm;
3838
39 using llvm::sys::windows::UTF8ToUTF16;
40 using llvm::sys::windows::UTF16ToUTF8;
41
3942 namespace {
4043 typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
4144 /*__in*/ LPCWSTR lpSymlinkFileName,
4548 PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
4649 ::GetProcAddress(::GetModuleHandleA("kernel32.dll"),
4750 "CreateSymbolicLinkW"));
48
49 error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl &utf16) {
50 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
51 utf8.begin(), utf8.size(),
52 utf16.begin(), 0);
53
54 if (len == 0)
55 return windows_error(::GetLastError());
56
57 utf16.reserve(len + 1);
58 utf16.set_size(len);
59
60 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
61 utf8.begin(), utf8.size(),
62 utf16.begin(), utf16.size());
63
64 if (len == 0)
65 return windows_error(::GetLastError());
66
67 // Make utf16 null terminated.
68 utf16.push_back(0);
69 utf16.pop_back();
70
71 return error_code::success();
72 }
73
74 error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
75 SmallVectorImpl &utf8) {
76 // Get length.
77 int len = ::WideCharToMultiByte(CP_UTF8, 0,
78 utf16, utf16_len,
79 utf8.begin(), 0,
80 NULL, NULL);
81
82 if (len == 0)
83 return windows_error(::GetLastError());
84
85 utf8.reserve(len);
86 utf8.set_size(len);
87
88 // Now do the actual conversion.
89 len = ::WideCharToMultiByte(CP_UTF8, 0,
90 utf16, utf16_len,
91 utf8.data(), utf8.size(),
92 NULL, NULL);
93
94 if (len == 0)
95 return windows_error(::GetLastError());
96
97 // Make utf8 null terminated.
98 utf8.push_back(0);
99 utf8.pop_back();
100
101 return error_code::success();
102 }
10351
10452 error_code TempDir(SmallVectorImpl &result) {
10553 retry_temp_dir:
10911039 ResultFD = FD;
10921040 return error_code::success();
10931041 }
1094
10951042 } // end namespace fs
1043
1044 namespace windows {
1045 llvm::error_code UTF8ToUTF16(llvm::StringRef utf8,
1046 llvm::SmallVectorImpl &utf16) {
1047 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
1048 utf8.begin(), utf8.size(),
1049 utf16.begin(), 0);
1050
1051 if (len == 0)
1052 return llvm::windows_error(::GetLastError());
1053
1054 utf16.reserve(len + 1);
1055 utf16.set_size(len);
1056
1057 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
1058 utf8.begin(), utf8.size(),
1059 utf16.begin(), utf16.size());
1060
1061 if (len == 0)
1062 return llvm::windows_error(::GetLastError());
1063
1064 // Make utf16 null terminated.
1065 utf16.push_back(0);
1066 utf16.pop_back();
1067
1068 return llvm::error_code::success();
1069 }
1070
1071 llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
1072 llvm::SmallVectorImpl &utf8) {
1073 // Get length.
1074 int len = ::WideCharToMultiByte(CP_UTF8, 0,
1075 utf16, utf16_len,
1076 utf8.begin(), 0,
1077 NULL, NULL);
1078
1079 if (len == 0)
1080 return llvm::windows_error(::GetLastError());
1081
1082 utf8.reserve(len);
1083 utf8.set_size(len);
1084
1085 // Now do the actual conversion.
1086 len = ::WideCharToMultiByte(CP_UTF8, 0,
1087 utf16, utf16_len,
1088 utf8.data(), utf8.size(),
1089 NULL, NULL);
1090
1091 if (len == 0)
1092 return llvm::windows_error(::GetLastError());
1093
1094 // Make utf8 null terminated.
1095 utf8.push_back(0);
1096 utf8.pop_back();
1097
1098 return llvm::error_code::success();
1099 }
1100 } // end namespace windows
10961101 } // end namespace sys
10971102 } // end namespace llvm
139139 SEM_NOOPENFILEERRORBOX);
140140 }
141141
142 /// Returns the environment variable \arg Name's value as a string encoded in
143 /// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
144 Optional Process::GetEnv(StringRef Name) {
145 // Convert the argument to UTF-16 to pass it to _wgetenv().
146 SmallVector NameUTF16;
147 if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16))
148 return None;
149
150 // Environment variable can be encoded in non-UTF8 encoding, and there's no
151 // way to know what the encoding is. The only reliable way to look up
152 // multibyte environment variable is to use GetEnvironmentVariableW().
153 std::vector Buf(16);
154 size_t Size = 0;
155 for (;;) {
156 Size = GetEnvironmentVariableW(&NameUTF16[0], &Buf[0], Buf.size());
157 if (Size < Buf.size())
158 break;
159 // Try again with larger buffer.
160 Buf.resize(Size + 1);
161 }
162 if (Size == 0)
163 return None;
164
165 // Convert the result from UTF-16 to UTF-8.
166 SmallVector Res;
167 if (error_code ec = windows::UTF16ToUTF8(&Buf[0], Size, Res))
168 return None;
169 return std::string(&Res[0]);
170 }
171
142172 bool Process::StandardInIsUserInput() {
143173 return FileDescriptorIsDisplayed(0);
144174 }
2323 #define _WIN32_IE 0x0600 // MinGW at it again.
2424 #define WIN32_LEAN_AND_MEAN
2525
26 #include "llvm/ADT/SmallVector.h"
27 #include "llvm/ADT/StringRef.h"
2628 #include "llvm/Config/config.h" // Get build system configuration settings
2729 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/system_error.h"
2831 #include
2932 #include
3033 #include
3134 #include
3235 #include
36 #include
3337
3438 inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) {
3539 if (!ErrMsg)
147151 str.pop_back();
148152 return str.data();
149153 }
154
155 namespace sys {
156 namespace windows {
157 error_code UTF8ToUTF16(StringRef utf8,
158 SmallVectorImpl &utf16);
159 error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
160 SmallVectorImpl &utf8);
161 } // end namespace windows
162 } // end namespace sys
150163 } // end namespace llvm.
3838 EXPECT_GT(TimeValue::MaxTime, process::get_self()->get_wall_time());
3939 }
4040
41 #ifdef LLVM_ON_WIN32
42 #define setenv(name, var, ignore) _putenv_s(name, var)
43 #endif
44
45 #if HAVE_SETENV || defined(LLVM_ON_WIN32)
46 TEST(ProcessTest, Basic) {
47 setenv("__LLVM_TEST_ENVIRON_VAR__", "abc", true);
48 Optional val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));
49 EXPECT_TRUE(val.hasValue());
50 EXPECT_STREQ("abc", val->c_str());
51 }
52
53 TEST(ProcessTest, None) {
54 Optional val(
55 Process::GetEnv("__LLVM_TEST_ENVIRON_NO_SUCH_VAR__"));
56 EXPECT_FALSE(val.hasValue());
57 }
58 #endif
59
60 #ifdef LLVM_ON_WIN32
61 TEST(ProcessTest, Wchar) {
62 SetEnvironmentVariableW(L"__LLVM_TEST_ENVIRON_VAR__", L"abcdefghijklmnopqrs");
63 Optional val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));
64 EXPECT_TRUE(val.hasValue());
65 EXPECT_STREQ("abcdefghijklmnopqrs", val->c_str());
66 }
67 #endif
68
4169 } // end anonymous namespace