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