From bf4aeed129ba7518be04ab9e53073bdb737a24b8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 18 Jun 2009 22:22:04 +0200 Subject: [PATCH] printf: fix exit code on conversion error Signed-off-by: Colin Watson Signed-off-by: Denys Vlasenko --- coreutils/printf.c | 24 +++++++++++------------- testsuite/printf.tests | 3 +-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/coreutils/printf.c b/coreutils/printf.c index 2beea7189..5b326c643 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -53,10 +53,7 @@ * (but negative numbers are not "bad"). * Both accept negative numbers for %u specifier. * - * We try to be compatible. We are not compatible here: - * - we do not accept -NUM for %u - * - exit code is 0 even if "invalid number" was seen (FIXME) - * See "if (errno)" checks in the code below. + * We try to be compatible. */ typedef void FAST_FUNC (*converter)(const char *arg, void *result); @@ -163,7 +160,6 @@ static void print_direc(char *format, unsigned fmt_length, case 'i': llv = my_xstrtoll(argument); print_long: - /* if (errno) return; - see comment at the top */ if (!have_width) { if (!have_prec) printf(format, llv); @@ -210,7 +206,6 @@ static void print_direc(char *format, unsigned fmt_length, case 'g': case 'G': dv = my_xstrtod(argument); - /* if (errno) return; */ if (!have_width) { if (!have_prec) printf(format, dv); @@ -241,7 +236,7 @@ static int get_width_prec(const char *str) /* Print the text in FORMAT, using ARGV for arguments to any '%' directives. Return advanced ARGV. */ -static char **print_formatted(char *f, char **argv) +static char **print_formatted(char *f, char **argv, int *conv_err) { char *direc_start; /* Start of % directive. */ unsigned direc_length; /* Length of % directive. */ @@ -299,8 +294,8 @@ static char **print_formatted(char *f, char **argv) /* Remove "lLhz" size modifiers, repeatedly. * bash does not like "%lld", but coreutils - * would happily take even "%Llllhhzhhzd"! - * We will be permissive like coreutils */ + * happily takes even "%Llllhhzhhzd"! + * We are permissive like coreutils */ while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { overlapping_strcpy(f, f + 1); } @@ -330,12 +325,12 @@ static char **print_formatted(char *f, char **argv) } if (*argv) { print_direc(direc_start, direc_length, field_width, - precision, *argv); - ++argv; + precision, *argv++); } else { print_direc(direc_start, direc_length, field_width, precision, ""); } + *conv_err |= errno; free(p); } break; @@ -356,6 +351,7 @@ static char **print_formatted(char *f, char **argv) int printf_main(int argc UNUSED_PARAM, char **argv) { + int conv_err; char *format; char **argv2; @@ -392,9 +388,10 @@ int printf_main(int argc UNUSED_PARAM, char **argv) format = argv[1]; argv2 = argv + 2; + conv_err = 0; do { argv = argv2; - argv2 = print_formatted(format, argv); + argv2 = print_formatted(format, argv, &conv_err); } while (argv2 > argv && *argv2); /* coreutils compat (bash doesn't do this): @@ -402,5 +399,6 @@ int printf_main(int argc UNUSED_PARAM, char **argv) fprintf(stderr, "excess args ignored"); */ - return (argv2 < argv); /* if true, print_formatted errored out */ + return (argv2 < argv) /* if true, print_formatted errored out */ + || conv_err; /* print_formatted saw invalid number */ } diff --git a/testsuite/printf.tests b/testsuite/printf.tests index 558ecb194..0a63f0f57 100755 --- a/testsuite/printf.tests +++ b/testsuite/printf.tests @@ -87,13 +87,12 @@ testing "printf understands %Ld" \ # "1\n""printf: -2: invalid number\n""0\n""3\n""0\n" \ # "" "" -# Actually, we are wrong here: exit code should be 1 testing "printf handles %d bad_input" \ "${bb}printf '%d\n' 1 - 2 bad 3 123bad 4 2>&1; echo \$?" \ "1\n""printf: -: invalid number\n""0\n"\ "2\n""printf: bad: invalid number\n""0\n"\ "3\n""printf: 123bad: invalid number\n""0\n"\ -"4\n""0\n" \ +"4\n""1\n" \ "" "" testing "printf aborts on bare %" \