2 * Modified by Dave Hart for integration into NTP 4.2.7 <hart@ntp.org>
4 * Changed in a backwards-incompatible way to separate HAVE_SNPRINTF
5 * from HW_WANT_RPL_SNPRINTF, etc. for each of the four replaced
8 * Changed to honor hw_force_rpl_snprintf=yes, etc. This is used by NTP
9 * to test rpl_snprintf() and rpl_vsnprintf() on platforms which provide
10 * C99-compliant implementations.
13 /* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */
16 * Copyright (c) 1995 Patrick Powell.
18 * This code is based on code written by Patrick Powell <papowell@astart.com>.
19 * It may be used for any purpose as long as this notice remains intact on all
20 * source code distributions.
24 * Copyright (c) 2008 Holger Weiss.
26 * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
27 * My changes to the code may freely be used, modified and/or redistributed for
28 * any purpose. It would be nice if additions and fixes to this file (including
29 * trivial code cleanups) would be sent back in order to let me include them in
30 * the version available at <http://www.jhweiss.de/software/snprintf.html>.
31 * However, this is not a requirement for using or redistributing (possibly
32 * modified) versions of this file, nor is leaving this notice intact mandatory.
38 * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
40 * Fixed the detection of infinite floating point values on IRIX (and
41 * possibly other systems) and applied another few minor cleanups.
43 * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
45 * Added a lot of new features, fixed many bugs, and incorporated various
46 * improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
47 * <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
48 * <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
49 * projects. The additions include: support the "e", "E", "g", "G", and
50 * "F" conversion specifiers (and use conversion style "f" or "F" for the
51 * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
52 * "t", and "z" length modifiers; support the "#" flag and the (non-C99)
53 * "'" flag; use localeconv(3) (if available) to get both the current
54 * locale's decimal point character and the separator between groups of
55 * digits; fix the handling of various corner cases of field width and
56 * precision specifications; fix various floating point conversion bugs;
57 * handle infinite and NaN floating point values; don't attempt to write to
58 * the output buffer (which may be NULL) if a size of zero was specified;
59 * check for integer overflow of the field width, precision, and return
60 * values and during the floating point conversion; use the OUTCHAR() macro
61 * instead of a function for better performance; provide asprintf(3) and
62 * vasprintf(3) functions; add new test cases. The replacement functions
63 * have been renamed to use an "rpl_" prefix, the function calls in the
64 * main project (and in this file) must be redefined accordingly for each
65 * replacement function which is needed (by using Autoconf or other means).
66 * Various other minor improvements have been applied and the coding style
67 * was cleaned up for consistency.
69 * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
71 * C99 compliant snprintf(3) and vsnprintf(3) functions return the number
72 * of characters that would have been written to a sufficiently sized
73 * buffer (excluding the '\0'). The original code simply returned the
74 * length of the resulting output string, so that's been fixed.
76 * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
78 * The original code assumed that both snprintf(3) and vsnprintf(3) were
79 * missing. Some systems only have snprintf(3) but not vsnprintf(3), so
80 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
82 * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
84 * The PGP code was using unsigned hexadecimal formats. Unfortunately,
85 * unsigned formats simply didn't work.
87 * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
89 * Ok, added some minimal floating point support, which means this probably
90 * requires libm on most operating systems. Don't yet support the exponent
91 * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just
92 * wasn't being exercised in ways which showed it, so that's been fixed.
93 * Also, formatted the code to Mutt conventions, and removed dead code left
94 * over from the original. Also, there is now a builtin-test, run with:
95 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
97 * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
99 * This was ugly. It is still ugly. I opted out of floating point
100 * numbers, but the formatter understands just about everything from the
101 * normal C string format, at least as far as I can tell from the Solaris
102 * 2.5 printf(3S) man page.
108 * - Add wide character support.
109 * - Add support for "%a" and "%A" conversions.
110 * - Create test routines which predefine the expected results. Our test cases
111 * usually expose bugs in system implementations rather than in ours :-)
117 * 1) The following preprocessor macros should be defined to 1 if the feature or
118 * file in question is available on the target system (by using Autoconf or
119 * other means), though basic functionality should be available as long as
120 * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly:
122 * HW_WANT_RPL_VSNPRINTF
123 * HW_WANT_RPL_SNPRINTF
124 * HW_WANT_RPL_VASPRINTF
125 * HW_WANT_RPL_ASPRINTF
126 * HAVE_VSNPRINTF // define to 1 #if HW_WANT_RPL_VSNPRINTF
127 * HAVE_SNPRINTF // define to 1 #if HW_WANT_RPL_SNPRINTF
128 * HAVE_VASPRINTF // define to 1 #if HW_WANT_RPL_VASPRINTF
129 * HAVE_ASPRINTF // define to 1 #if HW_WANT_RPL_ASPRINTF
137 * HAVE_LCONV_DECIMAL_POINT
138 * HAVE_LCONV_THOUSANDS_SEP
141 * HAVE_UNSIGNED_LONG_LONG_INT
149 * 2) The calls to the functions which should be replaced must be redefined
150 * throughout the project files (by using Autoconf or other means):
152 * #if HW_WANT_RPL_VSNPRINTF
153 * #define vsnprintf rpl_vsnprintf
155 * #if HW_WANT_RPL_SNPRINTF
156 * #define snprintf rpl_snprintf
158 * #if HW_WANT_RPL_VASPRINTF
159 * #define vasprintf rpl_vasprintf
161 * #if HW_WANT_RPL_ASPRINTF
162 * #define asprintf rpl_asprintf
165 * 3) The required replacement functions should be declared in some header file
166 * included throughout the project files:
169 * #include <config.h>
172 * #include <stdarg.h>
173 * #if HW_WANT_RPL_VSNPRINTF
174 * int rpl_vsnprintf(char *, size_t, const char *, va_list);
176 * #if HW_WANT_RPL_SNPRINTF
177 * int rpl_snprintf(char *, size_t, const char *, ...);
179 * #if HW_WANT_RPL_VASPRINTF
180 * int rpl_vasprintf(char **, const char *, va_list);
182 * #if HW_WANT_RPL_ASPRINTF
183 * int rpl_asprintf(char **, const char *, ...);
187 * Autoconf macros for handling step 1 and step 2 are available at
188 * <http://www.jhweiss.de/software/snprintf.html>.
193 #endif /* HAVE_CONFIG_H */
196 #include <math.h> /* For pow(3), NAN, and INFINITY. */
197 #include <string.h> /* For strcmp(3). */
198 #if defined(__NetBSD__) || \
199 defined(__FreeBSD__) || \
200 defined(__OpenBSD__) || \
201 defined(__NeXT__) || \
204 #elif defined(sgi) || defined(__sgi)
206 #define __c99 /* Force C99 mode to get <stdint.h> included on IRIX 6.5.30. */
207 #endif /* !defined(__c99) */
210 #elif defined(__svr4__)
212 #elif defined(__linux__)
214 #endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */
215 #if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */
218 #endif /* defined(HAVE_SNPRINTF) */
219 #ifdef HAVE_VSNPRINTF
220 #undef HAVE_VSNPRINTF
221 #endif /* defined(HAVE_VSNPRINTF) */
224 #endif /* defined(HAVE_ASPRINTF) */
225 #ifdef HAVE_VASPRINTF
226 #undef HAVE_VASPRINTF
227 #endif /* defined(HAVE_VASPRINTF) */
230 #endif /* defined(snprintf) */
233 #endif /* defined(vsnprintf) */
236 #endif /* defined(asprintf) */
239 #endif /* defined(vasprintf) */
240 #else /* By default, we assume a modern system for testing. */
241 #ifndef HAVE_STDARG_H
242 #define HAVE_STDARG_H 1
243 #endif /* HAVE_STDARG_H */
244 #ifndef HAVE_STDDEF_H
245 #define HAVE_STDDEF_H 1
246 #endif /* HAVE_STDDEF_H */
247 #ifndef HAVE_STDINT_H
248 #define HAVE_STDINT_H 1
249 #endif /* HAVE_STDINT_H */
250 #ifndef HAVE_STDLIB_H
251 #define HAVE_STDLIB_H 1
252 #endif /* HAVE_STDLIB_H */
253 #ifndef HAVE_INTTYPES_H
254 #define HAVE_INTTYPES_H 1
255 #endif /* HAVE_INTTYPES_H */
256 #ifndef HAVE_LOCALE_H
257 #define HAVE_LOCALE_H 1
258 #endif /* HAVE_LOCALE_H */
259 #ifndef HAVE_LOCALECONV
260 #define HAVE_LOCALECONV 1
261 #endif /* !defined(HAVE_LOCALECONV) */
262 #ifndef HAVE_LCONV_DECIMAL_POINT
263 #define HAVE_LCONV_DECIMAL_POINT 1
264 #endif /* HAVE_LCONV_DECIMAL_POINT */
265 #ifndef HAVE_LCONV_THOUSANDS_SEP
266 #define HAVE_LCONV_THOUSANDS_SEP 1
267 #endif /* HAVE_LCONV_THOUSANDS_SEP */
268 #ifndef HAVE_LONG_DOUBLE
269 #define HAVE_LONG_DOUBLE 1
270 #endif /* !defined(HAVE_LONG_DOUBLE) */
271 #ifndef HAVE_LONG_LONG_INT
272 #define HAVE_LONG_LONG_INT 1
273 #endif /* !defined(HAVE_LONG_LONG_INT) */
274 #ifndef HAVE_UNSIGNED_LONG_LONG_INT
275 #define HAVE_UNSIGNED_LONG_LONG_INT 1
276 #endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */
277 #ifndef HAVE_INTMAX_T
278 #define HAVE_INTMAX_T 1
279 #endif /* !defined(HAVE_INTMAX_T) */
280 #ifndef HAVE_UINTMAX_T
281 #define HAVE_UINTMAX_T 1
282 #endif /* !defined(HAVE_UINTMAX_T) */
283 #ifndef HAVE_UINTPTR_T
284 #define HAVE_UINTPTR_T 1
285 #endif /* !defined(HAVE_UINTPTR_T) */
286 #ifndef HAVE_PTRDIFF_T
287 #define HAVE_PTRDIFF_T 1
288 #endif /* !defined(HAVE_PTRDIFF_T) */
290 #define HAVE_VA_COPY 1
291 #endif /* !defined(HAVE_VA_COPY) */
292 #ifndef HAVE___VA_COPY
293 #define HAVE___VA_COPY 1
294 #endif /* !defined(HAVE___VA_COPY) */
295 #endif /* HAVE_CONFIG_H */
296 #define snprintf rpl_snprintf
297 #define vsnprintf rpl_vsnprintf
298 #define asprintf rpl_asprintf
299 #define vasprintf rpl_vasprintf
300 #endif /* TEST_SNPRINTF */
302 #if HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || HW_WANT_RPL_VASPRINTF
303 #include <stdio.h> /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */
306 #endif /* defined(VA_START) */
309 #endif /* defined(VA_SHIFT) */
312 #define VA_START(ap, last) va_start(ap, last)
313 #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
314 #else /* Assume <varargs.h> is available. */
316 #define VA_START(ap, last) va_start(ap) /* "last" is ignored. */
317 #define VA_SHIFT(ap, value, type) value = va_arg(ap, type)
318 #endif /* HAVE_STDARG_H */
320 #if HW_WANT_RPL_VASPRINTF
322 #include <stdlib.h> /* For malloc(3). */
323 #endif /* HAVE_STDLIB_H */
326 #endif /* defined(VA_COPY) */
329 #endif /* defined(VA_END_COPY) */
331 #define VA_COPY(dest, src) va_copy(dest, src)
332 #define VA_END_COPY(ap) va_end(ap)
334 #define VA_COPY(dest, src) __va_copy(dest, src)
335 #define VA_END_COPY(ap) va_end(ap)
337 #define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list))
338 #define VA_END_COPY(ap) /* No-op. */
339 #define NEED_MYMEMCPY 1
340 static void *mymemcpy(void *, void *, size_t);
341 #endif /* HAVE_VA_COPY */
342 #endif /* HW_WANT_RPL_VASPRINTF */
344 #if HW_WANT_RPL_VSNPRINTF
345 #include <errno.h> /* For ERANGE and errno. */
346 #include <limits.h> /* For *_MAX. */
348 #include <inttypes.h> /* For intmax_t (if not defined in <stdint.h>). */
349 #endif /* HAVE_INTTYPES_H */
351 #include <locale.h> /* For localeconv(3). */
352 #endif /* HAVE_LOCALE_H */
354 #include <stddef.h> /* For ptrdiff_t. */
355 #endif /* HAVE_STDDEF_H */
357 #include <stdint.h> /* For intmax_t. */
358 #endif /* HAVE_STDINT_H */
360 /* Support for unsigned long long int. We may also need ULLONG_MAX. */
361 #ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */
363 #define ULONG_MAX UINT_MAX
365 #define ULONG_MAX INT_MAX
366 #endif /* defined(UINT_MAX) */
367 #endif /* !defined(ULONG_MAX) */
370 #endif /* defined(ULLONG) */
371 #if HAVE_UNSIGNED_LONG_LONG_INT
372 #define ULLONG unsigned long long int
374 #define ULLONG_MAX ULONG_MAX
375 #endif /* !defined(ULLONG_MAX) */
377 #define ULLONG unsigned long int
380 #endif /* defined(ULLONG_MAX) */
381 #define ULLONG_MAX ULONG_MAX
382 #endif /* HAVE_LONG_LONG_INT */
384 /* Support for uintmax_t. We also need UINTMAX_MAX. */
387 #endif /* defined(UINTMAX_T) */
388 #if HAVE_UINTMAX_T || defined(uintmax_t)
389 #define UINTMAX_T uintmax_t
391 #define UINTMAX_MAX ULLONG_MAX
392 #endif /* !defined(UINTMAX_MAX) */
394 #define UINTMAX_T ULLONG
397 #endif /* defined(UINTMAX_MAX) */
398 #define UINTMAX_MAX ULLONG_MAX
399 #endif /* HAVE_UINTMAX_T || defined(uintmax_t) */
401 /* Support for long double. */
404 #define LDOUBLE long double
406 #define LDOUBLE double
407 #endif /* HAVE_LONG_DOUBLE */
408 #endif /* !defined(LDOUBLE) */
410 /* Support for long long int. */
412 #if HAVE_LONG_LONG_INT
413 #define LLONG long long int
415 #define LLONG long int
416 #endif /* HAVE_LONG_LONG_INT */
417 #endif /* !defined(LLONG) */
419 /* Support for intmax_t. */
421 #if HAVE_INTMAX_T || defined(intmax_t)
422 #define INTMAX_T intmax_t
424 #define INTMAX_T LLONG
425 #endif /* HAVE_INTMAX_T || defined(intmax_t) */
426 #endif /* !defined(INTMAX_T) */
428 /* Support for uintptr_t. */
430 #if HAVE_UINTPTR_T || defined(uintptr_t)
431 #define UINTPTR_T uintptr_t
433 #define UINTPTR_T unsigned long int
434 #endif /* HAVE_UINTPTR_T || defined(uintptr_t) */
435 #endif /* !defined(UINTPTR_T) */
437 /* Support for ptrdiff_t. */
439 #if HAVE_PTRDIFF_T || defined(ptrdiff_t)
440 #define PTRDIFF_T ptrdiff_t
442 #define PTRDIFF_T long int
443 #endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
444 #endif /* !defined(PTRDIFF_T) */
447 * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
448 * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an
449 * unsigned type if necessary. This should work just fine in practice.
452 #define UPTRDIFF_T PTRDIFF_T
453 #endif /* !defined(UPTRDIFF_T) */
456 * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
457 * However, we'll simply use size_t and convert it to a signed type if
458 * necessary. This should work just fine in practice.
461 #define SSIZE_T size_t
462 #endif /* !defined(SSIZE_T) */
464 /* Either ERANGE or E2BIG should be available everywhere. */
467 #endif /* !defined(ERANGE) */
469 #define EOVERFLOW ERANGE
470 #endif /* !defined(EOVERFLOW) */
473 * Buffer size to hold the octal string representation of UINT128_MAX without
474 * nul-termination ("3777777777777777777777777777777777777777777").
476 #ifdef MAX_CONVERT_LENGTH
477 #undef MAX_CONVERT_LENGTH
478 #endif /* defined(MAX_CONVERT_LENGTH) */
479 #define MAX_CONVERT_LENGTH 43
481 /* Format read states. */
482 #define PRINT_S_DEFAULT 0
483 #define PRINT_S_FLAGS 1
484 #define PRINT_S_WIDTH 2
485 #define PRINT_S_DOT 3
486 #define PRINT_S_PRECISION 4
487 #define PRINT_S_MOD 5
488 #define PRINT_S_CONV 6
491 #define PRINT_F_MINUS (1 << 0)
492 #define PRINT_F_PLUS (1 << 1)
493 #define PRINT_F_SPACE (1 << 2)
494 #define PRINT_F_NUM (1 << 3)
495 #define PRINT_F_ZERO (1 << 4)
496 #define PRINT_F_QUOTE (1 << 5)
497 #define PRINT_F_UP (1 << 6)
498 #define PRINT_F_UNSIGNED (1 << 7)
499 #define PRINT_F_TYPE_G (1 << 8)
500 #define PRINT_F_TYPE_E (1 << 9)
502 /* Conversion flags. */
503 #define PRINT_C_CHAR 1
504 #define PRINT_C_SHORT 2
505 #define PRINT_C_LONG 3
506 #define PRINT_C_LLONG 4
507 #define PRINT_C_LDOUBLE 5
508 #define PRINT_C_SIZE 6
509 #define PRINT_C_PTRDIFF 7
510 #define PRINT_C_INTMAX 8
513 #define MAX(x, y) ((x >= y) ? x : y)
514 #endif /* !defined(MAX) */
516 #define CHARTOINT(ch) (ch - '0')
517 #endif /* !defined(CHARTOINT) */
519 #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
520 #endif /* !defined(ISDIGIT) */
522 #define ISNAN(x) (x != x)
523 #endif /* !defined(ISNAN) */
525 #define ISINF(x) (x != 0.0 && x + x == x)
526 #endif /* !defined(ISINF) */
530 #endif /* defined(OUTCHAR) */
531 #define OUTCHAR(str, len, size, ch) \
533 if (len + 1 < size) \
536 } while (/* CONSTCOND */ 0)
538 static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
539 static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
540 static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *);
541 static void printsep(char *, size_t *, size_t);
542 static int getnumsep(int);
543 static int getexponent(LDOUBLE);
544 static int convert(UINTMAX_T, char *, size_t, int, int);
545 static UINTMAX_T cast(LDOUBLE);
546 static UINTMAX_T myround(LDOUBLE);
547 static LDOUBLE mypow10(int);
550 rpl_vsnprintf(char *str, size_t size, const char *format, va_list args);
553 rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
557 unsigned char cvalue;
558 const char *strvalue;
560 PTRDIFF_T *ptrdiffptr;
566 signed char *charptr;
574 int state = PRINT_S_DEFAULT;
578 * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
579 * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer
580 * even if a size larger than zero was specified. At least NetBSD's
581 * snprintf(3) does the same, as well as other versions of this file.
582 * (Though some of these versions will write to a non-NULL buffer even
583 * if a size of zero was specified, which violates the standard.)
585 if (str == NULL && size != 0)
590 case PRINT_S_DEFAULT:
592 state = PRINT_S_FLAGS;
594 OUTCHAR(str, len, size, ch);
600 flags |= PRINT_F_MINUS;
604 flags |= PRINT_F_PLUS;
608 flags |= PRINT_F_SPACE;
612 flags |= PRINT_F_NUM;
616 flags |= PRINT_F_ZERO;
619 case '\'': /* SUSv2 flag (not in C99). */
620 flags |= PRINT_F_QUOTE;
624 state = PRINT_S_WIDTH;
631 if (width > (INT_MAX - ch) / 10) {
635 width = 10 * width + ch;
637 } else if (ch == '*') {
639 * C99 says: "A negative field width argument is
640 * taken as a `-' flag followed by a positive
641 * field width." (7.19.6.1, 5)
643 if ((width = va_arg(args, int)) < 0) {
644 flags |= PRINT_F_MINUS;
654 state = PRINT_S_PRECISION;
659 case PRINT_S_PRECISION:
664 if (precision > (INT_MAX - ch) / 10) {
668 precision = 10 * precision + ch;
670 } else if (ch == '*') {
672 * C99 says: "A negative precision argument is
673 * taken as if the precision were omitted."
676 if ((precision = va_arg(args, int)) < 0)
687 if (ch == 'h') { /* It's a char. */
689 cflags = PRINT_C_CHAR;
691 cflags = PRINT_C_SHORT;
695 if (ch == 'l') { /* It's a long long. */
697 cflags = PRINT_C_LLONG;
699 cflags = PRINT_C_LONG;
702 cflags = PRINT_C_LDOUBLE;
706 cflags = PRINT_C_INTMAX;
710 cflags = PRINT_C_PTRDIFF;
714 cflags = PRINT_C_SIZE;
718 state = PRINT_S_CONV;
727 value = (signed char)va_arg(args, int);
730 value = (short int)va_arg(args, int);
733 value = va_arg(args, long int);
736 value = va_arg(args, LLONG);
739 value = va_arg(args, SSIZE_T);
742 value = va_arg(args, INTMAX_T);
744 case PRINT_C_PTRDIFF:
745 value = va_arg(args, PTRDIFF_T);
748 value = va_arg(args, int);
751 fmtint(str, &len, size, value, 10, width,
767 flags |= PRINT_F_UNSIGNED;
770 value = (unsigned char)va_arg(args,
774 value = (unsigned short int)va_arg(args,
778 value = va_arg(args, unsigned long int);
781 value = va_arg(args, ULLONG);
784 value = va_arg(args, size_t);
787 value = va_arg(args, UINTMAX_T);
789 case PRINT_C_PTRDIFF:
790 value = va_arg(args, UPTRDIFF_T);
793 value = va_arg(args, unsigned int);
796 fmtint(str, &len, size, value, base, width,
800 /* Not yet supported, we'll use "%F". */
806 /* Not yet supported, we'll use "%f". */
809 if (cflags == PRINT_C_LDOUBLE)
810 fvalue = va_arg(args, LDOUBLE);
812 fvalue = va_arg(args, double);
813 fmtflt(str, &len, size, fvalue, width,
814 precision, flags, &overflow);
822 flags |= PRINT_F_TYPE_E;
823 if (cflags == PRINT_C_LDOUBLE)
824 fvalue = va_arg(args, LDOUBLE);
826 fvalue = va_arg(args, double);
827 fmtflt(str, &len, size, fvalue, width,
828 precision, flags, &overflow);
836 flags |= PRINT_F_TYPE_G;
837 if (cflags == PRINT_C_LDOUBLE)
838 fvalue = va_arg(args, LDOUBLE);
840 fvalue = va_arg(args, double);
842 * If the precision is zero, it is treated as
843 * one (cf. C99: 7.19.6.1, 8).
847 fmtflt(str, &len, size, fvalue, width,
848 precision, flags, &overflow);
853 cvalue = va_arg(args, int);
854 OUTCHAR(str, len, size, cvalue);
857 strvalue = va_arg(args, char *);
858 fmtstr(str, &len, size, strvalue, width,
863 * C99 says: "The value of the pointer is
864 * converted to a sequence of printing
865 * characters, in an implementation-defined
866 * manner." (C99: 7.19.6.1, 8)
868 if ((strvalue = va_arg(args, void *)) == NULL)
870 * We use the glibc format. BSD prints
873 fmtstr(str, &len, size, "(nil)", width,
877 * We use the BSD/glibc format. SysV
878 * omits the "0x" prefix (which we emit
879 * using the PRINT_F_NUM flag).
881 flags |= PRINT_F_NUM;
882 flags |= PRINT_F_UNSIGNED;
883 fmtint(str, &len, size,
884 (UINTPTR_T)strvalue, 16, width,
891 charptr = va_arg(args, signed char *);
895 shortptr = va_arg(args, short int *);
899 longptr = va_arg(args, long int *);
903 llongptr = va_arg(args, LLONG *);
908 * C99 says that with the "z" length
909 * modifier, "a following `n' conversion
910 * specifier applies to a pointer to a
911 * signed integer type corresponding to
912 * size_t argument." (7.19.6.1, 7)
914 sizeptr = va_arg(args, SSIZE_T *);
918 intmaxptr = va_arg(args, INTMAX_T *);
921 case PRINT_C_PTRDIFF:
922 ptrdiffptr = va_arg(args, PTRDIFF_T *);
926 intptr = va_arg(args, int *);
931 case '%': /* Print a "%" character verbatim. */
932 OUTCHAR(str, len, size, ch);
934 default: /* Skip other characters. */
938 state = PRINT_S_DEFAULT;
939 base = cflags = flags = width = 0;
947 str[size - 1] = '\0';
949 if (overflow || len >= INT_MAX) {
950 errno = overflow ? EOVERFLOW : ERANGE;
957 fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
958 int precision, int flags)
960 int padlen, strln; /* Amount to pad. */
961 int noprecision = (precision == -1);
963 if (value == NULL) /* We're forgiving. */
966 /* If a precision was specified, don't read the string past it. */
967 for (strln = 0; value[strln] != '\0' &&
968 (noprecision || strln < precision); strln++)
971 if ((padlen = width - strln) < 0)
973 if (flags & PRINT_F_MINUS) /* Left justify. */
976 while (padlen > 0) { /* Leading spaces. */
977 OUTCHAR(str, *len, size, ' ');
980 while (*value != '\0' && (noprecision || precision-- > 0)) {
981 OUTCHAR(str, *len, size, *value);
984 while (padlen < 0) { /* Trailing spaces. */
985 OUTCHAR(str, *len, size, ' ');
991 fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
992 int precision, int flags)
995 char iconvert[MAX_CONVERT_LENGTH];
998 int spadlen = 0; /* Amount to space pad. */
999 int zpadlen = 0; /* Amount to zero pad. */
1001 int separators = (flags & PRINT_F_QUOTE);
1002 int noprecision = (precision == -1);
1004 if (flags & PRINT_F_UNSIGNED)
1007 uvalue = (value >= 0) ? value : -value;
1010 else if (flags & PRINT_F_PLUS) /* Do a sign. */
1012 else if (flags & PRINT_F_SPACE)
1016 pos = convert(uvalue, iconvert, sizeof(iconvert), base,
1017 flags & PRINT_F_UP);
1019 if (flags & PRINT_F_NUM && uvalue != 0) {
1021 * C99 says: "The result is converted to an `alternative form'.
1022 * For `o' conversion, it increases the precision, if and only
1023 * if necessary, to force the first digit of the result to be a
1024 * zero (if the value and precision are both 0, a single 0 is
1025 * printed). For `x' (or `X') conversion, a nonzero result has
1026 * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
1030 if (precision <= pos)
1031 precision = pos + 1;
1034 hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
1039 if (separators) /* Get the number of group separators we'll print. */
1040 separators = getnumsep(pos);
1042 zpadlen = precision - pos - separators;
1043 spadlen = width /* Minimum field width. */
1044 - separators /* Number of separators. */
1045 - MAX(precision, pos) /* Number of integer digits. */
1046 - ((sign != 0) ? 1 : 0) /* Will we print a sign? */
1047 - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */
1055 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
1056 * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a
1057 * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
1059 if (flags & PRINT_F_MINUS) /* Left justify. */
1061 else if (flags & PRINT_F_ZERO && noprecision) {
1065 while (spadlen > 0) { /* Leading spaces. */
1066 OUTCHAR(str, *len, size, ' ');
1069 if (sign != 0) /* Sign. */
1070 OUTCHAR(str, *len, size, sign);
1071 if (hexprefix != 0) { /* A "0x" or "0X" prefix. */
1072 OUTCHAR(str, *len, size, '0');
1073 OUTCHAR(str, *len, size, hexprefix);
1075 while (zpadlen > 0) { /* Leading zeros. */
1076 OUTCHAR(str, *len, size, '0');
1079 while (pos > 0) { /* The actual digits. */
1081 OUTCHAR(str, *len, size, iconvert[pos]);
1082 if (separators > 0 && pos > 0 && pos % 3 == 0)
1083 printsep(str, len, size);
1085 while (spadlen < 0) { /* Trailing spaces. */
1086 OUTCHAR(str, *len, size, ' ');
1092 fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
1093 int precision, int flags, int *overflow)
1099 const char *infnan = NULL;
1100 char iconvert[MAX_CONVERT_LENGTH];
1101 char fconvert[MAX_CONVERT_LENGTH];
1102 char econvert[4]; /* "e-12" (without nul-termination). */
1105 int leadfraczeros = 0;
1114 int separators = (flags & PRINT_F_QUOTE);
1115 int estyle = (flags & PRINT_F_TYPE_E);
1116 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
1117 struct lconv *lc = localeconv();
1118 #endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
1121 * AIX' man page says the default is 0, but C99 and at least Solaris'
1122 * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
1125 if (precision == -1)
1130 else if (flags & PRINT_F_PLUS) /* Do a sign. */
1132 else if (flags & PRINT_F_SPACE)
1136 infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
1137 else if (ISINF(fvalue))
1138 infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
1140 if (infnan != NULL) {
1142 iconvert[ipos++] = sign;
1143 while (*infnan != '\0')
1144 iconvert[ipos++] = *infnan++;
1145 fmtstr(str, len, size, iconvert, width, ipos, flags);
1149 /* "%e" (or "%E") or "%g" (or "%G") conversion. */
1150 if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
1151 if (flags & PRINT_F_TYPE_G) {
1153 * For "%g" (and "%G") conversions, the precision
1154 * specifies the number of significant digits, which
1155 * includes the digits in the integer part. The
1156 * conversion will or will not be using "e-style" (like
1157 * "%e" or "%E" conversions) depending on the precision
1158 * and on the exponent. However, the exponent can be
1159 * affected by rounding the converted value, so we'll
1160 * leave this decision for later. Until then, we'll
1161 * assume that we're going to do an "e-style" conversion
1162 * (in order to get the exponent calculated). For
1163 * "e-style", the precision must be decremented by one.
1167 * For "%g" (and "%G") conversions, trailing zeros are
1168 * removed from the fractional portion of the result
1169 * unless the "#" flag was specified.
1171 if (!(flags & PRINT_F_NUM))
1174 exponent = getexponent(fvalue);
1180 * Sorry, we only support 9, 19, or 38 digits (that is, the number of
1181 * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
1182 * minus one) past the decimal point due to our conversion method.
1184 switch (sizeof(UINTMAX_T)) {
1199 ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
1200 if (estyle) /* We want exactly one integer digit. */
1201 ufvalue /= mypow10(exponent);
1203 if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
1209 * Factor of ten with the number of digits needed for the fractional
1210 * part. For example, if the precision is 3, the mask will be 1000.
1212 mask = mypow10(precision);
1214 * We "cheat" by converting the fractional part to integer by
1215 * multiplying by a factor of ten.
1217 if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
1219 * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
1220 * (because precision = 3). Now, myround(1000 * 0.99962) will
1221 * return 1000. So, the integer part must be incremented by one
1222 * and the fractional part must be set to zero.
1226 if (estyle && intpart == 10) {
1228 * The value was rounded up to ten, but we only want one
1229 * integer digit if using "e-style". So, the integer
1230 * part must be set to one and the exponent must be
1231 * incremented by one.
1239 * Now that we know the real exponent, we can check whether or not to
1240 * use "e-style" for "%g" (and "%G") conversions. If we don't need
1241 * "e-style", the precision must be adjusted and the integer and
1242 * fractional parts must be recalculated from the original value.
1244 * C99 says: "Let P equal the precision if nonzero, 6 if the precision
1245 * is omitted, or 1 if the precision is zero. Then, if a conversion
1246 * with style `E' would have an exponent of X:
1248 * - if P > X >= -4, the conversion is with style `f' (or `F') and
1249 * precision P - (X + 1).
1251 * - otherwise, the conversion is with style `e' (or `E') and precision
1252 * P - 1." (7.19.6.1, 8)
1254 * Note that we had decremented the precision by one.
1256 if (flags & PRINT_F_TYPE_G && estyle &&
1257 precision + 1 > exponent && exponent >= -4) {
1258 precision -= exponent;
1265 exponent = -exponent;
1271 * Convert the exponent. The sizeof(econvert) is 4. So, the
1272 * econvert buffer can hold e.g. "e+99" and "e-99". We don't
1273 * support an exponent which contains more than two digits.
1274 * Therefore, the following stores are safe.
1276 epos = convert(exponent, econvert, 2, 10, 0);
1278 * C99 says: "The exponent always contains at least two digits,
1279 * and only as many more digits as necessary to represent the
1280 * exponent." (7.19.6.1, 8)
1283 econvert[epos++] = '0';
1284 econvert[epos++] = esign;
1285 econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
1288 /* Convert the integer part and the fractional part. */
1289 ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
1290 if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */
1291 fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
1293 leadfraczeros = precision - fpos;
1296 if (fpos > 0) /* Omit trailing fractional part zeros. */
1297 while (omitcount < fpos && fconvert[omitcount] == '0')
1299 else { /* The fractional part is zero, omit it completely. */
1300 omitcount = precision;
1303 precision -= omitcount;
1307 * Print a decimal point if either the fractional part is non-zero
1308 * and/or the "#" flag was specified.
1310 if (precision > 0 || flags & PRINT_F_NUM)
1312 if (separators) /* Get the number of group separators we'll print. */
1313 separators = getnumsep(ipos);
1315 padlen = width /* Minimum field width. */
1316 - ipos /* Number of integer digits. */
1317 - epos /* Number of exponent characters. */
1318 - precision /* Number of fractional digits. */
1319 - separators /* Number of group separators. */
1320 - (emitpoint ? 1 : 0) /* Will we print a decimal point? */
1321 - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */
1327 * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
1328 * ignored." (7.19.6.1, 6)
1330 if (flags & PRINT_F_MINUS) /* Left justifty. */
1332 else if (flags & PRINT_F_ZERO && padlen > 0) {
1333 if (sign != 0) { /* Sign. */
1334 OUTCHAR(str, *len, size, sign);
1337 while (padlen > 0) { /* Leading zeros. */
1338 OUTCHAR(str, *len, size, '0');
1342 while (padlen > 0) { /* Leading spaces. */
1343 OUTCHAR(str, *len, size, ' ');
1346 if (sign != 0) /* Sign. */
1347 OUTCHAR(str, *len, size, sign);
1348 while (ipos > 0) { /* Integer part. */
1350 OUTCHAR(str, *len, size, iconvert[ipos]);
1351 if (separators > 0 && ipos > 0 && ipos % 3 == 0)
1352 printsep(str, len, size);
1354 if (emitpoint) { /* Decimal point. */
1355 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
1356 if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
1357 OUTCHAR(str, *len, size, *lc->decimal_point);
1358 else /* We'll always print some decimal point character. */
1359 #endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
1360 OUTCHAR(str, *len, size, '.');
1362 while (leadfraczeros > 0) { /* Leading fractional part zeros. */
1363 OUTCHAR(str, *len, size, '0');
1366 while (fpos > omitcount) { /* The remaining fractional part. */
1368 OUTCHAR(str, *len, size, fconvert[fpos]);
1370 while (epos > 0) { /* Exponent. */
1372 OUTCHAR(str, *len, size, econvert[epos]);
1374 while (padlen < 0) { /* Trailing spaces. */
1375 OUTCHAR(str, *len, size, ' ');
1381 printsep(char *str, size_t *len, size_t size)
1383 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
1384 struct lconv *lc = localeconv();
1387 if (lc->thousands_sep != NULL)
1388 for (i = 0; lc->thousands_sep[i] != '\0'; i++)
1389 OUTCHAR(str, *len, size, lc->thousands_sep[i]);
1391 #endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
1392 OUTCHAR(str, *len, size, ',');
1396 getnumsep(int digits)
1398 int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
1399 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
1401 struct lconv *lc = localeconv();
1403 /* We support an arbitrary separator length (including zero). */
1404 if (lc->thousands_sep != NULL) {
1405 for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
1407 separators *= strln;
1409 #endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
1414 getexponent(LDOUBLE value)
1416 LDOUBLE tmp = (value >= 0.0) ? value : -value;
1420 * We check for 99 > exponent > -99 in order to work around possible
1421 * endless loops which could happen (at least) in the second loop (at
1422 * least) if we're called with an infinite value. However, we checked
1423 * for infinity before calling this function using our ISINF() macro, so
1424 * this might be somewhat paranoid.
1426 while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
1428 while (tmp >= 10.0 && ++exponent < 99)
1435 convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
1437 const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
1440 /* We return an unterminated buffer with the digits in reverse order. */
1442 buf[pos++] = digits[value % base];
1444 } while (value != 0 && pos < size);
1455 * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
1456 * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
1457 * it may be increased to the nearest higher representable value for the
1458 * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE
1459 * value although converting the latter to UINTMAX_T would overflow.
1461 if (value >= UINTMAX_MAX)
1466 * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
1467 * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
1468 * the standard). Sigh.
1470 return (result <= value) ? result : result - 1;
1474 myround(LDOUBLE value)
1476 UINTMAX_T intpart = cast(value);
1478 return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
1482 mypow10(int exponent)
1486 while (exponent > 0) {
1490 while (exponent < 0) {
1496 #endif /* HW_WANT_RPL_VSNPRINTF */
1498 #if HW_WANT_RPL_VASPRINTF
1501 mymemcpy(void *dst, void *src, size_t len)
1503 const char *from = src;
1506 /* No need for optimization, we use this only to replace va_copy(3). */
1511 #endif /* NEED_MYMEMCPY */
1514 rpl_vasprintf(char **ret, const char *format, va_list ap);
1517 rpl_vasprintf(char **ret, const char *format, va_list ap)
1524 len = vsnprintf(NULL, 0, format, aq);
1526 if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
1528 return vsnprintf(*ret, size, format, ap);
1530 #endif /* HW_WANT_RPL_VASPRINTF */
1532 #if HW_WANT_RPL_SNPRINTF
1535 rpl_snprintf(char *str, size_t size, const char *format, ...);
1538 rpl_snprintf(char *str, size_t size, const char *format, ...)
1541 rpl_snprintf(va_alist) va_dcl
1542 #endif /* HAVE_STDARG_H */
1548 #endif /* HAVE_STDARG_H */
1552 VA_START(ap, format);
1553 VA_SHIFT(ap, str, char *);
1554 VA_SHIFT(ap, size, size_t);
1555 VA_SHIFT(ap, format, const char *);
1556 len = vsnprintf(str, size, format, ap);
1560 #endif /* HW_WANT_RPL_SNPRINTF */
1562 #if HW_WANT_RPL_ASPRINTF
1565 rpl_asprintf(char **ret, const char *format, ...);
1568 rpl_asprintf(char **ret, const char *format, ...)
1571 rpl_asprintf(va_alist) va_dcl
1572 #endif /* HAVE_STDARG_H */
1577 #endif /* HAVE_STDARG_H */
1581 VA_START(ap, format);
1582 VA_SHIFT(ap, ret, char **);
1583 VA_SHIFT(ap, format, const char *);
1584 len = vasprintf(ret, format, ap);
1588 #endif /* HW_WANT_RPL_ASPRINTF */
1589 #else /* Dummy declaration to avoid empty translation unit warnings. */
1591 #endif /* HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || [...] */
1597 const char *float_fmt[] = {
1598 /* "%E" and "%e" formats. */
1599 #if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX
1605 #endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */
1606 "foo|%#+0123.9E|bar",
1618 #if !OS_LINUX /* glibc sometimes gets these wrong. */
1645 #endif /* !OS_LINUX */
1646 /* "%F" and "%f" formats. */
1647 #if !OS_BSD && !OS_IRIX
1652 #if HAVE_LONG_LONG_INT
1658 #endif /* HAVE_LONG_LONG_INT */
1659 #endif /* !OS_BSD && !OS_IRIX */
1660 "foo|%#+0123.9F|bar",
1698 /* "%G" and "%g" formats. */
1699 #if !OS_BSD && !OS_IRIX && !OS_LINUX
1704 #if HAVE_LONG_LONG_INT
1710 #endif /* HAVE_LONG_LONG_INT */
1711 #endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */
1712 "foo|%#+0123.9G|bar",
1724 #if !OS_LINUX /* glibc sometimes gets these wrong. */
1751 #endif /* !OS_LINUX */
1754 double float_val[] = {
1810 #if !OS_BSD /* BSD sometimes gets these wrong. */
1814 #endif /* defined(INFINITY) */
1817 #endif /* defined(NAN) */
1818 #endif /* !OS_BSD */
1821 const char *long_fmt[] = {
1828 #endif /* !OS_IRiX */
1869 long int long_val[] = {
1872 #endif /* LONG_MAX */
1875 #endif /* LONG_MIN */
1885 const char *ulong_fmt[] = {
1893 #endif /* !OS_IRiX */
1941 /* "%X" and "%x" formats. */
1977 unsigned long int ulong_val[] = {
1980 #endif /* ULONG_MAX */
1988 const char *llong_fmt[] = {
2007 LLONG llong_val[] = {
2010 #endif /* LLONG_MAX */
2013 #endif /* LLONG_MIN */
2023 const char *string_fmt[] = {
2043 const char *string_val[] = {
2046 "Sound check: One, two, three.",
2047 "This string is a little longer than the other strings.",
2052 #if !OS_SYSV /* SysV uses a different format than we do. */
2053 const char *pointer_fmt[] = {
2059 const char *pointer_val[] = {
2065 #endif /* !OS_SYSV */
2066 char buf1[1024], buf2[1024];
2067 double value, digits = 9.123456789012345678901234567890123456789;
2068 int i, j, r1, r2, failed = 0, num = 0;
2071 * Use -DTEST_NILS in order to also test the conversion of nil values. Might
2072 * segfault on systems which don't support converting a NULL pointer with "%s"
2073 * and lets some test cases fail against BSD and glibc due to bugs in their
2081 #endif /* !defined(TEST_NILS) */
2084 #endif /* defined(TEST) */
2085 #define TEST(fmt, val) \
2087 for (i = 0; fmt[i] != NULL; i++) \
2088 for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \
2089 r1 = sprintf(buf1, fmt[i], val[j]); \
2090 r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \
2091 if (strcmp(buf1, buf2) != 0 || r1 != r2) { \
2092 (void)printf("Results don't match, " \
2093 "format string: %s\n" \
2094 "\t sprintf(3): [%s] (%d)\n" \
2095 "\tsnprintf(3): [%s] (%d)\n", \
2096 fmt[i], buf1, r1, buf2, r2); \
2101 } while (/* CONSTCOND */ 0)
2104 (void)setlocale(LC_ALL, "");
2105 #endif /* HAVE_LOCALE_H */
2107 (void)puts("Testing our snprintf(3) against your system's sprintf(3).");
2108 TEST(float_fmt, float_val);
2109 TEST(long_fmt, long_val);
2110 TEST(ulong_fmt, ulong_val);
2111 TEST(llong_fmt, llong_val);
2112 TEST(string_fmt, string_val);
2113 #if !OS_SYSV /* SysV uses a different format than we do. */
2114 TEST(pointer_fmt, pointer_val);
2115 #endif /* !OS_SYSV */
2116 (void)printf("Result: %d out of %d tests failed.\n", failed, num);
2118 (void)fputs("Checking how many digits we support: ", stdout);
2119 for (i = 0; i < 100; i++) {
2120 value = pow(10, i) * digits;
2121 (void)sprintf(buf1, "%.1f", value);
2122 (void)snprintf(buf2, sizeof(buf2), "%.1f", value);
2123 if (strcmp(buf1, buf2) != 0) {
2124 (void)printf("apparently %d.\n", i);
2128 return (failed == 0) ? 0 : 1;
2130 #endif /* TEST_SNPRINTF */
2132 /* vim: set joinspaces textwidth=80: */