mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-11 14:44:18 +02:00
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.
This commit is contained in:
committed by
Jim Meyering
parent
153477479a
commit
2bf151cd93
69
src/seq.c
69
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;
|
||||
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++; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1)
|
||||
if (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++]);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user