Add support for Shell printf format strings, part 3.

* gettext-tools/src/format-invalid.h (INVALID_FLAG_FOR): New macro.
* gettext-tools/src/format-java-printf.c (INVALID_FLAG_FOR): Remove macro.
* gettext-tools/src/format-sh-printf.c (format_parse): Reject format strings
with invalid flag+specifier combinations.
* gettext-tools/tests/format-sh-printf-1: Add more test cases.
* gettext-tools/doc/gettext.texi (sh-format): Mention the ' flag.
This commit is contained in:
Bruno Haible 2025-06-23 21:20:02 +02:00
parent c6373812d7
commit 2fdcb6546c
5 changed files with 54 additions and 3 deletions

View File

@ -10266,6 +10266,9 @@ but without the obsolescent @code{b} conversion specifier.
Extensions by the GNU coreutils @samp{printf} command
(@url{https://www.gnu.org/software/coreutils/manual/html_node/printf-invocation.html})
are not supported:
use of the @samp{'} flag in the
@code{%i}, @code{%d}, @code{%u}, @code{%f}, @code{%F}, @code{%g}, @code{%G}
directives;
use of @samp{*} or @samp{*@var{m}$} as width or precision;
use of size specifiers @code{h}, @code{l}, @code{j}, @code{z}, @code{t} (ignored);
and the escape sequences @code{\c},

View File

@ -39,5 +39,8 @@
? xasprintf (_("In the directive number %u, the character '%c' is not a valid conversion specifier."), directive_number, conv_char) \
: xasprintf (_("The character that terminates the directive number %u is not a valid conversion specifier."), directive_number))
#define INVALID_FLAG_FOR(directive_number,flag_char,conv_char) \
xasprintf (_("In the directive number %u, the flag '%c' is invalid for the conversion '%c'."), directive_number, flag_char, conv_char)
#define INVALID_INCOMPATIBLE_ARG_TYPES(arg_number) \
xasprintf (_("The string refers to argument number %u in incompatible ways."), arg_number)

View File

@ -131,9 +131,6 @@ numbered_arg_compare (const void *p1, const void *p2)
#define INVALID_LAST_ARG(directive_number) \
xasprintf (_("In the directive number %u, the reference to the argument of the previous directive is invalid."), directive_number)
#define INVALID_FLAG_FOR(directive_number,flag_char,conv_char) \
xasprintf (_("In the directive number %u, the flag '%c' is invalid for the conversion '%c'."), directive_number, flag_char, conv_char)
#define INVALID_WIDTH_FOR(directive_number,conv_char) \
xasprintf (_("In the directive number %u, a width is invalid for the conversion '%c'."), directive_number, conv_char)

View File

@ -65,6 +65,9 @@
- 'u', 'o', 'x', 'X', that need an unsigned integer argument,
- [optional in POSIX, but supported here:] 'e', 'E', 'f', 'F', 'g', 'G',
'a', 'A', that need a floating-point argument.
Some flag+specifier combinations are invalid:
- The '#' flag with the specifiers 'c', 's', 'i', 'd', 'u'.
- The '0' flag with the specifiers 'c', 's'.
Additionally there is the directive '%%', which takes no argument.
Numbered ('%m$' or '*m$') and unnumbered argument specifications cannot
be used in the same string.
@ -172,11 +175,17 @@ format_parse (const char *format, bool translated, char *fdi,
}
/* Parse flags. */
bool have_hash_flag = false;
bool have_zero_flag = false;
while (*format == ' ' || *format == '+' || *format == '-'
|| *format == '#' || *format == '0')
{
if (*format == ' ')
likely_intentional = false;
if (*format == '#')
have_hash_flag = true;
if (*format == '0')
have_zero_flag = true;
format++;
}
@ -228,6 +237,23 @@ format_parse (const char *format, bool translated, char *fdi,
goto bad_format;
}
if (have_hash_flag
&& (*format == 'c' || *format == 's'
|| *format == 'i' || *format == 'd' || *format == 'u'))
{
*invalid_reason =
INVALID_FLAG_FOR (spec.directives, '#', *format);
FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (have_zero_flag && (*format == 'c' || *format == 's'))
{
*invalid_reason =
INVALID_FLAG_FOR (spec.directives, '0', *format);
FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (number)
{
/* Numbered argument. */

View File

@ -103,6 +103,28 @@ LC_ALL=C sed -e "$escape_backslashes" <<\EOF > f-sp-1.data
"abc%3$*2$.*1$g"
# Invalid: zero
"abc%2$*0$.*1$g"
# Invalid: flag not valid
"abc%'d"
# Invalid: flag not valid
"abc%'u"
# Invalid: flag not valid
"abc%'f"
# Invalid: flag not valid
"abc%'g"
# Invalid: flag not valid for specifier
"abc%#c"
# Invalid: flag not valid for specifier
"abc%#s"
# Invalid: flag not valid for specifier
"abc%#i"
# Invalid: flag not valid for specifier
"abc%#d"
# Invalid: flag not valid for specifier
"abc%#u"
# Invalid: flag not valid for specifier
"abc%0c"
# Invalid: flag not valid for specifier
"abc%0s"
# Valid: escape sequence
"abc%%def\\"
# Valid: escape sequence