]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/args.rs
Auto merge of #22517 - brson:relnotes, 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;
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: int, argv: *const *const u8) -> Vec<Vec<u8>> {
100         let argv = argv as *const *const libc::c_char;
101         (0..argc as uint).map(|i| {
102             ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
103         }).collect()
104     }
105
106     #[cfg(test)]
107     mod tests {
108         use prelude::v1::*;
109         use finally::Finally;
110
111         use super::*;
112
113         #[test]
114         fn smoke_test() {
115             // Preserve the actual global state.
116             let saved_value = take();
117
118             let expected = vec![
119                 b"happy".to_vec(),
120                 b"today?".to_vec(),
121             ];
122
123             put(expected.clone());
124             assert!(clone() == Some(expected.clone()));
125             assert!(take() == Some(expected.clone()));
126             assert!(take() == None);
127
128             (|| {
129             }).finally(|| {
130                 // Restore the actual global state.
131                 match saved_value {
132                     Some(ref args) => put(args.clone()),
133                     None => ()
134                 }
135             })
136         }
137     }
138 }
139
140 #[cfg(any(target_os = "macos",
141           target_os = "ios",
142           target_os = "windows"))]
143 mod imp {
144     use core::prelude::*;
145     use vec::Vec;
146
147     pub unsafe fn init(_argc: int, _argv: *const *const u8) {
148     }
149
150     pub fn cleanup() {
151     }
152
153     pub fn take() -> Option<Vec<Vec<u8>>> {
154         panic!()
155     }
156
157     pub fn put(_args: Vec<Vec<u8>>) {
158         panic!()
159     }
160
161     pub fn clone() -> Option<Vec<Vec<u8>>> {
162         panic!()
163     }
164 }