]> git.lizzy.rs Git - rust.git/blob - src/libstd/env.rs
Auto merge of #36078 - ollie27:rustdoc_search_assocconst, r=alexcrichton
[rust.git] / src / libstd / env.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Inspection and manipulation of the process's environment.
12 //!
13 //! This module contains methods to inspect various aspects such as
14 //! environment variables, process arguments, the current directory, and various
15 //! other important directories.
16
17 #![stable(feature = "env", since = "1.0.0")]
18
19 use error::Error;
20 use ffi::{OsStr, OsString};
21 use fmt;
22 use io;
23 use path::{Path, PathBuf};
24 use sys::os as os_imp;
25
26 /// Returns the current working directory as a `PathBuf`.
27 ///
28 /// # Errors
29 ///
30 /// Returns an `Err` if the current working directory value is invalid.
31 /// Possible cases:
32 ///
33 /// * Current directory does not exist.
34 /// * There are insufficient permissions to access the current directory.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// use std::env;
40 ///
41 /// // We assume that we are in a valid directory.
42 /// let p = env::current_dir().unwrap();
43 /// println!("The current directory is {}", p.display());
44 /// ```
45 #[stable(feature = "env", since = "1.0.0")]
46 pub fn current_dir() -> io::Result<PathBuf> {
47     os_imp::getcwd()
48 }
49
50 /// Changes the current working directory to the specified path, returning
51 /// whether the change was completed successfully or not.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use std::env;
57 /// use std::path::Path;
58 ///
59 /// let root = Path::new("/");
60 /// assert!(env::set_current_dir(&root).is_ok());
61 /// println!("Successfully changed working directory to {}!", root.display());
62 /// ```
63 #[stable(feature = "env", since = "1.0.0")]
64 pub fn set_current_dir<P: AsRef<Path>>(p: P) -> io::Result<()> {
65     os_imp::chdir(p.as_ref())
66 }
67
68 /// An iterator over a snapshot of the environment variables of this process.
69 ///
70 /// This iterator is created through `std::env::vars()` and yields `(String,
71 /// String)` pairs.
72 #[stable(feature = "env", since = "1.0.0")]
73 pub struct Vars { inner: VarsOs }
74
75 /// An iterator over a snapshot of the environment variables of this process.
76 ///
77 /// This iterator is created through `std::env::vars_os()` and yields
78 /// `(OsString, OsString)` pairs.
79 #[stable(feature = "env", since = "1.0.0")]
80 pub struct VarsOs { inner: os_imp::Env }
81
82 /// Returns an iterator of (variable, value) pairs of strings, for all the
83 /// environment variables of the current process.
84 ///
85 /// The returned iterator contains a snapshot of the process's environment
86 /// variables at the time of this invocation, modifications to environment
87 /// variables afterwards will not be reflected in the returned iterator.
88 ///
89 /// # Panics
90 ///
91 /// While iterating, the returned iterator will panic if any key or value in the
92 /// environment is not valid unicode. If this is not desired, consider using the
93 /// `env::vars_os` function.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use std::env;
99 ///
100 /// // We will iterate through the references to the element returned by
101 /// // env::vars();
102 /// for (key, value) in env::vars() {
103 ///     println!("{}: {}", key, value);
104 /// }
105 /// ```
106 #[stable(feature = "env", since = "1.0.0")]
107 pub fn vars() -> Vars {
108     Vars { inner: vars_os() }
109 }
110
111 /// Returns an iterator of (variable, value) pairs of OS strings, for all the
112 /// environment variables of the current process.
113 ///
114 /// The returned iterator contains a snapshot of the process's environment
115 /// variables at the time of this invocation, modifications to environment
116 /// variables afterwards will not be reflected in the returned iterator.
117 ///
118 /// # Examples
119 ///
120 /// ```
121 /// use std::env;
122 ///
123 /// // We will iterate through the references to the element returned by
124 /// // env::vars_os();
125 /// for (key, value) in env::vars_os() {
126 ///     println!("{:?}: {:?}", key, value);
127 /// }
128 /// ```
129 #[stable(feature = "env", since = "1.0.0")]
130 pub fn vars_os() -> VarsOs {
131     VarsOs { inner: os_imp::env() }
132 }
133
134 #[stable(feature = "env", since = "1.0.0")]
135 impl Iterator for Vars {
136     type Item = (String, String);
137     fn next(&mut self) -> Option<(String, String)> {
138         self.inner.next().map(|(a, b)| {
139             (a.into_string().unwrap(), b.into_string().unwrap())
140         })
141     }
142     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
143 }
144
145 #[stable(feature = "env", since = "1.0.0")]
146 impl Iterator for VarsOs {
147     type Item = (OsString, OsString);
148     fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
149     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
150 }
151
152 /// Fetches the environment variable `key` from the current process.
153 ///
154 /// The returned result is `Ok(s)` if the environment variable is present and is
155 /// valid unicode. If the environment variable is not present, or it is not
156 /// valid unicode, then `Err` will be returned.
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use std::env;
162 ///
163 /// let key = "HOME";
164 /// match env::var(key) {
165 ///     Ok(val) => println!("{}: {:?}", key, val),
166 ///     Err(e) => println!("couldn't interpret {}: {}", key, e),
167 /// }
168 /// ```
169 #[stable(feature = "env", since = "1.0.0")]
170 pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError> {
171     _var(key.as_ref())
172 }
173
174 fn _var(key: &OsStr) -> Result<String, VarError> {
175     match var_os(key) {
176         Some(s) => s.into_string().map_err(VarError::NotUnicode),
177         None => Err(VarError::NotPresent)
178     }
179 }
180
181 /// Fetches the environment variable `key` from the current process, returning
182 /// `None` if the variable isn't set.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use std::env;
188 ///
189 /// let key = "HOME";
190 /// match env::var_os(key) {
191 ///     Some(val) => println!("{}: {:?}", key, val),
192 ///     None => println!("{} is not defined in the environment.", key)
193 /// }
194 /// ```
195 #[stable(feature = "env", since = "1.0.0")]
196 pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
197     _var_os(key.as_ref())
198 }
199
200 fn _var_os(key: &OsStr) -> Option<OsString> {
201     os_imp::getenv(key).unwrap_or_else(|e| {
202         panic!("failed to get environment variable `{:?}`: {}", key, e)
203     })
204 }
205
206 /// Possible errors from the `env::var` method.
207 #[derive(Debug, PartialEq, Eq, Clone)]
208 #[stable(feature = "env", since = "1.0.0")]
209 pub enum VarError {
210     /// The specified environment variable was not present in the current
211     /// process's environment.
212     #[stable(feature = "env", since = "1.0.0")]
213     NotPresent,
214
215     /// The specified environment variable was found, but it did not contain
216     /// valid unicode data. The found data is returned as a payload of this
217     /// variant.
218     #[stable(feature = "env", since = "1.0.0")]
219     NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString),
220 }
221
222 #[stable(feature = "env", since = "1.0.0")]
223 impl fmt::Display for VarError {
224     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225         match *self {
226             VarError::NotPresent => write!(f, "environment variable not found"),
227             VarError::NotUnicode(ref s) => {
228                 write!(f, "environment variable was not valid unicode: {:?}", s)
229             }
230         }
231     }
232 }
233
234 #[stable(feature = "env", since = "1.0.0")]
235 impl Error for VarError {
236     fn description(&self) -> &str {
237         match *self {
238             VarError::NotPresent => "environment variable not found",
239             VarError::NotUnicode(..) => "environment variable was not valid unicode",
240         }
241     }
242 }
243
244 /// Sets the environment variable `k` to the value `v` for the currently running
245 /// process.
246 ///
247 /// Note that while concurrent access to environment variables is safe in Rust,
248 /// some platforms only expose inherently unsafe non-threadsafe APIs for
249 /// inspecting the environment. As a result extra care needs to be taken when
250 /// auditing calls to unsafe external FFI functions to ensure that any external
251 /// environment accesses are properly synchronized with accesses in Rust.
252 ///
253 /// Discussion of this unsafety on Unix may be found in:
254 ///
255 ///  - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
256 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
257 ///
258 /// # Panics
259 ///
260 /// This function may panic if `key` is empty, contains an ASCII equals sign
261 /// `'='` or the NUL character `'\0'`, or when the value contains the NUL
262 /// character.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use std::env;
268 ///
269 /// let key = "KEY";
270 /// env::set_var(key, "VALUE");
271 /// assert_eq!(env::var(key), Ok("VALUE".to_string()));
272 /// ```
273 #[stable(feature = "env", since = "1.0.0")]
274 pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(k: K, v: V) {
275     _set_var(k.as_ref(), v.as_ref())
276 }
277
278 fn _set_var(k: &OsStr, v: &OsStr) {
279     os_imp::setenv(k, v).unwrap_or_else(|e| {
280         panic!("failed to set environment variable `{:?}` to `{:?}`: {}",
281                k, v, e)
282     })
283 }
284
285 /// Removes an environment variable from the environment of the currently running process.
286 ///
287 /// Note that while concurrent access to environment variables is safe in Rust,
288 /// some platforms only expose inherently unsafe non-threadsafe APIs for
289 /// inspecting the environment. As a result extra care needs to be taken when
290 /// auditing calls to unsafe external FFI functions to ensure that any external
291 /// environment accesses are properly synchronized with accesses in Rust.
292 ///
293 /// Discussion of this unsafety on Unix may be found in:
294 ///
295 ///  - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
296 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
297 ///
298 /// # Panics
299 ///
300 /// This function may panic if `key` is empty, contains an ASCII equals sign
301 /// `'='` or the NUL character `'\0'`, or when the value contains the NUL
302 /// character.
303 ///
304 /// # Examples
305 ///
306 /// ```
307 /// use std::env;
308 ///
309 /// let key = "KEY";
310 /// env::set_var(key, "VALUE");
311 /// assert_eq!(env::var(key), Ok("VALUE".to_string()));
312 ///
313 /// env::remove_var(key);
314 /// assert!(env::var(key).is_err());
315 /// ```
316 #[stable(feature = "env", since = "1.0.0")]
317 pub fn remove_var<K: AsRef<OsStr>>(k: K) {
318     _remove_var(k.as_ref())
319 }
320
321 fn _remove_var(k: &OsStr) {
322     os_imp::unsetenv(k).unwrap_or_else(|e| {
323         panic!("failed to remove environment variable `{:?}`: {}", k, e)
324     })
325 }
326
327 /// An iterator over `PathBuf` instances for parsing an environment variable
328 /// according to platform-specific conventions.
329 ///
330 /// This structure is returned from `std::env::split_paths`.
331 #[stable(feature = "env", since = "1.0.0")]
332 pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
333
334 /// Parses input according to platform conventions for the `PATH`
335 /// environment variable.
336 ///
337 /// Returns an iterator over the paths contained in `unparsed`.
338 ///
339 /// # Examples
340 ///
341 /// ```
342 /// use std::env;
343 ///
344 /// let key = "PATH";
345 /// match env::var_os(key) {
346 ///     Some(paths) => {
347 ///         for path in env::split_paths(&paths) {
348 ///             println!("'{}'", path.display());
349 ///         }
350 ///     }
351 ///     None => println!("{} is not defined in the environment.", key)
352 /// }
353 /// ```
354 #[stable(feature = "env", since = "1.0.0")]
355 pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths {
356     SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) }
357 }
358
359 #[stable(feature = "env", since = "1.0.0")]
360 impl<'a> Iterator for SplitPaths<'a> {
361     type Item = PathBuf;
362     fn next(&mut self) -> Option<PathBuf> { self.inner.next() }
363     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
364 }
365
366 /// Error type returned from `std::env::join_paths` when paths fail to be
367 /// joined.
368 #[derive(Debug)]
369 #[stable(feature = "env", since = "1.0.0")]
370 pub struct JoinPathsError {
371     inner: os_imp::JoinPathsError
372 }
373
374 /// Joins a collection of `Path`s appropriately for the `PATH`
375 /// environment variable.
376 ///
377 /// Returns an `OsString` on success.
378 ///
379 /// Returns an `Err` (containing an error message) if one of the input
380 /// `Path`s contains an invalid character for constructing the `PATH`
381 /// variable (a double quote on Windows or a colon on Unix).
382 ///
383 /// # Examples
384 ///
385 /// ```
386 /// use std::env;
387 /// use std::path::PathBuf;
388 ///
389 /// if let Some(path) = env::var_os("PATH") {
390 ///     let mut paths = env::split_paths(&path).collect::<Vec<_>>();
391 ///     paths.push(PathBuf::from("/home/xyz/bin"));
392 ///     let new_path = env::join_paths(paths).unwrap();
393 ///     env::set_var("PATH", &new_path);
394 /// }
395 /// ```
396 #[stable(feature = "env", since = "1.0.0")]
397 pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
398     where I: IntoIterator<Item=T>, T: AsRef<OsStr>
399 {
400     os_imp::join_paths(paths.into_iter()).map_err(|e| {
401         JoinPathsError { inner: e }
402     })
403 }
404
405 #[stable(feature = "env", since = "1.0.0")]
406 impl fmt::Display for JoinPathsError {
407     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
408         self.inner.fmt(f)
409     }
410 }
411
412 #[stable(feature = "env", since = "1.0.0")]
413 impl Error for JoinPathsError {
414     fn description(&self) -> &str { self.inner.description() }
415 }
416
417 /// Returns the path of the current user's home directory if known.
418 ///
419 /// # Unix
420 ///
421 /// Returns the value of the 'HOME' environment variable if it is set
422 /// and not equal to the empty string. Otherwise, it tries to determine the
423 /// home directory by invoking the `getpwuid_r` function on the UID of the
424 /// current user.
425 ///
426 /// # Windows
427 ///
428 /// Returns the value of the 'HOME' environment variable if it is
429 /// set and not equal to the empty string. Otherwise, returns the value of the
430 /// 'USERPROFILE' environment variable if it is set and not equal to the empty
431 /// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to
432 /// return the appropriate path.
433 ///
434 /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx
435 ///
436 /// # Examples
437 ///
438 /// ```
439 /// use std::env;
440 ///
441 /// match env::home_dir() {
442 ///     Some(path) => println!("{}", path.display()),
443 ///     None => println!("Impossible to get your home dir!"),
444 /// }
445 /// ```
446 #[stable(feature = "env", since = "1.0.0")]
447 pub fn home_dir() -> Option<PathBuf> {
448     os_imp::home_dir()
449 }
450
451 /// Returns the path of a temporary directory.
452 ///
453 /// On Unix, returns the value of the `TMPDIR` environment variable if it is
454 /// set, otherwise for non-Android it returns `/tmp`. If Android, since there
455 /// is no global temporary folder (it is usually allocated per-app), it returns
456 /// `/data/local/tmp`.
457 ///
458 /// On Windows, returns the value of, in order, the `TMP`, `TEMP`,
459 /// `USERPROFILE` environment variable if any are set and not the empty
460 /// string. Otherwise, `temp_dir` returns the path of the Windows directory.
461 /// This behavior is identical to that of [`GetTempPath`][msdn], which this
462 /// function uses internally.
463 ///
464 /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx
465 ///
466 /// ```
467 /// use std::env;
468 /// use std::fs::File;
469 ///
470 /// # fn foo() -> std::io::Result<()> {
471 /// let mut dir = env::temp_dir();
472 /// dir.push("foo.txt");
473 ///
474 /// let f = try!(File::create(dir));
475 /// # Ok(())
476 /// # }
477 /// ```
478 #[stable(feature = "env", since = "1.0.0")]
479 pub fn temp_dir() -> PathBuf {
480     os_imp::temp_dir()
481 }
482
483 /// Returns the full filesystem path of the current running executable.
484 ///
485 /// The path returned is not necessarily a "real path" of the executable as
486 /// there may be intermediate symlinks.
487 ///
488 /// # Errors
489 ///
490 /// Acquiring the path of the current executable is a platform-specific operation
491 /// that can fail for a good number of reasons. Some errors can include, but not
492 /// be limited to, filesystem operations failing or general syscall failures.
493 ///
494 /// # Security
495 ///
496 /// The output of this function should not be used in anything that might have
497 /// security implications. For example:
498 ///
499 /// ```
500 /// fn main() {
501 ///     println!("{:?}", std::env::current_exe());
502 /// }
503 /// ```
504 ///
505 /// On Linux systems, if this is compiled as `foo`:
506 ///
507 /// ```bash
508 /// $ rustc foo.rs
509 /// $ ./foo
510 /// Ok("/home/alex/foo")
511 /// ```
512 ///
513 /// And you make a symbolic link of the program:
514 ///
515 /// ```bash
516 /// $ ln foo bar
517 /// ```
518 ///
519 /// When you run it, you won't get the original executable, you'll get the
520 /// symlink:
521 ///
522 /// ```bash
523 /// $ ./bar
524 /// Ok("/home/alex/bar")
525 /// ```
526 ///
527 /// This sort of behavior has been known to [lead to privilege escalation] when
528 /// used incorrectly, for example.
529 ///
530 /// [lead to privilege escalation]: http://securityvulns.com/Wdocument183.html
531 ///
532 /// # Examples
533 ///
534 /// ```
535 /// use std::env;
536 ///
537 /// match env::current_exe() {
538 ///     Ok(exe_path) => println!("Path of this executable is: {}",
539 ///                               exe_path.display()),
540 ///     Err(e) => println!("failed to get current exe path: {}", e),
541 /// };
542 /// ```
543 #[stable(feature = "env", since = "1.0.0")]
544 pub fn current_exe() -> io::Result<PathBuf> {
545     os_imp::current_exe()
546 }
547
548 /// An iterator over the arguments of a process, yielding a `String` value
549 /// for each argument.
550 ///
551 /// This structure is created through the `std::env::args` method.
552 #[stable(feature = "env", since = "1.0.0")]
553 pub struct Args { inner: ArgsOs }
554
555 /// An iterator over the arguments of a process, yielding an `OsString` value
556 /// for each argument.
557 ///
558 /// This structure is created through the `std::env::args_os` method.
559 #[stable(feature = "env", since = "1.0.0")]
560 pub struct ArgsOs { inner: os_imp::Args }
561
562 /// Returns the arguments which this program was started with (normally passed
563 /// via the command line).
564 ///
565 /// The first element is traditionally the path of the executable, but it can be
566 /// set to arbitrary text, and may not even exist. This means this property should
567 /// not be relied upon for security purposes.
568 ///
569 /// # Panics
570 ///
571 /// The returned iterator will panic during iteration if any argument to the
572 /// process is not valid unicode. If this is not desired,
573 /// use the `args_os` function instead.
574 ///
575 /// # Examples
576 ///
577 /// ```
578 /// use std::env;
579 ///
580 /// // Prints each argument on a separate line
581 /// for argument in env::args() {
582 ///     println!("{}", argument);
583 /// }
584 /// ```
585 #[stable(feature = "env", since = "1.0.0")]
586 pub fn args() -> Args {
587     Args { inner: args_os() }
588 }
589
590 /// Returns the arguments which this program was started with (normally passed
591 /// via the command line).
592 ///
593 /// The first element is traditionally the path of the executable, but it can be
594 /// set to arbitrary text, and it may not even exist, so this property should
595 /// not be relied upon for security purposes.
596 ///
597 /// # Examples
598 ///
599 /// ```
600 /// use std::env;
601 ///
602 /// // Prints each argument on a separate line
603 /// for argument in env::args_os() {
604 ///     println!("{:?}", argument);
605 /// }
606 /// ```
607 #[stable(feature = "env", since = "1.0.0")]
608 pub fn args_os() -> ArgsOs {
609     ArgsOs { inner: os_imp::args() }
610 }
611
612 #[stable(feature = "env", since = "1.0.0")]
613 impl Iterator for Args {
614     type Item = String;
615     fn next(&mut self) -> Option<String> {
616         self.inner.next().map(|s| s.into_string().unwrap())
617     }
618     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
619 }
620
621 #[stable(feature = "env", since = "1.0.0")]
622 impl ExactSizeIterator for Args {
623     fn len(&self) -> usize { self.inner.len() }
624 }
625
626 #[stable(feature = "env_iterators", since = "1.11.0")]
627 impl DoubleEndedIterator for Args {
628     fn next_back(&mut self) -> Option<String> {
629         self.inner.next_back().map(|s| s.into_string().unwrap())
630     }
631 }
632
633 #[stable(feature = "env", since = "1.0.0")]
634 impl Iterator for ArgsOs {
635     type Item = OsString;
636     fn next(&mut self) -> Option<OsString> { self.inner.next() }
637     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
638 }
639
640 #[stable(feature = "env", since = "1.0.0")]
641 impl ExactSizeIterator for ArgsOs {
642     fn len(&self) -> usize { self.inner.len() }
643 }
644
645 #[stable(feature = "env_iterators", since = "1.11.0")]
646 impl DoubleEndedIterator for ArgsOs {
647     fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
648 }
649 /// Constants associated with the current target
650 #[stable(feature = "env", since = "1.0.0")]
651 pub mod consts {
652     /// A string describing the architecture of the CPU that is currently
653     /// in use.
654     ///
655     /// Some possible values:
656     ///
657     /// - x86
658     /// - x86_64
659     /// - arm
660     /// - aarch64
661     /// - mips
662     /// - mips64
663     /// - powerpc
664     /// - powerpc64
665     #[stable(feature = "env", since = "1.0.0")]
666     pub const ARCH: &'static str = super::arch::ARCH;
667
668     /// The family of the operating system. Example value is `unix`.
669     ///
670     /// Some possible values:
671     ///
672     /// - unix
673     /// - windows
674     #[stable(feature = "env", since = "1.0.0")]
675     pub const FAMILY: &'static str = super::os::FAMILY;
676
677     /// A string describing the specific operating system in use.
678     /// Example value is `linux`.
679     ///
680     /// Some possible values:
681     ///
682     /// - linux
683     /// - macos
684     /// - ios
685     /// - freebsd
686     /// - dragonfly
687     /// - bitrig
688     /// - netbsd
689     /// - openbsd
690     /// - solaris
691     /// - android
692     /// - windows
693     #[stable(feature = "env", since = "1.0.0")]
694     pub const OS: &'static str = super::os::OS;
695
696     /// Specifies the filename prefix used for shared libraries on this
697     /// platform. Example value is `lib`.
698     ///
699     /// Some possible values:
700     ///
701     /// - lib
702     /// - `""` (an empty string)
703     #[stable(feature = "env", since = "1.0.0")]
704     pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
705
706     /// Specifies the filename suffix used for shared libraries on this
707     /// platform. Example value is `.so`.
708     ///
709     /// Some possible values:
710     ///
711     /// - .so
712     /// - .dylib
713     /// - .dll
714     #[stable(feature = "env", since = "1.0.0")]
715     pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
716
717     /// Specifies the file extension used for shared libraries on this
718     /// platform that goes after the dot. Example value is `so`.
719     ///
720     /// Some possible values:
721     ///
722     /// - so
723     /// - dylib
724     /// - dll
725     #[stable(feature = "env", since = "1.0.0")]
726     pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
727
728     /// Specifies the filename suffix used for executable binaries on this
729     /// platform. Example value is `.exe`.
730     ///
731     /// Some possible values:
732     ///
733     /// - .exe
734     /// - .nexe
735     /// - .pexe
736     /// - `""` (an empty string)
737     #[stable(feature = "env", since = "1.0.0")]
738     pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
739
740     /// Specifies the file extension, if any, used for executable binaries
741     /// on this platform. Example value is `exe`.
742     ///
743     /// Some possible values:
744     ///
745     /// - exe
746     /// - `""` (an empty string)
747     #[stable(feature = "env", since = "1.0.0")]
748     pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
749
750 }
751
752 #[cfg(target_os = "linux")]
753 mod os {
754     pub const FAMILY: &'static str = "unix";
755     pub const OS: &'static str = "linux";
756     pub const DLL_PREFIX: &'static str = "lib";
757     pub const DLL_SUFFIX: &'static str = ".so";
758     pub const DLL_EXTENSION: &'static str = "so";
759     pub const EXE_SUFFIX: &'static str = "";
760     pub const EXE_EXTENSION: &'static str = "";
761 }
762
763 #[cfg(target_os = "macos")]
764 mod os {
765     pub const FAMILY: &'static str = "unix";
766     pub const OS: &'static str = "macos";
767     pub const DLL_PREFIX: &'static str = "lib";
768     pub const DLL_SUFFIX: &'static str = ".dylib";
769     pub const DLL_EXTENSION: &'static str = "dylib";
770     pub const EXE_SUFFIX: &'static str = "";
771     pub const EXE_EXTENSION: &'static str = "";
772 }
773
774 #[cfg(target_os = "ios")]
775 mod os {
776     pub const FAMILY: &'static str = "unix";
777     pub const OS: &'static str = "ios";
778     pub const DLL_PREFIX: &'static str = "lib";
779     pub const DLL_SUFFIX: &'static str = ".dylib";
780     pub const DLL_EXTENSION: &'static str = "dylib";
781     pub const EXE_SUFFIX: &'static str = "";
782     pub const EXE_EXTENSION: &'static str = "";
783 }
784
785 #[cfg(target_os = "freebsd")]
786 mod os {
787     pub const FAMILY: &'static str = "unix";
788     pub const OS: &'static str = "freebsd";
789     pub const DLL_PREFIX: &'static str = "lib";
790     pub const DLL_SUFFIX: &'static str = ".so";
791     pub const DLL_EXTENSION: &'static str = "so";
792     pub const EXE_SUFFIX: &'static str = "";
793     pub const EXE_EXTENSION: &'static str = "";
794 }
795
796 #[cfg(target_os = "dragonfly")]
797 mod os {
798     pub const FAMILY: &'static str = "unix";
799     pub const OS: &'static str = "dragonfly";
800     pub const DLL_PREFIX: &'static str = "lib";
801     pub const DLL_SUFFIX: &'static str = ".so";
802     pub const DLL_EXTENSION: &'static str = "so";
803     pub const EXE_SUFFIX: &'static str = "";
804     pub const EXE_EXTENSION: &'static str = "";
805 }
806
807 #[cfg(target_os = "bitrig")]
808 mod os {
809     pub const FAMILY: &'static str = "unix";
810     pub const OS: &'static str = "bitrig";
811     pub const DLL_PREFIX: &'static str = "lib";
812     pub const DLL_SUFFIX: &'static str = ".so";
813     pub const DLL_EXTENSION: &'static str = "so";
814     pub const EXE_SUFFIX: &'static str = "";
815     pub const EXE_EXTENSION: &'static str = "";
816 }
817
818 #[cfg(target_os = "netbsd")]
819 mod os {
820     pub const FAMILY: &'static str = "unix";
821     pub const OS: &'static str = "netbsd";
822     pub const DLL_PREFIX: &'static str = "lib";
823     pub const DLL_SUFFIX: &'static str = ".so";
824     pub const DLL_EXTENSION: &'static str = "so";
825     pub const EXE_SUFFIX: &'static str = "";
826     pub const EXE_EXTENSION: &'static str = "";
827 }
828
829 #[cfg(target_os = "openbsd")]
830 mod os {
831     pub const FAMILY: &'static str = "unix";
832     pub const OS: &'static str = "openbsd";
833     pub const DLL_PREFIX: &'static str = "lib";
834     pub const DLL_SUFFIX: &'static str = ".so";
835     pub const DLL_EXTENSION: &'static str = "so";
836     pub const EXE_SUFFIX: &'static str = "";
837     pub const EXE_EXTENSION: &'static str = "";
838 }
839
840 #[cfg(target_os = "android")]
841 mod os {
842     pub const FAMILY: &'static str = "unix";
843     pub const OS: &'static str = "android";
844     pub const DLL_PREFIX: &'static str = "lib";
845     pub const DLL_SUFFIX: &'static str = ".so";
846     pub const DLL_EXTENSION: &'static str = "so";
847     pub const EXE_SUFFIX: &'static str = "";
848     pub const EXE_EXTENSION: &'static str = "";
849 }
850
851 #[cfg(target_os = "solaris")]
852 mod os {
853     pub const FAMILY: &'static str = "unix";
854     pub const OS: &'static str = "solaris";
855     pub const DLL_PREFIX: &'static str = "lib";
856     pub const DLL_SUFFIX: &'static str = ".so";
857     pub const DLL_EXTENSION: &'static str = "so";
858     pub const EXE_SUFFIX: &'static str = "";
859     pub const EXE_EXTENSION: &'static str = "";
860 }
861
862 #[cfg(target_os = "windows")]
863 mod os {
864     pub const FAMILY: &'static str = "windows";
865     pub const OS: &'static str = "windows";
866     pub const DLL_PREFIX: &'static str = "";
867     pub const DLL_SUFFIX: &'static str = ".dll";
868     pub const DLL_EXTENSION: &'static str = "dll";
869     pub const EXE_SUFFIX: &'static str = ".exe";
870     pub const EXE_EXTENSION: &'static str = "exe";
871 }
872
873 #[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
874 mod os {
875     pub const FAMILY: &'static str = "unix";
876     pub const OS: &'static str = "nacl";
877     pub const DLL_PREFIX: &'static str = "lib";
878     pub const DLL_SUFFIX: &'static str = ".so";
879     pub const DLL_EXTENSION: &'static str = "so";
880     pub const EXE_SUFFIX: &'static str = ".nexe";
881     pub const EXE_EXTENSION: &'static str = "nexe";
882 }
883 #[cfg(all(target_os = "nacl", target_arch = "le32"))]
884 mod os {
885     pub const FAMILY: &'static str = "unix";
886     pub const OS: &'static str = "pnacl";
887     pub const DLL_PREFIX: &'static str = "lib";
888     pub const DLL_SUFFIX: &'static str = ".pso";
889     pub const DLL_EXTENSION: &'static str = "pso";
890     pub const EXE_SUFFIX: &'static str = ".pexe";
891     pub const EXE_EXTENSION: &'static str = "pexe";
892 }
893
894 #[cfg(target_os = "emscripten")]
895 mod os {
896     pub const FAMILY: &'static str = "unix";
897     pub const OS: &'static str = "emscripten";
898     pub const DLL_PREFIX: &'static str = "lib";
899     pub const DLL_SUFFIX: &'static str = ".so";
900     pub const DLL_EXTENSION: &'static str = "so";
901     pub const EXE_SUFFIX: &'static str = ".js";
902     pub const EXE_EXTENSION: &'static str = "js";
903 }
904
905 #[cfg(target_arch = "x86")]
906 mod arch {
907     pub const ARCH: &'static str = "x86";
908 }
909
910 #[cfg(target_arch = "x86_64")]
911 mod arch {
912     pub const ARCH: &'static str = "x86_64";
913 }
914
915 #[cfg(target_arch = "arm")]
916 mod arch {
917     pub const ARCH: &'static str = "arm";
918 }
919
920 #[cfg(target_arch = "aarch64")]
921 mod arch {
922     pub const ARCH: &'static str = "aarch64";
923 }
924
925 #[cfg(target_arch = "mips")]
926 mod arch {
927     pub const ARCH: &'static str = "mips";
928 }
929
930 #[cfg(target_arch = "mips64")]
931 mod arch {
932     pub const ARCH: &'static str = "mips64";
933 }
934
935 #[cfg(target_arch = "powerpc")]
936 mod arch {
937     pub const ARCH: &'static str = "powerpc";
938 }
939
940 #[cfg(target_arch = "powerpc64")]
941 mod arch {
942     pub const ARCH: &'static str = "powerpc64";
943 }
944
945 #[cfg(target_arch = "le32")]
946 mod arch {
947     pub const ARCH: &'static str = "le32";
948 }
949
950 #[cfg(target_arch = "asmjs")]
951 mod arch {
952     pub const ARCH: &'static str = "asmjs";
953 }
954
955 #[cfg(test)]
956 mod tests {
957     use super::*;
958
959     use iter::repeat;
960     use rand::{self, Rng};
961     use ffi::{OsString, OsStr};
962     use path::{Path, PathBuf};
963
964     fn make_rand_name() -> OsString {
965         let mut rng = rand::thread_rng();
966         let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
967                                      .collect::<String>());
968         let n = OsString::from(n);
969         assert!(var_os(&n).is_none());
970         n
971     }
972
973     fn eq(a: Option<OsString>, b: Option<&str>) {
974         assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
975     }
976
977     #[test]
978     fn test_set_var() {
979         let n = make_rand_name();
980         set_var(&n, "VALUE");
981         eq(var_os(&n), Some("VALUE"));
982     }
983
984     #[test]
985     fn test_remove_var() {
986         let n = make_rand_name();
987         set_var(&n, "VALUE");
988         remove_var(&n);
989         eq(var_os(&n), None);
990     }
991
992     #[test]
993     fn test_set_var_overwrite() {
994         let n = make_rand_name();
995         set_var(&n, "1");
996         set_var(&n, "2");
997         eq(var_os(&n), Some("2"));
998         set_var(&n, "");
999         eq(var_os(&n), Some(""));
1000     }
1001
1002     #[test]
1003     fn test_var_big() {
1004         let mut s = "".to_string();
1005         let mut i = 0;
1006         while i < 100 {
1007             s.push_str("aaaaaaaaaa");
1008             i += 1;
1009         }
1010         let n = make_rand_name();
1011         set_var(&n, &s);
1012         eq(var_os(&n), Some(&s));
1013     }
1014
1015     #[test]
1016     fn test_self_exe_path() {
1017         let path = current_exe();
1018         assert!(path.is_ok());
1019         let path = path.unwrap();
1020
1021         // Hard to test this function
1022         assert!(path.is_absolute());
1023     }
1024
1025     #[test]
1026     fn test_env_set_get_huge() {
1027         let n = make_rand_name();
1028         let s = repeat("x").take(10000).collect::<String>();
1029         set_var(&n, &s);
1030         eq(var_os(&n), Some(&s));
1031         remove_var(&n);
1032         eq(var_os(&n), None);
1033     }
1034
1035     #[test]
1036     fn test_env_set_var() {
1037         let n = make_rand_name();
1038
1039         let mut e = vars_os();
1040         set_var(&n, "VALUE");
1041         assert!(!e.any(|(k, v)| {
1042             &*k == &*n && &*v == "VALUE"
1043         }));
1044
1045         assert!(vars_os().any(|(k, v)| {
1046             &*k == &*n && &*v == "VALUE"
1047         }));
1048     }
1049
1050     #[test]
1051     fn test() {
1052         assert!((!Path::new("test-path").is_absolute()));
1053
1054         current_dir().unwrap();
1055     }
1056
1057     #[test]
1058     #[cfg(windows)]
1059     fn split_paths_windows() {
1060         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1061             split_paths(unparsed).collect::<Vec<_>>() ==
1062                 parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
1063         }
1064
1065         assert!(check_parse("", &mut [""]));
1066         assert!(check_parse(r#""""#, &mut [""]));
1067         assert!(check_parse(";;", &mut ["", "", ""]));
1068         assert!(check_parse(r"c:\", &mut [r"c:\"]));
1069         assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
1070         assert!(check_parse(r"c:\;c:\Program Files\",
1071                             &mut [r"c:\", r"c:\Program Files\"]));
1072         assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
1073         assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
1074                             &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
1075     }
1076
1077     #[test]
1078     #[cfg(unix)]
1079     fn split_paths_unix() {
1080         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1081             split_paths(unparsed).collect::<Vec<_>>() ==
1082                 parsed.iter().map(|s| PathBuf::from(*s)).collect::<Vec<_>>()
1083         }
1084
1085         assert!(check_parse("", &mut [""]));
1086         assert!(check_parse("::", &mut ["", "", ""]));
1087         assert!(check_parse("/", &mut ["/"]));
1088         assert!(check_parse("/:", &mut ["/", ""]));
1089         assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
1090     }
1091
1092     #[test]
1093     #[cfg(unix)]
1094     fn join_paths_unix() {
1095         fn test_eq(input: &[&str], output: &str) -> bool {
1096             &*join_paths(input.iter().cloned()).unwrap() ==
1097                 OsStr::new(output)
1098         }
1099
1100         assert!(test_eq(&[], ""));
1101         assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
1102                          "/bin:/usr/bin:/usr/local/bin"));
1103         assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
1104                          ":/bin:::/usr/bin:"));
1105         assert!(join_paths(["/te:st"].iter().cloned()).is_err());
1106     }
1107
1108     #[test]
1109     #[cfg(windows)]
1110     fn join_paths_windows() {
1111         fn test_eq(input: &[&str], output: &str) -> bool {
1112             &*join_paths(input.iter().cloned()).unwrap() ==
1113                 OsStr::new(output)
1114         }
1115
1116         assert!(test_eq(&[], ""));
1117         assert!(test_eq(&[r"c:\windows", r"c:\"],
1118                         r"c:\windows;c:\"));
1119         assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
1120                         r";c:\windows;;;c:\;"));
1121         assert!(test_eq(&[r"c:\te;st", r"c:\"],
1122                         r#""c:\te;st";c:\"#));
1123         assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
1124     }
1125     }