diff --git a/libuwuc/src/fmt/printf.rs b/libuwuc/src/fmt/printf.rs index 7245be8..f09e8d4 100644 --- a/libuwuc/src/fmt/printf.rs +++ b/libuwuc/src/fmt/printf.rs @@ -5,16 +5,36 @@ use crate::{io::IoWrite, utils::SharedThinCstr}; pub unsafe fn printf_generic( mut sink: impl IoWrite, format: SharedThinCstr<'_>, - _args: VaList<'_, '_>, + mut args: VaList<'_, '_>, ) -> Result<(), i32> { let mut chars = format.into_iter(); while let Some(c) = chars.next() { if c == b'%' { - todo!(); + let Some(c) = chars.next() else { + return Err(-1); + }; + // todo: do this properly + match c { + b'c' => { + let char = args.arg::(); + write!(sink, "{}", char as char)?; + } + b'l' => { + let Some(c) = chars.next() else { + return Err(-1); + }; + if c != b'd' { + todo!(); + } + let long = args.arg::(); + write!(sink, "{}", long)?; + } + _ => todo!(), + }; + } else { + sink.write_byte(c)?; } - - sink.write_byte(c)?; } Ok(()) @@ -51,4 +71,16 @@ mod tests { fn constant_string() { unsafe { test_printf("hello, world", cstr!("hello, world")) } } + + #[test] + #[cfg_attr(miri, ignore = "variadic")] + fn char() { + unsafe { test_printf("a", cstr!("%c"), b'a' as u64) } + } + + #[test] + #[cfg_attr(miri, ignore = "variadic")] + fn long() { + unsafe { test_printf("234", cstr!("%ld"), 234_u64) } + } } diff --git a/libuwuc/src/io/traits.rs b/libuwuc/src/io/traits.rs index 7ad3ef4..e92d728 100644 --- a/libuwuc/src/io/traits.rs +++ b/libuwuc/src/io/traits.rs @@ -1,3 +1,5 @@ +use core::fmt; + pub trait IoWrite { fn write(&mut self, buf: &[u8]) -> Result; @@ -12,6 +14,43 @@ pub trait IoWrite { fn write_byte(&mut self, byte: u8) -> Result<(), i32> { self.write_all(&[byte]) } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<(), i32> { + // Create a shim which translates a Write to a fmt::Write and saves + // off I/O errors. instead of discarding them + struct Adapter<'a, T: ?Sized> { + inner: &'a mut T, + error: Result<(), i32>, + } + + impl fmt::Write for Adapter<'_, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adapter { + inner: self, + error: Ok(()), + }; + match fmt::write(&mut output, fmt) { + Ok(()) => Ok(()), + Err(..) => { + // check if the error came from the underlying `Write` or not + if output.error.is_err() { + output.error + } else { + Err(-1) + } + } + } + } } impl IoWrite for &mut W {