diff --git a/include/sys/types.h b/include/sys/types.h index 270a43e46afb73d8f90d32fa302b77632deac22b..19cf76bb78842cd92c32b428e6fead5c88776eed 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 592a77845bc929d47ecd316c9888e760abf9fe46..b86115e2d6f33caf73831d1704aee07ad360c87e 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<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, diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs index 399a8a8991a3d09d12b6d969ba9162c4762da088..6d5d9da8414e1dcb7bb84153a978ca08a296c3a6 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 0163ea1c8676372108edacee6a97fbfdb6aceb68..375409c2e035120075b9b4333a83739ed7409090 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<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 } @@ -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 727de9526474e4d7b8f1109ff3c1f3be6a5c6778..4c5550bebe64277b9cf7d30e0996c6bab36a9ef8 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -660,16 +660,22 @@ unsafe fn inner_printf<W: Write>(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 a6f967a87288da206243943a0d86613a2e6cd1a6..7ff599552b593a5fe45f63d3b1eef0ab2253ca4b 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/stdio/fscanf_offby1.stdout b/tests/expected/stdio/fscanf_offby1.stdout new file mode 100644 index 0000000000000000000000000000000000000000..daf724a9e5c2d676a8b87bef70c650515449e4e0 --- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/stdio/printf_neg_pad.stdout b/tests/expected/stdio/printf_neg_pad.stdout new file mode 100644 index 0000000000000000000000000000000000000000..f573a2b6d2582ec2ac0e6b24a95a4572880a896a --- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/stdio/ungetc_ftell.stdout b/tests/expected/stdio/ungetc_ftell.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e36f413519137223eb50d873fd529c385b69372e --- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/stdio/ungetc_multiple.stdout b/tests/expected/stdio/ungetc_multiple.stdout new file mode 100644 index 0000000000000000000000000000000000000000..3b18e512dba79e4c8300dd08aeb37f8e728b8dad --- /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 0000000000000000000000000000000000000000..c8339357933e27b929ef88778f6d2643a0daee4f --- /dev/null +++ b/tests/stdio/fscanf_offby1.c @@ -0,0 +1,8 @@ +//1234 a +#include <stdio.h> +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 0000000000000000000000000000000000000000..7f443034b9102082d6698d7f03f68eff633cdbee --- /dev/null +++ b/tests/stdio/printf_neg_pad.c @@ -0,0 +1,5 @@ +#include <stdio.h> +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 0000000000000000000000000000000000000000..10be6a3057ab92420b79fbbecf0b27b3eed26105 --- /dev/null +++ b/tests/stdio/ungetc_ftell.c @@ -0,0 +1,37 @@ +#include <stdio.h> +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 0000000000000000000000000000000000000000..611430489ae61c9088a7b9adc70b4c2a5c4e06ba --- /dev/null +++ b/tests/stdio/ungetc_multiple.c @@ -0,0 +1,27 @@ +#include <stdio.h> +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()); +}