diff --git a/src/header/stdio/printf.rs b/src/header/stdio/printf.rs index 4c5550bebe64277b9cf7d30e0996c6bab36a9ef8..f6f6f18341c2de333552a1bec87df67b456f0710 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -18,7 +18,7 @@ use crate::{ // |____/ \___/|_|_|\___|_| | .__/|_|\__,_|\__\___(_) // |_| -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] enum IntKind { Byte, Short, @@ -29,7 +29,7 @@ enum IntKind { PtrDiff, Size, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] enum FmtKind { Percent, @@ -52,8 +52,8 @@ enum Number { Next, } impl Number { - unsafe fn resolve(&self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { - let arg = match *self { + unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { + let arg = match self { Number::Static(num) => return num, Number::Index(i) => varargs.get(i - 1, ap, None), Number::Next => { @@ -231,12 +231,16 @@ impl VaListCache { default: Option<(FmtKind, IntKind)>, ) -> VaArg { if let Some(&arg) = self.args.get(i) { + // This value is already cached let mut arg = arg; if let Some((fmtkind, intkind)) = default { + // ...but as a different type arg = arg.transmute(fmtkind, intkind); } return arg; } + + // Get all values before this value while self.args.len() < i { // We can't POSSIBLY know the type if we reach this // point. Reaching here means there are unused gaps in the @@ -244,10 +248,14 @@ impl VaListCache { // defaulting to c_int. self.args.push(VaArg::c_int(ap.arg::<c_int>())) } + + // Add the value to the cache self.args.push(match default { Some((fmtkind, intkind)) => VaArg::arg_from(fmtkind, intkind, ap), None => VaArg::c_int(ap.arg::<c_int>()), }); + + // Return the value self.args[i] } } @@ -462,7 +470,7 @@ fn fmt_float_nonfinite<W: Write>(w: &mut W, float: c_double, case: FmtCase) -> i struct PrintfIter { format: *const u8, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct PrintfArg { index: Option<usize>, alternate: bool, @@ -472,11 +480,11 @@ struct PrintfArg { sign_always: bool, min_width: Number, precision: Option<Number>, - pad_zero: Number, intkind: IntKind, fmt: u8, fmtkind: FmtKind, } +#[derive(Debug)] enum PrintfFmt { Plain(&'static [u8]), Arg(PrintfArg), @@ -540,9 +548,6 @@ impl Iterator for PrintfIter { None }; - let pad_space = if zero { Number::Static(0) } else { min_width }; - let pad_zero = if zero { min_width } else { Number::Static(0) }; - // Integer size: let mut intkind = IntKind::Int; loop { @@ -595,7 +600,6 @@ impl Iterator for PrintfIter { sign_always, min_width, precision, - pad_zero, intkind, fmt, fmtkind, @@ -643,6 +647,7 @@ unsafe fn inner_printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> .push(VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap)), } } + // Make sure, in order, the positional arguments exist with the specified type for (i, arg) in positional { varargs.get(i, &mut ap, Some(arg)); @@ -665,7 +670,7 @@ unsafe fn inner_printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> 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_zero = if zero { min_width } else { 0 }; let signed_space = match pad_zero { 0 => min_width as isize, _ => 0, @@ -685,6 +690,7 @@ unsafe fn inner_printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> _ => None, }; + let index = arg.index.map(|i| i - 1).unwrap_or_else(|| { if fmtkind == FmtKind::Percent { 0 diff --git a/tests/expected/stdio/printf.stdout b/tests/expected/stdio/printf.stdout index 5683f0cad883a1b615eb03db779d4a4c17e3f51b..75c6a4941470e989eb22924329603113270fa918 100644 --- a/tests/expected/stdio/printf.stdout +++ b/tests/expected/stdio/printf.stdout @@ -60,6 +60,8 @@ Non-finite float madness: %F: INF -INF NAN -NAN %g: inf -inf nan -nan %G: INF -INF NAN -NAN +Things that have been buggy ++05 Testing asprintf... printed: test string, value: 11 printed: test string 2, value: 13 diff --git a/tests/stdio/printf.c b/tests/stdio/printf.c index c8fdafef677f4b64b2595a09ea144ccb6df43a14..49e690593389de06f8a874169638f194ba901fc8 100644 --- a/tests/stdio/printf.c +++ b/tests/stdio/printf.c @@ -75,6 +75,9 @@ int main(void) { printf("\n"); } + puts("Things that have been buggy"); + printf("%s%0*lu\n", "+", 2, 5l); // this format string was found in GDB + puts("Testing asprintf..."); char *s = NULL; int res = asprintf(&s, "test string");