resetting manifest requested domain to floor
[platform/upstream/ccache.git] / 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 extern int errno;
543
544 int
545 rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
546 {
547         LDOUBLE fvalue;
548         INTMAX_T value;
549         unsigned char cvalue;
550         const char *strvalue;
551         INTMAX_T *intmaxptr;
552         PTRDIFF_T *ptrdiffptr;
553         SSIZE_T *sizeptr;
554         LLONG *llongptr;
555         long int *longptr;
556         int *intptr;
557         short int *shortptr;
558         signed char *charptr;
559         size_t len = 0;
560         int overflow = 0;
561         int base = 0;
562         int cflags = 0;
563         int flags = 0;
564         int width = 0;
565         int precision = -1;
566         int state = PRINT_S_DEFAULT;
567         char ch = *format++;
568
569         /*
570          * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
571          * pointer." (7.19.6.5, 2)  We're forgiving and allow a NULL pointer
572          * even if a size larger than zero was specified.  At least NetBSD's
573          * snprintf(3) does the same, as well as other versions of this file.
574          * (Though some of these versions will write to a non-NULL buffer even
575          * if a size of zero was specified, which violates the standard.)
576          */
577         if (str == NULL && size != 0)
578                 size = 0;
579
580         while (ch != '\0')
581                 switch (state) {
582                 case PRINT_S_DEFAULT:
583                         if (ch == '%')
584                                 state = PRINT_S_FLAGS;
585                         else
586                                 OUTCHAR(str, len, size, ch);
587                         ch = *format++;
588                         break;
589                 case PRINT_S_FLAGS:
590                         switch (ch) {
591                         case '-':
592                                 flags |= PRINT_F_MINUS;
593                                 ch = *format++;
594                                 break;
595                         case '+':
596                                 flags |= PRINT_F_PLUS;
597                                 ch = *format++;
598                                 break;
599                         case ' ':
600                                 flags |= PRINT_F_SPACE;
601                                 ch = *format++;
602                                 break;
603                         case '#':
604                                 flags |= PRINT_F_NUM;
605                                 ch = *format++;
606                                 break;
607                         case '0':
608                                 flags |= PRINT_F_ZERO;
609                                 ch = *format++;
610                                 break;
611                         case '\'':      /* SUSv2 flag (not in C99). */
612                                 flags |= PRINT_F_QUOTE;
613                                 ch = *format++;
614                                 break;
615                         default:
616                                 state = PRINT_S_WIDTH;
617                                 break;
618                         }
619                         break;
620                 case PRINT_S_WIDTH:
621                         if (ISDIGIT(ch)) {
622                                 ch = CHARTOINT(ch);
623                                 if (width > (INT_MAX - ch) / 10) {
624                                         overflow = 1;
625                                         goto out;
626                                 }
627                                 width = 10 * width + ch;
628                                 ch = *format++;
629                         } else if (ch == '*') {
630                                 /*
631                                  * C99 says: "A negative field width argument is
632                                  * taken as a `-' flag followed by a positive
633                                  * field width." (7.19.6.1, 5)
634                                  */
635                                 if ((width = va_arg(args, int)) < 0) {
636                                         flags |= PRINT_F_MINUS;
637                                         width = -width;
638                                 }
639                                 ch = *format++;
640                                 state = PRINT_S_DOT;
641                         } else
642                                 state = PRINT_S_DOT;
643                         break;
644                 case PRINT_S_DOT:
645                         if (ch == '.') {
646                                 state = PRINT_S_PRECISION;
647                                 ch = *format++;
648                         } else
649                                 state = PRINT_S_MOD;
650                         break;
651                 case PRINT_S_PRECISION:
652                         if (precision == -1)
653                                 precision = 0;
654                         if (ISDIGIT(ch)) {
655                                 ch = CHARTOINT(ch);
656                                 if (precision > (INT_MAX - ch) / 10) {
657                                         overflow = 1;
658                                         goto out;
659                                 }
660                                 precision = 10 * precision + ch;
661                                 ch = *format++;
662                         } else if (ch == '*') {
663                                 /*
664                                  * C99 says: "A negative precision argument is
665                                  * taken as if the precision were omitted."
666                                  * (7.19.6.1, 5)
667                                  */
668                                 if ((precision = va_arg(args, int)) < 0)
669                                         precision = -1;
670                                 ch = *format++;
671                                 state = PRINT_S_MOD;
672                         } else
673                                 state = PRINT_S_MOD;
674                         break;
675                 case PRINT_S_MOD:
676                         switch (ch) {
677                         case 'h':
678                                 ch = *format++;
679                                 if (ch == 'h') {        /* It's a char. */
680                                         ch = *format++;
681                                         cflags = PRINT_C_CHAR;
682                                 } else
683                                         cflags = PRINT_C_SHORT;
684                                 break;
685                         case 'l':
686                                 ch = *format++;
687                                 if (ch == 'l') {        /* It's a long long. */
688                                         ch = *format++;
689                                         cflags = PRINT_C_LLONG;
690                                 } else
691                                         cflags = PRINT_C_LONG;
692                                 break;
693                         case 'L':
694                                 cflags = PRINT_C_LDOUBLE;
695                                 ch = *format++;
696                                 break;
697                         case 'j':
698                                 cflags = PRINT_C_INTMAX;
699                                 ch = *format++;
700                                 break;
701                         case 't':
702                                 cflags = PRINT_C_PTRDIFF;
703                                 ch = *format++;
704                                 break;
705                         case 'z':
706                                 cflags = PRINT_C_SIZE;
707                                 ch = *format++;
708                                 break;
709                         }
710                         state = PRINT_S_CONV;
711                         break;
712                 case PRINT_S_CONV:
713                         switch (ch) {
714                         case 'd':
715                                 /* FALLTHROUGH */
716                         case 'i':
717                                 switch (cflags) {
718                                 case PRINT_C_CHAR:
719                                         value = (signed char)va_arg(args, int);
720                                         break;
721                                 case PRINT_C_SHORT:
722                                         value = (short int)va_arg(args, int);
723                                         break;
724                                 case PRINT_C_LONG:
725                                         value = va_arg(args, long int);
726                                         break;
727                                 case PRINT_C_LLONG:
728                                         value = va_arg(args, LLONG);
729                                         break;
730                                 case PRINT_C_SIZE:
731                                         value = va_arg(args, SSIZE_T);
732                                         break;
733                                 case PRINT_C_INTMAX:
734                                         value = va_arg(args, INTMAX_T);
735                                         break;
736                                 case PRINT_C_PTRDIFF:
737                                         value = va_arg(args, PTRDIFF_T);
738                                         break;
739                                 default:
740                                         value = va_arg(args, int);
741                                         break;
742                                 }
743                                 fmtint(str, &len, size, value, 10, width,
744                                     precision, flags);
745                                 break;
746                         case 'X':
747                                 flags |= PRINT_F_UP;
748                                 /* FALLTHROUGH */
749                         case 'x':
750                                 base = 16;
751                                 /* FALLTHROUGH */
752                         case 'o':
753                                 if (base == 0)
754                                         base = 8;
755                                 /* FALLTHROUGH */
756                         case 'u':
757                                 if (base == 0)
758                                         base = 10;
759                                 flags |= PRINT_F_UNSIGNED;
760                                 switch (cflags) {
761                                 case PRINT_C_CHAR:
762                                         value = (unsigned char)va_arg(args,
763                                             unsigned int);
764                                         break;
765                                 case PRINT_C_SHORT:
766                                         value = (unsigned short int)va_arg(args,
767                                             unsigned int);
768                                         break;
769                                 case PRINT_C_LONG:
770                                         value = va_arg(args, unsigned long int);
771                                         break;
772                                 case PRINT_C_LLONG:
773                                         value = va_arg(args, ULLONG);
774                                         break;
775                                 case PRINT_C_SIZE:
776                                         value = va_arg(args, size_t);
777                                         break;
778                                 case PRINT_C_INTMAX:
779                                         value = va_arg(args, UINTMAX_T);
780                                         break;
781                                 case PRINT_C_PTRDIFF:
782                                         value = va_arg(args, UPTRDIFF_T);
783                                         break;
784                                 default:
785                                         value = va_arg(args, unsigned int);
786                                         break;
787                                 }
788                                 fmtint(str, &len, size, value, base, width,
789                                     precision, flags);
790                                 break;
791                         case 'A':
792                                 /* Not yet supported, we'll use "%F". */
793                                 /* FALLTHROUGH */
794                         case 'F':
795                                 flags |= PRINT_F_UP;
796                         case 'a':
797                                 /* Not yet supported, we'll use "%f". */
798                                 /* FALLTHROUGH */
799                         case 'f':
800                                 if (cflags == PRINT_C_LDOUBLE)
801                                         fvalue = va_arg(args, LDOUBLE);
802                                 else
803                                         fvalue = va_arg(args, double);
804                                 fmtflt(str, &len, size, fvalue, width,
805                                     precision, flags, &overflow);
806                                 if (overflow)
807                                         goto out;
808                                 break;
809                         case 'E':
810                                 flags |= PRINT_F_UP;
811                                 /* FALLTHROUGH */
812                         case 'e':
813                                 flags |= PRINT_F_TYPE_E;
814                                 if (cflags == PRINT_C_LDOUBLE)
815                                         fvalue = va_arg(args, LDOUBLE);
816                                 else
817                                         fvalue = va_arg(args, double);
818                                 fmtflt(str, &len, size, fvalue, width,
819                                     precision, flags, &overflow);
820                                 if (overflow)
821                                         goto out;
822                                 break;
823                         case 'G':
824                                 flags |= PRINT_F_UP;
825                                 /* FALLTHROUGH */
826                         case 'g':
827                                 flags |= PRINT_F_TYPE_G;
828                                 if (cflags == PRINT_C_LDOUBLE)
829                                         fvalue = va_arg(args, LDOUBLE);
830                                 else
831                                         fvalue = va_arg(args, double);
832                                 /*
833                                  * If the precision is zero, it is treated as
834                                  * one (cf. C99: 7.19.6.1, 8).
835                                  */
836                                 if (precision == 0)
837                                         precision = 1;
838                                 fmtflt(str, &len, size, fvalue, width,
839                                     precision, flags, &overflow);
840                                 if (overflow)
841                                         goto out;
842                                 break;
843                         case 'c':
844                                 cvalue = va_arg(args, int);
845                                 OUTCHAR(str, len, size, cvalue);
846                                 break;
847                         case 's':
848                                 strvalue = va_arg(args, char *);
849                                 fmtstr(str, &len, size, strvalue, width,
850                                     precision, flags);
851                                 break;
852                         case 'p':
853                                 /*
854                                  * C99 says: "The value of the pointer is
855                                  * converted to a sequence of printing
856                                  * characters, in an implementation-defined
857                                  * manner." (C99: 7.19.6.1, 8)
858                                  */
859                                 if ((strvalue = va_arg(args, void *)) == NULL)
860                                         /*
861                                          * We use the glibc format.  BSD prints
862                                          * "0x0", SysV "0".
863                                          */
864                                         fmtstr(str, &len, size, "(nil)", width,
865                                             -1, flags);
866                                 else {
867                                         /*
868                                          * We use the BSD/glibc format.  SysV
869                                          * omits the "0x" prefix (which we emit
870                                          * using the PRINT_F_NUM flag).
871                                          */
872                                         flags |= PRINT_F_NUM;
873                                         flags |= PRINT_F_UNSIGNED;
874                                         fmtint(str, &len, size,
875                                             (UINTPTR_T)strvalue, 16, width,
876                                             precision, flags);
877                                 }
878                                 break;
879                         case 'n':
880                                 switch (cflags) {
881                                 case PRINT_C_CHAR:
882                                         charptr = va_arg(args, signed char *);
883                                         *charptr = len;
884                                         break;
885                                 case PRINT_C_SHORT:
886                                         shortptr = va_arg(args, short int *);
887                                         *shortptr = len;
888                                         break;
889                                 case PRINT_C_LONG:
890                                         longptr = va_arg(args, long int *);
891                                         *longptr = len;
892                                         break;
893                                 case PRINT_C_LLONG:
894                                         llongptr = va_arg(args, LLONG *);
895                                         *llongptr = len;
896                                         break;
897                                 case PRINT_C_SIZE:
898                                         /*
899                                          * C99 says that with the "z" length
900                                          * modifier, "a following `n' conversion
901                                          * specifier applies to a pointer to a
902                                          * signed integer type corresponding to
903                                          * size_t argument." (7.19.6.1, 7)
904                                          */
905                                         sizeptr = va_arg(args, SSIZE_T *);
906                                         *sizeptr = len;
907                                         break;
908                                 case PRINT_C_INTMAX:
909                                         intmaxptr = va_arg(args, INTMAX_T *);
910                                         *intmaxptr = len;
911                                         break;
912                                 case PRINT_C_PTRDIFF:
913                                         ptrdiffptr = va_arg(args, PTRDIFF_T *);
914                                         *ptrdiffptr = len;
915                                         break;
916                                 default:
917                                         intptr = va_arg(args, int *);
918                                         *intptr = len;
919                                         break;
920                                 }
921                                 break;
922                         case '%':       /* Print a "%" character verbatim. */
923                                 OUTCHAR(str, len, size, ch);
924                                 break;
925                         default:        /* Skip other characters. */
926                                 break;
927                         }
928                         ch = *format++;
929                         state = PRINT_S_DEFAULT;
930                         base = cflags = flags = width = 0;
931                         precision = -1;
932                         break;
933                 }
934 out:
935         if (len < size)
936                 str[len] = '\0';
937         else if (size > 0)
938                 str[size - 1] = '\0';
939
940         if (overflow || len >= INT_MAX) {
941                 errno = overflow ? EOVERFLOW : ERANGE;
942                 return -1;
943         }
944         return (int)len;
945 }
946
947 static void
948 fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
949        int precision, int flags)
950 {
951         int padlen, strln;      /* Amount to pad. */
952         int noprecision = (precision == -1);
953
954         if (value == NULL)      /* We're forgiving. */
955                 value = "(null)";
956
957         /* If a precision was specified, don't read the string past it. */
958         for (strln = 0; value[strln] != '\0' &&
959             (noprecision || strln < precision); strln++)
960                 continue;
961
962         if ((padlen = width - strln) < 0)
963                 padlen = 0;
964         if (flags & PRINT_F_MINUS)      /* Left justify. */
965                 padlen = -padlen;
966
967         while (padlen > 0) {    /* Leading spaces. */
968                 OUTCHAR(str, *len, size, ' ');
969                 padlen--;
970         }
971         while (*value != '\0' && (noprecision || precision-- > 0)) {
972                 OUTCHAR(str, *len, size, *value);
973                 value++;
974         }
975         while (padlen < 0) {    /* Trailing spaces. */
976                 OUTCHAR(str, *len, size, ' ');
977                 padlen++;
978         }
979 }
980
981 static void
982 fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
983        int precision, int flags)
984 {
985         UINTMAX_T uvalue;
986         char iconvert[MAX_CONVERT_LENGTH];
987         char sign = 0;
988         char hexprefix = 0;
989         int spadlen = 0;        /* Amount to space pad. */
990         int zpadlen = 0;        /* Amount to zero pad. */
991         int pos;
992         int separators = (flags & PRINT_F_QUOTE);
993         int noprecision = (precision == -1);
994
995         if (flags & PRINT_F_UNSIGNED)
996                 uvalue = value;
997         else {
998                 uvalue = (value >= 0) ? value : -value;
999                 if (value < 0)
1000                         sign = '-';
1001                 else if (flags & PRINT_F_PLUS)  /* Do a sign. */
1002                         sign = '+';
1003                 else if (flags & PRINT_F_SPACE)
1004                         sign = ' ';
1005         }
1006
1007         pos = convert(uvalue, iconvert, sizeof(iconvert), base,
1008             flags & PRINT_F_UP);
1009
1010         if (flags & PRINT_F_NUM && uvalue != 0) {
1011                 /*
1012                  * C99 says: "The result is converted to an `alternative form'.
1013                  * For `o' conversion, it increases the precision, if and only
1014                  * if necessary, to force the first digit of the result to be a
1015                  * zero (if the value and precision are both 0, a single 0 is
1016                  * printed).  For `x' (or `X') conversion, a nonzero result has
1017                  * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
1018                  */
1019                 switch (base) {
1020                 case 8:
1021                         if (precision <= pos)
1022                                 precision = pos + 1;
1023                         break;
1024                 case 16:
1025                         hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
1026                         break;
1027                 }
1028         }
1029
1030         if (separators) /* Get the number of group separators we'll print. */
1031                 separators = getnumsep(pos);
1032
1033         zpadlen = precision - pos - separators;
1034         spadlen = width                         /* Minimum field width. */
1035             - separators                        /* Number of separators. */
1036             - MAX(precision, pos)               /* Number of integer digits. */
1037             - ((sign != 0) ? 1 : 0)             /* Will we print a sign? */
1038             - ((hexprefix != 0) ? 2 : 0);       /* Will we print a prefix? */
1039
1040         if (zpadlen < 0)
1041                 zpadlen = 0;
1042         if (spadlen < 0)
1043                 spadlen = 0;
1044
1045         /*
1046          * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
1047          * ignored.  For `d', `i', `o', `u', `x', and `X' conversions, if a
1048          * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
1049          */
1050         if (flags & PRINT_F_MINUS)      /* Left justify. */
1051                 spadlen = -spadlen;
1052         else if (flags & PRINT_F_ZERO && noprecision) {
1053                 zpadlen += spadlen;
1054                 spadlen = 0;
1055         }
1056         while (spadlen > 0) {   /* Leading spaces. */
1057                 OUTCHAR(str, *len, size, ' ');
1058                 spadlen--;
1059         }
1060         if (sign != 0)  /* Sign. */
1061                 OUTCHAR(str, *len, size, sign);
1062         if (hexprefix != 0) {   /* A "0x" or "0X" prefix. */
1063                 OUTCHAR(str, *len, size, '0');
1064                 OUTCHAR(str, *len, size, hexprefix);
1065         }
1066         while (zpadlen > 0) {   /* Leading zeros. */
1067                 OUTCHAR(str, *len, size, '0');
1068                 zpadlen--;
1069         }
1070         while (pos > 0) {       /* The actual digits. */
1071                 pos--;
1072                 OUTCHAR(str, *len, size, iconvert[pos]);
1073                 if (separators > 0 && pos > 0 && pos % 3 == 0)
1074                         printsep(str, len, size);
1075         }
1076         while (spadlen < 0) {   /* Trailing spaces. */
1077                 OUTCHAR(str, *len, size, ' ');
1078                 spadlen++;
1079         }
1080 }
1081
1082 static void
1083 fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
1084        int precision, int flags, int *overflow)
1085 {
1086         LDOUBLE ufvalue;
1087         UINTMAX_T intpart;
1088         UINTMAX_T fracpart;
1089         UINTMAX_T mask;
1090         const char *infnan = NULL;
1091         char iconvert[MAX_CONVERT_LENGTH];
1092         char fconvert[MAX_CONVERT_LENGTH];
1093         char econvert[4];       /* "e-12" (without nul-termination). */
1094         char esign = 0;
1095         char sign = 0;
1096         int leadfraczeros = 0;
1097         int exponent = 0;
1098         int emitpoint = 0;
1099         int omitzeros = 0;
1100         int omitcount = 0;
1101         int padlen = 0;
1102         int epos = 0;
1103         int fpos = 0;
1104         int ipos = 0;
1105         int separators = (flags & PRINT_F_QUOTE);
1106         int estyle = (flags & PRINT_F_TYPE_E);
1107 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
1108         struct lconv *lc = localeconv();
1109 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
1110
1111         /*
1112          * AIX' man page says the default is 0, but C99 and at least Solaris'
1113          * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
1114          * defaults to 6.
1115          */
1116         if (precision == -1)
1117                 precision = 6;
1118
1119         if (fvalue < 0.0)
1120                 sign = '-';
1121         else if (flags & PRINT_F_PLUS)  /* Do a sign. */
1122                 sign = '+';
1123         else if (flags & PRINT_F_SPACE)
1124                 sign = ' ';
1125
1126         if (ISNAN(fvalue))
1127                 infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
1128         else if (ISINF(fvalue))
1129                 infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
1130
1131         if (infnan != NULL) {
1132                 if (sign != 0)
1133                         iconvert[ipos++] = sign;
1134                 while (*infnan != '\0')
1135                         iconvert[ipos++] = *infnan++;
1136                 fmtstr(str, len, size, iconvert, width, ipos, flags);
1137                 return;
1138         }
1139
1140         /* "%e" (or "%E") or "%g" (or "%G") conversion. */
1141         if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
1142                 if (flags & PRINT_F_TYPE_G) {
1143                         /*
1144                          * For "%g" (and "%G") conversions, the precision
1145                          * specifies the number of significant digits, which
1146                          * includes the digits in the integer part.  The
1147                          * conversion will or will not be using "e-style" (like
1148                          * "%e" or "%E" conversions) depending on the precision
1149                          * and on the exponent.  However, the exponent can be
1150                          * affected by rounding the converted value, so we'll
1151                          * leave this decision for later.  Until then, we'll
1152                          * assume that we're going to do an "e-style" conversion
1153                          * (in order to get the exponent calculated).  For
1154                          * "e-style", the precision must be decremented by one.
1155                          */
1156                         precision--;
1157                         /*
1158                          * For "%g" (and "%G") conversions, trailing zeros are
1159                          * removed from the fractional portion of the result
1160                          * unless the "#" flag was specified.
1161                          */
1162                         if (!(flags & PRINT_F_NUM))
1163                                 omitzeros = 1;
1164                 }
1165                 exponent = getexponent(fvalue);
1166                 estyle = 1;
1167         }
1168
1169 again:
1170         /*
1171          * Sorry, we only support 9, 19, or 38 digits (that is, the number of
1172          * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
1173          * minus one) past the decimal point due to our conversion method.
1174          */
1175         switch (sizeof(UINTMAX_T)) {
1176         case 16:
1177                 if (precision > 38)
1178                         precision = 38;
1179                 break;
1180         case 8:
1181                 if (precision > 19)
1182                         precision = 19;
1183                 break;
1184         default:
1185                 if (precision > 9)
1186                         precision = 9;
1187                 break;
1188         }
1189
1190         ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
1191         if (estyle)     /* We want exactly one integer digit. */
1192                 ufvalue /= mypow10(exponent);
1193
1194         if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
1195                 *overflow = 1;
1196                 return;
1197         }
1198
1199         /*
1200          * Factor of ten with the number of digits needed for the fractional
1201          * part.  For example, if the precision is 3, the mask will be 1000.
1202          */
1203         mask = mypow10(precision);
1204         /*
1205          * We "cheat" by converting the fractional part to integer by
1206          * multiplying by a factor of ten.
1207          */
1208         if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
1209                 /*
1210                  * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
1211                  * (because precision = 3).  Now, myround(1000 * 0.99962) will
1212                  * return 1000.  So, the integer part must be incremented by one
1213                  * and the fractional part must be set to zero.
1214                  */
1215                 intpart++;
1216                 fracpart = 0;
1217                 if (estyle && intpart == 10) {
1218                         /*
1219                          * The value was rounded up to ten, but we only want one
1220                          * integer digit if using "e-style".  So, the integer
1221                          * part must be set to one and the exponent must be
1222                          * incremented by one.
1223                          */
1224                         intpart = 1;
1225                         exponent++;
1226                 }
1227         }
1228
1229         /*
1230          * Now that we know the real exponent, we can check whether or not to
1231          * use "e-style" for "%g" (and "%G") conversions.  If we don't need
1232          * "e-style", the precision must be adjusted and the integer and
1233          * fractional parts must be recalculated from the original value.
1234          *
1235          * C99 says: "Let P equal the precision if nonzero, 6 if the precision
1236          * is omitted, or 1 if the precision is zero.  Then, if a conversion
1237          * with style `E' would have an exponent of X:
1238          *
1239          * - if P > X >= -4, the conversion is with style `f' (or `F') and
1240          *   precision P - (X + 1).
1241          *
1242          * - otherwise, the conversion is with style `e' (or `E') and precision
1243          *   P - 1." (7.19.6.1, 8)
1244          *
1245          * Note that we had decremented the precision by one.
1246          */
1247         if (flags & PRINT_F_TYPE_G && estyle &&
1248             precision + 1 > exponent && exponent >= -4) {
1249                 precision -= exponent;
1250                 estyle = 0;
1251                 goto again;
1252         }
1253
1254         if (estyle) {
1255                 if (exponent < 0) {
1256                         exponent = -exponent;
1257                         esign = '-';
1258                 } else
1259                         esign = '+';
1260
1261                 /*
1262                  * Convert the exponent.  The sizeof(econvert) is 4.  So, the
1263                  * econvert buffer can hold e.g. "e+99" and "e-99".  We don't
1264                  * support an exponent which contains more than two digits.
1265                  * Therefore, the following stores are safe.
1266                  */
1267                 epos = convert(exponent, econvert, 2, 10, 0);
1268                 /*
1269                  * C99 says: "The exponent always contains at least two digits,
1270                  * and only as many more digits as necessary to represent the
1271                  * exponent." (7.19.6.1, 8)
1272                  */
1273                 if (epos == 1)
1274                         econvert[epos++] = '0';
1275                 econvert[epos++] = esign;
1276                 econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
1277         }
1278
1279         /* Convert the integer part and the fractional part. */
1280         ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
1281         if (fracpart != 0)      /* convert() would return 1 if fracpart == 0. */
1282                 fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
1283
1284         leadfraczeros = precision - fpos;
1285
1286         if (omitzeros) {
1287                 if (fpos > 0)   /* Omit trailing fractional part zeros. */
1288                         while (omitcount < fpos && fconvert[omitcount] == '0')
1289                                 omitcount++;
1290                 else {  /* The fractional part is zero, omit it completely. */
1291                         omitcount = precision;
1292                         leadfraczeros = 0;
1293                 }
1294                 precision -= omitcount;
1295         }
1296
1297         /*
1298          * Print a decimal point if either the fractional part is non-zero
1299          * and/or the "#" flag was specified.
1300          */
1301         if (precision > 0 || flags & PRINT_F_NUM)
1302                 emitpoint = 1;
1303         if (separators) /* Get the number of group separators we'll print. */
1304                 separators = getnumsep(ipos);
1305
1306         padlen = width                  /* Minimum field width. */
1307             - ipos                      /* Number of integer digits. */
1308             - epos                      /* Number of exponent characters. */
1309             - precision                 /* Number of fractional digits. */
1310             - separators                /* Number of group separators. */
1311             - (emitpoint ? 1 : 0)       /* Will we print a decimal point? */
1312             - ((sign != 0) ? 1 : 0);    /* Will we print a sign character? */
1313
1314         if (padlen < 0)
1315                 padlen = 0;
1316
1317         /*
1318          * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
1319          * ignored." (7.19.6.1, 6)
1320          */
1321         if (flags & PRINT_F_MINUS)      /* Left justifty. */
1322                 padlen = -padlen;
1323         else if (flags & PRINT_F_ZERO && padlen > 0) {
1324                 if (sign != 0) {        /* Sign. */
1325                         OUTCHAR(str, *len, size, sign);
1326                         sign = 0;
1327                 }
1328                 while (padlen > 0) {    /* Leading zeros. */
1329                         OUTCHAR(str, *len, size, '0');
1330                         padlen--;
1331                 }
1332         }
1333         while (padlen > 0) {    /* Leading spaces. */
1334                 OUTCHAR(str, *len, size, ' ');
1335                 padlen--;
1336         }
1337         if (sign != 0)  /* Sign. */
1338                 OUTCHAR(str, *len, size, sign);
1339         while (ipos > 0) {      /* Integer part. */
1340                 ipos--;
1341                 OUTCHAR(str, *len, size, iconvert[ipos]);
1342                 if (separators > 0 && ipos > 0 && ipos % 3 == 0)
1343                         printsep(str, len, size);
1344         }
1345         if (emitpoint) {        /* Decimal point. */
1346 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
1347                 if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
1348                         OUTCHAR(str, *len, size, *lc->decimal_point);
1349                 else    /* We'll always print some decimal point character. */
1350 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
1351                         OUTCHAR(str, *len, size, '.');
1352         }
1353         while (leadfraczeros > 0) {     /* Leading fractional part zeros. */
1354                 OUTCHAR(str, *len, size, '0');
1355                 leadfraczeros--;
1356         }
1357         while (fpos > omitcount) {      /* The remaining fractional part. */
1358                 fpos--;
1359                 OUTCHAR(str, *len, size, fconvert[fpos]);
1360         }
1361         while (epos > 0) {      /* Exponent. */
1362                 epos--;
1363                 OUTCHAR(str, *len, size, econvert[epos]);
1364         }
1365         while (padlen < 0) {    /* Trailing spaces. */
1366                 OUTCHAR(str, *len, size, ' ');
1367                 padlen++;
1368         }
1369 }
1370
1371 static void
1372 printsep(char *str, size_t *len, size_t size)
1373 {
1374 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
1375         struct lconv *lc = localeconv();
1376         int i;
1377
1378         if (lc->thousands_sep != NULL)
1379                 for (i = 0; lc->thousands_sep[i] != '\0'; i++)
1380                         OUTCHAR(str, *len, size, lc->thousands_sep[i]);
1381         else
1382 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
1383                 OUTCHAR(str, *len, size, ',');
1384 }
1385
1386 static int
1387 getnumsep(int digits)
1388 {
1389         int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
1390 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
1391         int strln;
1392         struct lconv *lc = localeconv();
1393
1394         /* We support an arbitrary separator length (including zero). */
1395         if (lc->thousands_sep != NULL) {
1396                 for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
1397                         continue;
1398                 separators *= strln;
1399         }
1400 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
1401         return separators;
1402 }
1403
1404 static int
1405 getexponent(LDOUBLE value)
1406 {
1407         LDOUBLE tmp = (value >= 0.0) ? value : -value;
1408         int exponent = 0;
1409
1410         /*
1411          * We check for 99 > exponent > -99 in order to work around possible
1412          * endless loops which could happen (at least) in the second loop (at
1413          * least) if we're called with an infinite value.  However, we checked
1414          * for infinity before calling this function using our ISINF() macro, so
1415          * this might be somewhat paranoid.
1416          */
1417         while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
1418                 tmp *= 10;
1419         while (tmp >= 10.0 && ++exponent < 99)
1420                 tmp /= 10;
1421
1422         return exponent;
1423 }
1424
1425 static int
1426 convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
1427 {
1428         const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
1429         size_t pos = 0;
1430
1431         /* We return an unterminated buffer with the digits in reverse order. */
1432         do {
1433                 buf[pos++] = digits[value % base];
1434                 value /= base;
1435         } while (value != 0 && pos < size);
1436
1437         return (int)pos;
1438 }
1439
1440 static UINTMAX_T
1441 cast(LDOUBLE value)
1442 {
1443         UINTMAX_T result;
1444
1445         /*
1446          * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
1447          * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
1448          * it may be increased to the nearest higher representable value for the
1449          * comparison (cf. C99: 6.3.1.4, 2).  It might then equal the LDOUBLE
1450          * value although converting the latter to UINTMAX_T would overflow.
1451          */
1452         if (value >= UINTMAX_MAX)
1453                 return UINTMAX_MAX;
1454
1455         result = value;
1456         /*
1457          * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
1458          * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
1459          * the standard).  Sigh.
1460          */
1461         return (result <= value) ? result : result - 1;
1462 }
1463
1464 static UINTMAX_T
1465 myround(LDOUBLE value)
1466 {
1467         UINTMAX_T intpart = cast(value);
1468
1469         return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
1470 }
1471
1472 static LDOUBLE
1473 mypow10(int exponent)
1474 {
1475         LDOUBLE result = 1;
1476
1477         while (exponent > 0) {
1478                 result *= 10;
1479                 exponent--;
1480         }
1481         while (exponent < 0) {
1482                 result /= 10;
1483                 exponent++;
1484         }
1485         return result;
1486 }
1487 #endif  /* !HAVE_VSNPRINTF */
1488
1489 #if !HAVE_VASPRINTF
1490 #if NEED_MYMEMCPY
1491 void *
1492 mymemcpy(void *dst, void *src, size_t len)
1493 {
1494         const char *from = src;
1495         char *to = dst;
1496
1497         /* No need for optimization, we use this only to replace va_copy(3). */
1498         while (len-- > 0)
1499                 *to++ = *from++;
1500         return dst;
1501 }
1502 #endif  /* NEED_MYMEMCPY */
1503
1504 int
1505 rpl_vasprintf(char **ret, const char *format, va_list ap)
1506 {
1507         size_t size;
1508         int len;
1509         va_list aq;
1510
1511         VA_COPY(aq, ap);
1512         len = vsnprintf(NULL, 0, format, aq);
1513         VA_END_COPY(aq);
1514         if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
1515                 return -1;
1516         return vsnprintf(*ret, size, format, ap);
1517 }
1518 #endif  /* !HAVE_VASPRINTF */
1519
1520 #if !HAVE_SNPRINTF
1521 #if HAVE_STDARG_H
1522 int
1523 rpl_snprintf(char *str, size_t size, const char *format, ...)
1524 #else
1525 int
1526 rpl_snprintf(va_alist) va_dcl
1527 #endif  /* HAVE_STDARG_H */
1528 {
1529 #if !HAVE_STDARG_H
1530         char *str;
1531         size_t size;
1532         char *format;
1533 #endif  /* HAVE_STDARG_H */
1534         va_list ap;
1535         int len;
1536
1537         VA_START(ap, format);
1538         VA_SHIFT(ap, str, char *);
1539         VA_SHIFT(ap, size, size_t);
1540         VA_SHIFT(ap, format, const char *);
1541         len = vsnprintf(str, size, format, ap);
1542         va_end(ap);
1543         return len;
1544 }
1545 #endif  /* !HAVE_SNPRINTF */
1546
1547 #if !HAVE_ASPRINTF
1548 #if HAVE_STDARG_H
1549 int
1550 rpl_asprintf(char **ret, const char *format, ...)
1551 #else
1552 int
1553 rpl_asprintf(va_alist) va_dcl
1554 #endif  /* HAVE_STDARG_H */
1555 {
1556 #if !HAVE_STDARG_H
1557         char **ret;
1558         char *format;
1559 #endif  /* HAVE_STDARG_H */
1560         va_list ap;
1561         int len;
1562
1563         VA_START(ap, format);
1564         VA_SHIFT(ap, ret, char **);
1565         VA_SHIFT(ap, format, const char *);
1566         len = vasprintf(ret, format, ap);
1567         va_end(ap);
1568         return len;
1569 }
1570 #endif  /* !HAVE_ASPRINTF */
1571 #else   /* Dummy declaration to avoid empty translation unit warnings. */
1572 int main(void);
1573 #endif  /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */
1574
1575 #if TEST_SNPRINTF
1576 int
1577 main(void)
1578 {
1579         const char *float_fmt[] = {
1580                 /* "%E" and "%e" formats. */
1581 #if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX
1582                 "%.16e",
1583                 "%22.16e",
1584                 "%022.16e",
1585                 "%-22.16e",
1586                 "%#+'022.16e",
1587 #endif  /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */
1588                 "foo|%#+0123.9E|bar",
1589                 "%-123.9e",
1590                 "%123.9e",
1591                 "%+23.9e",
1592                 "%+05.8e",
1593                 "%-05.8e",
1594                 "%05.8e",
1595                 "%+5.8e",
1596                 "%-5.8e",
1597                 "% 5.8e",
1598                 "%5.8e",
1599                 "%+4.9e",
1600 #if !OS_LINUX   /* glibc sometimes gets these wrong. */
1601                 "%+#010.0e",
1602                 "%#10.1e",
1603                 "%10.5e",
1604                 "% 10.5e",
1605                 "%5.0e",
1606                 "%5.e",
1607                 "%#5.0e",
1608                 "%#5.e",
1609                 "%3.2e",
1610                 "%3.1e",
1611                 "%-1.5e",
1612                 "%1.5e",
1613                 "%01.3e",
1614                 "%1.e",
1615                 "%.1e",
1616                 "%#.0e",
1617                 "%+.0e",
1618                 "% .0e",
1619                 "%.0e",
1620                 "%#.e",
1621                 "%+.e",
1622                 "% .e",
1623                 "%.e",
1624                 "%4e",
1625                 "%e",
1626                 "%E",
1627 #endif  /* !OS_LINUX */
1628                 /* "%F" and "%f" formats. */
1629 #if !OS_BSD && !OS_IRIX
1630                 "% '022f",
1631                 "%+'022f",
1632                 "%-'22f",
1633                 "%'22f",
1634 #if HAVE_LONG_LONG_INT
1635                 "%.16f",
1636                 "%22.16f",
1637                 "%022.16f",
1638                 "%-22.16f",
1639                 "%#+'022.16f",
1640 #endif  /* HAVE_LONG_LONG_INT */
1641 #endif  /* !OS_BSD && !OS_IRIX */
1642                 "foo|%#+0123.9F|bar",
1643                 "%-123.9f",
1644                 "%123.9f",
1645                 "%+23.9f",
1646                 "%+#010.0f",
1647                 "%#10.1f",
1648                 "%10.5f",
1649                 "% 10.5f",
1650                 "%+05.8f",
1651                 "%-05.8f",
1652                 "%05.8f",
1653                 "%+5.8f",
1654                 "%-5.8f",
1655                 "% 5.8f",
1656                 "%5.8f",
1657                 "%5.0f",
1658                 "%5.f",
1659                 "%#5.0f",
1660                 "%#5.f",
1661                 "%+4.9f",
1662                 "%3.2f",
1663                 "%3.1f",
1664                 "%-1.5f",
1665                 "%1.5f",
1666                 "%01.3f",
1667                 "%1.f",
1668                 "%.1f",
1669                 "%#.0f",
1670                 "%+.0f",
1671                 "% .0f",
1672                 "%.0f",
1673                 "%#.f",
1674                 "%+.f",
1675                 "% .f",
1676                 "%.f",
1677                 "%4f",
1678                 "%f",
1679                 "%F",
1680                 /* "%G" and "%g" formats. */
1681 #if !OS_BSD && !OS_IRIX && !OS_LINUX
1682                 "% '022g",
1683                 "%+'022g",
1684                 "%-'22g",
1685                 "%'22g",
1686 #if HAVE_LONG_LONG_INT
1687                 "%.16g",
1688                 "%22.16g",
1689                 "%022.16g",
1690                 "%-22.16g",
1691                 "%#+'022.16g",
1692 #endif  /* HAVE_LONG_LONG_INT */
1693 #endif  /* !OS_BSD && !OS_IRIX && !OS_LINUX */
1694                 "foo|%#+0123.9G|bar",
1695                 "%-123.9g",
1696                 "%123.9g",
1697                 "%+23.9g",
1698                 "%+05.8g",
1699                 "%-05.8g",
1700                 "%05.8g",
1701                 "%+5.8g",
1702                 "%-5.8g",
1703                 "% 5.8g",
1704                 "%5.8g",
1705                 "%+4.9g",
1706 #if !OS_LINUX   /* glibc sometimes gets these wrong. */
1707                 "%+#010.0g",
1708                 "%#10.1g",
1709                 "%10.5g",
1710                 "% 10.5g",
1711                 "%5.0g",
1712                 "%5.g",
1713                 "%#5.0g",
1714                 "%#5.g",
1715                 "%3.2g",
1716                 "%3.1g",
1717                 "%-1.5g",
1718                 "%1.5g",
1719                 "%01.3g",
1720                 "%1.g",
1721                 "%.1g",
1722                 "%#.0g",
1723                 "%+.0g",
1724                 "% .0g",
1725                 "%.0g",
1726                 "%#.g",
1727                 "%+.g",
1728                 "% .g",
1729                 "%.g",
1730                 "%4g",
1731                 "%g",
1732                 "%G",
1733 #endif  /* !OS_LINUX */
1734                 NULL
1735         };
1736         double float_val[] = {
1737                 -4.136,
1738                 -134.52,
1739                 -5.04030201,
1740                 -3410.01234,
1741                 -999999.999999,
1742                 -913450.29876,
1743                 -913450.2,
1744                 -91345.2,
1745                 -9134.2,
1746                 -913.2,
1747                 -91.2,
1748                 -9.2,
1749                 -9.9,
1750                 4.136,
1751                 134.52,
1752                 5.04030201,
1753                 3410.01234,
1754                 999999.999999,
1755                 913450.29876,
1756                 913450.2,
1757                 91345.2,
1758                 9134.2,
1759                 913.2,
1760                 91.2,
1761                 9.2,
1762                 9.9,
1763                 9.96,
1764                 9.996,
1765                 9.9996,
1766                 9.99996,
1767                 9.999996,
1768                 9.9999996,
1769                 9.99999996,
1770                 0.99999996,
1771                 0.99999999,
1772                 0.09999999,
1773                 0.00999999,
1774                 0.00099999,
1775                 0.00009999,
1776                 0.00000999,
1777                 0.00000099,
1778                 0.00000009,
1779                 0.00000001,
1780                 0.0000001,
1781                 0.000001,
1782                 0.00001,
1783                 0.0001,
1784                 0.001,
1785                 0.01,
1786                 0.1,
1787                 1.0,
1788                 1.5,
1789                 -1.5,
1790                 -1.0,
1791                 -0.1,
1792 #if !OS_BSD     /* BSD sometimes gets these wrong. */
1793 #ifdef INFINITY
1794                 INFINITY,
1795                 -INFINITY,
1796 #endif  /* defined(INFINITY) */
1797 #ifdef NAN
1798                 NAN,
1799 #endif  /* defined(NAN) */
1800 #endif  /* !OS_BSD */
1801                 0
1802         };
1803         const char *long_fmt[] = {
1804                 "foo|%0123ld|bar",
1805 #if !OS_IRIX
1806                 "% '0123ld",
1807                 "%+'0123ld",
1808                 "%-'123ld",
1809                 "%'123ld",
1810 #endif  /* !OS_IRiX */
1811                 "%123.9ld",
1812                 "% 123.9ld",
1813                 "%+123.9ld",
1814                 "%-123.9ld",
1815                 "%0123ld",
1816                 "% 0123ld",
1817                 "%+0123ld",
1818                 "%-0123ld",
1819                 "%10.5ld",
1820                 "% 10.5ld",
1821                 "%+10.5ld",
1822                 "%-10.5ld",
1823                 "%010ld",
1824                 "% 010ld",
1825                 "%+010ld",
1826                 "%-010ld",
1827                 "%4.2ld",
1828                 "% 4.2ld",
1829                 "%+4.2ld",
1830                 "%-4.2ld",
1831                 "%04ld",
1832                 "% 04ld",
1833                 "%+04ld",
1834                 "%-04ld",
1835                 "%5.5ld",
1836                 "%+22.33ld",
1837                 "%01.3ld",
1838                 "%1.5ld",
1839                 "%-1.5ld",
1840                 "%44ld",
1841                 "%4ld",
1842                 "%4.0ld",
1843                 "%4.ld",
1844                 "%.44ld",
1845                 "%.4ld",
1846                 "%.0ld",
1847                 "%.ld",
1848                 "%ld",
1849                 NULL
1850         };
1851         long int long_val[] = {
1852 #ifdef LONG_MAX
1853                 LONG_MAX,
1854 #endif  /* LONG_MAX */
1855 #ifdef LONG_MIN
1856                 LONG_MIN,
1857 #endif  /* LONG_MIN */
1858                 -91340,
1859                 91340,
1860                 341,
1861                 134,
1862                 0203,
1863                 -1,
1864                 1,
1865                 0
1866         };
1867         const char *ulong_fmt[] = {
1868                 /* "%u" formats. */
1869                 "foo|%0123lu|bar",
1870 #if !OS_IRIX
1871                 "% '0123lu",
1872                 "%+'0123lu",
1873                 "%-'123lu",
1874                 "%'123lu",
1875 #endif  /* !OS_IRiX */
1876                 "%123.9lu",
1877                 "% 123.9lu",
1878                 "%+123.9lu",
1879                 "%-123.9lu",
1880                 "%0123lu",
1881                 "% 0123lu",
1882                 "%+0123lu",
1883                 "%-0123lu",
1884                 "%5.5lu",
1885                 "%+22.33lu",
1886                 "%01.3lu",
1887                 "%1.5lu",
1888                 "%-1.5lu",
1889                 "%44lu",
1890                 "%lu",
1891                 /* "%o" formats. */
1892                 "foo|%#0123lo|bar",
1893                 "%#123.9lo",
1894                 "%# 123.9lo",
1895                 "%#+123.9lo",
1896                 "%#-123.9lo",
1897                 "%#0123lo",
1898                 "%# 0123lo",
1899                 "%#+0123lo",
1900                 "%#-0123lo",
1901                 "%#5.5lo",
1902                 "%#+22.33lo",
1903                 "%#01.3lo",
1904                 "%#1.5lo",
1905                 "%#-1.5lo",
1906                 "%#44lo",
1907                 "%#lo",
1908                 "%123.9lo",
1909                 "% 123.9lo",
1910                 "%+123.9lo",
1911                 "%-123.9lo",
1912                 "%0123lo",
1913                 "% 0123lo",
1914                 "%+0123lo",
1915                 "%-0123lo",
1916                 "%5.5lo",
1917                 "%+22.33lo",
1918                 "%01.3lo",
1919                 "%1.5lo",
1920                 "%-1.5lo",
1921                 "%44lo",
1922                 "%lo",
1923                 /* "%X" and "%x" formats. */
1924                 "foo|%#0123lX|bar",
1925                 "%#123.9lx",
1926                 "%# 123.9lx",
1927                 "%#+123.9lx",
1928                 "%#-123.9lx",
1929                 "%#0123lx",
1930                 "%# 0123lx",
1931                 "%#+0123lx",
1932                 "%#-0123lx",
1933                 "%#5.5lx",
1934                 "%#+22.33lx",
1935                 "%#01.3lx",
1936                 "%#1.5lx",
1937                 "%#-1.5lx",
1938                 "%#44lx",
1939                 "%#lx",
1940                 "%#lX",
1941                 "%123.9lx",
1942                 "% 123.9lx",
1943                 "%+123.9lx",
1944                 "%-123.9lx",
1945                 "%0123lx",
1946                 "% 0123lx",
1947                 "%+0123lx",
1948                 "%-0123lx",
1949                 "%5.5lx",
1950                 "%+22.33lx",
1951                 "%01.3lx",
1952                 "%1.5lx",
1953                 "%-1.5lx",
1954                 "%44lx",
1955                 "%lx",
1956                 "%lX",
1957                 NULL
1958         };
1959         unsigned long int ulong_val[] = {
1960 #ifdef ULONG_MAX
1961                 ULONG_MAX,
1962 #endif  /* ULONG_MAX */
1963                 91340,
1964                 341,
1965                 134,
1966                 0203,
1967                 1,
1968                 0
1969         };
1970         const char *llong_fmt[] = {
1971                 "foo|%0123lld|bar",
1972                 "%123.9lld",
1973                 "% 123.9lld",
1974                 "%+123.9lld",
1975                 "%-123.9lld",
1976                 "%0123lld",
1977                 "% 0123lld",
1978                 "%+0123lld",
1979                 "%-0123lld",
1980                 "%5.5lld",
1981                 "%+22.33lld",
1982                 "%01.3lld",
1983                 "%1.5lld",
1984                 "%-1.5lld",
1985                 "%44lld",
1986                 "%lld",
1987                 NULL
1988         };
1989         LLONG llong_val[] = {
1990 #ifdef LLONG_MAX
1991                 LLONG_MAX,
1992 #endif  /* LLONG_MAX */
1993 #ifdef LLONG_MIN
1994                 LLONG_MIN,
1995 #endif  /* LLONG_MIN */
1996                 -91340,
1997                 91340,
1998                 341,
1999                 134,
2000                 0203,
2001                 -1,
2002                 1,
2003                 0
2004         };
2005         const char *string_fmt[] = {
2006                 "foo|%10.10s|bar",
2007                 "%-10.10s",
2008                 "%10.10s",
2009                 "%10.5s",
2010                 "%5.10s",
2011                 "%10.1s",
2012                 "%1.10s",
2013                 "%10.0s",
2014                 "%0.10s",
2015                 "%-42.5s",
2016                 "%2.s",
2017                 "%.10s",
2018                 "%.1s",
2019                 "%.0s",
2020                 "%.s",
2021                 "%4s",
2022                 "%s",
2023                 NULL
2024         };
2025         const char *string_val[] = {
2026                 "Hello",
2027                 "Hello, world!",
2028                 "Sound check: One, two, three.",
2029                 "This string is a little longer than the other strings.",
2030                 "1",
2031                 "",
2032                 NULL
2033         };
2034 #if !OS_SYSV    /* SysV uses a different format than we do. */
2035         const char *pointer_fmt[] = {
2036                 "foo|%p|bar",
2037                 "%42p",
2038                 "%p",
2039                 NULL
2040         };
2041         const char *pointer_val[] = {
2042                 *pointer_fmt,
2043                 *string_fmt,
2044                 *string_val,
2045                 NULL
2046         };
2047 #endif  /* !OS_SYSV */
2048         char buf1[1024], buf2[1024];
2049         double value, digits = 9.123456789012345678901234567890123456789;
2050         int i, j, r1, r2, failed = 0, num = 0;
2051
2052 /*
2053  * Use -DTEST_NILS in order to also test the conversion of nil values.  Might
2054  * segfault on systems which don't support converting a NULL pointer with "%s"
2055  * and lets some test cases fail against BSD and glibc due to bugs in their
2056  * implementations.
2057  */
2058 #ifndef TEST_NILS
2059 #define TEST_NILS 0
2060 #elif TEST_NILS
2061 #undef TEST_NILS
2062 #define TEST_NILS 1
2063 #endif  /* !defined(TEST_NILS) */
2064 #ifdef TEST
2065 #undef TEST
2066 #endif  /* defined(TEST) */
2067 #define TEST(fmt, val)                                                         \
2068 do {                                                                           \
2069         for (i = 0; fmt[i] != NULL; i++)                                       \
2070                 for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) {          \
2071                         r1 = sprintf(buf1, fmt[i], val[j]);                    \
2072                         r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]);     \
2073                         if (strcmp(buf1, buf2) != 0 || r1 != r2) {             \
2074                                 (void)printf("Results don't match, "           \
2075                                     "format string: %s\n"                      \
2076                                     "\t sprintf(3): [%s] (%d)\n"               \
2077                                     "\tsnprintf(3): [%s] (%d)\n",              \
2078                                     fmt[i], buf1, r1, buf2, r2);               \
2079                                 failed++;                                      \
2080                         }                                                      \
2081                         num++;                                                 \
2082                 }                                                              \
2083 } while (/* CONSTCOND */ 0)
2084
2085 #if HAVE_LOCALE_H
2086         (void)setlocale(LC_ALL, "");
2087 #endif  /* HAVE_LOCALE_H */
2088
2089         (void)puts("Testing our snprintf(3) against your system's sprintf(3).");
2090         TEST(float_fmt, float_val);
2091         TEST(long_fmt, long_val);
2092         TEST(ulong_fmt, ulong_val);
2093         TEST(llong_fmt, llong_val);
2094         TEST(string_fmt, string_val);
2095 #if !OS_SYSV    /* SysV uses a different format than we do. */
2096         TEST(pointer_fmt, pointer_val);
2097 #endif  /* !OS_SYSV */
2098         (void)printf("Result: %d out of %d tests failed.\n", failed, num);
2099
2100         (void)fputs("Checking how many digits we support: ", stdout);
2101         for (i = 0; i < 100; i++) {
2102                 value = pow(10, i) * digits;
2103                 (void)sprintf(buf1, "%.1f", value);
2104                 (void)snprintf(buf2, sizeof(buf2), "%.1f", value);
2105                 if (strcmp(buf1, buf2) != 0) {
2106                         (void)printf("apparently %d.\n", i);
2107                         break;
2108                 }
2109         }
2110         return (failed == 0) ? 0 : 1;
2111 }
2112 #endif  /* TEST_SNPRINTF */
2113
2114 /* vim: set joinspaces textwidth=80: */