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