From: Bruno Haible Date: Mon, 23 Jun 2025 19:20:02 +0000 (+0200) Subject: Add support for Shell printf format strings, part 3. X-Git-Tag: v0.26~72 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2fdcb6546c245744f3e5a5056602be1ccebb34cf;p=thirdparty%2Fgettext.git 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. --- diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi index ce2c0f09d..fcbb42130 100644 --- a/gettext-tools/doc/gettext.texi +++ b/gettext-tools/doc/gettext.texi @@ -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}, diff --git a/gettext-tools/src/format-invalid.h b/gettext-tools/src/format-invalid.h index 763ca5988..c38daf5ab 100644 --- a/gettext-tools/src/format-invalid.h +++ b/gettext-tools/src/format-invalid.h @@ -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) diff --git a/gettext-tools/src/format-java-printf.c b/gettext-tools/src/format-java-printf.c index a22bbf50e..99f476941 100644 --- a/gettext-tools/src/format-java-printf.c +++ b/gettext-tools/src/format-java-printf.c @@ -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) diff --git a/gettext-tools/src/format-sh-printf.c b/gettext-tools/src/format-sh-printf.c index bcaf2d188..feb2b9309 100644 --- a/gettext-tools/src/format-sh-printf.c +++ b/gettext-tools/src/format-sh-printf.c @@ -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. */ diff --git a/gettext-tools/tests/format-sh-printf-1 b/gettext-tools/tests/format-sh-printf-1 index ee76814a0..e304f2320 100755 --- a/gettext-tools/tests/format-sh-printf-1 +++ b/gettext-tools/tests/format-sh-printf-1 @@ -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