glibc/stdio-common/printf-parse.h
Joseph Myers 5f83b2674e 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.
2023-06-19 18:52:12 +00:00

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;