This commit is contained in:
nora 2023-10-01 15:52:13 +02:00
parent 08938636d4
commit bbe7f04877
2 changed files with 75 additions and 4 deletions

View file

@ -5,17 +5,37 @@ use crate::{io::IoWrite, utils::SharedThinCstr};
pub unsafe fn printf_generic( pub unsafe fn printf_generic(
mut sink: impl IoWrite, mut sink: impl IoWrite,
format: SharedThinCstr<'_>, format: SharedThinCstr<'_>,
_args: VaList<'_, '_>, mut args: VaList<'_, '_>,
) -> Result<(), i32> { ) -> Result<(), i32> {
let mut chars = format.into_iter(); let mut chars = format.into_iter();
while let Some(c) = chars.next() { while let Some(c) = chars.next() {
if c == b'%' { if c == b'%' {
let Some(c) = chars.next() else {
return Err(-1);
};
// todo: do this properly
match c {
b'c' => {
let char = args.arg::<u8>();
write!(sink, "{}", char as char)?;
}
b'l' => {
let Some(c) = chars.next() else {
return Err(-1);
};
if c != b'd' {
todo!(); todo!();
} }
let long = args.arg::<i64>();
write!(sink, "{}", long)?;
}
_ => todo!(),
};
} else {
sink.write_byte(c)?; sink.write_byte(c)?;
} }
}
Ok(()) Ok(())
} }
@ -51,4 +71,16 @@ mod tests {
fn constant_string() { fn constant_string() {
unsafe { test_printf("hello, world", cstr!("hello, world")) } 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) }
}
} }

View file

@ -1,3 +1,5 @@
use core::fmt;
pub trait IoWrite { pub trait IoWrite {
fn write(&mut self, buf: &[u8]) -> Result<usize, i32>; fn write(&mut self, buf: &[u8]) -> Result<usize, i32>;
@ -12,6 +14,43 @@ pub trait IoWrite {
fn write_byte(&mut self, byte: u8) -> Result<(), i32> { fn write_byte(&mut self, byte: u8) -> Result<(), i32> {
self.write_all(&[byte]) 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<T: IoWrite + ?Sized> 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<W: IoWrite> IoWrite for &mut W { impl<W: IoWrite> IoWrite for &mut W {