From 9d26efa90c6dcbcd6b3e586c9927b6058ef4d529 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 11 Apr 2009 05:34:20 +0000 Subject: * 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. --- stdio-common/vfprintf.c | 65 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'stdio-common/vfprintf.c') diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 5a24e725d5..38ba8ffdcd 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -238,7 +238,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* This table maps a character into a number representing a class. In each step there is a destination label for each class. */ - static const int jump_table[] = + static const uint8_t jump_table[] = { /* ' ' */ 1, 0, 0, /* '#' */ 4, 0, /* '%' */ 14, 0, /* '\''*/ 6, @@ -1630,6 +1630,7 @@ do_positional: size_t nargs = 0; int *args_type; union printf_arg *args_value = NULL; + int *args_size; /* Positional parameters refer to arguments directly. This could also determine the maximum number of arguments. Track the @@ -1684,6 +1685,7 @@ do_positional: memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0', nargs * sizeof (int)); args_value = alloca (nargs * sizeof (union printf_arg)); + args_size = alloca (nargs * sizeof (int)); /* XXX Could do sanity check here: If any element in ARGS_TYPE is still zero after this loop, format is invalid. For now we @@ -1704,8 +1706,10 @@ do_positional: { case 0: /* No arguments. */ break; - case 1: /* One argument; we already have the type. */ + case 1: /* One argument; we already have the + type and size. */ args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; + args_size[specs[cnt].data_arg] = specs[cnt].size; break; default: /* We have more than one argument for this format spec. @@ -1713,7 +1717,8 @@ do_positional: all the types. */ (void) (*__printf_arginfo_table[specs[cnt].info.spec]) (&specs[cnt].info, - specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); + specs[cnt].ndata_args, &args_type[specs[cnt].data_arg], + &args_size[specs[cnt].data_arg]); break; } } @@ -1760,6 +1765,13 @@ do_positional: default: if ((args_type[cnt] & PA_FLAG_PTR) != 0) args_value[cnt].pa_pointer = va_arg (ap_save, void *); + else if (__builtin_expect (__printf_va_arg_table != NULL, 0) + && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL) + { + args_value[cnt].pa_user = alloca (args_size[cnt]); + (*__printf_va_arg_table[args_type[cnt] - PA_LAST]) + (args_value[cnt].pa_user, &ap_save); + } else args_value[cnt].pa_long_double = 0.0; break; @@ -1863,6 +1875,40 @@ do_positional: /* Process format specifiers. */ while (1) { + extern printf_function **__printf_function_table; + int function_done; + + if (spec <= UCHAR_MAX + && __printf_function_table != NULL + && __printf_function_table[(size_t) spec] != NULL) + { + const void **ptr = alloca (specs[nspecs_done].ndata_args + * sizeof (const void *)); + + /* Fill in an array of pointers to the argument values. */ + for (unsigned int i = 0; i < specs[nspecs_done].ndata_args; + ++i) + ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; + + /* Call the function. */ + function_done = __printf_function_table[(size_t) spec] + (s, &specs[nspecs_done].info, ptr); + + if (function_done != -2) + { + /* If an error occurred we don't have information + about # of chars. */ + if (function_done < 0) + { + done = -1; + goto all_done; + } + + done_add (function_done); + break; + } + } + JUMP (spec, step4_jumps); process_arg ((&specs[nspecs_done])); @@ -1870,19 +1916,9 @@ do_positional: LABEL (form_unknown): { - extern printf_function **__printf_function_table; - int function_done; - printf_function *function; unsigned int i; const void **ptr; - function = - (__printf_function_table == NULL ? NULL : - __printf_function_table[specs[nspecs_done].info.spec]); - - if (function == NULL) - function = &printf_unknown; - ptr = alloca (specs[nspecs_done].ndata_args * sizeof (const void *)); @@ -1891,7 +1927,8 @@ do_positional: ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; /* Call the function. */ - function_done = (*function) (s, &specs[nspecs_done].info, ptr); + function_done = printf_unknown (s, &specs[nspecs_done].info, + ptr); /* If an error occurred we don't have information about # of chars. */ -- cgit 1.4.1