use core::cmp::min;
use core::ptr;
use hierr::{set_errno, Error, Result};
#[allow(dead_code)]
pub fn env_string<'a>(name: &str, value: &'a mut [u8]) -> &'a [u8] {
let mut buf = [0_u8; 128];
let name = env_name(name, &mut buf);
let val = unsafe { libc::getenv(name) };
if val.is_null() {
return &value[0..0];
}
let len = min(value.len(), unsafe { libc::strlen(val) });
unsafe {
ptr::copy(val.cast::<u8>(), value.as_mut_ptr(), len);
}
&value[0..len]
}
#[allow(dead_code)]
pub fn env_signed<T>(name: &str, base: i32, def: T) -> T
where
T: TryFrom<i64> + Default,
{
env_number::<T, _, _>(name, base, |n, e, b| unsafe { libc::strtoll(n, e, b) }).unwrap_or(def)
}
#[allow(dead_code)]
pub fn env_unsigned<T>(name: &str, base: i32, def: T) -> T
where
T: TryFrom<u64> + Default,
{
env_number::<T, _, _>(name, base, |n, e, b| unsafe { libc::strtoull(n, e, b) }).unwrap_or(def)
}
fn env_number<T, N, F>(name: &str, base: i32, f: F) -> Result<T>
where
T: TryFrom<N> + Default,
F: Fn(*const i8, *mut *mut i8, i32) -> N,
{
let mut buf = [0_u8; 128];
let name = env_name(name, &mut buf);
let val = unsafe { libc::getenv(name) };
if val.is_null() {
return Ok(T::default());
}
set_errno(0);
let val = f(val, ptr::null_mut(), base);
let err = Error::last();
if err.errno == 0 {
T::try_from(val).map_err(|_| Error::new(libc::EINVAL))
} else {
Err(err)
}
}
fn env_name(name: &str, buf: &mut [u8]) -> *const i8 {
debug_assert!(!buf.is_empty());
if !name.is_empty() {
if name.as_bytes()[name.len() - 1] == 0 {
return name.as_bytes().as_ptr().cast::<i8>();
}
let len = min(buf.len() - 1, name.len());
unsafe {
ptr::copy_nonoverlapping(name.as_bytes().as_ptr(), buf.as_mut_ptr(), len);
}
buf[len] = 0;
} else {
buf[0] = 0;
}
buf.as_ptr().cast::<i8>()
}