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