printf: fix printf -%s- foo, printf -- -%s- foo (bug 3354)
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 18 May 2008 14:28:40 +0000 (14:28 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 18 May 2008 14:28:40 +0000 (14:28 -0000)
function                                             old     new   delta
printf_main                                          577     548     -29

coreutils/printf.c

index a9ef61f68f327bada1c8ae69f361e056cbf99500..a12f7cae7fc841db09f161fe70007be9d2b77586 100644 (file)
@@ -185,13 +185,10 @@ static void print_direc(char *start, size_t length, int field_width, int precisi
        free(p);
 }
 
-/* Print the text in FORMAT, using ARGV (with ARGC elements) for
-   arguments to any '%' directives.
-   Return the number of elements of ARGV used.  */
-
-static int print_formatted(char *format, int argc, char **argv)
+/* Print the text in FORMAT, using ARGV for arguments to any '%' directives.
+   Return advanced ARGV.  */
+static char **print_formatted(char *format, char **argv)
 {
-       int save_argc = argc;   /* Preserve original value.  */
        char *f;                /* Pointer into 'format'.  */
        char *direc_start;      /* Start of % directive.  */
        size_t direc_length;    /* Length of % directive.  */
@@ -209,10 +206,9 @@ static int print_formatted(char *format, int argc, char **argv)
                                break;
                        }
                        if (*f == 'b') {
-                               if (argc > 0) {
+                               if (*argv) {
                                        print_esc_string(*argv);
                                        ++argv;
-                                       --argc;
                                }
                                break;
                        }
@@ -223,10 +219,9 @@ static int print_formatted(char *format, int argc, char **argv)
                        if (*f == '*') {
                                ++f;
                                ++direc_length;
-                               if (argc > 0) {
+                               if (*argv) {
                                        field_width = my_xstrtoul(*argv);
                                        ++argv;
-                                       --argc;
                                } else
                                        field_width = 0;
                        } else {
@@ -241,10 +236,9 @@ static int print_formatted(char *format, int argc, char **argv)
                                if (*f == '*') {
                                        ++f;
                                        ++direc_length;
-                                       if (argc > 0) {
+                                       if (*argv) {
                                                precision = my_xstrtoul(*argv);
                                                ++argv;
-                                               --argc;
                                        } else
                                                precision = 0;
                                } else
@@ -262,11 +256,10 @@ static int print_formatted(char *format, int argc, char **argv)
                        fprintf(stderr, "%%%c: invalid directive", *f);
                        */
                        ++direc_length;
-                       if (argc > 0) {
+                       if (*argv) {
                                print_direc(direc_start, direc_length, field_width,
                                                        precision, *argv);
                                ++argv;
-                               --argc;
                        } else
                                print_direc(direc_start, direc_length, field_width,
                                                        precision, "");
@@ -282,32 +275,35 @@ static int print_formatted(char *format, int argc, char **argv)
                }
        }
 
-       return save_argc - argc;
+       return argv;
 }
 
 int printf_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int printf_main(int argc, char **argv)
+int printf_main(int argc ATTRIBUTE_UNUSED, char **argv)
 {
        char *format;
-       int args_used;
-
-       if (argc <= 1 || argv[1][0] == '-') {
+       char **argv2;
+
+       /* bash builtin errors out on "printf '-%s-\n' foo",
+        * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
+        * We will mimic coreutils. */
+       if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && argv[1][2] == '\0')
+               argv++;
+       if (!argv[1])
                bb_show_usage();
-       }
 
        format = argv[1];
-       argc -= 2;
-       argv += 2;
+       argv2 = argv + 2;
 
        do {
-               args_used = print_formatted(format, argc, argv);
-               argc -= args_used;
-               argv += args_used;
-       } while (args_used > 0 && argc > 0);
+               argv = argv2;
+               argv2 = print_formatted(format, argv);
+       } while (argv2 != argv && *argv2);
 
-/*     if (argc > 0)
+       /* coreutils compat (bash doesn't do this):
+       if (*argv)
                fprintf(stderr, "excess args ignored");
-*/
+       */
 
        return EXIT_SUCCESS;
 }