diff options
Diffstat (limited to 'stdio-common/vfprintf-internal.c')
-rw-r--r-- | stdio-common/vfprintf-internal.c | 664 |
1 files changed, 181 insertions, 483 deletions
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c index fb94961f37..83a6aea510 100644 --- a/stdio-common/vfprintf-internal.c +++ b/stdio-common/vfprintf-internal.c @@ -16,6 +16,7 @@ <https://www.gnu.org/licenses/>. */ #include <array_length.h> +#include <assert.h> #include <ctype.h> #include <limits.h> #include <printf.h> @@ -29,9 +30,12 @@ #include <sys/param.h> #include <_itoa.h> #include <locale/localeinfo.h> +#include <grouping_iterator.h> #include <stdio.h> #include <scratch_buffer.h> #include <intprops.h> +#include <printf_buffer.h> +#include <printf_buffer_to_file.h> /* This code is shared between the standard stdio implementation found in GNU C library and the libio implementation originally found in @@ -47,21 +51,21 @@ #endif #define ARGCHECK(S, Format) \ - do \ - { \ - /* Check file argument for consistence. */ \ - CHECK_FILE (S, -1); \ - if (S->_flags & _IO_NO_WRITES) \ - { \ - S->_flags |= _IO_ERR_SEEN; \ - __set_errno (EBADF); \ - return -1; \ - } \ - if (Format == NULL) \ - { \ - __set_errno (EINVAL); \ - return -1; \ - } \ + do \ + { \ + /* Check file argument for consistence. */ \ + CHECK_FILE (S, -1); \ + if (S->_flags & _IO_NO_WRITES) \ + { \ + S->_flags |= _IO_ERR_SEEN; \ + __set_errno (EBADF); \ + return -1; \ + } \ + if (Format == NULL) \ + { \ + __set_errno (EINVAL); \ + return -1; \ + } \ } while (0) #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED) @@ -116,37 +120,9 @@ while (0) #endif -/* Add LENGTH to DONE. Return the new value of DONE, or -1 on - overflow (and set errno accordingly). */ -static inline int -done_add_func (size_t length, int done) -{ - if (done < 0) - return done; - int ret; - if (INT_ADD_WRAPV (done, length, &ret)) - { - __set_errno (EOVERFLOW); - return -1; - } - return ret; -} - -#define done_add(val) \ - do \ - { \ - /* Ensure that VAL has a type similar to int. */ \ - _Static_assert (sizeof (val) == sizeof (int), "value int size"); \ - _Static_assert ((__typeof__ (val)) -1 < 0, "value signed"); \ - done = done_add_func ((val), done); \ - if (done < 0) \ - goto all_done; \ - } \ - while (0) - #ifndef COMPILE_WPRINTF +# include "printf_buffer-char.h" # define vfprintf __vfprintf_internal -# define CHAR_T char # define OTHER_CHAR_T wchar_t # define UCHAR_T unsigned char # define INT_T int @@ -155,14 +131,12 @@ typedef const char *THOUSANDS_SEP_T; # define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10) # define STR_LEN(Str) strlen (Str) -# define PUT(F, S, N) _IO_sputn ((F), (S), (N)) -# define PUTC(C, F) _IO_putc_unlocked (C, F) # define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\ return -1 # define CONVERT_FROM_OTHER_STRING __wcsrtombs #else +# include "printf_buffer-wchar_t.h" # define vfprintf __vfwprintf_internal -# define CHAR_T wchar_t # define OTHER_CHAR_T char /* This is a hack!!! There should be a type uwchar_t. */ # define UCHAR_T unsigned int /* uwchar_t */ @@ -174,8 +148,6 @@ typedef wchar_t THOUSANDS_SEP_T; # include <_itowa.h> -# define PUT(F, S, N) _IO_sputn ((F), (S), (N)) -# define PUTC(C, F) _IO_putwc_unlocked (C, F) # define ORIENT if (_IO_fwide (s, 1) != 1) return -1 # define CONVERT_FROM_OTHER_STRING __mbsrtowcs @@ -186,76 +158,16 @@ typedef wchar_t THOUSANDS_SEP_T; # define EOF WEOF #endif -static inline int -pad_func (FILE *s, CHAR_T padchar, int width, int done) -{ - if (width > 0) - { - ssize_t written; -#ifndef COMPILE_WPRINTF - written = _IO_padn (s, padchar, width); -#else - written = _IO_wpadn (s, padchar, width); -#endif - if (__glibc_unlikely (written != width)) - return -1; - return done_add_func (width, done); - } - return done; -} - -#define PAD(Padchar) \ - do \ - { \ - done = pad_func (s, (Padchar), width, done); \ - if (done < 0) \ - goto all_done; \ - } \ - while (0) - -#include "_i18n_number.h" - /* Include the shared code for parsing the format string. */ #include "printf-parse.h" -#define outchar(Ch) \ - do \ - { \ - const INT_T outc = (Ch); \ - if (PUTC (outc, s) == EOF || done == INT_MAX) \ - { \ - done = -1; \ - goto all_done; \ - } \ - ++done; \ - } \ - while (0) - -static inline int -outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done) -{ - assert ((size_t) done <= (size_t) INT_MAX); - if ((size_t) PUT (s, string, length) != (size_t) (length)) - return -1; - return done_add_func (length, done); -} - -#define outstring(String, Len) \ - do \ - { \ - const void *string_ = (String); \ - done = outstring_func (s, string_, (Len), done); \ - if (done < 0) \ - goto all_done; \ - } \ - while (0) - /* Write the string SRC to S. If PREC is non-negative, write at most PREC bytes. If LEFT is true, perform left justification. */ -static int -outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, - int width, bool left, int done) +static void +outstring_converted_wide_string (struct Xprintf_buffer *target, + const OTHER_CHAR_T *src, int prec, + int width, bool left) { /* Use a small buffer to combine processing of multiple characters. CONVERT_FROM_OTHER_STRING expects the buffer size in (wide) @@ -290,7 +202,10 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, size_t written = CONVERT_FROM_OTHER_STRING (buf, &src_copy, write_limit, &mbstate); if (written == (size_t) -1) - return -1; + { + Xprintf_buffer_mark_failed (target); + return; + } if (written == 0) break; total_written += written; @@ -299,12 +214,9 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, } /* Output initial padding. */ - if (total_written < width) - { - done = pad_func (s, L_(' '), width - total_written, done); - if (done < 0) - return done; - } + Xprintf_buffer_pad (target, L_(' '), width - total_written); + if (Xprintf_buffer_has_failed (target)) + return; } /* Convert the input string, piece by piece. */ @@ -324,12 +236,13 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, size_t written = CONVERT_FROM_OTHER_STRING (buf, &src, write_limit, &mbstate); if (written == (size_t) -1) - return -1; + { + Xprintf_buffer_mark_failed (target); + return; + } if (written == 0) break; - done = outstring_func (s, (const UCHAR_T *) buf, written, done); - if (done < 0) - return done; + Xprintf_buffer_write (target, buf, written); total_written += written; if (prec >= 0) remaining -= written; @@ -337,21 +250,20 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec, } /* Add final padding. */ - if (width > 0 && left && total_written < width) - return pad_func (s, L_(' '), width - total_written, done); - return done; + if (width > 0 && left) + Xprintf_buffer_pad (target, L_(' '), width - total_written); } /* Calls __printf_fp or __printf_fphex based on the value of the format specifier INFO->spec. */ -static inline int -__printf_fp_spec (FILE *fp, const struct printf_info *info, - const void *const *args) +static inline void +__printf_fp_spec (struct Xprintf_buffer *target, + const struct printf_info *info, const void *const *args) { if (info->spec == 'a' || info->spec == 'A') - return __printf_fphex (fp, info, args); + Xprintf (fphex_l_buffer) (target, _NL_CURRENT_LOCALE, info, args); else - return __printf_fp (fp, info, args); + Xprintf (fp_l_buffer) (target, _NL_CURRENT_LOCALE, info, args); } /* For handling long_double and longlong we use the same flag. If @@ -656,31 +568,29 @@ static const uint8_t jump_table[] = REF (form_binary), /* for 'B', 'b' */ \ } -/* Helper function to provide temporary buffering for unbuffered streams. */ -static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list, - unsigned int) - __THROW __attribute__ ((noinline)); - /* Handle positional format specifiers. */ -static int printf_positional (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, - unsigned int mode_flags); +static void printf_positional (struct Xprintf_buffer *buf, + const CHAR_T *format, int readonly_format, + va_list ap, va_list *ap_savep, + int nspecs_done, const UCHAR_T *lead_str_end, + CHAR_T *work_buffer, int save_errno, + const char *grouping, + THOUSANDS_SEP_T thousands_sep, + unsigned int mode_flags); /* Handle unknown format specifier. */ -static int printf_unknown (FILE *, const struct printf_info *) __THROW; - -/* Group digits of number string. */ -static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *, - THOUSANDS_SEP_T); - -/* The function itself. */ -int -vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) +static void printf_unknown (struct Xprintf_buffer *, + const struct printf_info *) __THROW; + +static void group_number (struct Xprintf_buffer *buf, + struct grouping_iterator *iter, + CHAR_T *from, CHAR_T *to, + THOUSANDS_SEP_T thousands_sep, bool i18n); + +/* The buffer-based function itself. */ +void +Xprintf_buffer (struct Xprintf_buffer *buf, const CHAR_T *format, + va_list ap, unsigned int mode_flags) { /* The character used as thousands separator. */ THOUSANDS_SEP_T thousands_sep = 0; @@ -688,9 +598,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) /* The string describing the size of groups of digits. */ const char *grouping; - /* Place to accumulate the result. */ - int done; - /* Current character in format string. */ const UCHAR_T *f; @@ -717,30 +624,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) 0 if unknown. */ int readonly_format = 0; - /* Orient the stream. */ -#ifdef ORIENT - ORIENT; -#endif - - /* Sanity check of arguments. */ - ARGCHECK (s, format); - -#ifdef ORIENT - /* Check for correct orientation. */ - if (_IO_vtable_offset (s) == 0 - && _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1) - != (sizeof (CHAR_T) == 1 ? -1 : 1)) - /* The stream is already oriented otherwise. */ - return EOF; -#endif - - if (UNBUFFERED_P (s)) - /* Use a helper function which will allocate a local temporary buffer - for the stream and then call us again. */ - return buffered_vfprintf (s, format, ap, mode_flags); - /* Initialize local variables. */ - done = 0; grouping = (const char *) -1; #ifdef __va_copy /* This macro will be available soon in gcc's <stdarg.h>. We need it @@ -759,17 +643,15 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) f = lead_str_end = __find_specmb ((const UCHAR_T *) format); #endif - /* Lock stream. */ - _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s); - _IO_flockfile (s); - /* Write the literal text before the first format. */ - outstring ((const UCHAR_T *) format, - lead_str_end - (const UCHAR_T *) format); + Xprintf_buffer_write (buf, format, + lead_str_end - (const UCHAR_T *) format); + if (Xprintf_buffer_has_failed (buf)) + return; /* If we only have to print a simple string, return now. */ if (*f == L_('\0')) - goto all_done; + return; /* Use the slow path in case any printf handler is registered. */ if (__glibc_unlikely (__printf_function_table != NULL @@ -885,7 +767,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) if (pos == -1) { __set_errno (EOVERFLOW); - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } @@ -912,7 +794,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) if (__glibc_unlikely (width == -1)) { __set_errno (EOVERFLOW); - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } @@ -935,7 +817,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) if (pos == -1) { __set_errno (EOVERFLOW); - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } @@ -958,7 +840,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) if (prec == -1) { __set_errno (EOVERFLOW); - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } } @@ -1058,13 +940,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) PARSE_FLOAT_VA_ARG_EXTENDED (info); const void *ptr = &the_arg; - int function_done = __printf_fp_spec (s, &info, &ptr); - if (function_done < 0) - { - done = -1; - goto all_done; - } - done_add (function_done); + __printf_fp_spec (buf, &info, &ptr); } break; @@ -1073,7 +949,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) { /* The format string ended before the specifier is complete. */ __set_errno (EINVAL); - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } @@ -1093,30 +969,28 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) #endif /* Write the following constant string. */ - outstring (end_of_spec, f - end_of_spec); + Xprintf_buffer_write (buf, (const CHAR_T *) end_of_spec, + f - end_of_spec); } - while (*f != L_('\0')); + while (*f != L_('\0') && !Xprintf_buffer_has_failed (buf)); - /* Unlock stream and return. */ - goto all_done; + all_done: + /* printf_positional performs cleanup under its all_done label, so + vfprintf-process-arg.c uses it for this function and + printf_positional below. */ + return; /* Hand off processing for positional parameters. */ do_positional: - done = printf_positional (s, format, readonly_format, ap, &ap_save, - done, nspecs_done, lead_str_end, work_buffer, - save_errno, grouping, thousands_sep, mode_flags); - - all_done: - /* Unlock the stream. */ - _IO_funlockfile (s); - _IO_cleanup_region_end (0); - - return done; + printf_positional (buf, format, readonly_format, ap, &ap_save, + nspecs_done, lead_str_end, work_buffer, + save_errno, grouping, thousands_sep, mode_flags); } -static int -printf_positional (FILE *s, const CHAR_T *format, int readonly_format, - va_list ap, va_list *ap_savep, int done, int nspecs_done, +static void +printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format, + int readonly_format, + va_list ap, va_list *ap_savep, int nspecs_done, const UCHAR_T *lead_str_end, CHAR_T *work_buffer, int save_errno, const char *grouping, THOUSANDS_SEP_T thousands_sep, @@ -1171,7 +1045,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, { if (!scratch_buffer_grow_preserve (&specsbuf)) { - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } specs = specsbuf.data; @@ -1199,7 +1073,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type); if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg)) { - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } args_value = argsbuf.data; @@ -1312,7 +1186,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, } /* Now walk through all format specifiers and process them. */ - for (; (size_t) nspecs_done < nspecs; ++nspecs_done) + for (; (size_t) nspecs_done < nspecs && !Xprintf_buffer_has_failed (buf); + ++nspecs_done) { STEP4_TABLE; @@ -1376,26 +1251,19 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, } /* Process format specifiers. */ - while (1) + do { - 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); - + int function_done + = Xprintf (function_invoke) (buf, + __printf_function_table[(size_t) spec], + &args_value[specs[nspecs_done] + .data_arg], + specs[nspecs_done].ndata_args, + &specs[nspecs_done].info); if (function_done != -2) { /* If an error occurred we don't have information @@ -1403,11 +1271,9 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, if (function_done < 0) { /* Function has set errno. */ - done = -1; + Xprintf_buffer_mark_failed (buf); goto all_done; } - - done_add (function_done); break; } } @@ -1450,327 +1316,159 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, } SETUP_FLOAT128_INFO (specs[nspecs_done].info); - int function_done - = __printf_fp_spec (s, &specs[nspecs_done].info, &ptr); - if (function_done < 0) - { - /* Error in print handler; up to handler to set errno. */ - done = -1; - goto all_done; - } - done_add (function_done); + __printf_fp_spec (buf, &specs[nspecs_done].info, &ptr); } break; LABEL (form_unknown): { - int function_done = printf_unknown (s, &specs[nspecs_done].info); - - /* 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); + printf_unknown (buf, &specs[nspecs_done].info); } break; } + while (Xprintf_buffer_has_failed (buf)); /* Write the following constant string. */ - outstring (specs[nspecs_done].end_of_fmt, - specs[nspecs_done].next_fmt - - specs[nspecs_done].end_of_fmt); + Xprintf_buffer_write (buf, + (const CHAR_T *) specs[nspecs_done].end_of_fmt, + (specs[nspecs_done].next_fmt + - specs[nspecs_done].end_of_fmt)); } all_done: scratch_buffer_free (&argsbuf); scratch_buffer_free (&specsbuf); - return done; } /* Handle an unknown format specifier. This prints out a canonicalized representation of the format spec itself. */ -static int -printf_unknown (FILE *s, const struct printf_info *info) +static void +printf_unknown (struct Xprintf_buffer *buf, const struct printf_info *info) { - int done = 0; CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3]; CHAR_T *const workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; CHAR_T *w; - outchar (L_('%')); + Xprintf_buffer_putc (buf, L_('%')); if (info->alt) - outchar (L_('#')); + Xprintf_buffer_putc (buf, L_('#')); if (info->group) - outchar (L_('\'')); + Xprintf_buffer_putc (buf, L_('\'')); if (info->showsign) - outchar (L_('+')); + Xprintf_buffer_putc (buf, L_('+')); else if (info->space) - outchar (L_(' ')); + Xprintf_buffer_putc (buf, L_(' ')); if (info->left) - outchar (L_('-')); + Xprintf_buffer_putc (buf, L_('-')); if (info->pad == L_('0')) - outchar (L_('0')); + Xprintf_buffer_putc (buf, L_('0')); if (info->i18n) - outchar (L_('I')); + Xprintf_buffer_putc (buf, L_('I')); if (info->width != 0) { w = _itoa_word (info->width, workend, 10, 0); while (w < workend) - outchar (*w++); + Xprintf_buffer_putc (buf, *w++); } if (info->prec != -1) { - outchar (L_('.')); + Xprintf_buffer_putc (buf, L_('.')); w = _itoa_word (info->prec, workend, 10, 0); while (w < workend) - outchar (*w++); + Xprintf_buffer_putc (buf, *w++); } if (info->spec != L_('\0')) - outchar (info->spec); - - all_done: - return done; + Xprintf_buffer_putc (buf, info->spec); } - -/* Group the digits from W to REAR_PTR according to the grouping rules - of the current locale. The interpretation of GROUPING is as in - `struct lconv' from <locale.h>. The grouped number extends from - the returned pointer until REAR_PTR. FRONT_PTR to W is used as a - scratch area. */ -static CHAR_T * -group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr, - const char *grouping, THOUSANDS_SEP_T thousands_sep) + +static void +group_number (struct Xprintf_buffer *buf, + struct grouping_iterator *iter, + CHAR_T *from, CHAR_T *to, THOUSANDS_SEP_T thousands_sep, + bool i18n) { - /* Length of the current group. */ - int len; -#ifndef COMPILE_WPRINTF - /* Length of the separator (in wide mode, the separator is always a - single wide character). */ - int tlen = strlen (thousands_sep); + if (!i18n) + for (CHAR_T *cp = from; cp != to; ++cp) + { + if (__grouping_iterator_next (iter)) + { +#ifdef COMPILE_WPRINTF + __wprintf_buffer_putc (buf, thousands_sep); +#else + __printf_buffer_puts (buf, thousands_sep); #endif - - /* We treat all negative values like CHAR_MAX. */ - - if (*grouping == CHAR_MAX || *grouping <= 0) - /* No grouping should be done. */ - return w; - - len = *grouping++; - - /* Copy existing string so that nothing gets overwritten. */ - memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T)); - CHAR_T *s = front_ptr + (rear_ptr - w); - - w = rear_ptr; - - /* Process all characters in the string. */ - while (s > front_ptr) + } + Xprintf_buffer_putc (buf, *cp); + } + else { - *--w = *--s; - - if (--len == 0 && s > front_ptr) + /* Apply digit translation and grouping. */ + for (CHAR_T *cp = from; cp != to; ++cp) { - /* A new group begins. */ + if (__grouping_iterator_next (iter)) + { #ifdef COMPILE_WPRINTF - if (w != s) - *--w = thousands_sep; - else - /* Not enough room for the separator. */ - goto copy_rest; + __wprintf_buffer_putc (buf, thousands_sep); #else - int cnt = tlen; - if (tlen < w - s) - do - *--w = thousands_sep[--cnt]; - while (cnt > 0); - else - /* Not enough room for the separator. */ - goto copy_rest; -#endif - - if (*grouping == CHAR_MAX -#if CHAR_MIN < 0 - || *grouping < 0 + __printf_buffer_puts (buf, thousands_sep); #endif - ) - { - copy_rest: - /* No further grouping to be done. Copy the rest of the - number. */ - w -= s - front_ptr; - memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T)); - break; } - else if (*grouping != '\0') - len = *grouping++; - else - /* The previous grouping repeats ad infinitum. */ - len = grouping[-1]; - } - } - return w; -} - -/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */ -struct helper_file - { - struct _IO_FILE_plus _f; + int digit = *cp - '0'; #ifdef COMPILE_WPRINTF - struct _IO_wide_data _wide_data; -#endif - FILE *_put_stream; -#ifdef _IO_MTSAFE_IO - _IO_lock_t lock; -#endif - }; - -static int -_IO_helper_overflow (FILE *s, int c) -{ - FILE *target = ((struct helper_file*) s)->_put_stream; -#ifdef COMPILE_WPRINTF - int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base; - if (used) - { - size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used); - if (written == 0 || written == WEOF) - return WEOF; - __wmemmove (s->_wide_data->_IO_write_base, - s->_wide_data->_IO_write_base + written, - used - written); - s->_wide_data->_IO_write_ptr -= written; - } + __wprintf_buffer_putc + (buf, _NL_CURRENT_WORD (LC_CTYPE, + _NL_CTYPE_OUTDIGIT0_WC + digit)); #else - int used = s->_IO_write_ptr - s->_IO_write_base; - if (used) - { - size_t written = _IO_sputn (target, s->_IO_write_base, used); - if (written == 0 || written == EOF) - return EOF; - memmove (s->_IO_write_base, s->_IO_write_base + written, - used - written); - s->_IO_write_ptr -= written; - } + __printf_buffer_puts + (buf, _NL_CURRENT (LC_CTYPE, _NL_CTYPE_OUTDIGIT0_MB + digit)); #endif - return PUTC (c, s); + } + } } -#ifdef COMPILE_WPRINTF -static const struct _IO_jump_t _IO_helper_jumps libio_vtable = -{ - JUMP_INIT_DUMMY, - JUMP_INIT (finish, _IO_wdefault_finish), - JUMP_INIT (overflow, _IO_helper_overflow), - JUMP_INIT (underflow, _IO_default_underflow), - JUMP_INIT (uflow, _IO_default_uflow), - JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail), - JUMP_INIT (xsputn, _IO_wdefault_xsputn), - JUMP_INIT (xsgetn, _IO_wdefault_xsgetn), - JUMP_INIT (seekoff, _IO_default_seekoff), - JUMP_INIT (seekpos, _IO_default_seekpos), - JUMP_INIT (setbuf, _IO_default_setbuf), - JUMP_INIT (sync, _IO_default_sync), - JUMP_INIT (doallocate, _IO_wdefault_doallocate), - JUMP_INIT (read, _IO_default_read), - JUMP_INIT (write, _IO_default_write), - JUMP_INIT (seek, _IO_default_seek), - JUMP_INIT (close, _IO_default_close), - JUMP_INIT (stat, _IO_default_stat) -}; -#else -static const struct _IO_jump_t _IO_helper_jumps libio_vtable = -{ - JUMP_INIT_DUMMY, - JUMP_INIT (finish, _IO_default_finish), - JUMP_INIT (overflow, _IO_helper_overflow), - JUMP_INIT (underflow, _IO_default_underflow), - JUMP_INIT (uflow, _IO_default_uflow), - JUMP_INIT (pbackfail, _IO_default_pbackfail), - JUMP_INIT (xsputn, _IO_default_xsputn), - JUMP_INIT (xsgetn, _IO_default_xsgetn), - JUMP_INIT (seekoff, _IO_default_seekoff), - JUMP_INIT (seekpos, _IO_default_seekpos), - JUMP_INIT (setbuf, _IO_default_setbuf), - JUMP_INIT (sync, _IO_default_sync), - JUMP_INIT (doallocate, _IO_default_doallocate), - JUMP_INIT (read, _IO_default_read), - JUMP_INIT (write, _IO_default_write), - JUMP_INIT (seek, _IO_default_seek), - JUMP_INIT (close, _IO_default_close), - JUMP_INIT (stat, _IO_default_stat) -}; -#endif -static int -buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args, - unsigned int mode_flags) +/* The FILE-based function. */ +int +vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) { - CHAR_T buf[BUFSIZ]; - struct helper_file helper; - FILE *hp = (FILE *) &helper._f; - int result, to_flush; - /* Orient the stream. */ #ifdef ORIENT ORIENT; #endif - /* Initialize helper. */ - helper._put_stream = s; -#ifdef COMPILE_WPRINTF - hp->_wide_data = &helper._wide_data; - _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T)); - hp->_mode = 1; -#else - _IO_setp (hp, buf, buf + sizeof buf); - hp->_mode = -1; -#endif - hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK; -#if _IO_JUMPS_OFFSET - hp->_vtable_offset = 0; -#endif -#ifdef _IO_MTSAFE_IO - hp->_lock = NULL; + /* Sanity check of arguments. */ + ARGCHECK (s, format); + +#ifdef ORIENT + /* Check for correct orientation. */ + if (_IO_vtable_offset (s) == 0 + && _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1) + != (sizeof (CHAR_T) == 1 ? -1 : 1)) + /* The stream is already oriented otherwise. */ + return EOF; #endif - hp->_flags2 = s->_flags2; - _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps; - /* Now print to helper instead. */ - result = vfprintf (hp, format, args, mode_flags); + int done; /* Lock stream. */ - __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s); + _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s); _IO_flockfile (s); - /* Now flush anything from the helper to the S. */ -#ifdef COMPILE_WPRINTF - if ((to_flush = (hp->_wide_data->_IO_write_ptr - - hp->_wide_data->_IO_write_base)) > 0) - { - if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush) - != to_flush) - result = -1; - } -#else - if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0) - { - if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush) - result = -1; - } -#endif + /* Set up the wrapping buffer. */ + struct Xprintf (buffer_to_file) wrap; + Xprintf (buffer_to_file_init) (&wrap, s); + + /* Perform the printing operation on the buffer. */ + Xprintf_buffer (&wrap.base, format, ap, mode_flags); + done = Xprintf (buffer_to_file_done) (&wrap); /* Unlock the stream. */ _IO_funlockfile (s); - __libc_cleanup_region_end (0); + _IO_cleanup_region_end (0); - return result; + return done; } |