[5/6] vfprintf: Introduce printf_positional function
Commit Message
This splits a considerable chunk of code from the main vfprintf
function. This will make it easier to remove the use of extend_alloca
from the positional argument handling code.
---
stdio-common/vfprintf.c | 716 +++++++++++++++++++++++++-----------------------
1 file changed, 369 insertions(+), 347 deletions(-)
Comments
On 03/01/2015 10:16 PM, Florian Weimer wrote:
> This splits a considerable chunk of code from the main vfprintf
> function. This will make it easier to remove the use of extend_alloca
> from the positional argument handling code.
Inspection of the generated assembly on x86_64 shows that splitting the
two functions helps GCC 4.9 with register allocation; there are fewer
spills.
I used the following totally made-up benchmark to see if there is a
performance regression.
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <err.h>
#ifdef POSITIONAL
#define FORMAT " %1$d: %2$c%3$c%4$c%5$c%6$c %7$20s %8$f (%9$02x)\n"
#else
#define FORMAT " %d: %c%c%c%c%c %20s %f (%02x)\n"
#endif
int
main (int argc, char **argv)
{
int iterations = atoi (argv[1]);
struct timespec ts_start;
if (clock_gettime (CLOCK_MONOTONIC_RAW, &ts_start) != 0)
err (1, "clock_gettime");
for (int i = 0; i < iterations; ++i)
{
char buf[256];
sprintf (buf, FORMAT,
1001, '1', '2', '3', '4', '5', "string", 1.5, 0x1234);
}
struct timespec ts_end;
if (clock_gettime (CLOCK_MONOTONIC_RAW, &ts_end) != 0)
err (1, "clock_gettime");
printf ("%f\n",
ts_end.tv_sec + ts_end.tv_nsec * 1e-9
- ts_start.tv_sec - ts_start.tv_nsec * 1e-9);
return 0;
}
t-test without -DPOSITONAL (50 runs):
data: before and after
t = 3.8079, df = 91.121, p-value = 0.0002539
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.01236649 0.03933739
sample estimates:
mean of x mean of y
1.0200367 0.9941847
t-test with -DPOSITIONAL=1 (50 runs):
data: before and after
t = 5.2566, df = 65.134, p-value = 1.74e-06
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.06132365 0.13646651
sample estimates:
mean of x mean of y
1.749552 1.650657
On 03/06/2015 07:57 AM, Florian Weimer wrote:
> On 03/01/2015 10:16 PM, Florian Weimer wrote:
>> This splits a considerable chunk of code from the main vfprintf
>> function. This will make it easier to remove the use of extend_alloca
>> from the positional argument handling code.
>
> Inspection of the generated assembly on x86_64 shows that splitting the
> two functions helps GCC 4.9 with register allocation; there are fewer
> spills.
Awesome.
> I used the following totally made-up benchmark to see if there is a
> performance regression.
Made up or not, it's a microbenchmark you used to test the changes.
Could you please post this as a separate patch for inclusion into
benchtests/ as a positional printf microbenchmark? That way we have
a record of what was used, and can look at changes to printf as we
adjust this code?
Cheers,
Carlos.
On 03/01/2015 04:16 PM, Florian Weimer wrote:
> This splits a considerable chunk of code from the main vfprintf
> function. This will make it easier to remove the use of extend_alloca
> from the positional argument handling code.
> ---
> stdio-common/vfprintf.c | 716 +++++++++++++++++++++++++-----------------------
> 1 file changed, 369 insertions(+), 347 deletions(-)
This patch is OK to checkin modulo testing with the new
bench-sprintf I just posted downthread.
> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
> index da52dbc..6e840aa 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf.c
> @@ -204,6 +204,14 @@ static const CHAR_T null[] = L_("(null)");
> static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
> __THROW __attribute__ ((noinline)) internal_function;
>
> +/* Handle positional format specifiers. */
> +static int printf_positional (_IO_FILE *s,
> + const CHAR_T *format, int readonly_format,
> + va_list ap, va_list *ap_savep, int done,
> + int nspecs_done, const UCHAR_T *lead_str_end,
> + CHAR_T *work_buffer, int save_errno,
> + const char *grouping, THOUSANDS_SEP_T);
OK. That's a lot of arguments, but we've already discussed the performance
impact downthread.
> +
> /* Handle unknown format specifier. */
> static int printf_unknown (FILE *, const struct printf_info *,
> const void *const *) __THROW;
> @@ -1257,15 +1265,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> 0 if unknown. */
> int readonly_format = 0;
>
> - /* For the argument descriptions, which may be allocated on the heap. */
> - void *args_malloced = NULL;
> -
> - /* For positional argument handling. */
> - struct printf_spec *specs;
> -
> - /* Track if we malloced the SPECS array and thus must free it. */
> - bool specs_malloced = false;
> -
OK.
> /* Orient the stream. */
> #ifdef ORIENT
> ORIENT;
> @@ -1670,232 +1669,265 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> /* Unlock stream and return. */
> goto all_done;
>
> - /* Here starts the more complex loop to handle positional parameters. */
> + /* Hand off processing for positional parameters. */
> do_positional:
> - {
> - /* Array with information about the needed arguments. This has to
> - be dynamically extensible. */
> - size_t nspecs = 0;
> - /* A more or less arbitrary start value. */
> - size_t nspecs_size = 32 * sizeof (struct printf_spec);
> -
> - specs = alloca (nspecs_size);
> - /* The number of arguments the format string requests. This will
> - determine the size of the array needed to store the argument
> - attributes. */
> - size_t nargs = 0;
> - size_t bytes_per_arg;
> - union printf_arg *args_value;
> - int *args_size;
> - int *args_type;
> -
> - /* Positional parameters refer to arguments directly. This could
> - also determine the maximum number of arguments. Track the
> - maximum number. */
> - size_t max_ref_arg = 0;
> -
> - /* Just a counter. */
> - size_t cnt;
> -
> - if (__glibc_unlikely (workstart != NULL))
> + if (__glibc_unlikely (workstart != NULL))
> + {
> free (workstart);
> - workstart = NULL;
> + workstart = NULL;
> + }
> + done = printf_positional (s, format, readonly_format, ap, &ap_save,
> + done, nspecs_done, lead_str_end, work_buffer,
> + save_errno, grouping, thousands_sep);
OK.
>
> - if (grouping == (const char *) -1)
> - {
> + all_done:
> + if (__glibc_unlikely (workstart != NULL))
> + free (workstart);
> + /* Unlock the stream. */
> + _IO_funlockfile (s);
> + _IO_cleanup_region_end (0);
> +
> + return done;
OK.
> +}
> +
> +static int
> +printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
> + va_list ap, va_list *ap_savep, int done, int nspecs_done,
> + const UCHAR_T *lead_str_end,
> + CHAR_T *work_buffer, int save_errno,
> + const char *grouping, THOUSANDS_SEP_T thousands_sep)
> +{
> + /* For the argument descriptions, which may be allocated on the heap. */
> + void *args_malloced = NULL;
> +
> + /* For positional argument handling. */
> + struct printf_spec *specs;
> +
> + /* Track if we malloced the SPECS array and thus must free it. */
> + bool specs_malloced = false;
> +
> + /* Array with information about the needed arguments. This has to
> + be dynamically extensible. */
> + size_t nspecs = 0;
> + /* A more or less arbitrary start value. */
> + size_t nspecs_size = 32 * sizeof (struct printf_spec);
> +
> + specs = alloca (nspecs_size);
> + /* The number of arguments the format string requests. This will
> + determine the size of the array needed to store the argument
> + attributes. */
> + size_t nargs = 0;
> + size_t bytes_per_arg;
> + union printf_arg *args_value;
> + int *args_size;
> + int *args_type;
> +
> + /* Positional parameters refer to arguments directly. This could
> + also determine the maximum number of arguments. Track the
> + maximum number. */
> + size_t max_ref_arg = 0;
> +
> + /* Just a counter. */
> + size_t cnt;
> +
> + CHAR_T *workstart = NULL;
> +
> + if (grouping == (const char *) -1)
> + {
OK.
> #ifdef COMPILE_WPRINTF
> - thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> - _NL_NUMERIC_THOUSANDS_SEP_WC);
> + thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
> + _NL_NUMERIC_THOUSANDS_SEP_WC);
> #else
> - thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> + thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
> #endif
>
> - grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> - if (*grouping == '\0' || *grouping == CHAR_MAX)
> - grouping = NULL;
> - }
> + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
> + if (*grouping == '\0' || *grouping == CHAR_MAX)
> + grouping = NULL;
> + }
>
OK.
> - for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
> - {
> - if (nspecs * sizeof (*specs) >= nspecs_size)
> - {
> - /* Extend the array of format specifiers. */
> - if (nspecs_size * 2 < nspecs_size)
> - {
> - __set_errno (ENOMEM);
> - done = -1;
> - goto all_done;
> - }
> - struct printf_spec *old = specs;
> - if (__libc_use_alloca (2 * nspecs_size))
> - specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
> - else
> - {
> - nspecs_size *= 2;
> - specs = malloc (nspecs_size);
> - if (specs == NULL)
> - {
> - __set_errno (ENOMEM);
> - specs = old;
> - done = -1;
> - goto all_done;
> - }
> - }
> + for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
> + f = specs[nspecs++].next_fmt)
> + {
> + if (nspecs * sizeof (*specs) >= nspecs_size)
> + {
> + /* Extend the array of format specifiers. */
> + if (nspecs_size * 2 < nspecs_size)
> + {
> + __set_errno (ENOMEM);
> + done = -1;
> + goto all_done;
> + }
> + struct printf_spec *old = specs;
> + if (__libc_use_alloca (2 * nspecs_size))
> + specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
> + else
> + {
> + nspecs_size *= 2;
> + specs = malloc (nspecs_size);
> + if (specs == NULL)
> + {
> + __set_errno (ENOMEM);
> + specs = old;
> + done = -1;
> + goto all_done;
> + }
OK.
> + }
>
> - /* Copy the old array's elements to the new space. */
> - memmove (specs, old, nspecs * sizeof (*specs));
> + /* Copy the old array's elements to the new space. */
> + memmove (specs, old, nspecs * sizeof (*specs));
>
> - /* If we had previously malloc'd space for SPECS, then
> - release it after the copy is complete. */
> - if (specs_malloced)
> - free (old);
> + /* If we had previously malloc'd space for SPECS, then
> + release it after the copy is complete. */
> + if (specs_malloced)
> + free (old);
>
> - /* Now set SPECS_MALLOCED if needed. */
> - if (!__libc_use_alloca (nspecs_size))
> - specs_malloced = true;
> - }
> + /* Now set SPECS_MALLOCED if needed. */
> + if (!__libc_use_alloca (nspecs_size))
> + specs_malloced = true;
OK.
> + }
>
> - /* Parse the format specifier. */
> + /* Parse the format specifier. */
> #ifdef COMPILE_WPRINTF
> - nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
> + nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
> #else
> - nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
> + nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
> #endif
> - }
> -
> - /* Determine the number of arguments the format string consumes. */
> - nargs = MAX (nargs, max_ref_arg);
> - /* Calculate total size needed to represent a single argument across
> - all three argument-related arrays. */
> - bytes_per_arg = (sizeof (*args_value) + sizeof (*args_size)
> - + sizeof (*args_type));
> + }
>
> - /* Check for potential integer overflow. */
> - if (__glibc_unlikely (nargs > INT_MAX / bytes_per_arg))
> - {
> - __set_errno (EOVERFLOW);
> - done = -1;
> - goto all_done;
> - }
> + /* Determine the number of arguments the format string consumes. */
> + nargs = MAX (nargs, max_ref_arg);
> + /* Calculate total size needed to represent a single argument across
> + all three argument-related arrays. */
> + bytes_per_arg = (sizeof (*args_value) + sizeof (*args_size)
> + + sizeof (*args_type));
OK.
>
> - /* Allocate memory for all three argument arrays. */
> - if (__libc_use_alloca (nargs * bytes_per_arg))
> - args_value = alloca (nargs * bytes_per_arg);
> - else
> - {
> - args_value = args_malloced = malloc (nargs * bytes_per_arg);
> - if (args_value == NULL)
> - {
> - done = -1;
> - goto all_done;
> - }
> - }
> + /* Check for potential integer overflow. */
> + if (__glibc_unlikely (nargs > INT_MAX / bytes_per_arg))
> + {
> + __set_errno (EOVERFLOW);
> + done = -1;
> + goto all_done;
> + }
OK.
>
> - /* Set up the remaining two arrays to each point past the end of the
> - prior array, since space for all three has been allocated now. */
> - args_size = &args_value[nargs].pa_int;
> - args_type = &args_size[nargs];
> - memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> - nargs * sizeof (*args_type));
> + /* Allocate memory for all three argument arrays. */
> + if (__libc_use_alloca (nargs * bytes_per_arg))
> + args_value = alloca (nargs * bytes_per_arg);
> + else
> + {
> + args_value = args_malloced = malloc (nargs * bytes_per_arg);
> + if (args_value == NULL)
> + {
> + done = -1;
> + goto all_done;
> + }
> + }
OK.
>
> - /* XXX Could do sanity check here: If any element in ARGS_TYPE is
> - still zero after this loop, format is invalid. For now we
> - simply use 0 as the value. */
> + /* Set up the remaining two arrays to each point past the end of the
> + prior array, since space for all three has been allocated now. */
> + args_size = &args_value[nargs].pa_int;
> + args_type = &args_size[nargs];
> + memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
> + nargs * sizeof (*args_type));
>
> - /* Fill in the types of all the arguments. */
> - for (cnt = 0; cnt < nspecs; ++cnt)
> - {
> - /* If the width is determined by an argument this is an int. */
> - if (specs[cnt].width_arg != -1)
> - args_type[specs[cnt].width_arg] = PA_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
> + simply use 0 as the value. */
>
> - /* If the precision is determined by an argument this is an int. */
> - if (specs[cnt].prec_arg != -1)
> - args_type[specs[cnt].prec_arg] = PA_INT;
> + /* Fill in the types of all the arguments. */
> + for (cnt = 0; cnt < nspecs; ++cnt)
> + {
> + /* If the width is determined by an argument this is an int. */
> + if (specs[cnt].width_arg != -1)
> + args_type[specs[cnt].width_arg] = PA_INT;
>
> - switch (specs[cnt].ndata_args)
> - {
> - case 0: /* No arguments. */
> - break;
> - 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.
> - We must call the arginfo function again to determine
> - all the types. */
> - (void) (*__printf_arginfo_table[specs[cnt].info.spec])
> - (&specs[cnt].info,
> - specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
> - &args_size[specs[cnt].data_arg]);
> - break;
> - }
> - }
> + /* If the precision is determined by an argument this is an int. */
> + if (specs[cnt].prec_arg != -1)
> + args_type[specs[cnt].prec_arg] = PA_INT;
>
> - /* Now we know all the types and the order. Fill in the argument
> - values. */
> - for (cnt = 0; cnt < nargs; ++cnt)
> - switch (args_type[cnt])
> + switch (specs[cnt].ndata_args)
> {
> -#define T(tag, mem, type) \
> - case tag: \
> - args_value[cnt].mem = va_arg (ap_save, type); \
> + case 0: /* No arguments. */
> + break;
> + 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.
> + We must call the arginfo function again to determine
> + all the types. */
> + (void) (*__printf_arginfo_table[specs[cnt].info.spec])
> + (&specs[cnt].info,
> + specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
> + &args_size[specs[cnt].data_arg]);
> + break;
> + }
> + }
> +
OK.
> + /* Now we know all the types and the order. Fill in the argument
> + values. */
> + for (cnt = 0; cnt < nargs; ++cnt)
> + switch (args_type[cnt])
> + {
> +#define T(tag, mem, type) \
> + case tag: \
> + args_value[cnt].mem = va_arg (*ap_savep, type); \
> break
>
> T (PA_WCHAR, pa_wchar, wint_t);
> - case PA_CHAR: /* Promoted. */
> - case PA_INT|PA_FLAG_SHORT: /* Promoted. */
> + case PA_CHAR: /* Promoted. */
> + case PA_INT|PA_FLAG_SHORT: /* Promoted. */
> #if LONG_MAX == INT_MAX
> - case PA_INT|PA_FLAG_LONG:
> + case PA_INT|PA_FLAG_LONG:
> #endif
> T (PA_INT, pa_int, int);
> #if LONG_MAX == LONG_LONG_MAX
> - case PA_INT|PA_FLAG_LONG:
> + case PA_INT|PA_FLAG_LONG:
> #endif
> T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
> #if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
> # error "he?"
> #endif
> - case PA_FLOAT: /* Promoted. */
> + case PA_FLOAT: /* Promoted. */
> T (PA_DOUBLE, pa_double, double);
> - case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> - if (__ldbl_is_dbl)
> - {
> - args_value[cnt].pa_double = va_arg (ap_save, double);
> - args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> - }
> - else
> - args_value[cnt].pa_long_double = va_arg (ap_save, long double);
> - break;
> - case PA_STRING: /* All pointers are the same */
> - case PA_WSTRING: /* All pointers are the same */
> + case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
> + if (__ldbl_is_dbl)
> + {
> + args_value[cnt].pa_double = va_arg (*ap_savep, double);
> + args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
> + }
> + else
> + args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
> + break;
> + case PA_STRING: /* All pointers are the same */
> + case PA_WSTRING: /* All pointers are the same */
> T (PA_POINTER, pa_pointer, void *);
> #undef T
> - default:
> - if ((args_type[cnt] & PA_FLAG_PTR) != 0)
> - args_value[cnt].pa_pointer = va_arg (ap_save, void *);
> - else if (__glibc_unlikely (__printf_va_arg_table != NULL)
> - && __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;
> - case -1:
> - /* Error case. Not all parameters appear in N$ format
> - strings. We have no way to determine their type. */
> - assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> - __libc_fatal ("*** invalid %N$ use detected ***\n");
> - }
> + default:
> + if ((args_type[cnt] & PA_FLAG_PTR) != 0)
> + args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
> + else if (__glibc_unlikely (__printf_va_arg_table != NULL)
> + && __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_savep);
> + }
> + else
> + args_value[cnt].pa_long_double = 0.0;
> + break;
> + case -1:
> + /* Error case. Not all parameters appear in N$ format
> + strings. We have no way to determine their type. */
> + assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
> + __libc_fatal ("*** invalid %N$ use detected ***\n");
> + }
>
> - /* Now walk through all format specifiers and process them. */
> - for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
> - {
> + /* Now walk through all format specifiers and process them. */
> + for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
> + {
> #undef REF
> #ifdef SHARED
> # undef JUMP_TABLE_BASE_LABEL
> @@ -1906,184 +1938,174 @@ do_positional:
> #endif
> #undef LABEL
> #define LABEL(Name) do2_##Name
> - STEP4_TABLE;
> + STEP4_TABLE;
>
> - int is_negative;
> - union
> + int is_negative;
> + union
> + {
> + unsigned long long int longlong;
> + unsigned long int word;
> + } number;
> + int base;
> + union printf_arg the_arg;
> + CHAR_T *string; /* Pointer to argument string. */
> +
> + /* Fill variables from values in struct. */
> + int alt = specs[nspecs_done].info.alt;
> + int space = specs[nspecs_done].info.space;
> + int left = specs[nspecs_done].info.left;
> + int showsign = specs[nspecs_done].info.showsign;
> + int group = specs[nspecs_done].info.group;
> + int is_long_double = specs[nspecs_done].info.is_long_double;
> + int is_short = specs[nspecs_done].info.is_short;
> + int is_char = specs[nspecs_done].info.is_char;
> + int is_long = specs[nspecs_done].info.is_long;
> + int width = specs[nspecs_done].info.width;
> + int prec = specs[nspecs_done].info.prec;
> + int use_outdigits = specs[nspecs_done].info.i18n;
> + char pad = specs[nspecs_done].info.pad;
> + CHAR_T spec = specs[nspecs_done].info.spec;
> +
> + workstart = NULL;
> + CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
> +
> + /* Fill in last information. */
> + if (specs[nspecs_done].width_arg != -1)
> {
> - unsigned long long int longlong;
> - unsigned long int word;
> - } number;
> - int base;
> - union printf_arg the_arg;
> - CHAR_T *string; /* Pointer to argument string. */
> -
> - /* Fill variables from values in struct. */
> - int alt = specs[nspecs_done].info.alt;
> - int space = specs[nspecs_done].info.space;
> - int left = specs[nspecs_done].info.left;
> - int showsign = specs[nspecs_done].info.showsign;
> - int group = specs[nspecs_done].info.group;
> - int is_long_double = specs[nspecs_done].info.is_long_double;
> - int is_short = specs[nspecs_done].info.is_short;
> - int is_char = specs[nspecs_done].info.is_char;
> - int is_long = specs[nspecs_done].info.is_long;
> - int width = specs[nspecs_done].info.width;
> - int prec = specs[nspecs_done].info.prec;
> - int use_outdigits = specs[nspecs_done].info.i18n;
> - char pad = specs[nspecs_done].info.pad;
> - CHAR_T spec = specs[nspecs_done].info.spec;
> -
> - workstart = NULL;
> - workend = work_buffer + WORK_BUFFER_SIZE;
> -
> - /* Fill in last information. */
> - if (specs[nspecs_done].width_arg != -1)
> - {
> - /* Extract the field width from an argument. */
> - specs[nspecs_done].info.width =
> - args_value[specs[nspecs_done].width_arg].pa_int;
> + /* Extract the field width from an argument. */
> + specs[nspecs_done].info.width =
> + args_value[specs[nspecs_done].width_arg].pa_int;
>
> - if (specs[nspecs_done].info.width < 0)
> - /* If the width value is negative left justification is
> - selected and the value is taken as being positive. */
> - {
> - specs[nspecs_done].info.width *= -1;
> - left = specs[nspecs_done].info.left = 1;
> - }
> - width = specs[nspecs_done].info.width;
> - }
> + if (specs[nspecs_done].info.width < 0)
> + /* If the width value is negative left justification is
> + selected and the value is taken as being positive. */
> + {
> + specs[nspecs_done].info.width *= -1;
> + left = specs[nspecs_done].info.left = 1;
> + }
> + width = specs[nspecs_done].info.width;
> + }
>
> - if (specs[nspecs_done].prec_arg != -1)
> - {
> - /* Extract the precision from an argument. */
> - specs[nspecs_done].info.prec =
> - args_value[specs[nspecs_done].prec_arg].pa_int;
> + if (specs[nspecs_done].prec_arg != -1)
> + {
> + /* Extract the precision from an argument. */
> + specs[nspecs_done].info.prec =
> + args_value[specs[nspecs_done].prec_arg].pa_int;
>
> - if (specs[nspecs_done].info.prec < 0)
> - /* If the precision is negative the precision is
> - omitted. */
> - specs[nspecs_done].info.prec = -1;
> + if (specs[nspecs_done].info.prec < 0)
> + /* If the precision is negative the precision is
> + omitted. */
> + specs[nspecs_done].info.prec = -1;
>
> - prec = specs[nspecs_done].info.prec;
> - }
> + prec = specs[nspecs_done].info.prec;
> + }
>
> - /* Maybe the buffer is too small. */
> - if (MAX (prec, width) + 32 > WORK_BUFFER_SIZE)
> - {
> - if (__libc_use_alloca ((MAX (prec, width) + 32)
> - * sizeof (CHAR_T)))
> - workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
> - * sizeof (CHAR_T))
> - + (MAX (prec, width) + 32));
> - else
> - {
> - workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
> - * sizeof (CHAR_T));
> - if (workstart == NULL)
> - {
> - done = -1;
> - goto all_done;
> - }
> - workend = workstart + (MAX (prec, width) + 32);
> - }
> - }
> + /* Maybe the buffer is too small. */
> + if (MAX (prec, width) + 32 > WORK_BUFFER_SIZE)
> + {
> + if (__libc_use_alloca ((MAX (prec, width) + 32)
> + * sizeof (CHAR_T)))
> + workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
> + * sizeof (CHAR_T))
> + + (MAX (prec, width) + 32));
> + else
> + {
> + workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
> + * sizeof (CHAR_T));
> + if (workstart == NULL)
> + {
> + done = -1;
> + goto all_done;
> + }
> + workend = workstart + (MAX (prec, width) + 32);
> + }
> + }
>
> - /* Process format specifiers. */
> - while (1)
> - {
> - extern printf_function **__printf_function_table;
> - int function_done;
> + /* 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 *));
> + 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];
> + /* 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);
> + /* 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)
> - {
> - /* Function has set errno. */
> - done = -1;
> - goto all_done;
> - }
> -
> - done_add (function_done);
> - break;
> - }
> - }
> + if (function_done != -2)
> + {
> + /* If an error occurred we don't have information
> + about # of chars. */
> + if (function_done < 0)
> + {
> + /* Function has set errno. */
> + done = -1;
> + goto all_done;
> + }
> +
> + done_add (function_done);
> + break;
> + }
> + }
>
> - JUMP (spec, step4_jumps);
> + JUMP (spec, step4_jumps);
>
> - process_arg ((&specs[nspecs_done]));
> - process_string_arg ((&specs[nspecs_done]));
> + process_arg ((&specs[nspecs_done]));
> + process_string_arg ((&specs[nspecs_done]));
>
> LABEL (form_unknown):
> - {
> - unsigned int i;
> - const void **ptr;
> + {
> + unsigned int i;
> + const void **ptr;
>
> - ptr = alloca (specs[nspecs_done].ndata_args
> - * sizeof (const void *));
> + ptr = alloca (specs[nspecs_done].ndata_args
> + * sizeof (const void *));
>
> - /* Fill in an array of pointers to the argument values. */
> - for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
> - ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
> + /* Fill in an array of pointers to the argument values. */
> + for (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_unknown (s, &specs[nspecs_done].info,
> - ptr);
> + /* Call the function. */
> + function_done = printf_unknown (s, &specs[nspecs_done].info,
> + ptr);
>
> - /* If an error occurred we don't have information about #
> - of chars. */
> - if (function_done < 0)
> - {
> - /* Function has set errno. */
> - done = -1;
> - goto all_done;
> - }
> + /* If an error occurred we don't have information about #
> + of chars. */
> + if (function_done < 0)
> + {
> + /* Function has set errno. */
> + done = -1;
> + goto all_done;
> + }
>
> - done_add (function_done);
> - }
> - break;
> + done_add (function_done);
> }
> + break;
> + }
>
> - if (__glibc_unlikely (workstart != NULL))
> - free (workstart);
> - workstart = NULL;
> -
> - /* Write the following constant string. */
> - outstring (specs[nspecs_done].end_of_fmt,
> - specs[nspecs_done].next_fmt
> - - specs[nspecs_done].end_of_fmt);
> - }
> - }
> + if (__glibc_unlikely (workstart != NULL))
> + free (workstart);
> + workstart = NULL;
>
> -all_done:
> - if (specs_malloced)
> - free (specs);
> - if (__glibc_unlikely (args_malloced != NULL))
> - free (args_malloced);
> + /* Write the following constant string. */
> + outstring (specs[nspecs_done].end_of_fmt,
> + specs[nspecs_done].next_fmt
> + - specs[nspecs_done].end_of_fmt);
> + }
> + all_done:
> if (__glibc_unlikely (workstart != NULL))
> free (workstart);
> - /* Unlock the stream. */
> - _IO_funlockfile (s);
> - _IO_cleanup_region_end (0);
> -
OK.
> return done;
> }
>
>
Cheers,
Carlos.
@@ -204,6 +204,14 @@ static const CHAR_T null[] = L_("(null)");
static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
__THROW __attribute__ ((noinline)) internal_function;
+/* Handle positional format specifiers. */
+static int printf_positional (_IO_FILE *s,
+ const CHAR_T *format, int readonly_format,
+ va_list ap, va_list *ap_savep, int done,
+ int nspecs_done, const UCHAR_T *lead_str_end,
+ CHAR_T *work_buffer, int save_errno,
+ const char *grouping, THOUSANDS_SEP_T);
+
/* Handle unknown format specifier. */
static int printf_unknown (FILE *, const struct printf_info *,
const void *const *) __THROW;
@@ -1257,15 +1265,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
0 if unknown. */
int readonly_format = 0;
- /* For the argument descriptions, which may be allocated on the heap. */
- void *args_malloced = NULL;
-
- /* For positional argument handling. */
- struct printf_spec *specs;
-
- /* Track if we malloced the SPECS array and thus must free it. */
- bool specs_malloced = false;
-
/* Orient the stream. */
#ifdef ORIENT
ORIENT;
@@ -1670,232 +1669,265 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
/* Unlock stream and return. */
goto all_done;
- /* Here starts the more complex loop to handle positional parameters. */
+ /* Hand off processing for positional parameters. */
do_positional:
- {
- /* Array with information about the needed arguments. This has to
- be dynamically extensible. */
- size_t nspecs = 0;
- /* A more or less arbitrary start value. */
- size_t nspecs_size = 32 * sizeof (struct printf_spec);
-
- specs = alloca (nspecs_size);
- /* The number of arguments the format string requests. This will
- determine the size of the array needed to store the argument
- attributes. */
- size_t nargs = 0;
- size_t bytes_per_arg;
- union printf_arg *args_value;
- int *args_size;
- int *args_type;
-
- /* Positional parameters refer to arguments directly. This could
- also determine the maximum number of arguments. Track the
- maximum number. */
- size_t max_ref_arg = 0;
-
- /* Just a counter. */
- size_t cnt;
-
- if (__glibc_unlikely (workstart != NULL))
+ if (__glibc_unlikely (workstart != NULL))
+ {
free (workstart);
- workstart = NULL;
+ workstart = NULL;
+ }
+ done = printf_positional (s, format, readonly_format, ap, &ap_save,
+ done, nspecs_done, lead_str_end, work_buffer,
+ save_errno, grouping, thousands_sep);
- if (grouping == (const char *) -1)
- {
+ all_done:
+ if (__glibc_unlikely (workstart != NULL))
+ free (workstart);
+ /* Unlock the stream. */
+ _IO_funlockfile (s);
+ _IO_cleanup_region_end (0);
+
+ return done;
+}
+
+static int
+printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
+ va_list ap, va_list *ap_savep, int done, int nspecs_done,
+ const UCHAR_T *lead_str_end,
+ CHAR_T *work_buffer, int save_errno,
+ const char *grouping, THOUSANDS_SEP_T thousands_sep)
+{
+ /* For the argument descriptions, which may be allocated on the heap. */
+ void *args_malloced = NULL;
+
+ /* For positional argument handling. */
+ struct printf_spec *specs;
+
+ /* Track if we malloced the SPECS array and thus must free it. */
+ bool specs_malloced = false;
+
+ /* Array with information about the needed arguments. This has to
+ be dynamically extensible. */
+ size_t nspecs = 0;
+ /* A more or less arbitrary start value. */
+ size_t nspecs_size = 32 * sizeof (struct printf_spec);
+
+ specs = alloca (nspecs_size);
+ /* The number of arguments the format string requests. This will
+ determine the size of the array needed to store the argument
+ attributes. */
+ size_t nargs = 0;
+ size_t bytes_per_arg;
+ union printf_arg *args_value;
+ int *args_size;
+ int *args_type;
+
+ /* Positional parameters refer to arguments directly. This could
+ also determine the maximum number of arguments. Track the
+ maximum number. */
+ size_t max_ref_arg = 0;
+
+ /* Just a counter. */
+ size_t cnt;
+
+ CHAR_T *workstart = NULL;
+
+ if (grouping == (const char *) -1)
+ {
#ifdef COMPILE_WPRINTF
- thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
- _NL_NUMERIC_THOUSANDS_SEP_WC);
+ thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
+ _NL_NUMERIC_THOUSANDS_SEP_WC);
#else
- thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
+ thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
#endif
- grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
- if (*grouping == '\0' || *grouping == CHAR_MAX)
- grouping = NULL;
- }
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping == '\0' || *grouping == CHAR_MAX)
+ grouping = NULL;
+ }
- for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
- {
- if (nspecs * sizeof (*specs) >= nspecs_size)
- {
- /* Extend the array of format specifiers. */
- if (nspecs_size * 2 < nspecs_size)
- {
- __set_errno (ENOMEM);
- done = -1;
- goto all_done;
- }
- struct printf_spec *old = specs;
- if (__libc_use_alloca (2 * nspecs_size))
- specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
- else
- {
- nspecs_size *= 2;
- specs = malloc (nspecs_size);
- if (specs == NULL)
- {
- __set_errno (ENOMEM);
- specs = old;
- done = -1;
- goto all_done;
- }
- }
+ for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
+ f = specs[nspecs++].next_fmt)
+ {
+ if (nspecs * sizeof (*specs) >= nspecs_size)
+ {
+ /* Extend the array of format specifiers. */
+ if (nspecs_size * 2 < nspecs_size)
+ {
+ __set_errno (ENOMEM);
+ done = -1;
+ goto all_done;
+ }
+ struct printf_spec *old = specs;
+ if (__libc_use_alloca (2 * nspecs_size))
+ specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
+ else
+ {
+ nspecs_size *= 2;
+ specs = malloc (nspecs_size);
+ if (specs == NULL)
+ {
+ __set_errno (ENOMEM);
+ specs = old;
+ done = -1;
+ goto all_done;
+ }
+ }
- /* Copy the old array's elements to the new space. */
- memmove (specs, old, nspecs * sizeof (*specs));
+ /* Copy the old array's elements to the new space. */
+ memmove (specs, old, nspecs * sizeof (*specs));
- /* If we had previously malloc'd space for SPECS, then
- release it after the copy is complete. */
- if (specs_malloced)
- free (old);
+ /* If we had previously malloc'd space for SPECS, then
+ release it after the copy is complete. */
+ if (specs_malloced)
+ free (old);
- /* Now set SPECS_MALLOCED if needed. */
- if (!__libc_use_alloca (nspecs_size))
- specs_malloced = true;
- }
+ /* Now set SPECS_MALLOCED if needed. */
+ if (!__libc_use_alloca (nspecs_size))
+ specs_malloced = true;
+ }
- /* Parse the format specifier. */
+ /* Parse the format specifier. */
#ifdef COMPILE_WPRINTF
- nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
+ nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
#else
- nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
+ nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
#endif
- }
-
- /* Determine the number of arguments the format string consumes. */
- nargs = MAX (nargs, max_ref_arg);
- /* Calculate total size needed to represent a single argument across
- all three argument-related arrays. */
- bytes_per_arg = (sizeof (*args_value) + sizeof (*args_size)
- + sizeof (*args_type));
+ }
- /* Check for potential integer overflow. */
- if (__glibc_unlikely (nargs > INT_MAX / bytes_per_arg))
- {
- __set_errno (EOVERFLOW);
- done = -1;
- goto all_done;
- }
+ /* Determine the number of arguments the format string consumes. */
+ nargs = MAX (nargs, max_ref_arg);
+ /* Calculate total size needed to represent a single argument across
+ all three argument-related arrays. */
+ bytes_per_arg = (sizeof (*args_value) + sizeof (*args_size)
+ + sizeof (*args_type));
- /* Allocate memory for all three argument arrays. */
- if (__libc_use_alloca (nargs * bytes_per_arg))
- args_value = alloca (nargs * bytes_per_arg);
- else
- {
- args_value = args_malloced = malloc (nargs * bytes_per_arg);
- if (args_value == NULL)
- {
- done = -1;
- goto all_done;
- }
- }
+ /* Check for potential integer overflow. */
+ if (__glibc_unlikely (nargs > INT_MAX / bytes_per_arg))
+ {
+ __set_errno (EOVERFLOW);
+ done = -1;
+ goto all_done;
+ }
- /* Set up the remaining two arrays to each point past the end of the
- prior array, since space for all three has been allocated now. */
- args_size = &args_value[nargs].pa_int;
- args_type = &args_size[nargs];
- memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
- nargs * sizeof (*args_type));
+ /* Allocate memory for all three argument arrays. */
+ if (__libc_use_alloca (nargs * bytes_per_arg))
+ args_value = alloca (nargs * bytes_per_arg);
+ else
+ {
+ args_value = args_malloced = malloc (nargs * bytes_per_arg);
+ if (args_value == NULL)
+ {
+ done = -1;
+ goto all_done;
+ }
+ }
- /* XXX Could do sanity check here: If any element in ARGS_TYPE is
- still zero after this loop, format is invalid. For now we
- simply use 0 as the value. */
+ /* Set up the remaining two arrays to each point past the end of the
+ prior array, since space for all three has been allocated now. */
+ args_size = &args_value[nargs].pa_int;
+ args_type = &args_size[nargs];
+ memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
+ nargs * sizeof (*args_type));
- /* Fill in the types of all the arguments. */
- for (cnt = 0; cnt < nspecs; ++cnt)
- {
- /* If the width is determined by an argument this is an int. */
- if (specs[cnt].width_arg != -1)
- args_type[specs[cnt].width_arg] = PA_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
+ simply use 0 as the value. */
- /* If the precision is determined by an argument this is an int. */
- if (specs[cnt].prec_arg != -1)
- args_type[specs[cnt].prec_arg] = PA_INT;
+ /* Fill in the types of all the arguments. */
+ for (cnt = 0; cnt < nspecs; ++cnt)
+ {
+ /* If the width is determined by an argument this is an int. */
+ if (specs[cnt].width_arg != -1)
+ args_type[specs[cnt].width_arg] = PA_INT;
- switch (specs[cnt].ndata_args)
- {
- case 0: /* No arguments. */
- break;
- 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.
- We must call the arginfo function again to determine
- all the types. */
- (void) (*__printf_arginfo_table[specs[cnt].info.spec])
- (&specs[cnt].info,
- specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
- &args_size[specs[cnt].data_arg]);
- break;
- }
- }
+ /* If the precision is determined by an argument this is an int. */
+ if (specs[cnt].prec_arg != -1)
+ args_type[specs[cnt].prec_arg] = PA_INT;
- /* Now we know all the types and the order. Fill in the argument
- values. */
- for (cnt = 0; cnt < nargs; ++cnt)
- switch (args_type[cnt])
+ switch (specs[cnt].ndata_args)
{
-#define T(tag, mem, type) \
- case tag: \
- args_value[cnt].mem = va_arg (ap_save, type); \
+ case 0: /* No arguments. */
+ break;
+ 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.
+ We must call the arginfo function again to determine
+ all the types. */
+ (void) (*__printf_arginfo_table[specs[cnt].info.spec])
+ (&specs[cnt].info,
+ specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
+ &args_size[specs[cnt].data_arg]);
+ break;
+ }
+ }
+
+ /* Now we know all the types and the order. Fill in the argument
+ values. */
+ for (cnt = 0; cnt < nargs; ++cnt)
+ switch (args_type[cnt])
+ {
+#define T(tag, mem, type) \
+ case tag: \
+ args_value[cnt].mem = va_arg (*ap_savep, type); \
break
T (PA_WCHAR, pa_wchar, wint_t);
- case PA_CHAR: /* Promoted. */
- case PA_INT|PA_FLAG_SHORT: /* Promoted. */
+ case PA_CHAR: /* Promoted. */
+ case PA_INT|PA_FLAG_SHORT: /* Promoted. */
#if LONG_MAX == INT_MAX
- case PA_INT|PA_FLAG_LONG:
+ case PA_INT|PA_FLAG_LONG:
#endif
T (PA_INT, pa_int, int);
#if LONG_MAX == LONG_LONG_MAX
- case PA_INT|PA_FLAG_LONG:
+ case PA_INT|PA_FLAG_LONG:
#endif
T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
#if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
# error "he?"
#endif
- case PA_FLOAT: /* Promoted. */
+ case PA_FLOAT: /* Promoted. */
T (PA_DOUBLE, pa_double, double);
- case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
- if (__ldbl_is_dbl)
- {
- args_value[cnt].pa_double = va_arg (ap_save, double);
- args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
- }
- else
- args_value[cnt].pa_long_double = va_arg (ap_save, long double);
- break;
- case PA_STRING: /* All pointers are the same */
- case PA_WSTRING: /* All pointers are the same */
+ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
+ if (__ldbl_is_dbl)
+ {
+ args_value[cnt].pa_double = va_arg (*ap_savep, double);
+ args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
+ }
+ else
+ args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
+ break;
+ case PA_STRING: /* All pointers are the same */
+ case PA_WSTRING: /* All pointers are the same */
T (PA_POINTER, pa_pointer, void *);
#undef T
- default:
- if ((args_type[cnt] & PA_FLAG_PTR) != 0)
- args_value[cnt].pa_pointer = va_arg (ap_save, void *);
- else if (__glibc_unlikely (__printf_va_arg_table != NULL)
- && __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;
- case -1:
- /* Error case. Not all parameters appear in N$ format
- strings. We have no way to determine their type. */
- assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
- __libc_fatal ("*** invalid %N$ use detected ***\n");
- }
+ default:
+ if ((args_type[cnt] & PA_FLAG_PTR) != 0)
+ args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
+ else if (__glibc_unlikely (__printf_va_arg_table != NULL)
+ && __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_savep);
+ }
+ else
+ args_value[cnt].pa_long_double = 0.0;
+ break;
+ case -1:
+ /* Error case. Not all parameters appear in N$ format
+ strings. We have no way to determine their type. */
+ assert (s->_flags2 & _IO_FLAGS2_FORTIFY);
+ __libc_fatal ("*** invalid %N$ use detected ***\n");
+ }
- /* Now walk through all format specifiers and process them. */
- for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
- {
+ /* Now walk through all format specifiers and process them. */
+ for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
+ {
#undef REF
#ifdef SHARED
# undef JUMP_TABLE_BASE_LABEL
@@ -1906,184 +1938,174 @@ do_positional:
#endif
#undef LABEL
#define LABEL(Name) do2_##Name
- STEP4_TABLE;
+ STEP4_TABLE;
- int is_negative;
- union
+ int is_negative;
+ union
+ {
+ unsigned long long int longlong;
+ unsigned long int word;
+ } number;
+ int base;
+ union printf_arg the_arg;
+ CHAR_T *string; /* Pointer to argument string. */
+
+ /* Fill variables from values in struct. */
+ int alt = specs[nspecs_done].info.alt;
+ int space = specs[nspecs_done].info.space;
+ int left = specs[nspecs_done].info.left;
+ int showsign = specs[nspecs_done].info.showsign;
+ int group = specs[nspecs_done].info.group;
+ int is_long_double = specs[nspecs_done].info.is_long_double;
+ int is_short = specs[nspecs_done].info.is_short;
+ int is_char = specs[nspecs_done].info.is_char;
+ int is_long = specs[nspecs_done].info.is_long;
+ int width = specs[nspecs_done].info.width;
+ int prec = specs[nspecs_done].info.prec;
+ int use_outdigits = specs[nspecs_done].info.i18n;
+ char pad = specs[nspecs_done].info.pad;
+ CHAR_T spec = specs[nspecs_done].info.spec;
+
+ workstart = NULL;
+ CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
+
+ /* Fill in last information. */
+ if (specs[nspecs_done].width_arg != -1)
{
- unsigned long long int longlong;
- unsigned long int word;
- } number;
- int base;
- union printf_arg the_arg;
- CHAR_T *string; /* Pointer to argument string. */
-
- /* Fill variables from values in struct. */
- int alt = specs[nspecs_done].info.alt;
- int space = specs[nspecs_done].info.space;
- int left = specs[nspecs_done].info.left;
- int showsign = specs[nspecs_done].info.showsign;
- int group = specs[nspecs_done].info.group;
- int is_long_double = specs[nspecs_done].info.is_long_double;
- int is_short = specs[nspecs_done].info.is_short;
- int is_char = specs[nspecs_done].info.is_char;
- int is_long = specs[nspecs_done].info.is_long;
- int width = specs[nspecs_done].info.width;
- int prec = specs[nspecs_done].info.prec;
- int use_outdigits = specs[nspecs_done].info.i18n;
- char pad = specs[nspecs_done].info.pad;
- CHAR_T spec = specs[nspecs_done].info.spec;
-
- workstart = NULL;
- workend = work_buffer + WORK_BUFFER_SIZE;
-
- /* Fill in last information. */
- if (specs[nspecs_done].width_arg != -1)
- {
- /* Extract the field width from an argument. */
- specs[nspecs_done].info.width =
- args_value[specs[nspecs_done].width_arg].pa_int;
+ /* Extract the field width from an argument. */
+ specs[nspecs_done].info.width =
+ args_value[specs[nspecs_done].width_arg].pa_int;
- if (specs[nspecs_done].info.width < 0)
- /* If the width value is negative left justification is
- selected and the value is taken as being positive. */
- {
- specs[nspecs_done].info.width *= -1;
- left = specs[nspecs_done].info.left = 1;
- }
- width = specs[nspecs_done].info.width;
- }
+ if (specs[nspecs_done].info.width < 0)
+ /* If the width value is negative left justification is
+ selected and the value is taken as being positive. */
+ {
+ specs[nspecs_done].info.width *= -1;
+ left = specs[nspecs_done].info.left = 1;
+ }
+ width = specs[nspecs_done].info.width;
+ }
- if (specs[nspecs_done].prec_arg != -1)
- {
- /* Extract the precision from an argument. */
- specs[nspecs_done].info.prec =
- args_value[specs[nspecs_done].prec_arg].pa_int;
+ if (specs[nspecs_done].prec_arg != -1)
+ {
+ /* Extract the precision from an argument. */
+ specs[nspecs_done].info.prec =
+ args_value[specs[nspecs_done].prec_arg].pa_int;
- if (specs[nspecs_done].info.prec < 0)
- /* If the precision is negative the precision is
- omitted. */
- specs[nspecs_done].info.prec = -1;
+ if (specs[nspecs_done].info.prec < 0)
+ /* If the precision is negative the precision is
+ omitted. */
+ specs[nspecs_done].info.prec = -1;
- prec = specs[nspecs_done].info.prec;
- }
+ prec = specs[nspecs_done].info.prec;
+ }
- /* Maybe the buffer is too small. */
- if (MAX (prec, width) + 32 > WORK_BUFFER_SIZE)
- {
- if (__libc_use_alloca ((MAX (prec, width) + 32)
- * sizeof (CHAR_T)))
- workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
- * sizeof (CHAR_T))
- + (MAX (prec, width) + 32));
- else
- {
- workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
- * sizeof (CHAR_T));
- if (workstart == NULL)
- {
- done = -1;
- goto all_done;
- }
- workend = workstart + (MAX (prec, width) + 32);
- }
- }
+ /* Maybe the buffer is too small. */
+ if (MAX (prec, width) + 32 > WORK_BUFFER_SIZE)
+ {
+ if (__libc_use_alloca ((MAX (prec, width) + 32)
+ * sizeof (CHAR_T)))
+ workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
+ * sizeof (CHAR_T))
+ + (MAX (prec, width) + 32));
+ else
+ {
+ workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
+ * sizeof (CHAR_T));
+ if (workstart == NULL)
+ {
+ done = -1;
+ goto all_done;
+ }
+ workend = workstart + (MAX (prec, width) + 32);
+ }
+ }
- /* Process format specifiers. */
- while (1)
- {
- extern printf_function **__printf_function_table;
- int function_done;
+ /* 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 *));
+ 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];
+ /* 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);
+ /* 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)
- {
- /* Function has set errno. */
- done = -1;
- goto all_done;
- }
-
- done_add (function_done);
- break;
- }
- }
+ if (function_done != -2)
+ {
+ /* If an error occurred we don't have information
+ about # of chars. */
+ if (function_done < 0)
+ {
+ /* Function has set errno. */
+ done = -1;
+ goto all_done;
+ }
+
+ done_add (function_done);
+ break;
+ }
+ }
- JUMP (spec, step4_jumps);
+ JUMP (spec, step4_jumps);
- process_arg ((&specs[nspecs_done]));
- process_string_arg ((&specs[nspecs_done]));
+ process_arg ((&specs[nspecs_done]));
+ process_string_arg ((&specs[nspecs_done]));
LABEL (form_unknown):
- {
- unsigned int i;
- const void **ptr;
+ {
+ unsigned int i;
+ const void **ptr;
- ptr = alloca (specs[nspecs_done].ndata_args
- * sizeof (const void *));
+ ptr = alloca (specs[nspecs_done].ndata_args
+ * sizeof (const void *));
- /* Fill in an array of pointers to the argument values. */
- for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
- ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
+ /* Fill in an array of pointers to the argument values. */
+ for (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_unknown (s, &specs[nspecs_done].info,
- ptr);
+ /* Call the function. */
+ function_done = printf_unknown (s, &specs[nspecs_done].info,
+ ptr);
- /* If an error occurred we don't have information about #
- of chars. */
- if (function_done < 0)
- {
- /* Function has set errno. */
- done = -1;
- goto all_done;
- }
+ /* If an error occurred we don't have information about #
+ of chars. */
+ if (function_done < 0)
+ {
+ /* Function has set errno. */
+ done = -1;
+ goto all_done;
+ }
- done_add (function_done);
- }
- break;
+ done_add (function_done);
}
+ break;
+ }
- if (__glibc_unlikely (workstart != NULL))
- free (workstart);
- workstart = NULL;
-
- /* Write the following constant string. */
- outstring (specs[nspecs_done].end_of_fmt,
- specs[nspecs_done].next_fmt
- - specs[nspecs_done].end_of_fmt);
- }
- }
+ if (__glibc_unlikely (workstart != NULL))
+ free (workstart);
+ workstart = NULL;
-all_done:
- if (specs_malloced)
- free (specs);
- if (__glibc_unlikely (args_malloced != NULL))
- free (args_malloced);
+ /* Write the following constant string. */
+ outstring (specs[nspecs_done].end_of_fmt,
+ specs[nspecs_done].next_fmt
+ - specs[nspecs_done].end_of_fmt);
+ }
+ all_done:
if (__glibc_unlikely (workstart != NULL))
free (workstart);
- /* Unlock the stream. */
- _IO_funlockfile (s);
- _IO_cleanup_region_end (0);
-
return done;
}