]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/args.rs
Unignore u128 test for stage 0,1
[rust.git] / src / libstd / sys / unix / args.rs
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
11 //! Global initialization and retreival of command line arguments.
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
18 use ffi::OsString;
19 use marker::PhantomData;
20 use vec;
21
22 /// One-time global initialization.
23 pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
24
25 /// One-time global cleanup.
26 pub unsafe fn cleanup() { imp::cleanup() }
27
28 /// Returns the command line arguments
29 pub fn args() -> Args {
30     imp::args()
31 }
32
33 pub struct Args {
34     iter: vec::IntoIter<OsString>,
35     _dont_send_or_sync_me: PhantomData<*mut ()>,
36 }
37
38 impl Iterator for Args {
39     type Item = OsString;
40     fn next(&mut self) -> Option<OsString> { self.iter.next() }
41     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
42 }
43
44 impl ExactSizeIterator for Args {
45     fn len(&self) -> usize { self.iter.len() }
46 }
47
48 impl DoubleEndedIterator for Args {
49     fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
50 }
51
52 #[cfg(any(target_os = "linux",
53           target_os = "android",
54           target_os = "freebsd",
55           target_os = "dragonfly",
56           target_os = "bitrig",
57           target_os = "netbsd",
58           target_os = "openbsd",
59           target_os = "solaris",
60           target_os = "emscripten",
61           target_os = "haiku",
62           target_os = "fuchsia"))]
63 mod imp {
64     use os::unix::prelude::*;
65     use mem;
66     use ffi::{CStr, OsString};
67     use marker::PhantomData;
68     use libc;
69     use super::Args;
70
71     use sys_common::mutex::Mutex;
72
73     static mut GLOBAL_ARGS_PTR: usize = 0;
74     static LOCK: Mutex = Mutex::new();
75
76     pub unsafe fn init(argc: isize, argv: *const *const u8) {
77         let args = (0..argc).map(|i| {
78             CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
79         }).collect();
80
81         LOCK.lock();
82         let ptr = get_global_ptr();
83         assert!((*ptr).is_none());
84         (*ptr) = Some(box args);
85         LOCK.unlock();
86     }
87
88     pub unsafe fn cleanup() {
89         LOCK.lock();
90         *get_global_ptr() = None;
91         LOCK.unlock();
92     }
93
94     pub fn args() -> Args {
95         let bytes = clone().unwrap_or(Vec::new());
96         let v: Vec<OsString> = bytes.into_iter().map(|v| {
97             OsStringExt::from_vec(v)
98         }).collect();
99         Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
100     }
101
102     fn clone() -> Option<Vec<Vec<u8>>> {
103         unsafe {
104             LOCK.lock();
105             let ptr = get_global_ptr();
106             let ret = (*ptr).as_ref().map(|s| (**s).clone());
107             LOCK.unlock();
108             return ret
109         }
110     }
111
112     fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
113         unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
114     }
115
116 }
117
118 #[cfg(any(target_os = "macos",
119           target_os = "ios"))]
120 mod imp {
121     use ffi::CStr;
122     use marker::PhantomData;
123     use libc;
124     use super::Args;
125
126     pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
127     }
128
129     pub fn cleanup() {
130     }
131
132     #[cfg(target_os = "macos")]
133     pub fn args() -> Args {
134         use os::unix::prelude::*;
135         extern {
136             // These functions are in crt_externs.h.
137             fn _NSGetArgc() -> *mut libc::c_int;
138             fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
139         }
140
141         let vec = unsafe {
142             let (argc, argv) = (*_NSGetArgc() as isize,
143                                 *_NSGetArgv() as *const *const libc::c_char);
144             (0.. argc as isize).map(|i| {
145                 let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
146                 OsStringExt::from_vec(bytes)
147             }).collect::<Vec<_>>()
148         };
149         Args {
150             iter: vec.into_iter(),
151             _dont_send_or_sync_me: PhantomData,
152         }
153     }
154
155     // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
156     // and use underscores in their names - they're most probably
157     // are considered private and therefore should be avoided
158     // Here is another way to get arguments using Objective C
159     // runtime
160     //
161     // In general it looks like:
162     // res = Vec::new()
163     // let args = [[NSProcessInfo processInfo] arguments]
164     // for i in (0..[args count])
165     //      res.push([args objectAtIndex:i])
166     // res
167     #[cfg(target_os = "ios")]
168     pub fn args() -> Args {
169         use ffi::OsString;
170         use mem;
171         use str;
172
173         extern {
174             fn sel_registerName(name: *const libc::c_uchar) -> Sel;
175             fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
176         }
177
178         #[cfg(target_arch="aarch64")]
179         extern {
180             fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
181             #[link_name="objc_msgSend"]
182             fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
183         }
184
185         #[cfg(not(target_arch="aarch64"))]
186         extern {
187             fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
188             #[link_name="objc_msgSend"]
189             fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
190         }
191
192         #[link(name = "Foundation", kind = "framework")]
193         #[link(name = "objc")]
194         #[cfg(not(cargobuild))]
195         extern {}
196
197         type Sel = *const libc::c_void;
198         type NsId = *const libc::c_void;
199
200         let mut res = Vec::new();
201
202         unsafe {
203             let process_info_sel = sel_registerName("processInfo\0".as_ptr());
204             let arguments_sel = sel_registerName("arguments\0".as_ptr());
205             let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
206             let count_sel = sel_registerName("count\0".as_ptr());
207             let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
208
209             let klass = objc_getClass("NSProcessInfo\0".as_ptr());
210             let info = objc_msgSend(klass, process_info_sel);
211             let args = objc_msgSend(info, arguments_sel);
212
213             let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
214             for i in 0..cnt {
215                 let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
216                 let utf_c_str: *const libc::c_char =
217                     mem::transmute(objc_msgSend(tmp, utf8_sel));
218                 let bytes = CStr::from_ptr(utf_c_str).to_bytes();
219                 res.push(OsString::from(str::from_utf8(bytes).unwrap()))
220             }
221         }
222
223         Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
224     }
225 }