]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys/unix/args.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / library / std / src / 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 8use crate::ffi::OsString;
cdc7bbd5 9use crate::fmt;
532ac7d7 10use crate::vec;
c30ab7b3
SL
11
12/// One-time global initialization.
dfeec247
XL
13pub unsafe fn init(argc: isize, argv: *const *const u8) {
14 imp::init(argc, argv)
15}
c30ab7b3 16
c30ab7b3
SL
17/// Returns the command line arguments
18pub fn args() -> Args {
19 imp::args()
20}
21
22pub struct Args {
23 iter: vec::IntoIter<OsString>,
c30ab7b3
SL
24}
25
cdc7bbd5
XL
26impl !Send for Args {}
27impl !Sync for Args {}
28
29impl fmt::Debug for Args {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 self.iter.as_slice().fmt(f)
041b39d2
XL
32 }
33}
34
c30ab7b3
SL
35impl Iterator for Args {
36 type Item = OsString;
dfeec247
XL
37 fn next(&mut self) -> Option<OsString> {
38 self.iter.next()
39 }
40 fn size_hint(&self) -> (usize, Option<usize>) {
41 self.iter.size_hint()
42 }
c30ab7b3
SL
43}
44
45impl ExactSizeIterator for Args {
dfeec247
XL
46 fn len(&self) -> usize {
47 self.iter.len()
48 }
c30ab7b3
SL
49}
50
51impl DoubleEndedIterator for Args {
dfeec247
XL
52 fn next_back(&mut self) -> Option<OsString> {
53 self.iter.next_back()
54 }
c30ab7b3
SL
55}
56
dfeec247
XL
57#[cfg(any(
58 target_os = "linux",
59 target_os = "android",
60 target_os = "freebsd",
61 target_os = "dragonfly",
62 target_os = "netbsd",
63 target_os = "openbsd",
64 target_os = "solaris",
ba9703b0 65 target_os = "illumos",
dfeec247
XL
66 target_os = "emscripten",
67 target_os = "haiku",
68 target_os = "l4re",
69 target_os = "fuchsia",
29967ef6 70 target_os = "redox",
923072b8
FG
71 target_os = "vxworks",
72 target_os = "horizon"
dfeec247 73))]
c30ab7b3 74mod imp {
dfeec247 75 use super::Args;
532ac7d7 76 use crate::ffi::{CStr, OsString};
dfeec247
XL
77 use crate::os::unix::prelude::*;
78 use crate::ptr;
f035d41b 79 use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
c30ab7b3 80
136023e0
XL
81 // The system-provided argc and argv, which we store in static memory
82 // here so that we can defer the work of parsing them until its actually
83 // needed.
84 //
85 // Note that we never mutate argv/argc, the argv array, or the argv
86 // strings, which allows the code in this file to be very simple.
f035d41b
XL
87 static ARGC: AtomicIsize = AtomicIsize::new(0);
88 static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
c30ab7b3 89
60c5eb7d 90 unsafe fn really_init(argc: isize, argv: *const *const u8) {
136023e0
XL
91 // These don't need to be ordered with each other or other stores,
92 // because they only hold the unmodified system-provide argv/argc.
f035d41b
XL
93 ARGC.store(argc, Ordering::Relaxed);
94 ARGV.store(argv as *mut _, Ordering::Relaxed);
c30ab7b3
SL
95 }
96
60c5eb7d
XL
97 #[inline(always)]
98 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
99 // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
100 // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
101 // still initialize here.
dfeec247 102 #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
60c5eb7d
XL
103 really_init(_argc, _argv);
104 }
105
106 /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
107 /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
108 #[cfg(all(target_os = "linux", target_env = "gnu"))]
109 #[used]
110 #[link_section = ".init_array.00099"]
111 static ARGV_INIT_ARRAY: extern "C" fn(
112 crate::os::raw::c_int,
113 *const *const u8,
114 *const *const u8,
115 ) = {
116 extern "C" fn init_wrapper(
117 argc: crate::os::raw::c_int,
118 argv: *const *const u8,
119 _envp: *const *const u8,
120 ) {
121 unsafe {
122 really_init(argc as isize, argv);
123 }
124 }
125 init_wrapper
126 };
127
c30ab7b3 128 pub fn args() -> Args {
cdc7bbd5 129 Args { iter: clone().into_iter() }
c30ab7b3
SL
130 }
131
2c00a5a8 132 fn clone() -> Vec<OsString> {
c30ab7b3 133 unsafe {
136023e0
XL
134 // Load ARGC and ARGV, which hold the unmodified system-provided
135 // argc/argv, so we can read the pointed-to memory without atomics
136 // or synchronization.
137 //
138 // If either ARGC or ARGV is still zero or null, then either there
139 // really are no arguments, or someone is asking for `args()`
140 // before initialization has completed, and we return an empty
141 // list.
f035d41b 142 let argv = ARGV.load(Ordering::Relaxed);
136023e0 143 let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
f035d41b 144 (0..argc)
dfeec247 145 .map(|i| {
f035d41b 146 let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
dfeec247
XL
147 OsStringExt::from_vec(cstr.to_bytes().to_vec())
148 })
149 .collect()
c30ab7b3
SL
150 }
151 }
c30ab7b3
SL
152}
153
064997fb 154#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
c30ab7b3 155mod imp {
dfeec247 156 use super::Args;
532ac7d7 157 use crate::ffi::CStr;
c30ab7b3 158
dfeec247 159 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
c30ab7b3 160
c30ab7b3
SL
161 #[cfg(target_os = "macos")]
162 pub fn args() -> Args {
532ac7d7 163 use crate::os::unix::prelude::*;
dfeec247 164 extern "C" {
c30ab7b3
SL
165 // These functions are in crt_externs.h.
166 fn _NSGetArgc() -> *mut libc::c_int;
167 fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
168 }
169
170 let vec = unsafe {
dfeec247
XL
171 let (argc, argv) =
172 (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
173 (0..argc as isize)
174 .map(|i| {
175 let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
176 OsStringExt::from_vec(bytes)
177 })
178 .collect::<Vec<_>>()
c30ab7b3 179 };
cdc7bbd5 180 Args { iter: vec.into_iter() }
c30ab7b3
SL
181 }
182
183 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
184 // and use underscores in their names - they're most probably
185 // are considered private and therefore should be avoided
186 // Here is another way to get arguments using Objective C
187 // runtime
188 //
189 // In general it looks like:
190 // res = Vec::new()
191 // let args = [[NSProcessInfo processInfo] arguments]
192 // for i in (0..[args count])
193 // res.push([args objectAtIndex:i])
194 // res
064997fb 195 #[cfg(any(target_os = "ios", target_os = "watchos"))]
c30ab7b3 196 pub fn args() -> Args {
532ac7d7
XL
197 use crate::ffi::OsString;
198 use crate::mem;
199 use crate::str;
c30ab7b3 200
dfeec247 201 extern "C" {
c30ab7b3 202 fn sel_registerName(name: *const libc::c_uchar) -> Sel;
c30ab7b3
SL
203 fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
204 }
205
dfeec247
XL
206 #[cfg(target_arch = "aarch64")]
207 extern "C" {
476ff2be 208 fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
3dfed10e 209 #[allow(clashing_extern_declarations)]
dfeec247 210 #[link_name = "objc_msgSend"]
476ff2be
SL
211 fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
212 }
213
dfeec247
XL
214 #[cfg(not(target_arch = "aarch64"))]
215 extern "C" {
476ff2be 216 fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
3dfed10e 217 #[allow(clashing_extern_declarations)]
dfeec247 218 #[link_name = "objc_msgSend"]
476ff2be
SL
219 fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
220 }
221
c30ab7b3
SL
222 type Sel = *const libc::c_void;
223 type NsId = *const libc::c_void;
224
225 let mut res = Vec::new();
226
227 unsafe {
228 let process_info_sel = sel_registerName("processInfo\0".as_ptr());
229 let arguments_sel = sel_registerName("arguments\0".as_ptr());
230 let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
231 let count_sel = sel_registerName("count\0".as_ptr());
232 let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
233
234 let klass = objc_getClass("NSProcessInfo\0".as_ptr());
235 let info = objc_msgSend(klass, process_info_sel);
236 let args = objc_msgSend(info, arguments_sel);
237
238 let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
239 for i in 0..cnt {
476ff2be 240 let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
dfeec247 241 let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
c30ab7b3
SL
242 let bytes = CStr::from_ptr(utf_c_str).to_bytes();
243 res.push(OsString::from(str::from_utf8(bytes).unwrap()))
244 }
245 }
246
cdc7bbd5 247 Args { iter: res.into_iter() }
c30ab7b3
SL
248 }
249}
94222f64
XL
250
251#[cfg(target_os = "espidf")]
252mod imp {
253 use super::Args;
254
255 #[inline(always)]
256 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
257
258 pub fn args() -> Args {
259 Args { iter: Vec::new().into_iter() }
260 }
261}