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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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