diff --git a/Cargo.lock b/Cargo.lock index b69becf5443ba5bfc82ef60de2acc639d5ccb7b2..d965c3153112d3f2ef0d8065ce64d526513aae91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,19 +25,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "cbindgen" version = "0.5.2" dependencies = [ - "clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "standalone-syn 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -47,7 +47,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.31.1" +version = "2.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -62,7 +62,7 @@ dependencies = [ [[package]] name = "compiler_builtins" version = "0.1.0" -source = "git+https://github.com/rust-lang-nursery/compiler-builtins.git#8fe94f3553f92cd6ba21aadc852bd6a3e01194db" +source = "git+https://github.com/rust-lang-nursery/compiler-builtins.git#263a703b10351d8930e48045b4fd09768991b867" [[package]] name = "crt0" @@ -145,21 +145,13 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.2", "platform 0.1.0", + "socket 0.1.0", ] [[package]] name = "itoa" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "libc" @@ -199,7 +191,7 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -293,11 +285,10 @@ dependencies = [ [[package]] name = "remove_dir_all" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -324,7 +315,7 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -351,13 +342,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -467,11 +458,11 @@ dependencies = [ [[package]] name = "tempdir" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -505,7 +496,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -534,6 +525,8 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.2", "platform 0.1.0", + "stdio 0.1.0", + "string 0.1.0", ] [[package]] @@ -547,7 +540,7 @@ dependencies = [ name = "va_list-helper" version = "0.0.2" dependencies = [ - "cc 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -572,11 +565,6 @@ dependencies = [ "platform 0.1.0", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" version = "0.3.4" @@ -586,11 +574,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -605,36 +588,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum cc 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "87f38f122db5615319a985757e526c00161d924d19b71a0f3e80c52bab1adcf6" +"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc18f6f4005132120d9711636b32c46a233fad94df6217fa1d81c5e97a9f200" +"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins.git)" = "<none>" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum itoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92a9df60778f789c37f76778ae8d0a2471c41baa8b059d98a5873c978f549587" "checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3" +"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" +"checksum remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24" "checksum sc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ebbb026ba4a707c25caec2db5ef59ad8b41f7ad77cad06257e06229c891f376" -"checksum serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c73f63e08b33f6e59dfb3365b009897ebc3a3edc4af6e4f3ce8e483cf3d80ce7" +"checksum serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe95aa0d46f04ce5c3a88bdcd4114ecd6144ed0b2725ebca2f1127744357807" "checksum serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "652bc323d694dc925829725ec6c890156d8e70ae5202919869cb00fe2eff3788" "checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab" -"checksum serde_json 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fab6c4d75bedcf880711c85e39ebf8ccc70d0eba259899047ec5d7436643ee17" +"checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74" "checksum standalone-quote 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcedac1d6d98e7e9d1d6e628f5635af9566688ae5f6cea70a3976f495ae8d839" "checksum standalone-syn 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "115808f5187c07c23cb93eee49d542fae54c6e8285d3a24c6ff683fcde9243db" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" @@ -643,8 +625,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/src/fcntl/src/linux.rs b/src/fcntl/src/linux.rs index fd68ffcf14c01e6adfcfaf4f34bb9412e65bd7d2..ce9499aab713cf36142986d781e8d9ef4b4cc076 100644 --- a/src/fcntl/src/linux.rs +++ b/src/fcntl/src/linux.rs @@ -6,3 +6,6 @@ pub const O_RDWR: c_int = 0x0002; pub const O_CREAT: c_int = 0x0040; pub const O_TRUNC: c_int = 0x0200; pub const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR; +pub const O_APPEND: c_int = 0o2000; +pub const O_CLOEXEC: c_int = 0o2_000_000; +pub const O_EXCL: c_int = 0o200; diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index 63732fbf61129c399658e8488e78c2ce0711e735..24fd605a2fc735a1046fbd6a54eed849216e8a0a 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -61,8 +61,8 @@ pub unsafe fn cstr_from_bytes_with_nul_unchecked(bytes: &[u8]) -> *const c_char pub struct FileWriter(pub c_int); impl FileWriter { - pub fn write(&mut self, buf: &[u8]) { - write(self.0, buf); + pub fn write(&mut self, buf: &[u8]) -> isize { + write(self.0, buf) } } @@ -73,6 +73,14 @@ impl fmt::Write for FileWriter { } } +pub struct FileReader(pub c_int); + +impl FileReader { + pub fn read(&mut self, buf: &mut [u8]) -> isize { + read(self.0, buf) + } +} + pub struct StringWriter(pub *mut u8, pub usize); impl StringWriter { diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 7bf42be63d217a630330f19474e49e87a3739f76..bf9a6169b3435a67af4fbf25c7dc9dc52331cd72 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -130,10 +130,22 @@ pub fn getuid() -> uid_t { e(unsafe { syscall!(GETUID) }) } +pub fn kill(pid: pid_t, sig: c_int) -> c_int { + e(unsafe { syscall!(KILL, pid, sig) }) as c_int +} + +pub fn killpg(pgrp: pid_t, sig: c_int) -> c_int { + e(unsafe { syscall!(KILL, -(pgrp as isize) as pid_t, sig) }) as c_int +} + pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { e(unsafe { syscall!(LINKAT, AT_FDCWD, path1, AT_FDCWD, path2, 0) }) as c_int } +pub fn lseek(fildes: c_int, offset: off_t, whence: c_int) -> off_t { + e(unsafe { syscall!(LSEEK, fildes, offset, whence) }) as off_t +} + pub fn lstat(file: *const c_char, buf: *mut stat) -> c_int { e(unsafe { syscall!(NEWFSTATAT, AT_FDCWD, file, buf, AT_SYMLINK_NOFOLLOW) }) as c_int } @@ -193,3 +205,7 @@ pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t { pub fn write(fildes: c_int, buf: &[u8]) -> ssize_t { e(unsafe { syscall!(WRITE, fildes, buf.as_ptr(), buf.len()) }) as ssize_t } + +pub fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int { + e(unsafe { syscall!(CLOCK_GETTIME, clk_id, tp) }) as c_int +} diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index 4155f6276081f084c9da3c2023b192f0c63d2d89..03c4b5cf5fd0a65ca128a3d106e222ec07204fc1 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -168,12 +168,28 @@ pub fn getuid() -> uid_t { e(syscall::getuid()) as pid_t } +pub fn kill(pid: pid_t, sig: c_int) -> c_int { + e(syscall::kill(pid, sig as usize)) as c_int +} + +pub fn killpg(pgrp: pid_t, sig: c_int) -> c_int { + e(syscall::kill(-(pgrp as isize) as pid_t, sig as usize)) as c_int +} + pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { let path1 = unsafe { c_str(path1) }; let path2 = unsafe { c_str(path2) }; e(unsafe { syscall::link(path1.as_ptr(), path2.as_ptr()) }) as c_int } +pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t { + e(syscall::lseek( + fd as usize, + offset as isize, + whence as usize, + )) as off_t +} + pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int { let path = unsafe { c_str(path) }; match syscall::open(path, O_RDONLY | O_NOFOLLOW) { @@ -184,7 +200,6 @@ pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int { res } } -} pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int { let flags = O_CREAT | O_EXCL | O_CLOEXEC | O_DIRECTORY | mode as usize & 0o777; @@ -297,3 +312,17 @@ pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t { pub fn write(fd: c_int, buf: &[u8]) -> ssize_t { e(syscall::write(fd as usize, buf)) as ssize_t } + +pub fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int { + let mut redox_tp = unsafe { redox_timespec::from(&*tp) }; + match e(syscall::clock_gettime(clk_id as usize, &mut redox_tp)) as c_int { + -1 => -1, + _ => { + unsafe { + (*tp).tv_sec = redox_tp.tv_sec; + (*tp).tv_nsec = redox_tp.tv_nsec as i64; + }; + 0 + } + } +} diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs index f721d674e0b7449ff3ee141ea91f31f29de9aece..1993edbe18af4952acf7e197fa7b293d40dbd9f6 100644 --- a/src/platform/src/types.rs +++ b/src/platform/src/types.rs @@ -68,6 +68,7 @@ pub type clockid_t = i32; pub type timer_t = c_void; #[repr(C)] +#[derive(Default)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, diff --git a/src/signal/src/lib.rs b/src/signal/src/lib.rs index 052cb13770eb2790ff5d12953652e06ddb42b2fc..031b8e4836cb844c1766b1fb57a5b6e43c235a6a 100644 --- a/src/signal/src/lib.rs +++ b/src/signal/src/lib.rs @@ -27,12 +27,12 @@ pub type sigset_t = sys_sigset_t; #[no_mangle] pub extern "C" fn kill(pid: pid_t, sig: c_int) -> c_int { - unimplemented!(); + platform::kill(pid, sig) } #[no_mangle] pub extern "C" fn killpg(pgrp: pid_t, sig: c_int) -> c_int { - unimplemented!(); + platform::killpg(pgrp, sig) } #[no_mangle] diff --git a/src/stdio/Cargo.toml b/src/stdio/Cargo.toml index 2f53e58dc70578c5c48c0a96c5bb6fb83b1c62ca..1a920812a6a730a62b6a53efa6b8ca42faa0ed44 100644 --- a/src/stdio/Cargo.toml +++ b/src/stdio/Cargo.toml @@ -8,6 +8,10 @@ build = "build.rs" cbindgen = { path = "../../cbindgen" } [dependencies] +compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins.git", default-features = false, features = ["mem"] } platform = { path = "../platform" } va_list = { path = "../../va_list", features = ["no_std"] } +fcntl = { path = "../fcntl" } +string = { path = "../string" } +stdlib = { path = "../stdlib" } errno = { path = "../errno"} diff --git a/src/stdio/cbindgen.toml b/src/stdio/cbindgen.toml index 58483d52ac51ae265ff8f156bb26a8800dc8250e..3f13ef55cb66b092e669e76578cce789ee7899ab 100644 --- a/src/stdio/cbindgen.toml +++ b/src/stdio/cbindgen.toml @@ -5,3 +5,6 @@ language = "C" [enum] prefix_with_name = true + +[export.rename] +"AtomicBool" = "volatile char" diff --git a/src/stdio/src/constants.rs b/src/stdio/src/constants.rs new file mode 100644 index 0000000000000000000000000000000000000000..c601cbc85e3d07206b6dfdaa0314dfe870b58771 --- /dev/null +++ b/src/stdio/src/constants.rs @@ -0,0 +1,27 @@ +use platform::types::*; + +pub const BUFSIZ: size_t = 1024; + +pub const UNGET: size_t = 8; + +pub const FILENAME_MAX: c_int = 4096; + +pub const F_PERM: c_int = 1; +pub const F_NORD: c_int = 4; +pub const F_NOWR: c_int = 8; +pub const F_EOF: c_int = 16; +pub const F_ERR: c_int = 32; +pub const F_SVB: c_int = 64; +pub const F_APP: c_int = 128; +pub const F_BADJ: c_int = 256; + +pub const SEEK_SET: c_int = 0; +pub const SEEK_CUR: c_int = 1; +pub const SEEK_END: c_int = 2; + +pub const _IOFBF: c_int = 0; +pub const _IOLBF: c_int = 1; +pub const _IONBF: c_int = 2; + +#[allow(non_camel_case_types)] +pub type fpos_t = off_t; diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs new file mode 100644 index 0000000000000000000000000000000000000000..840a6fa07ff1ef76d945ff7997403e6b153d1f40 --- /dev/null +++ b/src/stdio/src/default.rs @@ -0,0 +1,76 @@ +use core::sync::atomic::AtomicBool; +use core::ptr; +use super::{constants, internal, BUFSIZ, FILE, UNGET}; + +#[allow(non_upper_case_globals)] +static mut default_stdin_buf: [u8; BUFSIZ as usize + UNGET] = [0; BUFSIZ as usize + UNGET]; + +#[allow(non_upper_case_globals)] +static mut default_stdin: FILE = FILE { + flags: constants::F_PERM | constants::F_NOWR | constants::F_BADJ, + rpos: ptr::null_mut(), + rend: ptr::null_mut(), + wend: ptr::null_mut(), + wpos: ptr::null_mut(), + wbase: ptr::null_mut(), + fd: 0, + buf: unsafe { &mut default_stdin_buf as *mut [u8] as *mut u8 }, + buf_size: BUFSIZ as usize, + buf_char: -1, + unget: UNGET, + lock: AtomicBool::new(false), +}; + +#[allow(non_upper_case_globals)] +static mut default_stdout_buf: [u8; BUFSIZ as usize] = [0; BUFSIZ as usize]; + +#[allow(non_upper_case_globals)] +static mut default_stdout: FILE = FILE { + flags: constants::F_PERM | constants::F_NORD | constants::F_BADJ, + rpos: ptr::null_mut(), + rend: ptr::null_mut(), + wend: ptr::null_mut(), + wpos: ptr::null_mut(), + wbase: ptr::null_mut(), + fd: 1, + buf: unsafe { &mut default_stdout_buf } as *mut [u8] as *mut u8, + buf_size: BUFSIZ as usize, + buf_char: b'\n' as i8, + unget: 0, + lock: AtomicBool::new(false), +}; + +#[allow(non_upper_case_globals)] +static mut default_stderr_buf: [u8; BUFSIZ as usize] = [0; BUFSIZ as usize]; + +#[allow(non_upper_case_globals)] +static mut default_stderr: FILE = FILE { + flags: constants::F_PERM | constants::F_NORD | constants::F_BADJ, + rpos: ptr::null_mut(), + rend: ptr::null_mut(), + wend: ptr::null_mut(), + wpos: ptr::null_mut(), + wbase: ptr::null_mut(), + fd: 2, + buf: unsafe { &mut default_stderr_buf } as *mut [u8] as *mut u8, + buf_size: BUFSIZ as usize, + buf_char: -1, + unget: 0, + lock: AtomicBool::new(false), +}; + +// Don't ask me how the casting below works, I have no idea +// " as *const FILE as *mut FILE" rust pls +// +// -- Tommoa +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut stdin: *mut FILE = unsafe { &default_stdin } as *const FILE as *mut FILE; + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut stdout: *mut FILE = unsafe { &default_stdout } as *const FILE as *mut FILE; + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut stderr: *mut FILE = unsafe { &default_stderr } as *const FILE as *mut FILE; diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs new file mode 100644 index 0000000000000000000000000000000000000000..378d2af3b6cbdbc4d45b430b318a0abdcb7f59ca --- /dev/null +++ b/src/stdio/src/helpers.rs @@ -0,0 +1,147 @@ +use super::{internal, BUFSIZ, FILE, UNGET}; +use stdlib::calloc; +use core::{mem, ptr}; +use core::sync::atomic::AtomicBool; +use platform::types::*; +use super::constants::*; +use fcntl::*; +use platform; +use errno; + +/// Parse mode flags as a string and output a mode flags integer +pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 { + use string::strchr; + let mut flags = if !strchr(mode_str, b'+' as i32).is_null() { + O_RDWR + } else if (*mode_str) == b'r' as i8 { + O_RDONLY + } else { + O_WRONLY + }; + if !strchr(mode_str, b'x' as i32).is_null() { + flags |= O_EXCL; + } + if !strchr(mode_str, b'e' as i32).is_null() { + flags |= O_CLOEXEC; + } + if (*mode_str) != b'r' as i8 { + flags |= O_CREAT; + } + if (*mode_str) == b'w' as i8 { + flags |= O_TRUNC; + } + if (*mode_str) != b'a' as i8 { + flags |= O_APPEND; + } + + flags +} + +/// Open a file with the file descriptor `fd` in the mode `mode` +pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> *mut FILE { + use string::strchr; + if *mode != b'r' as i8 && *mode != b'w' as i8 && *mode != b'a' as i8 { + platform::errno = errno::EINVAL; + return ptr::null_mut(); + } + + let mut flags = 0; + if strchr(mode, b'+' as i32).is_null() { + flags |= if *mode == b'r' as i8 { F_NOWR } else { F_NORD }; + } + + if !strchr(mode, b'e' as i32).is_null() { + sys_fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + if *mode == 'a' as i8 { + let f = sys_fcntl(fd, F_GETFL, 0); + if (f & O_APPEND) == 0 { + sys_fcntl(fd, F_SETFL, f | O_APPEND); + } + flags |= F_APP; + } + + let file = calloc(mem::size_of::<FILE>() + BUFSIZ + UNGET, 1) as *mut FILE; + // Allocate the file + (*file) = FILE { + flags: flags, + rpos: ptr::null_mut(), + rend: ptr::null_mut(), + wend: ptr::null_mut(), + wpos: ptr::null_mut(), + wbase: ptr::null_mut(), + fd: fd, + buf: (file as *mut u8).add(mem::size_of::<FILE>() + UNGET), + buf_size: BUFSIZ, + buf_char: -1, + unget: UNGET, + lock: AtomicBool::new(false), + }; + file +} + +/// Write buffer `buf` of length `l` into `stream` +pub fn fwritex(buf: *const u8, l: size_t, stream: &mut FILE) -> size_t { + use core::ptr::copy_nonoverlapping; + use core::slice; + + let buf: &'static [u8] = unsafe { slice::from_raw_parts(buf, l) }; + let mut l = l; + let mut advance = 0; + + if stream.wend.is_null() && !stream.can_write() { + // We can't write to this stream + return 0; + } + if l > stream.wend as usize - stream.wpos as usize { + // We can't fit all of buf in the buffer + return stream.write(buf); + } + + let i = if stream.buf_char >= 0 { + let mut i = l; + while i > 0 && buf[i - 1] != b'\n' { + i -= 1; + } + if i > 0 { + let n = stream.write(buf); + if n < i { + return n; + } + advance += i; + l -= i; + } + i + } else { + 0 + }; + + unsafe { + // Copy and reposition + copy_nonoverlapping(&buf[advance..] as *const _ as *const u8, stream.wpos, l); + stream.wpos = stream.wpos.add(l); + } + l + i +} + +/// Flush `stream` without locking it. +pub fn fflush_unlocked(stream: &mut FILE) -> c_int { + if stream.wpos > stream.wbase { + stream.write(&[]); + if stream.wpos.is_null() { + return -1; + } + } + + if stream.rpos < stream.rend { + stream.seek(stream.rpos as i64 - stream.rend as i64, SEEK_CUR); + } + + stream.wpos = ptr::null_mut(); + stream.wend = ptr::null_mut(); + stream.wbase = ptr::null_mut(); + stream.rpos = ptr::null_mut(); + stream.rend = ptr::null_mut(); + 0 +} diff --git a/src/stdio/src/internal.rs b/src/stdio/src/internal.rs new file mode 100644 index 0000000000000000000000000000000000000000..35eb5f47e8896126ae57e64a41d383842659d189 --- /dev/null +++ b/src/stdio/src/internal.rs @@ -0,0 +1,19 @@ +use super::{constants, FILE}; +use platform; +use platform::types::*; +use core::{mem, ptr, slice}; + +pub fn ftello(stream: &mut FILE) -> off_t { + let pos = stream.seek( + 0, + if (stream.flags & constants::F_APP > 0) && stream.wpos > stream.wbase { + constants::SEEK_END + } else { + constants::SEEK_CUR + }, + ); + if pos < 0 { + return pos; + } + pos - (stream.rend as i64 - stream.rpos as i64) + (stream.wpos as i64 - stream.wbase as i64) +} diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index e99351639b22ed0de4e5c8d09eacbb288d8bea53..98e3a3913f180b08bf6671e1c095d133f7c8b7d3 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -1,41 +1,186 @@ //! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html +#![feature(compiler_builtins_lib)] #![no_std] +extern crate compiler_builtins; extern crate errno; +extern crate fcntl; extern crate platform; +extern crate stdlib; +extern crate string; extern crate va_list as vl; use core::str; -use core::fmt::Write; +use core::ptr; +use core::fmt::{Error, Result, Write}; +use core::sync::atomic::{AtomicBool, Ordering}; use platform::types::*; -use platform::c_str; -use platform::errno; +use platform::{c_str, errno}; use errno::STR_ERROR; use vl::VaList as va_list; mod printf; -pub const BUFSIZ: c_int = 4096; - -pub const FILENAME_MAX: c_int = 4096; - -pub type fpos_t = off_t; - -pub struct FILE; - -#[allow(non_upper_case_globals)] -#[no_mangle] -pub static mut stdout: *mut FILE = 1 as *mut FILE; - -#[allow(non_upper_case_globals)] -#[no_mangle] -pub static mut stderr: *mut FILE = 2 as *mut FILE; +mod default; +pub use default::*; + +mod constants; +pub use constants::*; + +mod helpers; + +mod internal; + +#[repr(C)] +pub struct FILE { + flags: c_int, + rpos: *mut u8, + rend: *mut u8, + wend: *mut u8, + wpos: *mut u8, + wbase: *mut u8, + fd: c_int, + buf: *mut u8, + buf_size: size_t, + buf_char: i8, + lock: AtomicBool, + unget: size_t, +} + +impl FILE { + pub fn can_read(&mut self) -> bool { + if self.flags & constants::F_BADJ > 0 { + // Static and needs unget region + self.buf = unsafe { self.buf.add(self.unget) }; + self.flags &= !constants::F_BADJ; + } + + if self.wpos > self.wbase { + self.write(&[]); + } + self.wpos = ptr::null_mut(); + self.wbase = ptr::null_mut(); + self.wend = ptr::null_mut(); + if self.flags & constants::F_NORD > 0 { + self.flags |= constants::F_ERR; + return false; + } + self.rpos = unsafe { self.buf.offset(self.buf_size as isize - 1) }; + self.rend = unsafe { self.buf.offset(self.buf_size as isize - 1) }; + if self.flags & constants::F_EOF > 0 { + false + } else { + true + } + } + pub fn can_write(&mut self) -> bool { + if self.flags & constants::F_BADJ > 0 { + // Static and needs unget region + self.buf = unsafe { self.buf.add(self.unget) }; + self.flags &= !constants::F_BADJ; + } + + if self.flags & constants::F_NOWR > 0 { + self.flags &= constants::F_ERR; + return false; + } + // Buffer repositioning + self.rpos = ptr::null_mut(); + self.rend = ptr::null_mut(); + self.wpos = self.buf; + self.wbase = self.buf; + self.wend = unsafe { self.buf.offset(self.buf_size as isize - 1) }; + return true; + } + pub fn write(&mut self, to_write: &[u8]) -> usize { + use core::slice; + use core::mem; + let len = self.wpos as usize - self.wbase as usize; + let mut advance = 0; + let mut f_buf: &'static _ = unsafe { slice::from_raw_parts(self.wbase, len) }; + let mut f_filled = false; + let mut rem = f_buf.len() + to_write.len(); + loop { + let mut count = if f_filled { + platform::write(self.fd, &f_buf[advance..]) + } else { + platform::write(self.fd, &f_buf[advance..]) + platform::write(self.fd, to_write) + }; + if count == rem as isize { + self.wend = unsafe { self.buf.add(self.buf_size - 1) }; + self.wpos = self.buf; + self.wbase = self.buf; + return to_write.len(); + } + if count < 0 { + self.wpos = ptr::null_mut(); + self.wbase = ptr::null_mut(); + self.wend = ptr::null_mut(); + self.flags |= constants::F_ERR; + return 0; + } + rem -= count as usize; + if count as usize > len { + count -= len as isize; + f_buf = unsafe { mem::transmute(to_write) }; + f_filled = true; + advance = 0; + } + advance += count as usize; + } + } + pub fn read(&mut self, buf: &mut [u8]) -> usize { + use core::slice; + // let buff = slice::from_raw_parts_mut(buf, size - !((*stream).buf_size == 0) as usize); + let adj = !(self.buf_size == 0) as usize; + let mut file_buf: &'static mut _ = + unsafe { slice::from_raw_parts_mut(self.buf, self.buf_size) }; + let count = if buf.len() <= 1 + adj { + platform::read(self.fd, file_buf) + } else { + platform::read(self.fd, buf) + platform::read(self.fd, file_buf) + }; + if count <= 0 { + self.flags |= if count == 0 { + constants::F_EOF + } else { + constants::F_ERR + }; + return 0; + } + if count as usize <= buf.len() - adj { + return count as usize; + } + unsafe { + // Adjust pointers + self.rpos = self.buf; + self.rend = self.buf.offset(count); + buf[buf.len() - 1] = *self.rpos; + self.rpos = self.rpos.add(1); + } + buf.len() + } + pub fn seek(&self, off: off_t, whence: c_int) -> off_t { + unsafe { platform::lseek(self.fd, off, whence) } + } +} +impl Write for FILE { + fn write_str(&mut self, s: &str) -> Result { + let s = s.as_bytes(); + if self.write(s) != s.len() { + Err(Error) + } else { + Ok(()) + } + } +} +/// Clears EOF and ERR indicators on a stream #[no_mangle] -pub extern "C" fn clearerr(stream: *mut FILE) { - unimplemented!(); +pub extern "C" fn clearerr(stream: &mut FILE) { + stream.flags &= !(F_EOF | F_ERR); } #[no_mangle] @@ -48,176 +193,468 @@ pub extern "C" fn cuserid(s: *mut c_char) -> *mut c_char { unimplemented!(); } +/// Close a file +/// This function does not guarentee that the file buffer will be flushed or that the file +/// descriptor will be closed, so if it is important that the file be written to, use `fflush()` +/// prior to using this function. #[no_mangle] -pub extern "C" fn fclose(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn fclose(stream: &mut FILE) -> c_int { + use stdlib::free; + flockfile(stream); + let r = helpers::fflush_unlocked(stream) | platform::close(stream.fd); + if stream.flags & constants::F_PERM == 0 { + // Not one of stdin, stdout or stderr + unsafe { + free(stream as *mut _ as *mut _); + } + } + r } +/// Open a file from a file descriptor #[no_mangle] pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE { - unimplemented!(); + unsafe { helpers::_fdopen(fildes, mode) } } +/// Check for EOF #[no_mangle] -pub extern "C" fn feof(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn feof(stream: &mut FILE) -> c_int { + flockfile(stream); + let ret = stream.flags & F_EOF; + funlockfile(stream); + ret } +/// Check for ERR #[no_mangle] -pub extern "C" fn ferror(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn ferror(stream: &mut FILE) -> c_int { + flockfile(stream); + let ret = stream.flags & F_ERR; + funlockfile(stream); + ret } +/// Flush output to stream, or sync read position +/// Ensure the file is unlocked before calling this function, as it will attempt to lock the file +/// itself. #[no_mangle] -pub extern "C" fn fflush(stream: *mut FILE) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn fflush(stream: &mut FILE) -> c_int { + flockfile(stream); + + let ret = helpers::fflush_unlocked(stream); + + funlockfile(stream); + ret } +/// Get a single char from a stream #[no_mangle] -pub extern "C" fn fgetc(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn fgetc(stream: &mut FILE) -> c_int { + flockfile(stream); + let c = getc_unlocked(stream); + funlockfile(stream); + c } +/// Get the position of the stream and store it in pos #[no_mangle] -pub extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int { - unimplemented!(); +pub extern "C" fn fgetpos(stream: &mut FILE, pos: *mut fpos_t) -> c_int { + let off = internal::ftello(stream); + if off < 0 { + return -1; + } + unsafe { + (*pos) = off; + } + 0 } +/// Get a string from the stream #[no_mangle] -pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char { - unimplemented!(); +pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_char { + use string::memchr; + use core::ptr::copy_nonoverlapping; + + flockfile(stream); + let mut ptr = s as *mut u8; + let mut n = n; + + if n <= 1 { + funlockfile(stream); + if n == 0 { + return ptr::null_mut(); + } + unsafe { + (*s) = b'\0' as i8; + } + return s; + } + while n > 0 { + let z = unsafe { + memchr( + stream.rpos as *const c_void, + b'\n' as c_int, + stream.rend as usize - stream.rpos as usize, + ) as *mut u8 + }; + let k = if z.is_null() { + stream.rend as usize - stream.rpos as usize + } else { + z as usize - stream.rpos as usize + 1 + }; + let k = if k as i32 > n { n as usize } else { k }; + unsafe { + // Copy + copy_nonoverlapping(stream.rpos, ptr, k); + // Reposition pointers + stream.rpos = stream.rpos.add(k); + ptr = ptr.add(k); + } + n -= k as i32; + if !z.is_null() || n < 1 { + break; + } + let c = getc_unlocked(stream); + if c < 0 { + break; + } + n -= 1; + + unsafe { + // Pointer stuff + *ptr = c as u8; + ptr = ptr.add(1); + } + + if c as u8 == b'\n' { + break; + } + } + if !s.is_null() { + unsafe { + *ptr = 0; + } + } + funlockfile(stream); + s } +/// Get the underlying file descriptor #[no_mangle] -pub extern "C" fn fileno(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn fileno(stream: &mut FILE) -> c_int { + flockfile(stream); + funlockfile(stream); + stream.fd } +/// Lock the file +/// Do not call any functions other than those with the `_unlocked` postfix while the file is +/// locked #[no_mangle] -pub extern "C" fn flockfile(file: *mut FILE) { - unimplemented!(); +pub extern "C" fn flockfile(file: &mut FILE) { + while ftrylockfile(file) != 0 {} } +/// Open the file in mode `mode` #[no_mangle] -pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE { - unimplemented!(); +pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE { + use core::ptr; + let initial_mode = *mode; + if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 { + platform::errno = errno::EINVAL; + return ptr::null_mut(); + } + + let flags = helpers::parse_mode_flags(mode); + + let fd = fcntl::sys_open(filename, flags, 0o666); + if fd < 0 { + return ptr::null_mut(); + } + + if flags & fcntl::O_CLOEXEC > 0 { + fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC); + } + + let f = helpers::_fdopen(fd, mode); + if f.is_null() { + platform::close(fd); + return ptr::null_mut(); + } + f } +/// Insert a character into the stream #[no_mangle] -pub extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int { - platform::FileWriter(stream as c_int) - .write_char(c as u8 as char) - .map_err(|_| return -1); +pub extern "C" fn fputc(c: c_int, stream: &mut FILE) -> c_int { + flockfile(stream); + let c = putc_unlocked(c, stream); + funlockfile(stream); c } +/// Insert a string into a stream #[no_mangle] -pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int { +pub extern "C" fn fputs(s: *const c_char, stream: &mut FILE) -> c_int { extern "C" { fn strlen(s: *const c_char) -> size_t; } - use core::{slice, str}; - let len = strlen(s); - platform::FileWriter(stream as c_int) - .write_str(str::from_utf8_unchecked(slice::from_raw_parts( - s as *const u8, - len, - ))) - .map_err(|_| return -1); - len as i32 -} + let len = unsafe { strlen(s) }; + (fwrite(s as *const c_void, 1, len, stream) == len) as c_int - 1 +} + +/// Read `nitems` of size `size` into `ptr` from `stream` +#[no_mangle] +pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &mut FILE) -> usize { + use core::ptr::copy_nonoverlapping; + use core::slice; + let mut dest = ptr as *mut u8; + let len = size * nitems; + let mut l = len as isize; + + flockfile(stream); + + if stream.rend > stream.rpos { + // We have some buffered data that can be read + let diff = stream.rend as usize - stream.rpos as usize; + let k = if diff < l as usize { diff } else { l as usize }; + unsafe { + // Copy data + copy_nonoverlapping(stream.rpos, dest, k); + // Reposition pointers + stream.rpos = stream.rpos.add(k); + dest = dest.add(k); + } + l -= k as isize; + } -#[no_mangle] -pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: *mut FILE) -> usize { - unimplemented!(); + while l > 0 { + let k = if !stream.can_read() { + 0 + } else { + stream.read(unsafe { slice::from_raw_parts_mut(dest, l as usize) }) + }; + + if k == 0 { + funlockfile(stream); + return (len - l as usize) / 2; + } + + l -= k as isize; + unsafe { + // Reposition + dest = dest.add(k); + } + } + + funlockfile(stream); + nitems } #[no_mangle] pub extern "C" fn freopen( filename: *const c_char, mode: *const c_char, - stream: *mut FILE, + stream: &mut FILE, ) -> *mut FILE { - unimplemented!(); + let mut flags = unsafe { helpers::parse_mode_flags(mode) }; + flockfile(stream); + + helpers::fflush_unlocked(stream); + if filename.is_null() { + // Reopen stream in new mode + if flags & fcntl::O_CLOEXEC > 0 { + fcntl::sys_fcntl(stream.fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC); + } + flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC); + if fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags) < 0 { + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + } else { + let new = unsafe { fopen(filename, mode) }; + if new.is_null() { + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + let new = unsafe { &mut *new }; // Should be safe, new is not null + if new.fd == stream.fd { + new.fd = -1; + } else if platform::dup2(new.fd, stream.fd) < 0 + || fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0 + { + fclose(new); + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + stream.flags = (stream.flags & constants::F_PERM) | new.flags; + fclose(new); + } + funlockfile(stream); + stream } +/// Seek to an offset `offset` from `whence` #[no_mangle] -pub extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int { - unimplemented!(); +pub extern "C" fn fseek(stream: &mut FILE, offset: c_long, whence: c_int) -> c_int { + if fseeko(stream, offset as off_t, whence) != -1 { + return 0; + } + -1 } +/// Seek to an offset `offset` from `whence` #[no_mangle] -pub extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> c_int { - unimplemented!(); +pub extern "C" fn fseeko(stream: &mut FILE, offset: off_t, whence: c_int) -> c_int { + let mut off = offset; + flockfile(stream); + // Adjust for what is currently in the buffer + if whence == SEEK_CUR { + off -= (stream.rend as usize - stream.rpos as usize) as i64; + } + if stream.wpos > stream.wbase { + stream.write(&[]); + if stream.wpos.is_null() { + return -1; + } + } + stream.wpos = ptr::null_mut(); + stream.wend = ptr::null_mut(); + stream.wbase = ptr::null_mut(); + if stream.seek(off, whence) < 0 { + return -1; + } + stream.rpos = ptr::null_mut(); + stream.rend = ptr::null_mut(); + stream.flags &= !F_EOF; + funlockfile(stream); + 0 } +/// Seek to a position `pos` in the file from the beginning of the file #[no_mangle] -pub extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn fsetpos(stream: &mut FILE, pos: *const fpos_t) -> c_int { + fseek(stream, *pos as off_t, SEEK_SET) } +/// Get the current position of the cursor in the file #[no_mangle] -pub extern "C" fn ftell(stream: *mut FILE) -> c_long { - unimplemented!(); +pub unsafe extern "C" fn ftell(stream: &mut FILE) -> c_long { + ftello(stream) as c_long } +/// Get the current position of the cursor in the file #[no_mangle] -pub extern "C" fn ftello(stream: *mut FILE) -> off_t { - unimplemented!(); +pub extern "C" fn ftello(stream: &mut FILE) -> off_t { + flockfile(stream); + let pos = internal::ftello(stream); + funlockfile(stream); + pos } +/// Try to lock the file. Returns 0 for success, 1 for failure #[no_mangle] -pub extern "C" fn ftrylockfile(file: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn ftrylockfile(file: &mut FILE) -> c_int { + file.lock.compare_and_swap(false, true, Ordering::Acquire) as c_int } +/// Unlock the file #[no_mangle] -pub extern "C" fn funlockfile(file: *mut FILE) { - unimplemented!(); +pub extern "C" fn funlockfile(file: &mut FILE) { + file.lock.store(false, Ordering::Release); } +/// Write `nitems` of size `size` from `ptr` to `stream` #[no_mangle] pub extern "C" fn fwrite( ptr: *const c_void, size: usize, nitems: usize, - stream: *mut FILE, + stream: &mut FILE, ) -> usize { - unimplemented!(); + let l = size * nitems; + let nitems = if size == 0 { 0 } else { nitems }; + flockfile(stream); + let k = helpers::fwritex(ptr as *const u8, l, stream); + funlockfile(stream); + if k == l { + nitems + } else { + k / size + } } +/// Get a single char from a stream #[no_mangle] -pub extern "C" fn getc(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn getc(stream: &mut FILE) -> c_int { + flockfile(stream); + let c = getc_unlocked(stream); + funlockfile(stream); + c } +/// Get a single char from `stdin` #[no_mangle] -pub extern "C" fn getchar() -> c_int { - unimplemented!(); +pub unsafe extern "C" fn getchar() -> c_int { + fgetc(&mut *stdin) } +/// Get a char from a stream without locking the stream #[no_mangle] -pub extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn getc_unlocked(stream: &mut FILE) -> c_int { + if stream.rpos < stream.rend { + unsafe { + let ret = *stream.rpos as c_int; + stream.rpos = stream.rpos.add(1); + ret + } + } else { + let mut c = [0u8; 1]; + if stream.can_read() && stream.read(&mut c) == 1 { + c[0] as c_int + } else { + -1 + } + } } +/// Get a char from `stdin` without locking `stdin` #[no_mangle] -pub extern "C" fn getchar_unlocked() -> c_int { - unimplemented!(); +pub unsafe extern "C" fn getchar_unlocked() -> c_int { + getc_unlocked(&mut *stdin) } +/// Get a string from `stdin` #[no_mangle] -pub extern "C" fn gets(s: *mut c_char) -> *mut c_char { - unimplemented!(); +pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char { + use core::i32; + fgets(s, i32::MAX, &mut *stdin) } +/// Get an integer from `stream` #[no_mangle] -pub extern "C" fn getw(stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn getw(stream: &mut FILE) -> c_int { + use core::mem; + let mut ret: c_int = 0; + if fread( + &mut ret as *mut c_int as *mut c_void, + mem::size_of_val(&ret), + 1, + stream, + ) > 0 + { + ret + } else { + -1 + } } #[no_mangle] -pub extern "C" fn pclose(stream: *mut FILE) -> c_int { +pub extern "C" fn pclose(stream: &mut FILE) -> c_int { unimplemented!(); } @@ -238,60 +675,135 @@ pub extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FIL unimplemented!(); } +/// Put a character `c` into `stream` #[no_mangle] -pub extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { - fputc(c, stream) +pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int { + flockfile(stream); + let ret = putc_unlocked(c, stream); + funlockfile(stream); + ret } +/// Put a character `c` into `stdout` #[no_mangle] pub unsafe extern "C" fn putchar(c: c_int) -> c_int { - putc(c, stdout) + fputc(c, &mut *stdout) } +/// Put a character `c` into `stream` without locking `stream` #[no_mangle] -pub extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int { + if c as i8 != stream.buf_char && stream.wpos < stream.wend { + unsafe { + *stream.wpos = c as u8; + stream.wpos = stream.wpos.add(1); + c + } + } else { + if stream.wend.is_null() && stream.can_write() { + -1 + } else if c as i8 != stream.buf_char && stream.wpos < stream.wend { + unsafe { + *stream.wpos = c as u8; + stream.wpos = stream.wpos.add(1); + c + } + } else if stream.write(&[c as u8]) != 1 { + -1 + } else { + c + } + } } +/// Put a character `c` into `stdout` without locking `stdout` #[no_mangle] pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int { - putc_unlocked(c, stdout) + putc_unlocked(c, &mut *stdout) } +/// Put a string `s` into `stdout` #[no_mangle] pub unsafe extern "C" fn puts(s: *const c_char) -> c_int { - fputs(s, stdout); - putchar(b'\n' as c_int) + let ret = (fputs(s, &mut *stdout) > 0) || (putchar_unlocked(b'\n' as c_int) > 0); + if ret { + 0 + } else { + -1 + } } +/// Put an integer `w` into `stream` #[no_mangle] -pub extern "C" fn putw(w: c_int, stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn putw(w: c_int, stream: &mut FILE) -> c_int { + use core::mem; + fwrite(&w as *const i32 as _, mem::size_of_val(&w), 1, stream) as i32 - 1 } +/// Delete file or directory `path` #[no_mangle] pub extern "C" fn remove(path: *const c_char) -> c_int { - unimplemented!(); + let r = platform::unlink(path); + if r == -errno::EISDIR { + platform::rmdir(path) + } else { + r + } } #[no_mangle] pub extern "C" fn rename(old: *const c_char, new: *const c_char) -> c_int { + // This function requires a rename syscall, which currently is not in platform. unimplemented!(); } +/// Rewind `stream` back to the beginning of it #[no_mangle] -pub extern "C" fn rewind(stream: *mut FILE) { - unimplemented!(); +pub extern "C" fn rewind(stream: &mut FILE) { + fseeko(stream, 0, SEEK_SET); + flockfile(stream); + stream.flags &= !F_ERR; + funlockfile(stream); } +/// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length #[no_mangle] -pub extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) { - unimplemented!(); +pub extern "C" fn setbuf(stream: &mut FILE, buf: *mut c_char) { + unsafe { + setvbuf( + stream, + buf, + if buf.is_null() { _IONBF } else { _IOFBF }, + BUFSIZ as usize, + ) + }; } +/// Reset `stream` to use buffer `buf` of size `size` +/// If this isn't the meaning of unsafe, idk what is #[no_mangle] -pub extern "C" fn setvbuf(stream: *mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn setvbuf( + stream: &mut FILE, + buf: *mut c_char, + mode: c_int, + size: usize, +) -> c_int { + // TODO: Check correctness + use stdlib::calloc; + let mut buf = buf; + if buf.is_null() && mode != _IONBF { + buf = calloc(size, 1) as *mut c_char; + } + (*stream).buf_size = size; + (*stream).buf_char = -1; + if mode == _IONBF { + (*stream).buf_size = 0; + } else if mode == _IOLBF { + (*stream).buf_char = b'\n' as i8; + } + (*stream).flags |= F_SVB; + (*stream).buf = buf as *mut u8; + 0 } #[no_mangle] @@ -309,19 +821,40 @@ pub extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char { unimplemented!(); } +/// Push character `c` back onto `stream` so it'll be read next #[no_mangle] -pub extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { - unimplemented!(); +pub extern "C" fn ungetc(c: c_int, stream: &mut FILE) -> c_int { + if c < 0 { + c + } else { + flockfile(stream); + if stream.rpos.is_null() { + stream.can_read(); + } + if stream.rpos.is_null() || stream.rpos <= unsafe { stream.buf.sub(stream.unget) } { + funlockfile(stream); + return -1; + } + + unsafe { + stream.rpos = stream.rpos.sub(1); + *stream.rpos = c as u8; + } + stream.flags &= !F_EOF; + + funlockfile(stream); + c + } } #[no_mangle] -pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int { - printf::printf(platform::FileWriter(file as c_int), format, ap) +pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int { + printf::printf(file, format, ap) } #[no_mangle] pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int { - vfprintf(stdout, format, ap) + vfprintf(&mut *stdout, format, ap) } #[no_mangle] @@ -331,12 +864,16 @@ pub unsafe extern "C" fn vsnprintf( format: *const c_char, ap: va_list, ) -> c_int { - printf::printf(platform::StringWriter(s as *mut u8, n as usize), format, ap) + printf::printf( + &mut platform::StringWriter(s as *mut u8, n as usize), + format, + ap, + ) } #[no_mangle] pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int { - printf::printf(platform::UnsafeStringWriter(s as *mut u8), format, ap) + printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap) } /* diff --git a/src/stdio/src/printf.rs b/src/stdio/src/printf.rs index 093ee82c122d6f902e00d8f9c05f2653dcdbc432..fee1c1156d60af5d615a08f828dbf22253af1c63 100644 --- a/src/stdio/src/printf.rs +++ b/src/stdio/src/printf.rs @@ -1,4 +1,4 @@ -use core::{fmt, mem, slice, str}; +use core::{fmt, slice, str}; use platform::types::*; use vl::VaList; diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index 97f5d44187b6fc477f3bb8ece793d9fd6d56fddd..cc96a5dc070fbb56e8961f4b62c2a339c27a3d88 100644 --- a/src/stdlib/Cargo.toml +++ b/src/stdlib/Cargo.toml @@ -12,3 +12,4 @@ platform = { path = "../platform" } ralloc = { path = "../../ralloc", default-features = false } ctype = { path = "../ctype" } errno = { path = "../errno" } +rand = { git = "https://github.com/rust-lang-nursery/rand/", default-features = false } diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index 575f759a264f4eb6624c2577be08145114bbac14..9c948d6779a381db7afdb911fa20aad476e1f982 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -8,8 +8,10 @@ extern crate ctype; extern crate errno; extern crate platform; extern crate ralloc; +extern crate rand; use core::{ptr, str}; +use rand::{Rng, SeedableRng, XorShiftRng}; use errno::*; use platform::types::*; @@ -19,8 +21,10 @@ static ALLOCATOR: ralloc::Allocator = ralloc::Allocator; pub const EXIT_FAILURE: c_int = 1; pub const EXIT_SUCCESS: c_int = 0; +pub const RAND_MAX: c_int = 2147483647; static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32]; +static mut RNG: Option<XorShiftRng> = None; #[no_mangle] pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long { @@ -375,8 +379,16 @@ pub extern "C" fn qsort( } #[no_mangle] -pub extern "C" fn rand() -> c_int { - unimplemented!(); +pub unsafe extern "C" fn rand() -> c_int { + match RNG { + Some(ref mut rng) => rng.gen_range::<c_int>(0, RAND_MAX), + None => { + let mut rng = XorShiftRng::from_seed([1; 16]); + let ret = rng.gen_range::<c_int>(0, RAND_MAX); + RNG = Some(rng); + ret + } + } } #[no_mangle] @@ -425,8 +437,8 @@ pub extern "C" fn setstate(state: *const c_char) -> *mut c_char { } #[no_mangle] -pub extern "C" fn srand(seed: c_uint) { - unimplemented!(); +pub unsafe extern "C" fn srand(seed: c_uint) { + RNG = Some(XorShiftRng::from_seed([seed as u8; 16])); } #[no_mangle] diff --git a/src/time/cbindgen.toml b/src/time/cbindgen.toml index ef3a5240e6d6dd30ae2b1b7421ecc5f4783a7f8f..40448b8f899a567c7c044c9f5705a89d65e7a8e8 100644 --- a/src/time/cbindgen.toml +++ b/src/time/cbindgen.toml @@ -4,3 +4,7 @@ language = "C" [enum] prefix_with_name = true + +[defines] +"target_os = linux" = "__linux__" +"target_os = redox" = "__redox__" diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs index 5b90e86f7482758341965c01524964cb4af57da7..5835d7014b7e01ae01e4ab067b27eff14a060c97 100644 --- a/src/time/src/lib.rs +++ b/src/time/src/lib.rs @@ -6,6 +6,33 @@ extern crate platform; use platform::types::*; +#[cfg(target_os = "redox")] +pub const CLOCK_REALTIME: c_int = 1; +#[cfg(target_os = "redox")] +pub const CLOCK_MONOTONIC: c_int = 4; +#[cfg(target_os = "linux")] +pub const CLOCK_REALTIME: c_int = 0; +#[cfg(target_os = "linux")] +pub const CLOCK_MONOTONIC: c_int = 1; +#[cfg(target_os = "linux")] +pub const CLOCK_PROCESS_CPUTIME_ID: c_int = 2; +#[cfg(target_os = "linux")] +pub const CLOCK_THREAD_CPUTIME_ID: c_int = 3; +#[cfg(target_os = "linux")] +pub const CLOCK_MONOTONIC_RAW: c_int = 4; +#[cfg(target_os = "linux")] +pub const CLOCK_REALTIME_COARSE: c_int = 5; +#[cfg(target_os = "linux")] +pub const CLOCK_MONOTONIC_COARSE: c_int = 6; +#[cfg(target_os = "linux")] +pub const CLOCK_BOOTTIME: c_int = 7; +#[cfg(target_os = "linux")] +pub const CLOCK_REALTIME_ALARM: c_int = 8; +#[cfg(target_os = "linux")] +pub const CLOCK_BOOTTIME_ALARM: c_int = 9; +#[cfg(target_os = "linux")] +pub const CLOCK_TAI: c_int = 11; + /* *#[repr(C)] *pub struct timespec { @@ -59,7 +86,7 @@ pub extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int #[no_mangle] pub extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int { - unimplemented!(); + platform::clock_gettime(clock_id, tp) } #[no_mangle] @@ -134,7 +161,14 @@ pub extern "C" fn strptime(buf: *const c_char, format: *const c_char, tm: *mut t #[no_mangle] pub extern "C" fn time(tloc: *mut time_t) -> time_t { - unimplemented!(); + let mut ts: timespec = Default::default(); + platform::clock_gettime(CLOCK_REALTIME, &mut ts); + unsafe { + if !tloc.is_null() { + *tloc = ts.tv_sec + }; + } + ts.tv_sec } #[no_mangle] diff --git a/src/unistd/Cargo.toml b/src/unistd/Cargo.toml index 3edd54a814220a16f00bbbe9093cbb4eb21ade0d..8de8a2b933f7dcab4ba2b819b12b6288c34666b3 100644 --- a/src/unistd/Cargo.toml +++ b/src/unistd/Cargo.toml @@ -9,3 +9,5 @@ cbindgen = { path = "../../cbindgen" } [dependencies] platform = { path = "../platform" } +stdio = { path = "../stdio" } +string = { path = "../string" } diff --git a/src/unistd/src/getopt.rs b/src/unistd/src/getopt.rs new file mode 100644 index 0000000000000000000000000000000000000000..c93a5487b94d3be9ca9e0522811ab028a6b316fb --- /dev/null +++ b/src/unistd/src/getopt.rs @@ -0,0 +1,149 @@ +//! getopt implementation for Redox, following http://pubs.opengroup.org/onlinepubs/009695399/functions/getopt.html + +use super::platform::types::*; +use super::platform; +use super::stdio; +use super::string; +use core::ptr; + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut optarg: *mut c_char = ptr::null_mut(); + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut optind: c_int = 1; + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut opterr: c_int = 1; + +#[allow(non_upper_case_globals)] +#[no_mangle] +pub static mut optopt: c_int = -1; + +static mut CURRENT_OPT: *mut c_char = ptr::null_mut(); + +#[no_mangle] +pub unsafe extern "C" fn getopt( + argc: c_int, + argv: *const *mut c_char, + optstring: *const c_char, +) -> c_int { + if CURRENT_OPT.is_null() || *CURRENT_OPT == 0 { + if optind >= argc { + -1 + } else { + let current_arg = *argv.offset(optind as isize); + if current_arg.is_null() || *current_arg != b'-' as c_char + || string::strcmp(current_arg, b"-\0".as_ptr() as _) == 0 + { + -1 + } else if string::strcmp(current_arg, b"--\0".as_ptr() as _) == 0 { + optind += 1; + -1 + } else { + // remove the '-' + let current_arg = current_arg.offset(1); + + parse_arg(argc, argv, current_arg, optstring) + } + } + } else { + parse_arg(argc, argv, CURRENT_OPT, optstring) + } +} + +unsafe fn parse_arg( + argc: c_int, + argv: *const *mut c_char, + current_arg: *mut c_char, + optstring: *const c_char, +) -> c_int { + let update_current_opt = || { + CURRENT_OPT = current_arg.offset(1); + if *CURRENT_OPT == 0 { + optind += 1; + } + }; + + let print_error = |desc: &[u8]| { + // NOTE: we don't use fprintf to get around the usage of va_list + stdio::fputs(*argv as _, &mut *stdio::stderr); + stdio::fputs(desc.as_ptr() as _, &mut *stdio::stderr); + stdio::fputc(*current_arg as _, &mut *stdio::stderr); + stdio::fputc(b'\n' as _, &mut *stdio::stderr); + }; + + match find_option(*current_arg, optstring) { + Some(GetoptOption::Flag) => { + update_current_opt(); + + *current_arg as c_int + } + Some(GetoptOption::OptArg) => { + CURRENT_OPT = b"\0".as_ptr() as _; + if *current_arg.offset(1) == 0 { + optind += 2; + if optind > argc { + CURRENT_OPT = ptr::null_mut(); + + optopt = *current_arg as c_int; + let errch = if *optstring == b':' as c_char { + b':' + } else { + if opterr != 0 { + print_error(b": option requries an argument -- \0"); + } + + b'?' + }; + errch as c_int + } else { + optarg = *argv.offset(optind as isize - 1); + + *current_arg as c_int + } + } else { + optarg = current_arg.offset(1); + optind += 1; + + *current_arg as c_int + } + } + None => { + // couldn't find the given option in optstring + if opterr != 0 { + print_error(b": illegal option -- \0"); + } + + update_current_opt(); + + optopt = *current_arg as _; + b'?' as c_int + } + } +} + +enum GetoptOption { + Flag, + OptArg, +} + +unsafe fn find_option(ch: c_char, optstring: *const c_char) -> Option<GetoptOption> { + let mut i = 0; + + while *optstring.offset(i) != 0 { + if *optstring.offset(i) == ch { + let result = if *optstring.offset(i + 1) == b':' as c_char { + GetoptOption::OptArg + } else { + GetoptOption::Flag + }; + return Some(result); + } + i += 1; + } + + None +} diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs index 7915a7e1421b8b790bf5e8b9b8d3a53546e0ef9d..e5aa6bc92656f5305711da829ae6aaacc03426a1 100644 --- a/src/unistd/src/lib.rs +++ b/src/unistd/src/lib.rs @@ -3,10 +3,15 @@ #![no_std] extern crate platform; +extern crate stdio; +extern crate string; pub use platform::types::*; +pub use getopt::*; use core::ptr; +mod getopt; + pub const R_OK: c_int = 1; pub const W_OK: c_int = 2; pub const X_OK: c_int = 4; @@ -204,11 +209,6 @@ pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int { unimplemented!(); } -#[no_mangle] -pub extern "C" fn getopt(argc: c_int, argv: *const *mut c_char, opstring: *const c_char) -> c_int { - unimplemented!(); -} - #[no_mangle] pub extern "C" fn getpagesize() -> c_int { unimplemented!(); diff --git a/tests/.gitignore b/tests/.gitignore index ff5cc28a8c266c21d6c227ce6743e1c49267f02f..e946dbbed8ade741f96369f63043b428ed8e20ba 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -15,25 +15,36 @@ /fsync /ftruncate /getid +/getc_unget /link /math /mem -/setid -/sleep /pipe /printf /rmdir /setid +/setid +/sleep /sprintf +/stdlib/a64l /stdlib/bsearch +/stdlib/rand /stdlib/strtol /stdlib/a64l -/string/strncmp -/string/strcspn +/stdio/fwrite +/stdio/all +/stdio/freopen /string/strchr +/string/strcspn +/string/strncmp +/string/strpbrk /string/strrchr /string/strspn +/string/strstr +/string/strtok +/string/strtok_r +/unistd/getopt /unlink /waitpid /write - +/time diff --git a/tests/Makefile b/tests/Makefile index e1b95b1839e1a3d66a2333907fb0470059a5bf99..cd6117e6e0efaba0f1cd497161e83c5da7237db1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,6 +12,8 @@ EXPECT_BINS=\ fcntl \ fsync \ ftruncate \ + getid \ + getc_unget \ link \ math \ mem \ @@ -20,9 +22,13 @@ EXPECT_BINS=\ rmdir \ sleep \ sprintf \ + stdio/fwrite \ + stdio/all \ + stdio/freopen \ stdlib/bsearch \ stdlib/strtol \ stdlib/a64l \ + stdlib/rand \ string/strncmp \ string/strcspn \ string/strchr \ @@ -32,9 +38,11 @@ EXPECT_BINS=\ string/strpbrk \ string/strtok \ string/strtok_r \ + unistd/getopt \ unlink \ waitpid \ - write + write \ + time # Binaries that may generate varied output BINS=\ diff --git a/tests/expected/unistd/getopt.stderr b/tests/expected/unistd/getopt.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/unistd/getopt.stdout b/tests/expected/unistd/getopt.stdout new file mode 100644 index 0000000000000000000000000000000000000000..aba2d44d3f96b0bbb82a1412c44b20ab8680d624 --- /dev/null +++ b/tests/expected/unistd/getopt.stdout @@ -0,0 +1,42 @@ +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 1 +errflg: 0 +ifile: +ofile: arg +result: 0 +bflg: 0 +aflg: 0 +errflg: 0 +ifile: +ofile: +result: 0 diff --git a/tests/getc_unget.c b/tests/getc_unget.c new file mode 100644 index 0000000000000000000000000000000000000000..f8008534fb0c4718f961e58c3c4a9f2dd50539a8 --- /dev/null +++ b/tests/getc_unget.c @@ -0,0 +1,12 @@ +#include <stdio.h> + +int main(int argc, char ** argv) { + ungetc('h', stdin); + char c; + if ((c = getchar()) == 'h') { + printf("Worked!\n"); + return 0; + } + printf("failed :( %c\n", c); + return 0; +} diff --git a/tests/stdio/all.c b/tests/stdio/all.c new file mode 100644 index 0000000000000000000000000000000000000000..450829364ef1384a6636be504b8c89a55fbc7709 --- /dev/null +++ b/tests/stdio/all.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char ** argv) { + FILE *f = fopen("stdio/stdio.in", "r"); + printf("%c\n", fgetc(f)); + ungetc('H', f); + char *in = malloc(30); + printf("%s\n", fgets(in, 30, f)); + return 0; +} diff --git a/tests/stdio/freopen.c b/tests/stdio/freopen.c new file mode 100644 index 0000000000000000000000000000000000000000..7bf3b64f20c3fcdfe351b9465c60eae7692d9a9a --- /dev/null +++ b/tests/stdio/freopen.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main(int argc, char ** argv) { + freopen("stdio/stdio.in", "r", stdin); + char in[6]; + fgets(in, 6, stdin); + printf("%s\n", in); // should print Hello + return 0; +} diff --git a/tests/stdio/fwrite.c b/tests/stdio/fwrite.c new file mode 100644 index 0000000000000000000000000000000000000000..da172d5b58d643ecdb8cdfe22d0151dff848375d --- /dev/null +++ b/tests/stdio/fwrite.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +int main(int argc, char ** argv) { + FILE *f = fopen("stdio/fwrite.out", "w"); + char *in = "Hello World!"; + fputs(in, f); // calls fwrite, helpers::fwritex, internal::to_write and internal::stdio_write + fclose(f); + return 0; +} diff --git a/tests/stdio/fwrite.out b/tests/stdio/fwrite.out new file mode 100644 index 0000000000000000000000000000000000000000..c57eff55ebc0c54973903af5f72bac72762cf4f4 --- /dev/null +++ b/tests/stdio/fwrite.out @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/tests/stdio/stdio.in b/tests/stdio/stdio.in new file mode 100644 index 0000000000000000000000000000000000000000..c50d87bb17331bbf91d4b38a48453dc1aee539f1 --- /dev/null +++ b/tests/stdio/stdio.in @@ -0,0 +1,3 @@ +Hello World! + +Line 2 diff --git a/tests/stdlib/rand.c b/tests/stdlib/rand.c new file mode 100644 index 0000000000000000000000000000000000000000..484b09906b4d3555280ef0a1b7b92fc41fb0b3a8 --- /dev/null +++ b/tests/stdlib/rand.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char** argv) { + printf("%d\n", rand()); + srand(259); + printf("%d\n", rand()); +} diff --git a/tests/time.c b/tests/time.c new file mode 100644 index 0000000000000000000000000000000000000000..e6ce164c2585ff7ebfbade6412bb90e057d638c9 --- /dev/null +++ b/tests/time.c @@ -0,0 +1,11 @@ +#include <time.h> +#include <stdio.h> + +int main(int argc, char** argv) { + timespec tm = {0, 0}; + clock_gettime(CLOCK_REALTIME, &tm); + perror("clock_gettime"); + time(NULL); + perror("time"); + return 0; +} diff --git a/tests/unistd/getopt.c b/tests/unistd/getopt.c new file mode 100644 index 0000000000000000000000000000000000000000..b1eb262556ab9ab09f1377ce99fda9e9d5ee6246 --- /dev/null +++ b/tests/unistd/getopt.c @@ -0,0 +1,69 @@ +#include <unistd.h> +#include <stdio.h> + +#define RUN(...) \ + { \ + optind = 1; \ + optarg = NULL; \ + opterr = 1; \ + optopt = -1; \ + char *args_arr[] = { __VA_ARGS__ }; \ + printf("result: %d\n", runner(sizeof(args_arr) / sizeof(args_arr[0]), args_arr)); \ + } + +int runner(int argc, char *argv[]) { + int c; + int bflg = 0, aflg = 0, errflg = 0; + char *ifile = ""; + char *ofile = ""; + + while((c = getopt(argc, argv, ":abf:o:")) != -1) { + switch(c) { + case 'a': + if(bflg) + errflg++; + else + aflg++; + break; + case 'b': + if(aflg) + errflg++; + else + bflg++; + break; + case 'f': + ifile = optarg; + break; + case 'o': + ofile = optarg; + break; + case ':': + printf("Option -%c requires an operand\n", optopt); + errflg++; + break; + case '?': + printf("Unrecognized option: -%c\n", optopt); + errflg++; + } + } + printf("bflg: %d\n", bflg); + printf("aflg: %d\n", aflg); + printf("errflg: %d\n", errflg); + printf("ifile: %s\n", ifile); + printf("ofile: %s\n", ofile); + if(errflg) { + printf("Usage: info goes here\n"); + return 2; + } + return 0; +} + +int main(int argc, const char *argv[]) { + RUN("test", "-ao", "arg", "path", "path"); + RUN("test", "-a", "-o", "arg", "path", "path"); + RUN("test", "-o", "arg", "-a", "path", "path"); + RUN("test", "-a", "-o", "arg", "--", "path", "path"); + RUN("test", "-a", "-oarg", "path", "path"); + RUN("test", "-aoarg", "path", "path"); + RUN("test"); +}