]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
Rollup merge of #21404 - japaric:hash, r=alexcrichton
[rust.git] / src / libstd / os.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 //! Higher-level interfaces to libc::* functions and operating system services.
12 //!
13 //! In general these take and return rust types, use rust idioms (enums, closures, vectors) rather
14 //! than C idioms, and do more extensive safety checks.
15 //!
16 //! This module is not meant to only contain 1:1 mappings to libc entries; any os-interface code
17 //! that is reasonably useful and broadly applicable can go here. Including utility routines that
18 //! merely build on other os code.
19 //!
20 //! We assume the general case is that users do not care, and do not want to be made to care, which
21 //! operating system they are on. While they may want to special case various special cases -- and
22 //! so we will not _hide_ the facts of which OS the user is on -- they should be given the
23 //! opportunity to write OS-ignorant code by default.
24
25 #![unstable]
26
27 #![allow(missing_docs)]
28 #![allow(non_snake_case)]
29 #![allow(unused_imports)]
30
31 use self::MemoryMapKind::*;
32 use self::MapOption::*;
33 use self::MapError::*;
34
35 use clone::Clone;
36 use error::{FromError, Error};
37 use fmt;
38 use io::{IoResult, IoError};
39 use iter::{Iterator, IteratorExt};
40 use marker::{Copy, Send};
41 use libc::{c_void, c_int, c_char};
42 use libc;
43 use boxed::Box;
44 use ops::{Drop, FnOnce};
45 use option::Option;
46 use option::Option::{Some, None};
47 use path::{Path, GenericPath, BytesContainer};
48 use sys;
49 use sys::os as os_imp;
50 use ptr::PtrExt;
51 use ptr;
52 use result::Result;
53 use result::Result::{Err, Ok};
54 use slice::{AsSlice, SliceExt};
55 use str::{Str, StrExt};
56 use string::{String, ToString};
57 use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
58 use vec::Vec;
59
60 #[cfg(unix)] use ffi::{self, CString};
61
62 #[cfg(unix)] pub use sys::ext as unix;
63 #[cfg(windows)] pub use sys::ext as windows;
64
65 /// Get the number of cores available
66 pub fn num_cpus() -> uint {
67     unsafe {
68         return rust_get_num_cpus() as uint;
69     }
70
71     extern {
72         fn rust_get_num_cpus() -> libc::uintptr_t;
73     }
74 }
75
76 pub const TMPBUF_SZ : uint = 1000u;
77
78 /// Returns the current working directory as a `Path`.
79 ///
80 /// # Errors
81 ///
82 /// Returns an `Err` if the current working directory value is invalid.
83 /// Possible cases:
84 ///
85 /// * Current directory does not exist.
86 /// * There are insufficient permissions to access the current directory.
87 /// * The internal buffer is not large enough to hold the path.
88 ///
89 /// # Example
90 ///
91 /// ```rust
92 /// use std::os;
93 ///
94 /// // We assume that we are in a valid directory.
95 /// let current_working_directory = os::getcwd().unwrap();
96 /// println!("The current directory is {:?}", current_working_directory.display());
97 /// ```
98 pub fn getcwd() -> IoResult<Path> {
99     sys::os::getcwd()
100 }
101
102 /*
103 Accessing environment variables is not generally threadsafe.
104 Serialize access through a global lock.
105 */
106 fn with_env_lock<T, F>(f: F) -> T where
107     F: FnOnce() -> T,
108 {
109     use sync::{StaticMutex, MUTEX_INIT};
110
111     static LOCK: StaticMutex = MUTEX_INIT;
112
113     let _guard = LOCK.lock();
114     f()
115 }
116
117 /// Returns a vector of (variable, value) pairs, for all the environment
118 /// variables of the current process.
119 ///
120 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()`
121 /// for details.
122 ///
123 /// # Example
124 ///
125 /// ```rust
126 /// use std::os;
127 ///
128 /// // We will iterate through the references to the element returned by os::env();
129 /// for &(ref key, ref value) in os::env().iter() {
130 ///     println!("'{}': '{}'", key, value );
131 /// }
132 /// ```
133 pub fn env() -> Vec<(String,String)> {
134     env_as_bytes().into_iter().map(|(k,v)| {
135         let k = String::from_utf8_lossy(k.as_slice()).into_owned();
136         let v = String::from_utf8_lossy(v.as_slice()).into_owned();
137         (k,v)
138     }).collect()
139 }
140
141 /// Returns a vector of (variable, value) byte-vector pairs for all the
142 /// environment variables of the current process.
143 pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
144     unsafe {
145         fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
146             let mut pairs = Vec::new();
147             for p in input.iter() {
148                 let mut it = p.splitn(1, |b| *b == b'=');
149                 let key = it.next().unwrap().to_vec();
150                 let default: &[u8] = &[];
151                 let val = it.next().unwrap_or(default).to_vec();
152                 pairs.push((key, val));
153             }
154             pairs
155         }
156         with_env_lock(|| {
157             let unparsed_environ = sys::os::get_env_pairs();
158             env_convert(unparsed_environ)
159         })
160     }
161 }
162
163 #[cfg(unix)]
164 /// Fetches the environment variable `n` from the current process, returning
165 /// None if the variable isn't set.
166 ///
167 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
168 /// `String::from_utf8_lossy()` for details.
169 ///
170 /// # Panics
171 ///
172 /// Panics if `n` has any interior NULs.
173 ///
174 /// # Example
175 ///
176 /// ```rust
177 /// use std::os;
178 ///
179 /// let key = "HOME";
180 /// match os::getenv(key) {
181 ///     Some(val) => println!("{}: {}", key, val),
182 ///     None => println!("{} is not defined in the environment.", key)
183 /// }
184 /// ```
185 pub fn getenv(n: &str) -> Option<String> {
186     getenv_as_bytes(n).map(|v| String::from_utf8_lossy(v.as_slice()).into_owned())
187 }
188
189 #[cfg(unix)]
190 /// Fetches the environment variable `n` byte vector from the current process,
191 /// returning None if the variable isn't set.
192 ///
193 /// # Panics
194 ///
195 /// Panics if `n` has any interior NULs.
196 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
197     unsafe {
198         with_env_lock(|| {
199             let s = CString::from_slice(n.as_bytes());
200             let s = libc::getenv(s.as_ptr()) as *const _;
201             if s.is_null() {
202                 None
203             } else {
204                 Some(ffi::c_str_to_bytes(&s).to_vec())
205             }
206         })
207     }
208 }
209
210 #[cfg(windows)]
211 /// Fetches the environment variable `n` from the current process, returning
212 /// None if the variable isn't set.
213 pub fn getenv(n: &str) -> Option<String> {
214     unsafe {
215         with_env_lock(|| {
216             use sys::os::fill_utf16_buf_and_decode;
217             let mut n: Vec<u16> = n.utf16_units().collect();
218             n.push(0);
219             fill_utf16_buf_and_decode(|buf, sz| {
220                 libc::GetEnvironmentVariableW(n.as_ptr(), buf, sz)
221             })
222         })
223     }
224 }
225
226 #[cfg(windows)]
227 /// Fetches the environment variable `n` byte vector from the current process,
228 /// returning None if the variable isn't set.
229 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
230     getenv(n).map(|s| s.into_bytes())
231 }
232
233 /// Sets the environment variable `n` to the value `v` for the currently running
234 /// process.
235 ///
236 /// # Example
237 ///
238 /// ```rust
239 /// use std::os;
240 ///
241 /// let key = "KEY";
242 /// os::setenv(key, "VALUE");
243 /// match os::getenv(key) {
244 ///     Some(ref val) => println!("{}: {}", key, val),
245 ///     None => println!("{} is not defined in the environment.", key)
246 /// }
247 /// ```
248 pub fn setenv<T: BytesContainer>(n: &str, v: T) {
249     #[cfg(unix)]
250     fn _setenv(n: &str, v: &[u8]) {
251         unsafe {
252             with_env_lock(|| {
253                 let k = CString::from_slice(n.as_bytes());
254                 let v = CString::from_slice(v);
255                 if libc::funcs::posix01::unistd::setenv(k.as_ptr(),
256                                                         v.as_ptr(), 1) != 0 {
257                     panic!(IoError::last_error());
258                 }
259             })
260         }
261     }
262
263     #[cfg(windows)]
264     fn _setenv(n: &str, v: &[u8]) {
265         let mut n: Vec<u16> = n.utf16_units().collect();
266         n.push(0);
267         let mut v: Vec<u16> = ::str::from_utf8(v).unwrap().utf16_units().collect();
268         v.push(0);
269
270         unsafe {
271             with_env_lock(|| {
272                 if libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr()) == 0 {
273                     panic!(IoError::last_error());
274                 }
275             })
276         }
277     }
278
279     _setenv(n, v.container_as_bytes())
280 }
281
282 /// Remove a variable from the environment entirely.
283 pub fn unsetenv(n: &str) {
284     #[cfg(unix)]
285     fn _unsetenv(n: &str) {
286         unsafe {
287             with_env_lock(|| {
288                 let nbuf = CString::from_slice(n.as_bytes());
289                 if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 {
290                     panic!(IoError::last_error());
291                 }
292             })
293         }
294     }
295
296     #[cfg(windows)]
297     fn _unsetenv(n: &str) {
298         let mut n: Vec<u16> = n.utf16_units().collect();
299         n.push(0);
300         unsafe {
301             with_env_lock(|| {
302                 if libc::SetEnvironmentVariableW(n.as_ptr(), ptr::null()) == 0 {
303                     panic!(IoError::last_error());
304                 }
305             })
306         }
307     }
308
309     _unsetenv(n)
310 }
311
312 /// Parses input according to platform conventions for the `PATH`
313 /// environment variable.
314 ///
315 /// # Example
316 /// ```rust
317 /// use std::os;
318 ///
319 /// let key = "PATH";
320 /// match os::getenv_as_bytes(key) {
321 ///     Some(paths) => {
322 ///         for path in os::split_paths(paths).iter() {
323 ///             println!("'{}'", path.display());
324 ///         }
325 ///     }
326 ///     None => println!("{} is not defined in the environment.", key)
327 /// }
328 /// ```
329 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
330     sys::os::split_paths(unparsed.container_as_bytes())
331 }
332
333 /// Joins a collection of `Path`s appropriately for the `PATH`
334 /// environment variable.
335 ///
336 /// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
337 /// encoded on all platforms.
338 ///
339 /// Returns an `Err` (containing an error message) if one of the input
340 /// `Path`s contains an invalid character for constructing the `PATH`
341 /// variable (a double quote on Windows or a colon on Unix).
342 ///
343 /// # Example
344 ///
345 /// ```rust
346 /// use std::os;
347 /// use std::path::Path;
348 ///
349 /// let key = "PATH";
350 /// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
351 /// paths.push(Path::new("/home/xyz/bin"));
352 /// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
353 /// ```
354 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
355     sys::os::join_paths(paths)
356 }
357
358 /// A low-level OS in-memory pipe.
359 #[derive(Copy)]
360 pub struct Pipe {
361     /// A file descriptor representing the reading end of the pipe. Data written
362     /// on the `out` file descriptor can be read from this file descriptor.
363     pub reader: c_int,
364     /// A file descriptor representing the write end of the pipe. Data written
365     /// to this file descriptor can be read from the `input` file descriptor.
366     pub writer: c_int,
367 }
368
369 /// Creates a new low-level OS in-memory pipe.
370 ///
371 /// This function can fail to succeed if there are no more resources available
372 /// to allocate a pipe.
373 ///
374 /// This function is also unsafe as there is no destructor associated with the
375 /// `Pipe` structure will return. If it is not arranged for the returned file
376 /// descriptors to be closed, the file descriptors will leak. For safe handling
377 /// of this scenario, use `std::io::PipeStream` instead.
378 pub unsafe fn pipe() -> IoResult<Pipe> {
379     let (reader, writer) = try!(sys::os::pipe());
380     Ok(Pipe {
381         reader: reader.unwrap(),
382         writer: writer.unwrap(),
383     })
384 }
385
386 /// Returns the proper dll filename for the given basename of a file
387 /// as a String.
388 #[cfg(not(target_os="ios"))]
389 pub fn dll_filename(base: &str) -> String {
390     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
391 }
392
393 /// Optionally returns the filesystem path to the current executable which is
394 /// running but with the executable name.
395 ///
396 /// # Examples
397 ///
398 /// ```rust
399 /// use std::os;
400 ///
401 /// match os::self_exe_name() {
402 ///     Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
403 ///     None => println!("Unable to get the path of this executable!")
404 /// };
405 /// ```
406 pub fn self_exe_name() -> Option<Path> {
407     sys::os::load_self().and_then(Path::new_opt)
408 }
409
410 /// Optionally returns the filesystem path to the current executable which is
411 /// running.
412 ///
413 /// Like self_exe_name() but without the binary's name.
414 ///
415 /// # Example
416 ///
417 /// ```rust
418 /// use std::os;
419 ///
420 /// match os::self_exe_path() {
421 ///     Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
422 ///     None => println!("Impossible to fetch the path of this executable.")
423 /// };
424 /// ```
425 pub fn self_exe_path() -> Option<Path> {
426     self_exe_name().map(|mut p| { p.pop(); p })
427 }
428
429 /// Optionally returns the path to the current user's home directory if known.
430 ///
431 /// # Unix
432 ///
433 /// Returns the value of the 'HOME' environment variable if it is set
434 /// and not equal to the empty string.
435 ///
436 /// # Windows
437 ///
438 /// Returns the value of the 'HOME' environment variable if it is
439 /// set and not equal to the empty string. Otherwise, returns the value of the
440 /// 'USERPROFILE' environment variable if it is set and not equal to the empty
441 /// string.
442 ///
443 /// # Example
444 ///
445 /// ```rust
446 /// use std::os;
447 ///
448 /// match os::homedir() {
449 ///     Some(ref p) => println!("{}", p.display()),
450 ///     None => println!("Impossible to get your home dir!")
451 /// }
452 /// ```
453 pub fn homedir() -> Option<Path> {
454     #[inline]
455     #[cfg(unix)]
456     fn _homedir() -> Option<Path> {
457         aux_homedir("HOME")
458     }
459
460     #[inline]
461     #[cfg(windows)]
462     fn _homedir() -> Option<Path> {
463         aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
464     }
465
466     #[inline]
467     fn aux_homedir(home_name: &str) -> Option<Path> {
468         match getenv_as_bytes(home_name) {
469             Some(p)  => {
470                 if p.is_empty() { None } else { Path::new_opt(p) }
471             },
472             _ => None
473         }
474     }
475     _homedir()
476 }
477
478 /// Returns the path to a temporary directory.
479 ///
480 /// On Unix, returns the value of the 'TMPDIR' environment variable if it is
481 /// set, otherwise for non-Android it returns '/tmp'. If Android, since there
482 /// is no global temporary folder (it is usually allocated per-app), we return
483 /// '/data/local/tmp'.
484 ///
485 /// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
486 /// 'USERPROFILE' environment variable  if any are set and not the empty
487 /// string. Otherwise, tmpdir returns the path to the Windows directory.
488 pub fn tmpdir() -> Path {
489     return lookup();
490
491     fn getenv_nonempty(v: &str) -> Option<Path> {
492         match getenv(v) {
493             Some(x) =>
494                 if x.is_empty() {
495                     None
496                 } else {
497                     Path::new_opt(x)
498                 },
499             _ => None
500         }
501     }
502
503     #[cfg(unix)]
504     fn lookup() -> Path {
505         let default = if cfg!(target_os = "android") {
506             Path::new("/data/local/tmp")
507         } else {
508             Path::new("/tmp")
509         };
510
511         getenv_nonempty("TMPDIR").unwrap_or(default)
512     }
513
514     #[cfg(windows)]
515     fn lookup() -> Path {
516         getenv_nonempty("TMP").or(
517             getenv_nonempty("TEMP").or(
518                 getenv_nonempty("USERPROFILE").or(
519                    getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
520     }
521 }
522
523 /// Convert a relative path to an absolute path
524 ///
525 /// If the given path is relative, return it prepended with the current working
526 /// directory. If the given path is already an absolute path, return it
527 /// as is.
528 ///
529 /// # Example
530 /// ```rust
531 /// use std::os;
532 /// use std::path::Path;
533 ///
534 /// // Assume we're in a path like /home/someuser
535 /// let rel_path = Path::new("..");
536 /// let abs_path = os::make_absolute(&rel_path).unwrap();
537 /// println!("The absolute path is {}", abs_path.display());
538 /// // Prints "The absolute path is /home"
539 /// ```
540 // NB: this is here rather than in path because it is a form of environment
541 // querying; what it does depends on the process working directory, not just
542 // the input paths.
543 pub fn make_absolute(p: &Path) -> IoResult<Path> {
544     if p.is_absolute() {
545         Ok(p.clone())
546     } else {
547         getcwd().map(|mut cwd| {
548             cwd.push(p);
549             cwd
550         })
551     }
552 }
553
554 /// Changes the current working directory to the specified path, returning
555 /// whether the change was completed successfully or not.
556 ///
557 /// # Example
558 /// ```rust
559 /// use std::os;
560 /// use std::path::Path;
561 ///
562 /// let root = Path::new("/");
563 /// assert!(os::change_dir(&root).is_ok());
564 /// println!("Successfully changed working directory to {}!", root.display());
565 /// ```
566 pub fn change_dir(p: &Path) -> IoResult<()> {
567     return sys::os::chdir(p);
568 }
569
570 /// Returns the platform-specific value of errno
571 pub fn errno() -> uint {
572     sys::os::errno() as uint
573 }
574
575 /// Return the string corresponding to an `errno()` value of `errnum`.
576 ///
577 /// # Example
578 /// ```rust
579 /// use std::os;
580 ///
581 /// // Same as println!("{}", last_os_error());
582 /// println!("{}", os::error_string(os::errno() as uint));
583 /// ```
584 pub fn error_string(errnum: uint) -> String {
585     return sys::os::error_string(errnum as i32);
586 }
587
588 /// Get a string representing the platform-dependent last error
589 pub fn last_os_error() -> String {
590     error_string(errno() as uint)
591 }
592
593 static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
594
595 /// Sets the process exit code
596 ///
597 /// Sets the exit code returned by the process if all supervised tasks
598 /// terminate successfully (without panicking). If the current root task panics
599 /// and is supervised by the scheduler then any user-specified exit status is
600 /// ignored and the process exits with the default panic status.
601 ///
602 /// Note that this is not synchronized against modifications of other threads.
603 pub fn set_exit_status(code: int) {
604     EXIT_STATUS.store(code, Ordering::SeqCst)
605 }
606
607 /// Fetches the process's current exit code. This defaults to 0 and can change
608 /// by calling `set_exit_status`.
609 pub fn get_exit_status() -> int {
610     EXIT_STATUS.load(Ordering::SeqCst)
611 }
612
613 #[cfg(target_os = "macos")]
614 unsafe fn load_argc_and_argv(argc: int,
615                              argv: *const *const c_char) -> Vec<Vec<u8>> {
616     use iter::range;
617
618     range(0, argc as uint).map(|i| {
619         ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
620     }).collect()
621 }
622
623 /// Returns the command line arguments
624 ///
625 /// Returns a list of the command line arguments.
626 #[cfg(target_os = "macos")]
627 fn real_args_as_bytes() -> Vec<Vec<u8>> {
628     unsafe {
629         let (argc, argv) = (*_NSGetArgc() as int,
630                             *_NSGetArgv() as *const *const c_char);
631         load_argc_and_argv(argc, argv)
632     }
633 }
634
635 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
636 // and use underscores in their names - they're most probably
637 // are considered private and therefore should be avoided
638 // Here is another way to get arguments using Objective C
639 // runtime
640 //
641 // In general it looks like:
642 // res = Vec::new()
643 // let args = [[NSProcessInfo processInfo] arguments]
644 // for i in range(0, [args count])
645 //      res.push([args objectAtIndex:i])
646 // res
647 #[cfg(target_os = "ios")]
648 fn real_args_as_bytes() -> Vec<Vec<u8>> {
649     use ffi::c_str_to_bytes;
650     use iter::range;
651     use mem;
652
653     #[link(name = "objc")]
654     extern {
655         fn sel_registerName(name: *const libc::c_uchar) -> Sel;
656         fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
657         fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
658     }
659
660     #[link(name = "Foundation", kind = "framework")]
661     extern {}
662
663     type Sel = *const libc::c_void;
664     type NsId = *const libc::c_void;
665
666     let mut res = Vec::new();
667
668     unsafe {
669         let processInfoSel = sel_registerName("processInfo\0".as_ptr());
670         let argumentsSel = sel_registerName("arguments\0".as_ptr());
671         let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
672         let countSel = sel_registerName("count\0".as_ptr());
673         let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
674
675         let klass = objc_getClass("NSProcessInfo\0".as_ptr());
676         let info = objc_msgSend(klass, processInfoSel);
677         let args = objc_msgSend(info, argumentsSel);
678
679         let cnt: int = mem::transmute(objc_msgSend(args, countSel));
680         for i in range(0, cnt) {
681             let tmp = objc_msgSend(args, objectAtSel, i);
682             let utf_c_str: *const libc::c_char =
683                 mem::transmute(objc_msgSend(tmp, utf8Sel));
684             res.push(c_str_to_bytes(&utf_c_str).to_vec());
685         }
686     }
687
688     res
689 }
690
691 #[cfg(any(target_os = "linux",
692           target_os = "android",
693           target_os = "freebsd",
694           target_os = "dragonfly"))]
695 fn real_args_as_bytes() -> Vec<Vec<u8>> {
696     use rt;
697     rt::args::clone().unwrap_or_else(|| vec![])
698 }
699
700 #[cfg(not(windows))]
701 fn real_args() -> Vec<String> {
702     real_args_as_bytes().into_iter()
703                         .map(|v| {
704                             String::from_utf8_lossy(v.as_slice()).into_owned()
705                         }).collect()
706 }
707
708 #[cfg(windows)]
709 fn real_args() -> Vec<String> {
710     use slice;
711     use iter::range;
712
713     let mut nArgs: c_int = 0;
714     let lpArgCount: *mut c_int = &mut nArgs;
715     let lpCmdLine = unsafe { GetCommandLineW() };
716     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
717
718     let args: Vec<_> = range(0, nArgs as uint).map(|i| unsafe {
719         // Determine the length of this argument.
720         let ptr = *szArgList.offset(i as int);
721         let mut len = 0;
722         while *ptr.offset(len as int) != 0 { len += 1; }
723
724         // Push it onto the list.
725         let ptr = ptr as *const u16;
726         let buf = slice::from_raw_buf(&ptr, len);
727         let opt_s = String::from_utf16(sys::os::truncate_utf16_at_nul(buf));
728         opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16")
729     }).collect();
730
731     unsafe {
732         LocalFree(szArgList as *mut c_void);
733     }
734
735     return args
736 }
737
738 #[cfg(windows)]
739 fn real_args_as_bytes() -> Vec<Vec<u8>> {
740     real_args().into_iter().map(|s| s.into_bytes()).collect()
741 }
742
743 type LPCWSTR = *const u16;
744
745 #[cfg(windows)]
746 #[link_name="kernel32"]
747 extern "system" {
748     fn GetCommandLineW() -> LPCWSTR;
749     fn LocalFree(ptr: *mut c_void);
750 }
751
752 #[cfg(windows)]
753 #[link_name="shell32"]
754 extern "system" {
755     fn CommandLineToArgvW(lpCmdLine: LPCWSTR,
756                           pNumArgs: *mut c_int) -> *mut *mut u16;
757 }
758
759 /// Returns the arguments which this program was started with (normally passed
760 /// via the command line).
761 ///
762 /// The first element is traditionally the path to the executable, but it can be
763 /// set to arbitrary text, and it may not even exist, so this property should not
764 /// be relied upon for security purposes.
765 ///
766 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
767 /// See `String::from_utf8_lossy` for details.
768 /// # Example
769 ///
770 /// ```rust
771 /// use std::os;
772 ///
773 /// // Prints each argument on a separate line
774 /// for argument in os::args().iter() {
775 ///     println!("{}", argument);
776 /// }
777 /// ```
778 pub fn args() -> Vec<String> {
779     real_args()
780 }
781
782 /// Returns the arguments which this program was started with (normally passed
783 /// via the command line) as byte vectors.
784 pub fn args_as_bytes() -> Vec<Vec<u8>> {
785     real_args_as_bytes()
786 }
787
788 #[cfg(target_os = "macos")]
789 extern {
790     // These functions are in crt_externs.h.
791     pub fn _NSGetArgc() -> *mut c_int;
792     pub fn _NSGetArgv() -> *mut *mut *mut c_char;
793 }
794
795 /// Returns the page size of the current architecture in bytes.
796 pub fn page_size() -> uint {
797     sys::os::page_size()
798 }
799
800 /// A memory mapped file or chunk of memory. This is a very system-specific
801 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
802 /// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at
803 /// abstracting platform differences, besides in error values returned. Consider
804 /// yourself warned.
805 ///
806 /// The memory map is released (unmapped) when the destructor is run, so don't
807 /// let it leave scope by accident if you want it to stick around.
808 #[allow(missing_copy_implementations)]
809 pub struct MemoryMap {
810     data: *mut u8,
811     len: uint,
812     kind: MemoryMapKind,
813 }
814
815 /// Type of memory map
816 pub enum MemoryMapKind {
817     /// Virtual memory map. Usually used to change the permissions of a given
818     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
819     MapFile(*const u8),
820     /// Virtual memory map. Usually used to change the permissions of a given
821     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
822     /// Windows.
823     MapVirtual
824 }
825
826 impl Copy for MemoryMapKind {}
827
828 /// Options the memory map is created with
829 pub enum MapOption {
830     /// The memory should be readable
831     MapReadable,
832     /// The memory should be writable
833     MapWritable,
834     /// The memory should be executable
835     MapExecutable,
836     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
837     /// POSIX.
838     MapAddr(*const u8),
839     /// Create a memory mapping for a file with a given HANDLE.
840     #[cfg(windows)]
841     MapFd(libc::HANDLE),
842     /// Create a memory mapping for a file with a given fd.
843     #[cfg(not(windows))]
844     MapFd(c_int),
845     /// When using `MapFd`, the start of the map is `uint` bytes from the start
846     /// of the file.
847     MapOffset(uint),
848     /// On POSIX, this can be used to specify the default flags passed to
849     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
850     /// `MAP_ANON`. This will override both of those. This is platform-specific
851     /// (the exact values used) and ignored on Windows.
852     MapNonStandardFlags(c_int),
853 }
854
855 impl Copy for MapOption {}
856
857 /// Possible errors when creating a map.
858 #[derive(Copy)]
859 pub enum MapError {
860     /// # The following are POSIX-specific
861     ///
862     /// fd was not open for reading or, if using `MapWritable`, was not open for
863     /// writing.
864     ErrFdNotAvail,
865     /// fd was not valid
866     ErrInvalidFd,
867     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
868     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
869     ErrUnaligned,
870     /// With `MapFd`, the fd does not support mapping.
871     ErrNoMapSupport,
872     /// If using `MapAddr`, the address + `min_len` was outside of the process's
873     /// address space. If using `MapFd`, the target of the fd didn't have enough
874     /// resources to fulfill the request.
875     ErrNoMem,
876     /// A zero-length map was requested. This is invalid according to
877     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
878     /// Not all platforms obey this, but this wrapper does.
879     ErrZeroLength,
880     /// Unrecognized error. The inner value is the unrecognized errno.
881     ErrUnknown(int),
882     /// # The following are Windows-specific
883     ///
884     /// Unsupported combination of protection flags
885     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
886     ErrUnsupProt,
887     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
888     /// at all)
889     ErrUnsupOffset,
890     /// When using `MapFd`, there was already a mapping to the file.
891     ErrAlreadyExists,
892     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
893     /// value of GetLastError.
894     ErrVirtualAlloc(uint),
895     /// Unrecognized error from `CreateFileMapping`. The inner value is the
896     /// return value of `GetLastError`.
897     ErrCreateFileMappingW(uint),
898     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
899     /// value of `GetLastError`.
900     ErrMapViewOfFile(uint)
901 }
902
903 impl fmt::Show for MapError {
904     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
905         let str = match *self {
906             ErrFdNotAvail => "fd not available for reading or writing",
907             ErrInvalidFd => "Invalid fd",
908             ErrUnaligned => {
909                 "Unaligned address, invalid flags, negative length or \
910                  unaligned offset"
911             }
912             ErrNoMapSupport=> "File doesn't support mapping",
913             ErrNoMem => "Invalid address, or not enough available memory",
914             ErrUnsupProt => "Protection mode unsupported",
915             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
916             ErrAlreadyExists => "File mapping for specified file already exists",
917             ErrZeroLength => "Zero-length mapping not allowed",
918             ErrUnknown(code) => {
919                 return write!(out, "Unknown error = {}", code)
920             },
921             ErrVirtualAlloc(code) => {
922                 return write!(out, "VirtualAlloc failure = {}", code)
923             },
924             ErrCreateFileMappingW(code) => {
925                 return write!(out, "CreateFileMappingW failure = {}", code)
926             },
927             ErrMapViewOfFile(code) => {
928                 return write!(out, "MapViewOfFile failure = {}", code)
929             }
930         };
931         write!(out, "{}", str)
932     }
933 }
934
935 impl Error for MapError {
936     fn description(&self) -> &str { "memory map error" }
937     fn detail(&self) -> Option<String> { Some(format!("{:?}", self)) }
938 }
939
940 impl FromError<MapError> for Box<Error + Send> {
941     fn from_error(err: MapError) -> Box<Error + Send> {
942         box err
943     }
944 }
945
946 // Round up `from` to be divisible by `to`
947 fn round_up(from: uint, to: uint) -> uint {
948     let r = if from % to == 0 {
949         from
950     } else {
951         from + to - (from % to)
952     };
953     if r == 0 {
954         to
955     } else {
956         r
957     }
958 }
959
960 #[cfg(unix)]
961 impl MemoryMap {
962     /// Create a new mapping with the given `options`, at least `min_len` bytes
963     /// long. `min_len` must be greater than zero; see the note on
964     /// `ErrZeroLength`.
965     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
966         use libc::off_t;
967
968         if min_len == 0 {
969             return Err(ErrZeroLength)
970         }
971         let mut addr: *const u8 = ptr::null();
972         let mut prot = 0;
973         let mut flags = libc::MAP_PRIVATE;
974         let mut fd = -1;
975         let mut offset = 0;
976         let mut custom_flags = false;
977         let len = round_up(min_len, page_size());
978
979         for &o in options.iter() {
980             match o {
981                 MapReadable => { prot |= libc::PROT_READ; },
982                 MapWritable => { prot |= libc::PROT_WRITE; },
983                 MapExecutable => { prot |= libc::PROT_EXEC; },
984                 MapAddr(addr_) => {
985                     flags |= libc::MAP_FIXED;
986                     addr = addr_;
987                 },
988                 MapFd(fd_) => {
989                     flags |= libc::MAP_FILE;
990                     fd = fd_;
991                 },
992                 MapOffset(offset_) => { offset = offset_ as off_t; },
993                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
994             }
995         }
996         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
997
998         let r = unsafe {
999             libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags,
1000                        fd, offset)
1001         };
1002         if r == libc::MAP_FAILED {
1003             Err(match errno() as c_int {
1004                 libc::EACCES => ErrFdNotAvail,
1005                 libc::EBADF => ErrInvalidFd,
1006                 libc::EINVAL => ErrUnaligned,
1007                 libc::ENODEV => ErrNoMapSupport,
1008                 libc::ENOMEM => ErrNoMem,
1009                 code => ErrUnknown(code as int)
1010             })
1011         } else {
1012             Ok(MemoryMap {
1013                data: r as *mut u8,
1014                len: len,
1015                kind: if fd == -1 {
1016                    MapVirtual
1017                } else {
1018                    MapFile(ptr::null())
1019                }
1020             })
1021         }
1022     }
1023
1024     /// Granularity that the offset or address must be for `MapOffset` and
1025     /// `MapAddr` respectively.
1026     pub fn granularity() -> uint {
1027         page_size()
1028     }
1029 }
1030
1031 #[cfg(unix)]
1032 impl Drop for MemoryMap {
1033     /// Unmap the mapping. Panics the task if `munmap` panics.
1034     fn drop(&mut self) {
1035         if self.len == 0 { /* workaround for dummy_stack */ return; }
1036
1037         unsafe {
1038             // `munmap` only panics due to logic errors
1039             libc::munmap(self.data as *mut c_void, self.len as libc::size_t);
1040         }
1041     }
1042 }
1043
1044 #[cfg(windows)]
1045 impl MemoryMap {
1046     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1047     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1048         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1049
1050         let mut lpAddress: LPVOID = ptr::null_mut();
1051         let mut readable = false;
1052         let mut writable = false;
1053         let mut executable = false;
1054         let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
1055         let mut offset: uint = 0;
1056         let len = round_up(min_len, page_size());
1057
1058         for &o in options.iter() {
1059             match o {
1060                 MapReadable => { readable = true; },
1061                 MapWritable => { writable = true; },
1062                 MapExecutable => { executable = true; }
1063                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1064                 MapFd(handle_) => { handle = handle_; },
1065                 MapOffset(offset_) => { offset = offset_; },
1066                 MapNonStandardFlags(..) => {}
1067             }
1068         }
1069
1070         let flProtect = match (executable, readable, writable) {
1071             (false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
1072             (false, true, false) => libc::PAGE_READONLY,
1073             (false, true, true) => libc::PAGE_READWRITE,
1074             (true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
1075             (true, true, false) => libc::PAGE_EXECUTE_READ,
1076             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1077             _ => return Err(ErrUnsupProt)
1078         };
1079
1080         if handle == libc::INVALID_HANDLE_VALUE {
1081             if offset != 0 {
1082                 return Err(ErrUnsupOffset);
1083             }
1084             let r = unsafe {
1085                 libc::VirtualAlloc(lpAddress,
1086                                    len as SIZE_T,
1087                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1088                                    flProtect)
1089             };
1090             match r as uint {
1091                 0 => Err(ErrVirtualAlloc(errno())),
1092                 _ => Ok(MemoryMap {
1093                    data: r as *mut u8,
1094                    len: len,
1095                    kind: MapVirtual
1096                 })
1097             }
1098         } else {
1099             let dwDesiredAccess = match (executable, readable, writable) {
1100                 (false, true, false) => libc::FILE_MAP_READ,
1101                 (false, true, true) => libc::FILE_MAP_WRITE,
1102                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1103                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1104                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1105                                               // we should never get here.
1106             };
1107             unsafe {
1108                 let hFile = handle;
1109                 let mapping = libc::CreateFileMappingW(hFile,
1110                                                        ptr::null_mut(),
1111                                                        flProtect,
1112                                                        0,
1113                                                        0,
1114                                                        ptr::null());
1115                 if mapping == ptr::null_mut() {
1116                     return Err(ErrCreateFileMappingW(errno()));
1117                 }
1118                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1119                     return Err(ErrAlreadyExists);
1120                 }
1121                 let r = libc::MapViewOfFile(mapping,
1122                                             dwDesiredAccess,
1123                                             ((len as u64) >> 32) as DWORD,
1124                                             (offset & 0xffff_ffff) as DWORD,
1125                                             0);
1126                 match r as uint {
1127                     0 => Err(ErrMapViewOfFile(errno())),
1128                     _ => Ok(MemoryMap {
1129                        data: r as *mut u8,
1130                        len: len,
1131                        kind: MapFile(mapping as *const u8)
1132                     })
1133                 }
1134             }
1135         }
1136     }
1137
1138     /// Granularity of MapAddr() and MapOffset() parameter values.
1139     /// This may be greater than the value returned by page_size().
1140     pub fn granularity() -> uint {
1141         use mem;
1142         unsafe {
1143             let mut info = mem::zeroed();
1144             libc::GetSystemInfo(&mut info);
1145
1146             return info.dwAllocationGranularity as uint;
1147         }
1148     }
1149 }
1150
1151 #[cfg(windows)]
1152 impl Drop for MemoryMap {
1153     /// Unmap the mapping. Panics the task if any of `VirtualFree`,
1154     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1155     fn drop(&mut self) {
1156         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1157         use libc::consts::os::extra::FALSE;
1158         if self.len == 0 { return }
1159
1160         unsafe {
1161             match self.kind {
1162                 MapVirtual => {
1163                     if libc::VirtualFree(self.data as *mut c_void, 0,
1164                                          libc::MEM_RELEASE) == 0 {
1165                         println!("VirtualFree failed: {}", errno());
1166                     }
1167                 },
1168                 MapFile(mapping) => {
1169                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1170                         println!("UnmapViewOfFile failed: {}", errno());
1171                     }
1172                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1173                         println!("CloseHandle failed: {}", errno());
1174                     }
1175                 }
1176             }
1177         }
1178     }
1179 }
1180
1181 impl MemoryMap {
1182     /// Returns the pointer to the memory created or modified by this map.
1183     pub fn data(&self) -> *mut u8 { self.data }
1184     /// Returns the number of bytes this map applies to.
1185     pub fn len(&self) -> uint { self.len }
1186     /// Returns the type of mapping this represents.
1187     pub fn kind(&self) -> MemoryMapKind { self.kind }
1188 }
1189
1190 #[cfg(target_os = "linux")]
1191 pub mod consts {
1192     pub use os::arch_consts::ARCH;
1193
1194     pub const FAMILY: &'static str = "unix";
1195
1196     /// A string describing the specific operating system in use: in this
1197     /// case, `linux`.
1198     pub const SYSNAME: &'static str = "linux";
1199
1200     /// Specifies the filename prefix used for shared libraries on this
1201     /// platform: in this case, `lib`.
1202     pub const DLL_PREFIX: &'static str = "lib";
1203
1204     /// Specifies the filename suffix used for shared libraries on this
1205     /// platform: in this case, `.so`.
1206     pub const DLL_SUFFIX: &'static str = ".so";
1207
1208     /// Specifies the file extension used for shared libraries on this
1209     /// platform that goes after the dot: in this case, `so`.
1210     pub const DLL_EXTENSION: &'static str = "so";
1211
1212     /// Specifies the filename suffix used for executable binaries on this
1213     /// platform: in this case, the empty string.
1214     pub const EXE_SUFFIX: &'static str = "";
1215
1216     /// Specifies the file extension, if any, used for executable binaries
1217     /// on this platform: in this case, the empty string.
1218     pub const EXE_EXTENSION: &'static str = "";
1219 }
1220
1221 #[cfg(target_os = "macos")]
1222 pub mod consts {
1223     pub use os::arch_consts::ARCH;
1224
1225     pub const FAMILY: &'static str = "unix";
1226
1227     /// A string describing the specific operating system in use: in this
1228     /// case, `macos`.
1229     pub const SYSNAME: &'static str = "macos";
1230
1231     /// Specifies the filename prefix used for shared libraries on this
1232     /// platform: in this case, `lib`.
1233     pub const DLL_PREFIX: &'static str = "lib";
1234
1235     /// Specifies the filename suffix used for shared libraries on this
1236     /// platform: in this case, `.dylib`.
1237     pub const DLL_SUFFIX: &'static str = ".dylib";
1238
1239     /// Specifies the file extension used for shared libraries on this
1240     /// platform that goes after the dot: in this case, `dylib`.
1241     pub const DLL_EXTENSION: &'static str = "dylib";
1242
1243     /// Specifies the filename suffix used for executable binaries on this
1244     /// platform: in this case, the empty string.
1245     pub const EXE_SUFFIX: &'static str = "";
1246
1247     /// Specifies the file extension, if any, used for executable binaries
1248     /// on this platform: in this case, the empty string.
1249     pub const EXE_EXTENSION: &'static str = "";
1250 }
1251
1252 #[cfg(target_os = "ios")]
1253 pub mod consts {
1254     pub use os::arch_consts::ARCH;
1255
1256     pub const FAMILY: &'static str = "unix";
1257
1258     /// A string describing the specific operating system in use: in this
1259     /// case, `ios`.
1260     pub const SYSNAME: &'static str = "ios";
1261
1262     /// Specifies the filename suffix used for executable binaries on this
1263     /// platform: in this case, the empty string.
1264     pub const EXE_SUFFIX: &'static str = "";
1265
1266     /// Specifies the file extension, if any, used for executable binaries
1267     /// on this platform: in this case, the empty string.
1268     pub const EXE_EXTENSION: &'static str = "";
1269 }
1270
1271 #[cfg(target_os = "freebsd")]
1272 pub mod consts {
1273     pub use os::arch_consts::ARCH;
1274
1275     pub const FAMILY: &'static str = "unix";
1276
1277     /// A string describing the specific operating system in use: in this
1278     /// case, `freebsd`.
1279     pub const SYSNAME: &'static str = "freebsd";
1280
1281     /// Specifies the filename prefix used for shared libraries on this
1282     /// platform: in this case, `lib`.
1283     pub const DLL_PREFIX: &'static str = "lib";
1284
1285     /// Specifies the filename suffix used for shared libraries on this
1286     /// platform: in this case, `.so`.
1287     pub const DLL_SUFFIX: &'static str = ".so";
1288
1289     /// Specifies the file extension used for shared libraries on this
1290     /// platform that goes after the dot: in this case, `so`.
1291     pub const DLL_EXTENSION: &'static str = "so";
1292
1293     /// Specifies the filename suffix used for executable binaries on this
1294     /// platform: in this case, the empty string.
1295     pub const EXE_SUFFIX: &'static str = "";
1296
1297     /// Specifies the file extension, if any, used for executable binaries
1298     /// on this platform: in this case, the empty string.
1299     pub const EXE_EXTENSION: &'static str = "";
1300 }
1301
1302 #[cfg(target_os = "dragonfly")]
1303 pub mod consts {
1304     pub use os::arch_consts::ARCH;
1305
1306     pub const FAMILY: &'static str = "unix";
1307
1308     /// A string describing the specific operating system in use: in this
1309     /// case, `dragonfly`.
1310     pub const SYSNAME: &'static str = "dragonfly";
1311
1312     /// Specifies the filename prefix used for shared libraries on this
1313     /// platform: in this case, `lib`.
1314     pub const DLL_PREFIX: &'static str = "lib";
1315
1316     /// Specifies the filename suffix used for shared libraries on this
1317     /// platform: in this case, `.so`.
1318     pub const DLL_SUFFIX: &'static str = ".so";
1319
1320     /// Specifies the file extension used for shared libraries on this
1321     /// platform that goes after the dot: in this case, `so`.
1322     pub const DLL_EXTENSION: &'static str = "so";
1323
1324     /// Specifies the filename suffix used for executable binaries on this
1325     /// platform: in this case, the empty string.
1326     pub const EXE_SUFFIX: &'static str = "";
1327
1328     /// Specifies the file extension, if any, used for executable binaries
1329     /// on this platform: in this case, the empty string.
1330     pub const EXE_EXTENSION: &'static str = "";
1331 }
1332
1333 #[cfg(target_os = "android")]
1334 pub mod consts {
1335     pub use os::arch_consts::ARCH;
1336
1337     pub const FAMILY: &'static str = "unix";
1338
1339     /// A string describing the specific operating system in use: in this
1340     /// case, `android`.
1341     pub const SYSNAME: &'static str = "android";
1342
1343     /// Specifies the filename prefix used for shared libraries on this
1344     /// platform: in this case, `lib`.
1345     pub const DLL_PREFIX: &'static str = "lib";
1346
1347     /// Specifies the filename suffix used for shared libraries on this
1348     /// platform: in this case, `.so`.
1349     pub const DLL_SUFFIX: &'static str = ".so";
1350
1351     /// Specifies the file extension used for shared libraries on this
1352     /// platform that goes after the dot: in this case, `so`.
1353     pub const DLL_EXTENSION: &'static str = "so";
1354
1355     /// Specifies the filename suffix used for executable binaries on this
1356     /// platform: in this case, the empty string.
1357     pub const EXE_SUFFIX: &'static str = "";
1358
1359     /// Specifies the file extension, if any, used for executable binaries
1360     /// on this platform: in this case, the empty string.
1361     pub const EXE_EXTENSION: &'static str = "";
1362 }
1363
1364 #[cfg(target_os = "windows")]
1365 pub mod consts {
1366     pub use os::arch_consts::ARCH;
1367
1368     pub const FAMILY: &'static str = "windows";
1369
1370     /// A string describing the specific operating system in use: in this
1371     /// case, `windows`.
1372     pub const SYSNAME: &'static str = "windows";
1373
1374     /// Specifies the filename prefix used for shared libraries on this
1375     /// platform: in this case, the empty string.
1376     pub const DLL_PREFIX: &'static str = "";
1377
1378     /// Specifies the filename suffix used for shared libraries on this
1379     /// platform: in this case, `.dll`.
1380     pub const DLL_SUFFIX: &'static str = ".dll";
1381
1382     /// Specifies the file extension used for shared libraries on this
1383     /// platform that goes after the dot: in this case, `dll`.
1384     pub const DLL_EXTENSION: &'static str = "dll";
1385
1386     /// Specifies the filename suffix used for executable binaries on this
1387     /// platform: in this case, `.exe`.
1388     pub const EXE_SUFFIX: &'static str = ".exe";
1389
1390     /// Specifies the file extension, if any, used for executable binaries
1391     /// on this platform: in this case, `exe`.
1392     pub const EXE_EXTENSION: &'static str = "exe";
1393 }
1394
1395 #[cfg(target_arch = "x86")]
1396 mod arch_consts {
1397     pub const ARCH: &'static str = "x86";
1398 }
1399
1400 #[cfg(target_arch = "x86_64")]
1401 mod arch_consts {
1402     pub const ARCH: &'static str = "x86_64";
1403 }
1404
1405 #[cfg(target_arch = "arm")]
1406 mod arch_consts {
1407     pub const ARCH: &'static str = "arm";
1408 }
1409
1410 #[cfg(target_arch = "aarch64")]
1411 mod arch_consts {
1412     pub const ARCH: &'static str = "aarch64";
1413 }
1414
1415 #[cfg(target_arch = "mips")]
1416 mod arch_consts {
1417     pub const ARCH: &'static str = "mips";
1418 }
1419
1420 #[cfg(target_arch = "mipsel")]
1421 mod arch_consts {
1422     pub const ARCH: &'static str = "mipsel";
1423 }
1424
1425 #[cfg(target_arch = "powerpc")]
1426 mod arch_consts {
1427     pub const ARCH: &'static str = "powerpc";
1428 }
1429
1430 #[cfg(test)]
1431 mod tests {
1432     use prelude::v1::*;
1433
1434     use iter::repeat;
1435     use os::{env, getcwd, getenv, make_absolute};
1436     use os::{split_paths, join_paths, setenv, unsetenv};
1437     use os;
1438     use rand::Rng;
1439     use rand;
1440
1441     #[test]
1442     pub fn last_os_error() {
1443         debug!("{}", os::last_os_error());
1444     }
1445
1446     fn make_rand_name() -> String {
1447         let mut rng = rand::thread_rng();
1448         let n = format!("TEST{}", rng.gen_ascii_chars().take(10u)
1449                                      .collect::<String>());
1450         assert!(getenv(n.as_slice()).is_none());
1451         n
1452     }
1453
1454     #[test]
1455     fn test_num_cpus() {
1456         assert!(os::num_cpus() > 0);
1457     }
1458
1459     #[test]
1460     fn test_setenv() {
1461         let n = make_rand_name();
1462         setenv(n.as_slice(), "VALUE");
1463         assert_eq!(getenv(n.as_slice()), Some("VALUE".to_string()));
1464     }
1465
1466     #[test]
1467     fn test_unsetenv() {
1468         let n = make_rand_name();
1469         setenv(n.as_slice(), "VALUE");
1470         unsetenv(n.as_slice());
1471         assert_eq!(getenv(n.as_slice()), None);
1472     }
1473
1474     #[test]
1475     #[ignore]
1476     fn test_setenv_overwrite() {
1477         let n = make_rand_name();
1478         setenv(n.as_slice(), "1");
1479         setenv(n.as_slice(), "2");
1480         assert_eq!(getenv(n.as_slice()), Some("2".to_string()));
1481         setenv(n.as_slice(), "");
1482         assert_eq!(getenv(n.as_slice()), Some("".to_string()));
1483     }
1484
1485     // Windows GetEnvironmentVariable requires some extra work to make sure
1486     // the buffer the variable is copied into is the right size
1487     #[test]
1488     #[ignore]
1489     fn test_getenv_big() {
1490         let mut s = "".to_string();
1491         let mut i = 0i;
1492         while i < 100 {
1493             s.push_str("aaaaaaaaaa");
1494             i += 1;
1495         }
1496         let n = make_rand_name();
1497         setenv(n.as_slice(), s.as_slice());
1498         debug!("{}", s.clone());
1499         assert_eq!(getenv(n.as_slice()), Some(s));
1500     }
1501
1502     #[test]
1503     fn test_self_exe_name() {
1504         let path = os::self_exe_name();
1505         assert!(path.is_some());
1506         let path = path.unwrap();
1507         debug!("{}", path.display());
1508
1509         // Hard to test this function
1510         assert!(path.is_absolute());
1511     }
1512
1513     #[test]
1514     fn test_self_exe_path() {
1515         let path = os::self_exe_path();
1516         assert!(path.is_some());
1517         let path = path.unwrap();
1518         debug!("{}", path.display());
1519
1520         // Hard to test this function
1521         assert!(path.is_absolute());
1522     }
1523
1524     #[test]
1525     #[ignore]
1526     fn test_env_getenv() {
1527         let e = env();
1528         assert!(e.len() > 0u);
1529         for p in e.iter() {
1530             let (n, v) = (*p).clone();
1531             debug!("{}", n);
1532             let v2 = getenv(n.as_slice());
1533             // MingW seems to set some funky environment variables like
1534             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1535             // from env() but not visible from getenv().
1536             assert!(v2.is_none() || v2 == Some(v));
1537         }
1538     }
1539
1540     #[test]
1541     fn test_env_set_get_huge() {
1542         let n = make_rand_name();
1543         let s = repeat("x").take(10000).collect::<String>();
1544         setenv(n.as_slice(), s.as_slice());
1545         assert_eq!(getenv(n.as_slice()), Some(s));
1546         unsetenv(n.as_slice());
1547         assert_eq!(getenv(n.as_slice()), None);
1548     }
1549
1550     #[test]
1551     fn test_env_setenv() {
1552         let n = make_rand_name();
1553
1554         let mut e = env();
1555         setenv(n.as_slice(), "VALUE");
1556         assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
1557
1558         e = env();
1559         assert!(e.contains(&(n, "VALUE".to_string())));
1560     }
1561
1562     #[test]
1563     fn test() {
1564         assert!((!Path::new("test-path").is_absolute()));
1565
1566         let cwd = getcwd().unwrap();
1567         debug!("Current working directory: {}", cwd.display());
1568
1569         debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display());
1570         debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display());
1571     }
1572
1573     #[test]
1574     #[cfg(unix)]
1575     fn homedir() {
1576         let oldhome = getenv("HOME");
1577
1578         setenv("HOME", "/home/MountainView");
1579         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1580
1581         setenv("HOME", "");
1582         assert!(os::homedir().is_none());
1583
1584         for s in oldhome.iter() {
1585             setenv("HOME", s.as_slice());
1586         }
1587     }
1588
1589     #[test]
1590     #[cfg(windows)]
1591     fn homedir() {
1592
1593         let oldhome = getenv("HOME");
1594         let olduserprofile = getenv("USERPROFILE");
1595
1596         setenv("HOME", "");
1597         setenv("USERPROFILE", "");
1598
1599         assert!(os::homedir().is_none());
1600
1601         setenv("HOME", "/home/MountainView");
1602         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1603
1604         setenv("HOME", "");
1605
1606         setenv("USERPROFILE", "/home/MountainView");
1607         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1608
1609         setenv("HOME", "/home/MountainView");
1610         setenv("USERPROFILE", "/home/PaloAlto");
1611         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1612
1613         for s in oldhome.iter() {
1614             setenv("HOME", s.as_slice());
1615         }
1616         for s in olduserprofile.iter() {
1617             setenv("USERPROFILE", s.as_slice());
1618         }
1619     }
1620
1621     #[test]
1622     fn memory_map_rw() {
1623         use result::Result::{Ok, Err};
1624
1625         let chunk = match os::MemoryMap::new(16, &[
1626             os::MapOption::MapReadable,
1627             os::MapOption::MapWritable
1628         ]) {
1629             Ok(chunk) => chunk,
1630             Err(msg) => panic!("{:?}", msg)
1631         };
1632         assert!(chunk.len >= 16);
1633
1634         unsafe {
1635             *chunk.data = 0xBE;
1636             assert!(*chunk.data == 0xBE);
1637         }
1638     }
1639
1640     #[test]
1641     fn memory_map_file() {
1642         use libc;
1643         use os::*;
1644         use io::fs::{File, unlink};
1645         use io::SeekStyle::SeekSet;
1646         use io::FileMode::Open;
1647         use io::FileAccess::ReadWrite;
1648
1649         #[cfg(not(windows))]
1650         fn get_fd(file: &File) -> libc::c_int {
1651             use os::unix::AsRawFd;
1652             file.as_raw_fd()
1653         }
1654
1655         #[cfg(windows)]
1656         fn get_fd(file: &File) -> libc::HANDLE {
1657             use os::windows::AsRawHandle;
1658             file.as_raw_handle()
1659         }
1660
1661         let mut path = tmpdir();
1662         path.push("mmap_file.tmp");
1663         let size = MemoryMap::granularity() * 2;
1664         let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
1665         file.seek(size as i64, SeekSet).unwrap();
1666         file.write_u8(0).unwrap();
1667
1668         let chunk = MemoryMap::new(size / 2, &[
1669             MapOption::MapReadable,
1670             MapOption::MapWritable,
1671             MapOption::MapFd(get_fd(&file)),
1672             MapOption::MapOffset(size / 2)
1673         ]).unwrap();
1674         assert!(chunk.len > 0);
1675
1676         unsafe {
1677             *chunk.data = 0xbe;
1678             assert!(*chunk.data == 0xbe);
1679         }
1680         drop(chunk);
1681
1682         unlink(&path).unwrap();
1683     }
1684
1685     #[test]
1686     #[cfg(windows)]
1687     fn split_paths_windows() {
1688         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1689             split_paths(unparsed) ==
1690                 parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
1691         }
1692
1693         assert!(check_parse("", &mut [""]));
1694         assert!(check_parse(r#""""#, &mut [""]));
1695         assert!(check_parse(";;", &mut ["", "", ""]));
1696         assert!(check_parse(r"c:\", &mut [r"c:\"]));
1697         assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
1698         assert!(check_parse(r"c:\;c:\Program Files\",
1699                             &mut [r"c:\", r"c:\Program Files\"]));
1700         assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
1701         assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
1702                             &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
1703     }
1704
1705     #[test]
1706     #[cfg(unix)]
1707     fn split_paths_unix() {
1708         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1709             split_paths(unparsed) ==
1710                 parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
1711         }
1712
1713         assert!(check_parse("", &mut [""]));
1714         assert!(check_parse("::", &mut ["", "", ""]));
1715         assert!(check_parse("/", &mut ["/"]));
1716         assert!(check_parse("/:", &mut ["/", ""]));
1717         assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
1718     }
1719
1720     #[test]
1721     #[cfg(unix)]
1722     fn join_paths_unix() {
1723         fn test_eq(input: &[&str], output: &str) -> bool {
1724             join_paths(input).unwrap() == output.as_bytes()
1725         }
1726
1727         assert!(test_eq(&[], ""));
1728         assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
1729                          "/bin:/usr/bin:/usr/local/bin"));
1730         assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
1731                          ":/bin:::/usr/bin:"));
1732         assert!(join_paths(&["/te:st"]).is_err());
1733     }
1734
1735     #[test]
1736     #[cfg(windows)]
1737     fn join_paths_windows() {
1738         fn test_eq(input: &[&str], output: &str) -> bool {
1739             join_paths(input).unwrap() == output.as_bytes()
1740         }
1741
1742         assert!(test_eq(&[], ""));
1743         assert!(test_eq(&[r"c:\windows", r"c:\"],
1744                         r"c:\windows;c:\"));
1745         assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
1746                         r";c:\windows;;;c:\;"));
1747         assert!(test_eq(&[r"c:\te;st", r"c:\"],
1748                         r#""c:\te;st";c:\"#));
1749         assert!(join_paths(&[r#"c:\te"st"#]).is_err());
1750     }
1751
1752     // More recursive_mkdir tests are in extra::tempfile
1753 }