mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-08 17:42:12 +03:00
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:
@@ -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>
|
2015-05-21 Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
* stdio-common/vfprintf.c (jump_table): Move out of the vfprintf
|
* 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)
|
static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
|
||||||
__THROW __attribute__ ((noinline)) internal_function;
|
__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. */
|
/* Handle unknown format specifier. */
|
||||||
static int printf_unknown (FILE *, const struct printf_info *,
|
static int printf_unknown (FILE *, const struct printf_info *,
|
||||||
const void *const *) __THROW;
|
const void *const *) __THROW;
|
||||||
@@ -1257,15 +1265,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||||||
0 if unknown. */
|
0 if unknown. */
|
||||||
int readonly_format = 0;
|
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. */
|
/* Orient the stream. */
|
||||||
#ifdef ORIENT
|
#ifdef ORIENT
|
||||||
ORIENT;
|
ORIENT;
|
||||||
@@ -1670,9 +1669,43 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||||||
/* Unlock stream and return. */
|
/* Unlock stream and return. */
|
||||||
goto all_done;
|
goto all_done;
|
||||||
|
|
||||||
/* Here starts the more complex loop to handle positional parameters. */
|
/* Hand off processing for positional parameters. */
|
||||||
do_positional:
|
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
|
/* Array with information about the needed arguments. This has to
|
||||||
be dynamically extensible. */
|
be dynamically extensible. */
|
||||||
size_t nspecs = 0;
|
size_t nspecs = 0;
|
||||||
@@ -1697,9 +1730,7 @@ do_positional:
|
|||||||
/* Just a counter. */
|
/* Just a counter. */
|
||||||
size_t cnt;
|
size_t cnt;
|
||||||
|
|
||||||
if (__glibc_unlikely (workstart != NULL))
|
CHAR_T *workstart = NULL;
|
||||||
free (workstart);
|
|
||||||
workstart = NULL;
|
|
||||||
|
|
||||||
if (grouping == (const char *) -1)
|
if (grouping == (const char *) -1)
|
||||||
{
|
{
|
||||||
@@ -1715,7 +1746,8 @@ do_positional:
|
|||||||
grouping = NULL;
|
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)
|
if (nspecs * sizeof (*specs) >= nspecs_size)
|
||||||
{
|
{
|
||||||
@@ -1841,7 +1873,7 @@ do_positional:
|
|||||||
{
|
{
|
||||||
#define T(tag, mem, type) \
|
#define T(tag, mem, type) \
|
||||||
case tag: \
|
case tag: \
|
||||||
args_value[cnt].mem = va_arg (ap_save, type); \
|
args_value[cnt].mem = va_arg (*ap_savep, type); \
|
||||||
break
|
break
|
||||||
|
|
||||||
T (PA_WCHAR, pa_wchar, wint_t);
|
T (PA_WCHAR, pa_wchar, wint_t);
|
||||||
@@ -1863,11 +1895,11 @@ do_positional:
|
|||||||
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
|
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
|
||||||
if (__ldbl_is_dbl)
|
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;
|
args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
|
||||||
}
|
}
|
||||||
else
|
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;
|
break;
|
||||||
case PA_STRING: /* All pointers are the same */
|
case PA_STRING: /* All pointers are the same */
|
||||||
case PA_WSTRING: /* All pointers are the same */
|
case PA_WSTRING: /* All pointers are the same */
|
||||||
@@ -1875,13 +1907,13 @@ do_positional:
|
|||||||
#undef T
|
#undef T
|
||||||
default:
|
default:
|
||||||
if ((args_type[cnt] & PA_FLAG_PTR) != 0)
|
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)
|
else if (__glibc_unlikely (__printf_va_arg_table != NULL)
|
||||||
&& __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
|
&& __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
|
||||||
{
|
{
|
||||||
args_value[cnt].pa_user = alloca (args_size[cnt]);
|
args_value[cnt].pa_user = alloca (args_size[cnt]);
|
||||||
(*__printf_va_arg_table[args_type[cnt] - PA_LAST])
|
(*__printf_va_arg_table[args_type[cnt] - PA_LAST])
|
||||||
(args_value[cnt].pa_user, &ap_save);
|
(args_value[cnt].pa_user, ap_savep);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
args_value[cnt].pa_long_double = 0.0;
|
args_value[cnt].pa_long_double = 0.0;
|
||||||
@@ -1935,7 +1967,7 @@ do_positional:
|
|||||||
CHAR_T spec = specs[nspecs_done].info.spec;
|
CHAR_T spec = specs[nspecs_done].info.spec;
|
||||||
|
|
||||||
workstart = NULL;
|
workstart = NULL;
|
||||||
workend = work_buffer + WORK_BUFFER_SIZE;
|
CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
|
||||||
|
|
||||||
/* Fill in last information. */
|
/* Fill in last information. */
|
||||||
if (specs[nspecs_done].width_arg != -1)
|
if (specs[nspecs_done].width_arg != -1)
|
||||||
@@ -2071,19 +2103,9 @@ do_positional:
|
|||||||
specs[nspecs_done].next_fmt
|
specs[nspecs_done].next_fmt
|
||||||
- specs[nspecs_done].end_of_fmt);
|
- specs[nspecs_done].end_of_fmt);
|
||||||
}
|
}
|
||||||
}
|
all_done:
|
||||||
|
|
||||||
all_done:
|
|
||||||
if (specs_malloced)
|
|
||||||
free (specs);
|
|
||||||
if (__glibc_unlikely (args_malloced != NULL))
|
|
||||||
free (args_malloced);
|
|
||||||
if (__glibc_unlikely (workstart != NULL))
|
if (__glibc_unlikely (workstart != NULL))
|
||||||
free (workstart);
|
free (workstart);
|
||||||
/* Unlock the stream. */
|
|
||||||
_IO_funlockfile (s);
|
|
||||||
_IO_cleanup_region_end (0);
|
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user