Skip to content

Commit d9eca56

Browse files
committed
Use Get/FreeEnvironmentStringsW instead of Get/FreeEnvironmentStringsA
Changed libstd to use Get/FreeEnvironmentStringsW instead of Get/FreeEnvironmentStringsA to support Unicode environment variables.
1 parent b6cce7e commit d9eca56

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

src/liblibc/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4195,7 +4195,7 @@ pub mod funcs {
41954195
use types::os::arch::c95::{c_uint};
41964196
use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE,
41974197
LPCWSTR, LPWSTR,
4198-
LPCH, LPDWORD, LPVOID,
4198+
LPWCH, LPDWORD, LPVOID,
41994199
LPCVOID, LPOVERLAPPED,
42004200
LPSECURITY_ATTRIBUTES,
42014201
LPSTARTUPINFO,
@@ -4212,8 +4212,8 @@ pub mod funcs {
42124212
-> DWORD;
42134213
pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
42144214
-> BOOL;
4215-
pub fn GetEnvironmentStringsA() -> LPCH;
4216-
pub fn FreeEnvironmentStringsA(env_ptr: LPCH) -> BOOL;
4215+
pub fn GetEnvironmentStringsW() -> LPWCH;
4216+
pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL;
42174217
pub fn GetModuleFileNameW(hModule: HMODULE,
42184218
lpFilename: LPWSTR,
42194219
nSize: DWORD)

src/libstd/os.rs

+31-9
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
use clone::Clone;
3232
use container::Container;
3333
use libc;
34-
use libc::{c_char, c_void, c_int};
34+
use libc::{c_void, c_int};
3535
use option::{Some, None, Option};
3636
use os;
3737
use ops::Drop;
@@ -49,6 +49,8 @@ use vec::Vec;
4949

5050
#[cfg(unix)]
5151
use c_str::ToCStr;
52+
#[cfg(unix)]
53+
use libc::c_char;
5254
#[cfg(windows)]
5355
use str::OwnedStr;
5456

@@ -186,22 +188,42 @@ pub fn env_as_bytes() -> Vec<(~[u8],~[u8])> {
186188
unsafe {
187189
#[cfg(windows)]
188190
unsafe fn get_env_pairs() -> Vec<~[u8]> {
189-
use c_str;
191+
use slice::raw;
190192

191193
use libc::funcs::extra::kernel32::{
192-
GetEnvironmentStringsA,
193-
FreeEnvironmentStringsA
194+
GetEnvironmentStringsW,
195+
FreeEnvironmentStringsW
194196
};
195-
let ch = GetEnvironmentStringsA();
197+
let ch = GetEnvironmentStringsW();
196198
if ch as uint == 0 {
197199
fail!("os::env() failure getting env string from OS: {}",
198200
os::last_os_error());
199201
}
202+
// Here, we lossily decode the string as UTF16.
203+
//
204+
// The docs suggest that the result should be in Unicode, but
205+
// Windows doesn't guarantee it's actually UTF16 -- it doesn't
206+
// validate the environment string passed to CreateProcess nor
207+
// SetEnvironmentVariable. Yet, it's unlikely that returning a
208+
// raw u16 buffer would be of practical use since the result would
209+
// be inherently platform-dependent and introduce additional
210+
// complexity to this code.
211+
//
212+
// Using the non-Unicode version of GetEnvironmentStrings is even
213+
// worse since the result is in an OEM code page. Characters that
214+
// can't be encoded in the code page would be turned into question
215+
// marks.
200216
let mut result = Vec::new();
201-
c_str::from_c_multistring(ch as *c_char, None, |cstr| {
202-
result.push(cstr.as_bytes_no_nul().to_owned());
203-
});
204-
FreeEnvironmentStringsA(ch);
217+
let mut i = 0;
218+
while *ch.offset(i) != 0 {
219+
let p = &*ch.offset(i);
220+
let len = ptr::position(p, |c| *c == 0);
221+
raw::buf_as_slice(p, len, |s| {
222+
result.push(str::from_utf16_lossy(s).into_bytes());
223+
});
224+
i += len as int + 1;
225+
}
226+
FreeEnvironmentStringsW(ch);
205227
result
206228
}
207229
#[cfg(unix)]

0 commit comments

Comments
 (0)