49 lines
1.5 KiB
Rust
49 lines
1.5 KiB
Rust
//! 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<usize>) {
|
|
let left = ARGC.load(Ordering::Acquire).saturating_sub(self.next);
|
|
(left, Some(left))
|
|
}
|
|
}
|
|
|
|
impl ExactSizeIterator for Args {}
|