mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 04:50:07 +00:00
stdio-common: Convert vfprintf and related functions to buffers
vfprintf is entangled with vfwprintf (of course), __printf_fp, __printf_fphex, __vstrfmon_l_internal, and the strfrom family of functions. The latter use the internal snprintf functionality, so vsnprintf is converted as well. The simples conversion is __printf_fphex, followed by __vstrfmon_l_internal and __printf_fp, and finally __vfprintf_internal and __vfwprintf_internal. __vsnprintf_internal and strfrom* are mostly consuming the new interfaces, so they are comparatively simple. __printf_fp is a public symbol, so the FILE *-based interface had to preserved. The __printf_fp rewrite does not change the actual binary-to-decimal conversion algorithm, and digits are still not emitted directly to the target buffer. However, the staging buffer now uses bytes instead of wide characters, and one buffer copy is eliminated. The changes are at least performance-neutral in my testing. Floating point printing and snprintf improved measurably, so that this Lua script for i=1,5000000 do print(i, i * math.pi) end runs about 5% faster for me. To preserve fprintf performance for a simple "%d" format, this commit has some logic changes under LABEL (unsigned_number) to avoid additional function calls. There are certainly some very easy performance improvements here: binary, octal and hexadecimal formatting can easily avoid the temporary work buffer (the number of digits can be computed ahead-of-time using one of the __builtin_clz* built-ins). Decimal formatting can use a specialized version of _itoa_word for base 10. The existing (inconsistent) width handling between strfmon and printf is preserved here. __print_fp_buffer_1 would have to use __translated_number_width to achieve ISO conformance for printf. Test expectations in libio/tst-vtables-common.c are adjusted because the internal staging buffer merges all virtual function calls into one. In general, stack buffer usage is greatly reduced, particularly for unbuffered input streams. __printf_fp can still use a large buffer in binary128 mode for %g, though. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
parent
46378560e0
commit
e88b9f0e5c
@ -599,14 +599,12 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
|
|||||||
--required=_IO_file_jumps \
|
--required=_IO_file_jumps \
|
||||||
--required=_IO_file_jumps_maybe_mmap \
|
--required=_IO_file_jumps_maybe_mmap \
|
||||||
--required=_IO_file_jumps_mmap \
|
--required=_IO_file_jumps_mmap \
|
||||||
--required=_IO_helper_jumps \
|
|
||||||
--required=_IO_mem_jumps \
|
--required=_IO_mem_jumps \
|
||||||
--required=_IO_obstack_jumps \
|
--required=_IO_obstack_jumps \
|
||||||
--required=_IO_printf_buffer_as_file_jumps \
|
--required=_IO_printf_buffer_as_file_jumps \
|
||||||
--required=_IO_proc_jumps \
|
--required=_IO_proc_jumps \
|
||||||
--required=_IO_str_chk_jumps \
|
--required=_IO_str_chk_jumps \
|
||||||
--required=_IO_str_jumps \
|
--required=_IO_str_jumps \
|
||||||
--required=_IO_strn_jumps \
|
|
||||||
--required=_IO_wfile_jumps \
|
--required=_IO_wfile_jumps \
|
||||||
--required=_IO_wfile_jumps_maybe_mmap \
|
--required=_IO_wfile_jumps_maybe_mmap \
|
||||||
--required=_IO_wfile_jumps_mmap \
|
--required=_IO_wfile_jumps_mmap \
|
||||||
|
@ -65,18 +65,31 @@ int __translated_number_width (locale_t loc,
|
|||||||
const char *first, const char *last)
|
const char *first, const char *last)
|
||||||
attribute_hidden;
|
attribute_hidden;
|
||||||
|
|
||||||
extern int __printf_fphex (FILE *, const struct printf_info *,
|
|
||||||
const void *const *) attribute_hidden;
|
struct __printf_buffer;
|
||||||
|
void __printf_buffer (struct __printf_buffer *buf, const char *format,
|
||||||
|
va_list ap, unsigned int mode_flags);
|
||||||
|
struct __wprintf_buffer;
|
||||||
|
void __wprintf_buffer (struct __wprintf_buffer *buf, const wchar_t *format,
|
||||||
|
va_list ap, unsigned int mode_flags);
|
||||||
|
|
||||||
extern int __printf_fp (FILE *, const struct printf_info *,
|
extern int __printf_fp (FILE *, const struct printf_info *,
|
||||||
const void *const *);
|
const void *const *);
|
||||||
libc_hidden_proto (__printf_fp)
|
libc_hidden_proto (__printf_fp)
|
||||||
extern int __printf_fp_l (FILE *, locale_t, const struct printf_info *,
|
|
||||||
const void *const *);
|
|
||||||
libc_hidden_proto (__printf_fp_l)
|
|
||||||
|
|
||||||
extern unsigned int __guess_grouping (unsigned int intdig_max,
|
void __printf_fphex_l_buffer (struct __printf_buffer *, locale_t,
|
||||||
const char *grouping)
|
const struct printf_info *,
|
||||||
attribute_hidden;
|
const void *const *) attribute_hidden;
|
||||||
|
void __printf_fp_l_buffer (struct __printf_buffer *, locale_t,
|
||||||
|
const struct printf_info *,
|
||||||
|
const void *const *) attribute_hidden;
|
||||||
|
struct __wprintf_buffer;
|
||||||
|
void __wprintf_fphex_l_buffer (struct __wprintf_buffer *, locale_t,
|
||||||
|
const struct printf_info *,
|
||||||
|
const void *const *) attribute_hidden;
|
||||||
|
void __wprintf_fp_l_buffer (struct __wprintf_buffer *, locale_t,
|
||||||
|
const struct printf_info *,
|
||||||
|
const void *const *) attribute_hidden;
|
||||||
|
|
||||||
# endif /* !_ISOMAC */
|
# endif /* !_ISOMAC */
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,7 +45,12 @@
|
|||||||
enum __printf_buffer_mode
|
enum __printf_buffer_mode
|
||||||
{
|
{
|
||||||
__printf_buffer_mode_failed,
|
__printf_buffer_mode_failed,
|
||||||
|
__printf_buffer_mode_snprintf,
|
||||||
__printf_buffer_mode_to_file,
|
__printf_buffer_mode_to_file,
|
||||||
|
__printf_buffer_mode_strfmon,
|
||||||
|
__printf_buffer_mode_fp, /* For __printf_fp_l_buffer. */
|
||||||
|
__printf_buffer_mode_fp_to_wide, /* For __wprintf_fp_l_buffer. */
|
||||||
|
__printf_buffer_mode_fphex_to_wide, /* For __wprintf_fphex_l_buffer. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Buffer for fast character writing with overflow handling.
|
/* Buffer for fast character writing with overflow handling.
|
||||||
@ -268,13 +273,45 @@ bool __wprintf_buffer_flush (struct __wprintf_buffer *buf) attribute_hidden;
|
|||||||
#define Xprintf_buffer_puts Xprintf (buffer_puts)
|
#define Xprintf_buffer_puts Xprintf (buffer_puts)
|
||||||
#define Xprintf_buffer_write Xprintf (buffer_write)
|
#define Xprintf_buffer_write Xprintf (buffer_write)
|
||||||
|
|
||||||
|
/* Commonly used buffers. */
|
||||||
|
|
||||||
|
struct __printf_buffer_snprintf
|
||||||
|
{
|
||||||
|
struct __printf_buffer base;
|
||||||
|
#define PRINTF_BUFFER_SIZE_DISCARD 128
|
||||||
|
char discard[PRINTF_BUFFER_SIZE_DISCARD]; /* Used in counting mode. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Sets up [BUFFER, BUFFER + LENGTH) as the write target. If LENGTH
|
||||||
|
is positive, also writes a NUL byte to *BUFFER. */
|
||||||
|
void __printf_buffer_snprintf_init (struct __printf_buffer_snprintf *,
|
||||||
|
char *buffer, size_t length)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
/* Add the null terminator after everything has been written. The
|
||||||
|
return value is the one expected by printf (see __printf_buffer_done). */
|
||||||
|
int __printf_buffer_snprintf_done (struct __printf_buffer_snprintf *)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
/* Flush function implementations follow. They are called from
|
/* Flush function implementations follow. They are called from
|
||||||
__printf_buffer_flush. Generic code should not call these flush
|
__printf_buffer_flush. Generic code should not call these flush
|
||||||
functions directly. Some modes have inline implementations. */
|
functions directly. Some modes have inline implementations. */
|
||||||
|
|
||||||
|
void __printf_buffer_flush_snprintf (struct __printf_buffer_snprintf *)
|
||||||
|
attribute_hidden;
|
||||||
struct __printf_buffer_to_file;
|
struct __printf_buffer_to_file;
|
||||||
void __printf_buffer_flush_to_file (struct __printf_buffer_to_file *)
|
void __printf_buffer_flush_to_file (struct __printf_buffer_to_file *)
|
||||||
attribute_hidden;
|
attribute_hidden;
|
||||||
|
struct __printf_buffer_fp;
|
||||||
|
void __printf_buffer_flush_fp (struct __printf_buffer_fp *)
|
||||||
|
attribute_hidden;
|
||||||
|
struct __printf_buffer_fp_to_wide;
|
||||||
|
void __printf_buffer_flush_fp_to_wide (struct __printf_buffer_fp_to_wide *)
|
||||||
|
attribute_hidden;
|
||||||
|
struct __printf_buffer_fphex_to_wide;
|
||||||
|
void __printf_buffer_flush_fphex_to_wide (struct
|
||||||
|
__printf_buffer_fphex_to_wide *)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
struct __wprintf_buffer_to_file;
|
struct __wprintf_buffer_to_file;
|
||||||
void __wprintf_buffer_flush_to_file (struct __wprintf_buffer_to_file *)
|
void __wprintf_buffer_flush_to_file (struct __wprintf_buffer_to_file *)
|
||||||
@ -282,10 +319,15 @@ void __wprintf_buffer_flush_to_file (struct __wprintf_buffer_to_file *)
|
|||||||
|
|
||||||
/* Buffer sizes. These can be tuned as necessary. There is a tension
|
/* Buffer sizes. These can be tuned as necessary. There is a tension
|
||||||
here between stack consumption, cache usage, and additional system
|
here between stack consumption, cache usage, and additional system
|
||||||
calls or heap allocations (if the buffer is too small). */
|
calls or heap allocations (if the buffer is too small).
|
||||||
|
|
||||||
|
Also see PRINTF_BUFFER_SIZE_DISCARD above for snprintf. */
|
||||||
|
|
||||||
/* Fallback buffer if the underlying FILE * stream does not provide
|
/* Fallback buffer if the underlying FILE * stream does not provide
|
||||||
buffer space. */
|
buffer space. */
|
||||||
#define PRINTF_BUFFER_SIZE_TO_FILE_STAGE 128
|
#define PRINTF_BUFFER_SIZE_TO_FILE_STAGE 128
|
||||||
|
|
||||||
|
/* Temporary buffer used during floating point digit translation. */
|
||||||
|
#define PRINTF_BUFFER_SIZE_DIGITS 64
|
||||||
|
|
||||||
#endif /* PRINTF_BUFFER_H */
|
#endif /* PRINTF_BUFFER_H */
|
||||||
|
@ -70,9 +70,6 @@ typedef struct
|
|||||||
char overflow_buf[64];
|
char overflow_buf[64];
|
||||||
} _IO_strnfile;
|
} _IO_strnfile;
|
||||||
|
|
||||||
extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
_IO_strfile f;
|
_IO_strfile f;
|
||||||
|
@ -409,11 +409,14 @@ void _IO_init (FILE *fp, int flags);
|
|||||||
static void
|
static void
|
||||||
with_compatibility_fprintf (void *closure)
|
with_compatibility_fprintf (void *closure)
|
||||||
{
|
{
|
||||||
|
/* A temporary staging buffer is used in the current fprintf
|
||||||
|
implementation, which is why there is just one call to
|
||||||
|
xsputn. */
|
||||||
TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
|
TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
|
||||||
TEST_COMPARE (shared->calls, 3);
|
TEST_COMPARE (shared->calls, 1);
|
||||||
TEST_COMPARE (shared->calls_xsputn, 3);
|
TEST_COMPARE (shared->calls_xsputn, 1);
|
||||||
TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
|
TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
|
||||||
"CD", 2);
|
"ABCD", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -25,97 +25,76 @@
|
|||||||
in files containing the exception. */
|
in files containing the exception. */
|
||||||
|
|
||||||
#include "libioP.h"
|
#include "libioP.h"
|
||||||
#include "strfile.h"
|
|
||||||
|
|
||||||
static int _IO_strn_overflow (FILE *fp, int c) __THROW;
|
#include <array_length.h>
|
||||||
|
#include <printf.h>
|
||||||
|
#include <printf_buffer.h>
|
||||||
|
|
||||||
static int
|
void
|
||||||
_IO_strn_overflow (FILE *fp, int c)
|
__printf_buffer_flush_snprintf (struct __printf_buffer_snprintf *buf)
|
||||||
{
|
{
|
||||||
/* When we come to here this means the user supplied buffer is
|
/* Record the bytes written so far, before switching buffers. */
|
||||||
filled. But since we must return the number of characters which
|
buf->base.written += buf->base.write_ptr - buf->base.write_base;
|
||||||
would have been written in total we must provide a buffer for
|
|
||||||
further use. We can do this by writing on and on in the overflow
|
|
||||||
buffer in the _IO_strnfile structure. */
|
|
||||||
_IO_strnfile *snf = (_IO_strnfile *) fp;
|
|
||||||
|
|
||||||
if (fp->_IO_buf_base != snf->overflow_buf)
|
if (buf->base.write_base != buf->discard)
|
||||||
{
|
{
|
||||||
/* Terminate the string. We know that there is room for at
|
/* We just finished writing the caller-supplied buffer. Force
|
||||||
least one more character since we initialized the stream with
|
NUL termination if the string length is not zero. */
|
||||||
a size to make this possible. */
|
if (buf->base.write_base != buf->base.write_end)
|
||||||
*fp->_IO_write_ptr = '\0';
|
buf->base.write_end[-1] = '\0';
|
||||||
|
|
||||||
_IO_setb (fp, snf->overflow_buf,
|
|
||||||
snf->overflow_buf + sizeof (snf->overflow_buf), 0);
|
|
||||||
|
|
||||||
fp->_IO_write_base = snf->overflow_buf;
|
/* Switch to the discard buffer. */
|
||||||
fp->_IO_read_base = snf->overflow_buf;
|
buf->base.write_base = buf->discard;
|
||||||
fp->_IO_read_ptr = snf->overflow_buf;
|
buf->base.write_ptr = buf->discard;
|
||||||
fp->_IO_read_end = snf->overflow_buf + sizeof (snf->overflow_buf);
|
buf->base.write_end = array_end (buf->discard);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp->_IO_write_ptr = snf->overflow_buf;
|
buf->base.write_base = buf->discard;
|
||||||
fp->_IO_write_end = snf->overflow_buf;
|
buf->base.write_ptr = buf->discard;
|
||||||
|
|
||||||
/* Since we are not really interested in storing the characters
|
|
||||||
which do not fit in the buffer we simply ignore it. */
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
|
__printf_buffer_snprintf_init (struct __printf_buffer_snprintf *buf,
|
||||||
|
char *buffer, size_t length)
|
||||||
{
|
{
|
||||||
JUMP_INIT_DUMMY,
|
__printf_buffer_init (&buf->base, buffer, length,
|
||||||
JUMP_INIT(finish, _IO_str_finish),
|
__printf_buffer_mode_snprintf);
|
||||||
JUMP_INIT(overflow, _IO_strn_overflow),
|
if (length > 0)
|
||||||
JUMP_INIT(underflow, _IO_str_underflow),
|
/* Historic behavior for trivially overlapping buffers (checked by
|
||||||
JUMP_INIT(uflow, _IO_default_uflow),
|
the test suite). */
|
||||||
JUMP_INIT(pbackfail, _IO_str_pbackfail),
|
*buffer = '\0';
|
||||||
JUMP_INIT(xsputn, _IO_default_xsputn),
|
}
|
||||||
JUMP_INIT(xsgetn, _IO_default_xsgetn),
|
|
||||||
JUMP_INIT(seekoff, _IO_str_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),
|
|
||||||
JUMP_INIT(showmanyc, _IO_default_showmanyc),
|
|
||||||
JUMP_INIT(imbue, _IO_default_imbue)
|
|
||||||
};
|
|
||||||
|
|
||||||
|
int
|
||||||
|
__printf_buffer_snprintf_done (struct __printf_buffer_snprintf *buf)
|
||||||
|
{
|
||||||
|
/* NB: Do not check for buf->base.fail here. Write the null
|
||||||
|
terminator even in case of errors. */
|
||||||
|
|
||||||
|
if (buf->base.write_ptr < buf->base.write_end)
|
||||||
|
*buf->base.write_ptr = '\0';
|
||||||
|
else if (buf->base.write_ptr > buf->base.write_base)
|
||||||
|
/* If write_ptr == write_base, nothing has been written. No null
|
||||||
|
termination is needed because of the early truncation in
|
||||||
|
__printf_buffer_snprintf_init (the historic behavior).
|
||||||
|
|
||||||
|
We might also be at the start of the discard buffer, but in
|
||||||
|
this case __printf_buffer_flush_snprintf has already written
|
||||||
|
the NUL terminator. */
|
||||||
|
buf->base.write_ptr[-1] = '\0';
|
||||||
|
|
||||||
|
return __printf_buffer_done (&buf->base);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__vsnprintf_internal (char *string, size_t maxlen, const char *format,
|
__vsnprintf_internal (char *string, size_t maxlen, const char *format,
|
||||||
va_list args, unsigned int mode_flags)
|
va_list args, unsigned int mode_flags)
|
||||||
{
|
{
|
||||||
_IO_strnfile sf;
|
struct __printf_buffer_snprintf buf;
|
||||||
int ret;
|
__printf_buffer_snprintf_init (&buf, string, maxlen);
|
||||||
#ifdef _IO_MTSAFE_IO
|
__printf_buffer (&buf.base, format, args, mode_flags);
|
||||||
sf.f._sbf._f._lock = NULL;
|
return __printf_buffer_snprintf_done (&buf);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We need to handle the special case where MAXLEN is 0. Use the
|
|
||||||
overflow buffer right from the start. */
|
|
||||||
if (maxlen == 0)
|
|
||||||
{
|
|
||||||
string = sf.overflow_buf;
|
|
||||||
maxlen = sizeof (sf.overflow_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
_IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
|
|
||||||
_IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
|
|
||||||
string[0] = '\0';
|
|
||||||
_IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
|
|
||||||
ret = __vfprintf_internal (&sf.f._sbf._f, format, args, mode_flags);
|
|
||||||
|
|
||||||
if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
|
|
||||||
*sf.f._sbf._f._IO_write_ptr = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
License along with the GNU C Library; if not, see
|
License along with the GNU C Library; if not, see
|
||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <printf_buffer.h>
|
#include <printf_buffer.h>
|
||||||
|
|
||||||
#include "printf_buffer-char.h"
|
#include "printf_buffer-char.h"
|
||||||
@ -24,7 +25,11 @@
|
|||||||
/* The __printf_buffer_flush_* functions are defined together with
|
/* The __printf_buffer_flush_* functions are defined together with
|
||||||
functions that are pulled in by strong references. */
|
functions that are pulled in by strong references. */
|
||||||
#ifndef SHARED
|
#ifndef SHARED
|
||||||
|
# pragma weak __printf_buffer_flush_snprintf
|
||||||
# pragma weak __printf_buffer_flush_to_file
|
# pragma weak __printf_buffer_flush_to_file
|
||||||
|
# pragma weak __printf_buffer_flush_fp
|
||||||
|
# pragma weak __printf_buffer_flush_fp_to_wide
|
||||||
|
# pragma weak __printf_buffer_flush_fphex_to_wide
|
||||||
#endif /* !SHARED */
|
#endif /* !SHARED */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -34,9 +39,27 @@ __printf_buffer_do_flush (struct __printf_buffer *buf)
|
|||||||
{
|
{
|
||||||
case __printf_buffer_mode_failed:
|
case __printf_buffer_mode_failed:
|
||||||
return;
|
return;
|
||||||
|
case __printf_buffer_mode_snprintf:
|
||||||
|
__printf_buffer_flush_snprintf ((struct __printf_buffer_snprintf *) buf);
|
||||||
|
return;
|
||||||
case __printf_buffer_mode_to_file:
|
case __printf_buffer_mode_to_file:
|
||||||
__printf_buffer_flush_to_file ((struct __printf_buffer_to_file *) buf);
|
__printf_buffer_flush_to_file ((struct __printf_buffer_to_file *) buf);
|
||||||
return;
|
return;
|
||||||
|
case __printf_buffer_mode_strfmon:
|
||||||
|
__set_errno (E2BIG);
|
||||||
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
|
case __printf_buffer_mode_fp:
|
||||||
|
__printf_buffer_flush_fp ((struct __printf_buffer_fp *) buf);
|
||||||
|
return;
|
||||||
|
case __printf_buffer_mode_fp_to_wide:
|
||||||
|
__printf_buffer_flush_fp_to_wide
|
||||||
|
((struct __printf_buffer_fp_to_wide *) buf);
|
||||||
|
return;
|
||||||
|
case __printf_buffer_mode_fphex_to_wide:
|
||||||
|
__printf_buffer_flush_fphex_to_wide
|
||||||
|
((struct __printf_buffer_fphex_to_wide *) buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
__builtin_trap ();
|
__builtin_trap ();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -17,10 +17,12 @@
|
|||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <array_length.h>
|
#include <array_length.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <ieee754.h>
|
#include <ieee754.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
|
#include <libioP.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -30,6 +32,9 @@
|
|||||||
#include <locale/localeinfo.h>
|
#include <locale/localeinfo.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <rounding-mode.h>
|
#include <rounding-mode.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <printf_buffer.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#if __HAVE_DISTINCT_FLOAT128
|
#if __HAVE_DISTINCT_FLOAT128
|
||||||
# include "ieee754_float128.h"
|
# include "ieee754_float128.h"
|
||||||
@ -39,56 +44,9 @@
|
|||||||
IEEE854_FLOAT128_BIAS)
|
IEEE854_FLOAT128_BIAS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
|
static void
|
||||||
#include <assert.h>
|
__printf_fphex_buffer (struct __printf_buffer *buf,
|
||||||
|
const char *decimal,
|
||||||
#include <libioP.h>
|
|
||||||
#define PUT(f, s, n) _IO_sputn (f, s, n)
|
|
||||||
#define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n))
|
|
||||||
#undef putc
|
|
||||||
#define putc(c, f) (wide \
|
|
||||||
? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
|
|
||||||
|
|
||||||
|
|
||||||
/* Macros for doing the actual output. */
|
|
||||||
|
|
||||||
#define outchar(ch) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
const int outc = (ch); \
|
|
||||||
if (putc (outc, fp) == EOF) \
|
|
||||||
return -1; \
|
|
||||||
++done; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define PRINT(ptr, wptr, len) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
size_t outlen = (len); \
|
|
||||||
if (wide) \
|
|
||||||
while (outlen-- > 0) \
|
|
||||||
outchar (*wptr++); \
|
|
||||||
else \
|
|
||||||
while (outlen-- > 0) \
|
|
||||||
outchar (*ptr++); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define PADN(ch, len) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (PAD (fp, ch, len) != len) \
|
|
||||||
return -1; \
|
|
||||||
done += len; \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
# define MIN(a,b) ((a)<(b)?(a):(b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
__printf_fphex (FILE *fp,
|
|
||||||
const struct printf_info *info,
|
const struct printf_info *info,
|
||||||
const void *const *args)
|
const void *const *args)
|
||||||
{
|
{
|
||||||
@ -106,34 +64,19 @@ __printf_fphex (FILE *fp,
|
|||||||
/* This function always uses LC_NUMERIC. */
|
/* This function always uses LC_NUMERIC. */
|
||||||
assert (info->extra == 0);
|
assert (info->extra == 0);
|
||||||
|
|
||||||
/* Locale-dependent representation of decimal point. Hexadecimal
|
|
||||||
formatting always using LC_NUMERIC (disregarding info->extra). */
|
|
||||||
const char *decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
|
|
||||||
wchar_t decimalwc = _NL_CURRENT_WORD (LC_NUMERIC,
|
|
||||||
_NL_NUMERIC_DECIMAL_POINT_WC);
|
|
||||||
|
|
||||||
/* The decimal point character must never be zero. */
|
|
||||||
assert (*decimal != '\0' && decimalwc != L'\0');
|
|
||||||
|
|
||||||
/* "NaN" or "Inf" for the special cases. */
|
/* "NaN" or "Inf" for the special cases. */
|
||||||
const char *special = NULL;
|
const char *special = NULL;
|
||||||
const wchar_t *wspecial = NULL;
|
|
||||||
|
|
||||||
/* Buffer for the generated number string for the mantissa. The
|
/* Buffer for the generated number string for the mantissa. The
|
||||||
maximal size for the mantissa is 128 bits. */
|
maximal size for the mantissa is 128 bits. */
|
||||||
char numbuf[32];
|
char numbuf[32];
|
||||||
char *numstr;
|
char *numstr;
|
||||||
char *numend;
|
char *numend;
|
||||||
wchar_t wnumbuf[32];
|
|
||||||
wchar_t *wnumstr;
|
|
||||||
wchar_t *wnumend;
|
|
||||||
int negative;
|
int negative;
|
||||||
|
|
||||||
/* The maximal exponent of two in decimal notation has 5 digits. */
|
/* The maximal exponent of two in decimal notation has 5 digits. */
|
||||||
char expbuf[5];
|
char expbuf[5];
|
||||||
char *expstr;
|
char *expstr;
|
||||||
wchar_t wexpbuf[5];
|
|
||||||
wchar_t *wexpstr;
|
|
||||||
int expnegative;
|
int expnegative;
|
||||||
int exponent;
|
int exponent;
|
||||||
|
|
||||||
@ -149,12 +92,6 @@ __printf_fphex (FILE *fp,
|
|||||||
/* Width. */
|
/* Width. */
|
||||||
int width = info->width;
|
int width = info->width;
|
||||||
|
|
||||||
/* Number of characters written. */
|
|
||||||
int done = 0;
|
|
||||||
|
|
||||||
/* Nonzero if this is output on a wide character stream. */
|
|
||||||
int wide = info->wide;
|
|
||||||
|
|
||||||
#define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
|
#define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
|
||||||
{ \
|
{ \
|
||||||
(VAR) = *(const FLOAT *) args[0]; \
|
(VAR) = *(const FLOAT *) args[0]; \
|
||||||
@ -163,30 +100,18 @@ __printf_fphex (FILE *fp,
|
|||||||
if (isnan (VAR)) \
|
if (isnan (VAR)) \
|
||||||
{ \
|
{ \
|
||||||
if (isupper (info->spec)) \
|
if (isupper (info->spec)) \
|
||||||
{ \
|
|
||||||
special = "NAN"; \
|
special = "NAN"; \
|
||||||
wspecial = L"NAN"; \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
special = "nan"; \
|
special = "nan"; \
|
||||||
wspecial = L"nan"; \
|
|
||||||
} \
|
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if (isinf (VAR)) \
|
if (isinf (VAR)) \
|
||||||
{ \
|
{ \
|
||||||
if (isupper (info->spec)) \
|
if (isupper (info->spec)) \
|
||||||
{ \
|
|
||||||
special = "INF"; \
|
special = "INF"; \
|
||||||
wspecial = L"INF"; \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
special = "inf"; \
|
special = "inf"; \
|
||||||
wspecial = L"inf"; \
|
|
||||||
} \
|
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
negative = signbit (VAR); \
|
negative = signbit (VAR); \
|
||||||
@ -215,22 +140,22 @@ __printf_fphex (FILE *fp,
|
|||||||
--width;
|
--width;
|
||||||
width -= 3;
|
width -= 3;
|
||||||
|
|
||||||
if (!info->left && width > 0)
|
if (!info->left)
|
||||||
PADN (' ', width);
|
__printf_buffer_pad (buf, ' ', width);
|
||||||
|
|
||||||
if (negative)
|
if (negative)
|
||||||
outchar ('-');
|
__printf_buffer_putc (buf, '-');
|
||||||
else if (info->showsign)
|
else if (info->showsign)
|
||||||
outchar ('+');
|
__printf_buffer_putc (buf, '+');
|
||||||
else if (info->space)
|
else if (info->space)
|
||||||
outchar (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
|
|
||||||
PRINT (special, wspecial, 3);
|
__printf_buffer_puts (buf, special);
|
||||||
|
|
||||||
if (info->left && width > 0)
|
if (info->left)
|
||||||
PADN (' ', width);
|
__printf_buffer_pad (buf, ' ', width);
|
||||||
|
|
||||||
return done;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __HAVE_DISTINCT_FLOAT128
|
#if __HAVE_DISTINCT_FLOAT128
|
||||||
@ -252,26 +177,15 @@ __printf_fphex (FILE *fp,
|
|||||||
zero_mantissa = num == 0;
|
zero_mantissa = num == 0;
|
||||||
|
|
||||||
if (sizeof (unsigned long int) > 6)
|
if (sizeof (unsigned long int) > 6)
|
||||||
{
|
|
||||||
wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
|
|
||||||
info->spec == 'A');
|
|
||||||
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
|
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
|
||||||
info->spec == 'A');
|
info->spec == 'A');
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
|
|
||||||
info->spec == 'A');
|
|
||||||
numstr = _itoa (num, numbuf + sizeof numbuf, 16,
|
numstr = _itoa (num, numbuf + sizeof numbuf, 16,
|
||||||
info->spec == 'A');
|
info->spec == 'A');
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill with zeroes. */
|
/* Fill with zeroes. */
|
||||||
while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
|
while (numstr > numbuf + (sizeof numbuf - 13))
|
||||||
{
|
|
||||||
*--wnumstr = L'0';
|
|
||||||
*--numstr = '0';
|
*--numstr = '0';
|
||||||
}
|
|
||||||
|
|
||||||
leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
|
leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
|
||||||
|
|
||||||
@ -307,13 +221,9 @@ __printf_fphex (FILE *fp,
|
|||||||
/* Look for trailing zeroes. */
|
/* Look for trailing zeroes. */
|
||||||
if (! zero_mantissa)
|
if (! zero_mantissa)
|
||||||
{
|
{
|
||||||
wnumend = array_end (wnumbuf);
|
|
||||||
numend = array_end (numbuf);
|
numend = array_end (numbuf);
|
||||||
while (wnumend[-1] == L'0')
|
while (numend[-1] == '0')
|
||||||
{
|
|
||||||
--wnumend;
|
|
||||||
--numend;
|
--numend;
|
||||||
}
|
|
||||||
|
|
||||||
bool do_round_away = false;
|
bool do_round_away = false;
|
||||||
|
|
||||||
@ -352,7 +262,6 @@ __printf_fphex (FILE *fp,
|
|||||||
like in ASCII. This is true for the rest of GNU, too. */
|
like in ASCII. This is true for the rest of GNU, too. */
|
||||||
if (ch == '9')
|
if (ch == '9')
|
||||||
{
|
{
|
||||||
wnumstr[cnt] = (wchar_t) info->spec;
|
|
||||||
numstr[cnt] = info->spec; /* This is tricky,
|
numstr[cnt] = info->spec; /* This is tricky,
|
||||||
think about it! */
|
think about it! */
|
||||||
break;
|
break;
|
||||||
@ -360,14 +269,10 @@ __printf_fphex (FILE *fp,
|
|||||||
else if (tolower (ch) < 'f')
|
else if (tolower (ch) < 'f')
|
||||||
{
|
{
|
||||||
++numstr[cnt];
|
++numstr[cnt];
|
||||||
++wnumstr[cnt];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
numstr[cnt] = '0';
|
numstr[cnt] = '0';
|
||||||
wnumstr[cnt] = L'0';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (cnt < 0)
|
if (cnt < 0)
|
||||||
{
|
{
|
||||||
@ -401,13 +306,10 @@ __printf_fphex (FILE *fp,
|
|||||||
if (precision == -1)
|
if (precision == -1)
|
||||||
precision = 0;
|
precision = 0;
|
||||||
numend = numstr;
|
numend = numstr;
|
||||||
wnumend = wnumstr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we can compute the exponent string. */
|
/* Now we can compute the exponent string. */
|
||||||
expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
|
expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
|
||||||
wexpstr = _itowa_word (exponent,
|
|
||||||
wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
|
|
||||||
|
|
||||||
/* Now we have all information to compute the size. */
|
/* Now we have all information to compute the size. */
|
||||||
width -= ((negative || info->showsign || info->space)
|
width -= ((negative || info->showsign || info->space)
|
||||||
@ -421,54 +323,110 @@ __printf_fphex (FILE *fp,
|
|||||||
A special case when the mantissa or the precision is zero and the `#'
|
A special case when the mantissa or the precision is zero and the `#'
|
||||||
is not given. In this case we must not print the decimal point. */
|
is not given. In this case we must not print the decimal point. */
|
||||||
if (precision > 0 || info->alt)
|
if (precision > 0 || info->alt)
|
||||||
width -= wide ? 1 : strlen (decimal);
|
--width;
|
||||||
|
|
||||||
if (!info->left && info->pad != '0' && width > 0)
|
if (!info->left && info->pad != '0')
|
||||||
PADN (' ', width);
|
__printf_buffer_pad (buf, ' ', width);
|
||||||
|
|
||||||
if (negative)
|
if (negative)
|
||||||
outchar ('-');
|
__printf_buffer_putc (buf, '-');
|
||||||
else if (info->showsign)
|
else if (info->showsign)
|
||||||
outchar ('+');
|
__printf_buffer_putc (buf, '+');
|
||||||
else if (info->space)
|
else if (info->space)
|
||||||
outchar (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
|
|
||||||
outchar ('0');
|
__printf_buffer_putc (buf, '0');
|
||||||
if ('X' - 'A' == 'x' - 'a')
|
if ('X' - 'A' == 'x' - 'a')
|
||||||
outchar (info->spec + ('x' - 'a'));
|
__printf_buffer_putc (buf, info->spec + ('x' - 'a'));
|
||||||
else
|
else
|
||||||
outchar (info->spec == 'A' ? 'X' : 'x');
|
__printf_buffer_putc (buf, info->spec == 'A' ? 'X' : 'x');
|
||||||
|
|
||||||
if (!info->left && info->pad == '0' && width > 0)
|
if (!info->left && info->pad == '0')
|
||||||
PADN ('0', width);
|
__printf_buffer_pad (buf, '0', width);
|
||||||
|
|
||||||
outchar (leading);
|
__printf_buffer_putc (buf, leading);
|
||||||
|
|
||||||
if (precision > 0 || info->alt)
|
if (precision > 0 || info->alt)
|
||||||
{
|
__printf_buffer_puts (buf, decimal);
|
||||||
const wchar_t *wtmp = &decimalwc;
|
|
||||||
PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (precision > 0)
|
if (precision > 0)
|
||||||
{
|
{
|
||||||
ssize_t tofill = precision - (numend - numstr);
|
ssize_t tofill = precision - (numend - numstr);
|
||||||
PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
|
__printf_buffer_write (buf, numstr, MIN (numend - numstr, precision));
|
||||||
if (tofill > 0)
|
__printf_buffer_pad (buf, '0', tofill);
|
||||||
PADN ('0', tofill);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('P' - 'A' == 'p' - 'a')
|
if ('P' - 'A' == 'p' - 'a')
|
||||||
outchar (info->spec + ('p' - 'a'));
|
__printf_buffer_putc (buf, info->spec + ('p' - 'a'));
|
||||||
else
|
else
|
||||||
outchar (info->spec == 'A' ? 'P' : 'p');
|
__printf_buffer_putc (buf, info->spec == 'A' ? 'P' : 'p');
|
||||||
|
|
||||||
outchar (expnegative ? '-' : '+');
|
__printf_buffer_putc (buf, expnegative ? '-' : '+');
|
||||||
|
|
||||||
PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
|
__printf_buffer_write (buf, expstr, (expbuf + sizeof expbuf) - expstr);
|
||||||
|
|
||||||
if (info->left && info->pad != '0' && width > 0)
|
if (info->left && info->pad != '0')
|
||||||
PADN (info->pad, width);
|
__printf_buffer_pad (buf, info->pad, width);
|
||||||
|
}
|
||||||
return done;
|
|
||||||
|
void
|
||||||
|
__printf_fphex_l_buffer (struct __printf_buffer *buf, locale_t loc,
|
||||||
|
const struct printf_info *info,
|
||||||
|
const void *const *args)
|
||||||
|
{
|
||||||
|
__printf_fphex_buffer (buf, _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT),
|
||||||
|
info, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The wide buffer version is implemented by translating the output of
|
||||||
|
the multibyte verison. */
|
||||||
|
|
||||||
|
struct __printf_buffer_fphex_to_wide
|
||||||
|
{
|
||||||
|
struct __printf_buffer base;
|
||||||
|
wchar_t decimalwc;
|
||||||
|
struct __wprintf_buffer *next;
|
||||||
|
char untranslated[PRINTF_BUFFER_SIZE_DIGITS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Translate to wide characters, rewriting "." to the actual decimal
|
||||||
|
point. */
|
||||||
|
void
|
||||||
|
__printf_buffer_flush_fphex_to_wide (struct __printf_buffer_fphex_to_wide *buf)
|
||||||
|
{
|
||||||
|
/* No need to adjust buf->base.written, only buf->next->written matters. */
|
||||||
|
for (char *p = buf->untranslated; p < buf->base.write_ptr; ++p)
|
||||||
|
{
|
||||||
|
/* wchar_t overlaps with char in the ASCII range. */
|
||||||
|
wchar_t ch = *p;
|
||||||
|
if (ch == L'.')
|
||||||
|
ch = buf->decimalwc;
|
||||||
|
__wprintf_buffer_putc (buf->next, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!__wprintf_buffer_has_failed (buf->next))
|
||||||
|
buf->base.write_ptr = buf->untranslated;
|
||||||
|
else
|
||||||
|
__printf_buffer_mark_failed (&buf->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__wprintf_fphex_l_buffer (struct __wprintf_buffer *next, locale_t loc,
|
||||||
|
const struct printf_info *info,
|
||||||
|
const void *const *args)
|
||||||
|
{
|
||||||
|
struct __printf_buffer_fphex_to_wide buf;
|
||||||
|
__printf_buffer_init (&buf.base, buf.untranslated, sizeof (buf.untranslated),
|
||||||
|
__printf_buffer_mode_fphex_to_wide);
|
||||||
|
buf.decimalwc = _nl_lookup_word (loc, LC_NUMERIC,
|
||||||
|
_NL_NUMERIC_DECIMAL_POINT_WC);
|
||||||
|
buf.next = next;
|
||||||
|
__printf_fphex_buffer (&buf.base, ".", info, args);
|
||||||
|
if (__printf_buffer_has_failed (&buf.base))
|
||||||
|
{
|
||||||
|
__wprintf_buffer_mark_failed (buf.next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
__printf_buffer_flush_fphex_to_wide (&buf);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <array_length.h>
|
#include <array_length.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
@ -29,9 +30,12 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <_itoa.h>
|
#include <_itoa.h>
|
||||||
#include <locale/localeinfo.h>
|
#include <locale/localeinfo.h>
|
||||||
|
#include <grouping_iterator.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <scratch_buffer.h>
|
#include <scratch_buffer.h>
|
||||||
#include <intprops.h>
|
#include <intprops.h>
|
||||||
|
#include <printf_buffer.h>
|
||||||
|
#include <printf_buffer_to_file.h>
|
||||||
|
|
||||||
/* This code is shared between the standard stdio implementation found
|
/* This code is shared between the standard stdio implementation found
|
||||||
in GNU C library and the libio implementation originally found in
|
in GNU C library and the libio implementation originally found in
|
||||||
@ -116,37 +120,9 @@
|
|||||||
while (0)
|
while (0)
|
||||||
#endif
|
#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
|
#ifndef COMPILE_WPRINTF
|
||||||
|
# include "printf_buffer-char.h"
|
||||||
# define vfprintf __vfprintf_internal
|
# define vfprintf __vfprintf_internal
|
||||||
# define CHAR_T char
|
|
||||||
# define OTHER_CHAR_T wchar_t
|
# define OTHER_CHAR_T wchar_t
|
||||||
# define UCHAR_T unsigned char
|
# define UCHAR_T unsigned char
|
||||||
# define INT_T int
|
# define INT_T int
|
||||||
@ -155,14 +131,12 @@ typedef const char *THOUSANDS_SEP_T;
|
|||||||
# define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10)
|
# define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10)
|
||||||
# define STR_LEN(Str) strlen (Str)
|
# 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)\
|
# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
|
||||||
return -1
|
return -1
|
||||||
# define CONVERT_FROM_OTHER_STRING __wcsrtombs
|
# define CONVERT_FROM_OTHER_STRING __wcsrtombs
|
||||||
#else
|
#else
|
||||||
|
# include "printf_buffer-wchar_t.h"
|
||||||
# define vfprintf __vfwprintf_internal
|
# define vfprintf __vfwprintf_internal
|
||||||
# define CHAR_T wchar_t
|
|
||||||
# define OTHER_CHAR_T char
|
# define OTHER_CHAR_T char
|
||||||
/* This is a hack!!! There should be a type uwchar_t. */
|
/* This is a hack!!! There should be a type uwchar_t. */
|
||||||
# define UCHAR_T unsigned int /* uwchar_t */
|
# define UCHAR_T unsigned int /* uwchar_t */
|
||||||
@ -174,8 +148,6 @@ typedef wchar_t THOUSANDS_SEP_T;
|
|||||||
|
|
||||||
# include <_itowa.h>
|
# 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 ORIENT if (_IO_fwide (s, 1) != 1) return -1
|
||||||
# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
|
# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
|
||||||
|
|
||||||
@ -186,76 +158,16 @@ typedef wchar_t THOUSANDS_SEP_T;
|
|||||||
# define EOF WEOF
|
# define EOF WEOF
|
||||||
#endif
|
#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 the shared code for parsing the format string. */
|
||||||
#include "printf-parse.h"
|
#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
|
/* Write the string SRC to S. If PREC is non-negative, write at most
|
||||||
PREC bytes. If LEFT is true, perform left justification. */
|
PREC bytes. If LEFT is true, perform left justification. */
|
||||||
static int
|
static void
|
||||||
outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
|
outstring_converted_wide_string (struct Xprintf_buffer *target,
|
||||||
int width, bool left, int done)
|
const OTHER_CHAR_T *src, int prec,
|
||||||
|
int width, bool left)
|
||||||
{
|
{
|
||||||
/* Use a small buffer to combine processing of multiple characters.
|
/* Use a small buffer to combine processing of multiple characters.
|
||||||
CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
|
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
|
size_t written = CONVERT_FROM_OTHER_STRING
|
||||||
(buf, &src_copy, write_limit, &mbstate);
|
(buf, &src_copy, write_limit, &mbstate);
|
||||||
if (written == (size_t) -1)
|
if (written == (size_t) -1)
|
||||||
return -1;
|
{
|
||||||
|
Xprintf_buffer_mark_failed (target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (written == 0)
|
if (written == 0)
|
||||||
break;
|
break;
|
||||||
total_written += written;
|
total_written += written;
|
||||||
@ -299,12 +214,9 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Output initial padding. */
|
/* Output initial padding. */
|
||||||
if (total_written < width)
|
Xprintf_buffer_pad (target, L_(' '), width - total_written);
|
||||||
{
|
if (Xprintf_buffer_has_failed (target))
|
||||||
done = pad_func (s, L_(' '), width - total_written, done);
|
return;
|
||||||
if (done < 0)
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the input string, piece by piece. */
|
/* 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
|
size_t written = CONVERT_FROM_OTHER_STRING
|
||||||
(buf, &src, write_limit, &mbstate);
|
(buf, &src, write_limit, &mbstate);
|
||||||
if (written == (size_t) -1)
|
if (written == (size_t) -1)
|
||||||
return -1;
|
{
|
||||||
|
Xprintf_buffer_mark_failed (target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (written == 0)
|
if (written == 0)
|
||||||
break;
|
break;
|
||||||
done = outstring_func (s, (const UCHAR_T *) buf, written, done);
|
Xprintf_buffer_write (target, buf, written);
|
||||||
if (done < 0)
|
|
||||||
return done;
|
|
||||||
total_written += written;
|
total_written += written;
|
||||||
if (prec >= 0)
|
if (prec >= 0)
|
||||||
remaining -= written;
|
remaining -= written;
|
||||||
@ -337,21 +250,20 @@ outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add final padding. */
|
/* Add final padding. */
|
||||||
if (width > 0 && left && total_written < width)
|
if (width > 0 && left)
|
||||||
return pad_func (s, L_(' '), width - total_written, done);
|
Xprintf_buffer_pad (target, L_(' '), width - total_written);
|
||||||
return done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calls __printf_fp or __printf_fphex based on the value of the
|
/* Calls __printf_fp or __printf_fphex based on the value of the
|
||||||
format specifier INFO->spec. */
|
format specifier INFO->spec. */
|
||||||
static inline int
|
static inline void
|
||||||
__printf_fp_spec (FILE *fp, const struct printf_info *info,
|
__printf_fp_spec (struct Xprintf_buffer *target,
|
||||||
const void *const *args)
|
const struct printf_info *info, const void *const *args)
|
||||||
{
|
{
|
||||||
if (info->spec == 'a' || info->spec == 'A')
|
if (info->spec == 'a' || info->spec == 'A')
|
||||||
return __printf_fphex (fp, info, args);
|
Xprintf (fphex_l_buffer) (target, _NL_CURRENT_LOCALE, info, args);
|
||||||
else
|
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
|
/* For handling long_double and longlong we use the same flag. If
|
||||||
@ -656,15 +568,10 @@ static const uint8_t jump_table[] =
|
|||||||
REF (form_binary), /* for 'B', 'b' */ \
|
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. */
|
/* Handle positional format specifiers. */
|
||||||
static int printf_positional (FILE *s,
|
static void printf_positional (struct Xprintf_buffer *buf,
|
||||||
const CHAR_T *format, int readonly_format,
|
const CHAR_T *format, int readonly_format,
|
||||||
va_list ap, va_list *ap_savep, int done,
|
va_list ap, va_list *ap_savep,
|
||||||
int nspecs_done, const UCHAR_T *lead_str_end,
|
int nspecs_done, const UCHAR_T *lead_str_end,
|
||||||
CHAR_T *work_buffer, int save_errno,
|
CHAR_T *work_buffer, int save_errno,
|
||||||
const char *grouping,
|
const char *grouping,
|
||||||
@ -672,15 +579,18 @@ static int printf_positional (FILE *s,
|
|||||||
unsigned int mode_flags);
|
unsigned int mode_flags);
|
||||||
|
|
||||||
/* Handle unknown format specifier. */
|
/* 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 void group_number (struct Xprintf_buffer *buf,
|
||||||
static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
|
struct grouping_iterator *iter,
|
||||||
THOUSANDS_SEP_T);
|
CHAR_T *from, CHAR_T *to,
|
||||||
|
THOUSANDS_SEP_T thousands_sep, bool i18n);
|
||||||
|
|
||||||
/* The function itself. */
|
/* The buffer-based function itself. */
|
||||||
int
|
void
|
||||||
vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
Xprintf_buffer (struct Xprintf_buffer *buf, const CHAR_T *format,
|
||||||
|
va_list ap, unsigned int mode_flags)
|
||||||
{
|
{
|
||||||
/* The character used as thousands separator. */
|
/* The character used as thousands separator. */
|
||||||
THOUSANDS_SEP_T thousands_sep = 0;
|
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. */
|
/* The string describing the size of groups of digits. */
|
||||||
const char *grouping;
|
const char *grouping;
|
||||||
|
|
||||||
/* Place to accumulate the result. */
|
|
||||||
int done;
|
|
||||||
|
|
||||||
/* Current character in format string. */
|
/* Current character in format string. */
|
||||||
const UCHAR_T *f;
|
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. */
|
0 if unknown. */
|
||||||
int readonly_format = 0;
|
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. */
|
/* Initialize local variables. */
|
||||||
done = 0;
|
|
||||||
grouping = (const char *) -1;
|
grouping = (const char *) -1;
|
||||||
#ifdef __va_copy
|
#ifdef __va_copy
|
||||||
/* This macro will be available soon in gcc's <stdarg.h>. We need it
|
/* 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);
|
f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Lock stream. */
|
|
||||||
_IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
|
|
||||||
_IO_flockfile (s);
|
|
||||||
|
|
||||||
/* Write the literal text before the first format. */
|
/* Write the literal text before the first format. */
|
||||||
outstring ((const UCHAR_T *) format,
|
Xprintf_buffer_write (buf, format,
|
||||||
lead_str_end - (const UCHAR_T *) 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 we only have to print a simple string, return now. */
|
||||||
if (*f == L_('\0'))
|
if (*f == L_('\0'))
|
||||||
goto all_done;
|
return;
|
||||||
|
|
||||||
/* Use the slow path in case any printf handler is registered. */
|
/* Use the slow path in case any printf handler is registered. */
|
||||||
if (__glibc_unlikely (__printf_function_table != NULL
|
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)
|
if (pos == -1)
|
||||||
{
|
{
|
||||||
__set_errno (EOVERFLOW);
|
__set_errno (EOVERFLOW);
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
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))
|
if (__glibc_unlikely (width == -1))
|
||||||
{
|
{
|
||||||
__set_errno (EOVERFLOW);
|
__set_errno (EOVERFLOW);
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,7 +817,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
|||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
{
|
{
|
||||||
__set_errno (EOVERFLOW);
|
__set_errno (EOVERFLOW);
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -958,7 +840,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
|||||||
if (prec == -1)
|
if (prec == -1)
|
||||||
{
|
{
|
||||||
__set_errno (EOVERFLOW);
|
__set_errno (EOVERFLOW);
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
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);
|
PARSE_FLOAT_VA_ARG_EXTENDED (info);
|
||||||
const void *ptr = &the_arg;
|
const void *ptr = &the_arg;
|
||||||
|
|
||||||
int function_done = __printf_fp_spec (s, &info, &ptr);
|
__printf_fp_spec (buf, &info, &ptr);
|
||||||
if (function_done < 0)
|
|
||||||
{
|
|
||||||
done = -1;
|
|
||||||
goto all_done;
|
|
||||||
}
|
|
||||||
done_add (function_done);
|
|
||||||
}
|
}
|
||||||
break;
|
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. */
|
/* The format string ended before the specifier is complete. */
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,30 +969,28 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Write the following constant string. */
|
/* 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. */
|
all_done:
|
||||||
goto 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. */
|
/* Hand off processing for positional parameters. */
|
||||||
do_positional:
|
do_positional:
|
||||||
done = printf_positional (s, format, readonly_format, ap, &ap_save,
|
printf_positional (buf, format, readonly_format, ap, &ap_save,
|
||||||
done, nspecs_done, lead_str_end, work_buffer,
|
nspecs_done, lead_str_end, work_buffer,
|
||||||
save_errno, grouping, thousands_sep, mode_flags);
|
save_errno, grouping, thousands_sep, mode_flags);
|
||||||
|
|
||||||
all_done:
|
|
||||||
/* Unlock the stream. */
|
|
||||||
_IO_funlockfile (s);
|
|
||||||
_IO_cleanup_region_end (0);
|
|
||||||
|
|
||||||
return done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
printf_positional (struct Xprintf_buffer * buf, const CHAR_T *format,
|
||||||
va_list ap, va_list *ap_savep, int done, int nspecs_done,
|
int readonly_format,
|
||||||
|
va_list ap, va_list *ap_savep, int nspecs_done,
|
||||||
const UCHAR_T *lead_str_end,
|
const UCHAR_T *lead_str_end,
|
||||||
CHAR_T *work_buffer, int save_errno,
|
CHAR_T *work_buffer, int save_errno,
|
||||||
const char *grouping, THOUSANDS_SEP_T thousands_sep,
|
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))
|
if (!scratch_buffer_grow_preserve (&specsbuf))
|
||||||
{
|
{
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
specs = specsbuf.data;
|
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);
|
= sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
|
||||||
if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
|
if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
|
||||||
{
|
{
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
args_value = argsbuf.data;
|
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. */
|
/* 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;
|
STEP4_TABLE;
|
||||||
|
|
||||||
@ -1376,26 +1251,19 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Process format specifiers. */
|
/* Process format specifiers. */
|
||||||
while (1)
|
do
|
||||||
{
|
{
|
||||||
int function_done;
|
|
||||||
|
|
||||||
if (spec <= UCHAR_MAX
|
if (spec <= UCHAR_MAX
|
||||||
&& __printf_function_table != NULL
|
&& __printf_function_table != NULL
|
||||||
&& __printf_function_table[(size_t) spec] != NULL)
|
&& __printf_function_table[(size_t) spec] != NULL)
|
||||||
{
|
{
|
||||||
const void **ptr = alloca (specs[nspecs_done].ndata_args
|
int function_done
|
||||||
* sizeof (const void *));
|
= Xprintf (function_invoke) (buf,
|
||||||
|
__printf_function_table[(size_t) spec],
|
||||||
/* Fill in an array of pointers to the argument values. */
|
&args_value[specs[nspecs_done]
|
||||||
for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
|
.data_arg],
|
||||||
++i)
|
specs[nspecs_done].ndata_args,
|
||||||
ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
|
&specs[nspecs_done].info);
|
||||||
|
|
||||||
/* Call the function. */
|
|
||||||
function_done = __printf_function_table[(size_t) spec]
|
|
||||||
(s, &specs[nspecs_done].info, ptr);
|
|
||||||
|
|
||||||
if (function_done != -2)
|
if (function_done != -2)
|
||||||
{
|
{
|
||||||
/* If an error occurred we don't have information
|
/* 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)
|
if (function_done < 0)
|
||||||
{
|
{
|
||||||
/* Function has set errno. */
|
/* Function has set errno. */
|
||||||
done = -1;
|
Xprintf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
done_add (function_done);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1450,327 +1316,159 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
|||||||
}
|
}
|
||||||
SETUP_FLOAT128_INFO (specs[nspecs_done].info);
|
SETUP_FLOAT128_INFO (specs[nspecs_done].info);
|
||||||
|
|
||||||
int function_done
|
__printf_fp_spec (buf, &specs[nspecs_done].info, &ptr);
|
||||||
= __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);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LABEL (form_unknown):
|
LABEL (form_unknown):
|
||||||
{
|
{
|
||||||
int function_done = printf_unknown (s, &specs[nspecs_done].info);
|
printf_unknown (buf, &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);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
while (Xprintf_buffer_has_failed (buf));
|
||||||
|
|
||||||
/* Write the following constant string. */
|
/* Write the following constant string. */
|
||||||
outstring (specs[nspecs_done].end_of_fmt,
|
Xprintf_buffer_write (buf,
|
||||||
specs[nspecs_done].next_fmt
|
(const CHAR_T *) specs[nspecs_done].end_of_fmt,
|
||||||
- specs[nspecs_done].end_of_fmt);
|
(specs[nspecs_done].next_fmt
|
||||||
|
- specs[nspecs_done].end_of_fmt));
|
||||||
}
|
}
|
||||||
all_done:
|
all_done:
|
||||||
scratch_buffer_free (&argsbuf);
|
scratch_buffer_free (&argsbuf);
|
||||||
scratch_buffer_free (&specsbuf);
|
scratch_buffer_free (&specsbuf);
|
||||||
return done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle an unknown format specifier. This prints out a canonicalized
|
/* Handle an unknown format specifier. This prints out a canonicalized
|
||||||
representation of the format spec itself. */
|
representation of the format spec itself. */
|
||||||
static int
|
static void
|
||||||
printf_unknown (FILE *s, const struct printf_info *info)
|
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 work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
|
||||||
CHAR_T *const workend
|
CHAR_T *const workend
|
||||||
= &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
|
= &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
|
||||||
CHAR_T *w;
|
CHAR_T *w;
|
||||||
|
|
||||||
outchar (L_('%'));
|
Xprintf_buffer_putc (buf, L_('%'));
|
||||||
|
|
||||||
if (info->alt)
|
if (info->alt)
|
||||||
outchar (L_('#'));
|
Xprintf_buffer_putc (buf, L_('#'));
|
||||||
if (info->group)
|
if (info->group)
|
||||||
outchar (L_('\''));
|
Xprintf_buffer_putc (buf, L_('\''));
|
||||||
if (info->showsign)
|
if (info->showsign)
|
||||||
outchar (L_('+'));
|
Xprintf_buffer_putc (buf, L_('+'));
|
||||||
else if (info->space)
|
else if (info->space)
|
||||||
outchar (L_(' '));
|
Xprintf_buffer_putc (buf, L_(' '));
|
||||||
if (info->left)
|
if (info->left)
|
||||||
outchar (L_('-'));
|
Xprintf_buffer_putc (buf, L_('-'));
|
||||||
if (info->pad == L_('0'))
|
if (info->pad == L_('0'))
|
||||||
outchar (L_('0'));
|
Xprintf_buffer_putc (buf, L_('0'));
|
||||||
if (info->i18n)
|
if (info->i18n)
|
||||||
outchar (L_('I'));
|
Xprintf_buffer_putc (buf, L_('I'));
|
||||||
|
|
||||||
if (info->width != 0)
|
if (info->width != 0)
|
||||||
{
|
{
|
||||||
w = _itoa_word (info->width, workend, 10, 0);
|
w = _itoa_word (info->width, workend, 10, 0);
|
||||||
while (w < workend)
|
while (w < workend)
|
||||||
outchar (*w++);
|
Xprintf_buffer_putc (buf, *w++);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->prec != -1)
|
if (info->prec != -1)
|
||||||
{
|
{
|
||||||
outchar (L_('.'));
|
Xprintf_buffer_putc (buf, L_('.'));
|
||||||
w = _itoa_word (info->prec, workend, 10, 0);
|
w = _itoa_word (info->prec, workend, 10, 0);
|
||||||
while (w < workend)
|
while (w < workend)
|
||||||
outchar (*w++);
|
Xprintf_buffer_putc (buf, *w++);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->spec != L_('\0'))
|
if (info->spec != L_('\0'))
|
||||||
outchar (info->spec);
|
Xprintf_buffer_putc (buf, info->spec);
|
||||||
|
|
||||||
all_done:
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
*--w = *--s;
|
|
||||||
|
|
||||||
if (--len == 0 && s > front_ptr)
|
|
||||||
{
|
|
||||||
/* A new group begins. */
|
|
||||||
#ifdef COMPILE_WPRINTF
|
|
||||||
if (w != s)
|
|
||||||
*--w = thousands_sep;
|
|
||||||
else
|
|
||||||
/* Not enough room for the separator. */
|
|
||||||
goto copy_rest;
|
|
||||||
#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
|
|
||||||
#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;
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return PUTC (c, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!i18n)
|
||||||
|
for (CHAR_T *cp = from; cp != to; ++cp)
|
||||||
|
{
|
||||||
|
if (__grouping_iterator_next (iter))
|
||||||
|
{
|
||||||
#ifdef COMPILE_WPRINTF
|
#ifdef COMPILE_WPRINTF
|
||||||
static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
|
__wprintf_buffer_putc (buf, thousands_sep);
|
||||||
{
|
|
||||||
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
|
#else
|
||||||
static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
|
__printf_buffer_puts (buf, thousands_sep);
|
||||||
{
|
|
||||||
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
|
#endif
|
||||||
|
}
|
||||||
|
Xprintf_buffer_putc (buf, *cp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Apply digit translation and grouping. */
|
||||||
|
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
|
||||||
|
}
|
||||||
|
int digit = *cp - '0';
|
||||||
|
#ifdef COMPILE_WPRINTF
|
||||||
|
__wprintf_buffer_putc
|
||||||
|
(buf, _NL_CURRENT_WORD (LC_CTYPE,
|
||||||
|
_NL_CTYPE_OUTDIGIT0_WC + digit));
|
||||||
|
#else
|
||||||
|
__printf_buffer_puts
|
||||||
|
(buf, _NL_CURRENT (LC_CTYPE, _NL_CTYPE_OUTDIGIT0_MB + digit));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
|
/* The FILE-based function. */
|
||||||
unsigned int mode_flags)
|
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. */
|
/* Orient the stream. */
|
||||||
#ifdef ORIENT
|
#ifdef ORIENT
|
||||||
ORIENT;
|
ORIENT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize helper. */
|
/* Sanity check of arguments. */
|
||||||
helper._put_stream = s;
|
ARGCHECK (s, format);
|
||||||
#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;
|
|
||||||
#endif
|
|
||||||
hp->_flags2 = s->_flags2;
|
|
||||||
_IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
|
|
||||||
|
|
||||||
/* Now print to helper instead. */
|
#ifdef ORIENT
|
||||||
result = vfprintf (hp, format, args, mode_flags);
|
/* 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
|
||||||
|
|
||||||
|
int done;
|
||||||
|
|
||||||
/* Lock stream. */
|
/* Lock stream. */
|
||||||
__libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
|
_IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
|
||||||
_IO_flockfile (s);
|
_IO_flockfile (s);
|
||||||
|
|
||||||
/* Now flush anything from the helper to the S. */
|
/* Set up the wrapping buffer. */
|
||||||
#ifdef COMPILE_WPRINTF
|
struct Xprintf (buffer_to_file) wrap;
|
||||||
if ((to_flush = (hp->_wide_data->_IO_write_ptr
|
Xprintf (buffer_to_file_init) (&wrap, s);
|
||||||
- hp->_wide_data->_IO_write_base)) > 0)
|
|
||||||
{
|
/* Perform the printing operation on the buffer. */
|
||||||
if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
|
Xprintf_buffer (&wrap.base, format, ap, mode_flags);
|
||||||
!= to_flush)
|
done = Xprintf (buffer_to_file_done) (&wrap);
|
||||||
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
|
|
||||||
|
|
||||||
/* Unlock the stream. */
|
/* Unlock the stream. */
|
||||||
_IO_funlockfile (s);
|
_IO_funlockfile (s);
|
||||||
__libc_cleanup_region_end (0);
|
_IO_cleanup_region_end (0);
|
||||||
|
|
||||||
return result;
|
return done;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
now process the wanted format specifier. */
|
now process the wanted format specifier. */
|
||||||
LABEL (form_percent):
|
LABEL (form_percent):
|
||||||
/* Write a literal "%". */
|
/* Write a literal "%". */
|
||||||
outchar (L_('%'));
|
Xprintf_buffer_putc (buf, L_('%'));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LABEL (form_integer):
|
LABEL (form_integer):
|
||||||
@ -116,16 +116,8 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */
|
|||||||
*--string = L_('0');
|
*--string = L_('0');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
/* Put the number in WORK. */
|
/* Put the number in WORK. */
|
||||||
string = _itoa (number.longlong, workend, base,
|
string = _itoa (number.longlong, workend, base, spec == L_('X'));
|
||||||
spec == L_('X'));
|
|
||||||
if (group && grouping)
|
|
||||||
string = group_number (work_buffer, string, workend,
|
|
||||||
grouping, thousands_sep);
|
|
||||||
if (use_outdigits && base == 10)
|
|
||||||
string = _i18n_number_rewrite (string, workend, workend);
|
|
||||||
}
|
|
||||||
/* Simplify further test for num != 0. */
|
/* Simplify further test for num != 0. */
|
||||||
number.word = number.longlong != 0;
|
number.word = number.longlong != 0;
|
||||||
}
|
}
|
||||||
@ -159,27 +151,46 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */
|
|||||||
*--string = L_('0');
|
*--string = L_('0');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
/* Put the number in WORK. */
|
/* Put the number in WORK. */
|
||||||
string = _itoa_word (number.word, workend, base,
|
string = _itoa_word (number.word, workend, base,
|
||||||
spec == L_('X'));
|
spec == L_('X'));
|
||||||
if (group && grouping)
|
|
||||||
string = group_number (work_buffer, string, workend,
|
|
||||||
grouping, thousands_sep);
|
|
||||||
if (use_outdigits && base == 10)
|
|
||||||
string = _i18n_number_rewrite (string, workend, workend);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prec <= workend - string && number.word != 0 && alt && base == 8)
|
/* Grouping is also used for outdigits translation. */
|
||||||
/* Add octal marker. */
|
struct grouping_iterator iter;
|
||||||
*--string = L_('0');
|
bool number_slow_path = group || (use_outdigits && base == 10);
|
||||||
|
if (group)
|
||||||
|
__grouping_iterator_init (&iter, LC_NUMERIC, _NL_CURRENT_LOCALE,
|
||||||
|
workend - string);
|
||||||
|
else if (use_outdigits && base == 10)
|
||||||
|
__grouping_iterator_init_none (&iter, workend - string);
|
||||||
|
|
||||||
|
int number_length;
|
||||||
|
#ifndef COMPILE_WPRINTF
|
||||||
|
if (use_outdigits && base == 10)
|
||||||
|
number_length = __translated_number_width (_NL_CURRENT_LOCALE,
|
||||||
|
string, workend);
|
||||||
|
else
|
||||||
|
number_length = workend - string;
|
||||||
|
if (group)
|
||||||
|
number_length += iter.separators * strlen (thousands_sep);
|
||||||
|
#else
|
||||||
|
number_length = workend - string;
|
||||||
|
/* All wide separators have length 1. */
|
||||||
|
if (group && thousands_sep != L'\0')
|
||||||
|
number_length += iter.separators;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The marker comes right before the number, but is not subject
|
||||||
|
to grouping. */
|
||||||
|
bool octal_marker = (prec <= number_length && number.word != 0
|
||||||
|
&& alt && base == 8);
|
||||||
|
|
||||||
prec = MAX (0, prec - (workend - string));
|
prec = MAX (0, prec - (workend - string));
|
||||||
|
|
||||||
if (!left)
|
if (!left)
|
||||||
{
|
{
|
||||||
width -= workend - string + prec;
|
width -= number_length + prec;
|
||||||
|
|
||||||
if (number.word != 0 && alt && (base == 16 || base == 2))
|
if (number.word != 0 && alt && (base == 16 || base == 2))
|
||||||
/* Account for 0X, 0x, 0B or 0b hex or binary marker. */
|
/* Account for 0X, 0x, 0B or 0b hex or binary marker. */
|
||||||
@ -190,27 +201,34 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */
|
|||||||
|
|
||||||
if (pad == L_(' '))
|
if (pad == L_(' '))
|
||||||
{
|
{
|
||||||
PAD (L_(' '));
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
width = 0;
|
width = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_negative)
|
if (is_negative)
|
||||||
outchar (L_('-'));
|
Xprintf_buffer_putc (buf, L_('-'));
|
||||||
else if (showsign)
|
else if (showsign)
|
||||||
outchar (L_('+'));
|
Xprintf_buffer_putc (buf, L_('+'));
|
||||||
else if (space)
|
else if (space)
|
||||||
outchar (L_(' '));
|
Xprintf_buffer_putc (buf, L_(' '));
|
||||||
|
|
||||||
if (number.word != 0 && alt && (base == 16 || base == 2))
|
if (number.word != 0 && alt && (base == 16 || base == 2))
|
||||||
{
|
{
|
||||||
outchar (L_('0'));
|
Xprintf_buffer_putc (buf, L_('0'));
|
||||||
outchar (spec);
|
Xprintf_buffer_putc (buf, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
width += prec;
|
width += prec;
|
||||||
PAD (L_('0'));
|
Xprintf_buffer_pad (buf, L_('0'), width);
|
||||||
|
|
||||||
outstring (string, workend - string);
|
if (octal_marker)
|
||||||
|
Xprintf_buffer_putc (buf, L_('0'));
|
||||||
|
|
||||||
|
if (number_slow_path)
|
||||||
|
group_number (buf, &iter, string, workend, thousands_sep,
|
||||||
|
use_outdigits && base == 10);
|
||||||
|
else
|
||||||
|
Xprintf_buffer_write (buf, string, workend - string);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -218,40 +236,41 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */
|
|||||||
{
|
{
|
||||||
if (is_negative)
|
if (is_negative)
|
||||||
{
|
{
|
||||||
outchar (L_('-'));
|
Xprintf_buffer_putc (buf, L_('-'));
|
||||||
--width;
|
--width;
|
||||||
}
|
}
|
||||||
else if (showsign)
|
else if (showsign)
|
||||||
{
|
{
|
||||||
outchar (L_('+'));
|
Xprintf_buffer_putc (buf, L_('+'));
|
||||||
--width;
|
--width;
|
||||||
}
|
}
|
||||||
else if (space)
|
else if (space)
|
||||||
{
|
{
|
||||||
outchar (L_(' '));
|
Xprintf_buffer_putc (buf, L_(' '));
|
||||||
--width;
|
--width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (number.word != 0 && alt && (base == 16 || base == 2))
|
if (number.word != 0 && alt && (base == 16 || base == 2))
|
||||||
{
|
{
|
||||||
outchar (L_('0'));
|
Xprintf_buffer_putc (buf, L_('0'));
|
||||||
outchar (spec);
|
Xprintf_buffer_putc (buf, spec);
|
||||||
width -= 2;
|
width -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
width -= workend - string + prec;
|
width -= workend - string + prec;
|
||||||
|
|
||||||
if (prec > 0)
|
Xprintf_buffer_pad (buf, L_('0'), prec);
|
||||||
{
|
|
||||||
int temp = width;
|
|
||||||
width = prec;
|
|
||||||
PAD (L_('0'));
|
|
||||||
width = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
outstring (string, workend - string);
|
if (octal_marker)
|
||||||
|
Xprintf_buffer_putc (buf, L_('0'));
|
||||||
|
|
||||||
PAD (L_(' '));
|
if (number_slow_path)
|
||||||
|
group_number (buf, &iter, string, workend, thousands_sep,
|
||||||
|
use_outdigits && base == 10);
|
||||||
|
else
|
||||||
|
Xprintf_buffer_write (buf, string, workend - string);
|
||||||
|
|
||||||
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,16 +319,17 @@ LABEL (form_number):
|
|||||||
}
|
}
|
||||||
/* Answer the count of characters written. */
|
/* Answer the count of characters written. */
|
||||||
void *ptrptr = process_arg_pointer ();
|
void *ptrptr = process_arg_pointer ();
|
||||||
|
unsigned int written = Xprintf_buffer_done (buf);
|
||||||
if (is_longlong)
|
if (is_longlong)
|
||||||
*(long long int *) ptrptr = done;
|
*(long long int *) ptrptr = written;
|
||||||
else if (is_long_num)
|
else if (is_long_num)
|
||||||
*(long int *) ptrptr = done;
|
*(long int *) ptrptr = written;
|
||||||
else if (is_char)
|
else if (is_char)
|
||||||
*(char *) ptrptr = done;
|
*(char *) ptrptr = written;
|
||||||
else if (!is_short)
|
else if (!is_short)
|
||||||
*(int *) ptrptr = done;
|
*(int *) ptrptr = written;
|
||||||
else
|
else
|
||||||
*(short int *) ptrptr = done;
|
*(short int *) ptrptr = written;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LABEL (form_strerror):
|
LABEL (form_strerror):
|
||||||
@ -341,14 +361,16 @@ LABEL (form_character):
|
|||||||
goto LABEL (form_wcharacter);
|
goto LABEL (form_wcharacter);
|
||||||
--width; /* Account for the character itself. */
|
--width; /* Account for the character itself. */
|
||||||
if (!left)
|
if (!left)
|
||||||
PAD (L_(' '));
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
#ifdef COMPILE_WPRINTF
|
#ifdef COMPILE_WPRINTF
|
||||||
outchar (__btowc ((unsigned char) process_arg_int ())); /* Promoted. */
|
__wprintf_buffer_putc (buf, __btowc ((unsigned char) /* Promoted. */
|
||||||
|
process_arg_int ()));
|
||||||
#else
|
#else
|
||||||
outchar ((unsigned char) process_arg_int ()); /* Promoted. */
|
__printf_buffer_putc (buf, (unsigned char) /* Promoted. */
|
||||||
|
process_arg_int ());
|
||||||
#endif
|
#endif
|
||||||
if (left)
|
if (left)
|
||||||
PAD (L_(' '));
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LABEL (form_string):
|
LABEL (form_string):
|
||||||
@ -382,10 +404,8 @@ LABEL (form_string):
|
|||||||
else if (!is_long && spec != L_('S'))
|
else if (!is_long && spec != L_('S'))
|
||||||
{
|
{
|
||||||
#ifdef COMPILE_WPRINTF
|
#ifdef COMPILE_WPRINTF
|
||||||
done = outstring_converted_wide_string
|
outstring_converted_wide_string (buf, (const char *) string,
|
||||||
(s, (const char *) string, prec, width, left, done);
|
prec, width, left);
|
||||||
if (done < 0)
|
|
||||||
goto all_done;
|
|
||||||
/* The padding has already been written. */
|
/* The padding has already been written. */
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
@ -407,10 +427,8 @@ LABEL (form_string):
|
|||||||
else
|
else
|
||||||
len = __wcslen (string);
|
len = __wcslen (string);
|
||||||
#else
|
#else
|
||||||
done = outstring_converted_wide_string
|
outstring_converted_wide_string (buf, (const wchar_t *) string,
|
||||||
(s, (const wchar_t *) string, prec, width, left, done);
|
prec, width, left);
|
||||||
if (done < 0)
|
|
||||||
goto all_done;
|
|
||||||
/* The padding has already been written. */
|
/* The padding has already been written. */
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -418,15 +436,15 @@ LABEL (form_string):
|
|||||||
|
|
||||||
if ((width -= len) < 0)
|
if ((width -= len) < 0)
|
||||||
{
|
{
|
||||||
outstring (string, len);
|
Xprintf_buffer_write (buf, string, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!left)
|
if (!left)
|
||||||
PAD (L_(' '));
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
outstring (string, len);
|
Xprintf_buffer_write (buf, string, len);
|
||||||
if (left)
|
if (left)
|
||||||
PAD (L_(' '));
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -436,10 +454,10 @@ LABEL (form_wcharacter):
|
|||||||
/* Wide character. */
|
/* Wide character. */
|
||||||
--width;
|
--width;
|
||||||
if (!left)
|
if (!left)
|
||||||
PAD (L' ');
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
outchar (process_arg_wchar_t ());
|
Xprintf_buffer_putc (buf, process_arg_wchar_t ());
|
||||||
if (left)
|
if (left)
|
||||||
PAD (L' ');
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -447,24 +465,24 @@ LABEL (form_wcharacter):
|
|||||||
LABEL (form_wcharacter):
|
LABEL (form_wcharacter):
|
||||||
{
|
{
|
||||||
/* Wide character. */
|
/* Wide character. */
|
||||||
char buf[MB_LEN_MAX];
|
char wcbuf[MB_LEN_MAX];
|
||||||
mbstate_t mbstate;
|
mbstate_t mbstate;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
memset (&mbstate, '\0', sizeof (mbstate_t));
|
memset (&mbstate, '\0', sizeof (mbstate_t));
|
||||||
len = __wcrtomb (buf, process_arg_wchar_t (), &mbstate);
|
len = __wcrtomb (wcbuf, process_arg_wchar_t (), &mbstate);
|
||||||
if (len == (size_t) -1)
|
if (len == (size_t) -1)
|
||||||
{
|
{
|
||||||
/* Something went wrong during the conversion. Bail out. */
|
/* Something went wrong during the conversion. Bail out. */
|
||||||
done = -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
width -= len;
|
width -= len;
|
||||||
if (!left)
|
if (!left)
|
||||||
PAD (' ');
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
outstring (buf, len);
|
Xprintf_buffer_write (buf, wcbuf, len);
|
||||||
if (left)
|
if (left)
|
||||||
PAD (' ');
|
Xprintf_buffer_pad (buf, L_(' '), width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* !COMPILE_WPRINTF */
|
#endif /* !COMPILE_WPRINTF */
|
||||||
|
@ -29,33 +29,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../locale/localeinfo.h"
|
#include "../locale/localeinfo.h"
|
||||||
#include <bits/floatn.h>
|
#include <bits/floatn.h>
|
||||||
|
#include <stdio-common/grouping_iterator.h>
|
||||||
|
#include <printf_buffer.h>
|
||||||
#define out_char(Ch) \
|
|
||||||
do { \
|
|
||||||
if (dest >= s + maxsize - 1) \
|
|
||||||
{ \
|
|
||||||
__set_errno (E2BIG); \
|
|
||||||
va_end (ap); \
|
|
||||||
return -1; \
|
|
||||||
} \
|
|
||||||
*dest++ = (Ch); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define out_string(String) \
|
|
||||||
do { \
|
|
||||||
const char *_s = (String); \
|
|
||||||
while (*_s) \
|
|
||||||
out_char (*_s++); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define out_nstring(String, N) \
|
|
||||||
do { \
|
|
||||||
int _n = (N); \
|
|
||||||
const char *_s = (String); \
|
|
||||||
while (_n-- > 0) \
|
|
||||||
out_char (*_s++); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define to_digit(Ch) ((Ch) - '0')
|
#define to_digit(Ch) ((Ch) - '0')
|
||||||
|
|
||||||
@ -75,21 +50,15 @@
|
|||||||
some information in the LC_MONETARY category which should be used,
|
some information in the LC_MONETARY category which should be used,
|
||||||
too. Some of the information contradicts the information which can
|
too. Some of the information contradicts the information which can
|
||||||
be specified in format string. */
|
be specified in format string. */
|
||||||
ssize_t
|
static void
|
||||||
__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
__vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
|
||||||
const char *format, va_list ap, unsigned int flags)
|
const char *fmt, va_list ap, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct __locale_data *current = loc->__locales[LC_MONETARY];
|
struct __locale_data *current = loc->__locales[LC_MONETARY];
|
||||||
_IO_strfile f;
|
|
||||||
struct printf_info info;
|
struct printf_info info;
|
||||||
char *dest; /* Pointer so copy the output. */
|
|
||||||
const char *fmt; /* Pointer that walks through format. */
|
|
||||||
|
|
||||||
dest = s;
|
|
||||||
fmt = format;
|
|
||||||
|
|
||||||
/* Loop through the format-string. */
|
/* Loop through the format-string. */
|
||||||
while (*fmt != '\0')
|
while (*fmt != '\0' && !__printf_buffer_has_failed (buf))
|
||||||
{
|
{
|
||||||
/* The floating-point value to output. */
|
/* The floating-point value to output. */
|
||||||
union
|
union
|
||||||
@ -122,11 +91,9 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
int other_cs_precedes;
|
int other_cs_precedes;
|
||||||
const char *sign_string;
|
const char *sign_string;
|
||||||
const char *other_sign_string;
|
const char *other_sign_string;
|
||||||
int done;
|
|
||||||
const char *currency_symbol;
|
const char *currency_symbol;
|
||||||
size_t currency_symbol_len;
|
size_t currency_symbol_len;
|
||||||
long int width;
|
long int width;
|
||||||
char *startp;
|
|
||||||
const void *ptr;
|
const void *ptr;
|
||||||
char space_char;
|
char space_char;
|
||||||
|
|
||||||
@ -134,14 +101,14 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
specification. */
|
specification. */
|
||||||
if (*fmt != '%')
|
if (*fmt != '%')
|
||||||
{
|
{
|
||||||
out_char (*fmt++);
|
__printf_buffer_putc (buf, *fmt++);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "%%" means a single '%' character. */
|
/* "%%" means a single '%' character. */
|
||||||
if (fmt[1] == '%')
|
if (fmt[1] == '%')
|
||||||
{
|
{
|
||||||
out_char (*++fmt);
|
__printf_buffer_putc (buf, *++fmt);
|
||||||
++fmt;
|
++fmt;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -171,7 +138,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
{
|
{
|
||||||
/* Premature EOS. */
|
/* Premature EOS. */
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case '^': /* Don't group digits. */
|
case '^': /* Don't group digits. */
|
||||||
@ -181,7 +149,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
if (n_sign_posn != -2)
|
if (n_sign_posn != -2)
|
||||||
{
|
{
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
|
p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
|
||||||
n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
|
n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
|
||||||
@ -190,7 +159,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
if (n_sign_posn != -2)
|
if (n_sign_posn != -2)
|
||||||
{
|
{
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
p_sign_posn = 0;
|
p_sign_posn = 0;
|
||||||
n_sign_posn = 0;
|
n_sign_posn = 0;
|
||||||
@ -220,19 +190,12 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
|| (width == LONG_MAX && val > LONG_MAX % 10))
|
|| (width == LONG_MAX && val > LONG_MAX % 10))
|
||||||
{
|
{
|
||||||
__set_errno (E2BIG);
|
__set_errno (E2BIG);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = width * 10 + val;
|
width = width * 10 + val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we don't have enough room for the demanded width we
|
|
||||||
can stop now and return an error. */
|
|
||||||
if (width >= maxsize - (dest - s))
|
|
||||||
{
|
|
||||||
__set_errno (E2BIG);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recognize left precision. */
|
/* Recognize left precision. */
|
||||||
@ -241,7 +204,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
if (!isdigit (*++fmt))
|
if (!isdigit (*++fmt))
|
||||||
{
|
{
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
left_prec = to_digit (*fmt);
|
left_prec = to_digit (*fmt);
|
||||||
|
|
||||||
@ -258,7 +222,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
if (!isdigit (*++fmt))
|
if (!isdigit (*++fmt))
|
||||||
{
|
{
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
right_prec = to_digit (*fmt);
|
right_prec = to_digit (*fmt);
|
||||||
|
|
||||||
@ -306,7 +271,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
break;
|
break;
|
||||||
default: /* Any unrecognized format is an error. */
|
default: /* Any unrecognized format is an error. */
|
||||||
__set_errno (EINVAL);
|
__set_errno (EINVAL);
|
||||||
return -1;
|
__printf_buffer_mark_failed (buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If not specified by the format string now find the values for
|
/* If not specified by the format string now find the values for
|
||||||
@ -327,8 +293,11 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
/* If we have to print the digits grouped determine how many
|
/* If we have to print the digits grouped determine how many
|
||||||
extra characters this means. */
|
extra characters this means. */
|
||||||
if (group && left_prec != -1)
|
if (group && left_prec != -1)
|
||||||
left_prec += __guess_grouping (left_prec,
|
{
|
||||||
_NL_CURRENT (LC_MONETARY, MON_GROUPING));
|
struct grouping_iterator it;
|
||||||
|
__grouping_iterator_init (&it, LC_MONETARY, loc, left_prec);
|
||||||
|
left_prec += it.separators;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now it's time to get the value. */
|
/* Now it's time to get the value. */
|
||||||
if (is_long_double == 1)
|
if (is_long_double == 1)
|
||||||
@ -482,57 +451,46 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
#define left_paren '('
|
#define left_paren '('
|
||||||
#define right_paren ')'
|
#define right_paren ')'
|
||||||
|
|
||||||
startp = dest; /* Remember start so we can compute length. */
|
char *startp = buf->write_ptr;
|
||||||
|
|
||||||
while (left_pad-- > 0)
|
__printf_buffer_pad (buf, ' ', left_pad);
|
||||||
out_char (' ');
|
|
||||||
|
|
||||||
if (sign_posn == 0 && is_negative)
|
if (sign_posn == 0 && is_negative)
|
||||||
out_char (left_paren);
|
__printf_buffer_putc (buf, left_paren);
|
||||||
|
|
||||||
if (cs_precedes)
|
if (cs_precedes)
|
||||||
{
|
{
|
||||||
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
|
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
|
||||||
&& sign_posn != 5)
|
&& sign_posn != 5)
|
||||||
{
|
{
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
if (sep_by_space == 2)
|
if (sep_by_space == 2)
|
||||||
out_char (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print_curr_symbol)
|
if (print_curr_symbol)
|
||||||
out_string (currency_symbol);
|
__printf_buffer_puts (buf, currency_symbol);
|
||||||
|
|
||||||
if (sign_posn == 4)
|
if (sign_posn == 4)
|
||||||
{
|
{
|
||||||
if (print_curr_symbol && sep_by_space == 2)
|
if (print_curr_symbol && sep_by_space == 2)
|
||||||
out_char (space_char);
|
__printf_buffer_putc (buf, space_char);
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
if (sep_by_space == 1)
|
if (sep_by_space == 1)
|
||||||
/* POSIX.2 and SUS are not clear on this case, but C99
|
/* POSIX.2 and SUS are not clear on this case, but C99
|
||||||
says a space follows the adjacent-symbol-and-sign */
|
says a space follows the adjacent-symbol-and-sign */
|
||||||
out_char (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (print_curr_symbol && sep_by_space == 1)
|
if (print_curr_symbol && sep_by_space == 1)
|
||||||
out_char (space_char);
|
__printf_buffer_putc (buf, space_char);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
|
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
|
||||||
&& sign_posn != 4 && sign_posn != 5)
|
&& sign_posn != 4 && sign_posn != 5)
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
|
|
||||||
/* Print the number. */
|
/* Print the number. */
|
||||||
#ifdef _IO_MTSAFE_IO
|
|
||||||
f._sbf._f._lock = NULL;
|
|
||||||
#endif
|
|
||||||
_IO_init_internal (&f._sbf._f, 0);
|
|
||||||
_IO_JUMPS (&f._sbf) = &_IO_str_jumps;
|
|
||||||
_IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
|
|
||||||
/* We clear the last available byte so we can find out whether
|
|
||||||
the numeric representation is too long. */
|
|
||||||
s[maxsize - 1] = '\0';
|
|
||||||
|
|
||||||
memset (&info, '\0', sizeof (info));
|
memset (&info, '\0', sizeof (info));
|
||||||
info.prec = right_prec;
|
info.prec = right_prec;
|
||||||
info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
|
info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
|
||||||
@ -544,25 +502,17 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
info.extra = 1; /* This means use values from LC_MONETARY. */
|
info.extra = 1; /* This means use values from LC_MONETARY. */
|
||||||
|
|
||||||
ptr = &fpnum;
|
ptr = &fpnum;
|
||||||
done = __printf_fp_l (&f._sbf._f, loc, &info, &ptr);
|
__printf_fp_l_buffer (buf, loc, &info, &ptr);
|
||||||
if (done < 0)
|
if (__printf_buffer_has_failed (buf))
|
||||||
return -1;
|
return;
|
||||||
|
|
||||||
if (s[maxsize - 1] != '\0')
|
|
||||||
{
|
|
||||||
__set_errno (E2BIG);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest += done;
|
|
||||||
|
|
||||||
if (!cs_precedes)
|
if (!cs_precedes)
|
||||||
{
|
{
|
||||||
if (sign_posn == 3)
|
if (sign_posn == 3)
|
||||||
{
|
{
|
||||||
if (sep_by_space == 1)
|
if (sep_by_space == 1)
|
||||||
out_char (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print_curr_symbol)
|
if (print_curr_symbol)
|
||||||
@ -572,55 +522,61 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
|||||||
|| (sign_posn == 2 && sep_by_space == 1)
|
|| (sign_posn == 2 && sep_by_space == 1)
|
||||||
|| (sign_posn == 1 && sep_by_space == 1)
|
|| (sign_posn == 1 && sep_by_space == 1)
|
||||||
|| (sign_posn == 0 && sep_by_space == 1))
|
|| (sign_posn == 0 && sep_by_space == 1))
|
||||||
out_char (space_char);
|
__printf_buffer_putc (buf, space_char);
|
||||||
out_nstring (currency_symbol, currency_symbol_len);
|
__printf_buffer_write (buf, currency_symbol,
|
||||||
|
__strnlen (currency_symbol,
|
||||||
|
currency_symbol_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sign_posn == 4)
|
if (sign_posn == 4)
|
||||||
{
|
{
|
||||||
if (sep_by_space == 2)
|
if (sep_by_space == 2)
|
||||||
out_char (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sign_posn == 2)
|
if (sign_posn == 2)
|
||||||
{
|
{
|
||||||
if (sep_by_space == 2)
|
if (sep_by_space == 2)
|
||||||
out_char (' ');
|
__printf_buffer_putc (buf, ' ');
|
||||||
out_string (sign_string);
|
__printf_buffer_puts (buf, sign_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sign_posn == 0 && is_negative)
|
if (sign_posn == 0 && is_negative)
|
||||||
out_char (right_paren);
|
__printf_buffer_putc (buf, right_paren);
|
||||||
|
|
||||||
/* Now test whether the output width is filled. */
|
/* Now test whether the output width is filled. */
|
||||||
if (dest - startp < width)
|
if (buf->write_ptr - startp < width)
|
||||||
{
|
{
|
||||||
if (left)
|
size_t pad_width = width - (buf->write_ptr - startp);
|
||||||
/* We simply have to fill using spaces. */
|
__printf_buffer_pad (buf, ' ', pad_width);
|
||||||
do
|
if (__printf_buffer_has_failed (buf))
|
||||||
out_char (' ');
|
/* Implies length check. */
|
||||||
while (dest - startp < width);
|
return;
|
||||||
|
/* Left padding is already in the correct position.
|
||||||
|
Otherwise move the field contents in place. */
|
||||||
|
if (!left)
|
||||||
|
{
|
||||||
|
memmove (startp + pad_width, startp, buf->write_ptr - startp);
|
||||||
|
memset (startp, ' ', pad_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|
||||||
|
const char *format, va_list ap, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct __printf_buffer buf;
|
||||||
|
__printf_buffer_init (&buf, s, maxsize, __printf_buffer_mode_strfmon);
|
||||||
|
__vstrfmon_l_buffer (&buf, loc, format, ap, flags);
|
||||||
|
__printf_buffer_putc (&buf, '\0'); /* Terminate the string. */
|
||||||
|
if (__printf_buffer_has_failed (&buf))
|
||||||
|
return -1;
|
||||||
else
|
else
|
||||||
{
|
return buf.write_ptr - buf.write_base - 1; /* Exclude NUL byte. */
|
||||||
long int dist = width - (dest - startp);
|
|
||||||
for (char *cp = dest - 1; cp >= startp; --cp)
|
|
||||||
cp[dist] = cp[0];
|
|
||||||
|
|
||||||
dest += dist;
|
|
||||||
|
|
||||||
do
|
|
||||||
startp[--dist] = ' ';
|
|
||||||
while (dist > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Terminate the string. */
|
|
||||||
*dest = '\0';
|
|
||||||
|
|
||||||
return dest - s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <locale/localeinfo.h>
|
#include <locale/localeinfo.h>
|
||||||
#include <fix-float-double-convert-nan.h>
|
#include <fix-float-double-convert-nan.h>
|
||||||
|
#include <printf_buffer.h>
|
||||||
|
|
||||||
#define UCHAR_T char
|
#define UCHAR_T char
|
||||||
#define L_(Str) Str
|
#define L_(Str) Str
|
||||||
@ -37,12 +38,7 @@
|
|||||||
int
|
int
|
||||||
STRFROM (char *dest, size_t size, const char *format, FLOAT f)
|
STRFROM (char *dest, size_t size, const char *format, FLOAT f)
|
||||||
{
|
{
|
||||||
_IO_strnfile sfile;
|
struct __printf_buffer_snprintf buf;
|
||||||
#ifdef _IO_MTSAFE_IO
|
|
||||||
sfile.f._sbf._f._lock = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int done;
|
|
||||||
|
|
||||||
/* Single-precision values need to be stored in a double type, because
|
/* Single-precision values need to be stored in a double type, because
|
||||||
__printf_fp_l and __printf_fphex do not accept the float type. */
|
__printf_fp_l and __printf_fphex do not accept the float type. */
|
||||||
@ -106,23 +102,8 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
|
|||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following code to prepare the virtual file has been adapted from the
|
/* Prepare the string buffer. */
|
||||||
function __vsnprintf_internal from libio. */
|
__printf_buffer_snprintf_init (&buf, dest, size);
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
/* When size is zero, nothing is written and dest may be a null pointer.
|
|
||||||
This is specified for snprintf in ISO/IEC 9899:2011, Section 7.21.6.5,
|
|
||||||
in the second paragraph. Thus, if size is zero, prepare to use the
|
|
||||||
overflow buffer right from the start. */
|
|
||||||
dest = sfile.overflow_buf;
|
|
||||||
size = sizeof (sfile.overflow_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare the virtual string file. */
|
|
||||||
_IO_no_init (&sfile.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
|
|
||||||
_IO_JUMPS (&sfile.f._sbf) = &_IO_strn_jumps;
|
|
||||||
_IO_str_init_static_internal (&sfile.f, dest, size - 1, dest);
|
|
||||||
|
|
||||||
/* Prepare the format specification for printf_fp. */
|
/* Prepare the format specification for printf_fp. */
|
||||||
memset (&info, '\0', sizeof (info));
|
memset (&info, '\0', sizeof (info));
|
||||||
@ -144,13 +125,8 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
|
|||||||
info.spec = specifier;
|
info.spec = specifier;
|
||||||
|
|
||||||
if (info.spec != 'a' && info.spec != 'A')
|
if (info.spec != 'a' && info.spec != 'A')
|
||||||
done = __printf_fp_l (&sfile.f._sbf._f, _NL_CURRENT_LOCALE, &info, &fpptr);
|
__printf_fp_l_buffer (&buf.base, _NL_CURRENT_LOCALE, &info, &fpptr);
|
||||||
else
|
else
|
||||||
done = __printf_fphex (&sfile.f._sbf._f, &info, &fpptr);
|
__printf_fphex_l_buffer (&buf.base, _NL_CURRENT_LOCALE, &info, &fpptr);
|
||||||
|
return __printf_buffer_snprintf_done (&buf);
|
||||||
/* Terminate the string. */
|
|
||||||
if (sfile.f._sbf._f._IO_buf_base != sfile.overflow_buf)
|
|
||||||
*sfile.f._sbf._f._IO_write_ptr = '\0';
|
|
||||||
|
|
||||||
return done;
|
|
||||||
}
|
}
|
||||||
|
@ -35,16 +35,10 @@ do { \
|
|||||||
\
|
\
|
||||||
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), \
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
\
|
\
|
||||||
/* Fill with zeroes. */ \
|
/* Fill with zeroes. */ \
|
||||||
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* We use a full nibble for the leading digit. */ \
|
/* We use a full nibble for the leading digit. */ \
|
||||||
leading = *numstr++; \
|
leading = *numstr++; \
|
||||||
|
@ -36,45 +36,23 @@ do { \
|
|||||||
zero_mantissa = (num0|num1) == 0; \
|
zero_mantissa = (num0|num1) == 0; \
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
|
||||||
numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num1, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),\
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
numstr = _itoa (num1, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa (num1, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa (num1, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), \
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
|
||||||
numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); \
|
numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
numstr = _itoa (num0, numstr, 16, info->spec == 'A'); \
|
numstr = _itoa (num0, numstr, 16, info->spec == 'A'); \
|
||||||
wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* Fill with zeroes. */ \
|
/* Fill with zeroes. */ \
|
||||||
while (numstr > numbuf + (sizeof numbuf - 112 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 112 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
leading = u.ieee.exponent == 0 ? '0' : '1'; \
|
leading = u.ieee.exponent == 0 ? '0' : '1'; \
|
||||||
\
|
\
|
||||||
|
@ -68,45 +68,23 @@ do { \
|
|||||||
zero_mantissa = (num0|num1) == 0; \
|
zero_mantissa = (num0|num1) == 0; \
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
|
||||||
numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num1, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),\
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
numstr = _itoa (num1, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa (num1, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa (num1, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), \
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
|
||||||
numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); \
|
numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
|
||||||
numstr = _itoa (num0, numstr, 16, info->spec == 'A'); \
|
numstr = _itoa (num0, numstr, 16, info->spec == 'A'); \
|
||||||
wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* Fill with zeroes. */ \
|
/* Fill with zeroes. */ \
|
||||||
while (numstr > numbuf + (sizeof numbuf - 112 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 112 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
leading = u.d[0].ieee.exponent == 0 ? '0' : '1'; \
|
leading = u.d[0].ieee.exponent == 0 ? '0' : '1'; \
|
||||||
\
|
\
|
||||||
|
@ -36,31 +36,17 @@ do { \
|
|||||||
zero_mantissa = num == 0; \
|
zero_mantissa = num == 0; \
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
|
||||||
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, \
|
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, \
|
||||||
info->spec == 'A'); \
|
info->spec == 'A'); \
|
||||||
wnumstr = _itowa_word (num, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),\
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
numstr = _itoa (num, numbuf + sizeof numbuf, 16, info->spec == 'A'); \
|
||||||
numstr = _itoa (num, numbuf + sizeof numbuf, 16, info->spec == 'A');\
|
|
||||||
wnumstr = _itowa (num, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), \
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* Fill with zeroes. */ \
|
/* Fill with zeroes. */ \
|
||||||
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* We use a full nibble for the leading digit. */ \
|
/* We use a full nibble for the leading digit. */ \
|
||||||
leading = *numstr++; \
|
leading = *numstr++; \
|
||||||
wnumstr++; \
|
|
||||||
\
|
\
|
||||||
/* We have 3 bits from the mantissa in the leading nibble. \
|
/* We have 3 bits from the mantissa in the leading nibble. \
|
||||||
Therefore we are here using `IEEE854_LONG_DOUBLE_BIAS + 3'. */ \
|
Therefore we are here using `IEEE854_LONG_DOUBLE_BIAS + 3'. */ \
|
||||||
|
@ -34,31 +34,16 @@ do { \
|
|||||||
zero_mantissa = num == 0; \
|
zero_mantissa = num == 0; \
|
||||||
\
|
\
|
||||||
if (sizeof (unsigned long int) > 6) \
|
if (sizeof (unsigned long int) > 6) \
|
||||||
{ \
|
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, info->spec == 'A');\
|
||||||
numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, \
|
|
||||||
info->spec == 'A'); \
|
|
||||||
wnumstr = _itowa_word (num, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),\
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
else \
|
else \
|
||||||
{ \
|
numstr = _itoa (num, numbuf + sizeof numbuf, 16, info->spec == 'A'); \
|
||||||
numstr = _itoa (num, numbuf + sizeof numbuf, 16, info->spec == 'A');\
|
|
||||||
wnumstr = _itowa (num, \
|
|
||||||
wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), \
|
|
||||||
16, info->spec == 'A'); \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* Fill with zeroes. */ \
|
/* Fill with zeroes. */ \
|
||||||
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
while (numstr > numbuf + (sizeof numbuf - 64 / 4)) \
|
||||||
{ \
|
|
||||||
*--numstr = '0'; \
|
*--numstr = '0'; \
|
||||||
*--wnumstr = L'0'; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* We use a full nibble for the leading digit. */ \
|
/* We use a full nibble for the leading digit. */ \
|
||||||
leading = *numstr++; \
|
leading = *numstr++; \
|
||||||
wnumstr++; \
|
|
||||||
\
|
\
|
||||||
/* We have 3 bits from the mantissa in the leading nibble. \
|
/* We have 3 bits from the mantissa in the leading nibble. \
|
||||||
Therefore we are here using `IEEE854_LONG_DOUBLE_BIAS + 3'. */ \
|
Therefore we are here using `IEEE854_LONG_DOUBLE_BIAS + 3'. */ \
|
||||||
|
Loading…
Reference in New Issue
Block a user