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
59 changed files with 1018 additions and 1998 deletions
|
@ -451,7 +451,7 @@ them.
|
||||||
~~~no_run
|
~~~no_run
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
#[link(name = "readline")]
|
#[link(name = "readline")]
|
||||||
|
@ -460,11 +460,10 @@ extern {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
"[my-awesome-shell] $".with_c_str(|buf| {
|
let prompt = CString::from_slice(b"[my-awesome-shell] $");
|
||||||
unsafe { rl_prompt = buf; }
|
unsafe { rl_prompt = prompt.as_ptr(); }
|
||||||
// get a line, process it
|
// get a line, process it
|
||||||
unsafe { rl_prompt = ptr::null(); }
|
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
|
# Interoperability with foreign code
|
||||||
|
|
||||||
Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C
|
Rust guarantees that the layout of a `struct` is compatible with the platform's
|
||||||
only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out
|
representation in C only if the `#[repr(C)]` attribute is applied to it.
|
||||||
struct members without padding. `#[repr(C)]` can also be applied to an enum.
|
`#[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
|
Rust's owned boxes (`Box<T>`) use non-nullable pointers as handles which point
|
||||||
object. However, they should not be manually created because they are managed by internal
|
to the contained object. However, they should not be manually created because
|
||||||
allocators. References can safely be assumed to be non-nullable pointers directly to the type.
|
they are managed by internal allocators. References can safely be assumed to be
|
||||||
However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer
|
non-nullable pointers directly to the type. However, breaking the borrow
|
||||||
using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about
|
checking or mutability rules is not guaranteed to be safe, so prefer using raw
|
||||||
them.
|
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
|
Vectors and strings share the same basic memory layout, and utilities are
|
||||||
`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a
|
available in the `vec` and `str` modules for working with C APIs. However,
|
||||||
NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function.
|
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 standard library includes type aliases and function definitions for the C
|
||||||
the `libc` module, and Rust links against `libc` and `libm` by default.
|
standard library in the `libc` module, and Rust links against `libc` and `libm`
|
||||||
|
by default.
|
||||||
|
|
||||||
# The "nullable pointer optimization"
|
# 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
|
/// Converts a vector of bytes to a new `String` without checking if
|
||||||
/// it contains valid UTF-8. This is unsafe because it assumes that
|
/// it contains valid UTF-8. This is unsafe because it assumes that
|
||||||
/// the UTF-8-ness of the vector has already been validated.
|
/// the UTF-8-ness of the vector has already been validated.
|
||||||
|
@ -1126,24 +1102,6 @@ mod tests {
|
||||||
String::from_str("\u{FFFD}𐒋\u{FFFD}"));
|
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]
|
#[test]
|
||||||
fn test_push_bytes() {
|
fn test_push_bytes() {
|
||||||
let mut s = String::from_str("ABC");
|
let mut s = String::from_str("ABC");
|
||||||
|
|
|
@ -190,7 +190,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function will panic if the string pointed to by `s` is not valid UTF-8.
|
/// 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 {
|
pub unsafe fn from_c_str(s: *const i8) -> &'static str {
|
||||||
let s = s as *const u8;
|
let s = s as *const u8;
|
||||||
let mut len = 0u;
|
let mut len = 0u;
|
||||||
|
|
|
@ -21,15 +21,34 @@
|
||||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
#![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_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
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;
|
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use libc::{c_void, size_t, c_int};
|
use libc::{c_void, size_t, c_int};
|
||||||
use std::c_vec::CVec;
|
use std::ops::Deref;
|
||||||
use std::ptr::Unique;
|
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")]
|
#[link(name = "miniz", kind = "static")]
|
||||||
extern {
|
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 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
|
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 {
|
unsafe {
|
||||||
let mut outsz : size_t = 0;
|
let mut outsz : size_t = 0;
|
||||||
let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _,
|
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,
|
&mut outsz,
|
||||||
flags);
|
flags);
|
||||||
if !res.is_null() {
|
if !res.is_null() {
|
||||||
let res = Unique(res);
|
let res = Unique(res as *mut u8);
|
||||||
Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
|
Some(Bytes { ptr: res, len: outsz as uint })
|
||||||
} else {
|
} else {
|
||||||
None
|
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.
|
/// 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)
|
deflate_bytes_internal(bytes, LZ_NORM)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compress a buffer, using a header that zlib can understand.
|
/// 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)
|
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 {
|
unsafe {
|
||||||
let mut outsz : size_t = 0;
|
let mut outsz : size_t = 0;
|
||||||
let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
|
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,
|
&mut outsz,
|
||||||
flags);
|
flags);
|
||||||
if !res.is_null() {
|
if !res.is_null() {
|
||||||
let res = Unique(res);
|
let res = Unique(res as *mut u8);
|
||||||
Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0)))
|
Some(Bytes { ptr: res, len: outsz as uint })
|
||||||
} else {
|
} else {
|
||||||
None
|
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.
|
/// 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)
|
inflate_bytes_internal(bytes, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decompress a buffer that starts with a zlib header.
|
/// 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)
|
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ use metadata::loader;
|
||||||
use util::nodemap::{FnvHashMap, NodeMap};
|
use util::nodemap::{FnvHashMap, NodeMap};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::c_vec::CVec;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use flate::Bytes;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token::IdentInterner;
|
use syntax::parse::token::IdentInterner;
|
||||||
|
@ -36,7 +36,7 @@ use syntax::parse::token::IdentInterner;
|
||||||
pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
|
pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
|
||||||
|
|
||||||
pub enum MetadataBlob {
|
pub enum MetadataBlob {
|
||||||
MetadataVec(CVec<u8>),
|
MetadataVec(Bytes),
|
||||||
MetadataArchive(loader::ArchiveMetadata),
|
MetadataArchive(loader::ArchiveMetadata),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ use syntax::codemap::Span;
|
||||||
use syntax::diagnostic::SpanHandler;
|
use syntax::diagnostic::SpanHandler;
|
||||||
use util::fs;
|
use util::fs;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io::fs::PathExtensions;
|
use std::io::fs::PathExtensions;
|
||||||
|
@ -720,9 +720,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let mb = filename.with_c_str(|buf| {
|
let buf = CString::from_slice(filename.as_vec());
|
||||||
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
|
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
|
||||||
});
|
|
||||||
if mb as int == 0 {
|
if mb as int == 0 {
|
||||||
return Err(format!("error reading library: '{}'",
|
return Err(format!("error reading library: '{}'",
|
||||||
filename.display()))
|
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 {
|
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
||||||
let mut name_buf = ptr::null();
|
let mut name_buf = ptr::null();
|
||||||
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
|
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
|
||||||
let name = String::from_raw_buf_len(name_buf as *const u8,
|
let name = slice::from_raw_buf(&(name_buf as *const u8),
|
||||||
name_len as uint);
|
name_len as uint).to_vec();
|
||||||
|
let name = String::from_utf8(name).unwrap();
|
||||||
debug!("get_metadata_section: name {}", name);
|
debug!("get_metadata_section: name {}", name);
|
||||||
if read_meta_section_name(is_osx) == name {
|
if read_meta_section_name(is_osx) == name {
|
||||||
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
use libc;
|
use libc;
|
||||||
use ArchiveRef;
|
use ArchiveRef;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::raw;
|
use std::raw;
|
||||||
|
|
||||||
|
@ -30,9 +30,8 @@ impl ArchiveRO {
|
||||||
/// raised.
|
/// raised.
|
||||||
pub fn open(dst: &Path) -> Option<ArchiveRO> {
|
pub fn open(dst: &Path) -> Option<ArchiveRO> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ar = dst.with_c_str(|dst| {
|
let s = CString::from_slice(dst.as_vec());
|
||||||
::LLVMRustOpenArchive(dst)
|
let ar = ::LLVMRustOpenArchive(s.as_ptr());
|
||||||
});
|
|
||||||
if ar.is_null() {
|
if ar.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -45,9 +44,9 @@ impl ArchiveRO {
|
||||||
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
|
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut size = 0 as libc::size_t;
|
let mut size = 0 as libc::size_t;
|
||||||
let ptr = file.with_c_str(|file| {
|
let file = CString::from_slice(file.as_bytes());
|
||||||
::LLVMRustArchiveReadSection(self.ptr, file, &mut size)
|
let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
|
||||||
});
|
&mut size);
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub use self::Visibility::*;
|
||||||
pub use self::DiagnosticSeverity::*;
|
pub use self::DiagnosticSeverity::*;
|
||||||
pub use self::Linkage::*;
|
pub use self::Linkage::*;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::{raw, mem};
|
use std::{raw, mem};
|
||||||
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
|
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 {
|
pub fn mk_target_data(string_rep: &str) -> TargetData {
|
||||||
|
let string_rep = CString::from_slice(string_rep.as_bytes());
|
||||||
TargetData {
|
TargetData {
|
||||||
lltd: string_rep.with_c_str(|buf| {
|
lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) }
|
||||||
unsafe { LLVMCreateTargetData(buf) }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc::util::common::time;
|
||||||
use libc;
|
use libc;
|
||||||
use flate;
|
use flate;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::Int;
|
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
|
// Internalize everything but the reachable symbols of the current module
|
||||||
let cstrs: Vec<::std::c_str::CString> =
|
let cstrs: Vec<CString> = reachable.iter().map(|s| {
|
||||||
reachable.iter().map(|s| s.to_c_str()).collect();
|
CString::from_slice(s.as_bytes())
|
||||||
let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
|
}).collect();
|
||||||
|
let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect();
|
||||||
let ptr = arr.as_ptr();
|
let ptr = arr.as_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustRunRestrictionPass(llmod,
|
llvm::LLVMRustRunRestrictionPass(llmod,
|
||||||
|
@ -164,7 +165,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||||
unsafe {
|
unsafe {
|
||||||
let pm = llvm::LLVMCreatePassManager();
|
let pm = llvm::LLVMCreatePassManager();
|
||||||
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
|
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();
|
let builder = llvm::LLVMPassManagerBuilderCreate();
|
||||||
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
|
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
|
||||||
|
@ -172,7 +173,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||||
/* RunInliner = */ True);
|
/* RunInliner = */ True);
|
||||||
llvm::LLVMPassManagerBuilderDispose(builder);
|
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", (), |()|
|
time(sess.time_passes(), "LTO passes", (), |()|
|
||||||
llvm::LLVMRunPassManager(pm, llmod));
|
llvm::LLVMRunPassManager(pm, llmod));
|
||||||
|
|
|
@ -22,7 +22,7 @@ use syntax::codemap;
|
||||||
use syntax::diagnostic;
|
use syntax::diagnostic;
|
||||||
use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
|
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::Command;
|
||||||
use std::io::fs;
|
use std::io::fs;
|
||||||
use std::iter::Unfold;
|
use std::iter::Unfold;
|
||||||
|
@ -32,7 +32,7 @@ use std::mem;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::thread;
|
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)]
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
pub enum OutputType {
|
pub enum OutputType {
|
||||||
|
@ -49,8 +49,9 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
|
||||||
if cstr == ptr::null() {
|
if cstr == ptr::null() {
|
||||||
handler.fatal(msg[]);
|
handler.fatal(msg[]);
|
||||||
} else {
|
} else {
|
||||||
let err = CString::new(cstr, true);
|
let err = ffi::c_str_to_bytes(&cstr);
|
||||||
let err = String::from_utf8_lossy(err.as_bytes());
|
let err = String::from_utf8_lossy(err.as_slice()).to_string();
|
||||||
|
libc::free(cstr as *mut _);
|
||||||
handler.fatal(format!("{}: {}",
|
handler.fatal(format!("{}: {}",
|
||||||
msg[],
|
msg[],
|
||||||
err[])[]);
|
err[])[]);
|
||||||
|
@ -66,13 +67,12 @@ pub fn write_output_file(
|
||||||
output: &Path,
|
output: &Path,
|
||||||
file_type: llvm::FileType) {
|
file_type: llvm::FileType) {
|
||||||
unsafe {
|
unsafe {
|
||||||
output.with_c_str(|output| {
|
let output = CString::from_slice(output.as_vec());
|
||||||
let result = llvm::LLVMRustWriteOutputFile(
|
let result = llvm::LLVMRustWriteOutputFile(
|
||||||
target, pm, m, output, file_type);
|
target, pm, m, output.as_ptr(), file_type);
|
||||||
if !result {
|
if !result {
|
||||||
llvm_err(handler, "could not write output".to_string());
|
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 triple = sess.target.target.llvm_target[];
|
||||||
|
|
||||||
let tm = unsafe {
|
let tm = unsafe {
|
||||||
triple.with_c_str(|t| {
|
let triple = CString::from_slice(triple.as_bytes());
|
||||||
let cpu = match sess.opts.cg.target_cpu {
|
let cpu = match sess.opts.cg.target_cpu {
|
||||||
Some(ref s) => s[],
|
Some(ref s) => s.as_slice(),
|
||||||
None => sess.target.target.options.cpu[]
|
None => sess.target.target.options.cpu.as_slice()
|
||||||
};
|
};
|
||||||
cpu.with_c_str(|cpu| {
|
let cpu = CString::from_slice(cpu.as_bytes());
|
||||||
target_feature(sess).with_c_str(|features| {
|
let features = CString::from_slice(target_feature(sess).as_bytes());
|
||||||
llvm::LLVMRustCreateTargetMachine(
|
llvm::LLVMRustCreateTargetMachine(
|
||||||
t, cpu, features,
|
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
|
||||||
code_model,
|
code_model,
|
||||||
reloc_model,
|
reloc_model,
|
||||||
opt_level,
|
opt_level,
|
||||||
true /* EnableSegstk */,
|
true /* EnableSegstk */,
|
||||||
use_softfp,
|
use_softfp,
|
||||||
no_fp_elim,
|
no_fp_elim,
|
||||||
!any_library && reloc_model == llvm::RelocPIC,
|
!any_library && reloc_model == llvm::RelocPIC,
|
||||||
ffunction_sections,
|
ffunction_sections,
|
||||||
fdata_sections,
|
fdata_sections,
|
||||||
)
|
)
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if tm.is_null() {
|
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) {
|
match llvm::diagnostic::Diagnostic::unpack(info) {
|
||||||
llvm::diagnostic::Optimization(opt) => {
|
llvm::diagnostic::Optimization(opt) => {
|
||||||
let pass_name = CString::new(opt.pass_name, false);
|
let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name))
|
||||||
let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM");
|
.ok()
|
||||||
|
.expect("got a non-UTF8 pass name from LLVM");
|
||||||
let enabled = match cgcx.remark {
|
let enabled = match cgcx.remark {
|
||||||
AllPasses => true,
|
AllPasses => true,
|
||||||
SomePasses(ref v) => v.iter().any(|s| *s == pass_name),
|
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 {
|
if config.emit_no_opt_bc {
|
||||||
let ext = format!("{}.no-opt.bc", name_extra);
|
let ext = format!("{}.no-opt.bc", name_extra);
|
||||||
output_names.with_extension(ext[]).with_c_str(|buf| {
|
let out = output_names.with_extension(ext.as_slice());
|
||||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
let out = CString::from_slice(out.as_vec());
|
||||||
})
|
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
match config.opt_level {
|
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
|
// If we're verifying or linting, add them to the function pass
|
||||||
// manager.
|
// manager.
|
||||||
let addpass = |&: pass: &str| {
|
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")); }
|
if !config.no_verify { assert!(addpass("verify")); }
|
||||||
|
|
||||||
|
@ -445,12 +444,11 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
for pass in config.passes.iter() {
|
for pass in config.passes.iter() {
|
||||||
pass.with_c_str(|s| {
|
let pass = CString::from_slice(pass.as_bytes());
|
||||||
if !llvm::LLVMRustAddPass(mpm, s) {
|
if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
|
||||||
cgcx.handler.warn(format!("unknown pass {}, ignoring",
|
cgcx.handler.warn(format!("unknown pass {}, ignoring",
|
||||||
*pass)[]);
|
pass).as_slice());
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, run the actual optimization passes
|
// Finally, run the actual optimization passes
|
||||||
|
@ -470,9 +468,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||||
|
|
||||||
if config.emit_lto_bc {
|
if config.emit_lto_bc {
|
||||||
let name = format!("{}.lto.bc", name_extra);
|
let name = format!("{}.lto.bc", name_extra);
|
||||||
output_names.with_extension(name[]).with_c_str(|buf| {
|
let out = output_names.with_extension(name.as_slice());
|
||||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
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 {
|
if config.emit_bc {
|
||||||
let ext = format!("{}.bc", name_extra);
|
let ext = format!("{}.bc", name_extra);
|
||||||
output_names.with_extension(ext[]).with_c_str(|buf| {
|
let out = output_names.with_extension(ext.as_slice());
|
||||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
let out = CString::from_slice(out.as_vec());
|
||||||
})
|
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
time(config.time_passes, "codegen passes", (), |()| {
|
time(config.time_passes, "codegen passes", (), |()| {
|
||||||
if config.emit_ir {
|
if config.emit_ir {
|
||||||
let ext = format!("{}.ll", name_extra);
|
let ext = format!("{}.ll", name_extra);
|
||||||
output_names.with_extension(ext[]).with_c_str(|output| {
|
let out = output_names.with_extension(ext.as_slice());
|
||||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
let out = CString::from_slice(out.as_vec());
|
||||||
llvm::LLVMRustPrintModule(cpm, llmod, output);
|
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 llvm_args = Vec::new();
|
||||||
{
|
{
|
||||||
let mut add = |&mut : arg: &str| {
|
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_args.push(s.as_ptr());
|
||||||
llvm_c_strs.push(s);
|
llvm_c_strs.push(s);
|
||||||
};
|
};
|
||||||
|
@ -1083,7 +1081,7 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
|
||||||
|
|
||||||
match opt {
|
match opt {
|
||||||
llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
|
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_of;
|
||||||
use trans::type_::Type;
|
use trans::type_::Type;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use std::string::String;
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
use std::ffi::CString;
|
||||||
use libc::{c_uint, c_char};
|
use libc::{c_uint, c_char};
|
||||||
|
|
||||||
// Take an inline assembly expression and splat it out via LLVM
|
// 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
|
ast::AsmIntel => llvm::AD_Intel
|
||||||
};
|
};
|
||||||
|
|
||||||
let r = ia.asm.get().with_c_str(|a| {
|
let asm = CString::from_slice(ia.asm.get().as_bytes());
|
||||||
constraints.with_c_str(|c| {
|
let constraints = CString::from_slice(constraints.as_bytes());
|
||||||
InlineAsmCall(bcx,
|
let r = InlineAsmCall(bcx,
|
||||||
a,
|
asm.as_ptr(),
|
||||||
c,
|
constraints.as_ptr(),
|
||||||
inputs[],
|
inputs.as_slice(),
|
||||||
output_type,
|
output_type,
|
||||||
ia.volatile,
|
ia.volatile,
|
||||||
ia.alignstack,
|
ia.alignstack,
|
||||||
dialect)
|
dialect);
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// Again, based on how many outputs we have
|
// Again, based on how many outputs we have
|
||||||
if num_outputs == 1 {
|
if num_outputs == 1 {
|
||||||
|
|
|
@ -88,11 +88,12 @@ use util::nodemap::NodeMap;
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use libc::{c_uint, uint64_t};
|
use libc::{c_uint, uint64_t};
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::{mod, CString};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::str;
|
||||||
use std::{i8, i16, i32, i64};
|
use std::{i8, i16, i32, i64};
|
||||||
use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi};
|
use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi};
|
||||||
use syntax::ast_util::local_def;
|
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,
|
pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
|
||||||
ty: Type, output: ty::FnOutput) -> ValueRef {
|
ty: Type, output: ty::FnOutput) -> ValueRef {
|
||||||
|
|
||||||
let llfn: ValueRef = name.with_c_str(|buf| {
|
let buf = CString::from_slice(name.as_bytes());
|
||||||
unsafe {
|
let llfn: ValueRef = unsafe {
|
||||||
llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref())
|
llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|
||||||
// diverging functions may unwind, but can never return normally
|
// diverging functions may unwind, but can never return normally
|
||||||
if output == ty::FnDiverging {
|
if output == ty::FnDiverging {
|
||||||
|
@ -334,9 +334,8 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let c = name.with_c_str(|buf| {
|
let buf = CString::from_slice(name.as_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf)
|
let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr());
|
||||||
});
|
|
||||||
// Thread-local statics in some other crate need to *always* be linked
|
// 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
|
// 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
|
// 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) {
|
pub fn set_split_stack(f: ValueRef) {
|
||||||
"split-stack".with_c_str(|buf| {
|
unsafe {
|
||||||
unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); }
|
llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint,
|
||||||
})
|
"split-stack\0".as_ptr() as *const _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unset_split_stack(f: ValueRef) {
|
pub fn unset_split_stack(f: ValueRef) {
|
||||||
"split-stack".with_c_str(|buf| {
|
unsafe {
|
||||||
unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); }
|
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
|
// 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.
|
// Structural comparison: a rather involved form of glue.
|
||||||
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
|
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
|
||||||
if cx.sess().opts.cg.save_temps {
|
if cx.sess().opts.cg.save_temps {
|
||||||
s.with_c_str(|buf| {
|
let buf = CString::from_slice(s.as_bytes());
|
||||||
unsafe {
|
unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
|
||||||
llvm::LLVMSetValueName(v, buf)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2645,11 +2643,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
|
||||||
unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
|
unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
|
||||||
}
|
}
|
||||||
|
|
||||||
let llbb = "top".with_c_str(|buf| {
|
let llbb = unsafe {
|
||||||
unsafe {
|
llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn,
|
||||||
llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf)
|
"top\0".as_ptr() as *const _)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
let bld = ccx.raw_builder();
|
let bld = ccx.raw_builder();
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
||||||
|
@ -2670,9 +2667,9 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = {
|
let args = {
|
||||||
let opaque_rust_main = "rust_main".with_c_str(|buf| {
|
let opaque_rust_main = llvm::LLVMBuildPointerCast(bld,
|
||||||
llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf)
|
rust_main, Type::i8p(ccx).to_ref(),
|
||||||
});
|
"rust_main\0".as_ptr() as *const _);
|
||||||
|
|
||||||
vec!(
|
vec!(
|
||||||
opaque_rust_main,
|
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 \
|
format!("Illegal null byte in export_name \
|
||||||
value: `{}`", sym)[]);
|
value: `{}`", sym)[]);
|
||||||
}
|
}
|
||||||
let g = sym.with_c_str(|buf| {
|
let buf = CString::from_slice(sym.as_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), llty, buf)
|
let g = llvm::LLVMAddGlobal(ccx.llmod(), llty,
|
||||||
});
|
buf.as_ptr());
|
||||||
|
|
||||||
if attr::contains_name(i.attrs[],
|
if attr::contains_name(i.attrs[],
|
||||||
"thread_local") {
|
"thread_local") {
|
||||||
|
@ -2823,9 +2820,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
||||||
sect.get())[]);
|
sect.get())[]);
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
sect.get().with_c_str(|buf| {
|
let buf = CString::from_slice(sect.get().as_bytes());
|
||||||
llvm::LLVMSetSection(v, buf);
|
llvm::LLVMSetSection(v, buf.as_ptr());
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => ()
|
None => ()
|
||||||
|
@ -2992,17 +2988,16 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
|
||||||
let name = format!("rust_metadata_{}_{}",
|
let name = format!("rust_metadata_{}_{}",
|
||||||
cx.link_meta().crate_name,
|
cx.link_meta().crate_name,
|
||||||
cx.link_meta().crate_hash);
|
cx.link_meta().crate_hash);
|
||||||
let llglobal = name.with_c_str(|buf| {
|
let buf = CString::from_vec(name.into_bytes());
|
||||||
unsafe {
|
let llglobal = unsafe {
|
||||||
llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf)
|
llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(),
|
||||||
}
|
buf.as_ptr())
|
||||||
});
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||||
let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
|
let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
|
||||||
name.with_c_str(|buf| {
|
let name = CString::from_slice(name.as_bytes());
|
||||||
llvm::LLVMSetSection(llglobal, buf)
|
llvm::LLVMSetSection(llglobal, name.as_ptr())
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return metadata;
|
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
|
/// Find any symbols that are defined in one compilation unit, but not declared
|
||||||
/// in any other compilation unit. Give these symbols internal linkage.
|
/// in any other compilation unit. Give these symbols internal linkage.
|
||||||
fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
|
fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
|
||||||
use std::c_str::CString;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut declared = HashSet::new();
|
let mut declared = HashSet::new();
|
||||||
|
|
||||||
|
@ -3041,7 +3034,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = CString::new(llvm::LLVMGetValueName(val), false);
|
let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
|
||||||
|
.to_vec();
|
||||||
declared.insert(name);
|
declared.insert(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3057,9 +3051,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
|
||||||
continue
|
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) &&
|
if !declared.contains(&name) &&
|
||||||
!reachable.contains(name.as_str().unwrap()) {
|
!reachable.contains(str::from_utf8(name.as_slice()).unwrap()) {
|
||||||
llvm::SetLinkage(val, llvm::InternalLinkage);
|
llvm::SetLinkage(val, llvm::InternalLinkage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ use trans::machine::llalign_of_pref;
|
||||||
use trans::type_::Type;
|
use trans::type_::Type;
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
use libc::{c_uint, c_char};
|
use libc::{c_uint, c_char};
|
||||||
use std::c_str::ToCStr;
|
|
||||||
|
use std::ffi::CString;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
|
||||||
pub struct Builder<'a, 'tcx: 'a> {
|
pub struct Builder<'a, 'tcx: 'a> {
|
||||||
|
@ -429,9 +430,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
|
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
|
||||||
} else {
|
} else {
|
||||||
name.with_c_str(|c| {
|
let name = CString::from_slice(name.as_bytes());
|
||||||
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c)
|
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
|
||||||
})
|
name.as_ptr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -774,12 +775,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let comment_text = format!("{} {}", "#",
|
let comment_text = format!("{} {}", "#",
|
||||||
sanitized.replace("\n", "\n\t# "));
|
sanitized.replace("\n", "\n\t# "));
|
||||||
self.count_insn("inlineasm");
|
self.count_insn("inlineasm");
|
||||||
let asm = comment_text.with_c_str(|c| {
|
let comment_text = CString::from_vec(comment_text.into_bytes());
|
||||||
unsafe {
|
let asm = unsafe {
|
||||||
llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
|
llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
|
||||||
c, noname(), False, False)
|
comment_text.as_ptr(), noname(), False,
|
||||||
}
|
False)
|
||||||
});
|
};
|
||||||
self.call(asm, &[], None);
|
self.call(asm, &[], None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -926,9 +927,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
|
let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
|
||||||
let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb);
|
let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb);
|
||||||
let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_);
|
let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_);
|
||||||
let t: ValueRef = "llvm.trap".with_c_str(|buf| {
|
let p = "llvm.trap\0".as_ptr();
|
||||||
llvm::LLVMGetNamedFunction(m, buf)
|
let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _);
|
||||||
});
|
|
||||||
assert!((t as int != 0));
|
assert!((t as int != 0));
|
||||||
let args: &[ValueRef] = &[];
|
let args: &[ValueRef] = &[];
|
||||||
self.count_insn("trap");
|
self.count_insn("trap");
|
||||||
|
|
|
@ -44,7 +44,7 @@ use util::nodemap::{FnvHashMap, NodeMap};
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use libc::{c_uint, c_char};
|
use libc::{c_uint, c_char};
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use syntax::ast::Ident;
|
use syntax::ast::Ident;
|
||||||
|
@ -401,9 +401,8 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
||||||
if self.llreturn.get().is_none() {
|
if self.llreturn.get().is_none() {
|
||||||
|
|
||||||
self.llreturn.set(Some(unsafe {
|
self.llreturn.set(Some(unsafe {
|
||||||
"return".with_c_str(|buf| {
|
llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn,
|
||||||
llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf)
|
"return\0".as_ptr() as *const _)
|
||||||
})
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,11 +428,10 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
||||||
opt_node_id: Option<ast::NodeId>)
|
opt_node_id: Option<ast::NodeId>)
|
||||||
-> Block<'a, 'tcx> {
|
-> Block<'a, 'tcx> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let llbb = name.with_c_str(|buf| {
|
let name = CString::from_slice(name.as_bytes());
|
||||||
llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
|
let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
|
||||||
self.llfn,
|
self.llfn,
|
||||||
buf)
|
name.as_ptr());
|
||||||
});
|
|
||||||
BlockS::new(llbb, is_lpad, opt_node_id, self)
|
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 {
|
pub fn C_floating(s: &str, t: Type) -> ValueRef {
|
||||||
unsafe {
|
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);
|
!null_terminated as Bool);
|
||||||
|
|
||||||
let gsym = token::gensym("str");
|
let gsym = token::gensym("str");
|
||||||
let g = format!("str{}", gsym.uint()).with_c_str(|buf| {
|
let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes());
|
||||||
llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf)
|
let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
|
||||||
});
|
|
||||||
llvm::LLVMSetInitializer(g, sc);
|
llvm::LLVMSetInitializer(g, sc);
|
||||||
llvm::LLVMSetGlobalConstant(g, True);
|
llvm::LLVMSetGlobalConstant(g, True);
|
||||||
llvm::SetLinkage(g, llvm::InternalLinkage);
|
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 lldata = C_bytes(cx, data);
|
||||||
|
|
||||||
let gsym = token::gensym("binary");
|
let gsym = token::gensym("binary");
|
||||||
let g = format!("binary{}", gsym.uint()).with_c_str(|buf| {
|
let name = format!("binary{}", gsym.uint());
|
||||||
llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf)
|
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::LLVMSetInitializer(g, lldata);
|
||||||
llvm::LLVMSetGlobalConstant(g, True);
|
llvm::LLVMSetGlobalConstant(g, True);
|
||||||
llvm::SetLinkage(g, llvm::InternalLinkage);
|
llvm::SetLinkage(g, llvm::InternalLinkage);
|
||||||
|
|
|
@ -24,7 +24,6 @@ use middle::subst::Substs;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use util::ppaux::{Repr, ty_to_string};
|
use util::ppaux::{Repr, ty_to_string};
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use syntax::{ast, ast_util};
|
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 {
|
pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef {
|
||||||
unsafe {
|
unsafe {
|
||||||
let gv = "const".with_c_str(|name| {
|
let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(),
|
||||||
llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name)
|
"const\0".as_ptr() as *const _);
|
||||||
});
|
|
||||||
llvm::LLVMSetInitializer(gv, cv);
|
llvm::LLVMSetInitializer(gv, cv);
|
||||||
llvm::LLVMSetGlobalConstant(gv,
|
llvm::LLVMSetGlobalConstant(gv,
|
||||||
if mutbl == ast::MutImmutable {True} else {False});
|
if mutbl == ast::MutImmutable {True} else {False});
|
||||||
|
|
|
@ -29,8 +29,8 @@ use util::ppaux::Repr;
|
||||||
use util::sha2::Sha256;
|
use util::sha2::Sha256;
|
||||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
|
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax::ast;
|
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) {
|
unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
|
||||||
let llcx = llvm::LLVMContextCreate();
|
let llcx = llvm::LLVMContextCreate();
|
||||||
let llmod = mod_name.with_c_str(|buf| {
|
let mod_name = CString::from_slice(mod_name.as_bytes());
|
||||||
llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
|
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
|
||||||
});
|
|
||||||
sess.target
|
let data_layout = sess.target.target.data_layout.as_slice();
|
||||||
.target
|
let data_layout = CString::from_slice(data_layout.as_bytes());
|
||||||
.data_layout
|
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||||
.with_c_str(|buf| {
|
|
||||||
llvm::LLVMSetDataLayout(llmod, buf);
|
let llvm_target = sess.target.target.llvm_target.as_slice();
|
||||||
});
|
let llvm_target = CString::from_slice(llvm_target.as_bytes());
|
||||||
sess.target
|
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||||
.target
|
|
||||||
.llvm_target
|
|
||||||
.with_c_str(|buf| {
|
|
||||||
llvm::LLVMRustSetNormalizedTarget(llmod, buf);
|
|
||||||
});
|
|
||||||
(llcx, llmod)
|
(llcx, llmod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use std::c_str::{CString, ToCStr};
|
use std::ffi::CString;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
@ -760,14 +760,15 @@ pub fn finalize(cx: &CrateContext) {
|
||||||
// for OS X to understand. For more info see #11352
|
// for OS X to understand. For more info see #11352
|
||||||
// This can be overridden using --llvm-opts -dwarf-version,N.
|
// This can be overridden using --llvm-opts -dwarf-version,N.
|
||||||
if cx.sess().target.target.options.is_like_osx {
|
if cx.sess().target.target.options.is_like_osx {
|
||||||
"Dwarf Version".with_c_str(
|
llvm::LLVMRustAddModuleFlag(cx.llmod(),
|
||||||
|s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2));
|
"Dwarf Version\0".as_ptr() as *const _,
|
||||||
|
2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent bitcode readers from deleting the debug info.
|
// Prevent bitcode readers from deleting the debug info.
|
||||||
"Debug Info Version".with_c_str(
|
let ptr = "Debug Info Version\0".as_ptr();
|
||||||
|s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s,
|
llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
|
||||||
llvm::LLVMRustDebugMetadataVersion));
|
llvm::LLVMRustDebugMetadataVersion);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,22 +830,20 @@ pub fn create_global_var_metadata(cx: &CrateContext,
|
||||||
namespace_node.mangled_name_of_contained_item(var_name[]);
|
namespace_node.mangled_name_of_contained_item(var_name[]);
|
||||||
let var_scope = namespace_node.scope;
|
let var_scope = namespace_node.scope;
|
||||||
|
|
||||||
var_name.with_c_str(|var_name| {
|
let var_name = CString::from_slice(var_name.as_bytes());
|
||||||
linkage_name.with_c_str(|linkage_name| {
|
let linkage_name = CString::from_slice(linkage_name.as_bytes());
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
|
llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
|
||||||
var_scope,
|
var_scope,
|
||||||
var_name,
|
var_name.as_ptr(),
|
||||||
linkage_name,
|
linkage_name.as_ptr(),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
line_number,
|
line_number,
|
||||||
type_metadata,
|
type_metadata,
|
||||||
is_local_to_unit,
|
is_local_to_unit,
|
||||||
global,
|
global,
|
||||||
ptr::null_mut());
|
ptr::null_mut());
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates debug information for the given local variable.
|
/// 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 is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
|
||||||
|
|
||||||
let fn_metadata = function_name.with_c_str(|function_name| {
|
let function_name = CString::from_slice(function_name.as_bytes());
|
||||||
linkage_name.with_c_str(|linkage_name| {
|
let linkage_name = CString::from_slice(linkage_name.as_bytes());
|
||||||
unsafe {
|
let fn_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateFunction(
|
llvm::LLVMDIBuilderCreateFunction(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
containing_scope,
|
containing_scope,
|
||||||
function_name,
|
function_name.as_ptr(),
|
||||||
linkage_name,
|
linkage_name.as_ptr(),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
loc.line as c_uint,
|
loc.line as c_uint,
|
||||||
function_type_metadata,
|
function_type_metadata,
|
||||||
is_local_to_unit,
|
is_local_to_unit,
|
||||||
true,
|
true,
|
||||||
scope_line as c_uint,
|
scope_line as c_uint,
|
||||||
FlagPrototyped as c_uint,
|
FlagPrototyped as c_uint,
|
||||||
cx.sess().opts.optimize != config::No,
|
cx.sess().opts.optimize != config::No,
|
||||||
llfn,
|
llfn,
|
||||||
template_parameters,
|
template_parameters,
|
||||||
ptr::null_mut())
|
ptr::null_mut())
|
||||||
}
|
};
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let scope_map = create_scope_map(cx,
|
let scope_map = create_scope_map(cx,
|
||||||
fn_decl.inputs.as_slice(),
|
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 ident = special_idents::type_self;
|
||||||
|
|
||||||
let param_metadata = token::get_ident(ident).get()
|
let ident = token::get_ident(ident);
|
||||||
.with_c_str(|name| {
|
let name = CString::from_slice(ident.get().as_bytes());
|
||||||
unsafe {
|
let param_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
name,
|
name.as_ptr(),
|
||||||
actual_self_type_metadata,
|
actual_self_type_metadata,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
0,
|
0,
|
||||||
0)
|
0)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|
||||||
template_params.push(param_metadata);
|
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
|
// Again, only create type information if full debuginfo is enabled
|
||||||
if cx.sess().opts.debuginfo == FullDebugInfo {
|
if cx.sess().opts.debuginfo == FullDebugInfo {
|
||||||
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
|
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
|
||||||
let param_metadata = token::get_ident(ident).get()
|
let ident = token::get_ident(ident);
|
||||||
.with_c_str(|name| {
|
let name = CString::from_slice(ident.get().as_bytes());
|
||||||
unsafe {
|
let param_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
name,
|
name.as_ptr(),
|
||||||
actual_type_metadata,
|
actual_type_metadata,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
0,
|
0,
|
||||||
0)
|
0)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
template_params.push(param_metadata);
|
template_params.push(param_metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1606,19 +1601,19 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
|
||||||
} else {
|
} else {
|
||||||
match abs_path.path_relative_from(work_dir) {
|
match abs_path.path_relative_from(work_dir) {
|
||||||
Some(ref p) if p.is_relative() => {
|
Some(ref p) if p.is_relative() => {
|
||||||
// prepend "./" if necessary
|
// prepend "./" if necessary
|
||||||
let dotdot = b"..";
|
let dotdot = b"..";
|
||||||
let prefix = [dotdot[0], ::std::path::SEP_BYTE];
|
let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE];
|
||||||
let mut path_bytes = p.as_vec().to_vec();
|
let mut path_bytes = p.as_vec().to_vec();
|
||||||
|
|
||||||
if path_bytes.slice_to(2) != prefix &&
|
if path_bytes.slice_to(2) != prefix &&
|
||||||
path_bytes.slice_to(2) != dotdot {
|
path_bytes.slice_to(2) != dotdot {
|
||||||
path_bytes.insert(0, prefix[0]);
|
path_bytes.insert(0, prefix[0]);
|
||||||
path_bytes.insert(1, prefix[1]);
|
path_bytes.insert(1, prefix[1]);
|
||||||
}
|
|
||||||
|
|
||||||
path_bytes.to_c_str()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CString::from_vec(path_bytes)
|
||||||
|
}
|
||||||
_ => fallback_path(cx)
|
_ => fallback_path(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1630,29 +1625,25 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
|
||||||
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
|
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
|
||||||
|
|
||||||
let compile_unit_name = compile_unit_name.as_ptr();
|
let compile_unit_name = compile_unit_name.as_ptr();
|
||||||
return work_dir.as_vec().with_c_str(|work_dir| {
|
let work_dir = CString::from_slice(work_dir.as_vec());
|
||||||
producer.with_c_str(|producer| {
|
let producer = CString::from_slice(producer.as_bytes());
|
||||||
"".with_c_str(|flags| {
|
let flags = "\0";
|
||||||
"".with_c_str(|split_name| {
|
let split_name = "\0";
|
||||||
unsafe {
|
return unsafe {
|
||||||
llvm::LLVMDIBuilderCreateCompileUnit(
|
llvm::LLVMDIBuilderCreateCompileUnit(
|
||||||
debug_context(cx).builder,
|
debug_context(cx).builder,
|
||||||
DW_LANG_RUST,
|
DW_LANG_RUST,
|
||||||
compile_unit_name,
|
compile_unit_name,
|
||||||
work_dir,
|
work_dir.as_ptr(),
|
||||||
producer,
|
producer.as_ptr(),
|
||||||
cx.sess().opts.optimize != config::No,
|
cx.sess().opts.optimize != config::No,
|
||||||
flags,
|
flags.as_ptr() as *const _,
|
||||||
0,
|
0,
|
||||||
split_name)
|
split_name.as_ptr() as *const _)
|
||||||
}
|
};
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
fn fallback_path(cx: &CrateContext) -> CString {
|
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)
|
CapturedVariable => (0, DW_TAG_auto_variable)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (var_alloca, var_metadata) = name.get().with_c_str(|name| {
|
let name = CString::from_slice(name.get().as_bytes());
|
||||||
match variable_access {
|
let (var_alloca, var_metadata) = match variable_access {
|
||||||
DirectVariable { alloca } => (
|
DirectVariable { alloca } => (
|
||||||
alloca,
|
alloca,
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMDIBuilderCreateLocalVariable(
|
llvm::LLVMDIBuilderCreateLocalVariable(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
dwarf_tag,
|
dwarf_tag,
|
||||||
scope_metadata,
|
scope_metadata,
|
||||||
name,
|
name.as_ptr(),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
loc.line as c_uint,
|
loc.line as c_uint,
|
||||||
type_metadata,
|
type_metadata,
|
||||||
cx.sess().opts.optimize != config::No,
|
cx.sess().opts.optimize != config::No,
|
||||||
0,
|
0,
|
||||||
argument_index)
|
argument_index)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
IndirectVariable { alloca, address_operations } => (
|
IndirectVariable { alloca, address_operations } => (
|
||||||
alloca,
|
alloca,
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMDIBuilderCreateComplexVariable(
|
llvm::LLVMDIBuilderCreateComplexVariable(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
dwarf_tag,
|
dwarf_tag,
|
||||||
scope_metadata,
|
scope_metadata,
|
||||||
name,
|
name.as_ptr(),
|
||||||
file_metadata,
|
file_metadata,
|
||||||
loc.line as c_uint,
|
loc.line as c_uint,
|
||||||
type_metadata,
|
type_metadata,
|
||||||
address_operations.as_ptr(),
|
address_operations.as_ptr(),
|
||||||
address_operations.len() as c_uint,
|
address_operations.len() as c_uint,
|
||||||
argument_index)
|
argument_index)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|
||||||
set_debug_location(cx, DebugLocation::new(scope_metadata,
|
set_debug_location(cx, DebugLocation::new(scope_metadata,
|
||||||
loc.line,
|
loc.line,
|
||||||
|
@ -1758,14 +1748,12 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile {
|
||||||
full_path
|
full_path
|
||||||
};
|
};
|
||||||
|
|
||||||
let file_metadata =
|
let file_name = CString::from_slice(file_name.as_bytes());
|
||||||
file_name.with_c_str(|file_name| {
|
let work_dir = CString::from_slice(work_dir.as_bytes());
|
||||||
work_dir.with_c_str(|work_dir| {
|
let file_metadata = unsafe {
|
||||||
unsafe {
|
llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(),
|
||||||
llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
|
work_dir.as_ptr())
|
||||||
}
|
};
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut created_files = debug_context(cx).created_files.borrow_mut();
|
let mut created_files = debug_context(cx).created_files.borrow_mut();
|
||||||
created_files.insert(full_path.to_string(), file_metadata);
|
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 {
|
fn diverging_type_metadata(cx: &CrateContext) -> DIType {
|
||||||
"!".with_c_str(|name| {
|
unsafe {
|
||||||
unsafe {
|
llvm::LLVMDIBuilderCreateBasicType(
|
||||||
llvm::LLVMDIBuilderCreateBasicType(
|
DIB(cx),
|
||||||
DIB(cx),
|
"!\0".as_ptr() as *const _,
|
||||||
name,
|
bytes_to_bits(0),
|
||||||
bytes_to_bits(0),
|
bytes_to_bits(0),
|
||||||
bytes_to_bits(0),
|
DW_ATE_unsigned)
|
||||||
DW_ATE_unsigned)
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
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 llvm_type = type_of::type_of(cx, t);
|
||||||
let (size, align) = size_and_align_of(cx, llvm_type);
|
let (size, align) = size_and_align_of(cx, llvm_type);
|
||||||
let ty_metadata = name.with_c_str(|name| {
|
let name = CString::from_slice(name.as_bytes());
|
||||||
unsafe {
|
let ty_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateBasicType(
|
llvm::LLVMDIBuilderCreateBasicType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
name,
|
name.as_ptr(),
|
||||||
bytes_to_bits(size),
|
bytes_to_bits(size),
|
||||||
bytes_to_bits(align),
|
bytes_to_bits(align),
|
||||||
encoding)
|
encoding)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|
||||||
return ty_metadata;
|
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_llvm_type = type_of::type_of(cx, pointer_type);
|
||||||
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
|
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
|
||||||
let name = compute_debuginfo_type_name(cx, pointer_type, false);
|
let name = compute_debuginfo_type_name(cx, pointer_type, false);
|
||||||
let ptr_metadata = name.with_c_str(|name| {
|
let name = CString::from_slice(name.as_bytes());
|
||||||
unsafe {
|
let ptr_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreatePointerType(
|
llvm::LLVMDIBuilderCreatePointerType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
pointee_type_metadata,
|
pointee_type_metadata,
|
||||||
bytes_to_bits(pointer_size),
|
bytes_to_bits(pointer_size),
|
||||||
bytes_to_bits(pointer_align),
|
bytes_to_bits(pointer_align),
|
||||||
name)
|
name.as_ptr())
|
||||||
}
|
};
|
||||||
});
|
|
||||||
return ptr_metadata;
|
return ptr_metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2478,14 +2462,14 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
let enumerators_metadata: Vec<DIDescriptor> = variants
|
let enumerators_metadata: Vec<DIDescriptor> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
token::get_name(v.name).get().with_c_str(|name| {
|
let token = token::get_name(v.name);
|
||||||
unsafe {
|
let name = CString::from_slice(token.get().as_bytes());
|
||||||
llvm::LLVMDIBuilderCreateEnumerator(
|
unsafe {
|
||||||
DIB(cx),
|
llvm::LLVMDIBuilderCreateEnumerator(
|
||||||
name,
|
DIB(cx),
|
||||||
v.disr_val as u64)
|
name.as_ptr(),
|
||||||
}
|
v.disr_val as u64)
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -2509,20 +2493,19 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
codemap::DUMMY_SP);
|
codemap::DUMMY_SP);
|
||||||
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
|
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
|
||||||
|
|
||||||
let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| {
|
let name = CString::from_slice(discriminant_name.get().as_bytes());
|
||||||
unsafe {
|
let discriminant_type_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateEnumerationType(
|
llvm::LLVMDIBuilderCreateEnumerationType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
containing_scope,
|
containing_scope,
|
||||||
name,
|
name.as_ptr(),
|
||||||
UNKNOWN_FILE_METADATA,
|
UNKNOWN_FILE_METADATA,
|
||||||
UNKNOWN_LINE_NUMBER,
|
UNKNOWN_LINE_NUMBER,
|
||||||
bytes_to_bits(discriminant_size),
|
bytes_to_bits(discriminant_size),
|
||||||
bytes_to_bits(discriminant_align),
|
bytes_to_bits(discriminant_align),
|
||||||
create_DIArray(DIB(cx), enumerators_metadata[]),
|
create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
|
||||||
discriminant_base_type_metadata)
|
discriminant_base_type_metadata)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|
||||||
debug_context(cx).created_enum_disr_types
|
debug_context(cx).created_enum_disr_types
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -2553,24 +2536,22 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_unique_type_id_as_string(unique_type_id);
|
.get_unique_type_id_as_string(unique_type_id);
|
||||||
|
|
||||||
let enum_metadata = enum_name.with_c_str(|enum_name| {
|
let enum_name = CString::from_slice(enum_name.as_bytes());
|
||||||
unique_type_id_str.with_c_str(|unique_type_id_str| {
|
let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes());
|
||||||
unsafe {
|
let enum_metadata = unsafe {
|
||||||
llvm::LLVMDIBuilderCreateUnionType(
|
llvm::LLVMDIBuilderCreateUnionType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
containing_scope,
|
containing_scope,
|
||||||
enum_name,
|
enum_name.as_ptr(),
|
||||||
UNKNOWN_FILE_METADATA,
|
UNKNOWN_FILE_METADATA,
|
||||||
UNKNOWN_LINE_NUMBER,
|
UNKNOWN_LINE_NUMBER,
|
||||||
bytes_to_bits(enum_type_size),
|
bytes_to_bits(enum_type_size),
|
||||||
bytes_to_bits(enum_type_align),
|
bytes_to_bits(enum_type_align),
|
||||||
0, // Flags
|
0, // Flags
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
0, // RuntimeLang
|
0, // RuntimeLang
|
||||||
unique_type_id_str)
|
unique_type_id_str.as_ptr())
|
||||||
}
|
};
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
return create_and_register_recursive_type_forward_declaration(
|
return create_and_register_recursive_type_forward_declaration(
|
||||||
cx,
|
cx,
|
||||||
|
@ -2681,21 +2662,20 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
||||||
ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
|
ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
|
||||||
};
|
};
|
||||||
|
|
||||||
member_description.name.with_c_str(|member_name| {
|
let member_name = CString::from_slice(member_description.name.as_bytes());
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMDIBuilderCreateMemberType(
|
llvm::LLVMDIBuilderCreateMemberType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
composite_type_metadata,
|
composite_type_metadata,
|
||||||
member_name,
|
member_name.as_ptr(),
|
||||||
UNKNOWN_FILE_METADATA,
|
UNKNOWN_FILE_METADATA,
|
||||||
UNKNOWN_LINE_NUMBER,
|
UNKNOWN_LINE_NUMBER,
|
||||||
bytes_to_bits(member_size),
|
bytes_to_bits(member_size),
|
||||||
bytes_to_bits(member_align),
|
bytes_to_bits(member_align),
|
||||||
bytes_to_bits(member_offset),
|
bytes_to_bits(member_offset),
|
||||||
member_description.flags,
|
member_description.flags,
|
||||||
member_description.type_metadata)
|
member_description.type_metadata)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -2719,30 +2699,28 @@ fn create_struct_stub(cx: &CrateContext,
|
||||||
let unique_type_id_str = debug_context(cx).type_map
|
let unique_type_id_str = debug_context(cx).type_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_unique_type_id_as_string(unique_type_id);
|
.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 {
|
let metadata_stub = unsafe {
|
||||||
struct_type_name.with_c_str(|name| {
|
// LLVMDIBuilderCreateStructType() wants an empty array. A null
|
||||||
unique_type_id_str.with_c_str(|unique_type_id| {
|
// pointer will lead to hard to trace and debug LLVM assertions
|
||||||
// LLVMDIBuilderCreateStructType() wants an empty array. A null
|
// later on in llvm/lib/IR/Value.cpp.
|
||||||
// pointer will lead to hard to trace and debug LLVM assertions
|
let empty_array = create_DIArray(DIB(cx), &[]);
|
||||||
// later on in llvm/lib/IR/Value.cpp.
|
|
||||||
let empty_array = create_DIArray(DIB(cx), &[]);
|
|
||||||
|
|
||||||
llvm::LLVMDIBuilderCreateStructType(
|
llvm::LLVMDIBuilderCreateStructType(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
containing_scope,
|
containing_scope,
|
||||||
name,
|
name.as_ptr(),
|
||||||
UNKNOWN_FILE_METADATA,
|
UNKNOWN_FILE_METADATA,
|
||||||
UNKNOWN_LINE_NUMBER,
|
UNKNOWN_LINE_NUMBER,
|
||||||
bytes_to_bits(struct_size),
|
bytes_to_bits(struct_size),
|
||||||
bytes_to_bits(struct_align),
|
bytes_to_bits(struct_align),
|
||||||
0,
|
0,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
empty_array,
|
empty_array,
|
||||||
0,
|
0,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
unique_type_id)
|
unique_type_id.as_ptr())
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return metadata_stub;
|
return metadata_stub;
|
||||||
|
@ -4079,18 +4057,18 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTree
|
||||||
None => ptr::null_mut()
|
None => ptr::null_mut()
|
||||||
};
|
};
|
||||||
let namespace_name = token::get_name(name);
|
let namespace_name = token::get_name(name);
|
||||||
let scope = namespace_name.get().with_c_str(|namespace_name| {
|
let namespace_name = CString::from_slice(namespace_name
|
||||||
unsafe {
|
.get().as_bytes());
|
||||||
llvm::LLVMDIBuilderCreateNameSpace(
|
let scope = unsafe {
|
||||||
DIB(cx),
|
llvm::LLVMDIBuilderCreateNameSpace(
|
||||||
parent_scope,
|
DIB(cx),
|
||||||
namespace_name,
|
parent_scope,
|
||||||
// cannot reconstruct file ...
|
namespace_name.as_ptr(),
|
||||||
ptr::null_mut(),
|
// cannot reconstruct file ...
|
||||||
// ... or line information, but that's not so important.
|
ptr::null_mut(),
|
||||||
0)
|
// ... or line information, but that's not so important.
|
||||||
}
|
0)
|
||||||
});
|
};
|
||||||
|
|
||||||
let node = Rc::new(NamespaceTreeNode {
|
let node = Rc::new(NamespaceTreeNode {
|
||||||
name: name,
|
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.
|
/// .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) {
|
pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) {
|
||||||
if needs_gdb_debug_scripts_section(ccx) {
|
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 =
|
let gdb_debug_scripts_section_global =
|
||||||
get_or_insert_gdb_debug_scripts_section_global(ccx);
|
get_or_insert_gdb_debug_scripts_section_global(ccx);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -4145,14 +4123,15 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext)
|
||||||
/// section.
|
/// section.
|
||||||
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
|
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
|
||||||
-> llvm::ValueRef {
|
-> 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 {
|
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() {
|
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";
|
let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -4160,8 +4139,9 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
|
||||||
section_contents.len() as u64);
|
section_contents.len() as u64);
|
||||||
let section_var = llvm::LLVMAddGlobal(ccx.llmod(),
|
let section_var = llvm::LLVMAddGlobal(ccx.llmod(),
|
||||||
llvm_type.to_ref(),
|
llvm_type.to_ref(),
|
||||||
section_var_name.as_ptr());
|
section_var_name.as_ptr()
|
||||||
llvm::LLVMSetSection(section_var, section_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::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
|
||||||
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
|
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
|
||||||
llvm::LLVMSetUnnamedAddr(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 trans::type_of;
|
use trans::type_of;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::subst::{Substs};
|
use middle::subst::Substs;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
|
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
|
||||||
use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
|
use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
|
||||||
|
@ -132,9 +133,9 @@ pub fn register_static(ccx: &CrateContext,
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
// Declare a symbol `foo` with the desired linkage.
|
// Declare a symbol `foo` with the desired linkage.
|
||||||
let g1 = ident.get().with_c_str(|buf| {
|
let buf = CString::from_slice(ident.get().as_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf)
|
let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(),
|
||||||
});
|
buf.as_ptr());
|
||||||
llvm::SetLinkage(g1, linkage);
|
llvm::SetLinkage(g1, linkage);
|
||||||
|
|
||||||
// Declare an internal global `extern_with_linkage_foo` which
|
// Declare an internal global `extern_with_linkage_foo` which
|
||||||
|
@ -145,9 +146,9 @@ pub fn register_static(ccx: &CrateContext,
|
||||||
// zero.
|
// zero.
|
||||||
let mut real_name = "_rust_extern_with_linkage_".to_string();
|
let mut real_name = "_rust_extern_with_linkage_".to_string();
|
||||||
real_name.push_str(ident.get());
|
real_name.push_str(ident.get());
|
||||||
let g2 = real_name.with_c_str(|buf| {
|
let real_name = CString::from_vec(real_name.into_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
|
let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(),
|
||||||
});
|
real_name.as_ptr());
|
||||||
llvm::SetLinkage(g2, llvm::InternalLinkage);
|
llvm::SetLinkage(g2, llvm::InternalLinkage);
|
||||||
llvm::LLVMSetInitializer(g2, g1);
|
llvm::LLVMSetInitializer(g2, g1);
|
||||||
g2
|
g2
|
||||||
|
@ -155,9 +156,8 @@ pub fn register_static(ccx: &CrateContext,
|
||||||
}
|
}
|
||||||
None => unsafe {
|
None => unsafe {
|
||||||
// Generate an external declaration.
|
// Generate an external declaration.
|
||||||
ident.get().with_c_str(|buf| {
|
let buf = CString::from_slice(ident.get().as_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
|
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;
|
// return r;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let the_block =
|
let ptr = "the block\0".as_ptr();
|
||||||
"the block".with_c_str(
|
let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn,
|
||||||
|s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s));
|
ptr as *const _);
|
||||||
|
|
||||||
let builder = ccx.builder();
|
let builder = ccx.builder();
|
||||||
builder.position_at_end(the_block);
|
builder.position_at_end(the_block);
|
||||||
|
|
|
@ -40,8 +40,8 @@ use util::ppaux::{ty_to_short_str, Repr};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
|
use std::ffi::CString;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::parse::token;
|
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 llalign = llalign_of(ccx, llty);
|
||||||
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
|
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
|
||||||
debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
|
debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
|
||||||
let gvar = name.with_c_str(|buf| {
|
let buf = CString::from_slice(name.as_bytes());
|
||||||
unsafe {
|
let gvar = unsafe {
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf)
|
llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(),
|
||||||
}
|
buf.as_ptr())
|
||||||
});
|
};
|
||||||
note_unique_llvm_symbol(ccx, name);
|
note_unique_llvm_symbol(ccx, name);
|
||||||
|
|
||||||
let ty_name = token::intern_and_get_ident(
|
let ty_name = token::intern_and_get_ident(
|
||||||
|
|
|
@ -34,7 +34,7 @@ use middle::ty::{self, Ty};
|
||||||
use middle::ty::MethodCall;
|
use middle::ty::MethodCall;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax::abi::{Rust, RustCall};
|
use syntax::abi::{Rust, RustCall};
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
@ -742,9 +742,9 @@ pub fn make_vtable<I: Iterator<Item=ValueRef>>(ccx: &CrateContext,
|
||||||
unsafe {
|
unsafe {
|
||||||
let tbl = C_struct(ccx, components[], false);
|
let tbl = C_struct(ccx, components[], false);
|
||||||
let sym = token::gensym("vtable");
|
let sym = token::gensym("vtable");
|
||||||
let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| {
|
let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes());
|
||||||
llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf)
|
let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(),
|
||||||
});
|
buf.as_ptr());
|
||||||
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
||||||
llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True);
|
llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True);
|
||||||
llvm::SetLinkage(vt_gvar, llvm::InternalLinkage);
|
llvm::SetLinkage(vt_gvar, llvm::InternalLinkage);
|
||||||
|
|
|
@ -19,7 +19,7 @@ use util::nodemap::FnvHashMap;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
@ -157,7 +157,8 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn named_struct(ccx: &CrateContext, name: &str) -> 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 {
|
pub fn empty_struct(ccx: &CrateContext) -> Type {
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub use self::imp::Lock;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod imp {
|
mod imp {
|
||||||
|
use std::ffi::CString;
|
||||||
use libc;
|
use libc;
|
||||||
use std::c_str::ToCStr;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod os {
|
mod os {
|
||||||
|
@ -111,9 +111,11 @@ mod imp {
|
||||||
|
|
||||||
impl Lock {
|
impl Lock {
|
||||||
pub fn new(p: &Path) -> Lock {
|
pub fn new(p: &Path) -> Lock {
|
||||||
let fd = p.with_c_str(|s| unsafe {
|
let buf = CString::from_slice(p.as_vec());
|
||||||
libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
|
let fd = unsafe {
|
||||||
});
|
libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
|
||||||
|
libc::S_IRWXU)
|
||||||
|
};
|
||||||
assert!(fd > 0);
|
assert!(fd > 0);
|
||||||
let flock = os::flock {
|
let flock = os::flock {
|
||||||
l_start: 0,
|
l_start: 0,
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
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());
|
let id = id.as_ref().map(|a| a.as_slice());
|
||||||
s.push_str(highlight::highlight(text.as_slice(), None, id)
|
s.push_str(highlight::highlight(text.as_slice(), None, id)
|
||||||
.as_slice());
|
.as_slice());
|
||||||
let output = s.to_c_str();
|
let output = CString::from_vec(s.into_bytes());
|
||||||
hoedown_buffer_puts(ob, output.as_ptr());
|
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,
|
extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
|
||||||
level: libc::c_int, opaque: *mut libc::c_void) {
|
level: libc::c_int, opaque: *mut libc::c_void) {
|
||||||
// hoedown does this, we may as well too
|
// 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
|
// Extract the text provided
|
||||||
let s = if text.is_null() {
|
let s = if text.is_null() {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
let s = unsafe {
|
||||||
String::from_raw_buf_len((*text).data, (*text).size as uint)
|
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
|
// 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)
|
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();
|
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 prelude::v1::*;
|
||||||
|
|
||||||
use c_str::ToCStr;
|
use ffi::CString;
|
||||||
use mem;
|
use mem;
|
||||||
use os;
|
use os;
|
||||||
use str;
|
use str;
|
||||||
|
@ -51,13 +51,11 @@ impl DynamicLibrary {
|
||||||
|
|
||||||
/// Lazily open a dynamic library. When passed None it gives a
|
/// Lazily open a dynamic library. When passed None it gives a
|
||||||
/// handle to the calling process
|
/// handle to the calling process
|
||||||
pub fn open<T: ToCStr>(filename: Option<T>)
|
pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
|
||||||
-> Result<DynamicLibrary, String> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut filename = filename;
|
|
||||||
let maybe_library = dl::check_for_errors_in(|| {
|
let maybe_library = dl::check_for_errors_in(|| {
|
||||||
match filename.take() {
|
match filename {
|
||||||
Some(name) => dl::open_external(name),
|
Some(name) => dl::open_external(name.as_vec()),
|
||||||
None => dl::open_internal()
|
None => dl::open_internal()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,9 +129,8 @@ impl DynamicLibrary {
|
||||||
// T but that feature is still unimplemented
|
// T but that feature is still unimplemented
|
||||||
|
|
||||||
let maybe_symbol_value = dl::check_for_errors_in(|| {
|
let maybe_symbol_value = dl::check_for_errors_in(|| {
|
||||||
symbol.with_c_str(|raw_string| {
|
let raw_string = CString::from_slice(symbol.as_bytes());
|
||||||
dl::symbol(self.handle, raw_string)
|
dl::symbol(self.handle, raw_string.as_ptr())
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// The value must not be constructed if there is an error so
|
// The value must not be constructed if there is an error so
|
||||||
|
@ -157,7 +154,7 @@ mod test {
|
||||||
fn test_loading_cosine() {
|
fn test_loading_cosine() {
|
||||||
// The math library does not need to be loaded since it is already
|
// The math library does not need to be loaded since it is already
|
||||||
// statically linked in
|
// 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) {
|
let libm = match DynamicLibrary::open(none) {
|
||||||
Err(error) => panic!("Could not load self as module: {}", error),
|
Err(error) => panic!("Could not load self as module: {}", error),
|
||||||
Ok(libm) => libm
|
Ok(libm) => libm
|
||||||
|
@ -202,17 +199,17 @@ mod test {
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
target_os = "dragonfly"))]
|
target_os = "dragonfly"))]
|
||||||
pub mod dl {
|
pub mod dl {
|
||||||
use self::Rtld::*;
|
pub use self::Rtld::*;
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
|
use ffi::{self, CString};
|
||||||
|
use str;
|
||||||
use libc;
|
use libc;
|
||||||
use ptr;
|
use ptr;
|
||||||
|
|
||||||
pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {
|
pub unsafe fn open_external(filename: &[u8]) -> *mut u8 {
|
||||||
filename.with_c_str(|raw_name| {
|
let s = CString::from_slice(filename);
|
||||||
dlopen(raw_name, Lazy as libc::c_int) as *mut u8
|
dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn open_internal() -> *mut u8 {
|
pub unsafe fn open_internal() -> *mut u8 {
|
||||||
|
@ -236,8 +233,8 @@ pub mod dl {
|
||||||
let ret = if ptr::null() == last_error {
|
let ret = if ptr::null() == last_error {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err(String::from_str(CString::new(last_error, false).as_str()
|
let s = ffi::c_str_to_bytes(&last_error);
|
||||||
.unwrap()))
|
Err(str::from_utf8(s).unwrap().to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
@ -273,7 +270,6 @@ pub mod dl {
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub mod dl {
|
pub mod dl {
|
||||||
use c_str::ToCStr;
|
|
||||||
use iter::IteratorExt;
|
use iter::IteratorExt;
|
||||||
use libc;
|
use libc;
|
||||||
use ops::FnOnce;
|
use ops::FnOnce;
|
||||||
|
@ -287,10 +283,9 @@ pub mod dl {
|
||||||
use string::String;
|
use string::String;
|
||||||
use vec::Vec;
|
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
|
// Windows expects Unicode data
|
||||||
let filename_cstr = filename.to_c_str();
|
let filename_str = str::from_utf8(filename).unwrap();
|
||||||
let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap();
|
|
||||||
let mut filename_str: Vec<u16> = filename_str.utf16_units().collect();
|
let mut filename_str: Vec<u16> = filename_str.utf16_units().collect();
|
||||||
filename_str.push(0);
|
filename_str.push(0);
|
||||||
LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8
|
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 prelude::v1::*;
|
||||||
|
|
||||||
use c_str::ToCStr;
|
use ffi::CString;
|
||||||
|
use path::BytesContainer;
|
||||||
use io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
|
use io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
|
||||||
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
|
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
|
||||||
use sys::pipe::UnixListener as UnixListenerImp;
|
use sys::pipe::UnixListener as UnixListenerImp;
|
||||||
|
@ -53,8 +54,9 @@ impl UnixStream {
|
||||||
/// let mut stream = UnixStream::connect(&server);
|
/// let mut stream = UnixStream::connect(&server);
|
||||||
/// stream.write(&[1, 2, 3]);
|
/// stream.write(&[1, 2, 3]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
|
pub fn connect<P: BytesContainer>(path: P) -> IoResult<UnixStream> {
|
||||||
UnixStreamImp::connect(&path.to_c_str(), None)
|
let path = CString::from_slice(path.container_as_bytes());
|
||||||
|
UnixStreamImp::connect(&path, None)
|
||||||
.map(|inner| UnixStream { inner: inner })
|
.map(|inner| UnixStream { inner: inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,13 +69,15 @@ impl UnixStream {
|
||||||
/// If a `timeout` with zero or negative duration is specified then
|
/// If a `timeout` with zero or negative duration is specified then
|
||||||
/// the function returns `Err`, with the error kind set to `TimedOut`.
|
/// the function returns `Err`, with the error kind set to `TimedOut`.
|
||||||
#[experimental = "the timeout argument is likely to change types"]
|
#[experimental = "the timeout argument is likely to change types"]
|
||||||
pub fn connect_timeout<P: ToCStr>(path: &P,
|
pub fn connect_timeout<P>(path: P, timeout: Duration)
|
||||||
timeout: Duration) -> IoResult<UnixStream> {
|
-> IoResult<UnixStream>
|
||||||
|
where P: BytesContainer {
|
||||||
if timeout <= Duration::milliseconds(0) {
|
if timeout <= Duration::milliseconds(0) {
|
||||||
return Err(standard_error(TimedOut));
|
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 })
|
.map(|inner| UnixStream { inner: inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,8 +181,9 @@ impl UnixListener {
|
||||||
/// }
|
/// }
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
|
pub fn bind<P: BytesContainer>(path: P) -> IoResult<UnixListener> {
|
||||||
UnixListenerImp::bind(&path.to_c_str())
|
let path = CString::from_slice(path.container_as_bytes());
|
||||||
|
UnixListenerImp::bind(&path)
|
||||||
.map(|inner| UnixListener { inner: inner })
|
.map(|inner| UnixListener { inner: inner })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ pub use self::ProcessExit::*;
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
use ffi::CString;
|
||||||
use fmt;
|
use fmt;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use io::pipe::{PipeStream, PipePair};
|
use io::pipe::{PipeStream, PipePair};
|
||||||
|
@ -35,6 +35,7 @@ use sys;
|
||||||
use thread::Thread;
|
use thread::Thread;
|
||||||
|
|
||||||
#[cfg(windows)] use std::hash::sip::SipState;
|
#[cfg(windows)] use std::hash::sip::SipState;
|
||||||
|
#[cfg(windows)] use str;
|
||||||
|
|
||||||
/// Signal a process to exit, without forcibly killing it. Corresponds to
|
/// Signal a process to exit, without forcibly killing it. Corresponds to
|
||||||
/// SIGTERM on unix platforms.
|
/// SIGTERM on unix platforms.
|
||||||
|
@ -109,11 +110,11 @@ struct EnvKey(CString);
|
||||||
impl Hash for EnvKey {
|
impl Hash for EnvKey {
|
||||||
fn hash(&self, state: &mut SipState) {
|
fn hash(&self, state: &mut SipState) {
|
||||||
let &EnvKey(ref x) = self;
|
let &EnvKey(ref x) = self;
|
||||||
match x.as_str() {
|
match str::from_utf8(x.as_bytes()) {
|
||||||
Some(s) => for ch in s.chars() {
|
Ok(s) => for ch in s.chars() {
|
||||||
(ch as u8 as char).to_lowercase().hash(state);
|
(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 {
|
fn eq(&self, other: &EnvKey) -> bool {
|
||||||
let &EnvKey(ref x) = self;
|
let &EnvKey(ref x) = self;
|
||||||
let &EnvKey(ref y) = other;
|
let &EnvKey(ref y) = other;
|
||||||
match (x.as_str(), y.as_str()) {
|
match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) {
|
||||||
(Some(xs), Some(ys)) => {
|
(Ok(xs), Ok(ys)) => {
|
||||||
if xs.len() != ys.len() {
|
if xs.len() != ys.len() {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
@ -185,10 +186,10 @@ pub struct Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
|
// 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
|
// 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
|
// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
|
||||||
// instance should be removed, and arguments bound by ToCStr should be passed by
|
// instance should be removed, and arguments bound by BytesContainer should be passed by
|
||||||
// reference. (Here: {new, arg, args, env}.)
|
// reference. (Here: {new, arg, args, env}.)
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
|
@ -203,9 +204,9 @@ impl Command {
|
||||||
///
|
///
|
||||||
/// Builder methods are provided to change these defaults and
|
/// Builder methods are provided to change these defaults and
|
||||||
/// otherwise configure the process.
|
/// otherwise configure the process.
|
||||||
pub fn new<T:ToCStr>(program: T) -> Command {
|
pub fn new<T: BytesContainer>(program: T) -> Command {
|
||||||
Command {
|
Command {
|
||||||
program: program.to_c_str(),
|
program: CString::from_slice(program.container_as_bytes()),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
env: None,
|
env: None,
|
||||||
cwd: None,
|
cwd: None,
|
||||||
|
@ -219,27 +220,29 @@ impl Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an argument to pass to the program.
|
/// Add an argument to pass to the program.
|
||||||
pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
|
pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
|
||||||
self.args.push(arg.to_c_str());
|
self.args.push(CString::from_slice(arg.container_as_bytes()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add multiple arguments to pass to the program.
|
/// Add multiple arguments to pass to the program.
|
||||||
pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
|
pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
|
||||||
self.args.extend(args.iter().map(|arg| arg.to_c_str()));;
|
self.args.extend(args.iter().map(|arg| {
|
||||||
|
CString::from_slice(arg.container_as_bytes())
|
||||||
|
}));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
// Get a mutable borrow of the environment variable map for this `Command`.
|
// 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 {
|
match self.env {
|
||||||
Some(ref mut map) => map,
|
Some(ref mut map) => map,
|
||||||
None => {
|
None => {
|
||||||
// if the env is currently just inheriting from the parent's,
|
// if the env is currently just inheriting from the parent's,
|
||||||
// materialize the parent's env into a hashtable.
|
// materialize the parent's env into a hashtable.
|
||||||
self.env = Some(os::env_as_bytes().into_iter()
|
self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
|
||||||
.map(|(k, v)| (EnvKey(k.to_c_str()),
|
(EnvKey(CString::from_slice(k.as_slice())),
|
||||||
v.to_c_str()))
|
CString::from_slice(v.as_slice()))
|
||||||
.collect());
|
}).collect());
|
||||||
self.env.as_mut().unwrap()
|
self.env.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,15 +252,20 @@ impl Command {
|
||||||
///
|
///
|
||||||
/// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
|
/// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
|
||||||
/// and case-sensitive on all other platforms.
|
/// and case-sensitive on all other platforms.
|
||||||
pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U)
|
pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
|
||||||
-> &'a mut Command {
|
-> &'a mut Command
|
||||||
self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str());
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an environment variable mapping.
|
/// Removes an environment variable mapping.
|
||||||
pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command {
|
pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
|
||||||
self.get_env_map().remove(&EnvKey(key.to_c_str()));
|
where T: BytesContainer {
|
||||||
|
let key = EnvKey(CString::from_slice(key.container_as_bytes()));
|
||||||
|
self.get_env_map().remove(&key);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,16 +273,19 @@ impl Command {
|
||||||
///
|
///
|
||||||
/// If the given slice contains multiple instances of an environment
|
/// If the given slice contains multiple instances of an environment
|
||||||
/// variable, the *rightmost* instance will determine the value.
|
/// variable, the *rightmost* instance will determine the value.
|
||||||
pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)])
|
pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
|
||||||
-> &'a mut Command {
|
-> &'a mut Command
|
||||||
self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str()))
|
where T: BytesContainer, U: BytesContainer {
|
||||||
.collect());
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the working directory for the child process.
|
/// Set the working directory for the child process.
|
||||||
pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,9 +400,9 @@ impl fmt::Show for Command {
|
||||||
/// non-utf8 data is lossily converted using the utf8 replacement
|
/// non-utf8 data is lossily converted using the utf8 replacement
|
||||||
/// character.
|
/// character.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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() {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1208,13 +1219,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn env_map_keys_ci() {
|
fn env_map_keys_ci() {
|
||||||
use c_str::ToCStr;
|
use ffi::CString;
|
||||||
use super::EnvKey;
|
use super::EnvKey;
|
||||||
let mut cmd = Command::new("");
|
let mut cmd = Command::new("");
|
||||||
cmd.env("path", "foo");
|
cmd.env("path", "foo");
|
||||||
cmd.env("Path", "bar");
|
cmd.env("Path", "bar");
|
||||||
let env = &cmd.env.unwrap();
|
let env = &cmd.env.unwrap();
|
||||||
let val = env.get(&EnvKey("PATH".to_c_str()));
|
let val = env.get(&EnvKey(CString::from_slice(b"PATH")));
|
||||||
assert!(val.unwrap() == &"bar".to_c_str());
|
assert!(val.unwrap() == &CString::from_slice(b"bar"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,10 +208,10 @@ pub mod num;
|
||||||
|
|
||||||
/* Runtime and platform support */
|
/* Runtime and platform support */
|
||||||
|
|
||||||
pub mod thread_local;
|
pub mod thread_local; // first for macros
|
||||||
pub mod c_str;
|
|
||||||
pub mod c_vec;
|
|
||||||
pub mod dynamic_lib;
|
pub mod dynamic_lib;
|
||||||
|
pub mod ffi;
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|
|
@ -57,12 +57,10 @@ use string::{String, ToString};
|
||||||
use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering};
|
use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering};
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
#[cfg(unix)] use c_str::ToCStr;
|
#[cfg(unix)] use ffi::{self, CString};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)] pub use sys::ext as unix;
|
||||||
pub use sys::ext as unix;
|
#[cfg(windows)] pub use sys::ext as windows;
|
||||||
#[cfg(windows)]
|
|
||||||
pub use sys::ext as windows;
|
|
||||||
|
|
||||||
/// Get the number of cores available
|
/// Get the number of cores available
|
||||||
pub fn num_cpus() -> uint {
|
pub fn num_cpus() -> uint {
|
||||||
|
@ -196,15 +194,14 @@ pub fn getenv(n: &str) -> Option<String> {
|
||||||
///
|
///
|
||||||
/// Panics if `n` has any interior NULs.
|
/// Panics if `n` has any interior NULs.
|
||||||
pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
|
pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
|
||||||
use c_str::CString;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
with_env_lock(|| {
|
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() {
|
if s.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} 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]) {
|
fn _setenv(n: &str, v: &[u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
with_env_lock(|| {
|
with_env_lock(|| {
|
||||||
n.with_c_str(|nbuf| {
|
let k = CString::from_slice(n.as_bytes());
|
||||||
v.with_c_str(|vbuf| {
|
let v = CString::from_slice(v);
|
||||||
if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 {
|
if libc::funcs::posix01::unistd::setenv(k.as_ptr(),
|
||||||
panic!(IoError::last_error());
|
v.as_ptr(), 1) != 0 {
|
||||||
}
|
panic!(IoError::last_error());
|
||||||
})
|
}
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,11 +285,10 @@ pub fn unsetenv(n: &str) {
|
||||||
fn _unsetenv(n: &str) {
|
fn _unsetenv(n: &str) {
|
||||||
unsafe {
|
unsafe {
|
||||||
with_env_lock(|| {
|
with_env_lock(|| {
|
||||||
n.with_c_str(|nbuf| {
|
let nbuf = CString::from_slice(n.as_bytes());
|
||||||
if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 {
|
if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
|
||||||
panic!(IoError::last_error());
|
panic!(IoError::last_error());
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,11 +613,10 @@ pub fn get_exit_status() -> int {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
unsafe fn load_argc_and_argv(argc: int,
|
unsafe fn load_argc_and_argv(argc: int,
|
||||||
argv: *const *const c_char) -> Vec<Vec<u8>> {
|
argv: *const *const c_char) -> Vec<Vec<u8>> {
|
||||||
use c_str::CString;
|
|
||||||
use iter::range;
|
use iter::range;
|
||||||
|
|
||||||
range(0, argc as uint).map(|i| {
|
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()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,7 +646,6 @@ fn real_args_as_bytes() -> Vec<Vec<u8>> {
|
||||||
// res
|
// res
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
fn real_args_as_bytes() -> Vec<Vec<u8>> {
|
fn real_args_as_bytes() -> Vec<Vec<u8>> {
|
||||||
use c_str::CString;
|
|
||||||
use iter::range;
|
use iter::range;
|
||||||
use mem;
|
use mem;
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
#![experimental]
|
#![experimental]
|
||||||
|
|
||||||
use core::kinds::Sized;
|
use core::kinds::Sized;
|
||||||
use c_str::CString;
|
use ffi::CString;
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use fmt;
|
use fmt;
|
||||||
use iter::IteratorExt;
|
use iter::IteratorExt;
|
||||||
|
@ -892,7 +892,7 @@ impl BytesContainer for Vec<u8> {
|
||||||
impl BytesContainer for CString {
|
impl BytesContainer for CString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
|
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 {
|
fn contains_nul<T: BytesContainer>(v: &T) -> bool {
|
||||||
v.container_as_bytes().iter().any(|&x| x == 0)
|
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
|
//! POSIX file path handling
|
||||||
|
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
|
||||||
use hash;
|
use hash;
|
||||||
use io::Writer;
|
use io::Writer;
|
||||||
use iter::{AdditiveIterator, Extend};
|
use iter::{AdditiveIterator, Extend};
|
||||||
use iter::{Iterator, IteratorExt, Map};
|
use iter::{Iterator, IteratorExt, Map};
|
||||||
use option::Option;
|
|
||||||
use option::Option::{None, Some};
|
|
||||||
use kinds::Sized;
|
use kinds::Sized;
|
||||||
use str::{FromStr, Str};
|
use option::Option::{self, Some, None};
|
||||||
use str;
|
use slice::{AsSlice, Split, SliceExt, SliceConcatExt};
|
||||||
use slice::{Split, AsSlice, SliceConcatExt, SliceExt};
|
use str::{self, FromStr, StrExt};
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
use super::{BytesContainer, GenericPath, GenericPathUnsafe};
|
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 {
|
impl<S: hash::Writer> hash::Hash<S> for Path {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash(&self, state: &mut S) {
|
fn hash(&self, state: &mut S) {
|
||||||
|
|
|
@ -15,17 +15,15 @@
|
||||||
use self::PathPrefix::*;
|
use self::PathPrefix::*;
|
||||||
|
|
||||||
use ascii::AsciiExt;
|
use ascii::AsciiExt;
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
use char::CharExt;
|
use char::CharExt;
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
|
||||||
use hash;
|
use hash;
|
||||||
use io::Writer;
|
use io::Writer;
|
||||||
use iter::{AdditiveIterator, Extend};
|
use iter::{AdditiveIterator, Extend};
|
||||||
use iter::{Iterator, IteratorExt, Map, repeat};
|
use iter::{Iterator, IteratorExt, Map, repeat};
|
||||||
use mem;
|
use mem;
|
||||||
use option::Option;
|
use option::Option::{self, Some, None};
|
||||||
use option::Option::{Some, None};
|
|
||||||
use slice::{SliceExt, SliceConcatExt};
|
use slice::{SliceExt, SliceConcatExt};
|
||||||
use str::{SplitTerminator, FromStr, StrExt};
|
use str::{SplitTerminator, FromStr, StrExt};
|
||||||
use string::{String, ToString};
|
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 {
|
impl<S: hash::Writer> hash::Hash<S> for Path {
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -46,8 +46,9 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
|
||||||
mod imp {
|
mod imp {
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
|
use libc;
|
||||||
use mem;
|
use mem;
|
||||||
use slice;
|
use ffi;
|
||||||
|
|
||||||
use sync::{StaticMutex, MUTEX_INIT};
|
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>> {
|
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| {
|
range(0, argc as uint).map(|i| {
|
||||||
let arg = *argv.offset(i as int);
|
ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
|
||||||
let mut len = 0u;
|
|
||||||
while *arg.offset(len as int) != 0 {
|
|
||||||
len += 1u;
|
|
||||||
}
|
|
||||||
slice::from_raw_buf(&arg, len).to_vec()
|
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use os;
|
use os;
|
||||||
use sync::atomic::{mod, Ordering};
|
use sync::atomic::{self, Ordering};
|
||||||
|
|
||||||
pub use sys::backtrace::write;
|
pub use sys::backtrace::write;
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ use fmt;
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use mem;
|
use mem;
|
||||||
use sync::atomic::{mod, Ordering};
|
use sync::atomic::{self, Ordering};
|
||||||
use sync::{Once, ONCE_INIT};
|
use sync::{Once, ONCE_INIT};
|
||||||
|
|
||||||
use rt::libunwind as uw;
|
use rt::libunwind as uw;
|
||||||
|
|
|
@ -19,7 +19,7 @@ use libc::{self, uintptr_t};
|
||||||
use os;
|
use os;
|
||||||
use slice;
|
use slice;
|
||||||
use str;
|
use str;
|
||||||
use sync::atomic::{mod, Ordering};
|
use sync::atomic::{self, Ordering};
|
||||||
|
|
||||||
/// Dynamically inquire about whether we're running under V.
|
/// Dynamically inquire about whether we're running under V.
|
||||||
/// You should usually not use this unless your test definitely
|
/// You should usually not use this unless your test definitely
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
use io::{self, IoError, IoResult};
|
use io::{self, IoError, IoResult};
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use sys::{last_error, retry};
|
use sys::{last_error, retry};
|
||||||
use c_str::CString;
|
use ffi::CString;
|
||||||
use num::Int;
|
use num::Int;
|
||||||
use path::BytesContainer;
|
use path::BytesContainer;
|
||||||
use collections;
|
use collections;
|
||||||
|
|
|
@ -12,15 +12,16 @@ use prelude::v1::*;
|
||||||
use self::SocketStatus::*;
|
use self::SocketStatus::*;
|
||||||
use self::InAddr::*;
|
use self::InAddr::*;
|
||||||
|
|
||||||
use c_str::ToCStr;
|
use ffi::CString;
|
||||||
|
use ffi;
|
||||||
use io::net::addrinfo;
|
use io::net::addrinfo;
|
||||||
use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use io::{IoResult, IoError};
|
use io::{IoResult, IoError};
|
||||||
use libc::{self, c_char, c_int};
|
use libc::{self, c_char, c_int};
|
||||||
use c_str::CString;
|
|
||||||
use mem;
|
use mem;
|
||||||
use num::Int;
|
use num::Int;
|
||||||
use ptr::{self, null, null_mut};
|
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,
|
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,
|
wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
|
||||||
decode_error_detailed};
|
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());
|
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_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 c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
|
||||||
|
|
||||||
let hint = hint.map(|hint| {
|
let hint = hint.map(|hint| {
|
||||||
|
@ -324,7 +325,8 @@ pub fn get_address_name(addr: IpAddr) -> Result<String, IoError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
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
|
/// 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.
|
/// all unix platforms we support right now, so it at least gets the job done.
|
||||||
|
|
||||||
use c_str::CString;
|
use prelude::v1::*;
|
||||||
use io::{IoResult, Writer};
|
|
||||||
|
use ffi;
|
||||||
|
use io::IoResult;
|
||||||
use libc;
|
use libc;
|
||||||
use mem;
|
use mem;
|
||||||
use option::Option::{self, Some, None};
|
use str;
|
||||||
use result::Result::{Ok, Err};
|
|
||||||
use sync::{StaticMutex, MUTEX_INIT};
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
|
|
||||||
use sys_common::backtrace::*;
|
use sys_common::backtrace::*;
|
||||||
|
@ -105,9 +106,7 @@ use sys_common::backtrace::*;
|
||||||
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn write(w: &mut Writer) -> IoResult<()> {
|
pub fn write(w: &mut Writer) -> IoResult<()> {
|
||||||
use iter::{IteratorExt, range};
|
|
||||||
use result;
|
use result;
|
||||||
use slice::SliceExt;
|
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
fn backtrace(buf: *mut *mut libc::c_void,
|
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)
|
output(w, idx,addr, None)
|
||||||
} else {
|
} else {
|
||||||
output(w, idx, addr, Some(unsafe {
|
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")))]
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||||
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
||||||
use iter::{Iterator, IteratorExt};
|
|
||||||
use os;
|
use os;
|
||||||
use path::GenericPath;
|
|
||||||
use ptr::PtrExt;
|
|
||||||
use ptr;
|
use ptr;
|
||||||
use slice::SliceExt;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// libbacktrace.h API
|
// 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() {
|
if ret == 0 || data.is_null() {
|
||||||
output(w, idx, addr, None)
|
output(w, idx, addr, None)
|
||||||
} else {
|
} 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.
|
// Finally, after all that work above, we can emit a symbol.
|
||||||
fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
|
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));
|
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)),
|
Some(string) => try!(demangle(w, string)),
|
||||||
None => try!(write!(w, "<unknown>")),
|
None => try!(write!(w, "<unknown>")),
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use c_str::{CString, ToCStr};
|
use ffi::{self, CString};
|
||||||
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
|
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
|
||||||
use io::{IoResult, FileStat, SeekStyle};
|
use io::{IoResult, FileStat, SeekStyle};
|
||||||
use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
|
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> {
|
pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
|
||||||
let flags = match fm {
|
let flags = match fm {
|
||||||
Open => 0,
|
Open => 0,
|
||||||
|
@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
|
||||||
libc::S_IRUSR | libc::S_IWUSR),
|
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) }) {
|
match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
|
||||||
-1 => Err(super::last_error()),
|
-1 => Err(super::last_error()),
|
||||||
fd => Ok(FileDesc::new(fd, true)),
|
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<()> {
|
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) })
|
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};
|
use libc::{opendir, readdir_r, closedir};
|
||||||
|
|
||||||
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
|
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
|
||||||
let root = unsafe { CString::new(root.as_ptr(), false) };
|
|
||||||
let root = Path::new(root);
|
let root = Path::new(root);
|
||||||
|
|
||||||
dirs.into_iter().filter(|path| {
|
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 mut buf = Vec::<u8>::with_capacity(size as uint);
|
||||||
let ptr = buf.as_mut_ptr() as *mut dirent_t;
|
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())};
|
let dir_ptr = unsafe {opendir(p.as_ptr())};
|
||||||
|
|
||||||
if dir_ptr as uint != 0 {
|
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;
|
let mut entry_ptr = 0 as *mut dirent_t;
|
||||||
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
|
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
|
||||||
if entry_ptr.is_null() { break }
|
if entry_ptr.is_null() { break }
|
||||||
let cstr = unsafe {
|
paths.push(unsafe {
|
||||||
CString::new(rust_list_dir_val(entry_ptr), false)
|
Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr)))
|
||||||
};
|
});
|
||||||
paths.push(Path::new(cstr));
|
|
||||||
}
|
}
|
||||||
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
|
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
|
||||||
Ok(prune(&p, paths))
|
Ok(prune(&p, paths))
|
||||||
|
@ -220,39 +222,39 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(p: &Path) -> IoResult<()> {
|
pub fn unlink(p: &Path) -> IoResult<()> {
|
||||||
let p = p.to_c_str();
|
let p = cstr(p);
|
||||||
mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
|
mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
|
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
|
||||||
let old = old.to_c_str();
|
let old = cstr(old);
|
||||||
let new = new.to_c_str();
|
let new = cstr(new);
|
||||||
mkerr_libc(unsafe {
|
mkerr_libc(unsafe {
|
||||||
libc::rename(old.as_ptr(), new.as_ptr())
|
libc::rename(old.as_ptr(), new.as_ptr())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
|
pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
|
||||||
let p = p.to_c_str();
|
let p = cstr(p);
|
||||||
mkerr_libc(retry(|| unsafe {
|
mkerr_libc(retry(|| unsafe {
|
||||||
libc::chmod(p.as_ptr(), mode as libc::mode_t)
|
libc::chmod(p.as_ptr(), mode as libc::mode_t)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rmdir(p: &Path) -> IoResult<()> {
|
pub fn rmdir(p: &Path) -> IoResult<()> {
|
||||||
let p = p.to_c_str();
|
let p = cstr(p);
|
||||||
mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
|
mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
|
pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
|
||||||
let p = p.to_c_str();
|
let p = cstr(p);
|
||||||
mkerr_libc(retry(|| unsafe {
|
mkerr_libc(retry(|| unsafe {
|
||||||
libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
|
libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readlink(p: &Path) -> IoResult<Path> {
|
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 p = c_path.as_ptr();
|
||||||
let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
|
let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
|
||||||
if len == -1 {
|
if len == -1 {
|
||||||
|
@ -273,14 +275,14 @@ pub fn readlink(p: &Path) -> IoResult<Path> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
|
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
|
||||||
let src = src.to_c_str();
|
let src = cstr(src);
|
||||||
let dst = dst.to_c_str();
|
let dst = cstr(dst);
|
||||||
mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
|
mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
|
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
|
||||||
let src = src.to_c_str();
|
let src = cstr(src);
|
||||||
let dst = dst.to_c_str();
|
let dst = cstr(dst);
|
||||||
mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
|
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> {
|
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() };
|
let mut stat: libc::stat = unsafe { mem::zeroed() };
|
||||||
match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
|
match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
|
||||||
0 => Ok(mkstat(&stat)),
|
0 => Ok(mkstat(&stat)),
|
||||||
|
@ -337,7 +339,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lstat(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() };
|
let mut stat: libc::stat = unsafe { mem::zeroed() };
|
||||||
match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
|
match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
|
||||||
0 => Ok(mkstat(&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<()> {
|
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
|
||||||
let p = p.to_c_str();
|
let p = cstr(p);
|
||||||
let buf = libc::utimbuf {
|
let buf = libc::utimbuf {
|
||||||
actime: (atime / 1000) as libc::time_t,
|
actime: (atime / 1000) as libc::time_t,
|
||||||
modtime: (mtime / 1000) as libc::time_t,
|
modtime: (mtime / 1000) as libc::time_t,
|
||||||
|
|
|
@ -15,12 +15,14 @@
|
||||||
#![allow(unused_unsafe)]
|
#![allow(unused_unsafe)]
|
||||||
#![allow(unused_mut)]
|
#![allow(unused_mut)]
|
||||||
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
use num;
|
|
||||||
use num::{Int, SignedInt};
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
|
use ffi;
|
||||||
use io::{self, IoResult, IoError};
|
use io::{self, IoResult, IoError};
|
||||||
|
use libc;
|
||||||
|
use num::{Int, SignedInt};
|
||||||
|
use num;
|
||||||
|
use str;
|
||||||
use sys_common::mkerr_libc;
|
use sys_common::mkerr_libc;
|
||||||
|
|
||||||
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
|
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 {
|
pub fn last_gai_error(s: libc::c_int) -> IoError {
|
||||||
use c_str::CString;
|
|
||||||
|
|
||||||
let mut err = decode_error(s);
|
let mut err = decode_error(s);
|
||||||
err.detail = Some(unsafe {
|
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
|
err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,18 @@
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use c_str::ToCStr;
|
|
||||||
use error::{FromError, Error};
|
use error::{FromError, Error};
|
||||||
|
use ffi::{self, CString};
|
||||||
use fmt;
|
use fmt;
|
||||||
use io::{IoError, IoResult};
|
use io::{IoError, IoResult};
|
||||||
use libc::{self, c_int, c_char, c_void};
|
use libc::{self, c_int, c_char, c_void};
|
||||||
|
use os::TMPBUF_SZ;
|
||||||
use os;
|
use os;
|
||||||
use path::{BytesContainer};
|
use path::{BytesContainer};
|
||||||
use ptr;
|
use ptr;
|
||||||
|
use str;
|
||||||
use sys::fs::FileDesc;
|
use sys::fs::FileDesc;
|
||||||
|
|
||||||
use os::TMPBUF_SZ;
|
|
||||||
|
|
||||||
const BUF_BYTES : uint = 2048u;
|
const BUF_BYTES : uint = 2048u;
|
||||||
|
|
||||||
/// Returns the platform-specific value of errno
|
/// Returns the platform-specific value of errno
|
||||||
|
@ -108,7 +108,8 @@ pub fn error_string(errno: i32) -> String {
|
||||||
panic!("strerror_r failure");
|
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> {
|
pub fn getcwd() -> IoResult<Path> {
|
||||||
use c_str::CString;
|
|
||||||
|
|
||||||
let mut buf = [0 as c_char; BUF_BYTES];
|
let mut buf = [0 as c_char; BUF_BYTES];
|
||||||
unsafe {
|
unsafe {
|
||||||
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
|
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
|
||||||
Err(IoError::last_error())
|
Err(IoError::last_error())
|
||||||
} else {
|
} 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>> {
|
pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
||||||
use c_str::CString;
|
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
fn rust_env_pairs() -> *const *const c_char;
|
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();
|
let mut result = Vec::new();
|
||||||
while *environ != 0 as *const _ {
|
while *environ != 0 as *const _ {
|
||||||
let env_pair =
|
let env_pair = ffi::c_str_to_bytes(&*environ).to_vec();
|
||||||
CString::new(*environ, false).as_bytes_no_nul().to_vec();
|
|
||||||
result.push(env_pair);
|
result.push(env_pair);
|
||||||
environ = environ.offset(1);
|
environ = environ.offset(1);
|
||||||
}
|
}
|
||||||
|
@ -234,14 +230,13 @@ pub fn load_self() -> Option<Vec<u8>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chdir(p: &Path) -> IoResult<()> {
|
pub fn chdir(p: &Path) -> IoResult<()> {
|
||||||
p.with_c_str(|buf| {
|
let p = CString::from_slice(p.as_vec());
|
||||||
unsafe {
|
unsafe {
|
||||||
match libc::chdir(buf) == (0 as c_int) {
|
match libc::chdir(p.as_ptr()) == (0 as c_int) {
|
||||||
true => Ok(()),
|
true => Ok(()),
|
||||||
false => Err(IoError::last_error()),
|
false => Err(IoError::last_error()),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_size() -> uint {
|
pub fn page_size() -> uint {
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
|
use ffi::CString;
|
||||||
use libc;
|
use libc;
|
||||||
use c_str::CString;
|
|
||||||
use mem;
|
use mem;
|
||||||
use sync::{Arc, Mutex};
|
use sync::{Arc, Mutex};
|
||||||
use sync::atomic::{AtomicBool, Ordering};
|
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;
|
s.sun_family = libc::AF_UNIX as libc::sa_family_t;
|
||||||
for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) {
|
for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) {
|
||||||
*slot = value;
|
*slot = *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// count the null terminator
|
// count the null terminator
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use self::Req::*;
|
use self::Req::*;
|
||||||
|
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
use collections;
|
use collections;
|
||||||
|
use ffi::CString;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use io::process::{ProcessExit, ExitStatus, ExitSignal};
|
use io::process::{ProcessExit, ExitStatus, ExitSignal};
|
||||||
use io::{self, IoResult, IoError, EndOfFile};
|
use io::{self, IoResult, IoError, EndOfFile};
|
||||||
|
@ -101,7 +101,7 @@ impl Process {
|
||||||
|
|
||||||
// We may use this in the child, so perform allocations before the
|
// We may use this in the child, so perform allocations before the
|
||||||
// fork
|
// fork
|
||||||
let devnull = "/dev/null".to_c_str();
|
let devnull = b"/dev/null\0";
|
||||||
|
|
||||||
set_cloexec(output.fd());
|
set_cloexec(output.fd());
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ impl Process {
|
||||||
} else {
|
} else {
|
||||||
libc::O_RDWR
|
libc::O_RDWR
|
||||||
};
|
};
|
||||||
libc::open(devnull.as_ptr(), flags, 0)
|
libc::open(devnull.as_ptr() as *const _, flags, 0)
|
||||||
}
|
}
|
||||||
Some(obj) => {
|
Some(obj) => {
|
||||||
let fd = obj.as_inner().fd();
|
let fd = obj.as_inner().fd();
|
||||||
|
|
|
@ -54,7 +54,7 @@ use libc;
|
||||||
use mem;
|
use mem;
|
||||||
use os;
|
use os;
|
||||||
use ptr;
|
use ptr;
|
||||||
use sync::atomic::{mod, Ordering};
|
use sync::atomic::{self, Ordering};
|
||||||
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
|
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
|
||||||
use sys::c;
|
use sys::c;
|
||||||
use sys::fs::FileDesc;
|
use sys::fs::FileDesc;
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
/// copy of that function in my mingw install (maybe it was broken?). Instead,
|
/// 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.
|
/// 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 intrinsics;
|
||||||
use io::{IoResult, Writer};
|
use io::{IoResult, Writer};
|
||||||
use libc;
|
use libc;
|
||||||
|
@ -30,10 +31,9 @@ use ops::Drop;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use result::Result::{Ok, Err};
|
use result::Result::{Ok, Err};
|
||||||
use sync::{StaticMutex, MUTEX_INIT};
|
|
||||||
use slice::SliceExt;
|
use slice::SliceExt;
|
||||||
use str::StrExt;
|
use str::{self, StrExt};
|
||||||
use dynamic_lib::DynamicLibrary;
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
|
|
||||||
use sys_common::backtrace::*;
|
use sys_common::backtrace::*;
|
||||||
|
|
||||||
|
@ -357,11 +357,11 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
|
||||||
|
|
||||||
if ret == libc::TRUE {
|
if ret == libc::TRUE {
|
||||||
try!(write!(w, " - "));
|
try!(write!(w, " - "));
|
||||||
let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
|
let ptr = info.Name.as_ptr() as *const libc::c_char;
|
||||||
let bytes = cstr.as_bytes();
|
let bytes = unsafe { ffi::c_str_to_bytes(&ptr) };
|
||||||
match cstr.as_str() {
|
match str::from_utf8(bytes) {
|
||||||
Some(s) => try!(demangle(w, s)),
|
Ok(s) => try!(demangle(w, s)),
|
||||||
None => try!(w.write(bytes[..bytes.len()-1])),
|
Err(..) => try!(w.write(bytes[..bytes.len()-1])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try!(w.write(&['\n' as u8]));
|
try!(w.write(&['\n' as u8]));
|
||||||
|
|
|
@ -133,7 +133,7 @@ pub mod compat {
|
||||||
use intrinsics::{atomic_store_relaxed, transmute};
|
use intrinsics::{atomic_store_relaxed, transmute};
|
||||||
use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
|
use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use c_str::ToCStr;
|
use ffi::CString;
|
||||||
|
|
||||||
extern "system" {
|
extern "system" {
|
||||||
fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
|
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) {
|
unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
|
||||||
let mut module: Vec<u16> = module.utf16_units().collect();
|
let mut module: Vec<u16> = module.utf16_units().collect();
|
||||||
module.push(0);
|
module.push(0);
|
||||||
symbol.with_c_str(|symbol| {
|
let symbol = CString::from_slice(symbol.as_bytes());
|
||||||
let handle = GetModuleHandleW(module.as_ptr());
|
let handle = GetModuleHandleW(module.as_ptr());
|
||||||
let func: uint = transmute(GetProcAddress(handle, symbol));
|
let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr()));
|
||||||
atomic_store_relaxed(ptr, if func == 0 {
|
atomic_store_relaxed(ptr, if func == 0 {
|
||||||
fallback
|
fallback
|
||||||
} else {
|
} else {
|
||||||
func
|
func
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
use alloc::arc::Arc;
|
use alloc::arc::Arc;
|
||||||
use libc::{self, c_int};
|
use libc::{self, c_int};
|
||||||
|
|
||||||
use c_str::CString;
|
|
||||||
use mem;
|
use mem;
|
||||||
use sys::os::fill_utf16_buf_and_decode;
|
use sys::os::fill_utf16_buf_and_decode;
|
||||||
use path;
|
use path;
|
||||||
|
|
|
@ -87,16 +87,21 @@
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use c_str::CString;
|
use ffi::CString;
|
||||||
|
use io::{self, IoError, IoResult};
|
||||||
use mem;
|
use mem;
|
||||||
use ptr;
|
use ptr;
|
||||||
use sync::{Arc, Mutex};
|
use str;
|
||||||
use sync::atomic::{AtomicBool, Ordering};
|
use sync::atomic::{AtomicBool, Ordering};
|
||||||
use io::{self, IoError, IoResult};
|
use sync::{Arc, Mutex};
|
||||||
|
|
||||||
use sys_common::{self, eof};
|
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);
|
struct Event(libc::HANDLE);
|
||||||
|
|
||||||
|
@ -270,7 +275,7 @@ impl UnixStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<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();
|
let start = timer::now();
|
||||||
loop {
|
loop {
|
||||||
match UnixStream::try_connect(addr.as_ptr()) {
|
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
|
// 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
|
// create the initial handle up front to test the validity of the name
|
||||||
// and such.
|
// 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) };
|
let ret = unsafe { pipe(addr_v.as_ptr(), true) };
|
||||||
if ret == libc::INVALID_HANDLE_VALUE {
|
if ret == libc::INVALID_HANDLE_VALUE {
|
||||||
Err(super::last_error())
|
Err(super::last_error())
|
||||||
|
@ -661,7 +666,7 @@ impl UnixAcceptor {
|
||||||
// proceed in accepting new clients in the future
|
// proceed in accepting new clients in the future
|
||||||
if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) }
|
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
|
// Once we've got a "server handle", we need to wait for a client to
|
||||||
// connect. The ConnectNamedPipe function will block this thread until
|
// connect. The ConnectNamedPipe function will block this thread until
|
||||||
|
@ -753,7 +758,7 @@ impl UnixAcceptor {
|
||||||
|
|
||||||
impl Clone for UnixAcceptor {
|
impl Clone for UnixAcceptor {
|
||||||
fn clone(&self) -> 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 {
|
UnixAcceptor {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
event: Event::new(true, false).ok().unwrap(),
|
event: Event::new(true, false).ok().unwrap(),
|
||||||
|
|
|
@ -10,27 +10,26 @@
|
||||||
|
|
||||||
use prelude::v1::*;
|
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::{pid_t, c_void, c_int};
|
||||||
use libc;
|
use libc;
|
||||||
use c_str::{CString, ToCStr};
|
|
||||||
use io;
|
|
||||||
use mem;
|
use mem;
|
||||||
use os;
|
use os;
|
||||||
use ptr;
|
|
||||||
use io::process::{ProcessExit, ExitStatus, ExitSignal};
|
|
||||||
use collections;
|
|
||||||
use path::BytesContainer;
|
use path::BytesContainer;
|
||||||
use hash::Hash;
|
use ptr;
|
||||||
use io::{IoResult, IoError};
|
use str;
|
||||||
|
use sys::fs::FileDesc;
|
||||||
use sys::fs;
|
use sys::fs;
|
||||||
use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
|
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::helper_thread::Helper;
|
||||||
use sys_common::{AsInner, mkerr_libc, timeout};
|
use sys_common::{AsInner, mkerr_libc, timeout};
|
||||||
|
|
||||||
use io::fs::PathExtensions;
|
|
||||||
|
|
||||||
pub use sys_common::ProcessConfig;
|
pub use sys_common::ProcessConfig;
|
||||||
|
|
||||||
/// A value representing a child process.
|
/// A value representing a child process.
|
||||||
|
@ -142,10 +141,10 @@ impl Process {
|
||||||
// Split the value and test each path to see if the
|
// Split the value and test each path to see if the
|
||||||
// program exists.
|
// program exists.
|
||||||
for path in os::split_paths(v.container_as_bytes()).into_iter() {
|
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);
|
.with_extension(os::consts::EXE_EXTENSION);
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
return Some(path.to_c_str())
|
return Some(CString::from_slice(path.as_vec()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
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 {
|
fn make_command_line(prog: &CString, args: &[CString]) -> String {
|
||||||
let mut cmd = String::new();
|
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"));
|
.expect("expected program name to be utf-8 encoded"));
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
cmd.push(' ');
|
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"));
|
.expect("expected argument to be utf-8 encoded"));
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
|
@ -449,7 +448,7 @@ fn with_dirp<T, F>(d: Option<&CString>, cb: F) -> T where
|
||||||
{
|
{
|
||||||
match d {
|
match d {
|
||||||
Some(dir) => {
|
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");
|
.expect("expected workingdirectory to be utf-8 encoded");
|
||||||
let mut dir_str: Vec<u16> = dir_str.utf16_units().collect();
|
let mut dir_str: Vec<u16> = dir_str.utf16_units().collect();
|
||||||
dir_str.push(0);
|
dir_str.push(0);
|
||||||
|
|
|
@ -27,7 +27,7 @@ fn bar() { }
|
||||||
fn baz() { }
|
fn baz() { }
|
||||||
|
|
||||||
pub fn test() {
|
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();
|
let lib = DynamicLibrary::open(none).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(lib.symbol::<int>("foo").is_ok());
|
assert!(lib.symbol::<int>("foo").is_ok());
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
|
|
||||||
mod mlibc {
|
mod mlibc {
|
||||||
use libc::{c_char, c_long, c_longlong};
|
use libc::{c_char, c_long, c_longlong};
|
||||||
|
@ -24,11 +24,13 @@ mod mlibc {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atol(s: String) -> int {
|
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 {
|
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() {
|
pub fn main() {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::{str, string};
|
use std::{str, string};
|
||||||
use std::c_str::ToCStr;
|
|
||||||
|
|
||||||
const A: [u8; 2] = ['h' as u8, 'i' as u8];
|
const A: [u8; 2] = ['h' as u8, 'i' as u8];
|
||||||
const B: &'static [u8; 2] = &A;
|
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_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string());
|
||||||
assert!(*C == A[0]);
|
assert!(*C == A[0]);
|
||||||
assert!(*(&B[0] as *const u8) == 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
|
// ignore-fast doesn't like extern crate
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use std::c_str::ToCStr;
|
use std::ffi::CString;
|
||||||
|
|
||||||
mod mlibc {
|
mod mlibc {
|
||||||
use libc::{c_char, size_t};
|
use libc::{c_char, size_t};
|
||||||
|
@ -24,11 +24,10 @@ mod mlibc {
|
||||||
|
|
||||||
fn strlen(str: String) -> uint {
|
fn strlen(str: String) -> uint {
|
||||||
// C string is terminated with a zero
|
// C string is terminated with a zero
|
||||||
str.as_slice().with_c_str(|buf| {
|
let s = CString::from_slice(str.as_bytes());
|
||||||
unsafe {
|
unsafe {
|
||||||
mlibc::my_strlen(buf) as uint
|
mlibc::my_strlen(s.as_ptr()) as uint
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
use std::io::TempDir;
|
use std::io::TempDir;
|
||||||
use std::c_str::ToCStr;
|
|
||||||
use std::io::fs::PathExtensions;
|
use std::io::fs::PathExtensions;
|
||||||
use std::io::fs;
|
use std::io::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -31,20 +31,17 @@ fn rename_directory() {
|
||||||
let test_file = &old_path.join("temp.txt");
|
let test_file = &old_path.join("temp.txt");
|
||||||
|
|
||||||
/* Write the temp input file */
|
/* Write the temp input file */
|
||||||
let ostream = test_file.with_c_str(|fromp| {
|
let fromp = CString::from_slice(test_file.as_vec());
|
||||||
"w+b".with_c_str(|modebuf| {
|
let modebuf = CString::from_slice(b"w+b");
|
||||||
libc::fopen(fromp, modebuf)
|
let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr());
|
||||||
})
|
|
||||||
});
|
|
||||||
assert!((ostream as uint != 0u));
|
assert!((ostream as uint != 0u));
|
||||||
let s = "hello".to_string();
|
let s = "hello".to_string();
|
||||||
"hello".with_c_str(|buf| {
|
let buf = CString::from_slice(b"hello");
|
||||||
let write_len = libc::fwrite(buf as *const libc::c_void,
|
let write_len = libc::fwrite(buf.as_ptr() as *mut _,
|
||||||
1u as libc::size_t,
|
1u as libc::size_t,
|
||||||
(s.len() + 1u) as libc::size_t,
|
(s.len() + 1u) as libc::size_t,
|
||||||
ostream);
|
ostream);
|
||||||
assert_eq!(write_len, (s.len() + 1) as libc::size_t)
|
assert_eq!(write_len, (s.len() + 1) as libc::size_t);
|
||||||
});
|
|
||||||
assert_eq!(libc::fclose(ostream), (0u as libc::c_int));
|
assert_eq!(libc::fclose(ostream), (0u as libc::c_int));
|
||||||
|
|
||||||
let new_path = tmpdir.join_many(&["quux", "blat"]);
|
let new_path = tmpdir.join_many(&["quux", "blat"]);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::c_str::{CString, ToCStr};
|
use std::ffi::{self, CString};
|
||||||
use libc::{c_char, c_int};
|
use libc::{c_char, c_int};
|
||||||
|
|
||||||
// ignore-fast doesn't like extern crate
|
// ignore-fast doesn't like extern crate
|
||||||
|
@ -22,40 +22,35 @@ extern {
|
||||||
unsafe fn check<T>(expected: &str, f: |*mut c_char| -> T) {
|
unsafe fn check<T>(expected: &str, f: |*mut c_char| -> T) {
|
||||||
let mut x = [0 as c_char; 50];
|
let mut x = [0 as c_char; 50];
|
||||||
f(&mut x[0] as *mut c_char);
|
f(&mut x[0] as *mut c_char);
|
||||||
let res = CString::new(&x[0], false);
|
assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr()));
|
||||||
assert_eq!(expected, res.as_str().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Call with just the named parameter
|
// Call with just the named parameter
|
||||||
"Hello World\n".with_c_str(|c| {
|
let c = CString::from_slice(b"Hello World\n");
|
||||||
check("Hello World\n", |s| sprintf(s, c));
|
check("Hello World\n", |s| sprintf(s, c.as_ptr()));
|
||||||
});
|
|
||||||
|
|
||||||
// Call with variable number of arguments
|
// Call with variable number of arguments
|
||||||
"%d %f %c %s\n".with_c_str(|c| {
|
let c = CString::from_slice(b"%d %f %c %s\n");
|
||||||
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
||||||
sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c);
|
sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make a function pointer
|
// 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
|
// A function that takes a function pointer
|
||||||
unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) {
|
unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
|
||||||
// Call with just the named parameter via fn pointer
|
// Call with just the named parameter
|
||||||
"Hello World\n".with_c_str(|c| {
|
let c = CString::from_slice(b"Hello World\n");
|
||||||
check("Hello World\n", |s| p(s, c));
|
check("Hello World\n", |s| sprintf(s, c.as_ptr()));
|
||||||
});
|
|
||||||
|
|
||||||
// Call with variable number of arguments
|
// Call with variable number of arguments
|
||||||
"%d %f %c %s\n".with_c_str(|c| {
|
let c = CString::from_slice(b"%d %f %c %s\n");
|
||||||
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
||||||
p(s, c, 42i, 42.5f64, 'a' as c_int, c);
|
sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue