diff --git a/src/lib/ctypes.rs b/src/lib/ctypes.rs index f5d625f1880..7e876ed7602 100644 --- a/src/lib/ctypes.rs +++ b/src/lib/ctypes.rs @@ -2,3 +2,4 @@ type size_t = uint; type ssize_t = int; +type uint32_t = u32; diff --git a/src/lib/linux_os.rs b/src/lib/linux_os.rs index 7ce8c05b095..563d10092cb 100644 --- a/src/lib/linux_os.rs +++ b/src/lib/linux_os.rs @@ -1,5 +1,3 @@ - - // FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult // by https://github.com/graydon/rust/issues#issue/268 native "cdecl" mod libc = "" { @@ -28,6 +26,8 @@ native "cdecl" mod libc = "" { fn unsetenv(n: str::sbuf) -> int; fn pipe(buf: *mutable int) -> int; fn waitpid(pid: int, &status: int, options: int) -> int; + fn readlink(path: str::sbuf, buf: str::sbuf, + bufsize: ctypes::size_t) -> ctypes::ssize_t; } mod libc_constants { @@ -78,6 +78,21 @@ native "rust" mod rustrt { fn getcwd() -> str { ret rustrt::rust_getcwd(); } +/// Returns the directory containing the running program +/// followed by a path separator +fn get_exe_path() -> option::t { + let bufsize = 1023u; + let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize)); + ret str::as_buf("/proc/self/exe", { |proc_self_buf| + str::as_buf(path, { |path_buf| + if libc::readlink(proc_self_buf, path_buf, bufsize) != -1 { + option::some(fs::dirname(path) + fs::path_sep()) + } else { + option::none + } + }) + }); +} // Local Variables: // mode: rust; diff --git a/src/lib/macos_os.rs b/src/lib/macos_os.rs index 2897551d80a..aaf682b23ba 100644 --- a/src/lib/macos_os.rs +++ b/src/lib/macos_os.rs @@ -25,6 +25,8 @@ native "cdecl" mod libc = "" { fn unsetenv(n: str::sbuf) -> int; fn pipe(buf: *mutable int) -> int; fn waitpid(pid: int, &status: int, options: int) -> int; + fn _NSGetExecutablePath(buf: str::sbuf, + bufsize: *mutable ctypes::uint32_t) -> int; } mod libc_constants { @@ -75,6 +77,18 @@ native "rust" mod rustrt { fn getcwd() -> str { ret rustrt::rust_getcwd(); } +fn get_exe_path() -> option::t { + // FIXME: This doesn't handle the case where the buffer is too small + let bufsize = 1023u32; + let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize as uint)); + ret str::as_buf(path, { |path_buf| + if libc::_NSGetExecutablePath(path_buf, ptr::addr_of(bufsize)) == 0 { + option::some(fs::dirname(path) + fs::path_sep()) + } else { + option::none + } + }); +} // Local Variables: // mode: rust; diff --git a/src/lib/win32_os.rs b/src/lib/win32_os.rs index 7cd3f58cdca..560d9be8c8e 100644 --- a/src/lib/win32_os.rs +++ b/src/lib/win32_os.rs @@ -39,10 +39,17 @@ mod libc_constants { } } +type DWORD = u32; +type HMODULE = uint; +type LPTSTR = str::sbuf; + native "x86stdcall" mod kernel32 { fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: uint) -> uint; fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> int; + fn GetModuleFileNameA(hModule: HMODULE, + lpFilename: LPTSTR, + nSize: DWORD) -> DWORD; } fn exec_suffix() -> str { ret ".exe"; } @@ -81,6 +88,20 @@ fn waitpid(pid: int) -> int { ret rustrt::rust_process_wait(pid); } fn getcwd() -> str { ret rustrt::rust_getcwd(); } +fn get_exe_path() -> option::t { + // FIXME: This doesn't handle the case where the buffer is too small + let bufsize = 1023u; + let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize)); + ret str::as_buf(path, { |path_buf| + if kernel32::GetModuleFileNameA(0u, path_buf, + bufsize as u32) != 0u32 { + option::some(fs::dirname(path) + fs::path_sep()) + } else { + option::none + } + }); +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/test/stdtest/os.rs b/src/test/stdtest/os.rs index 49ebb217dbf..2d17afddc95 100644 --- a/src/test/stdtest/os.rs +++ b/src/test/stdtest/os.rs @@ -28,6 +28,21 @@ fn test_getenv_big() { assert (getenv("NAME3") == option::some(s)); } +#[test] +fn get_exe_path() { + let path = std::os::get_exe_path(); + assert option::is_some(path); + let path = option::get(path); + log path; + + // Hard to test this function + if std::os::target_os() != "win32" { + assert std::str::starts_with(path, std::fs::path_sep()); + } else { + assert path[1] == ':' as u8; + } +} + // Local Variables: // mode: rust; // fill-column: 78;