浏览代码

More printf tests and corner cases

jD91mZM2 6 年之前
父节点
当前提交
8fca7bcbc1
共有 3 个文件被更改,包括 75 次插入3 次删除
  1. 68 3
      src/header/stdio/printf.rs
  2. 3 0
      tests/expected/stdio/printf.stdout
  3. 4 0
      tests/stdio/printf.c

+ 68 - 3
src/header/stdio/printf.rs

@@ -126,6 +126,67 @@ impl VaArg {
                 => VaArg::pointer(ap.arg::<*const c_void>()),
                 => 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)]
 #[derive(Default)]
 struct VaListCache {
 struct VaListCache {
@@ -133,8 +194,12 @@ struct VaListCache {
     i: usize
     i: usize
 }
 }
 impl VaListCache {
 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) {
         if let Some(&arg) = self.args.get(i) {
+            let mut arg = arg;
+            if let Some(default) = default {
+                arg = arg.transmute(default);
+            }
             return arg;
             return arg;
         }
         }
         while self.args.len() < i {
         while self.args.len() < i {
@@ -144,8 +209,8 @@ impl VaListCache {
             // defaulting to c_int.
             // defaulting to c_int.
             self.args.push(VaArg::c_int(ap.arg::<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>())
             None => VaArg::c_int(ap.arg::<c_int>())
         });
         });
         self.args[i]
         self.args[i]

+ 3 - 0
tests/expected/stdio/printf.stdout

@@ -26,6 +26,9 @@ Positional madness:
 4 3 2
 4 3 2
 00002
 00002
 |Fiz     |Buz     |     Fiz|     Tot|
 |Fiz     |Buz     |     Fiz|     Tot|
+int:          5 double: 0.100000 0.200000 0.300000 0.400000
+-1717986918 0.100000
+-1717986918 0.200000
 
 
 Float madness:
 Float madness:
         1.234568e+02
         1.234568e+02

+ 4 - 0
tests/stdio/printf.c

@@ -33,6 +33,10 @@ int main(void) {
     printf("%3$d %2$d %1$d\n", 2, 3, 4);
     printf("%3$d %2$d %1$d\n", 2, 3, 4);
     printf("%.*3$d\n", 2, 0, 5);
     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("|%-*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:");
     puts("\nFloat madness:");
     printf("%20e\n", 123.456789123);
     printf("%20e\n", 123.456789123);