core: rt/core: impl os::env() in rust ref #4812
This commit is contained in:
parent
4bc26ce575
commit
53db6c7e2a
4 changed files with 196 additions and 40 deletions
|
@ -534,6 +534,7 @@ pub mod types {
|
||||||
|
|
||||||
pub type LPCWSTR = *WCHAR;
|
pub type LPCWSTR = *WCHAR;
|
||||||
pub type LPCSTR = *CHAR;
|
pub type LPCSTR = *CHAR;
|
||||||
|
pub type LPTCH = *CHAR;
|
||||||
|
|
||||||
pub type LPWSTR = *mut WCHAR;
|
pub type LPWSTR = *mut WCHAR;
|
||||||
pub type LPSTR = *mut CHAR;
|
pub type LPSTR = *mut CHAR;
|
||||||
|
@ -1594,7 +1595,7 @@ pub mod funcs {
|
||||||
|
|
||||||
pub mod kernel32 {
|
pub mod kernel32 {
|
||||||
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
|
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};
|
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
|
||||||
|
|
||||||
#[abi = "stdcall"]
|
#[abi = "stdcall"]
|
||||||
|
@ -1605,6 +1606,8 @@ pub mod funcs {
|
||||||
-> DWORD;
|
-> DWORD;
|
||||||
unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
|
unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
|
||||||
-> BOOL;
|
-> BOOL;
|
||||||
|
unsafe fn GetEnvironmentStringsA() -> LPTCH;
|
||||||
|
unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
|
||||||
|
|
||||||
unsafe fn GetModuleFileNameW(hModule: HMODULE,
|
unsafe fn GetModuleFileNameW(hModule: HMODULE,
|
||||||
lpFilename: LPWSTR,
|
lpFilename: LPWSTR,
|
||||||
|
|
|
@ -171,20 +171,68 @@ fn with_env_lock<T>(f: &fn() -> T) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn env() -> ~[(~str,~str)] {
|
pub fn env() -> ~[(~str,~str)] {
|
||||||
extern {
|
|
||||||
unsafe fn rust_env_pairs() -> ~[~str];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
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 = ~[];
|
let mut pairs = ~[];
|
||||||
for vec::each(rust_env_pairs()) |p| {
|
for input.each |p| {
|
||||||
let vs = str::splitn_char(*p, '=', 1u);
|
let vs = str::splitn_char(*p, '=', 1);
|
||||||
fail_unless!(vec::len(vs) == 2u);
|
log(debug,
|
||||||
|
fmt!("splitting: len: %u",
|
||||||
|
vs.len()));
|
||||||
|
assert vs.len() == 2;
|
||||||
pairs.push((copy vs[0], copy vs[1]));
|
pairs.push((copy vs[0], copy vs[1]));
|
||||||
}
|
}
|
||||||
pairs
|
pairs
|
||||||
}
|
}
|
||||||
|
do with_env_lock {
|
||||||
|
let unparsed_environ = get_env_pairs();
|
||||||
|
env_convert(unparsed_environ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ use sys;
|
||||||
|
|
||||||
#[cfg(test)] use vec;
|
#[cfg(test)] use vec;
|
||||||
#[cfg(test)] use str;
|
#[cfg(test)] use str;
|
||||||
|
#[cfg(test)] use uint;
|
||||||
|
#[cfg(test)] use debug;
|
||||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
#[cfg(notest)] use cmp::{Eq, Ord};
|
||||||
|
|
||||||
pub mod libc_ {
|
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)
|
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> {
|
pub trait Ptr<T> {
|
||||||
pure fn is_null(&self) -> bool;
|
pure fn is_null(&self) -> bool;
|
||||||
pure fn is_not_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_null());
|
||||||
fail_unless!(mq.is_not_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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -53,44 +53,17 @@ timegm(struct tm *tm)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__WIN32__)
|
#if defined(__WIN32__)
|
||||||
extern "C" CDECL rust_vec_box *
|
extern "C" CDECL char**
|
||||||
rust_env_pairs() {
|
rust_env_pairs() {
|
||||||
rust_task *task = rust_get_current_task();
|
return 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
extern "C" CDECL rust_vec_box *
|
extern "C" CDECL char**
|
||||||
rust_env_pairs() {
|
rust_env_pairs() {
|
||||||
rust_task *task = rust_get_current_task();
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
char **environ = *_NSGetEnviron();
|
char **environ = *_NSGetEnviron();
|
||||||
#endif
|
#endif
|
||||||
char **e = environ;
|
return environ;
|
||||||
size_t envc = 0;
|
|
||||||
while (*e) {
|
|
||||||
++envc; ++e;
|
|
||||||
}
|
|
||||||
return make_str_vec(task->kernel, envc, environ);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue