]> git.lizzy.rs Git - rust.git/commitdiff
std: Add a new `env` module
authorAlex Crichton <alex@alexcrichton.com>
Tue, 27 Jan 2015 20:20:58 +0000 (12:20 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 1 Feb 2015 19:08:15 +0000 (11:08 -0800)
This is an implementation of [RFC 578][rfc] which adds a new `std::env` module
to replace most of the functionality in the current `std::os` module. More
details can be found in the RFC itself, but as a summary the following methods
have all been deprecated:

[rfc]: https://github.com/rust-lang/rfcs/pull/578

* `os::args_as_bytes`   => `env::args`
* `os::args`            => `env::args`
* `os::consts`          => `env::consts`
* `os::dll_filename`    => no replacement, use `env::consts` directly
* `os::page_size`       => `env::page_size`
* `os::make_absolute`   => use `env::current_dir` + `join` instead
* `os::getcwd`          => `env::current_dir`
* `os::change_dir`      => `env::set_current_dir`
* `os::homedir`         => `env::home_dir`
* `os::tmpdir`          => `env::temp_dir`
* `os::join_paths`      => `env::join_paths`
* `os::split_paths`     => `env::split_paths`
* `os::self_exe_name`   => `env::current_exe`
* `os::self_exe_path`   => use `env::current_exe` + `pop`
* `os::set_exit_status` => `env::set_exit_status`
* `os::get_exit_status` => `env::get_exit_status`
* `os::env`             => `env::vars`
* `os::env_as_bytes`    => `env::vars`
* `os::getenv`          => `env::var` or `env::var_string`
* `os::getenv_as_bytes` => `env::var`
* `os::setenv`          => `env::set_var`
* `os::unsetenv`        => `env::remove_var`

Many function signatures have also been tweaked for various purposes, but the
main changes were:

* `Vec`-returning APIs now all return iterators instead
* All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`.
  There is currently on convenience API, `env::var_string`, which can be used to
  get the value of an environment variable as a unicode `String`.

All old APIs are `#[deprecated]` in-place and will remain for some time to allow
for migrations. The semantics of the APIs have been tweaked slightly with regard
to dealing with invalid unicode (panic instead of replacement).

The new `std::env` module is all contained within the `env` feature, so crates
must add the following to access the new APIs:

    #![feature(env)]

[breaking-change]

66 files changed:
src/compiletest/compiletest.rs
src/compiletest/runtest.rs
src/etc/make-win-dist.py
src/liblog/lib.rs
src/librustc/lib.rs
src/librustc/metadata/filesearch.rs
src/librustc/middle/infer/region_inference/graphviz.rs
src/librustc/plugin/load.rs
src/librustc/session/mod.rs
src/librustc_back/archive.rs
src/librustc_back/fs.rs
src/librustc_back/lib.rs
src/librustc_back/rpath.rs
src/librustc_back/target/mod.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_trans/lib.rs
src/librustc_trans/save/mod.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/libstd/dynamic_lib.rs
src/libstd/env.rs [new file with mode: 0644]
src/libstd/ffi/mod.rs
src/libstd/ffi/os_str.rs
src/libstd/lib.rs
src/libstd/old_io/process.rs
src/libstd/old_io/tempfile.rs
src/libstd/old_io/test.rs
src/libstd/os.rs
src/libstd/rt/backtrace.rs
src/libstd/rt/mod.rs
src/libstd/rt/util.rs
src/libstd/sys/common/mutex.rs
src/libstd/sys/common/rwlock.rs
src/libstd/sys/unix/backtrace.rs
src/libstd/sys/unix/c.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/process.rs
src/libstd/sys/windows/backtrace.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/fs.rs
src/libstd/sys/windows/handle.rs [new file with mode: 0644]
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/mutex.rs
src/libstd/sys/windows/os.rs
src/libstd/sys/windows/pipe.rs
src/libstd/sys/windows/process.rs
src/libstd/sys/windows/rwlock.rs
src/libstd/sys/windows/stack_overflow.rs
src/libstd/sys/windows/sync.rs
src/libstd/sys/windows/tcp.rs
src/libstd/sys/windows/thread.rs
src/libstd/sys/windows/thread_local.rs
src/libstd/sys/windows/timer.rs
src/libstd/sys/windows/tty.rs
src/libsyntax/ext/env.rs
src/libsyntax/lib.rs
src/libterm/lib.rs
src/libterm/terminfo/mod.rs
src/libterm/terminfo/searcher.rs
src/libtest/lib.rs
src/test/bench/shootout-mandelbrot.rs
src/test/compile-fail/liveness-unused.rs
src/test/run-pass/env-home-dir.rs [new file with mode: 0644]
src/test/run-pass/env-vars.rs [new file with mode: 0644]

index b73623223fd4eecbc197eb940507ba40cf618059..7c0ee7be8a4449c8e430e5cb47c12cdd2f98199a 100644 (file)
@@ -22,6 +22,7 @@
 #![feature(std_misc)]
 #![feature(test)]
 #![feature(unicode)]
+#![feature(env)]
 
 #![deny(warnings)]
 
@@ -31,7 +32,7 @@
 #[macro_use]
 extern crate log;
 
-use std::os;
+use std::env;
 use std::old_io;
 use std::old_io::fs;
 use std::thunk::Thunk;
@@ -48,7 +49,7 @@
 pub mod errors;
 
 pub fn main() {
-    let args = os::args();
+    let args = env::args().map(|s| s.into_string().unwrap()).collect();;
     let config = parse_config(args);
 
     if config.valgrind_path.is_none() && config.force_valgrind {
@@ -224,7 +225,7 @@ pub fn run_tests(config: &Config) {
         //arm-linux-androideabi debug-info test uses remote debugger
         //so, we test 1 task at once.
         // also trying to isolate problems with adb_run_wrapper.sh ilooping
-        os::setenv("RUST_TEST_TASKS","1");
+        env::set_var("RUST_TEST_TASKS","1");
     }
 
     match config.mode {
@@ -232,7 +233,7 @@ pub fn run_tests(config: &Config) {
             // Some older versions of LLDB seem to have problems with multiple
             // instances running in parallel, so only run one test task at a
             // time.
-            os::setenv("RUST_TEST_TASKS", "1");
+            env::set_var("RUST_TEST_TASKS", "1");
         }
         _ => { /* proceed */ }
     }
@@ -245,7 +246,7 @@ pub fn run_tests(config: &Config) {
     old_io::test::raise_fd_limit();
     // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
     // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
-    os::setenv("__COMPAT_LAYER", "RunAsInvoker");
+    env::set_var("__COMPAT_LAYER", "RunAsInvoker");
     let res = test::run_tests_console(&opts, tests.into_iter().collect());
     match res {
         Ok(true) => {}
index 18cb3d1d5b006634158dc65a0b86737aaaacdec7..5b0ea3b4854edec05c4f7a875cde23e67603ab6e 100644 (file)
@@ -31,7 +31,7 @@
 use std::old_io::process;
 use std::old_io::timer;
 use std::old_io;
-use std::os;
+use std::env;
 use std::iter::repeat;
 use std::str;
 use std::string::String;
@@ -1298,9 +1298,9 @@ fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> Path {
 
 fn make_exe_name(config: &Config, testfile: &Path) -> Path {
     let mut f = output_base_name(config, testfile);
-    if !os::consts::EXE_SUFFIX.is_empty() {
+    if !env::consts::EXE_SUFFIX.is_empty() {
         let mut fname = f.filename().unwrap().to_vec();
-        fname.extend(os::consts::EXE_SUFFIX.bytes());
+        fname.extend(env::consts::EXE_SUFFIX.bytes());
         f.set_filename(fname);
     }
     f
index 13d051350248871d19e2f0268685af5050e6cb1e..defda27acc9ec663adc816983504002be17c7f55 100644 (file)
@@ -87,6 +87,7 @@ def make_win_dist(rust_root, gcc_root, target_triple):
                     "libsetupapi.a",
                     "libshell32.a",
                     "libuser32.a",
+                    "libuserenv.a",
                     "libuuid.a",
                     "libwinhttp.a",
                     "libwinmm.a",
index 81d8c60f8939b92a1cdd0f232a324c2713c1d030..34216518c21d2073bb61909101eae42b6c089c69 100644 (file)
 #![feature(int_uint)]
 #![feature(core)]
 #![feature(io)]
-#![feature(os)]
 #![feature(std_misc)]
+#![feature(env)]
 
 use std::cell::RefCell;
 use std::fmt;
 use std::old_io::LineBufferedWriter;
 use std::old_io;
 use std::mem;
-use std::os;
+use std::env;
 use std::ptr;
 use std::rt;
 use std::slice;
@@ -397,9 +397,9 @@ fn enabled(level: u32,
 /// This is not threadsafe at all, so initialization is performed through a
 /// `Once` primitive (and this function is called from that primitive).
 fn init() {
-    let (mut directives, filter) = match os::getenv("RUST_LOG") {
-        Some(spec) => directive::parse_logging_spec(&spec[]),
-        None => (Vec::new(), None),
+    let (mut directives, filter) = match env::var_string("RUST_LOG") {
+        Ok(spec) => directive::parse_logging_spec(&spec[]),
+        Err(..) => (Vec::new(), None),
     };
 
     // Sort the provided directives by length of their name, this allows a
index 6ae861fcb04241447609ddfc174775effd65a8df..2f31a2c083f7fbdd790b360f8ab25a9d8761849b 100644 (file)
@@ -32,7 +32,7 @@
 #![feature(int_uint)]
 #![feature(io)]
 #![feature(libc)]
-#![feature(os)]
+#![feature(env)]
 #![feature(path)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
index 26046cfb43d8a410cb5d021b5634b7998a258547..45dd4b4dbacbdb6419a9f3655d7f963bdd89d7c8 100644 (file)
@@ -13,9 +13,9 @@
 pub use self::FileMatch::*;
 
 use std::collections::HashSet;
+use std::env;
 use std::old_io::fs::PathExtensions;
 use std::old_io::fs;
-use std::os;
 
 use util::fs as myfs;
 use session::search_paths::{SearchPaths, PathKind};
@@ -194,7 +194,7 @@ fn canonicalize(path: Option<Path>) -> Option<Path> {
             })
     }
 
-    match canonicalize(os::self_exe_name()) {
+    match canonicalize(env::current_exe().ok()) {
         Some(mut p) => { p.pop(); p.pop(); p }
         None => panic!("can't determine value for sysroot")
     }
@@ -207,7 +207,7 @@ fn canonicalize(path: Option<Path>) -> Option<Path> {
 
 /// Returns RUST_PATH as a string, without default paths added
 pub fn get_rust_path() -> Option<String> {
-    os::getenv("RUST_PATH").map(|x| x.to_string())
+    env::var_string("RUST_PATH").ok()
 }
 
 /// Returns the value of RUST_PATH, as a list
@@ -224,7 +224,7 @@ pub fn rust_path() -> Vec<Path> {
         }
         None => Vec::new()
     };
-    let mut cwd = os::getcwd().unwrap();
+    let mut cwd = env::current_dir().unwrap();
     // now add in default entries
     let cwd_dot_rust = cwd.join(".rust");
     if !env_rust_path.contains(&cwd_dot_rust) {
@@ -243,7 +243,7 @@ pub fn rust_path() -> Vec<Path> {
         }
         cwd.pop();
     }
-    let h = os::homedir();
+    let h = env::home_dir();
     for h in h.iter() {
         let p = h.join(".rust");
         if !env_rust_path.contains(&p) && p.exists() {
index 460687629e7b545baa4ceb5c8ffdb943f11f0106..87ea5436dab6b545662d33faec5b9a0fed89ed7a 100644 (file)
@@ -27,7 +27,7 @@
 
 use std::collections::hash_map::Entry::Vacant;
 use std::old_io::{self, File};
-use std::os;
+use std::env;
 use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
 use syntax::ast;
 
@@ -59,13 +59,13 @@ pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a,
     }
 
     let requested_node : Option<ast::NodeId> =
-        os::getenv("RUST_REGION_GRAPH_NODE").and_then(|s| s.parse().ok());
+        env::var_string("RUST_REGION_GRAPH_NODE").ok().and_then(|s| s.parse().ok());
 
     if requested_node.is_some() && requested_node != Some(subject_node) {
         return;
     }
 
-    let requested_output = os::getenv("RUST_REGION_GRAPH");
+    let requested_output = env::var_string("RUST_REGION_GRAPH").ok();
     debug!("requested_output: {:?} requested_node: {:?}",
            requested_output, requested_node);
 
index c420d1f15b43b1213691b3c7735ddb1635ef80b8..c04bf755b1f6b76a0b4343371e5b28fff58494ac 100644 (file)
@@ -15,7 +15,7 @@
 use plugin::registry::Registry;
 
 use std::mem;
-use std::os;
+use std::env;
 use std::dynamic_lib::DynamicLibrary;
 use std::collections::HashSet;
 use syntax::ast;
@@ -233,7 +233,7 @@ fn dylink_registrar<'b>(&mut self,
                         path: Path,
                         symbol: String) -> PluginRegistrarFun {
         // Make sure the path contains a / or the linker will search for it.
-        let path = os::make_absolute(&path).unwrap();
+        let path = env::current_dir().unwrap().join(&path);
 
         let lib = match DynamicLibrary::open(Some(&path)) {
             Ok(lib) => lib,
index e62f3145e5a2e5e894a5ac06bdbfaf7fc9533ce0..a983f995d3f64a79783dd7b4086c80942bf6026a 100644 (file)
@@ -27,7 +27,7 @@
 
 use rustc_back::target::Target;
 
-use std::os;
+use std::env;
 use std::cell::{Cell, RefCell};
 
 pub mod config;
@@ -347,7 +347,7 @@ pub fn build_session_(sopts: config::Options,
         if path.is_absolute() {
             path.clone()
         } else {
-            os::getcwd().unwrap().join(&path)
+            env::current_dir().unwrap().join(&path)
         }
     );
 
@@ -370,7 +370,7 @@ pub fn build_session_(sopts: config::Options,
         plugin_registrar_fn: Cell::new(None),
         default_sysroot: default_sysroot,
         local_crate_source_file: local_crate_source_file,
-        working_dir: os::getcwd().unwrap(),
+        working_dir: env::current_dir().unwrap(),
         lint_store: RefCell::new(lint::LintStore::new()),
         lints: RefCell::new(NodeMap()),
         crate_types: RefCell::new(Vec::new()),
index ee8bc71668b357c34f650479223872dc272e5273..f5483e666cfd4663f93a21117964cc6baf4aeff6 100644 (file)
@@ -14,7 +14,7 @@
 use std::old_io::process::{Command, ProcessOutput};
 use std::old_io::{fs, TempDir};
 use std::old_io;
-use std::os;
+use std::env;
 use std::str;
 use syntax::diagnostic::Handler as ErrorHandler;
 
@@ -224,7 +224,7 @@ pub fn update_symbols(&mut self) {
     pub fn build(self) -> Archive<'a> {
         // Get an absolute path to the destination, so `ar` will work even
         // though we run it from `self.work_dir`.
-        let abs_dst = os::getcwd().unwrap().join(&self.archive.dst);
+        let abs_dst = env::current_dir().unwrap().join(&self.archive.dst);
         assert!(!abs_dst.is_relative());
         let mut args = vec![&abs_dst];
         let mut total_len = abs_dst.as_vec().len();
@@ -283,7 +283,7 @@ fn add_archive<F>(&mut self, archive: &Path, name: &str,
         // First, extract the contents of the archive to a temporary directory.
         // We don't unpack directly into `self.work_dir` due to the possibility
         // of filename collisions.
-        let archive = os::make_absolute(archive).unwrap();
+        let archive = env::current_dir().unwrap().join(archive);
         run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
                "x", Some(loc.path()), &[&archive]);
 
index 24f81b024789c1fdb19456cb9f584f4e957de4ca..acf49d1ca46e3b6d7a3c55cc44a607d48aea0681 100644 (file)
 
 use std::old_io;
 use std::old_io::fs;
-use std::os;
+use std::env;
 
 /// Returns an absolute path in the filesystem that `path` points to. The
 /// returned path does not contain any symlinks in its hierarchy.
 pub fn realpath(original: &Path) -> old_io::IoResult<Path> {
     static MAX_LINKS_FOLLOWED: uint = 256;
-    let original = os::make_absolute(original).unwrap();
+    let original = try!(env::current_dir()).join(original);
 
     // Right now lstat on windows doesn't work quite well
     if cfg!(windows) {
index 2c6b5797f572b3f4fafa142414abb7f70e59b876..54b3e8f208125e8253ddc528957bd0d774a84684 100644 (file)
@@ -40,6 +40,7 @@
 #![feature(path)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
+#![feature(env)]
 
 extern crate syntax;
 extern crate serialize;
index 47b909df5e8da77a402c765d288ac83deb15992b..b6a34b4beba717e0ca79e4fa0f8345044c462820 100644 (file)
@@ -10,7 +10,7 @@
 
 
 use std::collections::HashSet;
-use std::os;
+use std::env;
 use std::old_io::IoError;
 use syntax::ast;
 
@@ -105,8 +105,6 @@ fn get_rpath_relative_to_output<F, G>(config: &mut RPathConfig<F, G>, lib: &Path
     F: FnOnce() -> Path,
     G: FnMut(&Path) -> Result<Path, IoError>,
 {
-    use std::os;
-
     // Mac doesn't appear to support $ORIGIN
     let prefix = if config.is_like_osx {
         "@loader_path"
@@ -114,9 +112,10 @@ fn get_rpath_relative_to_output<F, G>(config: &mut RPathConfig<F, G>, lib: &Path
         "$ORIGIN"
     };
 
-    let mut lib = (config.realpath)(&os::make_absolute(lib).unwrap()).unwrap();
+    let cwd = env::current_dir().unwrap();
+    let mut lib = (config.realpath)(&cwd.join(lib)).unwrap();
     lib.pop();
-    let mut output = (config.realpath)(&os::make_absolute(&config.out_filename).unwrap()).unwrap();
+    let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap();
     output.pop();
     let relative = lib.path_relative_from(&output);
     let relative = relative.expect("could not create rpath relative to output");
@@ -131,7 +130,7 @@ fn get_install_prefix_rpath<F, G>(config: RPathConfig<F, G>) -> String where
     G: FnMut(&Path) -> Result<Path, IoError>,
 {
     let path = (config.get_install_prefix_lib_path)();
-    let path = os::make_absolute(&path).unwrap();
+    let path = env::current_dir().unwrap().join(&path);
     // FIXME (#9639): This needs to handle non-utf8 paths
     path.as_str().expect("non-utf8 component in rpath").to_string()
 }
index 16adccfba575e97013dd91bcce1689077a25e829..eb7c23f95e2e1998cfc6c5e8350fa51f43e2ee3d 100644 (file)
@@ -301,7 +301,8 @@ macro_rules! key {
     /// The error string could come from any of the APIs called, including filesystem access and
     /// JSON decoding.
     pub fn search(target: &str) -> Result<Target, String> {
-        use std::os;
+        use std::env;
+        use std::ffi::OsString;
         use std::old_io::File;
         use std::path::Path;
         use serialize::json;
@@ -379,12 +380,12 @@ macro_rules! load_specific {
             Path::new(target)
         };
 
-        let target_path = os::getenv("RUST_TARGET_PATH").unwrap_or(String::new());
+        let target_path = env::var("RUST_TARGET_PATH")
+                              .unwrap_or(OsString::from_str(""));
 
-        let paths = os::split_paths(&target_path[]);
         // FIXME 16351: add a sane default search path?
 
-        for dir in paths.iter() {
+        for dir in env::split_paths(&target_path) {
             let p =  dir.join(path.clone());
             if p.is_file() {
                 return load_file(&p);
index 9e00844b7eea23168ed7934d95702b6a58124c9d..4aa4193d51134c263eb9d96d9e7b1845646c064f 100644 (file)
 
 use serialize::json;
 
-use std::old_io;
+use std::env;
+use std::ffi::OsString;
 use std::old_io::fs;
-use std::os;
+use std::old_io;
 use syntax::ast;
 use syntax::ast_map;
 use syntax::attr;
@@ -460,12 +461,12 @@ pub fn phase_2_configure_and_expand(sess: &Session,
             // dependent dlls. Note that this uses cfg!(windows) as opposed to
             // targ_cfg because syntax extensions are always loaded for the host
             // compiler, not for the target.
-            let mut _old_path = String::new();
+            let mut _old_path = OsString::from_str("");
             if cfg!(windows) {
-                _old_path = os::getenv("PATH").unwrap_or(_old_path);
+                _old_path = env::var("PATH").unwrap_or(_old_path);
                 let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
-                new_path.extend(os::split_paths(&_old_path[]).into_iter());
-                os::setenv("PATH", os::join_paths(&new_path[]).unwrap());
+                new_path.extend(env::split_paths(&_old_path));
+                env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
             }
             let cfg = syntax::ext::expand::ExpansionConfig {
                 crate_name: crate_name.to_string(),
@@ -478,7 +479,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
                                               syntax_exts,
                                               krate);
             if cfg!(windows) {
-                os::setenv("PATH", _old_path);
+                env::set_var("PATH", &_old_path);
             }
             ret
         }
@@ -734,10 +735,10 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 pub fn phase_6_link_output(sess: &Session,
                            trans: &trans::CrateTranslation,
                            outputs: &OutputFilenames) {
-    let old_path = os::getenv("PATH").unwrap_or_else(||String::new());
+    let old_path = env::var("PATH").unwrap_or(OsString::from_str(""));
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
-    new_path.extend(os::split_paths(&old_path[]).into_iter());
-    os::setenv("PATH", os::join_paths(&new_path[]).unwrap());
+    new_path.extend(env::split_paths(&old_path));
+    env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
 
     time(sess.time_passes(), "linking", (), |_|
          link::link_binary(sess,
@@ -745,7 +746,7 @@ pub fn phase_6_link_output(sess: &Session,
                            outputs,
                            &trans.link.crate_name[]));
 
-    os::setenv("PATH", old_path);
+    env::set_var("PATH", &old_path);
 }
 
 fn escape_dep_filename(filename: &str) -> String {
index 2eada1ff174f15ccc5beecbe369712d781b191f7..6230f0b14a23b8672c59fa0d560b1dd7d6d62e33 100644 (file)
@@ -26,6 +26,7 @@
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(core)]
+#![feature(env)]
 #![feature(int_uint)]
 #![feature(io)]
 #![feature(libc)]
@@ -74,7 +75,7 @@
 use std::cmp::Ordering::Equal;
 use std::old_io;
 use std::iter::repeat;
-use std::os;
+use std::env;
 use std::sync::mpsc::channel;
 use std::thread;
 
@@ -252,7 +253,7 @@ pub fn get_unstable_features_setting() -> UnstableFeatures {
     // subverting the unstable features lints
     let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
     // The matching key to the above, only known by the build system
-    let bootstrap_provided_key = os::getenv("RUSTC_BOOTSTRAP_KEY");
+    let bootstrap_provided_key = env::var_string("RUSTC_BOOTSTRAP_KEY").ok();
     match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
         (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
         (true, _, _) => UnstableFeatures::Disallow,
@@ -618,7 +619,7 @@ pub fn monitor<F:FnOnce()+Send>(f: F) {
 
     // FIXME: Hacks on hacks. If the env is trying to override the stack size
     // then *don't* set it explicitly.
-    if os::getenv("RUST_MIN_STACK").is_none() {
+    if env::var("RUST_MIN_STACK").is_none() {
         cfg = cfg.stack_size(STACK_SIZE);
     }
 
@@ -682,8 +683,8 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry {
 }
 
 pub fn main() {
-    let args = std::os::args();
-    let result = run(args);
-    std::os::set_exit_status(result);
+    let args = env::args().map(|s| s.into_string().unwrap());
+    let result = run(args.collect());
+    std::env::set_exit_status(result as i32);
 }
 
index c46c2b7e6ddaf2410f45f08a0e4bf1238c081f55..11ffade6da6c6ef9aac596d92ee200ac09ca7bca 100644 (file)
@@ -32,8 +32,8 @@
 #![feature(hash)]
 #![feature(int_uint)]
 #![feature(io)]
+#![feature(env)]
 #![feature(libc)]
-#![feature(os)]
 #![feature(path)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
index fbeaae1d1dfa3a272ebd895447db8ca8b63ae2a4..f429ab7599fef676aec2ec3880bb621bce276f96 100644 (file)
@@ -34,7 +34,7 @@
 
 use std::cell::Cell;
 use std::old_io::{self, File, fs};
-use std::os;
+use std::env;
 
 use syntax::ast_util::{self, PostExpansionMethod};
 use syntax::ast::{self, NodeId, DefId};
@@ -1551,9 +1551,9 @@ pub fn process_crate(sess: &Session,
     info!("Dumping crate {}", cratename);
 
     // find a path to dump our data to
-    let mut root_path = match os::getenv("DXR_RUST_TEMP_FOLDER") {
-        Some(val) => Path::new(val),
-        None => match odir {
+    let mut root_path = match env::var_string("DXR_RUST_TEMP_FOLDER") {
+        Ok(val) => Path::new(val),
+        Err(..) => match odir {
             Some(val) => val.join("dxr"),
             None => Path::new("dxr-temp"),
         },
index 29e52d627cdfe8c98eaad8ed5d1476edd28f3313..c9b50bdd3c1d201025bbf4fe842cd7440e6e1ed0 100644 (file)
@@ -21,6 +21,7 @@
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(core)]
+#![feature(env)]
 #![feature(hash)]
 #![feature(int_uint)]
 #![feature(io)]
@@ -50,6 +51,7 @@
 
 use std::cell::RefCell;
 use std::collections::HashMap;
+use std::env;
 use std::old_io::File;
 use std::old_io;
 use std::rc::Rc;
@@ -121,9 +123,10 @@ struct Output {
 pub fn main() {
     static STACK_SIZE: uint = 32000000; // 32MB
     let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || {
-        main_args(std::os::args().as_slice())
+        let s = env::args().map(|s| s.into_string().unwrap());
+        main_args(&s.collect::<Vec<_>>())
     }).join();
-    std::os::set_exit_status(res.ok().unwrap());
+    env::set_exit_status(res.ok().unwrap() as i32);
 }
 
 pub fn opts() -> Vec<getopts::OptGroup> {
index 2f692fe99cda7f61275a4f204a1fd1946bbf512b..29abea009e547f2580a9b2a9e76d804ac06c9e33 100644 (file)
@@ -13,7 +13,7 @@
 use std::dynamic_lib::DynamicLibrary;
 use std::old_io::{Command, TempDir};
 use std::old_io;
-use std::os;
+use std::env;
 use std::str;
 use std::thread::Thread;
 use std::thunk::Thunk;
@@ -49,7 +49,7 @@ pub fn run(input: &str,
     let input = config::Input::File(input_path.clone());
 
     let sessopts = config::Options {
-        maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
+        maybe_sysroot: Some(env::current_exe().unwrap().dir_path().dir_path()),
         search_paths: libs.clone(),
         crate_types: vec!(config::CrateTypeDylib),
         externs: externs.clone(),
@@ -119,7 +119,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
     let input = config::Input::Str(test.to_string());
 
     let sessopts = config::Options {
-        maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
+        maybe_sysroot: Some(env::current_exe().unwrap().dir_path().dir_path()),
         search_paths: libs,
         crate_types: vec!(config::CrateTypeExecutable),
         output_types: vec!(config::OutputTypeExe),
index f35f63143ef8275cdeab063398d4da89c16e0adf..46567aedbec4ebebd5bd09f1da3e2b0564dab740 100644 (file)
@@ -19,7 +19,7 @@
 
 use ffi::CString;
 use mem;
-use os;
+use env;
 use str;
 
 #[allow(missing_copy_implementations)]
@@ -68,8 +68,8 @@ pub fn prepend_search_path(path: &Path) {
         let mut search_path = DynamicLibrary::search_path();
         search_path.insert(0, path.clone());
         let newval = DynamicLibrary::create_path(search_path.as_slice());
-        os::setenv(DynamicLibrary::envvar(),
-                   str::from_utf8(newval.as_slice()).unwrap());
+        env::set_var(DynamicLibrary::envvar(),
+                     str::from_utf8(newval.as_slice()).unwrap());
     }
 
     /// From a slice of paths, create a new vector which is suitable to be an
@@ -102,18 +102,10 @@ fn separator() -> u8 {
     /// Returns the current search path for dynamic libraries being used by this
     /// process
     pub fn search_path() -> Vec<Path> {
-        let mut ret = Vec::new();
-        match os::getenv_as_bytes(DynamicLibrary::envvar()) {
-            Some(env) => {
-                for portion in
-                        env.as_slice()
-                           .split(|a| *a == DynamicLibrary::separator()) {
-                    ret.push(Path::new(portion));
-                }
-            }
-            None => {}
+        match env::var(DynamicLibrary::envvar()) {
+            Some(var) => env::split_paths(&var).collect(),
+            None => Vec::new(),
         }
-        return ret;
     }
 
     /// Access the value at the symbol of the dynamic library
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
new file mode 100644 (file)
index 0000000..5070f8c
--- /dev/null
@@ -0,0 +1,833 @@
+// 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.
+
+//! Inspection and manipulation of the process's environment.
+//!
+//! This module contains methods to inspect various aspects such as
+//! environment varibles, process arguments, the current directory, and various
+//! other important directories.
+
+#![unstable(feature = "env", reason = "recently added via RFC 578")]
+
+use prelude::v1::*;
+
+use error::Error;
+use ffi::{OsString, AsOsStr};
+use fmt;
+use old_io::IoResult;
+use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
+use sync::{StaticMutex, MUTEX_INIT};
+use sys::os as os_imp;
+
+/// Returns the current working directory as a `Path`.
+///
+/// # Errors
+///
+/// Returns an `Err` if the current working directory value is invalid.
+/// Possible cases:
+///
+/// * Current directory does not exist.
+/// * There are insufficient permissions to access the current directory.
+/// * The internal buffer is not large enough to hold the path.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// // We assume that we are in a valid directory.
+/// let p = env::current_dir().unwrap();
+/// println!("The current directory is {}", p.display());
+/// ```
+pub fn current_dir() -> IoResult<Path> {
+    os_imp::getcwd()
+}
+
+/// Changes the current working directory to the specified path, returning
+/// whether the change was completed successfully or not.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+/// use std::path::Path;
+///
+/// let root = Path::new("/");
+/// assert!(env::set_current_dir(&root).is_ok());
+/// println!("Successfully changed working directory to {}!", root.display());
+/// ```
+pub fn set_current_dir(p: &Path) -> IoResult<()> {
+    os_imp::chdir(p)
+}
+
+static ENV_LOCK: StaticMutex = MUTEX_INIT;
+
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This iterator is created through `std::env::vars()` and yields `(OsString,
+/// OsString)` pairs.
+pub struct Vars { inner: os_imp::Env }
+
+/// Returns an iterator of (variable, value) pairs, for all the environment
+/// variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation, modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// // We will iterate through the references to the element returned by
+/// // env::vars();
+/// for (key, value) in env::vars() {
+///     println!("{:?}: {:?}", key, value);
+/// }
+/// ```
+pub fn vars() -> Vars {
+    let _g = ENV_LOCK.lock();
+    Vars { inner: os_imp::env() }
+}
+
+impl Iterator for Vars {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+/// Fetches the environment variable `key` from the current process, returning
+/// None if the variable isn't set.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var(key) {
+///     Some(val) => println!("{}: {:?}", key, val),
+///     None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+pub fn var<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
+    let _g = ENV_LOCK.lock();
+    os_imp::getenv(key.as_os_str())
+}
+
+/// Fetches the environment variable `key` from the current process.
+///
+/// The returned result is `Ok(s)` if the environment variable is present and is
+/// valid unicode. If the environment variable is not present, or it is not
+/// valid unicode, then `Err` will be returned.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var_string(key) {
+///     Ok(val) => println!("{}: {:?}", key, val),
+///     Err(e) => println!("couldn't interpret {}: {}", key, e),
+/// }
+/// ```
+pub fn var_string<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
+    match var(key) {
+        Some(s) => s.into_string().map_err(VarError::NotUnicode),
+        None => Err(VarError::NotPresent)
+    }
+}
+
+/// Possible errors from the `env::var` method.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum VarError {
+    /// The specified environment variable was not present in the current
+    /// process's environment.
+    NotPresent,
+
+    /// The specified environment variable was found, but it did not contain
+    /// valid unicode data. The found data is returned as a payload of this
+    /// variant.
+    NotUnicode(OsString),
+}
+
+impl fmt::Display for VarError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            VarError::NotPresent => write!(f, "environment variable not found"),
+            VarError::NotUnicode(ref s) => {
+                write!(f, "environment variable was not valid unicode: {:?}", s)
+            }
+        }
+    }
+}
+
+impl Error for VarError {
+    fn description(&self) -> &str {
+        match *self {
+            VarError::NotPresent => "environment variable not found",
+            VarError::NotUnicode(..) => "environment variable was not valid unicode",
+        }
+    }
+}
+
+/// Sets the environment variable `k` to the value `v` for the currently running
+/// process.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var_string(key), Ok("VALUE".to_string()));
+/// ```
+pub fn set_var<K: ?Sized, V: ?Sized>(k: &K, v: &V)
+    where K: AsOsStr, V: AsOsStr
+{
+    let _g = ENV_LOCK.lock();
+    os_imp::setenv(k.as_os_str(), v.as_os_str())
+}
+
+/// Remove a variable from the environment entirely.
+pub fn remove_var<K: ?Sized>(k: &K) where K: AsOsStr {
+    let _g = ENV_LOCK.lock();
+    os_imp::unsetenv(k.as_os_str())
+}
+
+/// An iterator over `Path` instances for parsing an environment variable
+/// according to platform-specific conventions.
+///
+/// This structure is returned from `std::env::split_paths`.
+pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
+
+/// Parses input according to platform conventions for the `PATH`
+/// environment variable.
+///
+/// Returns an iterator over the paths contained in `unparsed`.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// let key = "PATH";
+/// match env::var(key) {
+///     Some(paths) => {
+///         for path in env::split_paths(&paths) {
+///             println!("'{}'", path.display());
+///         }
+///     }
+///     None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+pub fn split_paths<T: AsOsStr + ?Sized>(unparsed: &T) -> SplitPaths {
+    SplitPaths { inner: os_imp::split_paths(unparsed.as_os_str()) }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = Path;
+    fn next(&mut self) -> Option<Path> { self.inner.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+/// Error type returned from `std::env::join_paths` when paths fail to be
+/// joined.
+#[derive(Debug)]
+pub struct JoinPathsError {
+    inner: os_imp::JoinPathsError
+}
+
+/// Joins a collection of `Path`s appropriately for the `PATH`
+/// environment variable.
+///
+/// Returns an `OsString` on success.
+///
+/// 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::env;
+///
+/// if let Some(path) = env::var("PATH") {
+///     let mut paths = env::split_paths(&path).collect::<Vec<_>>();
+///     paths.push(Path::new("/home/xyz/bin"));
+///     let new_path = env::join_paths(paths.iter()).unwrap();
+///     env::set_var("PATH", &new_path);
+/// }
+/// ```
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsOsStr
+{
+    os_imp::join_paths(paths).map_err(|e| {
+        JoinPathsError { inner: e }
+    })
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl Error for JoinPathsError {
+    fn description(&self) -> &str { self.inner.description() }
+}
+
+/// Optionally returns the path to the current user's home directory if known.
+///
+/// # Unix
+///
+/// Returns the value of the 'HOME' environment variable if it is set
+/// and not equal to the empty string.
+///
+/// # Windows
+///
+/// Returns the value of the 'HOME' environment variable if it is
+/// set and not equal to the empty string. Otherwise, returns the value of the
+/// 'USERPROFILE' environment variable if it is set and not equal to the empty
+/// string.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// match env::home_dir() {
+///     Some(ref p) => println!("{}", p.display()),
+///     None => println!("Impossible to get your home dir!")
+/// }
+/// ```
+pub fn home_dir() -> Option<Path> {
+    os_imp::home_dir()
+}
+
+/// Returns the path to a temporary directory.
+///
+/// On Unix, returns the value of the 'TMPDIR' environment variable if it is
+/// set, otherwise for non-Android it returns '/tmp'. If Android, since there
+/// is no global temporary folder (it is usually allocated per-app), we return
+/// '/data/local/tmp'.
+///
+/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
+/// 'USERPROFILE' environment variable  if any are set and not the empty
+/// string. Otherwise, tmpdir returns the path to the Windows directory.
+pub fn temp_dir() -> Path {
+    os_imp::temp_dir()
+}
+
+/// Optionally returns the filesystem path to the current executable which is
+/// running but with the executable name.
+///
+/// The path returned is not necessarily a "real path" to the executable as
+/// there may be intermediate symlinks.
+///
+/// # Errors
+///
+/// Acquring the path to the current executable is a platform-specific operation
+/// that can fail for a good number of reasons. Some errors can include, but not
+/// be limited to filesystem operations failing or general syscall failures.
+///
+/// # Examples
+///
+/// ```rust
+/// use std::env;
+///
+/// match env::current_exe() {
+///     Ok(exe_path) => println!("Path of this executable is: {}",
+///                               exe_path.display()),
+///     Err(e) => println!("failed to get current exe path: {}", e),
+/// };
+/// ```
+pub fn current_exe() -> IoResult<Path> {
+    os_imp::current_exe()
+}
+
+static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
+
+/// Sets the process exit code
+///
+/// Sets the exit code returned by the process if all supervised tasks
+/// terminate successfully (without panicking). If the current root task panics
+/// and is supervised by the scheduler then any user-specified exit status is
+/// ignored and the process exits with the default panic status.
+///
+/// Note that this is not synchronized against modifications of other threads.
+pub fn set_exit_status(code: i32) {
+    EXIT_STATUS.store(code as isize, Ordering::SeqCst)
+}
+
+/// Fetches the process's current exit code. This defaults to 0 and can change
+/// by calling `set_exit_status`.
+pub fn get_exit_status() -> i32 {
+    EXIT_STATUS.load(Ordering::SeqCst) as i32
+}
+
+/// An iterator over the arguments of a process, yielding an `OsString` value
+/// for each argument.
+///
+/// This structure is created through the `std::env::args` method.
+pub struct Args { inner: os_imp::Args }
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path to the executable, but it can be
+/// set to arbitrary text, and it may not even exist, so this property should
+/// not be relied upon for security purposes.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args() {
+///     println!("{:?}", argument);
+/// }
+/// ```
+pub fn args() -> Args {
+    Args { inner: os_imp::args() }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.inner.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+/// Returns the page size of the current architecture in bytes.
+pub fn page_size() -> usize {
+    os_imp::page_size()
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "linux")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `linux`.
+    pub const OS: &'static str = "linux";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, `lib`.
+    pub const DLL_PREFIX: &'static str = "lib";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.so`.
+    pub const 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 const DLL_EXTENSION: &'static str = "so";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "macos")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `macos`.
+    pub const OS: &'static str = "macos";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, `lib`.
+    pub const DLL_PREFIX: &'static str = "lib";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.dylib`.
+    pub const DLL_SUFFIX: &'static str = ".dylib";
+
+    /// Specifies the file extension used for shared libraries on this
+    /// platform that goes after the dot: in this case, `dylib`.
+    pub const DLL_EXTENSION: &'static str = "dylib";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "ios")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `ios`.
+    pub const OS: &'static str = "ios";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "freebsd")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `freebsd`.
+    pub const OS: &'static str = "freebsd";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, `lib`.
+    pub const DLL_PREFIX: &'static str = "lib";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.so`.
+    pub const 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 const DLL_EXTENSION: &'static str = "so";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "dragonfly")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `dragonfly`.
+    pub const OS: &'static str = "dragonfly";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, `lib`.
+    pub const DLL_PREFIX: &'static str = "lib";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.so`.
+    pub const 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 const DLL_EXTENSION: &'static str = "so";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "android")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `android`.
+    pub const OS: &'static str = "android";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, `lib`.
+    pub const DLL_PREFIX: &'static str = "lib";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.so`.
+    pub const 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 const DLL_EXTENSION: &'static str = "so";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub const EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub const EXE_EXTENSION: &'static str = "";
+}
+
+/// Constants associated with the current target
+#[cfg(target_os = "windows")]
+pub mod consts {
+    pub use super::arch_consts::ARCH;
+
+    pub const FAMILY: &'static str = "windows";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `windows`.
+    pub const OS: &'static str = "windows";
+
+    /// Specifies the filename prefix used for shared libraries on this
+    /// platform: in this case, the empty string.
+    pub const DLL_PREFIX: &'static str = "";
+
+    /// Specifies the filename suffix used for shared libraries on this
+    /// platform: in this case, `.dll`.
+    pub const DLL_SUFFIX: &'static str = ".dll";
+
+    /// Specifies the file extension used for shared libraries on this
+    /// platform that goes after the dot: in this case, `dll`.
+    pub const DLL_EXTENSION: &'static str = "dll";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, `.exe`.
+    pub const EXE_SUFFIX: &'static str = ".exe";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, `exe`.
+    pub const EXE_EXTENSION: &'static str = "exe";
+}
+
+#[cfg(target_arch = "x86")]
+mod arch_consts {
+    pub const ARCH: &'static str = "x86";
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch_consts {
+    pub const ARCH: &'static str = "x86_64";
+}
+
+#[cfg(target_arch = "arm")]
+mod arch_consts {
+    pub const ARCH: &'static str = "arm";
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch_consts {
+    pub const ARCH: &'static str = "aarch64";
+}
+
+#[cfg(target_arch = "mips")]
+mod arch_consts {
+    pub const ARCH: &'static str = "mips";
+}
+
+#[cfg(target_arch = "mipsel")]
+mod arch_consts {
+    pub const ARCH: &'static str = "mipsel";
+}
+
+#[cfg(target_arch = "powerpc")]
+mod arch_consts {
+    pub const ARCH: &'static str = "powerpc";
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+    use super::*;
+    use iter::repeat;
+    use rand::{self, Rng};
+    use ffi::{OsString, OsStr};
+
+    fn make_rand_name() -> OsString {
+        let mut rng = rand::thread_rng();
+        let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
+                                     .collect::<String>());
+        let n = OsString::from_string(n);
+        assert!(var(&n).is_none());
+        n
+    }
+
+    fn eq(a: Option<OsString>, b: Option<&str>) {
+        assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::from_str).map(|s| &*s));
+    }
+
+    #[test]
+    fn test_set_var() {
+        let n = make_rand_name();
+        set_var(&n, "VALUE");
+        eq(var(&n), Some("VALUE"));
+    }
+
+    #[test]
+    fn test_remove_var() {
+        let n = make_rand_name();
+        set_var(&n, "VALUE");
+        remove_var(&n);
+        eq(var(&n), None);
+    }
+
+    #[test]
+    fn test_set_var_overwrite() {
+        let n = make_rand_name();
+        set_var(&n, "1");
+        set_var(&n, "2");
+        eq(var(&n), Some("2"));
+        set_var(&n, "");
+        eq(var(&n), Some(""));
+    }
+
+    #[test]
+    fn test_var_big() {
+        let mut s = "".to_string();
+        let mut i = 0;
+        while i < 100 {
+            s.push_str("aaaaaaaaaa");
+            i += 1;
+        }
+        let n = make_rand_name();
+        set_var(&n, s.as_slice());
+        eq(var(&n), Some(s.as_slice()));
+    }
+
+    #[test]
+    fn test_self_exe_path() {
+        let path = current_exe();
+        assert!(path.is_ok());
+        let path = path.unwrap();
+
+        // Hard to test this function
+        assert!(path.is_absolute());
+    }
+
+    #[test]
+    fn test_env_set_get_huge() {
+        let n = make_rand_name();
+        let s = repeat("x").take(10000).collect::<String>();
+        set_var(&n, &s);
+        eq(var(&n), Some(s.as_slice()));
+        remove_var(&n);
+        eq(var(&n), None);
+    }
+
+    #[test]
+    fn test_env_set_var() {
+        let n = make_rand_name();
+
+        let mut e = vars();
+        set_var(&n, "VALUE");
+        assert!(!e.any(|(k, v)| {
+            &*k == &*n && &*v == "VALUE"
+        }));
+
+        assert!(vars().any(|(k, v)| {
+            &*k == &*n && &*v == "VALUE"
+        }));
+    }
+
+    #[test]
+    fn test() {
+        assert!((!Path::new("test-path").is_absolute()));
+
+        current_dir().unwrap();
+    }
+
+    #[test]
+    #[cfg(windows)]
+    fn split_paths_windows() {
+        fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+            split_paths(unparsed).collect::<Vec<_>>() ==
+                parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
+        }
+
+        assert!(check_parse("", &mut [""]));
+        assert!(check_parse(r#""""#, &mut [""]));
+        assert!(check_parse(";;", &mut ["", "", ""]));
+        assert!(check_parse(r"c:\", &mut [r"c:\"]));
+        assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
+        assert!(check_parse(r"c:\;c:\Program Files\",
+                            &mut [r"c:\", r"c:\Program Files\"]));
+        assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
+        assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
+                            &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn split_paths_unix() {
+        fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+            split_paths(unparsed).collect::<Vec<_>>() ==
+                parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
+        }
+
+        assert!(check_parse("", &mut [""]));
+        assert!(check_parse("::", &mut ["", "", ""]));
+        assert!(check_parse("/", &mut ["/"]));
+        assert!(check_parse("/:", &mut ["/", ""]));
+        assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn join_paths_unix() {
+        fn test_eq(input: &[&str], output: &str) -> bool {
+            &*join_paths(input.iter().map(|s| *s)).unwrap() ==
+                OsStr::from_str(output)
+        }
+
+        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"].iter().map(|s| *s)).is_err());
+    }
+
+    #[test]
+    #[cfg(windows)]
+    fn join_paths_windows() {
+        fn test_eq(input: &[&str], output: &str) -> bool {
+            &*join_paths(input.iter().map(|s| *s)).unwrap() ==
+                OsStr::from_str(output)
+        }
+
+        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"#].iter().map(|s| *s)).is_err());
+    }
+    }
index 69ada28a4b4a456ba05b452591d163d1e7c53fa4..76f925a23f17412e3cd4bac2a6a707ccadc9caa3 100644 (file)
 
 pub use self::os_str::OsString;
 pub use self::os_str::OsStr;
-pub use self::os_str::AsOsStr;
 
 mod c_str;
 mod os_str;
+
+/// Freely convertible to an `&OsStr` slice.
+pub trait AsOsStr {
+    /// Convert to an `&OsStr` slice.
+    fn as_os_str(&self) -> &OsStr;
+}
index 18e2aa8c098a712de0c4cc00dd849224a22b0be3..57489e86230069a168155e43460f4eb3c63cbc07 100644 (file)
 use ops;
 use cmp;
 use hash::{Hash, Hasher, Writer};
+use path::{Path, GenericPath};
 
 use sys::os_str::{Buf, Slice};
 use sys_common::{AsInner, IntoInner, FromInner};
+use super::AsOsStr;
 
 /// Owned, mutable OS strings.
 #[derive(Clone)]
@@ -69,6 +71,11 @@ pub fn from_str(s: &str) -> OsString {
         OsString { inner: Buf::from_str(s) }
     }
 
+    /// Constructs a new empty `OsString`.
+    pub fn new() -> OsString {
+        OsString { inner: Buf::from_string(String::new()) }
+    }
+
     /// Convert the `OsString` into a `String` if it contains valid Unicode data.
     ///
     /// On failure, ownership of the original `OsString` is returned.
@@ -117,6 +124,62 @@ fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
     }
 }
 
+impl PartialEq for OsString {
+    fn eq(&self, other: &OsString) -> bool {
+        &**self == &**other
+    }
+}
+
+impl PartialEq<str> for OsString {
+    fn eq(&self, other: &str) -> bool {
+        &**self == other
+    }
+}
+
+impl PartialEq<OsString> for str {
+    fn eq(&self, other: &OsString) -> bool {
+        &**other == self
+    }
+}
+
+impl Eq for OsString {}
+
+impl PartialOrd for OsString {
+    #[inline]
+    fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> {
+        (&**self).partial_cmp(&**other)
+    }
+    #[inline]
+    fn lt(&self, other: &OsString) -> bool { &**self < &**other }
+    #[inline]
+    fn le(&self, other: &OsString) -> bool { &**self <= &**other }
+    #[inline]
+    fn gt(&self, other: &OsString) -> bool { &**self > &**other }
+    #[inline]
+    fn ge(&self, other: &OsString) -> bool { &**self >= &**other }
+}
+
+impl PartialOrd<str> for OsString {
+    #[inline]
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        (&**self).partial_cmp(other)
+    }
+}
+
+impl Ord for OsString {
+    #[inline]
+    fn cmp(&self, other: &OsString) -> cmp::Ordering {
+        (&**self).cmp(&**other)
+    }
+}
+
+impl<'a, S: Hasher + Writer> Hash<S> for OsString {
+    #[inline]
+    fn hash(&self, state: &mut S) {
+        (&**self).hash(state)
+    }
+}
+
 impl OsStr {
     /// Coerce directly from a `&str` slice to a `&OsStr` slice.
     pub fn from_str(s: &str) -> &OsStr {
@@ -222,10 +285,10 @@ impl ToOwned<OsString> for OsStr {
     fn to_owned(&self) -> OsString { self.to_os_string() }
 }
 
-/// Freely convertible to an `&OsStr` slice.
-pub trait AsOsStr {
-    /// Convert to an `&OsStr` slice.
-    fn as_os_str(&self) -> &OsStr;
+impl<'a, T: AsOsStr + ?Sized> AsOsStr for &'a T {
+    fn as_os_str(&self) -> &OsStr {
+        (*self).as_os_str()
+    }
 }
 
 impl AsOsStr for OsStr {
@@ -252,6 +315,21 @@ fn as_os_str(&self) -> &OsStr {
     }
 }
 
+#[cfg(unix)]
+impl AsOsStr for Path {
+    fn as_os_str(&self) -> &OsStr {
+        unsafe { mem::transmute(self.as_vec()) }
+    }
+}
+
+#[cfg(windows)]
+impl AsOsStr for Path {
+    fn as_os_str(&self) -> &OsStr {
+        // currently .as_str() is actually infallible on windows
+        OsStr::from_str(self.as_str().unwrap())
+    }
+}
+
 impl FromInner<Buf> for OsString {
     fn from_inner(buf: Buf) -> OsString {
         OsString { inner: buf }
index 96aebb735ef123ea1fb3f0e495778f97089f0a4c..487efb4332682092311867abf18f5aab76a6c470 100644 (file)
 pub mod fmt;
 pub mod old_io;
 pub mod os;
+pub mod env;
 pub mod path;
 pub mod rand;
 pub mod time;
index f253f9799e9bdb5af4221808f78b9acea1e77867..81903d0a97e99b0b1cfe88c638c2e9864989d036 100644 (file)
@@ -231,6 +231,7 @@ pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command
         self
     }
     // Get a mutable borrow of the environment variable map for this `Command`.
+    #[allow(deprecated)]
     fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
         match self.env {
             Some(ref mut map) => map,
index 20cbde5db715ac69d031e4a787329f9008b5ca33..83a42549424d698dabee5242ff2075df1c04ceb0 100644 (file)
 
 //! Temporary files and directories
 
+use env;
+use iter::{IteratorExt};
 use old_io::{fs, IoError, IoErrorKind, IoResult};
 use old_io;
-use iter::IteratorExt;
 use ops::Drop;
-use option::Option;
 use option::Option::{None, Some};
-use os;
+use option::Option;
 use path::{Path, GenericPath};
 use rand::{Rng, thread_rng};
 use result::Result::{Ok, Err};
@@ -97,8 +97,8 @@ impl TempDir {
     /// If no directory can be created, `Err` is returned.
     pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
         if !tmpdir.is_absolute() {
-            let abs_tmpdir = try!(os::make_absolute(tmpdir));
-            return TempDir::new_in(&abs_tmpdir, prefix);
+            let cur_dir = try!(env::current_dir());
+            return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
         }
 
         let mut rng = thread_rng();
@@ -132,7 +132,7 @@ pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
     ///
     /// If no directory can be created, `Err` is returned.
     pub fn new(prefix: &str) -> IoResult<TempDir> {
-        TempDir::new_in(&os::tmpdir(), prefix)
+        TempDir::new_in(&env::temp_dir(), prefix)
     }
 
     /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
index f49e2397d4282b49fb2f8d0658268f6bf09e422a..3f4e070e30d95b66bb199d517e7ff1a3624a604f 100644 (file)
@@ -12,8 +12,8 @@
 
 use prelude::v1::*;
 
+use env;
 use libc;
-use os;
 use std::old_io::net::ip::*;
 use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
 
@@ -41,7 +41,7 @@ fn next_test_unix_socket() -> String {
 pub fn next_test_unix() -> Path {
     let string = next_test_unix_socket();
     if cfg!(unix) {
-        os::tmpdir().join(string)
+        env::temp_dir().join(string)
     } else {
         Path::new(format!("{}{}", r"\\.\pipe\", string))
     }
@@ -87,7 +87,7 @@ fn base_port() -> u16 {
     ];
 
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let path = os::getcwd().unwrap();
+    let path = env::current_dir().unwrap();
     let path_s = path.as_str().unwrap();
 
     let mut final_base = base;
index 600ca60349ae26ede5bee71d797a58d97b401f0d..27e843d2383bf429392ca2236268d7d789215f1a 100644 (file)
 use self::MapOption::*;
 use self::MapError::*;
 
+use boxed::Box;
 use clone::Clone;
+use env;
 use error::{FromError, Error};
+use ffi::{OsString, OsStr};
 use fmt;
-use old_io::{IoResult, IoError};
 use iter::{Iterator, IteratorExt};
-use marker::{Copy, Send};
 use libc::{c_void, c_int, c_char};
 use libc;
-use boxed::Box;
+use marker::{Copy, Send};
+use old_io::{IoResult, IoError};
 use ops::{Drop, FnOnce};
-use option::Option;
 use option::Option::{Some, None};
+use option::Option;
 use path::{Path, GenericPath, BytesContainer};
-use sys;
-use sys::os as os_imp;
 use ptr::PtrExt;
 use ptr;
-use result::Result;
 use result::Result::{Err, Ok};
+use result::Result;
 use slice::{AsSlice, SliceExt};
 use str::{Str, StrExt};
+use str;
 use string::{String, ToString};
 use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
+use sys::os as os_imp;
+use sys;
 use vec::Vec;
 
 #[cfg(unix)] use ffi::{self, CString};
@@ -97,23 +100,10 @@ pub fn num_cpus() -> uint {
 /// let current_working_directory = os::getcwd().unwrap();
 /// println!("The current directory is {:?}", current_working_directory.display());
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to std::env::current_dir")]
+#[unstable(feature = "os")]
 pub fn getcwd() -> IoResult<Path> {
-    sys::os::getcwd()
-}
-
-/*
-Accessing environment variables is not generally threadsafe.
-Serialize access through a global lock.
-*/
-fn with_env_lock<T, F>(f: F) -> T where
-    F: FnOnce() -> T,
-{
-    use sync::{StaticMutex, MUTEX_INIT};
-
-    static LOCK: StaticMutex = MUTEX_INIT;
-
-    let _guard = LOCK.lock();
-    f()
+    env::current_dir()
 }
 
 /// Returns a vector of (variable, value) pairs, for all the environment
@@ -132,37 +122,22 @@ fn with_env_lock<T, F>(f: F) -> T where
 ///     println!("'{}': '{}'", key, value );
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "use env::vars instead")]
+#[unstable(feature = "os")]
 pub fn env() -> Vec<(String,String)> {
-    env_as_bytes().into_iter().map(|(k,v)| {
-        let k = String::from_utf8_lossy(k.as_slice()).into_owned();
-        let v = String::from_utf8_lossy(v.as_slice()).into_owned();
-        (k,v)
+    env::vars().map(|(k, v)| {
+        (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned())
     }).collect()
 }
 
 /// Returns a vector of (variable, value) byte-vector pairs for all the
 /// environment variables of the current process.
-pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
-    unsafe {
-        fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
-            let mut pairs = Vec::new();
-            for p in input.iter() {
-                let mut it = p.splitn(1, |b| *b == b'=');
-                let key = it.next().unwrap().to_vec();
-                let default: &[u8] = &[];
-                let val = it.next().unwrap_or(default).to_vec();
-                pairs.push((key, val));
-            }
-            pairs
-        }
-        with_env_lock(|| {
-            let unparsed_environ = sys::os::get_env_pairs();
-            env_convert(unparsed_environ)
-        })
-    }
+#[deprecated(since = "1.0.0", reason = "use env::vars instead")]
+#[unstable(feature = "os")]
+pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
+    env::vars().map(|(k, v)| (byteify(k), byteify(v))).collect()
 }
 
-#[cfg(unix)]
 /// Fetches the environment variable `n` from the current process, returning
 /// None if the variable isn't set.
 ///
@@ -184,52 +159,32 @@ fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
 ///     None => println!("{} is not defined in the environment.", key)
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "use env::var or env::var_string instead")]
+#[unstable(feature = "os")]
 pub fn getenv(n: &str) -> Option<String> {
-    getenv_as_bytes(n).map(|v| String::from_utf8_lossy(v.as_slice()).into_owned())
+    env::var_string(n).ok()
 }
 
-#[cfg(unix)]
 /// Fetches the environment variable `n` byte vector from the current process,
 /// returning None if the variable isn't set.
 ///
 /// # Panics
 ///
 /// Panics if `n` has any interior NULs.
+#[deprecated(since = "1.0.0", reason = "use env::var instead")]
+#[unstable(feature = "os")]
 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
-    unsafe {
-        with_env_lock(|| {
-            let s = CString::from_slice(n.as_bytes());
-            let s = libc::getenv(s.as_ptr()) as *const _;
-            if s.is_null() {
-                None
-            } else {
-                Some(ffi::c_str_to_bytes(&s).to_vec())
-            }
-        })
-    }
+    env::var(n).map(byteify)
 }
 
-#[cfg(windows)]
-/// Fetches the environment variable `n` from the current process, returning
-/// None if the variable isn't set.
-pub fn getenv(n: &str) -> Option<String> {
-    unsafe {
-        with_env_lock(|| {
-            use sys::os::fill_utf16_buf_and_decode;
-            let mut n: Vec<u16> = n.utf16_units().collect();
-            n.push(0);
-            fill_utf16_buf_and_decode(|buf, sz| {
-                libc::GetEnvironmentVariableW(n.as_ptr(), buf, sz)
-            })
-        })
-    }
+#[cfg(unix)]
+fn byteify(s: OsString) -> Vec<u8> {
+    use os::unix::*;
+    s.into_vec()
 }
-
 #[cfg(windows)]
-/// Fetches the environment variable `n` byte vector from the current process,
-/// returning None if the variable isn't set.
-pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
-    getenv(n).map(|s| s.into_bytes())
+fn byteify(s: OsString) -> Vec<u8> {
+    s.to_string_lossy().as_bytes().to_vec()
 }
 
 /// Sets the environment variable `n` to the value `v` for the currently running
@@ -247,68 +202,30 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
 ///     None => println!("{} is not defined in the environment.", key)
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::set_var")]
+#[unstable(feature = "os")]
 pub fn setenv<T: BytesContainer>(n: &str, v: T) {
     #[cfg(unix)]
     fn _setenv(n: &str, v: &[u8]) {
-        unsafe {
-            with_env_lock(|| {
-                let k = CString::from_slice(n.as_bytes());
-                let v = CString::from_slice(v);
-                if libc::funcs::posix01::unistd::setenv(k.as_ptr(),
-                                                        v.as_ptr(), 1) != 0 {
-                    panic!(IoError::last_error());
-                }
-            })
-        }
+        use os::unix::*;
+        let v: OsString = OsStringExt::from_vec(v.to_vec());
+        env::set_var(n, &v)
     }
 
     #[cfg(windows)]
     fn _setenv(n: &str, v: &[u8]) {
-        let mut n: Vec<u16> = n.utf16_units().collect();
-        n.push(0);
-        let mut v: Vec<u16> = ::str::from_utf8(v).unwrap().utf16_units().collect();
-        v.push(0);
-
-        unsafe {
-            with_env_lock(|| {
-                if libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr()) == 0 {
-                    panic!(IoError::last_error());
-                }
-            })
-        }
+        let v = str::from_utf8(v).unwrap();
+        env::set_var(n, v)
     }
 
     _setenv(n, v.container_as_bytes())
 }
 
 /// Remove a variable from the environment entirely.
+#[deprecated(since = "1.0.0", reason = "renamed to env::remove_var")]
+#[unstable(feature = "os")]
 pub fn unsetenv(n: &str) {
-    #[cfg(unix)]
-    fn _unsetenv(n: &str) {
-        unsafe {
-            with_env_lock(|| {
-                let nbuf = CString::from_slice(n.as_bytes());
-                if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
-                    panic!(IoError::last_error());
-                }
-            })
-        }
-    }
-
-    #[cfg(windows)]
-    fn _unsetenv(n: &str) {
-        let mut n: Vec<u16> = n.utf16_units().collect();
-        n.push(0);
-        unsafe {
-            with_env_lock(|| {
-                if libc::SetEnvironmentVariableW(n.as_ptr(), ptr::null()) == 0 {
-                    panic!(IoError::last_error());
-                }
-            })
-        }
-    }
-
-    _unsetenv(n)
+    env::remove_var(n)
 }
 
 /// Parses input according to platform conventions for the `PATH`
@@ -328,8 +245,12 @@ fn _unsetenv(n: &str) {
 ///     None => println!("{} is not defined in the environment.", key)
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::split_paths")]
+#[unstable(feature = "os")]
 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
-    sys::os::split_paths(unparsed.container_as_bytes())
+    let b = unparsed.container_as_bytes();
+    let s = str::from_utf8(b).unwrap();
+    env::split_paths(s).collect()
 }
 
 /// Joins a collection of `Path`s appropriately for the `PATH`
@@ -353,8 +274,14 @@ pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
 /// paths.push(Path::new("/home/xyz/bin"));
 /// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::join_paths")]
+#[unstable(feature = "os")]
 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
-    sys::os::join_paths(paths)
+    env::join_paths(paths.iter().map(|s| {
+        str::from_utf8(s.container_as_bytes()).unwrap()
+    })).map(|s| {
+        s.to_string_lossy().into_owned().into_bytes()
+    }).map_err(|_| "failed to join paths")
 }
 
 /// A low-level OS in-memory pipe.
@@ -388,6 +315,8 @@ pub unsafe fn pipe() -> IoResult<Pipe> {
 /// Returns the proper dll filename for the given basename of a file
 /// as a String.
 #[cfg(not(target_os="ios"))]
+#[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")]
+#[unstable(feature = "os")]
 pub fn dll_filename(base: &str) -> String {
     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
 }
@@ -405,8 +334,10 @@ pub fn dll_filename(base: &str) -> String {
 ///     None => println!("Unable to get the path of this executable!")
 /// };
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::current_exe")]
+#[unstable(feature = "os")]
 pub fn self_exe_name() -> Option<Path> {
-    sys::os::load_self().and_then(Path::new_opt)
+    env::current_exe().ok()
 }
 
 /// Optionally returns the filesystem path to the current executable which is
@@ -424,8 +355,10 @@ pub fn self_exe_name() -> Option<Path> {
 ///     None => println!("Impossible to fetch the path of this executable.")
 /// };
 /// ```
+#[deprecated(since = "1.0.0", reason = "use env::current_exe + dir_path/pop")]
+#[unstable(feature = "os")]
 pub fn self_exe_path() -> Option<Path> {
-    self_exe_name().map(|mut p| { p.pop(); p })
+    env::current_exe().ok().map(|mut p| { p.pop(); p })
 }
 
 /// Optionally returns the path to the current user's home directory if known.
@@ -452,6 +385,9 @@ pub fn self_exe_path() -> Option<Path> {
 ///     None => println!("Impossible to get your home dir!")
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::home_dir")]
+#[allow(deprecated)]
+#[unstable(feature = "os")]
 pub fn homedir() -> Option<Path> {
     #[inline]
     #[cfg(unix)]
@@ -487,6 +423,9 @@ fn aux_homedir(home_name: &str) -> Option<Path> {
 /// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
 /// 'USERPROFILE' environment variable  if any are set and not the empty
 /// string. Otherwise, tmpdir returns the path to the Windows directory.
+#[deprecated(since = "1.0.0", reason = "renamed to env::temp_dir")]
+#[allow(deprecated)]
+#[unstable(feature = "os")]
 pub fn tmpdir() -> Path {
     return lookup();
 
@@ -542,11 +481,13 @@ fn lookup() -> Path {
 // 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.
+#[deprecated(since = "1.0.0", reason = "use env::current_dir + .join directly")]
+#[unstable(feature = "os")]
 pub fn make_absolute(p: &Path) -> IoResult<Path> {
     if p.is_absolute() {
         Ok(p.clone())
     } else {
-        getcwd().map(|mut cwd| {
+        env::current_dir().map(|mut cwd| {
             cwd.push(p);
             cwd
         })
@@ -565,6 +506,8 @@ pub fn make_absolute(p: &Path) -> IoResult<Path> {
 /// assert!(os::change_dir(&root).is_ok());
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
+#[deprecated(since = "1.0.0", reason = "renamed to env::set_current_dir")]
+#[unstable(feature = "os")]
 pub fn change_dir(p: &Path) -> IoResult<()> {
     return sys::os::chdir(p);
 }
@@ -592,8 +535,6 @@ pub fn last_os_error() -> String {
     error_string(errno() as uint)
 }
 
-static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
-
 /// Sets the process exit code
 ///
 /// Sets the exit code returned by the process if all supervised tasks
@@ -602,14 +543,18 @@ pub fn last_os_error() -> String {
 /// ignored and the process exits with the default panic status.
 ///
 /// Note that this is not synchronized against modifications of other threads.
+#[deprecated(since = "1.0.0", reason = "renamed to env::set_exit_status")]
+#[unstable(feature = "os")]
 pub fn set_exit_status(code: int) {
-    EXIT_STATUS.store(code, Ordering::SeqCst)
+    env::set_exit_status(code as i32)
 }
 
 /// Fetches the process's current exit code. This defaults to 0 and can change
 /// by calling `set_exit_status`.
+#[deprecated(since = "1.0.0", reason = "renamed to env::get_exit_status")]
+#[unstable(feature = "os")]
 pub fn get_exit_status() -> int {
-    EXIT_STATUS.load(Ordering::SeqCst)
+    env::get_exit_status() as isize
 }
 
 #[cfg(target_os = "macos")]
@@ -726,7 +671,7 @@ fn real_args() -> Vec<String> {
         // Push it onto the list.
         let ptr = ptr as *const u16;
         let buf = slice::from_raw_buf(&ptr, len);
-        let opt_s = String::from_utf16(sys::os::truncate_utf16_at_nul(buf));
+        let opt_s = String::from_utf16(sys::truncate_utf16_at_nul(buf));
         opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16")
     }).collect();
 
@@ -777,12 +722,16 @@ fn CommandLineToArgvW(lpCmdLine: LPCWSTR,
 ///     println!("{}", argument);
 /// }
 /// ```
+#[deprecated(since = "1.0.0", reason = "use env::args instead")]
+#[unstable(feature = "os")]
 pub fn args() -> Vec<String> {
     real_args()
 }
 
 /// Returns the arguments which this program was started with (normally passed
 /// via the command line) as byte vectors.
+#[deprecated(since = "1.0.0", reason = "use env::args_raw instead")]
+#[unstable(feature = "os")]
 pub fn args_as_bytes() -> Vec<Vec<u8>> {
     real_args_as_bytes()
 }
@@ -790,11 +739,13 @@ pub fn args_as_bytes() -> Vec<Vec<u8>> {
 #[cfg(target_os = "macos")]
 extern {
     // These functions are in crt_externs.h.
-    pub fn _NSGetArgc() -> *mut c_int;
-    pub fn _NSGetArgv() -> *mut *mut *mut c_char;
+    fn _NSGetArgc() -> *mut c_int;
+    fn _NSGetArgv() -> *mut *mut *mut c_char;
 }
 
 /// Returns the page size of the current architecture in bytes.
+#[deprecated(since = "1.0.0", reason = "renamed to env::page_size")]
+#[unstable(feature = "os")]
 pub fn page_size() -> uint {
     sys::os::page_size()
 }
@@ -970,7 +921,7 @@ pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError>
         let mut fd = -1;
         let mut offset = 0;
         let mut custom_flags = false;
-        let len = round_up(min_len, page_size());
+        let len = round_up(min_len, env::page_size());
 
         for &o in options.iter() {
             match o {
@@ -1020,7 +971,7 @@ pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError>
     /// Granularity that the offset or address must be for `MapOffset` and
     /// `MapAddr` respectively.
     pub fn granularity() -> uint {
-        page_size()
+        env::page_size()
     }
 }
 
@@ -1049,7 +1000,7 @@ pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError>
         let mut executable = false;
         let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
         let mut offset: uint = 0;
-        let len = round_up(min_len, page_size());
+        let len = round_up(min_len, env::page_size());
 
         for &o in options.iter() {
             match o {
@@ -1184,6 +1135,8 @@ pub fn kind(&self) -> MemoryMapKind { self.kind }
 }
 
 #[cfg(target_os = "linux")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1215,6 +1168,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "macos")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1246,6 +1201,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "ios")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1265,6 +1222,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "freebsd")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1296,6 +1255,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "dragonfly")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1327,6 +1288,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "android")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
@@ -1358,6 +1321,8 @@ pub mod consts {
 }
 
 #[cfg(target_os = "windows")]
+#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
+#[unstable(feature = "os")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
 
index f2d66e1a4d765ea91545e740f35ec77305c65cd4..905cc06c4f007f11d5640e31d1d8f3756a88fc8e 100644 (file)
@@ -14,7 +14,7 @@
 
 use prelude::v1::*;
 
-use os;
+use env;
 use sync::atomic::{self, Ordering};
 
 pub use sys::backtrace::write;
@@ -29,7 +29,7 @@ pub fn log_enabled() -> bool {
         _ => {}
     }
 
-    let val = match os::getenv("RUST_BACKTRACE") {
+    let val = match env::var("RUST_BACKTRACE") {
         Some(..) => 2,
         None => 1,
     };
index 7e19f1cac2c5bf5a0c74c7d25e3f0823061ba086..00088d6d99a0a6af49b02b8910da11c29832cd00 100644 (file)
@@ -65,7 +65,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
     use prelude::v1::*;
 
     use mem;
-    use os;
+    use env;
     use rt;
     use sys_common::thread_info::{self, NewThread};
     use sys_common;
@@ -131,7 +131,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
     if failed {
         rt::DEFAULT_ERROR_CODE
     } else {
-        os::get_exit_status()
+        env::get_exit_status() as isize
     }
 }
 
index f5727a38b69976fee9652dec5ae55d5129cb0c0b..86d21cf72782ed51a3b71db9225c346d1dc52e71 100644 (file)
@@ -13,6 +13,7 @@
 use prelude::v1::*;
 
 use cmp;
+use env;
 use fmt;
 use intrinsics;
 use libc::{self, uintptr_t};
@@ -51,7 +52,7 @@ pub fn min_stack() -> uint {
         0 => {}
         n => return n - 1,
     }
-    let amt = os::getenv("RUST_MIN_STACK").and_then(|s| s.parse().ok());
+    let amt = env::var_string("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
     let amt = amt.unwrap_or(2 * 1024 * 1024);
     // 0 is our sentinel value, so ensure that we'll never see 0 after
     // initialization has run
@@ -62,15 +63,15 @@ pub fn min_stack() -> uint {
 /// Get's the number of scheduler threads requested by the environment
 /// either `RUST_THREADS` or `num_cpus`.
 pub fn default_sched_threads() -> uint {
-    match os::getenv("RUST_THREADS") {
-        Some(nstr) => {
+    match env::var_string("RUST_THREADS") {
+        Ok(nstr) => {
             let opt_n: Option<uint> = nstr.parse().ok();
             match opt_n {
                 Some(n) if n > 0 => n,
                 _ => panic!("`RUST_THREADS` is `{}`, should be a positive integer", nstr)
             }
         }
-        None => {
+        Err(..) => {
             if limit_thread_creation_due_to_osx_and_valgrind() {
                 1
             } else {
index 9aea0fb3b31725f8743949065b48cc1c333ab8d5..0ca228267003db79e76a9e5b96a06dd1eed35b41 100644 (file)
@@ -24,13 +24,6 @@ unsafe impl Sync for Mutex {}
 pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT);
 
 impl Mutex {
-    /// Creates a newly initialized mutex.
-    ///
-    /// Behavior is undefined if the mutex is moved after the first method is
-    /// called on the mutex.
-    #[inline]
-    pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) }
-
     /// Lock the mutex blocking the current thread until it is available.
     ///
     /// Behavior is undefined if the mutex has been moved between this and any
index df016b9e293b7fb44e20aecd4ccdca1acd94429f..fe374e1fd78a3dd55ac97c08234d60054832fe90 100644 (file)
 pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT);
 
 impl RWLock {
-    /// Creates a new instance of an RWLock.
-    ///
-    /// Usage of an RWLock is undefined if it is moved after its first use (any
-    /// function calls below).
-    #[inline]
-    pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) }
-
     /// Acquire shared access to the underlying lock, blocking the current
     /// thread to do so.
     ///
index e310b8f6d90b3f3fe5a635124e1ba7ab06fbce8c..51186feeaf4bcb39df729aa8838717329b0d95c9 100644 (file)
@@ -240,7 +240,7 @@ fn dladdr(addr: *const libc::c_void,
 
 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
 fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
-    use os;
+    use env;
     use ptr;
 
     ////////////////////////////////////////////////////////////////////////
@@ -319,7 +319,7 @@ unsafe fn init_state() -> *mut backtrace_state {
         if !STATE.is_null() { return STATE }
         let selfname = if cfg!(target_os = "freebsd") ||
                           cfg!(target_os = "dragonfly") {
-            os::self_exe_name()
+            env::current_exe().ok()
         } else {
             None
         };
index 9016d1a2c99cab743260fd85d83f28d7697e3779..7a17e8b6f1e1512823f9dbea41c3574f05055236 100644 (file)
 
 pub const WNOHANG: libc::c_int = 1;
 
+#[cfg(target_os = "linux")]
+pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 70;
+#[cfg(any(target_os = "macos",
+          target_os = "freebsd"))]
+pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71;
+#[cfg(target_os = "android")]
+pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 0x0048;
+
+#[repr(C)]
+#[cfg(target_os = "linux")]
+pub struct passwd {
+    pub pw_name: *mut libc::c_char,
+    pub pw_passwd: *mut libc::c_char,
+    pub pw_uid: libc::uid_t,
+    pub pw_gid: libc::gid_t,
+    pub pw_gecos: *mut libc::c_char,
+    pub pw_dir: *mut libc::c_char,
+    pub pw_shell: *mut libc::c_char,
+}
+
+#[repr(C)]
+#[cfg(any(target_os = "macos",
+          target_os = "freebsd"))]
+pub struct passwd {
+    pub pw_name: *mut libc::c_char,
+    pub pw_passwd: *mut libc::c_char,
+    pub pw_uid: libc::uid_t,
+    pub pw_gid: libc::gid_t,
+    pub pw_change: libc::time_t,
+    pub pw_class: *mut libc::c_char,
+    pub pw_gecos: *mut libc::c_char,
+    pub pw_dir: *mut libc::c_char,
+    pub pw_shell: *mut libc::c_char,
+    pub pw_expire: libc::time_t,
+}
+
+#[repr(C)]
+#[cfg(target_os = "android")]
+pub struct passwd {
+    pub pw_name: *mut libc::c_char,
+    pub pw_passwd: *mut libc::c_char,
+    pub pw_uid: libc::uid_t,
+    pub pw_gid: libc::gid_t,
+    pub pw_dir: *mut libc::c_char,
+    pub pw_shell: *mut libc::c_char,
+}
+
 extern {
     pub fn gettimeofday(timeval: *mut libc::timeval,
                         tzp: *mut libc::c_void) -> libc::c_int;
@@ -92,6 +139,12 @@ pub fn sigaction(signum: libc::c_int,
     pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
     pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
     pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
+
+    pub fn getpwuid_r(uid: libc::uid_t,
+                      pwd: *mut passwd,
+                      buf: *mut libc::c_char,
+                      buflen: libc::size_t,
+                      result: *mut *mut passwd) -> libc::c_int;
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
index f2f2e7436bfb7d7d0d6da1a2b677ea688c517d69..b03b9046966a02dc3dccc99307c8a9900cbb6750 100644 (file)
@@ -141,7 +141,7 @@ pub fn retry<T, F> (mut f: F) -> T where
     let one: T = Int::one();
     loop {
         let n = f();
-        if n == -one && os::errno() == libc::EINTR as int { }
+        if n == -one && os::errno() == libc::EINTR as i32 { }
         else { return n }
     }
 }
@@ -155,7 +155,7 @@ pub fn ms_to_timeval(ms: u64) -> libc::timeval {
 
 pub fn wouldblock() -> bool {
     let err = os::errno();
-    err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
+    err == libc::EWOULDBLOCK as i32 || err == libc::EAGAIN as i32
 }
 
 pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
index dd343baa7c9c3842d4cc900a82253fbcd44e17d8..68818b07b7fefe7c0869c56ea8a9a8bb7009fc55 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
 //! Implementation of `std::os` functionality for unix systems
 
 use prelude::v1::*;
+use os::unix::*;
 
-use error::{FromError, Error};
-use ffi::{self, CString};
+use error::Error as StdError;
+use ffi::{self, CString, OsString, OsStr, AsOsStr};
 use fmt;
-use old_io::{IoError, IoResult};
+use iter;
 use libc::{self, c_int, c_char, c_void};
-use os::TMPBUF_SZ;
-use os;
-use path::{BytesContainer};
+use mem;
+use old_io::{IoResult, IoError, fs};
 use ptr;
+use slice;
 use str;
+use sys::c;
 use sys::fs::FileDesc;
+use vec;
 
-const BUF_BYTES : uint = 2048u;
+const BUF_BYTES: usize = 2048;
+const TMPBUF_SZ: usize = 128;
 
 /// Returns the platform-specific value of errno
-pub fn errno() -> int {
+pub fn errno() -> i32 {
     #[cfg(any(target_os = "macos",
               target_os = "ios",
               target_os = "freebsd"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __error() -> *const c_int;
-        }
-        unsafe {
-            __error()
-        }
+    unsafe fn errno_location() -> *const c_int {
+        extern { fn __error() -> *const c_int; }
+        __error()
     }
 
     #[cfg(target_os = "dragonfly")]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __dfly_error() -> *const c_int;
-        }
-        unsafe {
-            __dfly_error()
-        }
+    unsafe fn errno_location() -> *const c_int {
+        extern { fn __dfly_error() -> *const c_int; }
+        __dfly_error()
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __errno_location() -> *const c_int;
-        }
-        unsafe {
-            __errno_location()
-        }
+    unsafe fn errno_location() -> *const c_int {
+        extern { fn __errno_location() -> *const c_int; }
+        __errno_location()
     }
 
     unsafe {
-        (*errno_location()) as int
+        (*errno_location()) as i32
     }
 }
 
 /// Get a detailed string description for the given error number
 pub fn error_string(errno: i32) -> String {
-    #[cfg(any(target_os = "macos",
-              target_os = "ios",
-              target_os = "android",
-              target_os = "freebsd",
-              target_os = "dragonfly"))]
-    fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
-                  -> c_int {
-        extern {
-            fn strerror_r(errnum: c_int, buf: *mut c_char,
-                          buflen: libc::size_t) -> c_int;
-        }
-        unsafe {
-            strerror_r(errnum, buf, buflen)
-        }
-    }
-
-    // GNU libc provides a non-compliant version of strerror_r by default
-    // and requires macros to instead use the POSIX compliant variant.
-    // So we just use __xpg_strerror_r which is always POSIX compliant
     #[cfg(target_os = "linux")]
-    fn strerror_r(errnum: c_int, buf: *mut c_char,
-                  buflen: libc::size_t) -> c_int {
-        extern {
-            fn __xpg_strerror_r(errnum: c_int,
-                                buf: *mut c_char,
-                                buflen: libc::size_t)
-                                -> c_int;
-        }
-        unsafe {
-            __xpg_strerror_r(errnum, buf, buflen)
-        }
+    extern {
+        #[link_name = "__xpg_strerror_r"]
+        fn strerror_r(errnum: c_int, buf: *mut c_char,
+                      buflen: libc::size_t) -> c_int;
+    }
+    #[cfg(not(target_os = "linux"))]
+    extern {
+        fn strerror_r(errnum: c_int, buf: *mut c_char,
+                      buflen: libc::size_t) -> c_int;
     }
 
     let mut buf = [0 as c_char; TMPBUF_SZ];
@@ -113,15 +84,6 @@ fn __xpg_strerror_r(errnum: c_int,
     }
 }
 
-pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
-    let mut fds = [0; 2];
-    if libc::pipe(fds.as_mut_ptr()) == 0 {
-        Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
-    } else {
-        Err(super::last_error())
-    }
-}
-
 pub fn getcwd() -> IoResult<Path> {
     let mut buf = [0 as c_char; BUF_BYTES];
     unsafe {
@@ -133,43 +95,69 @@ pub fn getcwd() -> IoResult<Path> {
     }
 }
 
-pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
-    extern {
-        fn rust_env_pairs() -> *const *const c_char;
-    }
-    let mut environ = rust_env_pairs();
-    if environ as uint == 0 {
-        panic!("os::env() failure getting env string from OS: {}",
-               os::last_os_error());
+pub fn chdir(p: &Path) -> IoResult<()> {
+    let p = CString::from_slice(p.as_vec());
+    unsafe {
+        match libc::chdir(p.as_ptr()) == (0 as c_int) {
+            true => Ok(()),
+            false => Err(IoError::last_error()),
+        }
     }
-    let mut result = Vec::new();
-    while *environ != ptr::null() {
-        let env_pair = ffi::c_str_to_bytes(&*environ).to_vec();
-        result.push(env_pair);
-        environ = environ.offset(1);
+}
+
+pub struct SplitPaths<'a> {
+    iter: iter::Map<&'a [u8], Path,
+                    slice::Split<'a, u8, fn(&u8) -> bool>,
+                    fn(&'a [u8]) -> Path>,
+}
+
+pub fn split_paths<'a>(unparsed: &'a OsStr) -> SplitPaths<'a> {
+    fn is_colon(b: &u8) -> bool { *b == b':' }
+    let unparsed = unparsed.as_byte_slice();
+    SplitPaths {
+        iter: unparsed.split(is_colon as fn(&u8) -> bool)
+                      .map(Path::new as fn(&'a [u8]) ->  Path)
     }
-    result
 }
 
-pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
-    unparsed.split(|b| *b == b':').map(Path::new).collect()
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = Path;
+    fn next(&mut self) -> Option<Path> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 }
 
-pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsOsStr
+{
     let mut joined = Vec::new();
     let sep = b':';
 
-    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+    for (i, path) in paths.enumerate() {
+        let path = path.as_os_str().as_byte_slice();
         if i > 0 { joined.push(sep) }
-        if path.contains(&sep) { return Err("path segment contains separator `:`") }
+        if path.contains(&sep) {
+            return Err(JoinPathsError)
+        }
         joined.push_all(path);
     }
+    Ok(OsStringExt::from_vec(joined))
+}
 
-    Ok(joined)
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "path segment contains separator `:`".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str { "failed to join paths" }
 }
 
 #[cfg(target_os = "freebsd")]
-pub fn load_self() -> Option<Vec<u8>> {
+pub fn current_exe() -> IoResult<Path> {
     unsafe {
         use libc::funcs::bsd44::*;
         use libc::consts::os::extra::*;
@@ -181,66 +169,276 @@ pub fn load_self() -> Option<Vec<u8>> {
         let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
                          ptr::null_mut(), &mut sz, ptr::null_mut(),
                          0u as libc::size_t);
-        if err != 0 { return None; }
-        if sz == 0 { return None; }
+        if err != 0 { return Err(IoError::last_error()); }
+        if sz == 0 { return Err(IoError::last_error()); }
         let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
         let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
                          v.as_mut_ptr() as *mut libc::c_void, &mut sz,
                          ptr::null_mut(), 0u as libc::size_t);
-        if err != 0 { return None; }
-        if sz == 0 { return None; }
+        if err != 0 { return Err(IoError::last_error()); }
+        if sz == 0 { return Err(IoError::last_error()); }
         v.set_len(sz as uint - 1); // chop off trailing NUL
-        Some(v)
+        Ok(Path::new(v))
     }
 }
 
 #[cfg(target_os = "dragonfly")]
-pub fn load_self() -> Option<Vec<u8>> {
-    use old_io;
-
-    match old_io::fs::readlink(&Path::new("/proc/curproc/file")) {
-        Ok(path) => Some(path.into_vec()),
-        Err(..) => None
-    }
+pub fn current_exe() -> IoResult<Path> {
+    fs::readlink(&Path::new("/proc/curproc/file"))
 }
 
 #[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn load_self() -> Option<Vec<u8>> {
-    use old_io;
-
-    match old_io::fs::readlink(&Path::new("/proc/self/exe")) {
-        Ok(path) => Some(path.into_vec()),
-        Err(..) => None
-    }
+pub fn current_exe() -> IoResult<Path> {
+    fs::readlink(&Path::new("/proc/self/exe"))
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
-pub fn load_self() -> Option<Vec<u8>> {
+pub fn current_exe() -> IoResult<Path> {
     unsafe {
         use libc::funcs::extra::_NSGetExecutablePath;
         let mut sz: u32 = 0;
         _NSGetExecutablePath(ptr::null_mut(), &mut sz);
-        if sz == 0 { return None; }
+        if sz == 0 { return Err(IoError::last_error()); }
         let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
         let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
-        if err != 0 { return None; }
+        if err != 0 { return Err(IoError::last_error()); }
         v.set_len(sz as uint - 1); // chop off trailing NUL
-        Some(v)
+        Ok(Path::new(v))
     }
 }
 
-pub fn chdir(p: &Path) -> IoResult<()> {
-    let p = CString::from_slice(p.as_vec());
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: *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() }
+}
+
+/// 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);
+        range(0, argc as isize).map(|i| {
+            let bytes = ffi::c_str_to_bytes(&*argv.offset(i)).to_vec();
+            OsStringExt::from_vec(bytes)
+        }).collect::<Vec<_>>()
+    };
+    Args {
+        iter: vec.into_iter(),
+        _dont_send_or_sync_me: 0 as *mut (),
+    }
+}
+
+// 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 range(0, [args count])
+//      res.push([args objectAtIndex:i])
+// res
+#[cfg(target_os = "ios")]
+pub fn args() -> Args {
+    use iter::range;
+    use mem;
+
+    #[link(name = "objc")]
+    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")]
+    extern {}
+
+    type Sel = *const libc::c_void;
+    type NsId = *const libc::c_void;
+
+    let mut res = Vec::new();
+
     unsafe {
-        match libc::chdir(p.as_ptr()) == (0 as c_int) {
-            true => Ok(()),
-            false => Err(IoError::last_error()),
+        let processInfoSel = sel_registerName("processInfo\0".as_ptr());
+        let argumentsSel = sel_registerName("arguments\0".as_ptr());
+        let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
+        let countSel = sel_registerName("count\0".as_ptr());
+        let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+        let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+        let info = objc_msgSend(klass, processInfoSel);
+        let args = objc_msgSend(info, argumentsSel);
+
+        let cnt: int = mem::transmute(objc_msgSend(args, countSel));
+        for i in range(0, cnt) {
+            let tmp = objc_msgSend(args, objectAtSel, i);
+            let utf_c_str: *const libc::c_char =
+                mem::transmute(objc_msgSend(tmp, utf8Sel));
+            let bytes = ffi::c_str_to_bytes(&utf_c_str).to_vec();
+            res.push(OsString::from_vec(bytes))
+        }
+    }
+
+    Args { iter: res.into_iter(), _dont_send_or_sync_me: 0 as *mut _ }
+}
+
+#[cfg(any(target_os = "linux",
+          target_os = "android",
+          target_os = "freebsd",
+          target_os = "dragonfly"))]
+pub fn args() -> Args {
+    use rt;
+    let bytes = rt::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: 0 as *mut _ }
+}
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+    _dont_send_or_sync_me: *mut (),
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[cfg(target_os = "macos")]
+pub unsafe fn environ() -> *mut *const *const c_char {
+    extern { fn _NSGetEnviron() -> *mut *const *const c_char; }
+    _NSGetEnviron()
+}
+
+#[cfg(not(target_os = "macos"))]
+pub unsafe fn environ() -> *mut *const *const c_char {
+    extern { static mut environ: *const *const c_char; }
+    &mut environ
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+    return unsafe {
+        let mut environ = *environ();
+        if environ as usize == 0 {
+            panic!("os::env() failure getting env string from OS: {}",
+                   IoError::last_error());
+        }
+        let mut result = Vec::new();
+        while *environ != ptr::null() {
+            result.push(parse(ffi::c_str_to_bytes(&*environ)));
+            environ = environ.offset(1);
+        }
+        Env { iter: result.into_iter(), _dont_send_or_sync_me: 0 as *mut _ }
+    };
+
+    fn parse(input: &[u8]) -> (OsString, OsString) {
+        let mut it = input.splitn(1, |b| *b == b'=');
+        let key = it.next().unwrap().to_vec();
+        let default: &[u8] = &[];
+        let val = it.next().unwrap_or(default).to_vec();
+        (OsStringExt::from_vec(key), OsStringExt::from_vec(val))
+    }
+}
+
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    unsafe {
+        let s = CString::from_slice(k.as_byte_slice());
+        let s = libc::getenv(s.as_ptr()) as *const _;
+        if s.is_null() {
+            None
+        } else {
+            Some(OsStringExt::from_vec(ffi::c_str_to_bytes(&s).to_vec()))
+        }
+    }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) {
+    unsafe {
+        let k = CString::from_slice(k.as_byte_slice());
+        let v = CString::from_slice(v.as_byte_slice());
+        if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 {
+            panic!("failed setenv: {}", IoError::last_error());
+        }
+    }
+}
+
+pub fn unsetenv(n: &OsStr) {
+    unsafe {
+        let nbuf = CString::from_slice(n.as_byte_slice());
+        if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
+            panic!("failed unsetenv: {}", IoError::last_error());
         }
     }
 }
 
-pub fn page_size() -> uint {
+pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
+    let mut fds = [0; 2];
+    if libc::pipe(fds.as_mut_ptr()) == 0 {
+        Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
+    } else {
+        Err(IoError::last_error())
+    }
+}
+
+pub fn page_size() -> usize {
     unsafe {
-        libc::sysconf(libc::_SC_PAGESIZE) as uint
+        libc::sysconf(libc::_SC_PAGESIZE) as usize
     }
 }
+
+pub fn temp_dir() -> Path {
+    getenv("TMPDIR".as_os_str()).map(|p| Path::new(p.into_vec())).unwrap_or_else(|| {
+        if cfg!(target_os = "android") {
+            Path::new("/data/local/tmp")
+        } else {
+            Path::new("/tmp")
+        }
+    })
+}
+
+pub fn home_dir() -> Option<Path> {
+    getenv("HOME".as_os_str()).or_else(|| unsafe {
+        let mut amt = match libc::sysconf(c::_SC_GETPW_R_SIZE_MAX) {
+            n if n < 0 => 512 as usize,
+            n => n as usize,
+        };
+        let me = libc::getuid();
+        loop {
+            let mut buf = Vec::with_capacity(amt);
+            let mut passwd: c::passwd = mem::zeroed();
+            let mut result = 0 as *mut _;
+            match c::getpwuid_r(me, &mut passwd, buf.as_mut_ptr(),
+                                buf.capacity() as libc::size_t,
+                                &mut result) {
+                0 if !result.is_null() => {}
+                _ => return None
+            }
+            let ptr = passwd.pw_dir as *const _;
+            let bytes = ffi::c_str_to_bytes(&ptr).to_vec();
+            return Some(OsStringExt::from_vec(bytes))
+        }
+    }).map(|os| {
+        Path::new(os.into_vec())
+    })
+}
index b004a47f8a349481b05fb65296c8345234f36223..ae648d13959f952311bc59f0754d363807e81f08 100644 (file)
@@ -72,18 +72,6 @@ mod rustrt {
             }
         }
 
-        #[cfg(target_os = "macos")]
-        unsafe fn set_environ(envp: *const c_void) {
-            extern { fn _NSGetEnviron() -> *mut *const c_void; }
-
-            *_NSGetEnviron() = envp;
-        }
-        #[cfg(not(target_os = "macos"))]
-        unsafe fn set_environ(envp: *const c_void) {
-            extern { static mut environ: *const c_void; }
-            environ = envp;
-        }
-
         unsafe fn set_cloexec(fd: c_int) {
             let ret = c::ioctl(fd, c::FIOCLEX);
             assert_eq!(ret, 0);
@@ -269,7 +257,7 @@ fn setgroups(ngroups: libc::c_int,
                     fail(&mut output);
                 }
                 if !envp.is_null() {
-                    set_environ(envp);
+                    *sys::os::environ() = envp as *const _;
                 }
                 let _ = execvp(*argv, argv as *mut _);
                 fail(&mut output);
index 1be1a412ffa9ff9c7dead7f4bf5537a4f4e1010c..66712b9e3a1e6e6edfbd0bd50a0b3821b46fb555 100644 (file)
@@ -7,29 +7,31 @@
 // <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.
-/// As always, windows has something very different than unix, we mainly want
-/// to avoid having to depend too much on libunwind for windows.
-///
-/// If you google around, you'll find a fair bit of references to built-in
-/// functions to get backtraces on windows. It turns out that most of these are
-/// in an external library called dbghelp. I was unable to find this library
-/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
-/// of it.
-///
-/// You'll also find that there's a function called CaptureStackBackTrace
-/// mentioned frequently (which is also easy to use), but sadly I didn't have a
-/// copy of that function in my mingw install (maybe it was broken?). Instead,
-/// this takes the route of using StackWalk64 in order to walk the stack.
+
+//! As always, windows has something very different than unix, we mainly want
+//! to avoid having to depend too much on libunwind for windows.
+//!
+//! If you google around, you'll find a fair bit of references to built-in
+//! functions to get backtraces on windows. It turns out that most of these are
+//! in an external library called dbghelp. I was unable to find this library
+//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
+//! of it.
+//!
+//! You'll also find that there's a function called CaptureStackBackTrace
+//! mentioned frequently (which is also easy to use), but sadly I didn't have a
+//! copy of that function in my mingw install (maybe it was broken?). Instead,
+//! this takes the route of using StackWalk64 in order to walk the stack.
+
+#![allow(dead_code)]
 
 use dynamic_lib::DynamicLibrary;
 use ffi;
-use core::ops::Index;
 use intrinsics;
 use old_io::{IoResult, Writer};
 use libc;
 use mem;
 use ops::Drop;
-use option::Option::{Some, None};
+use option::Option::{Some};
 use path::Path;
 use ptr;
 use result::Result::{Ok, Err};
@@ -296,7 +298,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
     // According to windows documentation, all dbghelp functions are
     // single-threaded.
     static LOCK: StaticMutex = MUTEX_INIT;
-    let _g = unsafe { LOCK.lock() };
+    let _g = LOCK.lock();
 
     // Open up dbghelp.dll, we don't link to it explicitly because it can't
     // always be found. Additionally, it's nice having fewer dependencies.
index da3b7ee2f2fd5d7c560b59e658ae0143253ee5a3..0355565cf00f29d9b52c912b0f144eeba68b3b25 100644 (file)
 
 //! C definitions used by libnative that don't belong in liblibc
 
-#![allow(overflowing_literals)]
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
+#![allow(bad_style, dead_code, overflowing_literals)]
 
 use libc;
-use prelude::v1::*;
 
-pub const WSADESCRIPTION_LEN: uint = 256;
-pub const WSASYS_STATUS_LEN: uint = 128;
+pub use self::GET_FILEEX_INFO_LEVELS::*;
+pub use self::FILE_INFO_BY_HANDLE_CLASS::*;
+pub use libc::consts::os::extra::{
+    FILE_ATTRIBUTE_READONLY,
+    FILE_ATTRIBUTE_DIRECTORY,
+};
+
+pub const WSADESCRIPTION_LEN: usize = 256;
+pub const WSASYS_STATUS_LEN: usize = 128;
 pub const FIONBIO: libc::c_long = 0x8004667e;
-pub const FD_SETSIZE: uint = 64;
+pub const FD_SETSIZE: usize = 64;
 pub const MSG_DONTWAIT: libc::c_int = 0;
 pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582;
 pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4;
 pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT;
 
 pub const FD_ACCEPT: libc::c_long = 0x08;
-pub const FD_MAX_EVENTS: uint = 10;
+pub const FD_MAX_EVENTS: usize = 10;
 pub const WSA_INFINITE: libc::DWORD = libc::INFINITE;
 pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT;
 pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0;
 pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED;
 
+pub const ERROR_NO_MORE_FILES: libc::DWORD = 18;
+pub const TOKEN_READ: libc::DWORD = 0x20008;
+
 #[repr(C)]
 #[cfg(target_arch = "x86")]
 pub struct WSADATA {
@@ -80,7 +87,7 @@ pub struct fd_set {
 }
 
 pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
-    set.fd_array[set.fd_count as uint] = s;
+    set.fd_array[set.fd_count as usize] = s;
     set.fd_count += 1;
 }
 
@@ -110,6 +117,69 @@ pub struct CONSOLE_SCREEN_BUFFER_INFO {
 }
 pub type PCONSOLE_SCREEN_BUFFER_INFO = *mut CONSOLE_SCREEN_BUFFER_INFO;
 
+#[repr(C)]
+pub struct WIN32_FILE_ATTRIBUTE_DATA {
+    pub dwFileAttributes: libc::DWORD,
+    pub ftCreationTime: libc::FILETIME,
+    pub ftLastAccessTime: libc::FILETIME,
+    pub ftLastWriteTime: libc::FILETIME,
+    pub nFileSizeHigh: libc::DWORD,
+    pub nFileSizeLow: libc::DWORD,
+}
+
+#[repr(C)]
+pub struct BY_HANDLE_FILE_INFORMATION {
+    pub dwFileAttributes: libc::DWORD,
+    pub ftCreationTime: libc::FILETIME,
+    pub ftLastAccessTime: libc::FILETIME,
+    pub ftLastWriteTime: libc::FILETIME,
+    pub dwVolumeSerialNumber: libc::DWORD,
+    pub nFileSizeHigh: libc::DWORD,
+    pub nFileSizeLow: libc::DWORD,
+    pub nNumberOfLinks: libc::DWORD,
+    pub nFileIndexHigh: libc::DWORD,
+    pub nFileIndexLow: libc::DWORD,
+}
+
+pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
+
+#[repr(C)]
+pub enum GET_FILEEX_INFO_LEVELS {
+    GetFileExInfoStandard,
+    GetFileExMaxInfoLevel
+}
+
+#[repr(C)]
+pub enum FILE_INFO_BY_HANDLE_CLASS {
+    FileBasicInfo                   = 0,
+    FileStandardInfo                = 1,
+    FileNameInfo                    = 2,
+    FileRenameInfo                  = 3,
+    FileDispositionInfo             = 4,
+    FileAllocationInfo              = 5,
+    FileEndOfFileInfo               = 6,
+    FileStreamInfo                  = 7,
+    FileCompressionInfo             = 8,
+    FileAttributeTagInfo            = 9,
+    FileIdBothDirectoryInfo         = 10, // 0xA
+    FileIdBothDirectoryRestartInfo  = 11, // 0xB
+    FileIoPriorityHintInfo          = 12, // 0xC
+    FileRemoteProtocolInfo          = 13, // 0xD
+    FileFullDirectoryInfo           = 14, // 0xE
+    FileFullDirectoryRestartInfo    = 15, // 0xF
+    FileStorageInfo                 = 16, // 0x10
+    FileAlignmentInfo               = 17, // 0x11
+    FileIdInfo                      = 18, // 0x12
+    FileIdExtdDirectoryInfo         = 19, // 0x13
+    FileIdExtdDirectoryRestartInfo  = 20, // 0x14
+    MaximumFileInfoByHandlesClass
+}
+
+#[repr(C)]
+pub struct FILE_END_OF_FILE_INFO {
+    pub EndOfFile: libc::LARGE_INTEGER,
+}
+
 #[link(name = "ws2_32")]
 extern "system" {
     pub fn WSAStartup(wVersionRequested: libc::WORD,
@@ -156,31 +226,29 @@ pub fn CancelIoEx(hFile: libc::HANDLE,
 }
 
 pub mod compat {
-    use intrinsics::{atomic_store_relaxed, transmute};
-    use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
     use prelude::v1::*;
+
     use ffi::CString;
+    use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
+    use sync::atomic::{AtomicUsize, Ordering};
 
     extern "system" {
         fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
         fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
     }
 
-    // store_func() is idempotent, so using relaxed ordering for the atomics
-    // should be enough.  This way, calling a function in this compatibility
-    // layer (after it's loaded) shouldn't be any slower than a regular DLL
-    // call.
-    unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
+    fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str,
+                  fallback: usize) -> usize {
         let mut module: Vec<u16> = module.utf16_units().collect();
         module.push(0);
         let symbol = CString::from_slice(symbol.as_bytes());
-        let handle = GetModuleHandleW(module.as_ptr());
-        let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr()));
-        atomic_store_relaxed(ptr, if func == 0 {
-            fallback
-        } else {
-            func
-        })
+        let func = unsafe {
+            let handle = GetModuleHandleW(module.as_ptr());
+            GetProcAddress(handle, symbol.as_ptr()) as usize
+        };
+        let value = if func == 0 {fallback} else {func};
+        ptr.store(value, Ordering::SeqCst);
+        value
     }
 
     /// Macro for creating a compatibility fallback for a Windows function
@@ -192,29 +260,36 @@ unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint)
     /// })
     /// ```
     ///
-    /// Note that arguments unused by the fallback implementation should not be called `_` as
-    /// they are used to be passed to the real function if available.
+    /// Note that arguments unused by the fallback implementation should not be
+    /// called `_` as they are used to be passed to the real function if
+    /// available.
     macro_rules! compat_fn {
         ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*)
                                       -> $rettype:ty { $fallback:expr }) => (
             #[inline(always)]
             pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
-                static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk;
-
-                extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
-                    unsafe {
-                        ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
-                                                    stringify!($module),
-                                                    stringify!($symbol),
-                                                    fallback as uint);
-                        ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
-                    }
+                use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+                use mem;
+
+                static PTR: AtomicUsize = ATOMIC_USIZE_INIT;
+
+                fn load() -> usize {
+                    ::sys::c::compat::store_func(&PTR,
+                                                 stringify!($module),
+                                                 stringify!($symbol),
+                                                 fallback as usize)
                 }
 
                 extern "system" fn fallback($($argname: $argtype),*)
                                             -> $rettype { $fallback }
 
-                ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                let addr = match PTR.load(Ordering::SeqCst) {
+                    0 => load(),
+                    n => n,
+                };
+                let f: extern "system" fn($($argtype),*) -> $rettype =
+                    mem::transmute(addr);
+                f($($argname),*)
             }
         )
     }
@@ -229,10 +304,7 @@ pub mod kernel32 {
         use libc::c_uint;
         use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
         use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
-
-        extern "system" {
-            fn SetLastError(dwErrCode: DWORD);
-        }
+        use sys::c::SetLastError;
 
         compat_fn! {
             kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
@@ -282,4 +354,42 @@ pub fn GetConsoleScreenBufferInfo(
         hConsoleOutput: libc::HANDLE,
         lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO,
     ) -> libc::BOOL;
+
+    pub fn GetFileAttributesExW(lpFileName: libc::LPCWSTR,
+                                fInfoLevelId: GET_FILEEX_INFO_LEVELS,
+                                lpFileInformation: libc::LPVOID) -> libc::BOOL;
+    pub fn RemoveDirectoryW(lpPathName: libc::LPCWSTR) -> libc::BOOL;
+    pub fn SetFileAttributesW(lpFileName: libc::LPCWSTR,
+                              dwFileAttributes: libc::DWORD) -> libc::BOOL;
+    pub fn GetFileAttributesW(lpFileName: libc::LPCWSTR) -> libc::DWORD;
+    pub fn GetFileInformationByHandle(hFile: libc::HANDLE,
+                            lpFileInformation: LPBY_HANDLE_FILE_INFORMATION)
+                            -> libc::BOOL;
+
+    pub fn SetLastError(dwErrCode: libc::DWORD);
+    pub fn GetCommandLineW() -> *mut libc::LPCWSTR;
+    pub fn LocalFree(ptr: *mut libc::c_void);
+    pub fn CommandLineToArgvW(lpCmdLine: *mut libc::LPCWSTR,
+                              pNumArgs: *mut libc::c_int) -> *mut *mut u16;
+    pub fn SetFileTime(hFile: libc::HANDLE,
+                       lpCreationTime: *const libc::FILETIME,
+                       lpLastAccessTime: *const libc::FILETIME,
+                       lpLastWriteTime: *const libc::FILETIME) -> libc::BOOL;
+    pub fn SetFileInformationByHandle(hFile: libc::HANDLE,
+                    FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
+                    lpFileInformation: libc::LPVOID,
+                    dwBufferSize: libc::DWORD) -> libc::BOOL;
+    pub fn GetTempPathW(nBufferLength: libc::DWORD,
+                        lpBuffer: libc::LPCWSTR) -> libc::DWORD;
+    pub fn OpenProcessToken(ProcessHandle: libc::HANDLE,
+                            DesiredAccess: libc::DWORD,
+                            TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
+    pub fn GetCurrentProcess() -> libc::HANDLE;
+}
+
+#[link(name = "userenv")]
+extern "system" {
+    pub fn GetUserProfileDirectoryW(hToken: libc::HANDLE,
+                                    lpProfileDir: libc::LPCWSTR,
+                                    lpcchSize: *mut libc::DWORD) -> libc::BOOL;
 }
index 80cdf9782f20f7c0d2c2a5b9c5a0dd0c7dfcaff8..304d7e015327960747c3fc6dbb0e413d4b5845fd 100644 (file)
 
 //! Blocking Windows-based file I/O
 
-use alloc::arc::Arc;
 use libc::{self, c_int};
 
 use mem;
-use sys::os::fill_utf16_buf_and_decode;
-use path;
 use ptr;
-use str;
 use old_io;
 
 use prelude::v1::*;
 use sys;
-use sys::os;
-use sys_common::{keep_going, eof, mkerr_libc};
+use sys_common::{mkerr_libc};
 
 use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
 use old_io::{IoResult, IoError, FileStat, SeekStyle};
@@ -262,7 +257,7 @@ fn prune(root: &Path, dirs: Vec<Path>) -> Vec<Path> {
             let mut more_files = 1 as libc::BOOL;
             while more_files != 0 {
                 {
-                    let filename = os::truncate_utf16_at_nul(&wfd.cFileName);
+                    let filename = super::truncate_utf16_at_nul(&wfd.cFileName);
                     match String::from_utf16(filename) {
                         Ok(filename) => paths.push(Path::new(filename)),
                         Err(..) => {
@@ -368,19 +363,12 @@ pub fn readlink(p: &Path) -> IoResult<Path> {
     }
     // Specify (sz - 1) because the documentation states that it's the size
     // without the null pointer
-    let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
+    let ret = super::fill_utf16_buf(|buf, sz| unsafe {
         GetFinalPathNameByHandleW(handle,
                                   buf as *const u16,
                                   sz - 1,
                                   libc::VOLUME_NAME_DOS)
-    });
-    let ret = match ret {
-        Some(ref s) if s.starts_with(r"\\?\") => { // "
-            Ok(Path::new(&s[4..]))
-        }
-        Some(s) => Ok(Path::new(s)),
-        None => Err(super::last_error()),
-    };
+    }, super::os2path);
     assert!(unsafe { libc::CloseHandle(handle) } != 0);
     return ret;
 }
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
new file mode 100644 (file)
index 0000000..6737eee
--- /dev/null
@@ -0,0 +1,31 @@
+// 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 prelude::v1::*;
+
+use libc::{self, HANDLE};
+
+pub struct Handle(HANDLE);
+
+unsafe impl Send for Handle {}
+unsafe impl Sync for Handle {}
+
+impl Handle {
+    pub fn new(handle: HANDLE) -> Handle {
+        Handle(handle)
+    }
+}
+
+impl Drop for Handle {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.0); }
+    }
+}
+
index e8b65c9b64ea36e189543d55c977ce942a3cf5d0..8dd467eba9e2a885e5ffff07ee34ec4d28d08e26 100644 (file)
 #![allow(missing_docs)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
-#![allow(unused_imports)]
-#![allow(dead_code)]
-#![allow(unused_unsafe)]
-#![allow(unused_mut)]
-
-extern crate libc;
 
 use prelude::v1::*;
 
-use num;
+use ffi::OsStr;
+use libc;
 use mem;
 use old_io::{self, IoResult, IoError};
+use os::windows::OsStrExt;
 use sync::{Once, ONCE_INIT};
 
 macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
@@ -38,9 +34,10 @@ macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
 
 pub mod backtrace;
 pub mod c;
-pub mod ext;
 pub mod condvar;
+pub mod ext;
 pub mod fs;
+pub mod handle;
 pub mod helper_signal;
 pub mod mutex;
 pub mod os;
@@ -48,12 +45,12 @@ macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
 pub mod pipe;
 pub mod process;
 pub mod rwlock;
-pub mod sync;
 pub mod stack_overflow;
+pub mod sync;
 pub mod tcp;
-pub mod time;
 pub mod thread;
 pub mod thread_local;
+pub mod time;
 pub mod timer;
 pub mod tty;
 pub mod udp;
@@ -158,7 +155,7 @@ pub fn ms_to_timeval(ms: u64) -> libc::timeval {
 
 pub fn wouldblock() -> bool {
     let err = os::errno();
-    err == libc::WSAEWOULDBLOCK as uint
+    err == libc::WSAEWOULDBLOCK as i32
 }
 
 pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
@@ -191,17 +188,93 @@ pub fn unimpl() -> IoError {
     }
 }
 
-pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
+fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
     match s {
-        Some(s) => Ok({
-            let mut s = s.utf16_units().collect::<Vec<u16>>();
-            s.push(0);
-            s
-        }),
+        Some(s) => Ok(to_utf16_os(OsStr::from_str(s))),
         None => Err(IoError {
             kind: old_io::InvalidInput,
             desc: "valid unicode input required",
-            detail: None
-        })
+            detail: None,
+        }),
+    }
+}
+
+fn to_utf16_os(s: &OsStr) -> Vec<u16> {
+    let mut v: Vec<_> = s.encode_wide().collect();
+    v.push(0);
+    v
+}
+
+// Many Windows APIs follow a pattern of where we hand the a buffer and then
+// they will report back to us how large the buffer should be or how many bytes
+// currently reside in the buffer. This function is an abstraction over these
+// functions by making them easier to call.
+//
+// The first callback, `f1`, is yielded a (pointer, len) pair which can be
+// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
+// The closure is expected to return what the syscall returns which will be
+// interpreted by this function to determine if the syscall needs to be invoked
+// again (with more buffer space).
+//
+// Once the syscall has completed (errors bail out early) the second closure is
+// yielded the data which has been read from the syscall. The return value
+// from this closure is then the return value of the function.
+fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> IoResult<T>
+    where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD,
+          F2: FnOnce(&[u16]) -> T
+{
+    // Start off with a stack buf but then spill over to the heap if we end up
+    // needing more space.
+    let mut stack_buf = [0u16; 512];
+    let mut heap_buf = Vec::new();
+    unsafe {
+        let mut n = stack_buf.len();
+        loop {
+            let buf = if n <= stack_buf.len() {
+                &mut stack_buf[]
+            } else {
+                let extra = n - heap_buf.len();
+                heap_buf.reserve(extra);
+                heap_buf.set_len(n);
+                &mut heap_buf[]
+            };
+
+            // This function is typically called on windows API functions which
+            // will return the correct length of the string, but these functions
+            // also return the `0` on error. In some cases, however, the
+            // returned "correct length" may actually be 0!
+            //
+            // To handle this case we call `SetLastError` to reset it to 0 and
+            // then check it again if we get the "0 error value". If the "last
+            // error" is still 0 then we interpret it as a 0 length buffer and
+            // not an actual error.
+            c::SetLastError(0);
+            let k = match f1(buf.as_mut_ptr(), n as libc::DWORD) {
+                0 if libc::GetLastError() == 0 => 0,
+                0 => return Err(IoError::last_error()),
+                n => n,
+            } as usize;
+            if k == n && libc::GetLastError() ==
+                            libc::ERROR_INSUFFICIENT_BUFFER as libc::DWORD {
+                n *= 2;
+            } else if k >= n {
+                n = k;
+            } else {
+                return Ok(f2(&buf[..k]))
+            }
+        }
+    }
+}
+
+fn os2path(s: &[u16]) -> Path {
+    // FIXME: this should not be a panicking conversion (aka path reform)
+    Path::new(String::from_utf16(s).unwrap())
+}
+
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+    match v.iter().position(|c| *c == 0) {
+        // don't include the 0
+        Some(i) => &v[..i],
+        None => v
     }
 }
index 828ad795ed3b4eaa3871fb0d4c415fa79e714cab..75495efc7cbb60f9d2a7f12ffa78980f2540ab39 100644 (file)
@@ -37,8 +37,6 @@ pub unsafe fn raw(m: &Mutex) -> ffi::PSRWLOCK {
 // no guarantees of fairness.
 
 impl Mutex {
-    #[inline]
-    pub unsafe fn new() -> Mutex { MUTEX_INIT }
     #[inline]
     pub unsafe fn lock(&self) {
         ffi::AcquireSRWLockExclusive(self.inner.get())
index a82259ad5ec57ee4af485cdf655df00b50885b31..c71e2d057c35117af1cea05e2506f25fdf2f075a 100644 (file)
 
 //! Implementation of `std::os` functionality for Windows
 
-// FIXME: move various extern bindings from here into liblibc or
-// something similar
+#![allow(bad_style)]
 
 use prelude::v1::*;
+use os::windows::*;
 
+use error::Error as StdError;
+use ffi::{OsString, OsStr, AsOsStr};
 use fmt;
-use old_io::{IoResult, IoError};
-use iter::repeat;
-use libc::{c_int, c_void};
-use libc;
-use os;
-use path::BytesContainer;
+use iter::Range;
+use libc::types::os::arch::extra::LPWCH;
+use libc::{self, c_int, c_void};
+use mem;
+use old_io::{IoError, IoResult};
 use ptr;
 use slice;
+use sys::c;
 use sys::fs::FileDesc;
+use sys::handle::Handle as RawHandle;
 
-use os::TMPBUF_SZ;
-use libc::types::os::arch::extra::DWORD;
+use libc::funcs::extra::kernel32::{
+    GetEnvironmentStringsW,
+    FreeEnvironmentStringsW
+};
 
-const BUF_BYTES : uint = 2048u;
-
-/// Return a slice of `v` ending at (and not including) the first NUL
-/// (0).
-pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
-    match v.iter().position(|c| *c == 0) {
-        // don't include the 0
-        Some(i) => &v[..i],
-        None => v
-    }
-}
-
-pub fn errno() -> uint {
-    use libc::types::os::arch::extra::DWORD;
-
-    #[link_name = "kernel32"]
-    extern "system" {
-        fn GetLastError() -> DWORD;
-    }
-
-    unsafe {
-        GetLastError() as uint
-    }
+pub fn errno() -> i32 {
+    unsafe { libc::GetLastError() as i32 }
 }
 
 /// Get a detailed string description for the given error number
@@ -80,7 +64,7 @@ fn FormatMessageW(flags: DWORD,
     // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
     let langId = 0x0800 as DWORD;
 
-    let mut buf = [0 as WCHAR; TMPBUF_SZ];
+    let mut buf = [0 as WCHAR; 2048];
 
     unsafe {
         let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
@@ -94,200 +78,170 @@ fn FormatMessageW(flags: DWORD,
         if res == 0 {
             // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
             let fm_err = errno();
-            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+            return format!("OS Error {} (FormatMessageW() returned error {})",
+                           errnum, fm_err);
         }
 
-        let msg = String::from_utf16(truncate_utf16_at_nul(&buf));
+        let b = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
+        let msg = String::from_utf16(&buf[..b]);
         match msg {
-            Ok(msg) => format!("OS Error {}: {}", errnum, msg),
+            Ok(msg) => msg,
             Err(..) => format!("OS Error {} (FormatMessageW() returned \
                                 invalid UTF-16)", errnum),
         }
     }
 }
 
-pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
-    // Windows pipes work subtly differently than unix pipes, and their
-    // inheritance has to be handled in a different way that I do not
-    // fully understand. Here we explicitly make the pipe non-inheritable,
-    // which means to pass it to a subprocess they need to be duplicated
-    // first, as in std::run.
-    let mut fds = [0; 2];
-    match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
-                     (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
-        0 => {
-            assert!(fds[0] != -1 && fds[0] != 0);
-            assert!(fds[1] != -1 && fds[1] != 0);
-            Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
-        }
-        _ => Err(IoError::last_error()),
-    }
+pub struct Env {
+    base: LPWCH,
+    cur: LPWCH,
 }
 
-pub fn fill_utf16_buf_and_decode<F>(mut f: F) -> Option<String> where
-    F: FnMut(*mut u16, DWORD) -> DWORD,
-{
-    unsafe {
-        let mut n = TMPBUF_SZ as DWORD;
-        let mut res = None;
-        let mut done = false;
-        while !done {
-            let mut buf: Vec<u16> = repeat(0u16).take(n as uint).collect();
-            let k = f(buf.as_mut_ptr(), n);
-            if k == (0 as DWORD) {
-                done = true;
-            } else if k == n &&
-                      libc::GetLastError() ==
-                      libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
-                n *= 2 as DWORD;
-            } else if k >= n {
-                n = k;
-            } else {
-                done = true;
-            }
-            if k != 0 && done {
-                let sub = &buf[.. (k as uint)];
-                // We want to explicitly catch the case when the
-                // closure returned invalid UTF-16, rather than
-                // set `res` to None and continue.
-                let s = String::from_utf16(sub).ok()
-                    .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
-                res = Some(s)
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        unsafe {
+            if *self.cur == 0 { return None }
+            let p = &*self.cur;
+            let mut len = 0;
+            while *(p as *const _).offset(len) != 0 {
+                len += 1;
             }
+            let p = p as *const u16;
+            let s = slice::from_raw_buf(&p, len as usize);
+            self.cur = self.cur.offset(len + 1);
+
+            let (k, v) = match s.iter().position(|&b| b == '=' as u16) {
+                Some(n) => (&s[..n], &s[n+1..]),
+                None => (s, &[][]),
+            };
+            Some((OsStringExt::from_wide(k), OsStringExt::from_wide(v)))
         }
-        return res;
     }
 }
 
-pub fn getcwd() -> IoResult<Path> {
-    use libc::DWORD;
-    use libc::GetCurrentDirectoryW;
-    use old_io::OtherIoError;
+impl Drop for Env {
+    fn drop(&mut self) {
+        unsafe { FreeEnvironmentStringsW(self.base); }
+    }
+}
 
-    let mut buf = [0 as u16; BUF_BYTES];
+pub fn env() -> Env {
     unsafe {
-        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
-            return Err(IoError::last_error());
+        let ch = GetEnvironmentStringsW();
+        if ch as usize == 0 {
+            panic!("failure getting env string from OS: {}",
+                   IoError::last_error());
         }
+        Env { base: ch, cur: ch }
     }
+}
 
-    match String::from_utf16(truncate_utf16_at_nul(&buf)) {
-        Ok(ref cwd) => Ok(Path::new(cwd)),
-        Err(..) => Err(IoError {
-            kind: OtherIoError,
-            desc: "GetCurrentDirectoryW returned invalid UTF-16",
-            detail: None,
-        }),
-    }
+pub struct SplitPaths<'a> {
+    data: EncodeWide<'a>,
+    must_yield: bool,
 }
 
-pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
-    use libc::funcs::extra::kernel32::{
-        GetEnvironmentStringsW,
-        FreeEnvironmentStringsW
-    };
-    let ch = GetEnvironmentStringsW();
-    if ch as uint == 0 {
-        panic!("os::env() failure getting env string from OS: {}",
-               os::last_os_error());
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
+    SplitPaths {
+        data: unparsed.encode_wide(),
+        must_yield: true,
     }
-    // Here, we lossily decode the string as UTF16.
-    //
-    // The docs suggest that the result should be in Unicode, but
-    // Windows doesn't guarantee it's actually UTF16 -- it doesn't
-    // validate the environment string passed to CreateProcess nor
-    // SetEnvironmentVariable.  Yet, it's unlikely that returning a
-    // raw u16 buffer would be of practical use since the result would
-    // be inherently platform-dependent and introduce additional
-    // complexity to this code.
-    //
-    // Using the non-Unicode version of GetEnvironmentStrings is even
-    // worse since the result is in an OEM code page.  Characters that
-    // can't be encoded in the code page would be turned into question
-    // marks.
-    let mut result = Vec::new();
-    let mut i = 0;
-    while *ch.offset(i) != 0 {
-        let p = &*ch.offset(i);
-        let mut len = 0;
-        while *(p as *const _).offset(len) != 0 {
-            len += 1;
-        }
-        let p = p as *const u16;
-        let s = slice::from_raw_buf(&p, len as uint);
-        result.push(String::from_utf16_lossy(s).into_bytes());
-        i += len as int + 1;
-    }
-    FreeEnvironmentStringsW(ch);
-    result
 }
 
-pub fn split_paths(unparsed: &[u8]) -> 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.iter() {
-        match *b {
-            b';' if !in_quote => {
-                parsed.push(Path::new(in_progress.as_slice()));
-                in_progress.truncate(0)
-            }
-            b'"' => {
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = Path;
+    fn next(&mut self) -> Option<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 must_yield = self.must_yield;
+        self.must_yield = false;
+
+        let mut in_progress = Vec::new();
+        let mut in_quote = false;
+        for b in self.data.by_ref() {
+            if b == '"' as u16 {
                 in_quote = !in_quote;
+            } else if b == ';' as u16 && !in_quote {
+                self.must_yield = true;
+                break
+            } else {
+                in_progress.push(b)
             }
-            _  => {
-                in_progress.push(*b);
-            }
+        }
+
+        if !must_yield && in_progress.is_empty() {
+            None
+        } else {
+            Some(super::os2path(&in_progress[]))
         }
     }
-    parsed.push(Path::new(in_progress));
-    parsed
 }
 
-pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+#[derive(Show)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsOsStr
+{
     let mut joined = Vec::new();
-    let sep = b';';
+    let sep = b';' as u16;
 
-    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+    for (i, path) in paths.enumerate() {
+        let path = path.as_os_str();
         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'"');
+        let v = path.encode_wide().collect::<Vec<u16>>();
+        if v.contains(&(b'"' as u16)) {
+            return Err(JoinPathsError)
+        } else if v.contains(&sep) {
+            joined.push(b'"' as u16);
+            joined.push_all(&v[]);
+            joined.push(b'"' as u16);
         } else {
-            joined.push_all(path);
+            joined.push_all(&v[]);
         }
     }
 
-    Ok(joined)
+    Ok(OsStringExt::from_wide(&joined[]))
 }
 
-pub fn load_self() -> Option<Vec<u8>> {
-    unsafe {
-        fill_utf16_buf_and_decode(|buf, sz| {
-            libc::GetModuleFileNameW(ptr::null_mut(), buf, sz)
-        }).map(|s| s.to_string().into_bytes())
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "path segment contains `\"`".fmt(f)
     }
 }
 
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> IoResult<Path> {
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        libc::GetModuleFileNameW(ptr::null_mut(), buf, sz)
+    }, super::os2path)
+}
+
+pub fn getcwd() -> IoResult<Path> {
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        libc::GetCurrentDirectoryW(sz, buf)
+    }, super::os2path)
+}
+
 pub fn chdir(p: &Path) -> IoResult<()> {
-    let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
+    let mut p = p.as_os_str().encode_wide().collect::<Vec<_>>();
     p.push(0);
 
     unsafe {
@@ -298,39 +252,124 @@ pub fn chdir(p: &Path) -> IoResult<()> {
     }
 }
 
-pub fn page_size() -> uint {
-    use mem;
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    let k = super::to_utf16_os(k);
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        libc::GetEnvironmentVariableW(k.as_ptr(), buf, sz)
+    }, |buf| {
+        OsStringExt::from_wide(buf)
+    }).ok()
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) {
+    let k = super::to_utf16_os(k);
+    let v = super::to_utf16_os(v);
+
     unsafe {
-        let mut info = mem::zeroed();
-        libc::GetSystemInfo(&mut info);
+        if libc::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) == 0 {
+            panic!("failed to set env: {}", IoError::last_error());
+        }
+    }
+}
 
-        return info.dwPageSize as uint;
+pub fn unsetenv(n: &OsStr) {
+    let v = super::to_utf16_os(n);
+    unsafe {
+        if libc::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) == 0 {
+            panic!("failed to unset env: {}", IoError::last_error());
+        }
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::truncate_utf16_at_nul;
+pub struct Args {
+    range: Range<isize>,
+    cur: *mut *mut u16,
+}
 
-    #[test]
-    fn test_truncate_utf16_at_nul() {
-        let v = [];
-        let b: &[u16] = &[];
-        assert_eq!(truncate_utf16_at_nul(&v), b);
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        self.range.next().map(|i| unsafe {
+            let ptr = *self.cur.offset(i);
+            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_buf(&ptr, len as usize);
+            OsStringExt::from_wide(buf)
+        })
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+}
 
-        let v = [0, 2, 3];
-        assert_eq!(truncate_utf16_at_nul(&v), b);
+impl Drop for Args {
+    fn drop(&mut self) {
+        unsafe { c::LocalFree(self.cur as *mut c_void); }
+    }
+}
 
-        let v = [1, 0, 3];
-        let b: &[u16] = &[1];
-        assert_eq!(truncate_utf16_at_nul(&v), b);
+pub fn args() -> Args {
+    unsafe {
+        let mut nArgs: c_int = 0;
+        let lpCmdLine = c::GetCommandLineW();
+        let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs);
 
-        let v = [1, 2, 0];
-        let b: &[u16] = &[1, 2];
-        assert_eq!(truncate_utf16_at_nul(&v), b);
+        Args { cur: szArgList, range: range(0, nArgs as isize) }
+    }
+}
 
-        let v = [1, 2, 3];
-        let b: &[u16] = &[1, 2, 3];
-        assert_eq!(truncate_utf16_at_nul(&v), b);
+pub fn page_size() -> usize {
+    unsafe {
+        let mut info = mem::zeroed();
+        libc::GetSystemInfo(&mut info);
+        return info.dwPageSize as usize;
+    }
+}
+
+pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
+    // Windows pipes work subtly differently than unix pipes, and their
+    // inheritance has to be handled in a different way that I do not
+    // fully understand. Here we explicitly make the pipe non-inheritable,
+    // which means to pass it to a subprocess they need to be duplicated
+    // first, as in std::run.
+    let mut fds = [0; 2];
+    match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
+    (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
+        0 => {
+            assert!(fds[0] != -1 && fds[0] != 0);
+            assert!(fds[1] != -1 && fds[1] != 0);
+            Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
+        }
+        _ => Err(IoError::last_error()),
     }
 }
+
+pub fn temp_dir() -> Path {
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        c::GetTempPathW(sz, buf)
+    }, super::os2path).unwrap()
+}
+
+pub fn home_dir() -> Option<Path> {
+    getenv("HOME".as_os_str()).or_else(|| {
+        getenv("USERPROFILE".as_os_str())
+    }).map(|os| {
+        // FIXME: OsString => Path
+        Path::new(os.to_str().unwrap())
+    }).or_else(|| unsafe {
+        let me = c::GetCurrentProcess();
+        let mut token = ptr::null_mut();
+        if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
+            return None
+        }
+        let _handle = RawHandle::new(token);
+        super::fill_utf16_buf(|buf, mut sz| {
+            match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
+                0 if libc::GetLastError() != 0 => 0,
+                0 => sz,
+                n => n as libc::DWORD,
+            }
+        }, super::os2path).ok()
+    })
+}
index 0bc2a827272e607dede9d063ed9389a13698f316..1f228b7d32e35042131cefcbce51e8fab742409a 100644 (file)
@@ -352,7 +352,7 @@ fn write_closed(&self) -> bool {
 
     fn cancel_io(&self) -> IoResult<()> {
         match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } {
-            0 if os::errno() == libc::ERROR_NOT_FOUND as uint => {
+            0 if os::errno() == libc::ERROR_NOT_FOUND as i32 => {
                 Ok(())
             }
             0 => Err(super::last_error()),
@@ -374,7 +374,7 @@ pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         // acquire the lock.
         //
         // See comments in close_read() about why this lock is necessary.
-        let guard = unsafe { self.inner.lock.lock() };
+        let guard = self.inner.lock.lock();
         if self.read_closed() {
             return Err(eof())
         }
@@ -392,7 +392,7 @@ pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
 
         // If our errno doesn't say that the I/O is pending, then we hit some
         // legitimate error and return immediately.
-        if os::errno() != libc::ERROR_IO_PENDING as uint {
+        if os::errno() != libc::ERROR_IO_PENDING as i32 {
             return Err(super::last_error())
         }
 
@@ -417,7 +417,7 @@ pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
             // If we succeeded, or we failed for some reason other than
             // CancelIoEx, return immediately
             if ret != 0 { return Ok(bytes_read as uint) }
-            if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+            if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 {
                 return Err(super::last_error())
             }
 
@@ -450,7 +450,7 @@ pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
             // going after we woke up.
             //
             // See comments in close_read() about why this lock is necessary.
-            let guard = unsafe { self.inner.lock.lock() };
+            let guard = self.inner.lock.lock();
             if self.write_closed() {
                 return Err(epipe())
             }
@@ -465,7 +465,7 @@ pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
             drop(guard);
 
             if ret == 0 {
-                if err != libc::ERROR_IO_PENDING as uint {
+                if err != libc::ERROR_IO_PENDING as i32 {
                     return Err(decode_error_detailed(err as i32))
                 }
                 // Process a timeout if one is pending
@@ -481,7 +481,7 @@ pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
                 // aborted, then check to see if the write half was actually
                 // closed or whether we woke up from the read half closing.
                 if ret == 0 {
-                    if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+                    if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 {
                         return Err(super::last_error())
                     }
                     if !wait_succeeded.is_ok() {
@@ -525,14 +525,14 @@ pub fn close_read(&mut self) -> IoResult<()> {
         // close_read() between steps 1 and 2. By atomically executing steps 1
         // and 2 with a lock with respect to close_read(), we're guaranteed that
         // no thread will erroneously sit in a read forever.
-        let _guard = unsafe { self.inner.lock.lock() };
+        let _guard = self.inner.lock.lock();
         self.inner.read_closed.store(true, Ordering::SeqCst);
         self.cancel_io()
     }
 
     pub fn close_write(&mut self) -> IoResult<()> {
         // see comments in close_read() for why this lock is necessary
-        let _guard = unsafe { self.inner.lock.lock() };
+        let _guard = self.inner.lock.lock();
         self.inner.write_closed.store(true, Ordering::SeqCst);
         self.cancel_io()
     }
index 3d66718d00ba0c73f08cd996603eea48de612975..043fdb38805dc8d20b422c48491adde83a41e677 100644 (file)
 
 use prelude::v1::*;
 
+use collections::hash_map::Hasher;
 use collections;
+use env;
 use ffi::CString;
 use hash::Hash;
-use collections::hash_map::Hasher;
+use libc::{pid_t, c_void};
+use libc;
+use mem;
 use old_io::fs::PathExtensions;
-use old_io::process::{ProcessExit, ExitStatus, ExitSignal};
+use old_io::process::{ProcessExit, ExitStatus};
 use old_io::{IoResult, IoError};
 use old_io;
-use libc::{pid_t, c_void, c_int};
-use libc;
-use mem;
 use os;
 use path::BytesContainer;
 use ptr;
 use str;
-use sys::fs::FileDesc;
 use sync::{StaticMutex, MUTEX_INIT};
+use sys::fs::FileDesc;
 
-use sys::fs;
-use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
-use sys_common::helper_thread::Helper;
-use sys_common::{AsInner, mkerr_libc, timeout};
+use sys::timer;
+use sys_common::{AsInner, timeout};
 
 pub use sys_common::ProcessConfig;
 
@@ -106,6 +105,7 @@ pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
         return ret;
     }
 
+    #[allow(deprecated)]
     pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
                               out_fd: Option<P>, err_fd: Option<P>)
                               -> IoResult<Process>
@@ -128,7 +128,7 @@ pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
         use libc::funcs::extra::msvcrt::get_osfhandle;
 
         use mem;
-        use iter::{Iterator, IteratorExt};
+        use iter::IteratorExt;
         use str::StrExt;
 
         if cfg.gid().is_some() || cfg.uid().is_some() {
@@ -149,7 +149,7 @@ pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
                 // program exists.
                 for path in os::split_paths(v.container_as_bytes()).into_iter() {
                     let path = path.join(cfg.program().as_bytes())
-                                   .with_extension(os::consts::EXE_EXTENSION);
+                                   .with_extension(env::consts::EXE_EXTENSION);
                     if path.exists() {
                         return Some(CString::from_slice(path.as_vec()))
                     }
index 88ce85c39f625f67694fa326be1cd9c487b922b8..76fe352ed7717cf6ca623bb693a1fcf48663d5c1 100644 (file)
@@ -18,9 +18,6 @@ pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> }
 };
 
 impl RWLock {
-    #[inline]
-    pub unsafe fn new() -> RWLock { RWLOCK_INIT }
-
     #[inline]
     pub unsafe fn read(&self) {
         ffi::AcquireSRWLockShared(self.inner.get())
index 0cb4c573ae3ef63d47c48d04bac02d545eb638cf..b0410701ee1012817ece41b7fb16eda28c47cd08 100644 (file)
@@ -14,7 +14,7 @@
 use mem;
 use libc;
 use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
-use sys_common::{stack, thread_info};
+use sys_common::stack;
 
 pub struct Handler {
     _data: *mut libc::c_void
@@ -30,14 +30,6 @@ impl Drop for Handler {
     fn drop(&mut self) {}
 }
 
-// get_task_info is called from an exception / signal handler.
-// It returns the guard page of the current task or 0 if that
-// guard page doesn't exist. None is returned if there's currently
-// no local task.
-unsafe fn get_task_guard_page() -> uint {
-    thread_info::stack_guard()
-}
-
 // This is initialized in init() and only read from after
 static mut PAGE_SIZE: uint = 0;
 
index d60646b7db915cdd9e568619adf8d017b598bc6e..7614104c98bf37bd8759f6832b6fcaa39d70b4a9 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc::{BOOL, DWORD, c_void, LPVOID, c_ulong};
+use libc::{BOOL, DWORD, LPVOID, c_ulong};
 use libc::types::os::arch::extra::BOOLEAN;
 
 pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
index 64e440331c127e72c4b078ec098a33bbf794cba7..4804ca510cb0ba0e9be1b8fffdbd75285e78a703 100644 (file)
 use mem;
 use ptr;
 use prelude::v1::*;
-use super::{last_error, last_net_error, retry, sock_t};
+use super::{last_error, last_net_error, sock_t};
 use sync::Arc;
 use sync::atomic::{AtomicBool, Ordering};
-use sys::fs::FileDesc;
 use sys::{self, c, set_nonblocking, wouldblock, timer};
-use sys_common::{self, timeout, eof, net};
+use sys_common::{timeout, eof, net};
 
 pub use sys_common::net::TcpStream;
 
@@ -202,10 +201,6 @@ pub fn accept(&mut self) -> IoResult<TcpStream> {
         Err(eof())
     }
 
-    pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
-        net::sockname(self.socket(), libc::getsockname)
-    }
-
     pub fn set_timeout(&mut self, timeout: Option<u64>) {
         self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
     }
index a94adcb3bc7b93b80a61f5a8d621d3c1b96d6565..a38dc9b2d340770d643d9539e349abe706044292 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::prelude::*;
-
 use boxed::Box;
 use cmp;
 use mem;
index 0f8ceed39a6ccbfbcbcf98790fa0c618896795df..cc731738afe3e12b6d64a48a3f4587c6a6f580d2 100644 (file)
@@ -233,6 +233,7 @@ unsafe fn unregister_dtor(key: Key) -> bool {
     }
 }
 
+#[allow(dead_code)] // actually called above
 unsafe fn run_dtors() {
     let mut any_run = true;
     for _ in 0..5 {
index 34f3c418c558d5de67e0fe8be9299252ae8974fb..d156dd801f974905fa2d2adc64d461bbdd1f7525 100644 (file)
@@ -28,8 +28,6 @@
 
 use old_io::IoResult;
 use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
-use sys::c;
-use sys::fs::FileDesc;
 use sys_common::helper_thread::Helper;
 
 helper_init! { static HELPER: Helper<Req> }
index 6ecabfa985304efabddfcf36b8ffd7ee2962f8a1..f02c8e49f4188d1b26c783ffcd20ace768c8e8f7 100644 (file)
@@ -38,7 +38,7 @@
 use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
 use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
 use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
-use super::c::{ERROR_ILLEGAL_CHARACTER, CONSOLE_SCREEN_BUFFER_INFO};
+use super::c::{CONSOLE_SCREEN_BUFFER_INFO};
 use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
 use super::c::{GetConsoleScreenBufferInfo};
 
@@ -155,9 +155,6 @@ pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
                      (info.srWindow.Bottom + 1 - info.srWindow.Top) as int)),
         }
     }
-
-    // Let us magically declare this as a TTY
-    pub fn isatty(&self) -> bool { true }
 }
 
 impl Drop for TTY {
index 9f6bf352b040443609c0c30943259b5f8b0656d7..9aa454ae8d5c9c567395e92d4a39c9997be1bb09 100644 (file)
@@ -21,7 +21,7 @@
 use ext::build::AstBuilder;
 use parse::token;
 
-use std::os;
+use std::env;
 
 pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                               -> Box<base::MacResult+'cx> {
@@ -30,8 +30,8 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
         Some(v) => v
     };
 
-    let e = match os::getenv(&var[]) {
-      None => {
+    let e = match env::var_string(&var[]) {
+      Err(..) => {
           cx.expr_path(cx.path_all(sp,
                                    true,
                                    vec!(cx.ident_of("std"),
@@ -48,7 +48,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
                                                    ast::MutImmutable)),
                                    Vec::new()))
       }
-      Some(s) => {
+      Ok(s) => {
           cx.expr_call_global(sp,
                               vec!(cx.ident_of("std"),
                                    cx.ident_of("option"),
@@ -101,12 +101,12 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
         }
     }
 
-    let e = match os::getenv(var.get()) {
-        None => {
+    let e = match env::var_string(var.get()) {
+        Err(..) => {
             cx.span_err(sp, msg.get());
             cx.expr_usize(sp, 0)
         }
-        Some(s) => cx.expr_str(sp, token::intern_and_get_ident(&s[]))
+        Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s[]))
     };
     MacExpr::new(e)
 }
index 73424136cfbcb44594e0f6d964197b45dcaec803..54b37483f8cfdc5f456d1496fd53818fbe4a6d09 100644 (file)
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(core)]
+#![feature(env)]
 #![feature(hash)]
 #![feature(int_uint)]
 #![feature(io)]
 #![feature(libc)]
-#![feature(os)]
 #![feature(path)]
 #![feature(quote, unsafe_destructor)]
 #![feature(rustc_private)]
index 27a46fb5a682ddc3b1475a40c5c03c0218bb02ef..219c9baf4c8925a6a742917f42da6064febe825c 100644 (file)
 #![feature(core)]
 #![feature(int_uint)]
 #![feature(io)]
-#![feature(os)]
 #![feature(path)]
 #![feature(rustc_private)]
 #![feature(slicing_syntax)]
 #![feature(staged_api)]
 #![feature(std_misc)]
 #![feature(unicode)]
+#![feature(env)]
+#![cfg_attr(windows, feature(libc))]
 
 #[macro_use] extern crate log;
 
index d126717ce6817bce3520c57ed5b0847f78d890a0..17c1e8cdb8c6d119b9a06a2f28836638993f35e6 100644 (file)
@@ -12,7 +12,7 @@
 
 use std::collections::HashMap;
 use std::old_io::IoResult;
-use std::os;
+use std::env;
 
 use attr;
 use color;
@@ -172,9 +172,9 @@ impl<T: Writer+Send> TerminfoTerminal<T> {
     /// Returns `None` whenever the terminal cannot be created for some
     /// reason.
     pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
-        let term = match os::getenv("TERM") {
-            Some(t) => t,
-            None => {
+        let term = match env::var_string("TERM") {
+            Ok(t) => t,
+            Err(..) => {
                 debug!("TERM environment variable not defined");
                 return None;
             }
@@ -182,7 +182,7 @@ pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
 
         let entry = open(&term[]);
         if entry.is_err() {
-            if os::getenv("MSYSCON").map_or(false, |s| {
+            if env::var_string("MSYSCON").ok().map_or(false, |s| {
                     "mintty.exe" == s
                 }) {
                 // msys terminal
index 1e84c0462d61ac19d035b5ad6388706fff7571ec..74c986cd9e262358ec5029d1e443e02da767b31d 100644 (file)
@@ -14,8 +14,7 @@
 
 use std::old_io::File;
 use std::old_io::fs::PathExtensions;
-use std::os::getenv;
-use std::os;
+use std::env;
 
 /// Return path to database entry for `term`
 pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
@@ -23,21 +22,21 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
         return None;
     }
 
-    let homedir = os::homedir();
+    let homedir = env::home_dir();
 
     let mut dirs_to_search = Vec::new();
     let first_char = term.char_at(0);
 
     // Find search directory
-    match getenv("TERMINFO") {
-        Some(dir) => dirs_to_search.push(Path::new(dir)),
-        None => {
+    match env::var_string("TERMINFO") {
+        Ok(dir) => dirs_to_search.push(Path::new(dir)),
+        Err(..) => {
             if homedir.is_some() {
                 // ncurses compatibility;
                 dirs_to_search.push(homedir.unwrap().join(".terminfo"))
             }
-            match getenv("TERMINFO_DIRS") {
-                Some(dirs) => for i in dirs.split(':') {
+            match env::var_string("TERMINFO_DIRS") {
+                Ok(dirs) => for i in dirs.split(':') {
                     if i == "" {
                         dirs_to_search.push(Path::new("/usr/share/terminfo"));
                     } else {
@@ -48,7 +47,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
                 // According to  /etc/terminfo/README, after looking at
                 // ~/.terminfo, ncurses will search /etc/terminfo, then
                 // /lib/terminfo, and eventually /usr/share/terminfo.
-                None => {
+                Err(..) => {
                     dirs_to_search.push(Path::new("/etc/terminfo"));
                     dirs_to_search.push(Path::new("/lib/terminfo"));
                     dirs_to_search.push(Path::new("/usr/share/terminfo"));
index f22c58c54a6851a00cff14575b378ef1225b86f4..2295f122822db33f16f9995dc2e87350975a2d86 100644 (file)
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(core)]
+#![feature(env)]
 #![feature(hash)]
 #![feature(int_uint)]
 #![feature(io)]
-#![feature(os)]
 #![feature(path)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -75,7 +75,7 @@
 use std::old_io;
 use std::iter::repeat;
 use std::num::{Float, Int};
-use std::os;
+use std::env;
 use std::sync::mpsc::{channel, Sender};
 use std::thread::{self, Thread};
 use std::thunk::{Thunk, Invoke};
@@ -388,7 +388,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
 
     let mut nocapture = matches.opt_present("nocapture");
     if !nocapture {
-        nocapture = os::getenv("RUST_TEST_NOCAPTURE").is_some();
+        nocapture = env::var("RUST_TEST_NOCAPTURE").is_some();
     }
 
     let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
@@ -817,15 +817,15 @@ fn run_tests<F>(opts: &TestOpts,
 
 fn get_concurrency() -> uint {
     use std::rt;
-    match os::getenv("RUST_TEST_TASKS") {
-        Some(s) => {
+    match env::var_string("RUST_TEST_TASKS") {
+        Ok(s) => {
             let opt_n: Option<uint> = s.parse().ok();
             match opt_n {
                 Some(n) if n > 0 => n,
                 _ => panic!("RUST_TEST_TASKS is `{}`, should be a positive integer.", s)
             }
         }
-        None => {
+        Err(..) => {
             rt::default_sched_threads()
         }
     }
index 4a9c5a91dcf0bb5cbe976946e7782e8f9225c627..ac32b5848015d80c45096d676d183d4f274cd0bc 100644 (file)
 use std::sync::Arc;
 use std::thread::Thread;
 
-const ITER: int = 50;
+const ITER: usize = 50;
 const LIMIT: f64 = 2.0;
-const WORKERS: uint = 16;
+const WORKERS: usize = 16;
 
 #[inline(always)]
-fn mandelbrot<W: old_io::Writer>(w: uint, mut out: W) -> old_io::IoResult<()> {
+fn mandelbrot<W: old_io::Writer>(w: usize, mut out: W) -> old_io::IoResult<()> {
     assert!(WORKERS % 2 == 0);
 
     // Ensure w and h are multiples of 8.
@@ -198,7 +198,6 @@ fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
 
 fn main() {
     let args = os::args();
-    let args = args.as_slice();
     let res = if args.len() < 2 {
         println!("Test mode: do not dump the image because it's not utf8, \
                   which interferes with the test runner.");
index ebcf46f7277d6f41e23d5cdf0c02ef3c28258198..960d9ef0f2fb4d4b97a47e3ed2783fd8daa31987 100644 (file)
@@ -12,7 +12,6 @@
 #![deny(unused_assignments)]
 #![allow(dead_code, non_camel_case_types)]
 #![feature(core)]
-#![feature(os)]
 
 fn f1(x: isize) {
     //~^ ERROR unused variable: `x`
@@ -98,7 +97,7 @@ fn f5c() {
     for (_, x) in [1is, 2, 3].iter().enumerate() {
     //~^ ERROR unused variable: `x`
         continue;
-        std::os::set_exit_status(*x); //~ WARNING unreachable statement
+        drop(*x as i32); //~ WARNING unreachable statement
     }
 }
 
diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs
new file mode 100644 (file)
index 0000000..5623e98
--- /dev/null
@@ -0,0 +1,45 @@
+// 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 std::env::*;
+
+#[cfg(unix)]
+fn main() {
+    let oldhome = var("HOME");
+
+    set_var("HOME", "/home/MountainView");
+    assert!(home_dir() == Some(Path::new("/home/MountainView")));
+
+    remove_var("HOME");
+    assert!(home_dir().is_some());
+}
+
+#[cfg(windows)]
+fn main() {
+    let oldhome = var("HOME");
+    let olduserprofile = var("USERPROFILE");
+
+    remove_var("HOME");
+    remove_var("USERPROFILE");
+
+    assert!(home_dir().is_some());
+
+    set_var("HOME", "/home/MountainView");
+    assert!(home_dir() == Some(Path::new("/home/MountainView")));
+
+    remove_var("HOME");
+
+    set_var("USERPROFILE", "/home/MountainView");
+    assert!(home_dir() == Some(Path::new("/home/MountainView")));
+
+    set_var("HOME", "/home/MountainView");
+    set_var("USERPROFILE", "/home/PaloAlto");
+    assert!(home_dir() == Some(Path::new("/home/MountainView")));
+}
diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs
new file mode 100644 (file)
index 0000000..892041b
--- /dev/null
@@ -0,0 +1,22 @@
+// 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 std::env::*;
+
+fn main() {
+    for (k, v) in vars() {
+        let v2 = var(&k);
+        // MingW seems to set some funky environment variables like
+        // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
+        // from vars() but not visible from var().
+        assert!(v2.is_none() || v2.as_ref().map(|s| &**s) == Some(&*v),
+                "bad vars->var transition: {:?} {:?} {:?}", k, v, v2);
+    }
+}