//! Command-line arguments, captured from crt1.o's argv by [`crate::entry!`]. use core::ffi::CStr; use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; static ARGC: AtomicUsize = AtomicUsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(core::ptr::null_mut()); /// # Safety /// `argv` must point to `argc` NUL-terminated strings that live forever. #[doc(hidden)] pub unsafe fn init(argc: i32, argv: *const *const u8) { ARGV.store(argv as *mut *const u8, Ordering::Relaxed); ARGC.store(argc.max(0) as usize, Ordering::Release); } /// Iterator over the program arguments; argv[0] is the executable path. /// Arguments that are not valid UTF-8 are yielded lossily as `"?"`. pub fn args() -> Args { Args { next: 0 } } pub struct Args { next: usize, } impl Iterator for Args { type Item = &'static str; fn next(&mut self) -> Option<&'static str> { let argc = ARGC.load(Ordering::Acquire); if self.next >= argc { return None; } let argv = ARGV.load(Ordering::Relaxed); // SAFETY: init() guarantees argc valid, immortal C strings. let s = unsafe { CStr::from_ptr(*argv.add(self.next) as *const core::ffi::c_char) }; self.next += 1; Some(s.to_str().unwrap_or("?")) } fn size_hint(&self) -> (usize, Option) { let left = ARGC.load(Ordering::Acquire).saturating_sub(self.next); (left, Some(left)) } } impl ExactSizeIterator for Args {}