about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-05-13 16:01:48 -0700
committerbors <bors@rust-lang.org>2014-05-13 16:01:48 -0700
commitcb115ac2d4f57d8b590c8d46d8f9e2958ed9a527 (patch)
tree125dfe2d8e2f62ac6ce9b51e32b80b485086f2b8 /src/libstd
parent5ad42b3ae97fd363b1a13c43305995fe139fc8ef (diff)
parentb8e3f3a41715a7de7e32eb32456aa25132c8ff46 (diff)
downloadrust-cb115ac2d4f57d8b590c8d46d8f9e2958ed9a527.tar.gz
rust-cb115ac2d4f57d8b590c8d46d8f9e2958ed9a527.zip
auto merge of #14075 : Rufflewind/rust/patch-3, r=alexcrichton
- Use Unicode-aware versions of `CreateProcess` (Fixes #13815) and `Get/FreeEnvironmentStrings`.
    - Includes a helper function `os::win32::as_mut_utf16_p`, which does the same thing as `os::win32::as_utf16_p` except the pointer is mutable.
    - Fixed `make_command_line` to handle Unicode correctly.
- Tests for the above.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/os.rs46
1 files changed, 36 insertions, 10 deletions
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index f7324dc08b6..0a920a275ac 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -31,7 +31,7 @@
 use clone::Clone;
 use container::Container;
 use libc;
-use libc::{c_char, c_void, c_int};
+use libc::{c_void, c_int};
 use option::{Some, None, Option};
 use os;
 use ops::Drop;
@@ -49,6 +49,8 @@ use vec::Vec;
 
 #[cfg(unix)]
 use c_str::ToCStr;
+#[cfg(unix)]
+use libc::c_char;
 #[cfg(windows)]
 use str::OwnedStr;
 
@@ -141,10 +143,14 @@ pub mod win32 {
     }
 
     pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
+        as_mut_utf16_p(s, |t| { f(t as *u16) })
+    }
+
+    pub fn as_mut_utf16_p<T>(s: &str, f: |*mut u16| -> T) -> T {
         let mut t = s.to_utf16();
         // Null terminate before passing on.
         t.push(0u16);
-        f(t.as_ptr())
+        f(t.as_mut_ptr())
     }
 }
 
@@ -182,22 +188,42 @@ pub fn env_as_bytes() -> Vec<(~[u8],~[u8])> {
     unsafe {
         #[cfg(windows)]
         unsafe fn get_env_pairs() -> Vec<~[u8]> {
-            use c_str;
+            use slice::raw;
 
             use libc::funcs::extra::kernel32::{
-                GetEnvironmentStringsA,
-                FreeEnvironmentStringsA
+                GetEnvironmentStringsW,
+                FreeEnvironmentStringsW
             };
-            let ch = GetEnvironmentStringsA();
+            let ch = GetEnvironmentStringsW();
             if ch as uint == 0 {
                 fail!("os::env() failure getting env string from OS: {}",
                        os::last_os_error());
             }
+            // Here, we lossily decode the string as UTF16.
+            //
+            // The docs suggest that the result should be in Unicode, but
+            // Windows doesn't guarantee it's actually UTF16 -- it doesn't
+            // validate the environment string passed to CreateProcess nor
+            // SetEnvironmentVariable.  Yet, it's unlikely that returning a
+            // raw u16 buffer would be of practical use since the result would
+            // be inherently platform-dependent and introduce additional
+            // complexity to this code.
+            //
+            // Using the non-Unicode version of GetEnvironmentStrings is even
+            // worse since the result is in an OEM code page.  Characters that
+            // can't be encoded in the code page would be turned into question
+            // marks.
             let mut result = Vec::new();
-            c_str::from_c_multistring(ch as *c_char, None, |cstr| {
-                result.push(cstr.as_bytes_no_nul().to_owned());
-            });
-            FreeEnvironmentStringsA(ch);
+            let mut i = 0;
+            while *ch.offset(i) != 0 {
+                let p = &*ch.offset(i);
+                let len = ptr::position(p, |c| *c == 0);
+                raw::buf_as_slice(p, len, |s| {
+                    result.push(str::from_utf16_lossy(s).into_bytes());
+                });
+                i += len as int + 1;
+            }
+            FreeEnvironmentStringsW(ch);
             result
         }
         #[cfg(unix)]