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