]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/args.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / libstd / sys / unix / args.rs
CommitLineData
3b2f2976 1//! Global initialization and retrieval of command line arguments.
c30ab7b3
SL
2//!
3//! On some platforms these are stored during runtime startup,
4//! and on some they are retrieved from the system on demand.
5
6#![allow(dead_code)] // runtime init functions not used during testing
7
532ac7d7
XL
8use crate::ffi::OsString;
9use crate::marker::PhantomData;
10use crate::vec;
c30ab7b3
SL
11
12/// One-time global initialization.
13pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
14
15/// One-time global cleanup.
16pub unsafe fn cleanup() { imp::cleanup() }
17
18/// Returns the command line arguments
19pub fn args() -> Args {
20 imp::args()
21}
22
23pub struct Args {
24 iter: vec::IntoIter<OsString>,
25 _dont_send_or_sync_me: PhantomData<*mut ()>,
26}
27
041b39d2
XL
28impl Args {
29 pub fn inner_debug(&self) -> &[OsString] {
30 self.iter.as_slice()
31 }
32}
33
c30ab7b3
SL
34impl Iterator for Args {
35 type Item = OsString;
36 fn next(&mut self) -> Option<OsString> { self.iter.next() }
37 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
38}
39
40impl ExactSizeIterator for Args {
41 fn len(&self) -> usize { self.iter.len() }
42}
43
44impl DoubleEndedIterator for Args {
45 fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
46}
47
48#[cfg(any(target_os = "linux",
49 target_os = "android",
50 target_os = "freebsd",
51 target_os = "dragonfly",
c30ab7b3
SL
52 target_os = "netbsd",
53 target_os = "openbsd",
54 target_os = "solaris",
55 target_os = "emscripten",
56 target_os = "haiku",
ea8adc8c 57 target_os = "l4re",
b7449926 58 target_os = "fuchsia",
416331ca 59 target_os = "redox"))]
c30ab7b3 60mod imp {
532ac7d7
XL
61 use crate::os::unix::prelude::*;
62 use crate::ptr;
63 use crate::ffi::{CStr, OsString};
64 use crate::marker::PhantomData;
c30ab7b3
SL
65 use super::Args;
66
532ac7d7 67 use crate::sys_common::mutex::Mutex;
c30ab7b3 68
2c00a5a8
XL
69 static mut ARGC: isize = 0;
70 static mut ARGV: *const *const u8 = ptr::null();
b7449926
XL
71 // We never call `ENV_LOCK.init()`, so it is UB to attempt to
72 // acquire this mutex reentrantly!
c30ab7b3
SL
73 static LOCK: Mutex = Mutex::new();
74
60c5eb7d 75 unsafe fn really_init(argc: isize, argv: *const *const u8) {
94b46f34 76 let _guard = LOCK.lock();
2c00a5a8
XL
77 ARGC = argc;
78 ARGV = argv;
c30ab7b3
SL
79 }
80
60c5eb7d
XL
81 #[inline(always)]
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.
86 #[cfg(any(
87 miri,
88 not(all(target_os = "linux", target_env = "gnu"))
89 ))]
90 really_init(_argc, _argv);
91 }
92
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"))]
96 #[used]
97 #[link_section = ".init_array.00099"]
98 static ARGV_INIT_ARRAY: extern "C" fn(
99 crate::os::raw::c_int,
100 *const *const u8,
101 *const *const u8,
102 ) = {
103 extern "C" fn init_wrapper(
104 argc: crate::os::raw::c_int,
105 argv: *const *const u8,
106 _envp: *const *const u8,
107 ) {
108 unsafe {
109 really_init(argc as isize, argv);
110 }
111 }
112 init_wrapper
113 };
114
c30ab7b3 115 pub unsafe fn cleanup() {
94b46f34 116 let _guard = LOCK.lock();
2c00a5a8
XL
117 ARGC = 0;
118 ARGV = ptr::null();
c30ab7b3
SL
119 }
120
121 pub fn args() -> Args {
2c00a5a8
XL
122 Args {
123 iter: clone().into_iter(),
124 _dont_send_or_sync_me: PhantomData
125 }
c30ab7b3
SL
126 }
127
2c00a5a8 128 fn clone() -> Vec<OsString> {
c30ab7b3 129 unsafe {
94b46f34
XL
130 let _guard = LOCK.lock();
131 (0..ARGC).map(|i| {
2c00a5a8
XL
132 let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
133 OsStringExt::from_vec(cstr.to_bytes().to_vec())
94b46f34 134 }).collect()
c30ab7b3
SL
135 }
136 }
c30ab7b3
SL
137}
138
139#[cfg(any(target_os = "macos",
140 target_os = "ios"))]
141mod imp {
532ac7d7
XL
142 use crate::ffi::CStr;
143 use crate::marker::PhantomData;
c30ab7b3
SL
144 use super::Args;
145
146 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
147 }
148
149 pub fn cleanup() {
150 }
151
152 #[cfg(target_os = "macos")]
153 pub fn args() -> Args {
532ac7d7 154 use crate::os::unix::prelude::*;
c30ab7b3
SL
155 extern {
156 // These functions are in crt_externs.h.
157 fn _NSGetArgc() -> *mut libc::c_int;
158 fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
159 }
160
161 let vec = unsafe {
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<_>>()
168 };
169 Args {
170 iter: vec.into_iter(),
171 _dont_send_or_sync_me: PhantomData,
172 }
173 }
174
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
179 // runtime
180 //
181 // In general it looks like:
182 // res = Vec::new()
183 // let args = [[NSProcessInfo processInfo] arguments]
184 // for i in (0..[args count])
185 // res.push([args objectAtIndex:i])
186 // res
187 #[cfg(target_os = "ios")]
188 pub fn args() -> Args {
532ac7d7
XL
189 use crate::ffi::OsString;
190 use crate::mem;
191 use crate::str;
c30ab7b3
SL
192
193 extern {
194 fn sel_registerName(name: *const libc::c_uchar) -> Sel;
c30ab7b3
SL
195 fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
196 }
197
476ff2be
SL
198 #[cfg(target_arch="aarch64")]
199 extern {
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;
203 }
204
205 #[cfg(not(target_arch="aarch64"))]
206 extern {
207 fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
208 #[link_name="objc_msgSend"]
209 fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
210 }
211
c30ab7b3
SL
212 type Sel = *const libc::c_void;
213 type NsId = *const libc::c_void;
214
215 let mut res = Vec::new();
216
217 unsafe {
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());
223
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);
227
228 let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
229 for i in 0..cnt {
476ff2be 230 let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
c30ab7b3
SL
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()))
235 }
236 }
237
238 Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
239 }
240}