]> git.lizzy.rs Git - rust.git/blob - src/librustrt/args.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / librustrt / args.rs
1 // Copyright 2012-2013 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 storage for command line arguments
12 //!
13 //! The current incarnation of the Rust runtime expects for
14 //! the processes `argc` and `argv` arguments to be stored
15 //! in a globally-accessible location for use by the `os` module.
16 //!
17 //! Only valid to call on linux. Mac and Windows use syscalls to
18 //! discover the command line arguments.
19 //!
20 //! FIXME #7756: Would be nice for this to not exist.
21
22 use core::prelude::*;
23 use collections::vec::Vec;
24
25 /// One-time global initialization.
26 pub unsafe fn init(argc: int, argv: *const *const u8) { imp::init(argc, argv) }
27
28 /// One-time global cleanup.
29 pub unsafe fn cleanup() { imp::cleanup() }
30
31 /// Take the global arguments from global storage.
32 pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
33
34 /// Give the global arguments to global storage.
35 ///
36 /// It is an error if the arguments already exist.
37 pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
38
39 /// Make a clone of the global arguments.
40 pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
41
42 #[cfg(target_os = "linux")]
43 #[cfg(target_os = "android")]
44 #[cfg(target_os = "freebsd")]
45 #[cfg(target_os = "dragonfly")]
46 mod imp {
47     use core::prelude::*;
48
49     use alloc::boxed::Box;
50     use collections::vec::Vec;
51     use core::mem;
52     use core::slice;
53
54     use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
55
56     static mut global_args_ptr: uint = 0;
57     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
58
59     pub unsafe fn init(argc: int, argv: *const *const u8) {
60         let args = load_argc_and_argv(argc, argv);
61         put(args);
62     }
63
64     pub unsafe fn cleanup() {
65         rtassert!(take().is_some());
66         lock.destroy();
67     }
68
69     pub fn take() -> Option<Vec<Vec<u8>>> {
70         with_lock(|| unsafe {
71             let ptr = get_global_ptr();
72             let val = mem::replace(&mut *ptr, None);
73             val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
74         })
75     }
76
77     pub fn put(args: Vec<Vec<u8>>) {
78         with_lock(|| unsafe {
79             let ptr = get_global_ptr();
80             rtassert!((*ptr).is_none());
81             (*ptr) = Some(box args.clone());
82         })
83     }
84
85     pub fn clone() -> Option<Vec<Vec<u8>>> {
86         with_lock(|| unsafe {
87             let ptr = get_global_ptr();
88             (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
89         })
90     }
91
92     fn with_lock<T>(f: || -> T) -> T {
93         unsafe {
94             let _guard = lock.lock();
95             f()
96         }
97     }
98
99     fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
100         unsafe { mem::transmute(&global_args_ptr) }
101     }
102
103     unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec<Vec<u8>> {
104         Vec::from_fn(argc as uint, |i| {
105             let base = *argv.offset(i as int);
106             let mut len = 0;
107             while *base.offset(len) != 0 { len += 1; }
108             slice::raw::buf_as_slice(base, len as uint, |slice| {
109                 Vec::from_slice(slice)
110             })
111         })
112     }
113
114     #[cfg(test)]
115     mod tests {
116         use std::prelude::*;
117         use std::finally::Finally;
118
119         use super::*;
120
121         #[test]
122         fn smoke_test() {
123             // Preserve the actual global state.
124             let saved_value = take();
125
126             let expected = vec![
127                 Vec::from_slice(b"happy"),
128                 Vec::from_slice(b"today?"),
129             ];
130
131             put(expected.clone());
132             assert!(clone() == Some(expected.clone()));
133             assert!(take() == Some(expected.clone()));
134             assert!(take() == None);
135
136             (|| {
137             }).finally(|| {
138                 // Restore the actual global state.
139                 match saved_value {
140                     Some(ref args) => put(args.clone()),
141                     None => ()
142                 }
143             })
144         }
145     }
146 }
147
148 #[cfg(target_os = "macos")]
149 #[cfg(target_os = "ios")]
150 #[cfg(target_os = "win32")]
151 mod imp {
152     use core::prelude::*;
153     use collections::vec::Vec;
154
155     pub unsafe fn init(_argc: int, _argv: *const *const u8) {
156     }
157
158     pub fn cleanup() {
159     }
160
161     pub fn take() -> Option<Vec<Vec<u8>>> {
162         fail!()
163     }
164
165     pub fn put(_args: Vec<Vec<u8>>) {
166         fail!()
167     }
168
169     pub fn clone() -> Option<Vec<Vec<u8>>> {
170         fail!()
171     }
172 }