]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
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. | |
c34b1796 | 26 | pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } |
1a4d82fc JJ |
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", | |
85aaf69f | 45 | target_os = "dragonfly", |
c34b1796 | 46 | target_os = "bitrig", |
c1a9b12d | 47 | target_os = "netbsd", |
85aaf69f | 48 | target_os = "openbsd"))] |
1a4d82fc JJ |
49 | mod imp { |
50 | use prelude::v1::*; | |
51 | ||
52 | use libc; | |
53 | use mem; | |
85aaf69f | 54 | use ffi::CStr; |
1a4d82fc | 55 | |
62682a34 | 56 | use sync::StaticMutex; |
1a4d82fc | 57 | |
c34b1796 | 58 | static mut GLOBAL_ARGS_PTR: usize = 0; |
62682a34 | 59 | static LOCK: StaticMutex = StaticMutex::new(); |
1a4d82fc | 60 | |
c34b1796 | 61 | pub unsafe fn init(argc: isize, argv: *const *const u8) { |
1a4d82fc JJ |
62 | let args = load_argc_and_argv(argc, argv); |
63 | put(args); | |
64 | } | |
65 | ||
66 | pub unsafe fn cleanup() { | |
67 | take(); | |
68 | LOCK.destroy(); | |
69 | } | |
70 | ||
71 | pub fn take() -> Option<Vec<Vec<u8>>> { | |
72 | let _guard = LOCK.lock(); | |
73 | unsafe { | |
74 | let ptr = get_global_ptr(); | |
75 | let val = mem::replace(&mut *ptr, None); | |
76 | val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone()) | |
77 | } | |
78 | } | |
79 | ||
80 | pub fn put(args: Vec<Vec<u8>>) { | |
81 | let _guard = LOCK.lock(); | |
82 | unsafe { | |
83 | let ptr = get_global_ptr(); | |
84 | rtassert!((*ptr).is_none()); | |
85 | (*ptr) = Some(box args.clone()); | |
86 | } | |
87 | } | |
88 | ||
89 | pub fn clone() -> Option<Vec<Vec<u8>>> { | |
90 | let _guard = LOCK.lock(); | |
91 | unsafe { | |
92 | let ptr = get_global_ptr(); | |
93 | (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone()) | |
94 | } | |
95 | } | |
96 | ||
97 | fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { | |
98 | unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } | |
99 | } | |
100 | ||
85aaf69f SL |
101 | unsafe fn load_argc_and_argv(argc: isize, |
102 | argv: *const *const u8) -> Vec<Vec<u8>> { | |
1a4d82fc | 103 | let argv = argv as *const *const libc::c_char; |
85aaf69f SL |
104 | (0..argc).map(|i| { |
105 | CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec() | |
1a4d82fc JJ |
106 | }).collect() |
107 | } | |
108 | ||
109 | #[cfg(test)] | |
110 | mod tests { | |
111 | use prelude::v1::*; | |
1a4d82fc JJ |
112 | |
113 | use super::*; | |
114 | ||
115 | #[test] | |
116 | fn smoke_test() { | |
117 | // Preserve the actual global state. | |
118 | let saved_value = take(); | |
119 | ||
120 | let expected = vec![ | |
121 | b"happy".to_vec(), | |
122 | b"today?".to_vec(), | |
123 | ]; | |
124 | ||
125 | put(expected.clone()); | |
126 | assert!(clone() == Some(expected.clone())); | |
127 | assert!(take() == Some(expected.clone())); | |
128 | assert!(take() == None); | |
129 | ||
c34b1796 AL |
130 | // Restore the actual global state. |
131 | match saved_value { | |
132 | Some(ref args) => put(args.clone()), | |
133 | None => () | |
134 | } | |
1a4d82fc JJ |
135 | } |
136 | } | |
137 | } | |
138 | ||
139 | #[cfg(any(target_os = "macos", | |
140 | target_os = "ios", | |
141 | target_os = "windows"))] | |
142 | mod imp { | |
143 | use core::prelude::*; | |
144 | use vec::Vec; | |
145 | ||
c34b1796 | 146 | pub unsafe fn init(_argc: isize, _argv: *const *const u8) { |
1a4d82fc JJ |
147 | } |
148 | ||
149 | pub fn cleanup() { | |
150 | } | |
151 | ||
152 | pub fn take() -> Option<Vec<Vec<u8>>> { | |
153 | panic!() | |
154 | } | |
155 | ||
156 | pub fn put(_args: Vec<Vec<u8>>) { | |
157 | panic!() | |
158 | } | |
159 | ||
160 | pub fn clone() -> Option<Vec<Vec<u8>>> { | |
161 | panic!() | |
162 | } | |
163 | } |