From 698fb75b9ff5ae454a1344b5f9fafa0ca367c555 Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Wed, 7 Mar 2018 14:32:01 -0500 Subject: Add __v*printf_internal with flags arguments There are a lot more printf variants than there are scanf variants, and the code for setting up and tearing down their custom FILE variants around the call to __vf(w)printf is more complicated and variable. Therefore, I have added _internal versions of all the v*printf variants, rather than introducing helper routines so that they can all directly call __vf(w)printf_internal, as was done with scanf. As with the scanf changes, in this patch the _internal functions still look at the environmental mode bits and all callers pass 0 for the flags parameter. Several of the affected public functions had _IO_ name aliases that were not exported (but, in one case, appeared in libio.h anyway); I was originally planning to leave them as aliases to avoid having to touch internal callers, but it turns out ldbl_*_alias only work for exported symbols, so they've all been removed instead. It also turns out there were hardly any internal callers. _IO_vsprintf and _IO_vfprintf *are* exported, so those two stick around. Summary for the changes to each of the affected symbols: _IO_vfprintf, _IO_vsprintf: All internal calls removed, thus the internal declarations, as well as uses of libc_hidden_proto and libc_hidden_def, were also removed. The external symbol is now exposed via uses of ldbl_strong_alias to __vfprintf_internal and __vsprintf_internal, respectively. _IO_vasprintf, _IO_vdprintf, _IO_vsnprintf, _IO_vfwprintf, _IO_vswprintf, _IO_obstack_vprintf, _IO_obstack_printf: All internal calls removed, thus declaration in internal headers were also removed. They were never exported, so there are no aliases tying them to the internal functions. I.e.: entirely gone. __vsnprintf: Internal calls were always preceded by macros such as #define __vsnprintf _IO_vsnprintf, and #define __vsnprintf vsnprintf The macros were removed and their uses replaced with calls to the new internal function __vsnprintf_internal. Since there were no internal calls, the internal declaration was also removed. The external symbol is preserved with ldbl_weak_alias to ___vsnprintf. __vfwprintf: All internal calls converted into calls to __vfwprintf_internal, thus the internal declaration was removed. The function is now a wrapper that calls __vfwprintf_internal. The external symbol is preserved. __vswprintf: Similarly, but no external symbol. __vasprintf, __vdprintf, __vfprintf, __vsprintf: New internal wrappers. Not exported. vasprintf, vdprintf, vfprintf, vsprintf, vsnprintf, vfwprintf, vswprintf, obstack_vprintf, obstack_printf: These functions used to be aliases to the respective _IO_* function, they are now aliases to their respective __* functions. Tested for powerpc and powerpc64le. --- ChangeLog | 82 ++ argp/argp-fmtstream.c | 3 +- argp/argp-help.c | 4 +- argp/argp-namefrob.h | 2 - debug/fwprintf_chk.c | 2 +- debug/obprintf_chk.c | 2 +- debug/vasprintf_chk.c | 2 +- debug/vdprintf_chk.c | 2 +- debug/vfwprintf_chk.c | 2 +- debug/vsnprintf_chk.c | 2 +- debug/vsprintf_chk.c | 2 +- debug/vswprintf_chk.c | 2 +- debug/vwprintf_chk.c | 2 +- debug/wprintf_chk.c | 2 +- hurd/vpprintf.c | 2 +- include/stdio.h | 3 - include/wchar.h | 10 - libio/fwprintf.c | 2 +- libio/iolibio.h | 8 - libio/iovdprintf.c | 13 +- libio/iovsprintf.c | 16 +- libio/libio.h | 5 - libio/libioP.h | 47 +- libio/obprintf.c | 19 +- libio/swprintf.c | 2 +- libio/vasprintf.c | 20 +- libio/vsnprintf.c | 16 +- libio/vswprintf.c | 16 +- libio/vwprintf.c | 2 +- libio/wprintf.c | 2 +- stdio-common/Makefile | 3 +- stdio-common/asprintf.c | 6 +- stdio-common/dprintf.c | 5 +- stdio-common/fprintf.c | 2 +- stdio-common/fxprintf.c | 4 +- stdio-common/printf.c | 3 +- stdio-common/snprintf.c | 4 +- stdio-common/sprintf.c | 4 +- stdio-common/vfprintf-internal.c | 2364 +++++++++++++++++++++++++++++++ stdio-common/vfprintf.c | 2351 +----------------------------- stdio-common/vfwprintf-internal.c | 2 + stdio-common/vfwprintf.c | 28 +- stdio-common/vprintf.c | 4 +- stdlib/strfrom-skeleton.c | 2 +- sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 21 +- 45 files changed, 2632 insertions(+), 2465 deletions(-) create mode 100644 stdio-common/vfprintf-internal.c create mode 100644 stdio-common/vfwprintf-internal.c diff --git a/ChangeLog b/ChangeLog index 9ad1f41068..e96f3c60fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,85 @@ +2018-12-05 Zack Weinberg + Gabriel F. T. Gomes + + * libio/libioP.h (__vfprintf_internal, __vfwprintf_internal) + (__vasprintf_internal, __vdprintf_internal, __obstack_vprintf_internal) + (__vsprintf_internal, __vsnprintf_internal, __vswprintf_internal): + New functions. + (PRINTF_LDBL_IS_DBL, PRINTF_FORTIFY): New constants. + (_IO_vasprintf, _IO_vdprintf, _IO_vsnprintf): Remove prototypes. + + * stdio-common/vfprintf-internal.c: Rename from vfprintf.c. + Include wctype.h here if COMPILE_WPRINTF is defined. + Define __vfprintf_internal or __vfwprintf_internal, depending + on COMPILE_WPRINTF. + Temporarily, on entry to this function, update mode_flags + according to the environmental settings corresponding to + PRINTF_LDBL_IS_DBL and PRINTF_FORTIFY. + Throughout, check mode_flags instead of __ldbl_is_dbl and + _IO_FLAGS2_FORTIFY on the destination FILE. + * stdio-common/vfwprintf-internal.c: Rename from vfwprintf.c. + Include vfprintf-internal.c. Don't include wctype.h. + * stdio-common/vfprintf.c: New file. Just define __vfprintf + as a wrapper around __vfprintf_internal, with aliases _IO_vfprintf + and vfprintf. + * stdio-common/vfwprintf.c: New file. Just define __vfwprintf + as a wrapper around __vfwprintf_internal, with aliases _IO_vfwprintf + and vfwprintf. + * stdio-common/Makefile: Add vfprintf-internal and vfwprintf-internal. + + * libio/iovdprintf.c (_IO_vdprintf): Rename to __vdprintf_internal + and add mode_flags argument; use __vfprintf_internal. + (__vdprintf): New function. Alias vdprintf to this. + * libio/iovsprintf.c (_IO_vsprintf, __vsprintf): Similarly. + * libio/vasprintf.c (_IO_vasprintf, __vasprintf): Similarly. + * libio/obprintf.c (_IO_obstack_vprintf, __obstack_vprintf): Similarly. + (__obstack_printf): Use __obstack_printf_internal. + * libio/vsnprintf.c (_IO_vsnprintf, ___vsnprintf): Similarly, with + public aliases __vsnprintf and vsnprintf. + Remove use of ldbl_hidden_def, since __vsnprintf is no longer + called internally. + * libio/vswprintf (_IO_vswprintf, __vswprintf): Similarly, with + public aliases _IO_vsprintf and vsprintf. + * libio/swprintf.c (__swprintf): Use __vswprintf_internal. + * stdio-common/asprintf.c (__asprintf): Use __vasprintf_internal. + * stdio-common/dprintf.c (__dprintf): Use __vdprintf_internal. + * stdio-common/snprintf.c (__snprintf): Use __vsprintf_internal. + * stdio-common/sprintf.c (__sprintf): Use __vsprintf_internal. + + * debug/obprintf_chk.c, debug/vasprintf_chk.c, debug/vdprintf_chk.c + * debug/vsnprintf_chk.c, debug/vsprintf_chk.c, hurd/vpprintf.c + * stdio-common/fprintf.c, stdio-common/fxprintf.c + * stdio-common/printf.c: Use __vfprintf_internal. + + * debug/fwprintf_chk.c, debug/vfwprintf_chk.c, debug/vswprintf_chk.c + * debug/vwprintf_chk.c, debug/wprintf_chk.c, libio/fwprintf.c + * libio/vwprintf.c, libio/wprintf.c: Use __vfwprintf_internal. + + * sysdeps/ieee754/ldbl-opt/nldbl-compat.c: Use __vsprintf_internal, + __obstack_vprintf_internal, __vasprintf_internal, __vdprintf_internal, + __vsnprintf_internal, __vswprintf_internal, __vfprintf_internal, and + __vfwprintf_internal. + + * libio/libio.h: Remove libc_hidden_proto and declaration for + _IO_vfprintf. + Remove declaration of _IO_vfwprintf. + * libio/iolibio.h: Remove libc_hidden_proto and declaration for + _IO_vsprintf. + Remove declarations of _IO_vswprintf, _IO_obstack_printf, and + _IO_obstack_printf. + * include/stdio.h: Add prototype for __vasprintf. + (__vsnprintf): Remove declaration, because there are no more + internal calls. + * include/wchar.h (__vfwprintf, __vswprintf): Remove + declaration, because there are no more internal calls. + + * argp/argp-fmtstream.c (__argp_fmtstream_printf): Use + __vsnprintf_internal, instead of _IO_vsnprintf. + * argp/argp-help.c (__argp_error, __argp_failure): Use + __vasprintf_internal, instead of _IO_vasprintf. + * argp/argp-namefrob.h (__vsnprintf): Do not undefined then + redefine, because there are no more internal calls. + 2018-12-05 Zack Weinberg Gabriel F. T. Gomes diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c index e9e4c0e5cc..a5a5258684 100644 --- a/argp/argp-fmtstream.c +++ b/argp/argp-fmtstream.c @@ -42,7 +42,6 @@ #ifdef _LIBC # include # include -# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) #endif #define INIT_BUF_SIZE 200 @@ -413,7 +412,7 @@ __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...) va_start (args, fmt); avail = fs->end - fs->p; - out = __vsnprintf (fs->p, avail, fmt, args); + out = __vsnprintf_internal (fs->p, avail, fmt, args, 0); va_end (args); if ((size_t) out >= avail) size_guess = out + 1; diff --git a/argp/argp-help.c b/argp/argp-help.c index a17260378c..09c76734d3 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -1769,7 +1769,7 @@ __argp_error (const struct argp_state *state, const char *fmt, ...) #ifdef _LIBC char *buf; - if (_IO_vasprintf (&buf, fmt, ap) < 0) + if (__vasprintf_internal (&buf, fmt, ap, 0) < 0) buf = NULL; __fxprintf (stream, "%s: %s\n", @@ -1839,7 +1839,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum, #ifdef _LIBC char *buf; - if (_IO_vasprintf (&buf, fmt, ap) < 0) + if (__vasprintf_internal (&buf, fmt, ap, 0) < 0) buf = NULL; __fxprintf (stream, ": %s", buf); diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h index 5588fe172a..5e48b5940d 100644 --- a/argp/argp-namefrob.h +++ b/argp/argp-namefrob.h @@ -98,8 +98,6 @@ #define __strerror_r strerror_r #undef __strndup #define __strndup strndup -#undef __vsnprintf -#define __vsnprintf vsnprintf #if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED # define clearerr_unlocked(x) clearerr (x) diff --git a/debug/fwprintf_chk.c b/debug/fwprintf_chk.c index aeb83077da..63167c1839 100644 --- a/debug/fwprintf_chk.c +++ b/debug/fwprintf_chk.c @@ -32,7 +32,7 @@ __fwprintf_chk (FILE *fp, int flag, const wchar_t *format, ...) fp->_flags2 |= _IO_FLAGS2_FORTIFY; va_start (ap, format); - done = _IO_vfwprintf (fp, format, ap); + done = __vfwprintf_internal (fp, format, ap, 0); va_end (ap); if (flag > 0) diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c index 3ac5a3cd4f..41dd481c34 100644 --- a/debug/obprintf_chk.c +++ b/debug/obprintf_chk.c @@ -91,7 +91,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format, if (flags > 0) new_f.ofile.file.file._flags2 |= _IO_FLAGS2_FORTIFY; - result = _IO_vfprintf (&new_f.ofile.file.file, format, args); + result = __vfprintf_internal (&new_f.ofile.file.file, format, args, 0); /* Shrink the buffer to the space we really currently need. */ obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c index 48b4741651..dbfebff83f 100644 --- a/debug/vasprintf_chk.c +++ b/debug/vasprintf_chk.c @@ -63,7 +63,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format, if (flags > 0) sf._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY; - ret = _IO_vfprintf (&sf._sbf._f, format, args); + ret = __vfprintf_internal (&sf._sbf._f, format, args, 0); if (ret < 0) { free (sf._sbf._f._IO_buf_base); diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c index bc713b4962..4386127cfe 100644 --- a/debug/vdprintf_chk.c +++ b/debug/vdprintf_chk.c @@ -55,7 +55,7 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg) if (flags > 0) tmpfil.file._flags2 |= _IO_FLAGS2_FORTIFY; - done = _IO_vfprintf (&tmpfil.file, format, arg); + done = __vfprintf_internal (&tmpfil.file, format, arg, 0); _IO_FINISH (&tmpfil.file); diff --git a/debug/vfwprintf_chk.c b/debug/vfwprintf_chk.c index 1ffd18cbd2..abf2bd6517 100644 --- a/debug/vfwprintf_chk.c +++ b/debug/vfwprintf_chk.c @@ -30,7 +30,7 @@ __vfwprintf_chk (FILE *fp, int flag, const wchar_t *format, va_list ap) if (flag > 0) fp->_flags2 |= _IO_FLAGS2_FORTIFY; - done = _IO_vfwprintf (fp, format, ap); + done = __vfwprintf_internal (fp, format, ap, 0); if (flag > 0) fp->_flags2 &= ~_IO_FLAGS2_FORTIFY; diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c index d20d0fbd93..95d286f416 100644 --- a/debug/vsnprintf_chk.c +++ b/debug/vsnprintf_chk.c @@ -60,7 +60,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen, sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY; _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s); - ret = _IO_vfprintf (&sf.f._sbf._f, format, args); + ret = __vfprintf_internal (&sf.f._sbf._f, format, args, 0); if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf) *sf.f._sbf._f._IO_write_ptr = '\0'; diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c index 9a443bb699..53f07236ae 100644 --- a/debug/vsprintf_chk.c +++ b/debug/vsprintf_chk.c @@ -80,7 +80,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format, if (flags > 0) f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY; - ret = _IO_vfprintf (&f._sbf._f, format, args); + ret = __vfprintf_internal (&f._sbf._f, format, args, 0); *f._sbf._f._IO_write_ptr = '\0'; return ret; diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c index c6a7edcacd..4d616f8835 100644 --- a/debug/vswprintf_chk.c +++ b/debug/vswprintf_chk.c @@ -59,7 +59,7 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen, sf.f._sbf._f._flags2 |= _IO_FLAGS2_FORTIFY; _IO_wstr_init_static (&sf.f._sbf._f, s, maxlen - 1, s); - ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args); + ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, 0); if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf) /* ISO C99 requires swprintf/vswprintf to return an error if the diff --git a/debug/vwprintf_chk.c b/debug/vwprintf_chk.c index 51b67c159d..fedc7a46bf 100644 --- a/debug/vwprintf_chk.c +++ b/debug/vwprintf_chk.c @@ -31,7 +31,7 @@ __vwprintf_chk (int flag, const wchar_t *format, va_list ap) if (flag > 0) stdout->_flags2 |= _IO_FLAGS2_FORTIFY; - done = _IO_vfwprintf (stdout, format, ap); + done = __vfwprintf_internal (stdout, format, ap, 0); if (flag > 0) stdout->_flags2 &= ~_IO_FLAGS2_FORTIFY; diff --git a/debug/wprintf_chk.c b/debug/wprintf_chk.c index 17023b6bb4..819050e5af 100644 --- a/debug/wprintf_chk.c +++ b/debug/wprintf_chk.c @@ -33,7 +33,7 @@ __wprintf_chk (int flag, const wchar_t *format, ...) stdout->_flags2 |= _IO_FLAGS2_FORTIFY; va_start (ap, format); - done = _IO_vfwprintf (stdout, format, ap); + done = __vfwprintf_internal (stdout, format, ap, 0); va_end (ap); if (flag > 0) diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c index 76cd31f922..b9634afc2b 100644 --- a/hurd/vpprintf.c +++ b/hurd/vpprintf.c @@ -53,7 +53,7 @@ vpprintf (io_t port, const char *format, va_list arg) _IO_cookie_init (&temp_f.cfile, _IO_NO_READS, (void *) port, (cookie_io_functions_t) { write: do_write }); - done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg); + done = __vfprintf_internal (&temp_f.cfile.__fp.file, format, arg, 0); return done; } diff --git a/include/stdio.h b/include/stdio.h index 51ada4a4c4..0856d729d9 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -14,9 +14,6 @@ extern int __snprintf (char *__restrict __s, size_t __maxlen, const char *__restrict __format, ...) __attribute__ ((__format__ (__printf__, 3, 4))); libc_hidden_proto (__snprintf) -extern int __vsnprintf (char *__restrict __s, size_t __maxlen, - const char *__restrict __format, __gnuc_va_list __arg) - __attribute__ ((__format__ (__printf__, 3, 0))); extern int __vfscanf (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) diff --git a/include/wchar.h b/include/wchar.h index 1db0ac8278..d0fe45c3a6 100644 --- a/include/wchar.h +++ b/include/wchar.h @@ -203,20 +203,10 @@ extern int __vfwscanf (__FILE *__restrict __s, __gnuc_va_list __arg) attribute_hidden /* __attribute__ ((__format__ (__wscanf__, 2, 0)) */; -extern int __vswprintf (wchar_t *__restrict __s, size_t __n, - const wchar_t *__restrict __format, - __gnuc_va_list __arg) - attribute_hidden - /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */; extern int __fwprintf (__FILE *__restrict __s, const wchar_t *__restrict __format, ...) attribute_hidden /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */; -extern int __vfwprintf (__FILE *__restrict __s, - const wchar_t *__restrict __format, - __gnuc_va_list __arg) - attribute_hidden - /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */; extern int __vfwprintf_chk (FILE *__restrict __s, int __flag, const wchar_t *__restrict __format, __gnuc_va_list __arg) diff --git a/libio/fwprintf.c b/libio/fwprintf.c index fab63a8716..9903f1f342 100644 --- a/libio/fwprintf.c +++ b/libio/fwprintf.c @@ -30,7 +30,7 @@ __fwprintf (FILE *stream, const wchar_t *format, ...) int done; va_start (arg, format); - done = __vfwprintf (stream, format, arg); + done = __vfwprintf_internal (stream, format, arg, 0); va_end (arg); return done; diff --git a/libio/iolibio.h b/libio/iolibio.h index 6c94fe6d62..2642d71e4f 100644 --- a/libio/iolibio.h +++ b/libio/iolibio.h @@ -51,15 +51,7 @@ extern int _IO_sscanf (const char*, const char*, ...) __THROW; extern int _IO_sprintf (char *, const char*, ...) __THROW; extern int _IO_ungetc (int, FILE*) __THROW; extern int _IO_vsscanf (const char *, const char *, __gnuc_va_list) __THROW; -extern int _IO_vsprintf (char*, const char*, __gnuc_va_list) __THROW; -libc_hidden_proto (_IO_vsprintf) -extern int _IO_vswprintf (wchar_t*, size_t, const wchar_t*, __gnuc_va_list) - __THROW; -struct obstack; -extern int _IO_obstack_vprintf (struct obstack *, const char *, __gnuc_va_list) - __THROW; -extern int _IO_obstack_printf (struct obstack *, const char *, ...) __THROW; #define _IO_clearerr(FP) ((FP)->_flags &= ~(_IO_ERR_SEEN|_IO_EOF_SEEN)) #define _IO_fseek(__fp, __offset, __whence) \ (_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) \ diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c index 78a3a2bd15..1d2ed0f9e7 100644 --- a/libio/iovdprintf.c +++ b/libio/iovdprintf.c @@ -28,7 +28,8 @@ #include int -_IO_vdprintf (int d, const char *format, va_list arg) +__vdprintf_internal (int d, const char *format, va_list arg, + unsigned int mode_flags) { struct _IO_FILE_plus tmpfil; struct _IO_wide_data wd; @@ -50,7 +51,7 @@ _IO_vdprintf (int d, const char *format, va_list arg) _IO_mask_flags (&tmpfil.file, _IO_NO_READS, _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); - done = _IO_vfprintf (&tmpfil.file, format, arg); + done = __vfprintf_internal (&tmpfil.file, format, arg, mode_flags); if (done != EOF && _IO_do_flush (&tmpfil.file) == EOF) done = EOF; @@ -59,4 +60,10 @@ _IO_vdprintf (int d, const char *format, va_list arg) return done; } -ldbl_weak_alias (_IO_vdprintf, vdprintf) + +int +__vdprintf (int d, const char *format, va_list arg) +{ + return __vdprintf_internal (d, format, arg, 0); +} +ldbl_weak_alias (__vdprintf, vdprintf) diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c index 4def251701..3b1e8292b5 100644 --- a/libio/iovsprintf.c +++ b/libio/iovsprintf.c @@ -28,7 +28,8 @@ #include "strfile.h" int -__IO_vsprintf (char *string, const char *format, va_list args) +__vsprintf_internal (char *string, const char *format, va_list args, + unsigned int mode_flags) { _IO_strfile sf; int ret; @@ -39,11 +40,16 @@ __IO_vsprintf (char *string, const char *format, va_list args) _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; _IO_str_init_static_internal (&sf, string, -1, string); - ret = _IO_vfprintf (&sf._sbf._f, format, args); + ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags); _IO_putc_unlocked ('\0', &sf._sbf._f); return ret; } -ldbl_hidden_def (__IO_vsprintf, _IO_vsprintf) -ldbl_strong_alias (__IO_vsprintf, _IO_vsprintf) -ldbl_weak_alias (__IO_vsprintf, vsprintf) +int +__vsprintf (char *string, const char *format, va_list args) +{ + return __vsprintf_internal (string, format, args, 0); +} + +ldbl_strong_alias (__vsprintf, _IO_vsprintf) +ldbl_weak_alias (__vsprintf, vsprintf) diff --git a/libio/libio.h b/libio/libio.h index 30cb7d784f..c188814ccc 100644 --- a/libio/libio.h +++ b/libio/libio.h @@ -255,8 +255,6 @@ extern int _IO_ftrylockfile (FILE *) __THROW; extern int _IO_vfscanf (FILE * __restrict, const char * __restrict, __gnuc_va_list, int *__restrict); -extern int _IO_vfprintf (FILE *__restrict, const char *__restrict, - __gnuc_va_list); extern __ssize_t _IO_padn (FILE *, int, __ssize_t); extern size_t _IO_sgetn (FILE *, void *, size_t); @@ -298,8 +296,6 @@ weak_extern (_IO_stdin_used); extern int _IO_vfwscanf (FILE * __restrict, const wchar_t * __restrict, __gnuc_va_list, int *__restrict); -extern int _IO_vfwprintf (FILE *__restrict, const wchar_t *__restrict, - __gnuc_va_list); extern __ssize_t _IO_wpadn (FILE *, wint_t, __ssize_t); extern void _IO_free_wbackup_area (FILE *) __THROW; @@ -319,7 +315,6 @@ libc_hidden_proto (_IO_free_wbackup_area) libc_hidden_proto (_IO_padn) libc_hidden_proto (_IO_putc) libc_hidden_proto (_IO_sgetn) -libc_hidden_proto (_IO_vfprintf) #ifdef _IO_MTSAFE_IO # undef _IO_peekc diff --git a/libio/libioP.h b/libio/libioP.h index 9e971cb96b..fe52ef1752 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -658,12 +658,49 @@ extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int) extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW; extern void _IO_wstr_finish (FILE *, int) __THROW; -extern int _IO_vasprintf (char **result_ptr, const char *format, - va_list args) __THROW; -extern int _IO_vdprintf (int d, const char *format, va_list arg); -extern int _IO_vsnprintf (char *string, size_t maxlen, - const char *format, va_list args) __THROW; +/* Internal versions of v*printf that take an additional flags + parameter. */ +extern int __vfprintf_internal (FILE *fp, const char *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; +extern int __vfwprintf_internal (FILE *fp, const wchar_t *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; + +extern int __vasprintf_internal (char **result_ptr, const char *format, + va_list ap, unsigned int mode_flags) + attribute_hidden; +extern int __vdprintf_internal (int d, const char *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; +extern int __obstack_vprintf_internal (struct obstack *ob, const char *fmt, + va_list ap, unsigned int mode_flags) + attribute_hidden; + +extern int __vsprintf_internal (char *string, const char *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; +extern int __vsnprintf_internal (char *string, size_t maxlen, + const char *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; +extern int __vswprintf_internal (wchar_t *string, size_t maxlen, + const wchar_t *format, va_list ap, + unsigned int mode_flags) + attribute_hidden; + +/* Flags for __v*printf_internal. + + PRINTF_LDBL_IS_DBL indicates whether long double values are to be + handled as having the same format as double, in which case the flag + should be set to one, or as another format, otherwise. + PRINTF_FORTIFY, when set to one, indicates that fortification checks + are to be performed in input parameters. This is used by the + __*printf_chk functions, which are used when _FORTIFY_SOURCE is + defined to 1 or 2. Otherwise, such checks are ignored. */ +#define PRINTF_LDBL_IS_DBL 0x0001 +#define PRINTF_FORTIFY 0x0002 extern size_t _IO_getline (FILE *,char *, size_t, int, int); libc_hidden_proto (_IO_getline) diff --git a/libio/obprintf.c b/libio/obprintf.c index a74f9467a2..10a4b5c10c 100644 --- a/libio/obprintf.c +++ b/libio/obprintf.c @@ -117,7 +117,8 @@ const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden = int -_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args) +__obstack_vprintf_internal (struct obstack *obstack, const char *format, + va_list args, unsigned int mode_flags) { struct obstack_FILE { @@ -164,7 +165,8 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args) new_f.ofile.obstack = obstack; - result = _IO_vfprintf (&new_f.ofile.file.file, format, args); + result = __vfprintf_internal (&new_f.ofile.file.file, format, args, + mode_flags); /* Shrink the buffer to the space we really currently need. */ obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr @@ -172,17 +174,22 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args) return result; } -ldbl_weak_alias (_IO_obstack_vprintf, obstack_vprintf) +int +__obstack_vprintf (struct obstack *obstack, const char *format, va_list ap) +{ + return __obstack_vprintf_internal (obstack, format, ap, 0); +} +ldbl_weak_alias (__obstack_vprintf, obstack_vprintf) int -_IO_obstack_printf (struct obstack *obstack, const char *format, ...) +__obstack_printf (struct obstack *obstack, const char *format, ...) { int result; va_list ap; va_start (ap, format); - result = _IO_obstack_vprintf (obstack, format, ap); + result = __obstack_vprintf_internal (obstack, format, ap, 0); va_end (ap); return result; } -ldbl_weak_alias (_IO_obstack_printf, obstack_printf) +ldbl_weak_alias (__obstack_printf, obstack_printf) diff --git a/libio/swprintf.c b/libio/swprintf.c index 10f722d035..19b3f33198 100644 --- a/libio/swprintf.c +++ b/libio/swprintf.c @@ -28,7 +28,7 @@ __swprintf (wchar_t *s, size_t n, const wchar_t *format, ...) int done; va_start (arg, format); - done = __vswprintf (s, n, format, arg); + done = __vswprintf_internal (s, n, format, arg, 0); va_end (arg); return done; diff --git a/libio/vasprintf.c b/libio/vasprintf.c index 6c35d2b108..fabd84f403 100644 --- a/libio/vasprintf.c +++ b/libio/vasprintf.c @@ -24,15 +24,13 @@ This exception applies to code released by its copyright holders in files containing the exception. */ -#include #include -#include "libioP.h" -#include "stdio.h" -#include -#include "strfile.h" +#include +#include int -_IO_vasprintf (char **result_ptr, const char *format, va_list args) +__vasprintf_internal (char **result_ptr, const char *format, va_list args, + unsigned int mode_flags) { /* Initial size of the buffer to be used. Will be doubled each time an overflow occurs. */ @@ -56,7 +54,7 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args) sf._sbf._f._flags &= ~_IO_USER_BUF; sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; sf._s._free_buffer_unused = (_IO_free_type) free; - ret = _IO_vfprintf (&sf._sbf._f, format, args); + ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags); if (ret < 0) { free (sf._sbf._f._IO_buf_base); @@ -85,4 +83,10 @@ _IO_vasprintf (char **result_ptr, const char *format, va_list args) (*result_ptr)[needed - 1] = '\0'; return ret; } -ldbl_weak_alias (_IO_vasprintf, vasprintf) + +int +__vasprintf (char **result_ptr, const char *format, va_list args) +{ + return __vasprintf_internal (result_ptr, format, args, 0); +} +ldbl_weak_alias (__vasprintf, vasprintf) diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c index 39b5500528..35b267abf8 100644 --- a/libio/vsnprintf.c +++ b/libio/vsnprintf.c @@ -90,8 +90,8 @@ const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden = int -_IO_vsnprintf (char *string, size_t maxlen, const char *format, - va_list args) +__vsnprintf_internal (char *string, size_t maxlen, const char *format, + va_list args, unsigned int mode_flags) { _IO_strnfile sf; int ret; @@ -111,11 +111,17 @@ _IO_vsnprintf (char *string, size_t maxlen, const char *format, _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps; string[0] = '\0'; _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string); - ret = _IO_vfprintf (&sf.f._sbf._f, format, args); + 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; } -ldbl_weak_alias (_IO_vsnprintf, __vsnprintf) -ldbl_weak_alias (_IO_vsnprintf, vsnprintf) + +int +___vsnprintf (char *string, size_t maxlen, const char *format, va_list args) +{ + return __vsnprintf_internal (string, maxlen, format, args, 0); +} +ldbl_weak_alias (___vsnprintf, __vsnprintf) +ldbl_weak_alias (___vsnprintf, vsnprintf) diff --git a/libio/vswprintf.c b/libio/vswprintf.c index bcc473d115..e415e39fc9 100644 --- a/libio/vswprintf.c +++ b/libio/vswprintf.c @@ -89,8 +89,8 @@ const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden = int -_IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format, - va_list args) +__vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format, + va_list args, unsigned int mode_flags) { _IO_wstrnfile sf; int ret; @@ -108,7 +108,7 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format, _IO_fwide (&sf.f._sbf._f, 1); string[0] = L'\0'; _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string); - ret = _IO_vfwprintf ((FILE *) &sf.f._sbf, format, args); + ret = __vfwprintf_internal ((FILE *) &sf.f._sbf, format, args, mode_flags); if (sf.f._sbf._f._wide_data->_IO_buf_base == sf.overflow_buf) /* ISO C99 requires swprintf/vswprintf to return an error if the @@ -120,5 +120,11 @@ _IO_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format, return ret; } -weak_alias (_IO_vswprintf, __vswprintf) -ldbl_weak_alias (_IO_vswprintf, vswprintf) + +int +__vswprintf (wchar_t *string, size_t maxlen, const wchar_t *format, + va_list args) +{ + return __vswprintf_internal (string, maxlen, format, args, 0); +} +ldbl_weak_alias (__vswprintf, vswprintf) diff --git a/libio/vwprintf.c b/libio/vwprintf.c index 72ebfec92d..e8a529afff 100644 --- a/libio/vwprintf.c +++ b/libio/vwprintf.c @@ -25,6 +25,6 @@ int __vwprintf (const wchar_t *format, __gnuc_va_list arg) { - return __vfwprintf (stdout, format, arg); + return __vfwprintf_internal (stdout, format, arg, 0); } ldbl_strong_alias (__vwprintf, vwprintf) diff --git a/libio/wprintf.c b/libio/wprintf.c index 5945f651fc..361cd40a1b 100644 --- a/libio/wprintf.c +++ b/libio/wprintf.c @@ -29,7 +29,7 @@ __wprintf (const wchar_t *format, ...) int done; va_start (arg, format); - done = __vfwprintf (stdout, format, arg); + done = __vfwprintf_internal (stdout, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/Makefile b/stdio-common/Makefile index f3b3ceddbd..84bad1fafe 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -40,7 +40,8 @@ routines := \ isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \ isoc99_vsscanf \ psiginfo gentempfd \ - vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf + vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf \ + vfprintf-internal vfwprintf-internal aux := errlist siglist printf-parsemb printf-parsewc fxprintf diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c index bff858e657..8943ffcae1 100644 --- a/stdio-common/asprintf.c +++ b/stdio-common/asprintf.c @@ -16,11 +16,7 @@ . */ #include -#include - #include -#define vasprintf(s, f, a) _IO_vasprintf (s, f, a) -#undef __asprintf /* Write formatted output from FORMAT to a string which is allocated with malloc and stored in *STRING_PTR. */ @@ -32,7 +28,7 @@ ___asprintf (char **string_ptr, const char *format, ...) int done; va_start (arg, format); - done = vasprintf (string_ptr, format, arg); + done = __vasprintf_internal (string_ptr, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c index 11bd12b838..9adc8ae4c7 100644 --- a/stdio-common/dprintf.c +++ b/stdio-common/dprintf.c @@ -16,10 +16,7 @@ . */ #include -#include - #include -#define vdprintf(d, f, a) _IO_vdprintf (d, f, a) /* Write formatted output to D, according to the format string FORMAT. */ /* VARARGS2 */ @@ -30,7 +27,7 @@ __dprintf (int d, const char *format, ...) int done; va_start (arg, format); - done = vdprintf (d, format, arg); + done = __vdprintf_internal (d, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c index 2bbf14bf5d..c8f8ac4faf 100644 --- a/stdio-common/fprintf.c +++ b/stdio-common/fprintf.c @@ -29,7 +29,7 @@ __fprintf (FILE *stream, const char *format, ...) int done; va_start (arg, format); - done = vfprintf (stream, format, arg); + done = __vfprintf_internal (stream, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c index 8d02b71f91..a028e8edd5 100644 --- a/stdio-common/fxprintf.c +++ b/stdio-common/fxprintf.c @@ -27,7 +27,7 @@ static int locked_vfxprintf (FILE *fp, const char *fmt, va_list ap) { if (_IO_fwide (fp, 0) <= 0) - return _IO_vfprintf (fp, fmt, ap); + return __vfprintf_internal (fp, fmt, ap, 0); /* We must convert the narrow format string to a wide one. Each byte can produce at most one wide character. */ @@ -53,7 +53,7 @@ locked_vfxprintf (FILE *fp, const char *fmt, va_list ap) res = __mbsrtowcs (wfmt, &fmt, len, &mbstate); if (res != -1) - res = _IO_vfwprintf (fp, wfmt, ap); + res = __vfwprintf_internal (fp, wfmt, ap, 0); if (used_malloc) free (wfmt); diff --git a/stdio-common/printf.c b/stdio-common/printf.c index 205b5e42df..ea41dd557c 100644 --- a/stdio-common/printf.c +++ b/stdio-common/printf.c @@ -30,7 +30,7 @@ __printf (const char *format, ...) int done; va_start (arg, format); - done = vfprintf (stdout, format, arg); + done = __vfprintf_internal (stdout, format, arg, 0); va_end (arg); return done; @@ -38,5 +38,4 @@ __printf (const char *format, ...) #undef _IO_printf ldbl_strong_alias (__printf, printf); -/* This is for libg++. */ ldbl_strong_alias (__printf, _IO_printf); diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c index 29a169b08b..b75e160ea3 100644 --- a/stdio-common/snprintf.c +++ b/stdio-common/snprintf.c @@ -16,9 +16,7 @@ . */ #include -#include #include -#define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) /* Write formatted output into S, according to the format string FORMAT, writing no more than MAXLEN characters. */ @@ -30,7 +28,7 @@ __snprintf (char *s, size_t maxlen, const char *format, ...) int done; va_start (arg, format); - done = __vsnprintf (s, maxlen, format, arg); + done = __vsnprintf_internal (s, maxlen, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c index bf5671dde9..77423b292f 100644 --- a/stdio-common/sprintf.c +++ b/stdio-common/sprintf.c @@ -16,9 +16,7 @@ . */ #include -#include #include -#define vsprintf(s, f, a) _IO_vsprintf (s, f, a) /* Write formatted output into S, according to the format string FORMAT. */ /* VARARGS2 */ @@ -29,7 +27,7 @@ __sprintf (char *s, const char *format, ...) int done; va_start (arg, format); - done = vsprintf (s, format, arg); + done = __vsprintf_internal (s, format, arg, 0); va_end (arg); return done; diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c new file mode 100644 index 0000000000..b0c86e99bd --- /dev/null +++ b/stdio-common/vfprintf-internal.c @@ -0,0 +1,2364 @@ +/* Copyright (C) 1991-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include <_itoa.h> +#include +#include +#include + +/* This code is shared between the standard stdio implementation found + in GNU C library and the libio implementation originally found in + GNU libg++. + + Beside this it is also shared between the normal and wide character + implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */ + +#include + +#ifdef COMPILE_WPRINTF +#include +#endif + +/* In some cases we need extra space for all the output which is not + counted in the width of the string. We assume 32 characters is + enough. */ +#define EXTSIZ 32 +#define ARGCHECK(S, Format) \ + do \ + { \ + /* Check file argument for consistence. */ \ + CHECK_FILE (S, -1); \ + if (S->_flags & _IO_NO_WRITES) \ + { \ + S->_flags |= _IO_ERR_SEEN; \ + __set_errno (EBADF); \ + return -1; \ + } \ + if (Format == NULL) \ + { \ + __set_errno (EINVAL); \ + return -1; \ + } \ + } while (0) +#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED) + +#define done_add(val) \ + do { \ + unsigned int _val = val; \ + assert ((unsigned int) done < (unsigned int) INT_MAX); \ + if (__glibc_unlikely (INT_MAX - done < _val)) \ + { \ + done = -1; \ + __set_errno (EOVERFLOW); \ + goto all_done; \ + } \ + done += _val; \ + } while (0) + +#ifndef COMPILE_WPRINTF +# define vfprintf __vfprintf_internal +# define CHAR_T char +# define UCHAR_T unsigned char +# define INT_T int +typedef const char *THOUSANDS_SEP_T; +# define L_(Str) Str +# define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10) +# define STR_LEN(Str) strlen (Str) + +# define PUT(F, S, N) _IO_sputn ((F), (S), (N)) +# define PAD(Padchar) \ + do { \ + if (width > 0) \ + { \ + ssize_t written = _IO_padn (s, (Padchar), width); \ + if (__glibc_unlikely (written != width)) \ + { \ + done = -1; \ + goto all_done; \ + } \ + done_add (written); \ + } \ + } while (0) +# define PUTC(C, F) _IO_putc_unlocked (C, F) +# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\ + return -1 +#else +# define vfprintf __vfwprintf_internal +# define CHAR_T wchar_t +/* This is a hack!!! There should be a type uwchar_t. */ +# define UCHAR_T unsigned int /* uwchar_t */ +# define INT_T wint_t +typedef wchar_t THOUSANDS_SEP_T; +# define L_(Str) L##Str +# define ISDIGIT(Ch) ((unsigned int) ((Ch) - L'0') < 10) +# define STR_LEN(Str) __wcslen (Str) + +# include <_itowa.h> + +# define PUT(F, S, N) _IO_sputn ((F), (S), (N)) +# define PAD(Padchar) \ + do { \ + if (width > 0) \ + { \ + ssize_t written = _IO_wpadn (s, (Padchar), width); \ + if (__glibc_unlikely (written != width)) \ + { \ + done = -1; \ + goto all_done; \ + } \ + done_add (written); \ + } \ + } while (0) +# define PUTC(C, F) _IO_putwc_unlocked (C, F) +# define ORIENT if (_IO_fwide (s, 1) != 1) return -1 + +# undef _itoa +# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case) +# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case) +# undef EOF +# define EOF WEOF +#endif + +#include "_i18n_number.h" + +/* Include the shared code for parsing the format string. */ +#include "printf-parse.h" + + +#define outchar(Ch) \ + do \ + { \ + const INT_T outc = (Ch); \ + if (PUTC (outc, s) == EOF || done == INT_MAX) \ + { \ + done = -1; \ + goto all_done; \ + } \ + ++done; \ + } \ + while (0) + +#define outstring(String, Len) \ + do \ + { \ + assert ((size_t) done <= (size_t) INT_MAX); \ + if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \ + { \ + done = -1; \ + goto all_done; \ + } \ + if (__glibc_unlikely (INT_MAX - done < (Len))) \ + { \ + done = -1; \ + __set_errno (EOVERFLOW); \ + goto all_done; \ + } \ + done += (Len); \ + } \ + while (0) + +/* For handling long_double and longlong we use the same flag. If + `long' and `long long' are effectively the same type define it to + zero. */ +#if LONG_MAX == LONG_LONG_MAX +# define is_longlong 0 +#else +# define is_longlong is_long_double +#endif + +/* If `long' and `int' is effectively the same type we don't have to + handle `long separately. */ +#if INT_MAX == LONG_MAX +# define is_long_num 0 +#else +# define is_long_num is_long +#endif + + +/* Global constants. */ +static const CHAR_T null[] = L_("(null)"); + +/* Size of the work_buffer variable (in characters, not bytes. */ +enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) }; + +/* This table maps a character into a number representing a class. In + each step there is a destination label for each class. */ +static const uint8_t jump_table[] = + { + /* ' ' */ 1, 0, 0, /* '#' */ 4, + 0, /* '%' */ 14, 0, /* '\''*/ 6, + 0, 0, /* '*' */ 7, /* '+' */ 2, + 0, /* '-' */ 3, /* '.' */ 9, 0, + /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8, + /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8, + /* '8' */ 8, /* '9' */ 8, 0, 0, + 0, 0, 0, 0, + 0, /* 'A' */ 26, 0, /* 'C' */ 25, + 0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19, + 0, /* 'I' */ 29, 0, 0, + /* 'L' */ 12, 0, 0, 0, + 0, 0, 0, /* 'S' */ 21, + 0, 0, 0, 0, + /* 'X' */ 18, 0, /* 'Z' */ 13, 0, + 0, 0, 0, 0, + 0, /* 'a' */ 26, 0, /* 'c' */ 20, + /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19, + /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0, + /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17, + /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21, + /* 't' */ 27, /* 'u' */ 16, 0, 0, + /* 'x' */ 18, 0, /* 'z' */ 13 + }; + +#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z')) +#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')]) +#define LABEL(Name) do_##Name +#ifdef SHARED + /* 'int' is enough and it saves some space on 64 bit systems. */ +# define JUMP_TABLE_TYPE const int +# define JUMP_TABLE_BASE_LABEL do_form_unknown +# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL +# define JUMP(ChExpr, table) \ + do \ + { \ + int offset; \ + void *ptr; \ + spec = (ChExpr); \ + offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ + : table[CHAR_CLASS (spec)]; \ + ptr = &&JUMP_TABLE_BASE_LABEL + offset; \ + goto *ptr; \ + } \ + while (0) +#else +# define JUMP_TABLE_TYPE const void *const +# define REF(Name) &&do_##Name +# define JUMP(ChExpr, table) \ + do \ + { \ + const void *ptr; \ + spec = (ChExpr); \ + ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ + : table[CHAR_CLASS (spec)]; \ + goto *ptr; \ + } \ + while (0) +#endif + +#define STEP0_3_TABLE \ + /* Step 0: at the beginning. */ \ + static JUMP_TABLE_TYPE step0_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (flag_space), /* for ' ' */ \ + REF (flag_plus), /* for '+' */ \ + REF (flag_minus), /* for '-' */ \ + REF (flag_hash), /* for '' */ \ + REF (flag_zero), /* for '0' */ \ + REF (flag_quote), /* for '\'' */ \ + REF (width_asterics), /* for '*' */ \ + REF (width), /* for '1'...'9' */ \ + REF (precision), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's', 'S' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror), /* for 'm' */ \ + REF (form_wcharacter), /* for 'C' */ \ + REF (form_floathex), /* for 'A', 'a' */ \ + REF (mod_ptrdiff_t), /* for 't' */ \ + REF (mod_intmax_t), /* for 'j' */ \ + REF (flag_i18n), /* for 'I' */ \ + }; \ + /* Step 1: after processing width. */ \ + static JUMP_TABLE_TYPE step1_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (precision), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's', 'S' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror), /* for 'm' */ \ + REF (form_wcharacter), /* for 'C' */ \ + REF (form_floathex), /* for 'A', 'a' */ \ + REF (mod_ptrdiff_t), /* for 't' */ \ + REF (mod_intmax_t), /* for 'j' */ \ + REF (form_unknown) /* for 'I' */ \ + }; \ + /* Step 2: after processing precision. */ \ + static JUMP_TABLE_TYPE step2_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's', 'S' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror), /* for 'm' */ \ + REF (form_wcharacter), /* for 'C' */ \ + REF (form_floathex), /* for 'A', 'a' */ \ + REF (mod_ptrdiff_t), /* for 't' */ \ + REF (mod_intmax_t), /* for 'j' */ \ + REF (form_unknown) /* for 'I' */ \ + }; \ + /* Step 3a: after processing first 'h' modifier. */ \ + static JUMP_TABLE_TYPE step3a_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (mod_halfhalf), /* for 'h' */ \ + REF (form_unknown), /* for 'l' */ \ + REF (form_unknown), /* for 'L', 'q' */ \ + REF (form_unknown), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_unknown), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_unknown), /* for 'c' */ \ + REF (form_unknown), /* for 's', 'S' */ \ + REF (form_unknown), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_unknown), /* for 'm' */ \ + REF (form_unknown), /* for 'C' */ \ + REF (form_unknown), /* for 'A', 'a' */ \ + REF (form_unknown), /* for 't' */ \ + REF (form_unknown), /* for 'j' */ \ + REF (form_unknown) /* for 'I' */ \ + }; \ + /* Step 3b: after processing first 'l' modifier. */ \ + static JUMP_TABLE_TYPE step3b_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (form_unknown), /* for 'h' */ \ + REF (mod_longlong), /* for 'l' */ \ + REF (form_unknown), /* for 'L', 'q' */ \ + REF (form_unknown), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's', 'S' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror), /* for 'm' */ \ + REF (form_wcharacter), /* for 'C' */ \ + REF (form_floathex), /* for 'A', 'a' */ \ + REF (form_unknown), /* for 't' */ \ + REF (form_unknown), /* for 'j' */ \ + REF (form_unknown) /* for 'I' */ \ + } + +#define STEP4_TABLE \ + /* Step 4: processing format specifier. */ \ + static JUMP_TABLE_TYPE step4_jumps[30] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (form_unknown), /* for 'h' */ \ + REF (form_unknown), /* for 'l' */ \ + REF (form_unknown), /* for 'L', 'q' */ \ + REF (form_unknown), /* for 'z', 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's', 'S' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror), /* for 'm' */ \ + REF (form_wcharacter), /* for 'C' */ \ + REF (form_floathex), /* for 'A', 'a' */ \ + REF (form_unknown), /* for 't' */ \ + REF (form_unknown), /* for 'j' */ \ + REF (form_unknown) /* for 'I' */ \ + } + + +#define process_arg(fspec) \ + /* Start real work. We know about all flags and modifiers and \ + now process the wanted format specifier. */ \ + LABEL (form_percent): \ + /* Write a literal "%". */ \ + outchar (L_('%')); \ + break; \ + \ + LABEL (form_integer): \ + /* Signed decimal integer. */ \ + base = 10; \ + \ + if (is_longlong) \ + { \ + long long int signed_number; \ + \ + if (fspec == NULL) \ + signed_number = va_arg (ap, long long int); \ + else \ + signed_number = args_value[fspec->data_arg].pa_long_long_int; \ + \ + is_negative = signed_number < 0; \ + number.longlong = is_negative ? (- signed_number) : signed_number; \ + \ + goto LABEL (longlong_number); \ + } \ + else \ + { \ + long int signed_number; \ + \ + if (fspec == NULL) \ + { \ + if (is_long_num) \ + signed_number = va_arg (ap, long int); \ + else if (is_char) \ + signed_number = (signed char) va_arg (ap, unsigned int); \ + else if (!is_short) \ + signed_number = va_arg (ap, int); \ + else \ + signed_number = (short int) va_arg (ap, unsigned int); \ + } \ + else \ + if (is_long_num) \ + signed_number = args_value[fspec->data_arg].pa_long_int; \ + else if (is_char) \ + signed_number = (signed char) \ + args_value[fspec->data_arg].pa_u_int; \ + else if (!is_short) \ + signed_number = args_value[fspec->data_arg].pa_int; \ + else \ + signed_number = (short int) \ + args_value[fspec->data_arg].pa_u_int; \ + \ + is_negative = signed_number < 0; \ + number.word = is_negative ? (- signed_number) : signed_number; \ + \ + goto LABEL (number); \ + } \ + /* NOTREACHED */ \ + \ + LABEL (form_unsigned): \ + /* Unsigned decimal integer. */ \ + base = 10; \ + goto LABEL (unsigned_number); \ + /* NOTREACHED */ \ + \ + LABEL (form_octal): \ + /* Unsigned octal integer. */ \ + base = 8; \ + goto LABEL (unsigned_number); \ + /* NOTREACHED */ \ + \ + LABEL (form_hexa): \ + /* Unsigned hexadecimal integer. */ \ + base = 16; \ + \ + LABEL (unsigned_number): /* Unsigned number of base BASE. */ \ + \ + /* ISO specifies the `+' and ` ' flags only for signed \ + conversions. */ \ + is_negative = 0; \ + showsign = 0; \ + space = 0; \ + \ + if (is_longlong) \ + { \ + if (fspec == NULL) \ + number.longlong = va_arg (ap, unsigned long long int); \ + else \ + number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \ + \ + LABEL (longlong_number): \ + if (prec < 0) \ + /* Supply a default precision if none was given. */ \ + prec = 1; \ + else \ + /* We have to take care for the '0' flag. If a precision \ + is given it must be ignored. */ \ + pad = L_(' '); \ + \ + /* If the precision is 0 and the number is 0 nothing has to \ + be written for the number, except for the 'o' format in \ + alternate form. */ \ + if (prec == 0 && number.longlong == 0) \ + { \ + string = workend; \ + if (base == 8 && alt) \ + *--string = L_('0'); \ + } \ + else \ + { \ + /* Put the number in WORK. */ \ + string = _itoa (number.longlong, workend, base, \ + 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. */ \ + number.word = number.longlong != 0; \ + } \ + else \ + { \ + if (fspec == NULL) \ + { \ + if (is_long_num) \ + number.word = va_arg (ap, unsigned long int); \ + else if (is_char) \ + number.word = (unsigned char) va_arg (ap, unsigned int); \ + else if (!is_short) \ + number.word = va_arg (ap, unsigned int); \ + else \ + number.word = (unsigned short int) va_arg (ap, unsigned int); \ + } \ + else \ + if (is_long_num) \ + number.word = args_value[fspec->data_arg].pa_u_long_int; \ + else if (is_char) \ + number.word = (unsigned char) \ + args_value[fspec->data_arg].pa_u_int; \ + else if (!is_short) \ + number.word = args_value[fspec->data_arg].pa_u_int; \ + else \ + number.word = (unsigned short int) \ + args_value[fspec->data_arg].pa_u_int; \ + \ + LABEL (number): \ + if (prec < 0) \ + /* Supply a default precision if none was given. */ \ + prec = 1; \ + else \ + /* We have to take care for the '0' flag. If a precision \ + is given it must be ignored. */ \ + pad = L_(' '); \ + \ + /* If the precision is 0 and the number is 0 nothing has to \ + be written for the number, except for the 'o' format in \ + alternate form. */ \ + if (prec == 0 && number.word == 0) \ + { \ + string = workend; \ + if (base == 8 && alt) \ + *--string = L_('0'); \ + } \ + else \ + { \ + /* Put the number in WORK. */ \ + string = _itoa_word (number.word, workend, base, \ + spec == L_('X')); \ + if (group && grouping) \ + string = group_number (work_buffer, string, workend, \ + grouping, thousands_sep); \ + if (use_outd