summaryrefslogtreecommitdiff
path: root/stdio-common/printf-parsemb.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/printf-parsemb.c')
-rw-r--r--stdio-common/printf-parsemb.c123
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;