Auto merge of #36807 - brson:pal, r=brson
Restrict where in the tree platform-specific cfgs may be mentioned With the ports of Rust never ending, it's important that we keep things tidy. The main thing this PR does is introduce a new "pal" (platform abstraction layer) tidy check that limits where platform-specific CFGs may appear. This is intended to maintain existing standards of code organization in hopes that the standard library will continue to be refactored to isolate platform-specific bits, making porting easier; where "standard library" roughly means "all the dependencies of the std and test crates". This generally means placing restrictions on where `cfg(unix)`, `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear, the basic objective being to isolate platform-specific code to the platform-specific `std::sys` modules, and to the allocation, unwinding, and libc crates. Following are the basic rules, though there are currently exceptions: - core may not have platform-specific code - liballoc_system may have platform-specific code - liballoc_jemalloc may have platform-specific code - libpanic_abort may have platform-specific code - libpanic_unwind may have platform-specific code - other crates in the std facade may not - std may have platform-specific code in the following places - sys/unix/ - sys/windows/ - os/ There are plenty of exceptions today though, noted in the whitelist. The end-state, IMO, is for the standard library to be portable by porting only `std::sys` (possibly extracted to its own crate), an allocator crate, an unwinder crate, and possibly a libc crate (if std depends on it); but that outcome is far off and independent of the utility of enforcing where such code lives today. cc @rust-lang/libs
This commit is contained in:
commit
144af3e97a
@ -21,6 +21,7 @@ use ffi::{OsStr, OsString};
|
||||
use fmt;
|
||||
use io;
|
||||
use path::{Path, PathBuf};
|
||||
use sys;
|
||||
use sys::os as os_imp;
|
||||
|
||||
/// Returns the current working directory as a `PathBuf`.
|
||||
@ -557,7 +558,7 @@ pub struct Args { inner: ArgsOs }
|
||||
///
|
||||
/// This structure is created through the `std::env::args_os` method.
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub struct ArgsOs { inner: os_imp::Args }
|
||||
pub struct ArgsOs { inner: sys::args::Args }
|
||||
|
||||
/// Returns the arguments which this program was started with (normally passed
|
||||
/// via the command line).
|
||||
@ -606,7 +607,7 @@ pub fn args() -> Args {
|
||||
/// ```
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub fn args_os() -> ArgsOs {
|
||||
ArgsOs { inner: os_imp::args() }
|
||||
ArgsOs { inner: sys::args::args() }
|
||||
}
|
||||
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
@ -649,6 +650,8 @@ impl DoubleEndedIterator for ArgsOs {
|
||||
/// Constants associated with the current target
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub mod consts {
|
||||
use sys::env::os;
|
||||
|
||||
/// A string describing the architecture of the CPU that is currently
|
||||
/// in use.
|
||||
///
|
||||
@ -673,7 +676,7 @@ pub mod consts {
|
||||
/// - unix
|
||||
/// - windows
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const FAMILY: &'static str = super::os::FAMILY;
|
||||
pub const FAMILY: &'static str = os::FAMILY;
|
||||
|
||||
/// A string describing the specific operating system in use.
|
||||
/// Example value is `linux`.
|
||||
@ -692,7 +695,7 @@ pub mod consts {
|
||||
/// - android
|
||||
/// - windows
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const OS: &'static str = super::os::OS;
|
||||
pub const OS: &'static str = os::OS;
|
||||
|
||||
/// Specifies the filename prefix used for shared libraries on this
|
||||
/// platform. Example value is `lib`.
|
||||
@ -702,7 +705,7 @@ pub mod consts {
|
||||
/// - lib
|
||||
/// - `""` (an empty string)
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
|
||||
pub const DLL_PREFIX: &'static str = os::DLL_PREFIX;
|
||||
|
||||
/// Specifies the filename suffix used for shared libraries on this
|
||||
/// platform. Example value is `.so`.
|
||||
@ -713,7 +716,7 @@ pub mod consts {
|
||||
/// - .dylib
|
||||
/// - .dll
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
|
||||
pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX;
|
||||
|
||||
/// Specifies the file extension used for shared libraries on this
|
||||
/// platform that goes after the dot. Example value is `so`.
|
||||
@ -724,7 +727,7 @@ pub mod consts {
|
||||
/// - dylib
|
||||
/// - dll
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
|
||||
pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION;
|
||||
|
||||
/// Specifies the filename suffix used for executable binaries on this
|
||||
/// platform. Example value is `.exe`.
|
||||
@ -736,7 +739,7 @@ pub mod consts {
|
||||
/// - .pexe
|
||||
/// - `""` (an empty string)
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
|
||||
pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX;
|
||||
|
||||
/// Specifies the file extension, if any, used for executable binaries
|
||||
/// on this platform. Example value is `exe`.
|
||||
@ -746,183 +749,7 @@ pub mod consts {
|
||||
/// - exe
|
||||
/// - `""` (an empty string)
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
|
||||
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "linux";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "macos";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".dylib";
|
||||
pub const DLL_EXTENSION: &'static str = "dylib";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "ios";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".dylib";
|
||||
pub const DLL_EXTENSION: &'static str = "dylib";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "freebsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "dragonfly";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "bitrig")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "bitrig";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "netbsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "openbsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "android";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "solaris")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "solaris";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "windows";
|
||||
pub const OS: &'static str = "windows";
|
||||
pub const DLL_PREFIX: &'static str = "";
|
||||
pub const DLL_SUFFIX: &'static str = ".dll";
|
||||
pub const DLL_EXTENSION: &'static str = "dll";
|
||||
pub const EXE_SUFFIX: &'static str = ".exe";
|
||||
pub const EXE_EXTENSION: &'static str = "exe";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "nacl";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".nexe";
|
||||
pub const EXE_EXTENSION: &'static str = "nexe";
|
||||
}
|
||||
#[cfg(all(target_os = "nacl", target_arch = "le32"))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "pnacl";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".pso";
|
||||
pub const DLL_EXTENSION: &'static str = "pso";
|
||||
pub const EXE_SUFFIX: &'static str = ".pexe";
|
||||
pub const EXE_EXTENSION: &'static str = "pexe";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".js";
|
||||
pub const EXE_EXTENSION: &'static str = "js";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".js";
|
||||
pub const EXE_EXTENSION: &'static str = "js";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "haiku";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
|
@ -53,17 +53,6 @@ impl OsString {
|
||||
OsString { inner: Buf::from_string(String::new()) }
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
|
||||
use os::unix::ffi::OsStringExt;
|
||||
Some(OsString::from_vec(vec))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
|
||||
String::from_utf8(vec).ok().map(OsString::from)
|
||||
}
|
||||
|
||||
/// Converts to an `OsStr` slice.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn as_os_str(&self) -> &OsStr {
|
||||
|
@ -125,13 +125,10 @@ impl<R: io::Read> io::Read for Maybe<R> {
|
||||
}
|
||||
|
||||
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
|
||||
#[cfg(windows)]
|
||||
const ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
|
||||
#[cfg(not(windows))]
|
||||
const ERR: i32 = ::libc::EBADF as i32;
|
||||
use sys::stdio::EBADF_ERR;
|
||||
|
||||
match r {
|
||||
Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default),
|
||||
Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
|
||||
r => r
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,6 @@
|
||||
// Original implementation taken from rust-memchr
|
||||
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||
|
||||
|
||||
|
||||
/// A safe interface to `memchr`.
|
||||
///
|
||||
/// Returns the index corresponding to the first occurrence of `needle` in
|
||||
@ -32,32 +30,9 @@
|
||||
/// let haystack = b"the quick brown fox";
|
||||
/// assert_eq!(memchr(b'k', haystack), Some(8));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
// libc memchr
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
use libc;
|
||||
|
||||
let p = unsafe {
|
||||
libc::memchr(
|
||||
haystack.as_ptr() as *const libc::c_void,
|
||||
needle as libc::c_int,
|
||||
haystack.len() as libc::size_t)
|
||||
};
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p as usize - (haystack.as_ptr() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
// use fallback on windows, since it's faster
|
||||
#[cfg(target_os = "windows")]
|
||||
fn memchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
fallback::memchr(needle, haystack)
|
||||
}
|
||||
|
||||
memchr_specific(needle, haystack)
|
||||
::sys::memchr::memchr(needle, haystack)
|
||||
}
|
||||
|
||||
/// A safe interface to `memrchr`.
|
||||
@ -75,251 +50,9 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
/// let haystack = b"the quick brown fox";
|
||||
/// assert_eq!(memrchr(b'o', haystack), Some(17));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
use libc;
|
||||
|
||||
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
|
||||
if haystack.is_empty() {return None}
|
||||
let p = unsafe {
|
||||
libc::memrchr(
|
||||
haystack.as_ptr() as *const libc::c_void,
|
||||
needle as libc::c_int,
|
||||
haystack.len() as libc::size_t)
|
||||
};
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p as usize - (haystack.as_ptr() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
fallback::memrchr(needle, haystack)
|
||||
}
|
||||
|
||||
memrchr_specific(needle, haystack)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod fallback {
|
||||
use cmp;
|
||||
use mem;
|
||||
|
||||
const LO_U64: u64 = 0x0101010101010101;
|
||||
const HI_U64: u64 = 0x8080808080808080;
|
||||
|
||||
// use truncation
|
||||
const LO_USIZE: usize = LO_U64 as usize;
|
||||
const HI_USIZE: usize = HI_U64 as usize;
|
||||
|
||||
/// Return `true` if `x` contains any zero byte.
|
||||
///
|
||||
/// From *Matters Computational*, J. Arndt
|
||||
///
|
||||
/// "The idea is to subtract one from each of the bytes and then look for
|
||||
/// bytes where the borrow propagated all the way to the most significant
|
||||
/// bit."
|
||||
#[inline]
|
||||
fn contains_zero_byte(x: usize) -> bool {
|
||||
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[inline]
|
||||
fn repeat_byte(b: u8) -> usize {
|
||||
let mut rep = (b as usize) << 8 | b as usize;
|
||||
rep = rep << 16 | rep;
|
||||
rep
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[inline]
|
||||
fn repeat_byte(b: u8) -> usize {
|
||||
let mut rep = (b as usize) << 8 | b as usize;
|
||||
rep = rep << 16 | rep;
|
||||
rep = rep << 32 | rep;
|
||||
rep
|
||||
}
|
||||
|
||||
/// Return the first index matching the byte `a` in `text`.
|
||||
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
|
||||
// Scan for a single byte value by reading two `usize` words at a time.
|
||||
//
|
||||
// Split `text` in three parts
|
||||
// - unaligned initial part, before the first word aligned address in text
|
||||
// - body, scan by 2 words at a time
|
||||
// - the last remaining part, < 2 word size
|
||||
let len = text.len();
|
||||
let ptr = text.as_ptr();
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
|
||||
// search up to an aligned boundary
|
||||
let align = (ptr as usize) & (usize_bytes- 1);
|
||||
let mut offset;
|
||||
if align > 0 {
|
||||
offset = cmp::min(usize_bytes - align, len);
|
||||
if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
|
||||
return Some(index);
|
||||
}
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// search the body of the text
|
||||
let repeated_x = repeat_byte(x);
|
||||
|
||||
if len >= 2 * usize_bytes {
|
||||
while offset <= len - 2 * usize_bytes {
|
||||
unsafe {
|
||||
let u = *(ptr.offset(offset as isize) as *const usize);
|
||||
let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
|
||||
|
||||
// break if there is a matching byte
|
||||
let zu = contains_zero_byte(u ^ repeated_x);
|
||||
let zv = contains_zero_byte(v ^ repeated_x);
|
||||
if zu || zv {
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset += usize_bytes * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// find the byte after the point the body loop stopped
|
||||
text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
|
||||
}
|
||||
|
||||
/// Return the last index matching the byte `a` in `text`.
|
||||
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
|
||||
// Scan for a single byte value by reading two `usize` words at a time.
|
||||
//
|
||||
// Split `text` in three parts
|
||||
// - unaligned tail, after the last word aligned address in text
|
||||
// - body, scan by 2 words at a time
|
||||
// - the first remaining bytes, < 2 word size
|
||||
let len = text.len();
|
||||
let ptr = text.as_ptr();
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
|
||||
// search to an aligned boundary
|
||||
let end_align = (ptr as usize + len) & (usize_bytes - 1);
|
||||
let mut offset;
|
||||
if end_align > 0 {
|
||||
offset = if end_align >= len { 0 } else { len - end_align };
|
||||
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
|
||||
return Some(offset + index);
|
||||
}
|
||||
} else {
|
||||
offset = len;
|
||||
}
|
||||
|
||||
// search the body of the text
|
||||
let repeated_x = repeat_byte(x);
|
||||
|
||||
while offset >= 2 * usize_bytes {
|
||||
unsafe {
|
||||
let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
|
||||
let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
|
||||
|
||||
// break if there is a matching byte
|
||||
let zu = contains_zero_byte(u ^ repeated_x);
|
||||
let zv = contains_zero_byte(v ^ repeated_x);
|
||||
if zu || zv {
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset -= 2 * usize_bytes;
|
||||
}
|
||||
|
||||
// find the byte before the point the body loop stopped
|
||||
text[..offset].iter().rposition(|elt| *elt == x)
|
||||
}
|
||||
|
||||
// test fallback implementations on all platforms
|
||||
#[test]
|
||||
fn matches_one() {
|
||||
assert_eq!(Some(0), memchr(b'a', b"a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_begin() {
|
||||
assert_eq!(Some(0), memchr(b'a', b"aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_end() {
|
||||
assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_nul() {
|
||||
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_past_nul() {
|
||||
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_empty() {
|
||||
assert_eq!(None, memchr(b'a', b""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match() {
|
||||
assert_eq!(None, memchr(b'a', b"xyz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_one_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'a', b"a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_begin_reversed() {
|
||||
assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_end_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_nul_reversed() {
|
||||
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_past_nul_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_empty_reversed() {
|
||||
assert_eq!(None, memrchr(b'a', b""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_reversed() {
|
||||
assert_eq!(None, memrchr(b'a', b"xyz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn each_alignment_reversed() {
|
||||
let mut data = [1u8; 64];
|
||||
let needle = 2;
|
||||
let pos = 40;
|
||||
data[pos] = needle;
|
||||
for start in 0..16 {
|
||||
assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
|
||||
}
|
||||
}
|
||||
::sys::memchr::memrchr(needle, haystack)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -31,7 +31,7 @@ mod addr;
|
||||
mod tcp;
|
||||
mod udp;
|
||||
mod parser;
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// Possible values which can be passed to the [`shutdown`] method of
|
||||
|
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(dead_code)] // not used on emscripten
|
||||
|
||||
use env;
|
||||
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
||||
use sync::atomic::{AtomicUsize, Ordering};
|
||||
|
@ -113,7 +113,7 @@ use ops::{self, Deref};
|
||||
|
||||
use ffi::{OsStr, OsString};
|
||||
|
||||
use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
|
||||
use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GENERAL NOTES
|
||||
@ -125,130 +125,6 @@ use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
|
||||
// OsStr APIs for parsing, but it will take a while for those to become
|
||||
// available.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Platform-specific definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The following modules give the most basic tools for parsing paths on various
|
||||
// platforms. The bulk of the code is devoted to parsing prefixes on Windows.
|
||||
|
||||
#[cfg(unix)]
|
||||
mod platform {
|
||||
use super::Prefix;
|
||||
use ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
|
||||
None
|
||||
}
|
||||
|
||||
pub const MAIN_SEP_STR: &'static str = "/";
|
||||
pub const MAIN_SEP: char = '/';
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod platform {
|
||||
use ascii::*;
|
||||
|
||||
use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix};
|
||||
use ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/' || b == b'\\'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'\\'
|
||||
}
|
||||
|
||||
pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
|
||||
use super::Prefix::*;
|
||||
unsafe {
|
||||
// The unsafety here stems from converting between &OsStr and &[u8]
|
||||
// and back. This is safe to do because (1) we only look at ASCII
|
||||
// contents of the encoding and (2) new &OsStr values are produced
|
||||
// only from ASCII-bounded slices of existing &OsStr values.
|
||||
let mut path = os_str_as_u8_slice(path);
|
||||
|
||||
if path.starts_with(br"\\") {
|
||||
// \\
|
||||
path = &path[2..];
|
||||
if path.starts_with(br"?\") {
|
||||
// \\?\
|
||||
path = &path[2..];
|
||||
if path.starts_with(br"UNC\") {
|
||||
// \\?\UNC\server\share
|
||||
path = &path[4..];
|
||||
let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
|
||||
Some((server, share)) =>
|
||||
(u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
|
||||
None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
|
||||
};
|
||||
return Some(VerbatimUNC(server, share));
|
||||
} else {
|
||||
// \\?\path
|
||||
let idx = path.iter().position(|&b| b == b'\\');
|
||||
if idx == Some(2) && path[1] == b':' {
|
||||
let c = path[0];
|
||||
if c.is_ascii() && (c as char).is_alphabetic() {
|
||||
// \\?\C:\ path
|
||||
return Some(VerbatimDisk(c.to_ascii_uppercase()));
|
||||
}
|
||||
}
|
||||
let slice = &path[..idx.unwrap_or(path.len())];
|
||||
return Some(Verbatim(u8_slice_as_os_str(slice)));
|
||||
}
|
||||
} else if path.starts_with(b".\\") {
|
||||
// \\.\path
|
||||
path = &path[2..];
|
||||
let pos = path.iter().position(|&b| b == b'\\');
|
||||
let slice = &path[..pos.unwrap_or(path.len())];
|
||||
return Some(DeviceNS(u8_slice_as_os_str(slice)));
|
||||
}
|
||||
match parse_two_comps(path, is_sep_byte) {
|
||||
Some((server, share)) if !server.is_empty() && !share.is_empty() => {
|
||||
// \\server\share
|
||||
return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else if path.get(1) == Some(& b':') {
|
||||
// C:
|
||||
let c = path[0];
|
||||
if c.is_ascii() && (c as char).is_alphabetic() {
|
||||
return Some(Disk(c.to_ascii_uppercase()));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
|
||||
let first = match path.iter().position(|x| f(*x)) {
|
||||
None => return None,
|
||||
Some(x) => &path[..x],
|
||||
};
|
||||
path = &path[(first.len() + 1)..];
|
||||
let idx = path.iter().position(|x| f(*x));
|
||||
let second = &path[..idx.unwrap_or(path.len())];
|
||||
Some((first, second))
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAIN_SEP_STR: &'static str = "\\";
|
||||
pub const MAIN_SEP: char = '\\';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Windows Prefixes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -373,7 +249,7 @@ pub fn is_separator(c: char) -> bool {
|
||||
|
||||
/// The primary separator for the current platform
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MAIN_SEPARATOR: char = platform::MAIN_SEP;
|
||||
pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Misc helpers
|
||||
|
@ -51,7 +51,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
|
||||
thread_info::set(main_guard, thread);
|
||||
|
||||
// Store our args if necessary in a squirreled away location
|
||||
sys_common::args::init(argc, argv);
|
||||
sys::args::init(argc, argv);
|
||||
|
||||
// Let's run some code!
|
||||
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
|
||||
|
@ -366,8 +366,8 @@ impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
mod tests {
|
||||
use thread;
|
||||
use sync::mpsc::*;
|
||||
|
@ -1,100 +0,0 @@
|
||||
// Copyright 2012-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.
|
||||
|
||||
//! Global storage for command line arguments
|
||||
//!
|
||||
//! The current incarnation of the Rust runtime expects for
|
||||
//! the processes `argc` and `argv` arguments to be stored
|
||||
//! in a globally-accessible location for use by the `os` module.
|
||||
//!
|
||||
//! Only valid to call on Linux. Mac and Windows use syscalls to
|
||||
//! discover the command line arguments.
|
||||
//!
|
||||
//! FIXME #7756: Would be nice for this to not exist.
|
||||
|
||||
#![allow(dead_code)] // different code on OSX/linux/etc
|
||||
|
||||
/// One-time global initialization.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
|
||||
|
||||
/// One-time global cleanup.
|
||||
pub unsafe fn cleanup() { imp::cleanup() }
|
||||
|
||||
/// Make a clone of the global arguments.
|
||||
pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "bitrig",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku"))]
|
||||
mod imp {
|
||||
use libc::c_char;
|
||||
use mem;
|
||||
use ffi::CStr;
|
||||
|
||||
use sys_common::mutex::Mutex;
|
||||
|
||||
static mut GLOBAL_ARGS_PTR: usize = 0;
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
let args = (0..argc).map(|i| {
|
||||
CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
|
||||
}).collect();
|
||||
|
||||
LOCK.lock();
|
||||
let ptr = get_global_ptr();
|
||||
assert!((*ptr).is_none());
|
||||
(*ptr) = Some(box args);
|
||||
LOCK.unlock();
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup() {
|
||||
LOCK.lock();
|
||||
*get_global_ptr() = None;
|
||||
LOCK.unlock();
|
||||
}
|
||||
|
||||
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let ptr = get_global_ptr();
|
||||
let ret = (*ptr).as_ref().map(|s| (**s).clone());
|
||||
LOCK.unlock();
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
|
||||
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "windows"))]
|
||||
mod imp {
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
||||
}
|
||||
|
||||
pub fn cleanup() {
|
||||
}
|
||||
|
||||
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
||||
panic!()
|
||||
}
|
||||
}
|
@ -50,7 +50,8 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)] // not used on emscripten
|
||||
pub mod test {
|
||||
use path::{Path, PathBuf};
|
||||
use env;
|
||||
|
230
src/libstd/sys/common/memchr.rs
Normal file
230
src/libstd/sys/common/memchr.rs
Normal file
@ -0,0 +1,230 @@
|
||||
// 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.
|
||||
//
|
||||
// Original implementation taken from rust-memchr
|
||||
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod fallback {
|
||||
use cmp;
|
||||
use mem;
|
||||
|
||||
const LO_U64: u64 = 0x0101010101010101;
|
||||
const HI_U64: u64 = 0x8080808080808080;
|
||||
|
||||
// use truncation
|
||||
const LO_USIZE: usize = LO_U64 as usize;
|
||||
const HI_USIZE: usize = HI_U64 as usize;
|
||||
|
||||
/// Return `true` if `x` contains any zero byte.
|
||||
///
|
||||
/// From *Matters Computational*, J. Arndt
|
||||
///
|
||||
/// "The idea is to subtract one from each of the bytes and then look for
|
||||
/// bytes where the borrow propagated all the way to the most significant
|
||||
/// bit."
|
||||
#[inline]
|
||||
fn contains_zero_byte(x: usize) -> bool {
|
||||
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[inline]
|
||||
fn repeat_byte(b: u8) -> usize {
|
||||
let mut rep = (b as usize) << 8 | b as usize;
|
||||
rep = rep << 16 | rep;
|
||||
rep
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[inline]
|
||||
fn repeat_byte(b: u8) -> usize {
|
||||
let mut rep = (b as usize) << 8 | b as usize;
|
||||
rep = rep << 16 | rep;
|
||||
rep = rep << 32 | rep;
|
||||
rep
|
||||
}
|
||||
|
||||
/// Return the first index matching the byte `a` in `text`.
|
||||
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
|
||||
// Scan for a single byte value by reading two `usize` words at a time.
|
||||
//
|
||||
// Split `text` in three parts
|
||||
// - unaligned initial part, before the first word aligned address in text
|
||||
// - body, scan by 2 words at a time
|
||||
// - the last remaining part, < 2 word size
|
||||
let len = text.len();
|
||||
let ptr = text.as_ptr();
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
|
||||
// search up to an aligned boundary
|
||||
let align = (ptr as usize) & (usize_bytes- 1);
|
||||
let mut offset;
|
||||
if align > 0 {
|
||||
offset = cmp::min(usize_bytes - align, len);
|
||||
if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
|
||||
return Some(index);
|
||||
}
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// search the body of the text
|
||||
let repeated_x = repeat_byte(x);
|
||||
|
||||
if len >= 2 * usize_bytes {
|
||||
while offset <= len - 2 * usize_bytes {
|
||||
unsafe {
|
||||
let u = *(ptr.offset(offset as isize) as *const usize);
|
||||
let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
|
||||
|
||||
// break if there is a matching byte
|
||||
let zu = contains_zero_byte(u ^ repeated_x);
|
||||
let zv = contains_zero_byte(v ^ repeated_x);
|
||||
if zu || zv {
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset += usize_bytes * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// find the byte after the point the body loop stopped
|
||||
text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
|
||||
}
|
||||
|
||||
/// Return the last index matching the byte `a` in `text`.
|
||||
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
|
||||
// Scan for a single byte value by reading two `usize` words at a time.
|
||||
//
|
||||
// Split `text` in three parts
|
||||
// - unaligned tail, after the last word aligned address in text
|
||||
// - body, scan by 2 words at a time
|
||||
// - the first remaining bytes, < 2 word size
|
||||
let len = text.len();
|
||||
let ptr = text.as_ptr();
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
|
||||
// search to an aligned boundary
|
||||
let end_align = (ptr as usize + len) & (usize_bytes - 1);
|
||||
let mut offset;
|
||||
if end_align > 0 {
|
||||
offset = if end_align >= len { 0 } else { len - end_align };
|
||||
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
|
||||
return Some(offset + index);
|
||||
}
|
||||
} else {
|
||||
offset = len;
|
||||
}
|
||||
|
||||
// search the body of the text
|
||||
let repeated_x = repeat_byte(x);
|
||||
|
||||
while offset >= 2 * usize_bytes {
|
||||
unsafe {
|
||||
let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
|
||||
let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
|
||||
|
||||
// break if there is a matching byte
|
||||
let zu = contains_zero_byte(u ^ repeated_x);
|
||||
let zv = contains_zero_byte(v ^ repeated_x);
|
||||
if zu || zv {
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset -= 2 * usize_bytes;
|
||||
}
|
||||
|
||||
// find the byte before the point the body loop stopped
|
||||
text[..offset].iter().rposition(|elt| *elt == x)
|
||||
}
|
||||
|
||||
// test fallback implementations on all platforms
|
||||
#[test]
|
||||
fn matches_one() {
|
||||
assert_eq!(Some(0), memchr(b'a', b"a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_begin() {
|
||||
assert_eq!(Some(0), memchr(b'a', b"aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_end() {
|
||||
assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_nul() {
|
||||
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_past_nul() {
|
||||
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_empty() {
|
||||
assert_eq!(None, memchr(b'a', b""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match() {
|
||||
assert_eq!(None, memchr(b'a', b"xyz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_one_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'a', b"a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_begin_reversed() {
|
||||
assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_end_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_nul_reversed() {
|
||||
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_past_nul_reversed() {
|
||||
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_empty_reversed() {
|
||||
assert_eq!(None, memrchr(b'a', b""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_reversed() {
|
||||
assert_eq!(None, memrchr(b'a', b"xyz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn each_alignment_reversed() {
|
||||
let mut data = [1u8; 64];
|
||||
let needle = 2;
|
||||
let pos = 40;
|
||||
data[pos] = needle;
|
||||
for start in 0..16 {
|
||||
assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
|
||||
}
|
||||
}
|
||||
}
|
@ -25,12 +25,12 @@ macro_rules! rtassert {
|
||||
})
|
||||
}
|
||||
|
||||
pub mod args;
|
||||
pub mod at_exit_imp;
|
||||
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
||||
pub mod backtrace;
|
||||
pub mod condvar;
|
||||
pub mod io;
|
||||
pub mod memchr;
|
||||
pub mod mutex;
|
||||
pub mod net;
|
||||
pub mod poison;
|
||||
@ -91,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
|
||||
pub fn cleanup() {
|
||||
static CLEANUP: Once = Once::new();
|
||||
CLEANUP.call_once(|| unsafe {
|
||||
args::cleanup();
|
||||
sys::args::cleanup();
|
||||
sys::stack_overflow::cleanup();
|
||||
at_exit_imp::cleanup();
|
||||
});
|
||||
|
211
src/libstd/sys/unix/args.rs
Normal file
211
src/libstd/sys/unix/args.rs
Normal file
@ -0,0 +1,211 @@
|
||||
// Copyright 2012-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.
|
||||
|
||||
//! Global initialization and retreival of command line arguments.
|
||||
//!
|
||||
//! On some platforms these are stored during runtime startup,
|
||||
//! and on some they are retrieved from the system on demand.
|
||||
|
||||
#![allow(dead_code)] // runtime init functions not used during testing
|
||||
|
||||
use ffi::OsString;
|
||||
use marker::PhantomData;
|
||||
use vec;
|
||||
|
||||
/// One-time global initialization.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
|
||||
|
||||
/// One-time global cleanup.
|
||||
pub unsafe fn cleanup() { imp::cleanup() }
|
||||
|
||||
/// Returns the command line arguments
|
||||
pub fn args() -> Args {
|
||||
imp::args()
|
||||
}
|
||||
|
||||
pub struct Args {
|
||||
iter: vec::IntoIter<OsString>,
|
||||
_dont_send_or_sync_me: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
fn next(&mut self) -> Option<OsString> { self.iter.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize { self.iter.len() }
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "bitrig",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku"))]
|
||||
mod imp {
|
||||
use os::unix::prelude::*;
|
||||
use mem;
|
||||
use ffi::{CStr, OsString};
|
||||
use marker::PhantomData;
|
||||
use libc;
|
||||
use super::Args;
|
||||
|
||||
use sys_common::mutex::Mutex;
|
||||
|
||||
static mut GLOBAL_ARGS_PTR: usize = 0;
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
let args = (0..argc).map(|i| {
|
||||
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
|
||||
}).collect();
|
||||
|
||||
LOCK.lock();
|
||||
let ptr = get_global_ptr();
|
||||
assert!((*ptr).is_none());
|
||||
(*ptr) = Some(box args);
|
||||
LOCK.unlock();
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup() {
|
||||
LOCK.lock();
|
||||
*get_global_ptr() = None;
|
||||
LOCK.unlock();
|
||||
}
|
||||
|
||||
pub fn args() -> Args {
|
||||
let bytes = clone().unwrap_or(Vec::new());
|
||||
let v: Vec<OsString> = bytes.into_iter().map(|v| {
|
||||
OsStringExt::from_vec(v)
|
||||
}).collect();
|
||||
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
|
||||
}
|
||||
|
||||
fn clone() -> Option<Vec<Vec<u8>>> {
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let ptr = get_global_ptr();
|
||||
let ret = (*ptr).as_ref().map(|s| (**s).clone());
|
||||
LOCK.unlock();
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
|
||||
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios"))]
|
||||
mod imp {
|
||||
use ffi::CStr;
|
||||
use marker::PhantomData;
|
||||
use libc;
|
||||
use super::Args;
|
||||
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
||||
}
|
||||
|
||||
pub fn cleanup() {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn args() -> Args {
|
||||
use os::unix::prelude::*;
|
||||
extern {
|
||||
// These functions are in crt_externs.h.
|
||||
fn _NSGetArgc() -> *mut libc::c_int;
|
||||
fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
|
||||
}
|
||||
|
||||
let vec = unsafe {
|
||||
let (argc, argv) = (*_NSGetArgc() as isize,
|
||||
*_NSGetArgv() as *const *const libc::c_char);
|
||||
(0.. argc as isize).map(|i| {
|
||||
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
|
||||
OsStringExt::from_vec(bytes)
|
||||
}).collect::<Vec<_>>()
|
||||
};
|
||||
Args {
|
||||
iter: vec.into_iter(),
|
||||
_dont_send_or_sync_me: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
|
||||
// and use underscores in their names - they're most probably
|
||||
// are considered private and therefore should be avoided
|
||||
// Here is another way to get arguments using Objective C
|
||||
// runtime
|
||||
//
|
||||
// In general it looks like:
|
||||
// res = Vec::new()
|
||||
// let args = [[NSProcessInfo processInfo] arguments]
|
||||
// for i in (0..[args count])
|
||||
// res.push([args objectAtIndex:i])
|
||||
// res
|
||||
#[cfg(target_os = "ios")]
|
||||
pub fn args() -> Args {
|
||||
use ffi::OsString;
|
||||
use mem;
|
||||
use str;
|
||||
|
||||
extern {
|
||||
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
|
||||
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
|
||||
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
|
||||
}
|
||||
|
||||
#[link(name = "Foundation", kind = "framework")]
|
||||
#[link(name = "objc")]
|
||||
#[cfg(not(cargobuild))]
|
||||
extern {}
|
||||
|
||||
type Sel = *const libc::c_void;
|
||||
type NsId = *const libc::c_void;
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
unsafe {
|
||||
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
|
||||
let arguments_sel = sel_registerName("arguments\0".as_ptr());
|
||||
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
|
||||
let count_sel = sel_registerName("count\0".as_ptr());
|
||||
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
|
||||
|
||||
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
|
||||
let info = objc_msgSend(klass, process_info_sel);
|
||||
let args = objc_msgSend(info, arguments_sel);
|
||||
|
||||
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
|
||||
for i in 0..cnt {
|
||||
let tmp = objc_msgSend(args, object_at_sel, i);
|
||||
let utf_c_str: *const libc::c_char =
|
||||
mem::transmute(objc_msgSend(tmp, utf8_sel));
|
||||
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
|
||||
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
|
||||
}
|
||||
}
|
173
src/libstd/sys/unix/env.rs
Normal file
173
src/libstd/sys/unix/env.rs
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright 2012-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.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "linux";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "macos";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".dylib";
|
||||
pub const DLL_EXTENSION: &'static str = "dylib";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "ios";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".dylib";
|
||||
pub const DLL_EXTENSION: &'static str = "dylib";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "freebsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "dragonfly";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "bitrig")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "bitrig";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "netbsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "openbsd";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "android";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "solaris")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "solaris";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "nacl";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".nexe";
|
||||
pub const EXE_EXTENSION: &'static str = "nexe";
|
||||
}
|
||||
#[cfg(all(target_os = "nacl", target_arch = "le32"))]
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "pnacl";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".pso";
|
||||
pub const DLL_EXTENSION: &'static str = "pso";
|
||||
pub const EXE_SUFFIX: &'static str = ".pexe";
|
||||
pub const EXE_EXTENSION: &'static str = "pexe";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "haiku";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = "";
|
||||
pub const EXE_EXTENSION: &'static str = "";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".js";
|
||||
pub const EXE_EXTENSION: &'static str = "js";
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
|
||||
mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
pub const DLL_SUFFIX: &'static str = ".so";
|
||||
pub const DLL_EXTENSION: &'static str = "so";
|
||||
pub const EXE_SUFFIX: &'static str = ".js";
|
||||
pub const EXE_EXTENSION: &'static str = "js";
|
||||
}
|
57
src/libstd/sys/unix/memchr.rs
Normal file
57
src/libstd/sys/unix/memchr.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// 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.
|
||||
//
|
||||
// Original implementation taken from rust-memchr
|
||||
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||
|
||||
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
use libc;
|
||||
|
||||
let p = unsafe {
|
||||
libc::memchr(
|
||||
haystack.as_ptr() as *const libc::c_void,
|
||||
needle as libc::c_int,
|
||||
haystack.len() as libc::size_t)
|
||||
};
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p as usize - (haystack.as_ptr() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
use libc;
|
||||
|
||||
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
|
||||
if haystack.is_empty() {return None}
|
||||
let p = unsafe {
|
||||
libc::memrchr(
|
||||
haystack.as_ptr() as *const libc::c_void,
|
||||
needle as libc::c_int,
|
||||
haystack.len() as libc::size_t)
|
||||
};
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p as usize - (haystack.as_ptr() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
::sys_common::memchr::fallback::memrchr(needle, haystack)
|
||||
}
|
||||
|
||||
memrchr_specific(needle, haystack)
|
||||
}
|
@ -30,17 +30,21 @@ use libc;
|
||||
#[macro_use]
|
||||
pub mod weak;
|
||||
|
||||
pub mod args;
|
||||
pub mod android;
|
||||
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
||||
pub mod backtrace;
|
||||
pub mod condvar;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
pub mod memchr;
|
||||
pub mod mutex;
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
pub mod os_str;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
|
@ -347,126 +347,6 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Args {
|
||||
iter: vec::IntoIter<OsString>,
|
||||
_dont_send_or_sync_me: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
fn next(&mut self) -> Option<OsString> { self.iter.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize { self.iter.len() }
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
/// Returns the command line arguments
|
||||
///
|
||||
/// Returns a list of the command line arguments.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn args() -> Args {
|
||||
extern {
|
||||
// These functions are in crt_externs.h.
|
||||
fn _NSGetArgc() -> *mut c_int;
|
||||
fn _NSGetArgv() -> *mut *mut *mut c_char;
|
||||
}
|
||||
|
||||
let vec = unsafe {
|
||||
let (argc, argv) = (*_NSGetArgc() as isize,
|
||||
*_NSGetArgv() as *const *const c_char);
|
||||
(0.. argc as isize).map(|i| {
|
||||
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
|
||||
OsStringExt::from_vec(bytes)
|
||||
}).collect::<Vec<_>>()
|
||||
};
|
||||
Args {
|
||||
iter: vec.into_iter(),
|
||||
_dont_send_or_sync_me: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
|
||||
// and use underscores in their names - they're most probably
|
||||
// are considered private and therefore should be avoided
|
||||
// Here is another way to get arguments using Objective C
|
||||
// runtime
|
||||
//
|
||||
// In general it looks like:
|
||||
// res = Vec::new()
|
||||
// let args = [[NSProcessInfo processInfo] arguments]
|
||||
// for i in (0..[args count])
|
||||
// res.push([args objectAtIndex:i])
|
||||
// res
|
||||
#[cfg(target_os = "ios")]
|
||||
pub fn args() -> Args {
|
||||
use mem;
|
||||
|
||||
extern {
|
||||
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
|
||||
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
|
||||
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
|
||||
}
|
||||
|
||||
#[link(name = "Foundation", kind = "framework")]
|
||||
#[link(name = "objc")]
|
||||
#[cfg(not(cargobuild))]
|
||||
extern {}
|
||||
|
||||
type Sel = *const libc::c_void;
|
||||
type NsId = *const libc::c_void;
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
unsafe {
|
||||
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
|
||||
let arguments_sel = sel_registerName("arguments\0".as_ptr());
|
||||
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
|
||||
let count_sel = sel_registerName("count\0".as_ptr());
|
||||
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
|
||||
|
||||
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
|
||||
let info = objc_msgSend(klass, process_info_sel);
|
||||
let args = objc_msgSend(info, arguments_sel);
|
||||
|
||||
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
|
||||
for i in 0..cnt {
|
||||
let tmp = objc_msgSend(args, object_at_sel, i);
|
||||
let utf_c_str: *const libc::c_char =
|
||||
mem::transmute(objc_msgSend(tmp, utf8_sel));
|
||||
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
|
||||
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "bitrig",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "nacl",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku"))]
|
||||
pub fn args() -> Args {
|
||||
use sys_common;
|
||||
let bytes = sys_common::args::clone().unwrap_or(Vec::new());
|
||||
let v: Vec<OsString> = bytes.into_iter().map(|v| {
|
||||
OsStringExt::from_vec(v)
|
||||
}).collect();
|
||||
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
|
||||
}
|
||||
|
||||
pub struct Env {
|
||||
iter: vec::IntoIter<(OsString, OsString)>,
|
||||
_dont_send_or_sync_me: PhantomData<*mut ()>,
|
||||
|
29
src/libstd/sys/unix/path.rs
Normal file
29
src/libstd/sys/unix/path.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
use path::Prefix;
|
||||
use ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
|
||||
pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
|
||||
None
|
||||
}
|
||||
|
||||
pub const MAIN_SEP_STR: &'static str = "/";
|
||||
pub const MAIN_SEP: char = '/';
|
@ -65,3 +65,5 @@ impl io::Write for Stderr {
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
|
||||
|
76
src/libstd/sys/windows/args.rs
Normal file
76
src/libstd/sys/windows/args.rs
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2012-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.
|
||||
|
||||
#![allow(dead_code)] // runtime init functions not used during testing
|
||||
|
||||
use os::windows::prelude::*;
|
||||
use sys::c;
|
||||
use slice;
|
||||
use ops::Range;
|
||||
use ffi::OsString;
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }
|
||||
|
||||
pub unsafe fn cleanup() { }
|
||||
|
||||
pub fn args() -> Args {
|
||||
unsafe {
|
||||
let mut nArgs: c_int = 0;
|
||||
let lpCmdLine = c::GetCommandLineW();
|
||||
let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
|
||||
|
||||
// szArcList can be NULL if CommandLinToArgvW failed,
|
||||
// but in that case nArgs is 0 so we won't actually
|
||||
// try to read a null pointer
|
||||
Args { cur: szArgList, range: 0..(nArgs as isize) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Args {
|
||||
range: Range<isize>,
|
||||
cur: *mut *mut u16,
|
||||
}
|
||||
|
||||
unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
|
||||
let mut len = 0;
|
||||
while *ptr.offset(len) != 0 { len += 1; }
|
||||
|
||||
// Push it onto the list.
|
||||
let ptr = ptr as *const u16;
|
||||
let buf = slice::from_raw_parts(ptr, len as usize);
|
||||
OsStringExt::from_wide(buf)
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
fn next(&mut self) -> Option<OsString> {
|
||||
self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<OsString> {
|
||||
self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize { self.range.len() }
|
||||
}
|
||||
|
||||
impl Drop for Args {
|
||||
fn drop(&mut self) {
|
||||
// self.cur can be null if CommandLineToArgvW previously failed,
|
||||
// but LocalFree ignores NULL pointers
|
||||
unsafe { c::LocalFree(self.cur as *mut c_void); }
|
||||
}
|
||||
}
|
19
src/libstd/sys/windows/env.rs
Normal file
19
src/libstd/sys/windows/env.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2012-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.
|
||||
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "windows";
|
||||
pub const OS: &'static str = "windows";
|
||||
pub const DLL_PREFIX: &'static str = "";
|
||||
pub const DLL_SUFFIX: &'static str = ".dll";
|
||||
pub const DLL_EXTENSION: &'static str = "dll";
|
||||
pub const EXE_SUFFIX: &'static str = ".exe";
|
||||
pub const EXE_EXTENSION: &'static str = "exe";
|
||||
}
|
15
src/libstd/sys/windows/memchr.rs
Normal file
15
src/libstd/sys/windows/memchr.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// 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.
|
||||
//
|
||||
// Original implementation taken from rust-memchr
|
||||
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||
|
||||
// Fallback memchr is fastest on windows
|
||||
pub use sys_common::memchr::fallback::{memchr, memrchr};
|
@ -18,17 +18,21 @@ use time::Duration;
|
||||
|
||||
#[macro_use] pub mod compat;
|
||||
|
||||
pub mod args;
|
||||
pub mod backtrace;
|
||||
pub mod c;
|
||||
pub mod condvar;
|
||||
pub mod dynamic_lib;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fs;
|
||||
pub mod handle;
|
||||
pub mod memchr;
|
||||
pub mod mutex;
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
pub mod os_str;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
pub mod process;
|
||||
pub mod rand;
|
||||
|
@ -18,8 +18,6 @@ use error::Error as StdError;
|
||||
use ffi::{OsString, OsStr};
|
||||
use fmt;
|
||||
use io;
|
||||
use libc::{c_int, c_void};
|
||||
use ops::Range;
|
||||
use os::windows::ffi::EncodeWide;
|
||||
use path::{self, PathBuf};
|
||||
use ptr;
|
||||
@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
||||
}).map(|_| ())
|
||||
}
|
||||
|
||||
pub struct Args {
|
||||
range: Range<isize>,
|
||||
cur: *mut *mut u16,
|
||||
}
|
||||
|
||||
unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
|
||||
let mut len = 0;
|
||||
while *ptr.offset(len) != 0 { len += 1; }
|
||||
|
||||
// Push it onto the list.
|
||||
let ptr = ptr as *const u16;
|
||||
let buf = slice::from_raw_parts(ptr, len as usize);
|
||||
OsStringExt::from_wide(buf)
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
fn next(&mut self) -> Option<OsString> {
|
||||
self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<OsString> {
|
||||
self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize { self.range.len() }
|
||||
}
|
||||
|
||||
impl Drop for Args {
|
||||
fn drop(&mut self) {
|
||||
// self.cur can be null if CommandLineToArgvW previously failed,
|
||||
// but LocalFree ignores NULL pointers
|
||||
unsafe { c::LocalFree(self.cur as *mut c_void); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn args() -> Args {
|
||||
unsafe {
|
||||
let mut nArgs: c_int = 0;
|
||||
let lpCmdLine = c::GetCommandLineW();
|
||||
let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
|
||||
|
||||
// szArcList can be NULL if CommandLinToArgvW failed,
|
||||
// but in that case nArgs is 0 so we won't actually
|
||||
// try to read a null pointer
|
||||
Args { cur: szArgList, range: 0..(nArgs as isize) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
super::fill_utf16_buf(|buf, sz| unsafe {
|
||||
c::GetTempPathW(sz, buf)
|
||||
|
108
src/libstd/sys/windows/path.rs
Normal file
108
src/libstd/sys/windows/path.rs
Normal file
@ -0,0 +1,108 @@
|
||||
// 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.
|
||||
|
||||
use ascii::*;
|
||||
|
||||
use path::Prefix;
|
||||
use ffi::OsStr;
|
||||
use mem;
|
||||
|
||||
fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
|
||||
unsafe { mem::transmute(s) }
|
||||
}
|
||||
unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
|
||||
mem::transmute(s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/' || b == b'\\'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'\\'
|
||||
}
|
||||
|
||||
pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
|
||||
use path::Prefix::*;
|
||||
unsafe {
|
||||
// The unsafety here stems from converting between &OsStr and &[u8]
|
||||
// and back. This is safe to do because (1) we only look at ASCII
|
||||
// contents of the encoding and (2) new &OsStr values are produced
|
||||
// only from ASCII-bounded slices of existing &OsStr values.
|
||||
let mut path = os_str_as_u8_slice(path);
|
||||
|
||||
if path.starts_with(br"\\") {
|
||||
// \\
|
||||
path = &path[2..];
|
||||
if path.starts_with(br"?\") {
|
||||
// \\?\
|
||||
path = &path[2..];
|
||||
if path.starts_with(br"UNC\") {
|
||||
// \\?\UNC\server\share
|
||||
path = &path[4..];
|
||||
let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
|
||||
Some((server, share)) =>
|
||||
(u8_slice_as_os_str(server), u8_slice_as_os_str(share)),
|
||||
None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
|
||||
};
|
||||
return Some(VerbatimUNC(server, share));
|
||||
} else {
|
||||
// \\?\path
|
||||
let idx = path.iter().position(|&b| b == b'\\');
|
||||
if idx == Some(2) && path[1] == b':' {
|
||||
let c = path[0];
|
||||
if c.is_ascii() && (c as char).is_alphabetic() {
|
||||
// \\?\C:\ path
|
||||
return Some(VerbatimDisk(c.to_ascii_uppercase()));
|
||||
}
|
||||
}
|
||||
let slice = &path[..idx.unwrap_or(path.len())];
|
||||
return Some(Verbatim(u8_slice_as_os_str(slice)));
|
||||
}
|
||||
} else if path.starts_with(b".\\") {
|
||||
// \\.\path
|
||||
path = &path[2..];
|
||||
let pos = path.iter().position(|&b| b == b'\\');
|
||||
let slice = &path[..pos.unwrap_or(path.len())];
|
||||
return Some(DeviceNS(u8_slice_as_os_str(slice)));
|
||||
}
|
||||
match parse_two_comps(path, is_sep_byte) {
|
||||
Some((server, share)) if !server.is_empty() && !share.is_empty() => {
|
||||
// \\server\share
|
||||
return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else if path.get(1) == Some(& b':') {
|
||||
// C:
|
||||
let c = path[0];
|
||||
if c.is_ascii() && (c as char).is_alphabetic() {
|
||||
return Some(Disk(c.to_ascii_uppercase()));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
|
||||
let first = match path.iter().position(|x| f(*x)) {
|
||||
None => return None,
|
||||
Some(x) => &path[..x],
|
||||
};
|
||||
path = &path[(first.len() + 1)..];
|
||||
let idx = path.iter().position(|x| f(*x));
|
||||
let second = &path[..idx.unwrap_or(path.len())];
|
||||
Some((first, second))
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAIN_SEP_STR: &'static str = "\\";
|
||||
pub const MAIN_SEP: char = '\\';
|
@ -205,3 +205,5 @@ impl Output {
|
||||
fn invalid_encoding() -> io::Error {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
|
||||
}
|
||||
|
||||
pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
|
||||
|
@ -36,6 +36,7 @@ mod errors;
|
||||
mod features;
|
||||
mod cargo;
|
||||
mod cargo_lock;
|
||||
mod pal;
|
||||
|
||||
fn main() {
|
||||
let path = env::args_os().skip(1).next().expect("need an argument");
|
||||
@ -48,6 +49,7 @@ fn main() {
|
||||
cargo::check(&path, &mut bad);
|
||||
features::check(&path, &mut bad);
|
||||
cargo_lock::check(&path, &mut bad);
|
||||
pal::check(&path, &mut bad);
|
||||
|
||||
if bad {
|
||||
panic!("some tidy checks failed");
|
||||
|
230
src/tools/tidy/src/pal.rs
Normal file
230
src/tools/tidy/src/pal.rs
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
//! Tidy check to enforce rules about platform-specific code in std
|
||||
//!
|
||||
//! This is intended to maintain existing standards of code
|
||||
//! organization in hopes that the standard library will continue to
|
||||
//! be refactored to isolate platform-specific bits, making porting
|
||||
//! easier; where "standard library" roughly means "all the
|
||||
//! dependencies of the std and test crates".
|
||||
//!
|
||||
//! This generally means placing restrictions on where `cfg(unix)`,
|
||||
//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear,
|
||||
//! the basic objective being to isolate platform-specific code to the
|
||||
//! platform-specific `std::sys` modules, and to the allocation,
|
||||
//! unwinding, and libc crates.
|
||||
//!
|
||||
//! Following are the basic rules, though there are currently
|
||||
//! exceptions:
|
||||
//!
|
||||
//! - core may not have platform-specific code
|
||||
//! - liballoc_system may have platform-specific code
|
||||
//! - liballoc_jemalloc may have platform-specific code
|
||||
//! - libpanic_abort may have platform-specific code
|
||||
//! - libpanic_unwind may have platform-specific code
|
||||
//! - libunwind may have platform-specific code
|
||||
//! - other crates in the std facade may not
|
||||
//! - std may have platform-specific code in the following places
|
||||
//! - sys/unix/
|
||||
//! - sys/windows/
|
||||
//! - os/
|
||||
//!
|
||||
//! `std/sys_common` should _not_ contain platform-specific code.
|
||||
//! Finally, because std contains tests with platform-specific
|
||||
//! `ignore` attributes, once the parser encounters `mod tests`,
|
||||
//! platform-specific cfgs are allowed. Not sure yet how to deal with
|
||||
//! this in the long term.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::iter::Iterator;
|
||||
|
||||
// Paths that may contain platform-specific code
|
||||
const EXCEPTION_PATHS: &'static [&'static str] = &[
|
||||
// std crates
|
||||
"src/liballoc_jemalloc",
|
||||
"src/liballoc_system",
|
||||
"src/liblibc",
|
||||
"src/libpanic_abort",
|
||||
"src/libpanic_unwind",
|
||||
"src/libunwind",
|
||||
"src/libstd/sys/unix", // This is where platform-specific code for std should live
|
||||
"src/libstd/sys/windows", // Ditto
|
||||
"src/libstd/os", // Platform-specific public interfaces
|
||||
"src/rtstartup", // Not sure what to do about this. magic stuff for mingw
|
||||
|
||||
// temporary exceptions
|
||||
"src/libstd/lib.rs", // This could probably be done within the sys directory
|
||||
"src/libstd/rtdeps.rs", // Until rustbuild replaces make
|
||||
"src/libstd/path.rs",
|
||||
"src/libstd/io/stdio.rs",
|
||||
"src/libstd/num/f32.rs",
|
||||
"src/libstd/num/f64.rs",
|
||||
"src/libstd/thread/local.rs",
|
||||
"src/libstd/sys/common/mod.rs",
|
||||
"src/libstd/sys/common/net.rs",
|
||||
"src/libstd/sys/common/util.rs",
|
||||
"src/libterm", // Not sure how to make this crate portable, but test needs it
|
||||
"src/libtest", // Probably should defer to unstable std::sys APIs
|
||||
|
||||
// std testing crates, ok for now at least
|
||||
"src/libcoretest",
|
||||
|
||||
// non-std crates
|
||||
"src/test",
|
||||
"src/tools",
|
||||
"src/librustc",
|
||||
"src/librustdoc",
|
||||
"src/libsyntax",
|
||||
"src/bootstrap",
|
||||
];
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
let ref mut contents = String::new();
|
||||
// Sanity check that the complex parsing here works
|
||||
let ref mut saw_target_arch = false;
|
||||
let ref mut saw_cfg_bang = false;
|
||||
super::walk(path, &mut super::filter_dirs, &mut |file| {
|
||||
let filestr = file.to_string_lossy().replace("\\", "/");
|
||||
if !filestr.ends_with(".rs") { return }
|
||||
|
||||
let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
|
||||
if is_exception_path { return }
|
||||
|
||||
check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang);
|
||||
});
|
||||
|
||||
assert!(*saw_target_arch);
|
||||
assert!(*saw_cfg_bang);
|
||||
}
|
||||
|
||||
fn check_cfgs(contents: &mut String, file: &Path,
|
||||
bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
|
||||
contents.truncate(0);
|
||||
t!(t!(File::open(file), file).read_to_string(contents));
|
||||
|
||||
// For now it's ok to have platform-specific code after 'mod tests'.
|
||||
let mod_tests_idx = find_test_mod(contents);
|
||||
let contents = &contents[..mod_tests_idx];
|
||||
// Pull out all "cfg(...)" and "cfg!(...)" strings
|
||||
let cfgs = parse_cfgs(contents);
|
||||
|
||||
let mut line_numbers: Option<Vec<usize>> = None;
|
||||
let mut err = |idx: usize, cfg: &str| {
|
||||
if line_numbers.is_none() {
|
||||
line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect());
|
||||
}
|
||||
let line_numbers = line_numbers.as_ref().expect("");
|
||||
let line = match line_numbers.binary_search(&idx) {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(i) => i + 1
|
||||
};
|
||||
println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
|
||||
*bad = true;
|
||||
};
|
||||
|
||||
for (idx, cfg) in cfgs.into_iter() {
|
||||
// Sanity check that the parsing here works
|
||||
if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true }
|
||||
if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true }
|
||||
|
||||
let contains_platform_specific_cfg =
|
||||
cfg.contains("target_os")
|
||||
|| cfg.contains("target_env")
|
||||
|| cfg.contains("target_vendor")
|
||||
|| cfg.contains("unix")
|
||||
|| cfg.contains("windows");
|
||||
|
||||
if !contains_platform_specific_cfg { continue }
|
||||
|
||||
let preceeded_by_doc_comment = {
|
||||
let pre_contents = &contents[..idx];
|
||||
let pre_newline = pre_contents.rfind('\n');
|
||||
let pre_doc_comment = pre_contents.rfind("///");
|
||||
match (pre_newline, pre_doc_comment) {
|
||||
(Some(n), Some(c)) => n < c,
|
||||
(None, Some(_)) => true,
|
||||
(_, None) => false,
|
||||
}
|
||||
};
|
||||
|
||||
if preceeded_by_doc_comment { continue }
|
||||
|
||||
err(idx, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn find_test_mod(contents: &str) -> usize {
|
||||
if let Some(mod_tests_idx) = contents.find("mod tests") {
|
||||
// Also capture a previos line indicating "mod tests" in cfg-ed out
|
||||
let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
|
||||
let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
|
||||
if let Some(nl) = prev_newline_idx {
|
||||
let prev_line = &contents[nl + 1 .. mod_tests_idx];
|
||||
let emcc_cfg = "cfg(all(test, not(target_os";
|
||||
if prev_line.contains(emcc_cfg) {
|
||||
nl
|
||||
} else {
|
||||
mod_tests_idx
|
||||
}
|
||||
} else {
|
||||
mod_tests_idx
|
||||
}
|
||||
} else {
|
||||
contents.len()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> {
|
||||
let candidate_cfgs = contents.match_indices("cfg");
|
||||
let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i);
|
||||
// This is puling out the indexes of all "cfg" strings
|
||||
// that appear to be tokens succeeded by a paren.
|
||||
let cfgs = candidate_cfg_idxs.filter(|i| {
|
||||
let pre_idx = i.saturating_sub(*i);
|
||||
let succeeds_non_ident = !contents.as_bytes().get(pre_idx)
|
||||
.cloned()
|
||||
.map(char::from)
|
||||
.map(char::is_alphanumeric)
|
||||
.unwrap_or(false);
|
||||
let contents_after = &contents[*i..];
|
||||
let first_paren = contents_after.find('(');
|
||||
let paren_idx = first_paren.map(|ip| i + ip);
|
||||
let preceeds_whitespace_and_paren = paren_idx.map(|ip| {
|
||||
let maybe_space = &contents[*i + "cfg".len() .. ip];
|
||||
maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!')
|
||||
}).unwrap_or(false);
|
||||
|
||||
succeeds_non_ident && preceeds_whitespace_and_paren
|
||||
});
|
||||
|
||||
cfgs.map(|i| {
|
||||
let mut depth = 0;
|
||||
let contents_from = &contents[i..];
|
||||
for (j, byte) in contents_from.bytes().enumerate() {
|
||||
match byte {
|
||||
b'(' => {
|
||||
depth += 1;
|
||||
}
|
||||
b')' => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
return (i, &contents_from[.. j + 1]);
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}).collect()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user