]> git.lizzy.rs Git - rust.git/blob - src/libstd/c_str.rs
Find the cratemap at runtime on windows.
[rust.git] / src / libstd / 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 cast;
12 use iter::{Iterator, range};
13 use libc;
14 use ops::Drop;
15 use option::{Option, Some, None};
16 use ptr::RawPtr;
17 use ptr;
18 use str;
19 use str::StrSlice;
20 use vec::{ImmutableVector, CopyableVector};
21 use container::Container;
22
23 /// Resolution options for the `null_byte` condition
24 pub enum NullByteResolution {
25     /// Truncate at the null byte
26     Truncate,
27     /// Use a replacement byte
28     ReplaceWith(libc::c_char)
29 }
30
31 condition! {
32     // This should be &[u8] but there's a lifetime issue (#5370).
33     pub null_byte: (~[u8]) -> NullByteResolution;
34 }
35
36 /// The representation of a C String.
37 ///
38 /// This structure wraps a `*libc::c_char`, and will automatically free the
39 /// memory it is pointing to when it goes out of scope.
40 pub struct CString {
41     priv buf: *libc::c_char,
42     priv owns_buffer_: bool,
43 }
44
45 impl CString {
46     /// Create a C String from a pointer.
47     pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
48         CString { buf: buf, owns_buffer_: owns_buffer }
49     }
50
51     /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
52     /// Any ownership of the buffer by the `CString` wrapper is forgotten.
53     pub unsafe fn unwrap(self) -> *libc::c_char {
54         let mut c_str = self;
55         c_str.owns_buffer_ = false;
56         c_str.buf
57     }
58
59     /// Calls a closure with a reference to the underlying `*libc::c_char`.
60     ///
61     /// # Failure
62     ///
63     /// Fails if the CString is null.
64     pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
65         if self.buf.is_null() { fail!("CString is null!"); }
66         f(self.buf)
67     }
68
69     /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
70     ///
71     /// # Failure
72     ///
73     /// Fails if the CString is null.
74     pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T {
75         if self.buf.is_null() { fail!("CString is null!"); }
76         f(unsafe { cast::transmute_mut_unsafe(self.buf) })
77     }
78
79     /// Returns true if the CString is a null.
80     pub fn is_null(&self) -> bool {
81         self.buf.is_null()
82     }
83
84     /// Returns true if the CString is not null.
85     pub fn is_not_null(&self) -> bool {
86         self.buf.is_not_null()
87     }
88
89     /// Returns whether or not the `CString` owns the buffer.
90     pub fn owns_buffer(&self) -> bool {
91         self.owns_buffer_
92     }
93
94     /// Converts the CString into a `&[u8]` without copying.
95     ///
96     /// # Failure
97     ///
98     /// Fails if the CString is null.
99     #[inline]
100     pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
101         if self.buf.is_null() { fail!("CString is null!"); }
102         unsafe {
103             let len = ptr::position(self.buf, |c| *c == 0);
104             cast::transmute((self.buf, len + 1))
105         }
106     }
107
108     /// Converts the CString into a `&str` without copying.
109     /// Returns None if the CString is not UTF-8 or is null.
110     #[inline]
111     pub fn as_str<'a>(&'a self) -> Option<&'a str> {
112         if self.buf.is_null() { return None; }
113         let buf = self.as_bytes();
114         let buf = buf.slice_to(buf.len()-1); // chop off the trailing NUL
115         str::from_utf8_slice_opt(buf)
116     }
117
118     /// Return a CString iterator.
119     pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
120         CStringIterator {
121             ptr: self.buf,
122             lifetime: unsafe { cast::transmute(self.buf) },
123         }
124     }
125 }
126
127 impl Drop for CString {
128     fn drop(&mut self) {
129         #[fixed_stack_segment]; #[inline(never)];
130         if self.owns_buffer_ {
131             unsafe {
132                 libc::free(self.buf as *libc::c_void)
133             }
134         }
135     }
136 }
137
138 /// A generic trait for converting a value to a CString.
139 pub trait ToCStr {
140     /// Copy the receiver into a CString.
141     ///
142     /// # Failure
143     ///
144     /// Raises the `null_byte` condition if the receiver has an interior null.
145     fn to_c_str(&self) -> CString;
146
147     /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
148     unsafe fn to_c_str_unchecked(&self) -> CString;
149
150     /// Work with a temporary CString constructed from the receiver.
151     /// The provided `*libc::c_char` will be freed immediately upon return.
152     ///
153     /// # Example
154     ///
155     /// ~~~ {.rust}
156     /// let s = "PATH".with_c_str(|path| libc::getenv(path))
157     /// ~~~
158     ///
159     /// # Failure
160     ///
161     /// Raises the `null_byte` condition if the receiver has an interior null.
162     #[inline]
163     fn with_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
164         self.to_c_str().with_ref(f)
165     }
166
167     /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
168     #[inline]
169     unsafe fn with_c_str_unchecked<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
170         self.to_c_str_unchecked().with_ref(f)
171     }
172 }
173
174 impl<'self> ToCStr for &'self str {
175     #[inline]
176     fn to_c_str(&self) -> CString {
177         self.as_bytes().to_c_str()
178     }
179
180     #[inline]
181     unsafe fn to_c_str_unchecked(&self) -> CString {
182         self.as_bytes().to_c_str_unchecked()
183     }
184 }
185
186 impl<'self> ToCStr for &'self [u8] {
187     fn to_c_str(&self) -> CString {
188         #[fixed_stack_segment]; #[inline(never)];
189         let mut cs = unsafe { self.to_c_str_unchecked() };
190         do cs.with_mut_ref |buf| {
191             for i in range(0, self.len()) {
192                 unsafe {
193                     let p = buf.offset(i as int);
194                     if *p == 0 {
195                         match null_byte::cond.raise(self.to_owned()) {
196                             Truncate => break,
197                             ReplaceWith(c) => *p = c
198                         }
199                     }
200                 }
201             }
202         }
203         cs
204     }
205
206     unsafe fn to_c_str_unchecked(&self) -> CString {
207         #[fixed_stack_segment]; #[inline(never)];
208         do self.as_imm_buf |self_buf, self_len| {
209             let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
210             if buf.is_null() {
211                 fail!("failed to allocate memory!");
212             }
213
214             ptr::copy_memory(buf, self_buf, self_len);
215             *ptr::mut_offset(buf, self_len as int) = 0;
216
217             CString::new(buf as *libc::c_char, true)
218         }
219     }
220 }
221
222 /// External iterator for a CString's bytes.
223 ///
224 /// Use with the `std::iterator` module.
225 pub struct CStringIterator<'self> {
226     priv ptr: *libc::c_char,
227     priv lifetime: &'self libc::c_char, // FIXME: #5922
228 }
229
230 impl<'self> Iterator<libc::c_char> for CStringIterator<'self> {
231     fn next(&mut self) -> Option<libc::c_char> {
232         let ch = unsafe { *self.ptr };
233         if ch == 0 {
234             None
235         } else {
236             self.ptr = unsafe { ptr::offset(self.ptr, 1) };
237             Some(ch)
238         }
239     }
240 }
241
242 #[cfg(test)]
243 mod tests {
244     use super::*;
245     use libc;
246     use ptr;
247     use option::{Some, None};
248
249     #[test]
250     fn test_str_to_c_str() {
251         do "".to_c_str().with_ref |buf| {
252             unsafe {
253                 assert_eq!(*ptr::offset(buf, 0), 0);
254             }
255         }
256
257         do "hello".to_c_str().with_ref |buf| {
258             unsafe {
259                 assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
260                 assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
261                 assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
262                 assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
263                 assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
264                 assert_eq!(*ptr::offset(buf, 5), 0);
265             }
266         }
267     }
268
269     #[test]
270     fn test_vec_to_c_str() {
271         let b: &[u8] = [];
272         do b.to_c_str().with_ref |buf| {
273             unsafe {
274                 assert_eq!(*ptr::offset(buf, 0), 0);
275             }
276         }
277
278         do bytes!("hello").to_c_str().with_ref |buf| {
279             unsafe {
280                 assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
281                 assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
282                 assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
283                 assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
284                 assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
285                 assert_eq!(*ptr::offset(buf, 5), 0);
286             }
287         }
288
289         do bytes!("foo", 0xff).to_c_str().with_ref |buf| {
290             unsafe {
291                 assert_eq!(*ptr::offset(buf, 0), 'f' as libc::c_char);
292                 assert_eq!(*ptr::offset(buf, 1), 'o' as libc::c_char);
293                 assert_eq!(*ptr::offset(buf, 2), 'o' as libc::c_char);
294                 assert_eq!(*ptr::offset(buf, 3), 0xff);
295                 assert_eq!(*ptr::offset(buf, 4), 0);
296             }
297         }
298     }
299
300     #[test]
301     fn test_is_null() {
302         let c_str = unsafe { CString::new(ptr::null(), false) };
303         assert!(c_str.is_null());
304         assert!(!c_str.is_not_null());
305     }
306
307     #[test]
308     fn test_unwrap() {
309         #[fixed_stack_segment]; #[inline(never)];
310
311         let c_str = "hello".to_c_str();
312         unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
313     }
314
315     #[test]
316     fn test_with_ref() {
317         #[fixed_stack_segment]; #[inline(never)];
318
319         let c_str = "hello".to_c_str();
320         let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
321         assert!(!c_str.is_null());
322         assert!(c_str.is_not_null());
323         assert_eq!(len, 5);
324     }
325
326     #[test]
327     #[should_fail]
328     fn test_with_ref_empty_fail() {
329         let c_str = unsafe { CString::new(ptr::null(), false) };
330         c_str.with_ref(|_| ());
331     }
332
333     #[test]
334     fn test_iterator() {
335         let c_str = "".to_c_str();
336         let mut iter = c_str.iter();
337         assert_eq!(iter.next(), None);
338
339         let c_str = "hello".to_c_str();
340         let mut iter = c_str.iter();
341         assert_eq!(iter.next(), Some('h' as libc::c_char));
342         assert_eq!(iter.next(), Some('e' as libc::c_char));
343         assert_eq!(iter.next(), Some('l' as libc::c_char));
344         assert_eq!(iter.next(), Some('l' as libc::c_char));
345         assert_eq!(iter.next(), Some('o' as libc::c_char));
346         assert_eq!(iter.next(), None);
347     }
348
349     #[test]
350     fn test_to_c_str_fail() {
351         use c_str::null_byte::cond;
352
353         let mut error_happened = false;
354         do cond.trap(|err| {
355             assert_eq!(err, bytes!("he", 0, "llo").to_owned())
356             error_happened = true;
357             Truncate
358         }).inside {
359             "he\x00llo".to_c_str()
360         };
361         assert!(error_happened);
362
363         do cond.trap(|_| {
364             ReplaceWith('?' as libc::c_char)
365         }).inside(|| "he\x00llo".to_c_str()).with_ref |buf| {
366             unsafe {
367                 assert_eq!(*buf.offset(0), 'h' as libc::c_char);
368                 assert_eq!(*buf.offset(1), 'e' as libc::c_char);
369                 assert_eq!(*buf.offset(2), '?' as libc::c_char);
370                 assert_eq!(*buf.offset(3), 'l' as libc::c_char);
371                 assert_eq!(*buf.offset(4), 'l' as libc::c_char);
372                 assert_eq!(*buf.offset(5), 'o' as libc::c_char);
373                 assert_eq!(*buf.offset(6), 0);
374             }
375         }
376     }
377
378     #[test]
379     fn test_to_c_str_unchecked() {
380         unsafe {
381             do "he\x00llo".to_c_str_unchecked().with_ref |buf| {
382                 assert_eq!(*buf.offset(0), 'h' as libc::c_char);
383                 assert_eq!(*buf.offset(1), 'e' as libc::c_char);
384                 assert_eq!(*buf.offset(2), 0);
385                 assert_eq!(*buf.offset(3), 'l' as libc::c_char);
386                 assert_eq!(*buf.offset(4), 'l' as libc::c_char);
387                 assert_eq!(*buf.offset(5), 'o' as libc::c_char);
388                 assert_eq!(*buf.offset(6), 0);
389             }
390         }
391     }
392
393     #[test]
394     fn test_as_bytes() {
395         let c_str = "hello".to_c_str();
396         assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
397         let c_str = "".to_c_str();
398         assert_eq!(c_str.as_bytes(), bytes!(0));
399         let c_str = bytes!("foo", 0xff).to_c_str();
400         assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
401     }
402
403     #[test]
404     #[should_fail]
405     fn test_as_bytes_fail() {
406         let c_str = unsafe { CString::new(ptr::null(), false) };
407         c_str.as_bytes();
408     }
409
410     #[test]
411     fn test_as_str() {
412         let c_str = "hello".to_c_str();
413         assert_eq!(c_str.as_str(), Some("hello"));
414         let c_str = "".to_c_str();
415         assert_eq!(c_str.as_str(), Some(""));
416         let c_str = bytes!("foo", 0xff).to_c_str();
417         assert_eq!(c_str.as_str(), None);
418         let c_str = unsafe { CString::new(ptr::null(), false) };
419         assert_eq!(c_str.as_str(), None);
420     }
421 }