rollup merge of #20507: alexcrichton/issue-20444

This commit is an implementation of [RFC 494][rfc] which removes the entire
`std::c_vec` module and redesigns the `std::c_str` module as `std::ffi`.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0494-c_str-and-c_vec-stability.md

The interface of the new `CString` is outlined in the linked RFC, the primary
changes being:

* The `ToCStr` trait is gone, meaning the `with_c_str` and `to_c_str` methods
  are now gone. These two methods are replaced with a `CString::from_slice`
  method.
* The `CString` type is now just a wrapper around `Vec<u8>` with a static
  guarantee that there is a trailing nul byte with no internal nul bytes. This
  means that `CString` now implements `Deref<Target = [c_char]>`, which is where
  it gains most of its methods from. A few helper methods are added to acquire a
  slice of `u8` instead of `c_char`, as well as including a slice with the
  trailing nul byte if necessary.
* All usage of non-owned `CString` values is now done via two functions inside
  of `std::ffi`, called `c_str_to_bytes` and `c_str_to_bytes_with_nul`. These
  functions are now the one method used to convert a `*const c_char` to a Rust
  slice of `u8`.

Many more details, including newly deprecated methods, can be found linked in
the RFC. This is a:

[breaking-change]
Closes #20444
This commit is contained in:
Alex Crichton 2015-01-05 18:37:22 -08:00
commit 25d5a3a194
59 changed files with 1018 additions and 1998 deletions

View File

@ -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<T>`) 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<T>`) 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"

View File

@ -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");

View File

@ -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;

View File

@ -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<u8>,
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<CVec<u8>> {
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<Bytes> {
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<CVec<u8>> {
&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<CVec<u8>> {
}
/// Compress a buffer, without writing any sort of header on the output.
pub fn deflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
pub fn deflate_bytes(bytes: &[u8]) -> Option<Bytes> {
deflate_bytes_internal(bytes, LZ_NORM)
}
/// Compress a buffer, using a header that zlib can understand.
pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<Bytes> {
deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<Bytes> {
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<CVec<u8>> {
&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<CVec<u8>> {
}
/// Decompress a buffer, without parsing any sort of header on the input.
pub fn inflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
pub fn inflate_bytes(bytes: &[u8]) -> Option<Bytes> {
inflate_bytes_internal(bytes, 0)
}
/// Decompress a buffer that starts with a zlib header.
pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<Bytes> {
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}

View File

@ -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<ast::CrateNum, ast::CrateNum>;
pub enum MetadataBlob {
MetadataVec(CVec<u8>),
MetadataVec(Bytes),
MetadataArchive(loader::ArchiveMetadata),
}

View File

@ -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<MetadataBlo
}
}
unsafe {
let mb = filename.with_c_str(|buf| {
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
});
let buf = CString::from_slice(filename.as_vec());
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
if mb as int == 0 {
return Err(format!("error reading library: '{}'",
filename.display()))
@ -738,8 +737,9 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlo
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
let mut name_buf = ptr::null();
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
let name = String::from_raw_buf_len(name_buf as *const u8,
name_len as uint);
let name = slice::from_raw_buf(&(name_buf as *const u8),
name_len as uint).to_vec();
let name = String::from_utf8(name).unwrap();
debug!("get_metadata_section: name {}", name);
if read_meta_section_name(is_osx) == name {
let cbuf = llvm::LLVMGetSectionContents(si.llsi);

View File

@ -13,7 +13,7 @@
use libc;
use ArchiveRef;
use std::c_str::ToCStr;
use std::ffi::CString;
use std::mem;
use std::raw;
@ -30,9 +30,8 @@ impl ArchiveRO {
/// raised.
pub fn open(dst: &Path) -> Option<ArchiveRO> {
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 {

View File

@ -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()) }
}
}

View File

@ -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<CString> = 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));

View File

@ -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 _);
}
_ => {}
};

View File

@ -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 {

View File

@ -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<u8> {
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<u8> {
/// 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<String>) {
use std::c_str::CString;
unsafe {
let mut declared = HashSet::new();
@ -3035,7 +3028,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
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<String>) {
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);
}
}

View File

@ -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");

View File

@ -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<ast::NodeId>)
-> 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);

View File

@ -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});

View File

@ -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)
}

View File

@ -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<DIDescriptor> = 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<NamespaceTree
None => 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<NamespaceTree
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) {
if needs_gdb_debug_scripts_section(ccx) {
let empty = b"".to_c_str();
let empty = CString::from_slice(b"");
let gdb_debug_scripts_section_global =
get_or_insert_gdb_debug_scripts_section_global(ccx);
unsafe {
@ -4077,14 +4055,15 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext)
/// section.
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
-> 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);

View File

@ -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);

View File

@ -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(

View File

@ -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<I: Iterator<Item=ValueRef>>(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);

View File

@ -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 {

View File

@ -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,

View File

@ -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();

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<Ordering> {
self.as_bytes().partial_cmp(other.as_bytes())
}
}
impl Eq for CString {}
impl<S: hash::Writer> hash::Hash<S> 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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&self, f: F) -> T where
F: FnOnce(*const libc::c_char) -> T,
{
(**self).with_c_str(f)
}
#[inline]
unsafe fn with_c_str_unchecked<T, F>(&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<T, F>(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<libc::c_char> {
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<F>(buf: *const libc::c_char,
count: Option<uint>,
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: 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<CString> = 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)
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<T> {
base: *mut T,
len: uint,
dtor: Option<Thunk>,
}
#[unsafe_destructor]
impl<T> Drop for CVec<T> {
fn drop(&mut self) {
match self.dtor.take() {
None => (),
Some(f) => f.invoke(())
}
}
}
impl<T> CVec<T> {
/// 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<T> {
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<F>(base: *mut T,
len: uint,
dtor: F)
-> CVec<T>
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<T> AsSlice<T> for CVec<T> {
/// 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<u8> {
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::<u8>(), 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);
}
}
}

View File

@ -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<T: ToCStr>(filename: Option<T>)
-> Result<DynamicLibrary, String> {
pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
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<Path> = 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<T: ToCStr>(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<T: ToCStr>(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<u16> = filename_str.utf16_units().collect();
filename_str.push(0);
LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8

218
src/libstd/ffi/c_str.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use fmt;
use iter::IteratorExt;
use libc;
use mem;
use ops::Deref;
use slice::{self, SliceExt, AsSlice};
use string::String;
use vec::Vec;
/// A type representing a C-compatible string
///
/// This type serves the primary purpose of being able to generate a
/// C-compatible string from a Rust byte slice or vector. An instance of this
/// type is a static guarantee that the underlying bytes contain no interior 0
/// bytes and the final byte is 0.
///
/// A `CString` is created from either a byte slice or a byte vector. After
/// being created, a `CString` predominately inherits all of its methods from
/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
/// array is represented as an array of `libc::c_char` as opposed to `u8`. A
/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from
/// a `CString` do *not* contain the trailing nul terminator unless otherwise
/// specified.
///
/// # Example
///
/// ```no_run
/// # extern crate libc;
/// # fn main() {
/// use std::ffi::CString;
/// use libc;
///
/// extern {
/// fn my_printer(s: *const libc::c_char);
/// }
///
/// let to_print = "Hello, world!";
/// let c_to_print = CString::from_slice(to_print.as_bytes());
/// unsafe {
/// my_printer(c_to_print.as_ptr());
/// }
/// # }
/// ```
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct CString {
inner: Vec<libc::c_char>,
}
impl CString {
/// Create a new C-compatible string from a byte slice.
///
/// This method will copy the data of the slice provided into a new
/// allocation, ensuring that there is a trailing 0 byte.
///
/// # Panics
///
/// This function will panic if there are any 0 bytes already in the slice
/// provided.
pub fn from_slice(v: &[u8]) -> CString {
CString::from_vec(v.to_vec())
}
/// Create a C-compatible string from a byte vector.
///
/// This method will consume ownership of the provided vector, appending a 0
/// byte to the end after verifying that there are no interior 0 bytes.
///
/// # Panics
///
/// This function will panic if there are any 0 bytes already in the vector
/// provided.
pub fn from_vec(v: Vec<u8>) -> CString {
assert!(!v.iter().any(|&x| x == 0));
unsafe { CString::from_vec_unchecked(v) }
}
/// Create a C-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<u8>) -> CString {
v.push(0);
CString { inner: mem::transmute(v) }
}
/// Create a view into this C string which includes the trailing nul
/// terminator at the end of the string.
pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() }
/// Similar to the `as_slice` method, but returns a `u8` slice instead of a
/// `libc::c_char` slice.
pub fn as_bytes(&self) -> &[u8] {
unsafe { mem::transmute(self.as_slice()) }
}
/// 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");
}
}
}

20
src/libstd/ffi/mod.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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;

View File

@ -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<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
UnixStreamImp::connect(&path.to_c_str(), None)
pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> {
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<P: ToCStr>(path: &P,
timeout: Duration) -> IoResult<UnixStream> {
pub fn connect_timeout<P>(path: P, timeout: Duration)
-> IoResult<UnixStream>
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<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
UnixListenerImp::bind(&path.to_c_str())
pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> {
let path = CString::from_slice(path.container_as_bytes());
UnixListenerImp::bind(&path)
.map(|inner| UnixListener { inner: inner })
}
}

View File

@ -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<T:ToCStr>(program: T) -> Command {
pub fn new<T: BytesContainer>(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"));
}
}

View File

@ -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;

View File

@ -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<String> {
///
/// Panics if `n` has any interior NULs.
pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
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<T: BytesContainer>(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<Vec<u8>> {
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<Vec<u8>> {
// res
#[cfg(target_os = "ios")]
fn real_args_as_bytes() -> Vec<Vec<u8>> {
use c_str::CString;
use iter::range;
use mem;

View File

@ -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<u8> {
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<T: BytesContainer>(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);
}
}

View File

@ -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<S: hash::Writer> hash::Hash<S> for Path {
#[inline]
fn hash(&self, state: &mut S) {

View File

@ -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<S: hash::Writer> hash::Hash<S> for Path {
#[cfg(not(test))]
#[inline]

View File

@ -46,8 +46,9 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { 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<Vec<u8>> {
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()
}

View File

@ -15,7 +15,7 @@
use prelude::v1::*;
use os;
use sync::atomic::{mod, Ordering};
use sync::atomic::{self, Ordering};
pub use sys::backtrace::write;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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<String, IoError> {
}
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())
}
}

View File

@ -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<CString>) -> 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, "<unknown>")),
}

View File

@ -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<FileDesc> {
let flags = match fm {
Open => 0,
@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
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<FileDesc> {
}
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<Vec<Path>> {
use libc::{opendir, readdir_r, closedir};
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
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<Vec<Path>> {
let mut buf = Vec::<u8>::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<Vec<Path>> {
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<Vec<Path>> {
}
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<Path> {
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<Path> {
}
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<FileStat> {
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<FileStat> {
}
pub fn lstat(p: &Path) -> IoResult<FileStat> {
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<FileStat> {
}
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,

View File

@ -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
}

View File

@ -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<Path> {
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<Vec<u8>> {
use c_str::CString;
extern {
fn rust_env_pairs() -> *const *const c_char;
}
@ -147,8 +144,7 @@ pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
}
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<Vec<u8>> {
}
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 {

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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]));

View File

@ -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<u16> = 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
})
}

View File

@ -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;

View File

@ -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<Vec<u16>> {
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<u64>) -> IoResult<UnixStream> {
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(),

View File

@ -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<T, F>(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<u16> = dir_str.utf16_units().collect();
dir_str.push(0);

View File

@ -27,7 +27,7 @@ fn bar() { }
fn baz() { }
pub fn test() {
let none: Option<Path> = None; // appease the typechecker
let none: Option<&Path> = None; // appease the typechecker
let lib = DynamicLibrary::open(none).unwrap();
unsafe {
assert!(lib.symbol::<int>("foo").is_ok());

View File

@ -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() {

View File

@ -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());
}
}

View File

@ -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() {

View File

@ -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"]);

View File

@ -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<T, F>(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());
});
}