More printf tests and corner cases

This commit is contained in:
jD91mZM2
2019-04-23 08:15:58 +02:00
parent 0a0aec502b
commit 8fca7bcbc1
3 changed files with 75 additions and 3 deletions
+68 -3
View File
@@ -126,6 +126,67 @@ impl VaArg {
=> VaArg::pointer(ap.arg::<*const c_void>()),
}
}
unsafe fn transmute(&self, arg: &PrintfArg) -> VaArg {
// At this point, there are conflicting printf arguments. An
// example of this is:
// ```c
// printf("%1$d %1$lf\n", 5, 0.1);
// ```
// We handle it just like glibc: We read it from the VaList
// using the *last* argument type, but we transmute it when we
// try to access the other ones.
union Untyped {
c_char: c_char,
c_double: c_double,
c_int: c_int,
c_long: c_long,
c_longlong: c_longlong,
c_short: c_short,
intmax_t: intmax_t,
pointer: *const c_void,
ptrdiff_t: ptrdiff_t,
ssize_t: ssize_t
}
let untyped = match *self {
VaArg::c_char(i) => Untyped { c_char: i },
VaArg::c_double(i) => Untyped { c_double: i },
VaArg::c_int(i) => Untyped { c_int: i },
VaArg::c_long(i) => Untyped { c_long: i },
VaArg::c_longlong(i) => Untyped { c_longlong: i },
VaArg::c_short(i) => Untyped { c_short: i },
VaArg::intmax_t(i) => Untyped { intmax_t: i },
VaArg::pointer(i) => Untyped { pointer: i },
VaArg::ptrdiff_t(i) => Untyped { ptrdiff_t: i },
VaArg::ssize_t(i) => Untyped { ssize_t: i }
};
match (arg.fmtkind, arg.intkind) {
(FmtKind::Percent, _) => panic!("Can't call transmute on %"),
(FmtKind::Char, _) |
(FmtKind::Unsigned, IntKind::Byte) |
(FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char),
(FmtKind::Unsigned, IntKind::Short) |
(FmtKind::Signed, IntKind::Short) => VaArg::c_short(untyped.c_short),
(FmtKind::Unsigned, IntKind::Int) |
(FmtKind::Signed, IntKind::Int) => VaArg::c_int(untyped.c_int),
(FmtKind::Unsigned, IntKind::Long) |
(FmtKind::Signed, IntKind::Long) => VaArg::c_long(untyped.c_long),
(FmtKind::Unsigned, IntKind::LongLong) |
(FmtKind::Signed, IntKind::LongLong) => VaArg::c_longlong(untyped.c_longlong),
(FmtKind::Unsigned, IntKind::IntMax) |
(FmtKind::Signed, IntKind::IntMax) => VaArg::intmax_t(untyped.intmax_t),
(FmtKind::Unsigned, IntKind::PtrDiff) |
(FmtKind::Signed, IntKind::PtrDiff) => VaArg::ptrdiff_t(untyped.ptrdiff_t),
(FmtKind::Unsigned, IntKind::Size) |
(FmtKind::Signed, IntKind::Size) => VaArg::ssize_t(untyped.ssize_t),
(FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _)
=> VaArg::c_double(untyped.c_double),
(FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _)
=> VaArg::pointer(untyped.pointer),
}
}
}
#[derive(Default)]
struct VaListCache {
@@ -133,8 +194,12 @@ struct VaListCache {
i: usize
}
impl VaListCache {
unsafe fn get(&mut self, i: usize, ap: &mut VaList, arg: Option<&PrintfArg>) -> VaArg {
unsafe fn get(&mut self, i: usize, ap: &mut VaList, default: Option<&PrintfArg>) -> VaArg {
if let Some(&arg) = self.args.get(i) {
let mut arg = arg;
if let Some(default) = default {
arg = arg.transmute(default);
}
return arg;
}
while self.args.len() < i {
@@ -144,8 +209,8 @@ impl VaListCache {
// defaulting to c_int.
self.args.push(VaArg::c_int(ap.arg::<c_int>()))
}
self.args.push(match arg {
Some(arg) => VaArg::arg_from(arg, ap),
self.args.push(match default {
Some(default) => VaArg::arg_from(default, ap),
None => VaArg::c_int(ap.arg::<c_int>())
});
self.args[i]
+3
View File
@@ -26,6 +26,9 @@ Positional madness:
4 3 2
00002
|Fiz |Buz | Fiz| Tot|
int: 5 double: 0.100000 0.200000 0.300000 0.400000
-1717986918 0.100000
-1717986918 0.200000
Float madness:
1.234568e+02
+4
View File
@@ -33,6 +33,10 @@ int main(void) {
printf("%3$d %2$d %1$d\n", 2, 3, 4);
printf("%.*3$d\n", 2, 0, 5);
printf("|%-*6$.*5$s|%-*6$.*5$s|%*6$.*5$s|%*6$.*5$s|\n", "Fizz", "Buzz", "FizzBuzz", "TotalBuzz", 3, 8);
printf("int: %*6$d double: %lf %lf %lf %lf\n", 5, 0.1, 0.2, 0.3, 0.4, 10);
printf("%1$d %1$lf\n", 5, 0.1);
printf("%1$d %lf\n", 5, 0.2);
//printf("int: %*6$d no info on middle types\n", 5, 0.1, 0.2, 0.3, 0.4, 10);
puts("\nFloat madness:");
printf("%20e\n", 123.456789123);