mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-07 06:43:00 +03:00
* stdio-common/printf.h (struct printf_info): Add user element.
New types printf_arginfo_size_function, printf_va_arg_function. Declare register_printf_specifier, register_printf_modifier, register_printf_type. * stdio-common/printf-parse.h (struct printf_spec): Add size element. (union printf_arg): Add pa_user element. Adjust __printf_arginfo_table type. Add __printf_va_arg_table, __printf_modifier_table, __handle_registered_modifier_mb, and __handle_registered_modifier_wc declarations. * stdio-common/printf-parsemb.c: Recognize registered modifiers. If registered arginfo call failed try normal specifier. * stdio-common/printf-prs.c: Pass additional parameter to arginfo function. * stdio-common/Makefile (routines): Add reg-modifier and reg-type. * stdio-common/Versions: Export register_printf_modifier, register_printf_type, and register_printf_specifier for GLIBC_2.10. * stdio-common/reg-modifier.c: New file. * stdio-common/reg-type.c: New file. * stdio-common/reg-printf.c (__register_printf_specifier): New function. Mostly the old __register_printf_function function but uses locking and type of third parameter changed. (__register_printf_function): Implement using __register_printf_specifier. * stdio-common/vfprintf.c (vfprintf): Collect argument sizes in calls to arginfo functions. Allocate enough memory for user-defined types. Call new va_arg functions to get user-defined types. Try installed handlers even for existing format specifiers first.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* Helper functions for parsing printf format strings.
|
||||
Copyright (C) 1995-2000,2002,2003,2004,2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-2000,2002-2004,2006,2009 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
|
||||
@@ -31,12 +31,14 @@
|
||||
# define INT_T int
|
||||
# define L_(Str) Str
|
||||
# define ISDIGIT(Ch) isdigit (Ch)
|
||||
# define HANDLE_REGISTERED_MODIFIER __handle_registered_modifier_mb
|
||||
#else
|
||||
# define CHAR_T wchar_t
|
||||
# define UCHAR_T unsigned int
|
||||
# define INT_T wint_t
|
||||
# define L_(Str) L##Str
|
||||
# define ISDIGIT(Ch) iswdigit (Ch)
|
||||
# define HANDLE_REGISTERED_MODIFIER __handle_registered_modifier_wc
|
||||
#endif
|
||||
|
||||
#include "printf-parse.h"
|
||||
@@ -223,72 +225,79 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
|
||||
spec->info.is_short = 0;
|
||||
spec->info.is_long = 0;
|
||||
spec->info.is_char = 0;
|
||||
spec->info.user = 0;
|
||||
|
||||
switch (*format++)
|
||||
{
|
||||
case L_('h'):
|
||||
/* ints are short ints or chars. */
|
||||
if (*format != L_('h'))
|
||||
spec->info.is_short = 1;
|
||||
else
|
||||
{
|
||||
++format;
|
||||
spec->info.is_char = 1;
|
||||
}
|
||||
break;
|
||||
case L_('l'):
|
||||
/* ints are long ints. */
|
||||
spec->info.is_long = 1;
|
||||
if (*format != L_('l'))
|
||||
if (__builtin_expect (__printf_modifier_table == NULL, 1)
|
||||
|| __printf_modifier_table[*format] == NULL
|
||||
|| HANDLE_REGISTERED_MODIFIER (&format, &spec->info) != 0)
|
||||
switch (*format++)
|
||||
{
|
||||
case L_('h'):
|
||||
/* ints are short ints or chars. */
|
||||
if (*format != L_('h'))
|
||||
spec->info.is_short = 1;
|
||||
else
|
||||
{
|
||||
++format;
|
||||
spec->info.is_char = 1;
|
||||
}
|
||||
break;
|
||||
++format;
|
||||
/* FALLTHROUGH */
|
||||
case L_('L'):
|
||||
/* doubles are long doubles, and ints are long long ints. */
|
||||
case L_('q'):
|
||||
/* 4.4 uses this for long long. */
|
||||
spec->info.is_long_double = 1;
|
||||
break;
|
||||
case L_('z'):
|
||||
case L_('Z'):
|
||||
/* ints are size_ts. */
|
||||
assert (sizeof (size_t) <= sizeof (unsigned long long int));
|
||||
case L_('l'):
|
||||
/* ints are long ints. */
|
||||
spec->info.is_long = 1;
|
||||
if (*format != L_('l'))
|
||||
break;
|
||||
++format;
|
||||
/* FALLTHROUGH */
|
||||
case L_('L'):
|
||||
/* doubles are long doubles, and ints are long long ints. */
|
||||
case L_('q'):
|
||||
/* 4.4 uses this for long long. */
|
||||
spec->info.is_long_double = 1;
|
||||
break;
|
||||
case L_('z'):
|
||||
case L_('Z'):
|
||||
/* ints are size_ts. */
|
||||
assert (sizeof (size_t) <= sizeof (unsigned long long int));
|
||||
#if LONG_MAX != LONG_LONG_MAX
|
||||
spec->info.is_long_double = sizeof (size_t) > sizeof (unsigned long int);
|
||||
spec->info.is_long_double = (sizeof (size_t)
|
||||
> sizeof (unsigned long int));
|
||||
#endif
|
||||
spec->info.is_long = sizeof (size_t) > sizeof (unsigned int);
|
||||
break;
|
||||
case L_('t'):
|
||||
assert (sizeof (ptrdiff_t) <= sizeof (long long int));
|
||||
spec->info.is_long = sizeof (size_t) > sizeof (unsigned int);
|
||||
break;
|
||||
case L_('t'):
|
||||
assert (sizeof (ptrdiff_t) <= sizeof (long long int));
|
||||
#if LONG_MAX != LONG_LONG_MAX
|
||||
spec->info.is_long_double = (sizeof (ptrdiff_t) > sizeof (long int));
|
||||
spec->info.is_long_double = (sizeof (ptrdiff_t) > sizeof (long int));
|
||||
#endif
|
||||
spec->info.is_long = sizeof (ptrdiff_t) > sizeof (int);
|
||||
break;
|
||||
case L_('j'):
|
||||
assert (sizeof (uintmax_t) <= sizeof (unsigned long long int));
|
||||
spec->info.is_long = sizeof (ptrdiff_t) > sizeof (int);
|
||||
break;
|
||||
case L_('j'):
|
||||
assert (sizeof (uintmax_t) <= sizeof (unsigned long long int));
|
||||
#if LONG_MAX != LONG_LONG_MAX
|
||||
spec->info.is_long_double = (sizeof (uintmax_t)
|
||||
> sizeof (unsigned long int));
|
||||
spec->info.is_long_double = (sizeof (uintmax_t)
|
||||
> sizeof (unsigned long int));
|
||||
#endif
|
||||
spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int);
|
||||
break;
|
||||
default:
|
||||
/* Not a recognized modifier. Backup. */
|
||||
--format;
|
||||
break;
|
||||
}
|
||||
spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int);
|
||||
break;
|
||||
default:
|
||||
/* Not a recognized modifier. Backup. */
|
||||
--format;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the format specification. */
|
||||
spec->info.spec = (wchar_t) *format++;
|
||||
if (__builtin_expect (__printf_function_table != NULL, 0)
|
||||
&& spec->info.spec <= UCHAR_MAX
|
||||
&& __printf_arginfo_table[spec->info.spec] != NULL)
|
||||
/* We don't try to get the types for all arguments if the format
|
||||
uses more than one. The normal case is covered though. */
|
||||
spec->ndata_args = (*__printf_arginfo_table[spec->info.spec])
|
||||
(&spec->info, 1, &spec->data_arg_type);
|
||||
else
|
||||
spec->size = -1;
|
||||
if (__builtin_expect (__printf_function_table == NULL, 1)
|
||||
|| spec->info.spec > UCHAR_MAX
|
||||
|| __printf_arginfo_table[spec->info.spec] == NULL
|
||||
/* We don't try to get the types for all arguments if the format
|
||||
uses more than one. The normal case is covered though. If
|
||||
the call returns -1 we continue with the normal specifiers. */
|
||||
|| (spec->ndata_args = (*__printf_arginfo_table[spec->info.spec])
|
||||
(&spec->info, 1, &spec->data_arg_type,
|
||||
&spec->size)) < 0)
|
||||
{
|
||||
/* Find the data argument types of a built-in spec. */
|
||||
spec->ndata_args = 1;
|
||||
|
Reference in New Issue
Block a user