| use crate::ffi::{OsStr, OsString}; | |
| use crate::os::windows::prelude::*; | |
| use crate::sys::pal::{c, cvt, fill_utf16_buf, to_u16s}; | |
| use crate::{fmt, io, ptr, slice}; | |
| pub struct Env { | |
| base: *mut c::WCHAR, | |
| iter: EnvIterator, | |
| } | |
| impl fmt::Debug for Env { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| let Self { base: _, iter } = self; | |
| f.debug_list().entries(iter.clone()).finish() | |
| } | |
| } | |
| impl Iterator for Env { | |
| type Item = (OsString, OsString); | |
| fn next(&mut self) -> Option<(OsString, OsString)> { | |
| let Self { base: _, iter } = self; | |
| iter.next() | |
| } | |
| } | |
| #[derive(Clone)] | |
| struct EnvIterator(*mut c::WCHAR); | |
| impl Iterator for EnvIterator { | |
| type Item = (OsString, OsString); | |
| fn next(&mut self) -> Option<(OsString, OsString)> { | |
| let Self(cur) = self; | |
| loop { | |
| unsafe { | |
| if **cur == 0 { | |
| return None; | |
| } | |
| let p = *cur as *const u16; | |
| let mut len = 0; | |
| while *p.add(len) != 0 { | |
| len += 1; | |
| } | |
| let s = slice::from_raw_parts(p, len); | |
| *cur = cur.add(len + 1); | |
| // Windows allows environment variables to start with an equals | |
| // symbol (in any other position, this is the separator between | |
| // variable name and value). Since`s` has at least length 1 at | |
| // this point (because the empty string terminates the array of | |
| // environment variables), we can safely slice. | |
| let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { | |
| Some(p) => p, | |
| None => continue, | |
| }; | |
| return Some(( | |
| OsStringExt::from_wide(&s[..pos]), | |
| OsStringExt::from_wide(&s[pos + 1..]), | |
| )); | |
| } | |
| } | |
| } | |
| } | |
| impl Drop for Env { | |
| fn drop(&mut self) { | |
| unsafe { | |
| c::FreeEnvironmentStringsW(self.base); | |
| } | |
| } | |
| } | |
| pub fn env() -> Env { | |
| unsafe { | |
| let ch = c::GetEnvironmentStringsW(); | |
| if ch.is_null() { | |
| panic!("failure getting env string from OS: {}", io::Error::last_os_error()); | |
| } | |
| Env { base: ch, iter: EnvIterator(ch) } | |
| } | |
| } | |
| pub fn getenv(k: &OsStr) -> Option<OsString> { | |
| let k = to_u16s(k).ok()?; | |
| fill_utf16_buf( | |
| |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, | |
| OsStringExt::from_wide, | |
| ) | |
| .ok() | |
| } | |
| pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { | |
| // SAFETY: We ensure that k and v are null-terminated wide strings. | |
| unsafe { | |
| let k = to_u16s(k)?; | |
| let v = to_u16s(v)?; | |
| cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) | |
| } | |
| } | |
| pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { | |
| // SAFETY: We ensure that v is a null-terminated wide strings. | |
| unsafe { | |
| let v = to_u16s(n)?; | |
| cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) | |
| } | |
| } |