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