diff options
author | Ulrich Drepper <drepper@redhat.com> | 2009-04-11 05:34:20 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2009-04-11 05:34:20 +0000 |
commit | 9d26efa90c6dcbcd6b3e586c9927b6058ef4d529 (patch) | |
tree | fc306e24bf4b956abba8782e78d4118639c46361 /stdio-common/printf-parsemb.c | |
parent | f140a0d53d639c86408ac532091fb4644faa95c0 (diff) | |
download | glibc-9d26efa90c6dcbcd6b3e586c9927b6058ef4d529.tar.gz glibc-9d26efa90c6dcbcd6b3e586c9927b6058ef4d529.tar.xz glibc-9d26efa90c6dcbcd6b3e586c9927b6058ef4d529.zip |
* 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.
Diffstat (limited to 'stdio-common/printf-parsemb.c')
-rw-r--r-- | stdio-common/printf-parsemb.c | 123 |
1 files changed, 66 insertions, 57 deletions
diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c index da6fd3edb0..efd1eca3a2 100644 --- a/stdio-common/printf-parsemb.c +++ b/stdio-common/printf-parsemb.c @@ -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; - - 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')) + spec->info.user = 0; + + 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; |