Home | History | Annotate | Line # | Download | only in libntp
      1 /*	$NetBSD: snprintf.c,v 1.7 2024/08/18 20:47:13 christos Exp $	*/
      2 
      3 /*
      4  * Modified by Dave Hart for integration into NTP 4.2.7 <hart (at) ntp.org>
      5  *
      6  * Changed in a backwards-incompatible way to separate HAVE_SNPRINTF
      7  * from HW_WANT_RPL_SNPRINTF, etc. for each of the four replaced
      8  * functions.
      9  *
     10  * Changed to honor hw_force_rpl_snprintf=yes, etc.  This is used by NTP
     11  * to test rpl_snprintf() and rpl_vsnprintf() on platforms which provide
     12  * C99-compliant implementations.
     13  */
     14 
     15 /* Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp  */
     16 
     17 /*
     18  * Copyright (c) 1995 Patrick Powell.
     19  *
     20  * This code is based on code written by Patrick Powell <papowell (at) astart.com>.
     21  * It may be used for any purpose as long as this notice remains intact on all
     22  * source code distributions.
     23  */
     24 
     25 /*
     26  * Copyright (c) 2008 Holger Weiss.
     27  *
     28  * This version of the code is maintained by Holger Weiss <holger (at) jhweiss.de>.
     29  * My changes to the code may freely be used, modified and/or redistributed for
     30  * any purpose.  It would be nice if additions and fixes to this file (including
     31  * trivial code cleanups) would be sent back in order to let me include them in
     32  * the version available at <http://www.jhweiss.de/software/snprintf.html>.
     33  * However, this is not a requirement for using or redistributing (possibly
     34  * modified) versions of this file, nor is leaving this notice intact mandatory.
     35  */
     36 
     37 /*
     38  * History
     39  *
     40  * 2008-01-20 Holger Weiss <holger (at) jhweiss.de> for C99-snprintf 1.1:
     41  *
     42  * 	Fixed the detection of infinite floating point values on IRIX (and
     43  * 	possibly other systems) and applied another few minor cleanups.
     44  *
     45  * 2008-01-06 Holger Weiss <holger (at) jhweiss.de> for C99-snprintf 1.0:
     46  *
     47  * 	Added a lot of new features, fixed many bugs, and incorporated various
     48  * 	improvements done by Andrew Tridgell <tridge (at) samba.org>, Russ Allbery
     49  * 	<rra (at) stanford.edu>, Hrvoje Niksic <hniksic (at) xemacs.org>, Damien Miller
     50  * 	<djm (at) mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
     51  * 	projects.  The additions include: support the "e", "E", "g", "G", and
     52  * 	"F" conversion specifiers (and use conversion style "f" or "F" for the
     53  * 	still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
     54  * 	"t", and "z" length modifiers; support the "#" flag and the (non-C99)
     55  * 	"'" flag; use localeconv(3) (if available) to get both the current
     56  * 	locale's decimal point character and the separator between groups of
     57  * 	digits; fix the handling of various corner cases of field width and
     58  * 	precision specifications; fix various floating point conversion bugs;
     59  * 	handle infinite and NaN floating point values; don't attempt to write to
     60  * 	the output buffer (which may be NULL) if a size of zero was specified;
     61  * 	check for integer overflow of the field width, precision, and return
     62  * 	values and during the floating point conversion; use the OUTCHAR() macro
     63  * 	instead of a function for better performance; provide asprintf(3) and
     64  * 	vasprintf(3) functions; add new test cases.  The replacement functions
     65  * 	have been renamed to use an "rpl_" prefix, the function calls in the
     66  * 	main project (and in this file) must be redefined accordingly for each
     67  * 	replacement function which is needed (by using Autoconf or other means).
     68  * 	Various other minor improvements have been applied and the coding style
     69  * 	was cleaned up for consistency.
     70  *
     71  * 2007-07-23 Holger Weiss <holger (at) jhweiss.de> for Mutt 1.5.13:
     72  *
     73  * 	C99 compliant snprintf(3) and vsnprintf(3) functions return the number
     74  * 	of characters that would have been written to a sufficiently sized
     75  * 	buffer (excluding the '\0').  The original code simply returned the
     76  * 	length of the resulting output string, so that's been fixed.
     77  *
     78  * 1998-03-05 Michael Elkins <me (at) mutt.org> for Mutt 0.90.8:
     79  *
     80  * 	The original code assumed that both snprintf(3) and vsnprintf(3) were
     81  * 	missing.  Some systems only have snprintf(3) but not vsnprintf(3), so
     82  * 	the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
     83  *
     84  * 1998-01-27 Thomas Roessler <roessler (at) does-not-exist.org> for Mutt 0.89i:
     85  *
     86  * 	The PGP code was using unsigned hexadecimal formats.  Unfortunately,
     87  * 	unsigned formats simply didn't work.
     88  *
     89  * 1997-10-22 Brandon Long <blong (at) fiction.net> for Mutt 0.87.1:
     90  *
     91  * 	Ok, added some minimal floating point support, which means this probably
     92  * 	requires libm on most operating systems.  Don't yet support the exponent
     93  * 	(e,E) and sigfig (g,G).  Also, fmtint() was pretty badly broken, it just
     94  * 	wasn't being exercised in ways which showed it, so that's been fixed.
     95  * 	Also, formatted the code to Mutt conventions, and removed dead code left
     96  * 	over from the original.  Also, there is now a builtin-test, run with:
     97  * 	gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
     98  *
     99  * 2996-09-15 Brandon Long <blong (at) fiction.net> for Mutt 0.43:
    100  *
    101  * 	This was ugly.  It is still ugly.  I opted out of floating point
    102  * 	numbers, but the formatter understands just about everything from the
    103  * 	normal C string format, at least as far as I can tell from the Solaris
    104  * 	2.5 printf(3S) man page.
    105  */
    106 
    107 /*
    108  * ToDo
    109  *
    110  * - Add wide character support.
    111  * - Add support for "%a" and "%A" conversions.
    112  * - Create test routines which predefine the expected results.  Our test cases
    113  *   usually expose bugs in system implementations rather than in ours :-)
    114  */
    115 
    116 /*
    117  * Usage
    118  *
    119  * 1) The following preprocessor macros should be defined to 1 if the feature or
    120  *    file in question is available on the target system (by using Autoconf or
    121  *    other means), though basic functionality should be available as long as
    122  *    HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly:
    123  *
    124  *	HW_WANT_RPL_VSNPRINTF
    125  *	HW_WANT_RPL_SNPRINTF
    126  *	HW_WANT_RPL_VASPRINTF
    127  *	HW_WANT_RPL_ASPRINTF
    128  *	HAVE_VSNPRINTF	// define to 1 #if HW_WANT_RPL_VSNPRINTF
    129  *	HAVE_SNPRINTF	// define to 1 #if HW_WANT_RPL_SNPRINTF
    130  *	HAVE_VASPRINTF	// define to 1 #if HW_WANT_RPL_VASPRINTF
    131  *	HAVE_ASPRINTF	// define to 1 #if HW_WANT_RPL_ASPRINTF
    132  *	HAVE_STDARG_H
    133  *	HAVE_STDDEF_H
    134  *	HAVE_STDINT_H
    135  *	HAVE_STDLIB_H
    136  *	HAVE_INTTYPES_H
    137  *	HAVE_LOCALE_H
    138  *	HAVE_LOCALECONV
    139  *	HAVE_LCONV_DECIMAL_POINT
    140  *	HAVE_LCONV_THOUSANDS_SEP
    141  *	HAVE_LONG_DOUBLE
    142  *	HAVE_LONG_LONG_INT
    143  *	HAVE_UNSIGNED_LONG_LONG_INT
    144  *	HAVE_INTMAX_T
    145  *	HAVE_UINTMAX_T
    146  *	HAVE_UINTPTR_T
    147  *	HAVE_PTRDIFF_T
    148  *	HAVE_VA_COPY
    149  *	HAVE___VA_COPY
    150  *
    151  * 2) The calls to the functions which should be replaced must be redefined
    152  *    throughout the project files (by using Autoconf or other means):
    153  *
    154  *	#if HW_WANT_RPL_VSNPRINTF
    155  *	#define vsnprintf rpl_vsnprintf
    156  *	#endif
    157  *	#if HW_WANT_RPL_SNPRINTF
    158  *	#define snprintf rpl_snprintf
    159  *	#endif
    160  *	#if HW_WANT_RPL_VASPRINTF
    161  *	#define vasprintf rpl_vasprintf
    162  *	#endif
    163  *	#if HW_WANT_RPL_ASPRINTF
    164  *	#define asprintf rpl_asprintf
    165  *	#endif
    166  *
    167  * 3) The required replacement functions should be declared in some header file
    168  *    included throughout the project files:
    169  *
    170  *	#if HAVE_CONFIG_H
    171  *	#include <config.h>
    172  *	#endif
    173  *	#if HAVE_STDARG_H
    174  *	#include <stdarg.h>
    175  *	#if HW_WANT_RPL_VSNPRINTF
    176  *	int rpl_vsnprintf(char *, size_t, const char *, va_list);
    177  *	#endif
    178  *	#if HW_WANT_RPL_SNPRINTF
    179  *	int rpl_snprintf(char *, size_t, const char *, ...);
    180  *	#endif
    181  *	#if HW_WANT_RPL_VASPRINTF
    182  *	int rpl_vasprintf(char **, const char *, va_list);
    183  *	#endif
    184  *	#if HW_WANT_RPL_ASPRINTF
    185  *	int rpl_asprintf(char **, const char *, ...);
    186  *	#endif
    187  *	#endif
    188  *
    189  * Autoconf macros for handling step 1 and step 2 are available at
    190  * <http://www.jhweiss.de/software/snprintf.html>.
    191  */
    192 
    193 #if HAVE_CONFIG_H
    194 #include <config.h>
    195 #endif	/* HAVE_CONFIG_H */
    196 
    197 #if TEST_SNPRINTF
    198 #include <math.h>	/* For pow(3), NAN, and INFINITY. */
    199 #include <string.h>	/* For strcmp(3). */
    200 #if defined(__NetBSD__) || \
    201     defined(__FreeBSD__) || \
    202     defined(__OpenBSD__) || \
    203     defined(__NeXT__) || \
    204     defined(__bsd__)
    205 #define OS_BSD 1
    206 #elif defined(sgi) || defined(__sgi)
    207 #ifndef __c99
    208 #define __c99	/* Force C99 mode to get <stdint.h> included on IRIX 6.5.30. */
    209 #endif	/* !defined(__c99) */
    210 #define OS_IRIX 1
    211 #define OS_SYSV 1
    212 #elif defined(__svr4__)
    213 #define OS_SYSV 1
    214 #elif defined(__linux__)
    215 #define OS_LINUX 1
    216 #endif	/* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */
    217 #if HAVE_CONFIG_H	/* Undefine definitions possibly done in config.h. */
    218 #ifdef HAVE_SNPRINTF
    219 #undef HAVE_SNPRINTF
    220 #endif	/* defined(HAVE_SNPRINTF) */
    221 #ifdef HAVE_VSNPRINTF
    222 #undef HAVE_VSNPRINTF
    223 #endif	/* defined(HAVE_VSNPRINTF) */
    224 #ifdef HAVE_ASPRINTF
    225 #undef HAVE_ASPRINTF
    226 #endif	/* defined(HAVE_ASPRINTF) */
    227 #ifdef HAVE_VASPRINTF
    228 #undef HAVE_VASPRINTF
    229 #endif	/* defined(HAVE_VASPRINTF) */
    230 #ifdef snprintf
    231 #undef snprintf
    232 #endif	/* defined(snprintf) */
    233 #ifdef vsnprintf
    234 #undef vsnprintf
    235 #endif	/* defined(vsnprintf) */
    236 #ifdef asprintf
    237 #undef asprintf
    238 #endif	/* defined(asprintf) */
    239 #ifdef vasprintf
    240 #undef vasprintf
    241 #endif	/* defined(vasprintf) */
    242 #else	/* By default, we assume a modern system for testing. */
    243 #ifndef HAVE_STDARG_H
    244 #define HAVE_STDARG_H 1
    245 #endif	/* HAVE_STDARG_H */
    246 #ifndef HAVE_STDDEF_H
    247 #define HAVE_STDDEF_H 1
    248 #endif	/* HAVE_STDDEF_H */
    249 #ifndef HAVE_STDINT_H
    250 #define HAVE_STDINT_H 1
    251 #endif	/* HAVE_STDINT_H */
    252 #ifndef HAVE_STDLIB_H
    253 #define HAVE_STDLIB_H 1
    254 #endif	/* HAVE_STDLIB_H */
    255 #ifndef HAVE_INTTYPES_H
    256 #define HAVE_INTTYPES_H 1
    257 #endif	/* HAVE_INTTYPES_H */
    258 #ifndef HAVE_LOCALE_H
    259 #define HAVE_LOCALE_H 1
    260 #endif	/* HAVE_LOCALE_H */
    261 #ifndef HAVE_LOCALECONV
    262 #define HAVE_LOCALECONV 1
    263 #endif	/* !defined(HAVE_LOCALECONV) */
    264 #ifndef HAVE_LCONV_DECIMAL_POINT
    265 #define HAVE_LCONV_DECIMAL_POINT 1
    266 #endif	/* HAVE_LCONV_DECIMAL_POINT */
    267 #ifndef HAVE_LCONV_THOUSANDS_SEP
    268 #define HAVE_LCONV_THOUSANDS_SEP 1
    269 #endif	/* HAVE_LCONV_THOUSANDS_SEP */
    270 #ifndef HAVE_LONG_DOUBLE
    271 #define HAVE_LONG_DOUBLE 1
    272 #endif	/* !defined(HAVE_LONG_DOUBLE) */
    273 #ifndef HAVE_LONG_LONG_INT
    274 #define HAVE_LONG_LONG_INT 1
    275 #endif	/* !defined(HAVE_LONG_LONG_INT) */
    276 #ifndef HAVE_UNSIGNED_LONG_LONG_INT
    277 #define HAVE_UNSIGNED_LONG_LONG_INT 1
    278 #endif	/* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */
    279 #ifndef HAVE_INTMAX_T
    280 #define HAVE_INTMAX_T 1
    281 #endif	/* !defined(HAVE_INTMAX_T) */
    282 #ifndef HAVE_UINTMAX_T
    283 #define HAVE_UINTMAX_T 1
    284 #endif	/* !defined(HAVE_UINTMAX_T) */
    285 #ifndef HAVE_UINTPTR_T
    286 #define HAVE_UINTPTR_T 1
    287 #endif	/* !defined(HAVE_UINTPTR_T) */
    288 #ifndef HAVE_PTRDIFF_T
    289 #define HAVE_PTRDIFF_T 1
    290 #endif	/* !defined(HAVE_PTRDIFF_T) */
    291 #ifndef HAVE_VA_COPY
    292 #define HAVE_VA_COPY 1
    293 #endif	/* !defined(HAVE_VA_COPY) */
    294 #ifndef HAVE___VA_COPY
    295 #define HAVE___VA_COPY 1
    296 #endif	/* !defined(HAVE___VA_COPY) */
    297 #endif	/* HAVE_CONFIG_H */
    298 #define snprintf rpl_snprintf
    299 #define vsnprintf rpl_vsnprintf
    300 #define asprintf rpl_asprintf
    301 #define vasprintf rpl_vasprintf
    302 #endif	/* TEST_SNPRINTF */
    303 
    304 #if HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || HW_WANT_RPL_VASPRINTF
    305 #include <stdio.h>	/* For NULL, size_t, vsnprintf(3), and vasprintf(3). */
    306 #ifdef VA_START
    307 #undef VA_START
    308 #endif	/* defined(VA_START) */
    309 #ifdef VA_SHIFT
    310 #undef VA_SHIFT
    311 #endif	/* defined(VA_SHIFT) */
    312 #if HAVE_STDARG_H
    313 #include <stdarg.h>
    314 #define VA_START(ap, last) va_start(ap, last)
    315 #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
    316 #else	/* Assume <varargs.h> is available. */
    317 #include <varargs.h>
    318 #define VA_START(ap, last) va_start(ap)	/* "last" is ignored. */
    319 #define VA_SHIFT(ap, value, type) value = va_arg(ap, type)
    320 #endif	/* HAVE_STDARG_H */
    321 
    322 #if HW_WANT_RPL_VASPRINTF
    323 #if HAVE_STDLIB_H
    324 #include <stdlib.h>	/* For malloc(3). */
    325 #endif	/* HAVE_STDLIB_H */
    326 #ifdef VA_COPY
    327 #undef VA_COPY
    328 #endif	/* defined(VA_COPY) */
    329 #ifdef VA_END_COPY
    330 #undef VA_END_COPY
    331 #endif	/* defined(VA_END_COPY) */
    332 #if HAVE_VA_COPY
    333 #define VA_COPY(dest, src) va_copy(dest, src)
    334 #define VA_END_COPY(ap) va_end(ap)
    335 #elif HAVE___VA_COPY
    336 #define VA_COPY(dest, src) __va_copy(dest, src)
    337 #define VA_END_COPY(ap) va_end(ap)
    338 #else
    339 #define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list))
    340 #define VA_END_COPY(ap) /* No-op. */
    341 #define NEED_MYMEMCPY 1
    342 static void *mymemcpy(void *, void *, size_t);
    343 #endif	/* HAVE_VA_COPY */
    344 #endif	/* HW_WANT_RPL_VASPRINTF */
    345 
    346 #if HW_WANT_RPL_VSNPRINTF
    347 #include <errno.h>	/* For ERANGE and errno. */
    348 #include <limits.h>	/* For *_MAX. */
    349 #if HAVE_INTTYPES_H
    350 #include <inttypes.h>	/* For intmax_t (if not defined in <stdint.h>). */
    351 #endif	/* HAVE_INTTYPES_H */
    352 #if HAVE_LOCALE_H
    353 #include <locale.h>	/* For localeconv(3). */
    354 #endif	/* HAVE_LOCALE_H */
    355 #if HAVE_STDDEF_H
    356 #include <stddef.h>	/* For ptrdiff_t. */
    357 #endif	/* HAVE_STDDEF_H */
    358 #if HAVE_STDINT_H
    359 #include <stdint.h>	/* For intmax_t. */
    360 #endif	/* HAVE_STDINT_H */
    361 
    362 /* Support for unsigned long long int.  We may also need ULLONG_MAX. */
    363 #ifndef ULONG_MAX	/* We may need ULONG_MAX as a fallback. */
    364 #ifdef UINT_MAX
    365 #define ULONG_MAX UINT_MAX
    366 #else
    367 #define ULONG_MAX INT_MAX
    368 #endif	/* defined(UINT_MAX) */
    369 #endif	/* !defined(ULONG_MAX) */
    370 #ifdef ULLONG
    371 #undef ULLONG
    372 #endif	/* defined(ULLONG) */
    373 #if HAVE_UNSIGNED_LONG_LONG_INT
    374 #define ULLONG unsigned long long int
    375 #ifndef ULLONG_MAX
    376 #define ULLONG_MAX ULONG_MAX
    377 #endif	/* !defined(ULLONG_MAX) */
    378 #else
    379 #define ULLONG unsigned long int
    380 #ifdef ULLONG_MAX
    381 #undef ULLONG_MAX
    382 #endif	/* defined(ULLONG_MAX) */
    383 #define ULLONG_MAX ULONG_MAX
    384 #endif	/* HAVE_LONG_LONG_INT */
    385 
    386 /* Support for uintmax_t.  We also need UINTMAX_MAX. */
    387 #ifdef UINTMAX_T
    388 #undef UINTMAX_T
    389 #endif	/* defined(UINTMAX_T) */
    390 #if HAVE_UINTMAX_T || defined(uintmax_t)
    391 #define UINTMAX_T uintmax_t
    392 #ifndef UINTMAX_MAX
    393 #define UINTMAX_MAX ULLONG_MAX
    394 #endif	/* !defined(UINTMAX_MAX) */
    395 #else
    396 #define UINTMAX_T ULLONG
    397 #ifdef UINTMAX_MAX
    398 #undef UINTMAX_MAX
    399 #endif	/* defined(UINTMAX_MAX) */
    400 #define UINTMAX_MAX ULLONG_MAX
    401 #endif	/* HAVE_UINTMAX_T || defined(uintmax_t) */
    402 
    403 /* Support for long double. */
    404 #ifndef LDOUBLE
    405 #if HAVE_LONG_DOUBLE
    406 #define LDOUBLE long double
    407 #else
    408 #define LDOUBLE double
    409 #endif	/* HAVE_LONG_DOUBLE */
    410 #endif	/* !defined(LDOUBLE) */
    411 
    412 /* Support for long long int. */
    413 #ifndef LLONG
    414 #if HAVE_LONG_LONG_INT
    415 #define LLONG long long int
    416 #else
    417 #define LLONG long int
    418 #endif	/* HAVE_LONG_LONG_INT */
    419 #endif	/* !defined(LLONG) */
    420 
    421 /* Support for intmax_t. */
    422 #ifndef INTMAX_T
    423 #if HAVE_INTMAX_T || defined(intmax_t)
    424 #define INTMAX_T intmax_t
    425 #else
    426 #define INTMAX_T LLONG
    427 #endif	/* HAVE_INTMAX_T || defined(intmax_t) */
    428 #endif	/* !defined(INTMAX_T) */
    429 
    430 /* Support for uintptr_t. */
    431 #ifndef UINTPTR_T
    432 #if HAVE_UINTPTR_T || defined(uintptr_t)
    433 #define UINTPTR_T uintptr_t
    434 #else
    435 #define UINTPTR_T unsigned long int
    436 #endif	/* HAVE_UINTPTR_T || defined(uintptr_t) */
    437 #endif	/* !defined(UINTPTR_T) */
    438 
    439 /* Support for ptrdiff_t. */
    440 #ifndef PTRDIFF_T
    441 #if HAVE_PTRDIFF_T || defined(ptrdiff_t)
    442 #define PTRDIFF_T ptrdiff_t
    443 #else
    444 #define PTRDIFF_T long int
    445 #endif	/* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
    446 #endif	/* !defined(PTRDIFF_T) */
    447 
    448 /*
    449  * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
    450  * 7.19.6.1, 7).  However, we'll simply use PTRDIFF_T and convert it to an
    451  * unsigned type if necessary.  This should work just fine in practice.
    452  */
    453 #ifndef UPTRDIFF_T
    454 #define UPTRDIFF_T PTRDIFF_T
    455 #endif	/* !defined(UPTRDIFF_T) */
    456 
    457 /*
    458  * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
    459  * However, we'll simply use size_t and convert it to a signed type if
    460  * necessary.  This should work just fine in practice.
    461  */
    462 #ifndef SSIZE_T
    463 #define SSIZE_T size_t
    464 #endif	/* !defined(SSIZE_T) */
    465 
    466 /* Either ERANGE or E2BIG should be available everywhere. */
    467 #ifndef ERANGE
    468 #define ERANGE E2BIG
    469 #endif	/* !defined(ERANGE) */
    470 #ifndef EOVERFLOW
    471 #define EOVERFLOW ERANGE
    472 #endif	/* !defined(EOVERFLOW) */
    473 
    474 /*
    475  * Buffer size to hold the octal string representation of UINT128_MAX without
    476  * nul-termination ("3777777777777777777777777777777777777777777").
    477  */
    478 #ifdef MAX_CONVERT_LENGTH
    479 #undef MAX_CONVERT_LENGTH
    480 #endif	/* defined(MAX_CONVERT_LENGTH) */
    481 #define MAX_CONVERT_LENGTH      43
    482 
    483 /* Format read states. */
    484 #define PRINT_S_DEFAULT         0
    485 #define PRINT_S_FLAGS           1
    486 #define PRINT_S_WIDTH           2
    487 #define PRINT_S_DOT             3
    488 #define PRINT_S_PRECISION       4
    489 #define PRINT_S_MOD             5
    490 #define PRINT_S_CONV            6
    491 
    492 /* Format flags. */
    493 #define PRINT_F_MINUS           (1 << 0)
    494 #define PRINT_F_PLUS            (1 << 1)
    495 #define PRINT_F_SPACE           (1 << 2)
    496 #define PRINT_F_NUM             (1 << 3)
    497 #define PRINT_F_ZERO            (1 << 4)
    498 #define PRINT_F_QUOTE           (1 << 5)
    499 #define PRINT_F_UP              (1 << 6)
    500 #define PRINT_F_UNSIGNED        (1 << 7)
    501 #define PRINT_F_TYPE_G          (1 << 8)
    502 #define PRINT_F_TYPE_E          (1 << 9)
    503 
    504 /* Conversion flags. */
    505 #define PRINT_C_CHAR            1
    506 #define PRINT_C_SHORT           2
    507 #define PRINT_C_LONG            3
    508 #define PRINT_C_LLONG           4
    509 #define PRINT_C_LDOUBLE         5
    510 #define PRINT_C_SIZE            6
    511 #define PRINT_C_PTRDIFF         7
    512 #define PRINT_C_INTMAX          8
    513 
    514 #ifndef MAX
    515 #define MAX(x, y) ((x >= y) ? x : y)
    516 #endif	/* !defined(MAX) */
    517 #ifndef CHARTOINT
    518 #define CHARTOINT(ch) (ch - '0')
    519 #endif	/* !defined(CHARTOINT) */
    520 #ifndef ISDIGIT
    521 #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
    522 #endif	/* !defined(ISDIGIT) */
    523 #ifndef ISNAN
    524 #define ISNAN(x) (x != x)
    525 #endif	/* !defined(ISNAN) */
    526 #ifndef ISINF
    527 #define ISINF(x) (x != 0.0 && x + x == x)
    528 #endif	/* !defined(ISINF) */
    529 
    530 #ifdef OUTCHAR
    531 #undef OUTCHAR
    532 #endif	/* defined(OUTCHAR) */
    533 #define OUTCHAR(str, len, size, ch)                                          \
    534 do {                                                                         \
    535 	if (len + 1 < size)                                                  \
    536 		str[len] = ch;                                               \
    537 	(len)++;                                                             \
    538 } while (/* CONSTCOND */ 0)
    539 
    540 static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
    541 static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
    542 static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *);
    543 static void printsep(char *, size_t *, size_t);
    544 static int getnumsep(int);
    545 static int getexponent(LDOUBLE);
    546 static int convert(UINTMAX_T, char *, size_t, int, int);
    547 static UINTMAX_T cast(LDOUBLE);
    548 static UINTMAX_T myround(LDOUBLE);
    549 static LDOUBLE mypow10(int);
    550 
    551 int
    552 rpl_vsnprintf(char *str, size_t size, const char *format, va_list args);
    553 
    554 int
    555 rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
    556 {
    557 	LDOUBLE fvalue;
    558 	INTMAX_T value;
    559 	unsigned char cvalue;
    560 	const char *strvalue;
    561 	INTMAX_T *intmaxptr;
    562 	PTRDIFF_T *ptrdiffptr;
    563 	SSIZE_T *sizeptr;
    564 	LLONG *llongptr;
    565 	long int *longptr;
    566 	int *intptr;
    567 	short int *shortptr;
    568 	signed char *charptr;
    569 	size_t len = 0;
    570 	int overflow = 0;
    571 	int base = 0;
    572 	int cflags = 0;
    573 	int flags = 0;
    574 	int width = 0;
    575 	int precision = -1;
    576 	int state = PRINT_S_DEFAULT;
    577 	char ch = *format++;
    578 
    579 	/*
    580 	 * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
    581 	 * pointer." (7.19.6.5, 2)  We're forgiving and allow a NULL pointer
    582 	 * even if a size larger than zero was specified.  At least NetBSD's
    583 	 * snprintf(3) does the same, as well as other versions of this file.
    584 	 * (Though some of these versions will write to a non-NULL buffer even
    585 	 * if a size of zero was specified, which violates the standard.)
    586 	 */
    587 	if (str == NULL && size != 0)
    588 		size = 0;
    589 
    590 	while (ch != '\0')
    591 		switch (state) {
    592 		case PRINT_S_DEFAULT:
    593 			if (ch == '%')
    594 				state = PRINT_S_FLAGS;
    595 			else
    596 				OUTCHAR(str, len, size, ch);
    597 			ch = *format++;
    598 			break;
    599 		case PRINT_S_FLAGS:
    600 			switch (ch) {
    601 			case '-':
    602 				flags |= PRINT_F_MINUS;
    603 				ch = *format++;
    604 				break;
    605 			case '+':
    606 				flags |= PRINT_F_PLUS;
    607 				ch = *format++;
    608 				break;
    609 			case ' ':
    610 				flags |= PRINT_F_SPACE;
    611 				ch = *format++;
    612 				break;
    613 			case '#':
    614 				flags |= PRINT_F_NUM;
    615 				ch = *format++;
    616 				break;
    617 			case '0':
    618 				flags |= PRINT_F_ZERO;
    619 				ch = *format++;
    620 				break;
    621 			case '\'':	/* SUSv2 flag (not in C99). */
    622 				flags |= PRINT_F_QUOTE;
    623 				ch = *format++;
    624 				break;
    625 			default:
    626 				state = PRINT_S_WIDTH;
    627 				break;
    628 			}
    629 			break;
    630 		case PRINT_S_WIDTH:
    631 			if (ISDIGIT(ch)) {
    632 				ch = CHARTOINT(ch);
    633 				if (width > (INT_MAX - ch) / 10) {
    634 					overflow = 1;
    635 					goto out;
    636 				}
    637 				width = 10 * width + ch;
    638 				ch = *format++;
    639 			} else if (ch == '*') {
    640 				/*
    641 				 * C99 says: "A negative field width argument is
    642 				 * taken as a `-' flag followed by a positive
    643 				 * field width." (7.19.6.1, 5)
    644 				 */
    645 				if ((width = va_arg(args, int)) < 0) {
    646 					flags |= PRINT_F_MINUS;
    647 					width = -width;
    648 				}
    649 				ch = *format++;
    650 				state = PRINT_S_DOT;
    651 			} else
    652 				state = PRINT_S_DOT;
    653 			break;
    654 		case PRINT_S_DOT:
    655 			if (ch == '.') {
    656 				state = PRINT_S_PRECISION;
    657 				ch = *format++;
    658 			} else
    659 				state = PRINT_S_MOD;
    660 			break;
    661 		case PRINT_S_PRECISION:
    662 			if (precision == -1)
    663 				precision = 0;
    664 			if (ISDIGIT(ch)) {
    665 				ch = CHARTOINT(ch);
    666 				if (precision > (INT_MAX - ch) / 10) {
    667 					overflow = 1;
    668 					goto out;
    669 				}
    670 				precision = 10 * precision + ch;
    671 				ch = *format++;
    672 			} else if (ch == '*') {
    673 				/*
    674 				 * C99 says: "A negative precision argument is
    675 				 * taken as if the precision were omitted."
    676 				 * (7.19.6.1, 5)
    677 				 */
    678 				if ((precision = va_arg(args, int)) < 0)
    679 					precision = -1;
    680 				ch = *format++;
    681 				state = PRINT_S_MOD;
    682 			} else
    683 				state = PRINT_S_MOD;
    684 			break;
    685 		case PRINT_S_MOD:
    686 			switch (ch) {
    687 			case 'h':
    688 				ch = *format++;
    689 				if (ch == 'h') {	/* It's a char. */
    690 					ch = *format++;
    691 					cflags = PRINT_C_CHAR;
    692 				} else
    693 					cflags = PRINT_C_SHORT;
    694 				break;
    695 			case 'l':
    696 				ch = *format++;
    697 				if (ch == 'l') {	/* It's a long long. */
    698 					ch = *format++;
    699 					cflags = PRINT_C_LLONG;
    700 				} else
    701 					cflags = PRINT_C_LONG;
    702 				break;
    703 			case 'L':
    704 				cflags = PRINT_C_LDOUBLE;
    705 				ch = *format++;
    706 				break;
    707 			case 'j':
    708 				cflags = PRINT_C_INTMAX;
    709 				ch = *format++;
    710 				break;
    711 			case 't':
    712 				cflags = PRINT_C_PTRDIFF;
    713 				ch = *format++;
    714 				break;
    715 			case 'z':
    716 				cflags = PRINT_C_SIZE;
    717 				ch = *format++;
    718 				break;
    719 			}
    720 			state = PRINT_S_CONV;
    721 			break;
    722 		case PRINT_S_CONV:
    723 			switch (ch) {
    724 			case 'd':
    725 				/* FALLTHROUGH */
    726 			case 'i':
    727 				switch (cflags) {
    728 				case PRINT_C_CHAR:
    729 					value = (signed char)va_arg(args, int);
    730 					break;
    731 				case PRINT_C_SHORT:
    732 					value = (short int)va_arg(args, int);
    733 					break;
    734 				case PRINT_C_LONG:
    735 					value = va_arg(args, long int);
    736 					break;
    737 				case PRINT_C_LLONG:
    738 					value = va_arg(args, LLONG);
    739 					break;
    740 				case PRINT_C_SIZE:
    741 					value = va_arg(args, SSIZE_T);
    742 					break;
    743 				case PRINT_C_INTMAX:
    744 					value = va_arg(args, INTMAX_T);
    745 					break;
    746 				case PRINT_C_PTRDIFF:
    747 					value = va_arg(args, PTRDIFF_T);
    748 					break;
    749 				default:
    750 					value = va_arg(args, int);
    751 					break;
    752 				}
    753 				fmtint(str, &len, size, value, 10, width,
    754 				    precision, flags);
    755 				break;
    756 			case 'X':
    757 				flags |= PRINT_F_UP;
    758 				/* FALLTHROUGH */
    759 			case 'x':
    760 				base = 16;
    761 				/* FALLTHROUGH */
    762 			case 'o':
    763 				if (base == 0)
    764 					base = 8;
    765 				/* FALLTHROUGH */
    766 			case 'u':
    767 				if (base == 0)
    768 					base = 10;
    769 				flags |= PRINT_F_UNSIGNED;
    770 				switch (cflags) {
    771 				case PRINT_C_CHAR:
    772 					value = (unsigned char)va_arg(args,
    773 					    unsigned int);
    774 					break;
    775 				case PRINT_C_SHORT:
    776 					value = (unsigned short int)va_arg(args,
    777 					    unsigned int);
    778 					break;
    779 				case PRINT_C_LONG:
    780 					value = va_arg(args, unsigned long int);
    781 					break;
    782 				case PRINT_C_LLONG:
    783 					value = va_arg(args, ULLONG);
    784 					break;
    785 				case PRINT_C_SIZE:
    786 					value = va_arg(args, size_t);
    787 					break;
    788 				case PRINT_C_INTMAX:
    789 					value = va_arg(args, UINTMAX_T);
    790 					break;
    791 				case PRINT_C_PTRDIFF:
    792 					value = va_arg(args, UPTRDIFF_T);
    793 					break;
    794 				default:
    795 					value = va_arg(args, unsigned int);
    796 					break;
    797 				}
    798 				fmtint(str, &len, size, value, base, width,
    799 				    precision, flags);
    800 				break;
    801 			case 'A':
    802 				/* Not yet supported, we'll use "%F". */
    803 				/* FALLTHROUGH */
    804 			case 'F':
    805 				flags |= PRINT_F_UP;
    806 				/* FALLTHROUGH */
    807 			case 'a':
    808 				/* Not yet supported, we'll use "%f". */
    809 				/* FALLTHROUGH */
    810 			case 'f':
    811 				if (cflags == PRINT_C_LDOUBLE)
    812 					fvalue = va_arg(args, LDOUBLE);
    813 				else
    814 					fvalue = va_arg(args, double);
    815 				fmtflt(str, &len, size, fvalue, width,
    816 				    precision, flags, &overflow);
    817 				if (overflow)
    818 					goto out;
    819 				break;
    820 			case 'E':
    821 				flags |= PRINT_F_UP;
    822 				/* FALLTHROUGH */
    823 			case 'e':
    824 				flags |= PRINT_F_TYPE_E;
    825 				if (cflags == PRINT_C_LDOUBLE)
    826 					fvalue = va_arg(args, LDOUBLE);
    827 				else
    828 					fvalue = va_arg(args, double);
    829 				fmtflt(str, &len, size, fvalue, width,
    830 				    precision, flags, &overflow);
    831 				if (overflow)
    832 					goto out;
    833 				break;
    834 			case 'G':
    835 				flags |= PRINT_F_UP;
    836 				/* FALLTHROUGH */
    837 			case 'g':
    838 				flags |= PRINT_F_TYPE_G;
    839 				if (cflags == PRINT_C_LDOUBLE)
    840 					fvalue = va_arg(args, LDOUBLE);
    841 				else
    842 					fvalue = va_arg(args, double);
    843 				/*
    844 				 * If the precision is zero, it is treated as
    845 				 * one (cf. C99: 7.19.6.1, 8).
    846 				 */
    847 				if (precision == 0)
    848 					precision = 1;
    849 				fmtflt(str, &len, size, fvalue, width,
    850 				    precision, flags, &overflow);
    851 				if (overflow)
    852 					goto out;
    853 				break;
    854 			case 'c':
    855 				cvalue = va_arg(args, int);
    856 				OUTCHAR(str, len, size, cvalue);
    857 				break;
    858 			case 's':
    859 				strvalue = va_arg(args, char *);
    860 				fmtstr(str, &len, size, strvalue, width,
    861 				    precision, flags);
    862 				break;
    863 			case 'p':
    864 				/*
    865 				 * C99 says: "The value of the pointer is
    866 				 * converted to a sequence of printing
    867 				 * characters, in an implementation-defined
    868 				 * manner." (C99: 7.19.6.1, 8)
    869 				 */
    870 				if ((strvalue = va_arg(args, void *)) == NULL)
    871 					/*
    872 					 * We use the glibc format.  BSD prints
    873 					 * "0x0", SysV "0".
    874 					 */
    875 					fmtstr(str, &len, size, "(nil)", width,
    876 					    -1, flags);
    877 				else {
    878 					/*
    879 					 * We use the BSD/glibc format.  SysV
    880 					 * omits the "0x" prefix (which we emit
    881 					 * using the PRINT_F_NUM flag).
    882 					 */
    883 					flags |= PRINT_F_NUM;
    884 					flags |= PRINT_F_UNSIGNED;
    885 					fmtint(str, &len, size,
    886 					    (UINTPTR_T)strvalue, 16, width,
    887 					    precision, flags);
    888 				}
    889 				break;
    890 			case 'n':
    891 				switch (cflags) {
    892 				case PRINT_C_CHAR:
    893 					charptr = va_arg(args, signed char *);
    894 					*charptr = (signed char)len;
    895 					break;
    896 				case PRINT_C_SHORT:
    897 					shortptr = va_arg(args, short int *);
    898 					*shortptr = (short int)len;
    899 					break;
    900 				case PRINT_C_LONG:
    901 					longptr = va_arg(args, long int *);
    902 					*longptr = (long int)len;
    903 					break;
    904 				case PRINT_C_LLONG:
    905 					llongptr = va_arg(args, LLONG *);
    906 					*llongptr = (LLONG)len;
    907 					break;
    908 				case PRINT_C_SIZE:
    909 					/*
    910 					 * C99 says that with the "z" length
    911 					 * modifier, "a following `n' conversion
    912 					 * specifier applies to a pointer to a
    913 					 * signed integer type corresponding to
    914 					 * size_t argument." (7.19.6.1, 7)
    915 					 */
    916 					sizeptr = va_arg(args, SSIZE_T *);
    917 					*sizeptr = (SSIZE_T)len;
    918 					break;
    919 				case PRINT_C_INTMAX:
    920 					intmaxptr = va_arg(args, INTMAX_T *);
    921 					*intmaxptr = (INTMAX_T)len;
    922 					break;
    923 				case PRINT_C_PTRDIFF:
    924 					ptrdiffptr = va_arg(args, PTRDIFF_T *);
    925 					*ptrdiffptr = (PTRDIFF_T)len;
    926 					break;
    927 				default:
    928 					intptr = va_arg(args, int *);
    929 					*intptr = (int)len;
    930 					break;
    931 				}
    932 				break;
    933 			case '%':	/* Print a "%" character verbatim. */
    934 				OUTCHAR(str, len, size, ch);
    935 				break;
    936 			default:	/* Skip other characters. */
    937 				break;
    938 			}
    939 			ch = *format++;
    940 			state = PRINT_S_DEFAULT;
    941 			base = cflags = flags = width = 0;
    942 			precision = -1;
    943 			break;
    944 		}
    945 out:
    946 	if (len < size)
    947 		str[len] = '\0';
    948 	else if (size > 0)
    949 		str[size - 1] = '\0';
    950 
    951 	if (overflow || len >= INT_MAX) {
    952 		errno = overflow ? EOVERFLOW : ERANGE;
    953 		return -1;
    954 	}
    955 	return (int)len;
    956 }
    957 
    958 static void
    959 fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
    960        int precision, int flags)
    961 {
    962 	int padlen, strln;	/* Amount to pad. */
    963 	int noprecision = (precision == -1);
    964 
    965 	if (value == NULL)	/* We're forgiving. */
    966 		value = "(null)";
    967 
    968 	/* If a precision was specified, don't read the string past it. */
    969 	for (strln = 0; value[strln] != '\0' &&
    970 	    (noprecision || strln < precision); strln++)
    971 		continue;
    972 
    973 	if ((padlen = width - strln) < 0)
    974 		padlen = 0;
    975 	if (flags & PRINT_F_MINUS)	/* Left justify. */
    976 		padlen = -padlen;
    977 
    978 	while (padlen > 0) {	/* Leading spaces. */
    979 		OUTCHAR(str, *len, size, ' ');
    980 		padlen--;
    981 	}
    982 	while (*value != '\0' && (noprecision || precision-- > 0)) {
    983 		OUTCHAR(str, *len, size, *value);
    984 		value++;
    985 	}
    986 	while (padlen < 0) {	/* Trailing spaces. */
    987 		OUTCHAR(str, *len, size, ' ');
    988 		padlen++;
    989 	}
    990 }
    991 
    992 static void
    993 fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
    994        int precision, int flags)
    995 {
    996 	UINTMAX_T uvalue;
    997 	char iconvert[MAX_CONVERT_LENGTH];
    998 	char sign = 0;
    999 	char hexprefix = 0;
   1000 	int spadlen = 0;	/* Amount to space pad. */
   1001 	int zpadlen = 0;	/* Amount to zero pad. */
   1002 	int pos;
   1003 	int separators = (flags & PRINT_F_QUOTE);
   1004 	int noprecision = (precision == -1);
   1005 
   1006 	if (flags & PRINT_F_UNSIGNED)
   1007 		uvalue = value;
   1008 	else {
   1009 		uvalue = (value >= 0) ? value : -value;
   1010 		if (value < 0)
   1011 			sign = '-';
   1012 		else if (flags & PRINT_F_PLUS)	/* Do a sign. */
   1013 			sign = '+';
   1014 		else if (flags & PRINT_F_SPACE)
   1015 			sign = ' ';
   1016 	}
   1017 
   1018 	pos = convert(uvalue, iconvert, sizeof(iconvert), base,
   1019 	    flags & PRINT_F_UP);
   1020 
   1021 	if (flags & PRINT_F_NUM && uvalue != 0) {
   1022 		/*
   1023 		 * C99 says: "The result is converted to an `alternative form'.
   1024 		 * For `o' conversion, it increases the precision, if and only
   1025 		 * if necessary, to force the first digit of the result to be a
   1026 		 * zero (if the value and precision are both 0, a single 0 is
   1027 		 * printed).  For `x' (or `X') conversion, a nonzero result has
   1028 		 * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
   1029 		 */
   1030 		switch (base) {
   1031 		case 8:
   1032 			if (precision <= pos)
   1033 				precision = pos + 1;
   1034 			break;
   1035 		case 16:
   1036 			hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
   1037 			break;
   1038 		}
   1039 	}
   1040 
   1041 	if (separators)	/* Get the number of group separators we'll print. */
   1042 		separators = getnumsep(pos);
   1043 
   1044 	zpadlen = precision - pos - separators;
   1045 	spadlen = width                         /* Minimum field width. */
   1046 	    - separators                        /* Number of separators. */
   1047 	    - MAX(precision, pos)               /* Number of integer digits. */
   1048 	    - ((sign != 0) ? 1 : 0)             /* Will we print a sign? */
   1049 	    - ((hexprefix != 0) ? 2 : 0);       /* Will we print a prefix? */
   1050 
   1051 	if (zpadlen < 0)
   1052 		zpadlen = 0;
   1053 	if (spadlen < 0)
   1054 		spadlen = 0;
   1055 
   1056 	/*
   1057 	 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
   1058 	 * ignored.  For `d', `i', `o', `u', `x', and `X' conversions, if a
   1059 	 * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
   1060 	 */
   1061 	if (flags & PRINT_F_MINUS)	/* Left justify. */
   1062 		spadlen = -spadlen;
   1063 	else if (flags & PRINT_F_ZERO && noprecision) {
   1064 		zpadlen += spadlen;
   1065 		spadlen = 0;
   1066 	}
   1067 	while (spadlen > 0) {	/* Leading spaces. */
   1068 		OUTCHAR(str, *len, size, ' ');
   1069 		spadlen--;
   1070 	}
   1071 	if (sign != 0)	/* Sign. */
   1072 		OUTCHAR(str, *len, size, sign);
   1073 	if (hexprefix != 0) {	/* A "0x" or "0X" prefix. */
   1074 		OUTCHAR(str, *len, size, '0');
   1075 		OUTCHAR(str, *len, size, hexprefix);
   1076 	}
   1077 	while (zpadlen > 0) {	/* Leading zeros. */
   1078 		OUTCHAR(str, *len, size, '0');
   1079 		zpadlen--;
   1080 	}
   1081 	while (pos > 0) {	/* The actual digits. */
   1082 		pos--;
   1083 		OUTCHAR(str, *len, size, iconvert[pos]);
   1084 		if (separators > 0 && pos > 0 && pos % 3 == 0)
   1085 			printsep(str, len, size);
   1086 	}
   1087 	while (spadlen < 0) {	/* Trailing spaces. */
   1088 		OUTCHAR(str, *len, size, ' ');
   1089 		spadlen++;
   1090 	}
   1091 }
   1092 
   1093 static void
   1094 fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
   1095        int precision, int flags, int *overflow)
   1096 {
   1097 	LDOUBLE ufvalue;
   1098 	UINTMAX_T intpart;
   1099 	UINTMAX_T fracpart;
   1100 	UINTMAX_T mask;
   1101 	const char *infnan = NULL;
   1102 	char iconvert[MAX_CONVERT_LENGTH];
   1103 	char fconvert[MAX_CONVERT_LENGTH];
   1104 	char econvert[4];	/* "e-12" (without nul-termination). */
   1105 	char esign = 0;
   1106 	char sign = 0;
   1107 	int leadfraczeros = 0;
   1108 	int exponent = 0;
   1109 	int emitpoint = 0;
   1110 	int omitzeros = 0;
   1111 	int omitcount = 0;
   1112 	int padlen = 0;
   1113 	int epos = 0;
   1114 	int fpos = 0;
   1115 	int ipos = 0;
   1116 	int separators = (flags & PRINT_F_QUOTE);
   1117 	int estyle = (flags & PRINT_F_TYPE_E);
   1118 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
   1119 	struct lconv *lc = localeconv();
   1120 #endif	/* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
   1121 
   1122 	/*
   1123 	 * AIX' man page says the default is 0, but C99 and at least Solaris'
   1124 	 * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
   1125 	 * defaults to 6.
   1126 	 */
   1127 	if (precision == -1)
   1128 		precision = 6;
   1129 
   1130 	if (fvalue < 0.0)
   1131 		sign = '-';
   1132 	else if (flags & PRINT_F_PLUS)	/* Do a sign. */
   1133 		sign = '+';
   1134 	else if (flags & PRINT_F_SPACE)
   1135 		sign = ' ';
   1136 
   1137 	if (ISNAN(fvalue))
   1138 		infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
   1139 	else if (ISINF(fvalue))
   1140 		infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
   1141 
   1142 	if (infnan != NULL) {
   1143 		if (sign != 0)
   1144 			iconvert[ipos++] = sign;
   1145 		while (*infnan != '\0')
   1146 			iconvert[ipos++] = *infnan++;
   1147 		fmtstr(str, len, size, iconvert, width, ipos, flags);
   1148 		return;
   1149 	}
   1150 
   1151 	/* "%e" (or "%E") or "%g" (or "%G") conversion. */
   1152 	if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
   1153 		if (flags & PRINT_F_TYPE_G) {
   1154 			/*
   1155 			 * For "%g" (and "%G") conversions, the precision
   1156 			 * specifies the number of significant digits, which
   1157 			 * includes the digits in the integer part.  The
   1158 			 * conversion will or will not be using "e-style" (like
   1159 			 * "%e" or "%E" conversions) depending on the precision
   1160 			 * and on the exponent.  However, the exponent can be
   1161 			 * affected by rounding the converted value, so we'll
   1162 			 * leave this decision for later.  Until then, we'll
   1163 			 * assume that we're going to do an "e-style" conversion
   1164 			 * (in order to get the exponent calculated).  For
   1165 			 * "e-style", the precision must be decremented by one.
   1166 			 */
   1167 			precision--;
   1168 			/*
   1169 			 * For "%g" (and "%G") conversions, trailing zeros are
   1170 			 * removed from the fractional portion of the result
   1171 			 * unless the "#" flag was specified.
   1172 			 */
   1173 			if (!(flags & PRINT_F_NUM))
   1174 				omitzeros = 1;
   1175 		}
   1176 		exponent = getexponent(fvalue);
   1177 		estyle = 1;
   1178 	}
   1179 
   1180 again:
   1181 	/*
   1182 	 * Sorry, we only support 9, 19, or 38 digits (that is, the number of
   1183 	 * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
   1184 	 * minus one) past the decimal point due to our conversion method.
   1185 	 */
   1186 	switch (sizeof(UINTMAX_T)) {
   1187 	case 16:
   1188 		if (precision > 38)
   1189 			precision = 38;
   1190 		break;
   1191 	case 8:
   1192 		if (precision > 19)
   1193 			precision = 19;
   1194 		break;
   1195 	default:
   1196 		if (precision > 9)
   1197 			precision = 9;
   1198 		break;
   1199 	}
   1200 
   1201 	ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
   1202 	if (estyle)	/* We want exactly one integer digit. */
   1203 		ufvalue /= mypow10(exponent);
   1204 
   1205 	if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
   1206 		*overflow = 1;
   1207 		return;
   1208 	}
   1209 
   1210 	/*
   1211 	 * Factor of ten with the number of digits needed for the fractional
   1212 	 * part.  For example, if the precision is 3, the mask will be 1000.
   1213 	 */
   1214 	mask = (UINTMAX_T)mypow10(precision);
   1215 	/*
   1216 	 * We "cheat" by converting the fractional part to integer by
   1217 	 * multiplying by a factor of ten.
   1218 	 */
   1219 	if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
   1220 		/*
   1221 		 * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
   1222 		 * (because precision = 3).  Now, myround(1000 * 0.99962) will
   1223 		 * return 1000.  So, the integer part must be incremented by one
   1224 		 * and the fractional part must be set to zero.
   1225 		 */
   1226 		intpart++;
   1227 		fracpart = 0;
   1228 		if (estyle && intpart == 10) {
   1229 			/*
   1230 			 * The value was rounded up to ten, but we only want one
   1231 			 * integer digit if using "e-style".  So, the integer
   1232 			 * part must be set to one and the exponent must be
   1233 			 * incremented by one.
   1234 			 */
   1235 			intpart = 1;
   1236 			exponent++;
   1237 		}
   1238 	}
   1239 
   1240 	/*
   1241 	 * Now that we know the real exponent, we can check whether or not to
   1242 	 * use "e-style" for "%g" (and "%G") conversions.  If we don't need
   1243 	 * "e-style", the precision must be adjusted and the integer and
   1244 	 * fractional parts must be recalculated from the original value.
   1245 	 *
   1246 	 * C99 says: "Let P equal the precision if nonzero, 6 if the precision
   1247 	 * is omitted, or 1 if the precision is zero.  Then, if a conversion
   1248 	 * with style `E' would have an exponent of X:
   1249 	 *
   1250 	 * - if P > X >= -4, the conversion is with style `f' (or `F') and
   1251 	 *   precision P - (X + 1).
   1252 	 *
   1253 	 * - otherwise, the conversion is with style `e' (or `E') and precision
   1254 	 *   P - 1." (7.19.6.1, 8)
   1255 	 *
   1256 	 * Note that we had decremented the precision by one.
   1257 	 */
   1258 	if (flags & PRINT_F_TYPE_G && estyle &&
   1259 	    precision + 1 > exponent && exponent >= -4) {
   1260 		precision -= exponent;
   1261 		estyle = 0;
   1262 		goto again;
   1263 	}
   1264 
   1265 	if (estyle) {
   1266 		if (exponent < 0) {
   1267 			exponent = -exponent;
   1268 			esign = '-';
   1269 		} else
   1270 			esign = '+';
   1271 
   1272 		/*
   1273 		 * Convert the exponent.  The sizeof(econvert) is 4.  So, the
   1274 		 * econvert buffer can hold e.g. "e+99" and "e-99".  We don't
   1275 		 * support an exponent which contains more than two digits.
   1276 		 * Therefore, the following stores are safe.
   1277 		 */
   1278 		epos = convert(exponent, econvert, 2, 10, 0);
   1279 		/*
   1280 		 * C99 says: "The exponent always contains at least two digits,
   1281 		 * and only as many more digits as necessary to represent the
   1282 		 * exponent." (7.19.6.1, 8)
   1283 		 */
   1284 		if (epos == 1)
   1285 			econvert[epos++] = '0';
   1286 		econvert[epos++] = esign;
   1287 		econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
   1288 	}
   1289 
   1290 	/* Convert the integer part and the fractional part. */
   1291 	ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
   1292 	if (fracpart != 0)	/* convert() would return 1 if fracpart == 0. */
   1293 		fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
   1294 
   1295 	leadfraczeros = precision - fpos;
   1296 
   1297 	if (omitzeros) {
   1298 		if (fpos > 0)	/* Omit trailing fractional part zeros. */
   1299 			while (omitcount < fpos && fconvert[omitcount] == '0')
   1300 				omitcount++;
   1301 		else {	/* The fractional part is zero, omit it completely. */
   1302 			omitcount = precision;
   1303 			leadfraczeros = 0;
   1304 		}
   1305 		precision -= omitcount;
   1306 	}
   1307 
   1308 	/*
   1309 	 * Print a decimal point if either the fractional part is non-zero
   1310 	 * and/or the "#" flag was specified.
   1311 	 */
   1312 	if (precision > 0 || flags & PRINT_F_NUM)
   1313 		emitpoint = 1;
   1314 	if (separators)	/* Get the number of group separators we'll print. */
   1315 		separators = getnumsep(ipos);
   1316 
   1317 	padlen = width                  /* Minimum field width. */
   1318 	    - ipos                      /* Number of integer digits. */
   1319 	    - epos                      /* Number of exponent characters. */
   1320 	    - precision                 /* Number of fractional digits. */
   1321 	    - separators                /* Number of group separators. */
   1322 	    - (emitpoint ? 1 : 0)       /* Will we print a decimal point? */
   1323 	    - ((sign != 0) ? 1 : 0);    /* Will we print a sign character? */
   1324 
   1325 	if (padlen < 0)
   1326 		padlen = 0;
   1327 
   1328 	/*
   1329 	 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
   1330 	 * ignored." (7.19.6.1, 6)
   1331 	 */
   1332 	if (flags & PRINT_F_MINUS)	/* Left justifty. */
   1333 		padlen = -padlen;
   1334 	else if (flags & PRINT_F_ZERO && padlen > 0) {
   1335 		if (sign != 0) {	/* Sign. */
   1336 			OUTCHAR(str, *len, size, sign);
   1337 			sign = 0;
   1338 		}
   1339 		while (padlen > 0) {	/* Leading zeros. */
   1340 			OUTCHAR(str, *len, size, '0');
   1341 			padlen--;
   1342 		}
   1343 	}
   1344 	while (padlen > 0) {	/* Leading spaces. */
   1345 		OUTCHAR(str, *len, size, ' ');
   1346 		padlen--;
   1347 	}
   1348 	if (sign != 0)	/* Sign. */
   1349 		OUTCHAR(str, *len, size, sign);
   1350 	while (ipos > 0) {	/* Integer part. */
   1351 		ipos--;
   1352 		OUTCHAR(str, *len, size, iconvert[ipos]);
   1353 		if (separators > 0 && ipos > 0 && ipos % 3 == 0)
   1354 			printsep(str, len, size);
   1355 	}
   1356 	if (emitpoint) {	/* Decimal point. */
   1357 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
   1358 		if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
   1359 			OUTCHAR(str, *len, size, *lc->decimal_point);
   1360 		else	/* We'll always print some decimal point character. */
   1361 #endif	/* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
   1362 			OUTCHAR(str, *len, size, '.');
   1363 	}
   1364 	while (leadfraczeros > 0) {	/* Leading fractional part zeros. */
   1365 		OUTCHAR(str, *len, size, '0');
   1366 		leadfraczeros--;
   1367 	}
   1368 	while (fpos > omitcount) {	/* The remaining fractional part. */
   1369 		fpos--;
   1370 		OUTCHAR(str, *len, size, fconvert[fpos]);
   1371 	}
   1372 	while (epos > 0) {	/* Exponent. */
   1373 		epos--;
   1374 		OUTCHAR(str, *len, size, econvert[epos]);
   1375 	}
   1376 	while (padlen < 0) {	/* Trailing spaces. */
   1377 		OUTCHAR(str, *len, size, ' ');
   1378 		padlen++;
   1379 	}
   1380 }
   1381 
   1382 static void
   1383 printsep(char *str, size_t *len, size_t size)
   1384 {
   1385 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
   1386 	struct lconv *lc = localeconv();
   1387 	int i;
   1388 
   1389 	if (lc->thousands_sep != NULL)
   1390 		for (i = 0; lc->thousands_sep[i] != '\0'; i++)
   1391 			OUTCHAR(str, *len, size, lc->thousands_sep[i]);
   1392 	else
   1393 #endif	/* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
   1394 		OUTCHAR(str, *len, size, ',');
   1395 }
   1396 
   1397 static int
   1398 getnumsep(int digits)
   1399 {
   1400 	int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
   1401 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
   1402 	int strln;
   1403 	struct lconv *lc = localeconv();
   1404 
   1405 	/* We support an arbitrary separator length (including zero). */
   1406 	if (lc->thousands_sep != NULL) {
   1407 		for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
   1408 			continue;
   1409 		separators *= strln;
   1410 	}
   1411 #endif	/* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
   1412 	return separators;
   1413 }
   1414 
   1415 static int
   1416 getexponent(LDOUBLE value)
   1417 {
   1418 	LDOUBLE tmp = (value >= 0.0) ? value : -value;
   1419 	int exponent = 0;
   1420 
   1421 	/*
   1422 	 * We check for 99 > exponent > -99 in order to work around possible
   1423 	 * endless loops which could happen (at least) in the second loop (at
   1424 	 * least) if we're called with an infinite value.  However, we checked
   1425 	 * for infinity before calling this function using our ISINF() macro, so
   1426 	 * this might be somewhat paranoid.
   1427 	 */
   1428 	while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
   1429 		tmp *= 10;
   1430 	while (tmp >= 10.0 && ++exponent < 99)
   1431 		tmp /= 10;
   1432 
   1433 	return exponent;
   1434 }
   1435 
   1436 static int
   1437 convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
   1438 {
   1439 	const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
   1440 	size_t pos = 0;
   1441 
   1442 	/* We return an unterminated buffer with the digits in reverse order. */
   1443 	do {
   1444 		buf[pos++] = digits[value % base];
   1445 		value /= base;
   1446 	} while (value != 0 && pos < size);
   1447 
   1448 	return (int)pos;
   1449 }
   1450 
   1451 static UINTMAX_T
   1452 cast(LDOUBLE value)
   1453 {
   1454 	UINTMAX_T result;
   1455 
   1456 	/*
   1457 	 * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
   1458 	 * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
   1459 	 * it may be increased to the nearest higher representable value for the
   1460 	 * comparison (cf. C99: 6.3.1.4, 2).  It might then equal the LDOUBLE
   1461 	 * value although converting the latter to UINTMAX_T would overflow.
   1462 	 */
   1463 	if (value >= UINTMAX_MAX)
   1464 		return UINTMAX_MAX;
   1465 
   1466 	result = (UINTMAX_T)value;
   1467 	/*
   1468 	 * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
   1469 	 * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
   1470 	 * the standard).  Sigh.
   1471 	 */
   1472 	return (result <= value) ? result : result - 1;
   1473 }
   1474 
   1475 static UINTMAX_T
   1476 myround(LDOUBLE value)
   1477 {
   1478 	UINTMAX_T intpart = cast(value);
   1479 
   1480 	return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
   1481 }
   1482 
   1483 static LDOUBLE
   1484 mypow10(int exponent)
   1485 {
   1486 	LDOUBLE result = 1;
   1487 
   1488 	while (exponent > 0) {
   1489 		result *= 10;
   1490 		exponent--;
   1491 	}
   1492 	while (exponent < 0) {
   1493 		result /= 10;
   1494 		exponent++;
   1495 	}
   1496 	return result;
   1497 }
   1498 #endif	/* HW_WANT_RPL_VSNPRINTF */
   1499 
   1500 #if HW_WANT_RPL_VASPRINTF
   1501 #if NEED_MYMEMCPY
   1502 void *
   1503 mymemcpy(void *dst, void *src, size_t len)
   1504 {
   1505 	const char *from = src;
   1506 	char *to = dst;
   1507 
   1508 	/* No need for optimization, we use this only to replace va_copy(3). */
   1509 	while (len-- > 0)
   1510 		*to++ = *from++;
   1511 	return dst;
   1512 }
   1513 #endif	/* NEED_MYMEMCPY */
   1514 
   1515 int
   1516 rpl_vasprintf(char **ret, const char *format, va_list ap);
   1517 
   1518 int
   1519 rpl_vasprintf(char **ret, const char *format, va_list ap)
   1520 {
   1521 	size_t size;
   1522 	int len;
   1523 	va_list aq;
   1524 
   1525 	VA_COPY(aq, ap);
   1526 	len = vsnprintf(NULL, 0, format, aq);
   1527 	VA_END_COPY(aq);
   1528 	if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
   1529 		return -1;
   1530 	return vsnprintf(*ret, size, format, ap);
   1531 }
   1532 #endif	/* HW_WANT_RPL_VASPRINTF */
   1533 
   1534 #if HW_WANT_RPL_SNPRINTF
   1535 #if HAVE_STDARG_H
   1536 int
   1537 rpl_snprintf(char *str, size_t size, const char *format, ...);
   1538 
   1539 int
   1540 rpl_snprintf(char *str, size_t size, const char *format, ...)
   1541 #else
   1542 int
   1543 rpl_snprintf(va_alist) va_dcl
   1544 #endif	/* HAVE_STDARG_H */
   1545 {
   1546 #if !HAVE_STDARG_H
   1547 	char *str;
   1548 	size_t size;
   1549 	char *format;
   1550 #endif	/* HAVE_STDARG_H */
   1551 	va_list ap;
   1552 	int len;
   1553 
   1554 	VA_START(ap, format);
   1555 	VA_SHIFT(ap, str, char *);
   1556 	VA_SHIFT(ap, size, size_t);
   1557 	VA_SHIFT(ap, format, const char *);
   1558 	len = vsnprintf(str, size, format, ap);
   1559 	va_end(ap);
   1560 	return len;
   1561 }
   1562 #endif	/* HW_WANT_RPL_SNPRINTF */
   1563 
   1564 #if HW_WANT_RPL_ASPRINTF
   1565 #if HAVE_STDARG_H
   1566 int
   1567 rpl_asprintf(char **ret, const char *format, ...);
   1568 
   1569 int
   1570 rpl_asprintf(char **ret, const char *format, ...)
   1571 #else
   1572 int
   1573 rpl_asprintf(va_alist) va_dcl
   1574 #endif	/* HAVE_STDARG_H */
   1575 {
   1576 #if !HAVE_STDARG_H
   1577 	char **ret;
   1578 	char *format;
   1579 #endif	/* HAVE_STDARG_H */
   1580 	va_list ap;
   1581 	int len;
   1582 
   1583 	VA_START(ap, format);
   1584 	VA_SHIFT(ap, ret, char **);
   1585 	VA_SHIFT(ap, format, const char *);
   1586 	len = vasprintf(ret, format, ap);
   1587 	va_end(ap);
   1588 	return len;
   1589 }
   1590 #endif	/* HW_WANT_RPL_ASPRINTF */
   1591 #else	/* Dummy declaration to avoid empty translation unit warnings. */
   1592 NONEMPTY_TRANSLATION_UNIT
   1593 #endif	/* HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || [...] */
   1594 
   1595 #if TEST_SNPRINTF
   1596 int
   1597 main(void)
   1598 {
   1599 	const char *float_fmt[] = {
   1600 		/* "%E" and "%e" formats. */
   1601 #if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX
   1602 		"%.16e",
   1603 		"%22.16e",
   1604 		"%022.16e",
   1605 		"%-22.16e",
   1606 		"%#+'022.16e",
   1607 #endif	/* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */
   1608 		"foo|%#+0123.9E|bar",
   1609 		"%-123.9e",
   1610 		"%123.9e",
   1611 		"%+23.9e",
   1612 		"%+05.8e",
   1613 		"%-05.8e",
   1614 		"%05.8e",
   1615 		"%+5.8e",
   1616 		"%-5.8e",
   1617 		"% 5.8e",
   1618 		"%5.8e",
   1619 		"%+4.9e",
   1620 #if !OS_LINUX	/* glibc sometimes gets these wrong. */
   1621 		"%+#010.0e",
   1622 		"%#10.1e",
   1623 		"%10.5e",
   1624 		"% 10.5e",
   1625 		"%5.0e",
   1626 		"%5.e",
   1627 		"%#5.0e",
   1628 		"%#5.e",
   1629 		"%3.2e",
   1630 		"%3.1e",
   1631 		"%-1.5e",
   1632 		"%1.5e",
   1633 		"%01.3e",
   1634 		"%1.e",
   1635 		"%.1e",
   1636 		"%#.0e",
   1637 		"%+.0e",
   1638 		"% .0e",
   1639 		"%.0e",
   1640 		"%#.e",
   1641 		"%+.e",
   1642 		"% .e",
   1643 		"%.e",
   1644 		"%4e",
   1645 		"%e",
   1646 		"%E",
   1647 #endif	/* !OS_LINUX */
   1648 		/* "%F" and "%f" formats. */
   1649 #if !OS_BSD && !OS_IRIX
   1650 		"% '022f",
   1651 		"%+'022f",
   1652 		"%-'22f",
   1653 		"%'22f",
   1654 #if HAVE_LONG_LONG_INT
   1655 		"%.16f",
   1656 		"%22.16f",
   1657 		"%022.16f",
   1658 		"%-22.16f",
   1659 		"%#+'022.16f",
   1660 #endif	/* HAVE_LONG_LONG_INT */
   1661 #endif	/* !OS_BSD && !OS_IRIX */
   1662 		"foo|%#+0123.9F|bar",
   1663 		"%-123.9f",
   1664 		"%123.9f",
   1665 		"%+23.9f",
   1666 		"%+#010.0f",
   1667 		"%#10.1f",
   1668 		"%10.5f",
   1669 		"% 10.5f",
   1670 		"%+05.8f",
   1671 		"%-05.8f",
   1672 		"%05.8f",
   1673 		"%+5.8f",
   1674 		"%-5.8f",
   1675 		"% 5.8f",
   1676 		"%5.8f",
   1677 		"%5.0f",
   1678 		"%5.f",
   1679 		"%#5.0f",
   1680 		"%#5.f",
   1681 		"%+4.9f",
   1682 		"%3.2f",
   1683 		"%3.1f",
   1684 		"%-1.5f",
   1685 		"%1.5f",
   1686 		"%01.3f",
   1687 		"%1.f",
   1688 		"%.1f",
   1689 		"%#.0f",
   1690 		"%+.0f",
   1691 		"% .0f",
   1692 		"%.0f",
   1693 		"%#.f",
   1694 		"%+.f",
   1695 		"% .f",
   1696 		"%.f",
   1697 		"%4f",
   1698 		"%f",
   1699 		"%F",
   1700 		/* "%G" and "%g" formats. */
   1701 #if !OS_BSD && !OS_IRIX && !OS_LINUX
   1702 		"% '022g",
   1703 		"%+'022g",
   1704 		"%-'22g",
   1705 		"%'22g",
   1706 #if HAVE_LONG_LONG_INT
   1707 		"%.16g",
   1708 		"%22.16g",
   1709 		"%022.16g",
   1710 		"%-22.16g",
   1711 		"%#+'022.16g",
   1712 #endif	/* HAVE_LONG_LONG_INT */
   1713 #endif	/* !OS_BSD && !OS_IRIX && !OS_LINUX */
   1714 		"foo|%#+0123.9G|bar",
   1715 		"%-123.9g",
   1716 		"%123.9g",
   1717 		"%+23.9g",
   1718 		"%+05.8g",
   1719 		"%-05.8g",
   1720 		"%05.8g",
   1721 		"%+5.8g",
   1722 		"%-5.8g",
   1723 		"% 5.8g",
   1724 		"%5.8g",
   1725 		"%+4.9g",
   1726 #if !OS_LINUX	/* glibc sometimes gets these wrong. */
   1727 		"%+#010.0g",
   1728 		"%#10.1g",
   1729 		"%10.5g",
   1730 		"% 10.5g",
   1731 		"%5.0g",
   1732 		"%5.g",
   1733 		"%#5.0g",
   1734 		"%#5.g",
   1735 		"%3.2g",
   1736 		"%3.1g",
   1737 		"%-1.5g",
   1738 		"%1.5g",
   1739 		"%01.3g",
   1740 		"%1.g",
   1741 		"%.1g",
   1742 		"%#.0g",
   1743 		"%+.0g",
   1744 		"% .0g",
   1745 		"%.0g",
   1746 		"%#.g",
   1747 		"%+.g",
   1748 		"% .g",
   1749 		"%.g",
   1750 		"%4g",
   1751 		"%g",
   1752 		"%G",
   1753 #endif	/* !OS_LINUX */
   1754 		NULL
   1755 	};
   1756 	double float_val[] = {
   1757 		-4.136,
   1758 		-134.52,
   1759 		-5.04030201,
   1760 		-3410.01234,
   1761 		-999999.999999,
   1762 		-913450.29876,
   1763 		-913450.2,
   1764 		-91345.2,
   1765 		-9134.2,
   1766 		-913.2,
   1767 		-91.2,
   1768 		-9.2,
   1769 		-9.9,
   1770 		4.136,
   1771 		134.52,
   1772 		5.04030201,
   1773 		3410.01234,
   1774 		999999.999999,
   1775 		913450.29876,
   1776 		913450.2,
   1777 		91345.2,
   1778 		9134.2,
   1779 		913.2,
   1780 		91.2,
   1781 		9.2,
   1782 		9.9,
   1783 		9.96,
   1784 		9.996,
   1785 		9.9996,
   1786 		9.99996,
   1787 		9.999996,
   1788 		9.9999996,
   1789 		9.99999996,
   1790 		0.99999996,
   1791 		0.99999999,
   1792 		0.09999999,
   1793 		0.00999999,
   1794 		0.00099999,
   1795 		0.00009999,
   1796 		0.00000999,
   1797 		0.00000099,
   1798 		0.00000009,
   1799 		0.00000001,
   1800 		0.0000001,
   1801 		0.000001,
   1802 		0.00001,
   1803 		0.0001,
   1804 		0.001,
   1805 		0.01,
   1806 		0.1,
   1807 		1.0,
   1808 		1.5,
   1809 		-1.5,
   1810 		-1.0,
   1811 		-0.1,
   1812 #if !OS_BSD	/* BSD sometimes gets these wrong. */
   1813 #ifdef INFINITY
   1814 		INFINITY,
   1815 		-INFINITY,
   1816 #endif	/* defined(INFINITY) */
   1817 #ifdef NAN
   1818 		NAN,
   1819 #endif	/* defined(NAN) */
   1820 #endif	/* !OS_BSD */
   1821 		0
   1822 	};
   1823 	const char *long_fmt[] = {
   1824 		"foo|%0123ld|bar",
   1825 #if !OS_IRIX
   1826 		"% '0123ld",
   1827 		"%+'0123ld",
   1828 		"%-'123ld",
   1829 		"%'123ld",
   1830 #endif	/* !OS_IRiX */
   1831 		"%123.9ld",
   1832 		"% 123.9ld",
   1833 		"%+123.9ld",
   1834 		"%-123.9ld",
   1835 		"%0123ld",
   1836 		"% 0123ld",
   1837 		"%+0123ld",
   1838 		"%-0123ld",
   1839 		"%10.5ld",
   1840 		"% 10.5ld",
   1841 		"%+10.5ld",
   1842 		"%-10.5ld",
   1843 		"%010ld",
   1844 		"% 010ld",
   1845 		"%+010ld",
   1846 		"%-010ld",
   1847 		"%4.2ld",
   1848 		"% 4.2ld",
   1849 		"%+4.2ld",
   1850 		"%-4.2ld",
   1851 		"%04ld",
   1852 		"% 04ld",
   1853 		"%+04ld",
   1854 		"%-04ld",
   1855 		"%5.5ld",
   1856 		"%+22.33ld",
   1857 		"%01.3ld",
   1858 		"%1.5ld",
   1859 		"%-1.5ld",
   1860 		"%44ld",
   1861 		"%4ld",
   1862 		"%4.0ld",
   1863 		"%4.ld",
   1864 		"%.44ld",
   1865 		"%.4ld",
   1866 		"%.0ld",
   1867 		"%.ld",
   1868 		"%ld",
   1869 		NULL
   1870 	};
   1871 	long int long_val[] = {
   1872 #ifdef LONG_MAX
   1873 		LONG_MAX,
   1874 #endif	/* LONG_MAX */
   1875 #ifdef LONG_MIN
   1876 		LONG_MIN,
   1877 #endif	/* LONG_MIN */
   1878 		-91340,
   1879 		91340,
   1880 		341,
   1881 		134,
   1882 		0203,
   1883 		-1,
   1884 		1,
   1885 		0
   1886 	};
   1887 	const char *ulong_fmt[] = {
   1888 		/* "%u" formats. */
   1889 		"foo|%0123lu|bar",
   1890 #if !OS_IRIX
   1891 		"% '0123lu",
   1892 		"%+'0123lu",
   1893 		"%-'123lu",
   1894 		"%'123lu",
   1895 #endif	/* !OS_IRiX */
   1896 		"%123.9lu",
   1897 		"% 123.9lu",
   1898 		"%+123.9lu",
   1899 		"%-123.9lu",
   1900 		"%0123lu",
   1901 		"% 0123lu",
   1902 		"%+0123lu",
   1903 		"%-0123lu",
   1904 		"%5.5lu",
   1905 		"%+22.33lu",
   1906 		"%01.3lu",
   1907 		"%1.5lu",
   1908 		"%-1.5lu",
   1909 		"%44lu",
   1910 		"%lu",
   1911 		/* "%o" formats. */
   1912 		"foo|%#0123lo|bar",
   1913 		"%#123.9lo",
   1914 		"%# 123.9lo",
   1915 		"%#+123.9lo",
   1916 		"%#-123.9lo",
   1917 		"%#0123lo",
   1918 		"%# 0123lo",
   1919 		"%#+0123lo",
   1920 		"%#-0123lo",
   1921 		"%#5.5lo",
   1922 		"%#+22.33lo",
   1923 		"%#01.3lo",
   1924 		"%#1.5lo",
   1925 		"%#-1.5lo",
   1926 		"%#44lo",
   1927 		"%#lo",
   1928 		"%123.9lo",
   1929 		"% 123.9lo",
   1930 		"%+123.9lo",
   1931 		"%-123.9lo",
   1932 		"%0123lo",
   1933 		"% 0123lo",
   1934 		"%+0123lo",
   1935 		"%-0123lo",
   1936 		"%5.5lo",
   1937 		"%+22.33lo",
   1938 		"%01.3lo",
   1939 		"%1.5lo",
   1940 		"%-1.5lo",
   1941 		"%44lo",
   1942 		"%lo",
   1943 		/* "%X" and "%x" formats. */
   1944 		"foo|%#0123lX|bar",
   1945 		"%#123.9lx",
   1946 		"%# 123.9lx",
   1947 		"%#+123.9lx",
   1948 		"%#-123.9lx",
   1949 		"%#0123lx",
   1950 		"%# 0123lx",
   1951 		"%#+0123lx",
   1952 		"%#-0123lx",
   1953 		"%#5.5lx",
   1954 		"%#+22.33lx",
   1955 		"%#01.3lx",
   1956 		"%#1.5lx",
   1957 		"%#-1.5lx",
   1958 		"%#44lx",
   1959 		"%#lx",
   1960 		"%#lX",
   1961 		"%123.9lx",
   1962 		"% 123.9lx",
   1963 		"%+123.9lx",
   1964 		"%-123.9lx",
   1965 		"%0123lx",
   1966 		"% 0123lx",
   1967 		"%+0123lx",
   1968 		"%-0123lx",
   1969 		"%5.5lx",
   1970 		"%+22.33lx",
   1971 		"%01.3lx",
   1972 		"%1.5lx",
   1973 		"%-1.5lx",
   1974 		"%44lx",
   1975 		"%lx",
   1976 		"%lX",
   1977 		NULL
   1978 	};
   1979 	unsigned long int ulong_val[] = {
   1980 #ifdef ULONG_MAX
   1981 		ULONG_MAX,
   1982 #endif	/* ULONG_MAX */
   1983 		91340,
   1984 		341,
   1985 		134,
   1986 		0203,
   1987 		1,
   1988 		0
   1989 	};
   1990 	const char *llong_fmt[] = {
   1991 		"foo|%0123lld|bar",
   1992 		"%123.9lld",
   1993 		"% 123.9lld",
   1994 		"%+123.9lld",
   1995 		"%-123.9lld",
   1996 		"%0123lld",
   1997 		"% 0123lld",
   1998 		"%+0123lld",
   1999 		"%-0123lld",
   2000 		"%5.5lld",
   2001 		"%+22.33lld",
   2002 		"%01.3lld",
   2003 		"%1.5lld",
   2004 		"%-1.5lld",
   2005 		"%44lld",
   2006 		"%lld",
   2007 		NULL
   2008 	};
   2009 	LLONG llong_val[] = {
   2010 #ifdef LLONG_MAX
   2011 		LLONG_MAX,
   2012 #endif	/* LLONG_MAX */
   2013 #ifdef LLONG_MIN
   2014 		LLONG_MIN,
   2015 #endif	/* LLONG_MIN */
   2016 		-91340,
   2017 		91340,
   2018 		341,
   2019 		134,
   2020 		0203,
   2021 		-1,
   2022 		1,
   2023 		0
   2024 	};
   2025 	const char *string_fmt[] = {
   2026 		"foo|%10.10s|bar",
   2027 		"%-10.10s",
   2028 		"%10.10s",
   2029 		"%10.5s",
   2030 		"%5.10s",
   2031 		"%10.1s",
   2032 		"%1.10s",
   2033 		"%10.0s",
   2034 		"%0.10s",
   2035 		"%-42.5s",
   2036 		"%2.s",
   2037 		"%.10s",
   2038 		"%.1s",
   2039 		"%.0s",
   2040 		"%.s",
   2041 		"%4s",
   2042 		"%s",
   2043 		NULL
   2044 	};
   2045 	const char *string_val[] = {
   2046 		"Hello",
   2047 		"Hello, world!",
   2048 		"Sound check: One, two, three.",
   2049 		"This string is a little longer than the other strings.",
   2050 		"1",
   2051 		"",
   2052 		NULL
   2053 	};
   2054 #if !OS_SYSV	/* SysV uses a different format than we do. */
   2055 	const char *pointer_fmt[] = {
   2056 		"foo|%p|bar",
   2057 		"%42p",
   2058 		"%p",
   2059 		NULL
   2060 	};
   2061 	const char *pointer_val[] = {
   2062 		*pointer_fmt,
   2063 		*string_fmt,
   2064 		*string_val,
   2065 		NULL
   2066 	};
   2067 #endif	/* !OS_SYSV */
   2068 	char buf1[1024], buf2[1024];
   2069 	double value, digits = 9.123456789012345678901234567890123456789;
   2070 	int i, j, r1, r2, failed = 0, num = 0;
   2071 
   2072 /*
   2073  * Use -DTEST_NILS in order to also test the conversion of nil values.  Might
   2074  * segfault on systems which don't support converting a NULL pointer with "%s"
   2075  * and lets some test cases fail against BSD and glibc due to bugs in their
   2076  * implementations.
   2077  */
   2078 #ifndef TEST_NILS
   2079 #define TEST_NILS 0
   2080 #elif TEST_NILS
   2081 #undef TEST_NILS
   2082 #define TEST_NILS 1
   2083 #endif	/* !defined(TEST_NILS) */
   2084 #ifdef TEST
   2085 #undef TEST
   2086 #endif	/* defined(TEST) */
   2087 #define TEST(fmt, val)                                                         \
   2088 do {                                                                           \
   2089 	for (i = 0; fmt[i] != NULL; i++)                                       \
   2090 		for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) {          \
   2091 			r1 = sprintf(buf1, fmt[i], val[j]);                    \
   2092 			r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]);     \
   2093 			if (strcmp(buf1, buf2) != 0 || r1 != r2) {             \
   2094 				(void)printf("Results don't match, "           \
   2095 				    "format string: %s\n"                      \
   2096 				    "\t sprintf(3): [%s] (%d)\n"               \
   2097 				    "\tsnprintf(3): [%s] (%d)\n",              \
   2098 				    fmt[i], buf1, r1, buf2, r2);               \
   2099 				failed++;                                      \
   2100 			}                                                      \
   2101 			num++;                                                 \
   2102 		}                                                              \
   2103 } while (/* CONSTCOND */ 0)
   2104 
   2105 #if HAVE_LOCALE_H
   2106 	(void)setlocale(LC_ALL, "");
   2107 #endif	/* HAVE_LOCALE_H */
   2108 
   2109 	(void)puts("Testing our snprintf(3) against your system's sprintf(3).");
   2110 	TEST(float_fmt, float_val);
   2111 	TEST(long_fmt, long_val);
   2112 	TEST(ulong_fmt, ulong_val);
   2113 	TEST(llong_fmt, llong_val);
   2114 	TEST(string_fmt, string_val);
   2115 #if !OS_SYSV	/* SysV uses a different format than we do. */
   2116 	TEST(pointer_fmt, pointer_val);
   2117 #endif	/* !OS_SYSV */
   2118 	(void)printf("Result: %d out of %d tests failed.\n", failed, num);
   2119 
   2120 	(void)fputs("Checking how many digits we support: ", stdout);
   2121 	for (i = 0; i < 100; i++) {
   2122 		value = pow(10, i) * digits;
   2123 		(void)sprintf(buf1, "%.1f", value);
   2124 		(void)snprintf(buf2, sizeof(buf2), "%.1f", value);
   2125 		if (strcmp(buf1, buf2) != 0) {
   2126 			(void)printf("apparently %d.\n", i);
   2127 			break;
   2128 		}
   2129 	}
   2130 	return (failed == 0) ? 0 : 1;
   2131 }
   2132 #endif	/* TEST_SNPRINTF */
   2133 
   2134 /* vim: set joinspaces textwidth=80: */
   2135