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(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(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(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(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 { 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(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