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