about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJeff Olson <olson.jeffery@gmail.com>2013-02-14 22:16:53 -0800
committerBrian Anderson <banderson@mozilla.com>2013-03-11 15:38:55 -0700
commit53db6c7e2a11764a806e87c7268d31288fa9171d (patch)
treec835cfe8a43f81b6701704a8e6ad95ab2d4ae8d7 /src
parent4bc26ce575b4bc6f7254a2cfe9fee0a08de90b49 (diff)
downloadrust-53db6c7e2a11764a806e87c7268d31288fa9171d.tar.gz
rust-53db6c7e2a11764a806e87c7268d31288fa9171d.zip
core: rt/core: impl os::env() in rust ref #4812
Diffstat (limited to 'src')
-rw-r--r--src/libcore/libc.rs5
-rw-r--r--src/libcore/os.rs64
-rw-r--r--src/libcore/ptr.rs132
-rw-r--r--src/rt/rust_builtin.cpp35
4 files changed, 196 insertions, 40 deletions
diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs
index b59824969bb..9a45ffc5b2e 100644
--- a/src/libcore/libc.rs
+++ b/src/libcore/libc.rs
@@ -534,6 +534,7 @@ pub mod types {
 
                 pub type LPCWSTR = *WCHAR;
                 pub type LPCSTR = *CHAR;
+                pub type LPTCH = *CHAR;
 
                 pub type LPWSTR = *mut WCHAR;
                 pub type LPSTR = *mut CHAR;
@@ -1594,7 +1595,7 @@ pub mod funcs {
 
         pub mod kernel32 {
             use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
-            use libc::types::os::arch::extra::{LPCWSTR, LPWSTR};
+            use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
             use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
 
             #[abi = "stdcall"]
@@ -1605,6 +1606,8 @@ pub mod funcs {
                                                -> DWORD;
                 unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
                                                -> BOOL;
+                unsafe fn GetEnvironmentStringsA() -> LPTCH;
+                unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
 
                 unsafe fn GetModuleFileNameW(hModule: HMODULE,
                                              lpFilename: LPWSTR,
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 43e20a1a83f..a1793cc5efa 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -171,20 +171,68 @@ fn with_env_lock<T>(f: &fn() -> T) -> T {
 }
 
 pub fn env() -> ~[(~str,~str)] {
-    extern {
-        unsafe fn rust_env_pairs() -> ~[~str];
-    }
-
     unsafe {
-        do with_env_lock {
+        #[cfg(windows)]
+        unsafe fn get_env_pairs() -> ~[~str] {
+            use libc::types::os::arch::extra::LPTCH;
+            use libc::funcs::extra::kernel32::{
+                GetEnvironmentStringsA,
+                FreeEnvironmentStringsA
+            };
+            let ch = GetEnvironmentStringsA();
+            if (ch as uint == 0) {
+                fail!(fmt!("os::env() failure getting env string from OS: %s",
+                           os::last_os_error()));
+            }
+            let mut curr_ptr: uint = ch as uint;
+            let mut result = ~[];
+            while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
+                let env_pair = str::raw::from_c_str(
+                    curr_ptr as *libc::c_char);
+                result.push(env_pair);
+                curr_ptr +=
+                    libc::strlen(curr_ptr as *libc::c_char) as uint
+                    + 1;
+            }
+            FreeEnvironmentStringsA(ch);
+            result
+        }
+        #[cfg(unix)]
+        unsafe fn get_env_pairs() -> ~[~str] {
+            extern mod rustrt {
+                unsafe fn rust_env_pairs() -> **libc::c_char;
+            }
+            let environ = rustrt::rust_env_pairs();
+            if (environ as uint == 0) {
+                fail!(fmt!("os::env() failure getting env string from OS: %s",
+                           os::last_os_error()));
+            }
+            let mut result = ~[];
+            ptr::array_each(environ, |e| {
+                let env_pair = str::raw::from_c_str(e);
+                log(debug, fmt!("get_env_pairs: %s",
+                                env_pair));
+                result.push(env_pair);
+            });
+            result
+        }
+
+        fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
             let mut pairs = ~[];
-            for vec::each(rust_env_pairs()) |p| {
-                let vs = str::splitn_char(*p, '=', 1u);
-                fail_unless!(vec::len(vs) == 2u);
+            for input.each |p| {
+                let vs = str::splitn_char(*p, '=', 1);
+                log(debug,
+                    fmt!("splitting: len: %u",
+                    vs.len()));
+                assert vs.len() == 2;
                 pairs.push((copy vs[0], copy vs[1]));
             }
             pairs
         }
+        do with_env_lock {
+            let unparsed_environ = get_env_pairs();
+            env_convert(unparsed_environ)
+        }
     }
 }
 
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index b66c1c4696f..042720e1b4e 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -18,6 +18,8 @@ use sys;
 
 #[cfg(test)] use vec;
 #[cfg(test)] use str;
+#[cfg(test)] use uint;
+#[cfg(test)] use debug;
 #[cfg(notest)] use cmp::{Eq, Ord};
 
 pub mod libc_ {
@@ -181,6 +183,46 @@ pub pure fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
     to_uint(thing) == to_uint(other)
 }
 
+/**
+  Given a **T (pointer to an array of pointers),
+  iterate through each *T, up to the provided `len`,
+  passing to the provided callback function
+
+  SAFETY NOTE: Pointer-arithmetic. Dragons be here.
+*/
+pub unsafe fn array_each_with_len<T>(arr: **T, len: uint, cb: fn(*T)) {
+    log(debug, "array_each_with_len: before iterate");
+    if (arr as uint == 0) {
+        fail!(~"ptr::array_each_with_len failure: arr input is null pointer");
+    }
+    //let start_ptr = *arr;
+    uint::iterate(0, len, |e| {
+        let n = offset(arr, e);
+        cb(*n);
+        true
+    });
+    log(debug, "array_each_with_len: after iterate");
+}
+
+/**
+  Given a null-pointer-terminated **T (pointer to
+  an array of pointers), iterate through each *T,
+  passing to the provided callback function
+
+  SAFETY NOTE: This will only work with a null-terminated
+  pointer array. Barely less-dodgey Pointer Arithmetic.
+  Dragons be here.
+*/
+pub unsafe fn array_each<T>(arr: **T, cb: fn(*T)) {
+    if (arr as uint == 0) {
+        fail!(~"ptr::array_each_with_len failure: arr input is null pointer");
+    }
+    let len = buf_len(arr);
+    log(debug, fmt!("array_each inferred len: %u",
+                    len));
+    array_each_with_len(arr, len, cb);
+}
+
 pub trait Ptr<T> {
     pure fn is_null(&self) -> bool;
     pure fn is_not_null(&self) -> bool;
@@ -389,3 +431,93 @@ pub fn test_is_null() {
    fail_unless!(!mq.is_null());
    fail_unless!(mq.is_not_null());
 }
+
+#[cfg(test)]
+pub mod ptr_tests {
+    use debug;
+    use ptr;
+    use str;
+    use libc;
+    use vec;
+    #[test]
+    pub fn test_ptr_array_each_with_len() {
+        unsafe {
+            let one = ~"oneOne";
+            let two = ~"twoTwo";
+            let three = ~"threeThree";
+            let arr: ~[*i8] = ~[
+                ::cast::transmute(&one[0]),
+                ::cast::transmute(&two[0]),
+                ::cast::transmute(&three[0]),
+            ];
+            let expected_arr = [
+                one, two, three
+            ];
+            let arr_ptr = &arr[0];
+            let mut ctr = 0;
+            let mut iteration_count = 0;
+            ptr::array_each_with_len(arr_ptr, vec::len(arr),
+                |e| {
+                let actual = str::raw::from_c_str(e);
+                let expected = copy expected_arr[ctr];
+                log(debug,
+                    fmt!("test_ptr_array_each e: %s, a: %s",
+                         expected, actual));
+                assert actual == expected;
+                ctr += 1;
+                iteration_count += 1;
+            });
+            assert iteration_count == 3u;
+        }
+    }
+    #[test]
+    pub fn test_ptr_array_each() {
+        unsafe {
+            let one = ~"oneOne";
+            let two = ~"twoTwo";
+            let three = ~"threeThree";
+            let arr: ~[*i8] = ~[
+                ::cast::transmute(&one[0]),
+                ::cast::transmute(&two[0]),
+                ::cast::transmute(&three[0]),
+                // fake a null terminator
+                0 as *i8
+            ];
+            let expected_arr = [
+                one, two, three
+            ];
+            let arr_ptr = &arr[0];
+            let mut ctr = 0;
+            let mut iteration_count = 0;
+            ptr::array_each(arr_ptr, |e| {
+                let actual = str::raw::from_c_str(e);
+                let expected = copy expected_arr[ctr];
+                log(debug,
+                    fmt!("test_ptr_array_each e: %s, a: %s",
+                         expected, actual));
+                assert actual == expected;
+                ctr += 1;
+                iteration_count += 1;
+            });
+            assert iteration_count == 3;
+        }
+    }
+    #[test]
+    #[should_fail]
+    pub fn test_ptr_array_each_with_len_null_ptr() {
+        unsafe {
+            ptr::array_each_with_len(0 as **libc::c_char, 1, |e| {
+                str::raw::from_c_str(e);
+            });
+        }
+    }
+    #[test]
+    #[should_fail]
+    pub fn test_ptr_array_each_null_ptr() {
+        unsafe {
+            ptr::array_each(0 as **libc::c_char, |e| {
+                str::raw::from_c_str(e);
+            });
+        }
+    }
+}
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 750962b37e8..2c9c4a70681 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -53,44 +53,17 @@ timegm(struct tm *tm)
 #endif
 
 #if defined(__WIN32__)
-extern "C" CDECL rust_vec_box *
+extern "C" CDECL char**
 rust_env_pairs() {
-    rust_task *task = rust_get_current_task();
-    size_t envc = 0;
-    LPTCH ch = GetEnvironmentStringsA();
-    LPTCH c;
-    for (c = ch; *c; c += strlen(c) + 1) {
-        ++envc;
-    }
-    c = ch;
-    rust_vec_box *v = (rust_vec_box *)
-        task->kernel->malloc(vec_size<rust_vec_box*>(envc),
-                       "str vec interior");
-    v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc;
-    for (size_t i = 0; i < envc; ++i) {
-        size_t n = strlen(c);
-        rust_str *str = make_str(task->kernel, c, n, "str");
-        ((rust_str**)&v->body.data)[i] = str;
-        c += n + 1;
-    }
-    if (ch) {
-        FreeEnvironmentStrings(ch);
-    }
-    return v;
+    return 0;
 }
 #else
-extern "C" CDECL rust_vec_box *
+extern "C" CDECL char**
 rust_env_pairs() {
-    rust_task *task = rust_get_current_task();
 #ifdef __APPLE__
     char **environ = *_NSGetEnviron();
 #endif
-    char **e = environ;
-    size_t envc = 0;
-    while (*e) {
-        ++envc; ++e;
-    }
-    return make_str_vec(task->kernel, envc, environ);
+    return environ;
 }
 #endif