mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-28 13:31:13 +00:00
5f83b2674e
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.
122 lines
3.8 KiB
C
122 lines
3.8 KiB
C
/* Internal header for parsing printf format strings.
|
|
Copyright (C) 1995-2023 Free Software Foundation, Inc.
|
|
This file is part of th GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include <printf.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
|
|
struct printf_spec
|
|
{
|
|
/* Information parsed from the format spec. */
|
|
struct printf_info info;
|
|
|
|
/* Pointers into the format string for the end of this format
|
|
spec and the next (or to the end of the string if no more). */
|
|
const UCHAR_T *end_of_fmt, *next_fmt;
|
|
|
|
/* Position of arguments for precision and width, or -1 if `info' has
|
|
the constant value. */
|
|
int prec_arg, width_arg;
|
|
|
|
int data_arg; /* Position of data argument. */
|
|
int data_arg_type; /* Type of first argument. */
|
|
/* Number of arguments consumed by this format specifier. */
|
|
size_t ndata_args;
|
|
/* Size of the parameter for PA_USER type. */
|
|
int size;
|
|
};
|
|
|
|
#ifndef DONT_NEED_READ_INT
|
|
/* Read a simple integer from a string and update the string pointer.
|
|
It is assumed that the first character is a digit. */
|
|
static int
|
|
read_int (const UCHAR_T * *pstr)
|
|
{
|
|
int retval = **pstr - L_('0');
|
|
|
|
while (ISDIGIT (*++(*pstr)))
|
|
if (retval >= 0)
|
|
{
|
|
if (INT_MAX / 10 < retval)
|
|
retval = -1;
|
|
else
|
|
{
|
|
int digit = **pstr - L_('0');
|
|
|
|
retval *= 10;
|
|
if (INT_MAX - digit < retval)
|
|
retval = -1;
|
|
else
|
|
retval += digit;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Find the next spec in FORMAT, or the end of the string. Returns
|
|
a pointer into FORMAT, to a '%' or a '\0'. */
|
|
__extern_always_inline const unsigned char *
|
|
__find_specmb (const unsigned char *format)
|
|
{
|
|
return (const unsigned char *) __strchrnul ((const char *) format, '%');
|
|
}
|
|
|
|
__extern_always_inline const unsigned int *
|
|
__find_specwc (const unsigned int *format)
|
|
{
|
|
return (const unsigned int *) __wcschrnul ((const wchar_t *) format, L'%');
|
|
}
|
|
|
|
|
|
/* FORMAT must point to a '%' at the beginning of a spec. Fills in *SPEC
|
|
with the parsed details. POSN is the number of arguments already
|
|
consumed. At most MAXTYPES - POSN types are filled in TYPES. Return
|
|
the number of args consumed by this spec; *MAX_REF_ARG is updated so it
|
|
remains the highest argument index used. *FAILED is set to indicate
|
|
whether parsing failed and printf should return with an error status. */
|
|
extern size_t __parse_one_specmb (const unsigned char *format, size_t posn,
|
|
struct printf_spec *spec,
|
|
size_t *max_ref_arg,
|
|
bool *failed) attribute_hidden;
|
|
|
|
extern size_t __parse_one_specwc (const unsigned int *format, size_t posn,
|
|
struct printf_spec *spec,
|
|
size_t *max_ref_arg,
|
|
bool *failed) attribute_hidden;
|
|
|
|
|
|
|
|
/* This variable is defined in reg-modifier.c. */
|
|
struct printf_modifier_record;
|
|
extern struct printf_modifier_record **__printf_modifier_table
|
|
attribute_hidden;
|
|
|
|
/* Handle registered modifiers. */
|
|
extern int __handle_registered_modifier_mb (const unsigned char **format,
|
|
struct printf_info *info)
|
|
attribute_hidden;
|
|
extern int __handle_registered_modifier_wc (const unsigned int **format,
|
|
struct printf_info *info)
|
|
attribute_hidden;
|