diff options
author | Po Lu <luangruo@yahoo.com> | 2023-05-15 10:39:43 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2023-05-15 10:40:34 +0800 |
commit | 5a3f009ad70d87366889e977d3b7d13f01b93e69 (patch) | |
tree | 28f084eb094292f6a5eb2d2d1ad6e919e3c12753 /lib | |
parent | a46e231a5f27c46933cc53865cee452ad1a0c0d3 (diff) | |
download | emacs-5a3f009ad70d87366889e977d3b7d13f01b93e69.tar.gz |
; Update from Gnulib
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fseterr.h | 5 | ||||
-rw-r--r-- | lib/gnulib.mk.in | 10 | ||||
-rw-r--r-- | lib/isnand-nolibm.h | 5 | ||||
-rw-r--r-- | lib/isnanf-nolibm.h | 5 | ||||
-rw-r--r-- | lib/isnanl-nolibm.h | 5 | ||||
-rw-r--r-- | lib/math.in.h | 14 | ||||
-rw-r--r-- | lib/printf-args.c | 123 | ||||
-rw-r--r-- | lib/printf-args.h | 59 | ||||
-rw-r--r-- | lib/printf-parse.c | 497 | ||||
-rw-r--r-- | lib/printf-parse.h | 8 | ||||
-rw-r--r-- | lib/size_max.h | 5 | ||||
-rw-r--r-- | lib/vasnprintf.c | 1512 | ||||
-rw-r--r-- | lib/vasnprintf.h | 5 | ||||
-rw-r--r-- | lib/xsize.h | 8 |
14 files changed, 1888 insertions, 373 deletions
diff --git a/lib/fseterr.h b/lib/fseterr.h index 0e9d2060aef..87dc347332d 100644 --- a/lib/fseterr.h +++ b/lib/fseterr.h @@ -17,6 +17,11 @@ #ifndef _FSETERR_H #define _FSETERR_H +/* This file uses HAVE___FSETERR. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + #include <stdio.h> /* Set the error indicator of the stream FP. diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index e447a2c4054..1f59f02b1e9 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -186,6 +186,8 @@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ANDROID = @ANDROID@ ANDROID_ABI = @ANDROID_ABI@ ANDROID_BUILD_CFLAGS = @ANDROID_BUILD_CFLAGS@ +ANDROID_CC = @ANDROID_CC@ +ANDROID_CFLAGS = @ANDROID_CFLAGS@ ANDROID_DEBUGGABLE = @ANDROID_DEBUGGABLE@ ANDROID_JAR = @ANDROID_JAR@ ANDROID_LDFLAGS = @ANDROID_LDFLAGS@ @@ -194,6 +196,7 @@ ANDROID_MIN_SDK = @ANDROID_MIN_SDK@ ANDROID_OBJ = @ANDROID_OBJ@ ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@ ANDROID_SDK_8_OR_EARLIER = @ANDROID_SDK_8_OR_EARLIER@ +ANDROID_SHARED_USER_ID = @ANDROID_SHARED_USER_ID@ APKSIGNER = @APKSIGNER@ APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ AR = @AR@ @@ -1193,7 +1196,6 @@ LIB_WSOCK32 = @LIB_WSOCK32@ LIB_XATTR = @LIB_XATTR@ LIMITS_H = @LIMITS_H@ LN_S_FILEONLY = @LN_S_FILEONLY@ -LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ LTLIBGMP = @LTLIBGMP@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ @@ -1495,11 +1497,8 @@ REPLACE_REMAINDERL = @REPLACE_REMAINDERL@ REPLACE_REMOVE = @REPLACE_REMOVE@ REPLACE_RENAME = @REPLACE_RENAME@ REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ -<<<<<<< HEAD -REPLACE_RINTL = @REPLACE_RINTL@ -======= REPLACE_REWINDDIR = @REPLACE_REWINDDIR@ ->>>>>>> origin/master +REPLACE_RINTL = @REPLACE_RINTL@ REPLACE_RMDIR = @REPLACE_RMDIR@ REPLACE_ROUND = @REPLACE_ROUND@ REPLACE_ROUNDF = @REPLACE_ROUNDF@ @@ -1682,6 +1681,7 @@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ emacs_major_version = @emacs_major_version@ +emacs_use_mailutils = @emacs_use_mailutils@ etcdir = @etcdir@ etcdocdir = @etcdocdir@ exec_prefix = @exec_prefix@ diff --git a/lib/isnand-nolibm.h b/lib/isnand-nolibm.h index 9c75a8c47bf..bb5a38b39f0 100644 --- a/lib/isnand-nolibm.h +++ b/lib/isnand-nolibm.h @@ -14,6 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/* This file uses HAVE_ISNAND_IN_LIBC. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + #if HAVE_ISNAND_IN_LIBC /* Get declaration of isnan macro. */ # include <math.h> diff --git a/lib/isnanf-nolibm.h b/lib/isnanf-nolibm.h index cc6b4198ff1..f4bcba143e6 100644 --- a/lib/isnanf-nolibm.h +++ b/lib/isnanf-nolibm.h @@ -14,6 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/* This file uses HAVE_ISNANF_IN_LIBC. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + #if HAVE_ISNANF_IN_LIBC /* Get declaration of isnan macro or (older) isnanf function. */ # include <math.h> diff --git a/lib/isnanl-nolibm.h b/lib/isnanl-nolibm.h index f04c489bb8e..8becc5b409e 100644 --- a/lib/isnanl-nolibm.h +++ b/lib/isnanl-nolibm.h @@ -14,6 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/* This file uses HAVE_ISNANL_IN_LIBC. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + #if HAVE_ISNANL_IN_LIBC /* Get declaration of isnan macro or (older) isnanl function. */ # include <math.h> diff --git a/lib/math.in.h b/lib/math.in.h index 76d48a44437..f841a1356e4 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -48,14 +48,17 @@ #ifndef _@GUARD_PREFIX@_MATH_H #define _@GUARD_PREFIX@_MATH_H +/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_ATTRIBUTE_CONST, + GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + /* On OpenVMS, NAN, INFINITY, and HUGEVAL macros are defined in <fp.h>. */ #if defined __VMS && ! defined NAN # include <fp.h> #endif -#ifndef _GL_INLINE_HEADER_BEGIN - #error "Please include config.h first." -#endif _GL_INLINE_HEADER_BEGIN #ifndef _GL_MATH_INLINE # define _GL_MATH_INLINE _GL_INLINE @@ -2630,6 +2633,11 @@ _GL_MATH_CXX_REAL_FLOATING_DECL_1 (isnan) _GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, rpl_isnan, bool) # define isnan rpl_isnan # define GNULIB_NAMESPACE_LACKS_ISNAN 1 +# elif (defined __FreeBSD__ && __clang_major__ >= 14) + /* Neither of the two possible _GL_MATH_CXX_REAL_FLOATING_DECL_2 invocations + works. Inline functions are already present in /usr/include/c++/v1/math.h, + which comes from LLVM. */ +# define GNULIB_NAMESPACE_LACKS_ISNAN 1 # else _GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, isnan, bool) # endif diff --git a/lib/printf-args.c b/lib/printf-args.c index 5e14f654794..b2b21aeec18 100644 --- a/lib/printf-args.c +++ b/lib/printf-args.c @@ -29,6 +29,9 @@ # include "printf-args.h" #endif +/* Get INT_WIDTH. */ +#include <limits.h> + #ifdef STATIC STATIC #endif @@ -71,6 +74,102 @@ PRINTF_FETCHARGS (va_list args, arguments *a) case TYPE_ULONGLONGINT: ap->a.a_ulonglongint = va_arg (args, unsigned long long int); break; + case TYPE_INT8_T: + #if INT8_WIDTH < INT_WIDTH + ap->a.a_int8_t = va_arg (args, /* int8_t */ int); + #else + ap->a.a_int8_t = va_arg (args, int8_t); + #endif + break; + case TYPE_UINT8_T: + #if UINT8_WIDTH < INT_WIDTH + ap->a.a_uint8_t = va_arg (args, /* uint8_t */ int); + #else + ap->a.a_uint8_t = va_arg (args, uint8_t); + #endif + break; + case TYPE_INT16_T: + #if INT16_WIDTH < INT_WIDTH + ap->a.a_int16_t = va_arg (args, /* int16_t */ int); + #else + ap->a.a_int16_t = va_arg (args, int16_t); + #endif + break; + case TYPE_UINT16_T: + #if UINT16_WIDTH < INT_WIDTH + ap->a.a_uint16_t = va_arg (args, /* uint16_t */ int); + #else + ap->a.a_uint16_t = va_arg (args, uint16_t); + #endif + break; + case TYPE_INT32_T: + #if INT32_WIDTH < INT_WIDTH + ap->a.a_int32_t = va_arg (args, /* int32_t */ int); + #else + ap->a.a_int32_t = va_arg (args, int32_t); + #endif + break; + case TYPE_UINT32_T: + #if UINT32_WIDTH < INT_WIDTH + ap->a.a_uint32_t = va_arg (args, /* uint32_t */ int); + #else + ap->a.a_uint32_t = va_arg (args, uint32_t); + #endif + break; + case TYPE_INT64_T: + ap->a.a_int64_t = va_arg (args, int64_t); + break; + case TYPE_UINT64_T: + ap->a.a_uint64_t = va_arg (args, uint64_t); + break; + case TYPE_INT_FAST8_T: + #if INT_FAST8_WIDTH < INT_WIDTH + ap->a.a_int_fast8_t = va_arg (args, /* int_fast8_t */ int); + #else + ap->a.a_int_fast8_t = va_arg (args, int_fast8_t); + #endif + break; + case TYPE_UINT_FAST8_T: + #if UINT_FAST8_WIDTH < INT_WIDTH + ap->a.a_uint_fast8_t = va_arg (args, /* uint_fast8_t */ int); + #else + ap->a.a_uint_fast8_t = va_arg (args, uint_fast8_t); + #endif + break; + case TYPE_INT_FAST16_T: + #if INT_FAST16_WIDTH < INT_WIDTH + ap->a.a_int_fast16_t = va_arg (args, /* int_fast16_t */ int); + #else + ap->a.a_int_fast16_t = va_arg (args, int_fast16_t); + #endif + break; + case TYPE_UINT_FAST16_T: + #if UINT_FAST16_WIDTH < INT_WIDTH + ap->a.a_uint_fast16_t = va_arg (args, /* uint_fast16_t */ int); + #else + ap->a.a_uint_fast16_t = va_arg (args, uint_fast16_t); + #endif + break; + case TYPE_INT_FAST32_T: + #if INT_FAST32_WIDTH < INT_WIDTH + ap->a.a_int_fast32_t = va_arg (args, /* int_fast32_t */ int); + #else + ap->a.a_int_fast32_t = va_arg (args, int_fast32_t); + #endif + break; + case TYPE_UINT_FAST32_T: + #if UINT_FAST32_WIDTH < INT_WIDTH + ap->a.a_uint_fast32_t = va_arg (args, /* uint_fast32_t */ int); + #else + ap->a.a_uint_fast32_t = va_arg (args, uint_fast32_t); + #endif + break; + case TYPE_INT_FAST64_T: + ap->a.a_int_fast64_t = va_arg (args, int_fast64_t); + break; + case TYPE_UINT_FAST64_T: + ap->a.a_uint_fast64_t = va_arg (args, uint_fast64_t); + break; case TYPE_DOUBLE: ap->a.a_double = va_arg (args, double); break; @@ -136,6 +235,30 @@ PRINTF_FETCHARGS (va_list args, arguments *a) case TYPE_COUNT_LONGLONGINT_POINTER: ap->a.a_count_longlongint_pointer = va_arg (args, long long int *); break; + case TYPE_COUNT_INT8_T_POINTER: + ap->a.a_count_int8_t_pointer = va_arg (args, int8_t *); + break; + case TYPE_COUNT_INT16_T_POINTER: + ap->a.a_count_int16_t_pointer = va_arg (args, int16_t *); + break; + case TYPE_COUNT_INT32_T_POINTER: + ap->a.a_count_int32_t_pointer = va_arg (args, int32_t *); + break; + case TYPE_COUNT_INT64_T_POINTER: + ap->a.a_count_int64_t_pointer = va_arg (args, int64_t *); + break; + case TYPE_COUNT_INT_FAST8_T_POINTER: + ap->a.a_count_int_fast8_t_pointer = va_arg (args, int_fast8_t *); + break; + case TYPE_COUNT_INT_FAST16_T_POINTER: + ap->a.a_count_int_fast16_t_pointer = va_arg (args, int_fast16_t *); + break; + case TYPE_COUNT_INT_FAST32_T_POINTER: + ap->a.a_count_int_fast32_t_pointer = va_arg (args, int_fast32_t *); + break; + case TYPE_COUNT_INT_FAST64_T_POINTER: + ap->a.a_count_int_fast64_t_pointer = va_arg (args, int_fast64_t *); + break; #if ENABLE_UNISTDIO /* The unistdio extensions. */ case TYPE_U8_STRING: diff --git a/lib/printf-args.h b/lib/printf-args.h index f303cb19e9b..11016102828 100644 --- a/lib/printf-args.h +++ b/lib/printf-args.h @@ -41,6 +41,9 @@ # include <wchar.h> #endif +/* Get intN_t, uintN_t, intN_fast_t, uintN_fast_t. */ +#include <stdint.h> + /* Get va_list. */ #include <stdarg.h> @@ -59,6 +62,26 @@ typedef enum TYPE_ULONGINT, TYPE_LONGLONGINT, TYPE_ULONGLONGINT, + /* According to ISO C 23 ยง 7.23.6.1, "all exact-width integer types", + "all minimum-width integer types", and "all fastest minimum-width integer + types" defined in <stdint.h> should be supported. But for portability + between platforms, we support only those with N = 8, 16, 32, 64. */ + TYPE_INT8_T, + TYPE_UINT8_T, + TYPE_INT16_T, + TYPE_UINT16_T, + TYPE_INT32_T, + TYPE_UINT32_T, + TYPE_INT64_T, + TYPE_UINT64_T, + TYPE_INT_FAST8_T, + TYPE_UINT_FAST8_T, + TYPE_INT_FAST16_T, + TYPE_UINT_FAST16_T, + TYPE_INT_FAST32_T, + TYPE_UINT_FAST32_T, + TYPE_INT_FAST64_T, + TYPE_UINT_FAST64_T, TYPE_DOUBLE, TYPE_LONGDOUBLE, TYPE_CHAR, @@ -74,7 +97,15 @@ typedef enum TYPE_COUNT_SHORT_POINTER, TYPE_COUNT_INT_POINTER, TYPE_COUNT_LONGINT_POINTER, - TYPE_COUNT_LONGLONGINT_POINTER + TYPE_COUNT_LONGLONGINT_POINTER, + TYPE_COUNT_INT8_T_POINTER, + TYPE_COUNT_INT16_T_POINTER, + TYPE_COUNT_INT32_T_POINTER, + TYPE_COUNT_INT64_T_POINTER, + TYPE_COUNT_INT_FAST8_T_POINTER, + TYPE_COUNT_INT_FAST16_T_POINTER, + TYPE_COUNT_INT_FAST32_T_POINTER, + TYPE_COUNT_INT_FAST64_T_POINTER #if ENABLE_UNISTDIO /* The unistdio extensions. */ , TYPE_U8_STRING @@ -99,7 +130,23 @@ typedef struct unsigned long int a_ulongint; long long int a_longlongint; unsigned long long int a_ulonglongint; - float a_float; + int8_t a_int8_t; + uint8_t a_uint8_t; + int16_t a_int16_t; + uint16_t a_uint16_t; + int32_t a_int32_t; + uint32_t a_uint32_t; + int64_t a_int64_t; + uint64_t a_uint64_t; + int_fast8_t a_int_fast8_t; + uint_fast8_t a_uint_fast8_t; + int_fast16_t a_int_fast16_t; + uint_fast16_t a_uint_fast16_t; + int_fast32_t a_int_fast32_t; + uint_fast32_t a_uint_fast32_t; + int_fast64_t a_int_fast64_t; + uint_fast64_t a_uint_fast64_t; + float a_float; /* unused */ double a_double; long double a_longdouble; int a_char; @@ -116,6 +163,14 @@ typedef struct int * a_count_int_pointer; long int * a_count_longint_pointer; long long int * a_count_longlongint_pointer; + int8_t * a_count_int8_t_pointer; + int16_t * a_count_int16_t_pointer; + int32_t * a_count_int32_t_pointer; + int64_t * a_count_int64_t_pointer; + int_fast8_t * a_count_int_fast8_t_pointer; + int_fast16_t * a_count_int_fast16_t_pointer; + int_fast32_t * a_count_int_fast32_t_pointer; + int_fast64_t * a_count_int_fast64_t_pointer; #if ENABLE_UNISTDIO /* The unistdio extensions. */ const uint8_t * a_u8_string; diff --git a/lib/printf-parse.c b/lib/printf-parse.c index 3040749abdf..d3f2c3cb5d1 100644 --- a/lib/printf-parse.c +++ b/lib/printf-parse.c @@ -326,226 +326,317 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) arg_type type; /* Parse argument type/size specifiers. */ - { - int flags = 0; - - for (;;) - { - if (*cp == 'h') - { - flags |= (1 << (flags & 1)); - cp++; - } - else if (*cp == 'L') - { - flags |= 4; - cp++; - } - else if (*cp == 'l') - { - flags += 8; - cp++; - } - else if (*cp == 'j') - { - if (sizeof (intmax_t) > sizeof (long)) - { - /* intmax_t = long long */ - flags += 16; - } - else if (sizeof (intmax_t) > sizeof (int)) - { - /* intmax_t = long */ - flags += 8; - } - cp++; - } - else if (*cp == 'z' || *cp == 'Z') - { - /* 'z' is standardized in ISO C 99, but glibc uses 'Z' - because the warning facility in gcc-2.95.2 understands - only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ - if (sizeof (size_t) > sizeof (long)) - { - /* size_t = long long */ - flags += 16; - } - else if (sizeof (size_t) > sizeof (int)) - { - /* size_t = long */ - flags += 8; - } - cp++; - } - else if (*cp == 't') - { - if (sizeof (ptrdiff_t) > sizeof (long)) - { - /* ptrdiff_t = long long */ - flags += 16; - } - else if (sizeof (ptrdiff_t) > sizeof (int)) - { - /* ptrdiff_t = long */ - flags += 8; - } - cp++; - } + /* Relevant for the conversion characters d, i. */ + arg_type signed_type = TYPE_INT; + /* Relevant for the conversion characters b, o, u, x, X. */ + arg_type unsigned_type = TYPE_UINT; + /* Relevant for the conversion characters n. */ + arg_type pointer_type = TYPE_COUNT_INT_POINTER; + /* Relevant for the conversion characters a, A, e, E, f, F, g, G. */ + arg_type floatingpoint_type = TYPE_DOUBLE; + + if (*cp == 'h') + { + if (cp[1] == 'h') + { + signed_type = TYPE_SCHAR; + unsigned_type = TYPE_UCHAR; + pointer_type = TYPE_COUNT_SCHAR_POINTER; + cp += 2; + } + else + { + signed_type = TYPE_SHORT; + unsigned_type = TYPE_USHORT; + pointer_type = TYPE_COUNT_SHORT_POINTER; + cp++; + } + } + else if (*cp == 'l') + { + if (cp[1] == 'l') + { + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + cp += 2; + } + else + { + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + cp++; + } + } + else if (*cp == 'j') + { + if (sizeof (intmax_t) > sizeof (long)) + { + /* intmax_t = long long */ + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + } + else if (sizeof (intmax_t) > sizeof (int)) + { + /* intmax_t = long */ + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + } + cp++; + } + else if (*cp == 'z' || *cp == 'Z') + { + /* 'z' is standardized in ISO C 99, but glibc uses 'Z' + because the warning facility in gcc-2.95.2 understands + only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ + if (sizeof (size_t) > sizeof (long)) + { + /* size_t = unsigned long long */ + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + } + else if (sizeof (size_t) > sizeof (int)) + { + /* size_t = unsigned long */ + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + } + cp++; + } + else if (*cp == 't') + { + if (sizeof (ptrdiff_t) > sizeof (long)) + { + /* ptrdiff_t = long long */ + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + } + else if (sizeof (ptrdiff_t) > sizeof (int)) + { + /* ptrdiff_t = long */ + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + } + cp++; + } + else if (*cp == 'w') + { + /* wN and wfN are standardized in ISO C 23. */ + if (cp[1] == 'f') + { + if (cp[2] == '8') + { + signed_type = TYPE_INT_FAST8_T; + unsigned_type = TYPE_UINT_FAST8_T; + pointer_type = TYPE_COUNT_INT_FAST8_T_POINTER; + cp += 3; + } + else if (cp[2] == '1' && cp[3] == '6') + { + signed_type = TYPE_INT_FAST16_T; + unsigned_type = TYPE_UINT_FAST16_T; + pointer_type = TYPE_COUNT_INT_FAST16_T_POINTER; + cp += 4; + } + else if (cp[2] == '3' && cp[3] == '2') + { + signed_type = TYPE_INT_FAST32_T; + unsigned_type = TYPE_UINT_FAST32_T; + pointer_type = TYPE_COUNT_INT_FAST32_T_POINTER; + cp += 4; + } + else if (cp[2] == '6' && cp[3] == '4') + { + signed_type = TYPE_INT_FAST64_T; + unsigned_type = TYPE_UINT_FAST64_T; + pointer_type = TYPE_COUNT_INT_FAST64_T_POINTER; + cp += 4; + } + } + else + { + if (cp[1] == '8') + { + signed_type = TYPE_INT8_T; + unsigned_type = TYPE_UINT8_T; + pointer_type = TYPE_COUNT_INT8_T_POINTER; + cp += 2; + } + else if (cp[1] == '1' && cp[2] == '6') + { + signed_type = TYPE_INT16_T; + unsigned_type = TYPE_UINT16_T; + pointer_type = TYPE_COUNT_INT16_T_POINTER; + cp += 3; + } + else if (cp[1] == '3' && cp[2] == '2') + { + signed_type = TYPE_INT32_T; + unsigned_type = TYPE_UINT32_T; + pointer_type = TYPE_COUNT_INT32_T_POINTER; + cp += 3; + } + else if (cp[1] == '6' && cp[2] == '4') + { + signed_type = TYPE_INT64_T; + unsigned_type = TYPE_UINT64_T; + pointer_type = TYPE_COUNT_INT64_T_POINTER; + cp += 3; + } + } + } + else if (*cp == 'L') + { + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + floatingpoint_type = TYPE_LONGDOUBLE; + cp++; + } #if defined __APPLE__ && defined __MACH__ - /* On Mac OS X 10.3, PRIdMAX is defined as "qd". - We cannot change it to "lld" because PRIdMAX must also - be understood by the system's printf routines. */ - else if (*cp == 'q') - { - if (64 / 8 > sizeof (long)) - { - /* int64_t = long long */ - flags += 16; - } - else - { - /* int64_t = long */ - flags += 8; - } - cp++; - } + /* On Mac OS X 10.3, PRIdMAX is defined as "qd". + We cannot change it to "lld" because PRIdMAX must also + be understood by the system's printf routines. */ + else if (*cp == 'q') + { + if (64 / 8 > sizeof (long)) + { + /* int64_t = long long */ + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + } + else + { + /* int64_t = long */ + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + } + cp++; + } #endif #if defined _WIN32 && ! defined __CYGWIN__ - /* On native Windows, PRIdMAX is defined as "I64d". - We cannot change it to "lld" because PRIdMAX must also - be understood by the system's printf routines. */ - else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4') - { - if (64 / 8 > sizeof (long)) - { - /* __int64 = long long */ - flags += 16; - } - else - { - /* __int64 = long */ - flags += 8; - } - cp += 3; - } + /* On native Windows, PRIdMAX is defined as "I64d". + We cannot change it to "lld" because PRIdMAX must also + be understood by the system's printf routines. */ + else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4') + { + if (64 / 8 > sizeof (long)) + { + /* __int64_t = long long */ + signed_type = TYPE_LONGLONGINT; + unsigned_type = TYPE_ULONGLONGINT; + pointer_type = TYPE_COUNT_LONGLONGINT_POINTER; + /* For backward compatibility only. */ + floatingpoint_type = TYPE_LONGDOUBLE; + } + else + { + /* __int64_t = long */ + signed_type = TYPE_LONGINT; + unsigned_type = TYPE_ULONGINT; + pointer_type = TYPE_COUNT_LONGINT_POINTER; + } + cp++; + } #endif - else - break; - } - /* Read the conversion character. */ - c = *cp++; - switch (c) - { - case 'd': case 'i': - /* If 'long long' is larger than 'long': */ - if (flags >= 16 || (flags & 4)) - type = TYPE_LONGLONGINT; - else - /* If 'long long' is the same as 'long', we parse "lld" into - TYPE_LONGINT. */ - if (flags >= 8) - type = TYPE_LONGINT; - else if (flags & 2) - type = TYPE_SCHAR; - else if (flags & 1) - type = TYPE_SHORT; - else - type = TYPE_INT; - break; - case 'o': case 'u': case 'x': case 'X': - /* If 'unsigned long long' is larger than 'unsigned long': */ - if (flags >= 16 || (flags & 4)) - type = TYPE_ULONGLONGINT; - else - /* If 'unsigned long long' is the same as 'unsigned long', we - parse "llu" into TYPE_ULONGINT. */ - if (flags >= 8) - type = TYPE_ULONGINT; - else if (flags & 2) - type = TYPE_UCHAR; - else if (flags & 1) - type = TYPE_USHORT; - else - type = TYPE_UINT; - break; - case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': - case 'a': case 'A': - if (flags >= 16 || (flags & 4)) - type = TYPE_LONGDOUBLE; - else - type = TYPE_DOUBLE; - break; - case 'c': - if (flags >= 8) + /* Read the conversion character. */ + c = *cp++; + switch (c) + { + case 'd': case 'i': + type = signed_type; + break; + case 'b': case 'o': case 'u': case 'x': case 'X': + #if SUPPORT_GNU_PRINTF_DIRECTIVES \ + || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2) + case 'B': + #endif + type = unsigned_type; + break; + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': + type = floatingpoint_type; + break; + case 'c': + if (signed_type == TYPE_LONGINT + /* For backward compatibility only. */ + || signed_type == TYPE_LONGLONGINT) #if HAVE_WINT_T - type = TYPE_WIDE_CHAR; + type = TYPE_WIDE_CHAR; #else - goto error; + goto error; #endif - else - type = TYPE_CHAR; - break; + else + type = TYPE_CHAR; + break; #if HAVE_WINT_T - case 'C': - type = TYPE_WIDE_CHAR; - c = 'c'; - break; + case 'C': + type = TYPE_WIDE_CHAR; + c = 'c'; + break; #endif - case 's': - if (flags >= 8) + case 's': + if (signed_type == TYPE_LONGINT + /* For backward compatibility only. */ + || signed_type == TYPE_LONGLONGINT) #if HAVE_WCHAR_T - type = TYPE_WIDE_STRING; + type = TYPE_WIDE_STRING; #else - goto error; + goto error; #endif - else - type = TYPE_STRING; - break; + else + type = TYPE_STRING; + break; #if HAVE_WCHAR_T - case 'S': - type = TYPE_WIDE_STRING; - c = 's'; - break; + case 'S': + type = TYPE_WIDE_STRING; + c = 's'; + break; #endif - case 'p': - type = TYPE_POINTER; - break; - case 'n': - /* If 'long long' is larger than 'long': */ - if (flags >= 16 || (flags & 4)) - type = TYPE_COUNT_LONGLONGINT_POINTER; - else - /* If 'long long' is the same as 'long', we parse "lln" into - TYPE_COUNT_LONGINT_POINTER. */ - if (flags >= 8) - type = TYPE_COUNT_LONGINT_POINTER; - else if (flags & 2) - type = TYPE_COUNT_SCHAR_POINTER; - else if (flags & 1) - type = TYPE_COUNT_SHORT_POINTER; - else - type = TYPE_COUNT_INT_POINTER; - break; + case 'p': + type = TYPE_POINTER; + break; + case 'n': + type = pointer_type; + break; #if ENABLE_UNISTDIO - /* The unistdio extensions. */ - case 'U': - if (flags >= 16) - type = TYPE_U32_STRING; - else if (flags >= 8) - type = TYPE_U16_STRING; - else - type = TYPE_U8_STRING; - break; + /* The unistdio extensions. */ + case 'U': + if (signed_type == TYPE_LONGLONGINT) + type = TYPE_U32_STRING; + else if (signed_type == TYPE_LONGINT) + type = TYPE_U16_STRING; + else + type = TYPE_U8_STRING; + break; #endif - case '%': - type = TYPE_NONE; - break; - default: - /* Unknown conversion character. */ - goto error; - } - } + case '%': + type = TYPE_NONE; + break; + default: + /* Unknown conversion character. */ + goto error; + } if (type != TYPE_NONE) { diff --git a/lib/printf-parse.h b/lib/printf-parse.h index 1f86e32c99e..45febac1f04 100644 --- a/lib/printf-parse.h +++ b/lib/printf-parse.h @@ -61,7 +61,7 @@ typedef struct const char* precision_start; const char* precision_end; size_t precision_arg_index; - char conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ + char conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */ size_t arg_index; } char_directive; @@ -91,7 +91,7 @@ typedef struct const uint8_t* precision_start; const uint8_t* precision_end; size_t precision_arg_index; - uint8_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ + uint8_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */ size_t arg_index; } u8_directive; @@ -119,7 +119,7 @@ typedef struct const uint16_t* precision_start; const uint16_t* precision_end; size_t precision_arg_index; - uint16_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ + uint16_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */ size_t arg_index; } u16_directive; @@ -147,7 +147,7 @@ typedef struct const uint32_t* precision_start; const uint32_t* precision_end; size_t precision_arg_index; - uint32_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ + uint32_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */ size_t arg_index; } u32_directive; diff --git a/lib/size_max.h b/lib/size_max.h index 48af0250556..2cfd31a59b8 100644 --- a/lib/size_max.h +++ b/lib/size_max.h @@ -18,6 +18,11 @@ #ifndef GNULIB_SIZE_MAX_H #define GNULIB_SIZE_MAX_H +/* This file uses HAVE_STDINT_H. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + /* Get SIZE_MAX declaration on systems like Solaris 7/8/9. */ # include <limits.h> /* Get SIZE_MAX declaration on systems like glibc 2. */ diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 72b8cdbfa6b..802790e14e4 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -85,7 +85,7 @@ #include <string.h> /* memcpy(), strlen() */ #include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb() */ #include <errno.h> /* errno */ -#include <limits.h> /* CHAR_BIT */ +#include <limits.h> /* CHAR_BIT, INT_WIDTH, LONG_WIDTH */ #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ #if HAVE_NL_LANGINFO # include <langinfo.h> @@ -103,29 +103,29 @@ #include "attribute.h" -#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) # include <math.h> # include "float+.h" #endif -#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE # include <math.h> # include "isnand-nolibm.h" #endif -#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) # include <math.h> # include "isnanl-nolibm.h" # include "fpucw.h" #endif -#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE # include <math.h> # include "isnand-nolibm.h" # include "printf-frexp.h" #endif -#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) # include <math.h> # include "isnanl-nolibm.h" # include "printf-frexpl.h" @@ -138,8 +138,6 @@ # define VASNPRINTF vasnwprintf # define FCHAR_T wchar_t # define DCHAR_T wchar_t -# define TCHAR_T wchar_t -# define DCHAR_IS_TCHAR 1 # define DIRECTIVE wchar_t_directive # define DIRECTIVES wchar_t_directives # define PRINTF_PARSE wprintf_parse @@ -159,24 +157,32 @@ # endif #endif #if WIDE_CHAR_VERSION - /* TCHAR_T is wchar_t. */ -# define USE_SNPRINTF 1 -# if HAVE_DECL__SNWPRINTF - /* On Windows, the function swprintf() has a different signature than - on Unix; we use the function _snwprintf() or - on mingw - snwprintf() - instead. The mingw function snwprintf() has fewer bugs than the - MSVCRT function _snwprintf(), so prefer that. */ -# if defined __MINGW32__ -# define SNPRINTF snwprintf + /* DCHAR_T is wchar_t. */ +# if HAVE_DECL__SNWPRINTF || (HAVE_SWPRINTF && HAVE_WORKING_SWPRINTF) +# define TCHAR_T wchar_t +# define DCHAR_IS_TCHAR 1 +# define USE_SNPRINTF 1 +# if HAVE_DECL__SNWPRINTF + /* On Windows, the function swprintf() has a different signature than + on Unix; we use the function _snwprintf() or - on mingw - snwprintf() + instead. The mingw function snwprintf() has fewer bugs than the + MSVCRT function _snwprintf(), so prefer that. */ +# if defined __MINGW32__ +# define SNPRINTF snwprintf +# else +# define SNPRINTF _snwprintf +# define USE_MSVC__SNPRINTF 1 +# endif # else -# define SNPRINTF _snwprintf -# define USE_MSVC__SNPRINTF 1 + /* Unix. */ +# define SNPRINTF swprintf # endif # else - /* Unix. */ -# define SNPRINTF swprintf + /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00, IRIX 6.5. */ +# define TCHAR_T char # endif -#else +#endif +#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR /* TCHAR_T is char. */ /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. But don't use it on BeOS, since BeOS snprintf produces no output if the @@ -241,7 +247,7 @@ local_strnlen (const char *string, size_t maxlen) # endif #endif -#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T +#if (((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T # if HAVE_WCSLEN # define local_wcslen wcslen # else @@ -264,8 +270,8 @@ local_wcslen (const wchar_t *s) # endif #endif -#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION -# if HAVE_WCSNLEN +#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION +# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN # define local_wcsnlen wcsnlen # else # ifndef local_wcsnlen_defined @@ -283,7 +289,7 @@ local_wcsnlen (const wchar_t *s, size_t maxlen) # endif #endif -#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || (ENABLE_WCHAR_FALLBACK && HAVE_WINT_T)) && !WIDE_CHAR_VERSION +#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T)) && !WIDE_CHAR_VERSION # if ENABLE_WCHAR_FALLBACK static size_t wctomb_fallback (char *s, wchar_t wc) @@ -351,7 +357,7 @@ local_wctomb (char *s, wchar_t wc) # endif #endif -#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) /* Determine the decimal-point character according to the current locale. */ # ifndef decimal_point_char_defined # define decimal_point_char_defined 1 @@ -378,7 +384,7 @@ decimal_point_char (void) # endif #endif -#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL +#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE /* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ static int @@ -389,7 +395,7 @@ is_infinite_or_zero (double x) #endif -#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL +#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE /* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ static int @@ -400,7 +406,7 @@ is_infinite_or_zerol (long double x) #endif -#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE /* Converting 'long double' to decimal without rare rounding bugs requires real bignums. We use the naming conventions of GNU gmp, but vastly simpler @@ -1604,7 +1610,7 @@ is_borderline (const char *digits, size_t precision) #endif -#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF +#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF /* Use a different function name, to make it possible that the 'wchar_t' parametrization and the 'char' parametrization get compiled in the same @@ -1627,24 +1633,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, switch (conversion) { case 'd': case 'i': case 'u': - if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long long) * CHAR_BIT - * 0.30103 /* binary -> decimal */ - ) - + 1; /* turn floor into ceil */ - else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long) * CHAR_BIT - * 0.30103 /* binary -> decimal */ - ) - + 1; /* turn floor into ceil */ - else - tmp_length = - (unsigned int) (sizeof (unsigned int) * CHAR_BIT - * 0.30103 /* binary -> decimal */ - ) - + 1; /* turn floor into ceil */ + switch (type) + { + default: + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_LONGINT: + tmp_length = + (unsigned int) (sizeof (long int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_LONGLONGINT: + tmp_length = + (unsigned int) (sizeof (long long int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGLONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT8_T: + tmp_length = + (unsigned int) (sizeof (int8_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT8_T: + tmp_length = + (unsigned int) (sizeof (uint8_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT16_T: + tmp_length = + (unsigned int) (sizeof (int16_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT16_T: + tmp_length = + (unsigned int) (sizeof (uint16_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT32_T: + tmp_length = + (unsigned int) (sizeof (int32_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT32_T: + tmp_length = + (unsigned int) (sizeof (uint32_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT64_T: + tmp_length = + (unsigned int) (sizeof (int64_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT64_T: + tmp_length = + (unsigned int) (sizeof (uint64_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (int_fast8_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (int_fast16_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (int_fast32_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_INT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (int_fast64_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + ) + + 1; /* turn floor into ceil */ + break; + } if (tmp_length < precision) tmp_length = precision; /* Multiply by 2, as an estimate for FLAG_GROUP. */ @@ -1653,25 +1791,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, tmp_length = xsum (tmp_length, 1); break; + case 'b': + #if SUPPORT_GNU_PRINTF_DIRECTIVES \ + || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2) + case 'B': + #endif + switch (type) + { + default: + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGLONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT8_T: + tmp_length = + (unsigned int) (sizeof (uint8_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT16_T: + tmp_length = + (unsigned int) (sizeof (uint16_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT32_T: + tmp_length = + (unsigned int) (sizeof (uint32_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT64_T: + tmp_length = + (unsigned int) (sizeof (uint64_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + } + if (tmp_length < precision) + tmp_length = precision; + /* Add 2, to account for a prefix from the alternate form. */ + tmp_length = xsum (tmp_length, 2); + break; + case 'o': - if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long long) * CHAR_BIT - * 0.333334 /* binary -> octal */ - ) - + 1; /* turn floor into ceil */ - else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long) * CHAR_BIT - * 0.333334 /* binary -> octal */ - ) - + 1; /* turn floor into ceil */ - else - tmp_length = - (unsigned int) (sizeof (unsigned int) * CHAR_BIT - * 0.333334 /* binary -> octal */ - ) - + 1; /* turn floor into ceil */ + switch (type) + { + default: + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long int) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGLONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT8_T: + tmp_length = + (unsigned int) (sizeof (uint8_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT16_T: + tmp_length = + (unsigned int) (sizeof (uint16_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT32_T: + tmp_length = + (unsigned int) (sizeof (uint32_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT64_T: + tmp_length = + (unsigned int) (sizeof (uint64_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1; /* turn floor into ceil */ + break; + } if (tmp_length < precision) tmp_length = precision; /* Add 1, to account for a leading sign. */ @@ -1679,27 +1948,89 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, break; case 'x': case 'X': - if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long long) * CHAR_BIT - * 0.25 /* binary -> hexadecimal */ - ) - + 1; /* turn floor into ceil */ - else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) - tmp_length = - (unsigned int) (sizeof (unsigned long) * CHAR_BIT - * 0.25 /* binary -> hexadecimal */ - ) - + 1; /* turn floor into ceil */ - else - tmp_length = - (unsigned int) (sizeof (unsigned int) * CHAR_BIT - * 0.25 /* binary -> hexadecimal */ - ) - + 1; /* turn floor into ceil */ + switch (type) + { + default: + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long int) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGLONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT8_T: + tmp_length = + (unsigned int) (sizeof (uint8_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT16_T: + tmp_length = + (unsigned int) (sizeof (uint16_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT32_T: + tmp_length = + (unsigned int) (sizeof (uint32_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT64_T: + tmp_length = + (unsigned int) (sizeof (uint64_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + break; + } if (tmp_length < precision) tmp_length = precision; - /* Add 2, to account for a leading sign or alternate form. */ + /* Add 2, to account for a prefix from the alternate form. */ tmp_length = xsum (tmp_length, 2); break; @@ -2005,6 +2336,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, case TYPE_COUNT_LONGLONGINT_POINTER: *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; break; + case TYPE_COUNT_INT8_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int8_t_pointer = length; + break; + case TYPE_COUNT_INT16_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int16_t_pointer = length; + break; + case TYPE_COUNT_INT32_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int32_t_pointer = length; + break; + case TYPE_COUNT_INT64_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int64_t_pointer = length; + break; + case TYPE_COUNT_INT_FAST8_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int_fast8_t_pointer = length; + break; + case TYPE_COUNT_INT_FAST16_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int_fast16_t_pointer = length; + break; + case TYPE_COUNT_INT_FAST32_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int_fast32_t_pointer = length; + break; + case TYPE_COUNT_INT_FAST64_T_POINTER: + *a.arg[dp->arg_index].a.a_count_int_fast64_t_pointer = length; + break; default: abort (); } @@ -2394,7 +2749,150 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } #endif -#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T +#if WIDE_CHAR_VERSION && !DCHAR_IS_TCHAR + else if ((dp->conversion == 's' + && a.arg[dp->arg_index].type == TYPE_WIDE_STRING) + || (dp->conversion == 'c' + && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)) + { + /* %ls or %lc in vasnwprintf. See the specification of + fwprintf. */ + /* It would be silly to use snprintf ("%ls", ...) and then + convert back the result from a char[] to a wchar_t[]. + Instead, just copy the argument wchar_t[] to the result. */ + int flags = dp->flags; + size_t width; + + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = arg; + if (arg < 0) + { + /* "A negative field width is taken as a '-' flag + followed by a positive field width." */ + flags |= FLAG_LEFT; + width = -width; + } + } + else + { + const FCHAR_T *digitp = dp->width_start; + + do + width = xsum (xtimes (width, 10), *digitp++ - '0'); + while (digitp != dp->width_end); + } + } + + { + const wchar_t *ls_arg; + wchar_t lc_arg[1]; + size_t characters; + + if (dp->conversion == 's') + { + int has_precision; + size_t precision; + + has_precision = 0; + precision = 6; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + /* "A negative precision is taken as if the precision + were omitted." */ + if (arg >= 0) + { + precision = arg; + has_precision = 1; + } + } + else + { + const FCHAR_T *digitp = dp->precision_start + 1; + + precision = 0; + while (digitp != dp->precision_end) + precision = xsum (xtimes (precision, 10), *digitp++ - '0'); + has_precision = 1; + } + } + + ls_arg = a.arg[dp->arg_index].a.a_wide_string; + + if (has_precision) + { + /* Use only at most PRECISION wide characters, from + the left. */ + const wchar_t *ls_arg_end; + + ls_arg_end = ls_arg; + characters = 0; + for (; precision > 0; precision--) + { + if (*ls_arg_end == 0) + /* Found the terminating null wide character. */ + break; + ls_arg_end++; + characters++; + } + } + else + { + /* Use the entire string, and count the number of wide + characters. */ + characters = local_wcslen (ls_arg); + } + } + else /* dp->conversion == 'c' */ + { + lc_arg[0] = (wchar_t) a.arg[dp->arg_index].a.a_wide_char; + ls_arg = lc_arg; + characters = 1; + } + + { + size_t total = (characters < width ? width : characters); + ENSURE_ALLOCATION (xsum (length, total)); + + if (characters < width && !(flags & FLAG_LEFT)) + { + size_t n = width - characters; + DCHAR_SET (result + length, ' ', n); + length += n; + } + + if (characters > 0) + { + DCHAR_CPY (result + length, ls_arg, characters); + length += characters; + } + + if (characters < width && (flags & FLAG_LEFT)) + { + size_t n = width - characters; + DCHAR_SET (result + length, ' ', n); + length += n; + } + } + } + } +#endif +#if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T else if (dp->conversion == 's' # if WIDE_CHAR_VERSION && a.arg[dp->arg_index].type != TYPE_WIDE_STRING @@ -2602,10 +3100,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # else count = mbtowc (&wc, arg, arg_end - arg); # endif - if (count <= 0) - /* mbrtowc not consistent with mbrlen, or mbtowc - not consistent with mblen. */ + if (count == 0) + /* mbrtowc not consistent with strlen. */ abort (); + if (count < 0) + /* Invalid or incomplete multibyte character. */ + goto fail_with_EILSEQ; ENSURE_ALLOCATION (xsum (length, 1)); result[length++] = wc; arg += count; @@ -2847,12 +3347,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # endif } #endif -#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION +#if (NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION else if (dp->conversion == 'c' && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR) { /* Implement the 'lc' directive ourselves, in order to provide - the fallback that avoids EILSEQ. */ + a correct behaviour for the null wint_t argument and/or the + fallback that avoids EILSEQ. */ int flags = dp->flags; int has_width; size_t width; @@ -2918,8 +3419,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, count = local_wcrtomb (cbuf, arg, &state); if (count < 0) - /* Inconsistency. */ - abort (); + /* Cannot convert. */ + goto fail_with_EILSEQ; characters = count; } } @@ -3017,9 +3518,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # endif count = local_wcrtomb (cbuf, arg, &state); - if (count <= 0) - /* Inconsistency. */ - abort (); + if (count < 0) + /* Cannot convert. */ + goto fail_with_EILSEQ; ENSURE_ALLOCATION (xsum (length, count)); memcpy (result + length, cbuf, count); length += count; @@ -3043,14 +3544,399 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } #endif -#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL +#if NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION + else if (dp->conversion == 'c' + && a.arg[dp->arg_index].type != TYPE_WIDE_CHAR) + { + /* Implement the 'c' directive ourselves, in order to avoid + EILSEQ in the "C" locale. */ + int flags = dp->flags; + size_t width; + + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = arg; + if (arg < 0) + { + /* "A negative field width is taken as a '-' flag + followed by a positive field width." */ + flags |= FLAG_LEFT; + width = -width; + } + } + else + { + const FCHAR_T *digitp = dp->width_start; + + do + width = xsum (xtimes (width, 10), *digitp++ - '0'); + while (digitp != dp->width_end); + } + } + + /* %c in vasnwprintf. See the specification of fwprintf. */ + { + char arg = (char) a.arg[dp->arg_index].a.a_char; + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + int count = mbrtowc (&wc, &arg, 1, &state); + if (count < 0) + /* Invalid or incomplete multibyte character. */ + goto fail_with_EILSEQ; + + if (1 < width && !(flags & FLAG_LEFT)) + { + size_t n = width - 1; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + + ENSURE_ALLOCATION (xsum (length, 1)); + result[length++] = wc; + + if (1 < width && (flags & FLAG_LEFT)) + { + size_t n = width - 1; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + } + } +#endif +#if NEED_PRINTF_DIRECTIVE_B || NEED_PRINTF_DIRECTIVE_UPPERCASE_B + else if (0 +# if NEED_PRINTF_DIRECTIVE_B + || (dp->conversion == 'b') +# endif +# if NEED_PRINTF_DIRECTIVE_UPPERCASE_B + || (dp->conversion == 'B') +# endif + ) + { + arg_type type = a.arg[dp->arg_index].type; + int flags = dp->flags; + int has_width; + size_t width; + int has_precision; + size_t precision; + size_t tmp_length; + size_t count; + DCHAR_T tmpbuf[700]; + DCHAR_T *tmp; + DCHAR_T *tmp_end; + DCHAR_T *tmp_start; + DCHAR_T *pad_ptr; + DCHAR_T *p; + + has_width = 0; + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = arg; + if (arg < 0) + { + /* "A negative field width is taken as a '-' flag + followed by a positive field width." */ + flags |= FLAG_LEFT; + width = -width; + } + } + else + { + const FCHAR_T *digitp = dp->width_start; + + do + width = xsum (xtimes (width, 10), *digitp++ - '0'); + while (digitp != dp->width_end); + } + has_width = 1; + } + + has_precision = 0; + precision = 1; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + /* "A negative precision is taken as if the precision + were omitted." */ + if (arg >= 0) + { + precision = arg; + has_precision = 1; + } + } + else + { + const FCHAR_T *digitp = dp->precision_start + 1; + + precision = 0; + while (digitp != dp->precision_end) + precision = xsum (xtimes (precision, 10), *digitp++ - '0'); + has_precision = 1; + } + } + + /* Allocate a temporary buffer of sufficient size. */ + switch (type) + { + default: + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_ULONGLONGINT: + tmp_length = + (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT8_T: + tmp_length = + (unsigned int) (sizeof (uint8_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT16_T: + tmp_length = + (unsigned int) (sizeof (uint16_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT32_T: + tmp_length = + (unsigned int) (sizeof (uint32_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT64_T: + tmp_length = + (unsigned int) (sizeof (uint64_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST8_T: + tmp_length = + (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST16_T: + tmp_length = + (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST32_T: + tmp_length = + (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + case TYPE_UINT_FAST64_T: + tmp_length = + (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT) + + 1; /* turn floor into ceil */ + break; + } + if (tmp_length < precision) + tmp_length = precision; + /* Add 2, to account for a prefix from the alternate form. */ + tmp_length = xsum (tmp_length, 2); + + if (tmp_length < width) + tmp_length = width; + + if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T)) + tmp = tmpbuf; + else + { + size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T)); + + if (size_overflow_p (tmp_memsize)) + /* Overflow, would lead to out of memory. */ + goto out_of_memory; + tmp = (DCHAR_T *) malloc (tmp_memsize); + if (tmp == NULL) + /* Out of memory. */ + goto out_of_memory; + } + + tmp_end = tmp + tmp_length; + + unsigned long long arg; + switch (type) + { + case TYPE_UCHAR: + arg = a.arg[dp->arg_index].a.a_uchar; + break; + case TYPE_USHORT: + arg = a.arg[dp->arg_index].a.a_ushort; + break; + case TYPE_UINT: + arg = a.arg[dp->arg_index].a.a_uint; + break; + case TYPE_ULONGINT: + arg = a.arg[dp->arg_index].a.a_ulongint; + break; + case TYPE_ULONGLONGINT: + arg = a.arg[dp->arg_index].a.a_ulonglongint; + break; + case TYPE_UINT8_T: + arg = a.arg[dp->arg_index].a.a_uint8_t; + break; + case TYPE_UINT16_T: + arg = a.arg[dp->arg_index].a.a_uint16_t; + break; + case TYPE_UINT32_T: + arg = a.arg[dp->arg_index].a.a_uint32_t; + break; + case TYPE_UINT64_T: + arg = a.arg[dp->arg_index].a.a_uint64_t; + break; + case TYPE_UINT_FAST8_T: + arg = a.arg[dp->arg_index].a.a_uint_fast8_t; + break; + case TYPE_UINT_FAST16_T: + arg = a.arg[dp->arg_index].a.a_uint_fast16_t; + break; + case TYPE_UINT_FAST32_T: + arg = a.arg[dp->arg_index].a.a_uint_fast32_t; + break; + case TYPE_UINT_FAST64_T: + arg = a.arg[dp->arg_index].a.a_uint_fast64_t; + break; + default: + abort (); + } + int need_prefix = ((flags & FLAG_ALT) && arg != 0); + + p = tmp_end; + /* "The result of converting a zero value with a precision + of zero is no characters." */ + if (!(has_precision && precision == 0 && arg == 0)) + { + do + { + *--p = '0' + (arg & 1); + arg = arg >> 1; + } + while (arg != 0); + } + + if (has_precision) + { + DCHAR_T *digits_start = tmp_end - precision; + while (p > digits_start) + *--p = '0'; + } + + pad_ptr = p; + + if (need_prefix) + { +# if NEED_PRINTF_DIRECTIVE_B && !NEED_PRINTF_DIRECTIVE_UPPERCASE_B + *--p = 'b'; +# elif NEED_PRINTF_DIRECTIVE_UPPERCASE_B && !NEED_PRINTF_DIRECTIVE_B + *--p = 'B'; +# else + *--p = dp->conversion; +# endif + *--p = '0'; + } + tmp_start = p; + + /* The generated string now extends from tmp_start to tmp_end, + with the zero padding insertion point being at pad_ptr, + tmp_start <= pad_ptr <= tmp_end. */ + count = tmp_end - tmp_start; + + if (count < width) + { + size_t pad = width - count; + + if (flags & FLAG_LEFT) + { + /* Pad with spaces on the right. */ + for (p = tmp_start; p < tmp_end; p++) + *(p - pad) = *p; + for (p = tmp_end - pad; p < tmp_end; p++) + *p = ' '; + } + else if ((flags & FLAG_ZERO) + /* Neither ISO C nor POSIX specify that the '0' + flag is ignored when a width and a precision + are both present. But most implementations + do so. */ + && !(has_width && has_precision)) + { + /* Pad with zeroes. */ + for (p = tmp_start; p < pad_ptr; p++) + *(p - pad) = *p; + for (p = pad_ptr - pad; p < pad_ptr; p++) + *p = '0'; + } + else + { + /* Pad with spaces on the left. */ + for (p = tmp_start - pad; p < tmp_start; p++) + *p = ' '; + } + + tmp_start = tmp_start - pad; + } + + count = tmp_end - tmp_start; + + if (count > tmp_length) + /* tmp_length was incorrectly calculated - fix the + code above! */ + abort (); + + /* Make room for the result. */ + if (count >= allocated - length) + { + size_t n = xsum (length, count); + + ENSURE_ALLOCATION (n); + } + + /* Append the result. */ + memcpy (result + length, tmp_start, count * sizeof (DCHAR_T)); + if (tmp != tmpbuf) + free (tmp); + length += count; + } +#endif +#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) else if ((dp->conversion == 'a' || dp->conversion == 'A') # if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) && (0 # if NEED_PRINTF_DOUBLE || a.arg[dp->arg_index].type == TYPE_DOUBLE # endif -# if NEED_PRINTF_LONG_DOUBLE +# if NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE # endif ) @@ -3170,7 +4056,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, p = tmp; if (type == TYPE_LONGDOUBLE) { -# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE +# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) long double arg = a.arg[dp->arg_index].a.a_longdouble; if (isnanl (arg)) @@ -3290,7 +4176,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } *p++ = dp->conversion - 'A' + 'P'; -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = { '%', '+', 'd', '\0' }; @@ -3441,7 +4327,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } *p++ = dp->conversion - 'A' + 'P'; -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = { '%', '+', 'd', '\0' }; @@ -3533,7 +4419,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, length += count; } #endif -#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +#if NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE else if ((dp->conversion == 'f' || dp->conversion == 'F' || dp->conversion == 'e' || dp->conversion == 'E' || dp->conversion == 'g' || dp->conversion == 'G' @@ -3901,7 +4787,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } *p++ = dp->conversion; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = { '%', '+', '.', '2', 'd', '\0' }; @@ -4082,7 +4968,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = { '%', '+', '.', '2', 'd', '\0' }; @@ -4359,7 +5245,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } *p++ = dp->conversion; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = /* Produce the same number of exponent digits @@ -4552,7 +5438,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR { static const wchar_t decimal_format[] = /* Produce the same number of exponent digits @@ -4720,13 +5606,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, { arg_type type = a.arg[dp->arg_index].type; int flags = dp->flags; -#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION int has_width; #endif -#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION size_t width; #endif -#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION int has_precision; size_t precision; #endif @@ -4735,7 +5621,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, #else # define prec_ourselves 0 #endif -#if NEED_PRINTF_FLAG_LEFTADJUST +#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST # define pad_ourselves 1 #elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION int pad_ourselves; @@ -4752,10 +5638,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, TCHAR_T *tmp; #endif -#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION has_width = 0; #endif -#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION width = 0; if (dp->width_start != dp->width_end) { @@ -4783,13 +5669,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, width = xsum (xtimes (width, 10), *digitp++ - '0'); while (digitp != dp->width_end); } -#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION has_width = 1; -#endif +# endif } #endif -#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION +#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION has_precision = 0; precision = 6; if (dp->precision_start != dp->precision_end) @@ -4826,6 +5712,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, switch (dp->conversion) { case 'd': case 'i': case 'u': + case 'b': + #if SUPPORT_GNU_PRINTF_DIRECTIVES \ + || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2) + case 'B': + #endif case 'o': case 'x': case 'X': case 'p': prec_ourselves = has_precision && (precision > 0); @@ -4837,7 +5728,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, #endif /* Decide whether to perform the padding ourselves. */ -#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) +#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) switch (dp->conversion) { # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO @@ -4956,6 +5847,54 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, { case TYPE_LONGLONGINT: case TYPE_ULONGLONGINT: + #if INT8_WIDTH > LONG_WIDTH + case TYPE_INT8_T: + #endif + #if UINT8_WIDTH > LONG_WIDTH + case TYPE_UINT8_T: + #endif + #if INT16_WIDTH > LONG_WIDTH + case TYPE_INT16_T: + #endif + #if UINT16_WIDTH > LONG_WIDTH + case TYPE_UINT16_T: + #endif + #if INT32_WIDTH > LONG_WIDTH + case TYPE_INT32_T: + #endif + #if UINT32_WIDTH > LONG_WIDTH + case TYPE_UINT32_T: + #endif + #if INT64_WIDTH > LONG_WIDTH + case TYPE_INT64_T: + #endif + #if UINT64_WIDTH > LONG_WIDTH + case TYPE_UINT64_T: + #endif + #if INT_FAST8_WIDTH > LONG_WIDTH + case TYPE_INT_FAST8_T: + #endif + #if UINT_FAST8_WIDTH > LONG_WIDTH + case TYPE_UINT_FAST8_T: + #endif + #if INT_FAST16_WIDTH > LONG_WIDTH + case TYPE_INT_FAST16_T: + #endif + #if UINT_FAST16_WIDTH > LONG_WIDTH + case TYPE_UINT_FAST16_T: + #endif + #if INT_FAST32_WIDTH > LONG_WIDTH + case TYPE_INT3_FAST2_T: + #endif + #if UINT_FAST32_WIDTH > LONG_WIDTH + case TYPE_UINT_FAST32_T: + #endif + #if INT_FAST64_WIDTH > LONG_WIDTH + case TYPE_INT_FAST64_T: + #endif + #if UINT_FAST64_WIDTH > LONG_WIDTH + case TYPE_UINT_FAST64_T: + #endif #if defined _WIN32 && ! defined __CYGWIN__ *fbp++ = 'I'; *fbp++ = '6'; @@ -4967,12 +5906,60 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, FALLTHROUGH; case TYPE_LONGINT: case TYPE_ULONGINT: -#if HAVE_WINT_T + #if INT8_WIDTH > INT_WIDTH && INT8_WIDTH <= LONG_WIDTH + case TYPE_INT8_T: + #endif + #if UINT8_WIDTH > INT_WIDTH && UINT8_WIDTH <= LONG_WIDTH + case TYPE_UINT8_T: + #endif + #if INT16_WIDTH > INT_WIDTH && INT16_WIDTH <= LONG_WIDTH + case TYPE_INT16_T: + #endif + #if UINT16_WIDTH > INT_WIDTH && UINT16_WIDTH <= LONG_WIDTH + case TYPE_UINT16_T: + #endif + #if INT32_WIDTH > INT_WIDTH && INT32_WIDTH <= LONG_WIDTH + case TYPE_INT32_T: + #endif + #if UINT32_WIDTH > INT_WIDTH && UINT32_WIDTH <= LONG_WIDTH + case TYPE_UINT32_T: + #endif + #if INT64_WIDTH > INT_WIDTH && INT64_WIDTH <= LONG_WIDTH + case TYPE_INT64_T: + #endif + #if UINT64_WIDTH > INT_WIDTH && UINT64_WIDTH <= LONG_WIDTH + case TYPE_UINT64_T: + #endif + #if INT_FAST8_WIDTH > INT_WIDTH && INT_FAST8_WIDTH <= LONG_WIDTH + case TYPE_INT_FAST8_T: + #endif + #if UINT_FAST8_WIDTH > INT_WIDTH && UINT_FAST8_WIDTH <= LONG_WIDTH + case TYPE_UINT_FAST8_T: + #endif + #if INT_FAST16_WIDTH > INT_WIDTH && INT_FAST16_WIDTH <= LONG_WIDTH + case TYPE_INT_FAST16_T: + #endif + #if UINT_FAST16_WIDTH > INT_WIDTH && UINT_FAST16_WIDTH <= LONG_WIDTH + case TYPE_UINT_FAST16_T: + #endif + #if INT_FAST32_WIDTH > INT_WIDTH && INT_FAST32_WIDTH <= LONG_WIDTH + case TYPE_INT_FAST32_T: + #endif + #if UINT_FAST32_WIDTH > INT_WIDTH && UINT_FAST32_WIDTH <= LONG_WIDTH + case TYPE_UINT_FAST32_T: + #endif + #if INT_FAST64_WIDTH > INT_WIDTH && INT_FAST64_WIDTH <= LONG_WIDTH + case TYPE_INT_FAST64_T: + #endif + #if UINT_FAST64_WIDTH > INT_WIDTH && UINT_FAST64_WIDTH <= LONG_WIDTH + case TYPE_UINT_FAST64_T: + #endif + #if HAVE_WINT_T case TYPE_WIDE_CHAR: -#endif -#if HAVE_WCHAR_T + #endif + #if HAVE_WCHAR_T case TYPE_WIDE_STRING: -#endif + #endif *fbp++ = 'l'; break; case TYPE_LONGDOUBLE: @@ -4988,47 +5975,74 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, #endif *fbp = dp->conversion; #if USE_SNPRINTF -# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \ + /* Decide whether to pass %n in the format string + to SNPRINTF. */ +# if (((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) \ + && (HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99)) \ || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \ && !defined __UCLIBC__) \ || (defined __APPLE__ && defined __MACH__) \ + || defined __OpenBSD__ \ || defined __ANDROID__ \ - || (defined _WIN32 && ! defined __CYGWIN__)) - /* On systems where we know that snprintf's return value - conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that - snprintf always produces NUL-terminated strings - (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid - using %n. And it is desirable to do so, because more and - more platforms no longer support %n, for "security reasons". - In particular, the following platforms: + || (defined _WIN32 && ! defined __CYGWIN__)) \ + || (WIDE_CHAR_VERSION && MUSL_LIBC) + /* We can avoid passing %n and instead rely on SNPRINTF's + return value if + - !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR, because otherwise, + when WIDE_CHAR_VERSION && DCHAR_IS_TCHAR, + snwprintf()/_snwprintf() (Windows) and swprintf() (Unix) + don't return the needed buffer size, + and + - we're compiling for a system where we know + - that snprintf's return value conforms to ISO C 99 + (HAVE_SNPRINTF_RETVAL_C99) and + - that snprintf always produces NUL-terminated strings + (HAVE_SNPRINTF_TRUNCATION_C99). + And it is desirable to do so, because more and more platforms + no longer support %n, for "security reasons". */ + /* On specific platforms, listed below, we *must* avoid %n. + In the case + !WIDE_CHAR_VERSION && HAVE_SNPRINTF_RETVAL_C99 && !USE_MSVC__SNPRINTF + we can rely on the return value of snprintf instead. Whereas + in the opposite case + WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF + we need to make room based on an estimation, computed by + MAX_ROOM_NEEDED. */ + /* The following platforms forbid %n: - On glibc2 systems from 2004-10-18 or newer, the use of %n in format strings in writable memory may crash the program (if compiled with _FORTIFY_SOURCE=2). - - On Mac OS X 10.13 or newer, the use of %n in format + - On macOS 10.13 or newer, the use of %n in format strings in writable memory by default crashes the program. + - On OpenBSD, since 2021-08-30, the use of %n in format + strings produces an abort (see + <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfprintf.c.diff?r1=1.79&r2=1.80&f=h>, + <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfwprintf.c.diff?r1=1.20&r2=1.21&f=h>). - On Android, starting on 2018-03-07, the use of %n in format strings produces a fatal error (see <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>). - On these platforms, HAVE_SNPRINTF_RETVAL_C99 and - HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them - explicitly in the condition above, in case of cross- - compilation (just to be sure). */ - /* On native Windows systems (such as mingw), we can avoid using - %n because: + - On native Windows systems (such as mingw) where the OS is + Windows Vista, the use of %n in format strings by default + crashes the program. See + <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and + <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output> + On the first four of these platforms, if !WIDE_CHAR_VERSION, + it is not a big deal to avoid %n, because on these platforms, + HAVE_SNPRINTF_RETVAL_C99 and HAVE_SNPRINTF_TRUNCATION_C99 are + 1. + On native Windows, if !WIDE_CHAR_VERSION, it's not a big deal + either because: - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, snprintf does not write more than the specified number of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes '4', '5', '6' into buf, not '4', '5', '\0'.) - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf allows us to recognize the case of an insufficient - buffer size: it returns -1 in this case. - On native Windows systems (such as mingw) where the OS is - Windows Vista, the use of %n in format strings by default - crashes the program. See - <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and - <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output> - So we should avoid %n in this situation. */ + buffer size: it returns -1 in this case. */ + /* Additionally, in the WIDE_CHAR_VERSION case, we cannot use %n + on musl libc because we would run into an swprintf() bug. + See <https://www.openwall.com/lists/musl/2023/03/19/1>. */ fbp[1] = '\0'; # else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */ fbp[1] = '%'; @@ -5189,6 +6203,102 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, SNPRINTF_BUF (arg); } break; + case TYPE_INT8_T: + { + int8_t arg = a.arg[dp->arg_index].a.a_int8_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT8_T: + { + uint8_t arg = a.arg[dp->arg_index].a.a_uint8_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT16_T: + { + int16_t arg = a.arg[dp->arg_index].a.a_int16_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT16_T: + { + uint16_t arg = a.arg[dp->arg_index].a.a_uint16_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT32_T: + { + int32_t arg = a.arg[dp->arg_index].a.a_int32_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT32_T: + { + uint32_t arg = a.arg[dp->arg_index].a.a_uint32_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT64_T: + { + int64_t arg = a.arg[dp->arg_index].a.a_int64_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT64_T: + { + uint64_t arg = a.arg[dp->arg_index].a.a_uint64_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT_FAST8_T: + { + int_fast8_t arg = a.arg[dp->arg_index].a.a_int_fast8_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT_FAST8_T: + { + uint_fast8_t arg = a.arg[dp->arg_index].a.a_uint_fast8_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT_FAST16_T: + { + int_fast16_t arg = a.arg[dp->arg_index].a.a_int_fast16_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT_FAST16_T: + { + uint_fast16_t arg = a.arg[dp->arg_index].a.a_uint_fast16_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT_FAST32_T: + { + int_fast32_t arg = a.arg[dp->arg_index].a.a_int_fast32_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT_FAST32_T: + { + uint_fast32_t arg = a.arg[dp->arg_index].a.a_uint_fast32_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT_FAST64_T: + { + int_fast64_t arg = a.arg[dp->arg_index].a.a_int_fast64_t; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT_FAST64_T: + { + uint_fast64_t arg = a.arg[dp->arg_index].a.a_uint_fast64_t; + SNPRINTF_BUF (arg); + } + break; case TYPE_DOUBLE: { double arg = a.arg[dp->arg_index].a.a_double; @@ -5271,12 +6381,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, /* Look at the snprintf() return value. */ if (retcount < 0) { -# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF +# if (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF /* HP-UX 10.20 snprintf() is doubly deficient: It doesn't understand the '%n' directive, *and* it returns -1 (rather than the length that would have been required) when the buffer is too small. + Likewise, in case of + WIDE_CHAR_VERSION && DCHAR_IS_TCHAR, the + functions snwprintf()/_snwprintf() (Windows) + or swprintf() (Unix). But a failure at this point can also come from other reasons than a too small buffer, such as an invalid wide string argument to @@ -5312,7 +6426,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # endif } else - count = retcount; + { + count = retcount; +# if WIDE_CHAR_VERSION && defined __MINGW32__ + if (count == 0 && dp->conversion == 'c') + /* snwprintf returned 0 instead of 1. But it + wrote a null wide character. */ + count = 1; +# endif + } } } #endif @@ -5442,11 +6564,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, #if !DCHAR_IS_TCHAR /* Convert from TCHAR_T[] to DCHAR_T[]. */ - if (dp->conversion == 'c' || dp->conversion == 's') + if (dp->conversion == 'c' || dp->conversion == 's' +# if __GLIBC__ >= 2 && !defined __UCLIBC__ + || (flags & FLAG_LOCALIZED) +# endif + ) { - /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING - TYPE_WIDE_STRING. - The result string is not certainly ASCII. */ + /* The result string is not guaranteed to be ASCII. */ const TCHAR_T *tmpsrc; DCHAR_T *tmpdst; size_t tmpdst_len; @@ -5457,6 +6581,56 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # else tmpsrc = tmp; # endif +# if WIDE_CHAR_VERSION + /* Convert tmpsrc[0..count-1] to a freshly allocated + wide character array. */ + mbstate_t state; + + memset (&state, '\0', sizeof (mbstate_t)); + tmpdst_len = 0; + { + const TCHAR_T *src = tmpsrc; + size_t srclen = count; + + for (; srclen > 0; tmpdst_len++) + { + /* Parse the next multibyte character. */ + size_t ret = mbrtowc (NULL, src, srclen, &state); + if (ret == (size_t)(-2) || ret == (size_t)(-1)) + goto fail_with_EILSEQ; + if (ret == 0) + ret = 1; + src += ret; + srclen -= ret; + } + } + + tmpdst = + (wchar_t *) malloc ((tmpdst_len + 1) * sizeof (wchar_t)); + if (tmpdst == NULL) + goto out_of_memory; + + memset (&state, '\0', sizeof (mbstate_t)); + { + DCHAR_T *destptr = tmpdst; + const TCHAR_T *src = tmpsrc; + size_t srclen = count; + + for (; srclen > 0; destptr++) + { + /* Parse the next multibyte character. */ + size_t ret = mbrtowc (destptr, src, srclen, &state); + if (ret == (size_t)(-2) || ret == (size_t)(-1)) + /* Should already have been caught in the first + loop, above. */ + abort (); + if (ret == 0) + ret = 1; + src += ret; + srclen -= ret; + } + } +# else tmpdst = DCHAR_CONV_FROM_ENCODING (locale_charset (), iconveh_question_mark, @@ -5465,6 +6639,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, NULL, &tmpdst_len); if (tmpdst == NULL) goto fail_with_errno; +# endif ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), { free (tmpdst); goto out_of_memory; }); DCHAR_CPY (result + length, tmpdst, tmpdst_len); @@ -5531,7 +6706,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, /* Here count <= allocated - length. */ /* Perform padding. */ -#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION if (pad_ourselves && has_width) { size_t w; @@ -5590,6 +6765,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) pad_ptr = NULL; + else + /* Do the zero-padding after the "0x" or + "0b" prefix, not before. */ + if (p - rp >= 2 + && *rp == '0' + && (((dp->conversion == 'a' + || dp->conversion == 'x') + && rp[1] == 'x') + || ((dp->conversion == 'A' + || dp->conversion == 'X') + && rp[1] == 'X') + || (dp->conversion == 'b' + && rp[1] == 'b') + || (dp->conversion == 'B' + && rp[1] == 'B'))) + pad_ptr += 2; } /* The generated string now extends from rp to p, with the zero padding insertion point being at @@ -5603,7 +6794,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, for (; pad > 0; pad--) *p++ = ' '; } - else if ((flags & FLAG_ZERO) && pad_ptr != NULL) + else if ((flags & FLAG_ZERO) && pad_ptr != NULL + /* ISO C says: "For d, i, o, u, x, and X + conversions, if a precision is + specified, the 0 flag is ignored. */ + && !(has_precision + && (dp->conversion == 'd' + || dp->conversion == 'i' + || dp->conversion == 'o' + || dp->conversion == 'u' + || dp->conversion == 'x' + || dp->conversion == 'X' + /* Although ISO C does not + require it, treat 'b' and 'B' + like 'x' and 'X'. */ + || dp->conversion == 'b' + || dp->conversion == 'B'))) { /* Pad with zeroes. */ DCHAR_T *q = end; @@ -5697,7 +6903,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, errno = ENOMEM; goto fail_with_errno; -#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) +#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION) fail_with_EILSEQ: errno = EILSEQ; goto fail_with_errno; diff --git a/lib/vasnprintf.h b/lib/vasnprintf.h index f69649fb457..2d134070796 100644 --- a/lib/vasnprintf.h +++ b/lib/vasnprintf.h @@ -17,6 +17,11 @@ #ifndef _VASNPRINTF_H #define _VASNPRINTF_H +/* This file uses _GL_ATTRIBUTE_FORMAT. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + /* Get va_list. */ #include <stdarg.h> diff --git a/lib/xsize.h b/lib/xsize.h index 1ec78e776fc..5b08d61f2f7 100644 --- a/lib/xsize.h +++ b/lib/xsize.h @@ -18,6 +18,11 @@ #ifndef _XSIZE_H #define _XSIZE_H +/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, HAVE_STDINT_H. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + /* Get size_t. */ #include <stddef.h> @@ -30,9 +35,6 @@ /* Get ATTRIBUTE_PURE. */ #include "attribute.h" -#ifndef _GL_INLINE_HEADER_BEGIN - #error "Please include config.h first." -#endif _GL_INLINE_HEADER_BEGIN #ifndef XSIZE_INLINE # define XSIZE_INLINE _GL_INLINE |