#![allow(non_snake_case_functions)]
use clone::Clone;
-use collections::Collection;
+use collections::{Collection, MutableSeq};
use fmt;
use io::{IoResult, IoError};
use iter::Iterator;
use ptr::RawPtr;
use ptr;
use result::{Err, Ok, Result};
-use slice::{Vector, ImmutableVector, MutableVector};
+use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector};
use str::{Str, StrSlice, StrAllocating};
-use str;
use string::String;
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
use vec::Vec;
use c_str::ToCStr;
#[cfg(unix)]
use libc::c_char;
-#[cfg(windows)]
-use str::OwnedStr;
/// Get the number of cores available
pub fn num_cpus() -> uint {
fail!();
}
}
- Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
+ Path::new(String::from_utf16(::str::truncate_utf16_at_nul(buf))
.expect("GetCurrentDirectoryW returned invalid UTF-16"))
}
use slice::{MutableVector, ImmutableVector};
use string::String;
use str::StrSlice;
- use str;
use vec::Vec;
pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
// We want to explicitly catch the case when the
// closure returned invalid UTF-16, rather than
// set `res` to None and continue.
- let s = str::from_utf16(sub)
+ let s = String::from_utf16(sub)
.expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
res = option::Some(s)
}
/// Returns a vector of (variable, value) pairs, for all the environment
/// variables of the current process.
///
-/// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
+/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()`
/// for details.
///
/// # Example
/// ```
pub fn env() -> Vec<(String,String)> {
env_as_bytes().move_iter().map(|(k,v)| {
- let k = str::from_utf8_lossy(k.as_slice()).to_string();
- let v = str::from_utf8_lossy(v.as_slice()).to_string();
+ let k = String::from_utf8_lossy(k.as_slice()).into_string();
+ let v = String::from_utf8_lossy(v.as_slice()).into_string();
(k,v)
}).collect()
}
let p = &*ch.offset(i);
let len = ptr::position(p, |c| *c == 0);
raw::buf_as_slice(p, len, |s| {
- result.push(str::from_utf16_lossy(s).into_bytes());
+ result.push(String::from_utf16_lossy(s).into_bytes());
});
i += len as int + 1;
}
/// None if the variable isn't set.
///
/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
-/// `str::from_utf8_lossy()` for details.
+/// `String::from_utf8_lossy()` for details.
///
/// # Failure
///
/// }
/// ```
pub fn getenv(n: &str) -> Option<String> {
- getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v.as_slice()).to_string())
+ getenv_as_bytes(n).map(|v| String::from_utf8_lossy(v.as_slice()).into_string())
}
#[cfg(unix)]
/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
-pub fn setenv(n: &str, v: &str) {
+pub fn setenv<T: BytesContainer>(n: &str, v: T) {
#[cfg(unix)]
- fn _setenv(n: &str, v: &str) {
+ fn _setenv(n: &str, v: &[u8]) {
unsafe {
with_env_lock(|| {
n.with_c_str(|nbuf| {
}
#[cfg(windows)]
- fn _setenv(n: &str, v: &str) {
+ fn _setenv(n: &str, v: &[u8]) {
let n: Vec<u16> = n.utf16_units().collect();
let n = n.append_one(0);
- let v: Vec<u16> = v.utf16_units().collect();
+ let v: Vec<u16> = ::str::from_utf8(v).unwrap().utf16_units().collect();
let v = v.append_one(0);
+
unsafe {
with_env_lock(|| {
libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
})
}
}
- _setenv(n, v)
+
+ _setenv(n, v.container_as_bytes())
}
/// Remove a variable from the environment entirely.
_unsetenv(n);
}
-#[cfg(unix)]
-/// Parse a string or vector according to the platform's conventions
-/// for the `PATH` environment variable and return a Vec<Path>.
-/// Drops empty paths.
+/// Parses input according to platform conventions for the `PATH`
+/// environment variable.
///
/// # Example
/// ```rust
/// use std::os;
///
/// let key = "PATH";
-/// match os::getenv(key) {
+/// match os::getenv_as_bytes(key) {
/// Some(paths) => {
/// for path in os::split_paths(paths).iter() {
/// println!("'{}'", path.display());
/// }
/// }
-/// None => println!("{} is not defined in the environnement.", key)
+/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- unparsed.container_as_bytes()
- .split(|b| *b == ':' as u8)
- .filter(|s| s.len() > 0)
- .map(Path::new)
- .collect()
-}
+ #[cfg(unix)]
+ fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
+ unparsed.container_as_bytes()
+ .split(|b| *b == b':')
+ .map(Path::new)
+ .collect()
+ }
-#[cfg(windows)]
-/// Parse a string or vector according to the platform's conventions
-/// for the `PATH` environment variable. Drops empty paths.
-pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- // On Windows, the PATH environment variable is semicolon separated. Double
- // quotes are used as a way of introducing literal semicolons (since
- // c:\some;dir is a valid Windows path). Double quotes are not themselves
- // permitted in path names, so there is no way to escape a double quote.
- // Quoted regions can appear in arbitrary locations, so
- //
- // c:\foo;c:\som"e;di"r;c:\bar
- //
- // Should parse as [c:\foo, c:\some;dir, c:\bar].
- //
- // (The above is based on testing; there is no clear reference available
- // for the grammar.)
-
- let mut parsed = Vec::new();
- let mut in_progress = Vec::new();
- let mut in_quote = false;
-
- for b in unparsed.container_as_bytes().iter() {
- match *b as char {
- ';' if !in_quote => {
- // ignore zero-length path strings
- if in_progress.len() > 0 {
+ #[cfg(windows)]
+ fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
+ // On Windows, the PATH environment variable is semicolon separated. Double
+ // quotes are used as a way of introducing literal semicolons (since
+ // c:\some;dir is a valid Windows path). Double quotes are not themselves
+ // permitted in path names, so there is no way to escape a double quote.
+ // Quoted regions can appear in arbitrary locations, so
+ //
+ // c:\foo;c:\som"e;di"r;c:\bar
+ //
+ // Should parse as [c:\foo, c:\some;dir, c:\bar].
+ //
+ // (The above is based on testing; there is no clear reference available
+ // for the grammar.)
+
+ let mut parsed = Vec::new();
+ let mut in_progress = Vec::new();
+ let mut in_quote = false;
+
+ for b in unparsed.container_as_bytes().iter() {
+ match *b {
+ b';' if !in_quote => {
parsed.push(Path::new(in_progress.as_slice()));
+ in_progress.truncate(0)
+ }
+ b'"' => {
+ in_quote = !in_quote;
+ }
+ _ => {
+ in_progress.push(*b);
}
- in_progress.truncate(0)
- }
- '\"' => {
- in_quote = !in_quote;
}
- _ => {
- in_progress.push(*b);
+ }
+ parsed.push(Path::new(in_progress));
+ parsed
+ }
+
+ _split_paths(unparsed)
+}
+
+/// Joins a collection of `Path`s appropriately for the `PATH`
+/// environment variable.
+///
+/// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
+/// encoded on all platforms.
+///
+/// Returns an `Err` (containing an error message) if one of the input
+/// `Path`s contains an invalid character for constructing the `PATH`
+/// variable (a double quote on Windows or a colon on Unix).
+///
+/// # Example
+///
+/// ```rust
+/// use std::os;
+/// use std::path::Path;
+///
+/// let key = "PATH";
+/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
+/// paths.push(Path::new("/home/xyz/bin"));
+/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
+/// ```
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ #[cfg(windows)]
+ fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ let mut joined = Vec::new();
+ let sep = b';';
+
+ for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+ if i > 0 { joined.push(sep) }
+ if path.contains(&b'"') {
+ return Err("path segment contains `\"`");
+ } else if path.contains(&sep) {
+ joined.push(b'"');
+ joined.push_all(path);
+ joined.push(b'"');
+ } else {
+ joined.push_all(path);
}
}
+
+ Ok(joined)
}
- if in_progress.len() > 0 {
- parsed.push(Path::new(in_progress));
+ #[cfg(unix)]
+ fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ let mut joined = Vec::new();
+ let sep = b':';
+
+ for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+ if i > 0 { joined.push(sep) }
+ if path.contains(&sep) { return Err("path segment contains separator `:`") }
+ joined.push_all(path);
+ }
+
+ Ok(joined)
}
- parsed
+ _join_paths(paths)
}
/// A low-level OS in-memory pipe.
pub fn self_exe_name() -> Option<Path> {
#[cfg(target_os = "freebsd")]
+ #[cfg(target_os = "dragonfly")]
fn load_self() -> Option<Vec<u8>> {
unsafe {
use libc::funcs::bsd44::*;
#[cfg(windows)]
fn load_self() -> Option<Vec<u8>> {
- use str::OwnedStr;
-
unsafe {
use os::win32::fill_utf16_buf_and_decode;
fill_utf16_buf_and_decode(|buf, sz| {
}
}
-/**
- * Convert a relative path to an absolute path
- *
- * If the given path is relative, return it prepended with the current working
- * directory. If the given path is already an absolute path, return it
- * as is.
- */
+///
+/// Convert a relative path to an absolute path
+///
+/// If the given path is relative, return it prepended with the current working
+/// directory. If the given path is already an absolute path, return it
+/// as is.
+///
+/// # Example
+/// ```rust
+/// use std::os;
+/// use std::path::Path;
+///
+/// // Assume we're in a path like /home/someuser
+/// let rel_path = Path::new("..");
+/// let abs_path = os::make_absolute(&rel_path);
+/// println!("The absolute path is {}", abs_path.display());
+/// // Prints "The absolute path is /home"
+/// ```
// NB: this is here rather than in path because it is a form of environment
// querying; what it does depends on the process working directory, not just
// the input paths.
/// Changes the current working directory to the specified path, returning
/// whether the change was completed successfully or not.
+///
+/// # Example
+/// ```rust
+/// use std::os;
+/// use std::path::Path;
+///
+/// let root = Path::new("/");
+/// assert!(os::change_dir(&root));
+/// println!("Succesfully changed working directory to {}!", root.display());
+/// ```
pub fn change_dir(p: &Path) -> bool {
return chdir(p);
}
}
+ #[cfg(target_os = "dragonfly")]
+ fn errno_location() -> *const c_int {
+ extern {
+ fn __dfly_error() -> *const c_int;
+ }
+ unsafe {
+ __dfly_error()
+ }
+ }
+
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn errno_location() -> *const c_int {
}
/// Return the string corresponding to an `errno()` value of `errnum`.
+/// # Example
+/// ```rust
+/// use std::os;
+///
+/// // Same as println!("{}", last_os_error());
+/// println!("{}", os::error_string(os::errno() as uint));
+/// ```
pub fn error_string(errnum: uint) -> String {
return strerror(errnum);
#[cfg(target_os = "ios")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
+ #[cfg(target_os = "dragonfly")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
-> c_int {
extern {
fail!("strerror_r failure");
}
- str::raw::from_c_str(p as *const c_char).into_string()
+ ::string::raw::from_buf(p as *const u8)
}
}
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
}
- let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
+ let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
match msg {
Some(msg) => format!("OS Error {}: {}", errnum, msg),
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
+#[cfg(target_os = "dragonfly")]
fn real_args_as_bytes() -> Vec<Vec<u8>> {
use rt;
fn real_args() -> Vec<String> {
real_args_as_bytes().move_iter()
.map(|v| {
- str::from_utf8_lossy(v.as_slice()).into_string()
+ String::from_utf8_lossy(v.as_slice()).into_string()
}).collect()
}
// Push it onto the list.
let opt_s = slice::raw::buf_as_slice(ptr as *const _, len, |buf| {
- str::from_utf16(str::truncate_utf16_at_nul(buf))
+ String::from_utf16(::str::truncate_utf16_at_nul(buf))
});
opt_s.expect("CommandLineToArgvW returned invalid UTF-16")
});
/// via the command line).
///
/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
-/// See `str::from_utf8_lossy` for details.
+/// See `String::from_utf8_lossy` for details.
+/// # Example
+///
+/// ```rust
+/// use std::os;
+///
+/// // Prints each argument on a separate line
+/// for argument in os::args().iter() {
+/// println!("{}", argument);
+/// }
+/// ```
pub fn args() -> Vec<String> {
real_args()
}
/// The memory map is released (unmapped) when the destructor is run, so don't
/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
- /// Pointer to the memory created or modified by this map.
- pub data: *mut u8,
- /// Number of bytes this map applies to
- pub len: uint,
- /// Type of mapping
- pub kind: MemoryMapKind,
+ data: *mut u8,
+ len: uint,
+ kind: MemoryMapKind,
}
/// Type of memory map
}
}
+impl MemoryMap {
+ /// Returns the pointer to the memory created or modified by this map.
+ pub fn data(&self) -> *mut u8 { self.data }
+ /// Returns the number of bytes this map applies to.
+ pub fn len(&self) -> uint { self.len }
+ /// Returns the type of mapping this represents.
+ pub fn kind(&self) -> MemoryMapKind { self.kind }
+}
+
#[cfg(target_os = "linux")]
pub mod consts {
pub use os::arch_consts::ARCH;
pub static EXE_EXTENSION: &'static str = "";
}
+#[cfg(target_os = "dragonfly")]
+pub mod consts {
+ pub use os::arch_consts::ARCH;
+
+ pub static FAMILY: &'static str = "unix";
+
+ /// A string describing the specific operating system in use: in this
+ /// case, `dragonfly`.
+ pub static SYSNAME: &'static str = "dragonfly";
+
+ /// Specifies the filename prefix used for shared libraries on this
+ /// platform: in this case, `lib`.
+ pub static DLL_PREFIX: &'static str = "lib";
+
+ /// Specifies the filename suffix used for shared libraries on this
+ /// platform: in this case, `.so`.
+ pub static DLL_SUFFIX: &'static str = ".so";
+
+ /// Specifies the file extension used for shared libraries on this
+ /// platform that goes after the dot: in this case, `so`.
+ pub static DLL_EXTENSION: &'static str = "so";
+
+ /// Specifies the filename suffix used for executable binaries on this
+ /// platform: in this case, the empty string.
+ pub static EXE_SUFFIX: &'static str = "";
+
+ /// Specifies the file extension, if any, used for executable binaries
+ /// on this platform: in this case, the empty string.
+ pub static EXE_EXTENSION: &'static str = "";
+}
+
#[cfg(target_os = "android")]
pub mod consts {
pub use os::arch_consts::ARCH;
use c_str::ToCStr;
use option;
use os::{env, getcwd, getenv, make_absolute};
- use os::{split_paths, setenv, unsetenv};
+ use os::{split_paths, join_paths, setenv, unsetenv};
use os;
use rand::Rng;
use rand;
parsed.iter().map(|s| Path::new(*s)).collect()
}
- assert!(check_parse("", []));
- assert!(check_parse(r#""""#, []));
- assert!(check_parse(";;", []));
+ assert!(check_parse("", [""]));
+ assert!(check_parse(r#""""#, [""]));
+ assert!(check_parse(";;", ["", "", ""]));
assert!(check_parse(r"c:\", [r"c:\"]));
- assert!(check_parse(r"c:\;", [r"c:\"]));
+ assert!(check_parse(r"c:\;", [r"c:\", ""]));
assert!(check_parse(r"c:\;c:\Program Files\",
[r"c:\", r"c:\Program Files\"]));
assert!(check_parse(r#"c:\;c:\"foo"\"#, [r"c:\", r"c:\foo\"]));
parsed.iter().map(|s| Path::new(*s)).collect()
}
- assert!(check_parse("", []));
- assert!(check_parse("::", []));
+ assert!(check_parse("", [""]));
+ assert!(check_parse("::", ["", "", ""]));
assert!(check_parse("/", ["/"]));
- assert!(check_parse("/:", ["/"]));
+ assert!(check_parse("/:", ["/", ""]));
assert!(check_parse("/:/usr/local", ["/", "/usr/local"]));
}
+ #[test]
+ #[cfg(unix)]
+ fn join_paths_unix() {
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ join_paths(input).unwrap().as_slice() == output.as_bytes()
+ }
+
+ assert!(test_eq([], ""));
+ assert!(test_eq(["/bin", "/usr/bin", "/usr/local/bin"],
+ "/bin:/usr/bin:/usr/local/bin"));
+ assert!(test_eq(["", "/bin", "", "", "/usr/bin", ""],
+ ":/bin:::/usr/bin:"));
+ assert!(join_paths(["/te:st"]).is_err());
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn join_paths_windows() {
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ join_paths(input).unwrap().as_slice() == output.as_bytes()
+ }
+
+ assert!(test_eq([], ""));
+ assert!(test_eq([r"c:\windows", r"c:\"],
+ r"c:\windows;c:\"));
+ assert!(test_eq(["", r"c:\windows", "", "", r"c:\", ""],
+ r";c:\windows;;;c:\;"));
+ assert!(test_eq([r"c:\te;st", r"c:\"],
+ r#""c:\te;st";c:\"#));
+ assert!(join_paths([r#"c:\te"st"#]).is_err());
+ }
+
// More recursive_mkdir tests are in extra::tempfile
}