ソースを参照

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 crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex};
+use alloc::vec::Vec;
 
 pub struct GlobalFile(UnsafeCell<FILE>);
 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,

+ 3 - 3
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,

+ 14 - 15
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<u8>,
+    unget: Vec<u8>,
     // pub for stdio_ext
     pub(crate) writer: LineWriter<File>,
 
@@ -86,11 +87,12 @@ pub struct FILE {
 
 impl Read for FILE {
     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 = {
@@ -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
 }