2017-08-15 21:45:21 +02:00
|
|
|
//! Global initialization and retrieval of command line arguments.
|
2016-09-29 22:00:44 +00:00
|
|
|
//!
|
|
|
|
//! On some platforms these are stored during runtime startup,
|
|
|
|
//! and on some they are retrieved from the system on demand.
|
|
|
|
|
|
|
|
#![allow(dead_code)] // runtime init functions not used during testing
|
|
|
|
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::ffi::OsString;
|
|
|
|
use crate::marker::PhantomData;
|
|
|
|
use crate::vec;
|
2016-09-29 22:00:44 +00:00
|
|
|
|
|
|
|
/// One-time global initialization.
|
2019-12-22 17:42:04 -05:00
|
|
|
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
|
|
|
imp::init(argc, argv)
|
|
|
|
}
|
2016-09-29 22:00:44 +00:00
|
|
|
|
|
|
|
/// One-time global cleanup.
|
2019-12-22 17:42:04 -05:00
|
|
|
pub unsafe fn cleanup() {
|
|
|
|
imp::cleanup()
|
|
|
|
}
|
2016-09-29 22:00:44 +00:00
|
|
|
|
|
|
|
/// Returns the command line arguments
|
|
|
|
pub fn args() -> Args {
|
|
|
|
imp::args()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Args {
|
|
|
|
iter: vec::IntoIter<OsString>,
|
|
|
|
_dont_send_or_sync_me: PhantomData<*mut ()>,
|
|
|
|
}
|
|
|
|
|
2017-06-21 15:40:45 +03:00
|
|
|
impl Args {
|
|
|
|
pub fn inner_debug(&self) -> &[OsString] {
|
|
|
|
self.iter.as_slice()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-29 22:00:44 +00:00
|
|
|
impl Iterator for Args {
|
|
|
|
type Item = OsString;
|
2019-12-22 17:42:04 -05:00
|
|
|
fn next(&mut self) -> Option<OsString> {
|
|
|
|
self.iter.next()
|
|
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
self.iter.size_hint()
|
|
|
|
}
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ExactSizeIterator for Args {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn len(&self) -> usize {
|
|
|
|
self.iter.len()
|
|
|
|
}
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DoubleEndedIterator for Args {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn next_back(&mut self) -> Option<OsString> {
|
|
|
|
self.iter.next_back()
|
|
|
|
}
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
#[cfg(any(
|
|
|
|
target_os = "linux",
|
|
|
|
target_os = "android",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "netbsd",
|
|
|
|
target_os = "openbsd",
|
|
|
|
target_os = "solaris",
|
2020-04-13 23:37:22 +00:00
|
|
|
target_os = "illumos",
|
2019-12-22 17:42:04 -05:00
|
|
|
target_os = "emscripten",
|
|
|
|
target_os = "haiku",
|
|
|
|
target_os = "l4re",
|
|
|
|
target_os = "fuchsia",
|
|
|
|
target_os = "redox"
|
|
|
|
))]
|
2016-09-29 22:00:44 +00:00
|
|
|
mod imp {
|
2019-12-22 17:42:04 -05:00
|
|
|
use super::Args;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::ffi::{CStr, OsString};
|
|
|
|
use crate::marker::PhantomData;
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::os::unix::prelude::*;
|
|
|
|
use crate::ptr;
|
2020-07-03 14:13:22 -04:00
|
|
|
use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
|
2016-09-29 22:00:44 +00:00
|
|
|
|
Split sys_common::Mutex in StaticMutex and MovableMutex.
The (unsafe) Mutex from sys_common had a rather complicated interface.
You were supposed to call init() manually, unless you could guarantee it
was neither moved nor used reentrantly.
Calling `destroy()` was also optional, although it was unclear if 1)
resources might be leaked or not, and 2) if destroy() should only be
called when `init()` was called.
This allowed for a number of interesting (confusing?) different ways to
use this Mutex, all captured in a single type.
In practice, this type was only ever used in two ways:
1. As a static variable. In this case, neither init() nor destroy() are
called. The variable is never moved, and it is never used
reentrantly. It is only ever locked using the LockGuard, never with
raw_lock.
2. As a Boxed variable. In this case, both init() and destroy() are
called, it will be moved and possibly used reentrantly.
No other combinations are used anywhere in `std`.
This change simplifies things by splitting this Mutex type into
two types matching the two use cases: StaticMutex and MovableMutex.
The interface of both new types is now both safer and simpler. The first
one does not call nor expose init/destroy, and the second one calls
those automatically in its new() and Drop functions. Also, the locking
functions of MovableMutex are no longer unsafe.
2020-09-24 16:03:20 +02:00
|
|
|
use crate::sys_common::mutex::StaticMutex;
|
2016-09-29 22:00:44 +00:00
|
|
|
|
2020-07-03 14:13:22 -04:00
|
|
|
static ARGC: AtomicIsize = AtomicIsize::new(0);
|
|
|
|
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
|
2018-08-08 18:12:33 +02:00
|
|
|
// We never call `ENV_LOCK.init()`, so it is UB to attempt to
|
2018-08-06 14:39:55 +02:00
|
|
|
// acquire this mutex reentrantly!
|
Split sys_common::Mutex in StaticMutex and MovableMutex.
The (unsafe) Mutex from sys_common had a rather complicated interface.
You were supposed to call init() manually, unless you could guarantee it
was neither moved nor used reentrantly.
Calling `destroy()` was also optional, although it was unclear if 1)
resources might be leaked or not, and 2) if destroy() should only be
called when `init()` was called.
This allowed for a number of interesting (confusing?) different ways to
use this Mutex, all captured in a single type.
In practice, this type was only ever used in two ways:
1. As a static variable. In this case, neither init() nor destroy() are
called. The variable is never moved, and it is never used
reentrantly. It is only ever locked using the LockGuard, never with
raw_lock.
2. As a Boxed variable. In this case, both init() and destroy() are
called, it will be moved and possibly used reentrantly.
No other combinations are used anywhere in `std`.
This change simplifies things by splitting this Mutex type into
two types matching the two use cases: StaticMutex and MovableMutex.
The interface of both new types is now both safer and simpler. The first
one does not call nor expose init/destroy, and the second one calls
those automatically in its new() and Drop functions. Also, the locking
functions of MovableMutex are no longer unsafe.
2020-09-24 16:03:20 +02:00
|
|
|
static LOCK: StaticMutex = StaticMutex::new();
|
2016-09-29 22:00:44 +00:00
|
|
|
|
2019-11-21 13:42:25 -05:00
|
|
|
unsafe fn really_init(argc: isize, argv: *const *const u8) {
|
2018-06-09 21:13:04 +08:00
|
|
|
let _guard = LOCK.lock();
|
2020-07-03 14:13:22 -04:00
|
|
|
ARGC.store(argc, Ordering::Relaxed);
|
|
|
|
ARGV.store(argv as *mut _, Ordering::Relaxed);
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 13:42:25 -05:00
|
|
|
#[inline(always)]
|
|
|
|
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
2019-11-29 20:07:55 +01:00
|
|
|
// On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
|
|
|
|
// `ARGC` and `ARGV`. But in Miri that does not actually happen so we
|
|
|
|
// still initialize here.
|
2019-12-22 17:42:04 -05:00
|
|
|
#[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
|
2019-11-21 13:42:25 -05:00
|
|
|
really_init(_argc, _argv);
|
|
|
|
}
|
|
|
|
|
2019-11-21 11:47:01 -05:00
|
|
|
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
|
|
|
|
/// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
|
2019-11-21 08:21:14 -05:00
|
|
|
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
|
|
|
#[used]
|
2019-11-21 11:44:22 -05:00
|
|
|
#[link_section = ".init_array.00099"]
|
2019-11-21 08:21:14 -05:00
|
|
|
static ARGV_INIT_ARRAY: extern "C" fn(
|
|
|
|
crate::os::raw::c_int,
|
|
|
|
*const *const u8,
|
|
|
|
*const *const u8,
|
|
|
|
) = {
|
|
|
|
extern "C" fn init_wrapper(
|
|
|
|
argc: crate::os::raw::c_int,
|
|
|
|
argv: *const *const u8,
|
|
|
|
_envp: *const *const u8,
|
|
|
|
) {
|
|
|
|
unsafe {
|
2019-11-21 13:42:25 -05:00
|
|
|
really_init(argc as isize, argv);
|
2019-11-21 08:21:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
init_wrapper
|
|
|
|
};
|
|
|
|
|
2016-09-29 22:00:44 +00:00
|
|
|
pub unsafe fn cleanup() {
|
2018-06-09 21:13:04 +08:00
|
|
|
let _guard = LOCK.lock();
|
2020-07-03 14:13:22 -04:00
|
|
|
ARGC.store(0, Ordering::Relaxed);
|
|
|
|
ARGV.store(ptr::null_mut(), Ordering::Relaxed);
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn args() -> Args {
|
2019-12-22 17:42:04 -05:00
|
|
|
Args { iter: clone().into_iter(), _dont_send_or_sync_me: PhantomData }
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
2018-01-03 12:09:22 -08:00
|
|
|
fn clone() -> Vec<OsString> {
|
2016-09-29 22:00:44 +00:00
|
|
|
unsafe {
|
2018-06-09 21:13:04 +08:00
|
|
|
let _guard = LOCK.lock();
|
2020-07-03 14:13:22 -04:00
|
|
|
let argc = ARGC.load(Ordering::Relaxed);
|
|
|
|
let argv = ARGV.load(Ordering::Relaxed);
|
|
|
|
(0..argc)
|
2019-12-22 17:42:04 -05:00
|
|
|
.map(|i| {
|
2020-07-03 14:13:22 -04:00
|
|
|
let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
|
2019-12-22 17:42:04 -05:00
|
|
|
OsStringExt::from_vec(cstr.to_bytes().to_vec())
|
|
|
|
})
|
|
|
|
.collect()
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
2016-09-29 22:00:44 +00:00
|
|
|
mod imp {
|
2019-12-22 17:42:04 -05:00
|
|
|
use super::Args;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::ffi::CStr;
|
|
|
|
use crate::marker::PhantomData;
|
2016-09-29 22:00:44 +00:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
|
2016-09-29 22:00:44 +00:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
pub fn cleanup() {}
|
2016-09-29 22:00:44 +00:00
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub fn args() -> Args {
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::os::unix::prelude::*;
|
2019-12-22 17:42:04 -05:00
|
|
|
extern "C" {
|
2016-09-29 22:00:44 +00:00
|
|
|
// These functions are in crt_externs.h.
|
|
|
|
fn _NSGetArgc() -> *mut libc::c_int;
|
|
|
|
fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
|
|
|
|
}
|
|
|
|
|
|
|
|
let vec = unsafe {
|
2019-12-22 17:42:04 -05:00
|
|
|
let (argc, argv) =
|
|
|
|
(*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
|
|
|
|
(0..argc as isize)
|
|
|
|
.map(|i| {
|
|
|
|
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
|
|
|
|
OsStringExt::from_vec(bytes)
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
2016-09-29 22:00:44 +00:00
|
|
|
};
|
2019-12-22 17:42:04 -05:00
|
|
|
Args { iter: vec.into_iter(), _dont_send_or_sync_me: PhantomData }
|
2016-09-29 22:00:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
|
|
|
|
// and use underscores in their names - they're most probably
|
|
|
|
// are considered private and therefore should be avoided
|
|
|
|
// Here is another way to get arguments using Objective C
|
|
|
|
// runtime
|
|
|
|
//
|
|
|
|
// In general it looks like:
|
|
|
|
// res = Vec::new()
|
|
|
|
// let args = [[NSProcessInfo processInfo] arguments]
|
|
|
|
// for i in (0..[args count])
|
|
|
|
// res.push([args objectAtIndex:i])
|
|
|
|
// res
|
|
|
|
#[cfg(target_os = "ios")]
|
|
|
|
pub fn args() -> Args {
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::ffi::OsString;
|
|
|
|
use crate::mem;
|
|
|
|
use crate::str;
|
2016-09-29 22:00:44 +00:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
extern "C" {
|
2016-09-29 22:00:44 +00:00
|
|
|
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
|
|
|
|
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
#[cfg(target_arch = "aarch64")]
|
|
|
|
extern "C" {
|
2016-12-03 19:47:27 +01:00
|
|
|
fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
|
2020-07-16 09:12:59 -04:00
|
|
|
#[allow(clashing_extern_declarations)]
|
2019-12-22 17:42:04 -05:00
|
|
|
#[link_name = "objc_msgSend"]
|
2016-12-03 19:47:27 +01:00
|
|
|
fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
#[cfg(not(target_arch = "aarch64"))]
|
|
|
|
extern "C" {
|
2016-12-03 19:47:27 +01:00
|
|
|
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
|
2020-07-16 09:12:59 -04:00
|
|
|
#[allow(clashing_extern_declarations)]
|
2019-12-22 17:42:04 -05:00
|
|
|
#[link_name = "objc_msgSend"]
|
2016-12-03 19:47:27 +01:00
|
|
|
fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
|
|
|
|
}
|
|
|
|
|
2016-09-29 22:00:44 +00:00
|
|
|
type Sel = *const libc::c_void;
|
|
|
|
type NsId = *const libc::c_void;
|
|
|
|
|
|
|
|
let mut res = Vec::new();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
|
|
|
|
let arguments_sel = sel_registerName("arguments\0".as_ptr());
|
|
|
|
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
|
|
|
|
let count_sel = sel_registerName("count\0".as_ptr());
|
|
|
|
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
|
|
|
|
|
|
|
|
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
|
|
|
|
let info = objc_msgSend(klass, process_info_sel);
|
|
|
|
let args = objc_msgSend(info, arguments_sel);
|
|
|
|
|
|
|
|
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
|
|
|
|
for i in 0..cnt {
|
2016-12-03 19:47:27 +01:00
|
|
|
let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
|
2019-12-22 17:42:04 -05:00
|
|
|
let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
|
2016-09-29 22:00:44 +00:00
|
|
|
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
|
|
|
|
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
|
|
|
|
}
|
|
|
|
}
|