Implement setenv/unsetenv
This commit is contained in:
+84
-41
@@ -258,7 +258,7 @@ pub extern "C" fn gcvt(value: c_double, ndigit: c_int, buf: *mut c_char) -> *mut
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn find_env(name: *const c_char) -> Option<(usize, *mut c_char)> {
|
||||
unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
|
||||
for (i, item) in platform::inner_environ.iter().enumerate() {
|
||||
let mut item = *item;
|
||||
if item == ptr::null_mut() {
|
||||
@@ -269,23 +269,25 @@ unsafe fn find_env(name: *const c_char) -> Option<(usize, *mut c_char)> {
|
||||
);
|
||||
break;
|
||||
}
|
||||
let mut name = name;
|
||||
let mut search = search;
|
||||
loop {
|
||||
let end_of_name = *name == 0 || *name == b'=' as c_char;
|
||||
if *item == 0 || *item == b'=' as c_char || end_of_name {
|
||||
if *item == b'=' as c_char || end_of_name {
|
||||
let end_of_query = *search == 0 || *search == b'=' as c_char;
|
||||
assert_ne!(*item, 0, "environ has an item without value");
|
||||
if *item == b'=' as c_char || end_of_query {
|
||||
if *item == b'=' as c_char && end_of_query {
|
||||
// Both keys env here
|
||||
return Some((i, item.offset(1)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if *item != *name {
|
||||
if *item != *search {
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.offset(1);
|
||||
name = name.offset(1);
|
||||
search = search.offset(1);
|
||||
}
|
||||
}
|
||||
None
|
||||
@@ -513,43 +515,16 @@ pub extern "C" fn ptsname(fildes: c_int) -> *mut c_char {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn putenv(s: *mut c_char) -> c_int {
|
||||
let mut s_len = 0;
|
||||
while *s.offset(s_len) != 0 {
|
||||
s_len += 1;
|
||||
}
|
||||
|
||||
let ptr;
|
||||
|
||||
if let Some((i, _)) = find_env(s) {
|
||||
let mut item = platform::inner_environ[i];
|
||||
let mut item_len = 0;
|
||||
while *item.offset(item_len) != 0 {
|
||||
item_len += 1;
|
||||
}
|
||||
|
||||
if item_len > s_len {
|
||||
ptr = item;
|
||||
} else {
|
||||
platform::free(item as *mut c_void);
|
||||
ptr = platform::alloc(s_len as usize + 1) as *mut c_char;
|
||||
platform::inner_environ[i] = ptr;
|
||||
}
|
||||
pub unsafe extern "C" fn putenv(insert: *mut c_char) -> c_int {
|
||||
assert_ne!(insert, ptr::null_mut(), "putenv(NULL)");
|
||||
if let Some((i, _)) = find_env(insert) {
|
||||
platform::free(platform::inner_environ[i] as *mut c_void);
|
||||
platform::inner_environ[i] = insert;
|
||||
} else {
|
||||
ptr = platform::alloc(s_len as usize + 1) as *mut c_char;
|
||||
let i = platform::inner_environ.len() - 1;
|
||||
assert_eq!(
|
||||
platform::inner_environ[i],
|
||||
ptr::null_mut(),
|
||||
"last element in environ vector was not null"
|
||||
);
|
||||
platform::inner_environ[i] = ptr;
|
||||
assert_eq!(platform::inner_environ[i], ptr::null_mut(), "environ did not end with null");
|
||||
platform::inner_environ[i] = insert;
|
||||
platform::inner_environ.push(ptr::null_mut());
|
||||
|
||||
platform::environ = platform::inner_environ.as_mut_ptr();
|
||||
}
|
||||
for i in 0..=s_len {
|
||||
*ptr.offset(i) = *s.offset(i);
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -609,6 +584,64 @@ pub extern "C" fn seed48(seed16v: [c_ushort; 3]) -> c_ushort {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn setenv(mut key: *const c_char, mut value: *const c_char, overwrite: c_int) -> c_int {
|
||||
let mut key_len = 0;
|
||||
while *key.offset(key_len) != 0 {
|
||||
key_len += 1;
|
||||
}
|
||||
let mut value_len = 0;
|
||||
while *value.offset(value_len) != 0 {
|
||||
value_len += 1;
|
||||
}
|
||||
|
||||
let index = if let Some((i, existing)) = find_env(key) {
|
||||
if overwrite == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut existing_len = 0;
|
||||
while *existing.offset(existing_len) != 0 {
|
||||
existing_len += 1;
|
||||
}
|
||||
|
||||
if existing_len >= value_len {
|
||||
// Reuse existing element's allocation
|
||||
for i in 0..=value_len {
|
||||
*existing.offset(i) = *value.offset(i);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
i
|
||||
}
|
||||
} else {
|
||||
let i = platform::inner_environ.len() - 1;
|
||||
assert_eq!(platform::inner_environ[i], ptr::null_mut(), "environ did not end with null");
|
||||
platform::inner_environ.push(ptr::null_mut());
|
||||
i
|
||||
};
|
||||
|
||||
//platform::free(platform::inner_environ[index] as *mut c_void);
|
||||
let mut ptr = platform::alloc(key_len as usize + 1 + value_len as usize) as *mut c_char;
|
||||
platform::inner_environ[index] = ptr;
|
||||
|
||||
while *key != 0 {
|
||||
*ptr = *key;
|
||||
ptr = ptr.offset(1);
|
||||
key = key.offset(1);
|
||||
}
|
||||
*ptr = b'=' as c_char;
|
||||
ptr = ptr.offset(1);
|
||||
while *value != 0 {
|
||||
*ptr = *value;
|
||||
ptr = ptr.offset(1);
|
||||
value = value.offset(1);
|
||||
}
|
||||
*ptr = 0;
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn setkey(key: *const c_char) {
|
||||
unimplemented!();
|
||||
@@ -987,6 +1020,16 @@ pub extern "C" fn unlockpt(fildes: c_int) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn unsetenv(key: *mut c_char) -> c_int {
|
||||
if let Some((i, _)) = find_env(key) {
|
||||
// No need to worry about updating the pointer, this does not
|
||||
// reallocate in any way. And the final null is already shifted back.
|
||||
platform::inner_environ.remove(i);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
|
||||
memalign(4096, size)
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
It's working!!
|
||||
Updates accordingly.
|
||||
in place
|
||||
TEST=in place
|
||||
Value overwritten and not in place because it's really long
|
||||
TEST=in place
|
||||
Value overwritten and not in place because it's really long
|
||||
Value deleted successfully!
|
||||
|
||||
+33
-1
@@ -1,11 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
//puts(getenv("SHELL"));
|
||||
//puts(getenv("CC"));
|
||||
|
||||
putenv("TEST=It's working!!");
|
||||
char* owned = malloc(26); // "TEST=Updates accordingly." + NUL
|
||||
strcpy(owned, "TEST=It's working!!");
|
||||
|
||||
putenv(owned);
|
||||
puts(getenv("TEST"));
|
||||
|
||||
strcpy(owned, "TEST=Updates accordingly.");
|
||||
puts(getenv("TEST"));
|
||||
|
||||
// Allocation is reused
|
||||
setenv("TEST", "in place", 1);
|
||||
puts(getenv("TEST"));
|
||||
puts(owned);
|
||||
|
||||
// Allocation is not reused
|
||||
setenv("TEST", "Value overwritten and not in place because it's really long", 1);
|
||||
puts(getenv("TEST"));
|
||||
puts(owned);
|
||||
|
||||
// Value is not overwritten
|
||||
setenv("TEST", "Value not overwritten", 0);
|
||||
puts(getenv("TEST"));
|
||||
|
||||
unsetenv("TEST");
|
||||
char* env = getenv("TEST");
|
||||
if (env) {
|
||||
puts("This should be null, but isn't");
|
||||
puts(env);
|
||||
return 1;
|
||||
} else {
|
||||
puts("Value deleted successfully!");
|
||||
}
|
||||
|
||||
free(owned);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user