]> git.lizzy.rs Git - rust.git/blob - src/librustrt/args.rs
doc/guide-ffi: A few minor typo/language fixes
[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 mod imp {
46     use core::prelude::*;
47
48     use alloc::owned::Box;
49     use collections::vec::Vec;
50     use core::mem;
51     use core::slice;
52
53     use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
54
55     static mut global_args_ptr: uint = 0;
56     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
57
58     pub unsafe fn init(argc: int, argv: *const *const u8) {
59         let args = load_argc_and_argv(argc, argv);
60         put(args);
61     }
62
63     pub unsafe fn cleanup() {
64         rtassert!(take().is_some());
65         lock.destroy();
66     }
67
68     pub fn take() -> Option<Vec<Vec<u8>>> {
69         with_lock(|| unsafe {
70             let ptr = get_global_ptr();
71             let val = mem::replace(&mut *ptr, None);
72             val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
73         })
74     }
75
76     pub fn put(args: Vec<Vec<u8>>) {
77         with_lock(|| unsafe {
78             let ptr = get_global_ptr();
79             rtassert!((*ptr).is_none());
80             (*ptr) = Some(box args.clone());
81         })
82     }
83
84     pub fn clone() -> Option<Vec<Vec<u8>>> {
85         with_lock(|| unsafe {
86             let ptr = get_global_ptr();
87             (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
88         })
89     }
90
91     fn with_lock<T>(f: || -> T) -> T {
92         unsafe {
93             let _guard = lock.lock();
94             f()
95         }
96     }
97
98     fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
99         unsafe { mem::transmute(&global_args_ptr) }
100     }
101
102     unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec<Vec<u8>> {
103         Vec::from_fn(argc as uint, |i| {
104             let base = *argv.offset(i as int);
105             let mut len = 0;
106             while *base.offset(len) != 0 { len += 1; }
107             slice::raw::buf_as_slice(base, len as uint, |slice| {
108                 Vec::from_slice(slice)
109             })
110         })
111     }
112
113     #[cfg(test)]
114     mod tests {
115         use std::prelude::*;
116         use std::finally::Finally;
117
118         use super::*;
119
120         #[test]
121         fn smoke_test() {
122             // Preserve the actual global state.
123             let saved_value = take();
124
125             let expected = vec![
126                 Vec::from_slice(b"happy"),
127                 Vec::from_slice(b"today?"),
128             ];
129
130             put(expected.clone());
131             assert!(clone() == Some(expected.clone()));
132             assert!(take() == Some(expected.clone()));
133             assert!(take() == None);
134
135             (|| {
136             }).finally(|| {
137                 // Restore the actual global state.
138                 match saved_value {
139                     Some(ref args) => put(args.clone()),
140                     None => ()
141                 }
142             })
143         }
144     }
145 }
146
147 #[cfg(target_os = "macos")]
148 #[cfg(target_os = "ios")]
149 #[cfg(target_os = "win32")]
150 mod imp {
151     use core::prelude::*;
152     use collections::vec::Vec;
153
154     pub unsafe fn init(_argc: int, _argv: *const *const u8) {
155     }
156
157     pub fn cleanup() {
158     }
159
160     pub fn take() -> Option<Vec<Vec<u8>>> {
161         fail!()
162     }
163
164     pub fn put(_args: Vec<Vec<u8>>) {
165         fail!()
166     }
167
168     pub fn clone() -> Option<Vec<Vec<u8>>> {
169         fail!()
170     }
171 }