xref: /freebsd/contrib/ntp/libntp/snprintf.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Modified by Dave Hart for integration into NTP 4.2.7 <hart@ntp.org>
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Changed in a backwards-incompatible way to separate HAVE_SNPRINTF
52b15cb3dSCy Schubert  * from HW_WANT_RPL_SNPRINTF, etc. for each of the four replaced
62b15cb3dSCy Schubert  * functions.
72b15cb3dSCy Schubert  *
82b15cb3dSCy Schubert  * Changed to honor hw_force_rpl_snprintf=yes, etc.  This is used by NTP
92b15cb3dSCy Schubert  * to test rpl_snprintf() and rpl_vsnprintf() on platforms which provide
102b15cb3dSCy Schubert  * C99-compliant implementations.
112b15cb3dSCy Schubert  */
122b15cb3dSCy Schubert 
132b15cb3dSCy Schubert /* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */
142b15cb3dSCy Schubert 
152b15cb3dSCy Schubert /*
162b15cb3dSCy Schubert  * Copyright (c) 1995 Patrick Powell.
172b15cb3dSCy Schubert  *
182b15cb3dSCy Schubert  * This code is based on code written by Patrick Powell <papowell@astart.com>.
192b15cb3dSCy Schubert  * It may be used for any purpose as long as this notice remains intact on all
202b15cb3dSCy Schubert  * source code distributions.
212b15cb3dSCy Schubert  */
222b15cb3dSCy Schubert 
232b15cb3dSCy Schubert /*
242b15cb3dSCy Schubert  * Copyright (c) 2008 Holger Weiss.
252b15cb3dSCy Schubert  *
262b15cb3dSCy Schubert  * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
272b15cb3dSCy Schubert  * My changes to the code may freely be used, modified and/or redistributed for
282b15cb3dSCy Schubert  * any purpose.  It would be nice if additions and fixes to this file (including
292b15cb3dSCy Schubert  * trivial code cleanups) would be sent back in order to let me include them in
302b15cb3dSCy Schubert  * the version available at <http://www.jhweiss.de/software/snprintf.html>.
312b15cb3dSCy Schubert  * However, this is not a requirement for using or redistributing (possibly
322b15cb3dSCy Schubert  * modified) versions of this file, nor is leaving this notice intact mandatory.
332b15cb3dSCy Schubert  */
342b15cb3dSCy Schubert 
352b15cb3dSCy Schubert /*
362b15cb3dSCy Schubert  * History
372b15cb3dSCy Schubert  *
382b15cb3dSCy Schubert  * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
392b15cb3dSCy Schubert  *
402b15cb3dSCy Schubert  * 	Fixed the detection of infinite floating point values on IRIX (and
412b15cb3dSCy Schubert  * 	possibly other systems) and applied another few minor cleanups.
422b15cb3dSCy Schubert  *
432b15cb3dSCy Schubert  * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
442b15cb3dSCy Schubert  *
452b15cb3dSCy Schubert  * 	Added a lot of new features, fixed many bugs, and incorporated various
462b15cb3dSCy Schubert  * 	improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
472b15cb3dSCy Schubert  * 	<rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
482b15cb3dSCy Schubert  * 	<djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
492b15cb3dSCy Schubert  * 	projects.  The additions include: support the "e", "E", "g", "G", and
502b15cb3dSCy Schubert  * 	"F" conversion specifiers (and use conversion style "f" or "F" for the
512b15cb3dSCy Schubert  * 	still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
522b15cb3dSCy Schubert  * 	"t", and "z" length modifiers; support the "#" flag and the (non-C99)
532b15cb3dSCy Schubert  * 	"'" flag; use localeconv(3) (if available) to get both the current
542b15cb3dSCy Schubert  * 	locale's decimal point character and the separator between groups of
552b15cb3dSCy Schubert  * 	digits; fix the handling of various corner cases of field width and
562b15cb3dSCy Schubert  * 	precision specifications; fix various floating point conversion bugs;
572b15cb3dSCy Schubert  * 	handle infinite and NaN floating point values; don't attempt to write to
582b15cb3dSCy Schubert  * 	the output buffer (which may be NULL) if a size of zero was specified;
592b15cb3dSCy Schubert  * 	check for integer overflow of the field width, precision, and return
602b15cb3dSCy Schubert  * 	values and during the floating point conversion; use the OUTCHAR() macro
612b15cb3dSCy Schubert  * 	instead of a function for better performance; provide asprintf(3) and
622b15cb3dSCy Schubert  * 	vasprintf(3) functions; add new test cases.  The replacement functions
632b15cb3dSCy Schubert  * 	have been renamed to use an "rpl_" prefix, the function calls in the
642b15cb3dSCy Schubert  * 	main project (and in this file) must be redefined accordingly for each
652b15cb3dSCy Schubert  * 	replacement function which is needed (by using Autoconf or other means).
662b15cb3dSCy Schubert  * 	Various other minor improvements have been applied and the coding style
672b15cb3dSCy Schubert  * 	was cleaned up for consistency.
682b15cb3dSCy Schubert  *
692b15cb3dSCy Schubert  * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
702b15cb3dSCy Schubert  *
712b15cb3dSCy Schubert  * 	C99 compliant snprintf(3) and vsnprintf(3) functions return the number
722b15cb3dSCy Schubert  * 	of characters that would have been written to a sufficiently sized
732b15cb3dSCy Schubert  * 	buffer (excluding the '\0').  The original code simply returned the
742b15cb3dSCy Schubert  * 	length of the resulting output string, so that's been fixed.
752b15cb3dSCy Schubert  *
762b15cb3dSCy Schubert  * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
772b15cb3dSCy Schubert  *
782b15cb3dSCy Schubert  * 	The original code assumed that both snprintf(3) and vsnprintf(3) were
792b15cb3dSCy Schubert  * 	missing.  Some systems only have snprintf(3) but not vsnprintf(3), so
802b15cb3dSCy Schubert  * 	the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
812b15cb3dSCy Schubert  *
822b15cb3dSCy Schubert  * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
832b15cb3dSCy Schubert  *
842b15cb3dSCy Schubert  * 	The PGP code was using unsigned hexadecimal formats.  Unfortunately,
852b15cb3dSCy Schubert  * 	unsigned formats simply didn't work.
862b15cb3dSCy Schubert  *
872b15cb3dSCy Schubert  * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
882b15cb3dSCy Schubert  *
892b15cb3dSCy Schubert  * 	Ok, added some minimal floating point support, which means this probably
902b15cb3dSCy Schubert  * 	requires libm on most operating systems.  Don't yet support the exponent
912b15cb3dSCy Schubert  * 	(e,E) and sigfig (g,G).  Also, fmtint() was pretty badly broken, it just
922b15cb3dSCy Schubert  * 	wasn't being exercised in ways which showed it, so that's been fixed.
932b15cb3dSCy Schubert  * 	Also, formatted the code to Mutt conventions, and removed dead code left
942b15cb3dSCy Schubert  * 	over from the original.  Also, there is now a builtin-test, run with:
952b15cb3dSCy Schubert  * 	gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
962b15cb3dSCy Schubert  *
972b15cb3dSCy Schubert  * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
982b15cb3dSCy Schubert  *
992b15cb3dSCy Schubert  * 	This was ugly.  It is still ugly.  I opted out of floating point
1002b15cb3dSCy Schubert  * 	numbers, but the formatter understands just about everything from the
1012b15cb3dSCy Schubert  * 	normal C string format, at least as far as I can tell from the Solaris
1022b15cb3dSCy Schubert  * 	2.5 printf(3S) man page.
1032b15cb3dSCy Schubert  */
1042b15cb3dSCy Schubert 
1052b15cb3dSCy Schubert /*
1062b15cb3dSCy Schubert  * ToDo
1072b15cb3dSCy Schubert  *
1082b15cb3dSCy Schubert  * - Add wide character support.
1092b15cb3dSCy Schubert  * - Add support for "%a" and "%A" conversions.
1102b15cb3dSCy Schubert  * - Create test routines which predefine the expected results.  Our test cases
1112b15cb3dSCy Schubert  *   usually expose bugs in system implementations rather than in ours :-)
1122b15cb3dSCy Schubert  */
1132b15cb3dSCy Schubert 
1142b15cb3dSCy Schubert /*
1152b15cb3dSCy Schubert  * Usage
1162b15cb3dSCy Schubert  *
1172b15cb3dSCy Schubert  * 1) The following preprocessor macros should be defined to 1 if the feature or
1182b15cb3dSCy Schubert  *    file in question is available on the target system (by using Autoconf or
1192b15cb3dSCy Schubert  *    other means), though basic functionality should be available as long as
1202b15cb3dSCy Schubert  *    HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly:
1212b15cb3dSCy Schubert  *
1222b15cb3dSCy Schubert  *	HW_WANT_RPL_VSNPRINTF
1232b15cb3dSCy Schubert  *	HW_WANT_RPL_SNPRINTF
1242b15cb3dSCy Schubert  *	HW_WANT_RPL_VASPRINTF
1252b15cb3dSCy Schubert  *	HW_WANT_RPL_ASPRINTF
1262b15cb3dSCy Schubert  *	HAVE_VSNPRINTF	// define to 1 #if HW_WANT_RPL_VSNPRINTF
1272b15cb3dSCy Schubert  *	HAVE_SNPRINTF	// define to 1 #if HW_WANT_RPL_SNPRINTF
1282b15cb3dSCy Schubert  *	HAVE_VASPRINTF	// define to 1 #if HW_WANT_RPL_VASPRINTF
1292b15cb3dSCy Schubert  *	HAVE_ASPRINTF	// define to 1 #if HW_WANT_RPL_ASPRINTF
1302b15cb3dSCy Schubert  *	HAVE_STDARG_H
1312b15cb3dSCy Schubert  *	HAVE_STDDEF_H
1322b15cb3dSCy Schubert  *	HAVE_STDINT_H
1332b15cb3dSCy Schubert  *	HAVE_STDLIB_H
1342b15cb3dSCy Schubert  *	HAVE_INTTYPES_H
1352b15cb3dSCy Schubert  *	HAVE_LOCALE_H
1362b15cb3dSCy Schubert  *	HAVE_LOCALECONV
1372b15cb3dSCy Schubert  *	HAVE_LCONV_DECIMAL_POINT
1382b15cb3dSCy Schubert  *	HAVE_LCONV_THOUSANDS_SEP
1392b15cb3dSCy Schubert  *	HAVE_LONG_DOUBLE
1402b15cb3dSCy Schubert  *	HAVE_LONG_LONG_INT
1412b15cb3dSCy Schubert  *	HAVE_UNSIGNED_LONG_LONG_INT
1422b15cb3dSCy Schubert  *	HAVE_INTMAX_T
1432b15cb3dSCy Schubert  *	HAVE_UINTMAX_T
1442b15cb3dSCy Schubert  *	HAVE_UINTPTR_T
1452b15cb3dSCy Schubert  *	HAVE_PTRDIFF_T
1462b15cb3dSCy Schubert  *	HAVE_VA_COPY
1472b15cb3dSCy Schubert  *	HAVE___VA_COPY
1482b15cb3dSCy Schubert  *
1492b15cb3dSCy Schubert  * 2) The calls to the functions which should be replaced must be redefined
1502b15cb3dSCy Schubert  *    throughout the project files (by using Autoconf or other means):
1512b15cb3dSCy Schubert  *
1522b15cb3dSCy Schubert  *	#if HW_WANT_RPL_VSNPRINTF
1532b15cb3dSCy Schubert  *	#define vsnprintf rpl_vsnprintf
1542b15cb3dSCy Schubert  *	#endif
1552b15cb3dSCy Schubert  *	#if HW_WANT_RPL_SNPRINTF
1562b15cb3dSCy Schubert  *	#define snprintf rpl_snprintf
1572b15cb3dSCy Schubert  *	#endif
1582b15cb3dSCy Schubert  *	#if HW_WANT_RPL_VASPRINTF
1592b15cb3dSCy Schubert  *	#define vasprintf rpl_vasprintf
1602b15cb3dSCy Schubert  *	#endif
1612b15cb3dSCy Schubert  *	#if HW_WANT_RPL_ASPRINTF
1622b15cb3dSCy Schubert  *	#define asprintf rpl_asprintf
1632b15cb3dSCy Schubert  *	#endif
1642b15cb3dSCy Schubert  *
1652b15cb3dSCy Schubert  * 3) The required replacement functions should be declared in some header file
1662b15cb3dSCy Schubert  *    included throughout the project files:
1672b15cb3dSCy Schubert  *
1682b15cb3dSCy Schubert  *	#if HAVE_CONFIG_H
1692b15cb3dSCy Schubert  *	#include <config.h>
1702b15cb3dSCy Schubert  *	#endif
1712b15cb3dSCy Schubert  *	#if HAVE_STDARG_H
1722b15cb3dSCy Schubert  *	#include <stdarg.h>
1732b15cb3dSCy Schubert  *	#if HW_WANT_RPL_VSNPRINTF
1742b15cb3dSCy Schubert  *	int rpl_vsnprintf(char *, size_t, const char *, va_list);
1752b15cb3dSCy Schubert  *	#endif
1762b15cb3dSCy Schubert  *	#if HW_WANT_RPL_SNPRINTF
1772b15cb3dSCy Schubert  *	int rpl_snprintf(char *, size_t, const char *, ...);
1782b15cb3dSCy Schubert  *	#endif
1792b15cb3dSCy Schubert  *	#if HW_WANT_RPL_VASPRINTF
1802b15cb3dSCy Schubert  *	int rpl_vasprintf(char **, const char *, va_list);
1812b15cb3dSCy Schubert  *	#endif
1822b15cb3dSCy Schubert  *	#if HW_WANT_RPL_ASPRINTF
1832b15cb3dSCy Schubert  *	int rpl_asprintf(char **, const char *, ...);
1842b15cb3dSCy Schubert  *	#endif
1852b15cb3dSCy Schubert  *	#endif
1862b15cb3dSCy Schubert  *
1872b15cb3dSCy Schubert  * Autoconf macros for handling step 1 and step 2 are available at
1882b15cb3dSCy Schubert  * <http://www.jhweiss.de/software/snprintf.html>.
1892b15cb3dSCy Schubert  */
1902b15cb3dSCy Schubert 
1912b15cb3dSCy Schubert #if HAVE_CONFIG_H
192224ba2bdSOllivier Robert #include <config.h>
1932b15cb3dSCy Schubert #endif	/* HAVE_CONFIG_H */
194224ba2bdSOllivier Robert 
1952b15cb3dSCy Schubert #if TEST_SNPRINTF
1962b15cb3dSCy Schubert #include <math.h>	/* For pow(3), NAN, and INFINITY. */
1972b15cb3dSCy Schubert #include <string.h>	/* For strcmp(3). */
1982b15cb3dSCy Schubert #if defined(__NetBSD__) || \
1992b15cb3dSCy Schubert     defined(__FreeBSD__) || \
2002b15cb3dSCy Schubert     defined(__OpenBSD__) || \
2012b15cb3dSCy Schubert     defined(__NeXT__) || \
2022b15cb3dSCy Schubert     defined(__bsd__)
2032b15cb3dSCy Schubert #define OS_BSD 1
2042b15cb3dSCy Schubert #elif defined(sgi) || defined(__sgi)
2052b15cb3dSCy Schubert #ifndef __c99
2062b15cb3dSCy Schubert #define __c99	/* Force C99 mode to get <stdint.h> included on IRIX 6.5.30. */
2072b15cb3dSCy Schubert #endif	/* !defined(__c99) */
2082b15cb3dSCy Schubert #define OS_IRIX 1
2092b15cb3dSCy Schubert #define OS_SYSV 1
2102b15cb3dSCy Schubert #elif defined(__svr4__)
2112b15cb3dSCy Schubert #define OS_SYSV 1
2122b15cb3dSCy Schubert #elif defined(__linux__)
2132b15cb3dSCy Schubert #define OS_LINUX 1
2142b15cb3dSCy Schubert #endif	/* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */
2152b15cb3dSCy Schubert #if HAVE_CONFIG_H	/* Undefine definitions possibly done in config.h. */
2162b15cb3dSCy Schubert #ifdef HAVE_SNPRINTF
2172b15cb3dSCy Schubert #undef HAVE_SNPRINTF
2182b15cb3dSCy Schubert #endif	/* defined(HAVE_SNPRINTF) */
2192b15cb3dSCy Schubert #ifdef HAVE_VSNPRINTF
2202b15cb3dSCy Schubert #undef HAVE_VSNPRINTF
2212b15cb3dSCy Schubert #endif	/* defined(HAVE_VSNPRINTF) */
2222b15cb3dSCy Schubert #ifdef HAVE_ASPRINTF
2232b15cb3dSCy Schubert #undef HAVE_ASPRINTF
2242b15cb3dSCy Schubert #endif	/* defined(HAVE_ASPRINTF) */
2252b15cb3dSCy Schubert #ifdef HAVE_VASPRINTF
2262b15cb3dSCy Schubert #undef HAVE_VASPRINTF
2272b15cb3dSCy Schubert #endif	/* defined(HAVE_VASPRINTF) */
2282b15cb3dSCy Schubert #ifdef snprintf
2292b15cb3dSCy Schubert #undef snprintf
2302b15cb3dSCy Schubert #endif	/* defined(snprintf) */
2312b15cb3dSCy Schubert #ifdef vsnprintf
2322b15cb3dSCy Schubert #undef vsnprintf
2332b15cb3dSCy Schubert #endif	/* defined(vsnprintf) */
2342b15cb3dSCy Schubert #ifdef asprintf
2352b15cb3dSCy Schubert #undef asprintf
2362b15cb3dSCy Schubert #endif	/* defined(asprintf) */
2372b15cb3dSCy Schubert #ifdef vasprintf
2382b15cb3dSCy Schubert #undef vasprintf
2392b15cb3dSCy Schubert #endif	/* defined(vasprintf) */
2402b15cb3dSCy Schubert #else	/* By default, we assume a modern system for testing. */
2412b15cb3dSCy Schubert #ifndef HAVE_STDARG_H
2422b15cb3dSCy Schubert #define HAVE_STDARG_H 1
2432b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
2442b15cb3dSCy Schubert #ifndef HAVE_STDDEF_H
2452b15cb3dSCy Schubert #define HAVE_STDDEF_H 1
2462b15cb3dSCy Schubert #endif	/* HAVE_STDDEF_H */
2472b15cb3dSCy Schubert #ifndef HAVE_STDINT_H
2482b15cb3dSCy Schubert #define HAVE_STDINT_H 1
2492b15cb3dSCy Schubert #endif	/* HAVE_STDINT_H */
2502b15cb3dSCy Schubert #ifndef HAVE_STDLIB_H
2512b15cb3dSCy Schubert #define HAVE_STDLIB_H 1
2522b15cb3dSCy Schubert #endif	/* HAVE_STDLIB_H */
2532b15cb3dSCy Schubert #ifndef HAVE_INTTYPES_H
2542b15cb3dSCy Schubert #define HAVE_INTTYPES_H 1
2552b15cb3dSCy Schubert #endif	/* HAVE_INTTYPES_H */
2562b15cb3dSCy Schubert #ifndef HAVE_LOCALE_H
2572b15cb3dSCy Schubert #define HAVE_LOCALE_H 1
2582b15cb3dSCy Schubert #endif	/* HAVE_LOCALE_H */
2592b15cb3dSCy Schubert #ifndef HAVE_LOCALECONV
2602b15cb3dSCy Schubert #define HAVE_LOCALECONV 1
2612b15cb3dSCy Schubert #endif	/* !defined(HAVE_LOCALECONV) */
2622b15cb3dSCy Schubert #ifndef HAVE_LCONV_DECIMAL_POINT
2632b15cb3dSCy Schubert #define HAVE_LCONV_DECIMAL_POINT 1
2642b15cb3dSCy Schubert #endif	/* HAVE_LCONV_DECIMAL_POINT */
2652b15cb3dSCy Schubert #ifndef HAVE_LCONV_THOUSANDS_SEP
2662b15cb3dSCy Schubert #define HAVE_LCONV_THOUSANDS_SEP 1
2672b15cb3dSCy Schubert #endif	/* HAVE_LCONV_THOUSANDS_SEP */
2682b15cb3dSCy Schubert #ifndef HAVE_LONG_DOUBLE
2692b15cb3dSCy Schubert #define HAVE_LONG_DOUBLE 1
2702b15cb3dSCy Schubert #endif	/* !defined(HAVE_LONG_DOUBLE) */
2712b15cb3dSCy Schubert #ifndef HAVE_LONG_LONG_INT
2722b15cb3dSCy Schubert #define HAVE_LONG_LONG_INT 1
2732b15cb3dSCy Schubert #endif	/* !defined(HAVE_LONG_LONG_INT) */
2742b15cb3dSCy Schubert #ifndef HAVE_UNSIGNED_LONG_LONG_INT
2752b15cb3dSCy Schubert #define HAVE_UNSIGNED_LONG_LONG_INT 1
2762b15cb3dSCy Schubert #endif	/* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */
2772b15cb3dSCy Schubert #ifndef HAVE_INTMAX_T
2782b15cb3dSCy Schubert #define HAVE_INTMAX_T 1
2792b15cb3dSCy Schubert #endif	/* !defined(HAVE_INTMAX_T) */
2802b15cb3dSCy Schubert #ifndef HAVE_UINTMAX_T
2812b15cb3dSCy Schubert #define HAVE_UINTMAX_T 1
2822b15cb3dSCy Schubert #endif	/* !defined(HAVE_UINTMAX_T) */
2832b15cb3dSCy Schubert #ifndef HAVE_UINTPTR_T
2842b15cb3dSCy Schubert #define HAVE_UINTPTR_T 1
2852b15cb3dSCy Schubert #endif	/* !defined(HAVE_UINTPTR_T) */
2862b15cb3dSCy Schubert #ifndef HAVE_PTRDIFF_T
2872b15cb3dSCy Schubert #define HAVE_PTRDIFF_T 1
2882b15cb3dSCy Schubert #endif	/* !defined(HAVE_PTRDIFF_T) */
2892b15cb3dSCy Schubert #ifndef HAVE_VA_COPY
2902b15cb3dSCy Schubert #define HAVE_VA_COPY 1
2912b15cb3dSCy Schubert #endif	/* !defined(HAVE_VA_COPY) */
2922b15cb3dSCy Schubert #ifndef HAVE___VA_COPY
2932b15cb3dSCy Schubert #define HAVE___VA_COPY 1
2942b15cb3dSCy Schubert #endif	/* !defined(HAVE___VA_COPY) */
2952b15cb3dSCy Schubert #endif	/* HAVE_CONFIG_H */
2962b15cb3dSCy Schubert #define snprintf rpl_snprintf
2972b15cb3dSCy Schubert #define vsnprintf rpl_vsnprintf
2982b15cb3dSCy Schubert #define asprintf rpl_asprintf
2992b15cb3dSCy Schubert #define vasprintf rpl_vasprintf
3002b15cb3dSCy Schubert #endif	/* TEST_SNPRINTF */
301224ba2bdSOllivier Robert 
3022b15cb3dSCy Schubert #if HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || HW_WANT_RPL_VASPRINTF
3032b15cb3dSCy Schubert #include <stdio.h>	/* For NULL, size_t, vsnprintf(3), and vasprintf(3). */
3042b15cb3dSCy Schubert #ifdef VA_START
3052b15cb3dSCy Schubert #undef VA_START
3062b15cb3dSCy Schubert #endif	/* defined(VA_START) */
3072b15cb3dSCy Schubert #ifdef VA_SHIFT
3082b15cb3dSCy Schubert #undef VA_SHIFT
3092b15cb3dSCy Schubert #endif	/* defined(VA_SHIFT) */
3102b15cb3dSCy Schubert #if HAVE_STDARG_H
311224ba2bdSOllivier Robert #include <stdarg.h>
3122b15cb3dSCy Schubert #define VA_START(ap, last) va_start(ap, last)
3132b15cb3dSCy Schubert #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
3142b15cb3dSCy Schubert #else	/* Assume <varargs.h> is available. */
315224ba2bdSOllivier Robert #include <varargs.h>
3162b15cb3dSCy Schubert #define VA_START(ap, last) va_start(ap)	/* "last" is ignored. */
3172b15cb3dSCy Schubert #define VA_SHIFT(ap, value, type) value = va_arg(ap, type)
3182b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
319224ba2bdSOllivier Robert 
3202b15cb3dSCy Schubert #if HW_WANT_RPL_VASPRINTF
3212b15cb3dSCy Schubert #if HAVE_STDLIB_H
3222b15cb3dSCy Schubert #include <stdlib.h>	/* For malloc(3). */
3232b15cb3dSCy Schubert #endif	/* HAVE_STDLIB_H */
3242b15cb3dSCy Schubert #ifdef VA_COPY
3252b15cb3dSCy Schubert #undef VA_COPY
3262b15cb3dSCy Schubert #endif	/* defined(VA_COPY) */
3272b15cb3dSCy Schubert #ifdef VA_END_COPY
3282b15cb3dSCy Schubert #undef VA_END_COPY
3292b15cb3dSCy Schubert #endif	/* defined(VA_END_COPY) */
3302b15cb3dSCy Schubert #if HAVE_VA_COPY
3312b15cb3dSCy Schubert #define VA_COPY(dest, src) va_copy(dest, src)
3322b15cb3dSCy Schubert #define VA_END_COPY(ap) va_end(ap)
3332b15cb3dSCy Schubert #elif HAVE___VA_COPY
3342b15cb3dSCy Schubert #define VA_COPY(dest, src) __va_copy(dest, src)
3352b15cb3dSCy Schubert #define VA_END_COPY(ap) va_end(ap)
3362b15cb3dSCy Schubert #else
3372b15cb3dSCy Schubert #define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list))
3382b15cb3dSCy Schubert #define VA_END_COPY(ap) /* No-op. */
3392b15cb3dSCy Schubert #define NEED_MYMEMCPY 1
3402b15cb3dSCy Schubert static void *mymemcpy(void *, void *, size_t);
3412b15cb3dSCy Schubert #endif	/* HAVE_VA_COPY */
3422b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_VASPRINTF */
3439c2daa00SOllivier Robert 
3442b15cb3dSCy Schubert #if HW_WANT_RPL_VSNPRINTF
3452b15cb3dSCy Schubert #include <errno.h>	/* For ERANGE and errno. */
3462b15cb3dSCy Schubert #include <limits.h>	/* For *_MAX. */
3472b15cb3dSCy Schubert #if HAVE_INTTYPES_H
3482b15cb3dSCy Schubert #include <inttypes.h>	/* For intmax_t (if not defined in <stdint.h>). */
3492b15cb3dSCy Schubert #endif	/* HAVE_INTTYPES_H */
3502b15cb3dSCy Schubert #if HAVE_LOCALE_H
3512b15cb3dSCy Schubert #include <locale.h>	/* For localeconv(3). */
3522b15cb3dSCy Schubert #endif	/* HAVE_LOCALE_H */
3532b15cb3dSCy Schubert #if HAVE_STDDEF_H
3542b15cb3dSCy Schubert #include <stddef.h>	/* For ptrdiff_t. */
3552b15cb3dSCy Schubert #endif	/* HAVE_STDDEF_H */
3562b15cb3dSCy Schubert #if HAVE_STDINT_H
3572b15cb3dSCy Schubert #include <stdint.h>	/* For intmax_t. */
3582b15cb3dSCy Schubert #endif	/* HAVE_STDINT_H */
3592b15cb3dSCy Schubert 
3602b15cb3dSCy Schubert /* Support for unsigned long long int.  We may also need ULLONG_MAX. */
3612b15cb3dSCy Schubert #ifndef ULONG_MAX	/* We may need ULONG_MAX as a fallback. */
3622b15cb3dSCy Schubert #ifdef UINT_MAX
3632b15cb3dSCy Schubert #define ULONG_MAX UINT_MAX
364224ba2bdSOllivier Robert #else
3652b15cb3dSCy Schubert #define ULONG_MAX INT_MAX
3662b15cb3dSCy Schubert #endif	/* defined(UINT_MAX) */
3672b15cb3dSCy Schubert #endif	/* !defined(ULONG_MAX) */
3682b15cb3dSCy Schubert #ifdef ULLONG
3692b15cb3dSCy Schubert #undef ULLONG
3702b15cb3dSCy Schubert #endif	/* defined(ULLONG) */
3712b15cb3dSCy Schubert #if HAVE_UNSIGNED_LONG_LONG_INT
3722b15cb3dSCy Schubert #define ULLONG unsigned long long int
3732b15cb3dSCy Schubert #ifndef ULLONG_MAX
3742b15cb3dSCy Schubert #define ULLONG_MAX ULONG_MAX
3752b15cb3dSCy Schubert #endif	/* !defined(ULLONG_MAX) */
376224ba2bdSOllivier Robert #else
3772b15cb3dSCy Schubert #define ULLONG unsigned long int
3782b15cb3dSCy Schubert #ifdef ULLONG_MAX
3792b15cb3dSCy Schubert #undef ULLONG_MAX
3802b15cb3dSCy Schubert #endif	/* defined(ULLONG_MAX) */
3812b15cb3dSCy Schubert #define ULLONG_MAX ULONG_MAX
3822b15cb3dSCy Schubert #endif	/* HAVE_LONG_LONG_INT */
3832b15cb3dSCy Schubert 
3842b15cb3dSCy Schubert /* Support for uintmax_t.  We also need UINTMAX_MAX. */
3852b15cb3dSCy Schubert #ifdef UINTMAX_T
3862b15cb3dSCy Schubert #undef UINTMAX_T
3872b15cb3dSCy Schubert #endif	/* defined(UINTMAX_T) */
3882b15cb3dSCy Schubert #if HAVE_UINTMAX_T || defined(uintmax_t)
3892b15cb3dSCy Schubert #define UINTMAX_T uintmax_t
3902b15cb3dSCy Schubert #ifndef UINTMAX_MAX
3912b15cb3dSCy Schubert #define UINTMAX_MAX ULLONG_MAX
3922b15cb3dSCy Schubert #endif	/* !defined(UINTMAX_MAX) */
393224ba2bdSOllivier Robert #else
3942b15cb3dSCy Schubert #define UINTMAX_T ULLONG
3952b15cb3dSCy Schubert #ifdef UINTMAX_MAX
3962b15cb3dSCy Schubert #undef UINTMAX_MAX
3972b15cb3dSCy Schubert #endif	/* defined(UINTMAX_MAX) */
3982b15cb3dSCy Schubert #define UINTMAX_MAX ULLONG_MAX
3992b15cb3dSCy Schubert #endif	/* HAVE_UINTMAX_T || defined(uintmax_t) */
4002b15cb3dSCy Schubert 
4012b15cb3dSCy Schubert /* Support for long double. */
4022b15cb3dSCy Schubert #ifndef LDOUBLE
4032b15cb3dSCy Schubert #if HAVE_LONG_DOUBLE
4042b15cb3dSCy Schubert #define LDOUBLE long double
4052b15cb3dSCy Schubert #else
4062b15cb3dSCy Schubert #define LDOUBLE double
4072b15cb3dSCy Schubert #endif	/* HAVE_LONG_DOUBLE */
4082b15cb3dSCy Schubert #endif	/* !defined(LDOUBLE) */
4092b15cb3dSCy Schubert 
4102b15cb3dSCy Schubert /* Support for long long int. */
4112b15cb3dSCy Schubert #ifndef LLONG
4122b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT
4132b15cb3dSCy Schubert #define LLONG long long int
4142b15cb3dSCy Schubert #else
4152b15cb3dSCy Schubert #define LLONG long int
4162b15cb3dSCy Schubert #endif	/* HAVE_LONG_LONG_INT */
4172b15cb3dSCy Schubert #endif	/* !defined(LLONG) */
4182b15cb3dSCy Schubert 
4192b15cb3dSCy Schubert /* Support for intmax_t. */
4202b15cb3dSCy Schubert #ifndef INTMAX_T
4212b15cb3dSCy Schubert #if HAVE_INTMAX_T || defined(intmax_t)
4222b15cb3dSCy Schubert #define INTMAX_T intmax_t
4232b15cb3dSCy Schubert #else
4242b15cb3dSCy Schubert #define INTMAX_T LLONG
4252b15cb3dSCy Schubert #endif	/* HAVE_INTMAX_T || defined(intmax_t) */
4262b15cb3dSCy Schubert #endif	/* !defined(INTMAX_T) */
4272b15cb3dSCy Schubert 
4282b15cb3dSCy Schubert /* Support for uintptr_t. */
4292b15cb3dSCy Schubert #ifndef UINTPTR_T
4302b15cb3dSCy Schubert #if HAVE_UINTPTR_T || defined(uintptr_t)
4312b15cb3dSCy Schubert #define UINTPTR_T uintptr_t
4322b15cb3dSCy Schubert #else
4332b15cb3dSCy Schubert #define UINTPTR_T unsigned long int
4342b15cb3dSCy Schubert #endif	/* HAVE_UINTPTR_T || defined(uintptr_t) */
4352b15cb3dSCy Schubert #endif	/* !defined(UINTPTR_T) */
4362b15cb3dSCy Schubert 
4372b15cb3dSCy Schubert /* Support for ptrdiff_t. */
4382b15cb3dSCy Schubert #ifndef PTRDIFF_T
4392b15cb3dSCy Schubert #if HAVE_PTRDIFF_T || defined(ptrdiff_t)
4402b15cb3dSCy Schubert #define PTRDIFF_T ptrdiff_t
4412b15cb3dSCy Schubert #else
4422b15cb3dSCy Schubert #define PTRDIFF_T long int
4432b15cb3dSCy Schubert #endif	/* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
4442b15cb3dSCy Schubert #endif	/* !defined(PTRDIFF_T) */
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert /*
4472b15cb3dSCy Schubert  * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
4482b15cb3dSCy Schubert  * 7.19.6.1, 7).  However, we'll simply use PTRDIFF_T and convert it to an
4492b15cb3dSCy Schubert  * unsigned type if necessary.  This should work just fine in practice.
4502b15cb3dSCy Schubert  */
4512b15cb3dSCy Schubert #ifndef UPTRDIFF_T
4522b15cb3dSCy Schubert #define UPTRDIFF_T PTRDIFF_T
4532b15cb3dSCy Schubert #endif	/* !defined(UPTRDIFF_T) */
4542b15cb3dSCy Schubert 
4552b15cb3dSCy Schubert /*
4562b15cb3dSCy Schubert  * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
4572b15cb3dSCy Schubert  * However, we'll simply use size_t and convert it to a signed type if
4582b15cb3dSCy Schubert  * necessary.  This should work just fine in practice.
4592b15cb3dSCy Schubert  */
4602b15cb3dSCy Schubert #ifndef SSIZE_T
4612b15cb3dSCy Schubert #define SSIZE_T size_t
4622b15cb3dSCy Schubert #endif	/* !defined(SSIZE_T) */
4632b15cb3dSCy Schubert 
4642b15cb3dSCy Schubert /* Either ERANGE or E2BIG should be available everywhere. */
4652b15cb3dSCy Schubert #ifndef ERANGE
4662b15cb3dSCy Schubert #define ERANGE E2BIG
4672b15cb3dSCy Schubert #endif	/* !defined(ERANGE) */
4682b15cb3dSCy Schubert #ifndef EOVERFLOW
4692b15cb3dSCy Schubert #define EOVERFLOW ERANGE
4702b15cb3dSCy Schubert #endif	/* !defined(EOVERFLOW) */
4712b15cb3dSCy Schubert 
4722b15cb3dSCy Schubert /*
4732b15cb3dSCy Schubert  * Buffer size to hold the octal string representation of UINT128_MAX without
4742b15cb3dSCy Schubert  * nul-termination ("3777777777777777777777777777777777777777777").
4752b15cb3dSCy Schubert  */
4762b15cb3dSCy Schubert #ifdef MAX_CONVERT_LENGTH
4772b15cb3dSCy Schubert #undef MAX_CONVERT_LENGTH
4782b15cb3dSCy Schubert #endif	/* defined(MAX_CONVERT_LENGTH) */
4792b15cb3dSCy Schubert #define MAX_CONVERT_LENGTH      43
4802b15cb3dSCy Schubert 
4812b15cb3dSCy Schubert /* Format read states. */
4822b15cb3dSCy Schubert #define PRINT_S_DEFAULT         0
4832b15cb3dSCy Schubert #define PRINT_S_FLAGS           1
4842b15cb3dSCy Schubert #define PRINT_S_WIDTH           2
4852b15cb3dSCy Schubert #define PRINT_S_DOT             3
4862b15cb3dSCy Schubert #define PRINT_S_PRECISION       4
4872b15cb3dSCy Schubert #define PRINT_S_MOD             5
4882b15cb3dSCy Schubert #define PRINT_S_CONV            6
4892b15cb3dSCy Schubert 
4902b15cb3dSCy Schubert /* Format flags. */
4912b15cb3dSCy Schubert #define PRINT_F_MINUS           (1 << 0)
4922b15cb3dSCy Schubert #define PRINT_F_PLUS            (1 << 1)
4932b15cb3dSCy Schubert #define PRINT_F_SPACE           (1 << 2)
4942b15cb3dSCy Schubert #define PRINT_F_NUM             (1 << 3)
4952b15cb3dSCy Schubert #define PRINT_F_ZERO            (1 << 4)
4962b15cb3dSCy Schubert #define PRINT_F_QUOTE           (1 << 5)
4972b15cb3dSCy Schubert #define PRINT_F_UP              (1 << 6)
4982b15cb3dSCy Schubert #define PRINT_F_UNSIGNED        (1 << 7)
4992b15cb3dSCy Schubert #define PRINT_F_TYPE_G          (1 << 8)
5002b15cb3dSCy Schubert #define PRINT_F_TYPE_E          (1 << 9)
5012b15cb3dSCy Schubert 
5022b15cb3dSCy Schubert /* Conversion flags. */
5032b15cb3dSCy Schubert #define PRINT_C_CHAR            1
5042b15cb3dSCy Schubert #define PRINT_C_SHORT           2
5052b15cb3dSCy Schubert #define PRINT_C_LONG            3
5062b15cb3dSCy Schubert #define PRINT_C_LLONG           4
5072b15cb3dSCy Schubert #define PRINT_C_LDOUBLE         5
5082b15cb3dSCy Schubert #define PRINT_C_SIZE            6
5092b15cb3dSCy Schubert #define PRINT_C_PTRDIFF         7
5102b15cb3dSCy Schubert #define PRINT_C_INTMAX          8
5112b15cb3dSCy Schubert 
5122b15cb3dSCy Schubert #ifndef MAX
5132b15cb3dSCy Schubert #define MAX(x, y) ((x >= y) ? x : y)
5142b15cb3dSCy Schubert #endif	/* !defined(MAX) */
5152b15cb3dSCy Schubert #ifndef CHARTOINT
5162b15cb3dSCy Schubert #define CHARTOINT(ch) (ch - '0')
5172b15cb3dSCy Schubert #endif	/* !defined(CHARTOINT) */
5182b15cb3dSCy Schubert #ifndef ISDIGIT
5192b15cb3dSCy Schubert #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
5202b15cb3dSCy Schubert #endif	/* !defined(ISDIGIT) */
5212b15cb3dSCy Schubert #ifndef ISNAN
5222b15cb3dSCy Schubert #define ISNAN(x) (x != x)
5232b15cb3dSCy Schubert #endif	/* !defined(ISNAN) */
5242b15cb3dSCy Schubert #ifndef ISINF
5252b15cb3dSCy Schubert #define ISINF(x) (x != 0.0 && x + x == x)
5262b15cb3dSCy Schubert #endif	/* !defined(ISINF) */
5272b15cb3dSCy Schubert 
5282b15cb3dSCy Schubert #ifdef OUTCHAR
5292b15cb3dSCy Schubert #undef OUTCHAR
5302b15cb3dSCy Schubert #endif	/* defined(OUTCHAR) */
5312b15cb3dSCy Schubert #define OUTCHAR(str, len, size, ch)                                          \
5322b15cb3dSCy Schubert do {                                                                         \
5332b15cb3dSCy Schubert 	if (len + 1 < size)                                                  \
5342b15cb3dSCy Schubert 		str[len] = ch;                                               \
5352b15cb3dSCy Schubert 	(len)++;                                                             \
5362b15cb3dSCy Schubert } while (/* CONSTCOND */ 0)
5372b15cb3dSCy Schubert 
5382b15cb3dSCy Schubert static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
5392b15cb3dSCy Schubert static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
5402b15cb3dSCy Schubert static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *);
5412b15cb3dSCy Schubert static void printsep(char *, size_t *, size_t);
5422b15cb3dSCy Schubert static int getnumsep(int);
5432b15cb3dSCy Schubert static int getexponent(LDOUBLE);
5442b15cb3dSCy Schubert static int convert(UINTMAX_T, char *, size_t, int, int);
5452b15cb3dSCy Schubert static UINTMAX_T cast(LDOUBLE);
5462b15cb3dSCy Schubert static UINTMAX_T myround(LDOUBLE);
5472b15cb3dSCy Schubert static LDOUBLE mypow10(int);
548224ba2bdSOllivier Robert 
549224ba2bdSOllivier Robert int
5502b15cb3dSCy Schubert rpl_vsnprintf(char *str, size_t size, const char *format, va_list args);
5512b15cb3dSCy Schubert 
5522b15cb3dSCy Schubert int
5532b15cb3dSCy Schubert rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
554224ba2bdSOllivier Robert {
5552b15cb3dSCy Schubert 	LDOUBLE fvalue;
5562b15cb3dSCy Schubert 	INTMAX_T value;
5572b15cb3dSCy Schubert 	unsigned char cvalue;
5582b15cb3dSCy Schubert 	const char *strvalue;
5592b15cb3dSCy Schubert 	INTMAX_T *intmaxptr;
5602b15cb3dSCy Schubert 	PTRDIFF_T *ptrdiffptr;
5612b15cb3dSCy Schubert 	SSIZE_T *sizeptr;
5622b15cb3dSCy Schubert 	LLONG *llongptr;
5632b15cb3dSCy Schubert 	long int *longptr;
5642b15cb3dSCy Schubert 	int *intptr;
5652b15cb3dSCy Schubert 	short int *shortptr;
5662b15cb3dSCy Schubert 	signed char *charptr;
5672b15cb3dSCy Schubert 	size_t len = 0;
5682b15cb3dSCy Schubert 	int overflow = 0;
5692b15cb3dSCy Schubert 	int base = 0;
5702b15cb3dSCy Schubert 	int cflags = 0;
5712b15cb3dSCy Schubert 	int flags = 0;
5722b15cb3dSCy Schubert 	int width = 0;
5732b15cb3dSCy Schubert 	int precision = -1;
5742b15cb3dSCy Schubert 	int state = PRINT_S_DEFAULT;
5752b15cb3dSCy Schubert 	char ch = *format++;
5762b15cb3dSCy Schubert 
5772b15cb3dSCy Schubert 	/*
5782b15cb3dSCy Schubert 	 * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
5792b15cb3dSCy Schubert 	 * pointer." (7.19.6.5, 2)  We're forgiving and allow a NULL pointer
5802b15cb3dSCy Schubert 	 * even if a size larger than zero was specified.  At least NetBSD's
5812b15cb3dSCy Schubert 	 * snprintf(3) does the same, as well as other versions of this file.
5822b15cb3dSCy Schubert 	 * (Though some of these versions will write to a non-NULL buffer even
5832b15cb3dSCy Schubert 	 * if a size of zero was specified, which violates the standard.)
5842b15cb3dSCy Schubert 	 */
5852b15cb3dSCy Schubert 	if (str == NULL && size != 0)
5862b15cb3dSCy Schubert 		size = 0;
5872b15cb3dSCy Schubert 
5882b15cb3dSCy Schubert 	while (ch != '\0')
5892b15cb3dSCy Schubert 		switch (state) {
5902b15cb3dSCy Schubert 		case PRINT_S_DEFAULT:
5912b15cb3dSCy Schubert 			if (ch == '%')
5922b15cb3dSCy Schubert 				state = PRINT_S_FLAGS;
5932b15cb3dSCy Schubert 			else
5942b15cb3dSCy Schubert 				OUTCHAR(str, len, size, ch);
5952b15cb3dSCy Schubert 			ch = *format++;
5962b15cb3dSCy Schubert 			break;
5972b15cb3dSCy Schubert 		case PRINT_S_FLAGS:
5982b15cb3dSCy Schubert 			switch (ch) {
5992b15cb3dSCy Schubert 			case '-':
6002b15cb3dSCy Schubert 				flags |= PRINT_F_MINUS;
6012b15cb3dSCy Schubert 				ch = *format++;
6022b15cb3dSCy Schubert 				break;
6032b15cb3dSCy Schubert 			case '+':
6042b15cb3dSCy Schubert 				flags |= PRINT_F_PLUS;
6052b15cb3dSCy Schubert 				ch = *format++;
6062b15cb3dSCy Schubert 				break;
6072b15cb3dSCy Schubert 			case ' ':
6082b15cb3dSCy Schubert 				flags |= PRINT_F_SPACE;
6092b15cb3dSCy Schubert 				ch = *format++;
6102b15cb3dSCy Schubert 				break;
6112b15cb3dSCy Schubert 			case '#':
6122b15cb3dSCy Schubert 				flags |= PRINT_F_NUM;
6132b15cb3dSCy Schubert 				ch = *format++;
6142b15cb3dSCy Schubert 				break;
6152b15cb3dSCy Schubert 			case '0':
6162b15cb3dSCy Schubert 				flags |= PRINT_F_ZERO;
6172b15cb3dSCy Schubert 				ch = *format++;
6182b15cb3dSCy Schubert 				break;
6192b15cb3dSCy Schubert 			case '\'':	/* SUSv2 flag (not in C99). */
6202b15cb3dSCy Schubert 				flags |= PRINT_F_QUOTE;
6212b15cb3dSCy Schubert 				ch = *format++;
6222b15cb3dSCy Schubert 				break;
6232b15cb3dSCy Schubert 			default:
6242b15cb3dSCy Schubert 				state = PRINT_S_WIDTH;
6252b15cb3dSCy Schubert 				break;
626224ba2bdSOllivier Robert 			}
6272b15cb3dSCy Schubert 			break;
6282b15cb3dSCy Schubert 		case PRINT_S_WIDTH:
6292b15cb3dSCy Schubert 			if (ISDIGIT(ch)) {
6302b15cb3dSCy Schubert 				ch = CHARTOINT(ch);
6312b15cb3dSCy Schubert 				if (width > (INT_MAX - ch) / 10) {
6322b15cb3dSCy Schubert 					overflow = 1;
6332b15cb3dSCy Schubert 					goto out;
6342b15cb3dSCy Schubert 				}
6352b15cb3dSCy Schubert 				width = 10 * width + ch;
6362b15cb3dSCy Schubert 				ch = *format++;
6372b15cb3dSCy Schubert 			} else if (ch == '*') {
6382b15cb3dSCy Schubert 				/*
6392b15cb3dSCy Schubert 				 * C99 says: "A negative field width argument is
6402b15cb3dSCy Schubert 				 * taken as a `-' flag followed by a positive
6412b15cb3dSCy Schubert 				 * field width." (7.19.6.1, 5)
6422b15cb3dSCy Schubert 				 */
6432b15cb3dSCy Schubert 				if ((width = va_arg(args, int)) < 0) {
6442b15cb3dSCy Schubert 					flags |= PRINT_F_MINUS;
6452b15cb3dSCy Schubert 					width = -width;
6462b15cb3dSCy Schubert 				}
6472b15cb3dSCy Schubert 				ch = *format++;
6482b15cb3dSCy Schubert 				state = PRINT_S_DOT;
6492b15cb3dSCy Schubert 			} else
6502b15cb3dSCy Schubert 				state = PRINT_S_DOT;
6512b15cb3dSCy Schubert 			break;
6522b15cb3dSCy Schubert 		case PRINT_S_DOT:
6532b15cb3dSCy Schubert 			if (ch == '.') {
6542b15cb3dSCy Schubert 				state = PRINT_S_PRECISION;
6552b15cb3dSCy Schubert 				ch = *format++;
6562b15cb3dSCy Schubert 			} else
6572b15cb3dSCy Schubert 				state = PRINT_S_MOD;
6582b15cb3dSCy Schubert 			break;
6592b15cb3dSCy Schubert 		case PRINT_S_PRECISION:
6602b15cb3dSCy Schubert 			if (precision == -1)
6612b15cb3dSCy Schubert 				precision = 0;
6622b15cb3dSCy Schubert 			if (ISDIGIT(ch)) {
6632b15cb3dSCy Schubert 				ch = CHARTOINT(ch);
6642b15cb3dSCy Schubert 				if (precision > (INT_MAX - ch) / 10) {
6652b15cb3dSCy Schubert 					overflow = 1;
6662b15cb3dSCy Schubert 					goto out;
6672b15cb3dSCy Schubert 				}
6682b15cb3dSCy Schubert 				precision = 10 * precision + ch;
6692b15cb3dSCy Schubert 				ch = *format++;
6702b15cb3dSCy Schubert 			} else if (ch == '*') {
6712b15cb3dSCy Schubert 				/*
6722b15cb3dSCy Schubert 				 * C99 says: "A negative precision argument is
6732b15cb3dSCy Schubert 				 * taken as if the precision were omitted."
6742b15cb3dSCy Schubert 				 * (7.19.6.1, 5)
6752b15cb3dSCy Schubert 				 */
6762b15cb3dSCy Schubert 				if ((precision = va_arg(args, int)) < 0)
6772b15cb3dSCy Schubert 					precision = -1;
6782b15cb3dSCy Schubert 				ch = *format++;
6792b15cb3dSCy Schubert 				state = PRINT_S_MOD;
6802b15cb3dSCy Schubert 			} else
6812b15cb3dSCy Schubert 				state = PRINT_S_MOD;
6822b15cb3dSCy Schubert 			break;
6832b15cb3dSCy Schubert 		case PRINT_S_MOD:
6842b15cb3dSCy Schubert 			switch (ch) {
6852b15cb3dSCy Schubert 			case 'h':
6862b15cb3dSCy Schubert 				ch = *format++;
6872b15cb3dSCy Schubert 				if (ch == 'h') {	/* It's a char. */
6882b15cb3dSCy Schubert 					ch = *format++;
6892b15cb3dSCy Schubert 					cflags = PRINT_C_CHAR;
6902b15cb3dSCy Schubert 				} else
6912b15cb3dSCy Schubert 					cflags = PRINT_C_SHORT;
6922b15cb3dSCy Schubert 				break;
6932b15cb3dSCy Schubert 			case 'l':
6942b15cb3dSCy Schubert 				ch = *format++;
6952b15cb3dSCy Schubert 				if (ch == 'l') {	/* It's a long long. */
6962b15cb3dSCy Schubert 					ch = *format++;
6972b15cb3dSCy Schubert 					cflags = PRINT_C_LLONG;
6982b15cb3dSCy Schubert 				} else
6992b15cb3dSCy Schubert 					cflags = PRINT_C_LONG;
7002b15cb3dSCy Schubert 				break;
7012b15cb3dSCy Schubert 			case 'L':
7022b15cb3dSCy Schubert 				cflags = PRINT_C_LDOUBLE;
7032b15cb3dSCy Schubert 				ch = *format++;
7042b15cb3dSCy Schubert 				break;
7052b15cb3dSCy Schubert 			case 'j':
7062b15cb3dSCy Schubert 				cflags = PRINT_C_INTMAX;
7072b15cb3dSCy Schubert 				ch = *format++;
7082b15cb3dSCy Schubert 				break;
7092b15cb3dSCy Schubert 			case 't':
7102b15cb3dSCy Schubert 				cflags = PRINT_C_PTRDIFF;
7112b15cb3dSCy Schubert 				ch = *format++;
7122b15cb3dSCy Schubert 				break;
7132b15cb3dSCy Schubert 			case 'z':
7142b15cb3dSCy Schubert 				cflags = PRINT_C_SIZE;
7152b15cb3dSCy Schubert 				ch = *format++;
7162b15cb3dSCy Schubert 				break;
7172b15cb3dSCy Schubert 			}
7182b15cb3dSCy Schubert 			state = PRINT_S_CONV;
7192b15cb3dSCy Schubert 			break;
7202b15cb3dSCy Schubert 		case PRINT_S_CONV:
7212b15cb3dSCy Schubert 			switch (ch) {
7222b15cb3dSCy Schubert 			case 'd':
7232b15cb3dSCy Schubert 				/* FALLTHROUGH */
7242b15cb3dSCy Schubert 			case 'i':
7252b15cb3dSCy Schubert 				switch (cflags) {
7262b15cb3dSCy Schubert 				case PRINT_C_CHAR:
7272b15cb3dSCy Schubert 					value = (signed char)va_arg(args, int);
7282b15cb3dSCy Schubert 					break;
7292b15cb3dSCy Schubert 				case PRINT_C_SHORT:
7302b15cb3dSCy Schubert 					value = (short int)va_arg(args, int);
7312b15cb3dSCy Schubert 					break;
7322b15cb3dSCy Schubert 				case PRINT_C_LONG:
7332b15cb3dSCy Schubert 					value = va_arg(args, long int);
7342b15cb3dSCy Schubert 					break;
7352b15cb3dSCy Schubert 				case PRINT_C_LLONG:
7362b15cb3dSCy Schubert 					value = va_arg(args, LLONG);
7372b15cb3dSCy Schubert 					break;
7382b15cb3dSCy Schubert 				case PRINT_C_SIZE:
7392b15cb3dSCy Schubert 					value = va_arg(args, SSIZE_T);
7402b15cb3dSCy Schubert 					break;
7412b15cb3dSCy Schubert 				case PRINT_C_INTMAX:
7422b15cb3dSCy Schubert 					value = va_arg(args, INTMAX_T);
7432b15cb3dSCy Schubert 					break;
7442b15cb3dSCy Schubert 				case PRINT_C_PTRDIFF:
7452b15cb3dSCy Schubert 					value = va_arg(args, PTRDIFF_T);
7462b15cb3dSCy Schubert 					break;
7472b15cb3dSCy Schubert 				default:
7482b15cb3dSCy Schubert 					value = va_arg(args, int);
7492b15cb3dSCy Schubert 					break;
7502b15cb3dSCy Schubert 				}
7512b15cb3dSCy Schubert 				fmtint(str, &len, size, value, 10, width,
7522b15cb3dSCy Schubert 				    precision, flags);
7532b15cb3dSCy Schubert 				break;
7542b15cb3dSCy Schubert 			case 'X':
7552b15cb3dSCy Schubert 				flags |= PRINT_F_UP;
7562b15cb3dSCy Schubert 				/* FALLTHROUGH */
7572b15cb3dSCy Schubert 			case 'x':
7582b15cb3dSCy Schubert 				base = 16;
7592b15cb3dSCy Schubert 				/* FALLTHROUGH */
7602b15cb3dSCy Schubert 			case 'o':
7612b15cb3dSCy Schubert 				if (base == 0)
7622b15cb3dSCy Schubert 					base = 8;
7632b15cb3dSCy Schubert 				/* FALLTHROUGH */
7642b15cb3dSCy Schubert 			case 'u':
7652b15cb3dSCy Schubert 				if (base == 0)
7662b15cb3dSCy Schubert 					base = 10;
7672b15cb3dSCy Schubert 				flags |= PRINT_F_UNSIGNED;
7682b15cb3dSCy Schubert 				switch (cflags) {
7692b15cb3dSCy Schubert 				case PRINT_C_CHAR:
7702b15cb3dSCy Schubert 					value = (unsigned char)va_arg(args,
7712b15cb3dSCy Schubert 					    unsigned int);
7722b15cb3dSCy Schubert 					break;
7732b15cb3dSCy Schubert 				case PRINT_C_SHORT:
7742b15cb3dSCy Schubert 					value = (unsigned short int)va_arg(args,
7752b15cb3dSCy Schubert 					    unsigned int);
7762b15cb3dSCy Schubert 					break;
7772b15cb3dSCy Schubert 				case PRINT_C_LONG:
7782b15cb3dSCy Schubert 					value = va_arg(args, unsigned long int);
7792b15cb3dSCy Schubert 					break;
7802b15cb3dSCy Schubert 				case PRINT_C_LLONG:
7812b15cb3dSCy Schubert 					value = va_arg(args, ULLONG);
7822b15cb3dSCy Schubert 					break;
7832b15cb3dSCy Schubert 				case PRINT_C_SIZE:
7842b15cb3dSCy Schubert 					value = va_arg(args, size_t);
7852b15cb3dSCy Schubert 					break;
7862b15cb3dSCy Schubert 				case PRINT_C_INTMAX:
7872b15cb3dSCy Schubert 					value = va_arg(args, UINTMAX_T);
7882b15cb3dSCy Schubert 					break;
7892b15cb3dSCy Schubert 				case PRINT_C_PTRDIFF:
7902b15cb3dSCy Schubert 					value = va_arg(args, UPTRDIFF_T);
7912b15cb3dSCy Schubert 					break;
7922b15cb3dSCy Schubert 				default:
7932b15cb3dSCy Schubert 					value = va_arg(args, unsigned int);
7942b15cb3dSCy Schubert 					break;
7952b15cb3dSCy Schubert 				}
7962b15cb3dSCy Schubert 				fmtint(str, &len, size, value, base, width,
7972b15cb3dSCy Schubert 				    precision, flags);
7982b15cb3dSCy Schubert 				break;
7992b15cb3dSCy Schubert 			case 'A':
8002b15cb3dSCy Schubert 				/* Not yet supported, we'll use "%F". */
8012b15cb3dSCy Schubert 				/* FALLTHROUGH */
8022b15cb3dSCy Schubert 			case 'F':
8032b15cb3dSCy Schubert 				flags |= PRINT_F_UP;
8042b15cb3dSCy Schubert 				/* FALLTHROUGH */
8052b15cb3dSCy Schubert 			case 'a':
8062b15cb3dSCy Schubert 				/* Not yet supported, we'll use "%f". */
8072b15cb3dSCy Schubert 				/* FALLTHROUGH */
8082b15cb3dSCy Schubert 			case 'f':
8092b15cb3dSCy Schubert 				if (cflags == PRINT_C_LDOUBLE)
8102b15cb3dSCy Schubert 					fvalue = va_arg(args, LDOUBLE);
8112b15cb3dSCy Schubert 				else
8122b15cb3dSCy Schubert 					fvalue = va_arg(args, double);
8132b15cb3dSCy Schubert 				fmtflt(str, &len, size, fvalue, width,
8142b15cb3dSCy Schubert 				    precision, flags, &overflow);
8152b15cb3dSCy Schubert 				if (overflow)
8162b15cb3dSCy Schubert 					goto out;
8172b15cb3dSCy Schubert 				break;
8182b15cb3dSCy Schubert 			case 'E':
8192b15cb3dSCy Schubert 				flags |= PRINT_F_UP;
8202b15cb3dSCy Schubert 				/* FALLTHROUGH */
8212b15cb3dSCy Schubert 			case 'e':
8222b15cb3dSCy Schubert 				flags |= PRINT_F_TYPE_E;
8232b15cb3dSCy Schubert 				if (cflags == PRINT_C_LDOUBLE)
8242b15cb3dSCy Schubert 					fvalue = va_arg(args, LDOUBLE);
8252b15cb3dSCy Schubert 				else
8262b15cb3dSCy Schubert 					fvalue = va_arg(args, double);
8272b15cb3dSCy Schubert 				fmtflt(str, &len, size, fvalue, width,
8282b15cb3dSCy Schubert 				    precision, flags, &overflow);
8292b15cb3dSCy Schubert 				if (overflow)
8302b15cb3dSCy Schubert 					goto out;
8312b15cb3dSCy Schubert 				break;
8322b15cb3dSCy Schubert 			case 'G':
8332b15cb3dSCy Schubert 				flags |= PRINT_F_UP;
8342b15cb3dSCy Schubert 				/* FALLTHROUGH */
8352b15cb3dSCy Schubert 			case 'g':
8362b15cb3dSCy Schubert 				flags |= PRINT_F_TYPE_G;
8372b15cb3dSCy Schubert 				if (cflags == PRINT_C_LDOUBLE)
8382b15cb3dSCy Schubert 					fvalue = va_arg(args, LDOUBLE);
8392b15cb3dSCy Schubert 				else
8402b15cb3dSCy Schubert 					fvalue = va_arg(args, double);
8412b15cb3dSCy Schubert 				/*
8422b15cb3dSCy Schubert 				 * If the precision is zero, it is treated as
8432b15cb3dSCy Schubert 				 * one (cf. C99: 7.19.6.1, 8).
8442b15cb3dSCy Schubert 				 */
8452b15cb3dSCy Schubert 				if (precision == 0)
8462b15cb3dSCy Schubert 					precision = 1;
8472b15cb3dSCy Schubert 				fmtflt(str, &len, size, fvalue, width,
8482b15cb3dSCy Schubert 				    precision, flags, &overflow);
8492b15cb3dSCy Schubert 				if (overflow)
8502b15cb3dSCy Schubert 					goto out;
8512b15cb3dSCy Schubert 				break;
8522b15cb3dSCy Schubert 			case 'c':
8532b15cb3dSCy Schubert 				cvalue = va_arg(args, int);
8542b15cb3dSCy Schubert 				OUTCHAR(str, len, size, cvalue);
8552b15cb3dSCy Schubert 				break;
8562b15cb3dSCy Schubert 			case 's':
8572b15cb3dSCy Schubert 				strvalue = va_arg(args, char *);
8582b15cb3dSCy Schubert 				fmtstr(str, &len, size, strvalue, width,
8592b15cb3dSCy Schubert 				    precision, flags);
8602b15cb3dSCy Schubert 				break;
8612b15cb3dSCy Schubert 			case 'p':
8622b15cb3dSCy Schubert 				/*
8632b15cb3dSCy Schubert 				 * C99 says: "The value of the pointer is
8642b15cb3dSCy Schubert 				 * converted to a sequence of printing
8652b15cb3dSCy Schubert 				 * characters, in an implementation-defined
8662b15cb3dSCy Schubert 				 * manner." (C99: 7.19.6.1, 8)
8672b15cb3dSCy Schubert 				 */
8682b15cb3dSCy Schubert 				if ((strvalue = va_arg(args, void *)) == NULL)
8692b15cb3dSCy Schubert 					/*
8702b15cb3dSCy Schubert 					 * We use the glibc format.  BSD prints
8712b15cb3dSCy Schubert 					 * "0x0", SysV "0".
8722b15cb3dSCy Schubert 					 */
8732b15cb3dSCy Schubert 					fmtstr(str, &len, size, "(nil)", width,
8742b15cb3dSCy Schubert 					    -1, flags);
8752b15cb3dSCy Schubert 				else {
8762b15cb3dSCy Schubert 					/*
8772b15cb3dSCy Schubert 					 * We use the BSD/glibc format.  SysV
8782b15cb3dSCy Schubert 					 * omits the "0x" prefix (which we emit
8792b15cb3dSCy Schubert 					 * using the PRINT_F_NUM flag).
8802b15cb3dSCy Schubert 					 */
8812b15cb3dSCy Schubert 					flags |= PRINT_F_NUM;
8822b15cb3dSCy Schubert 					flags |= PRINT_F_UNSIGNED;
8832b15cb3dSCy Schubert 					fmtint(str, &len, size,
8842b15cb3dSCy Schubert 					    (UINTPTR_T)strvalue, 16, width,
8852b15cb3dSCy Schubert 					    precision, flags);
8862b15cb3dSCy Schubert 				}
8872b15cb3dSCy Schubert 				break;
8882b15cb3dSCy Schubert 			case 'n':
8892b15cb3dSCy Schubert 				switch (cflags) {
8902b15cb3dSCy Schubert 				case PRINT_C_CHAR:
8912b15cb3dSCy Schubert 					charptr = va_arg(args, signed char *);
8923311ff84SXin LI 					*charptr = (signed char)len;
8932b15cb3dSCy Schubert 					break;
8942b15cb3dSCy Schubert 				case PRINT_C_SHORT:
8952b15cb3dSCy Schubert 					shortptr = va_arg(args, short int *);
8963311ff84SXin LI 					*shortptr = (short int)len;
8972b15cb3dSCy Schubert 					break;
8982b15cb3dSCy Schubert 				case PRINT_C_LONG:
8992b15cb3dSCy Schubert 					longptr = va_arg(args, long int *);
9003311ff84SXin LI 					*longptr = (long int)len;
9012b15cb3dSCy Schubert 					break;
9022b15cb3dSCy Schubert 				case PRINT_C_LLONG:
9032b15cb3dSCy Schubert 					llongptr = va_arg(args, LLONG *);
9043311ff84SXin LI 					*llongptr = (LLONG)len;
9052b15cb3dSCy Schubert 					break;
9062b15cb3dSCy Schubert 				case PRINT_C_SIZE:
9072b15cb3dSCy Schubert 					/*
9082b15cb3dSCy Schubert 					 * C99 says that with the "z" length
9092b15cb3dSCy Schubert 					 * modifier, "a following `n' conversion
9102b15cb3dSCy Schubert 					 * specifier applies to a pointer to a
9112b15cb3dSCy Schubert 					 * signed integer type corresponding to
9122b15cb3dSCy Schubert 					 * size_t argument." (7.19.6.1, 7)
9132b15cb3dSCy Schubert 					 */
9142b15cb3dSCy Schubert 					sizeptr = va_arg(args, SSIZE_T *);
9153311ff84SXin LI 					*sizeptr = (SSIZE_T)len;
9162b15cb3dSCy Schubert 					break;
9172b15cb3dSCy Schubert 				case PRINT_C_INTMAX:
9182b15cb3dSCy Schubert 					intmaxptr = va_arg(args, INTMAX_T *);
9193311ff84SXin LI 					*intmaxptr = (INTMAX_T)len;
9202b15cb3dSCy Schubert 					break;
9212b15cb3dSCy Schubert 				case PRINT_C_PTRDIFF:
9222b15cb3dSCy Schubert 					ptrdiffptr = va_arg(args, PTRDIFF_T *);
9233311ff84SXin LI 					*ptrdiffptr = (PTRDIFF_T)len;
9242b15cb3dSCy Schubert 					break;
9252b15cb3dSCy Schubert 				default:
9262b15cb3dSCy Schubert 					intptr = va_arg(args, int *);
9273311ff84SXin LI 					*intptr = (int)len;
9282b15cb3dSCy Schubert 					break;
9292b15cb3dSCy Schubert 				}
9302b15cb3dSCy Schubert 				break;
9312b15cb3dSCy Schubert 			case '%':	/* Print a "%" character verbatim. */
9322b15cb3dSCy Schubert 				OUTCHAR(str, len, size, ch);
9332b15cb3dSCy Schubert 				break;
9342b15cb3dSCy Schubert 			default:	/* Skip other characters. */
9352b15cb3dSCy Schubert 				break;
9362b15cb3dSCy Schubert 			}
9372b15cb3dSCy Schubert 			ch = *format++;
9382b15cb3dSCy Schubert 			state = PRINT_S_DEFAULT;
9392b15cb3dSCy Schubert 			base = cflags = flags = width = 0;
9402b15cb3dSCy Schubert 			precision = -1;
9412b15cb3dSCy Schubert 			break;
9422b15cb3dSCy Schubert 		}
9432b15cb3dSCy Schubert out:
9442b15cb3dSCy Schubert 	if (len < size)
9452b15cb3dSCy Schubert 		str[len] = '\0';
9462b15cb3dSCy Schubert 	else if (size > 0)
9472b15cb3dSCy Schubert 		str[size - 1] = '\0';
9482b15cb3dSCy Schubert 
9492b15cb3dSCy Schubert 	if (overflow || len >= INT_MAX) {
9502b15cb3dSCy Schubert 		errno = overflow ? EOVERFLOW : ERANGE;
9512b15cb3dSCy Schubert 		return -1;
9522b15cb3dSCy Schubert 	}
9532b15cb3dSCy Schubert 	return (int)len;
9542b15cb3dSCy Schubert }
9552b15cb3dSCy Schubert 
9562b15cb3dSCy Schubert static void
9572b15cb3dSCy Schubert fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
9582b15cb3dSCy Schubert        int precision, int flags)
9592b15cb3dSCy Schubert {
9602b15cb3dSCy Schubert 	int padlen, strln;	/* Amount to pad. */
9612b15cb3dSCy Schubert 	int noprecision = (precision == -1);
9622b15cb3dSCy Schubert 
9632b15cb3dSCy Schubert 	if (value == NULL)	/* We're forgiving. */
9642b15cb3dSCy Schubert 		value = "(null)";
9652b15cb3dSCy Schubert 
9662b15cb3dSCy Schubert 	/* If a precision was specified, don't read the string past it. */
9672b15cb3dSCy Schubert 	for (strln = 0; value[strln] != '\0' &&
9682b15cb3dSCy Schubert 	    (noprecision || strln < precision); strln++)
9692b15cb3dSCy Schubert 		continue;
9702b15cb3dSCy Schubert 
9712b15cb3dSCy Schubert 	if ((padlen = width - strln) < 0)
9722b15cb3dSCy Schubert 		padlen = 0;
9732b15cb3dSCy Schubert 	if (flags & PRINT_F_MINUS)	/* Left justify. */
9742b15cb3dSCy Schubert 		padlen = -padlen;
9752b15cb3dSCy Schubert 
9762b15cb3dSCy Schubert 	while (padlen > 0) {	/* Leading spaces. */
9772b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
9782b15cb3dSCy Schubert 		padlen--;
9792b15cb3dSCy Schubert 	}
9802b15cb3dSCy Schubert 	while (*value != '\0' && (noprecision || precision-- > 0)) {
9812b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, *value);
9822b15cb3dSCy Schubert 		value++;
9832b15cb3dSCy Schubert 	}
9842b15cb3dSCy Schubert 	while (padlen < 0) {	/* Trailing spaces. */
9852b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
9862b15cb3dSCy Schubert 		padlen++;
9872b15cb3dSCy Schubert 	}
9882b15cb3dSCy Schubert }
9892b15cb3dSCy Schubert 
9902b15cb3dSCy Schubert static void
9912b15cb3dSCy Schubert fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
9922b15cb3dSCy Schubert        int precision, int flags)
9932b15cb3dSCy Schubert {
9942b15cb3dSCy Schubert 	UINTMAX_T uvalue;
9952b15cb3dSCy Schubert 	char iconvert[MAX_CONVERT_LENGTH];
9962b15cb3dSCy Schubert 	char sign = 0;
9972b15cb3dSCy Schubert 	char hexprefix = 0;
9982b15cb3dSCy Schubert 	int spadlen = 0;	/* Amount to space pad. */
9992b15cb3dSCy Schubert 	int zpadlen = 0;	/* Amount to zero pad. */
10002b15cb3dSCy Schubert 	int pos;
10012b15cb3dSCy Schubert 	int separators = (flags & PRINT_F_QUOTE);
10022b15cb3dSCy Schubert 	int noprecision = (precision == -1);
10032b15cb3dSCy Schubert 
10042b15cb3dSCy Schubert 	if (flags & PRINT_F_UNSIGNED)
10052b15cb3dSCy Schubert 		uvalue = value;
10062b15cb3dSCy Schubert 	else {
10072b15cb3dSCy Schubert 		uvalue = (value >= 0) ? value : -value;
10082b15cb3dSCy Schubert 		if (value < 0)
10092b15cb3dSCy Schubert 			sign = '-';
10102b15cb3dSCy Schubert 		else if (flags & PRINT_F_PLUS)	/* Do a sign. */
10112b15cb3dSCy Schubert 			sign = '+';
10122b15cb3dSCy Schubert 		else if (flags & PRINT_F_SPACE)
10132b15cb3dSCy Schubert 			sign = ' ';
10142b15cb3dSCy Schubert 	}
10152b15cb3dSCy Schubert 
10162b15cb3dSCy Schubert 	pos = convert(uvalue, iconvert, sizeof(iconvert), base,
10172b15cb3dSCy Schubert 	    flags & PRINT_F_UP);
10182b15cb3dSCy Schubert 
10192b15cb3dSCy Schubert 	if (flags & PRINT_F_NUM && uvalue != 0) {
10202b15cb3dSCy Schubert 		/*
10212b15cb3dSCy Schubert 		 * C99 says: "The result is converted to an `alternative form'.
10222b15cb3dSCy Schubert 		 * For `o' conversion, it increases the precision, if and only
10232b15cb3dSCy Schubert 		 * if necessary, to force the first digit of the result to be a
10242b15cb3dSCy Schubert 		 * zero (if the value and precision are both 0, a single 0 is
10252b15cb3dSCy Schubert 		 * printed).  For `x' (or `X') conversion, a nonzero result has
10262b15cb3dSCy Schubert 		 * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
10272b15cb3dSCy Schubert 		 */
10282b15cb3dSCy Schubert 		switch (base) {
10292b15cb3dSCy Schubert 		case 8:
10302b15cb3dSCy Schubert 			if (precision <= pos)
10312b15cb3dSCy Schubert 				precision = pos + 1;
10322b15cb3dSCy Schubert 			break;
10332b15cb3dSCy Schubert 		case 16:
10342b15cb3dSCy Schubert 			hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
10352b15cb3dSCy Schubert 			break;
10362b15cb3dSCy Schubert 		}
10372b15cb3dSCy Schubert 	}
10382b15cb3dSCy Schubert 
10392b15cb3dSCy Schubert 	if (separators)	/* Get the number of group separators we'll print. */
10402b15cb3dSCy Schubert 		separators = getnumsep(pos);
10412b15cb3dSCy Schubert 
10422b15cb3dSCy Schubert 	zpadlen = precision - pos - separators;
10432b15cb3dSCy Schubert 	spadlen = width                         /* Minimum field width. */
10442b15cb3dSCy Schubert 	    - separators                        /* Number of separators. */
10452b15cb3dSCy Schubert 	    - MAX(precision, pos)               /* Number of integer digits. */
10462b15cb3dSCy Schubert 	    - ((sign != 0) ? 1 : 0)             /* Will we print a sign? */
10472b15cb3dSCy Schubert 	    - ((hexprefix != 0) ? 2 : 0);       /* Will we print a prefix? */
10482b15cb3dSCy Schubert 
10492b15cb3dSCy Schubert 	if (zpadlen < 0)
10502b15cb3dSCy Schubert 		zpadlen = 0;
10512b15cb3dSCy Schubert 	if (spadlen < 0)
10522b15cb3dSCy Schubert 		spadlen = 0;
10532b15cb3dSCy Schubert 
10542b15cb3dSCy Schubert 	/*
10552b15cb3dSCy Schubert 	 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
10562b15cb3dSCy Schubert 	 * ignored.  For `d', `i', `o', `u', `x', and `X' conversions, if a
10572b15cb3dSCy Schubert 	 * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
10582b15cb3dSCy Schubert 	 */
10592b15cb3dSCy Schubert 	if (flags & PRINT_F_MINUS)	/* Left justify. */
10602b15cb3dSCy Schubert 		spadlen = -spadlen;
10612b15cb3dSCy Schubert 	else if (flags & PRINT_F_ZERO && noprecision) {
10622b15cb3dSCy Schubert 		zpadlen += spadlen;
10632b15cb3dSCy Schubert 		spadlen = 0;
10642b15cb3dSCy Schubert 	}
10652b15cb3dSCy Schubert 	while (spadlen > 0) {	/* Leading spaces. */
10662b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
10672b15cb3dSCy Schubert 		spadlen--;
10682b15cb3dSCy Schubert 	}
10692b15cb3dSCy Schubert 	if (sign != 0)	/* Sign. */
10702b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, sign);
10712b15cb3dSCy Schubert 	if (hexprefix != 0) {	/* A "0x" or "0X" prefix. */
10722b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, '0');
10732b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, hexprefix);
10742b15cb3dSCy Schubert 	}
10752b15cb3dSCy Schubert 	while (zpadlen > 0) {	/* Leading zeros. */
10762b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, '0');
10772b15cb3dSCy Schubert 		zpadlen--;
10782b15cb3dSCy Schubert 	}
10792b15cb3dSCy Schubert 	while (pos > 0) {	/* The actual digits. */
10802b15cb3dSCy Schubert 		pos--;
10812b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, iconvert[pos]);
10822b15cb3dSCy Schubert 		if (separators > 0 && pos > 0 && pos % 3 == 0)
10832b15cb3dSCy Schubert 			printsep(str, len, size);
10842b15cb3dSCy Schubert 	}
10852b15cb3dSCy Schubert 	while (spadlen < 0) {	/* Trailing spaces. */
10862b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
10872b15cb3dSCy Schubert 		spadlen++;
10882b15cb3dSCy Schubert 	}
10892b15cb3dSCy Schubert }
10902b15cb3dSCy Schubert 
10912b15cb3dSCy Schubert static void
10922b15cb3dSCy Schubert fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
10932b15cb3dSCy Schubert        int precision, int flags, int *overflow)
10942b15cb3dSCy Schubert {
10952b15cb3dSCy Schubert 	LDOUBLE ufvalue;
10962b15cb3dSCy Schubert 	UINTMAX_T intpart;
10972b15cb3dSCy Schubert 	UINTMAX_T fracpart;
10982b15cb3dSCy Schubert 	UINTMAX_T mask;
10992b15cb3dSCy Schubert 	const char *infnan = NULL;
11002b15cb3dSCy Schubert 	char iconvert[MAX_CONVERT_LENGTH];
11012b15cb3dSCy Schubert 	char fconvert[MAX_CONVERT_LENGTH];
11022b15cb3dSCy Schubert 	char econvert[4];	/* "e-12" (without nul-termination). */
11032b15cb3dSCy Schubert 	char esign = 0;
11042b15cb3dSCy Schubert 	char sign = 0;
11052b15cb3dSCy Schubert 	int leadfraczeros = 0;
11062b15cb3dSCy Schubert 	int exponent = 0;
11072b15cb3dSCy Schubert 	int emitpoint = 0;
11082b15cb3dSCy Schubert 	int omitzeros = 0;
11092b15cb3dSCy Schubert 	int omitcount = 0;
11102b15cb3dSCy Schubert 	int padlen = 0;
11112b15cb3dSCy Schubert 	int epos = 0;
11122b15cb3dSCy Schubert 	int fpos = 0;
11132b15cb3dSCy Schubert 	int ipos = 0;
11142b15cb3dSCy Schubert 	int separators = (flags & PRINT_F_QUOTE);
11152b15cb3dSCy Schubert 	int estyle = (flags & PRINT_F_TYPE_E);
11162b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
11172b15cb3dSCy Schubert 	struct lconv *lc = localeconv();
11182b15cb3dSCy Schubert #endif	/* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
11192b15cb3dSCy Schubert 
11202b15cb3dSCy Schubert 	/*
11212b15cb3dSCy Schubert 	 * AIX' man page says the default is 0, but C99 and at least Solaris'
11222b15cb3dSCy Schubert 	 * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
11232b15cb3dSCy Schubert 	 * defaults to 6.
11242b15cb3dSCy Schubert 	 */
11252b15cb3dSCy Schubert 	if (precision == -1)
11262b15cb3dSCy Schubert 		precision = 6;
11272b15cb3dSCy Schubert 
11282b15cb3dSCy Schubert 	if (fvalue < 0.0)
11292b15cb3dSCy Schubert 		sign = '-';
11302b15cb3dSCy Schubert 	else if (flags & PRINT_F_PLUS)	/* Do a sign. */
11312b15cb3dSCy Schubert 		sign = '+';
11322b15cb3dSCy Schubert 	else if (flags & PRINT_F_SPACE)
11332b15cb3dSCy Schubert 		sign = ' ';
11342b15cb3dSCy Schubert 
11352b15cb3dSCy Schubert 	if (ISNAN(fvalue))
11362b15cb3dSCy Schubert 		infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
11372b15cb3dSCy Schubert 	else if (ISINF(fvalue))
11382b15cb3dSCy Schubert 		infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
11392b15cb3dSCy Schubert 
11402b15cb3dSCy Schubert 	if (infnan != NULL) {
11412b15cb3dSCy Schubert 		if (sign != 0)
11422b15cb3dSCy Schubert 			iconvert[ipos++] = sign;
11432b15cb3dSCy Schubert 		while (*infnan != '\0')
11442b15cb3dSCy Schubert 			iconvert[ipos++] = *infnan++;
11452b15cb3dSCy Schubert 		fmtstr(str, len, size, iconvert, width, ipos, flags);
11462b15cb3dSCy Schubert 		return;
11472b15cb3dSCy Schubert 	}
11482b15cb3dSCy Schubert 
11492b15cb3dSCy Schubert 	/* "%e" (or "%E") or "%g" (or "%G") conversion. */
11502b15cb3dSCy Schubert 	if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
11512b15cb3dSCy Schubert 		if (flags & PRINT_F_TYPE_G) {
11522b15cb3dSCy Schubert 			/*
11532b15cb3dSCy Schubert 			 * For "%g" (and "%G") conversions, the precision
11542b15cb3dSCy Schubert 			 * specifies the number of significant digits, which
11552b15cb3dSCy Schubert 			 * includes the digits in the integer part.  The
11562b15cb3dSCy Schubert 			 * conversion will or will not be using "e-style" (like
11572b15cb3dSCy Schubert 			 * "%e" or "%E" conversions) depending on the precision
11582b15cb3dSCy Schubert 			 * and on the exponent.  However, the exponent can be
11592b15cb3dSCy Schubert 			 * affected by rounding the converted value, so we'll
11602b15cb3dSCy Schubert 			 * leave this decision for later.  Until then, we'll
11612b15cb3dSCy Schubert 			 * assume that we're going to do an "e-style" conversion
11622b15cb3dSCy Schubert 			 * (in order to get the exponent calculated).  For
11632b15cb3dSCy Schubert 			 * "e-style", the precision must be decremented by one.
11642b15cb3dSCy Schubert 			 */
11652b15cb3dSCy Schubert 			precision--;
11662b15cb3dSCy Schubert 			/*
11672b15cb3dSCy Schubert 			 * For "%g" (and "%G") conversions, trailing zeros are
11682b15cb3dSCy Schubert 			 * removed from the fractional portion of the result
11692b15cb3dSCy Schubert 			 * unless the "#" flag was specified.
11702b15cb3dSCy Schubert 			 */
11712b15cb3dSCy Schubert 			if (!(flags & PRINT_F_NUM))
11722b15cb3dSCy Schubert 				omitzeros = 1;
11732b15cb3dSCy Schubert 		}
11742b15cb3dSCy Schubert 		exponent = getexponent(fvalue);
11752b15cb3dSCy Schubert 		estyle = 1;
11762b15cb3dSCy Schubert 	}
11772b15cb3dSCy Schubert 
11782b15cb3dSCy Schubert again:
11792b15cb3dSCy Schubert 	/*
11802b15cb3dSCy Schubert 	 * Sorry, we only support 9, 19, or 38 digits (that is, the number of
11812b15cb3dSCy Schubert 	 * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
11822b15cb3dSCy Schubert 	 * minus one) past the decimal point due to our conversion method.
11832b15cb3dSCy Schubert 	 */
11842b15cb3dSCy Schubert 	switch (sizeof(UINTMAX_T)) {
11852b15cb3dSCy Schubert 	case 16:
11862b15cb3dSCy Schubert 		if (precision > 38)
11872b15cb3dSCy Schubert 			precision = 38;
11882b15cb3dSCy Schubert 		break;
11892b15cb3dSCy Schubert 	case 8:
11902b15cb3dSCy Schubert 		if (precision > 19)
11912b15cb3dSCy Schubert 			precision = 19;
11922b15cb3dSCy Schubert 		break;
11932b15cb3dSCy Schubert 	default:
11942b15cb3dSCy Schubert 		if (precision > 9)
11952b15cb3dSCy Schubert 			precision = 9;
11962b15cb3dSCy Schubert 		break;
11972b15cb3dSCy Schubert 	}
11982b15cb3dSCy Schubert 
11992b15cb3dSCy Schubert 	ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
12002b15cb3dSCy Schubert 	if (estyle)	/* We want exactly one integer digit. */
12012b15cb3dSCy Schubert 		ufvalue /= mypow10(exponent);
12022b15cb3dSCy Schubert 
12032b15cb3dSCy Schubert 	if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
12042b15cb3dSCy Schubert 		*overflow = 1;
12052b15cb3dSCy Schubert 		return;
12062b15cb3dSCy Schubert 	}
12072b15cb3dSCy Schubert 
12082b15cb3dSCy Schubert 	/*
12092b15cb3dSCy Schubert 	 * Factor of ten with the number of digits needed for the fractional
12102b15cb3dSCy Schubert 	 * part.  For example, if the precision is 3, the mask will be 1000.
12112b15cb3dSCy Schubert 	 */
12123311ff84SXin LI 	mask = (UINTMAX_T)mypow10(precision);
12132b15cb3dSCy Schubert 	/*
12142b15cb3dSCy Schubert 	 * We "cheat" by converting the fractional part to integer by
12152b15cb3dSCy Schubert 	 * multiplying by a factor of ten.
12162b15cb3dSCy Schubert 	 */
12172b15cb3dSCy Schubert 	if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
12182b15cb3dSCy Schubert 		/*
12192b15cb3dSCy Schubert 		 * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
12202b15cb3dSCy Schubert 		 * (because precision = 3).  Now, myround(1000 * 0.99962) will
12212b15cb3dSCy Schubert 		 * return 1000.  So, the integer part must be incremented by one
12222b15cb3dSCy Schubert 		 * and the fractional part must be set to zero.
12232b15cb3dSCy Schubert 		 */
12242b15cb3dSCy Schubert 		intpart++;
12252b15cb3dSCy Schubert 		fracpart = 0;
12262b15cb3dSCy Schubert 		if (estyle && intpart == 10) {
12272b15cb3dSCy Schubert 			/*
12282b15cb3dSCy Schubert 			 * The value was rounded up to ten, but we only want one
12292b15cb3dSCy Schubert 			 * integer digit if using "e-style".  So, the integer
12302b15cb3dSCy Schubert 			 * part must be set to one and the exponent must be
12312b15cb3dSCy Schubert 			 * incremented by one.
12322b15cb3dSCy Schubert 			 */
12332b15cb3dSCy Schubert 			intpart = 1;
12342b15cb3dSCy Schubert 			exponent++;
12352b15cb3dSCy Schubert 		}
12362b15cb3dSCy Schubert 	}
12372b15cb3dSCy Schubert 
12382b15cb3dSCy Schubert 	/*
12392b15cb3dSCy Schubert 	 * Now that we know the real exponent, we can check whether or not to
12402b15cb3dSCy Schubert 	 * use "e-style" for "%g" (and "%G") conversions.  If we don't need
12412b15cb3dSCy Schubert 	 * "e-style", the precision must be adjusted and the integer and
12422b15cb3dSCy Schubert 	 * fractional parts must be recalculated from the original value.
12432b15cb3dSCy Schubert 	 *
12442b15cb3dSCy Schubert 	 * C99 says: "Let P equal the precision if nonzero, 6 if the precision
12452b15cb3dSCy Schubert 	 * is omitted, or 1 if the precision is zero.  Then, if a conversion
12462b15cb3dSCy Schubert 	 * with style `E' would have an exponent of X:
12472b15cb3dSCy Schubert 	 *
12482b15cb3dSCy Schubert 	 * - if P > X >= -4, the conversion is with style `f' (or `F') and
12492b15cb3dSCy Schubert 	 *   precision P - (X + 1).
12502b15cb3dSCy Schubert 	 *
12512b15cb3dSCy Schubert 	 * - otherwise, the conversion is with style `e' (or `E') and precision
12522b15cb3dSCy Schubert 	 *   P - 1." (7.19.6.1, 8)
12532b15cb3dSCy Schubert 	 *
12542b15cb3dSCy Schubert 	 * Note that we had decremented the precision by one.
12552b15cb3dSCy Schubert 	 */
12562b15cb3dSCy Schubert 	if (flags & PRINT_F_TYPE_G && estyle &&
12572b15cb3dSCy Schubert 	    precision + 1 > exponent && exponent >= -4) {
12582b15cb3dSCy Schubert 		precision -= exponent;
12592b15cb3dSCy Schubert 		estyle = 0;
12602b15cb3dSCy Schubert 		goto again;
12612b15cb3dSCy Schubert 	}
12622b15cb3dSCy Schubert 
12632b15cb3dSCy Schubert 	if (estyle) {
12642b15cb3dSCy Schubert 		if (exponent < 0) {
12652b15cb3dSCy Schubert 			exponent = -exponent;
12662b15cb3dSCy Schubert 			esign = '-';
12672b15cb3dSCy Schubert 		} else
12682b15cb3dSCy Schubert 			esign = '+';
12692b15cb3dSCy Schubert 
12702b15cb3dSCy Schubert 		/*
12712b15cb3dSCy Schubert 		 * Convert the exponent.  The sizeof(econvert) is 4.  So, the
12722b15cb3dSCy Schubert 		 * econvert buffer can hold e.g. "e+99" and "e-99".  We don't
12732b15cb3dSCy Schubert 		 * support an exponent which contains more than two digits.
12742b15cb3dSCy Schubert 		 * Therefore, the following stores are safe.
12752b15cb3dSCy Schubert 		 */
12762b15cb3dSCy Schubert 		epos = convert(exponent, econvert, 2, 10, 0);
12772b15cb3dSCy Schubert 		/*
12782b15cb3dSCy Schubert 		 * C99 says: "The exponent always contains at least two digits,
12792b15cb3dSCy Schubert 		 * and only as many more digits as necessary to represent the
12802b15cb3dSCy Schubert 		 * exponent." (7.19.6.1, 8)
12812b15cb3dSCy Schubert 		 */
12822b15cb3dSCy Schubert 		if (epos == 1)
12832b15cb3dSCy Schubert 			econvert[epos++] = '0';
12842b15cb3dSCy Schubert 		econvert[epos++] = esign;
12852b15cb3dSCy Schubert 		econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
12862b15cb3dSCy Schubert 	}
12872b15cb3dSCy Schubert 
12882b15cb3dSCy Schubert 	/* Convert the integer part and the fractional part. */
12892b15cb3dSCy Schubert 	ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
12902b15cb3dSCy Schubert 	if (fracpart != 0)	/* convert() would return 1 if fracpart == 0. */
12912b15cb3dSCy Schubert 		fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
12922b15cb3dSCy Schubert 
12932b15cb3dSCy Schubert 	leadfraczeros = precision - fpos;
12942b15cb3dSCy Schubert 
12952b15cb3dSCy Schubert 	if (omitzeros) {
12962b15cb3dSCy Schubert 		if (fpos > 0)	/* Omit trailing fractional part zeros. */
12972b15cb3dSCy Schubert 			while (omitcount < fpos && fconvert[omitcount] == '0')
12982b15cb3dSCy Schubert 				omitcount++;
12992b15cb3dSCy Schubert 		else {	/* The fractional part is zero, omit it completely. */
13002b15cb3dSCy Schubert 			omitcount = precision;
13012b15cb3dSCy Schubert 			leadfraczeros = 0;
13022b15cb3dSCy Schubert 		}
13032b15cb3dSCy Schubert 		precision -= omitcount;
13042b15cb3dSCy Schubert 	}
13052b15cb3dSCy Schubert 
13062b15cb3dSCy Schubert 	/*
13072b15cb3dSCy Schubert 	 * Print a decimal point if either the fractional part is non-zero
13082b15cb3dSCy Schubert 	 * and/or the "#" flag was specified.
13092b15cb3dSCy Schubert 	 */
13102b15cb3dSCy Schubert 	if (precision > 0 || flags & PRINT_F_NUM)
13112b15cb3dSCy Schubert 		emitpoint = 1;
13122b15cb3dSCy Schubert 	if (separators)	/* Get the number of group separators we'll print. */
13132b15cb3dSCy Schubert 		separators = getnumsep(ipos);
13142b15cb3dSCy Schubert 
13152b15cb3dSCy Schubert 	padlen = width                  /* Minimum field width. */
13162b15cb3dSCy Schubert 	    - ipos                      /* Number of integer digits. */
13172b15cb3dSCy Schubert 	    - epos                      /* Number of exponent characters. */
13182b15cb3dSCy Schubert 	    - precision                 /* Number of fractional digits. */
13192b15cb3dSCy Schubert 	    - separators                /* Number of group separators. */
13202b15cb3dSCy Schubert 	    - (emitpoint ? 1 : 0)       /* Will we print a decimal point? */
13212b15cb3dSCy Schubert 	    - ((sign != 0) ? 1 : 0);    /* Will we print a sign character? */
13222b15cb3dSCy Schubert 
13232b15cb3dSCy Schubert 	if (padlen < 0)
13242b15cb3dSCy Schubert 		padlen = 0;
13252b15cb3dSCy Schubert 
13262b15cb3dSCy Schubert 	/*
13272b15cb3dSCy Schubert 	 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
13282b15cb3dSCy Schubert 	 * ignored." (7.19.6.1, 6)
13292b15cb3dSCy Schubert 	 */
13302b15cb3dSCy Schubert 	if (flags & PRINT_F_MINUS)	/* Left justifty. */
13312b15cb3dSCy Schubert 		padlen = -padlen;
13322b15cb3dSCy Schubert 	else if (flags & PRINT_F_ZERO && padlen > 0) {
13332b15cb3dSCy Schubert 		if (sign != 0) {	/* Sign. */
13342b15cb3dSCy Schubert 			OUTCHAR(str, *len, size, sign);
13352b15cb3dSCy Schubert 			sign = 0;
13362b15cb3dSCy Schubert 		}
13372b15cb3dSCy Schubert 		while (padlen > 0) {	/* Leading zeros. */
13382b15cb3dSCy Schubert 			OUTCHAR(str, *len, size, '0');
13392b15cb3dSCy Schubert 			padlen--;
13402b15cb3dSCy Schubert 		}
13412b15cb3dSCy Schubert 	}
13422b15cb3dSCy Schubert 	while (padlen > 0) {	/* Leading spaces. */
13432b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
13442b15cb3dSCy Schubert 		padlen--;
13452b15cb3dSCy Schubert 	}
13462b15cb3dSCy Schubert 	if (sign != 0)	/* Sign. */
13472b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, sign);
13482b15cb3dSCy Schubert 	while (ipos > 0) {	/* Integer part. */
13492b15cb3dSCy Schubert 		ipos--;
13502b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, iconvert[ipos]);
13512b15cb3dSCy Schubert 		if (separators > 0 && ipos > 0 && ipos % 3 == 0)
13522b15cb3dSCy Schubert 			printsep(str, len, size);
13532b15cb3dSCy Schubert 	}
13542b15cb3dSCy Schubert 	if (emitpoint) {	/* Decimal point. */
13552b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
13562b15cb3dSCy Schubert 		if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
13572b15cb3dSCy Schubert 			OUTCHAR(str, *len, size, *lc->decimal_point);
13582b15cb3dSCy Schubert 		else	/* We'll always print some decimal point character. */
13592b15cb3dSCy Schubert #endif	/* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
13602b15cb3dSCy Schubert 			OUTCHAR(str, *len, size, '.');
13612b15cb3dSCy Schubert 	}
13622b15cb3dSCy Schubert 	while (leadfraczeros > 0) {	/* Leading fractional part zeros. */
13632b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, '0');
13642b15cb3dSCy Schubert 		leadfraczeros--;
13652b15cb3dSCy Schubert 	}
13662b15cb3dSCy Schubert 	while (fpos > omitcount) {	/* The remaining fractional part. */
13672b15cb3dSCy Schubert 		fpos--;
13682b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, fconvert[fpos]);
13692b15cb3dSCy Schubert 	}
13702b15cb3dSCy Schubert 	while (epos > 0) {	/* Exponent. */
13712b15cb3dSCy Schubert 		epos--;
13722b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, econvert[epos]);
13732b15cb3dSCy Schubert 	}
13742b15cb3dSCy Schubert 	while (padlen < 0) {	/* Trailing spaces. */
13752b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ' ');
13762b15cb3dSCy Schubert 		padlen++;
13772b15cb3dSCy Schubert 	}
13782b15cb3dSCy Schubert }
13792b15cb3dSCy Schubert 
13802b15cb3dSCy Schubert static void
13812b15cb3dSCy Schubert printsep(char *str, size_t *len, size_t size)
13822b15cb3dSCy Schubert {
13832b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
13842b15cb3dSCy Schubert 	struct lconv *lc = localeconv();
13852b15cb3dSCy Schubert 	int i;
13862b15cb3dSCy Schubert 
13872b15cb3dSCy Schubert 	if (lc->thousands_sep != NULL)
13882b15cb3dSCy Schubert 		for (i = 0; lc->thousands_sep[i] != '\0'; i++)
13892b15cb3dSCy Schubert 			OUTCHAR(str, *len, size, lc->thousands_sep[i]);
13902b15cb3dSCy Schubert 	else
13912b15cb3dSCy Schubert #endif	/* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
13922b15cb3dSCy Schubert 		OUTCHAR(str, *len, size, ',');
13932b15cb3dSCy Schubert }
13942b15cb3dSCy Schubert 
13952b15cb3dSCy Schubert static int
13962b15cb3dSCy Schubert getnumsep(int digits)
13972b15cb3dSCy Schubert {
13982b15cb3dSCy Schubert 	int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
13992b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
14002b15cb3dSCy Schubert 	int strln;
14012b15cb3dSCy Schubert 	struct lconv *lc = localeconv();
14022b15cb3dSCy Schubert 
14032b15cb3dSCy Schubert 	/* We support an arbitrary separator length (including zero). */
14042b15cb3dSCy Schubert 	if (lc->thousands_sep != NULL) {
14052b15cb3dSCy Schubert 		for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
14062b15cb3dSCy Schubert 			continue;
14072b15cb3dSCy Schubert 		separators *= strln;
14082b15cb3dSCy Schubert 	}
14092b15cb3dSCy Schubert #endif	/* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
14102b15cb3dSCy Schubert 	return separators;
14112b15cb3dSCy Schubert }
14122b15cb3dSCy Schubert 
14132b15cb3dSCy Schubert static int
14142b15cb3dSCy Schubert getexponent(LDOUBLE value)
14152b15cb3dSCy Schubert {
14162b15cb3dSCy Schubert 	LDOUBLE tmp = (value >= 0.0) ? value : -value;
14172b15cb3dSCy Schubert 	int exponent = 0;
14182b15cb3dSCy Schubert 
14192b15cb3dSCy Schubert 	/*
14202b15cb3dSCy Schubert 	 * We check for 99 > exponent > -99 in order to work around possible
14212b15cb3dSCy Schubert 	 * endless loops which could happen (at least) in the second loop (at
14222b15cb3dSCy Schubert 	 * least) if we're called with an infinite value.  However, we checked
14232b15cb3dSCy Schubert 	 * for infinity before calling this function using our ISINF() macro, so
14242b15cb3dSCy Schubert 	 * this might be somewhat paranoid.
14252b15cb3dSCy Schubert 	 */
14262b15cb3dSCy Schubert 	while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
14272b15cb3dSCy Schubert 		tmp *= 10;
14282b15cb3dSCy Schubert 	while (tmp >= 10.0 && ++exponent < 99)
14292b15cb3dSCy Schubert 		tmp /= 10;
14302b15cb3dSCy Schubert 
14312b15cb3dSCy Schubert 	return exponent;
14322b15cb3dSCy Schubert }
14332b15cb3dSCy Schubert 
14342b15cb3dSCy Schubert static int
14352b15cb3dSCy Schubert convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
14362b15cb3dSCy Schubert {
14372b15cb3dSCy Schubert 	const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
14382b15cb3dSCy Schubert 	size_t pos = 0;
14392b15cb3dSCy Schubert 
14402b15cb3dSCy Schubert 	/* We return an unterminated buffer with the digits in reverse order. */
14412b15cb3dSCy Schubert 	do {
14422b15cb3dSCy Schubert 		buf[pos++] = digits[value % base];
14432b15cb3dSCy Schubert 		value /= base;
14442b15cb3dSCy Schubert 	} while (value != 0 && pos < size);
14452b15cb3dSCy Schubert 
14462b15cb3dSCy Schubert 	return (int)pos;
14472b15cb3dSCy Schubert }
14482b15cb3dSCy Schubert 
14492b15cb3dSCy Schubert static UINTMAX_T
14502b15cb3dSCy Schubert cast(LDOUBLE value)
14512b15cb3dSCy Schubert {
14522b15cb3dSCy Schubert 	UINTMAX_T result;
14532b15cb3dSCy Schubert 
14542b15cb3dSCy Schubert 	/*
14552b15cb3dSCy Schubert 	 * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
14562b15cb3dSCy Schubert 	 * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
14572b15cb3dSCy Schubert 	 * it may be increased to the nearest higher representable value for the
14582b15cb3dSCy Schubert 	 * comparison (cf. C99: 6.3.1.4, 2).  It might then equal the LDOUBLE
14592b15cb3dSCy Schubert 	 * value although converting the latter to UINTMAX_T would overflow.
14602b15cb3dSCy Schubert 	 */
14612b15cb3dSCy Schubert 	if (value >= UINTMAX_MAX)
14622b15cb3dSCy Schubert 		return UINTMAX_MAX;
14632b15cb3dSCy Schubert 
14643311ff84SXin LI 	result = (UINTMAX_T)value;
14652b15cb3dSCy Schubert 	/*
14662b15cb3dSCy Schubert 	 * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
14672b15cb3dSCy Schubert 	 * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
14682b15cb3dSCy Schubert 	 * the standard).  Sigh.
14692b15cb3dSCy Schubert 	 */
14702b15cb3dSCy Schubert 	return (result <= value) ? result : result - 1;
14712b15cb3dSCy Schubert }
14722b15cb3dSCy Schubert 
14732b15cb3dSCy Schubert static UINTMAX_T
14742b15cb3dSCy Schubert myround(LDOUBLE value)
14752b15cb3dSCy Schubert {
14762b15cb3dSCy Schubert 	UINTMAX_T intpart = cast(value);
14772b15cb3dSCy Schubert 
14782b15cb3dSCy Schubert 	return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
14792b15cb3dSCy Schubert }
14802b15cb3dSCy Schubert 
14812b15cb3dSCy Schubert static LDOUBLE
14822b15cb3dSCy Schubert mypow10(int exponent)
14832b15cb3dSCy Schubert {
14842b15cb3dSCy Schubert 	LDOUBLE result = 1;
14852b15cb3dSCy Schubert 
14862b15cb3dSCy Schubert 	while (exponent > 0) {
14872b15cb3dSCy Schubert 		result *= 10;
14882b15cb3dSCy Schubert 		exponent--;
14892b15cb3dSCy Schubert 	}
14902b15cb3dSCy Schubert 	while (exponent < 0) {
14912b15cb3dSCy Schubert 		result /= 10;
14922b15cb3dSCy Schubert 		exponent++;
14932b15cb3dSCy Schubert 	}
14942b15cb3dSCy Schubert 	return result;
14952b15cb3dSCy Schubert }
14962b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_VSNPRINTF */
14972b15cb3dSCy Schubert 
14982b15cb3dSCy Schubert #if HW_WANT_RPL_VASPRINTF
14992b15cb3dSCy Schubert #if NEED_MYMEMCPY
15002b15cb3dSCy Schubert void *
15012b15cb3dSCy Schubert mymemcpy(void *dst, void *src, size_t len)
15022b15cb3dSCy Schubert {
15032b15cb3dSCy Schubert 	const char *from = src;
15042b15cb3dSCy Schubert 	char *to = dst;
15052b15cb3dSCy Schubert 
15062b15cb3dSCy Schubert 	/* No need for optimization, we use this only to replace va_copy(3). */
15072b15cb3dSCy Schubert 	while (len-- > 0)
15082b15cb3dSCy Schubert 		*to++ = *from++;
15092b15cb3dSCy Schubert 	return dst;
15102b15cb3dSCy Schubert }
15112b15cb3dSCy Schubert #endif	/* NEED_MYMEMCPY */
15122b15cb3dSCy Schubert 
15132b15cb3dSCy Schubert int
15142b15cb3dSCy Schubert rpl_vasprintf(char **ret, const char *format, va_list ap);
15152b15cb3dSCy Schubert 
15162b15cb3dSCy Schubert int
15172b15cb3dSCy Schubert rpl_vasprintf(char **ret, const char *format, va_list ap)
15182b15cb3dSCy Schubert {
15192b15cb3dSCy Schubert 	size_t size;
15202b15cb3dSCy Schubert 	int len;
15212b15cb3dSCy Schubert 	va_list aq;
15222b15cb3dSCy Schubert 
15232b15cb3dSCy Schubert 	VA_COPY(aq, ap);
15242b15cb3dSCy Schubert 	len = vsnprintf(NULL, 0, format, aq);
15252b15cb3dSCy Schubert 	VA_END_COPY(aq);
15262b15cb3dSCy Schubert 	if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
15272b15cb3dSCy Schubert 		return -1;
15282b15cb3dSCy Schubert 	return vsnprintf(*ret, size, format, ap);
15292b15cb3dSCy Schubert }
15302b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_VASPRINTF */
15312b15cb3dSCy Schubert 
15322b15cb3dSCy Schubert #if HW_WANT_RPL_SNPRINTF
15332b15cb3dSCy Schubert #if HAVE_STDARG_H
15342b15cb3dSCy Schubert int
15352b15cb3dSCy Schubert rpl_snprintf(char *str, size_t size, const char *format, ...);
15362b15cb3dSCy Schubert 
15372b15cb3dSCy Schubert int
15382b15cb3dSCy Schubert rpl_snprintf(char *str, size_t size, const char *format, ...)
1539ce265a54SOllivier Robert #else
15402b15cb3dSCy Schubert int
15412b15cb3dSCy Schubert rpl_snprintf(va_alist) va_dcl
15422b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
15432b15cb3dSCy Schubert {
15442b15cb3dSCy Schubert #if !HAVE_STDARG_H
15452b15cb3dSCy Schubert 	char *str;
15462b15cb3dSCy Schubert 	size_t size;
15472b15cb3dSCy Schubert 	char *format;
15482b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
15492b15cb3dSCy Schubert 	va_list ap;
15502b15cb3dSCy Schubert 	int len;
15512b15cb3dSCy Schubert 
15522b15cb3dSCy Schubert 	VA_START(ap, format);
15532b15cb3dSCy Schubert 	VA_SHIFT(ap, str, char *);
15542b15cb3dSCy Schubert 	VA_SHIFT(ap, size, size_t);
15552b15cb3dSCy Schubert 	VA_SHIFT(ap, format, const char *);
15562b15cb3dSCy Schubert 	len = vsnprintf(str, size, format, ap);
15572b15cb3dSCy Schubert 	va_end(ap);
15582b15cb3dSCy Schubert 	return len;
15592b15cb3dSCy Schubert }
15602b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_SNPRINTF */
15612b15cb3dSCy Schubert 
15622b15cb3dSCy Schubert #if HW_WANT_RPL_ASPRINTF
15632b15cb3dSCy Schubert #if HAVE_STDARG_H
15642b15cb3dSCy Schubert int
15652b15cb3dSCy Schubert rpl_asprintf(char **ret, const char *format, ...);
15662b15cb3dSCy Schubert 
15672b15cb3dSCy Schubert int
15682b15cb3dSCy Schubert rpl_asprintf(char **ret, const char *format, ...)
15692b15cb3dSCy Schubert #else
15702b15cb3dSCy Schubert int
15712b15cb3dSCy Schubert rpl_asprintf(va_alist) va_dcl
15722b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
15732b15cb3dSCy Schubert {
15742b15cb3dSCy Schubert #if !HAVE_STDARG_H
15752b15cb3dSCy Schubert 	char **ret;
15762b15cb3dSCy Schubert 	char *format;
15772b15cb3dSCy Schubert #endif	/* HAVE_STDARG_H */
15782b15cb3dSCy Schubert 	va_list ap;
15792b15cb3dSCy Schubert 	int len;
15802b15cb3dSCy Schubert 
15812b15cb3dSCy Schubert 	VA_START(ap, format);
15822b15cb3dSCy Schubert 	VA_SHIFT(ap, ret, char **);
15832b15cb3dSCy Schubert 	VA_SHIFT(ap, format, const char *);
15842b15cb3dSCy Schubert 	len = vasprintf(ret, format, ap);
15852b15cb3dSCy Schubert 	va_end(ap);
15862b15cb3dSCy Schubert 	return len;
15872b15cb3dSCy Schubert }
15882b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_ASPRINTF */
15892b15cb3dSCy Schubert #else	/* Dummy declaration to avoid empty translation unit warnings. */
1590*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
15912b15cb3dSCy Schubert #endif	/* HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || [...] */
15922b15cb3dSCy Schubert 
15932b15cb3dSCy Schubert #if TEST_SNPRINTF
15942b15cb3dSCy Schubert int
15952b15cb3dSCy Schubert main(void)
15962b15cb3dSCy Schubert {
15972b15cb3dSCy Schubert 	const char *float_fmt[] = {
15982b15cb3dSCy Schubert 		/* "%E" and "%e" formats. */
15992b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX
16002b15cb3dSCy Schubert 		"%.16e",
16012b15cb3dSCy Schubert 		"%22.16e",
16022b15cb3dSCy Schubert 		"%022.16e",
16032b15cb3dSCy Schubert 		"%-22.16e",
16042b15cb3dSCy Schubert 		"%#+'022.16e",
16052b15cb3dSCy Schubert #endif	/* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */
16062b15cb3dSCy Schubert 		"foo|%#+0123.9E|bar",
16072b15cb3dSCy Schubert 		"%-123.9e",
16082b15cb3dSCy Schubert 		"%123.9e",
16092b15cb3dSCy Schubert 		"%+23.9e",
16102b15cb3dSCy Schubert 		"%+05.8e",
16112b15cb3dSCy Schubert 		"%-05.8e",
16122b15cb3dSCy Schubert 		"%05.8e",
16132b15cb3dSCy Schubert 		"%+5.8e",
16142b15cb3dSCy Schubert 		"%-5.8e",
16152b15cb3dSCy Schubert 		"% 5.8e",
16162b15cb3dSCy Schubert 		"%5.8e",
16172b15cb3dSCy Schubert 		"%+4.9e",
16182b15cb3dSCy Schubert #if !OS_LINUX	/* glibc sometimes gets these wrong. */
16192b15cb3dSCy Schubert 		"%+#010.0e",
16202b15cb3dSCy Schubert 		"%#10.1e",
16212b15cb3dSCy Schubert 		"%10.5e",
16222b15cb3dSCy Schubert 		"% 10.5e",
16232b15cb3dSCy Schubert 		"%5.0e",
16242b15cb3dSCy Schubert 		"%5.e",
16252b15cb3dSCy Schubert 		"%#5.0e",
16262b15cb3dSCy Schubert 		"%#5.e",
16272b15cb3dSCy Schubert 		"%3.2e",
16282b15cb3dSCy Schubert 		"%3.1e",
16292b15cb3dSCy Schubert 		"%-1.5e",
16302b15cb3dSCy Schubert 		"%1.5e",
16312b15cb3dSCy Schubert 		"%01.3e",
16322b15cb3dSCy Schubert 		"%1.e",
16332b15cb3dSCy Schubert 		"%.1e",
16342b15cb3dSCy Schubert 		"%#.0e",
16352b15cb3dSCy Schubert 		"%+.0e",
16362b15cb3dSCy Schubert 		"% .0e",
16372b15cb3dSCy Schubert 		"%.0e",
16382b15cb3dSCy Schubert 		"%#.e",
16392b15cb3dSCy Schubert 		"%+.e",
16402b15cb3dSCy Schubert 		"% .e",
16412b15cb3dSCy Schubert 		"%.e",
16422b15cb3dSCy Schubert 		"%4e",
16432b15cb3dSCy Schubert 		"%e",
16442b15cb3dSCy Schubert 		"%E",
16452b15cb3dSCy Schubert #endif	/* !OS_LINUX */
16462b15cb3dSCy Schubert 		/* "%F" and "%f" formats. */
16472b15cb3dSCy Schubert #if !OS_BSD && !OS_IRIX
16482b15cb3dSCy Schubert 		"% '022f",
16492b15cb3dSCy Schubert 		"%+'022f",
16502b15cb3dSCy Schubert 		"%-'22f",
16512b15cb3dSCy Schubert 		"%'22f",
16522b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT
16532b15cb3dSCy Schubert 		"%.16f",
16542b15cb3dSCy Schubert 		"%22.16f",
16552b15cb3dSCy Schubert 		"%022.16f",
16562b15cb3dSCy Schubert 		"%-22.16f",
16572b15cb3dSCy Schubert 		"%#+'022.16f",
16582b15cb3dSCy Schubert #endif	/* HAVE_LONG_LONG_INT */
16592b15cb3dSCy Schubert #endif	/* !OS_BSD && !OS_IRIX */
16602b15cb3dSCy Schubert 		"foo|%#+0123.9F|bar",
16612b15cb3dSCy Schubert 		"%-123.9f",
16622b15cb3dSCy Schubert 		"%123.9f",
16632b15cb3dSCy Schubert 		"%+23.9f",
16642b15cb3dSCy Schubert 		"%+#010.0f",
16652b15cb3dSCy Schubert 		"%#10.1f",
16662b15cb3dSCy Schubert 		"%10.5f",
16672b15cb3dSCy Schubert 		"% 10.5f",
16682b15cb3dSCy Schubert 		"%+05.8f",
16692b15cb3dSCy Schubert 		"%-05.8f",
16702b15cb3dSCy Schubert 		"%05.8f",
16712b15cb3dSCy Schubert 		"%+5.8f",
16722b15cb3dSCy Schubert 		"%-5.8f",
16732b15cb3dSCy Schubert 		"% 5.8f",
16742b15cb3dSCy Schubert 		"%5.8f",
16752b15cb3dSCy Schubert 		"%5.0f",
16762b15cb3dSCy Schubert 		"%5.f",
16772b15cb3dSCy Schubert 		"%#5.0f",
16782b15cb3dSCy Schubert 		"%#5.f",
16792b15cb3dSCy Schubert 		"%+4.9f",
16802b15cb3dSCy Schubert 		"%3.2f",
16812b15cb3dSCy Schubert 		"%3.1f",
16822b15cb3dSCy Schubert 		"%-1.5f",
16832b15cb3dSCy Schubert 		"%1.5f",
16842b15cb3dSCy Schubert 		"%01.3f",
16852b15cb3dSCy Schubert 		"%1.f",
16862b15cb3dSCy Schubert 		"%.1f",
16872b15cb3dSCy Schubert 		"%#.0f",
16882b15cb3dSCy Schubert 		"%+.0f",
16892b15cb3dSCy Schubert 		"% .0f",
16902b15cb3dSCy Schubert 		"%.0f",
16912b15cb3dSCy Schubert 		"%#.f",
16922b15cb3dSCy Schubert 		"%+.f",
16932b15cb3dSCy Schubert 		"% .f",
16942b15cb3dSCy Schubert 		"%.f",
16952b15cb3dSCy Schubert 		"%4f",
16962b15cb3dSCy Schubert 		"%f",
16972b15cb3dSCy Schubert 		"%F",
16982b15cb3dSCy Schubert 		/* "%G" and "%g" formats. */
16992b15cb3dSCy Schubert #if !OS_BSD && !OS_IRIX && !OS_LINUX
17002b15cb3dSCy Schubert 		"% '022g",
17012b15cb3dSCy Schubert 		"%+'022g",
17022b15cb3dSCy Schubert 		"%-'22g",
17032b15cb3dSCy Schubert 		"%'22g",
17042b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT
17052b15cb3dSCy Schubert 		"%.16g",
17062b15cb3dSCy Schubert 		"%22.16g",
17072b15cb3dSCy Schubert 		"%022.16g",
17082b15cb3dSCy Schubert 		"%-22.16g",
17092b15cb3dSCy Schubert 		"%#+'022.16g",
17102b15cb3dSCy Schubert #endif	/* HAVE_LONG_LONG_INT */
17112b15cb3dSCy Schubert #endif	/* !OS_BSD && !OS_IRIX && !OS_LINUX */
17122b15cb3dSCy Schubert 		"foo|%#+0123.9G|bar",
17132b15cb3dSCy Schubert 		"%-123.9g",
17142b15cb3dSCy Schubert 		"%123.9g",
17152b15cb3dSCy Schubert 		"%+23.9g",
17162b15cb3dSCy Schubert 		"%+05.8g",
17172b15cb3dSCy Schubert 		"%-05.8g",
17182b15cb3dSCy Schubert 		"%05.8g",
17192b15cb3dSCy Schubert 		"%+5.8g",
17202b15cb3dSCy Schubert 		"%-5.8g",
17212b15cb3dSCy Schubert 		"% 5.8g",
17222b15cb3dSCy Schubert 		"%5.8g",
17232b15cb3dSCy Schubert 		"%+4.9g",
17242b15cb3dSCy Schubert #if !OS_LINUX	/* glibc sometimes gets these wrong. */
17252b15cb3dSCy Schubert 		"%+#010.0g",
17262b15cb3dSCy Schubert 		"%#10.1g",
17272b15cb3dSCy Schubert 		"%10.5g",
17282b15cb3dSCy Schubert 		"% 10.5g",
17292b15cb3dSCy Schubert 		"%5.0g",
17302b15cb3dSCy Schubert 		"%5.g",
17312b15cb3dSCy Schubert 		"%#5.0g",
17322b15cb3dSCy Schubert 		"%#5.g",
17332b15cb3dSCy Schubert 		"%3.2g",
17342b15cb3dSCy Schubert 		"%3.1g",
17352b15cb3dSCy Schubert 		"%-1.5g",
17362b15cb3dSCy Schubert 		"%1.5g",
17372b15cb3dSCy Schubert 		"%01.3g",
17382b15cb3dSCy Schubert 		"%1.g",
17392b15cb3dSCy Schubert 		"%.1g",
17402b15cb3dSCy Schubert 		"%#.0g",
17412b15cb3dSCy Schubert 		"%+.0g",
17422b15cb3dSCy Schubert 		"% .0g",
17432b15cb3dSCy Schubert 		"%.0g",
17442b15cb3dSCy Schubert 		"%#.g",
17452b15cb3dSCy Schubert 		"%+.g",
17462b15cb3dSCy Schubert 		"% .g",
17472b15cb3dSCy Schubert 		"%.g",
17482b15cb3dSCy Schubert 		"%4g",
17492b15cb3dSCy Schubert 		"%g",
17502b15cb3dSCy Schubert 		"%G",
17512b15cb3dSCy Schubert #endif	/* !OS_LINUX */
17522b15cb3dSCy Schubert 		NULL
17532b15cb3dSCy Schubert 	};
17542b15cb3dSCy Schubert 	double float_val[] = {
17552b15cb3dSCy Schubert 		-4.136,
17562b15cb3dSCy Schubert 		-134.52,
17572b15cb3dSCy Schubert 		-5.04030201,
17582b15cb3dSCy Schubert 		-3410.01234,
17592b15cb3dSCy Schubert 		-999999.999999,
17602b15cb3dSCy Schubert 		-913450.29876,
17612b15cb3dSCy Schubert 		-913450.2,
17622b15cb3dSCy Schubert 		-91345.2,
17632b15cb3dSCy Schubert 		-9134.2,
17642b15cb3dSCy Schubert 		-913.2,
17652b15cb3dSCy Schubert 		-91.2,
17662b15cb3dSCy Schubert 		-9.2,
17672b15cb3dSCy Schubert 		-9.9,
17682b15cb3dSCy Schubert 		4.136,
17692b15cb3dSCy Schubert 		134.52,
17702b15cb3dSCy Schubert 		5.04030201,
17712b15cb3dSCy Schubert 		3410.01234,
17722b15cb3dSCy Schubert 		999999.999999,
17732b15cb3dSCy Schubert 		913450.29876,
17742b15cb3dSCy Schubert 		913450.2,
17752b15cb3dSCy Schubert 		91345.2,
17762b15cb3dSCy Schubert 		9134.2,
17772b15cb3dSCy Schubert 		913.2,
17782b15cb3dSCy Schubert 		91.2,
17792b15cb3dSCy Schubert 		9.2,
17802b15cb3dSCy Schubert 		9.9,
17812b15cb3dSCy Schubert 		9.96,
17822b15cb3dSCy Schubert 		9.996,
17832b15cb3dSCy Schubert 		9.9996,
17842b15cb3dSCy Schubert 		9.99996,
17852b15cb3dSCy Schubert 		9.999996,
17862b15cb3dSCy Schubert 		9.9999996,
17872b15cb3dSCy Schubert 		9.99999996,
17882b15cb3dSCy Schubert 		0.99999996,
17892b15cb3dSCy Schubert 		0.99999999,
17902b15cb3dSCy Schubert 		0.09999999,
17912b15cb3dSCy Schubert 		0.00999999,
17922b15cb3dSCy Schubert 		0.00099999,
17932b15cb3dSCy Schubert 		0.00009999,
17942b15cb3dSCy Schubert 		0.00000999,
17952b15cb3dSCy Schubert 		0.00000099,
17962b15cb3dSCy Schubert 		0.00000009,
17972b15cb3dSCy Schubert 		0.00000001,
17982b15cb3dSCy Schubert 		0.0000001,
17992b15cb3dSCy Schubert 		0.000001,
18002b15cb3dSCy Schubert 		0.00001,
18012b15cb3dSCy Schubert 		0.0001,
18022b15cb3dSCy Schubert 		0.001,
18032b15cb3dSCy Schubert 		0.01,
18042b15cb3dSCy Schubert 		0.1,
18052b15cb3dSCy Schubert 		1.0,
18062b15cb3dSCy Schubert 		1.5,
18072b15cb3dSCy Schubert 		-1.5,
18082b15cb3dSCy Schubert 		-1.0,
18092b15cb3dSCy Schubert 		-0.1,
18102b15cb3dSCy Schubert #if !OS_BSD	/* BSD sometimes gets these wrong. */
18112b15cb3dSCy Schubert #ifdef INFINITY
18122b15cb3dSCy Schubert 		INFINITY,
18132b15cb3dSCy Schubert 		-INFINITY,
18142b15cb3dSCy Schubert #endif	/* defined(INFINITY) */
18152b15cb3dSCy Schubert #ifdef NAN
18162b15cb3dSCy Schubert 		NAN,
18172b15cb3dSCy Schubert #endif	/* defined(NAN) */
18182b15cb3dSCy Schubert #endif	/* !OS_BSD */
18192b15cb3dSCy Schubert 		0
18202b15cb3dSCy Schubert 	};
18212b15cb3dSCy Schubert 	const char *long_fmt[] = {
18222b15cb3dSCy Schubert 		"foo|%0123ld|bar",
18232b15cb3dSCy Schubert #if !OS_IRIX
18242b15cb3dSCy Schubert 		"% '0123ld",
18252b15cb3dSCy Schubert 		"%+'0123ld",
18262b15cb3dSCy Schubert 		"%-'123ld",
18272b15cb3dSCy Schubert 		"%'123ld",
18282b15cb3dSCy Schubert #endif	/* !OS_IRiX */
18292b15cb3dSCy Schubert 		"%123.9ld",
18302b15cb3dSCy Schubert 		"% 123.9ld",
18312b15cb3dSCy Schubert 		"%+123.9ld",
18322b15cb3dSCy Schubert 		"%-123.9ld",
18332b15cb3dSCy Schubert 		"%0123ld",
18342b15cb3dSCy Schubert 		"% 0123ld",
18352b15cb3dSCy Schubert 		"%+0123ld",
18362b15cb3dSCy Schubert 		"%-0123ld",
18372b15cb3dSCy Schubert 		"%10.5ld",
18382b15cb3dSCy Schubert 		"% 10.5ld",
18392b15cb3dSCy Schubert 		"%+10.5ld",
18402b15cb3dSCy Schubert 		"%-10.5ld",
18412b15cb3dSCy Schubert 		"%010ld",
18422b15cb3dSCy Schubert 		"% 010ld",
18432b15cb3dSCy Schubert 		"%+010ld",
18442b15cb3dSCy Schubert 		"%-010ld",
18452b15cb3dSCy Schubert 		"%4.2ld",
18462b15cb3dSCy Schubert 		"% 4.2ld",
18472b15cb3dSCy Schubert 		"%+4.2ld",
18482b15cb3dSCy Schubert 		"%-4.2ld",
18492b15cb3dSCy Schubert 		"%04ld",
18502b15cb3dSCy Schubert 		"% 04ld",
18512b15cb3dSCy Schubert 		"%+04ld",
18522b15cb3dSCy Schubert 		"%-04ld",
18532b15cb3dSCy Schubert 		"%5.5ld",
18542b15cb3dSCy Schubert 		"%+22.33ld",
18552b15cb3dSCy Schubert 		"%01.3ld",
18562b15cb3dSCy Schubert 		"%1.5ld",
18572b15cb3dSCy Schubert 		"%-1.5ld",
18582b15cb3dSCy Schubert 		"%44ld",
18592b15cb3dSCy Schubert 		"%4ld",
18602b15cb3dSCy Schubert 		"%4.0ld",
18612b15cb3dSCy Schubert 		"%4.ld",
18622b15cb3dSCy Schubert 		"%.44ld",
18632b15cb3dSCy Schubert 		"%.4ld",
18642b15cb3dSCy Schubert 		"%.0ld",
18652b15cb3dSCy Schubert 		"%.ld",
18662b15cb3dSCy Schubert 		"%ld",
18672b15cb3dSCy Schubert 		NULL
18682b15cb3dSCy Schubert 	};
18692b15cb3dSCy Schubert 	long int long_val[] = {
18702b15cb3dSCy Schubert #ifdef LONG_MAX
18712b15cb3dSCy Schubert 		LONG_MAX,
18722b15cb3dSCy Schubert #endif	/* LONG_MAX */
18732b15cb3dSCy Schubert #ifdef LONG_MIN
18742b15cb3dSCy Schubert 		LONG_MIN,
18752b15cb3dSCy Schubert #endif	/* LONG_MIN */
18762b15cb3dSCy Schubert 		-91340,
18772b15cb3dSCy Schubert 		91340,
18782b15cb3dSCy Schubert 		341,
18792b15cb3dSCy Schubert 		134,
18802b15cb3dSCy Schubert 		0203,
18812b15cb3dSCy Schubert 		-1,
18822b15cb3dSCy Schubert 		1,
18832b15cb3dSCy Schubert 		0
18842b15cb3dSCy Schubert 	};
18852b15cb3dSCy Schubert 	const char *ulong_fmt[] = {
18862b15cb3dSCy Schubert 		/* "%u" formats. */
18872b15cb3dSCy Schubert 		"foo|%0123lu|bar",
18882b15cb3dSCy Schubert #if !OS_IRIX
18892b15cb3dSCy Schubert 		"% '0123lu",
18902b15cb3dSCy Schubert 		"%+'0123lu",
18912b15cb3dSCy Schubert 		"%-'123lu",
18922b15cb3dSCy Schubert 		"%'123lu",
18932b15cb3dSCy Schubert #endif	/* !OS_IRiX */
18942b15cb3dSCy Schubert 		"%123.9lu",
18952b15cb3dSCy Schubert 		"% 123.9lu",
18962b15cb3dSCy Schubert 		"%+123.9lu",
18972b15cb3dSCy Schubert 		"%-123.9lu",
18982b15cb3dSCy Schubert 		"%0123lu",
18992b15cb3dSCy Schubert 		"% 0123lu",
19002b15cb3dSCy Schubert 		"%+0123lu",
19012b15cb3dSCy Schubert 		"%-0123lu",
19022b15cb3dSCy Schubert 		"%5.5lu",
19032b15cb3dSCy Schubert 		"%+22.33lu",
19042b15cb3dSCy Schubert 		"%01.3lu",
19052b15cb3dSCy Schubert 		"%1.5lu",
19062b15cb3dSCy Schubert 		"%-1.5lu",
19072b15cb3dSCy Schubert 		"%44lu",
19082b15cb3dSCy Schubert 		"%lu",
19092b15cb3dSCy Schubert 		/* "%o" formats. */
19102b15cb3dSCy Schubert 		"foo|%#0123lo|bar",
19112b15cb3dSCy Schubert 		"%#123.9lo",
19122b15cb3dSCy Schubert 		"%# 123.9lo",
19132b15cb3dSCy Schubert 		"%#+123.9lo",
19142b15cb3dSCy Schubert 		"%#-123.9lo",
19152b15cb3dSCy Schubert 		"%#0123lo",
19162b15cb3dSCy Schubert 		"%# 0123lo",
19172b15cb3dSCy Schubert 		"%#+0123lo",
19182b15cb3dSCy Schubert 		"%#-0123lo",
19192b15cb3dSCy Schubert 		"%#5.5lo",
19202b15cb3dSCy Schubert 		"%#+22.33lo",
19212b15cb3dSCy Schubert 		"%#01.3lo",
19222b15cb3dSCy Schubert 		"%#1.5lo",
19232b15cb3dSCy Schubert 		"%#-1.5lo",
19242b15cb3dSCy Schubert 		"%#44lo",
19252b15cb3dSCy Schubert 		"%#lo",
19262b15cb3dSCy Schubert 		"%123.9lo",
19272b15cb3dSCy Schubert 		"% 123.9lo",
19282b15cb3dSCy Schubert 		"%+123.9lo",
19292b15cb3dSCy Schubert 		"%-123.9lo",
19302b15cb3dSCy Schubert 		"%0123lo",
19312b15cb3dSCy Schubert 		"% 0123lo",
19322b15cb3dSCy Schubert 		"%+0123lo",
19332b15cb3dSCy Schubert 		"%-0123lo",
19342b15cb3dSCy Schubert 		"%5.5lo",
19352b15cb3dSCy Schubert 		"%+22.33lo",
19362b15cb3dSCy Schubert 		"%01.3lo",
19372b15cb3dSCy Schubert 		"%1.5lo",
19382b15cb3dSCy Schubert 		"%-1.5lo",
19392b15cb3dSCy Schubert 		"%44lo",
19402b15cb3dSCy Schubert 		"%lo",
19412b15cb3dSCy Schubert 		/* "%X" and "%x" formats. */
19422b15cb3dSCy Schubert 		"foo|%#0123lX|bar",
19432b15cb3dSCy Schubert 		"%#123.9lx",
19442b15cb3dSCy Schubert 		"%# 123.9lx",
19452b15cb3dSCy Schubert 		"%#+123.9lx",
19462b15cb3dSCy Schubert 		"%#-123.9lx",
19472b15cb3dSCy Schubert 		"%#0123lx",
19482b15cb3dSCy Schubert 		"%# 0123lx",
19492b15cb3dSCy Schubert 		"%#+0123lx",
19502b15cb3dSCy Schubert 		"%#-0123lx",
19512b15cb3dSCy Schubert 		"%#5.5lx",
19522b15cb3dSCy Schubert 		"%#+22.33lx",
19532b15cb3dSCy Schubert 		"%#01.3lx",
19542b15cb3dSCy Schubert 		"%#1.5lx",
19552b15cb3dSCy Schubert 		"%#-1.5lx",
19562b15cb3dSCy Schubert 		"%#44lx",
19572b15cb3dSCy Schubert 		"%#lx",
19582b15cb3dSCy Schubert 		"%#lX",
19592b15cb3dSCy Schubert 		"%123.9lx",
19602b15cb3dSCy Schubert 		"% 123.9lx",
19612b15cb3dSCy Schubert 		"%+123.9lx",
19622b15cb3dSCy Schubert 		"%-123.9lx",
19632b15cb3dSCy Schubert 		"%0123lx",
19642b15cb3dSCy Schubert 		"% 0123lx",
19652b15cb3dSCy Schubert 		"%+0123lx",
19662b15cb3dSCy Schubert 		"%-0123lx",
19672b15cb3dSCy Schubert 		"%5.5lx",
19682b15cb3dSCy Schubert 		"%+22.33lx",
19692b15cb3dSCy Schubert 		"%01.3lx",
19702b15cb3dSCy Schubert 		"%1.5lx",
19712b15cb3dSCy Schubert 		"%-1.5lx",
19722b15cb3dSCy Schubert 		"%44lx",
19732b15cb3dSCy Schubert 		"%lx",
19742b15cb3dSCy Schubert 		"%lX",
19752b15cb3dSCy Schubert 		NULL
19762b15cb3dSCy Schubert 	};
19772b15cb3dSCy Schubert 	unsigned long int ulong_val[] = {
19782b15cb3dSCy Schubert #ifdef ULONG_MAX
19792b15cb3dSCy Schubert 		ULONG_MAX,
19802b15cb3dSCy Schubert #endif	/* ULONG_MAX */
19812b15cb3dSCy Schubert 		91340,
19822b15cb3dSCy Schubert 		341,
19832b15cb3dSCy Schubert 		134,
19842b15cb3dSCy Schubert 		0203,
19852b15cb3dSCy Schubert 		1,
19862b15cb3dSCy Schubert 		0
19872b15cb3dSCy Schubert 	};
19882b15cb3dSCy Schubert 	const char *llong_fmt[] = {
19892b15cb3dSCy Schubert 		"foo|%0123lld|bar",
19902b15cb3dSCy Schubert 		"%123.9lld",
19912b15cb3dSCy Schubert 		"% 123.9lld",
19922b15cb3dSCy Schubert 		"%+123.9lld",
19932b15cb3dSCy Schubert 		"%-123.9lld",
19942b15cb3dSCy Schubert 		"%0123lld",
19952b15cb3dSCy Schubert 		"% 0123lld",
19962b15cb3dSCy Schubert 		"%+0123lld",
19972b15cb3dSCy Schubert 		"%-0123lld",
19982b15cb3dSCy Schubert 		"%5.5lld",
19992b15cb3dSCy Schubert 		"%+22.33lld",
20002b15cb3dSCy Schubert 		"%01.3lld",
20012b15cb3dSCy Schubert 		"%1.5lld",
20022b15cb3dSCy Schubert 		"%-1.5lld",
20032b15cb3dSCy Schubert 		"%44lld",
20042b15cb3dSCy Schubert 		"%lld",
20052b15cb3dSCy Schubert 		NULL
20062b15cb3dSCy Schubert 	};
20072b15cb3dSCy Schubert 	LLONG llong_val[] = {
20082b15cb3dSCy Schubert #ifdef LLONG_MAX
20092b15cb3dSCy Schubert 		LLONG_MAX,
20102b15cb3dSCy Schubert #endif	/* LLONG_MAX */
20112b15cb3dSCy Schubert #ifdef LLONG_MIN
20122b15cb3dSCy Schubert 		LLONG_MIN,
20132b15cb3dSCy Schubert #endif	/* LLONG_MIN */
20142b15cb3dSCy Schubert 		-91340,
20152b15cb3dSCy Schubert 		91340,
20162b15cb3dSCy Schubert 		341,
20172b15cb3dSCy Schubert 		134,
20182b15cb3dSCy Schubert 		0203,
20192b15cb3dSCy Schubert 		-1,
20202b15cb3dSCy Schubert 		1,
20212b15cb3dSCy Schubert 		0
20222b15cb3dSCy Schubert 	};
20232b15cb3dSCy Schubert 	const char *string_fmt[] = {
20242b15cb3dSCy Schubert 		"foo|%10.10s|bar",
20252b15cb3dSCy Schubert 		"%-10.10s",
20262b15cb3dSCy Schubert 		"%10.10s",
20272b15cb3dSCy Schubert 		"%10.5s",
20282b15cb3dSCy Schubert 		"%5.10s",
20292b15cb3dSCy Schubert 		"%10.1s",
20302b15cb3dSCy Schubert 		"%1.10s",
20312b15cb3dSCy Schubert 		"%10.0s",
20322b15cb3dSCy Schubert 		"%0.10s",
20332b15cb3dSCy Schubert 		"%-42.5s",
20342b15cb3dSCy Schubert 		"%2.s",
20352b15cb3dSCy Schubert 		"%.10s",
20362b15cb3dSCy Schubert 		"%.1s",
20372b15cb3dSCy Schubert 		"%.0s",
20382b15cb3dSCy Schubert 		"%.s",
20392b15cb3dSCy Schubert 		"%4s",
20402b15cb3dSCy Schubert 		"%s",
20412b15cb3dSCy Schubert 		NULL
20422b15cb3dSCy Schubert 	};
20432b15cb3dSCy Schubert 	const char *string_val[] = {
20442b15cb3dSCy Schubert 		"Hello",
20452b15cb3dSCy Schubert 		"Hello, world!",
20462b15cb3dSCy Schubert 		"Sound check: One, two, three.",
20472b15cb3dSCy Schubert 		"This string is a little longer than the other strings.",
20482b15cb3dSCy Schubert 		"1",
20492b15cb3dSCy Schubert 		"",
20502b15cb3dSCy Schubert 		NULL
20512b15cb3dSCy Schubert 	};
20522b15cb3dSCy Schubert #if !OS_SYSV	/* SysV uses a different format than we do. */
20532b15cb3dSCy Schubert 	const char *pointer_fmt[] = {
20542b15cb3dSCy Schubert 		"foo|%p|bar",
20552b15cb3dSCy Schubert 		"%42p",
20562b15cb3dSCy Schubert 		"%p",
20572b15cb3dSCy Schubert 		NULL
20582b15cb3dSCy Schubert 	};
20592b15cb3dSCy Schubert 	const char *pointer_val[] = {
20602b15cb3dSCy Schubert 		*pointer_fmt,
20612b15cb3dSCy Schubert 		*string_fmt,
20622b15cb3dSCy Schubert 		*string_val,
20632b15cb3dSCy Schubert 		NULL
20642b15cb3dSCy Schubert 	};
20652b15cb3dSCy Schubert #endif	/* !OS_SYSV */
20662b15cb3dSCy Schubert 	char buf1[1024], buf2[1024];
20672b15cb3dSCy Schubert 	double value, digits = 9.123456789012345678901234567890123456789;
20682b15cb3dSCy Schubert 	int i, j, r1, r2, failed = 0, num = 0;
20692b15cb3dSCy Schubert 
20702b15cb3dSCy Schubert /*
20712b15cb3dSCy Schubert  * Use -DTEST_NILS in order to also test the conversion of nil values.  Might
20722b15cb3dSCy Schubert  * segfault on systems which don't support converting a NULL pointer with "%s"
20732b15cb3dSCy Schubert  * and lets some test cases fail against BSD and glibc due to bugs in their
20742b15cb3dSCy Schubert  * implementations.
20752b15cb3dSCy Schubert  */
20762b15cb3dSCy Schubert #ifndef TEST_NILS
20772b15cb3dSCy Schubert #define TEST_NILS 0
20782b15cb3dSCy Schubert #elif TEST_NILS
20792b15cb3dSCy Schubert #undef TEST_NILS
20802b15cb3dSCy Schubert #define TEST_NILS 1
20812b15cb3dSCy Schubert #endif	/* !defined(TEST_NILS) */
20822b15cb3dSCy Schubert #ifdef TEST
20832b15cb3dSCy Schubert #undef TEST
20842b15cb3dSCy Schubert #endif	/* defined(TEST) */
20852b15cb3dSCy Schubert #define TEST(fmt, val)                                                         \
20862b15cb3dSCy Schubert do {                                                                           \
20872b15cb3dSCy Schubert 	for (i = 0; fmt[i] != NULL; i++)                                       \
20882b15cb3dSCy Schubert 		for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) {          \
20892b15cb3dSCy Schubert 			r1 = sprintf(buf1, fmt[i], val[j]);                    \
20902b15cb3dSCy Schubert 			r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]);     \
20912b15cb3dSCy Schubert 			if (strcmp(buf1, buf2) != 0 || r1 != r2) {             \
20922b15cb3dSCy Schubert 				(void)printf("Results don't match, "           \
20932b15cb3dSCy Schubert 				    "format string: %s\n"                      \
20942b15cb3dSCy Schubert 				    "\t sprintf(3): [%s] (%d)\n"               \
20952b15cb3dSCy Schubert 				    "\tsnprintf(3): [%s] (%d)\n",              \
20962b15cb3dSCy Schubert 				    fmt[i], buf1, r1, buf2, r2);               \
20972b15cb3dSCy Schubert 				failed++;                                      \
20982b15cb3dSCy Schubert 			}                                                      \
20992b15cb3dSCy Schubert 			num++;                                                 \
21002b15cb3dSCy Schubert 		}                                                              \
21012b15cb3dSCy Schubert } while (/* CONSTCOND */ 0)
21022b15cb3dSCy Schubert 
21032b15cb3dSCy Schubert #if HAVE_LOCALE_H
21042b15cb3dSCy Schubert 	(void)setlocale(LC_ALL, "");
21052b15cb3dSCy Schubert #endif	/* HAVE_LOCALE_H */
21062b15cb3dSCy Schubert 
21072b15cb3dSCy Schubert 	(void)puts("Testing our snprintf(3) against your system's sprintf(3).");
21082b15cb3dSCy Schubert 	TEST(float_fmt, float_val);
21092b15cb3dSCy Schubert 	TEST(long_fmt, long_val);
21102b15cb3dSCy Schubert 	TEST(ulong_fmt, ulong_val);
21112b15cb3dSCy Schubert 	TEST(llong_fmt, llong_val);
21122b15cb3dSCy Schubert 	TEST(string_fmt, string_val);
21132b15cb3dSCy Schubert #if !OS_SYSV	/* SysV uses a different format than we do. */
21142b15cb3dSCy Schubert 	TEST(pointer_fmt, pointer_val);
21152b15cb3dSCy Schubert #endif	/* !OS_SYSV */
21162b15cb3dSCy Schubert 	(void)printf("Result: %d out of %d tests failed.\n", failed, num);
21172b15cb3dSCy Schubert 
21182b15cb3dSCy Schubert 	(void)fputs("Checking how many digits we support: ", stdout);
21192b15cb3dSCy Schubert 	for (i = 0; i < 100; i++) {
21202b15cb3dSCy Schubert 		value = pow(10, i) * digits;
21212b15cb3dSCy Schubert 		(void)sprintf(buf1, "%.1f", value);
21222b15cb3dSCy Schubert 		(void)snprintf(buf2, sizeof(buf2), "%.1f", value);
21232b15cb3dSCy Schubert 		if (strcmp(buf1, buf2) != 0) {
21242b15cb3dSCy Schubert 			(void)printf("apparently %d.\n", i);
21252b15cb3dSCy Schubert 			break;
21262b15cb3dSCy Schubert 		}
21272b15cb3dSCy Schubert 	}
21282b15cb3dSCy Schubert 	return (failed == 0) ? 0 : 1;
21292b15cb3dSCy Schubert }
21302b15cb3dSCy Schubert #endif	/* TEST_SNPRINTF */
21312b15cb3dSCy Schubert 
21322b15cb3dSCy Schubert /* vim: set joinspaces textwidth=80: */
2133