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:
@@ -21,6 +21,7 @@ use ffi::{OsStr, OsString};
|
|||||||
use fmt;
|
use fmt;
|
||||||
use io;
|
use io;
|
||||||
use path::{Path, PathBuf};
|
use path::{Path, PathBuf};
|
||||||
|
use sys;
|
||||||
use sys::os as os_imp;
|
use sys::os as os_imp;
|
||||||
|
|
||||||
/// Returns the current working directory as a `PathBuf`.
|
/// 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.
|
/// This structure is created through the `std::env::args_os` method.
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Returns the arguments which this program was started with (normally passed
|
||||||
/// via the command line).
|
/// via the command line).
|
||||||
@@ -606,7 +607,7 @@ pub fn args() -> Args {
|
|||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[stable(feature = "env", since = "1.0.0")]
|
||||||
pub fn args_os() -> ArgsOs {
|
pub fn args_os() -> ArgsOs {
|
||||||
ArgsOs { inner: os_imp::args() }
|
ArgsOs { inner: sys::args::args() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[stable(feature = "env", since = "1.0.0")]
|
||||||
@@ -649,6 +650,8 @@ impl DoubleEndedIterator for ArgsOs {
|
|||||||
/// Constants associated with the current target
|
/// Constants associated with the current target
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[stable(feature = "env", since = "1.0.0")]
|
||||||
pub mod consts {
|
pub mod consts {
|
||||||
|
use sys::env::os;
|
||||||
|
|
||||||
/// A string describing the architecture of the CPU that is currently
|
/// A string describing the architecture of the CPU that is currently
|
||||||
/// in use.
|
/// in use.
|
||||||
///
|
///
|
||||||
@@ -673,7 +676,7 @@ pub mod consts {
|
|||||||
/// - unix
|
/// - unix
|
||||||
/// - windows
|
/// - windows
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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.
|
/// A string describing the specific operating system in use.
|
||||||
/// Example value is `linux`.
|
/// Example value is `linux`.
|
||||||
@@ -692,7 +695,7 @@ pub mod consts {
|
|||||||
/// - android
|
/// - android
|
||||||
/// - windows
|
/// - windows
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Specifies the filename prefix used for shared libraries on this
|
||||||
/// platform. Example value is `lib`.
|
/// platform. Example value is `lib`.
|
||||||
@@ -702,7 +705,7 @@ pub mod consts {
|
|||||||
/// - lib
|
/// - lib
|
||||||
/// - `""` (an empty string)
|
/// - `""` (an empty string)
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Specifies the filename suffix used for shared libraries on this
|
||||||
/// platform. Example value is `.so`.
|
/// platform. Example value is `.so`.
|
||||||
@@ -713,7 +716,7 @@ pub mod consts {
|
|||||||
/// - .dylib
|
/// - .dylib
|
||||||
/// - .dll
|
/// - .dll
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Specifies the file extension used for shared libraries on this
|
||||||
/// platform that goes after the dot. Example value is `so`.
|
/// platform that goes after the dot. Example value is `so`.
|
||||||
@@ -724,7 +727,7 @@ pub mod consts {
|
|||||||
/// - dylib
|
/// - dylib
|
||||||
/// - dll
|
/// - dll
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Specifies the filename suffix used for executable binaries on this
|
||||||
/// platform. Example value is `.exe`.
|
/// platform. Example value is `.exe`.
|
||||||
@@ -736,7 +739,7 @@ pub mod consts {
|
|||||||
/// - .pexe
|
/// - .pexe
|
||||||
/// - `""` (an empty string)
|
/// - `""` (an empty string)
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[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
|
/// Specifies the file extension, if any, used for executable binaries
|
||||||
/// on this platform. Example value is `exe`.
|
/// on this platform. Example value is `exe`.
|
||||||
@@ -746,183 +749,7 @@ pub mod consts {
|
|||||||
/// - exe
|
/// - exe
|
||||||
/// - `""` (an empty string)
|
/// - `""` (an empty string)
|
||||||
#[stable(feature = "env", since = "1.0.0")]
|
#[stable(feature = "env", since = "1.0.0")]
|
||||||
pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
|
pub const EXE_EXTENSION: &'static str = 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 = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
|
|||||||
@@ -53,17 +53,6 @@ impl OsString {
|
|||||||
OsString { inner: Buf::from_string(String::new()) }
|
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.
|
/// Converts to an `OsStr` slice.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn as_os_str(&self) -> &OsStr {
|
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> {
|
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
|
||||||
#[cfg(windows)]
|
use sys::stdio::EBADF_ERR;
|
||||||
const ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
const ERR: i32 = ::libc::EBADF as i32;
|
|
||||||
|
|
||||||
match r {
|
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
|
r => r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
// Original implementation taken from rust-memchr
|
// Original implementation taken from rust-memchr
|
||||||
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A safe interface to `memchr`.
|
/// A safe interface to `memchr`.
|
||||||
///
|
///
|
||||||
/// Returns the index corresponding to the first occurrence of `needle` in
|
/// Returns the index corresponding to the first occurrence of `needle` in
|
||||||
@@ -32,32 +30,9 @@
|
|||||||
/// let haystack = b"the quick brown fox";
|
/// let haystack = b"the quick brown fox";
|
||||||
/// assert_eq!(memchr(b'k', haystack), Some(8));
|
/// assert_eq!(memchr(b'k', haystack), Some(8));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[inline]
|
||||||
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||||
// libc memchr
|
::sys::memchr::memchr(needle, haystack)
|
||||||
#[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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A safe interface to `memrchr`.
|
/// 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";
|
/// let haystack = b"the quick brown fox";
|
||||||
/// assert_eq!(memrchr(b'o', haystack), Some(17));
|
/// assert_eq!(memrchr(b'o', haystack), Some(17));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[inline]
|
||||||
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||||
|
::sys::memchr::memrchr(needle, haystack)
|
||||||
#[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..]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ mod addr;
|
|||||||
mod tcp;
|
mod tcp;
|
||||||
mod udp;
|
mod udp;
|
||||||
mod parser;
|
mod parser;
|
||||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
/// Possible values which can be passed to the [`shutdown`] method of
|
/// 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
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[allow(dead_code)] // not used on emscripten
|
||||||
|
|
||||||
use env;
|
use env;
|
||||||
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
||||||
use sync::atomic::{AtomicUsize, Ordering};
|
use sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ use ops::{self, Deref};
|
|||||||
|
|
||||||
use ffi::{OsStr, OsString};
|
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
|
// 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
|
// OsStr APIs for parsing, but it will take a while for those to become
|
||||||
// available.
|
// 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
|
// Windows Prefixes
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -373,7 +249,7 @@ pub fn is_separator(c: char) -> bool {
|
|||||||
|
|
||||||
/// The primary separator for the current platform
|
/// The primary separator for the current platform
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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
|
// 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);
|
thread_info::set(main_guard, thread);
|
||||||
|
|
||||||
// Store our args if necessary in a squirreled away location
|
// 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's run some code!
|
||||||
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));
|
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)]
|
#[allow(unused_imports)]
|
||||||
|
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||||
mod tests {
|
mod tests {
|
||||||
use thread;
|
use thread;
|
||||||
use sync::mpsc::*;
|
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 {
|
pub mod test {
|
||||||
use path::{Path, PathBuf};
|
use path::{Path, PathBuf};
|
||||||
use env;
|
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;
|
pub mod at_exit_imp;
|
||||||
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
pub mod condvar;
|
pub mod condvar;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
pub mod memchr;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod poison;
|
pub mod poison;
|
||||||
@@ -91,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
|
|||||||
pub fn cleanup() {
|
pub fn cleanup() {
|
||||||
static CLEANUP: Once = Once::new();
|
static CLEANUP: Once = Once::new();
|
||||||
CLEANUP.call_once(|| unsafe {
|
CLEANUP.call_once(|| unsafe {
|
||||||
args::cleanup();
|
sys::args::cleanup();
|
||||||
sys::stack_overflow::cleanup();
|
sys::stack_overflow::cleanup();
|
||||||
at_exit_imp::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]
|
#[macro_use]
|
||||||
pub mod weak;
|
pub mod weak;
|
||||||
|
|
||||||
|
pub mod args;
|
||||||
pub mod android;
|
pub mod android;
|
||||||
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
pub mod condvar;
|
pub mod condvar;
|
||||||
|
pub mod env;
|
||||||
pub mod ext;
|
pub mod ext;
|
||||||
pub mod fd;
|
pub mod fd;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod memchr;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod os_str;
|
pub mod os_str;
|
||||||
|
pub mod path;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod rand;
|
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 {
|
pub struct Env {
|
||||||
iter: vec::IntoIter<(OsString, OsString)>,
|
iter: vec::IntoIter<(OsString, OsString)>,
|
||||||
_dont_send_or_sync_me: PhantomData<*mut ()>,
|
_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(()) }
|
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;
|
#[macro_use] pub mod compat;
|
||||||
|
|
||||||
|
pub mod args;
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
pub mod c;
|
pub mod c;
|
||||||
pub mod condvar;
|
pub mod condvar;
|
||||||
pub mod dynamic_lib;
|
pub mod dynamic_lib;
|
||||||
|
pub mod env;
|
||||||
pub mod ext;
|
pub mod ext;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
|
pub mod memchr;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod os_str;
|
pub mod os_str;
|
||||||
|
pub mod path;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod rand;
|
pub mod rand;
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ use error::Error as StdError;
|
|||||||
use ffi::{OsString, OsStr};
|
use ffi::{OsString, OsStr};
|
||||||
use fmt;
|
use fmt;
|
||||||
use io;
|
use io;
|
||||||
use libc::{c_int, c_void};
|
|
||||||
use ops::Range;
|
|
||||||
use os::windows::ffi::EncodeWide;
|
use os::windows::ffi::EncodeWide;
|
||||||
use path::{self, PathBuf};
|
use path::{self, PathBuf};
|
||||||
use ptr;
|
use ptr;
|
||||||
@@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
|||||||
}).map(|_| ())
|
}).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 {
|
pub fn temp_dir() -> PathBuf {
|
||||||
super::fill_utf16_buf(|buf, sz| unsafe {
|
super::fill_utf16_buf(|buf, sz| unsafe {
|
||||||
c::GetTempPathW(sz, buf)
|
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 {
|
fn invalid_encoding() -> io::Error {
|
||||||
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
|
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 features;
|
||||||
mod cargo;
|
mod cargo;
|
||||||
mod cargo_lock;
|
mod cargo_lock;
|
||||||
|
mod pal;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let path = env::args_os().skip(1).next().expect("need an argument");
|
let path = env::args_os().skip(1).next().expect("need an argument");
|
||||||
@@ -48,6 +49,7 @@ fn main() {
|
|||||||
cargo::check(&path, &mut bad);
|
cargo::check(&path, &mut bad);
|
||||||
features::check(&path, &mut bad);
|
features::check(&path, &mut bad);
|
||||||
cargo_lock::check(&path, &mut bad);
|
cargo_lock::check(&path, &mut bad);
|
||||||
|
pal::check(&path, &mut bad);
|
||||||
|
|
||||||
if bad {
|
if bad {
|
||||||
panic!("some tidy checks failed");
|
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()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user