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());
+}