3131use clone:: Clone ;
3232use container:: Container ;
3333use libc;
34- use libc:: { c_char , c_void, c_int} ;
34+ use libc:: { c_void, c_int} ;
3535use option:: { Some , None , Option } ;
3636use os;
3737use ops:: Drop ;
@@ -49,6 +49,8 @@ use vec::Vec;
4949
5050#[ cfg( unix) ]
5151use c_str:: ToCStr ;
52+ #[ cfg( unix) ]
53+ use libc:: c_char;
5254#[ cfg( windows) ]
5355use 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