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,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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Now set SPECS_MALLOCED if needed. */
|
||||
if (!__libc_use_alloca (nspecs_size))
|
||||
specs_malloced = true;
|
||||
}
|
||||
|
||||
/* Parse the format specifier. */
|
||||
#ifdef COMPILE_WPRINTF
|
||||
nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
|
||||
#else
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know all the types and the order. Fill in the argument
|
||||
values. */
|
||||
for (cnt = 0; cnt < nargs; ++cnt)
|
||||
switch (args_type[cnt])
|
||||
for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
|
||||
f = specs[nspecs++].next_fmt)
|
||||
{
|
||||
if (nspecs * sizeof (*specs) >= nspecs_size)
|
||||
{
|
||||
#define T(tag, mem, type) \
|
||||
case tag: \
|
||||
args_value[cnt].mem = va_arg (ap_save, type); \
|
||||
/* 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));
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Parse the format specifier. */
|
||||
#ifdef COMPILE_WPRINTF
|
||||
nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
|
||||
#else
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* Extract the field width from an argument. */
|
||||
specs[nspecs_done].info.width =
|
||||
args_value[specs[nspecs_done].width_arg].pa_int;
|
||||
|
||||
/* 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;
|
||||
|
||||
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].info.prec < 0)
|
||||
/* If the precision is negative the precision is
|
||||
omitted. */
|
||||
specs[nspecs_done].info.prec = -1;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 *));
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
process_arg ((&specs[nspecs_done]));
|
||||
process_string_arg ((&specs[nspecs_done]));
|
||||
|
||||
LABEL (form_unknown):
|
||||
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. */
|
||||
{
|
||||
unsigned int i;
|
||||
const void **ptr;
|
||||
specs[nspecs_done].info.width *= -1;
|
||||
left = specs[nspecs_done].info.left = 1;
|
||||
}
|
||||
width = specs[nspecs_done].info.width;
|
||||
}
|
||||
|
||||
ptr = alloca (specs[nspecs_done].ndata_args
|
||||
* sizeof (const void *));
|
||||
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;
|
||||
|
||||
/* 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];
|
||||
if (specs[nspecs_done].info.prec < 0)
|
||||
/* If the precision is negative the precision is
|
||||
omitted. */
|
||||
specs[nspecs_done].info.prec = -1;
|
||||
|
||||
/* Call the function. */
|
||||
function_done = printf_unknown (s, &specs[nspecs_done].info,
|
||||
ptr);
|
||||
prec = specs[nspecs_done].info.prec;
|
||||
}
|
||||
|
||||
/* If an error occurred we don't have information about #
|
||||
of chars. */
|
||||
if (function_done < 0)
|
||||
/* 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)
|
||||
{
|
||||
/* Function has set errno. */
|
||||
done = -1;
|
||||
goto all_done;
|
||||
}
|
||||
|
||||
done_add (function_done);
|
||||
workend = workstart + (MAX (prec, width) + 32);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 *));
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
process_arg ((&specs[nspecs_done]));
|
||||
process_string_arg ((&specs[nspecs_done]));
|
||||
|
||||
LABEL (form_unknown):
|
||||
{
|
||||
unsigned int i;
|
||||
const void **ptr;
|
||||
|
||||
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];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
done_add (function_done);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (workstart != NULL))
|
||||
free (workstart);
|
||||
workstart = NULL;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user