]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/args.rs
New upstream version 1.21.0+dfsg1
[rustc.git] / src / libstd / sys / unix / args.rs
CommitLineData
c30ab7b3
SL
1// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
3b2f2976 11//! Global initialization and retrieval of command line arguments.
c30ab7b3
SL
12//!
13//! On some platforms these are stored during runtime startup,
14//! and on some they are retrieved from the system on demand.
15
16#![allow(dead_code)] // runtime init functions not used during testing
17
18use ffi::OsString;
19use marker::PhantomData;
20use vec;
21
22/// One-time global initialization.
23pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
24
25/// One-time global cleanup.
26pub unsafe fn cleanup() { imp::cleanup() }
27
28/// Returns the command line arguments
29pub fn args() -> Args {
30 imp::args()
31}
32
33pub struct Args {
34 iter: vec::IntoIter<OsString>,
35 _dont_send_or_sync_me: PhantomData<*mut ()>,
36}
37
041b39d2
XL
38impl Args {
39 pub fn inner_debug(&self) -> &[OsString] {
40 self.iter.as_slice()
41 }
42}
43
c30ab7b3
SL
44impl Iterator for Args {
45 type Item = OsString;
46 fn next(&mut self) -> Option<OsString> { self.iter.next() }
47 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
48}
49
50impl ExactSizeIterator for Args {
51 fn len(&self) -> usize { self.iter.len() }
52}
53
54impl DoubleEndedIterator for Args {
55 fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
56}
57
58#[cfg(any(target_os = "linux",
59 target_os = "android",
60 target_os = "freebsd",
61 target_os = "dragonfly",
62 target_os = "bitrig",
63 target_os = "netbsd",
64 target_os = "openbsd",
65 target_os = "solaris",
66 target_os = "emscripten",
67 target_os = "haiku",
68 target_os = "fuchsia"))]
69mod imp {
70 use os::unix::prelude::*;
71 use mem;
72 use ffi::{CStr, OsString};
73 use marker::PhantomData;
74 use libc;
75 use super::Args;
76
77 use sys_common::mutex::Mutex;
78
79 static mut GLOBAL_ARGS_PTR: usize = 0;
80 static LOCK: Mutex = Mutex::new();
81
82 pub unsafe fn init(argc: isize, argv: *const *const u8) {
83 let args = (0..argc).map(|i| {
84 CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
85 }).collect();
86
87 LOCK.lock();
88 let ptr = get_global_ptr();
89 assert!((*ptr).is_none());
90 (*ptr) = Some(box args);
91 LOCK.unlock();
92 }
93
94 pub unsafe fn cleanup() {
95 LOCK.lock();
96 *get_global_ptr() = None;
97 LOCK.unlock();
98 }
99
100 pub fn args() -> Args {
101 let bytes = clone().unwrap_or(Vec::new());
102 let v: Vec<OsString> = bytes.into_iter().map(|v| {
103 OsStringExt::from_vec(v)
104 }).collect();
105 Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
106 }
107
108 fn clone() -> Option<Vec<Vec<u8>>> {
109 unsafe {
110 LOCK.lock();
111 let ptr = get_global_ptr();
112 let ret = (*ptr).as_ref().map(|s| (**s).clone());
113 LOCK.unlock();
114 return ret
115 }
116 }
117
118 fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
119 unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
120 }
121
122}
123
124#[cfg(any(target_os = "macos",
125 target_os = "ios"))]
126mod imp {
127 use ffi::CStr;
128 use marker::PhantomData;
129 use libc;
130 use super::Args;
131
132 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
133 }
134
135 pub fn cleanup() {
136 }
137
138 #[cfg(target_os = "macos")]
139 pub fn args() -> Args {
140 use os::unix::prelude::*;
141 extern {
142 // These functions are in crt_externs.h.
143 fn _NSGetArgc() -> *mut libc::c_int;
144 fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
145 }
146
147 let vec = unsafe {
148 let (argc, argv) = (*_NSGetArgc() as isize,
149 *_NSGetArgv() as *const *const libc::c_char);
150 (0.. argc as isize).map(|i| {
151 let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
152 OsStringExt::from_vec(bytes)
153 }).collect::<Vec<_>>()
154 };
155 Args {
156 iter: vec.into_iter(),
157 _dont_send_or_sync_me: PhantomData,
158 }
159 }
160
161 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
162 // and use underscores in their names - they're most probably
163 // are considered private and therefore should be avoided
164 // Here is another way to get arguments using Objective C
165 // runtime
166 //
167 // In general it looks like:
168 // res = Vec::new()
169 // let args = [[NSProcessInfo processInfo] arguments]
170 // for i in (0..[args count])
171 // res.push([args objectAtIndex:i])
172 // res
173 #[cfg(target_os = "ios")]
174 pub fn args() -> Args {
175 use ffi::OsString;
176 use mem;
177 use str;
178
179 extern {
180 fn sel_registerName(name: *const libc::c_uchar) -> Sel;
c30ab7b3
SL
181 fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
182 }
183
476ff2be
SL
184 #[cfg(target_arch="aarch64")]
185 extern {
186 fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
187 #[link_name="objc_msgSend"]
188 fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
189 }
190
191 #[cfg(not(target_arch="aarch64"))]
192 extern {
193 fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
194 #[link_name="objc_msgSend"]
195 fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
196 }
197
c30ab7b3
SL
198 type Sel = *const libc::c_void;
199 type NsId = *const libc::c_void;
200
201 let mut res = Vec::new();
202
203 unsafe {
204 let process_info_sel = sel_registerName("processInfo\0".as_ptr());
205 let arguments_sel = sel_registerName("arguments\0".as_ptr());
206 let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
207 let count_sel = sel_registerName("count\0".as_ptr());
208 let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
209
210 let klass = objc_getClass("NSProcessInfo\0".as_ptr());
211 let info = objc_msgSend(klass, process_info_sel);
212 let args = objc_msgSend(info, arguments_sel);
213
214 let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
215 for i in 0..cnt {
476ff2be 216 let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
c30ab7b3
SL
217 let utf_c_str: *const libc::c_char =
218 mem::transmute(objc_msgSend(tmp, utf8_sel));
219 let bytes = CStr::from_ptr(utf_c_str).to_bytes();
220 res.push(OsString::from(str::from_utf8(bytes).unwrap()))
221 }
222 }
223
224 Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
225 }
226}