1 //! Global initialization and retrieval of command line arguments.
3 //! On some platforms these are stored during runtime startup,
4 //! and on some they are retrieved from the system on demand.
6 #![allow(dead_code)] // runtime init functions not used during testing
8 use crate::ffi
::OsString
;
9 use crate::marker
::PhantomData
;
12 /// One-time global initialization.
13 pub unsafe fn init(argc
: isize, argv
: *const *const u8) { imp::init(argc, argv) }
15 /// One-time global cleanup.
16 pub unsafe fn cleanup() { imp::cleanup() }
18 /// Returns the command line arguments
19 pub fn args() -> Args
{
24 iter
: vec
::IntoIter
<OsString
>,
25 _dont_send_or_sync_me
: PhantomData
<*mut ()>,
29 pub fn inner_debug(&self) -> &[OsString
] {
34 impl Iterator
for Args
{
36 fn next(&mut self) -> Option
<OsString
> { self.iter.next() }
37 fn size_hint(&self) -> (usize, Option
<usize>) { self.iter.size_hint() }
40 impl ExactSizeIterator
for Args
{
41 fn len(&self) -> usize { self.iter.len() }
44 impl DoubleEndedIterator
for Args
{
45 fn next_back(&mut self) -> Option
<OsString
> { self.iter.next_back() }
48 #[cfg(any(target_os = "linux",
49 target_os
= "android",
50 target_os
= "freebsd",
51 target_os
= "dragonfly",
53 target_os
= "openbsd",
54 target_os
= "solaris",
55 target_os
= "emscripten",
58 target_os
= "fuchsia",
59 target_os
= "redox"))]
61 use crate::os
::unix
::prelude
::*;
63 use crate::ffi
::{CStr, OsString}
;
64 use crate::marker
::PhantomData
;
67 use crate::sys_common
::mutex
::Mutex
;
69 static mut ARGC
: isize = 0;
70 static mut ARGV
: *const *const u8 = ptr
::null();
71 // We never call `ENV_LOCK.init()`, so it is UB to attempt to
72 // acquire this mutex reentrantly!
73 static LOCK
: Mutex
= Mutex
::new();
75 unsafe fn really_init(argc
: isize, argv
: *const *const u8) {
76 let _guard
= LOCK
.lock();
82 pub unsafe fn init(_argc
: isize, _argv
: *const *const u8) {
83 // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
84 // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
85 // still initialize here.
88 not(all(target_os
= "linux", target_env
= "gnu"))
90 really_init(_argc
, _argv
);
93 /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
94 /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
95 #[cfg(all(target_os = "linux", target_env = "gnu"))]
97 #[link_section = ".init_array.00099"]
98 static ARGV_INIT_ARRAY
: extern "C" fn(
99 crate::os
::raw
::c_int
,
103 extern "C" fn init_wrapper(
104 argc
: crate::os
::raw
::c_int
,
105 argv
: *const *const u8,
106 _envp
: *const *const u8,
109 really_init(argc
as isize, argv
);
115 pub unsafe fn cleanup() {
116 let _guard
= LOCK
.lock();
121 pub fn args() -> Args
{
123 iter
: clone().into_iter(),
124 _dont_send_or_sync_me
: PhantomData
128 fn clone() -> Vec
<OsString
> {
130 let _guard
= LOCK
.lock();
132 let cstr
= CStr
::from_ptr(*ARGV
.offset(i
) as *const libc
::c_char
);
133 OsStringExt
::from_vec(cstr
.to_bytes().to_vec())
139 #[cfg(any(target_os = "macos",
142 use crate::ffi
::CStr
;
143 use crate::marker
::PhantomData
;
146 pub unsafe fn init(_argc
: isize, _argv
: *const *const u8) {
152 #[cfg(target_os = "macos")]
153 pub fn args() -> Args
{
154 use crate::os
::unix
::prelude
::*;
156 // These functions are in crt_externs.h.
157 fn _NSGetArgc() -> *mut libc
::c_int
;
158 fn _NSGetArgv() -> *mut *mut *mut libc
::c_char
;
162 let (argc
, argv
) = (*_NSGetArgc() as isize,
163 *_NSGetArgv() as *const *const libc
::c_char
);
164 (0.. argc
as isize).map(|i
| {
165 let bytes
= CStr
::from_ptr(*argv
.offset(i
)).to_bytes().to_vec();
166 OsStringExt
::from_vec(bytes
)
167 }).collect
::<Vec
<_
>>()
170 iter
: vec
.into_iter(),
171 _dont_send_or_sync_me
: PhantomData
,
175 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
176 // and use underscores in their names - they're most probably
177 // are considered private and therefore should be avoided
178 // Here is another way to get arguments using Objective C
181 // In general it looks like:
183 // let args = [[NSProcessInfo processInfo] arguments]
184 // for i in (0..[args count])
185 // res.push([args objectAtIndex:i])
187 #[cfg(target_os = "ios")]
188 pub fn args() -> Args
{
189 use crate::ffi
::OsString
;
194 fn sel_registerName(name
: *const libc
::c_uchar
) -> Sel
;
195 fn objc_getClass(class_name
: *const libc
::c_uchar
) -> NsId
;
198 #[cfg(target_arch="aarch64")]
200 fn objc_msgSend(obj
: NsId
, sel
: Sel
) -> NsId
;
201 #[link_name="objc_msgSend"]
202 fn objc_msgSend_ul(obj
: NsId
, sel
: Sel
, i
: libc
::c_ulong
) -> NsId
;
205 #[cfg(not(target_arch="aarch64"))]
207 fn objc_msgSend(obj
: NsId
, sel
: Sel
, ...) -> NsId
;
208 #[link_name="objc_msgSend"]
209 fn objc_msgSend_ul(obj
: NsId
, sel
: Sel
, ...) -> NsId
;
212 type Sel
= *const libc
::c_void
;
213 type NsId
= *const libc
::c_void
;
215 let mut res
= Vec
::new();
218 let process_info_sel
= sel_registerName("processInfo\0".as_ptr());
219 let arguments_sel
= sel_registerName("arguments\0".as_ptr());
220 let utf8_sel
= sel_registerName("UTF8String\0".as_ptr());
221 let count_sel
= sel_registerName("count\0".as_ptr());
222 let object_at_sel
= sel_registerName("objectAtIndex:\0".as_ptr());
224 let klass
= objc_getClass("NSProcessInfo\0".as_ptr());
225 let info
= objc_msgSend(klass
, process_info_sel
);
226 let args
= objc_msgSend(info
, arguments_sel
);
228 let cnt
: usize = mem
::transmute(objc_msgSend(args
, count_sel
));
230 let tmp
= objc_msgSend_ul(args
, object_at_sel
, i
as libc
::c_ulong
);
231 let utf_c_str
: *const libc
::c_char
=
232 mem
::transmute(objc_msgSend(tmp
, utf8_sel
));
233 let bytes
= CStr
::from_ptr(utf_c_str
).to_bytes();
234 res
.push(OsString
::from(str::from_utf8(bytes
).unwrap()))
238 Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }