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:
parent
f0f98189d8
commit
f8194fa6f9
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user