浏览代码

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
oddcoder 4 年之前
父节点
当前提交
7a6f96373e
共有 3 个文件被更改,包括 19 次插入19 次删除
  1. 2 1
      src/header/stdio/default.rs
  2. 3 3
      src/header/stdio/helpers.rs
  3. 14 15
      src/header/stdio/mod.rs

+ 2 - 1
src/header/stdio/default.rs

@@ -2,6 +2,7 @@ use super::{constants, Buffer, BUFSIZ, FILE};
 use core::{cell::UnsafeCell, ptr};
 use core::{cell::UnsafeCell, ptr};
 
 
 use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex};
 use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex};
+use alloc::vec::Vec;
 
 
 pub struct GlobalFile(UnsafeCell<FILE>);
 pub struct GlobalFile(UnsafeCell<FILE>);
 impl GlobalFile {
 impl GlobalFile {
@@ -16,7 +17,7 @@ impl GlobalFile {
             read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
             read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
             read_pos: 0,
             read_pos: 0,
             read_size: 0,
             read_size: 0,
-            unget: None,
+            unget: Vec::new(),
             writer,
             writer,
 
 
             pid: None,
             pid: None,

+ 3 - 3
src/header/stdio/helpers.rs

@@ -1,5 +1,6 @@
 use alloc::boxed::Box;
 use alloc::boxed::Box;
 
 
+use super::{constants::*, Buffer, FILE};
 use crate::{
 use crate::{
     fs::File,
     fs::File,
     header::{errno, fcntl::*, string::strchr},
     header::{errno, fcntl::*, string::strchr},
@@ -7,8 +8,7 @@ use crate::{
     platform::{self, types::*},
     platform::{self, types::*},
     sync::Mutex,
     sync::Mutex,
 };
 };
-
-use super::{constants::*, Buffer, FILE};
+use alloc::vec::Vec;
 
 
 /// Parse mode flags as a string and output a mode flags integer
 /// Parse mode flags as a string and output a mode flags integer
 pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 {
 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_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
         read_pos: 0,
         read_pos: 0,
         read_size: 0,
         read_size: 0,
-        unget: None,
+        unget: Vec::new(),
         writer,
         writer,
 
 
         pid: None,
         pid: None,

+ 14 - 15
src/header/stdio/mod.rs

@@ -6,6 +6,7 @@ use alloc::{
     vec::Vec,
     vec::Vec,
 };
 };
 use core::{
 use core::{
+    cmp,
     ffi::VaList as va_list,
     ffi::VaList as va_list,
     fmt::{self, Write as WriteFmt},
     fmt::{self, Write as WriteFmt},
     mem,
     mem,
@@ -76,7 +77,7 @@ pub struct FILE {
     read_buf: Buffer<'static>,
     read_buf: Buffer<'static>,
     read_pos: usize,
     read_pos: usize,
     read_size: usize,
     read_size: usize,
-    unget: Option<u8>,
+    unget: Vec<u8>,
     // pub for stdio_ext
     // pub for stdio_ext
     pub(crate) writer: LineWriter<File>,
     pub(crate) writer: LineWriter<File>,
 
 
@@ -86,11 +87,12 @@ pub struct FILE {
 
 
 impl Read for FILE {
 impl Read for FILE {
     fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
     fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
-        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 = {
         let len = {
@@ -311,11 +313,12 @@ pub unsafe extern "C" fn fgets(
     let mut wrote = false;
     let mut wrote = false;
 
 
     if left >= 1 {
     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);
             out = out.offset(1);
-            left -= 1;
         }
         }
+        left -= unget_read_size;
     }
     }
 
 
     loop {
     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.flags &= !(F_EOF | F_ERR);
     stream.read_pos = 0;
     stream.read_pos = 0;
     stream.read_size = 0;
     stream.read_size = 0;
-    stream.unget = None;
+    stream.unget = Vec::new();
     0
     0
 }
 }
 
 
@@ -990,11 +993,7 @@ unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_cha
 #[no_mangle]
 #[no_mangle]
 pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
 pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
     let mut stream = (*stream).lock();
     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
     c
 }
 }