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