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