printf: do not print garbage on "%Ld". closes bug 4214.
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 18 Jul 2008 18:41:55 +0000 (18:41 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 18 Jul 2008 18:41:55 +0000 (18:41 -0000)
function                                             old     new   delta
printf_main                                          633     637      +4
multiconvert                                          99      79     -20
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 4/-20)             Total: -16 bytes

coreutils/printf.c
testsuite/printf.tests

index ca035cc48507f5b6c9b715ba33f00ff352bcec62..7f6235a874b944144a113a51385fa8a59ef42ce7 100644 (file)
@@ -63,11 +63,8 @@ typedef void FAST_FUNC (*converter)(const char *arg, void *result);
 
 static int multiconvert(const char *arg, void *result, converter convert)
 {
-       char s[sizeof(int)*3 + 2];
-
        if (*arg == '"' || *arg == '\'') {
-               sprintf(s, "%d", (unsigned char)arg[1]);
-               arg = s;
+               arg = utoa((unsigned char)arg[1]);
        }
        errno = 0;
        convert(arg, result);
@@ -289,10 +286,22 @@ static char **print_formatted(char *f, char **argv)
                                        }
                                }
                        }
+                       /* Remove size modifiers - "%Ld" would try to printf
+                        * long long, we pass long, and it spews garbage */
                        if ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') {
-                               ++f;
-                               ++direc_length;
+                               strcpy(f, f + 1);
                        }
+//FIXME: actually, the same happens with bare "%d":
+//it printfs an int, but we pass long!
+//What saves us is that on most arches stack slot
+//is pointer-sized -> long-sized -> ints are promoted to longs
+// for variadic functions -> printf("%d", int_v) is in reality
+// indistinqushable from printf("%d", long_v) ->
+// since printf("%d", int_v) works, printf("%d", long_v) has to work.
+//But "clean" solution would be to add "l" to d,i,o,x,X.
+//Probably makes sense to go all the way to "ll" then.
+//Coreutils support long long-sized arguments.
+
                        /* needed - try "printf %" without it */
                        if (!strchr("diouxXfeEgGcs", *f)) {
                                bb_error_msg("%s: invalid format", direc_start);
index a5c71ec9d427962ec4fac24c0ac813d889f4d084..f9d1decae908a07ae9d2ba95f18bbb991482442d 100755 (executable)
@@ -74,6 +74,11 @@ testing "printf understands %ld" \
        "-5\n""0\n" \
        "" ""
 
+testing "printf understands %Ld" \
+       "${bb}printf '%Ld\n' -5 2>&1; echo \$?" \
+       "-5\n""0\n" \
+       "" ""
+
 # We are "more correct" here than bash/coreutils: they happily print -2
 # as if it is a huge unsigned number
 testing "printf handles %u -N" \