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