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