summaryrefslogtreecommitdiff
path: root/stdio-common/vfprintf-internal.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/vfprintf-internal.c')
-rw-r--r--stdio-common/vfprintf-internal.c660
1 files changed, 179 insertions, 481 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;
+static void printf_unknown (struct Xprintf_buffer *,
+ 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);
+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 function itself. */
-int
-vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+/* 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;
-#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;
+ int digit = *cp - '0';
#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;
}