From 2bf151cd937dd44f00bc7249d5d8d95e9a34f207 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 26 Oct 2008 00:45:18 -0700 Subject: [PATCH] seq: improve quality of format-checking code * src/seq.c (validate_format): Remove. Migrate its checks into... (long_double_format): Report an error and exit if an error is found, instead of returning NULL. All callers changed. Use a more-consistent format for diagnostics. * tests/misc/seq: Adjust to the more-consistent format for diagnostics. --- src/seq.c | 71 +++++++++++++++++----------------------------------------- tests/misc/seq | 10 ++++----- 2 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/seq.c b/src/seq.c index 3ae158b08..5f9da963b 100644 --- a/src/seq.c +++ b/src/seq.c @@ -174,37 +174,10 @@ scan_arg (const char *arg) return ret; } -/* Validate the format, FMT. Print a diagnostic and exit - if there is not exactly one %-directive. */ - -static void -validate_format (char const *fmt) -{ - unsigned int n_directives = 0; - char const *p; - - for (p = fmt; *p; p++) - { - if (p[0] == '%' && p[1] != '%' && p[1] != '\0') - { - ++n_directives; - ++p; - } - } - if (n_directives == 0) - { - error (0, 0, _("no %% directive in format string %s"), quote (fmt)); - usage (EXIT_FAILURE); - } - else if (1 < n_directives) - error (EXIT_FAILURE, 0, _("too many %% directives in format string %s"), - quote (fmt)); -} - /* If FORMAT is a valid printf format for a double argument, return - its long double equivalent, possibly allocated from dynamic - storage, and store into *LAYOUT a description of the output layout; - otherwise, return NULL. */ + its long double equivalent, allocated from dynamic storage, and + store into *LAYOUT a description of the output layout; otherwise, + report an error and exit. */ static char const * long_double_format (char const *fmt, struct layout *layout) @@ -216,10 +189,12 @@ long_double_format (char const *fmt, struct layout *layout) bool has_L; for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1) - if (fmt[i]) + { + if (!fmt[i]) + error (EXIT_FAILURE, 0, + _("format %s has no %% directive"), quote (fmt)); prefix_len++; - else - return NULL; + } i++; i += strspn (fmt + i, "-+#0 '"); @@ -233,12 +208,17 @@ long_double_format (char const *fmt, struct layout *layout) length_modifier_offset = i; has_L = (fmt[i] == 'L'); i += has_L; - /* In a valid format string, fmt[i] must be one of these specifiers. */ - if (fmt[i] == '\0' || ! strchr ("efgaEFGA", fmt[i])) - return NULL; - - for (i++; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1) - if (fmt[i]) + if (fmt[i] == '\0') + error (EXIT_FAILURE, 0, _("format %s ends in %%"), quote (fmt)); + if (! strchr ("efgaEFGA", fmt[i])) + error (EXIT_FAILURE, 0, + _("format %s has unknown %%%c directive"), quote (fmt), fmt[i]); + + for (i++; ; i += (fmt[i] == '%') + 1) + if (fmt[i] == '%' && fmt[i + 1] != '%') + error (EXIT_FAILURE, 0, _("format %s has too many %% directives"), + quote (fmt)); + else if (fmt[i]) suffix_len++; else { @@ -252,8 +232,6 @@ long_double_format (char const *fmt, struct layout *layout) layout->suffix_len = suffix_len; return ldfmt; } - - return NULL; } /* Actually print the sequence of numbers in the specified range, with the @@ -432,16 +410,7 @@ main (int argc, char **argv) } if (format_str) - { - validate_format (format_str); - char const *f = long_double_format (format_str, &layout); - if (! f) - { - error (0, 0, _("invalid format string: %s"), quote (format_str)); - usage (EXIT_FAILURE); - } - format_str = f; - } + format_str = long_double_format (format_str, &layout); last = scan_arg (argv[optind++]); diff --git a/tests/misc/seq b/tests/misc/seq index 227132208..7f808cf6c 100755 --- a/tests/misc/seq +++ b/tests/misc/seq @@ -81,20 +81,20 @@ my @Tests = # In coreutils-[6.0..6.9], this would mistakenly succeed and print "%Lg". ['fmt-c', qw(-f %%g 1), {EXIT => 1}, - {ERR => "seq: invalid format string: `%%g'\n" . $try_help }], + {ERR => "seq: format `%%g' has no % directive\n"}], # In coreutils-6.9..6.10, this would fail with an erroneous diagnostic: # "seq: memory exhausted". In coreutils-6.0..6.8, it would mistakenly # succeed and print a blank line. ['fmt-eos1', qw(-f % 1), {EXIT => 1}, - {ERR => "seq: no % directive in format string `%'\n" . $try_help }], + {ERR => "seq: format `%' ends in %\n"}], ['fmt-eos2', qw(-f %g% 1), {EXIT => 1}, - {ERR => "seq: invalid format string: `%g%'\n" . $try_help }], + {ERR => "seq: format `%g%' has too many % directives\n"}], ['fmt-d', qw(-f "" 1), {EXIT => 1}, - {ERR => "seq: no % directive in format string `'\n" . $try_help }], + {ERR => "seq: format `' has no % directive\n"}], ['fmt-e', qw(-f %g%g 1), {EXIT => 1}, - {ERR => "seq: too many % directives in format string `%g%g'\n"}], + {ERR => "seq: format `%g%g' has too many % directives\n"}], # With coreutils-6.12 and earlier, with a UTF8 numeric locale that uses # something other than "." as the decimal point, this use of seq would -- 2.11.4.GIT