diff options
author | Florian Weimer <fweimer@redhat.com> | 2015-05-21 15:46:46 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2015-05-21 16:46:46 +0200 |
commit | f8194fa6f991456bd2cf79f2cdfbec7b497eb342 (patch) | |
tree | c22bf79aade57413f67e76705761f989fc442be5 /stdio-common/vfprintf.c | |
parent | f0f98189d83940152e876c31724c6bb699b7e578 (diff) | |
download | glibc-f8194fa6f991456bd2cf79f2cdfbec7b497eb342.tar.gz glibc-f8194fa6f991456bd2cf79f2cdfbec7b497eb342.tar.xz glibc-f8194fa6f991456bd2cf79f2cdfbec7b497eb342.zip |
vfprintf: Introduce printf_positional function
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.
Diffstat (limited to 'stdio-common/vfprintf.c')
-rw-r--r-- | stdio-common/vfprintf.c | 716 |
1 files changed, 369 insertions, 347 deletions
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 83b4b008ac..4753cbf954 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1209,6 +1209,14 @@ static const uint8_t jump_table[] = 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; } |