]> git.lizzy.rs Git - rust.git/commitdiff
std: Implement CString-related RFCs
authorAlex Crichton <alex@alexcrichton.com>
Wed, 18 Feb 2015 06:47:40 +0000 (22:47 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 18 Feb 2015 22:15:43 +0000 (14:15 -0800)
This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These
two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type
to the module.

[r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md
[r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md

The new `CStr` type is only constructable via two methods:

1. By `deref`'ing from a `CString`
2. Unsafely via `CStr::from_ptr`

The purpose of `CStr` is to be an unsized type which is a thin pointer to a
`libc::c_char` (currently it is a fat pointer slice due to implementation
limitations). Strings from C can be safely represented with a `CStr` and an
appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr`
instead to allow producers to pass in C-originating strings instead of just
Rust-allocated strings.

A new constructor was added to `CString`, `new`, which takes `T: IntoBytes`
instead of separate `from_slice` and `from_vec` methods (both have been
deprecated in favor of `new`). The `new` method returns a `Result` instead of
panicking.  The error variant contains the relevant information about where the
error happened and bytes (if present). Conversions are provided to the
`io::Error` and `old_io::IoError` types via the `FromError` trait which
translate to `InvalidInput`.

This is a breaking change due to the modification of existing `#[unstable]` APIs
and new deprecation, and more detailed information can be found in the two RFCs.
Notable breakage includes:

* All construction of `CString` now needs to use `new` and handle the outgoing
  `Result`.
* Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call.
* The `as_slice*` methods have been removed in favor of just having the
  `as_bytes*` methods.

Closes #22469
Closes #22470
[breaking-change]

40 files changed:
src/doc/trpl/ffi.md
src/librustc/metadata/loader.rs
src/librustc_llvm/archive_ro.rs
src/librustc_llvm/lib.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/write.rs
src/librustc_trans/trans/asm.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/builder.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/foreign.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/type_.rs
src/librustdoc/flock.rs
src/librustdoc/html/markdown.rs
src/libstd/dynamic_lib.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/mod.rs
src/libstd/old_io/net/pipe.rs
src/libstd/old_io/process.rs
src/libstd/rt/args.rs
src/libstd/sys/common/net.rs
src/libstd/sys/common/net2.rs
src/libstd/sys/unix/backtrace.rs
src/libstd/sys/unix/ext.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/fs2.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/pipe.rs
src/libstd/sys/unix/process2.rs
src/libstd/sys/unix/thread.rs
src/libsyntax/diagnostic.rs
src/test/run-pass/c-stack-returning-int64.rs
src/test/run-pass/foreign-fn-linkname.rs
src/test/run-pass/rename-directory.rs
src/test/run-pass/variadic-ffi.rs

index f2b95f19edce21336c808454969cc3ff27f50ac5..60750160f5fe3f83932a92f0d6feef8c871f61c5 100644 (file)
@@ -435,8 +435,8 @@ extern {
 }
 
 fn main() {
-    let prompt = CString::from_slice(b"[my-awesome-shell] $");
-    unsafe { 
+    let prompt = CString::new("[my-awesome-shell] $").unwrap();
+    unsafe {
         rl_prompt = prompt.as_ptr();
 
         println!("{:?}", rl_prompt);
index 3158ccd076522f76dc9eec476b9122bc09bbadd4..89f19b6c47c518ce8851bad6c2d729bfbf8b8233 100644 (file)
@@ -744,7 +744,7 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlo
         }
     }
     unsafe {
-        let buf = CString::from_slice(filename.as_vec());
+        let buf = CString::new(filename.as_vec()).unwrap();
         let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
         if mb as int == 0 {
             return Err(format!("error reading library: '{}'",
index d3555e4c0436354055399d04ab1cbb2f58995c97..14a99026aac8ac18c8e06b377e68981ca534f52b 100644 (file)
@@ -30,7 +30,7 @@ impl ArchiveRO {
     /// raised.
     pub fn open(dst: &Path) -> Option<ArchiveRO> {
         unsafe {
-            let s = CString::from_slice(dst.as_vec());
+            let s = CString::new(dst.as_vec()).unwrap();
             let ar = ::LLVMRustOpenArchive(s.as_ptr());
             if ar.is_null() {
                 None
@@ -44,7 +44,7 @@ pub fn open(dst: &Path) -> Option<ArchiveRO> {
     pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
         unsafe {
             let mut size = 0 as libc::size_t;
-            let file = CString::from_slice(file.as_bytes());
+            let file = CString::new(file).unwrap();
             let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
                                                    &mut size);
             if ptr.is_null() {
index aa90d7c851ba62f8b6c75e9f38be8bb081dcd463..c3fe23eff46905543dfa35d9f31ebbb493f4a428 100644 (file)
@@ -2149,7 +2149,7 @@ fn drop(&mut self) {
 }
 
 pub fn mk_target_data(string_rep: &str) -> TargetData {
-    let string_rep = CString::from_slice(string_rep.as_bytes());
+    let string_rep = CString::new(string_rep).unwrap();
     TargetData {
         lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) }
     }
index c88e76f42707348001214e34eff7889dba5cc897..9d604695cf75f6d76a32f5146066c35c11bdaad8 100644 (file)
@@ -140,7 +140,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
 
     // Internalize everything but the reachable symbols of the current module
     let cstrs: Vec<CString> = reachable.iter().map(|s| {
-        CString::from_slice(s.as_bytes())
+        CString::new(s.clone()).unwrap()
     }).collect();
     let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
     let ptr = arr.as_ptr();
index 9934d9993d61df0b2b95e6bacc048fd181aa616d..20cd1624a8c9715c9991a8c7314d34921cd861e1 100644 (file)
@@ -22,7 +22,7 @@
 use syntax::diagnostic;
 use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
 
-use std::ffi::{self, CString};
+use std::ffi::{CStr, CString};
 use std::old_io::Command;
 use std::old_io::fs;
 use std::iter::Unfold;
@@ -49,7 +49,7 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
         if cstr == ptr::null() {
             handler.fatal(&msg[]);
         } else {
-            let err = ffi::c_str_to_bytes(&cstr);
+            let err = CStr::from_ptr(cstr).to_bytes();
             let err = String::from_utf8_lossy(err).to_string();
             libc::free(cstr as *mut _);
             handler.fatal(&format!("{}: {}",
@@ -67,7 +67,7 @@ pub fn write_output_file(
         output: &Path,
         file_type: llvm::FileType) {
     unsafe {
-        let output_c = CString::from_slice(output.as_vec());
+        let output_c = CString::new(output.as_vec()).unwrap();
         let result = llvm::LLVMRustWriteOutputFile(
                 target, pm, m, output_c.as_ptr(), file_type);
         if !result {
@@ -221,13 +221,13 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
     let triple = &sess.target.target.llvm_target[];
 
     let tm = unsafe {
-        let triple = CString::from_slice(triple.as_bytes());
+        let triple = CString::new(triple.as_bytes()).unwrap();
         let cpu = match sess.opts.cg.target_cpu {
             Some(ref s) => &**s,
             None => &*sess.target.target.options.cpu
         };
-        let cpu = CString::from_slice(cpu.as_bytes());
-        let features = CString::from_slice(target_feature(sess).as_bytes());
+        let cpu = CString::new(cpu.as_bytes()).unwrap();
+        let features = CString::new(target_feature(sess).as_bytes()).unwrap();
         llvm::LLVMRustCreateTargetMachine(
             triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
             code_model,
@@ -380,7 +380,7 @@ struct HandlerFreeVars<'a> {
         }
 
         llvm::diagnostic::Optimization(opt) => {
-            let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name))
+            let pass_name = str::from_utf8(CStr::from_ptr(opt.pass_name).to_bytes())
                                 .ok()
                                 .expect("got a non-UTF8 pass name from LLVM");
             let enabled = match cgcx.remark {
@@ -424,7 +424,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     if config.emit_no_opt_bc {
         let ext = format!("{}.no-opt.bc", name_extra);
         let out = output_names.with_extension(&ext);
-        let out = CString::from_slice(out.as_vec());
+        let out = CString::new(out.as_vec()).unwrap();
         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
     }
 
@@ -440,7 +440,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
             // If we're verifying or linting, add them to the function pass
             // manager.
             let addpass = |pass: &str| {
-                let pass = CString::from_slice(pass.as_bytes());
+                let pass = CString::new(pass).unwrap();
                 llvm::LLVMRustAddPass(fpm, pass.as_ptr())
             };
             if !config.no_verify { assert!(addpass("verify")); }
@@ -453,7 +453,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
             }
 
             for pass in &config.passes {
-                let pass = CString::from_slice(pass.as_bytes());
+                let pass = CString::new(pass.clone()).unwrap();
                 if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
                     cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass));
                 }
@@ -477,7 +477,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                     if config.emit_lto_bc {
                         let name = format!("{}.lto.bc", name_extra);
                         let out = output_names.with_extension(&name);
-                        let out = CString::from_slice(out.as_vec());
+                        let out = CString::new(out.as_vec()).unwrap();
                         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
                     }
                 },
@@ -511,7 +511,7 @@ unsafe fn with_codegen<F>(tm: TargetMachineRef,
     if config.emit_bc {
         let ext = format!("{}.bc", name_extra);
         let out = output_names.with_extension(&ext);
-        let out = CString::from_slice(out.as_vec());
+        let out = CString::new(out.as_vec()).unwrap();
         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
     }
 
@@ -519,7 +519,7 @@ unsafe fn with_codegen<F>(tm: TargetMachineRef,
         if config.emit_ir {
             let ext = format!("{}.ll", name_extra);
             let out = output_names.with_extension(&ext);
-            let out = CString::from_slice(out.as_vec());
+            let out = CString::new(out.as_vec()).unwrap();
             with_codegen(tm, llmod, config.no_builtins, |cpm| {
                 llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
             })
@@ -1004,7 +1004,7 @@ unsafe fn configure_llvm(sess: &Session) {
     let mut llvm_args = Vec::new();
     {
         let mut add = |arg: &str| {
-            let s = CString::from_slice(arg.as_bytes());
+            let s = CString::new(arg).unwrap();
             llvm_args.push(s.as_ptr());
             llvm_c_strs.push(s);
         };
index e419be65fc4cc33f1a141aff8bf5e2dbf775d8c1..53c21d04a9297cb33bff730ef84a530d59d59eb4 100644 (file)
@@ -120,8 +120,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
         ast::AsmIntel => llvm::AD_Intel
     };
 
-    let asm = CString::from_slice(ia.asm.as_bytes());
-    let constraints = CString::from_slice(constraints.as_bytes());
+    let asm = CString::new(ia.asm.as_bytes()).unwrap();
+    let constraints = CString::new(constraints).unwrap();
     let r = InlineAsmCall(bcx,
                           asm.as_ptr(),
                           constraints.as_ptr(),
index 7f7b5cd800660abd835bd50e5b458d674cbab961..e136f61ce1cc8418b1c84326627710893b1dd29b 100644 (file)
@@ -86,7 +86,7 @@
 
 use arena::TypedArena;
 use libc::{c_uint, uint64_t};
-use std::ffi::{self, CString};
+use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
 use std::collections::HashSet;
 use std::mem;
@@ -186,7 +186,7 @@ fn drop(&mut self) {
 pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
                ty: Type, output: ty::FnOutput) -> ValueRef {
 
-    let buf = CString::from_slice(name.as_bytes());
+    let buf = CString::new(name).unwrap();
     let llfn: ValueRef = unsafe {
         llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
     };
@@ -340,7 +340,7 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
         None => ()
     }
     unsafe {
-        let buf = CString::from_slice(name.as_bytes());
+        let buf = CString::new(name.clone()).unwrap();
         let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr());
         // Thread-local statics in some other crate need to *always* be linked
         // against in a thread-local fashion, so we need to be sure to apply the
@@ -2788,7 +2788,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                                 &format!("Illegal null byte in export_name \
                                          value: `{}`", sym)[]);
                         }
-                        let buf = CString::from_slice(sym.as_bytes());
+                        let buf = CString::new(sym.clone()).unwrap();
                         let g = llvm::LLVMAddGlobal(ccx.llmod(), llty,
                                                     buf.as_ptr());
 
@@ -2826,7 +2826,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                                                  &sect)[]);
                     }
                     unsafe {
-                        let buf = CString::from_slice(sect.as_bytes());
+                        let buf = CString::new(sect.as_bytes()).unwrap();
                         llvm::LLVMSetSection(v, buf.as_ptr());
                     }
                 },
@@ -2993,7 +2993,7 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
     let name = format!("rust_metadata_{}_{}",
                        cx.link_meta().crate_name,
                        cx.link_meta().crate_hash);
-    let buf = CString::from_vec(name.into_bytes());
+    let buf = CString::new(name).unwrap();
     let llglobal = unsafe {
         llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(),
                             buf.as_ptr())
@@ -3001,7 +3001,7 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
         let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
-        let name = CString::from_slice(name.as_bytes());
+        let name = CString::new(name).unwrap();
         llvm::LLVMSetSection(llglobal, name.as_ptr())
     }
     return metadata;
@@ -3039,8 +3039,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
                     continue
                 }
 
-                let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
-                               .to_vec();
+                let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
+                                .to_bytes().to_vec();
                 declared.insert(name);
             }
         }
@@ -3056,8 +3056,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
                     continue
                 }
 
-                let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
-                               .to_vec();
+                let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
+                                .to_bytes().to_vec();
                 if !declared.contains(&name) &&
                    !reachable.contains(str::from_utf8(&name).unwrap()) {
                     llvm::SetLinkage(val, llvm::InternalLinkage);
index e268c2f0d5cc2b1dc766d7aab821f62e41894fe3..3bd0479c0d8e83e96a07e8b50ec0a3b3a0b27c59 100644 (file)
@@ -431,7 +431,7 @@ pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
             if name.is_empty() {
                 llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
             } else {
-                let name = CString::from_slice(name.as_bytes());
+                let name = CString::new(name).unwrap();
                 llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
                                       name.as_ptr())
             }
@@ -786,7 +786,7 @@ pub fn add_comment(&self, text: &str) {
             let comment_text = format!("{} {}", "#",
                                        sanitized.replace("\n", "\n\t# "));
             self.count_insn("inlineasm");
-            let comment_text = CString::from_vec(comment_text.into_bytes());
+            let comment_text = CString::new(comment_text).unwrap();
             let asm = unsafe {
                 llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
                                          comment_text.as_ptr(), noname(), False,
index d658003702dcaabbb90924dd1e326774dbad7a8e..85ba3f938fdf2fa96d923b0bcf863965303f043c 100644 (file)
@@ -488,7 +488,7 @@ pub fn new_block(&'a self,
                      opt_node_id: Option<ast::NodeId>)
                      -> Block<'a, 'tcx> {
         unsafe {
-            let name = CString::from_slice(name.as_bytes());
+            let name = CString::new(name).unwrap();
             let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
                                                            self.llfn,
                                                            name.as_ptr());
@@ -761,7 +761,7 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
 
 pub fn C_floating(s: &str, t: Type) -> ValueRef {
     unsafe {
-        let s = CString::from_slice(s.as_bytes());
+        let s = CString::new(s).unwrap();
         llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr())
     }
 }
@@ -839,7 +839,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
                                                 !null_terminated as Bool);
 
         let gsym = token::gensym("str");
-        let buf = CString::from_vec(format!("str{}", gsym.usize()).into_bytes());
+        let buf = CString::new(format!("str{}", gsym.usize()));
+        let buf = buf.unwrap();
         let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
         llvm::LLVMSetInitializer(g, sc);
         llvm::LLVMSetGlobalConstant(g, True);
index 96506291b5aae65e22e4db7c30f60f2abeb3c8e4..cd5aed6d84636f7786177315182852a15879a459 100644 (file)
@@ -225,15 +225,15 @@ fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> {
 
 unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
     let llcx = llvm::LLVMContextCreate();
-    let mod_name = CString::from_slice(mod_name.as_bytes());
+    let mod_name = CString::new(mod_name).unwrap();
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
-    let data_layout = &*sess.target.target.data_layout;
-    let data_layout = CString::from_slice(data_layout.as_bytes());
+    let data_layout = sess.target.target.data_layout.as_bytes();
+    let data_layout = CString::new(data_layout).unwrap();
     llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
 
-    let llvm_target = &*sess.target.target.llvm_target;
-    let llvm_target = CString::from_slice(llvm_target.as_bytes());
+    let llvm_target = sess.target.target.llvm_target.as_bytes();
+    let llvm_target = CString::new(llvm_target).unwrap();
     llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
     (llcx, llmod)
 }
index 23498089c5839cc2aad225b5acbb7f99ff5aa853..653ad1b2b630b46130e45ffd2ca0bf7ba58d7a48 100644 (file)
@@ -809,8 +809,8 @@ pub fn create_global_var_metadata(cx: &CrateContext,
         namespace_node.mangled_name_of_contained_item(&var_name[]);
     let var_scope = namespace_node.scope;
 
-    let var_name = CString::from_slice(var_name.as_bytes());
-    let linkage_name = CString::from_slice(linkage_name.as_bytes());
+    let var_name = CString::new(var_name).unwrap();
+    let linkage_name = CString::new(linkage_name).unwrap();
     unsafe {
         llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
                                                 var_scope,
@@ -1379,8 +1379,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
 
-    let function_name = CString::from_slice(function_name.as_bytes());
-    let linkage_name = CString::from_slice(linkage_name.as_bytes());
+    let function_name = CString::new(function_name).unwrap();
+    let linkage_name = CString::new(linkage_name).unwrap();
     let fn_metadata = unsafe {
         llvm::LLVMDIBuilderCreateFunction(
             DIB(cx),
@@ -1501,7 +1501,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 let ident = special_idents::type_self;
 
                 let ident = token::get_ident(ident);
-                let name = CString::from_slice(ident.as_bytes());
+                let name = CString::new(ident.as_bytes()).unwrap();
                 let param_metadata = unsafe {
                     llvm::LLVMDIBuilderCreateTemplateTypeParameter(
                         DIB(cx),
@@ -1535,7 +1535,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             if cx.sess().opts.debuginfo == FullDebugInfo {
                 let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
                 let ident = token::get_ident(ident);
-                let name = CString::from_slice(ident.as_bytes());
+                let name = CString::new(ident.as_bytes()).unwrap();
                 let param_metadata = unsafe {
                     llvm::LLVMDIBuilderCreateTemplateTypeParameter(
                         DIB(cx),
@@ -1601,7 +1601,7 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
                             path_bytes.insert(1, prefix[1]);
                         }
 
-                        CString::from_vec(path_bytes)
+                        CString::new(path_bytes).unwrap()
                     }
                     _ => fallback_path(cx)
                 }
@@ -1614,8 +1614,8 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
                            (option_env!("CFG_VERSION")).expect("CFG_VERSION"));
 
     let compile_unit_name = compile_unit_name.as_ptr();
-    let work_dir = CString::from_slice(work_dir.as_vec());
-    let producer = CString::from_slice(producer.as_bytes());
+    let work_dir = CString::new(work_dir.as_vec()).unwrap();
+    let producer = CString::new(producer).unwrap();
     let flags = "\0";
     let split_name = "\0";
     return unsafe {
@@ -1632,7 +1632,7 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
     };
 
     fn fallback_path(cx: &CrateContext) -> CString {
-        CString::from_slice(cx.link_meta().crate_name.as_bytes())
+        CString::new(cx.link_meta().crate_name.clone()).unwrap()
     }
 }
 
@@ -1658,7 +1658,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         CapturedVariable => (0, DW_TAG_auto_variable)
     };
 
-    let name = CString::from_slice(name.as_bytes());
+    let name = CString::new(name.as_bytes()).unwrap();
     match (variable_access, [].as_slice()) {
         (DirectVariable { alloca }, address_operations) |
         (IndirectVariable {alloca, address_operations}, _) => {
@@ -1724,8 +1724,8 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile {
             full_path
         };
 
-    let file_name = CString::from_slice(file_name.as_bytes());
-    let work_dir = CString::from_slice(work_dir.as_bytes());
+    let file_name = CString::new(file_name).unwrap();
+    let work_dir = CString::new(work_dir).unwrap();
     let file_metadata = unsafe {
         llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(),
                                       work_dir.as_ptr())
@@ -1800,7 +1800,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let llvm_type = type_of::type_of(cx, t);
     let (size, align) = size_and_align_of(cx, llvm_type);
-    let name = CString::from_slice(name.as_bytes());
+    let name = CString::new(name).unwrap();
     let ty_metadata = unsafe {
         llvm::LLVMDIBuilderCreateBasicType(
             DIB(cx),
@@ -1820,7 +1820,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let pointer_llvm_type = type_of::type_of(cx, pointer_type);
     let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
     let name = compute_debuginfo_type_name(cx, pointer_type, false);
-    let name = CString::from_slice(name.as_bytes());
+    let name = CString::new(name).unwrap();
     let ptr_metadata = unsafe {
         llvm::LLVMDIBuilderCreatePointerType(
             DIB(cx),
@@ -2445,7 +2445,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         .iter()
         .map(|v| {
             let token = token::get_name(v.name);
-            let name = CString::from_slice(token.as_bytes());
+            let name = CString::new(token.as_bytes()).unwrap();
             unsafe {
                 llvm::LLVMDIBuilderCreateEnumerator(
                     DIB(cx),
@@ -2475,7 +2475,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                   codemap::DUMMY_SP);
                 let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
 
-                let name = CString::from_slice(discriminant_name.as_bytes());
+                let name = CString::new(discriminant_name.as_bytes()).unwrap();
                 let discriminant_type_metadata = unsafe {
                     llvm::LLVMDIBuilderCreateEnumerationType(
                         DIB(cx),
@@ -2518,8 +2518,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                              .borrow()
                              .get_unique_type_id_as_string(unique_type_id);
 
-    let enum_name = CString::from_slice(enum_name.as_bytes());
-    let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes());
+    let enum_name = CString::new(enum_name).unwrap();
+    let unique_type_id_str = CString::new(unique_type_id_str.as_bytes()).unwrap();
     let enum_metadata = unsafe {
         llvm::LLVMDIBuilderCreateUnionType(
         DIB(cx),
@@ -2644,7 +2644,8 @@ fn set_members_of_composite_type(cx: &CrateContext,
                 ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
             };
 
-            let member_name = CString::from_slice(member_description.name.as_bytes());
+            let member_name = member_description.name.as_bytes();
+            let member_name = CString::new(member_name).unwrap();
             unsafe {
                 llvm::LLVMDIBuilderCreateMemberType(
                     DIB(cx),
@@ -2681,8 +2682,8 @@ fn create_struct_stub(cx: &CrateContext,
     let unique_type_id_str = debug_context(cx).type_map
                                               .borrow()
                                               .get_unique_type_id_as_string(unique_type_id);
-    let name = CString::from_slice(struct_type_name.as_bytes());
-    let unique_type_id = CString::from_slice(unique_type_id_str.as_bytes());
+    let name = CString::new(struct_type_name).unwrap();
+    let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap();
     let metadata_stub = unsafe {
         // LLVMDIBuilderCreateStructType() wants an empty array. A null
         // pointer will lead to hard to trace and debug LLVM assertions
@@ -3971,8 +3972,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTree
                         None => ptr::null_mut()
                     };
                     let namespace_name = token::get_name(name);
-                    let namespace_name = CString::from_slice(namespace_name
-                                                                .as_bytes());
+                    let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
                     let scope = unsafe {
                         llvm::LLVMDIBuilderCreateNameSpace(
                             DIB(cx),
@@ -4020,7 +4020,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTree
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
 pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) {
     if needs_gdb_debug_scripts_section(ccx) {
-        let empty = CString::from_slice(b"");
+        let empty = CString::new(b"").unwrap();
         let gdb_debug_scripts_section_global =
             get_or_insert_gdb_debug_scripts_section_global(ccx);
         unsafe {
index 8f0e4e647b5b3d1c8cceb646416d418b027ec037..f97f660a9e8a3f976227ea519f35cc3d703ff476 100644 (file)
@@ -135,7 +135,7 @@ pub fn register_static(ccx: &CrateContext,
             };
             unsafe {
                 // Declare a symbol `foo` with the desired linkage.
-                let buf = CString::from_slice(ident.as_bytes());
+                let buf = CString::new(ident.as_bytes()).unwrap();
                 let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(),
                                              buf.as_ptr());
                 llvm::SetLinkage(g1, linkage);
@@ -148,7 +148,7 @@ pub fn register_static(ccx: &CrateContext,
                 // zero.
                 let mut real_name = "_rust_extern_with_linkage_".to_string();
                 real_name.push_str(&ident);
-                let real_name = CString::from_vec(real_name.into_bytes());
+                let real_name = CString::new(real_name).unwrap();
                 let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(),
                                              real_name.as_ptr());
                 llvm::SetLinkage(g2, llvm::InternalLinkage);
@@ -158,7 +158,7 @@ pub fn register_static(ccx: &CrateContext,
         }
         None => unsafe {
             // Generate an external declaration.
-            let buf = CString::from_slice(ident.as_bytes());
+            let buf = CString::new(ident.as_bytes()).unwrap();
             llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr())
         }
     }
index af90e1ec5c5dd47cb85ee6c152386f2c4eb06bea..9e6867d48291a0e93a317160da0464486a1992c6 100644 (file)
@@ -513,7 +513,7 @@ pub fn declare_tydesc<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
     let llalign = llalign_of(ccx, llty);
     let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
     debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
-    let buf = CString::from_slice(name.as_bytes());
+    let buf = CString::new(name.clone()).unwrap();
     let gvar = unsafe {
         llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(),
                             buf.as_ptr())
index e3e4ca62c262f0f4931fd4691a4062f9ed3f2f41..ad83135a0d46fa3681df8b6f4d6bc2cb8b7d7d64 100644 (file)
@@ -163,7 +163,7 @@ pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
     }
 
     pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
-        let name = CString::from_slice(name.as_bytes());
+        let name = CString::new(name).unwrap();
         ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
     }
 
index a7cf5eb89187f2a99ac4b6133e33fea74d710062..eba915af519c83addd2a32c6c686e2bc894fe068 100644 (file)
@@ -112,7 +112,7 @@ pub struct Lock {
 
     impl Lock {
         pub fn new(p: &Path) -> Lock {
-            let buf = CString::from_slice(p.as_vec());
+            let buf = CString::from_slice(p.as_vec()).unwrap();
             let fd = unsafe {
                 libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
                            libc::S_IRWXU)
index c513fe2e8eb3cf2b44056a6d1395cf5669aa1cd2..3ceaec5f53d824fcdfbf2cd6bc547002f9d34467 100644 (file)
@@ -236,7 +236,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
                 s.push_str(&highlight::highlight(&text,
                                                  None,
                                                  Some("rust-example-rendered")));
-                let output = CString::from_vec(s.into_bytes());
+                let output = CString::from_vec(s.into_bytes()).unwrap();
                 hoedown_buffer_puts(ob, output.as_ptr());
             })
         }
@@ -293,7 +293,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
                                format!("{} ", sec)
                            });
 
-        let text = CString::from_vec(text.into_bytes());
+        let text = CString::from_vec(text.into_bytes()).unwrap();
         unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
     }
 
index c5dd66630b4201d908aacf9159743dddd9f23a17..b0fb9c29403511d13e42b274030523c50efbbf67 100644 (file)
@@ -112,7 +112,7 @@ pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
         // This function should have a lifetime constraint of 'a on
         // T but that feature is still unimplemented
 
-        let raw_string = CString::from_slice(symbol.as_bytes());
+        let raw_string = CString::new(symbol).unwrap();
         let maybe_symbol_value = dl::check_for_errors_in(|| {
             dl::symbol(self.handle, raw_string.as_ptr())
         });
@@ -187,7 +187,7 @@ fn test_errors_do_not_crash() {
 mod dl {
     use prelude::v1::*;
 
-    use ffi::{self, CString};
+    use ffi::{CString, CStr};
     use str;
     use libc;
     use ptr;
@@ -206,7 +206,7 @@ pub fn open(filename: Option<&[u8]>) -> Result<*mut u8, String> {
     const LAZY: libc::c_int = 1;
 
     unsafe fn open_external(filename: &[u8]) -> *mut u8 {
-        let s = CString::from_slice(filename);
+        let s = CString::new(filename).unwrap();
         dlopen(s.as_ptr(), LAZY) as *mut u8
     }
 
@@ -231,7 +231,7 @@ pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
             let ret = if ptr::null() == last_error {
                 Ok(result)
             } else {
-                let s = ffi::c_str_to_bytes(&last_error);
+                let s = CStr::from_ptr(last_error).to_bytes();
                 Err(str::from_utf8(s).unwrap().to_string())
             };
 
index 45089176cba961b97e285456ad2346e2e4787b9d..70c14ef1978293b3cf42226218acbd2908698a39 100644 (file)
@@ -8,18 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use error::{Error, FromError};
 use fmt;
+use io;
 use iter::IteratorExt;
 use libc;
 use mem;
+use old_io;
 use ops::Deref;
+use option::Option::{self, Some, None};
+use result::Result::{self, Ok, Err};
 use slice::{self, SliceExt};
+use str::StrExt;
 use string::String;
 use vec::Vec;
 
-/// A type representing a C-compatible string
+/// A type representing an owned C-compatible string
 ///
-/// This type serves the primary purpose of being able to generate a
+/// This type serves the primary purpose of being able to safely 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.
@@ -44,8 +51,8 @@
 ///     fn my_printer(s: *const libc::c_char);
 /// }
 ///
-/// let to_print = "Hello, world!";
-/// let c_to_print = CString::from_slice(to_print.as_bytes());
+/// let to_print = b"Hello, world!";
+/// let c_to_print = CString::new(to_print).unwrap();
 /// unsafe {
 ///     my_printer(c_to_print.as_ptr());
 /// }
 /// ```
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 pub struct CString {
-    inner: Vec<libc::c_char>,
+    inner: Vec<u8>,
+}
+
+/// Representation of a borrowed C string.
+///
+/// This dynamically sized type is only safely constructed via a borrowed
+/// version of an instance of `CString`. This type can be constructed from a raw
+/// C string as well and represents a C string borrowed from another location.
+///
+/// Note that this structure is **not** `repr(C)` and is not recommended to be
+/// placed in the signatures of FFI functions. Instead safe wrappers of FFI
+/// functions may leverage the unsafe `from_ptr` constructor to provide a safe
+/// interface to other consumers.
+///
+/// # Examples
+///
+/// Inspecting a foreign C string
+///
+/// ```no_run
+/// extern crate libc;
+/// use std::ffi::CStr;
+///
+/// extern { fn my_string() -> *const libc::c_char; }
+///
+/// fn main() {
+///     unsafe {
+///         let slice = CStr::from_ptr(my_string());
+///         println!("string length: {}", slice.to_bytes().len());
+///     }
+/// }
+/// ```
+///
+/// Passing a Rust-originating C string
+///
+/// ```no_run
+/// extern crate libc;
+/// use std::ffi::{CString, CStr};
+///
+/// fn work(data: &CStr) {
+///     extern { fn work_with(data: *const libc::c_char); }
+///
+///     unsafe { work_with(data.as_ptr()) }
+/// }
+///
+/// fn main() {
+///     let s = CString::from_slice(b"data data data data").unwrap();
+///     work(&s);
+/// }
+/// ```
+#[derive(Hash)]
+pub struct CStr {
+    inner: [libc::c_char]
+}
+
+/// An error returned from `CString::new` to indicate that a nul byte was found
+/// in the vector provided.
+#[derive(Clone, PartialEq, Debug)]
+pub struct NulError(usize, Vec<u8>);
+
+/// A conversion trait used by the constructor of `CString` for types that can
+/// be converted to a vector of bytes.
+pub trait IntoBytes {
+    /// Consumes this container, returning a vector of bytes.
+    fn into_bytes(self) -> Vec<u8>;
 }
 
 impl CString {
+    /// Create a new C-compatible string from a container of bytes.
+    ///
+    /// This method will consume the provided data and use the underlying bytes
+    /// to construct a new string, ensuring that there is a trailing 0 byte.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// extern crate libc;
+    /// use std::ffi::CString;
+    ///
+    /// extern { fn puts(s: *const libc::c_char); }
+    ///
+    /// fn main() {
+    ///     let to_print = CString::from_slice(b"Hello!").unwrap();
+    ///     unsafe {
+    ///         puts(to_print.as_ptr());
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the bytes yielded contain an
+    /// internal 0 byte. The error returned will contain the bytes as well as
+    /// the position of the nul byte.
+    pub fn new<T: IntoBytes>(t: T) -> Result<CString, NulError> {
+        let bytes = t.into_bytes();
+        match bytes.iter().position(|x| *x == 0) {
+            Some(i) => Err(NulError(i, bytes)),
+            None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+        }
+    }
+
     /// 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.
     ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// extern crate libc;
+    /// use std::ffi::CString;
+    ///
+    /// extern { fn puts(s: *const libc::c_char); }
+    ///
+    /// fn main() {
+    ///     let to_print = CString::from_slice(b"Hello!").unwrap();
+    ///     unsafe {
+    ///         puts(to_print.as_ptr());
+    ///     }
+    /// }
+    /// ```
+    ///
     /// # Panics
     ///
-    /// This function will panic if there are any 0 bytes already in the slice
-    /// provided.
+    /// This function will panic if the provided slice contains any
+    /// interior nul bytes.
+    #[unstable(feature = "std_misc")]
+    #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
+    #[allow(deprecated)]
     pub fn from_slice(v: &[u8]) -> CString {
         CString::from_vec(v.to_vec())
     }
@@ -77,11 +200,15 @@ pub fn from_slice(v: &[u8]) -> CString {
     ///
     /// # Panics
     ///
-    /// This function will panic if there are any 0 bytes already in the vector
-    /// provided.
+    /// This function will panic if the provided slice contains any
+    /// interior nul bytes.
+    #[unstable(feature = "std_misc")]
+    #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
     pub fn from_vec(v: Vec<u8>) -> CString {
-        assert!(!v.iter().any(|&x| x == 0));
-        unsafe { CString::from_vec_unchecked(v) }
+        match v.iter().position(|x| *x == 0) {
+            Some(i) => panic!("null byte found in slice at: {}", i),
+            None => unsafe { CString::from_vec_unchecked(v) },
+        }
     }
 
     /// Create a C-compatible string from a byte vector without checking for
@@ -91,31 +218,29 @@ pub fn from_vec(v: Vec<u8>) -> CString {
     /// 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) }
+        CString { inner: 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 }
-
-    /// Similar to the `as_slice` method, but returns a `u8` slice instead of a
-    /// `libc::c_char` slice.
+    /// Returns the contents of this `CString` as a slice of bytes.
+    ///
+    /// The returned slice does **not** contain the trailing nul separator and
+    /// it is guaranteet to not have any interior nul bytes.
     pub fn as_bytes(&self) -> &[u8] {
-        unsafe { mem::transmute(&**self) }
+        &self.inner[..self.inner.len() - 1]
     }
 
-    /// Equivalent to `as_slice_with_nul` except that the type returned is a
-    /// `u8` slice instead of a `libc::c_char` slice.
+    /// Equivalent to the `as_bytes` function except that the returned slice
+    /// includes the trailing nul byte.
     pub fn as_bytes_with_nul(&self) -> &[u8] {
-        unsafe { mem::transmute(self.as_slice_with_nul()) }
+        &self.inner
     }
 }
 
 impl Deref for CString {
-    type Target = [libc::c_char];
+    type Target = CStr;
 
-    fn deref(&self) -> &[libc::c_char] {
-        &self.inner[..(self.inner.len() - 1)]
+    fn deref(&self) -> &CStr {
+        unsafe { mem::transmute(self.as_bytes_with_nul()) }
     }
 }
 
@@ -126,54 +251,172 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// 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());
-/// }
-/// # }
-/// ```
+impl NulError {
+    /// Returns the position of the nul byte in the slice that was provided to
+    /// `CString::from_vec`.
+    pub fn nul_position(&self) -> usize { self.0 }
+
+    /// Consumes this error, returning the underlying vector of bytes which
+    /// generated the error in the first place.
+    pub fn into_vec(self) -> Vec<u8> { self.1 }
+}
+
+impl Error for NulError {
+    fn description(&self) -> &str { "nul byte found in data" }
+}
+
+impl fmt::Display for NulError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "nul byte found in provided data at position: {}", self.0)
+    }
+}
+
+impl FromError<NulError> for io::Error {
+    fn from_error(_: NulError) -> io::Error {
+        io::Error::new(io::ErrorKind::InvalidInput,
+                       "data provided contains a nul byte", None)
+    }
+}
+
+impl FromError<NulError> for old_io::IoError {
+    fn from_error(_: NulError) -> old_io::IoError {
+        old_io::IoError {
+            kind: old_io::IoErrorKind::InvalidInput,
+            desc: "data provided contains a nul byte",
+            detail: None
+        }
+    }
+}
+
+impl CStr {
+    /// Cast a raw C string to a safe C string wrapper.
+    ///
+    /// This function will cast the provided `ptr` to the `CStr` wrapper which
+    /// allows inspection and interoperation of non-owned C strings. This method
+    /// is unsafe for a number of reasons:
+    ///
+    /// * There is no guarantee to the validity of `ptr`
+    /// * The returned lifetime is not guaranteed to be the actual lifetime of
+    ///   `ptr`
+    /// * There is no guarantee that the memory pointed to by `ptr` contains a
+    ///   valid nul terminator byte at the end of the string.
+    ///
+    /// > **Note**: This operation is intended to be a 0-cost cast but it is
+    /// > currently implemented with an up-front calculation of the length of
+    /// > the string. This is not guaranteed to always be the case.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// # extern crate libc;
+    /// # fn main() {
+    /// use std::ffi::CStr;
+    /// use std::str;
+    /// use libc;
+    ///
+    /// extern {
+    ///     fn my_string() -> *const libc::c_char;
+    /// }
+    ///
+    /// unsafe {
+    ///     let slice = CStr::from_ptr(my_string());
+    ///     println!("string returned: {}",
+    ///              str::from_utf8(slice.to_bytes()).unwrap());
+    /// }
+    /// # }
+    /// ```
+    pub unsafe fn from_ptr<'a>(ptr: *const libc::c_char) -> &'a CStr {
+        let len = libc::strlen(ptr);
+        mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
+    }
+
+    /// Return the inner pointer to this C string.
+    ///
+    /// The returned pointer will be valid for as long as `self` is and points
+    /// to a continguous region of memory terminated with a 0 byte to represent
+    /// the end of the string.
+    pub fn as_ptr(&self) -> *const libc::c_char {
+        self.inner.as_ptr()
+    }
+
+    /// Convert this C string to a byte slice.
+    ///
+    /// This function will calculate the length of this string (which normally
+    /// requires a linear amount of work to be done) and then return the
+    /// resulting slice of `u8` elements.
+    ///
+    /// The returned slice will **not** contain the trailing nul that this C
+    /// string has.
+    ///
+    /// > **Note**: This method is currently implemented as a 0-cost cast, but
+    /// > it is planned to alter its definition in the future to perform the
+    /// > length calculation whenever this method is called.
+    pub fn to_bytes(&self) -> &[u8] {
+        let bytes = self.to_bytes_with_nul();
+        &bytes[..bytes.len() - 1]
+    }
+
+    /// Convert this C string to a byte slice containing the trailing 0 byte.
+    ///
+    /// This function is the equivalent of `to_bytes` except that it will retain
+    /// the trailing nul instead of chopping it off.
+    ///
+    /// > **Note**: This method is currently implemented as a 0-cost cast, but
+    /// > it is planned to alter its definition in the future to perform the
+    /// > length calculation whenever this method is called.
+    pub fn to_bytes_with_nul(&self) -> &[u8] {
+        unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.inner) }
+    }
+}
+
+impl PartialEq for CStr {
+    fn eq(&self, other: &CStr) -> bool {
+        self.to_bytes().eq(&other.to_bytes())
+    }
+}
+impl Eq for CStr {}
+impl PartialOrd for CStr {
+    fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
+        self.to_bytes().partial_cmp(&other.to_bytes())
+    }
+}
+impl Ord for CStr {
+    fn cmp(&self, other: &CStr) -> Ordering {
+        self.to_bytes().cmp(&other.to_bytes())
+    }
+}
+
+/// Deprecated in favor of `CStr`
+#[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")]
 pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
     let len = libc::strlen(*raw);
     slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
 }
 
-/// 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] {
+/// Deprecated in favor of `CStr`
+#[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0",
+             reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")]
+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_parts(*(raw as *const _ as *const *const u8), len as usize)
 }
 
+impl<'a> IntoBytes for &'a str {
+    fn into_bytes(self) -> Vec<u8> { self.as_bytes().to_vec() }
+}
+impl<'a> IntoBytes for &'a [u8] {
+    fn into_bytes(self) -> Vec<u8> { self.to_vec() }
+}
+impl IntoBytes for String {
+    fn into_bytes(self) -> Vec<u8> { self.into_bytes() }
+}
+impl IntoBytes for Vec<u8> {
+    fn into_bytes(self) -> Vec<u8> { self }
+}
+
 #[cfg(test)]
 mod tests {
     use prelude::v1::*;
@@ -193,21 +436,19 @@ fn c_to_rust() {
 
     #[test]
     fn simple() {
-        let s = CString::from_slice(b"1234");
+        let s = CString::from_slice(b"1234").unwrap();
         assert_eq!(s.as_bytes(), b"1234");
         assert_eq!(s.as_bytes_with_nul(), b"1234\0");
-        unsafe {
-            assert_eq!(&*s,
-                       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_zero1() {
+        assert!(CString::from_slice(b"\0").is_err());
+    }
+    #[test]
+    fn build_with_zero2() {
+        assert!(CString::from_vec(vec![0]).is_err());
+    }
 
     #[test]
     fn build_with_zero3() {
@@ -219,7 +460,16 @@ fn build_with_zero3() {
 
     #[test]
     fn formatted() {
-        let s = CString::from_slice(b"12");
+        let s = CString::from_slice(b"12").unwrap();
         assert_eq!(format!("{:?}", s), "\"12\"");
     }
+
+    #[test]
+    fn borrowed() {
+        unsafe {
+            let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
+            assert_eq!(s.to_bytes(), b"12");
+            assert_eq!(s.to_bytes_with_nul(), b"12\0");
+        }
+    }
 }
index 07a4f17796c4994f14638ac3258ee15a0da40b4e..1bff6afb776079b0e5102ad2b0e92541d089263c 100644 (file)
             reason = "module just underwent fairly large reorganization and the dust \
                       still needs to settle")]
 
-pub use self::c_str::CString;
+pub use self::c_str::{CString, CStr, NulError, IntoBytes};
+#[allow(deprecated)]
 pub use self::c_str::c_str_to_bytes;
+#[allow(deprecated)]
 pub use self::c_str::c_str_to_bytes_with_nul;
 
 pub use self::os_str::OsString;
index 6b32d936c05bec0e8352b373dbdf88ec81c20dfa..392a253d7336683c13b19943dc10bbc8eae6de43 100644 (file)
@@ -55,7 +55,7 @@ impl UnixStream {
     /// stream.write(&[1, 2, 3]);
     /// ```
     pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> {
-        let path = CString::from_slice(path.container_as_bytes());
+        let path = try!(CString::new(path.container_as_bytes()));
         UnixStreamImp::connect(&path, None)
             .map(|inner| UnixStream { inner: inner })
     }
@@ -77,7 +77,7 @@ pub fn connect_timeout<P>(path: P, timeout: Duration)
             return Err(standard_error(TimedOut));
         }
 
-        let path = CString::from_slice(path.container_as_bytes());
+        let path = try!(CString::new(path.container_as_bytes()));
         UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64))
             .map(|inner| UnixStream { inner: inner })
     }
@@ -184,7 +184,7 @@ impl UnixListener {
     /// # }
     /// ```
     pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> {
-        let path = CString::from_slice(path.container_as_bytes());
+        let path = try!(CString::new(path.container_as_bytes()));
         UnixListenerImp::bind(&path)
             .map(|inner| UnixListener { inner: inner })
     }
index ea6510c61b76be626372d567d9c4818d43228f0c..c761bf705a81ff3022bebd2184163789a6fc80c7 100644 (file)
@@ -204,7 +204,7 @@ impl Command {
     /// otherwise configure the process.
     pub fn new<T: BytesContainer>(program: T) -> Command {
         Command {
-            program: CString::from_slice(program.container_as_bytes()),
+            program: CString::new(program.container_as_bytes()).unwrap(),
             args: Vec::new(),
             env: None,
             cwd: None,
@@ -219,14 +219,14 @@ pub fn new<T: BytesContainer>(program: T) -> Command {
 
     /// Add an argument to pass to the program.
     pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
-        self.args.push(CString::from_slice(arg.container_as_bytes()));
+        self.args.push(CString::new(arg.container_as_bytes()).unwrap());
         self
     }
 
     /// Add multiple arguments to pass to the program.
     pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
         self.args.extend(args.iter().map(|arg| {
-            CString::from_slice(arg.container_as_bytes())
+            CString::new(arg.container_as_bytes()).unwrap()
         }));
         self
     }
@@ -239,8 +239,8 @@ fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
                 // if the env is currently just inheriting from the parent's,
                 // materialize the parent's env into a hashtable.
                 self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
-                    (EnvKey(CString::from_slice(&k)),
-                     CString::from_slice(&v))
+                    (EnvKey(CString::new(k).unwrap()),
+                     CString::new(v).unwrap())
                 }).collect());
                 self.env.as_mut().unwrap()
             }
@@ -254,8 +254,8 @@ fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
     pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
                          -> &'a mut Command
                          where T: BytesContainer, U: BytesContainer {
-        let key = EnvKey(CString::from_slice(key.container_as_bytes()));
-        let val = CString::from_slice(val.container_as_bytes());
+        let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
+        let val = CString::new(val.container_as_bytes()).unwrap();
         self.get_env_map().insert(key, val);
         self
     }
@@ -263,7 +263,7 @@ pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
     /// Removes an environment variable mapping.
     pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
                              where T: BytesContainer {
-        let key = EnvKey(CString::from_slice(key.container_as_bytes()));
+        let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
         self.get_env_map().remove(&key);
         self
     }
@@ -276,15 +276,15 @@ pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
                                  -> &'a mut Command
                                  where T: BytesContainer, U: BytesContainer {
         self.env = Some(env.iter().map(|&(ref k, ref v)| {
-            (EnvKey(CString::from_slice(k.container_as_bytes())),
-             CString::from_slice(v.container_as_bytes()))
+            (EnvKey(CString::new(k.container_as_bytes()).unwrap()),
+             CString::new(v.container_as_bytes()).unwrap())
         }).collect());
         self
     }
 
     /// Set the working directory for the child process.
     pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
-        self.cwd = Some(CString::from_slice(dir.as_vec()));
+        self.cwd = Some(CString::new(dir.as_vec()).unwrap());
         self
     }
 
@@ -1226,7 +1226,7 @@ fn env_map_keys_ci() {
         cmd.env("path", "foo");
         cmd.env("Path", "bar");
         let env = &cmd.env.unwrap();
-        let val = env.get(&EnvKey(CString::from_slice(b"PATH")));
-        assert!(val.unwrap() == &CString::from_slice(b"bar"));
+        let val = env.get(&EnvKey(CString::new(b"PATH").unwrap()));
+        assert!(val.unwrap() == &CString::new(b"bar").unwrap());
     }
 }
index c2f5133eaf3fe5547a3fd450274d0948d127cee4..61f5bd0f013606f37f2e4476acf3b155c5f7f6af 100644 (file)
@@ -49,7 +49,7 @@ mod imp {
 
     use libc;
     use mem;
-    use ffi;
+    use ffi::CStr;
 
     use sync::{StaticMutex, MUTEX_INIT};
 
@@ -96,10 +96,11 @@ fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
         unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
     }
 
-    unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec<Vec<u8>> {
+    unsafe fn load_argc_and_argv(argc: isize,
+                                 argv: *const *const u8) -> Vec<Vec<u8>> {
         let argv = argv as *const *const libc::c_char;
-        (0..argc as uint).map(|i| {
-            ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
+        (0..argc).map(|i| {
+            CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
         }).collect()
     }
 
index 7325e0a5ac8ddfaeb3726aeca06be0c723b5d987..e2ac5ac24f89ec01269f0eb545a58d381e296b46 100644 (file)
@@ -12,8 +12,7 @@
 use self::SocketStatus::*;
 use self::InAddr::*;
 
-use ffi::CString;
-use ffi;
+use ffi::{CString, CStr};
 use old_io::net::addrinfo;
 use old_io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
 use old_io::{IoResult, IoError};
@@ -235,9 +234,15 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>,
 
     assert!(host.is_some() || servname.is_some());
 
-    let c_host = host.map(|x| CString::from_slice(x.as_bytes()));
+    let c_host = match host {
+        Some(x) => Some(try!(CString::new(x))),
+        None => None,
+    };
     let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
-    let c_serv = servname.map(|x| CString::from_slice(x.as_bytes()));
+    let c_serv = match servname {
+        Some(x) => Some(try!(CString::new(x))),
+        None => None,
+    };
     let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
 
     let hint = hint.map(|hint| {
@@ -325,8 +330,8 @@ pub fn get_address_name(addr: IpAddr) -> Result<String, IoError> {
     }
 
     unsafe {
-        Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr()))
-               .unwrap().to_string())
+        let data = CStr::from_ptr(hostbuf.as_ptr());
+        Ok(str::from_utf8(data.to_bytes()).unwrap().to_string())
     }
 }
 
index 5af59ec6d2b1473ae3b513bf420c0eff0400eb96..713f79c5d0814d29b64d0936779ce547cd3ce29c 100644 (file)
@@ -121,7 +121,7 @@ fn drop(&mut self) {
 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
     init();
 
-    let c_host = CString::from_slice(host.as_bytes());
+    let c_host = try!(CString::new(host));
     let mut res = 0 as *mut _;
     unsafe {
         try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
index 5e512e9261b1dfe475ec84ecad7adcb36c608c44..8b560339f304474c6cb67d523d69a138f7c2341f 100644 (file)
@@ -85,7 +85,7 @@
 
 use prelude::v1::*;
 
-use ffi;
+use ffi::CStr;
 use old_io::IoResult;
 use libc;
 use mem;
@@ -233,7 +233,7 @@ fn dladdr(addr: *const libc::c_void,
         output(w, idx,addr, None)
     } else {
         output(w, idx, addr, Some(unsafe {
-            ffi::c_str_to_bytes(&info.dli_sname)
+            CStr::from_ptr(info.dli_sname).to_bytes()
         }))
     }
 }
@@ -364,7 +364,7 @@ unsafe fn init_state() -> *mut backtrace_state {
     if ret == 0 || data.is_null() {
         output(w, idx, addr, None)
     } else {
-        output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) }))
+        output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() }))
     }
 }
 
index bbbe022fbaf619ce9c5cbef9dd978aa97888e2b0..b8b9dcfb3c68920b2602ed2e1e22072ac5d106be 100644 (file)
@@ -33,7 +33,7 @@
 
 use prelude::v1::*;
 
-use ffi::{CString, OsStr, OsString};
+use ffi::{CString, NulError, OsStr, OsString};
 use fs::{self, Permissions, OpenOptions};
 use net;
 use mem;
@@ -155,7 +155,7 @@ pub trait OsStrExt {
     fn as_bytes(&self) -> &[u8];
 
     /// Convert the `OsStr` slice into a `CString`.
-    fn to_cstring(&self) -> CString;
+    fn to_cstring(&self) -> Result<CString, NulError>;
 }
 
 impl OsStrExt for OsStr {
@@ -166,8 +166,8 @@ fn as_bytes(&self) -> &[u8] {
         &self.as_inner().inner
     }
 
-    fn to_cstring(&self) -> CString {
-        CString::from_slice(self.as_bytes())
+    fn to_cstring(&self) -> Result<CString, NulError> {
+        CString::new(self.as_bytes())
     }
 }
 
@@ -249,5 +249,7 @@ fn signal(&self) -> Option<i32> {
 /// Includes all extension traits, and some important type definitions.
 pub mod prelude {
     #[doc(no_inline)]
-    pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt, CommandExt, ExitStatusExt};
+    pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt};
+    #[doc(no_inline)]
+    pub use super::{CommandExt, ExitStatusExt};
 }
index 0ee2b5b68090ede1123950edbb95c94059d8ed8a..5c847002d2394f35c1f4d7cb9c142f40edbe2de6 100644 (file)
@@ -12,7 +12,7 @@
 
 use prelude::v1::*;
 
-use ffi::{self, CString};
+use ffi::{CString, CStr};
 use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
 use old_io::{IoResult, FileStat, SeekStyle};
 use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
@@ -151,8 +151,8 @@ fn drop(&mut self) {
     }
 }
 
-fn cstr(path: &Path) -> CString {
-    CString::from_slice(path.as_vec())
+fn cstr(path: &Path) -> IoResult<CString> {
+    Ok(try!(CString::new(path.as_vec())))
 }
 
 pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
@@ -170,7 +170,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
                             libc::S_IRUSR | libc::S_IWUSR),
     };
 
-    let path = cstr(path);
+    let path = try!(cstr(path));
     match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
         -1 => Err(super::last_error()),
         fd => Ok(FileDesc::new(fd, true)),
@@ -178,7 +178,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
 }
 
 pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
 }
 
@@ -203,7 +203,7 @@ fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
     let mut buf = Vec::<u8>::with_capacity(size as uint);
     let ptr = buf.as_mut_ptr() as *mut dirent_t;
 
-    let p = CString::from_slice(p.as_vec());
+    let p = try!(CString::new(p.as_vec()));
     let dir_ptr = unsafe {opendir(p.as_ptr())};
 
     if dir_ptr as uint != 0 {
@@ -212,7 +212,7 @@ fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
         while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
             if entry_ptr.is_null() { break }
             paths.push(unsafe {
-                Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr)))
+                Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes())
             });
         }
         assert_eq!(unsafe { closedir(dir_ptr) }, 0);
@@ -223,39 +223,39 @@ fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
 }
 
 pub fn unlink(p: &Path) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
 }
 
 pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
-    let old = cstr(old);
-    let new = cstr(new);
+    let old = try!(cstr(old));
+    let new = try!(cstr(new));
     mkerr_libc(unsafe {
         libc::rename(old.as_ptr(), new.as_ptr())
     })
 }
 
 pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     mkerr_libc(retry(|| unsafe {
         libc::chmod(p.as_ptr(), mode as libc::mode_t)
     }))
 }
 
 pub fn rmdir(p: &Path) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
 }
 
 pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     mkerr_libc(retry(|| unsafe {
         libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
     }))
 }
 
 pub fn readlink(p: &Path) -> IoResult<Path> {
-    let c_path = cstr(p);
+    let c_path = try!(cstr(p));
     let p = c_path.as_ptr();
     let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
     if len == -1 {
@@ -276,14 +276,14 @@ pub fn readlink(p: &Path) -> IoResult<Path> {
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
-    let src = cstr(src);
-    let dst = cstr(dst);
+    let src = try!(cstr(src));
+    let dst = try!(cstr(dst));
     mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
 }
 
 pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
-    let src = cstr(src);
-    let dst = cstr(dst);
+    let src = try!(cstr(src));
+    let dst = try!(cstr(dst));
     mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
 }
 
@@ -331,7 +331,7 @@ fn gen(_stat: &libc::stat) -> u64 { 0 }
 }
 
 pub fn stat(p: &Path) -> IoResult<FileStat> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let mut stat: libc::stat = unsafe { mem::zeroed() };
     match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
         0 => Ok(mkstat(&stat)),
@@ -340,7 +340,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> {
 }
 
 pub fn lstat(p: &Path) -> IoResult<FileStat> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let mut stat: libc::stat = unsafe { mem::zeroed() };
     match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
         0 => Ok(mkstat(&stat)),
@@ -349,7 +349,7 @@ pub fn lstat(p: &Path) -> IoResult<FileStat> {
 }
 
 pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let buf = libc::utimbuf {
         actime: (atime / 1000) as libc::time_t,
         modtime: (mtime / 1000) as libc::time_t,
index e5904b074bcb980cc3fe502b2671de8daf52c4d3..92a47c6c3850df3a34b3ac132e83f72314db86d6 100644 (file)
@@ -12,7 +12,7 @@
 use io::prelude::*;
 use os::unix::prelude::*;
 
-use ffi::{self, CString, OsString, AsOsStr, OsStr};
+use ffi::{CString, CStr, OsString, AsOsStr, OsStr};
 use io::{self, Error, Seek, SeekFrom};
 use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t};
 use mem;
@@ -147,8 +147,7 @@ fn name_bytes(&self) -> &[u8] {
             fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
         }
         unsafe {
-            let ptr = rust_list_dir_val(self.dirent);
-            ffi::c_str_to_bytes(mem::copy_lifetime(self, &ptr))
+            CStr::from_ptr(rust_list_dir_val(self.dirent)).to_bytes()
         }
     }
 }
@@ -204,7 +203,7 @@ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
             (true, false) |
             (false, false) => libc::O_RDONLY,
         };
-        let path = cstr(path);
+        let path = try!(cstr(path));
         let fd = try!(cvt_r(|| unsafe {
             libc::open(path.as_ptr(), flags, opts.mode)
         }));
@@ -268,19 +267,20 @@ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
     pub fn fd(&self) -> &FileDesc { &self.0 }
 }
 
-fn cstr(path: &Path) -> CString {
-    CString::from_slice(path.as_os_str().as_bytes())
+fn cstr(path: &Path) -> io::Result<CString> {
+    let cstring = try!(path.as_os_str().to_cstring());
+    Ok(cstring)
 }
 
 pub fn mkdir(p: &Path) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) }));
     Ok(())
 }
 
 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     let root = Rc::new(p.to_path_buf());
-    let p = cstr(p);
+    let p = try!(cstr(p));
     unsafe {
         let ptr = libc::opendir(p.as_ptr());
         if ptr.is_null() {
@@ -292,32 +292,32 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     try!(cvt(unsafe { libc::unlink(p.as_ptr()) }));
     Ok(())
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let old = cstr(old);
-    let new = cstr(new);
+    let old = try!(cstr(old));
+    let new = try!(cstr(new));
     try!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }));
     Ok(())
 }
 
 pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     try!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }));
     Ok(())
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     try!(cvt(unsafe { libc::rmdir(p.as_ptr()) }));
     Ok(())
 }
 
 pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     try!(cvt_r(|| unsafe {
         libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
     }));
@@ -325,7 +325,7 @@ pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let c_path = cstr(p);
+    let c_path = try!(cstr(p));
     let p = c_path.as_ptr();
     let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
     if len < 0 {
@@ -343,35 +343,35 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> {
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
-    let src = cstr(src);
-    let dst = cstr(dst);
+    let src = try!(cstr(src));
+    let dst = try!(cstr(dst));
     try!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }));
     Ok(())
 }
 
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
-    let src = cstr(src);
-    let dst = cstr(dst);
+    let src = try!(cstr(src));
+    let dst = try!(cstr(dst));
     try!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }));
     Ok(())
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let mut stat: libc::stat = unsafe { mem::zeroed() };
     try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }));
     Ok(FileAttr { stat: stat })
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let mut stat: libc::stat = unsafe { mem::zeroed() };
     try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }));
     Ok(FileAttr { stat: stat })
 }
 
 pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
-    let p = cstr(p);
+    let p = try!(cstr(p));
     let buf = [super::ms_to_timeval(atime), super::ms_to_timeval(mtime)];
     try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }));
     Ok(())
index 850189140d1eb494ff9717159d1602779b0d87dd..b79ad7031fa48dc31dcc208036ae5f5bf353eaf1 100644 (file)
@@ -17,7 +17,7 @@
 
 use prelude::v1::*;
 
-use ffi;
+use ffi::CStr;
 use io::{self, ErrorKind};
 use libc;
 use num::{Int, SignedInt};
@@ -91,7 +91,8 @@ pub fn last_gai_error(s: libc::c_int) -> IoError {
 
     let mut err = decode_error(s);
     err.detail = Some(unsafe {
-        str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string()
+        let data = CStr::from_ptr(gai_strerror(s));
+        str::from_utf8(data.to_bytes()).unwrap().to_string()
     });
     err
 }
index 54aec7cf4b193a9b25cea06d4062969752ac5ebc..83b6a14b78d95fd3f1ed4d8c385ec550bbb63d11 100644 (file)
@@ -10,7 +10,7 @@
 
 use prelude::v1::*;
 
-use ffi;
+use ffi::CStr;
 use io;
 use libc::{self, c_int, size_t};
 use str;
@@ -31,7 +31,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
     if err == 0 { return Ok(()) }
 
     let detail = unsafe {
-        str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap()
+        str::from_utf8(CStr::from_ptr(c::gai_strerror(err)).to_bytes()).unwrap()
             .to_string()
     };
     Err(io::Error::new(io::ErrorKind::Other,
index df03841276e9e483cf22444cd9e6cc4f1559f1f2..ad56555997ff8237f17f7f2f08d3ccf2a4b465be 100644 (file)
@@ -14,7 +14,7 @@
 use os::unix::*;
 
 use error::Error as StdError;
-use ffi::{self, CString, OsString, OsStr, AsOsStr};
+use ffi::{CString, CStr, OsString, OsStr, AsOsStr};
 use fmt;
 use iter;
 use libc::{self, c_int, c_char, c_void};
@@ -88,7 +88,7 @@ fn strerror_r(errnum: c_int, buf: *mut c_char,
         }
 
         let p = p as *const _;
-        str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string()
+        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string()
     }
 }
 
@@ -98,13 +98,13 @@ pub fn getcwd() -> IoResult<Path> {
         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
             Err(IoError::last_error())
         } else {
-            Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr())))
+            Ok(Path::new(CStr::from_ptr(buf.as_ptr()).to_bytes()))
         }
     }
 }
 
 pub fn chdir(p: &Path) -> IoResult<()> {
-    let p = CString::from_slice(p.as_vec());
+    let p = CString::new(p.as_vec()).unwrap();
     unsafe {
         match libc::chdir(p.as_ptr()) == (0 as c_int) {
             true => Ok(()),
@@ -211,7 +211,7 @@ pub fn current_exe() -> IoResult<Path> {
         if v.is_null() {
             Err(IoError::last_error())
         } else {
-            Ok(Path::new(ffi::c_str_to_bytes(&v).to_vec()))
+            Ok(Path::new(CStr::from_ptr(&v).to_bytes().to_vec()))
         }
     }
 }
@@ -266,7 +266,7 @@ pub fn args() -> Args {
         let (argc, argv) = (*_NSGetArgc() as isize,
                             *_NSGetArgv() as *const *const c_char);
         range(0, argc as isize).map(|i| {
-            let bytes = ffi::c_str_to_bytes(&*argv.offset(i)).to_vec();
+            let bytes = CStr::from_ptr(&*argv.offset(i)).to_bytes().to_vec();
             OsStringExt::from_vec(bytes)
         }).collect::<Vec<_>>()
     };
@@ -324,7 +324,7 @@ pub fn args() -> Args {
             let tmp = objc_msgSend(args, object_at_sel, i);
             let utf_c_str: *const libc::c_char =
                 mem::transmute(objc_msgSend(tmp, utf8_sel));
-            let bytes = ffi::c_str_to_bytes(&utf_c_str);
+            let bytes = CStr::from_ptr(utf_c_str).to_bytes();
             res.push(OsString::from_str(str::from_utf8(bytes).unwrap()))
         }
     }
@@ -380,7 +380,7 @@ pub fn env() -> Env {
         }
         let mut result = Vec::new();
         while *environ != ptr::null() {
-            result.push(parse(ffi::c_str_to_bytes(&*environ)));
+            result.push(parse(CStr::from_ptr(*environ).to_bytes()));
             environ = environ.offset(1);
         }
         Env { iter: result.into_iter(), _dont_send_or_sync_me: 0 as *mut _ }
@@ -397,20 +397,20 @@ fn parse(input: &[u8]) -> (OsString, OsString) {
 
 pub fn getenv(k: &OsStr) -> Option<OsString> {
     unsafe {
-        let s = CString::from_slice(k.as_bytes());
+        let s = k.to_cstring().unwrap();
         let s = libc::getenv(s.as_ptr()) as *const _;
         if s.is_null() {
             None
         } else {
-            Some(OsStringExt::from_vec(ffi::c_str_to_bytes(&s).to_vec()))
+            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
         }
     }
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) {
     unsafe {
-        let k = CString::from_slice(k.as_bytes());
-        let v = CString::from_slice(v.as_bytes());
+        let k = k.to_cstring().unwrap();
+        let v = v.to_cstring().unwrap();
         if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 {
             panic!("failed setenv: {}", IoError::last_error());
         }
@@ -419,7 +419,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) {
 
 pub fn unsetenv(n: &OsStr) {
     unsafe {
-        let nbuf = CString::from_slice(n.as_bytes());
+        let nbuf = n.to_cstring().unwrap();
         if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
             panic!("failed unsetenv: {}", IoError::last_error());
         }
@@ -480,7 +480,7 @@ unsafe fn fallback() -> Option<OsString> {
                 _ => return None
             }
             let ptr = passwd.pw_dir as *const _;
-            let bytes = ffi::c_str_to_bytes(&ptr).to_vec();
+            let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
             return Some(OsStringExt::from_vec(bytes))
         }
     }
index 45d5b1506c3aaf13145740f055c5f78075b2d0d3..3c9cdc65975f6f9f5e1b7027774b2a7dd0fa564f 100644 (file)
@@ -38,7 +38,7 @@ fn addr_to_sockaddr_un(addr: &CString,
             mem::size_of::<libc::sockaddr_un>());
     let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) };
 
-    let len = addr.len();
+    let len = addr.as_bytes().len();
     if len > s.sun_path.len() - 1 {
         return Err(IoError {
             kind: old_io::InvalidInput,
@@ -47,8 +47,8 @@ fn addr_to_sockaddr_un(addr: &CString,
         })
     }
     s.sun_family = libc::AF_UNIX as libc::sa_family_t;
-    for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) {
-        *slot = *value;
+    for (slot, value) in s.sun_path.iter_mut().zip(addr.as_bytes().iter()) {
+        *slot = *value as libc::c_char;
     }
 
     // count the null terminator
index 5e2c207f3756ae545c9e184a52f56ce64e1189ef..0e78efa209683a3efc4cb9c5709945d5c1b1321a 100644 (file)
@@ -46,7 +46,7 @@ pub struct Command {
 impl Command {
     pub fn new(program: &OsStr) -> Command {
         Command {
-            program: program.to_cstring(),
+            program: program.to_cstring().unwrap(),
             args: Vec::new(),
             env: None,
             cwd: None,
@@ -57,10 +57,10 @@ pub fn new(program: &OsStr) -> Command {
     }
 
     pub fn arg(&mut self, arg: &OsStr) {
-        self.args.push(arg.to_cstring())
+        self.args.push(arg.to_cstring().unwrap())
     }
     pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) {
-        self.args.extend(args.map(OsStrExt::to_cstring))
+        self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap()))
     }
     fn init_env_map(&mut self) {
         if self.env.is_none() {
@@ -79,7 +79,7 @@ pub fn env_clear(&mut self) {
         self.env = Some(HashMap::new())
     }
     pub fn cwd(&mut self, dir: &OsStr) {
-        self.cwd = Some(dir.to_cstring())
+        self.cwd = Some(dir.to_cstring().unwrap())
     }
 }
 
index 82c52471d109719ef99d0e5aab5a6fa4103a434f..c90ba7645feb4b29f14a6b6854804c6d79d617e9 100644 (file)
@@ -237,7 +237,7 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
 pub unsafe fn set_name(name: &str) {
     // pthread_setname_np() since glibc 2.12
     // availability autodetected via weak linkage
-    let cname = CString::from_slice(name.as_bytes());
+    let cname = CString::new(name).unwrap();
     type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char) -> libc::c_int;
     extern {
         #[linkage = "extern_weak"]
@@ -255,14 +255,14 @@ pub unsafe fn set_name(name: &str) {
           target_os = "openbsd"))]
 pub unsafe fn set_name(name: &str) {
     // pthread_set_name_np() since almost forever on all BSDs
-    let cname = CString::from_slice(name.as_bytes());
+    let cname = CString::new(name).unwrap();
     pthread_set_name_np(pthread_self(), cname.as_ptr());
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub unsafe fn set_name(name: &str) {
     // pthread_setname_np() since OS X 10.6 and iOS 3.2
-    let cname = CString::from_slice(name.as_bytes());
+    let cname = CString::new(name).unwrap();
     pthread_setname_np(cname.as_ptr());
 }
 
index 83a4d938bb5d5567ef9af4fc4fea835aa4e2d2e8..b7a758a00d55da65217655ec0499ef20cfd3b982 100644 (file)
@@ -618,22 +618,25 @@ fn print_macro_backtrace(w: &mut EmitterWriter,
                          cm: &codemap::CodeMap,
                          sp: Span)
                          -> old_io::IoResult<()> {
-    let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| match expn_info {
-        Some(ei) => {
-            let ss = ei.callee.span.map_or(String::new(), |span| cm.span_to_string(span));
-            let (pre, post) = match ei.callee.format {
-                codemap::MacroAttribute => ("#[", "]"),
-                codemap::MacroBang => ("", "!")
-            };
-            try!(print_diagnostic(w, &ss[], Note,
-                                  &format!("in expansion of {}{}{}", pre,
-                                          ei.callee.name,
-                                          post)[], None));
-            let ss = cm.span_to_string(ei.call_site);
-            try!(print_diagnostic(w, &ss[], Note, "expansion site", None));
-            Ok(Some(ei.call_site))
-        }
-        None => Ok(None)
+    let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> old_io::IoResult<_> {
+        match expn_info {
+            Some(ei) => {
+                let ss = ei.callee.span.map_or(String::new(),
+                                               |span| cm.span_to_string(span));
+                let (pre, post) = match ei.callee.format {
+                    codemap::MacroAttribute => ("#[", "]"),
+                    codemap::MacroBang => ("", "!")
+                };
+                try!(print_diagnostic(w, &ss[], Note,
+                                      &format!("in expansion of {}{}{}", pre,
+                                              ei.callee.name,
+                                              post)[], None));
+                let ss = cm.span_to_string(ei.call_site);
+                try!(print_diagnostic(w, &ss[], Note, "expansion site", None));
+                Ok(Some(ei.call_site))
+            }
+            None => Ok(None)
+    }
     }));
     cs.map_or(Ok(()), |call_site| print_macro_backtrace(w, cm, call_site))
 }
index 22c322b86c97963d800c3485a482d2c7aa2d846d..d18a3055b9c814662c8f08aa9e5328731ef99b31 100644 (file)
@@ -24,12 +24,12 @@ mod mlibc {
 }
 
 fn atol(s: String) -> int {
-    let c = CString::from_slice(s.as_bytes());
+    let c = CString::from_slice(s.as_bytes()).unwrap();
     unsafe { mlibc::atol(c.as_ptr()) as int }
 }
 
 fn atoll(s: String) -> i64 {
-    let c = CString::from_slice(s.as_bytes());
+    let c = CString::from_slice(s.as_bytes()).unwrap();
     unsafe { mlibc::atoll(c.as_ptr()) as i64 }
 }
 
index dff1a1eaa0473aaf7b3a3225051da1d5072ad8ff..25d0cbbcdb6d3a4772a95daa9d9308f6f14b4eb7 100644 (file)
@@ -24,7 +24,7 @@ mod mlibc {
 
 fn strlen(str: String) -> uint {
     // C string is terminated with a zero
-    let s = CString::from_slice(str.as_bytes());
+    let s = CString::from_slice(str.as_bytes()).unwrap();
     unsafe {
         mlibc::my_strlen(s.as_ptr()) as uint
     }
index 12e4f27a64f21f51924aadaa7f89fe32992aea1a..1282720d4cb3686b10773b998c9ada7ff3198dda 100644 (file)
@@ -31,12 +31,12 @@ fn rename_directory() {
         let test_file = &old_path.join("temp.txt");
 
         /* Write the temp input file */
-        let fromp = CString::from_slice(test_file.as_vec());
-        let modebuf = CString::from_slice(b"w+b");
+        let fromp = CString::from_slice(test_file.as_vec()).unwrap();
+        let modebuf = CString::from_slice(b"w+b").unwrap();
         let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr());
         assert!((ostream as uint != 0u));
         let s = "hello".to_string();
-        let buf = CString::from_slice(b"hello");
+        let buf = CString::from_slice(b"hello").unwrap();
         let write_len = libc::fwrite(buf.as_ptr() as *mut _,
                                      1u as libc::size_t,
                                      (s.len() + 1u) as libc::size_t,
index a729fedb27157a6d64fad9ac0aab0371141fa9a2..85f6ef0ddcd1bcd5e63c7c1059793d4e0e4e926c 100644 (file)
@@ -29,11 +29,11 @@ pub fn main() {
 
     unsafe {
         // Call with just the named parameter
-        let c = CString::from_slice(b"Hello World\n");
+        let c = CString::from_slice(b"Hello World\n").unwrap();
         check("Hello World\n", |s| sprintf(s, c.as_ptr()));
 
         // Call with variable number of arguments
-        let c = CString::from_slice(b"%d %f %c %s\n");
+        let c = CString::from_slice(b"%d %f %c %s\n").unwrap();
         check("42 42.500000 a %d %f %c %s\n\n", |s| {
             sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
         });
@@ -44,11 +44,11 @@ pub fn main() {
         // A function that takes a function pointer
         unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
             // Call with just the named parameter
-            let c = CString::from_slice(b"Hello World\n");
+            let c = CString::from_slice(b"Hello World\n").unwrap();
             check("Hello World\n", |s| sprintf(s, c.as_ptr()));
 
             // Call with variable number of arguments
-            let c = CString::from_slice(b"%d %f %c %s\n");
+            let c = CString::from_slice(b"%d %f %c %s\n").unwrap();
             check("42 42.500000 a %d %f %c %s\n\n", |s| {
                 sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
             });