diff --git a/include/sys/types.h b/include/sys/types.h index 270a43e46a..19cf76bb78 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -30,5 +30,6 @@ typedef unsigned int u_int, uint; typedef unsigned long u_long, ulong; typedef long long quad_t; typedef unsigned long long u_quad_t; +typedef char *caddr_t; #endif /* _SYS_TYPES_H */ 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..375409c2e0 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 } @@ -558,7 +561,7 @@ pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { return -1; } - pos - (stream.read_size - stream.read_pos) as off_t + pos - (stream.read_size - stream.read_pos) as off_t - stream.unget.len() as off_t } /// Try to lock the file. Returns 0 for success, 1 for failure @@ -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 } @@ -1042,8 +1041,12 @@ pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_ #[no_mangle] pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int { - let mut file = (*file).lock(); - scanf::scanf(&mut *file, format, ap) + let ret = { + let mut file = (*file).lock(); + scanf::scanf(&mut *file, format, ap) + }; + fseeko(file, -1, SEEK_CUR); + ret } #[no_mangle] diff --git a/src/header/stdio/printf.rs b/src/header/stdio/printf.rs index 727de95264..4c5550bebe 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -660,16 +660,22 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> }; let alternate = arg.alternate; let zero = arg.zero; - let left = arg.left; + let mut left = arg.left; let sign_reserve = arg.sign_reserve; let sign_always = arg.sign_always; let min_width = arg.min_width.resolve(&mut varargs, &mut ap); let precision = arg.precision.map(|n| n.resolve(&mut varargs, &mut ap)); let pad_zero = arg.pad_zero.resolve(&mut varargs, &mut ap); - let pad_space = match pad_zero { - 0 => min_width, + let signed_space = match pad_zero { + 0 => min_width as isize, _ => 0, }; + let pad_space = if signed_space < 0 { + left = true; + -signed_space as usize + } else { + signed_space as usize + }; let intkind = arg.intkind; let fmt = arg.fmt; let fmtkind = arg.fmtkind; diff --git a/tests/Makefile b/tests/Makefile index a6f967a872..7ff599552b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -42,6 +42,10 @@ EXPECT_NAMES=\ stdio/setvbuf \ stdio/sprintf \ stdio/printf_space_pad \ + stdio/ungetc_multiple \ + stdio/ungetc_ftell \ + stdio/fscanf_offby1 \ + stdio/printf_neg_pad \ stdlib/a64l \ stdlib/alloc \ stdlib/atof \ diff --git a/tests/expected/stdio/fscanf_offby1.stderr b/tests/expected/stdio/fscanf_offby1.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/fscanf_offby1.stdout b/tests/expected/stdio/fscanf_offby1.stdout new file mode 100644 index 0000000000..daf724a9e5 --- /dev/null +++ b/tests/expected/stdio/fscanf_offby1.stdout @@ -0,0 +1 @@ +1234, 7, 32 diff --git a/tests/expected/stdio/printf_neg_pad.stderr b/tests/expected/stdio/printf_neg_pad.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/printf_neg_pad.stdout b/tests/expected/stdio/printf_neg_pad.stdout new file mode 100644 index 0000000000..f573a2b6d2 --- /dev/null +++ b/tests/expected/stdio/printf_neg_pad.stdout @@ -0,0 +1,2 @@ +A BCC/ +AB CC/ diff --git a/tests/expected/stdio/ungetc_ftell.stderr b/tests/expected/stdio/ungetc_ftell.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/ungetc_ftell.stdout b/tests/expected/stdio/ungetc_ftell.stdout new file mode 100644 index 0000000000..e36f413519 --- /dev/null +++ b/tests/expected/stdio/ungetc_ftell.stdout @@ -0,0 +1,28 @@ +#, 0 +i, 1 +n, 2 +h, -9 +e, -8 +l, -7 +l, -6 +o, -5 + , -4 +w, -3 +o, -2 +r, -1 +l, 0 +d, 1 + +, 2 +c, 3 +l, 4 +u, 5 +d, 6 +e, 7 + , 8 +<, 9 +s, 10 +t, 11 +d, 12 +i, 13 +o, 14 diff --git a/tests/expected/stdio/ungetc_multiple.stderr b/tests/expected/stdio/ungetc_multiple.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/ungetc_multiple.stdout b/tests/expected/stdio/ungetc_multiple.stdout new file mode 100644 index 0000000000..3b18e512db --- /dev/null +++ b/tests/expected/stdio/ungetc_multiple.stdout @@ -0,0 +1 @@ +hello world diff --git a/tests/stdio/fscanf_offby1.c b/tests/stdio/fscanf_offby1.c new file mode 100644 index 0000000000..c833935793 --- /dev/null +++ b/tests/stdio/fscanf_offby1.c @@ -0,0 +1,8 @@ +//1234 a +#include +int main() { + FILE *f = fopen("stdio/fscanf_offby1.c", "r"); + int x; + fscanf(f, "//%d", &x); + printf("%d, %ld, %d\n", x, ftell(f), fgetc(f)); +} diff --git a/tests/stdio/printf_neg_pad.c b/tests/stdio/printf_neg_pad.c new file mode 100644 index 0000000000..7f443034b9 --- /dev/null +++ b/tests/stdio/printf_neg_pad.c @@ -0,0 +1,5 @@ +#include +int main() { + printf ("A%*s%s/\n", 5, "B", "CC"); + printf ("A%*s%s/\n", -5, "B", "CC"); +} diff --git a/tests/stdio/ungetc_ftell.c b/tests/stdio/ungetc_ftell.c new file mode 100644 index 0000000000..10be6a3057 --- /dev/null +++ b/tests/stdio/ungetc_ftell.c @@ -0,0 +1,37 @@ +#include +int main() { + FILE *f = fopen("stdio/ungetc_ftell.c", "r"); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + ungetc('\n', f);ungetc('d', f); + ungetc('l', f); ungetc('r', f); + ungetc('o', f); ungetc('w', f); + ungetc(' ', f); ungetc('o', f); + ungetc('l', f); ungetc('l', f); + ungetc('e', f); ungetc('h', f); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); +} diff --git a/tests/stdio/ungetc_multiple.c b/tests/stdio/ungetc_multiple.c new file mode 100644 index 0000000000..611430489a --- /dev/null +++ b/tests/stdio/ungetc_multiple.c @@ -0,0 +1,27 @@ +#include +int main() { + ungetc('\n', stdin); + ungetc('d', stdin); + ungetc('l', stdin); + ungetc('r', stdin); + ungetc('o', stdin); + ungetc('w', stdin); + ungetc(' ', stdin); + ungetc('o', stdin); + ungetc('l', stdin); + ungetc('l', stdin); + ungetc('e', stdin); + ungetc('h', stdin); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); +}