Skip to content

Commit 4d76ac8

Browse files
committed
Move platform-specific arg handling to sys::args
1 parent 29e0235 commit 4d76ac8

File tree

11 files changed

+294
-282
lines changed

11 files changed

+294
-282
lines changed

src/libstd/env.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use ffi::{OsStr, OsString};
2121
use fmt;
2222
use io;
2323
use path::{Path, PathBuf};
24+
use sys;
2425
use sys::os as os_imp;
2526

2627
/// Returns the current working directory as a `PathBuf`.
@@ -557,7 +558,7 @@ pub struct Args { inner: ArgsOs }
557558
///
558559
/// This structure is created through the `std::env::args_os` method.
559560
#[stable(feature = "env", since = "1.0.0")]
560-
pub struct ArgsOs { inner: os_imp::Args }
561+
pub struct ArgsOs { inner: sys::args::Args }
561562

562563
/// Returns the arguments which this program was started with (normally passed
563564
/// via the command line).
@@ -606,7 +607,7 @@ pub fn args() -> Args {
606607
/// ```
607608
#[stable(feature = "env", since = "1.0.0")]
608609
pub fn args_os() -> ArgsOs {
609-
ArgsOs { inner: os_imp::args() }
610+
ArgsOs { inner: sys::args::args() }
610611
}
611612

612613
#[stable(feature = "env", since = "1.0.0")]

src/libstd/rt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
5151
thread_info::set(main_guard, thread);
5252

5353
// Store our args if necessary in a squirreled away location
54-
sys_common::args::init(argc, argv);
54+
sys::args::init(argc, argv);
5555

5656
// Let's run some code!
5757
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));

src/libstd/sys/common/args.rs

-100
This file was deleted.

src/libstd/sys/common/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ macro_rules! rtassert {
2525
})
2626
}
2727

28-
pub mod args;
2928
pub mod at_exit_imp;
3029
#[cfg(any(not(cargobuild), feature = "backtrace"))]
3130
pub mod backtrace;
@@ -92,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
9291
pub fn cleanup() {
9392
static CLEANUP: Once = Once::new();
9493
CLEANUP.call_once(|| unsafe {
95-
args::cleanup();
94+
sys::args::cleanup();
9695
sys::stack_overflow::cleanup();
9796
at_exit_imp::cleanup();
9897
});

src/libstd/sys/unix/args.rs

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
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+
mod imp {
63+
use os::unix::prelude::*;
64+
use mem;
65+
use ffi::{CStr, OsString};
66+
use marker::PhantomData;
67+
use libc;
68+
use super::Args;
69+
70+
use sys_common::mutex::Mutex;
71+
72+
static mut GLOBAL_ARGS_PTR: usize = 0;
73+
static LOCK: Mutex = Mutex::new();
74+
75+
pub unsafe fn init(argc: isize, argv: *const *const u8) {
76+
let args = (0..argc).map(|i| {
77+
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
78+
}).collect();
79+
80+
LOCK.lock();
81+
let ptr = get_global_ptr();
82+
assert!((*ptr).is_none());
83+
(*ptr) = Some(box args);
84+
LOCK.unlock();
85+
}
86+
87+
pub unsafe fn cleanup() {
88+
LOCK.lock();
89+
*get_global_ptr() = None;
90+
LOCK.unlock();
91+
}
92+
93+
pub fn args() -> Args {
94+
let bytes = clone().unwrap_or(Vec::new());
95+
let v: Vec<OsString> = bytes.into_iter().map(|v| {
96+
OsStringExt::from_vec(v)
97+
}).collect();
98+
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
99+
}
100+
101+
fn clone() -> Option<Vec<Vec<u8>>> {
102+
unsafe {
103+
LOCK.lock();
104+
let ptr = get_global_ptr();
105+
let ret = (*ptr).as_ref().map(|s| (**s).clone());
106+
LOCK.unlock();
107+
return ret
108+
}
109+
}
110+
111+
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
112+
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
113+
}
114+
115+
}
116+
117+
#[cfg(any(target_os = "macos",
118+
target_os = "ios"))]
119+
mod imp {
120+
use ffi::CStr;
121+
use marker::PhantomData;
122+
use libc;
123+
use super::Args;
124+
125+
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
126+
}
127+
128+
pub fn cleanup() {
129+
}
130+
131+
#[cfg(target_os = "macos")]
132+
pub fn args() -> Args {
133+
use os::unix::prelude::*;
134+
extern {
135+
// These functions are in crt_externs.h.
136+
fn _NSGetArgc() -> *mut libc::c_int;
137+
fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
138+
}
139+
140+
let vec = unsafe {
141+
let (argc, argv) = (*_NSGetArgc() as isize,
142+
*_NSGetArgv() as *const *const libc::c_char);
143+
(0.. argc as isize).map(|i| {
144+
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
145+
OsStringExt::from_vec(bytes)
146+
}).collect::<Vec<_>>()
147+
};
148+
Args {
149+
iter: vec.into_iter(),
150+
_dont_send_or_sync_me: PhantomData,
151+
}
152+
}
153+
154+
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
155+
// and use underscores in their names - they're most probably
156+
// are considered private and therefore should be avoided
157+
// Here is another way to get arguments using Objective C
158+
// runtime
159+
//
160+
// In general it looks like:
161+
// res = Vec::new()
162+
// let args = [[NSProcessInfo processInfo] arguments]
163+
// for i in (0..[args count])
164+
// res.push([args objectAtIndex:i])
165+
// res
166+
#[cfg(target_os = "ios")]
167+
pub fn args() -> Args {
168+
use ffi::OsString;
169+
use mem;
170+
use str;
171+
172+
extern {
173+
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
174+
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
175+
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
176+
}
177+
178+
#[link(name = "Foundation", kind = "framework")]
179+
#[link(name = "objc")]
180+
#[cfg(not(cargobuild))]
181+
extern {}
182+
183+
type Sel = *const libc::c_void;
184+
type NsId = *const libc::c_void;
185+
186+
let mut res = Vec::new();
187+
188+
unsafe {
189+
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
190+
let arguments_sel = sel_registerName("arguments\0".as_ptr());
191+
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
192+
let count_sel = sel_registerName("count\0".as_ptr());
193+
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
194+
195+
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
196+
let info = objc_msgSend(klass, process_info_sel);
197+
let args = objc_msgSend(info, arguments_sel);
198+
199+
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
200+
for i in 0..cnt {
201+
let tmp = objc_msgSend(args, object_at_sel, i);
202+
let utf_c_str: *const libc::c_char =
203+
mem::transmute(objc_msgSend(tmp, utf8_sel));
204+
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
205+
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
206+
}
207+
}
208+
209+
Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
210+
}
211+
}

src/libstd/sys/unix/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use libc;
3030
#[macro_use]
3131
pub mod weak;
3232

33+
pub mod args;
3334
pub mod android;
3435
#[cfg(any(not(cargobuild), feature = "backtrace"))]
3536
pub mod backtrace;

0 commit comments

Comments
 (0)