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.
This commit is contained in:
Florian Weimer 2015-05-21 15:46:46 +01:00
parent f0f98189d8
commit f8194fa6f9
2 changed files with 399 additions and 370 deletions

View File

@ -1,3 +1,10 @@
2015-05-21 Florian Weimer <fweimer@redhat.com>
* stdio-common/vfprintf.c (vfprintf): Move local variables
args_malloced, specs, specs_malloced, and the code after
do_positional to the printf_positional function.
(printf_positional): New function.
2015-05-21 Florian Weimer <fweimer@redhat.com>
* stdio-common/vfprintf.c (jump_table): Move out of the vfprintf

View File

@ -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,9 +1669,43 @@ 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:
if (__glibc_unlikely (workstart != NULL))
{
free (workstart);
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);
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;
@ -1697,9 +1730,7 @@ do_positional:
/* Just a counter. */
size_t cnt;
if (__glibc_unlikely (workstart != NULL))
free (workstart);
workstart = NULL;
CHAR_T *workstart = NULL;
if (grouping == (const char *) -1)
{
@ -1715,7 +1746,8 @@ do_positional:
grouping = NULL;
}
for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
f = specs[nspecs++].next_fmt)
{
if (nspecs * sizeof (*specs) >= nspecs_size)
{
@ -1841,7 +1873,7 @@ do_positional:
{
#define T(tag, mem, type) \
case tag: \
args_value[cnt].mem = va_arg (ap_save, type); \
args_value[cnt].mem = va_arg (*ap_savep, type); \
break
T (PA_WCHAR, pa_wchar, wint_t);
@ -1863,11 +1895,11 @@ do_positional:
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
if (__ldbl_is_dbl)
{
args_value[cnt].pa_double = va_arg (ap_save, double);
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_save, long double);
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 */
@ -1875,13 +1907,13 @@ do_positional:
#undef T
default:
if ((args_type[cnt] & PA_FLAG_PTR) != 0)
args_value[cnt].pa_pointer = va_arg (ap_save, void *);
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_save);
(args_value[cnt].pa_user, ap_savep);
}
else
args_value[cnt].pa_long_double = 0.0;
@ -1935,7 +1967,7 @@ do_positional:
CHAR_T spec = specs[nspecs_done].info.spec;
workstart = NULL;
workend = work_buffer + WORK_BUFFER_SIZE;
CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
/* Fill in last information. */
if (specs[nspecs_done].width_arg != -1)
@ -2071,19 +2103,9 @@ do_positional:
specs[nspecs_done].next_fmt
- specs[nspecs_done].end_of_fmt);
}
}
all_done:
if (specs_malloced)
free (specs);
if (__glibc_unlikely (args_malloced != NULL))
free (args_malloced);
all_done:
if (__glibc_unlikely (workstart != NULL))
free (workstart);
/* Unlock the stream. */
_IO_funlockfile (s);
_IO_cleanup_region_end (0);
return done;
}