diff options
| author | Graydon Hoare <graydon@mozilla.com> | 2012-03-12 20:04:27 -0700 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2012-03-12 20:08:29 -0700 |
| commit | 6f5853f5a1767e0c418fd5f348a795b76d701b3e (patch) | |
| tree | 7d054b8471a75c47854edbd52a14d8d2acf81c9d /src/libstd | |
| parent | ac57bb38560fa35d883505af2e8e68498b436fe7 (diff) | |
| download | rust-6f5853f5a1767e0c418fd5f348a795b76d701b3e.tar.gz rust-6f5853f5a1767e0c418fd5f348a795b76d701b3e.zip | |
Libc/os/run/rand/io reorganization. Close #1373. Close #1638.
- Move io, run and rand to core. - Remove incorrect ctypes module (use libc). - Remove os-specific modules for os and fs. - Split fs between core::path and core::os.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/c_vec.rs | 12 | ||||
| -rw-r--r-- | src/libstd/freebsd_os.rs | 160 | ||||
| -rw-r--r-- | src/libstd/fs.rs | 765 | ||||
| -rw-r--r-- | src/libstd/generic_os.rs | 190 | ||||
| -rw-r--r-- | src/libstd/io.rs | 750 | ||||
| -rw-r--r-- | src/libstd/linux_os.rs | 152 | ||||
| -rw-r--r-- | src/libstd/macos_os.rs | 160 | ||||
| -rw-r--r-- | src/libstd/posix_fs.rs | 46 | ||||
| -rw-r--r-- | src/libstd/rand.rs | 113 | ||||
| -rw-r--r-- | src/libstd/run_program.rs | 395 | ||||
| -rw-r--r-- | src/libstd/std.rc | 43 | ||||
| -rw-r--r-- | src/libstd/tempfile.rs | 5 | ||||
| -rw-r--r-- | src/libstd/term.rs | 2 | ||||
| -rw-r--r-- | src/libstd/test.rs | 3 | ||||
| -rw-r--r-- | src/libstd/uv.rs | 68 | ||||
| -rw-r--r-- | src/libstd/win32_fs.rs | 35 | ||||
| -rw-r--r-- | src/libstd/win32_os.rs | 140 |
17 files changed, 42 insertions, 2997 deletions
diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index e17a44234f4..99233725362 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -126,21 +126,15 @@ unsafe fn ptr<T>(t: t<T>) -> *mutable T { #[cfg(test)] mod tests { - import ctypes::*; - - #[nolink] - #[abi = "cdecl"] - native mod libc { - fn malloc(n: size_t) -> *mutable u8; - fn free(m: *mutable u8); - } + import libc::*; fn malloc(n: size_t) -> t<u8> { let mem = libc::malloc(n); assert mem as int != 0; - ret unsafe { create_with_dtor(mem, n, bind libc::free(mem)) }; + ret unsafe { create_with_dtor(mem as *mutable u8, n, + bind free(mem)) }; } #[test] diff --git a/src/libstd/freebsd_os.rs b/src/libstd/freebsd_os.rs deleted file mode 100644 index 6fbe0b00fde..00000000000 --- a/src/libstd/freebsd_os.rs +++ /dev/null @@ -1,160 +0,0 @@ -/* -Module: os - -TODO: Restructure and document -*/ - -import core::option; -import core::ctypes::*; - -export libc; -export libc_constants; -export pipe; -export FILE, fd_FILE; -export close; -export fclose; -export waitpid; -export getcwd; -export exec_suffix; -export target_os; -export dylib_filename; -export get_exe_path; -export fsync_fd; -export rustrt; - -// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult -// by https://github.com/graydon/rust/issues#issue/268 - -enum FILE_opaque {} -type FILE = *FILE_opaque; -enum dir {} -enum dirent {} - -#[nolink] -#[abi = "cdecl"] -native mod libc { - fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t; - fn close(fd: fd_t) -> c_int; - fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE; - fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE; - fn fclose(f: FILE); - fn fflush(f: FILE) -> c_int; - fn fsync(fd: fd_t) -> c_int; - fn fileno(f: FILE) -> fd_t; - fn fgetc(f: FILE) -> c_int; - fn ungetc(c: c_int, f: FILE); - fn feof(f: FILE) -> c_int; - fn fseek(f: FILE, offset: long, whence: c_int) -> c_int; - fn ftell(f: FILE) -> long; - fn opendir(d: str::sbuf) -> *dir; - fn closedir(d: *dir) -> c_int; - fn readdir(d: *dir) -> *dirent; - fn getenv(n: str::sbuf) -> str::sbuf; - fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int; - fn unsetenv(n: str::sbuf) -> c_int; - fn pipe(buf: *mutable fd_t) -> c_int; - fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> pid_t; - fn readlink(path: str::sbuf, buf: str::sbuf, bufsize: size_t) -> ssize_t; - fn mkdir(path: str::sbuf, mode: c_int) -> c_int; - fn rmdir(path: str::sbuf) -> c_int; - fn chdir(path: str::sbuf) -> c_int; - fn unlink(path: str::sbuf) -> c_int; - - fn sysctl(name: *c_int, namelen: c_uint, - oldp: *u8, &oldlenp: size_t, - newp: *u8, newlen: size_t) -> c_int; -} - -mod libc_constants { - const O_RDONLY: c_int = 0i32; - const O_WRONLY: c_int = 1i32; - const O_RDWR: c_int = 2i32; - const O_APPEND: c_int = 8i32; - const O_CREAT: c_int = 512i32; - const O_EXCL: c_int = 2048i32; - const O_TRUNC: c_int = 1024i32; - const O_TEXT: c_int = 0i32; // nonexistent in FreeBSD libc - const O_BINARY: c_int = 0i32; // nonexistent in FreeBSD libc - - const S_IRUSR: unsigned = 256u32; - const S_IWUSR: unsigned = 128u32; - - const CTL_KERN: c_int = 1i32; - const KERN_PROC: c_int = 14i32; - const KERN_PROC_PATHNAME: c_int = 12i32; -} - -fn pipe() -> {in: fd_t, out: fd_t} { - let fds = {mutable in: 0i32, mutable out: 0i32}; - assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32); - ret {in: fds.in, out: fds.out}; -} - -fn fd_FILE(fd: fd_t) -> FILE { - ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) }); -} - -fn close(fd: fd_t) -> c_int { - libc::close(fd) -} - -fn fclose(file: FILE) { - libc::fclose(file) -} - -fn fsync_fd(fd: fd_t, _l: io::fsync::level) -> c_int { - ret libc::fsync(fd); -} - -fn waitpid(pid: pid_t) -> i32 { - let status = 0i32; - assert (os::libc::waitpid(pid, status, 0i32) != -1i32); - ret status; -} - -#[abi = "cdecl"] -native mod rustrt { - fn rust_env_pairs() -> [str]; - fn rust_getcwd() -> str; -} - -fn getcwd() -> str { ret rustrt::rust_getcwd(); } - -fn exec_suffix() -> str { ret ""; } - -fn target_os() -> str { ret "freebsd"; } - -fn dylib_filename(base: str) -> str { ret "lib" + base + ".so"; } - -/// Returns the directory containing the running program -/// followed by a path separator -fn get_exe_path() -> option<fs::path> unsafe { - let bufsize = 1023u; - // FIXME: path "strings" will likely need fixing... - let path = str::from_bytes(vec::init_elt(bufsize, 0u8)); - let mib = [libc_constants::CTL_KERN, - libc_constants::KERN_PROC, - libc_constants::KERN_PROC_PATHNAME, -1i32]; - ret str::as_buf(path, { |path_buf| - if libc::sysctl(vec::unsafe::to_ptr(mib), - vec::len(mib) as c_uint, - path_buf, bufsize, - ptr::null(), 0u) == 0i32 { - option::some(fs::dirname(path) + fs::path_sep()) - } else { - option::none - } - }); -} - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs deleted file mode 100644 index 8a5b88f7480..00000000000 --- a/src/libstd/fs.rs +++ /dev/null @@ -1,765 +0,0 @@ -/* -Module: fs - -File system manipulation -*/ - -import core::ctypes; -import core::vec; -import core::option; -import os; -import os::getcwd; -import os_fs; - -#[abi = "cdecl"] -native mod rustrt { - fn rust_path_is_dir(path: str::sbuf) -> ctypes::c_int; - fn rust_path_exists(path: str::sbuf) -> ctypes::c_int; -} - -/* -Function: path_sep - -Get the default path separator for the host platform -*/ -fn path_sep() -> str { ret str::from_char(os_fs::path_sep); } - -// FIXME: This type should probably be constrained -/* -Type: path - -A path or fragment of a filesystem path -*/ -type path = str; - -fn split_dirname_basename (pp: path) -> {dirname: str, basename: str} { - alt str::rfind(pp, {|ch| - ch == os_fs::path_sep || ch == os_fs::alt_path_sep - }) { - some(i) { - {dirname: str::slice(pp, 0u, i), - basename: str::slice(pp, i + 1u, str::len(pp))} - } - none { {dirname: ".", basename: pp} } - } -} - -/* -Function: dirname - -Get the directory portion of a path - -Returns all of the path up to, but excluding, the final path separator. -The dirname of "/usr/share" will be "/usr", but the dirname of -"/usr/share/" is "/usr/share". - -If the path is not prefixed with a directory, then "." is returned. -*/ -fn dirname(pp: path) -> path { - ret split_dirname_basename(pp).dirname; -} - -/* -Function: basename - -Get the file name portion of a path - -Returns the portion of the path after the final path separator. -The basename of "/usr/share" will be "share". If there are no -path separators in the path then the returned path is identical to -the provided path. If an empty path is provided or the path ends -with a path separator then an empty path is returned. -*/ -fn basename(pp: path) -> path { - ret split_dirname_basename(pp).basename; -} - -// FIXME: Need some typestate to avoid bounds check when len(pre) == 0 -/* -Function: connect - -Connects to path segments - -Given paths `pre` and `post, removes any trailing path separator on `pre` and -any leading path separator on `post`, and returns the concatenation of the two -with a single path separator between them. -*/ - -fn connect(pre: path, post: path) -> path unsafe { - let pre_ = pre; - let post_ = post; - let sep = os_fs::path_sep as u8; - let pre_len = str::len(pre); - let post_len = str::len(post); - if pre_len > 1u && pre[pre_len-1u] == sep { str::unsafe::pop_byte(pre_); } - if post_len > 1u && post[0] == sep { str::unsafe::shift_byte(post_); } - ret pre_ + path_sep() + post_; -} - -/* -Function: connect_many - -Connects a vector of path segments into a single path. - -Inserts path separators as needed. -*/ -fn connect_many(paths: [path]) -> path { - ret if vec::len(paths) == 1u { - paths[0] - } else { - let rest = vec::slice(paths, 1u, vec::len(paths)); - connect(paths[0], connect_many(rest)) - } -} - -/* -Function: path_is_dir - -Indicates whether a path represents a directory. -*/ -fn path_is_dir(p: path) -> bool { - ret str::as_buf(p, {|buf| - rustrt::rust_path_is_dir(buf) != 0 as ctypes::c_int - }); -} - -/* -Function: path_exists - -Indicates whether a path exists. -*/ -fn path_exists(p: path) -> bool { - ret str::as_buf(p, {|buf| - rustrt::rust_path_exists(buf) != 0 as ctypes::c_int - }); -} - -/* -Function: make_dir - -Creates a directory at the specified path. -*/ -fn make_dir(p: path, mode: ctypes::c_int) -> bool { - ret mkdir(p, mode); - - #[cfg(target_os = "win32")] - fn mkdir(_p: path, _mode: ctypes::c_int) -> bool unsafe { - // FIXME: turn mode into something useful? - ret str::as_buf(_p, {|buf| - os::kernel32::CreateDirectoryA( - buf, unsafe::reinterpret_cast(0)) - }); - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn mkdir(_p: path, _mode: ctypes::c_int) -> bool { - ret str::as_buf(_p, {|buf| os::libc::mkdir(buf, _mode) == 0i32 }); - } -} - -/* -Function: list_dir - -Lists the contents of a directory. -*/ -fn list_dir(p: path) -> [str] { - let p = p; - let pl = str::len(p); - if pl == 0u || p[pl - 1u] as char != os_fs::path_sep { p += path_sep(); } - let full_paths: [str] = []; - for filename: str in os_fs::list_dir(p) { - if !str::eq(filename, ".") { - if !str::eq(filename, "..") { full_paths += [p + filename]; } - } - } - ret full_paths; -} - -/* -Function: remove_dir - -Removes a directory at the specified path. -*/ -fn remove_dir(p: path) -> bool { - ret rmdir(p); - - #[cfg(target_os = "win32")] - fn rmdir(_p: path) -> bool { - ret str::as_buf(_p, {|buf| os::kernel32::RemoveDirectoryA(buf)}); - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn rmdir(_p: path) -> bool { - ret str::as_buf(_p, {|buf| os::libc::rmdir(buf) == 0i32 }); - } -} - -fn change_dir(p: path) -> bool { - ret chdir(p); - - #[cfg(target_os = "win32")] - fn chdir(_p: path) -> bool { - ret str::as_buf(_p, {|buf| os::kernel32::SetCurrentDirectoryA(buf)}); - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn chdir(_p: path) -> bool { - ret str::as_buf(_p, {|buf| os::libc::chdir(buf) == 0i32 }); - } -} - -/* -Function: path_is_absolute - -Indicates whether a path is absolute. - -A path is considered absolute if it begins at the filesystem root ("/") or, -on Windows, begins with a drive letter. -*/ -fn path_is_absolute(p: path) -> bool { ret os_fs::path_is_absolute(p); } - -// FIXME: under Windows, we should prepend the current drive letter to paths -// that start with a slash. -/* -Function: make_absolute - -Convert a relative path to an absolute path - -If the given path is relative, return it prepended with the current working -directory. If the given path is already an absolute path, return it -as is. -*/ -fn make_absolute(p: path) -> path { - if path_is_absolute(p) { ret p; } else { ret connect(getcwd(), p); } -} - -/* -Function: split - -Split a path into it's individual components - -Splits a given path by path separators and returns a vector containing -each piece of the path. On Windows, if the path is absolute then -the first element of the returned vector will be the drive letter -followed by a colon. -*/ -fn split(p: path) -> [path] { - str::split_nonempty(p, {|c| - c == os_fs::path_sep || c == os_fs::alt_path_sep - }) -} - -/* -Function: splitext - -Split a path into a pair of strings with the first element being the filename -without the extension and the second being either empty or the file extension -including the period. Leading periods in the basename are ignored. If the -path includes directory components then they are included in the filename part -of the result pair. -*/ -fn splitext(p: path) -> (str, str) { - if str::is_empty(p) { ("", "") } - else { - let parts = str::split_char(p, '.'); - if vec::len(parts) > 1u { - let base = str::connect(vec::init(parts), "."); - // We just checked that parts is non-empty - let ext = "." + vec::last(parts); - - fn is_dotfile(base: str) -> bool { - str::is_empty(base) - || str::ends_with( - base, str::from_char(os_fs::path_sep)) - || str::ends_with( - base, str::from_char(os_fs::alt_path_sep)) - } - - fn ext_contains_sep(ext: str) -> bool { - vec::len(split(ext)) > 1u - } - - fn no_basename(ext: str) -> bool { - str::ends_with( - ext, str::from_char(os_fs::path_sep)) - || str::ends_with( - ext, str::from_char(os_fs::alt_path_sep)) - } - - if is_dotfile(base) - || ext_contains_sep(ext) - || no_basename(ext) { - (p, "") - } else { - (base, ext) - } - } else { - (p, "") - } - } -} - -/* -Function: normalize - -Removes extra "." and ".." entries from paths. - -Does not follow symbolic links. -*/ -fn normalize(p: path) -> path { - let s = split(p); - let s = strip_dots(s); - let s = rollup_doubledots(s); - - let s = if check vec::is_not_empty(s) { - connect_many(s) - } else { - "" - }; - let s = reabsolute(p, s); - let s = reterminate(p, s); - - let s = if str::len(s) == 0u { - "." - } else { - s - }; - - ret s; - - fn strip_dots(s: [path]) -> [path] { - vec::filter_map(s, { |elem| - if elem == "." { - option::none - } else { - option::some(elem) - } - }) - } - - fn rollup_doubledots(s: [path]) -> [path] { - if vec::is_empty(s) { - ret []; - } - - let t = []; - let i = vec::len(s); - let skip = 0; - do { - i -= 1u; - if s[i] == ".." { - skip += 1; - } else { - if skip == 0 { - t += [s[i]]; - } else { - skip -= 1; - } - } - } while i != 0u; - let t = vec::reversed(t); - while skip > 0 { - t += [".."]; - skip -= 1; - } - ret t; - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn reabsolute(orig: path, new: path) -> path { - if path_is_absolute(orig) { - path_sep() + new - } else { - new - } - } - - #[cfg(target_os = "win32")] - fn reabsolute(orig: path, new: path) -> path { - if path_is_absolute(orig) && orig[0] == os_fs::path_sep as u8 { - str::from_char(os_fs::path_sep) + new - } else { - new - } - } - - fn reterminate(orig: path, new: path) -> path { - let last = orig[str::len(orig) - 1u]; - if last == os_fs::path_sep as u8 - || last == os_fs::path_sep as u8 { - ret new + path_sep(); - } else { - ret new; - } - } -} - -/* -Function: homedir - -Returns the path to the user's home directory, if known. - -On Unix, returns the value of the "HOME" environment variable if it is set and -not equal to the empty string. - -On Windows, returns the value of the "HOME" environment variable if it is set -and not equal to the empty string. Otherwise, returns the value of the -"USERPROFILE" environment variable if it is set and not equal to the empty -string. - -Otherwise, homedir returns option::none. -*/ -fn homedir() -> option<path> { - ret alt generic_os::getenv("HOME") { - some(p) { - if !str::is_empty(p) { - some(p) - } else { - secondary() - } - } - none { - secondary() - } - }; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn secondary() -> option<path> { - none - } - - #[cfg(target_os = "win32")] - fn secondary() -> option<path> { - option::maybe(none, generic_os::getenv("USERPROFILE")) {|p| - if !str::is_empty(p) { - some(p) - } else { - none - } - } - } -} - -/* -Function: remove_file - -Deletes an existing file. -*/ -fn remove_file(p: path) -> bool { - ret unlink(p); - - #[cfg(target_os = "win32")] - fn unlink(p: path) -> bool { - ret str::as_buf(p, {|buf| os::kernel32::DeleteFileA(buf)}); - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn unlink(_p: path) -> bool { - ret str::as_buf(_p, {|buf| os::libc::unlink(buf) == 0i32 }); - } -} - -#[cfg(test)] -mod tests { - #[test] - fn test_connect() { - let slash = fs::path_sep(); - log(error, fs::connect("a", "b")); - assert (fs::connect("a", "b") == "a" + slash + "b"); - assert (fs::connect("a" + slash, "b") == "a" + slash + "b"); - } - - // Issue #712 - #[test] - fn test_list_dir_no_invalid_memory_access() { fs::list_dir("."); } - - #[test] - fn list_dir() { - let dirs = fs::list_dir("."); - // Just assuming that we've got some contents in the current directory - assert (vec::len(dirs) > 0u); - - for dir in dirs { log(debug, dir); } - } - - #[test] - fn path_is_dir() { - assert (fs::path_is_dir(".")); - assert (!fs::path_is_dir("test/stdtest/fs.rs")); - } - - #[test] - fn path_exists() { - assert (fs::path_exists(".")); - assert (!fs::path_exists("test/nonexistent-bogus-path")); - } - - fn ps() -> str { - fs::path_sep() - } - - fn aps() -> str { - "/" - } - - #[test] - fn split1() { - let actual = fs::split("a" + ps() + "b"); - let expected = ["a", "b"]; - assert actual == expected; - } - - #[test] - fn split2() { - let actual = fs::split("a" + aps() + "b"); - let expected = ["a", "b"]; - assert actual == expected; - } - - #[test] - fn split3() { - let actual = fs::split(ps() + "a" + ps() + "b"); - let expected = ["a", "b"]; - assert actual == expected; - } - - #[test] - fn split4() { - let actual = fs::split("a" + ps() + "b" + aps() + "c"); - let expected = ["a", "b", "c"]; - assert actual == expected; - } - - #[test] - fn normalize1() { - let actual = fs::normalize("a/b/.."); - let expected = "a"; - assert actual == expected; - } - - #[test] - fn normalize2() { - let actual = fs::normalize("/a/b/.."); - let expected = "/a"; - assert actual == expected; - } - - #[test] - fn normalize3() { - let actual = fs::normalize("a/../b"); - let expected = "b"; - assert actual == expected; - } - - #[test] - fn normalize4() { - let actual = fs::normalize("/a/../b"); - let expected = "/b"; - assert actual == expected; - } - - #[test] - fn normalize5() { - let actual = fs::normalize("a/."); - let expected = "a"; - assert actual == expected; - } - - #[test] - fn normalize6() { - let actual = fs::normalize("a/./b/"); - let expected = "a/b/"; - assert actual == expected; - } - - #[test] - fn normalize7() { - let actual = fs::normalize("a/.."); - let expected = "."; - assert actual == expected; - } - - #[test] - fn normalize8() { - let actual = fs::normalize("../../.."); - let expected = "../../.."; - assert actual == expected; - } - - #[test] - fn normalize9() { - let actual = fs::normalize("a/b/../../.."); - let expected = ".."; - assert actual == expected; - } - - #[test] - fn normalize10() { - let actual = fs::normalize("/a/b/c/../d/./../../e/"); - let expected = "/a/e/"; - log(error, actual); - assert actual == expected; - } - - #[test] - fn normalize11() { - let actual = fs::normalize("/a/.."); - let expected = "/"; - assert actual == expected; - } - - #[test] - #[cfg(target_os = "win32")] - fn normalize12() { - let actual = fs::normalize("C:/whatever"); - let expected = "C:/whatever"; - log(error, actual); - assert actual == expected; - } - - #[test] - #[cfg(target_os = "win32")] - fn path_is_absolute_win32() { - assert fs::path_is_absolute("C:/whatever"); - } - - #[test] - fn splitext_empty() { - let (base, ext) = fs::splitext(""); - assert base == ""; - assert ext == ""; - } - - #[test] - fn splitext_ext() { - let (base, ext) = fs::splitext("grum.exe"); - assert base == "grum"; - assert ext == ".exe"; - } - - #[test] - fn splitext_noext() { - let (base, ext) = fs::splitext("grum"); - assert base == "grum"; - assert ext == ""; - } - - #[test] - fn splitext_dotfile() { - let (base, ext) = fs::splitext(".grum"); - assert base == ".grum"; - assert ext == ""; - } - - #[test] - fn splitext_path_ext() { - let (base, ext) = fs::splitext("oh/grum.exe"); - assert base == "oh/grum"; - assert ext == ".exe"; - } - - #[test] - fn splitext_path_noext() { - let (base, ext) = fs::splitext("oh/grum"); - assert base == "oh/grum"; - assert ext == ""; - } - - #[test] - fn splitext_dot_in_path() { - let (base, ext) = fs::splitext("oh.my/grum"); - assert base == "oh.my/grum"; - assert ext == ""; - } - - #[test] - fn splitext_nobasename() { - let (base, ext) = fs::splitext("oh.my/"); - assert base == "oh.my/"; - assert ext == ""; - } - - #[test] - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn homedir() { - import getenv = generic_os::getenv; - import setenv = generic_os::setenv; - - let oldhome = getenv("HOME"); - - setenv("HOME", "/home/MountainView"); - assert fs::homedir() == some("/home/MountainView"); - - setenv("HOME", ""); - assert fs::homedir() == none; - - option::may(oldhome, {|s| setenv("HOME", s)}); - } - - #[test] - #[cfg(target_os = "win32")] - fn homedir() { - import getenv = generic_os::getenv; - import setenv = generic_os::setenv; - - let oldhome = getenv("HOME"); - let olduserprofile = getenv("USERPROFILE"); - - setenv("HOME", ""); - setenv("USERPROFILE", ""); - - assert fs::homedir() == none; - - setenv("HOME", "/home/MountainView"); - assert fs::homedir() == some("/home/MountainView"); - - setenv("HOME", ""); - - setenv("USERPROFILE", "/home/MountainView"); - assert fs::homedir() == some("/home/MountainView"); - - setenv("USERPROFILE", "/home/MountainView"); - assert fs::homedir() == some("/home/MountainView"); - - setenv("HOME", "/home/MountainView"); - setenv("USERPROFILE", "/home/PaloAlto"); - assert fs::homedir() == some("/home/MountainView"); - - option::may(oldhome, {|s| setenv("HOME", s)}); - option::may(olduserprofile, {|s| setenv("USERPROFILE", s)}); - } -} - - -#[test] -fn test() { - assert (!fs::path_is_absolute("test-path")); - - log(debug, "Current working directory: " + os::getcwd()); - - log(debug, fs::make_absolute("test-path")); - log(debug, fs::make_absolute("/usr/bin")); -} - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/generic_os.rs b/src/libstd/generic_os.rs deleted file mode 100644 index 77542cd11f8..00000000000 --- a/src/libstd/generic_os.rs +++ /dev/null @@ -1,190 +0,0 @@ -/* -Module: generic_os - -Some miscellaneous platform functions. - -These should be rolled into another module. -*/ - -import core::option; - -// Wow, this is an ugly way to write doc comments - -#[cfg(bogus)] -#[doc = "Get the value of an environment variable"] -fn getenv(n: str) -> option<str> { } - -#[cfg(bogus)] -#[doc = "Set the value of an environment variable"] -fn setenv(n: str, v: str) { } - -fn env() -> [(str,str)] { - let pairs = []; - for p in os::rustrt::rust_env_pairs() { - let vs = str::splitn_char(p, '=', 1u); - assert vec::len(vs) == 2u; - pairs += [(vs[0], vs[1])]; - } - ret pairs; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -#[cfg(target_os = "freebsd")] -fn getenv(n: str) -> option<str> unsafe { - let s = str::as_buf(n, {|buf| os::libc::getenv(buf) }); - ret if unsafe::reinterpret_cast(s) == 0 { - option::none::<str> - } else { - let s = unsafe::reinterpret_cast(s); - option::some::<str>(str::from_cstr(s)) - }; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -#[cfg(target_os = "freebsd")] -fn setenv(n: str, v: str) { - // FIXME (868) - str::as_buf( - n, - // FIXME (868) - {|nbuf| - str::as_buf( - v, - {|vbuf| - os::libc::setenv(nbuf, vbuf, 1i32)})}); -} - -#[cfg(target_os = "win32")] -fn getenv(n: str) -> option<str> { - let nsize = 256u; - loop { - let v: [u8] = []; - vec::reserve(v, nsize); - let res = - str::as_buf(n, - {|nbuf| - unsafe { - let vbuf = vec::unsafe::to_ptr(v); - os::kernel32::GetEnvironmentVariableA(nbuf, vbuf, - nsize) - } - }); - if res == 0u { - ret option::none; - } else if res < nsize { - unsafe { - vec::unsafe::set_len(v, res); - } - ret option::some(str::from_bytes(v)); // UTF-8 or fail - } else { nsize = res; } - }; -} - -#[cfg(target_os = "win32")] -fn setenv(n: str, v: str) { - // FIXME (868) - let _: () = - str::as_buf(n, {|nbuf| - let _: () = - str::as_buf(v, {|vbuf| - os::kernel32::SetEnvironmentVariableA(nbuf, vbuf); - }); - }); -} - - -#[cfg(test)] -mod tests { - - fn make_rand_name() -> str { - import rand; - let rng: rand::rng = rand::mk_rng(); - let n = "TEST" + rng.gen_str(10u); - assert option::is_none(getenv(n)); - n - } - - #[test] - #[ignore(reason = "fails periodically on mac")] - fn test_setenv() { - let n = make_rand_name(); - setenv(n, "VALUE"); - assert getenv(n) == option::some("VALUE"); - } - - #[test] - #[ignore(reason = "fails periodically on mac")] - fn test_setenv_overwrite() { - let n = make_rand_name(); - setenv(n, "1"); - setenv(n, "2"); - assert getenv(n) == option::some("2"); - setenv(n, ""); - assert getenv(n) == option::some(""); - } - - // Windows GetEnvironmentVariable requires some extra work to make sure - // the buffer the variable is copied into is the right size - #[test] - #[ignore(reason = "fails periodically on mac")] - fn test_getenv_big() { - let s = ""; - let i = 0; - while i < 100 { s += "aaaaaaaaaa"; i += 1; } - let n = make_rand_name(); - setenv(n, s); - log(debug, s); - assert getenv(n) == option::some(s); - } - - #[test] - fn test_get_exe_path() { - let path = os::get_exe_path(); - assert option::is_some(path); - let path = option::get(path); - log(debug, path); - - // Hard to test this function - if os::target_os() != "win32" { - assert str::starts_with(path, fs::path_sep()); - } else { - assert path[1] == ':' as u8; - } - } - - #[test] - fn test_env_getenv() { - let e = env(); - assert vec::len(e) > 0u; - for (n, v) in e { - log(debug, n); - let v2 = getenv(n); - // MingW seems to set some funky environment variables like - // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned - // from env() but not visible from getenv(). - assert option::is_none(v2) || v2 == option::some(v); - } - } - - #[test] - fn test_env_setenv() { - let n = make_rand_name(); - - let e = env(); - setenv(n, "VALUE"); - assert !vec::contains(e, (n, "VALUE")); - - e = env(); - assert vec::contains(e, (n, "VALUE")); - } -} - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/io.rs b/src/libstd/io.rs deleted file mode 100644 index 516aa25f05b..00000000000 --- a/src/libstd/io.rs +++ /dev/null @@ -1,750 +0,0 @@ -/* -Module: io - -Basic input/output -*/ - -import core::ctypes::fd_t; -import core::ctypes::c_int; - -#[abi = "cdecl"] -native mod rustrt { - fn rust_get_stdin() -> os::FILE; - fn rust_get_stdout() -> os::FILE; - fn rust_get_stderr() -> os::FILE; -} - -// Reading - -// FIXME This is all buffered. We might need an unbuffered variant as well -enum seek_style { seek_set, seek_end, seek_cur, } - - -// The raw underlying reader iface. All readers must implement this. -iface reader { - // FIXME: Seekable really should be orthogonal. - fn read_bytes(uint) -> [u8]; - fn read_byte() -> int; - fn unread_byte(int); - fn eof() -> bool; - fn seek(int, seek_style); - fn tell() -> uint; -} - -// Generic utility functions defined on readers - -impl reader_util for reader { - fn read_chars(n: uint) -> [char] { - // returns the (consumed offset, n_req), appends characters to &chars - fn chars_from_buf(buf: [u8], &chars: [char]) -> (uint, uint) { - let i = 0u; - while i < vec::len(buf) { - let b0 = buf[i]; - let w = str::utf8_char_width(b0); - let end = i + w; - i += 1u; - assert (w > 0u); - if w == 1u { - chars += [ b0 as char ]; - cont; - } - // can't satisfy this char with the existing data - if end > vec::len(buf) { - ret (i - 1u, end - vec::len(buf)); - } - let val = 0u; - while i < end { - let next = buf[i] as int; - i += 1u; - assert (next > -1); - assert (next & 192 == 128); - val <<= 6u; - val += (next & 63) as uint; - } - // See str::char_at - val += ((b0 << ((w + 1u) as u8)) as uint) - << (w - 1u) * 6u - w - 1u; - chars += [ val as char ]; - } - ret (i, 0u); - } - let buf: [u8] = []; - let chars: [char] = []; - // might need more bytes, but reading n will never over-read - let nbread = n; - while nbread > 0u { - let data = self.read_bytes(nbread); - if vec::len(data) == 0u { - // eof - FIXME should we do something if - // we're split in a unicode char? - break; - } - buf += data; - let (offset, nbreq) = chars_from_buf(buf, chars); - let ncreq = n - vec::len(chars); - // again we either know we need a certain number of bytes - // to complete a character, or we make sure we don't - // over-read by reading 1-byte per char needed - nbread = if ncreq > nbreq { ncreq } else { nbreq }; - if nbread > 0u { - buf = vec::slice(buf, offset, vec::len(buf)); - } - } - chars - } - - fn read_char() -> char { - let c = self.read_chars(1u); - if vec::len(c) == 0u { - ret -1 as char; // FIXME will this stay valid? - } - assert(vec::len(c) == 1u); - ret c[0]; - } - - fn read_line() -> str { - let buf: [u8] = []; - loop { - let ch = self.read_byte(); - if ch == -1 || ch == 10 { break; } - buf += [ch as u8]; - } - str::from_bytes(buf) - } - - fn read_c_str() -> str { - let buf: [u8] = []; - loop { - let ch = self.read_byte(); - if ch < 1 { break; } else { buf += [ch as u8]; } - } - str::from_bytes(buf) - } - - // FIXME deal with eof? - fn read_le_uint(size: uint) -> uint { - let val = 0u, pos = 0u, i = size; - while i > 0u { - val += (self.read_byte() as uint) << pos; - pos += 8u; - i -= 1u; - } - val - } - fn read_le_int(size: uint) -> int { - let val = 0u, pos = 0u, i = size; - while i > 0u { - val += (self.read_byte() as uint) << pos; - pos += 8u; - i -= 1u; - } - val as int - } - fn read_be_uint(size: uint) -> uint { - let val = 0u, i = size; - while i > 0u { - i -= 1u; - val += (self.read_byte() as uint) << i * 8u; - } - val - } - - fn read_whole_stream() -> [u8] { - let buf: [u8] = []; - while !self.eof() { buf += self.read_bytes(2048u); } - buf - } -} - -// Reader implementations - -fn convert_whence(whence: seek_style) -> i32 { - ret alt whence { - seek_set { 0i32 } - seek_cur { 1i32 } - seek_end { 2i32 } - }; -} - -impl of reader for os::FILE { - fn read_bytes(len: uint) -> [u8] unsafe { - let buf = []; - vec::reserve(buf, len); - let read = os::libc::fread(vec::unsafe::to_ptr(buf), 1u, len, self); - vec::unsafe::set_len(buf, read); - ret buf; - } - fn read_byte() -> int { ret os::libc::fgetc(self) as int; } - fn unread_byte(byte: int) { os::libc::ungetc(byte as i32, self); } - fn eof() -> bool { ret os::libc::feof(self) != 0i32; } - fn seek(offset: int, whence: seek_style) { - assert os::libc::fseek(self, offset, convert_whence(whence)) == 0i32; - } - fn tell() -> uint { ret os::libc::ftell(self) as uint; } -} - -// A forwarding impl of reader that also holds on to a resource for the -// duration of its lifetime. -// FIXME there really should be a better way to do this -impl <T: reader, C> of reader for {base: T, cleanup: C} { - fn read_bytes(len: uint) -> [u8] { self.base.read_bytes(len) } - fn read_byte() -> int { self.base.read_byte() } - fn unread_byte(byte: int) { self.base.unread_byte(byte); } - fn eof() -> bool { self.base.eof() } - fn seek(off: int, whence: seek_style) { self.base.seek(off, whence) } - fn tell() -> uint { self.base.tell() } -} - -resource FILE_res(f: os::FILE) { os::libc::fclose(f); } - -fn FILE_reader(f: os::FILE, cleanup: bool) -> reader { - if cleanup { - {base: f, cleanup: FILE_res(f)} as reader - } else { - f as reader - } -} - -// FIXME: this should either be an iface-less impl, a set of top-level -// functions that take a reader, or a set of default methods on reader -// (which can then be called reader) - -fn stdin() -> reader { rustrt::rust_get_stdin() as reader } - -fn file_reader(path: str) -> result::t<reader, str> { - let f = str::as_buf(path, {|pathbuf| - str::as_buf("r", {|modebuf| - os::libc::fopen(pathbuf, modebuf) - }) - }); - ret if f as uint == 0u { result::err("error opening " + path) } - else { - result::ok(FILE_reader(f, true)) - } -} - - -// Byte buffer readers - -// TODO: const u8, but this fails with rustboot. -type byte_buf = {buf: [u8], mutable pos: uint, len: uint}; - -impl of reader for byte_buf { - fn read_bytes(len: uint) -> [u8] { - let rest = self.len - self.pos; - let to_read = len; - if rest < to_read { to_read = rest; } - let range = vec::slice(self.buf, self.pos, self.pos + to_read); - self.pos += to_read; - ret range; - } - fn read_byte() -> int { - if self.pos == self.len { ret -1; } - let b = self.buf[self.pos]; - self.pos += 1u; - ret b as int; - } - fn unread_byte(_byte: int) { #error("TODO: unread_byte"); fail; } - fn eof() -> bool { self.pos == self.len } - fn seek(offset: int, whence: seek_style) { - let pos = self.pos; - self.pos = seek_in_buf(offset, pos, self.len, whence); - } - fn tell() -> uint { self.pos } -} - -fn bytes_reader(bytes: [u8]) -> reader { - bytes_reader_between(bytes, 0u, vec::len(bytes)) -} - -fn bytes_reader_between(bytes: [u8], start: uint, end: uint) -> reader { - {buf: bytes, mutable pos: start, len: end} as reader -} - -fn with_bytes_reader<t>(bytes: [u8], f: fn(reader) -> t) -> t { - f(bytes_reader(bytes)) -} - -fn with_bytes_reader_between<t>(bytes: [u8], start: uint, end: uint, - f: fn(reader) -> t) -> t { - f(bytes_reader_between(bytes, start, end)) -} - -fn str_reader(s: str) -> reader { - bytes_reader(str::bytes(s)) -} - -fn with_str_reader<T>(s: str, f: fn(reader) -> T) -> T { - str::as_bytes(s) { |bytes| - with_bytes_reader_between(bytes, 0u, str::len(s), f) - } -} - -// Writing -enum fileflag { append, create, truncate, no_flag, } - -// FIXME: Seekable really should be orthogonal. -// FIXME: eventually u64 -iface writer { - fn write([const u8]); - fn seek(int, seek_style); - fn tell() -> uint; - fn flush() -> int; -} - -impl <T: writer, C> of writer for {base: T, cleanup: C} { - fn write(bs: [const u8]) { self.base.write(bs); } - fn seek(off: int, style: seek_style) { self.base.seek(off, style); } - fn tell() -> uint { self.base.tell() } - fn flush() -> int { self.base.flush() } -} - -impl of writer for os::FILE { - fn write(v: [const u8]) unsafe { - let len = vec::len(v); - let vbuf = vec::unsafe::to_ptr(v); - let nout = os::libc::fwrite(vbuf, len, 1u, self); - if nout < 1u { #error("error dumping buffer"); } - } - fn seek(offset: int, whence: seek_style) { - assert os::libc::fseek(self, offset, convert_whence(whence)) == 0i32; - } - fn tell() -> uint { os::libc::ftell(self) as uint } - fn flush() -> int { os::libc::fflush(self) as int } -} - -fn FILE_writer(f: os::FILE, cleanup: bool) -> writer { - if cleanup { - {base: f, cleanup: FILE_res(f)} as writer - } else { - f as writer - } -} - -impl of writer for fd_t { - fn write(v: [const u8]) unsafe { - let len = vec::len(v); - let count = 0u; - let vbuf; - while count < len { - vbuf = ptr::offset(vec::unsafe::to_ptr(v), count); - let nout = os::libc::write(self, vbuf, len); - if nout < 0 { - #error("error dumping buffer"); - log(error, sys::last_os_error()); - fail; - } - count += nout as uint; - } - } - fn seek(_offset: int, _whence: seek_style) { - #error("need 64-bit native calls for seek, sorry"); - fail; - } - fn tell() -> uint { - #error("need 64-bit native calls for tell, sorry"); - fail; - } - fn flush() -> int { 0 } -} - -resource fd_res(fd: fd_t) { os::libc::close(fd); } - -fn fd_writer(fd: fd_t, cleanup: bool) -> writer { - if cleanup { - {base: fd, cleanup: fd_res(fd)} as writer - } else { - fd as writer - } -} - -fn mk_file_writer(path: str, flags: [fileflag]) - -> result::t<writer, str> { - let fflags: i32 = - os::libc_constants::O_WRONLY | os::libc_constants::O_BINARY; - for f: fileflag in flags { - alt f { - append { fflags |= os::libc_constants::O_APPEND; } - create { fflags |= os::libc_constants::O_CREAT; } - truncate { fflags |= os::libc_constants::O_TRUNC; } - no_flag { } - } - } - let fd = str::as_buf(path, {|pathbuf| - os::libc::open(pathbuf, fflags, os::libc_constants::S_IRUSR | - os::libc_constants::S_IWUSR) - }); - if fd < 0i32 { - // FIXME don't log this! put it in the returned error string - log(error, sys::last_os_error()); - result::err("error opening " + path) - } else { - result::ok(fd_writer(fd, true)) - } -} - -fn u64_to_le_bytes(n: u64, size: uint) -> [u8] { - let bytes: [u8] = [], i = size, n = n; - while i > 0u { - bytes += [(n & 255_u64) as u8]; - n >>= 8_u64; - i -= 1u; - } - ret bytes; -} - -fn u64_to_be_bytes(n: u64, size: uint) -> [u8] { - assert size <= 8u; - let bytes: [u8] = []; - let i = size; - while i > 0u { - let shift = ((i - 1u) * 8u) as u64; - bytes += [(n >> shift) as u8]; - i -= 1u; - } - ret bytes; -} - -fn u64_from_be_bytes(data: [u8], start: uint, size: uint) -> u64 { - let sz = size; - assert (sz <= 8u); - let val = 0_u64; - let pos = start; - while sz > 0u { - sz -= 1u; - val += (data[pos] as u64) << ((sz * 8u) as u64); - pos += 1u; - } - ret val; -} - -impl writer_util for writer { - fn write_char(ch: char) { - if ch as uint < 128u { - self.write([ch as u8]); - } else { - self.write(str::bytes(str::from_char(ch))); - } - } - fn write_str(s: str) { self.write(str::bytes(s)); } - fn write_line(s: str) { self.write(str::bytes(s + "\n")); } - fn write_int(n: int) { self.write(str::bytes(int::to_str(n, 10u))); } - fn write_uint(n: uint) { self.write(str::bytes(uint::to_str(n, 10u))); } - - fn write_le_uint(n: uint, size: uint) { - self.write(u64_to_le_bytes(n as u64, size)); - } - fn write_le_int(n: int, size: uint) { - self.write(u64_to_le_bytes(n as u64, size)); - } - - fn write_be_uint(n: uint, size: uint) { - self.write(u64_to_be_bytes(n as u64, size)); - } - fn write_be_int(n: int, size: uint) { - self.write(u64_to_be_bytes(n as u64, size)); - } - - fn write_be_u64(n: u64) { self.write(u64_to_be_bytes(n, 8u)); } - fn write_be_u32(n: u32) { self.write(u64_to_be_bytes(n as u64, 4u)); } - fn write_be_u16(n: u16) { self.write(u64_to_be_bytes(n as u64, 2u)); } - - fn write_be_i64(n: i64) { self.write(u64_to_be_bytes(n as u64, 8u)); } - fn write_be_i32(n: i32) { self.write(u64_to_be_bytes(n as u64, 4u)); } - fn write_be_i16(n: i16) { self.write(u64_to_be_bytes(n as u64, 2u)); } - - fn write_le_u64(n: u64) { self.write(u64_to_le_bytes(n, 8u)); } - fn write_le_u32(n: u32) { self.write(u64_to_le_bytes(n as u64, 4u)); } - fn write_le_u16(n: u16) { self.write(u64_to_le_bytes(n as u64, 2u)); } - - fn write_le_i64(n: i64) { self.write(u64_to_le_bytes(n as u64, 8u)); } - fn write_le_i32(n: i32) { self.write(u64_to_le_bytes(n as u64, 4u)); } - fn write_le_i16(n: i16) { self.write(u64_to_le_bytes(n as u64, 2u)); } - - fn write_u8(n: u8) { self.write([n]) } -} - -fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> { - result::chain(mk_file_writer(path, flags), { |w| result::ok(w)}) -} - - -// FIXME: fileflags -fn buffered_file_writer(path: str) -> result::t<writer, str> { - let f = str::as_buf(path, {|pathbuf| - str::as_buf("w", {|modebuf| os::libc::fopen(pathbuf, modebuf) }) - }); - ret if f as uint == 0u { result::err("error opening " + path) } - else { result::ok(FILE_writer(f, true)) } -} - -// FIXME it would be great if this could be a const -fn stdout() -> writer { fd_writer(1i32, false) } -fn stderr() -> writer { fd_writer(2i32, false) } - -fn print(s: str) { stdout().write_str(s); } -fn println(s: str) { stdout().write_line(s); } - -type mem_buffer = @{mutable buf: [mutable u8], - mutable pos: uint}; - -impl of writer for mem_buffer { - fn write(v: [const u8]) { - // Fast path. - if self.pos == vec::len(self.buf) { - for b: u8 in v { self.buf += [mutable b]; } - self.pos += vec::len(v); - ret; - } - // FIXME: Optimize: These should be unique pointers. - let vlen = vec::len(v); - let vpos = 0u; - while vpos < vlen { - let b = v[vpos]; - if self.pos == vec::len(self.buf) { - self.buf += [mutable b]; - } else { self.buf[self.pos] = b; } - self.pos += 1u; - vpos += 1u; - } - } - fn seek(offset: int, whence: seek_style) { - let pos = self.pos; - let len = vec::len(self.buf); - self.pos = seek_in_buf(offset, pos, len, whence); - } - fn tell() -> uint { self.pos } - fn flush() -> int { 0 } -} - -fn mk_mem_buffer() -> mem_buffer { - @{mutable buf: [mutable], mutable pos: 0u} -} -fn mem_buffer_writer(b: mem_buffer) -> writer { b as writer } -fn mem_buffer_buf(b: mem_buffer) -> [u8] { vec::from_mut(b.buf) } -fn mem_buffer_str(b: mem_buffer) -> str { - let b_ = vec::from_mut(b.buf); - str::from_bytes(b_) -} - -fn with_str_writer(f: fn(writer)) -> str { - let buf = mk_mem_buffer(); - let wr = mem_buffer_writer(buf); - f(wr); - io::mem_buffer_str(buf) -} - -fn with_buf_writer(f: fn(writer)) -> [u8] { - let buf = mk_mem_buffer(); - let wr = mem_buffer_writer(buf); - f(wr); - io::mem_buffer_buf(buf) -} - -// Utility functions -fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) -> - uint { - let bpos = pos as int; - let blen = len as int; - alt whence { - seek_set { bpos = offset; } - seek_cur { bpos += offset; } - seek_end { bpos = blen + offset; } - } - if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; } - ret bpos as uint; -} - -fn read_whole_file_str(file: str) -> result::t<str, str> { - result::chain(read_whole_file(file), { |bytes| - result::ok(str::from_bytes(bytes)) - }) -} - -// FIXME implement this in a low-level way. Going through the abstractions is -// pointless. -fn read_whole_file(file: str) -> result::t<[u8], str> { - result::chain(file_reader(file), { |rdr| - result::ok(rdr.read_whole_stream()) - }) -} - -// fsync related - -mod fsync { - - enum level { - // whatever fsync does on that platform - fsync, - - // fdatasync on linux, similiar or more on other platforms - fdatasync, - - // full fsync - // - // You must additionally sync the parent directory as well! - fullfsync, - } - - - // Resource of artifacts that need to fsync on destruction - resource res<t>(arg: arg<t>) { - alt arg.opt_level { - option::none { } - option::some(level) { - // fail hard if not succesful - assert(arg.fsync_fn(arg.val, level) != -1); - } - } - } - - type arg<t> = { - val: t, - opt_level: option<level>, - fsync_fn: fn@(t, level) -> int - }; - - // fsync file after executing blk - // FIXME find better way to create resources within lifetime of outer res - fn FILE_res_sync(&&file: FILE_res, opt_level: option<level>, - blk: fn(&&res<os::FILE>)) { - blk(res({ - val: *file, opt_level: opt_level, - fsync_fn: fn@(&&file: os::FILE, l: level) -> int { - ret os::fsync_fd(os::libc::fileno(file), l) as int; - } - })); - } - - // fsync fd after executing blk - fn fd_res_sync(&&fd: fd_res, opt_level: option<level>, - blk: fn(&&res<fd_t>)) { - blk(res({ - val: *fd, opt_level: opt_level, - fsync_fn: fn@(&&fd: fd_t, l: level) -> int { - ret os::fsync_fd(fd, l) as int; - } - })); - } - - // Type of objects that may want to fsync - iface t { fn fsync(l: level) -> int; } - - // Call o.fsync after executing blk - fn obj_sync(&&o: t, opt_level: option<level>, blk: fn(&&res<t>)) { - blk(res({ - val: o, opt_level: opt_level, - fsync_fn: fn@(&&o: t, l: level) -> int { ret o.fsync(l); } - })); - } -} - -#[cfg(test)] -mod tests { - - #[test] - fn test_simple() { - let tmpfile: str = "tmp/lib-io-test-simple.tmp"; - log(debug, tmpfile); - let frood: str = "A hoopy frood who really knows where his towel is."; - log(debug, frood); - { - let out: io::writer = - result::get( - io::file_writer(tmpfile, [io::create, io::truncate])); - out.write_str(frood); - } - let inp: io::reader = result::get(io::file_reader(tmpfile)); - let frood2: str = inp.read_c_str(); - log(debug, frood2); - assert (str::eq(frood, frood2)); - } - - #[test] - fn test_readchars_empty() { - let inp : io::reader = io::str_reader(""); - let res : [char] = inp.read_chars(128u); - assert(vec::len(res) == 0u); - } - - #[test] - fn test_readchars_wide() { - let wide_test = "生锈的汤匙切肉汤hello生锈的汤匙切肉汤"; - let ivals : [int] = [ - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748, - 104, 101, 108, 108, 111, - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748]; - fn check_read_ln(len : uint, s: str, ivals: [int]) { - let inp : io::reader = io::str_reader(s); - let res : [char] = inp.read_chars(len); - if (len <= vec::len(ivals)) { - assert(vec::len(res) == len); - } - assert(vec::slice(ivals, 0u, vec::len(res)) == - vec::map(res, {|x| x as int})); - } - let i = 0u; - while i < 8u { - check_read_ln(i, wide_test, ivals); - i += 1u; - } - // check a long read for good measure - check_read_ln(128u, wide_test, ivals); - } - - #[test] - fn test_readchar() { - let inp : io::reader = io::str_reader("生"); - let res : char = inp.read_char(); - assert(res as int == 29983); - } - - #[test] - fn test_readchar_empty() { - let inp : io::reader = io::str_reader(""); - let res : char = inp.read_char(); - assert(res as int == -1); - } - - #[test] - fn file_reader_not_exist() { - alt io::file_reader("not a file") { - result::err(e) { - assert e == "error opening not a file"; - } - result::ok(_) { fail; } - } - } - - #[test] - fn file_writer_bad_name() { - alt io::file_writer("?/?", []) { - result::err(e) { - assert e == "error opening ?/?"; - } - result::ok(_) { fail; } - } - } - - #[test] - fn buffered_file_writer_bad_name() { - alt io::buffered_file_writer("?/?") { - result::err(e) { - assert e == "error opening ?/?"; - } - result::ok(_) { fail; } - } - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libstd/linux_os.rs b/src/libstd/linux_os.rs deleted file mode 100644 index bfbbaf52ff2..00000000000 --- a/src/libstd/linux_os.rs +++ /dev/null @@ -1,152 +0,0 @@ -/* -Module: os - -TODO: Restructure and document -*/ - -import core::option; -import core::ctypes::*; - -export libc; -export libc_constants; -export pipe; -export FILE, fd_FILE; -export close; -export fclose; -export waitpid; -export getcwd; -export exec_suffix; -export target_os; -export dylib_filename; -export get_exe_path; -export fsync_fd; -export rustrt; - -// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult -// by https://github.com/graydon/rust/issues#issue/268 - -enum FILE_opaque {} -type FILE = *FILE_opaque; -enum dir {} -enum dirent {} - -#[nolink] -#[abi = "cdecl"] -native mod libc { - fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t; - fn close(fd: fd_t) -> c_int; - fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE; - fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE; - fn fclose(f: FILE); - fn fflush(f: FILE) -> c_int; - fn fsync(fd: fd_t) -> c_int; - fn fdatasync(fd: fd_t) -> c_int; - fn fileno(f: FILE) -> fd_t; - fn fgetc(f: FILE) -> c_int; - fn ungetc(c: c_int, f: FILE); - fn feof(f: FILE) -> c_int; - fn fseek(f: FILE, offset: long, whence: c_int) -> c_int; - fn ftell(f: FILE) -> long; - fn opendir(d: str::sbuf) -> *dir; - fn closedir(d: *dir) -> c_int; - fn readdir(d: *dir) -> *dirent; - fn getenv(n: str::sbuf) -> str::sbuf; - fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int; - fn unsetenv(n: str::sbuf) -> c_int; - fn pipe(buf: *mutable fd_t) -> c_int; - fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> pid_t; - fn readlink(path: str::sbuf, buf: str::sbuf, bufsize: size_t) -> ssize_t; - fn mkdir(path: str::sbuf, mode: c_int) -> c_int; - fn rmdir(path: str::sbuf) -> c_int; - fn chdir(path: str::sbuf) -> c_int; - fn unlink(path: str::sbuf) -> c_int; -} - -mod libc_constants { - const O_RDONLY: c_int = 0i32; - const O_WRONLY: c_int = 1i32; - const O_RDWR: c_int = 2i32; - const O_APPEND: c_int = 1024i32; - const O_CREAT: c_int = 64i32; - const O_EXCL: c_int = 128i32; - const O_TRUNC: c_int = 512i32; - const O_TEXT: c_int = 0i32; // nonexistent in linux libc - const O_BINARY: c_int = 0i32; // nonexistent in linux libc - - const S_IRUSR: unsigned = 256u32; - const S_IWUSR: unsigned = 128u32; -} - -fn pipe() -> {in: fd_t, out: fd_t} { - let fds = {mutable in: 0i32, mutable out: 0i32}; - assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32); - ret {in: fds.in, out: fds.out}; -} - -fn fd_FILE(fd: fd_t) -> FILE { - ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) }); -} - -fn close(fd: fd_t) -> c_int { - libc::close(fd) -} - -fn fclose(file: FILE) { - libc::fclose(file) -} - -fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int { - alt level { - io::fsync::fsync | io::fsync::fullfsync { ret libc::fsync(fd); } - io::fsync::fdatasync { ret libc::fdatasync(fd); } - } -} - -fn waitpid(pid: pid_t) -> i32 { - let status = 0i32; - assert (os::libc::waitpid(pid, status, 0i32) != -1i32); - ret status; -} - -#[abi = "cdecl"] -native mod rustrt { - fn rust_env_pairs() -> [str]; - fn rust_getcwd() -> str; -} - -fn getcwd() -> str { ret rustrt::rust_getcwd(); } - -fn exec_suffix() -> str { ret ""; } - -fn target_os() -> str { ret "linux"; } - -fn dylib_filename(base: str) -> str { ret "lib" + base + ".so"; } - -/// Returns the directory containing the running program -/// followed by a path separator -fn get_exe_path() -> option<fs::path> { - let bufsize = 1023u; - // FIXME: path "strings" will likely need fixing... - let path = str::from_bytes(vec::init_elt(bufsize, 0u8)); - 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; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/macos_os.rs b/src/libstd/macos_os.rs deleted file mode 100644 index bb9efdcbc09..00000000000 --- a/src/libstd/macos_os.rs +++ /dev/null @@ -1,160 +0,0 @@ -import core::option; -import core::ctypes::*; - -export libc; -export libc_constants; -export pipe; -export FILE, fd_FILE; -export close; -export fclose; -export waitpid; -export getcwd; -export exec_suffix; -export target_os; -export dylib_filename; -export get_exe_path; -export fsync_fd; -export rustrt; - -// FIXME Refactor into unix_os module or some such. Doesn't -// seem to work right now. - -enum FILE_opaque {} -type FILE = *FILE_opaque; -enum dir {} -enum dirent {} - -#[nolink] -#[abi = "cdecl"] -native mod libc { - fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t; - fn close(fd: fd_t) -> c_int; - fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE; - fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE; - fn fflush(f: FILE) -> c_int; - fn fsync(fd: fd_t) -> c_int; - fn fileno(f: FILE) -> fd_t; - fn fclose(f: FILE); - fn fgetc(f: FILE) -> c_int; - fn ungetc(c: c_int, f: FILE); - fn feof(f: FILE) -> c_int; - fn fseek(f: FILE, offset: long, whence: c_int) -> c_int; - fn ftell(f: FILE) -> long; - fn opendir(d: str::sbuf) -> *dir; - fn closedir(d: *dir) -> c_int; - fn readdir(d: *dir) -> *dirent; - fn getenv(n: str::sbuf) -> str::sbuf; - fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int; - fn unsetenv(n: str::sbuf) -> c_int; - fn pipe(buf: *mutable c_int) -> c_int; - fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> c_int; - fn mkdir(s: str::sbuf, mode: c_int) -> c_int; - fn rmdir(s: str::sbuf) -> c_int; - fn chdir(s: str::sbuf) -> c_int; - fn unlink(path: str::sbuf) -> c_int; - - // FIXME: Needs varags - fn fcntl(fd: fd_t, cmd: c_int) -> c_int; -} - -mod libc_constants { - const O_RDONLY: c_int = 0i32; - const O_WRONLY: c_int = 1i32; - const O_RDWR: c_int = 2i32; - const O_APPEND: c_int = 8i32; - const O_CREAT: c_int = 512i32; - const O_EXCL: c_int = 2048i32; - const O_TRUNC: c_int = 1024i32; - const O_TEXT: c_int = 0i32; // nonexistent in darwin libc - const O_BINARY: c_int = 0i32; // nonexistent in darwin libc - - const S_IRUSR: unsigned = 256u32; - const S_IWUSR: unsigned = 128u32; - - const F_FULLFSYNC: c_int = 51i32; -} - -fn pipe() -> {in: fd_t, out: fd_t} { - let fds = {mutable in: 0i32, mutable out: 0i32}; - assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32); - ret {in: fds.in, out: fds.out}; -} - -fn fd_FILE(fd: fd_t) -> FILE { - ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) }); -} - -fn close(fd: fd_t) -> c_int { - libc::close(fd) -} - -fn fclose(file: FILE) { - libc::fclose(file) -} - -fn waitpid(pid: pid_t) -> i32 { - let status = 0i32; - assert (os::libc::waitpid(pid, status, 0i32) != -1i32); - ret status; -} - -fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int { - alt level { - io::fsync::fsync { ret libc::fsync(fd); } - _ { - // According to man fnctl, the ok retval is only specified to be !=-1 - if (libc::fcntl(libc_constants::F_FULLFSYNC, fd) == -1 as c_int) - { ret -1 as c_int; } - else - { ret 0 as c_int; } - } - } -} - -#[abi = "cdecl"] -native mod rustrt { - fn rust_env_pairs() -> [str]; - fn rust_getcwd() -> str; -} - -fn getcwd() -> str { ret rustrt::rust_getcwd(); } - -#[nolink] -#[abi = "cdecl"] -native mod mac_libc { - fn _NSGetExecutablePath(buf: str::sbuf, - bufsize: *mutable uint32_t) -> c_int; -} - -fn exec_suffix() -> str { ret ""; } - -fn target_os() -> str { ret "macos"; } - -fn dylib_filename(base: str) -> str { ret "lib" + base + ".dylib"; } - -fn get_exe_path() -> option<fs::path> { - // FIXME: This doesn't handle the case where the buffer is too small - // FIXME: path "strings" will likely need fixing... - let bufsize = 1023u32; - let path = str::from_bytes(vec::init_elt(bufsize as uint, 0u8)); - ret str::as_buf(path, { |path_buf| - if mac_libc::_NSGetExecutablePath(path_buf, - ptr::mut_addr_of(bufsize)) == 0i32 { - option::some(fs::dirname(path) + fs::path_sep()) - } else { - option::none - } - }); -} - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/posix_fs.rs b/src/libstd/posix_fs.rs deleted file mode 100644 index e774650f980..00000000000 --- a/src/libstd/posix_fs.rs +++ /dev/null @@ -1,46 +0,0 @@ -#[abi = "cdecl"] -native mod rustrt { - fn rust_list_files(path: str) -> [str]; -} - -fn list_dir(path: str) -> [str] { - ret rustrt::rust_list_files(path); - - // FIXME: No idea why, but this appears to corrupt memory on OSX. I - // suspect it has to do with the tasking primitives somehow, or perhaps - // the FFI. Worth investigating more when we're digging into the FFI and - // unsafe mode in more detail; in the meantime we just call list_files - // above and skip this code. - - /* - auto dir = os::libc::opendir(str::buf(path)); - assert (dir as uint != 0u); - let vec<str> result = []; - while (true) { - auto ent = os::libc::readdir(dir); - if (ent as int == 0) { - os::libc::closedir(dir); - ret result; - } - vec::push::<str>(result, rustrt::rust_dirent_filename(ent)); - } - os::libc::closedir(dir); - ret result; - */ - -} - -// FIXME make pure when str::char_at is -fn path_is_absolute(p: str) -> bool { ret str::char_at(p, 0u) == '/'; } - -const path_sep: char = '/'; - -const alt_path_sep: char = '/'; - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs deleted file mode 100644 index f9052e6c848..00000000000 --- a/src/libstd/rand.rs +++ /dev/null @@ -1,113 +0,0 @@ -#[doc = "Random number generation"] - -enum rctx {} - -#[abi = "cdecl"] -native mod rustrt { - fn rand_new() -> *rctx; - fn rand_next(c: *rctx) -> u32; - fn rand_free(c: *rctx); -} - -#[doc = "A random number generator"] -iface rng { - #[doc = "Return the next random integer"] - fn next() -> u32; - - #[doc = "Return the next random float"] - fn next_float() -> float; - - #[doc = "Return a random string composed of A-Z, a-z, 0-9."] - fn gen_str(len: uint) -> str; - - #[doc = "Return a random byte string."] - fn gen_bytes(len: uint) -> [u8]; -} - -resource rand_res(c: *rctx) { rustrt::rand_free(c); } - -#[doc = "Create a random number generator"] -fn mk_rng() -> rng { - impl of rng for @rand_res { - fn next() -> u32 { ret rustrt::rand_next(**self); } - fn next_float() -> float { - let u1 = rustrt::rand_next(**self) as float; - let u2 = rustrt::rand_next(**self) as float; - let u3 = rustrt::rand_next(**self) as float; - let scale = u32::max_value as float; - ret ((u1 / scale + u2) / scale + u3) / scale; - } - fn gen_str(len: uint) -> str { - let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "abcdefghijklmnopqrstuvwxyz" + - "0123456789"; - let s = ""; - let i = 0u; - while (i < len) { - let n = rustrt::rand_next(**self) as uint % - str::len(charset); - s = s + str::from_char(str::char_at(charset, n)); - i += 1u; - } - s - } - fn gen_bytes(len: uint) -> [u8] { - let v = []; - let i = 0u; - while i < len { - let n = rustrt::rand_next(**self) as uint; - v += [(n % (u8::max_value as uint)) as u8]; - i += 1u; - } - v - } - } - @rand_res(rustrt::rand_new()) as rng -} - -#[cfg(test)] -mod tests { - - #[test] - fn test() { - let r1: rand::rng = rand::mk_rng(); - log(debug, r1.next()); - log(debug, r1.next()); - { - let r2 = rand::mk_rng(); - log(debug, r1.next()); - log(debug, r2.next()); - log(debug, r1.next()); - log(debug, r1.next()); - log(debug, r2.next()); - log(debug, r2.next()); - log(debug, r1.next()); - log(debug, r1.next()); - log(debug, r1.next()); - log(debug, r2.next()); - log(debug, r2.next()); - log(debug, r2.next()); - } - log(debug, r1.next()); - log(debug, r1.next()); - } - - #[test] - fn genstr() { - let r: rand::rng = rand::mk_rng(); - log(debug, r.gen_str(10u)); - log(debug, r.gen_str(10u)); - log(debug, r.gen_str(10u)); - assert(str::len(r.gen_str(10u)) == 10u); - assert(str::len(r.gen_str(16u)) == 16u); - } -} - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/run_program.rs b/src/libstd/run_program.rs deleted file mode 100644 index 1334e7db723..00000000000 --- a/src/libstd/run_program.rs +++ /dev/null @@ -1,395 +0,0 @@ -#[doc ="Process spawning"]; -import option::{some, none}; -import str::sbuf; -import ctypes::{fd_t, pid_t, void}; - -export program; -export run_program; -export start_program; -export program_output; -export spawn_process; -export waitpid; - -#[abi = "cdecl"] -native mod rustrt { - fn rust_run_program(argv: *sbuf, envp: *void, dir: sbuf, - in_fd: fd_t, out_fd: fd_t, err_fd: fd_t) - -> pid_t; -} - -#[doc ="A value representing a child process"] -iface program { - #[doc ="Returns the process id of the program"] - fn get_id() -> pid_t; - - #[doc ="Returns an io::writer that can be used to write to stdin"] - fn input() -> io::writer; - - #[doc ="Returns an io::reader that can be used to read from stdout"] - fn output() -> io::reader; - - #[doc ="Returns an io::reader that can be used to read from stderr"] - fn err() -> io::reader; - - #[doc = "Closes the handle to the child processes standard input"] - fn close_input(); - - #[doc = " - Waits for the child process to terminate. Closes the handle - to stdin if necessary. - "] - fn finish() -> int; - - #[doc ="Closes open handles"] - fn destroy(); -} - - -#[doc = " -Run a program, providing stdin, stdout and stderr handles - -# Arguments - -* prog - The path to an executable -* args - Vector of arguments to pass to the child process -* env - optional env-modification for child -* dir - optional dir to run child in (default current dir) -* in_fd - A file descriptor for the child to use as std input -* out_fd - A file descriptor for the child to use as std output -* err_fd - A file descriptor for the child to use as std error - -# Return value - -The process id of the spawned process -"] -fn spawn_process(prog: str, args: [str], - env: option<[(str,str)]>, - dir: option<str>, - in_fd: fd_t, out_fd: fd_t, err_fd: fd_t) - -> pid_t unsafe { - with_argv(prog, args) {|argv| - with_envp(env) { |envp| - with_dirp(dir) { |dirp| - rustrt::rust_run_program(argv, envp, dirp, - in_fd, out_fd, err_fd) - } - } - } -} - -fn with_argv<T>(prog: str, args: [str], - cb: fn(*sbuf) -> T) -> T unsafe { - let argptrs = str::as_buf(prog) {|b| [b] }; - let tmps = []; - for arg in args { - let t = @arg; - tmps += [t]; - argptrs += str::as_buf(*t) {|b| [b] }; - } - argptrs += [ptr::null()]; - vec::as_buf(argptrs, cb) -} - -#[cfg(target_os = "macos")] -#[cfg(target_os = "linux")] -#[cfg(target_os = "freebsd")] -fn with_envp<T>(env: option<[(str,str)]>, - cb: fn(*void) -> T) -> T unsafe { - // On posixy systems we can pass a char** for envp, which is - // a null-terminated array of "k=v\n" strings. - alt env { - some (es) { - let tmps = []; - let ptrs = []; - - for (k,v) in es { - let t = @(#fmt("%s=%s", k, v)); - vec::push(tmps, t); - ptrs += str::as_buf(*t) {|b| [b]}; - } - ptrs += [ptr::null()]; - vec::as_buf(ptrs) { |p| cb(::unsafe::reinterpret_cast(p)) } - } - none { - cb(ptr::null()) - } - } -} - -#[cfg(target_os = "win32")] -fn with_envp<T>(env: option<[(str,str)]>, - cb: fn(*void) -> T) -> T unsafe { - // On win32 we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - alt env { - some (es) { - let blk : [u8] = []; - for (k,v) in es { - let t = #fmt("%s=%s", k, v); - let v : [u8] = ::unsafe::reinterpret_cast(t); - blk += v; - ::unsafe::leak(v); - } - blk += [0_u8]; - vec::as_buf(blk) {|p| cb(::unsafe::reinterpret_cast(p)) } - } - none { - cb(ptr::null()) - } - } -} - -fn with_dirp<T>(d: option<str>, - cb: fn(sbuf) -> T) -> T unsafe { - alt d { - some(dir) { str::as_buf(dir, cb) } - none { cb(ptr::null()) } - } -} - -#[doc =" -Spawns a process and waits for it to terminate - -# Arguments - -* prog - The path to an executable -* args - Vector of arguments to pass to the child process - -# Return value - -The process id -"] -fn run_program(prog: str, args: [str]) -> int { - ret waitpid(spawn_process(prog, args, none, none, - 0i32, 0i32, 0i32)); -} - -#[doc =" -Spawns a process and returns a program - -The returned value is a boxed resource containing a <program> object that can -be used for sending and recieving data over the standard file descriptors. -The resource will ensure that file descriptors are closed properly. - -# Arguments - -* prog - The path to an executable -* args - Vector of arguments to pass to the child process - -# Return value - -A boxed resource of <program> -"] -fn start_program(prog: str, args: [str]) -> program { - let pipe_input = os::pipe(); - let pipe_output = os::pipe(); - let pipe_err = os::pipe(); - let pid = - spawn_process(prog, args, none, none, - pipe_input.in, pipe_output.out, - pipe_err.out); - - if pid == -1i32 { fail; } - os::libc::close(pipe_input.in); - os::libc::close(pipe_output.out); - os::libc::close(pipe_err.out); - - type prog_repr = {pid: pid_t, - mutable in_fd: fd_t, - out_file: os::FILE, - err_file: os::FILE, - mutable finished: bool}; - - fn close_repr_input(r: prog_repr) { - let invalid_fd = -1i32; - if r.in_fd != invalid_fd { - os::libc::close(r.in_fd); - r.in_fd = invalid_fd; - } - } - fn finish_repr(r: prog_repr) -> int { - if r.finished { ret 0; } - r.finished = true; - close_repr_input(r); - ret waitpid(r.pid); - } - fn destroy_repr(r: prog_repr) { - finish_repr(r); - os::libc::fclose(r.out_file); - os::libc::fclose(r.err_file); - } - resource prog_res(r: prog_repr) { destroy_repr(r); } - - impl of program for prog_res { - fn get_id() -> pid_t { ret self.pid; } - fn input() -> io::writer { io::fd_writer(self.in_fd, false) } - fn output() -> io::reader { io::FILE_reader(self.out_file, false) } - fn err() -> io::reader { io::FILE_reader(self.err_file, false) } - fn close_input() { close_repr_input(*self); } - fn finish() -> int { finish_repr(*self) } - fn destroy() { destroy_repr(*self); } - } - let repr = {pid: pid, - mutable in_fd: pipe_input.out, - out_file: os::fd_FILE(pipe_output.in), - err_file: os::fd_FILE(pipe_err.in), - mutable finished: false}; - ret prog_res(repr) as program; -} - -fn read_all(rd: io::reader) -> str { - let buf = ""; - while !rd.eof() { - let bytes = rd.read_bytes(4096u); - buf += str::from_bytes(bytes); - } - ret buf; -} - -#[doc =" -Spawns a process, waits for it to exit, and returns the exit code, and -contents of stdout and stderr. - -# Arguments - -* prog - The path to an executable -* args - Vector of arguments to pass to the child process - -# Return value - -A record, {status: int, out: str, err: str} containing the exit code, -the contents of stdout and the contents of stderr. -"] -fn program_output(prog: str, args: [str]) -> - {status: int, out: str, err: str} { - let pr = start_program(prog, args); - pr.close_input(); - let out = read_all(pr.output()); - let err = read_all(pr.err()); - ret {status: pr.finish(), out: out, err: err}; -} - -#[doc ="Waits for a process to exit and returns the exit code"] -fn waitpid(pid: pid_t) -> int { - ret waitpid_os(pid); - - #[cfg(target_os = "win32")] - fn waitpid_os(pid: pid_t) -> int { - os::waitpid(pid) as int - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn waitpid_os(pid: pid_t) -> int { - #[cfg(target_os = "linux")] - fn WIFEXITED(status: i32) -> bool { - (status & 0xffi32) == 0i32 - } - - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn WIFEXITED(status: i32) -> bool { - (status & 0x7fi32) == 0i32 - } - - #[cfg(target_os = "linux")] - fn WEXITSTATUS(status: i32) -> i32 { - (status >> 8i32) & 0xffi32 - } - - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn WEXITSTATUS(status: i32) -> i32 { - status >> 8i32 - } - - let status = os::waitpid(pid); - ret if WIFEXITED(status) { - WEXITSTATUS(status) as int - } else { - 1 - }; - } -} - -#[cfg(test)] -mod tests { - - import io::writer_util; - import ctypes::fd_t; - - // Regression test for memory leaks - #[ignore(cfg(target_os = "win32"))] // FIXME - fn test_leaks() { - run::run_program("echo", []); - run::start_program("echo", []); - run::program_output("echo", []); - } - - #[test] - fn test_pipes() { - let pipe_in = os::pipe(); - let pipe_out = os::pipe(); - let pipe_err = os::pipe(); - - let pid = - run::spawn_process( - "cat", [], none, none, - pipe_in.in, pipe_out.out, pipe_err.out); - os::close(pipe_in.in); - os::close(pipe_out.out); - os::close(pipe_err.out); - - if pid == -1i32 { fail; } - let expected = "test"; - writeclose(pipe_in.out, expected); - let actual = readclose(pipe_out.in); - readclose(pipe_err.in); - os::waitpid(pid); - - log(debug, expected); - log(debug, actual); - assert (expected == actual); - - fn writeclose(fd: fd_t, s: str) { - #error("writeclose %d, %s", fd as int, s); - let writer = io::fd_writer(fd, false); - writer.write_str(s); - - os::close(fd); - } - - fn readclose(fd: fd_t) -> str { - // Copied from run::program_output - let file = os::fd_FILE(fd); - let reader = io::FILE_reader(file, false); - let buf = ""; - while !reader.eof() { - let bytes = reader.read_bytes(4096u); - buf += str::from_bytes(bytes); - } - os::fclose(file); - ret buf; - } - } - - #[test] - fn waitpid() { - let pid = run::spawn_process("false", [], - none, none, - 0i32, 0i32, 0i32); - let status = run::waitpid(pid); - assert status == 1; - } - -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 604e5cb63a7..a06cca77f75 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -6,26 +6,19 @@ #[comment = "The Rust standard library"]; #[license = "MIT"]; #[crate_type = "lib"]; - #[doc = "The Rust standard library"]; -export fs, io, net, run, uv; +export net, uv; export c_vec, four, tri, util; export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind; export rope; export ebml, dbg, getopts, json, rand, sha1, term, time; export test, tempfile, serialization; -// FIXME: generic_os and os_fs shouldn't be exported -export generic_os, os, os_fs; // General io and system-services modules -mod fs; -mod io; mod net; -#[path = "run_program.rs"] -mod run; mod uv; @@ -57,7 +50,6 @@ mod ebml; mod dbg; mod getopts; mod json; -mod rand; mod sha1; mod md4; mod tempfile; @@ -73,39 +65,6 @@ mod unicode; mod test; mod serialization; -// Target-os module. - -// TODO: Have each os module re-export everything from genericos. -mod generic_os; - -#[cfg(target_os = "win32")] -#[path = "win32_os.rs"] -mod os; -#[cfg(target_os = "win32")] -#[path = "win32_fs.rs"] -mod os_fs; - -#[cfg(target_os = "macos")] -#[path = "macos_os.rs"] -mod os; -#[cfg(target_os = "macos")] -#[path = "posix_fs.rs"] -mod os_fs; - -#[cfg(target_os = "linux")] -#[path = "linux_os.rs"] -mod os; -#[cfg(target_os = "linux")] -#[path = "posix_fs.rs"] -mod os_fs; - -#[cfg(target_os = "freebsd")] -#[path = "freebsd_os.rs"] -mod os; -#[cfg(target_os = "freebsd")] -#[path = "posix_fs.rs"] -mod os_fs; - // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index c7e3e60ef20..3ed70bb9535 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -1,7 +1,6 @@ #[doc = "Temporary files and directories"]; import core::option; -import fs; import option::{none, some}; import rand; @@ -10,7 +9,7 @@ fn mkdtemp(prefix: str, suffix: str) -> option<str> { let i = 0u; while (i < 1000u) { let s = prefix + r.gen_str(16u) + suffix; - if fs::make_dir(s, 0x1c0i32) { // FIXME: u+rwx + if os::make_dir(s, 0x1c0i32) { // FIXME: u+rwx ret some(s); } i += 1u; @@ -23,7 +22,7 @@ fn test_mkdtemp() { let r = mkdtemp("./", "foobar"); alt r { some(p) { - fs::remove_dir(p); + os::remove_dir(p); assert(str::ends_with(p, "foobar")); } _ { assert(false); } diff --git a/src/libstd/term.rs b/src/libstd/term.rs index e782abb8e6f..302852a8edf 100644 --- a/src/libstd/term.rs +++ b/src/libstd/term.rs @@ -35,7 +35,7 @@ fn reset(writer: io::writer) { fn color_supported() -> bool { let supported_terms = ["xterm-color", "xterm", "screen-bce", "xterm-256color"]; - ret alt generic_os::getenv("TERM") { + ret alt os::getenv("TERM") { option::some(env) { for term: str in supported_terms { if str::eq(term, env) { ret true; } diff --git a/src/libstd/test.rs b/src/libstd/test.rs index a82ec1e668f..540966b2a78 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -7,7 +7,6 @@ import result::{ok, err}; import io::writer_util; -import core::ctypes; export test_name; export test_fn; @@ -22,7 +21,7 @@ export run_tests_console; #[abi = "cdecl"] native mod rustrt { - fn sched_threads() -> ctypes::size_t; + fn sched_threads() -> libc::size_t; } // The name of a test. By convention this follows the rules for rust diff --git a/src/libstd/uv.rs b/src/libstd/uv.rs index 6797ad9873d..d91f4333560 100644 --- a/src/libstd/uv.rs +++ b/src/libstd/uv.rs @@ -7,11 +7,11 @@ export timer_init, timer_start, timer_stop; // process_operation() crust fn below enum uv_operation { op_async_init([u8]), - op_close(uv_handle, *ctypes::void), + op_close(uv_handle, *libc::c_void), op_timer_init([u8]), - op_timer_start([u8], *ctypes::void, u32, u32), - op_timer_stop([u8], *ctypes::void, fn~(uv_handle)), - op_teardown(*ctypes::void) + op_timer_start([u8], *libc::c_void, u32, u32), + op_timer_stop([u8], *libc::c_void, fn~(uv_handle)), + op_teardown(*libc::c_void) } enum uv_handle { @@ -31,10 +31,10 @@ enum uv_msg { msg_timer_stop([u8], fn~(uv_handle)), // dispatches from libuv - uv_async_init([u8], *ctypes::void), + uv_async_init([u8], *libc::c_void), uv_async_send([u8]), uv_close([u8]), - uv_timer_init([u8], *ctypes::void), + uv_timer_init([u8], *libc::c_void), uv_timer_call([u8]), uv_timer_stop([u8], fn~(uv_handle)), uv_end(), @@ -47,37 +47,37 @@ type uv_loop_data = { }; enum uv_loop { - uv_loop_new(comm::chan<uv_msg>, *ctypes::void) + uv_loop_new(comm::chan<uv_msg>, *libc::c_void) } #[nolink] native mod rustrt { - fn rust_uv_loop_new() -> *ctypes::void; - fn rust_uv_loop_delete(lp: *ctypes::void); + fn rust_uv_loop_new() -> *libc::c_void; + fn rust_uv_loop_delete(lp: *libc::c_void); fn rust_uv_loop_set_data( - lp: *ctypes::void, + lp: *libc::c_void, data: *uv_loop_data); - fn rust_uv_bind_op_cb(lp: *ctypes::void, cb: *u8) - -> *ctypes::void; - fn rust_uv_stop_op_cb(handle: *ctypes::void); - fn rust_uv_run(loop_handle: *ctypes::void); - fn rust_uv_close(handle: *ctypes::void, cb: *u8); - fn rust_uv_close_async(handle: *ctypes::void); - fn rust_uv_close_timer(handle: *ctypes::void); - fn rust_uv_async_send(handle: *ctypes::void); + fn rust_uv_bind_op_cb(lp: *libc::c_void, cb: *u8) + -> *libc::c_void; + fn rust_uv_stop_op_cb(handle: *libc::c_void); + fn rust_uv_run(loop_handle: *libc::c_void); + fn rust_uv_close(handle: *libc::c_void, cb: *u8); + fn rust_uv_close_async(handle: *libc::c_void); + fn rust_uv_close_timer(handle: *libc::c_void); + fn rust_uv_async_send(handle: *libc::c_void); fn rust_uv_async_init( - loop_handle: *ctypes::void, + loop_handle: *libc::c_void, cb: *u8, - id: *u8) -> *ctypes::void; + id: *u8) -> *libc::c_void; fn rust_uv_timer_init( - loop_handle: *ctypes::void, + loop_handle: *libc::c_void, cb: *u8, - id: *u8) -> *ctypes::void; + id: *u8) -> *libc::c_void; fn rust_uv_timer_start( - timer_handle: *ctypes::void, - timeout: ctypes::c_uint, - repeat: ctypes::c_uint); - fn rust_uv_timer_stop(handle: *ctypes::void); + timer_handle: *libc::c_void, + timeout: libc::c_uint, + repeat: libc::c_uint); + fn rust_uv_timer_stop(handle: *libc::c_void); } // public functions @@ -130,7 +130,7 @@ fn loop_new() -> uv_loop unsafe { process_operation); // all state goes here - let handles: map::hashmap<[u8], *ctypes::void> = + let handles: map::hashmap<[u8], *libc::c_void> = map::new_bytes_hash(); let id_to_handle: map::hashmap<[u8], uv_handle> = map::new_bytes_hash(); @@ -399,13 +399,13 @@ fn timer_stop(the_timer: uv_handle, after_cb: fn~(uv_handle)) { // internal functions fn pass_to_libuv( - op_handle: *ctypes::void, + op_handle: *libc::c_void, operation_chan: comm::chan<uv_operation>, op: uv_operation) unsafe { comm::send(operation_chan, copy(op)); do_send(op_handle); } -fn do_send(h: *ctypes::void) { +fn do_send(h: *libc::c_void) { rustrt::rust_uv_async_send(h); } fn gen_handle_id() -> [u8] { @@ -434,7 +434,7 @@ fn get_loop_chan_from_handle(handle: uv_handle) } } -fn get_loop_ptr_from_uv_loop(lp: uv_loop) -> *ctypes::void { +fn get_loop_ptr_from_uv_loop(lp: uv_loop) -> *libc::c_void { alt lp { uv_loop_new(loop_chan, loop_ptr) { ret loop_ptr; @@ -462,7 +462,7 @@ fn get_id_from_handle(handle: uv_handle) -> [u8] { // crust crust fn process_operation( - lp: *ctypes::void, + lp: *libc::c_void, data: *uv_loop_data) unsafe { let op_port = (*data).operation_port; let loop_chan = get_loop_chan_from_data(data); @@ -512,7 +512,7 @@ crust fn process_operation( } } -fn handle_op_close(handle: uv_handle, handle_ptr: *ctypes::void) { +fn handle_op_close(handle: uv_handle, handle_ptr: *libc::c_void) { // it's just like im doing C alt handle { uv_async(id, lp) { @@ -557,7 +557,7 @@ fn process_close_common(id: [u8], data: *uv_loop_data) crust fn process_close_async( id_buf: *u8, - handle_ptr: *ctypes::void, + handle_ptr: *libc::c_void, data: *uv_loop_data) unsafe { let id = get_handle_id_from(id_buf); @@ -571,7 +571,7 @@ crust fn process_close_async( crust fn process_close_timer( id_buf: *u8, - handle_ptr: *ctypes::void, + handle_ptr: *libc::c_void, data: *uv_loop_data) unsafe { let id = get_handle_id_from(id_buf); diff --git a/src/libstd/win32_fs.rs b/src/libstd/win32_fs.rs deleted file mode 100644 index bca09fcf835..00000000000 --- a/src/libstd/win32_fs.rs +++ /dev/null @@ -1,35 +0,0 @@ - - -#[abi = "cdecl"] -native mod rustrt { - fn rust_list_files(path: str) -> [str]; -} - -fn list_dir(path: str) -> [str] { - let path = path + "*"; - ret rustrt::rust_list_files(path); -} - -fn path_is_absolute(p: str) -> bool { - ret str::char_at(p, 0u) == '/' || - str::char_at(p, 1u) == ':' - && (str::char_at(p, 2u) == path_sep - || str::char_at(p, 2u) == alt_path_sep); -} - -/* FIXME: win32 path handling actually accepts '/' or '\' and has subtly - * different semantics for each. Since we build on mingw, we are usually - * dealing with /-separated paths. But the whole interface to splitting and - * joining pathnames needs a bit more abstraction on win32. Possibly a vec or - * enum type. - */ -const path_sep: char = '/'; - -const alt_path_sep: char = '\\'; -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/win32_os.rs b/src/libstd/win32_os.rs deleted file mode 100644 index 74de2c14668..00000000000 --- a/src/libstd/win32_os.rs +++ /dev/null @@ -1,140 +0,0 @@ -import core::option; -import core::ctypes::*; - -enum FILE_opaque {} -type FILE = *FILE_opaque; - -#[abi = "cdecl"] -#[nolink] -native mod libc { - fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t; - fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t; - #[link_name = "_open"] - fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> c_int; - #[link_name = "_close"] - fn close(fd: fd_t) -> c_int; - fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE; - fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE; - fn fclose(f: FILE); - fn fflush(f: FILE) -> c_int; - fn fileno(f: FILE) -> fd_t; - fn fgetc(f: FILE) -> c_int; - fn ungetc(c: c_int, f: FILE); - fn feof(f: FILE) -> c_int; - fn fseek(f: FILE, offset: long, whence: c_int) -> c_int; - fn ftell(f: FILE) -> long; - fn _pipe(fds: *mutable fd_t, size: unsigned, mode: c_int) -> c_int; -} - -mod libc_constants { - const O_RDONLY: c_int = 0i32; - const O_WRONLY: c_int = 1i32; - const O_RDWR: c_int = 2i32; - const O_APPEND: c_int = 8i32; - const O_CREAT: c_int = 256i32; - const O_EXCL: c_int = 1024i32; - const O_TRUNC: c_int = 512i32; - const O_TEXT: c_int = 16384i32; - const O_BINARY: c_int = 32768i32; - const O_NOINHERIT: c_int = 128i32; - const S_IRUSR: unsigned = 256u32; // really _S_IREAD in win32 - const S_IWUSR: unsigned = 128u32; // really _S_IWRITE in win32 -} - -type DWORD = u32; -type HMODULE = c_uint; -type LPTSTR = str::sbuf; -type LPCTSTR = str::sbuf; - -type LPSECURITY_ATTRIBUTES = *ctypes::void; - -#[abi = "stdcall"] -native mod kernel32 { - fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: c_uint) -> - c_uint; - fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> c_int; - fn GetModuleFileNameA(hModule: HMODULE, - lpFilename: LPTSTR, - nSize: DWORD) -> DWORD; - fn CreateDirectoryA(lpPathName: LPCTSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> bool; - fn RemoveDirectoryA(lpPathName: LPCTSTR) -> bool; - fn SetCurrentDirectoryA(lpPathName: LPCTSTR) -> bool; - fn DeleteFileA(lpFileName: LPCTSTR) -> bool; -} - -// FIXME turn into constants -fn exec_suffix() -> str { ret ".exe"; } -fn target_os() -> str { ret "win32"; } - -fn dylib_filename(base: str) -> str { ret base + ".dll"; } - -fn pipe() -> {in: fd_t, out: fd_t} { - // Windows pipes work subtly differently than unix pipes, and their - // inheritance has to be handled in a different way that I don't fully - // understand. Here we explicitly make the pipe non-inheritable, - // which means to pass it to a subprocess they need to be duplicated - // first, as in rust_run_program. - let fds = {mutable in: 0i32, mutable out: 0i32}; - let res = - os::libc::_pipe(ptr::mut_addr_of(fds.in), 1024u32, - libc_constants::O_BINARY | - libc_constants::O_NOINHERIT); - assert (res == 0i32); - assert (fds.in != -1i32 && fds.in != 0i32); - assert (fds.out != -1i32 && fds.in != 0i32); - ret {in: fds.in, out: fds.out}; -} - -fn fd_FILE(fd: fd_t) -> FILE { - ret str::as_buf("r", {|modebuf| libc::_fdopen(fd, modebuf) }); -} - -fn close(fd: fd_t) -> c_int { - libc::close(fd) -} - -fn fclose(file: FILE) { - libc::fclose(file) -} - -fn fsync_fd(_fd: fd_t, _level: io::fsync::level) -> c_int { - // FIXME (1253) - fail; -} - -#[abi = "cdecl"] -native mod rustrt { - fn rust_env_pairs() -> [str]; - fn rust_process_wait(handle: c_int) -> c_int; - fn rust_getcwd() -> str; -} - -fn waitpid(pid: pid_t) -> i32 { ret rustrt::rust_process_wait(pid); } - -fn getcwd() -> str { ret rustrt::rust_getcwd(); } - -fn get_exe_path() -> option<fs::path> { - // FIXME: This doesn't handle the case where the buffer is too small - // FIXME: path "strings" will likely need fixing... - let bufsize = 1023u; - let path = str::from_bytes(vec::init_elt(bufsize, 0u8)); - 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; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: |
