1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

root/csw/mgar/pkg/watch/trunk/files/snprintf.c @ 3587

Revision 3587, 51.5 KB (checked in by skayser, 4 years ago)

watch: fixed asprintf()

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