From 7a6f96373e1f93b0ad556974822ebd83979741b2 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Fri, 22 May 2020 23:05:49 +0200 Subject: [PATCH] Add support for multiple unget at the same time According to the standards, only one ungetc may be guaranteed however glibc allows more than one of those, and to be glibc compatiable, one needs to be able to do the same, allowing only 1 ungetc may trigger bug while compiling gcc as ungetc is used there alot --- src/header/stdio/default.rs | 3 ++- src/header/stdio/helpers.rs | 6 +++--- src/header/stdio/mod.rs | 29 ++++++++++++++--------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/header/stdio/default.rs b/src/header/stdio/default.rs index 592a77845b..b86115e2d6 100644 --- a/src/header/stdio/default.rs +++ b/src/header/stdio/default.rs @@ -2,6 +2,7 @@ use super::{constants, Buffer, BUFSIZ, FILE}; use core::{cell::UnsafeCell, ptr}; use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex}; +use alloc::vec::Vec; pub struct GlobalFile(UnsafeCell); impl GlobalFile { @@ -16,7 +17,7 @@ impl GlobalFile { read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]), read_pos: 0, read_size: 0, - unget: None, + unget: Vec::new(), writer, pid: None, diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs index 399a8a8991..6d5d9da841 100644 --- a/src/header/stdio/helpers.rs +++ b/src/header/stdio/helpers.rs @@ -1,5 +1,6 @@ use alloc::boxed::Box; +use super::{constants::*, Buffer, FILE}; use crate::{ fs::File, header::{errno, fcntl::*, string::strchr}, @@ -7,8 +8,7 @@ use crate::{ platform::{self, types::*}, sync::Mutex, }; - -use super::{constants::*, Buffer, FILE}; +use alloc::vec::Vec; /// Parse mode flags as a string and output a mode flags integer pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 { @@ -72,7 +72,7 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> { read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]), read_pos: 0, read_size: 0, - unget: None, + unget: Vec::new(), writer, pid: None, diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 0163ea1c86..636c6a1ae5 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -6,6 +6,7 @@ use alloc::{ vec::Vec, }; use core::{ + cmp, ffi::VaList as va_list, fmt::{self, Write as WriteFmt}, mem, @@ -76,7 +77,7 @@ pub struct FILE { read_buf: Buffer<'static>, read_pos: usize, read_size: usize, - unget: Option, + unget: Vec, // pub for stdio_ext pub(crate) writer: LineWriter, @@ -86,11 +87,12 @@ pub struct FILE { impl Read for FILE { fn read(&mut self, out: &mut [u8]) -> io::Result { - if !out.is_empty() { - if let Some(c) = self.unget.take() { - out[0] = c; - return Ok(1); - } + let unget_read_size = cmp::min(out.len(), self.unget.len()); + for i in 0..unget_read_size { + out[i] = self.unget.pop().unwrap(); + } + if unget_read_size != 0 { + return Ok(unget_read_size); } let len = { @@ -311,11 +313,12 @@ pub unsafe extern "C" fn fgets( let mut wrote = false; if left >= 1 { - if let Some(c) = stream.unget.take() { - *out = c as c_char; + let unget_read_size = cmp::min(left, stream.unget.len()); + for _ in 0..unget_read_size { + *out = stream.unget.pop().unwrap() as i8; out = out.offset(1); - left -= 1; } + left -= unget_read_size; } loop { @@ -533,7 +536,7 @@ pub unsafe extern "C" fn fseeko(stream: *mut FILE, mut off: off_t, whence: c_int stream.flags &= !(F_EOF | F_ERR); stream.read_pos = 0; stream.read_size = 0; - stream.unget = None; + stream.unget = Vec::new(); 0 } @@ -990,11 +993,7 @@ unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_cha #[no_mangle] pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { let mut stream = (*stream).lock(); - if stream.unget.is_some() { - platform::errno = errno::EIO; - return EOF; - } - stream.unget = Some(c as u8); + stream.unget.push(c as u8); c }