diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index b8808eaf57d..7ee1c1a7032 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -451,7 +451,7 @@ them. ~~~no_run extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; use std::ptr; #[link(name = "readline")] @@ -460,11 +460,10 @@ extern { } fn main() { - "[my-awesome-shell] $".with_c_str(|buf| { - unsafe { rl_prompt = buf; } - // get a line, process it - unsafe { rl_prompt = ptr::null(); } - }); + let prompt = CString::from_slice(b"[my-awesome-shell] $"); + unsafe { rl_prompt = prompt.as_ptr(); } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } } ~~~ @@ -509,23 +508,28 @@ to define a block for all windows systems, not just x86 ones. # Interoperability with foreign code -Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C -only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out -struct members without padding. `#[repr(C)]` can also be applied to an enum. +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. -Rust's owned boxes (`Box`) use non-nullable pointers as handles which point to the contained -object. However, they should not be manually created because they are managed by internal -allocators. References can safely be assumed to be non-nullable pointers directly to the type. -However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer -using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about -them. +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. -Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and -`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a -NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function. +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. -The standard library includes type aliases and function definitions for the C standard library in -the `libc` module, and Rust links against `libc` and `libm` by default. +The standard library includes type aliases and function definitions for the C +standard library in the `libc` module, and Rust links against `libc` and `libm` +by default. # The "nullable pointer optimization" diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e7451331908..11e6c48cfdb 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -320,30 +320,6 @@ impl String { } } - /// Creates a `String` from a null-terminated `*const u8` buffer. - /// - /// This function is unsafe because we dereference memory until we find the - /// NUL character, which is not guaranteed to be present. Additionally, the - /// slice is not checked to see whether it contains valid UTF-8 - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf(buf: *const u8) -> String { - String::from_str(str::from_c_str(buf as *const i8)) - } - - /// Creates a `String` from a `*const u8` buffer of the given length. - /// - /// This function is unsafe because it blindly assumes the validity of the - /// pointer `buf` for `len` bytes of memory. This function will copy the - /// memory from `buf` into a new allocation (owned by the returned - /// `String`). - /// - /// This function is also unsafe because it does not validate that the - /// buffer is valid UTF-8 encoded data. - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String { - String::from_utf8_unchecked(Vec::from_raw_buf(buf, len)) - } - /// Converts a vector of bytes to a new `String` without checking if /// it contains valid UTF-8. This is unsafe because it assumes that /// the UTF-8-ness of the vector has already been validated. @@ -1126,24 +1102,6 @@ mod tests { String::from_str("\u{FFFD}𐒋\u{FFFD}")); } - #[test] - fn test_from_buf_len() { - unsafe { - let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0]; - assert_eq!(String::from_raw_buf_len(a.as_ptr(), 3), String::from_str("AAA")); - } - } - - #[test] - fn test_from_buf() { - unsafe { - let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; - let b = a.as_ptr(); - let c = String::from_raw_buf(b); - assert_eq!(c, String::from_str("AAAAAAA")); - } - } - #[test] fn test_push_bytes() { let mut s = String::from_str("ABC"); diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da..8fdd66f83ce 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -190,7 +190,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { /// # Panics /// /// This function will panic if the string pointed to by `s` is not valid UTF-8. -#[unstable = "may change location based on the outcome of the c_str module"] +#[deprecated = "use std::ffi::c_str_to_bytes + str::from_utf8"] pub unsafe fn from_c_str(s: *const i8) -> &'static str { let s = s as *const u8; let mut len = 0u; diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index aa1550ae5b8..a0c9da3ae6d 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -21,15 +21,34 @@ #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(phase, unboxed_closures)] +#![feature(phase, unboxed_closures, associated_types)] #[cfg(test)] #[phase(plugin, link)] extern crate log; extern crate libc; use libc::{c_void, size_t, c_int}; -use std::c_vec::CVec; +use std::ops::Deref; use std::ptr::Unique; +use std::slice; + +pub struct Bytes { + ptr: Unique, + len: uint, +} + +impl Deref for Bytes { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_mut_buf(&self.ptr.0, self.len) } + } +} + +impl Drop for Bytes { + fn drop(&mut self) { + unsafe { libc::free(self.ptr.0 as *mut _); } + } +} #[link(name = "miniz", kind = "static")] extern { @@ -52,7 +71,7 @@ static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, @@ -60,8 +79,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -69,16 +88,16 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Option> { +pub fn deflate_bytes(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM) } /// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -86,8 +105,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -95,12 +114,12 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Option> { +pub fn inflate_bytes(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, 0) } /// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 2f4acaca4de..ec0b80c3a53 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -23,8 +23,8 @@ use metadata::loader; use util::nodemap::{FnvHashMap, NodeMap}; use std::cell::RefCell; -use std::c_vec::CVec; use std::rc::Rc; +use flate::Bytes; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::IdentInterner; @@ -36,7 +36,7 @@ use syntax::parse::token::IdentInterner; pub type cnum_map = FnvHashMap; pub enum MetadataBlob { - MetadataVec(CVec), + MetadataVec(Bytes), MetadataArchive(loader::ArchiveMetadata), } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index c18bd421b3b..7c0645b4ca2 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -226,7 +226,7 @@ use syntax::codemap::Span; use syntax::diagnostic::SpanHandler; use util::fs; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cmp; use std::collections::{HashMap, HashSet}; use std::io::fs::PathExtensions; @@ -720,9 +720,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result Result Option { unsafe { - let ar = dst.with_c_str(|dst| { - ::LLVMRustOpenArchive(dst) - }); + let s = CString::from_slice(dst.as_vec()); + let ar = ::LLVMRustOpenArchive(s.as_ptr()); if ar.is_null() { None } else { @@ -45,9 +44,9 @@ impl ArchiveRO { pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> { unsafe { let mut size = 0 as libc::size_t; - let ptr = file.with_c_str(|file| { - ::LLVMRustArchiveReadSection(self.ptr, file, &mut size) - }); + let file = CString::from_slice(file.as_bytes()); + let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(), + &mut size); if ptr.is_null() { None } else { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 2ec5f37634a..854ac5ff5c0 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -47,7 +47,7 @@ pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::RefCell; use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; @@ -2114,10 +2114,9 @@ impl Drop for TargetData { } pub fn mk_target_data(string_rep: &str) -> TargetData { + let string_rep = CString::from_slice(string_rep.as_bytes()); TargetData { - lltd: string_rep.with_c_str(|buf| { - unsafe { LLVMCreateTargetData(buf) } - }) + lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index c6488ec6638..f3e90c43a84 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -20,7 +20,7 @@ use rustc::util::common::time; use libc; use flate; -use std::c_str::ToCStr; +use std::ffi::CString; use std::iter; use std::mem; use std::num::Int; @@ -139,9 +139,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } // Internalize everything but the reachable symbols of the current module - let cstrs: Vec<::std::c_str::CString> = - reachable.iter().map(|s| s.to_c_str()).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let cstrs: Vec = reachable.iter().map(|s| { + CString::from_slice(s.as_bytes()) + }).collect(); + let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, @@ -164,7 +165,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); let builder = llvm::LLVMPassManagerBuilderCreate(); llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm, @@ -172,7 +173,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, /* RunInliner = */ True); llvm::LLVMPassManagerBuilderDispose(builder); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); time(sess.time_passes(), "LTO passes", (), |()| llvm::LLVMRunPassManager(pm, llmod)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 33011d9e35c..089d7f737d3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,7 +22,7 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level, mk_handler}; -use std::c_str::{ToCStr, CString}; +use std::ffi::{mod, CString}; use std::io::Command; use std::io::fs; use std::iter::Unfold; @@ -32,7 +32,7 @@ use std::mem; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{c_uint, c_int, c_void}; +use libc::{mod, c_uint, c_int, c_void}; #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { @@ -49,8 +49,9 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { if cstr == ptr::null() { handler.fatal(msg[]); } else { - let err = CString::new(cstr, true); - let err = String::from_utf8_lossy(err.as_bytes()); + let err = ffi::c_str_to_bytes(&cstr); + let err = String::from_utf8_lossy(err.as_slice()).to_string(); + libc::free(cstr as *mut _); handler.fatal(format!("{}: {}", msg[], err[])[]); @@ -66,13 +67,12 @@ pub fn write_output_file( output: &Path, file_type: llvm::FileType) { unsafe { - output.with_c_str(|output| { - let result = llvm::LLVMRustWriteOutputFile( - target, pm, m, output, file_type); - if !result { - llvm_err(handler, "could not write output".to_string()); - } - }) + let output = CString::from_slice(output.as_vec()); + let result = llvm::LLVMRustWriteOutputFile( + target, pm, m, output.as_ptr(), file_type); + if !result { + llvm_err(handler, "could not write output".to_string()); + } } } @@ -221,28 +221,25 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let triple = sess.target.target.llvm_target[]; let tm = unsafe { - triple.with_c_str(|t| { - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => s[], - None => sess.target.target.options.cpu[] - }; - cpu.with_c_str(|cpu| { - target_feature(sess).with_c_str(|features| { - llvm::LLVMRustCreateTargetMachine( - t, cpu, features, - code_model, - reloc_model, - opt_level, - true /* EnableSegstk */, - use_softfp, - no_fp_elim, - !any_library && reloc_model == llvm::RelocPIC, - ffunction_sections, - fdata_sections, - ) - }) - }) - }) + let triple = CString::from_slice(triple.as_bytes()); + let cpu = match sess.opts.cg.target_cpu { + Some(ref s) => s.as_slice(), + None => sess.target.target.options.cpu.as_slice() + }; + let cpu = CString::from_slice(cpu.as_bytes()); + let features = CString::from_slice(target_feature(sess).as_bytes()); + llvm::LLVMRustCreateTargetMachine( + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + code_model, + reloc_model, + opt_level, + true /* EnableSegstk */, + use_softfp, + no_fp_elim, + !any_library && reloc_model == llvm::RelocPIC, + ffunction_sections, + fdata_sections, + ) }; if tm.is_null() { @@ -371,8 +368,9 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::Optimization(opt) => { - let pass_name = CString::new(opt.pass_name, false); - let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM"); + let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name)) + .ok() + .expect("got a non-UTF8 pass name from LLVM"); let enabled = match cgcx.remark { AllPasses => true, SomePasses(ref v) => v.iter().any(|s| *s == pass_name), @@ -416,9 +414,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_no_opt_bc { let ext = format!("{}.no-opt.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } match config.opt_level { @@ -433,7 +431,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. let addpass = |&: pass: &str| { - pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s)) + let pass = CString::from_slice(pass.as_bytes()); + llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; if !config.no_verify { assert!(addpass("verify")); } @@ -445,12 +444,11 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } for pass in config.passes.iter() { - pass.with_c_str(|s| { - if !llvm::LLVMRustAddPass(mpm, s) { - cgcx.handler.warn(format!("unknown pass {}, ignoring", - *pass)[]); - } - }) + let pass = CString::from_slice(pass.as_bytes()); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.warn(format!("unknown pass {}, ignoring", + pass).as_slice()); + } } // Finally, run the actual optimization passes @@ -470,9 +468,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_lto_bc { let name = format!("{}.lto.bc", name_extra); - output_names.with_extension(name[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(name.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } }, _ => {}, @@ -504,18 +502,18 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_bc { let ext = format!("{}.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } time(config.time_passes, "codegen passes", (), |()| { if config.emit_ir { let ext = format!("{}.ll", name_extra); - output_names.with_extension(ext[]).with_c_str(|output| { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, output); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + with_codegen(tm, llmod, config.no_builtins, |cpm| { + llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); }) } @@ -995,7 +993,7 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_args = Vec::new(); { let mut add = |&mut : arg: &str| { - let s = arg.to_c_str(); + let s = CString::from_slice(arg.as_bytes()); llvm_args.push(s.as_ptr()); llvm_c_strs.push(s); }; @@ -1083,7 +1081,7 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, match opt { llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - "mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s)); + llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); } _ => {} }; diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 5597e112f76..f18d483f703 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -20,9 +20,8 @@ use trans::expr; use trans::type_of; use trans::type_::Type; -use std::c_str::ToCStr; -use std::string::String; use syntax::ast; +use std::ffi::CString; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM @@ -121,18 +120,16 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) ast::AsmIntel => llvm::AD_Intel }; - let r = ia.asm.get().with_c_str(|a| { - constraints.with_c_str(|c| { - InlineAsmCall(bcx, - a, - c, - inputs[], + let asm = CString::from_slice(ia.asm.get().as_bytes()); + let constraints = CString::from_slice(constraints.as_bytes()); + let r = InlineAsmCall(bcx, + asm.as_ptr(), + constraints.as_ptr(), + inputs.as_slice(), output_type, ia.volatile, ia.alignstack, - dialect) - }) - }); + dialect); // Again, based on how many outputs we have if num_outputs == 1 { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 56c1e2ddba0..7031710c679 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -88,11 +88,12 @@ use util::nodemap::NodeMap; use arena::TypedArena; use libc::{c_uint, uint64_t}; -use std::c_str::ToCStr; +use std::ffi::{mod, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::mem; use std::rc::Rc; +use std::str; use std::{i8, i16, i32, i64}; use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; use syntax::ast_util::local_def; @@ -187,11 +188,10 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, ty: Type, output: ty::FnOutput) -> ValueRef { - let llfn: ValueRef = name.with_c_str(|buf| { - unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref()) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let llfn: ValueRef = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) + }; // diverging functions may unwind, but can never return normally if output == ty::FnDiverging { @@ -331,9 +331,8 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, None => () } unsafe { - let c = name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf) - }); + let buf = CString::from_slice(name.as_bytes()); + 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 // thread-local attribute locally if it was present remotely. If we @@ -472,15 +471,17 @@ pub fn set_always_inline(f: ValueRef) { } pub fn set_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } pub fn unset_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } // Double-check that we never ask LLVM to declare the same symbol twice. It @@ -534,11 +535,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Structural comparison: a rather involved form of glue. pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { if cx.sess().opts.cg.save_temps { - s.with_c_str(|buf| { - unsafe { - llvm::LLVMSetValueName(v, buf) - } - }) + let buf = CString::from_slice(s.as_bytes()); + unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) } } } @@ -2639,11 +2637,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext, unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) } } - let llbb = "top".with_c_str(|buf| { - unsafe { - llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf) - } - }); + let llbb = unsafe { + llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, + "top\0".as_ptr() as *const _) + }; let bld = ccx.raw_builder(); unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); @@ -2664,9 +2661,9 @@ pub fn create_entry_wrapper(ccx: &CrateContext, }; let args = { - let opaque_rust_main = "rust_main".with_c_str(|buf| { - llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf) - }); + let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, + rust_main, Type::i8p(ccx).to_ref(), + "rust_main\0".as_ptr() as *const _); vec!( opaque_rust_main, @@ -2773,9 +2770,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { format!("Illegal null byte in export_name \ value: `{}`", sym)[]); } - let g = sym.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty, buf) - }); + let buf = CString::from_slice(sym.as_bytes()); + let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, + buf.as_ptr()); if attr::contains_name(i.attrs[], "thread_local") { @@ -2817,9 +2814,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sect.get())[]); } unsafe { - sect.get().with_c_str(|buf| { - llvm::LLVMSetSection(v, buf); - }) + let buf = CString::from_slice(sect.get().as_bytes()); + llvm::LLVMSetSection(v, buf.as_ptr()); } }, None => () @@ -2986,17 +2982,16 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { let name = format!("rust_metadata_{}_{}", cx.link_meta().crate_name, cx.link_meta().crate_hash); - let llglobal = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf) - } - }); + let buf = CString::from_vec(name.into_bytes()); + let llglobal = unsafe { + llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), + buf.as_ptr()) + }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx); - name.with_c_str(|buf| { - llvm::LLVMSetSection(llglobal, buf) - }); + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMSetSection(llglobal, name.as_ptr()) } return metadata; } @@ -3004,8 +2999,6 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { - use std::c_str::CString; - unsafe { let mut declared = HashSet::new(); @@ -3035,7 +3028,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); declared.insert(name); } } @@ -3051,9 +3045,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); if !declared.contains(&name) && - !reachable.contains(name.as_str().unwrap()) { + !reachable.contains(str::from_utf8(name.as_slice()).unwrap()) { llvm::SetLinkage(val, llvm::InternalLinkage); } } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index 97f0b92a290..e09d36ddae9 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -20,7 +20,8 @@ use trans::machine::llalign_of_pref; use trans::type_::Type; use util::nodemap::FnvHashMap; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; + +use std::ffi::CString; use syntax::codemap::Span; pub struct Builder<'a, 'tcx: 'a> { @@ -429,9 +430,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { - name.with_c_str(|c| { - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c) - }) + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), + name.as_ptr()) } } } @@ -774,12 +775,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let comment_text = format!("{} {}", "#", sanitized.replace("\n", "\n\t# ")); self.count_insn("inlineasm"); - let asm = comment_text.with_c_str(|c| { - unsafe { - llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), - c, noname(), False, False) - } - }); + let comment_text = CString::from_vec(comment_text.into_bytes()); + let asm = unsafe { + llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), + comment_text.as_ptr(), noname(), False, + False) + }; self.call(asm, &[], None); } } @@ -926,9 +927,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let t: ValueRef = "llvm.trap".with_c_str(|buf| { - llvm::LLVMGetNamedFunction(m, buf) - }); + let p = "llvm.trap\0".as_ptr(); + let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); assert!((t as int != 0)); let args: &[ValueRef] = &[]; self.count_insn("trap"); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index e8dee19ed54..094f98e988a 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -44,7 +44,7 @@ use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::vec::Vec; use syntax::ast::Ident; @@ -401,9 +401,8 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { if self.llreturn.get().is_none() { self.llreturn.set(Some(unsafe { - "return".with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf) - }) + llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, + "return\0".as_ptr() as *const _) })) } @@ -429,11 +428,10 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { opt_node_id: Option) -> Block<'a, 'tcx> { unsafe { - let llbb = name.with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), - self.llfn, - buf) - }); + let name = CString::from_slice(name.as_bytes()); + let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), + self.llfn, + name.as_ptr()); BlockS::new(llbb, is_lpad, opt_node_id, self) } } @@ -708,7 +706,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf)) + let s = CString::from_slice(s.as_bytes()); + llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr()) } } @@ -789,9 +788,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let g = format!("str{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf) - }); + let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); @@ -815,9 +813,10 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { let lldata = C_bytes(cx, data); let gsym = token::gensym("binary"); - let g = format!("binary{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf) - }); + let name = format!("binary{}", gsym.uint()); + let name = CString::from_vec(name.into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), + name.as_ptr()); llvm::LLVMSetInitializer(g, lldata); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 7e47c8f3b95..a3861e71d83 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -24,7 +24,6 @@ use middle::subst::Substs; use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; -use std::c_str::ToCStr; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; @@ -103,9 +102,8 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr, pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { unsafe { - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name) - }); + let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), + "const\0".as_ptr() as *const _); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, if mutbl == ast::MutImmutable {True} else {False}); diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index e5a0e2e9234..f974a6faf4c 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -29,8 +29,8 @@ use util::ppaux::Repr; use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; -use std::c_str::ToCStr; use std::ptr; use std::rc::Rc; use syntax::ast; @@ -221,21 +221,16 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); - let llmod = mod_name.with_c_str(|buf| { - llvm::LLVMModuleCreateWithNameInContext(buf, llcx) - }); - sess.target - .target - .data_layout - .with_c_str(|buf| { - llvm::LLVMSetDataLayout(llmod, buf); - }); - sess.target - .target - .llvm_target - .with_c_str(|buf| { - llvm::LLVMRustSetNormalizedTarget(llmod, buf); - }); + let mod_name = CString::from_slice(mod_name.as_bytes()); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + let data_layout = sess.target.target.data_layout.as_slice(); + let data_layout = CString::from_slice(data_layout.as_bytes()); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_slice(); + let llvm_target = CString::from_slice(llvm_target.as_bytes()); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); (llcx, llmod) } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 84ae088f5be..f6c09629f31 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -207,7 +207,7 @@ use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; use util::ppaux; use libc::c_uint; -use std::c_str::{CString, ToCStr}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::{Rc, Weak}; @@ -755,14 +755,15 @@ pub fn finalize(cx: &CrateContext) { // for OS X to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. if cx.sess().target.target.options.is_like_osx { - "Dwarf Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2)); + llvm::LLVMRustAddModuleFlag(cx.llmod(), + "Dwarf Version\0".as_ptr() as *const _, + 2) } // Prevent bitcode readers from deleting the debug info. - "Debug Info Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, - llvm::LLVMRustDebugMetadataVersion)); + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _, + llvm::LLVMRustDebugMetadataVersion); }; } @@ -824,22 +825,20 @@ pub fn create_global_var_metadata(cx: &CrateContext, namespace_node.mangled_name_of_contained_item(var_name[]); let var_scope = namespace_node.scope; - var_name.with_c_str(|var_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name, - linkage_name, - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); - } - }) - }); + let var_name = CString::from_slice(var_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); + } } /// Creates debug information for the given local variable. @@ -1383,28 +1382,26 @@ 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 fn_metadata = function_name.with_c_str(|function_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name, - linkage_name, - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - FlagPrototyped as c_uint, - cx.sess().opts.optimize != config::No, - llfn, - template_parameters, - ptr::null_mut()) - } - }) - }); + let function_name = CString::from_slice(function_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + let fn_metadata = unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + FlagPrototyped as c_uint, + cx.sess().opts.optimize != config::No, + llfn, + template_parameters, + ptr::null_mut()) + }; let scope_map = create_scope_map(cx, fn_decl.inputs.as_slice(), @@ -1509,19 +1506,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let ident = special_idents::type_self; - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_self_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_self_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } @@ -1544,19 +1540,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == FullDebugInfo { let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP); - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } } @@ -1601,19 +1596,19 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { } else { match abs_path.path_relative_from(work_dir) { Some(ref p) if p.is_relative() => { - // prepend "./" if necessary - let dotdot = b".."; - let prefix = [dotdot[0], ::std::path::SEP_BYTE]; - let mut path_bytes = p.as_vec().to_vec(); + // prepend "./" if necessary + let dotdot = b".."; + let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE]; + let mut path_bytes = p.as_vec().to_vec(); - if path_bytes.slice_to(2) != prefix && - path_bytes.slice_to(2) != dotdot { - path_bytes.insert(0, prefix[0]); - path_bytes.insert(1, prefix[1]); - } - - path_bytes.to_c_str() + if path_bytes.slice_to(2) != prefix && + path_bytes.slice_to(2) != dotdot { + path_bytes.insert(0, prefix[0]); + path_bytes.insert(1, prefix[1]); } + + CString::from_vec(path_bytes) + } _ => fallback_path(cx) } } @@ -1625,29 +1620,25 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); - return work_dir.as_vec().with_c_str(|work_dir| { - producer.with_c_str(|producer| { - "".with_c_str(|flags| { - "".with_c_str(|split_name| { - unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, - DW_LANG_RUST, - compile_unit_name, - work_dir, - producer, - cx.sess().opts.optimize != config::No, - flags, - 0, - split_name) - } - }) - }) - }) - }); + let work_dir = CString::from_slice(work_dir.as_vec()); + let producer = CString::from_slice(producer.as_bytes()); + let flags = "\0"; + let split_name = "\0"; + return unsafe { + llvm::LLVMDIBuilderCreateCompileUnit( + debug_context(cx).builder, + DW_LANG_RUST, + compile_unit_name, + work_dir.as_ptr(), + producer.as_ptr(), + cx.sess().opts.optimize != config::No, + flags.as_ptr() as *const _, + 0, + split_name.as_ptr() as *const _) + }; fn fallback_path(cx: &CrateContext) -> CString { - cx.link_meta().crate_name.to_c_str() + CString::from_slice(cx.link_meta().crate_name.as_bytes()) } } @@ -1673,42 +1664,41 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, CapturedVariable => (0, DW_TAG_auto_variable) }; - let (var_alloca, var_metadata) = name.get().with_c_str(|name| { - match variable_access { - DirectVariable { alloca } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::No, - 0, - argument_index) - } - ), - IndirectVariable { alloca, address_operations } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateComplexVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - argument_index) - } - ) - } - }); + let name = CString::from_slice(name.get().as_bytes()); + let (var_alloca, var_metadata) = match variable_access { + DirectVariable { alloca } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::No, + 0, + argument_index) + } + ), + IndirectVariable { alloca, address_operations } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + argument_index) + } + ) + }; set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, @@ -1753,14 +1743,12 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile { full_path }; - let file_metadata = - file_name.with_c_str(|file_name| { - work_dir.with_c_str(|work_dir| { - unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) - } - }) - }); + let file_name = CString::from_slice(file_name.as_bytes()); + let work_dir = CString::from_slice(work_dir.as_bytes()); + let file_metadata = unsafe { + llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) + }; let mut created_files = debug_context(cx).created_files.borrow_mut(); created_files.insert(full_path.to_string(), file_metadata); @@ -1788,16 +1776,14 @@ fn scope_metadata(fcx: &FunctionContext, } fn diverging_type_metadata(cx: &CrateContext) -> DIType { - "!".with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(0), - bytes_to_bits(0), - DW_ATE_unsigned) - } - }) + unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + "!\0".as_ptr() as *const _, + bytes_to_bits(0), + bytes_to_bits(0), + DW_ATE_unsigned) + } } fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -1833,16 +1819,15 @@ 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 ty_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(size), - bytes_to_bits(align), - encoding) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ty_metadata = unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr(), + bytes_to_bits(size), + bytes_to_bits(align), + encoding) + }; return ty_metadata; } @@ -1854,16 +1839,15 @@ 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 ptr_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align), - name) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ptr_metadata = unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + bytes_to_bits(pointer_size), + bytes_to_bits(pointer_align), + name.as_ptr()) + }; return ptr_metadata; } @@ -2473,14 +2457,14 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enumerators_metadata: Vec = variants .iter() .map(|v| { - token::get_name(v.name).get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerator( - DIB(cx), - name, - v.disr_val as u64) - } - }) + let token = token::get_name(v.name); + let name = CString::from_slice(token.get().as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + v.disr_val as u64) + } }) .collect(); @@ -2504,20 +2488,19 @@ 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 discriminant_type_metadata = discriminant_name.get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align), - create_DIArray(DIB(cx), enumerators_metadata[]), - discriminant_base_type_metadata) - } - }); + let name = CString::from_slice(discriminant_name.get().as_bytes()); + let discriminant_type_metadata = unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata.as_slice()), + discriminant_base_type_metadata) + }; debug_context(cx).created_enum_disr_types .borrow_mut() @@ -2548,24 +2531,22 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .borrow() .get_unique_type_id_as_string(unique_type_id); - let enum_metadata = enum_name.with_c_str(|enum_name| { - unique_type_id_str.with_c_str(|unique_type_id_str| { - unsafe { - llvm::LLVMDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align), - 0, // Flags - ptr::null_mut(), - 0, // RuntimeLang - unique_type_id_str) - } - }) - }); + 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_metadata = unsafe { + llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + ptr::null_mut(), + 0, // RuntimeLang + unique_type_id_str.as_ptr()) + }; return create_and_register_recursive_type_forward_declaration( cx, @@ -2676,21 +2657,20 @@ fn set_members_of_composite_type(cx: &CrateContext, ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i) }; - member_description.name.with_c_str(|member_name| { - unsafe { - llvm::LLVMDIBuilderCreateMemberType( - DIB(cx), - composite_type_metadata, - member_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(member_size), - bytes_to_bits(member_align), - bytes_to_bits(member_offset), - member_description.flags, - member_description.type_metadata) - } - }) + let member_name = CString::from_slice(member_description.name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + member_description.flags, + member_description.type_metadata) + } }) .collect(); @@ -2714,30 +2694,28 @@ 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 metadata_stub = unsafe { - struct_type_name.with_c_str(|name| { - unique_type_id_str.with_c_str(|unique_type_id| { - // LLVMDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); + // LLVMDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); - llvm::LLVMDIBuilderCreateStructType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(struct_size), - bytes_to_bits(struct_align), - 0, - ptr::null_mut(), - empty_array, - 0, - ptr::null_mut(), - unique_type_id) - }) - }) + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(struct_size), + bytes_to_bits(struct_align), + 0, + ptr::null_mut(), + empty_array, + 0, + ptr::null_mut(), + unique_type_id.as_ptr()) }; return metadata_stub; @@ -4011,18 +3989,18 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc ptr::null_mut() }; let namespace_name = token::get_name(name); - let scope = namespace_name.get().with_c_str(|namespace_name| { - unsafe { - llvm::LLVMDIBuilderCreateNameSpace( - DIB(cx), - parent_scope, - namespace_name, - // cannot reconstruct file ... - ptr::null_mut(), - // ... or line information, but that's not so important. - 0) - } - }); + let namespace_name = CString::from_slice(namespace_name + .get().as_bytes()); + let scope = unsafe { + llvm::LLVMDIBuilderCreateNameSpace( + DIB(cx), + parent_scope, + namespace_name.as_ptr(), + // cannot reconstruct file ... + ptr::null_mut(), + // ... or line information, but that's not so important. + 0) + }; let node = Rc::new(NamespaceTreeNode { name: name, @@ -4060,7 +4038,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__".to_c_str(); + let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; let section_var = unsafe { - llvm::LLVMGetNamedGlobal(ccx.llmod(), section_var_name.as_ptr()) + llvm::LLVMGetNamedGlobal(ccx.llmod(), + section_var_name.as_ptr() as *const _) }; if section_var == ptr::null_mut() { - let section_name = b".debug_gdb_scripts".to_c_str(); + let section_name = b".debug_gdb_scripts\0"; let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; unsafe { @@ -4092,8 +4071,9 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) section_contents.len() as u64); let section_var = llvm::LLVMAddGlobal(ccx.llmod(), llvm_type.to_ref(), - section_var_name.as_ptr()); - llvm::LLVMSetSection(section_var, section_name.as_ptr()); + section_var_name.as_ptr() + as *const _); + llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index a4cfec791d8..1c9be6ae4a8 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -24,9 +24,10 @@ use trans::type_::Type; use trans::type_of::*; use trans::type_of; use middle::ty::{self, Ty}; -use middle::subst::{Substs}; +use middle::subst::Substs; + +use std::ffi::CString; use std::cmp; -use std::c_str::ToCStr; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; @@ -132,9 +133,9 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf) - }); + let buf = CString::from_slice(ident.get().as_bytes()); + let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), + buf.as_ptr()); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -145,9 +146,9 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(ident.get()); - let g2 = real_name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }); + let real_name = CString::from_vec(real_name.into_bytes()); + let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), + real_name.as_ptr()); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 @@ -155,9 +156,8 @@ pub fn register_static(ccx: &CrateContext, } None => unsafe { // Generate an external declaration. - ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }) + let buf = CString::from_slice(ident.get().as_bytes()); + llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) } } } @@ -606,9 +606,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } - let the_block = - "the block".with_c_str( - |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s)); + let ptr = "the block\0".as_ptr(); + let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, + ptr as *const _); let builder = ccx.builder(); builder.position_at_end(the_block); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 491c6a83ca9..2fd9031fdfe 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -40,8 +40,8 @@ use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; use arena::TypedArena; -use std::c_str::ToCStr; use libc::c_uint; +use std::ffi::CString; use syntax::ast; use syntax::parse::token; @@ -486,11 +486,11 @@ 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 gvar = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let gvar = unsafe { + llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), + buf.as_ptr()) + }; note_unique_llvm_symbol(ccx, name); let ty_name = token::intern_and_get_ident( diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index e219b45d3d9..f6d69959dad 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -34,7 +34,7 @@ use middle::ty::{self, Ty}; use middle::ty::MethodCall; use util::ppaux::Repr; -use std::c_str::ToCStr; +use std::ffi::CString; use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; @@ -762,9 +762,9 @@ pub fn make_vtable>(ccx: &CrateContext, unsafe { let tbl = C_struct(ccx, components[], false); let sym = token::gensym("vtable"); - let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf) - }); + let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes()); + let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), + buf.as_ptr()); llvm::LLVMSetInitializer(vt_gvar, tbl); llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True); llvm::SetLinkage(vt_gvar, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 5b76f5bb827..3785c2fb9bc 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -19,7 +19,7 @@ use util::nodemap::FnvHashMap; use syntax::ast; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::cell::RefCell; use std::iter::repeat; @@ -157,7 +157,8 @@ impl Type { } pub fn named_struct(ccx: &CrateContext, name: &str) -> Type { - ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx(), s))) + let name = CString::from_slice(name.as_bytes()); + ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr())) } pub fn empty_struct(ccx: &CrateContext) -> Type { diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 0f0dbf6a24d..dcc90117d26 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -20,8 +20,8 @@ pub use self::imp::Lock; #[cfg(unix)] mod imp { + use std::ffi::CString; use libc; - use std::c_str::ToCStr; #[cfg(target_os = "linux")] mod os { @@ -111,9 +111,11 @@ mod imp { impl Lock { pub fn new(p: &Path) -> Lock { - let fd = p.with_c_str(|s| unsafe { - libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU) - }); + let buf = CString::from_slice(p.as_vec()); + let fd = unsafe { + libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT, + libc::S_IRWXU) + }; assert!(fd > 0); let flock = os::flock { l_start: 0, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9d003eca27f..3b9265cf569 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,7 +29,7 @@ use libc; use std::ascii::AsciiExt; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::fmt; @@ -215,7 +215,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let id = id.as_ref().map(|a| a.as_slice()); s.push_str(highlight::highlight(text.as_slice(), None, id) .as_slice()); - let output = s.to_c_str(); + let output = CString::from_vec(s.into_bytes()); hoedown_buffer_puts(ob, output.as_ptr()); }) } @@ -224,15 +224,16 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, level: libc::c_int, opaque: *mut libc::c_void) { // hoedown does this, we may as well too - "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } // Extract the text provided let s = if text.is_null() { "".to_string() } else { - unsafe { - String::from_raw_buf_len((*text).data, (*text).size as uint) - } + let s = unsafe { + slice::from_raw_buf(&(*text).data, (*text).size as uint) + }; + str::from_utf8(s).unwrap().to_string() }; // Transform the contents of the header into a hyphenated string @@ -273,7 +274,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { format!("{} ", sec) }); - text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + let text = CString::from_vec(text.into_bytes()); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } } reset_headers(); diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs deleted file mode 100644 index 9c96a9cac78..00000000000 --- a/src/libstd/c_str.rs +++ /dev/null @@ -1,857 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C-string manipulation and management -//! -//! This modules provides the basic methods for creating and manipulating -//! null-terminated strings for use with FFI calls (back to C). Most C APIs require -//! that the string being passed to them is null-terminated, and by default rust's -//! string types are *not* null terminated. -//! -//! The other problem with translating Rust strings to C strings is that Rust -//! strings can validly contain a null-byte in the middle of the string (0 is a -//! valid Unicode codepoint). This means that not all Rust strings can actually be -//! translated to C strings. -//! -//! # Creation of a C string -//! -//! A C string is managed through the `CString` type defined in this module. It -//! "owns" the internal buffer of characters and will automatically deallocate the -//! buffer when the string is dropped. The `ToCStr` trait is implemented for `&str` -//! and `&[u8]`, but the conversions can fail due to some of the limitations -//! explained above. -//! -//! This also means that currently whenever a C string is created, an allocation -//! must be performed to place the data elsewhere (the lifetime of the C string is -//! not tied to the lifetime of the original string/data buffer). If C strings are -//! heavily used in applications, then caching may be advisable to prevent -//! unnecessary amounts of allocations. -//! -//! Be carefull to remember that the memory is managed by C allocator API and not -//! by Rust allocator API. -//! That means that the CString pointers should be freed with C allocator API -//! if you intend to do that on your own, as the behaviour if you free them with -//! Rust's allocator API is not well defined -//! -//! An example of creating and using a C string would be: -//! -//! ```rust -//! extern crate libc; -//! -//! use std::c_str::ToCStr; -//! -//! extern { -//! fn puts(s: *const libc::c_char); -//! } -//! -//! fn main() { -//! let my_string = "Hello, world!"; -//! -//! // Allocate the C string with an explicit local that owns the string. The -//! // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope. -//! let my_c_string = my_string.to_c_str(); -//! unsafe { -//! puts(my_c_string.as_ptr()); -//! } -//! -//! // Don't save/return the pointer to the C string, the `c_buffer` will be -//! // deallocated when this block returns! -//! my_string.with_c_str(|c_buffer| { -//! unsafe { puts(c_buffer); } -//! }); -//! } -//! ``` - -use core::prelude::*; -use libc; - -use cmp::Ordering; -use fmt; -use hash; -use mem; -use ptr; -use slice::{self, IntSliceExt}; -use str; -use string::String; -use core::kinds::marker; - -/// The representation of a C String. -/// -/// This structure wraps a `*libc::c_char`, and will automatically free the -/// memory it is pointing to when it goes out of scope. -#[allow(missing_copy_implementations)] -pub struct CString { - buf: *const libc::c_char, - owns_buffer_: bool, -} - -unsafe impl Send for CString { } -unsafe impl Sync for CString { } - -impl Clone for CString { - /// Clone this CString into a new, uniquely owned CString. For safety - /// reasons, this is always a deep clone with the memory allocated - /// with C's allocator API, rather than the usual shallow clone. - fn clone(&self) -> CString { - let len = self.len() + 1; - let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char; - if buf.is_null() { ::alloc::oom() } - unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); } - CString { buf: buf as *const libc::c_char, owns_buffer_: true } - } -} - -impl PartialEq for CString { - fn eq(&self, other: &CString) -> bool { - // Check if the two strings share the same buffer - if self.buf as uint == other.buf as uint { - true - } else { - unsafe { - libc::strcmp(self.buf, other.buf) == 0 - } - } - } -} - -impl PartialOrd for CString { - #[inline] - fn partial_cmp(&self, other: &CString) -> Option { - self.as_bytes().partial_cmp(other.as_bytes()) - } -} - -impl Eq for CString {} - -impl hash::Hash for CString { - #[inline] - fn hash(&self, state: &mut S) { - self.as_bytes().hash(state) - } -} - -impl CString { - /// Create a C String from a pointer, with memory managed by C's allocator - /// API, so avoid calling it with a pointer to memory managed by Rust's - /// allocator API, as the behaviour would not be well defined. - /// - ///# Panics - /// - /// Panics if `buf` is null - pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString { - assert!(!buf.is_null()); - CString { buf: buf, owns_buffer_: owns_buffer } - } - - /// Return a pointer to the NUL-terminated string data. - /// - /// `.as_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let x = foo.to_c_str(); - /// let p = x.as_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_ptr(); - /// ``` - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let c_str = "foo bar".to_c_str(); - /// unsafe { - /// libc::puts(c_str.as_ptr()); - /// } - /// } - /// ``` - pub fn as_ptr(&self) -> *const libc::c_char { - self.buf - } - - /// Return a mutable pointer to the NUL-terminated string data. - /// - /// `.as_mut_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let mut x = foo.to_c_str(); - /// let p = x.as_mut_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_mut_ptr(); - /// ``` - pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - self.buf as *mut _ - } - - /// Returns whether or not the `CString` owns the buffer. - pub fn owns_buffer(&self) -> bool { - self.owns_buffer_ - } - - /// Converts the CString into a `&[u8]` without copying. - /// Includes the terminating NUL byte. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned() - } - } - - /// Converts the CString into a `&[u8]` without copying. - /// Does not include the terminating NUL byte. - #[inline] - pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len()).as_unsigned() - } - } - - /// Converts the CString into a `&str` without copying. - /// Returns None if the CString is not UTF-8. - #[inline] - pub fn as_str<'a>(&'a self) -> Option<&'a str> { - let buf = self.as_bytes_no_nul(); - str::from_utf8(buf).ok() - } - - /// Return a CString iterator. - pub fn iter<'a>(&'a self) -> CChars<'a> { - CChars { - ptr: self.buf, - marker: marker::ContravariantLifetime, - } - } - - /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper. - /// - /// Any ownership of the buffer by the `CString` wrapper is - /// forgotten, meaning that the backing allocation of this - /// `CString` is not automatically freed if it owns the - /// allocation. In this case, a user of `.unwrap()` should ensure - /// the allocation is freed, to avoid leaking memory. You should - /// use libc's memory allocator in this case. - /// - /// Prefer `.as_ptr()` when just retrieving a pointer to the - /// string data, as that does not relinquish ownership. - pub unsafe fn into_inner(mut self) -> *const libc::c_char { - self.owns_buffer_ = false; - self.buf - } - - /// Return the number of bytes in the CString (not including the NUL - /// terminator). - #[inline] - pub fn len(&self) -> uint { - unsafe { libc::strlen(self.buf) as uint } - } - - /// Returns if there are no bytes in this string - #[inline] - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl Drop for CString { - fn drop(&mut self) { - if self.owns_buffer_ { - unsafe { - libc::free(self.buf as *mut libc::c_void) - } - } - } -} - -impl fmt::Show for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - String::from_utf8_lossy(self.as_bytes_no_nul()).fmt(f) - } -} - -/// A generic trait for converting a value to a CString. -pub trait ToCStr for Sized? { - /// Copy the receiver into a CString. - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - fn to_c_str(&self) -> CString; - - /// Unsafe variant of `to_c_str()` that doesn't check for nulls. - unsafe fn to_c_str_unchecked(&self) -> CString; - - /// Work with a temporary CString constructed from the receiver. - /// The provided `*libc::c_char` will be freed immediately upon return. - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let s = "PATH".with_c_str(|path| unsafe { - /// libc::getenv(path) - /// }); - /// } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str(); - f(c_str.as_ptr()) - } - - /// Unsafe variant of `with_c_str()` that doesn't check for nulls. - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str_unchecked(); - f(c_str.as_ptr()) - } -} - -impl ToCStr for str { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -impl ToCStr for String { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -// The length of the stack allocated buffer for `vec.with_c_str()` -const BUF_LEN: uint = 128; - -impl ToCStr for [u8] { - fn to_c_str(&self) -> CString { - let mut cs = unsafe { self.to_c_str_unchecked() }; - check_for_null(self, cs.as_mut_ptr()); - cs - } - - unsafe fn to_c_str_unchecked(&self) -> CString { - let self_len = self.len(); - let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8; - if buf.is_null() { ::alloc::oom() } - - ptr::copy_memory(buf, self.as_ptr(), self_len); - *buf.offset(self_len as int) = 0; - - CString::new(buf as *const libc::c_char, true) - } - - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - unsafe { with_c_str(self, true, f) } - } - - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - with_c_str(self, false, f) - } -} - -impl<'a, Sized? T: ToCStr> ToCStr for &'a T { - #[inline] - fn to_c_str(&self) -> CString { - (**self).to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - (**self).to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str_unchecked(f) - } -} - -// Unsafe function that handles possibly copying the &[u8] into a stack array. -unsafe fn with_c_str(v: &[u8], checked: bool, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, -{ - let c_str = if v.len() < BUF_LEN { - let mut buf: [u8; BUF_LEN] = mem::uninitialized(); - slice::bytes::copy_memory(&mut buf, v); - buf[v.len()] = 0; - - let buf = buf.as_mut_ptr(); - if checked { - check_for_null(v, buf as *mut libc::c_char); - } - - return f(buf as *const libc::c_char) - } else if checked { - v.to_c_str() - } else { - v.to_c_str_unchecked() - }; - - f(c_str.as_ptr()) -} - -#[inline] -fn check_for_null(v: &[u8], buf: *mut libc::c_char) { - for i in range(0, v.len()) { - unsafe { - let p = buf.offset(i as int); - assert!(*p != 0); - } - } -} - -/// External iterator for a CString's bytes. -/// -/// Use with the `std::iter` module. -#[allow(raw_pointer_deriving)] -#[derive(Clone)] -pub struct CChars<'a> { - ptr: *const libc::c_char, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a> Iterator for CChars<'a> { - type Item = libc::c_char; - - fn next(&mut self) -> Option { - let ch = unsafe { *self.ptr }; - if ch == 0 { - None - } else { - self.ptr = unsafe { self.ptr.offset(1) }; - Some(ch) - } - } -} - -/// Parses a C "multistring", eg windows env values or -/// the req->ptr result in a uv_fs_readdir() call. -/// -/// Optionally, a `count` can be passed in, limiting the -/// parsing to only being done `count`-times. -/// -/// The specified closure is invoked with each string that -/// is found, and the number of strings found is returned. -pub unsafe fn from_c_multistring(buf: *const libc::c_char, - count: Option, - mut f: F) - -> uint where - F: FnMut(&CString), -{ - - let mut curr_ptr: uint = buf as uint; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while ((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char { - let cstr = CString::new(curr_ptr as *const libc::c_char, false); - f(&cstr); - curr_ptr += cstr.len() + 1; - ctr += 1; - } - return ctr; -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use super::*; - use ptr; - use thread::Thread; - use libc; - - #[test] - fn test_str_multistring_parsing() { - unsafe { - let input = b"zero\0one\0\0"; - let ptr = input.as_ptr(); - let expected = ["zero", "one"]; - let mut it = expected.iter(); - let result = from_c_multistring(ptr as *const libc::c_char, None, |c| { - let cbytes = c.as_bytes_no_nul(); - assert_eq!(cbytes, it.next().unwrap().as_bytes()); - }); - assert_eq!(result, 2); - assert!(it.next().is_none()); - } - } - - #[test] - fn test_str_to_c_str() { - let c_str = "".to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = "hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - } - - #[test] - fn test_vec_to_c_str() { - let b: &[u8] = &[]; - let c_str = b.to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = b"hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - - let c_str = b"foo\xFF".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'f' as libc::c_char); - assert_eq!(*buf.offset(1), 'o' as libc::c_char); - assert_eq!(*buf.offset(2), 'o' as libc::c_char); - assert_eq!(*buf.offset(3), 0xffu8 as libc::c_char); - assert_eq!(*buf.offset(4), 0); - } - } - - #[test] - fn test_unwrap() { - let c_str = "hello".to_c_str(); - unsafe { libc::free(c_str.into_inner() as *mut libc::c_void) } - } - - #[test] - fn test_as_ptr() { - let c_str = "hello".to_c_str(); - let len = unsafe { libc::strlen(c_str.as_ptr()) }; - assert_eq!(len, 5); - } - - #[test] - fn test_iterator() { - let c_str = "".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), None); - - let c_str = "hello".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), Some('h' as libc::c_char)); - assert_eq!(iter.next(), Some('e' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('o' as libc::c_char)); - assert_eq!(iter.next(), None); - } - - #[test] - fn test_to_c_str_fail() { - assert!(Thread::spawn(move|| { "he\x00llo".to_c_str() }).join().is_err()); - } - - #[test] - fn test_to_c_str_unchecked() { - unsafe { - let c_string = "he\x00llo".to_c_str_unchecked(); - let buf = c_string.as_ptr(); - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 0); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'l' as libc::c_char); - assert_eq!(*buf.offset(5), 'o' as libc::c_char); - assert_eq!(*buf.offset(6), 0); - } - } - - #[test] - fn test_as_bytes() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes(), b"hello\0"); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_bytes(), b"\0"); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes(), b"foo\xFF\0"); - } - - #[test] - fn test_as_bytes_no_nul() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"hello"); - let c_str = "".to_c_str(); - let exp: &[u8] = &[]; - assert_eq!(c_str.as_bytes_no_nul(), exp); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); - } - - #[test] - fn test_as_str() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_str(), Some("hello")); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_str(), Some("")); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_str(), None); - } - - #[test] - #[should_fail] - fn test_new_fail() { - let _c_str = unsafe { CString::new(ptr::null(), false) }; - } - - #[test] - fn test_clone() { - let a = "hello".to_c_str(); - let b = a.clone(); - assert!(a == b); - } - - #[test] - fn test_clone_noleak() { - fn foo(f: F) where F: FnOnce(&CString) { - let s = "test".to_string(); - let c = s.to_c_str(); - // give the closure a non-owned CString - let mut c_ = unsafe { CString::new(c.as_ptr(), false) }; - f(&c_); - // muck with the buffer for later printing - unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char } - } - - let mut c_: Option = None; - foo(|c| { - c_ = Some(c.clone()); - c.clone(); - // force a copy, reading the memory - c.as_bytes().to_vec(); - }); - let c_ = c_.unwrap(); - // force a copy, reading the memory - c_.as_bytes().to_vec(); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - use prelude::v1::*; - use self::test::Bencher; - use libc; - use c_str::ToCStr; - - #[inline] - fn check(s: &str, c_str: *const libc::c_char) { - let s_buf = s.as_ptr(); - for i in range(0, s.len()) { - unsafe { - assert_eq!( - *s_buf.offset(i as int) as libc::c_char, - *c_str.offset(i as int)); - } - } - } - - static S_SHORT: &'static str = "Mary"; - static S_MEDIUM: &'static str = "Mary had a little lamb"; - static S_LONG: &'static str = "\ - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb"; - - fn bench_to_string(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = s.to_c_str(); - check(s, c_str.as_ptr()); - }) - } - - #[bench] - fn bench_to_c_str_short(b: &mut Bencher) { - bench_to_string(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_medium(b: &mut Bencher) { - bench_to_string(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_long(b: &mut Bencher) { - bench_to_string(b, S_LONG) - } - - fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = unsafe { s.to_c_str_unchecked() }; - check(s, c_str.as_ptr()) - }) - } - - #[bench] - fn bench_to_c_str_unchecked_short(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_unchecked_medium(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_unchecked_long(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_LONG) - } - - fn bench_with_c_str(b: &mut Bencher, s: &str) { - b.iter(|| { - s.with_c_str(|c_str_buf| check(s, c_str_buf)) - }) - } - - #[bench] - fn bench_with_c_str_short(b: &mut Bencher) { - bench_with_c_str(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_medium(b: &mut Bencher) { - bench_with_c_str(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_long(b: &mut Bencher) { - bench_with_c_str(b, S_LONG) - } - - fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - unsafe { - s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf)) - } - }) - } - - #[bench] - fn bench_with_c_str_unchecked_short(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_unchecked_medium(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_unchecked_long(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_LONG) - } -} diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs deleted file mode 100644 index 4a20208f31a..00000000000 --- a/src/libstd/c_vec.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Library to interface with chunks of memory allocated in C. -//! -//! It is often desirable to safely interface with memory allocated from C, -//! encapsulating the unsafety into allocation and destruction time. Indeed, -//! allocating memory externally is currently the only way to give Rust shared -//! mut state with C programs that keep their own references; vectors are -//! unsuitable because they could be reallocated or moved at any time, and -//! importing C memory into a vector takes a one-time snapshot of the memory. -//! -//! This module simplifies the usage of such external blocks of memory. Memory -//! is encapsulated into an opaque object after creation; the lifecycle of the -//! memory can be optionally managed by Rust, if an appropriate destructor -//! closure is provided. Safety is ensured by bounds-checking accesses, which -//! are marshalled through get and set functions. -//! -//! There are three unsafe functions: the two constructors, and the -//! unwrap method. The constructors are unsafe for the -//! obvious reason (they act on a pointer that cannot be checked inside the -//! method), but `unwrap()` is somewhat more subtle in its unsafety. -//! It returns the contained pointer, but at the same time destroys the CVec -//! without running its destructor. This can be used to pass memory back to -//! C, but care must be taken that the ownership of underlying resources are -//! handled correctly, i.e. that allocated memory is eventually freed -//! if necessary. - -#![experimental] - -use kinds::Send; -use mem; -use ops::{Drop, FnOnce}; -use option::Option; -use option::Option::{Some, None}; -use ptr::PtrExt; -use ptr; -use raw; -use slice::AsSlice; -use thunk::{Thunk}; - -/// The type representing a foreign chunk of memory -pub struct CVec { - base: *mut T, - len: uint, - dtor: Option, -} - -#[unsafe_destructor] -impl Drop for CVec { - fn drop(&mut self) { - match self.dtor.take() { - None => (), - Some(f) => f.invoke(()) - } - } -} - -impl CVec { - /// Create a `CVec` from a raw pointer to a buffer with a given length. - /// - /// Panics if the given pointer is null. The returned vector will not attempt - /// to deallocate the vector when dropped. - /// - /// # Arguments - /// - /// * base - A raw pointer to a buffer - /// * len - The number of elements in the buffer - pub unsafe fn new(base: *mut T, len: uint) -> CVec { - assert!(base != ptr::null_mut()); - CVec { - base: base, - len: len, - dtor: None, - } - } - - /// Create a `CVec` from a foreign buffer, with a given length, - /// and a function to run upon destruction. - /// - /// Panics if the given pointer is null. - /// - /// # Arguments - /// - /// * base - A foreign pointer to a buffer - /// * len - The number of elements in the buffer - /// * dtor - A fn to run when the value is destructed, useful - /// for freeing the buffer, etc. - pub unsafe fn new_with_dtor(base: *mut T, - len: uint, - dtor: F) - -> CVec - where F : FnOnce(), F : Send - { - assert!(base != ptr::null_mut()); - let dtor: Thunk = Thunk::new(dtor); - CVec { - base: base, - len: len, - dtor: Some(dtor) - } - } - - /// View the stored data as a mutable slice. - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } - - /// Retrieves an element at a given index, returning `None` if the requested - /// index is greater than the length of the vector. - pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> { - if ofs < self.len { - Some(unsafe { &*self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Retrieves a mutable element at a given index, returning `None` if the - /// requested index is greater than the length of the vector. - pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> { - if ofs < self.len { - Some(unsafe { &mut *self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Unwrap the pointer without running the destructor - /// - /// This method retrieves the underlying pointer, and in the process - /// destroys the CVec but without running the destructor. A use case - /// would be transferring ownership of the buffer to a C function, as - /// in this case you would not want to run the destructor. - /// - /// Note that if you want to access the underlying pointer without - /// cancelling the destructor, you can simply call `transmute` on the return - /// value of `get(0)`. - pub unsafe fn into_inner(mut self) -> *mut T { - self.dtor = None; - self.base - } - - /// Returns the number of items in this vector. - pub fn len(&self) -> uint { self.len } - - /// Returns whether this vector is empty. - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl AsSlice for CVec { - /// View the stored data as a slice. - fn as_slice<'a>(&'a self) -> &'a [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use super::CVec; - use libc; - use ptr; - - fn malloc(n: uint) -> CVec { - unsafe { - let mem = ptr::Unique(libc::malloc(n as libc::size_t)); - if mem.0.is_null() { ::alloc::oom() } - - CVec::new_with_dtor(mem.0 as *mut u8, - n, - move|| { libc::free(mem.0 as *mut libc::c_void); }) - } - } - - #[test] - fn test_basic() { - let mut cv = malloc(16); - - *cv.get_mut(3).unwrap() = 8; - *cv.get_mut(4).unwrap() = 9; - assert_eq!(*cv.get(3).unwrap(), 8); - assert_eq!(*cv.get(4).unwrap(), 9); - assert_eq!(cv.len(), 16); - } - - #[test] - #[should_fail] - fn test_panic_at_null() { - unsafe { - CVec::new(ptr::null_mut::(), 9); - } - } - - #[test] - fn test_overrun_get() { - let cv = malloc(16); - - assert!(cv.get(17).is_none()); - } - - #[test] - fn test_overrun_set() { - let mut cv = malloc(16); - - assert!(cv.get_mut(17).is_none()); - } - - #[test] - fn test_unwrap() { - unsafe { - let cv = CVec::new_with_dtor(1 as *mut int, - 0, - move|:| panic!("Don't run this destructor!")); - let p = cv.into_inner(); - assert_eq!(p, 1 as *mut int); - } - } - -} diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index de3d75ffb32..66cb1f2c948 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; use mem; use os; use str; @@ -51,13 +51,11 @@ impl DynamicLibrary { /// Lazily open a dynamic library. When passed None it gives a /// handle to the calling process - pub fn open(filename: Option) - -> Result { + pub fn open(filename: Option<&Path>) -> Result { unsafe { - let mut filename = filename; let maybe_library = dl::check_for_errors_in(|| { - match filename.take() { - Some(name) => dl::open_external(name), + match filename { + Some(name) => dl::open_external(name.as_vec()), None => dl::open_internal() } }); @@ -131,9 +129,8 @@ impl DynamicLibrary { // T but that feature is still unimplemented let maybe_symbol_value = dl::check_for_errors_in(|| { - symbol.with_c_str(|raw_string| { - dl::symbol(self.handle, raw_string) - }) + let raw_string = CString::from_slice(symbol.as_bytes()); + dl::symbol(self.handle, raw_string.as_ptr()) }); // The value must not be constructed if there is an error so @@ -157,7 +154,7 @@ mod test { fn test_loading_cosine() { // The math library does not need to be loaded since it is already // statically linked in - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let libm = match DynamicLibrary::open(none) { Err(error) => panic!("Could not load self as module: {}", error), Ok(libm) => libm @@ -202,17 +199,17 @@ mod test { target_os = "freebsd", target_os = "dragonfly"))] pub mod dl { - use self::Rtld::*; - + pub use self::Rtld::*; use prelude::v1::*; - use c_str::{CString, ToCStr}; + + use ffi::{self, CString}; + use str; use libc; use ptr; - pub unsafe fn open_external(filename: T) -> *mut u8 { - filename.with_c_str(|raw_name| { - dlopen(raw_name, Lazy as libc::c_int) as *mut u8 - }) + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { + let s = CString::from_slice(filename); + dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8 } pub unsafe fn open_internal() -> *mut u8 { @@ -236,8 +233,8 @@ pub mod dl { let ret = if ptr::null() == last_error { Ok(result) } else { - Err(String::from_str(CString::new(last_error, false).as_str() - .unwrap())) + let s = ffi::c_str_to_bytes(&last_error); + Err(str::from_utf8(s).unwrap().to_string()) }; ret @@ -273,7 +270,6 @@ pub mod dl { #[cfg(target_os = "windows")] pub mod dl { - use c_str::ToCStr; use iter::IteratorExt; use libc; use ops::FnOnce; @@ -287,10 +283,9 @@ pub mod dl { use string::String; use vec::Vec; - pub unsafe fn open_external(filename: T) -> *mut u8 { + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { // Windows expects Unicode data - let filename_cstr = filename.to_c_str(); - let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap(); + let filename_str = str::from_utf8(filename).unwrap(); let mut filename_str: Vec = filename_str.utf16_units().collect(); filename_str.push(0); LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8 diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs new file mode 100644 index 00000000000..bef2344d9e8 --- /dev/null +++ b/src/libstd/ffi/c_str.rs @@ -0,0 +1,218 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use iter::IteratorExt; +use libc; +use mem; +use ops::Deref; +use slice::{self, SliceExt, AsSlice}; +use string::String; +use vec::Vec; + +/// A type representing a C-compatible string +/// +/// This type serves the primary purpose of being able to generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. After +/// being created, a `CString` predominately inherits all of its methods from +/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying +/// array is represented as an array of `libc::c_char` as opposed to `u8`. A +/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from +/// a `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi::CString; +/// use libc; +/// +/// extern { +/// fn my_printer(s: *const libc::c_char); +/// } +/// +/// let to_print = "Hello, world!"; +/// let c_to_print = CString::from_slice(to_print.as_bytes()); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct CString { + inner: Vec, +} + +impl CString { + /// Create a new C-compatible string from a byte slice. + /// + /// This method will copy the data of the slice provided into a new + /// allocation, ensuring that there is a trailing 0 byte. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the slice + /// provided. + pub fn from_slice(v: &[u8]) -> CString { + CString::from_vec(v.to_vec()) + } + + /// Create a C-compatible string from a byte vector. + /// + /// This method will consume ownership of the provided vector, appending a 0 + /// byte to the end after verifying that there are no interior 0 bytes. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the vector + /// provided. + pub fn from_vec(v: Vec) -> CString { + assert!(!v.iter().any(|&x| x == 0)); + unsafe { CString::from_vec_unchecked(v) } + } + + /// Create a C-compatibel string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to `from_vec` except that no runtime assertion + /// is made that `v` contains no 0 bytes. + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.push(0); + CString { inner: mem::transmute(v) } + } + + /// Create a view into this C string which includes the trailing nul + /// terminator at the end of the string. + pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() } + + /// Similar to the `as_slice` method, but returns a `u8` slice instead of a + /// `libc::c_char` slice. + pub fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice()) } + } + + /// Equivalend to `as_slice_with_nul` except that the type returned is a + /// `u8` slice instead of a `libc::c_char` slice. + pub fn as_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice_with_nul()) } + } +} + +impl Deref for CString { + type Target = [libc::c_char]; + + fn deref(&self) -> &[libc::c_char] { + self.inner.slice_to(self.inner.len() - 1) + } +} + +impl fmt::Show for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + String::from_utf8_lossy(self.as_bytes()).fmt(f) + } +} + +/// Interpret a C string as a byte slice. +/// +/// This function will calculate the length of the C string provided, and it +/// will then return a corresponding slice for the contents of the C string not +/// including the nul terminator. +/// +/// This function will tie the lifetime of the returned slice to the lifetime of +/// the pointer provided. This is done to help prevent the slice from escaping +/// the lifetime of the pointer itself. If a longer lifetime is needed, then +/// `mem::copy_lifetime` should be used. +/// +/// This function is unsafe because there is no guarantee of the validity of the +/// pointer `raw` or a guarantee that a nul terminator will be found. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi; +/// use std::str; +/// use libc; +/// +/// extern { +/// fn my_string() -> *const libc::c_char; +/// } +/// +/// unsafe { +/// let to_print = my_string(); +/// let slice = ffi::c_str_to_bytes(&to_print); +/// println!("string returned: {}", str::from_utf8(slice).unwrap()); +/// } +/// # } +/// ``` +pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw); + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +/// Interpret a C string as a byte slice with the nul terminator. +/// +/// This function is identical to `from_raw_buf` except that the returned slice +/// will include the nul terminator of the string. +pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw) + 1; + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use super::*; + use libc; + use mem; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const libc::c_char; + unsafe { + assert_eq!(c_str_to_bytes(&ptr), b"123"); + assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::from_slice(b"1234"); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + unsafe { + assert_eq!(s.as_slice(), + mem::transmute::<_, &[libc::c_char]>(b"1234")); + assert_eq!(s.as_slice_with_nul(), + mem::transmute::<_, &[libc::c_char]>(b"1234\0")); + } + } + + #[should_fail] #[test] + fn build_with_zero1() { CString::from_slice(b"\0"); } + #[should_fail] #[test] + fn build_with_zero2() { CString::from_vec(vec![0]); } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } +} diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs new file mode 100644 index 00000000000..cc86f804e3e --- /dev/null +++ b/src/libstd/ffi/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities related to FFI bindings. + +#![unstable = "module just underwent fairly large reorganization and the dust \ + still needs to settle"] + +pub use self::c_str::CString; +pub use self::c_str::c_str_to_bytes; +pub use self::c_str::c_str_to_bytes_with_nul; + +mod c_str; diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index daefdd28b30..738c70412f7 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -22,7 +22,8 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; +use path::BytesContainer; use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; use sys::pipe::UnixAcceptor as UnixAcceptorImp; use sys::pipe::UnixListener as UnixListenerImp; @@ -53,8 +54,9 @@ impl UnixStream { /// let mut stream = UnixStream::connect(&server); /// stream.write(&[1, 2, 3]); /// ``` - pub fn connect(path: &P) -> IoResult { - UnixStreamImp::connect(&path.to_c_str(), None) + pub fn connect(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, None) .map(|inner| UnixStream { inner: inner }) } @@ -67,13 +69,15 @@ impl UnixStream { /// If a `timeout` with zero or negative duration is specified then /// the function returns `Err`, with the error kind set to `TimedOut`. #[experimental = "the timeout argument is likely to change types"] - pub fn connect_timeout(path: &P, - timeout: Duration) -> IoResult { + pub fn connect_timeout

(path: P, timeout: Duration) + -> IoResult + where P: BytesContainer { if timeout <= Duration::milliseconds(0) { return Err(standard_error(TimedOut)); } - UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64)) + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) .map(|inner| UnixStream { inner: inner }) } @@ -177,8 +181,9 @@ impl UnixListener { /// } /// # } /// ``` - pub fn bind(path: &P) -> IoResult { - UnixListenerImp::bind(&path.to_c_str()) + pub fn bind(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixListenerImp::bind(&path) .map(|inner| UnixListener { inner: inner }) } } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 5886c9cc3e2..ea232ad0c3f 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -18,8 +18,8 @@ pub use self::ProcessExit::*; use prelude::v1::*; -use c_str::{CString, ToCStr}; use collections::HashMap; +use ffi::CString; use fmt; use hash::Hash; use io::pipe::{PipeStream, PipePair}; @@ -35,6 +35,7 @@ use sys; use thread::Thread; #[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to /// SIGTERM on unix platforms. @@ -109,11 +110,11 @@ struct EnvKey(CString); impl Hash for EnvKey { fn hash(&self, state: &mut SipState) { let &EnvKey(ref x) = self; - match x.as_str() { - Some(s) => for ch in s.chars() { + match str::from_utf8(x.as_bytes()) { + Ok(s) => for ch in s.chars() { (ch as u8 as char).to_lowercase().hash(state); }, - None => x.hash(state) + Err(..) => x.hash(state) } } } @@ -123,8 +124,8 @@ impl PartialEq for EnvKey { fn eq(&self, other: &EnvKey) -> bool { let &EnvKey(ref x) = self; let &EnvKey(ref y) = other; - match (x.as_str(), y.as_str()) { - (Some(xs), Some(ys)) => { + match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { + (Ok(xs), Ok(ys)) => { if xs.len() != ys.len() { return false } else { @@ -185,10 +186,10 @@ pub struct Command { } // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an +// we cannot usefully take BytesContainer arguments by reference (without forcing an // additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by +// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by BytesContainer should be passed by // reference. (Here: {new, arg, args, env}.) impl Command { @@ -203,9 +204,9 @@ impl Command { /// /// Builder methods are provided to change these defaults and /// otherwise configure the process. - pub fn new(program: T) -> Command { + pub fn new(program: T) -> Command { Command { - program: program.to_c_str(), + program: CString::from_slice(program.container_as_bytes()), args: Vec::new(), env: None, cwd: None, @@ -219,27 +220,29 @@ impl Command { } /// Add an argument to pass to the program. - pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(arg.to_c_str()); + 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 } /// Add multiple arguments to pass to the program. - pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| arg.to_c_str()));; + 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()) + })); self } // Get a mutable borrow of the environment variable map for this `Command`. - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { + fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { match self.env { Some(ref mut map) => map, None => { // 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(k.to_c_str()), - v.to_c_str())) - .collect()); + self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { + (EnvKey(CString::from_slice(k.as_slice())), + CString::from_slice(v.as_slice())) + }).collect()); self.env.as_mut().unwrap() } } @@ -249,15 +252,20 @@ impl Command { /// /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, /// and case-sensitive on all other platforms. - pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U) - -> &'a mut Command { - self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str()); + 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()); + self.get_env_map().insert(key, val); self } /// Removes an environment variable mapping. - pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { - self.get_env_map().remove(&EnvKey(key.to_c_str())); + 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())); + self.get_env_map().remove(&key); self } @@ -265,16 +273,19 @@ impl Command { /// /// If the given slice contains multiple instances of an environment /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command { - self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str())) - .collect()); + 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())) + }).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(dir.to_c_str()); + self.cwd = Some(CString::from_slice(dir.as_vec())); self } @@ -389,9 +400,9 @@ impl fmt::Show for Command { /// non-utf8 data is lossily converted using the utf8 replacement /// character. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes_no_nul()))); + try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes()))); for arg in self.args.iter() { - try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes_no_nul()))); + try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes()))); } Ok(()) } @@ -1208,13 +1219,13 @@ mod tests { #[test] #[cfg(windows)] fn env_map_keys_ci() { - use c_str::ToCStr; + use ffi::CString; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); cmd.env("Path", "bar"); let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey("PATH".to_c_str())); - assert!(val.unwrap() == &"bar".to_c_str()); + let val = env.get(&EnvKey(CString::from_slice(b"PATH"))); + assert!(val.unwrap() == &CString::from_slice(b"bar")); } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 608ad9882b9..2d3a4639379 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -208,10 +208,10 @@ pub mod num; /* Runtime and platform support */ -pub mod thread_local; -pub mod c_str; -pub mod c_vec; +pub mod thread_local; // first for macros + pub mod dynamic_lib; +pub mod ffi; pub mod fmt; pub mod io; pub mod os; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index be8f82349c2..300ceec4b45 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -57,12 +57,10 @@ use string::{String, ToString}; use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering}; use vec::Vec; -#[cfg(unix)] use c_str::ToCStr; +#[cfg(unix)] use ffi::{self, CString}; -#[cfg(unix)] -pub use sys::ext as unix; -#[cfg(windows)] -pub use sys::ext as windows; +#[cfg(unix)] pub use sys::ext as unix; +#[cfg(windows)] pub use sys::ext as windows; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -196,15 +194,14 @@ pub fn getenv(n: &str) -> Option { /// /// Panics if `n` has any interior NULs. pub fn getenv_as_bytes(n: &str) -> Option> { - use c_str::CString; - unsafe { with_env_lock(|| { - let s = n.with_c_str(|buf| libc::getenv(buf)); + let s = CString::from_slice(n.as_bytes()); + let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(CString::new(s as *const libc::c_char, false).as_bytes_no_nul().to_vec()) + Some(ffi::c_str_to_bytes(&s).to_vec()) } }) } @@ -253,13 +250,12 @@ pub fn setenv(n: &str, v: T) { fn _setenv(n: &str, v: &[u8]) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - v.with_c_str(|vbuf| { - if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 { - panic!(IoError::last_error()); - } - }) - }) + let k = CString::from_slice(n.as_bytes()); + let v = CString::from_slice(v); + if libc::funcs::posix01::unistd::setenv(k.as_ptr(), + v.as_ptr(), 1) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -289,11 +285,10 @@ pub fn unsetenv(n: &str) { fn _unsetenv(n: &str) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 { - panic!(IoError::last_error()); - } - }) + let nbuf = CString::from_slice(n.as_bytes()); + if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -618,11 +613,10 @@ pub fn get_exit_status() -> int { #[cfg(target_os = "macos")] unsafe fn load_argc_and_argv(argc: int, argv: *const *const c_char) -> Vec> { - use c_str::CString; use iter::range; range(0, argc as uint).map(|i| { - CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } @@ -652,7 +646,6 @@ fn real_args_as_bytes() -> Vec> { // res #[cfg(target_os = "ios")] fn real_args_as_bytes() -> Vec> { - use c_str::CString; use iter::range; use mem; diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index bf9ffbffe7d..2f014872402 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -62,7 +62,7 @@ #![experimental] use core::kinds::Sized; -use c_str::CString; +use ffi::CString; use clone::Clone; use fmt; use iter::IteratorExt; @@ -892,7 +892,7 @@ impl BytesContainer for Vec { impl BytesContainer for CString { #[inline] fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_bytes_no_nul() + self.as_bytes() } } @@ -913,21 +913,3 @@ impl<'a, Sized? T: BytesContainer> BytesContainer for &'a T { fn contains_nul(v: &T) -> bool { v.container_as_bytes().iter().any(|&x| x == 0) } - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use c_str::ToCStr; - use path::{WindowsPath, PosixPath}; - - #[test] - fn test_cstring() { - let input = "/foo/bar/baz"; - let path: PosixPath = PosixPath::new(input.to_c_str()); - assert_eq!(path.as_vec(), input.as_bytes()); - - let input = r"\foo\bar\baz"; - let path: WindowsPath = WindowsPath::new(input.to_c_str()); - assert_eq!(path.as_str().unwrap(), input); - } -} diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index ae82e201cb8..013212b2705 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -10,19 +10,16 @@ //! POSIX file path handling -use c_str::{CString, ToCStr}; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; -use option::Option; -use option::Option::{None, Some}; use kinds::Sized; -use str::{FromStr, Str}; -use str; -use slice::{Split, AsSlice, SliceConcatExt, SliceExt}; +use option::Option::{self, Some, None}; +use slice::{AsSlice, Split, SliceExt, SliceConcatExt}; +use str::{self, FromStr, StrExt}; use vec::Vec; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; @@ -86,26 +83,6 @@ impl FromStr for Path { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index cf8bc0e6242..05129a7ab9d 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -15,17 +15,15 @@ use self::PathPrefix::*; use ascii::AsciiExt; -use c_str::{CString, ToCStr}; use char::CharExt; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map, repeat}; use mem; -use option::Option; -use option::Option::{Some, None}; +use option::Option::{self, Some, None}; use slice::{SliceExt, SliceConcatExt}; use str::{SplitTerminator, FromStr, StrExt}; use string::{String, ToString}; @@ -112,26 +110,6 @@ impl FromStr for Path { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[cfg(not(test))] #[inline] diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 4734a39c835..86abacb9365 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -46,8 +46,9 @@ pub fn clone() -> Option>> { imp::clone() } mod imp { use prelude::v1::*; + use libc; use mem; - use slice; + use ffi; use sync::{StaticMutex, MUTEX_INIT}; @@ -95,13 +96,9 @@ mod imp { } unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec> { + let argv = argv as *const *const libc::c_char; range(0, argc as uint).map(|i| { - let arg = *argv.offset(i as int); - let mut len = 0u; - while *arg.offset(len as int) != 0 { - len += 1u; - } - slice::from_raw_buf(&arg, len).to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 578239c9cc4..bb0b6fe804b 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -15,7 +15,7 @@ use prelude::v1::*; use os; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; pub use sys::backtrace::write; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index a48a8edd82f..71169386c18 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -67,7 +67,7 @@ use fmt; use intrinsics; use libc::c_void; use mem; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::{Once, ONCE_INIT}; use rt::libunwind as uw; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 883a01fa318..bc01ce926f8 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -19,7 +19,7 @@ use libc::{self, uintptr_t}; use os; use slice; use str; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; /// Dynamically inquire about whether we're running under V. /// You should usually not use this unless your test definitely diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a441e55a732..a31dcc9884f 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -14,7 +14,7 @@ use io::{self, IoError, IoResult}; use prelude::v1::*; use sys::{last_error, retry}; -use c_str::CString; +use ffi::CString; use num::Int; use path::BytesContainer; use collections; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 3f67b284f68..4cf891ac498 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,15 +12,16 @@ use prelude::v1::*; use self::SocketStatus::*; use self::InAddr::*; -use c_str::ToCStr; +use ffi::CString; +use ffi; use io::net::addrinfo; use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult, IoError}; use libc::{self, c_char, c_int}; -use c_str::CString; use mem; use num::Int; use ptr::{self, null, null_mut}; +use str; use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; @@ -234,9 +235,9 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| x.to_c_str()); + let c_host = host.map(|x| CString::from_slice(x.as_bytes())); let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| x.to_c_str()); + let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -324,7 +325,8 @@ pub fn get_address_name(addr: IpAddr) -> Result { } unsafe { - Ok(CString::new(hostbuf.as_ptr(), false).as_str().unwrap().to_string()) + Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) + .unwrap().to_string()) } } diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5b261ea6b9e..ca268a8f27f 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,13 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. -use c_str::CString; -use io::{IoResult, Writer}; +use prelude::v1::*; + +use ffi; +use io::IoResult; use libc; use mem; -use option::Option::{self, Some, None}; -use result::Result::{Ok, Err}; +use str; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -105,9 +106,7 @@ use sys_common::backtrace::*; #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Writer) -> IoResult<()> { - use iter::{IteratorExt, range}; use result; - use slice::SliceExt; extern { fn backtrace(buf: *mut *mut libc::c_void, @@ -234,19 +233,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - CString::new(info.dli_sname, false) + ffi::c_str_to_bytes(&info.dli_sname) })) } } #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API @@ -368,15 +363,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { CString::new(data, false) })) + output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) } } // Finally, after all that work above, we can emit a symbol. fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void, - s: Option) -> IoResult<()> { + s: Option<&[u8]>) -> IoResult<()> { try!(write!(w, " {:2}: {:2$} - ", idx, addr, HEX_WIDTH)); - match s.as_ref().and_then(|c| c.as_str()) { + match s.and_then(|s| str::from_utf8(s).ok()) { Some(string) => try!(demangle(w, string)), None => try!(write!(w, "")), } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index b49ace8e2f8..1ad775517bb 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use c_str::{CString, ToCStr}; +use ffi::{self, CString}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, FileStat, SeekStyle}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -150,6 +150,10 @@ impl Drop for FileDesc { } } +fn cstr(path: &Path) -> CString { + CString::from_slice(path.as_vec()) +} + pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { let flags = match fm { Open => 0, @@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { libc::S_IRUSR | libc::S_IWUSR), }; - let path = path.to_c_str(); + let path = cstr(path); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -173,7 +177,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -182,7 +186,6 @@ pub fn readdir(p: &Path) -> IoResult> { use libc::{opendir, readdir_r, closedir}; fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; let root = Path::new(root); dirs.into_iter().filter(|path| { @@ -199,7 +202,7 @@ pub fn readdir(p: &Path) -> IoResult> { let mut buf = Vec::::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = p.to_c_str(); + let p = CString::from_slice(p.as_vec()); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -207,10 +210,9 @@ pub fn readdir(p: &Path) -> IoResult> { let mut entry_ptr = 0 as *mut dirent_t; while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } - let cstr = unsafe { - CString::new(rust_list_dir_val(entry_ptr), false) - }; - paths.push(Path::new(cstr)); + paths.push(unsafe { + Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); Ok(prune(&p, paths)) @@ -220,39 +222,39 @@ pub fn readdir(p: &Path) -> IoResult> { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = old.to_c_str(); - let new = new.to_c_str(); + let old = cstr(old); + let new = cstr(new); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = p.to_c_str(); + let p = 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 { - let c_path = p.to_c_str(); + let c_path = cstr(p); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -273,14 +275,14 @@ pub fn readlink(p: &Path) -> IoResult { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -328,7 +330,7 @@ fn mkstat(stat: &libc::stat) -> FileStat { } pub fn stat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -337,7 +339,7 @@ pub fn stat(p: &Path) -> IoResult { } pub fn lstat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -346,7 +348,7 @@ pub fn lstat(p: &Path) -> IoResult { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index ea0d230e8b2..6a408aa60f0 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -15,12 +15,14 @@ #![allow(unused_unsafe)] #![allow(unused_mut)] -extern crate libc; - -use num; -use num::{Int, SignedInt}; use prelude::v1::*; + +use ffi; use io::{self, IoResult, IoError}; +use libc; +use num::{Int, SignedInt}; +use num; +use str; use sys_common::mkerr_libc; macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( @@ -78,11 +80,10 @@ extern "system" { } pub fn last_gai_error(s: libc::c_int) -> IoError { - use c_str::CString; let mut err = decode_error(s); err.detail = Some(unsafe { - CString::new(gai_strerror(s), false).as_str().unwrap().to_string() + str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 181b8fdd0f8..175c4e2e353 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -12,18 +12,18 @@ use prelude::v1::*; -use c_str::ToCStr; use error::{FromError, Error}; +use ffi::{self, CString}; use fmt; use io::{IoError, IoResult}; use libc::{self, c_int, c_char, c_void}; +use os::TMPBUF_SZ; use os; use path::{BytesContainer}; use ptr; +use str; use sys::fs::FileDesc; -use os::TMPBUF_SZ; - const BUF_BYTES : uint = 2048u; /// Returns the platform-specific value of errno @@ -108,7 +108,8 @@ pub fn error_string(errno: i32) -> String { panic!("strerror_r failure"); } - String::from_raw_buf(p as *const u8) + let p = p as *const _; + str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() } } @@ -122,21 +123,17 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { } pub fn getcwd() -> IoResult { - use c_str::CString; - let mut buf = [0 as c_char; BUF_BYTES]; unsafe { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(CString::new(buf.as_ptr(), false))) + Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) } } } pub unsafe fn get_env_pairs() -> Vec> { - use c_str::CString; - extern { fn rust_env_pairs() -> *const *const c_char; } @@ -147,8 +144,7 @@ pub unsafe fn get_env_pairs() -> Vec> { } let mut result = Vec::new(); while *environ != 0 as *const _ { - let env_pair = - CString::new(*environ, false).as_bytes_no_nul().to_vec(); + let env_pair = ffi::c_str_to_bytes(&*environ).to_vec(); result.push(env_pair); environ = environ.offset(1); } @@ -234,14 +230,13 @@ pub fn load_self() -> Option> { } pub fn chdir(p: &Path) -> IoResult<()> { - p.with_c_str(|buf| { - unsafe { - match libc::chdir(buf) == (0 as c_int) { - true => Ok(()), - false => Err(IoError::last_error()), - } + let p = CString::from_slice(p.as_vec()); + unsafe { + match libc::chdir(p.as_ptr()) == (0 as c_int) { + true => Ok(()), + false => Err(IoError::last_error()), } - }) + } } pub fn page_size() -> uint { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 9063fbc2ba9..158a1ce2204 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -10,8 +10,8 @@ use prelude::v1::*; +use ffi::CString; use libc; -use c_str::CString; use mem; use sync::{Arc, Mutex}; use sync::atomic::{AtomicBool, Ordering}; @@ -48,7 +48,7 @@ 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; + *slot = *value; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index b73919fe2a2..5bc6b0c703b 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,8 +11,8 @@ use prelude::v1::*; use self::Req::*; -use c_str::{CString, ToCStr}; use collections; +use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{self, IoResult, IoError, EndOfFile}; @@ -101,7 +101,7 @@ impl Process { // We may use this in the child, so perform allocations before the // fork - let devnull = "/dev/null".to_c_str(); + let devnull = b"/dev/null\0"; set_cloexec(output.fd()); @@ -204,7 +204,7 @@ impl Process { } else { libc::O_RDWR }; - libc::open(devnull.as_ptr(), flags, 0) + libc::open(devnull.as_ptr() as *const _, flags, 0) } Some(obj) => { let fd = obj.as_inner().fd(); diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 11f29232a92..62f3242a206 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -54,7 +54,7 @@ use libc; use mem; use os; use ptr; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; use sys::c; use sys::fs::FileDesc; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 319a458087b..4ccecfd1f5f 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -21,7 +21,8 @@ /// copy of that function in my mingw install (maybe it was broken?). Instead, /// this takes the route of using StackWalk64 in order to walk the stack. -use c_str::CString; +use dynamic_lib::DynamicLibrary; +use ffi; use intrinsics; use io::{IoResult, Writer}; use libc; @@ -30,10 +31,9 @@ use ops::Drop; use option::Option::{Some, None}; use path::Path; use result::Result::{Ok, Err}; -use sync::{StaticMutex, MUTEX_INIT}; use slice::SliceExt; -use str::StrExt; -use dynamic_lib::DynamicLibrary; +use str::{self, StrExt}; +use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -357,11 +357,11 @@ pub fn write(w: &mut Writer) -> IoResult<()> { if ret == libc::TRUE { try!(write!(w, " - ")); - let cstr = unsafe { CString::new(info.Name.as_ptr(), false) }; - let bytes = cstr.as_bytes(); - match cstr.as_str() { - Some(s) => try!(demangle(w, s)), - None => try!(w.write(bytes[..bytes.len()-1])), + let ptr = info.Name.as_ptr() as *const libc::c_char; + let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + match str::from_utf8(bytes) { + Ok(s) => try!(demangle(w, s)), + Err(..) => try!(w.write(bytes[..bytes.len()-1])), } } try!(w.write(&['\n' as u8])); diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 1ee57434fb9..945c2e8e7d1 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -133,7 +133,7 @@ pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::v1::*; - use c_str::ToCStr; + use ffi::CString; extern "system" { fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -147,14 +147,13 @@ pub mod compat { unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { let mut module: Vec = module.utf16_units().collect(); module.push(0); - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module.as_ptr()); - let func: uint = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, if func == 0 { - fallback - } else { - func - }) + let symbol = CString::from_slice(symbol.as_bytes()); + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr())); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func }) } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 9a942300656..f8c75335b35 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -13,7 +13,6 @@ use alloc::arc::Arc; use libc::{self, c_int}; -use c_str::CString; use mem; use sys::os::fill_utf16_buf_and_decode; use path; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 9057515cad2..9996909f2f5 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -87,16 +87,21 @@ use prelude::v1::*; use libc; -use c_str::CString; +use ffi::CString; +use io::{self, IoError, IoResult}; use mem; use ptr; -use sync::{Arc, Mutex}; +use str; use sync::atomic::{AtomicBool, Ordering}; -use io::{self, IoError, IoResult}; +use sync::{Arc, Mutex}; use sys_common::{self, eof}; -use super::{c, os, timer, to_utf16, decode_error_detailed}; +use super::{c, os, timer, decode_error_detailed}; + +fn to_utf16(c: &CString) -> IoResult> { + super::to_utf16(str::from_utf8(c.as_bytes()).ok()) +} struct Event(libc::HANDLE); @@ -270,7 +275,7 @@ impl UnixStream { } pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr.as_str())); + let addr = try!(to_utf16(addr)); let start = timer::now(); loop { match UnixStream::try_connect(addr.as_ptr()) { @@ -571,7 +576,7 @@ impl UnixListener { // Although we technically don't need the pipe until much later, we // create the initial handle up front to test the validity of the name // and such. - let addr_v = try!(to_utf16(addr.as_str())); + let addr_v = try!(to_utf16(addr)); let ret = unsafe { pipe(addr_v.as_ptr(), true) }; if ret == libc::INVALID_HANDLE_VALUE { Err(super::last_error()) @@ -661,7 +666,7 @@ impl UnixAcceptor { // proceed in accepting new clients in the future if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) } - let name = try!(to_utf16(self.listener.name.as_str())); + let name = try!(to_utf16(&self.listener.name)); // Once we've got a "server handle", we need to wait for a client to // connect. The ConnectNamedPipe function will block this thread until @@ -753,7 +758,7 @@ impl UnixAcceptor { impl Clone for UnixAcceptor { fn clone(&self) -> UnixAcceptor { - let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); + let name = to_utf16(&self.listener.name).ok().unwrap(); UnixAcceptor { inner: self.inner.clone(), event: Event::new(true, false).ok().unwrap(), diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 81e8f974a12..9b3f2ca0373 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,27 +10,26 @@ use prelude::v1::*; +use collections; +use ffi::CString; +use hash::Hash; +use io::fs::PathExtensions; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::{IoResult, IoError}; +use io; use libc::{pid_t, c_void, c_int}; use libc; -use c_str::{CString, ToCStr}; -use io; use mem; use os; -use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; use path::BytesContainer; -use hash::Hash; -use io::{IoResult, IoError}; - +use ptr; +use str; +use sys::fs::FileDesc; use sys::fs; use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; use sys_common::{AsInner, mkerr_libc, timeout}; -use io::fs::PathExtensions; - pub use sys_common::ProcessConfig; /// A value representing a child process. @@ -142,10 +141,10 @@ impl Process { // Split the value and test each path to see if the // program exists. for path in os::split_paths(v.container_as_bytes()).into_iter() { - let path = path.join(cfg.program().as_bytes_no_nul()) + let path = path.join(cfg.program().as_bytes()) .with_extension(os::consts::EXE_EXTENSION); if path.exists() { - return Some(path.to_c_str()) + return Some(CString::from_slice(path.as_vec())) } } break @@ -363,11 +362,11 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA fn make_command_line(prog: &CString, args: &[CString]) -> String { let mut cmd = String::new(); - append_arg(&mut cmd, prog.as_str() + append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() .expect("expected program name to be utf-8 encoded")); for arg in args.iter() { cmd.push(' '); - append_arg(&mut cmd, arg.as_str() + append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() .expect("expected argument to be utf-8 encoded")); } return cmd; @@ -449,7 +448,7 @@ fn with_dirp(d: Option<&CString>, cb: F) -> T where { match d { Some(dir) => { - let dir_str = dir.as_str() + let dir_str = str::from_utf8(dir.as_bytes()).ok() .expect("expected workingdirectory to be utf-8 encoded"); let mut dir_str: Vec = dir_str.utf16_units().collect(); dir_str.push(0); diff --git a/src/test/auxiliary/linkage-visibility.rs b/src/test/auxiliary/linkage-visibility.rs index 0b4bea49fa2..6cd94ee5602 100644 --- a/src/test/auxiliary/linkage-visibility.rs +++ b/src/test/auxiliary/linkage-visibility.rs @@ -27,7 +27,7 @@ fn bar() { } fn baz() { } pub fn test() { - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let lib = DynamicLibrary::open(none).unwrap(); unsafe { assert!(lib.symbol::("foo").is_ok()); diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index c95cf0bfdee..22c322b86c9 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -12,7 +12,7 @@ extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, c_long, c_longlong}; @@ -24,11 +24,13 @@ mod mlibc { } fn atol(s: String) -> int { - s.as_slice().with_c_str(|x| unsafe { mlibc::atol(x) as int }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atol(c.as_ptr()) as int } } fn atoll(s: String) -> i64 { - s.as_slice().with_c_str(|x| unsafe { mlibc::atoll(x) as i64 }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atoll(c.as_ptr()) as i64 } } pub fn main() { diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 5e028d3774f..1a84236793b 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::{str, string}; -use std::c_str::ToCStr; const A: [u8; 2] = ['h' as u8, 'i' as u8]; const B: &'static [u8; 2] = &A; @@ -23,8 +22,5 @@ pub fn main() { assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); - - let bar = str::from_utf8_unchecked(&A).to_c_str(); - assert_eq!(bar.as_str(), "hi".to_c_str().as_str()); } } diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 8a75fdd685d..dff1a1eaa04 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -11,7 +11,7 @@ // ignore-fast doesn't like extern crate extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; @@ -24,11 +24,10 @@ mod mlibc { fn strlen(str: String) -> uint { // C string is terminated with a zero - str.as_slice().with_c_str(|buf| { - unsafe { - mlibc::my_strlen(buf) as uint - } - }) + let s = CString::from_slice(str.as_bytes()); + unsafe { + mlibc::my_strlen(s.as_ptr()) as uint + } } pub fn main() { diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index c7aa405b513..d610bf09edb 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -13,8 +13,8 @@ extern crate libc; +use std::ffi::CString; use std::io::TempDir; -use std::c_str::ToCStr; use std::io::fs::PathExtensions; use std::io::fs; use std::io; @@ -31,20 +31,17 @@ fn rename_directory() { let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ - let ostream = test_file.with_c_str(|fromp| { - "w+b".with_c_str(|modebuf| { - libc::fopen(fromp, modebuf) - }) - }); + let fromp = CString::from_slice(test_file.as_vec()); + let modebuf = CString::from_slice(b"w+b"); + let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr()); assert!((ostream as uint != 0u)); let s = "hello".to_string(); - "hello".with_c_str(|buf| { - let write_len = libc::fwrite(buf as *const libc::c_void, - 1u as libc::size_t, - (s.len() + 1u) as libc::size_t, - ostream); - assert_eq!(write_len, (s.len() + 1) as libc::size_t) - }); + let buf = CString::from_slice(b"hello"); + let write_len = libc::fwrite(buf.as_ptr() as *mut _, + 1u as libc::size_t, + (s.len() + 1u) as libc::size_t, + ostream); + assert_eq!(write_len, (s.len() + 1) as libc::size_t); assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(&["quux", "blat"]); diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index 3e771897025..9600a242ca1 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -10,7 +10,7 @@ extern crate libc; -use std::c_str::{CString, ToCStr}; +use std::ffi::{self, CString}; use libc::{c_char, c_int}; // ignore-fast doesn't like extern crate @@ -22,40 +22,35 @@ extern { unsafe fn check(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T { let mut x = [0 as c_char; 50]; f(&mut x[0] as *mut c_char); - let res = CString::new(&x[0], false); - assert_eq!(expected, res.as_str().unwrap()); + assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr())); } pub fn main() { unsafe { // Call with just the named parameter - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| sprintf(s, c)); - }); + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); // Make a function pointer - let x: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; + let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; // A function that takes a function pointer - unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) { - // Call with just the named parameter via fn pointer - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| p(s, c)); - }); + 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"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - p(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); }