mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 09:23:05 +00:00
std: Redesign c_str and c_vec
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:
parent
1f732ef53d
commit
ec7a50d20d
@ -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"
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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 _);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
@ -334,9 +334,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
|
||||
@ -475,15 +474,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
|
||||
@ -537,11 +538,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()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2645,11 +2643,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);
|
||||
@ -2670,9 +2667,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,
|
||||
@ -2779,9 +2776,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") {
|
||||
@ -2823,9 +2820,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 => ()
|
||||
@ -2992,17 +2988,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;
|
||||
}
|
||||
@ -3010,8 +3005,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();
|
||||
|
||||
@ -3041,7 +3034,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);
|
||||
}
|
||||
}
|
||||
@ -3057,9 +3051,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);
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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});
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
@ -760,14 +760,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);
|
||||
};
|
||||
}
|
||||
|
||||
@ -829,22 +830,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.
|
||||
@ -1388,28 +1387,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(),
|
||||
@ -1514,19 +1511,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);
|
||||
}
|
||||
@ -1549,19 +1545,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);
|
||||
}
|
||||
}
|
||||
@ -1606,19 +1601,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)
|
||||
}
|
||||
}
|
||||
@ -1630,29 +1625,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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1678,42 +1669,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,
|
||||
@ -1758,14 +1748,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);
|
||||
@ -1793,16 +1781,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>,
|
||||
@ -1838,16 +1824,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;
|
||||
}
|
||||
@ -1859,16 +1844,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;
|
||||
}
|
||||
|
||||
@ -2478,14 +2462,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();
|
||||
|
||||
@ -2509,20 +2493,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()
|
||||
@ -2553,24 +2536,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,
|
||||
@ -2681,21 +2662,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();
|
||||
|
||||
@ -2719,30 +2699,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;
|
||||
@ -4079,18 +4057,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,
|
||||
@ -4128,7 +4106,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 {
|
||||
@ -4145,14 +4123,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 {
|
||||
@ -4160,8 +4139,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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
@ -498,11 +498,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(
|
||||
|
@ -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;
|
||||
@ -742,9 +742,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);
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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
218
src/libstd/ffi/c_str.rs
Normal 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
20
src/libstd/ffi/mod.rs
Normal 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;
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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]
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
use prelude::v1::*;
|
||||
|
||||
use os;
|
||||
use sync::atomic::{mod, Ordering};
|
||||
use sync::atomic::{self, Ordering};
|
||||
|
||||
pub use sys::backtrace::write;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>")),
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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]));
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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"]);
|
||||
|
@ -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>(expected: &str, f: |*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());
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user