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