From aa8b14e10797d732f2170b2704c7f5270d42f2ca Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:21:02 +0800 Subject: [PATCH 01/27] Added some constants in linux for file modes --- src/fcntl/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fcntl/src/lib.rs b/src/fcntl/src/lib.rs index 0e5048277a..dc29bb99b4 100644 --- a/src/fcntl/src/lib.rs +++ b/src/fcntl/src/lib.rs @@ -18,6 +18,12 @@ pub const O_CREAT: c_int = 0x0040; pub const O_TRUNC: c_int = 0x0200; #[cfg(target_os = "linux")] pub const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR; +#[cfg(target_os = "linux")] +pub const O_APPEND: c_int = 0o2000; +#[cfg(target_os = "linux")] +pub const O_CLOEXEC: c_int = 0o2_000_000; +#[cfg(target_os = "linux")] +pub const O_EXCL: c_int = 0o200; #[cfg(target_os = "redox")] pub const O_RDONLY: c_int = 0x0001_0000; From f20878c5922972f50e17811354b71603826f120b Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:21:52 +0800 Subject: [PATCH 02/27] Added lseek to syscalls --- src/platform/src/linux/mod.rs | 4 ++++ src/platform/src/redox/mod.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 8915e6fea7..6868ac3af2 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -119,6 +119,10 @@ 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 mkdir(path: *const c_char, mode: mode_t) -> c_int { e(unsafe { syscall!(MKDIRAT, AT_FDCWD, path, mode) }) as c_int } diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index e663a1b2da..869e52b42e 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -125,6 +125,10 @@ pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { e(unsafe { syscall::link(path1.as_ptr(), path2.as_ptr()) }) as c_int } +pub fn lseek(fd: c_int, offset: isize, whence: usize) -> c_int { + e(syscall::lseek(fd as usize, offset, whence)) as c_int +} + 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; let path = unsafe { c_str(path) }; From e73678d8adb134b93064ceb81ac887815d6d093d Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:22:18 +0800 Subject: [PATCH 03/27] Added a FileReader struct --- src/platform/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index 5f57298db7..a9b6d25c46 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -57,8 +57,8 @@ pub unsafe fn c_str_n(s: *const c_char, n: usize) -> &'static [u8] { 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) } } @@ -69,6 +69,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 { From 046ce1468ef803b0ccbb796431528da7281344ad Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:23:38 +0800 Subject: [PATCH 04/27] Removed an unused import from printf --- src/stdio/src/printf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdio/src/printf.rs b/src/stdio/src/printf.rs index 093ee82c12..fee1c1156d 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; From 7f2b720962f9fbabdfda651af4fa59c914021f20 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:27:07 +0800 Subject: [PATCH 05/27] Implemented stdio functions --- src/stdio/Cargo.toml | 4 + src/stdio/src/constants.rs | 27 ++ src/stdio/src/default.rs | 85 ++++++ src/stdio/src/helpers.rs | 159 ++++++++++ src/stdio/src/internal.rs | 143 +++++++++ src/stdio/src/lib.rs | 596 +++++++++++++++++++++++++++++-------- 6 files changed, 898 insertions(+), 116 deletions(-) create mode 100644 src/stdio/src/constants.rs create mode 100644 src/stdio/src/default.rs create mode 100644 src/stdio/src/helpers.rs create mode 100644 src/stdio/src/internal.rs diff --git a/src/stdio/Cargo.toml b/src/stdio/Cargo.toml index 2f53e58dc7..1a920812a6 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/src/constants.rs b/src/stdio/src/constants.rs new file mode 100644 index 0000000000..c601cbc85e --- /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 0000000000..b3c1d71f67 --- /dev/null +++ b/src/stdio/src/default.rs @@ -0,0 +1,85 @@ +use core::sync::atomic::AtomicBool; +use core::ptr; +use super::{internal, BUFSIZ, FILE, UNGET, constants}; + +#[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), + write: None, + read: Some(&internal::stdio_read), + seek: None, +}; + +#[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), + write: Some(&internal::stdio_write), + read: None, + seek: None, +}; + +#[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), + write: Some(&internal::stdio_write), + read: None, + seek: None, +}; + +// 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 0000000000..4bc84ac375 --- /dev/null +++ b/src/stdio/src/helpers.rs @@ -0,0 +1,159 @@ +use super::{internal, BUFSIZ, FILE, UNGET}; +use compiler_builtins::mem::memset; +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::() + 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::() + UNGET), + buf_size: BUFSIZ, + buf_char: -1, + unget: UNGET, + lock: AtomicBool::new(false), + write: Some(&internal::stdio_write), + read: Some(&internal::stdio_read), + seek: Some(&internal::stdio_seek), + }; + file +} + +/// Write buffer `buf` of length `l` into `stream` +pub unsafe fn fwritex(buf: *const u8, l: size_t, stream: *mut FILE) -> size_t { + use compiler_builtins::mem::memcpy; + let mut buf = buf; + let mut l = l; + if let Some(stream_write) = (*stream).write { + if (*stream).wend.is_null() && !internal::to_write(stream) { + // 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)(stream, buf, l); + } + + let i = if (*stream).buf_char >= 0 { + let mut i = l; + while i > 0 && *buf.offset(i as isize - 1) != b'\n' { + i -= 1; + } + if i > 0 { + let n = (*stream_write)(stream, buf, i); + if n < i { + return n; + } + buf = buf.add(i); + l -= i; + } + i + } else { + 0 + }; + + memcpy((*stream).wpos, buf, l); + (*stream).wpos = (*stream).wpos.add(l); + l + i + } else { + // We can't write to this stream + 0 + } +} + +/// Flush `stream` without locking it. +pub unsafe fn fflush_unlocked(stream: *mut FILE) -> c_int { + if (*stream).wpos > (*stream).wbase { + if let Some(f) = (*stream).write { + (*f)(stream, ptr::null(), 0); + if (*stream).wpos.is_null() { + return -1; + } + } else { + return -1; + } + } + + if (*stream).rpos < (*stream).rend { + if let Some(s) = (*stream).seek { + (*s)( + stream, + (*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 0000000000..5330eb269d --- /dev/null +++ b/src/stdio/src/internal.rs @@ -0,0 +1,143 @@ +use super::{FILE, constants}; +use platform; +use platform::types::*; +use core::{mem, ptr, slice}; + +pub fn stdio_read(stream: *mut FILE, buf: *mut u8, size: usize) -> usize { + unsafe { + let mut buff = slice::from_raw_parts_mut(buf, size - !((*stream).buf_size == 0) as usize); + let mut file_buf = slice::from_raw_parts_mut((*stream).buf, (*stream).buf_size); + let mut file = platform::FileReader((*stream).fd); + let count = if buff.len() == 0 { + file.read(&mut file_buf) + } else { + file.read(&mut buff) + file.read(&mut file_buf) + }; + mem::forget(buff); + mem::forget(file_buf); + if count <= 0 { + (*stream).flags |= if count == 0 { constants::F_EOF } else { constants::F_ERR }; + return 0; + } + if count as usize <= size { + return count as usize; + } + (*stream).rpos = (*stream).buf; + (*stream).rend = (*stream).buf.offset(count); + *buf.offset(size as isize - 1) = *(*stream).rpos; + (*stream).rpos = (*stream).rpos.add(1); + } + size +} + +pub fn stdio_write(stream: *mut FILE, buf: *const u8, size: usize) -> usize { + unsafe { + let len = (*stream).wpos as usize - (*stream).wbase as usize; + let mut advance = 0; + let mut f_buf = slice::from_raw_parts((*stream).wbase, len); + let mut buff = slice::from_raw_parts(buf, size); + let mut f_filled = false; + let mut rem = f_buf.len() + buff.len(); + let mut file = platform::FileWriter((*stream).fd); + loop { + let mut count = if f_filled { + file.write(&f_buf[advance..]) + } else { + file.write(&f_buf[advance..]) + file.write(buff) + }; + if count == rem as isize { + (*stream).wend = (*stream).buf.add((*stream).buf_size -1); + (*stream).wpos = (*stream).buf; + (*stream).wbase = (*stream).buf; + return size; + } + if count < 0 { + (*stream).wpos = ptr::null_mut(); + (*stream).wbase = ptr::null_mut(); + (*stream).wend = ptr::null_mut(); + (*stream).flags |= constants::F_ERR; + return 0; + } + rem -= count as usize; + if count as usize > len { + count -= len as isize; + f_buf = buff; + f_filled = true; + advance = 0; + } + advance += count as usize; + } + } +} + +pub unsafe fn to_read(stream: *mut FILE) -> bool { + if (*stream).flags & constants::F_BADJ > 0 { + // Static and needs unget region + (*stream).buf = (*stream).buf.add((*stream).unget); + (*stream).flags &= !constants::F_BADJ; + } + + if (*stream).wpos > (*stream).wbase { + if let Some(f) = (*stream).write { + (*f)(stream, ptr::null(), 0); + } + } + (*stream).wpos = ptr::null_mut(); + (*stream).wbase = ptr::null_mut(); + (*stream).wend = ptr::null_mut(); + if (*stream).flags & constants::F_NORD > 0 { + (*stream).flags |= constants::F_ERR; + return true; + } + (*stream).rpos = (*stream).buf.offset((*stream).buf_size as isize -1); + (*stream).rend = (*stream).buf.offset((*stream).buf_size as isize -1); + if (*stream).flags & constants::F_EOF > 0 { + true + } else { + false + } +} + +pub unsafe fn to_write(stream: *mut FILE) -> bool { + if (*stream).flags & constants::F_BADJ > 0 { + // Static and needs unget region + (*stream).buf = (*stream).buf.add((*stream).unget); + (*stream).flags &= !constants::F_BADJ; + } + + if (*stream).flags & constants::F_NOWR > 0 { + (*stream).flags &= constants::F_ERR; + return false; + } + (*stream).rpos = ptr::null_mut(); + (*stream).rend = ptr::null_mut(); + (*stream).wpos = (*stream).buf; + (*stream).wbase = (*stream).buf; + (*stream).wend = (*stream).buf.offset((*stream).buf_size as isize -1); + return true; +} + +pub unsafe fn ftello(stream: *mut FILE) -> off_t { + if let Some(s) = (*stream).seek { + let pos = (*s)( + stream, + 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) + } else { + -1 + } +} + +pub fn stdio_seek(stream: *mut FILE, off: off_t, whence: c_int) -> off_t { + unsafe { platform::lseek((*stream).fd, off, whence) } +} diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index e99351639b..e77b86eaa8 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -1,41 +1,64 @@ //! 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::ptr; use core::fmt::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; +mod default; +pub use default::*; -pub const FILENAME_MAX: c_int = 4096; +mod constants; +pub use constants::*; -pub type fpos_t = off_t; +mod helpers; -pub struct FILE; +mod internal; -#[allow(non_upper_case_globals)] +/// The structure of this struct is likely to change. +/// all of the _pos pointers are likely to change to isize offsets and its possible that the +/// function pointers will be removed +#[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, + write: Option<*const (Fn(*mut FILE, *const u8, usize) -> size_t)>, + read: Option<*const (Fn(*mut FILE, *mut u8, usize) -> size_t)>, + seek: Option<*const (Fn(*mut FILE, off_t, c_int) -> off_t)>, +} + +/// Clears EOF and ERR indicators on a stream #[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; - -#[no_mangle] -pub extern "C" fn clearerr(stream: *mut FILE) { - unimplemented!(); +pub unsafe extern "C" fn clearerr(stream: *mut FILE) { + (*stream).flags &= !(F_EOF & F_ERR); } #[no_mangle] @@ -48,88 +71,244 @@ 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 unsafe 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 + free(stream 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!(); +pub unsafe extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE { + helpers::_fdopen(fildes, mode) } +/// Check for EOF #[no_mangle] -pub extern "C" fn feof(stream: *mut FILE) -> c_int { - unimplemented!(); +pub unsafe 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 unsafe 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!(); -} - -#[no_mangle] -pub extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fileno(stream: *mut FILE) -> c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn flockfile(file: *mut FILE) { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE { - unimplemented!(); -} - -#[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 unsafe 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 unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int { + let off = internal::ftello(stream); + if off < 0 { + return -1; + } + (*pos) = off; + 0 +} + +/// Get a string from the stream +#[no_mangle] +pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char { + use string::memchr; + use compiler_builtins::mem::memcpy; + 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(); + } + (*s) = b'\0' as i8; + return s; + } + while n > 0 { + let z = 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 }; + memcpy(ptr, (*stream).rpos, k); + (*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; + *ptr = c as u8; + ptr = ptr.add(1); + if c as u8 == b'\n' { + break; + } + } + if !s.is_null() { + *ptr = 0; + } + funlockfile(stream); + s +} + +/// Get the underlying file descriptor +#[no_mangle] +pub unsafe 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 unsafe extern "C" fn flockfile(file: *mut FILE) { + while ftrylockfile(file) != 0 {} +} + +/// Open the file in mode `mode` +#[no_mangle] +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 unsafe 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 { 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 + (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 { - unimplemented!(); +pub unsafe extern "C" fn fread( + ptr: *mut c_void, + size: usize, + nitems: usize, + stream: *mut FILE, +) -> usize { + use compiler_builtins::mem::memcpy; + 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 }; + memcpy(dest, (*stream).rpos, k); + (*stream).rpos = (*stream).rpos.add(k); + dest = dest.add(k); + l -= k as isize; + } + + while l > 0 { + let k = if internal::to_read(stream) { + 0 + } else { + if let Some(f) = (*stream).read { + (*f)(stream, dest, l as usize) + } + else { + 0 + } + }; + + if k == 0 { + funlockfile(stream); + return (len - l as usize) / 2; + } + + l -= k as isize; + dest = dest.add(k); + } + + funlockfile(stream); + nitems } #[no_mangle] @@ -141,79 +320,169 @@ pub extern "C" fn freopen( unimplemented!(); } +/// 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 unsafe 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 unsafe 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 { + if let Some(f) = (*stream).write { + (*f)(stream, ptr::null(), 0); + if (*stream).wpos.is_null() { + return -1; + } + } + } + (*stream).wpos = ptr::null_mut(); + (*stream).wend = ptr::null_mut(); + (*stream).wbase = ptr::null_mut(); + if let Some(s) = (*stream).seek { + if (*s)(stream, off, whence) < 0 { + return -1; + } + } else { + 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 unsafe 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 unsafe 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 unsafe 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( +pub unsafe extern "C" fn fwrite( ptr: *const c_void, size: usize, nitems: usize, 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 unsafe 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(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 unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { + if (*stream).rpos < (*stream).rend { + let ret = *(*stream).rpos as c_int; + (*stream).rpos = (*stream).rpos.add(1); + ret + } else { + if let Some(read) = (*stream).read { + let mut c = 0u8; + if !internal::to_read(stream) && (*read)(stream, &mut c, 1) == 1 { + c as c_int + } else { + -1 + } + } 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(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, stdin) } +/// Get an integer from `stream` #[no_mangle] -pub extern "C" fn getw(stream: *mut FILE) -> c_int { - unimplemented!(); +pub unsafe 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] @@ -238,60 +507,134 @@ 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 unsafe 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, 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 unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int { + if c as i8 != (*stream).buf_char && (*stream).wpos < (*stream).wend { + *(*stream).wpos = c as u8; + (*stream).wpos = (*stream).wpos.add(1); + c + } else { + if let Some(write) = (*stream).write { + if (*stream).wend.is_null() && internal::to_write(stream) { + -1 + } else if c as i8 != (*stream).buf_char && (*stream).wpos < (*stream).wend { + *(*stream).wpos = c as u8; + (*stream).wpos = (*stream).wpos.add(1); + c + } else if (*write)(stream, &c as *const i32 as *const _, 1) != 1 { + -1 + } else { + c + } + } else { + -1 + } + } } +/// 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) } +/// 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, 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 unsafe 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 unsafe 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!(); + unsafe { + setvbuf( + stream, + buf, + if buf.is_null() { _IONBF } else { _IOFBF }, + BUFSIZ as usize, + ) + }; } +/// Reset `stream` to use buffer `buf` of size `size` #[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,14 +652,35 @@ 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 unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { + if c < 0 { + c + } else { + flockfile(stream); + if (*stream).rpos.is_null() { + internal::to_read(stream); + } + if (*stream).rpos.is_null() + || (*stream).rpos <= (*stream).buf.sub((*stream).unget) + { + funlockfile(stream); + return -1; + } + + (*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) + printf::printf(platform::FileWriter((*file).fd), format, ap) } #[no_mangle] From b0492eba842bfb9ccadc5cefccf75cd675f01bcd Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:28:14 +0800 Subject: [PATCH 06/27] Added some tests for stdio --- tests/.gitignore | 3 +++ tests/Makefile | 4 ++++ tests/getc_unget.c | 12 ++++++++++++ tests/stdio/all.c | 11 +++++++++++ tests/stdio/fwrite.c | 11 +++++++++++ tests/stdio/fwrite.out | 1 + tests/stdio/stdio.in | 3 +++ 7 files changed, 45 insertions(+) create mode 100644 tests/getc_unget.c create mode 100644 tests/stdio/all.c create mode 100644 tests/stdio/fwrite.c create mode 100644 tests/stdio/fwrite.out create mode 100644 tests/stdio/stdio.in diff --git a/tests/.gitignore b/tests/.gitignore index 6cfb8396be..10ba484ea8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -15,6 +15,7 @@ /fsync /ftruncate /getid +/getc_unget /link /math /mem @@ -27,6 +28,8 @@ /sprintf /stdlib/strtol /stdlib/a64l +/stdio/fwrite +/stdio/all /string/strncmp /string/strcspn /string/strchr diff --git a/tests/Makefile b/tests/Makefile index a252889605..43b5512399 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,6 +12,8 @@ EXPECT_BINS=\ fcntl \ fsync \ ftruncate \ + getid \ + getc_unget \ link \ math \ mem \ @@ -20,6 +22,8 @@ EXPECT_BINS=\ rmdir \ sleep \ sprintf \ + stdio/fwrite \ + stdio/all \ stdlib/strtol \ stdlib/a64l \ string/strncmp \ diff --git a/tests/getc_unget.c b/tests/getc_unget.c new file mode 100644 index 0000000000..f8008534fb --- /dev/null +++ b/tests/getc_unget.c @@ -0,0 +1,12 @@ +#include + +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 0000000000..450829364e --- /dev/null +++ b/tests/stdio/all.c @@ -0,0 +1,11 @@ +#include +#include + +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/fwrite.c b/tests/stdio/fwrite.c new file mode 100644 index 0000000000..da172d5b58 --- /dev/null +++ b/tests/stdio/fwrite.c @@ -0,0 +1,11 @@ +#include +#include +#include + +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 0000000000..c57eff55eb --- /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 0000000000..c50d87bb17 --- /dev/null +++ b/tests/stdio/stdio.in @@ -0,0 +1,3 @@ +Hello World! + +Line 2 From c4c8b739032e6e1274f1f0b3dd3ce97b727e3e2f Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:34:39 +0800 Subject: [PATCH 07/27] Formatted stdio files --- src/stdio/src/default.rs | 2 +- src/stdio/src/helpers.rs | 2 +- src/stdio/src/internal.rs | 16 ++++++++++------ src/stdio/src/lib.rs | 11 ++++------- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs index b3c1d71f67..8ba56533de 100644 --- a/src/stdio/src/default.rs +++ b/src/stdio/src/default.rs @@ -1,6 +1,6 @@ use core::sync::atomic::AtomicBool; use core::ptr; -use super::{internal, BUFSIZ, FILE, UNGET, constants}; +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]; diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs index 4bc84ac375..267d49da39 100644 --- a/src/stdio/src/helpers.rs +++ b/src/stdio/src/helpers.rs @@ -32,7 +32,7 @@ pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 { flags |= O_TRUNC; } if (*mode_str) != b'a' as i8 { - flags |= O_APPEND; + flags |= O_APPEND; } flags diff --git a/src/stdio/src/internal.rs b/src/stdio/src/internal.rs index 5330eb269d..00b6892404 100644 --- a/src/stdio/src/internal.rs +++ b/src/stdio/src/internal.rs @@ -1,4 +1,4 @@ -use super::{FILE, constants}; +use super::{constants, FILE}; use platform; use platform::types::*; use core::{mem, ptr, slice}; @@ -16,7 +16,11 @@ pub fn stdio_read(stream: *mut FILE, buf: *mut u8, size: usize) -> usize { mem::forget(buff); mem::forget(file_buf); if count <= 0 { - (*stream).flags |= if count == 0 { constants::F_EOF } else { constants::F_ERR }; + (*stream).flags |= if count == 0 { + constants::F_EOF + } else { + constants::F_ERR + }; return 0; } if count as usize <= size { @@ -46,7 +50,7 @@ pub fn stdio_write(stream: *mut FILE, buf: *const u8, size: usize) -> usize { file.write(&f_buf[advance..]) + file.write(buff) }; if count == rem as isize { - (*stream).wend = (*stream).buf.add((*stream).buf_size -1); + (*stream).wend = (*stream).buf.add((*stream).buf_size - 1); (*stream).wpos = (*stream).buf; (*stream).wbase = (*stream).buf; return size; @@ -89,8 +93,8 @@ pub unsafe fn to_read(stream: *mut FILE) -> bool { (*stream).flags |= constants::F_ERR; return true; } - (*stream).rpos = (*stream).buf.offset((*stream).buf_size as isize -1); - (*stream).rend = (*stream).buf.offset((*stream).buf_size as isize -1); + (*stream).rpos = (*stream).buf.offset((*stream).buf_size as isize - 1); + (*stream).rend = (*stream).buf.offset((*stream).buf_size as isize - 1); if (*stream).flags & constants::F_EOF > 0 { true } else { @@ -113,7 +117,7 @@ pub unsafe fn to_write(stream: *mut FILE) -> bool { (*stream).rend = ptr::null_mut(); (*stream).wpos = (*stream).buf; (*stream).wbase = (*stream).buf; - (*stream).wend = (*stream).buf.offset((*stream).buf_size as isize -1); + (*stream).wend = (*stream).buf.offset((*stream).buf_size as isize - 1); return true; } diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index e77b86eaa8..0979a695d1 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -80,7 +80,7 @@ pub unsafe 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 { + if (*stream).flags & constants::F_PERM == 0 { // Not one of stdin, stdout or stderr free(stream as *mut _); } @@ -234,7 +234,7 @@ pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC); } - let f = helpers::_fdopen(fd, mode); + let f = helpers::_fdopen(fd, mode); if f.is_null() { platform::close(fd); return ptr::null_mut(); @@ -292,8 +292,7 @@ pub unsafe extern "C" fn fread( } else { if let Some(f) = (*stream).read { (*f)(stream, dest, l as usize) - } - else { + } else { 0 } }; @@ -662,9 +661,7 @@ pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { if (*stream).rpos.is_null() { internal::to_read(stream); } - if (*stream).rpos.is_null() - || (*stream).rpos <= (*stream).buf.sub((*stream).unget) - { + if (*stream).rpos.is_null() || (*stream).rpos <= (*stream).buf.sub((*stream).unget) { funlockfile(stream); return -1; } From 41b96fede3c869491412d6efbe748080b1017650 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 15 Mar 2018 15:57:19 +0800 Subject: [PATCH 08/27] Added a different internal function for redox --- src/stdio/src/internal.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/stdio/src/internal.rs b/src/stdio/src/internal.rs index 00b6892404..f9ef756f64 100644 --- a/src/stdio/src/internal.rs +++ b/src/stdio/src/internal.rs @@ -142,6 +142,12 @@ pub unsafe fn ftello(stream: *mut FILE) -> off_t { } } +#[cfg(target_os = "linux")] pub fn stdio_seek(stream: *mut FILE, off: off_t, whence: c_int) -> off_t { unsafe { platform::lseek((*stream).fd, off, whence) } } + +#[cfg(target_os = "redox")] +pub fn stdio_seek(stream: *mut FILE, off: off_t, whence: c_int) -> off_t { + unsafe { platform::lseek((*stream).fd, off as isize, whence as usize) as off_t } +} From 8d4042402077687d5b5c60decc33897a29053322 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Fri, 16 Mar 2018 20:24:40 +0800 Subject: [PATCH 09/27] Added freopen() and relevant tests --- src/stdio/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++-- tests/.gitignore | 1 + tests/Makefile | 1 + tests/stdio/freopen.c | 9 +++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/stdio/freopen.c diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index 0979a695d1..4748fdfb38 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -311,12 +311,48 @@ pub unsafe extern "C" fn fread( } #[no_mangle] -pub extern "C" fn freopen( +pub unsafe extern "C" fn freopen( filename: *const c_char, mode: *const c_char, stream: *mut FILE, ) -> *mut FILE { - unimplemented!(); + let mut flags = 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 = fopen(filename, mode); + if new.is_null() { + funlockfile(stream); + fclose(stream); + return ptr::null_mut(); + } + 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; + (*stream).read = (*new).read; + (*stream).write = (*new).write; + (*stream).seek = (*new).seek; + fclose(new); + } + funlockfile(stream); + stream } /// Seek to an offset `offset` from `whence` diff --git a/tests/.gitignore b/tests/.gitignore index 10ba484ea8..64317b6cbe 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ /stdlib/a64l /stdio/fwrite /stdio/all +/stdio/freopen /string/strncmp /string/strcspn /string/strchr diff --git a/tests/Makefile b/tests/Makefile index f5e47bb4e4..92e3f70f46 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -24,6 +24,7 @@ EXPECT_BINS=\ sprintf \ stdio/fwrite \ stdio/all \ + stdio/freopen \ stdlib/strtol \ stdlib/a64l \ string/strncmp \ diff --git a/tests/stdio/freopen.c b/tests/stdio/freopen.c new file mode 100644 index 0000000000..7bf3b64f20 --- /dev/null +++ b/tests/stdio/freopen.c @@ -0,0 +1,9 @@ +#include + +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; +} From 81d96c214a9cc9ce9af7f48558db635db53a6062 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Fri, 16 Mar 2018 20:47:32 +0800 Subject: [PATCH 10/27] Ran formatting for freopen() --- src/stdio/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index 4748fdfb38..8c291ca281 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -320,7 +320,8 @@ pub unsafe extern "C" fn freopen( flockfile(stream); helpers::fflush_unlocked(stream); - if filename.is_null() { // Reopen stream in new mode + 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); } @@ -339,7 +340,9 @@ pub unsafe extern "C" fn freopen( } 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 { + } 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); From 659d3d10428c4bd6d5f6c4ffaa298a77e2f37ce1 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Fri, 16 Mar 2018 23:14:43 +0800 Subject: [PATCH 11/27] Changed object type of function pointers from Option<*const (Fn(...))> to Option for readability --- src/stdio/src/default.rs | 6 +++--- src/stdio/src/helpers.rs | 14 +++++++------- src/stdio/src/internal.rs | 4 ++-- src/stdio/src/lib.rs | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs index 8ba56533de..efeb05c9a4 100644 --- a/src/stdio/src/default.rs +++ b/src/stdio/src/default.rs @@ -20,7 +20,7 @@ static mut default_stdin: FILE = FILE { unget: UNGET, lock: AtomicBool::new(false), write: None, - read: Some(&internal::stdio_read), + read: Some(internal::stdio_read), seek: None, }; @@ -41,7 +41,7 @@ static mut default_stdout: FILE = FILE { buf_char: b'\n' as i8, unget: 0, lock: AtomicBool::new(false), - write: Some(&internal::stdio_write), + write: Some(internal::stdio_write), read: None, seek: None, }; @@ -63,7 +63,7 @@ static mut default_stderr: FILE = FILE { buf_char: -1, unget: 0, lock: AtomicBool::new(false), - write: Some(&internal::stdio_write), + write: Some(internal::stdio_write), read: None, seek: None, }; diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs index 267d49da39..5342490269 100644 --- a/src/stdio/src/helpers.rs +++ b/src/stdio/src/helpers.rs @@ -78,9 +78,9 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> *mut FILE { buf_char: -1, unget: UNGET, lock: AtomicBool::new(false), - write: Some(&internal::stdio_write), - read: Some(&internal::stdio_read), - seek: Some(&internal::stdio_seek), + write: Some(internal::stdio_write), + read: Some(internal::stdio_read), + seek: Some(internal::stdio_seek), }; file } @@ -97,7 +97,7 @@ pub unsafe fn fwritex(buf: *const u8, l: size_t, stream: *mut FILE) -> size_t { } if l > (*stream).wend as usize - (*stream).wpos as usize { // We can't fit all of buf in the buffer - return (*stream_write)(stream, buf, l); + return stream_write(stream, buf, l); } let i = if (*stream).buf_char >= 0 { @@ -106,7 +106,7 @@ pub unsafe fn fwritex(buf: *const u8, l: size_t, stream: *mut FILE) -> size_t { i -= 1; } if i > 0 { - let n = (*stream_write)(stream, buf, i); + let n = stream_write(stream, buf, i); if n < i { return n; } @@ -131,7 +131,7 @@ pub unsafe fn fwritex(buf: *const u8, l: size_t, stream: *mut FILE) -> size_t { pub unsafe fn fflush_unlocked(stream: *mut FILE) -> c_int { if (*stream).wpos > (*stream).wbase { if let Some(f) = (*stream).write { - (*f)(stream, ptr::null(), 0); + f(stream, ptr::null(), 0); if (*stream).wpos.is_null() { return -1; } @@ -142,7 +142,7 @@ pub unsafe fn fflush_unlocked(stream: *mut FILE) -> c_int { if (*stream).rpos < (*stream).rend { if let Some(s) = (*stream).seek { - (*s)( + s( stream, (*stream).rpos as i64 - (*stream).rend as i64, SEEK_CUR, diff --git a/src/stdio/src/internal.rs b/src/stdio/src/internal.rs index f9ef756f64..99005e87a6 100644 --- a/src/stdio/src/internal.rs +++ b/src/stdio/src/internal.rs @@ -83,7 +83,7 @@ pub unsafe fn to_read(stream: *mut FILE) -> bool { if (*stream).wpos > (*stream).wbase { if let Some(f) = (*stream).write { - (*f)(stream, ptr::null(), 0); + f(stream, ptr::null(), 0); } } (*stream).wpos = ptr::null_mut(); @@ -123,7 +123,7 @@ pub unsafe fn to_write(stream: *mut FILE) -> bool { pub unsafe fn ftello(stream: *mut FILE) -> off_t { if let Some(s) = (*stream).seek { - let pos = (*s)( + let pos = s( stream, 0, if ((*stream).flags & constants::F_APP > 0) && (*stream).wpos > (*stream).wbase { diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index 8c291ca281..df5e9b6db3 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -50,9 +50,9 @@ pub struct FILE { buf_char: i8, lock: AtomicBool, unget: size_t, - write: Option<*const (Fn(*mut FILE, *const u8, usize) -> size_t)>, - read: Option<*const (Fn(*mut FILE, *mut u8, usize) -> size_t)>, - seek: Option<*const (Fn(*mut FILE, off_t, c_int) -> off_t)>, + write: Option<(fn(*mut FILE, *const u8, usize) -> size_t)>, + read: Option<(fn(*mut FILE, *mut u8, usize) -> size_t)>, + seek: Option<(fn(*mut FILE, off_t, c_int) -> off_t)>, } /// Clears EOF and ERR indicators on a stream @@ -291,7 +291,7 @@ pub unsafe extern "C" fn fread( 0 } else { if let Some(f) = (*stream).read { - (*f)(stream, dest, l as usize) + f(stream, dest, l as usize) } else { 0 } @@ -378,7 +378,7 @@ pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) } if (*stream).wpos > (*stream).wbase { if let Some(f) = (*stream).write { - (*f)(stream, ptr::null(), 0); + f(stream, ptr::null(), 0); if (*stream).wpos.is_null() { return -1; } @@ -388,7 +388,7 @@ pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) (*stream).wend = ptr::null_mut(); (*stream).wbase = ptr::null_mut(); if let Some(s) = (*stream).seek { - if (*s)(stream, off, whence) < 0 { + if s(stream, off, whence) < 0 { return -1; } } else { @@ -481,7 +481,7 @@ pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { } else { if let Some(read) = (*stream).read { let mut c = 0u8; - if !internal::to_read(stream) && (*read)(stream, &mut c, 1) == 1 { + if !internal::to_read(stream) && read(stream, &mut c, 1) == 1 { c as c_int } else { -1 @@ -575,7 +575,7 @@ pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int { *(*stream).wpos = c as u8; (*stream).wpos = (*stream).wpos.add(1); c - } else if (*write)(stream, &c as *const i32 as *const _, 1) != 1 { + } else if write(stream, &c as *const i32 as *const _, 1) != 1 { -1 } else { c From 25501b364006f833a122bd0491d2406031758924 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Sun, 18 Mar 2018 00:18:14 +0800 Subject: [PATCH 12/27] Changed redox lseek to have the same function signature as the linux version --- src/platform/src/redox/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index 869e52b42e..0db7bfaac0 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -125,8 +125,12 @@ pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { e(unsafe { syscall::link(path1.as_ptr(), path2.as_ptr()) }) as c_int } -pub fn lseek(fd: c_int, offset: isize, whence: usize) -> c_int { - e(syscall::lseek(fd as usize, offset, whence)) 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 mkdir(path: *const c_char, mode: mode_t) -> c_int { From d7965f25983108e82ffb6ff5efe80da310f8fc13 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Sun, 18 Mar 2018 00:19:08 +0800 Subject: [PATCH 13/27] Made it so that AtomicBool exports as volatile char --- src/stdio/cbindgen.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/stdio/cbindgen.toml b/src/stdio/cbindgen.toml index 58483d52ac..3f13ef55cb 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" From c24d1e2b361eae5227d2294d98e45d0658374785 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Sun, 18 Mar 2018 00:20:21 +0800 Subject: [PATCH 14/27] Removed all function pointers in FILE, moved internal functions to be member functions of FILE, made relevant *mut FILEs into &mut FILE and made suitable functions safe again --- src/stdio/src/default.rs | 9 - src/stdio/src/helpers.rs | 108 ++++----- src/stdio/src/internal.rs | 156 +------------ src/stdio/src/lib.rs | 465 ++++++++++++++++++++++++-------------- 4 files changed, 360 insertions(+), 378 deletions(-) diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs index efeb05c9a4..840a6fa07f 100644 --- a/src/stdio/src/default.rs +++ b/src/stdio/src/default.rs @@ -19,9 +19,6 @@ static mut default_stdin: FILE = FILE { buf_char: -1, unget: UNGET, lock: AtomicBool::new(false), - write: None, - read: Some(internal::stdio_read), - seek: None, }; #[allow(non_upper_case_globals)] @@ -41,9 +38,6 @@ static mut default_stdout: FILE = FILE { buf_char: b'\n' as i8, unget: 0, lock: AtomicBool::new(false), - write: Some(internal::stdio_write), - read: None, - seek: None, }; #[allow(non_upper_case_globals)] @@ -63,9 +57,6 @@ static mut default_stderr: FILE = FILE { buf_char: -1, unget: 0, lock: AtomicBool::new(false), - write: Some(internal::stdio_write), - read: None, - seek: None, }; // Don't ask me how the casting below works, I have no idea diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs index 5342490269..378d2af3b6 100644 --- a/src/stdio/src/helpers.rs +++ b/src/stdio/src/helpers.rs @@ -1,5 +1,4 @@ use super::{internal, BUFSIZ, FILE, UNGET}; -use compiler_builtins::mem::memset; use stdlib::calloc; use core::{mem, ptr}; use core::sync::atomic::AtomicBool; @@ -78,82 +77,71 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> *mut FILE { buf_char: -1, unget: UNGET, lock: AtomicBool::new(false), - write: Some(internal::stdio_write), - read: Some(internal::stdio_read), - seek: Some(internal::stdio_seek), }; file } /// Write buffer `buf` of length `l` into `stream` -pub unsafe fn fwritex(buf: *const u8, l: size_t, stream: *mut FILE) -> size_t { - use compiler_builtins::mem::memcpy; - let mut buf = buf; +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; - if let Some(stream_write) = (*stream).write { - if (*stream).wend.is_null() && !internal::to_write(stream) { - // 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(stream, buf, l); - } + let mut advance = 0; - let i = if (*stream).buf_char >= 0 { - let mut i = l; - while i > 0 && *buf.offset(i as isize - 1) != b'\n' { - i -= 1; - } - if i > 0 { - let n = stream_write(stream, buf, i); - if n < i { - return n; - } - buf = buf.add(i); - l -= i; - } - i - } else { - 0 - }; - - memcpy((*stream).wpos, buf, l); - (*stream).wpos = (*stream).wpos.add(l); - l + i - } else { + if stream.wend.is_null() && !stream.can_write() { // We can't write to this stream - 0 + 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 unsafe fn fflush_unlocked(stream: *mut FILE) -> c_int { - if (*stream).wpos > (*stream).wbase { - if let Some(f) = (*stream).write { - f(stream, ptr::null(), 0); - if (*stream).wpos.is_null() { - return -1; - } - } else { +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 { - if let Some(s) = (*stream).seek { - s( - stream, - (*stream).rpos as i64 - (*stream).rend as i64, - SEEK_CUR, - ); - } + 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(); + 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 index 99005e87a6..35eb5f47e8 100644 --- a/src/stdio/src/internal.rs +++ b/src/stdio/src/internal.rs @@ -3,151 +3,17 @@ use platform; use platform::types::*; use core::{mem, ptr, slice}; -pub fn stdio_read(stream: *mut FILE, buf: *mut u8, size: usize) -> usize { - unsafe { - let mut buff = slice::from_raw_parts_mut(buf, size - !((*stream).buf_size == 0) as usize); - let mut file_buf = slice::from_raw_parts_mut((*stream).buf, (*stream).buf_size); - let mut file = platform::FileReader((*stream).fd); - let count = if buff.len() == 0 { - file.read(&mut file_buf) +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 { - file.read(&mut buff) + file.read(&mut file_buf) - }; - mem::forget(buff); - mem::forget(file_buf); - if count <= 0 { - (*stream).flags |= if count == 0 { - constants::F_EOF - } else { - constants::F_ERR - }; - return 0; - } - if count as usize <= size { - return count as usize; - } - (*stream).rpos = (*stream).buf; - (*stream).rend = (*stream).buf.offset(count); - *buf.offset(size as isize - 1) = *(*stream).rpos; - (*stream).rpos = (*stream).rpos.add(1); + constants::SEEK_CUR + }, + ); + if pos < 0 { + return pos; } - size -} - -pub fn stdio_write(stream: *mut FILE, buf: *const u8, size: usize) -> usize { - unsafe { - let len = (*stream).wpos as usize - (*stream).wbase as usize; - let mut advance = 0; - let mut f_buf = slice::from_raw_parts((*stream).wbase, len); - let mut buff = slice::from_raw_parts(buf, size); - let mut f_filled = false; - let mut rem = f_buf.len() + buff.len(); - let mut file = platform::FileWriter((*stream).fd); - loop { - let mut count = if f_filled { - file.write(&f_buf[advance..]) - } else { - file.write(&f_buf[advance..]) + file.write(buff) - }; - if count == rem as isize { - (*stream).wend = (*stream).buf.add((*stream).buf_size - 1); - (*stream).wpos = (*stream).buf; - (*stream).wbase = (*stream).buf; - return size; - } - if count < 0 { - (*stream).wpos = ptr::null_mut(); - (*stream).wbase = ptr::null_mut(); - (*stream).wend = ptr::null_mut(); - (*stream).flags |= constants::F_ERR; - return 0; - } - rem -= count as usize; - if count as usize > len { - count -= len as isize; - f_buf = buff; - f_filled = true; - advance = 0; - } - advance += count as usize; - } - } -} - -pub unsafe fn to_read(stream: *mut FILE) -> bool { - if (*stream).flags & constants::F_BADJ > 0 { - // Static and needs unget region - (*stream).buf = (*stream).buf.add((*stream).unget); - (*stream).flags &= !constants::F_BADJ; - } - - if (*stream).wpos > (*stream).wbase { - if let Some(f) = (*stream).write { - f(stream, ptr::null(), 0); - } - } - (*stream).wpos = ptr::null_mut(); - (*stream).wbase = ptr::null_mut(); - (*stream).wend = ptr::null_mut(); - if (*stream).flags & constants::F_NORD > 0 { - (*stream).flags |= constants::F_ERR; - return true; - } - (*stream).rpos = (*stream).buf.offset((*stream).buf_size as isize - 1); - (*stream).rend = (*stream).buf.offset((*stream).buf_size as isize - 1); - if (*stream).flags & constants::F_EOF > 0 { - true - } else { - false - } -} - -pub unsafe fn to_write(stream: *mut FILE) -> bool { - if (*stream).flags & constants::F_BADJ > 0 { - // Static and needs unget region - (*stream).buf = (*stream).buf.add((*stream).unget); - (*stream).flags &= !constants::F_BADJ; - } - - if (*stream).flags & constants::F_NOWR > 0 { - (*stream).flags &= constants::F_ERR; - return false; - } - (*stream).rpos = ptr::null_mut(); - (*stream).rend = ptr::null_mut(); - (*stream).wpos = (*stream).buf; - (*stream).wbase = (*stream).buf; - (*stream).wend = (*stream).buf.offset((*stream).buf_size as isize - 1); - return true; -} - -pub unsafe fn ftello(stream: *mut FILE) -> off_t { - if let Some(s) = (*stream).seek { - let pos = s( - stream, - 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) - } else { - -1 - } -} - -#[cfg(target_os = "linux")] -pub fn stdio_seek(stream: *mut FILE, off: off_t, whence: c_int) -> off_t { - unsafe { platform::lseek((*stream).fd, off, whence) } -} - -#[cfg(target_os = "redox")] -pub fn stdio_seek(stream: *mut FILE, off: off_t, whence: c_int) -> off_t { - unsafe { platform::lseek((*stream).fd, off as isize, whence as usize) as off_t } + 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 df5e9b6db3..fcae989865 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -13,7 +13,7 @@ extern crate va_list as vl; use core::str; use core::ptr; -use core::fmt::Write; +use core::fmt::{Error, Result, Write}; use core::sync::atomic::{AtomicBool, Ordering}; use platform::types::*; @@ -33,9 +33,6 @@ mod helpers; mod internal; -/// The structure of this struct is likely to change. -/// all of the _pos pointers are likely to change to isize offsets and its possible that the -/// function pointers will be removed #[repr(C)] pub struct FILE { flags: c_int, @@ -50,15 +47,140 @@ pub struct FILE { buf_char: i8, lock: AtomicBool, unget: size_t, - write: Option<(fn(*mut FILE, *const u8, usize) -> size_t)>, - read: Option<(fn(*mut FILE, *mut u8, usize) -> size_t)>, - seek: Option<(fn(*mut FILE, off_t, c_int) -> off_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 unsafe extern "C" fn clearerr(stream: *mut FILE) { - (*stream).flags &= !(F_EOF & F_ERR); +pub extern "C" fn clearerr(stream: &mut FILE) { + stream.flags &= !(F_EOF & F_ERR); } #[no_mangle] @@ -76,37 +198,39 @@ pub extern "C" fn cuserid(s: *mut c_char) -> *mut c_char { /// 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 unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int { +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 { + let r = helpers::fflush_unlocked(stream) | platform::close(stream.fd); + if stream.flags & constants::F_PERM == 0 { // Not one of stdin, stdout or stderr - free(stream as *mut _); + unsafe { + free(stream as *mut _ as *mut _); + } } r } /// Open a file from a file descriptor #[no_mangle] -pub unsafe extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE { - helpers::_fdopen(fildes, mode) +pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE { + unsafe { helpers::_fdopen(fildes, mode) } } /// Check for EOF #[no_mangle] -pub unsafe extern "C" fn feof(stream: *mut FILE) -> c_int { +pub extern "C" fn feof(stream: &mut FILE) -> c_int { flockfile(stream); - let ret = (*stream).flags & F_EOF; + let ret = stream.flags & F_EOF; funlockfile(stream); ret } /// Check for ERR #[no_mangle] -pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int { +pub extern "C" fn ferror(stream: &mut FILE) -> c_int { flockfile(stream); - let ret = (*stream).flags & F_ERR; + let ret = stream.flags & F_ERR; funlockfile(stream); ret } @@ -115,7 +239,7 @@ pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int { /// Ensure the file is unlocked before calling this function, as it will attempt to lock the file /// itself. #[no_mangle] -pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fflush(stream: &mut FILE) -> c_int { flockfile(stream); let ret = helpers::fflush_unlocked(stream); @@ -126,7 +250,7 @@ pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int { /// Get a single char from a stream #[no_mangle] -pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int { +pub extern "C" fn fgetc(stream: &mut FILE) -> c_int { flockfile(stream); let c = getc_unlocked(stream); funlockfile(stream); @@ -135,46 +259,58 @@ pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int { /// Get the position of the stream and store it in pos #[no_mangle] -pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int { +pub extern "C" fn fgetpos(stream: &mut FILE, pos: *mut fpos_t) -> c_int { let off = internal::ftello(stream); if off < 0 { return -1; } - (*pos) = off; + unsafe { + (*pos) = off; + } 0 } /// Get a string from the stream #[no_mangle] -pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char { +pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_char { use string::memchr; - use compiler_builtins::mem::memcpy; + 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(); } - (*s) = b'\0' as i8; + unsafe { + (*s) = b'\0' as i8; + } return s; } while n > 0 { - let z = memchr( - (*stream).rpos as *const c_void, - b'\n' as c_int, - (*stream).rend as usize - (*stream).rpos as usize, - ) as *mut u8; + 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 + stream.rend as usize - stream.rpos as usize } else { - z as usize - (*stream).rpos as usize + 1 + z as usize - stream.rpos as usize + 1 }; let k = if k as i32 > n { n as usize } else { k }; - memcpy(ptr, (*stream).rpos, k); - (*stream).rpos = (*stream).rpos.add(k); - ptr = ptr.add(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; @@ -184,14 +320,21 @@ pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> * break; } n -= 1; - *ptr = c as u8; - ptr = ptr.add(1); + + unsafe { + // Pointer stuff + *ptr = c as u8; + ptr = ptr.add(1); + } + if c as u8 == b'\n' { break; } } if !s.is_null() { - *ptr = 0; + unsafe { + *ptr = 0; + } } funlockfile(stream); s @@ -199,17 +342,17 @@ pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> * /// Get the underlying file descriptor #[no_mangle] -pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int { +pub extern "C" fn fileno(stream: &mut FILE) -> c_int { flockfile(stream); funlockfile(stream); - (*stream).fd + 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 unsafe extern "C" fn flockfile(file: *mut FILE) { +pub extern "C" fn flockfile(file: &mut FILE) { while ftrylockfile(file) != 0 {} } @@ -244,7 +387,7 @@ pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> /// Insert a character into the stream #[no_mangle] -pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int { +pub extern "C" fn fputc(c: c_int, stream: &mut FILE) -> c_int { flockfile(stream); let c = putc_unlocked(c, stream); funlockfile(stream); @@ -253,48 +396,44 @@ pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int { /// 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; } - let len = strlen(s); + 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 unsafe extern "C" fn fread( - ptr: *mut c_void, - size: usize, - nitems: usize, - stream: *mut FILE, -) -> usize { - use compiler_builtins::mem::memcpy; +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 { + 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 diff = stream.rend as usize - stream.rpos as usize; let k = if diff < l as usize { diff } else { l as usize }; - memcpy(dest, (*stream).rpos, k); - (*stream).rpos = (*stream).rpos.add(k); - dest = dest.add(k); + 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; } while l > 0 { - let k = if internal::to_read(stream) { + let k = if !stream.can_read() { 0 } else { - if let Some(f) = (*stream).read { - f(stream, dest, l as usize) - } else { - 0 - } + stream.read(unsafe { slice::from_raw_parts_mut(dest, l as usize) }) }; if k == 0 { @@ -303,7 +442,10 @@ pub unsafe extern "C" fn fread( } l -= k as isize; - dest = dest.add(k); + unsafe { + // Reposition + dest = dest.add(k); + } } funlockfile(stream); @@ -311,47 +453,45 @@ pub unsafe extern "C" fn fread( } #[no_mangle] -pub unsafe extern "C" fn freopen( +pub extern "C" fn freopen( filename: *const c_char, mode: *const c_char, - stream: *mut FILE, + stream: &mut FILE, ) -> *mut FILE { - let mut flags = helpers::parse_mode_flags(mode); + 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); + 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 { + if fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags) < 0 { funlockfile(stream); fclose(stream); return ptr::null_mut(); } } else { - let new = fopen(filename, mode); + let new = unsafe { fopen(filename, mode) }; if new.is_null() { funlockfile(stream); fclose(stream); return ptr::null_mut(); } - 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 + 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; - (*stream).read = (*new).read; - (*stream).write = (*new).write; - (*stream).seek = (*new).seek; + stream.flags = (stream.flags & constants::F_PERM) | new.flags; fclose(new); } funlockfile(stream); @@ -360,7 +500,7 @@ pub unsafe extern "C" fn freopen( /// Seek to an offset `offset` from `whence` #[no_mangle] -pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int { +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; } @@ -369,53 +509,47 @@ pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) /// Seek to an offset `offset` from `whence` #[no_mangle] -pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> c_int { +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; + off -= (stream.rend as usize - stream.rpos as usize) as i64; } - if (*stream).wpos > (*stream).wbase { - if let Some(f) = (*stream).write { - f(stream, ptr::null(), 0); - if (*stream).wpos.is_null() { - return -1; - } - } - } - (*stream).wpos = ptr::null_mut(); - (*stream).wend = ptr::null_mut(); - (*stream).wbase = ptr::null_mut(); - if let Some(s) = (*stream).seek { - if s(stream, off, whence) < 0 { + if stream.wpos > stream.wbase { + stream.write(&[]); + if stream.wpos.is_null() { return -1; } - } else { + } + 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; + 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 unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int { +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 unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long { +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 unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { +pub extern "C" fn ftello(stream: &mut FILE) -> off_t { flockfile(stream); let pos = internal::ftello(stream); funlockfile(stream); @@ -424,25 +558,23 @@ pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { /// Try to lock the file. Returns 0 for success, 1 for failure #[no_mangle] -pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int { - (*file) - .lock - .compare_and_swap(false, true, Ordering::Acquire) as c_int +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 unsafe extern "C" fn funlockfile(file: *mut FILE) { - (*file).lock.store(false, Ordering::Release); +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 unsafe extern "C" fn fwrite( +pub extern "C" fn fwrite( ptr: *const c_void, size: usize, nitems: usize, - stream: *mut FILE, + stream: &mut FILE, ) -> usize { let l = size * nitems; let nitems = if size == 0 { 0 } else { nitems }; @@ -458,7 +590,7 @@ pub unsafe extern "C" fn fwrite( /// Get a single char from a stream #[no_mangle] -pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { +pub extern "C" fn getc(stream: &mut FILE) -> c_int { flockfile(stream); let c = getc_unlocked(stream); funlockfile(stream); @@ -468,24 +600,22 @@ pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { /// Get a single char from `stdin` #[no_mangle] pub unsafe extern "C" fn getchar() -> c_int { - fgetc(stdin) + fgetc(&mut *stdin) } /// Get a char from a stream without locking the stream #[no_mangle] -pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { - if (*stream).rpos < (*stream).rend { - let ret = *(*stream).rpos as c_int; - (*stream).rpos = (*stream).rpos.add(1); - ret +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 { - if let Some(read) = (*stream).read { - let mut c = 0u8; - if !internal::to_read(stream) && read(stream, &mut c, 1) == 1 { - c as c_int - } else { - -1 - } + let mut c = [0u8; 1]; + if stream.can_read() && stream.read(&mut c) == 1 { + c[0] as c_int } else { -1 } @@ -495,19 +625,19 @@ pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { /// Get a char from `stdin` without locking `stdin` #[no_mangle] pub unsafe extern "C" fn getchar_unlocked() -> c_int { - getc_unlocked(stdin) + getc_unlocked(&mut *stdin) } /// Get a string from `stdin` #[no_mangle] pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char { use core::i32; - fgets(s, i32::MAX, stdin) + fgets(s, i32::MAX, &mut *stdin) } /// Get an integer from `stream` #[no_mangle] -pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int { +pub extern "C" fn getw(stream: &mut FILE) -> c_int { use core::mem; let mut ret: c_int = 0; if fread( @@ -524,7 +654,7 @@ pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int { } #[no_mangle] -pub extern "C" fn pclose(stream: *mut FILE) -> c_int { +pub extern "C" fn pclose(stream: &mut FILE) -> c_int { unimplemented!(); } @@ -547,7 +677,7 @@ pub extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FIL /// Put a character `c` into `stream` #[no_mangle] -pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { +pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int { flockfile(stream); let ret = putc_unlocked(c, stream); funlockfile(stream); @@ -557,31 +687,31 @@ pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { /// Put a character `c` into `stdout` #[no_mangle] pub unsafe extern "C" fn putchar(c: c_int) -> c_int { - fputc(c, stdout) + fputc(c, &mut *stdout) } /// Put a character `c` into `stream` without locking `stream` #[no_mangle] -pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int { - if c as i8 != (*stream).buf_char && (*stream).wpos < (*stream).wend { - *(*stream).wpos = c as u8; - (*stream).wpos = (*stream).wpos.add(1); - c +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 let Some(write) = (*stream).write { - if (*stream).wend.is_null() && internal::to_write(stream) { - -1 - } else if c as i8 != (*stream).buf_char && (*stream).wpos < (*stream).wend { - *(*stream).wpos = c as u8; - (*stream).wpos = (*stream).wpos.add(1); - c - } else if write(stream, &c as *const i32 as *const _, 1) != 1 { - -1 - } 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 { + } else if stream.write(&[c as u8]) != 1 { -1 + } else { + c } } } @@ -589,13 +719,13 @@ pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int { /// 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 { - let ret = (fputs(s, stdout) > 0) || (putchar_unlocked(b'\n' as c_int) > 0); + let ret = (fputs(s, &mut *stdout) > 0) || (putchar_unlocked(b'\n' as c_int) > 0); if ret { 0 } else { @@ -605,7 +735,7 @@ pub unsafe extern "C" fn puts(s: *const c_char) -> c_int { /// Put an integer `w` into `stream` #[no_mangle] -pub unsafe extern "C" fn putw(w: c_int, stream: *mut FILE) -> c_int { +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 } @@ -629,16 +759,16 @@ pub extern "C" fn rename(old: *const c_char, new: *const c_char) -> c_int { /// Rewind `stream` back to the beginning of it #[no_mangle] -pub unsafe extern "C" fn rewind(stream: *mut FILE) { +pub extern "C" fn rewind(stream: &mut FILE) { fseeko(stream, 0, SEEK_SET); flockfile(stream); - (*stream).flags &= !F_ERR; + 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) { +pub extern "C" fn setbuf(stream: &mut FILE, buf: *mut c_char) { unsafe { setvbuf( stream, @@ -650,9 +780,10 @@ pub extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) { } /// Reset `stream` to use buffer `buf` of size `size` +/// If this isn't the meaning of unsafe, idk what is #[no_mangle] pub unsafe extern "C" fn setvbuf( - stream: *mut FILE, + stream: &mut FILE, buf: *mut c_char, mode: c_int, size: usize, @@ -692,22 +823,24 @@ pub extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char { /// Push character `c` back onto `stream` so it'll be read next #[no_mangle] -pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { +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() { - internal::to_read(stream); + if stream.rpos.is_null() { + stream.can_read(); } - if (*stream).rpos.is_null() || (*stream).rpos <= (*stream).buf.sub((*stream).unget) { + if stream.rpos.is_null() || stream.rpos <= unsafe { stream.buf.sub(stream.unget) } { funlockfile(stream); return -1; } - (*stream).rpos = (*stream).rpos.sub(1); - *(*stream).rpos = c as u8; - (*stream).flags &= !F_EOF; + unsafe { + stream.rpos = stream.rpos.sub(1); + *stream.rpos = c as u8; + } + stream.flags &= !F_EOF; funlockfile(stream); c @@ -715,13 +848,13 @@ pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { } #[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).fd), 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] @@ -731,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) } /* From af78348d4a4b4a37daa91fa3a531bb00dfa1196f Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Sun, 18 Mar 2018 00:28:31 -0700 Subject: [PATCH 15/27] unistd: add a preliminary implementation of getopt() --- Cargo.lock | 2 + src/unistd/Cargo.toml | 2 + src/unistd/src/getopt.rs | 142 ++++++++++++++++++++++++++++ src/unistd/src/lib.rs | 10 +- tests/.gitignore | 1 + tests/Makefile | 1 + tests/expected/unistd/getopt.stderr | 0 tests/expected/unistd/getopt.stdout | 36 +++++++ tests/unistd/getopt.c | 68 +++++++++++++ 9 files changed, 257 insertions(+), 5 deletions(-) create mode 100644 src/unistd/src/getopt.rs create mode 100644 tests/expected/unistd/getopt.stderr create mode 100644 tests/expected/unistd/getopt.stdout create mode 100644 tests/unistd/getopt.c diff --git a/Cargo.lock b/Cargo.lock index b69becf544..70a043de61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,6 +534,8 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.2", "platform 0.1.0", + "stdio 0.1.0", + "string 0.1.0", ] [[package]] diff --git a/src/unistd/Cargo.toml b/src/unistd/Cargo.toml index 3edd54a814..8de8a2b933 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 0000000000..40560fae2b --- /dev/null +++ b/src/unistd/src/getopt.rs @@ -0,0 +1,142 @@ +//! 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; + +#[no_mangle] +pub static mut optarg: *mut c_char = ptr::null_mut(); + +#[no_mangle] +pub static mut optind: c_int = 1; + +#[no_mangle] +pub static mut opterr: c_int = 1; + +#[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 == ptr::null_mut() || *current_opt == 0 { + let current_arg = *argv.offset(optind as isize); + // XXX: is argc check needed? + if optind > argc || current_arg == ptr::null_mut() || *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 _, stdio::stderr); + stdio::fputs(desc.as_ptr() as _, stdio::stderr); + stdio::fputc(*current_arg as _, stdio::stderr); + stdio::fputc(b'\n' as _, 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 { + 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 7915a7e142..e5aa6bc926 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 ff5cc28a8c..dceeae741b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -33,6 +33,7 @@ /string/strchr /string/strrchr /string/strspn +/unistd/getopt /unlink /waitpid /write diff --git a/tests/Makefile b/tests/Makefile index e1b95b1839..52983f3f6a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -32,6 +32,7 @@ EXPECT_BINS=\ string/strpbrk \ string/strtok \ string/strtok_r \ + unistd/getopt \ unlink \ waitpid \ write diff --git a/tests/expected/unistd/getopt.stderr b/tests/expected/unistd/getopt.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/unistd/getopt.stdout b/tests/expected/unistd/getopt.stdout new file mode 100644 index 0000000000..c48147eb6f --- /dev/null +++ b/tests/expected/unistd/getopt.stdout @@ -0,0 +1,36 @@ +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 diff --git a/tests/unistd/getopt.c b/tests/unistd/getopt.c new file mode 100644 index 0000000000..f8e95ac955 --- /dev/null +++ b/tests/unistd/getopt.c @@ -0,0 +1,68 @@ +#include +#include + +#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, const 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"); +} From 42a6693a0bd283d4c2eacb2c3c096d0903c1f45a Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Mon, 19 Mar 2018 14:48:38 -0700 Subject: [PATCH 16/27] unistd: fix off-by-one in getopt() --- src/unistd/src/getopt.rs | 43 +++++++++++++++++------------ tests/expected/unistd/getopt.stdout | 6 ++++ tests/unistd/getopt.c | 3 +- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/unistd/src/getopt.rs b/src/unistd/src/getopt.rs index 40560fae2b..0f8e538f20 100644 --- a/src/unistd/src/getopt.rs +++ b/src/unistd/src/getopt.rs @@ -6,19 +6,23 @@ 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(); +static mut CURRENT_OPT: *mut c_char = ptr::null_mut(); #[no_mangle] pub unsafe extern "C" fn getopt( @@ -26,24 +30,27 @@ pub unsafe extern "C" fn getopt( argv: *const *mut c_char, optstring: *const c_char, ) -> c_int { - if current_opt == ptr::null_mut() || *current_opt == 0 { - let current_arg = *argv.offset(optind as isize); - // XXX: is argc check needed? - if optind > argc || current_arg == ptr::null_mut() || *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; + if CURRENT_OPT == ptr::null_mut() || *CURRENT_OPT == 0 { + if optind >= argc { -1 } else { - // remove the '-' - let current_arg = current_arg.offset(1); + let current_arg = *argv.offset(optind as isize); + if current_arg == ptr::null_mut() || *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) + parse_arg(argc, argv, current_arg, optstring) + } } } else { - parse_arg(argc, argv, current_opt, optstring) + parse_arg(argc, argv, CURRENT_OPT, optstring) } } @@ -54,8 +61,8 @@ unsafe fn parse_arg( optstring: *const c_char, ) -> c_int { let update_current_opt = || { - current_opt = current_arg.offset(1); - if *current_opt == 0 { + CURRENT_OPT = current_arg.offset(1); + if *CURRENT_OPT == 0 { optind += 1; } }; @@ -75,11 +82,11 @@ unsafe fn parse_arg( *current_arg as c_int } Some(GetoptOption::OptArg) => { - current_opt = b"\0".as_ptr() as _; + CURRENT_OPT = b"\0".as_ptr() as _; if *current_arg.offset(1) == 0 { optind += 2; if optind > argc { - current_opt = ptr::null_mut(); + CURRENT_OPT = ptr::null_mut(); optopt = *current_arg as c_int; let errch = if *optstring == b':' as c_char { diff --git a/tests/expected/unistd/getopt.stdout b/tests/expected/unistd/getopt.stdout index c48147eb6f..aba2d44d3f 100644 --- a/tests/expected/unistd/getopt.stdout +++ b/tests/expected/unistd/getopt.stdout @@ -34,3 +34,9 @@ errflg: 0 ifile: ofile: arg result: 0 +bflg: 0 +aflg: 0 +errflg: 0 +ifile: +ofile: +result: 0 diff --git a/tests/unistd/getopt.c b/tests/unistd/getopt.c index f8e95ac955..b1eb262556 100644 --- a/tests/unistd/getopt.c +++ b/tests/unistd/getopt.c @@ -11,7 +11,7 @@ printf("result: %d\n", runner(sizeof(args_arr) / sizeof(args_arr[0]), args_arr)); \ } -int runner(int argc, const char *argv[]) { +int runner(int argc, char *argv[]) { int c; int bflg = 0, aflg = 0, errflg = 0; char *ifile = ""; @@ -65,4 +65,5 @@ int main(int argc, const char *argv[]) { RUN("test", "-a", "-o", "arg", "--", "path", "path"); RUN("test", "-a", "-oarg", "path", "path"); RUN("test", "-aoarg", "path", "path"); + RUN("test"); } From 2751d457bf815333b2ba8f96b544d1fe5aa49b83 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Mon, 19 Mar 2018 15:05:38 -0700 Subject: [PATCH 17/27] unistd: use .is_null() for pointers --- src/unistd/src/getopt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unistd/src/getopt.rs b/src/unistd/src/getopt.rs index 0f8e538f20..2790529a35 100644 --- a/src/unistd/src/getopt.rs +++ b/src/unistd/src/getopt.rs @@ -30,12 +30,12 @@ pub unsafe extern "C" fn getopt( argv: *const *mut c_char, optstring: *const c_char, ) -> c_int { - if CURRENT_OPT == ptr::null_mut() || *CURRENT_OPT == 0 { + if CURRENT_OPT.is_null() || *CURRENT_OPT == 0 { if optind >= argc { -1 } else { let current_arg = *argv.offset(optind as isize); - if current_arg == ptr::null_mut() || *current_arg != b'-' as c_char + if current_arg.is_null() || *current_arg != b'-' as c_char || string::strcmp(current_arg, b"-\0".as_ptr() as _) == 0 { -1 From dbc3e413cc49f5a0a9c1364ed764eb6791847763 Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Tue, 20 Mar 2018 23:43:42 +0800 Subject: [PATCH 18/27] Fixed clearerr actually doing nothing --- src/stdio/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index fcae989865..98e3a3913f 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -180,7 +180,7 @@ impl Write for FILE { /// Clears EOF and ERR indicators on a stream #[no_mangle] pub extern "C" fn clearerr(stream: &mut FILE) { - stream.flags &= !(F_EOF & F_ERR); + stream.flags &= !(F_EOF | F_ERR); } #[no_mangle] From 4db812d34dfdf7896d8630307b4608f10f652614 Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Tue, 20 Mar 2018 19:31:58 -0700 Subject: [PATCH 19/27] implement rand and srand --- src/stdlib/Cargo.toml | 1 + src/stdlib/src/lib.rs | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index 97f5d44187..cc96a5dc07 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 575f759a26..8a5535f739 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -1,15 +1,18 @@ -//! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html - #![no_std] #![feature(core_intrinsics)] #![feature(global_allocator)] + +///! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html + extern crate ctype; extern crate errno; extern crate platform; extern crate ralloc; +extern crate rand; use core::{ptr, str}; +use rand::{Rng, XorShiftRng, SeedableRng}; use errno::*; use platform::types::*; @@ -19,8 +22,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; 32] = [None; 32]; +static mut RNG: Option = None; #[no_mangle] pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long { @@ -375,8 +380,18 @@ 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::(0, RAND_MAX) + }, + None => { + let mut rng = XorShiftRng::from_seed([1; 16]); + let ret = rng.gen_range::(0, RAND_MAX); + RNG = Some(rng); + ret + }, + } } #[no_mangle] @@ -425,8 +440,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] From a24f537a3834dd235057ae00128244df50af5458 Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Tue, 20 Mar 2018 19:42:49 -0700 Subject: [PATCH 20/27] test --- tests/.gitignore | 1 + tests/Makefile | 1 + tests/stdlib/rand.c | 8 ++++++++ 3 files changed, 10 insertions(+) create mode 100644 tests/stdlib/rand.c diff --git a/tests/.gitignore b/tests/.gitignore index ff5cc28a8c..e611cfdbec 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -28,6 +28,7 @@ /stdlib/bsearch /stdlib/strtol /stdlib/a64l +/stdlib/rand /string/strncmp /string/strcspn /string/strchr diff --git a/tests/Makefile b/tests/Makefile index e1b95b1839..a4d455d1da 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -23,6 +23,7 @@ EXPECT_BINS=\ stdlib/bsearch \ stdlib/strtol \ stdlib/a64l \ + stdlib/rand \ string/strncmp \ string/strcspn \ string/strchr \ diff --git a/tests/stdlib/rand.c b/tests/stdlib/rand.c new file mode 100644 index 0000000000..484b09906b --- /dev/null +++ b/tests/stdlib/rand.c @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char** argv) { + printf("%d\n", rand()); + srand(259); + printf("%d\n", rand()); +} From cc5a4e92ce85153bd625119dbad5c6ec61dcb65f Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Tue, 20 Mar 2018 19:45:45 -0700 Subject: [PATCH 21/27] fmt --- src/stdlib/src/lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index 8a5535f739..acc68d08d1 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -2,9 +2,7 @@ #![feature(core_intrinsics)] #![feature(global_allocator)] - ///! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html - extern crate ctype; extern crate errno; extern crate platform; @@ -12,7 +10,7 @@ extern crate ralloc; extern crate rand; use core::{ptr, str}; -use rand::{Rng, XorShiftRng, SeedableRng}; +use rand::{Rng, SeedableRng, XorShiftRng}; use errno::*; use platform::types::*; @@ -382,15 +380,13 @@ pub extern "C" fn qsort( #[no_mangle] pub unsafe extern "C" fn rand() -> c_int { match RNG { - Some(ref mut rng) => { - rng.gen_range::(0, RAND_MAX) - }, + Some(ref mut rng) => rng.gen_range::(0, RAND_MAX), None => { let mut rng = XorShiftRng::from_seed([1; 16]); let ret = rng.gen_range::(0, RAND_MAX); RNG = Some(rng); ret - }, + } } } From cdc6209ff48cac5714df7b958e9cd2063816caad Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Wed, 21 Mar 2018 20:12:22 -0700 Subject: [PATCH 22/27] fix comment --- src/stdlib/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index acc68d08d1..9c948d6779 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -1,8 +1,9 @@ +//! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html + #![no_std] #![feature(core_intrinsics)] #![feature(global_allocator)] -///! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html extern crate ctype; extern crate errno; extern crate platform; From e34d32aefe12af2b9a87f245e9db796df58dae15 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 21 Mar 2018 21:12:58 -0600 Subject: [PATCH 23/27] Update gitignore --- tests/.gitignore | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index dceeae741b..3fecd58cfb 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -18,21 +18,25 @@ /link /math /mem -/setid -/sleep /pipe /printf /rmdir /setid +/setid +/sleep /sprintf +/stdlib/a64l /stdlib/bsearch /stdlib/strtol -/stdlib/a64l -/string/strncmp -/string/strcspn /string/strchr +/string/strcspn +/string/strncmp +/string/strpbrk /string/strrchr /string/strspn +/string/strstr +/string/strtok +/string/strtok_r /unistd/getopt /unlink /waitpid From e5849526a06642242d9f61171babda0cc5a9b1af Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 21 Mar 2018 21:16:21 -0600 Subject: [PATCH 24/27] Update lock file --- Cargo.lock | 80 ++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70a043de61..d965c31531 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,22 +145,14 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.2", "platform 0.1.0", + "socket 0.1.0", ] [[package]] name = "itoa" -version = "0.3.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -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" version = "0.2.39" @@ -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]] @@ -549,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]] @@ -574,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" @@ -588,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" @@ -607,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)" = "" "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" @@ -645,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" From e1b20ed368cc74a27fe0a1c96a6babf69e721c8b Mon Sep 17 00:00:00 2001 From: Tom Almeida Date: Thu, 22 Mar 2018 12:43:05 +0800 Subject: [PATCH 25/27] Fixed getopt passing the wrong argument to stdio functions --- src/unistd/src/getopt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unistd/src/getopt.rs b/src/unistd/src/getopt.rs index 2790529a35..c93a5487b9 100644 --- a/src/unistd/src/getopt.rs +++ b/src/unistd/src/getopt.rs @@ -69,10 +69,10 @@ unsafe fn parse_arg( let print_error = |desc: &[u8]| { // NOTE: we don't use fprintf to get around the usage of va_list - stdio::fputs(*argv as _, stdio::stderr); - stdio::fputs(desc.as_ptr() as _, stdio::stderr); - stdio::fputc(*current_arg as _, stdio::stderr); - stdio::fputc(b'\n' as _, stdio::stderr); + 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) { From 58b2b641830664fff0be752ce0e452db8b1a64d2 Mon Sep 17 00:00:00 2001 From: Marat Safin Date: Thu, 22 Mar 2018 14:11:45 +0300 Subject: [PATCH 26/27] add clock_gettime and time --- src/platform/src/linux/mod.rs | 4 ++++ src/platform/src/redox/mod.rs | 14 +++++++++++++ src/platform/src/types.rs | 1 + src/time/cbindgen.toml | 4 ++++ src/time/src/lib.rs | 38 +++++++++++++++++++++++++++++++++-- tests/.gitignore | 2 +- tests/Makefile | 3 ++- tests/time.c | 11 ++++++++++ 8 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 tests/time.c diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 44d7ed2cfb..d055989d17 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -170,3 +170,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 3e03bbde90..ea7954ec20 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -220,3 +220,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 d6e19dbd58..722fe706ce 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/time/cbindgen.toml b/src/time/cbindgen.toml index ef3a5240e6..40448b8f89 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 5b90e86f74..5835d7014b 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/tests/.gitignore b/tests/.gitignore index 433d1e3fd6..e946dbbed8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -47,4 +47,4 @@ /unlink /waitpid /write - +/time diff --git a/tests/Makefile b/tests/Makefile index e788930ed0..cd6117e6e0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -41,7 +41,8 @@ EXPECT_BINS=\ unistd/getopt \ unlink \ waitpid \ - write + write \ + time # Binaries that may generate varied output BINS=\ diff --git a/tests/time.c b/tests/time.c new file mode 100644 index 0000000000..e6ce164c25 --- /dev/null +++ b/tests/time.c @@ -0,0 +1,11 @@ +#include +#include + +int main(int argc, char** argv) { + timespec tm = {0, 0}; + clock_gettime(CLOCK_REALTIME, &tm); + perror("clock_gettime"); + time(NULL); + perror("time"); + return 0; +} From 43e95a9b9216e83c9c753a3ff3a8b16b9803413a Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Sun, 25 Mar 2018 14:22:12 -0400 Subject: [PATCH 27/27] Implement kill() and killpg() --- src/platform/src/linux/mod.rs | 8 ++++++++ src/platform/src/redox/mod.rs | 8 ++++++++ src/signal/src/lib.rs | 4 ++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index d055989d17..b764d1f742 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -115,6 +115,14 @@ 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 } diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index ea7954ec20..4dfb2b28d4 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -119,6 +119,14 @@ 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) }; diff --git a/src/signal/src/lib.rs b/src/signal/src/lib.rs index 052cb13770..031b8e4836 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]