summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2014-11-24 16:21:39 -0800
committerAaron Turon <aturon@mozilla.com>2014-12-18 23:31:34 -0800
commit74d07699938b846703ab552f52cd5c32f751900f (patch)
tree692dd24ed1e8ee2091ec6728ac17c7f7d4063659 /src/libstd/sys
parent2b3477d373603527d23cc578f3737857b7b253d7 (diff)
downloadrust-74d07699938b846703ab552f52cd5c32f751900f.tar.gz
rust-74d07699938b846703ab552f52cd5c32f751900f.zip
Refactor std::os to use sys::os
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/unix/os.rs135
-rw-r--r--src/libstd/sys/windows/os.rs198
2 files changed, 327 insertions, 6 deletions
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index d951977fa59..0ed079df55b 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -8,14 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc;
-use libc::{c_int, c_char};
+//! Implementation of `std::os` functionality for unix systems
+
 use prelude::*;
-use io::IoResult;
+
+use error::{FromError, Error};
+use fmt;
+use io::{IoError, IoResult};
+use libc::{mod, c_int, c_char, c_void};
+use path::{Path, GenericPath, BytesContainer};
+use ptr::{mod, RawPtr};
+use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 use sys::fs::FileDesc;
+use os;
 
 use os::TMPBUF_SZ;
 
+const BUF_BYTES : uint = 2048u;
+
 /// Returns the platform-specific value of errno
 pub fn errno() -> int {
     #[cfg(any(target_os = "macos",
@@ -110,3 +120,122 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
         Err(super::last_error())
     }
 }
+
+pub fn getcwd() -> IoResult<Path> {
+    use c_str::CString;
+
+    let mut buf = [0 as c_char, ..BUF_BYTES];
+    unsafe {
+        if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
+            Err(IoError::last_error())
+        } else {
+            Ok(Path::new(CString::new(buf.as_ptr(), false)))
+        }
+    }
+}
+
+pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
+    use c_str::CString;
+
+    extern {
+        fn rust_env_pairs() -> *const *const c_char;
+    }
+    let mut environ = rust_env_pairs();
+    if environ as uint == 0 {
+        panic!("os::env() failure getting env string from OS: {}",
+               os::last_os_error());
+    }
+    let mut result = Vec::new();
+    while *environ != 0 as *const _ {
+        let env_pair =
+            CString::new(*environ, false).as_bytes_no_nul().to_vec();
+        result.push(env_pair);
+        environ = environ.offset(1);
+    }
+    result
+}
+
+pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
+    unparsed.split(|b| *b == b':').map(Path::new).collect()
+}
+
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+    let mut joined = Vec::new();
+    let sep = b':';
+
+    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+        if i > 0 { joined.push(sep) }
+        if path.contains(&sep) { return Err("path segment contains separator `:`") }
+        joined.push_all(path);
+    }
+
+    Ok(joined)
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        use libc::funcs::bsd44::*;
+        use libc::consts::os::extra::*;
+        let mut mib = vec![CTL_KERN as c_int,
+                           KERN_PROC as c_int,
+                           KERN_PROC_PATHNAME as c_int,
+                           -1 as c_int];
+        let mut sz: libc::size_t = 0;
+        let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+                         ptr::null_mut(), &mut sz, ptr::null_mut(),
+                         0u as libc::size_t);
+        if err != 0 { return None; }
+        if sz == 0 { return None; }
+        let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
+        let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
+                         v.as_mut_ptr() as *mut c_void, &mut sz,
+                         ptr::null_mut(), 0u as libc::size_t);
+        if err != 0 { return None; }
+        if sz == 0 { return None; }
+        v.set_len(sz as uint - 1); // chop off trailing NUL
+        Some(v)
+    }
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    use std::io;
+
+    match io::fs::readlink(&Path::new("/proc/self/exe")) {
+        Ok(path) => Some(path.into_vec()),
+        Err(..) => None
+    }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        use libc::funcs::extra::_NSGetExecutablePath;
+        let mut sz: u32 = 0;
+        _NSGetExecutablePath(ptr::null_mut(), &mut sz);
+        if sz == 0 { return None; }
+        let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
+        let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
+        if err != 0 { return None; }
+        v.set_len(sz as uint - 1); // chop off trailing NUL
+        Some(v)
+    }
+}
+
+pub fn chdir(p: &Path) -> IoResult<()> {
+    p.with_c_str(|buf| {
+        unsafe {
+            match libc::chdir(buf) == (0 as c_int) {
+                true => Ok(()),
+                false => Err(IoError::last_error()),
+            }
+        }
+    })
+}
+
+pub fn page_size() -> uint {
+    unsafe {
+        libc::sysconf(libc::_SC_PAGESIZE) as uint
+    }
+}
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
index aa43b42e746..5c690180c44 100644
--- a/src/libstd/sys/windows/os.rs
+++ b/src/libstd/sys/windows/os.rs
@@ -8,17 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Implementation of `std::os` functionality for Windows
+
 // FIXME: move various extern bindings from here into liblibc or
 // something similar
 
-use libc;
-use libc::{c_int, c_char, c_void};
 use prelude::*;
+
+use fmt;
 use io::{IoResult, IoError};
+use libc::{c_int, c_char, c_void};
+use libc;
+use os;
+use path::{Path, GenericPath, BytesContainer};
+use ptr::{mod, RawPtr};
+use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 use sys::fs::FileDesc;
-use ptr;
 
 use os::TMPBUF_SZ;
+use libc::types::os::arch::extra::DWORD;
+
+const BUF_BYTES : uint = 2048u;
 
 pub fn errno() -> uint {
     use libc::types::os::arch::extra::DWORD;
@@ -101,3 +111,185 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
         _ => Err(IoError::last_error()),
     }
 }
+
+pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) -> Option<String> {
+    unsafe {
+        let mut n = TMPBUF_SZ as DWORD;
+        let mut res = None;
+        let mut done = false;
+        while !done {
+            let mut buf = Vec::from_elem(n as uint, 0u16);
+            let k = f(buf.as_mut_ptr(), n);
+            if k == (0 as DWORD) {
+                done = true;
+            } else if k == n &&
+                      libc::GetLastError() ==
+                      libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
+                n *= 2 as DWORD;
+            } else if k >= n {
+                n = k;
+            } else {
+                done = true;
+            }
+            if k != 0 && done {
+                let sub = buf.slice(0, k as uint);
+                // We want to explicitly catch the case when the
+                // closure returned invalid UTF-16, rather than
+                // set `res` to None and continue.
+                let s = String::from_utf16(sub)
+                    .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+                res = option::Some(s)
+            }
+        }
+        return res;
+    }
+}
+
+pub fn getcwd() -> IoResult<Path> {
+    use libc::DWORD;
+    use libc::GetCurrentDirectoryW;
+    use io::OtherIoError;
+
+    let mut buf = [0 as u16, ..BUF_BYTES];
+    unsafe {
+        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
+            return Err(IoError::last_error());
+        }
+    }
+
+    match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
+        Some(ref cwd) => Ok(Path::new(cwd)),
+        None => Err(IoError {
+            kind: OtherIoError,
+            desc: "GetCurrentDirectoryW returned invalid UTF-16",
+            detail: None,
+        }),
+    }
+}
+
+pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
+    use libc::funcs::extra::kernel32::{
+        GetEnvironmentStringsW,
+        FreeEnvironmentStringsW
+    };
+    let ch = GetEnvironmentStringsW();
+    if ch as uint == 0 {
+        panic!("os::env() failure getting env string from OS: {}",
+               os::last_os_error());
+    }
+    // Here, we lossily decode the string as UTF16.
+    //
+    // The docs suggest that the result should be in Unicode, but
+    // Windows doesn't guarantee it's actually UTF16 -- it doesn't
+    // validate the environment string passed to CreateProcess nor
+    // SetEnvironmentVariable.  Yet, it's unlikely that returning a
+    // raw u16 buffer would be of practical use since the result would
+    // be inherently platform-dependent and introduce additional
+    // complexity to this code.
+    //
+    // Using the non-Unicode version of GetEnvironmentStrings is even
+    // worse since the result is in an OEM code page.  Characters that
+    // can't be encoded in the code page would be turned into question
+    // marks.
+    let mut result = Vec::new();
+    let mut i = 0;
+    while *ch.offset(i) != 0 {
+        let p = &*ch.offset(i);
+        let mut len = 0;
+        while *(p as *const _).offset(len) != 0 {
+            len += 1;
+        }
+        let p = p as *const u16;
+        let s = slice::from_raw_buf(&p, len as uint);
+        result.push(String::from_utf16_lossy(s).into_bytes());
+        i += len as int + 1;
+    }
+    FreeEnvironmentStringsW(ch);
+    result
+}
+
+pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
+    // On Windows, the PATH environment variable is semicolon separated.  Double
+    // quotes are used as a way of introducing literal semicolons (since
+    // c:\some;dir is a valid Windows path). Double quotes are not themselves
+    // permitted in path names, so there is no way to escape a double quote.
+    // Quoted regions can appear in arbitrary locations, so
+    //
+    //   c:\foo;c:\som"e;di"r;c:\bar
+    //
+    // Should parse as [c:\foo, c:\some;dir, c:\bar].
+    //
+    // (The above is based on testing; there is no clear reference available
+    // for the grammar.)
+
+    let mut parsed = Vec::new();
+    let mut in_progress = Vec::new();
+    let mut in_quote = false;
+
+    for b in unparsed.iter() {
+        match *b {
+            b';' if !in_quote => {
+                parsed.push(Path::new(in_progress.as_slice()));
+                in_progress.truncate(0)
+            }
+            b'"' => {
+                in_quote = !in_quote;
+            }
+            _  => {
+                in_progress.push(*b);
+            }
+        }
+    }
+    parsed.push(Path::new(in_progress));
+    parsed
+}
+
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+    let mut joined = Vec::new();
+    let sep = b';';
+
+    for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+        if i > 0 { joined.push(sep) }
+        if path.contains(&b'"') {
+            return Err("path segment contains `\"`");
+        } else if path.contains(&sep) {
+            joined.push(b'"');
+            joined.push_all(path);
+            joined.push(b'"');
+        } else {
+            joined.push_all(path);
+        }
+    }
+
+    Ok(joined)
+}
+
+pub fn load_self() -> Option<Vec<u8>> {
+    unsafe {
+        fill_utf16_buf_and_decode(|buf, sz| {
+            libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
+        }).map(|s| s.into_string().into_bytes())
+    }
+}
+
+pub fn chdir(p: &Path) -> IoResult<()> {
+    let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
+    p.push(0);
+
+    unsafe {
+        match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
+            true => Ok(()),
+            false => Err(IoError::last_error()),
+        }
+    }
+}
+
+pub fn page_size() -> uint {
+    use mem;
+    unsafe {
+        let mut info = mem::zeroed();
+        libc::GetSystemInfo(&mut info);
+
+        return info.dwPageSize as uint;
+    }
+}