]> git.lizzy.rs Git - rust.git/blob - src/libstd/ffi/c_str.rs
complete openbsd support for `std::env`
[rust.git] / src / libstd / ffi / c_str.rs
1 // Copyright 2012 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 use fmt;
12 use iter::IteratorExt;
13 use libc;
14 use mem;
15 use ops::Deref;
16 use slice::{self, SliceExt, AsSlice};
17 use string::String;
18 use vec::Vec;
19
20 /// A type representing a C-compatible string
21 ///
22 /// This type serves the primary purpose of being able to generate a
23 /// C-compatible string from a Rust byte slice or vector. An instance of this
24 /// type is a static guarantee that the underlying bytes contain no interior 0
25 /// bytes and the final byte is 0.
26 ///
27 /// A `CString` is created from either a byte slice or a byte vector. After
28 /// being created, a `CString` predominately inherits all of its methods from
29 /// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
30 /// array is represented as an array of `libc::c_char` as opposed to `u8`. A
31 /// `u8` slice can be obtained with the `as_bytes` method.  Slices produced from
32 /// a `CString` do *not* contain the trailing nul terminator unless otherwise
33 /// specified.
34 ///
35 /// # Example
36 ///
37 /// ```no_run
38 /// # extern crate libc;
39 /// # fn main() {
40 /// use std::ffi::CString;
41 /// use libc;
42 ///
43 /// extern {
44 ///     fn my_printer(s: *const libc::c_char);
45 /// }
46 ///
47 /// let to_print = "Hello, world!";
48 /// let c_to_print = CString::from_slice(to_print.as_bytes());
49 /// unsafe {
50 ///     my_printer(c_to_print.as_ptr());
51 /// }
52 /// # }
53 /// ```
54 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
55 pub struct CString {
56     inner: Vec<libc::c_char>,
57 }
58
59 impl CString {
60     /// Create a new C-compatible string from a byte slice.
61     ///
62     /// This method will copy the data of the slice provided into a new
63     /// allocation, ensuring that there is a trailing 0 byte.
64     ///
65     /// # Panics
66     ///
67     /// This function will panic if there are any 0 bytes already in the slice
68     /// provided.
69     pub fn from_slice(v: &[u8]) -> CString {
70         CString::from_vec(v.to_vec())
71     }
72
73     /// Create a C-compatible string from a byte vector.
74     ///
75     /// This method will consume ownership of the provided vector, appending a 0
76     /// byte to the end after verifying that there are no interior 0 bytes.
77     ///
78     /// # Panics
79     ///
80     /// This function will panic if there are any 0 bytes already in the vector
81     /// provided.
82     pub fn from_vec(v: Vec<u8>) -> CString {
83         assert!(!v.iter().any(|&x| x == 0));
84         unsafe { CString::from_vec_unchecked(v) }
85     }
86
87     /// Create a C-compatible string from a byte vector without checking for
88     /// interior 0 bytes.
89     ///
90     /// This method is equivalent to `from_vec` except that no runtime assertion
91     /// is made that `v` contains no 0 bytes.
92     pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
93         v.push(0);
94         CString { inner: mem::transmute(v) }
95     }
96
97     /// Create a view into this C string which includes the trailing nul
98     /// terminator at the end of the string.
99     pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() }
100
101     /// Similar to the `as_slice` method, but returns a `u8` slice instead of a
102     /// `libc::c_char` slice.
103     pub fn as_bytes(&self) -> &[u8] {
104         unsafe { mem::transmute(self.as_slice()) }
105     }
106
107     /// Equivalent to `as_slice_with_nul` except that the type returned is a
108     /// `u8` slice instead of a `libc::c_char` slice.
109     pub fn as_bytes_with_nul(&self) -> &[u8] {
110         unsafe { mem::transmute(self.as_slice_with_nul()) }
111     }
112 }
113
114 impl Deref for CString {
115     type Target = [libc::c_char];
116
117     fn deref(&self) -> &[libc::c_char] {
118         &self.inner[..(self.inner.len() - 1)]
119     }
120 }
121
122 #[stable(feature = "rust1", since = "1.0.0")]
123 impl fmt::Debug for CString {
124     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125         fmt::Debug::fmt(&String::from_utf8_lossy(self.as_bytes()), f)
126     }
127 }
128
129 /// Interpret a C string as a byte slice.
130 ///
131 /// This function will calculate the length of the C string provided, and it
132 /// will then return a corresponding slice for the contents of the C string not
133 /// including the nul terminator.
134 ///
135 /// This function will tie the lifetime of the returned slice to the lifetime of
136 /// the pointer provided. This is done to help prevent the slice from escaping
137 /// the lifetime of the pointer itself. If a longer lifetime is needed, then
138 /// `mem::copy_lifetime` should be used.
139 ///
140 /// This function is unsafe because there is no guarantee of the validity of the
141 /// pointer `raw` or a guarantee that a nul terminator will be found.
142 ///
143 /// # Example
144 ///
145 /// ```no_run
146 /// # extern crate libc;
147 /// # fn main() {
148 /// use std::ffi;
149 /// use std::str;
150 /// use libc;
151 ///
152 /// extern {
153 ///     fn my_string() -> *const libc::c_char;
154 /// }
155 ///
156 /// unsafe {
157 ///     let to_print = my_string();
158 ///     let slice = ffi::c_str_to_bytes(&to_print);
159 ///     println!("string returned: {}", str::from_utf8(slice).unwrap());
160 /// }
161 /// # }
162 /// ```
163 pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
164     let len = libc::strlen(*raw);
165     slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
166 }
167
168 /// Interpret a C string as a byte slice with the nul terminator.
169 ///
170 /// This function is identical to `from_raw_buf` except that the returned slice
171 /// will include the nul terminator of the string.
172 pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
173     let len = libc::strlen(*raw) + 1;
174     slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
175 }
176
177 #[cfg(test)]
178 mod tests {
179     use prelude::v1::*;
180     use super::*;
181     use libc;
182     use mem;
183
184     #[test]
185     fn c_to_rust() {
186         let data = b"123\0";
187         let ptr = data.as_ptr() as *const libc::c_char;
188         unsafe {
189             assert_eq!(c_str_to_bytes(&ptr), b"123");
190             assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0");
191         }
192     }
193
194     #[test]
195     fn simple() {
196         let s = CString::from_slice(b"1234");
197         assert_eq!(s.as_bytes(), b"1234");
198         assert_eq!(s.as_bytes_with_nul(), b"1234\0");
199         unsafe {
200             assert_eq!(s.as_slice(),
201                        mem::transmute::<_, &[libc::c_char]>(b"1234"));
202             assert_eq!(s.as_slice_with_nul(),
203                        mem::transmute::<_, &[libc::c_char]>(b"1234\0"));
204         }
205     }
206
207     #[should_fail] #[test]
208     fn build_with_zero1() { CString::from_slice(b"\0"); }
209     #[should_fail] #[test]
210     fn build_with_zero2() { CString::from_vec(vec![0]); }
211
212     #[test]
213     fn build_with_zero3() {
214         unsafe {
215             let s = CString::from_vec_unchecked(vec![0]);
216             assert_eq!(s.as_bytes(), b"\0");
217         }
218     }
219
220     #[test]
221     fn formatted() {
222         let s = CString::from_slice(b"12");
223         assert_eq!(format!("{:?}", s), "\"12\"");
224     }
225 }