]> git.lizzy.rs Git - rust.git/blob - src/libstd/ffi/c_str.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[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 cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
12 use error::{Error, FromError};
13 use fmt;
14 use io;
15 use iter::IteratorExt;
16 use libc;
17 use mem;
18 use old_io;
19 use ops::Deref;
20 use option::Option::{self, Some, None};
21 use result::Result::{self, Ok, Err};
22 use slice::{self, SliceExt};
23 use str::StrExt;
24 use string::String;
25 use vec::Vec;
26
27 /// A type representing an owned C-compatible string
28 ///
29 /// This type serves the primary purpose of being able to safely generate a
30 /// C-compatible string from a Rust byte slice or vector. An instance of this
31 /// type is a static guarantee that the underlying bytes contain no interior 0
32 /// bytes and the final byte is 0.
33 ///
34 /// A `CString` is created from either a byte slice or a byte vector. After
35 /// being created, a `CString` predominately inherits all of its methods from
36 /// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
37 /// array is represented as an array of `libc::c_char` as opposed to `u8`. A
38 /// `u8` slice can be obtained with the `as_bytes` method.  Slices produced from
39 /// a `CString` do *not* contain the trailing nul terminator unless otherwise
40 /// specified.
41 ///
42 /// # Example
43 ///
44 /// ```no_run
45 /// # extern crate libc;
46 /// # fn main() {
47 /// use std::ffi::CString;
48 /// use libc;
49 ///
50 /// extern {
51 ///     fn my_printer(s: *const libc::c_char);
52 /// }
53 ///
54 /// let to_print = b"Hello, world!";
55 /// let c_to_print = CString::new(to_print).unwrap();
56 /// unsafe {
57 ///     my_printer(c_to_print.as_ptr());
58 /// }
59 /// # }
60 /// ```
61 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
62 pub struct CString {
63     inner: Vec<u8>,
64 }
65
66 /// Representation of a borrowed C string.
67 ///
68 /// This dynamically sized type is only safely constructed via a borrowed
69 /// version of an instance of `CString`. This type can be constructed from a raw
70 /// C string as well and represents a C string borrowed from another location.
71 ///
72 /// Note that this structure is **not** `repr(C)` and is not recommended to be
73 /// placed in the signatures of FFI functions. Instead safe wrappers of FFI
74 /// functions may leverage the unsafe `from_ptr` constructor to provide a safe
75 /// interface to other consumers.
76 ///
77 /// # Examples
78 ///
79 /// Inspecting a foreign C string
80 ///
81 /// ```no_run
82 /// extern crate libc;
83 /// use std::ffi::CStr;
84 ///
85 /// extern { fn my_string() -> *const libc::c_char; }
86 ///
87 /// fn main() {
88 ///     unsafe {
89 ///         let slice = CStr::from_ptr(my_string());
90 ///         println!("string length: {}", slice.to_bytes().len());
91 ///     }
92 /// }
93 /// ```
94 ///
95 /// Passing a Rust-originating C string
96 ///
97 /// ```no_run
98 /// extern crate libc;
99 /// use std::ffi::{CString, CStr};
100 ///
101 /// fn work(data: &CStr) {
102 ///     extern { fn work_with(data: *const libc::c_char); }
103 ///
104 ///     unsafe { work_with(data.as_ptr()) }
105 /// }
106 ///
107 /// fn main() {
108 ///     let s = CString::new("data data data data").unwrap();
109 ///     work(&s);
110 /// }
111 /// ```
112 #[derive(Hash)]
113 pub struct CStr {
114     inner: [libc::c_char]
115 }
116
117 /// An error returned from `CString::new` to indicate that a nul byte was found
118 /// in the vector provided.
119 #[derive(Clone, PartialEq, Debug)]
120 pub struct NulError(usize, Vec<u8>);
121
122 /// A conversion trait used by the constructor of `CString` for types that can
123 /// be converted to a vector of bytes.
124 pub trait IntoBytes {
125     /// Consumes this container, returning a vector of bytes.
126     fn into_bytes(self) -> Vec<u8>;
127 }
128
129 impl CString {
130     /// Create a new C-compatible string from a container of bytes.
131     ///
132     /// This method will consume the provided data and use the underlying bytes
133     /// to construct a new string, ensuring that there is a trailing 0 byte.
134     ///
135     /// # Examples
136     ///
137     /// ```no_run
138     /// extern crate libc;
139     /// use std::ffi::CString;
140     ///
141     /// extern { fn puts(s: *const libc::c_char); }
142     ///
143     /// fn main() {
144     ///     let to_print = CString::new("Hello!").unwrap();
145     ///     unsafe {
146     ///         puts(to_print.as_ptr());
147     ///     }
148     /// }
149     /// ```
150     ///
151     /// # Errors
152     ///
153     /// This function will return an error if the bytes yielded contain an
154     /// internal 0 byte. The error returned will contain the bytes as well as
155     /// the position of the nul byte.
156     pub fn new<T: IntoBytes>(t: T) -> Result<CString, NulError> {
157         let bytes = t.into_bytes();
158         match bytes.iter().position(|x| *x == 0) {
159             Some(i) => Err(NulError(i, bytes)),
160             None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
161         }
162     }
163
164     /// Create a new C-compatible string from a byte slice.
165     ///
166     /// This method will copy the data of the slice provided into a new
167     /// allocation, ensuring that there is a trailing 0 byte.
168     ///
169     /// # Examples
170     ///
171     /// ```no_run
172     /// extern crate libc;
173     /// use std::ffi::CString;
174     ///
175     /// extern { fn puts(s: *const libc::c_char); }
176     ///
177     /// fn main() {
178     ///     let to_print = CString::new("Hello!").unwrap();
179     ///     unsafe {
180     ///         puts(to_print.as_ptr());
181     ///     }
182     /// }
183     /// ```
184     ///
185     /// # Panics
186     ///
187     /// This function will panic if the provided slice contains any
188     /// interior nul bytes.
189     #[unstable(feature = "std_misc")]
190     #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
191     #[allow(deprecated)]
192     pub fn from_slice(v: &[u8]) -> CString {
193         CString::from_vec(v.to_vec())
194     }
195
196     /// Create a C-compatible string from a byte vector.
197     ///
198     /// This method will consume ownership of the provided vector, appending a 0
199     /// byte to the end after verifying that there are no interior 0 bytes.
200     ///
201     /// # Panics
202     ///
203     /// This function will panic if the provided slice contains any
204     /// interior nul bytes.
205     #[unstable(feature = "std_misc")]
206     #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
207     pub fn from_vec(v: Vec<u8>) -> CString {
208         match v.iter().position(|x| *x == 0) {
209             Some(i) => panic!("null byte found in slice at: {}", i),
210             None => unsafe { CString::from_vec_unchecked(v) },
211         }
212     }
213
214     /// Create a C-compatible string from a byte vector without checking for
215     /// interior 0 bytes.
216     ///
217     /// This method is equivalent to `from_vec` except that no runtime assertion
218     /// is made that `v` contains no 0 bytes.
219     pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
220         v.push(0);
221         CString { inner: v }
222     }
223
224     /// Returns the contents of this `CString` as a slice of bytes.
225     ///
226     /// The returned slice does **not** contain the trailing nul separator and
227     /// it is guaranteet to not have any interior nul bytes.
228     pub fn as_bytes(&self) -> &[u8] {
229         &self.inner[..self.inner.len() - 1]
230     }
231
232     /// Equivalent to the `as_bytes` function except that the returned slice
233     /// includes the trailing nul byte.
234     pub fn as_bytes_with_nul(&self) -> &[u8] {
235         &self.inner
236     }
237 }
238
239 impl Deref for CString {
240     type Target = CStr;
241
242     fn deref(&self) -> &CStr {
243         unsafe { mem::transmute(self.as_bytes_with_nul()) }
244     }
245 }
246
247 #[stable(feature = "rust1", since = "1.0.0")]
248 impl fmt::Debug for CString {
249     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250         fmt::Debug::fmt(&String::from_utf8_lossy(self.as_bytes()), f)
251     }
252 }
253
254 impl NulError {
255     /// Returns the position of the nul byte in the slice that was provided to
256     /// `CString::from_vec`.
257     pub fn nul_position(&self) -> usize { self.0 }
258
259     /// Consumes this error, returning the underlying vector of bytes which
260     /// generated the error in the first place.
261     pub fn into_vec(self) -> Vec<u8> { self.1 }
262 }
263
264 impl Error for NulError {
265     fn description(&self) -> &str { "nul byte found in data" }
266 }
267
268 impl fmt::Display for NulError {
269     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270         write!(f, "nul byte found in provided data at position: {}", self.0)
271     }
272 }
273
274 impl FromError<NulError> for io::Error {
275     fn from_error(_: NulError) -> io::Error {
276         io::Error::new(io::ErrorKind::InvalidInput,
277                        "data provided contains a nul byte", None)
278     }
279 }
280
281 impl FromError<NulError> for old_io::IoError {
282     fn from_error(_: NulError) -> old_io::IoError {
283         old_io::IoError {
284             kind: old_io::IoErrorKind::InvalidInput,
285             desc: "data provided contains a nul byte",
286             detail: None
287         }
288     }
289 }
290
291 impl CStr {
292     /// Cast a raw C string to a safe C string wrapper.
293     ///
294     /// This function will cast the provided `ptr` to the `CStr` wrapper which
295     /// allows inspection and interoperation of non-owned C strings. This method
296     /// is unsafe for a number of reasons:
297     ///
298     /// * There is no guarantee to the validity of `ptr`
299     /// * The returned lifetime is not guaranteed to be the actual lifetime of
300     ///   `ptr`
301     /// * There is no guarantee that the memory pointed to by `ptr` contains a
302     ///   valid nul terminator byte at the end of the string.
303     ///
304     /// > **Note**: This operation is intended to be a 0-cost cast but it is
305     /// > currently implemented with an up-front calculation of the length of
306     /// > the string. This is not guaranteed to always be the case.
307     ///
308     /// # Example
309     ///
310     /// ```no_run
311     /// # extern crate libc;
312     /// # fn main() {
313     /// use std::ffi::CStr;
314     /// use std::str;
315     /// use libc;
316     ///
317     /// extern {
318     ///     fn my_string() -> *const libc::c_char;
319     /// }
320     ///
321     /// unsafe {
322     ///     let slice = CStr::from_ptr(my_string());
323     ///     println!("string returned: {}",
324     ///              str::from_utf8(slice.to_bytes()).unwrap());
325     /// }
326     /// # }
327     /// ```
328     pub unsafe fn from_ptr<'a>(ptr: *const libc::c_char) -> &'a CStr {
329         let len = libc::strlen(ptr);
330         mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
331     }
332
333     /// Return the inner pointer to this C string.
334     ///
335     /// The returned pointer will be valid for as long as `self` is and points
336     /// to a continguous region of memory terminated with a 0 byte to represent
337     /// the end of the string.
338     pub fn as_ptr(&self) -> *const libc::c_char {
339         self.inner.as_ptr()
340     }
341
342     /// Convert this C string to a byte slice.
343     ///
344     /// This function will calculate the length of this string (which normally
345     /// requires a linear amount of work to be done) and then return the
346     /// resulting slice of `u8` elements.
347     ///
348     /// The returned slice will **not** contain the trailing nul that this C
349     /// string has.
350     ///
351     /// > **Note**: This method is currently implemented as a 0-cost cast, but
352     /// > it is planned to alter its definition in the future to perform the
353     /// > length calculation whenever this method is called.
354     pub fn to_bytes(&self) -> &[u8] {
355         let bytes = self.to_bytes_with_nul();
356         &bytes[..bytes.len() - 1]
357     }
358
359     /// Convert this C string to a byte slice containing the trailing 0 byte.
360     ///
361     /// This function is the equivalent of `to_bytes` except that it will retain
362     /// the trailing nul instead of chopping it off.
363     ///
364     /// > **Note**: This method is currently implemented as a 0-cost cast, but
365     /// > it is planned to alter its definition in the future to perform the
366     /// > length calculation whenever this method is called.
367     pub fn to_bytes_with_nul(&self) -> &[u8] {
368         unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.inner) }
369     }
370 }
371
372 impl PartialEq for CStr {
373     fn eq(&self, other: &CStr) -> bool {
374         self.to_bytes().eq(&other.to_bytes())
375     }
376 }
377 impl Eq for CStr {}
378 impl PartialOrd for CStr {
379     fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
380         self.to_bytes().partial_cmp(&other.to_bytes())
381     }
382 }
383 impl Ord for CStr {
384     fn cmp(&self, other: &CStr) -> Ordering {
385         self.to_bytes().cmp(&other.to_bytes())
386     }
387 }
388
389 /// Deprecated in favor of `CStr`
390 #[unstable(feature = "std_misc")]
391 #[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")]
392 pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
393     let len = libc::strlen(*raw);
394     slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
395 }
396
397 /// Deprecated in favor of `CStr`
398 #[unstable(feature = "std_misc")]
399 #[deprecated(since = "1.0.0",
400              reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")]
401 pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char)
402                                           -> &'a [u8] {
403     let len = libc::strlen(*raw) + 1;
404     slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
405 }
406
407 impl<'a> IntoBytes for &'a str {
408     fn into_bytes(self) -> Vec<u8> { self.as_bytes().to_vec() }
409 }
410 impl<'a> IntoBytes for &'a [u8] {
411     fn into_bytes(self) -> Vec<u8> { self.to_vec() }
412 }
413 impl IntoBytes for String {
414     fn into_bytes(self) -> Vec<u8> { self.into_bytes() }
415 }
416 impl IntoBytes for Vec<u8> {
417     fn into_bytes(self) -> Vec<u8> { self }
418 }
419
420 #[cfg(test)]
421 mod tests {
422     use prelude::v1::*;
423     use super::*;
424     use libc;
425     use mem;
426
427     #[test]
428     fn c_to_rust() {
429         let data = b"123\0";
430         let ptr = data.as_ptr() as *const libc::c_char;
431         unsafe {
432             assert_eq!(c_str_to_bytes(&ptr), b"123");
433             assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0");
434         }
435     }
436
437     #[test]
438     fn simple() {
439         let s = CString::new(b"1234").unwrap();
440         assert_eq!(s.as_bytes(), b"1234");
441         assert_eq!(s.as_bytes_with_nul(), b"1234\0");
442     }
443
444     #[test]
445     fn build_with_zero1() {
446         assert!(CString::new(b"\0").is_err());
447     }
448     #[test]
449     fn build_with_zero2() {
450         assert!(CString::new(vec![0]).is_err());
451     }
452
453     #[test]
454     fn build_with_zero3() {
455         unsafe {
456             let s = CString::from_vec_unchecked(vec![0]);
457             assert_eq!(s.as_bytes(), b"\0");
458         }
459     }
460
461     #[test]
462     fn formatted() {
463         let s = CString::new(b"12").unwrap();
464         assert_eq!(format!("{:?}", s), "\"12\"");
465     }
466
467     #[test]
468     fn borrowed() {
469         unsafe {
470             let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
471             assert_eq!(s.to_bytes(), b"12");
472             assert_eq!(s.to_bytes_with_nul(), b"12\0");
473         }
474     }
475 }