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