]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/args.rs
cde20521c2f66bda09b1486bfa368ffa9f338da1
[rust.git] / src / libstd / rt / 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 //! FIXME #7756: This has a lot of C glue for lack of globals.
22
23 use option::Option;
24 use vec::Vec;
25 #[cfg(test)] use option::{Some, None};
26 #[cfg(test)] use realstd;
27 #[cfg(test)] use realargs = realstd::rt::args;
28
29 /// One-time global initialization.
30 #[cfg(not(test))]
31 pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) }
32 #[cfg(test)]
33 pub unsafe fn init(argc: int, argv: **u8) { realargs::init(argc, argv) }
34
35 /// One-time global cleanup.
36 #[cfg(not(test))] pub unsafe fn cleanup() { imp::cleanup() }
37 #[cfg(test)]      pub unsafe fn cleanup() { realargs::cleanup() }
38
39 /// Take the global arguments from global storage.
40 #[cfg(not(test))] pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
41 #[cfg(test)]      pub fn take() -> Option<Vec<Vec<u8>>> {
42     match realargs::take() {
43         realstd::option::Some(v) => Some(unsafe{ ::mem::transmute(v) }),
44         realstd::option::None => None,
45     }
46 }
47
48 /// Give the global arguments to global storage.
49 ///
50 /// It is an error if the arguments already exist.
51 #[cfg(not(test))] pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
52 #[cfg(test)]      pub fn put(args: Vec<Vec<u8>>) {
53     realargs::put(unsafe {
54         ::mem::transmute(args)
55     })
56 }
57
58 /// Make a clone of the global arguments.
59 #[cfg(not(test))] pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
60 #[cfg(test)]      pub fn clone() -> Option<Vec<Vec<u8>>> {
61     match realargs::clone() {
62         realstd::option::Some(v) => Some(unsafe { ::mem::transmute(v) }),
63         realstd::option::None => None,
64     }
65 }
66
67 #[cfg(target_os = "linux")]
68 #[cfg(target_os = "android")]
69 #[cfg(target_os = "freebsd")]
70 mod imp {
71     use clone::Clone;
72     use iter::Iterator;
73     use option::{Option, Some, None};
74     use owned::Box;
75     use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
76     use mem;
77     use vec::Vec;
78     #[cfg(not(test))] use ptr::RawPtr;
79
80     static mut global_args_ptr: uint = 0;
81     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
82
83     #[cfg(not(test))]
84     pub unsafe fn init(argc: int, argv: **u8) {
85         let args = load_argc_and_argv(argc, argv);
86         put(args);
87     }
88
89     #[cfg(not(test))]
90     pub unsafe fn cleanup() {
91         rtassert!(take().is_some());
92         lock.destroy();
93     }
94
95     pub fn take() -> Option<Vec<Vec<u8>>> {
96         with_lock(|| unsafe {
97             let ptr = get_global_ptr();
98             let val = mem::replace(&mut *ptr, None);
99             val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
100         })
101     }
102
103     pub fn put(args: Vec<Vec<u8>>) {
104         with_lock(|| unsafe {
105             let ptr = get_global_ptr();
106             rtassert!((*ptr).is_none());
107             (*ptr) = Some(box args.clone());
108         })
109     }
110
111     pub fn clone() -> Option<Vec<Vec<u8>>> {
112         with_lock(|| unsafe {
113             let ptr = get_global_ptr();
114             (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
115         })
116     }
117
118     fn with_lock<T>(f: || -> T) -> T {
119         unsafe {
120             let _guard = lock.lock();
121             f()
122         }
123     }
124
125     fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
126         unsafe { mem::transmute(&global_args_ptr) }
127     }
128
129     // Copied from `os`.
130     #[cfg(not(test))]
131     unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> Vec<Vec<u8>> {
132         use c_str::CString;
133         use ptr::RawPtr;
134         use libc;
135         use vec::Vec;
136
137         Vec::from_fn(argc as uint, |i| {
138             let cs = CString::new(*(argv as **libc::c_char).offset(i as int), false);
139             Vec::from_slice(cs.as_bytes_no_nul())
140         })
141     }
142
143     #[cfg(test)]
144     mod tests {
145         use prelude::*;
146         use super::*;
147         use unstable::finally::Finally;
148
149         #[test]
150         fn smoke_test() {
151             // Preserve the actual global state.
152             let saved_value = take();
153
154             let expected = vec![
155                 Vec::from_slice(bytes!("happy")),
156                 Vec::from_slice(bytes!("today?")),
157             ];
158
159             put(expected.clone());
160             assert!(clone() == Some(expected.clone()));
161             assert!(take() == Some(expected.clone()));
162             assert!(take() == None);
163
164             (|| {
165             }).finally(|| {
166                 // Restore the actual global state.
167                 match saved_value {
168                     Some(ref args) => put(args.clone()),
169                     None => ()
170                 }
171             })
172         }
173     }
174 }
175
176 #[cfg(target_os = "macos", not(test))]
177 #[cfg(target_os = "win32", not(test))]
178 mod imp {
179     use option::Option;
180     use vec::Vec;
181
182     pub unsafe fn init(_argc: int, _argv: **u8) {
183     }
184
185     pub fn cleanup() {
186     }
187
188     pub fn take() -> Option<Vec<Vec<u8>>> {
189         fail!()
190     }
191
192     pub fn put(_args: Vec<Vec<u8>>) {
193         fail!()
194     }
195
196     pub fn clone() -> Option<Vec<Vec<u8>>> {
197         fail!()
198     }
199 }