]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/args.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[rust.git] / src / libstd / rt / 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 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 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(any(target_os = "linux",
43           target_os = "android",
44           target_os = "freebsd",
45           target_os = "dragonfly",
46           target_os = "openbsd"))]
47 mod imp {
48     use prelude::v1::*;
49
50     use libc;
51     use mem;
52     use ffi::CStr;
53
54     use sync::{StaticMutex, MUTEX_INIT};
55
56     static mut GLOBAL_ARGS_PTR: uint = 0;
57     static LOCK: StaticMutex = 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         take();
66         LOCK.destroy();
67     }
68
69     pub fn take() -> Option<Vec<Vec<u8>>> {
70         let _guard = LOCK.lock();
71         unsafe {
72             let ptr = get_global_ptr();
73             let val = mem::replace(&mut *ptr, None);
74             val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
75         }
76     }
77
78     pub fn put(args: Vec<Vec<u8>>) {
79         let _guard = LOCK.lock();
80         unsafe {
81             let ptr = get_global_ptr();
82             rtassert!((*ptr).is_none());
83             (*ptr) = Some(box args.clone());
84         }
85     }
86
87     pub fn clone() -> Option<Vec<Vec<u8>>> {
88         let _guard = LOCK.lock();
89         unsafe {
90             let ptr = get_global_ptr();
91             (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
92         }
93     }
94
95     fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
96         unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
97     }
98
99     unsafe fn load_argc_and_argv(argc: isize,
100                                  argv: *const *const u8) -> Vec<Vec<u8>> {
101         let argv = argv as *const *const libc::c_char;
102         (0..argc).map(|i| {
103             CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
104         }).collect()
105     }
106
107     #[cfg(test)]
108     mod tests {
109         use prelude::v1::*;
110         use finally::Finally;
111
112         use super::*;
113
114         #[test]
115         fn smoke_test() {
116             // Preserve the actual global state.
117             let saved_value = take();
118
119             let expected = vec![
120                 b"happy".to_vec(),
121                 b"today?".to_vec(),
122             ];
123
124             put(expected.clone());
125             assert!(clone() == Some(expected.clone()));
126             assert!(take() == Some(expected.clone()));
127             assert!(take() == None);
128
129             (|| {
130             }).finally(|| {
131                 // Restore the actual global state.
132                 match saved_value {
133                     Some(ref args) => put(args.clone()),
134                     None => ()
135                 }
136             })
137         }
138     }
139 }
140
141 #[cfg(any(target_os = "macos",
142           target_os = "ios",
143           target_os = "windows"))]
144 mod imp {
145     use core::prelude::*;
146     use vec::Vec;
147
148     pub unsafe fn init(_argc: int, _argv: *const *const u8) {
149     }
150
151     pub fn cleanup() {
152     }
153
154     pub fn take() -> Option<Vec<Vec<u8>>> {
155         panic!()
156     }
157
158     pub fn put(_args: Vec<Vec<u8>>) {
159         panic!()
160     }
161
162     pub fn clone() -> Option<Vec<Vec<u8>>> {
163         panic!()
164     }
165 }