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