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