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