From c24d1e2b361eae5227d2294d98e45d0658374785 Mon Sep 17 00:00:00 2001 From: Tom Almeida <tommoa256@gmail.com> Date: Sun, 18 Mar 2018 00:20:21 +0800 Subject: [PATCH] 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 | 104 ++++----- src/stdio/src/internal.rs | 156 +------------ src/stdio/src/lib.rs | 465 ++++++++++++++++++++++++-------------- 4 files changed, 358 insertions(+), 376 deletions(-) diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs index efeb05c9..840a6fa0 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 53424902..378d2af3 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 - }; + if stream.wend.is_null() && !stream.can_write() { + // We can't write to this stream + return 0; + } + if l > stream.wend as usize - stream.wpos as usize { + // We can't fit all of buf in the buffer + return stream.write(buf); + } - memcpy((*stream).wpos, buf, l); - (*stream).wpos = (*stream).wpos.add(l); - l + i + 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 { - // We can't write to this stream 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 99005e87..35eb5f47 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 df5e9b6d..fcae9898 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) } /* -- GitLab