aboutsummaryrefslogtreecommitdiff
path: root/stdio-common/printf-parsemb.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2023-06-19 18:52:12 +0000
committerJoseph Myers <joseph@codesourcery.com>2023-06-19 18:52:12 +0000
commit5f83b2674e42cd74257731b281f66d0442bf045f (patch)
treecb4d3f19d481d718c4800218f20afc93441199e3 /stdio-common/printf-parsemb.c
parent8022fc7d5119a22e9e0ac72798f649385b0e167a (diff)
downloadglibc-5f83b2674e42cd74257731b281f66d0442bf045f.zip
glibc-5f83b2674e42cd74257731b281f66d0442bf045f.tar.gz
glibc-5f83b2674e42cd74257731b281f66d0442bf045f.tar.bz2
C2x printf %wN, %wfN support (bug 24466)
ISO C2x defines printf length modifiers wN (for intN_t / int_leastN_t / uintN_t / uint_leastN_t) and wfN (for int_fastN_t / uint_fastN_t). Add support for those length modifiers (such a feature was previously requested in bug 24466). scanf support is to be added separately. GCC 13 has format checking support for these modifiers. When used with the support for registering format specifiers, these modifiers are translated to existing flags in struct printf_info, rather than trying to add some way of distinguishing them without breaking the printf_info ABI. C2x requires an error to be returned for unsupported values of N; this is implemented for printf-family functions, but the parse_printf_format interface doesn't support error returns, so such an error gets discarded by that function. Tested for x86_64 and x86.
Diffstat (limited to 'stdio-common/printf-parsemb.c')
-rw-r--r--stdio-common/printf-parsemb.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c
index c5d2704..414cbc7 100644
--- a/stdio-common/printf-parsemb.c
+++ b/stdio-common/printf-parsemb.c
@@ -56,14 +56,17 @@ size_t
attribute_hidden
#ifdef COMPILE_WPRINTF
__parse_one_specwc (const UCHAR_T *format, size_t posn,
- struct printf_spec *spec, size_t *max_ref_arg)
+ struct printf_spec *spec, size_t *max_ref_arg,
+ bool *failed)
#else
__parse_one_specmb (const UCHAR_T *format, size_t posn,
- struct printf_spec *spec, size_t *max_ref_arg)
+ struct printf_spec *spec, size_t *max_ref_arg,
+ bool *failed)
#endif
{
unsigned int n;
size_t nargs = 0;
+ bool is_fast;
/* Skip the '%'. */
++format;
@@ -81,6 +84,8 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
spec->info.wide = sizeof (UCHAR_T) > 1;
spec->info.is_binary128 = 0;
+ *failed = false;
+
/* Test for positional argument. */
if (ISDIGIT (*format))
{
@@ -298,6 +303,53 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
#endif
spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int);
break;
+ case L_('w'):
+ is_fast = false;
+ if (*format == L_('f'))
+ {
+ ++format;
+ is_fast = true;
+ }
+ int bitwidth = 0;
+ if (ISDIGIT (*format))
+ bitwidth = read_int (&format);
+ if (is_fast)
+ switch (bitwidth)
+ {
+ case 8:
+ bitwidth = INT_FAST8_WIDTH;
+ break;
+ case 16:
+ bitwidth = INT_FAST16_WIDTH;
+ break;
+ case 32:
+ bitwidth = INT_FAST32_WIDTH;
+ break;
+ case 64:
+ bitwidth = INT_FAST64_WIDTH;
+ break;
+ }
+ switch (bitwidth)
+ {
+ case 8:
+ spec->info.is_char = 1;
+ break;
+ case 16:
+ spec->info.is_short = 1;
+ break;
+ case 32:
+ break;
+ case 64:
+ spec->info.is_long_double = 1;
+ spec->info.is_long = 1;
+ break;
+ default:
+ /* ISO C requires this error to be detected. */
+ __set_errno (EINVAL);
+ *failed = true;
+ break;
+ }
+ break;
default:
/* Not a recognized modifier. Backup. */
--format;