1 /* 2 * NOTE: If you change this file, please merge it into rsync, samba, etc. 3 */ 4 5 /* 6 * Copyright Patrick Powell 1995 7 * This code is based on code written by Patrick Powell (papowell@astart.com) 8 * It may be used for any purpose as long as this notice remains intact 9 * on all source code distributions 10 */ 11 12 /************************************************************** 13 * Original: 14 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 15 * A bombproof version of doprnt (dopr) included. 16 * Sigh. This sort of thing is always nasty do deal with. Note that 17 * the version here does not include floating point... 18 * 19 * snprintf() is used instead of sprintf() as it does limit checks 20 * for string length. This covers a nasty loophole. 21 * 22 * The other functions are there to prevent NULL pointers from 23 * causing nast effects. 24 * 25 * More Recently: 26 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 27 * This was ugly. It is still ugly. I opted out of floating point 28 * numbers, but the formatter understands just about everything 29 * from the normal C string format, at least as far as I can tell from 30 * the Solaris 2.5 printf(3S) man page. 31 * 32 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 33 * Ok, added some minimal floating point support, which means this 34 * probably requires libm on most operating systems. Don't yet 35 * support the exponent (e,E) and sigfig (g,G). Also, fmtint() 36 * was pretty badly broken, it just wasn't being exercised in ways 37 * which showed it, so that's been fixed. Also, formatted the code 38 * to mutt conventions, and removed dead code left over from the 39 * original. Also, there is now a builtin-test, just compile with: 40 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm 41 * and run snprintf for results. 42 * 43 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i 44 * The PGP code was using unsigned hexadecimal formats. 45 * Unfortunately, unsigned formats simply didn't work. 46 * 47 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 48 * The original code assumed that both snprintf() and vsnprintf() were 49 * missing. Some systems only have snprintf() but not vsnprintf(), so 50 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 51 * 52 * Andrew Tridgell (tridge@samba.org) Oct 1998 53 * fixed handling of %.0f 54 * added test for HAVE_LONG_DOUBLE 55 * 56 * tridge@samba.org, idra@samba.org, April 2001 57 * got rid of fcvt code (twas buggy and made testing harder) 58 * added C99 semantics 59 * 60 * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 61 * actually print args for %g and %e 62 * 63 * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 64 * Since includes.h isn't included here, VA_COPY has to be defined here. I don't 65 * see any include file that is guaranteed to be here, so I'm defining it 66 * locally. Fixes AIX and Solaris builds. 67 * 68 * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 69 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of 70 * functions 71 * 72 * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 73 * Fix usage of va_list passed as an arg. Use __va_copy before using it 74 * when it exists. 75 * 76 * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 77 * Fix incorrect zpadlen handling in fmtfp. 78 * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it. 79 * few mods to make it easier to compile the tests. 80 * addedd the "Ollie" test to the floating point ones. 81 * 82 * Martin Pool (mbp@samba.org) April 2003 83 * Remove NO_CONFIG_H so that the test case can be built within a source 84 * tree with less trouble. 85 * Remove unnecessary SAFE_FREE() definition. 86 * 87 * Martin Pool (mbp@samba.org) May 2003 88 * Put in a prototype for dummy_snprintf() to quiet compiler warnings. 89 * 90 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even 91 * if the C library has some snprintf functions already. 92 * 93 * Darren Tucker (dtucker@zip.com.au) 2005 94 * Fix bug allowing read overruns of the source string with "%.*s" 95 * Usually harmless unless the read runs outside the process' allocation 96 * (eg if your malloc does guard pages) in which case it will segfault. 97 * From OpenSSH. Also added test for same. 98 * 99 * Simo Sorce (idra@samba.org) Jan 2006 100 * 101 * Add support for position independent parameters 102 * fix fmtstr now it conforms to sprintf wrt min.max 103 * 104 **************************************************************/ 105 106 #include "replace.h" 107 #include "system/locale.h" 108 109 #ifdef TEST_SNPRINTF /* need math library headers for testing */ 110 111 /* In test mode, we pretend that this system doesn't have any snprintf 112 * functions, regardless of what config.h says. */ 113 # undef HAVE_SNPRINTF 114 # undef HAVE_VSNPRINTF 115 # undef HAVE_C99_VSNPRINTF 116 # undef HAVE_ASPRINTF 117 # undef HAVE_VASPRINTF 118 # include <math.h> 119 #endif /* TEST_SNPRINTF */ 120 121 #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) 122 /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ 123 #include <stdio.h> 124 /* make the compiler happy with an empty file */ 125 void dummy_snprintf(void); 126 void dummy_snprintf(void) {} 127 #endif /* HAVE_SNPRINTF, etc */ 128 129 /* yes this really must be a ||. Don't muck with this (tridge) */ 130 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 131 132 #ifdef HAVE_LONG_DOUBLE 133 #define LDOUBLE long double 134 #else 135 #define LDOUBLE double 136 #endif 137 138 #ifdef HAVE_LONG_LONG 139 #define LLONG long long 140 #else 141 #define LLONG long 142 #endif 143 144 #ifndef VA_COPY 145 #ifdef HAVE_VA_COPY 146 #define VA_COPY(dest, src) va_copy(dest, src) 147 #else 148 #ifdef HAVE___VA_COPY 149 #define VA_COPY(dest, src) __va_copy(dest, src) 150 #else 151 #define VA_COPY(dest, src) (dest) = (src) 152 #endif 153 #endif 154 155 /* 156 * dopr(): poor man's version of doprintf 157 */ 158 159 /* format read states */ 160 #define DP_S_DEFAULT 0 161 #define DP_S_FLAGS 1 162 #define DP_S_MIN 2 163 #define DP_S_DOT 3 164 #define DP_S_MAX 4 165 #define DP_S_MOD 5 166 #define DP_S_CONV 6 167 #define DP_S_DONE 7 168 169 /* format flags - Bits */ 170 #define DP_F_MINUS (1 << 0) 171 #define DP_F_PLUS (1 << 1) 172 #define DP_F_SPACE (1 << 2) 173 #define DP_F_NUM (1 << 3) 174 #define DP_F_ZERO (1 << 4) 175 #define DP_F_UP (1 << 5) 176 #define DP_F_UNSIGNED (1 << 6) 177 178 /* Conversion Flags */ 179 #define DP_C_CHAR 1 180 #define DP_C_SHORT 2 181 #define DP_C_LONG 3 182 #define DP_C_LDOUBLE 4 183 #define DP_C_LLONG 5 184 #define DP_C_SIZET 6 185 186 /* Chunk types */ 187 #define CNK_FMT_STR 0 188 #define CNK_INT 1 189 #define CNK_OCTAL 2 190 #define CNK_UINT 3 191 #define CNK_HEX 4 192 #define CNK_FLOAT 5 193 #define CNK_CHAR 6 194 #define CNK_STRING 7 195 #define CNK_PTR 8 196 #define CNK_NUM 9 197 #define CNK_PRCNT 10 198 199 #define char_to_int(p) ((p)- '0') 200 #ifndef MAX 201 #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 202 #endif 203 204 struct pr_chunk { 205 int type; /* chunk type */ 206 int num; /* parameter number */ 207 int min; 208 int max; 209 int flags; 210 int cflags; 211 int start; 212 int len; 213 LLONG value; 214 LDOUBLE fvalue; 215 char *strvalue; 216 void *pnum; 217 struct pr_chunk *min_star; 218 struct pr_chunk *max_star; 219 struct pr_chunk *next; 220 }; 221 222 struct pr_chunk_x { 223 struct pr_chunk **chunks; 224 int num; 225 }; 226 227 static int dopr(char *buffer, size_t maxlen, const char *format, 228 va_list args_in); 229 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 230 char *value, int flags, int min, int max); 231 static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 232 LLONG value, int base, int min, int max, int flags); 233 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, 234 LDOUBLE fvalue, int min, int max, int flags); 235 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 236 static struct pr_chunk *new_chunk(void); 237 static int add_cnk_list_entry(struct pr_chunk_x **list, 238 int max_num, struct pr_chunk *chunk); 239 240 static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) 241 { 242 char ch; 243 int state; 244 int pflag; 245 int pnum; 246 int pfirst; 247 size_t currlen; 248 va_list args; 249 const char *base; 250 struct pr_chunk *chunks = NULL; 251 struct pr_chunk *cnk = NULL; 252 struct pr_chunk_x *clist = NULL; 253 int max_pos; 254 int ret = -1; 255 256 VA_COPY(args, args_in); 257 258 state = DP_S_DEFAULT; 259 pfirst = 1; 260 pflag = 0; 261 pnum = 0; 262 263 max_pos = 0; 264 base = format; 265 ch = *format++; 266 267 /* retrieve the string structure as chunks */ 268 while (state != DP_S_DONE) { 269 if (ch == '\0') 270 state = DP_S_DONE; 271 272 switch(state) { 273 case DP_S_DEFAULT: 274 275 if (cnk) { 276 cnk->next = new_chunk(); 277 cnk = cnk->next; 278 } else { 279 cnk = new_chunk(); 280 } 281 if (!cnk) goto done; 282 if (!chunks) chunks = cnk; 283 284 if (ch == '%') { 285 state = DP_S_FLAGS; 286 ch = *format++; 287 } else { 288 cnk->type = CNK_FMT_STR; 289 cnk->start = format - base -1; 290 while ((ch != '\0') && (ch != '%')) ch = *format++; 291 cnk->len = format - base - cnk->start -1; 292 } 293 break; 294 case DP_S_FLAGS: 295 switch (ch) { 296 case '-': 297 cnk->flags |= DP_F_MINUS; 298 ch = *format++; 299 break; 300 case '+': 301 cnk->flags |= DP_F_PLUS; 302 ch = *format++; 303 break; 304 case ' ': 305 cnk->flags |= DP_F_SPACE; 306 ch = *format++; 307 break; 308 case '#': 309 cnk->flags |= DP_F_NUM; 310 ch = *format++; 311 break; 312 case '0': 313 cnk->flags |= DP_F_ZERO; 314 ch = *format++; 315 break; 316 case 'I': 317 /* internationalization not supported yet */ 318 ch = *format++; 319 break; 320 default: 321 state = DP_S_MIN; 322 break; 323 } 324 break; 325 case DP_S_MIN: 326 if (isdigit((unsigned char)ch)) { 327 cnk->min = 10 * cnk->min + char_to_int (ch); 328 ch = *format++; 329 } else if (ch == '$') { 330 if (!pfirst && !pflag) { 331 /* parameters must be all positioned or none */ 332 goto done; 333 } 334 if (pfirst) { 335 pfirst = 0; 336 pflag = 1; 337 } 338 if (cnk->min == 0) /* what ?? */ 339 goto done; 340 cnk->num = cnk->min; 341 cnk->min = 0; 342 ch = *format++; 343 } else if (ch == '*') { 344 if (pfirst) pfirst = 0; 345 cnk->min_star = new_chunk(); 346 if (!cnk->min_star) /* out of memory :-( */ 347 goto done; 348 cnk->min_star->type = CNK_INT; 349 if (pflag) { 350 int num; 351 ch = *format++; 352 if (!isdigit((unsigned char)ch)) { 353 /* parameters must be all positioned or none */ 354 goto done; 355 } 356 for (num = 0; isdigit((unsigned char)ch); ch = *format++) { 357 num = 10 * num + char_to_int(ch); 358 } 359 cnk->min_star->num = num; 360 if (ch != '$') /* what ?? */ 361 goto done; 362 } else { 363 cnk->min_star->num = ++pnum; 364 } 365 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); 366 if (max_pos == 0) /* out of memory :-( */ 367 goto done; 368 ch = *format++; 369 state = DP_S_DOT; 370 } else { 371 if (pfirst) pfirst = 0; 372 state = DP_S_DOT; 373 } 374 break; 375 case DP_S_DOT: 376 if (ch == '.') { 377 state = DP_S_MAX; 378 ch = *format++; 379 } else { 380 state = DP_S_MOD; 381 } 382 break; 383 case DP_S_MAX: 384 if (isdigit((unsigned char)ch)) { 385 if (cnk->max < 0) 386 cnk->max = 0; 387 cnk->max = 10 * cnk->max + char_to_int (ch); 388 ch = *format++; 389 } else if (ch == '$') { 390 if (!pfirst && !pflag) { 391 /* parameters must be all positioned or none */ 392 goto done; 393 } 394 if (cnk->max <= 0) /* what ?? */ 395 goto done; 396 cnk->num = cnk->max; 397 cnk->max = -1; 398 ch = *format++; 399 } else if (ch == '*') { 400 cnk->max_star = new_chunk(); 401 if (!cnk->max_star) /* out of memory :-( */ 402 goto done; 403 cnk->max_star->type = CNK_INT; 404 if (pflag) { 405 int num; 406 ch = *format++; 407 if (!isdigit((unsigned char)ch)) { 408 /* parameters must be all positioned or none */ 409 goto done; 410 } 411 for (num = 0; isdigit((unsigned char)ch); ch = *format++) { 412 num = 10 * num + char_to_int(ch); 413 } 414 cnk->max_star->num = num; 415 if (ch != '$') /* what ?? */ 416 goto done; 417 } else { 418 cnk->max_star->num = ++pnum; 419 } 420 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); 421 if (max_pos == 0) /* out of memory :-( */ 422 goto done; 423 424 ch = *format++; 425 state = DP_S_MOD; 426 } else { 427 state = DP_S_MOD; 428 } 429 break; 430 case DP_S_MOD: 431 switch (ch) { 432 case 'h': 433 cnk->cflags = DP_C_SHORT; 434 ch = *format++; 435 if (ch == 'h') { 436 cnk->cflags = DP_C_CHAR; 437 ch = *format++; 438 } 439 break; 440 case 'l': 441 cnk->cflags = DP_C_LONG; 442 ch = *format++; 443 if (ch == 'l') { /* It's a long long */ 444 cnk->cflags = DP_C_LLONG; 445 ch = *format++; 446 } 447 break; 448 case 'j': 449 cnk->cflags = DP_C_LLONG; 450 ch = *format++; 451 break; 452 case 'L': 453 cnk->cflags = DP_C_LDOUBLE; 454 ch = *format++; 455 break; 456 case 'z': 457 cnk->cflags = DP_C_SIZET; 458 ch = *format++; 459 break; 460 default: 461 break; 462 } 463 state = DP_S_CONV; 464 break; 465 case DP_S_CONV: 466 if (cnk->num == 0) cnk->num = ++pnum; 467 max_pos = add_cnk_list_entry(&clist, max_pos, cnk); 468 if (max_pos == 0) /* out of memory :-( */ 469 goto done; 470 471 switch (ch) { 472 case 'd': 473 case 'i': 474 cnk->type = CNK_INT; 475 break; 476 case 'o': 477 cnk->type = CNK_OCTAL; 478 cnk->flags |= DP_F_UNSIGNED; 479 break; 480 case 'u': 481 cnk->type = CNK_UINT; 482 cnk->flags |= DP_F_UNSIGNED; 483 break; 484 case 'X': 485 cnk->flags |= DP_F_UP; 486 case 'x': 487 cnk->type = CNK_HEX; 488 cnk->flags |= DP_F_UNSIGNED; 489 break; 490 case 'A': 491 /* hex float not supported yet */ 492 case 'E': 493 case 'G': 494 case 'F': 495 cnk->flags |= DP_F_UP; 496 case 'a': 497 /* hex float not supported yet */ 498 case 'e': 499 case 'f': 500 case 'g': 501 cnk->type = CNK_FLOAT; 502 break; 503 case 'c': 504 cnk->type = CNK_CHAR; 505 break; 506 case 's': 507 cnk->type = CNK_STRING; 508 break; 509 case 'p': 510 cnk->type = CNK_PTR; 511 cnk->flags |= DP_F_UNSIGNED; 512 break; 513 case 'n': 514 cnk->type = CNK_NUM; 515 break; 516 case '%': 517 cnk->type = CNK_PRCNT; 518 break; 519 default: 520 /* Unknown, bail out*/ 521 goto done; 522 } 523 ch = *format++; 524 state = DP_S_DEFAULT; 525 break; 526 case DP_S_DONE: 527 break; 528 default: 529 /* hmm? */ 530 break; /* some picky compilers need this */ 531 } 532 } 533 534 /* retrieve the format arguments */ 535 for (pnum = 0; pnum < max_pos; pnum++) { 536 int i; 537 538 if (clist[pnum].num == 0) { 539 /* ignoring a parameter should not be permitted 540 * all parameters must be matched at least once 541 * BUT seem some system ignore this rule ... 542 * at least my glibc based system does --SSS 543 */ 544 #ifdef DEBUG_SNPRINTF 545 printf("parameter at position %d not used\n", pnum+1); 546 #endif 547 /* eat the parameter */ 548 va_arg (args, int); 549 continue; 550 } 551 for (i = 1; i < clist[pnum].num; i++) { 552 if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) { 553 /* nooo noo no! 554 * all the references to a parameter 555 * must be of the same type 556 */ 557 goto done; 558 } 559 } 560 cnk = clist[pnum].chunks[0]; 561 switch (cnk->type) { 562 case CNK_INT: 563 if (cnk->cflags == DP_C_SHORT) 564 cnk->value = va_arg (args, int); 565 else if (cnk->cflags == DP_C_LONG) 566 cnk->value = va_arg (args, long int); 567 else if (cnk->cflags == DP_C_LLONG) 568 cnk->value = va_arg (args, LLONG); 569 else if (cnk->cflags == DP_C_SIZET) 570 cnk->value = va_arg (args, ssize_t); 571 else 572 cnk->value = va_arg (args, int); 573 574 for (i = 1; i < clist[pnum].num; i++) { 575 clist[pnum].chunks[i]->value = cnk->value; 576 } 577 break; 578 579 case CNK_OCTAL: 580 case CNK_UINT: 581 case CNK_HEX: 582 if (cnk->cflags == DP_C_SHORT) 583 cnk->value = va_arg (args, unsigned int); 584 else if (cnk->cflags == DP_C_LONG) 585 cnk->value = (unsigned long int)va_arg (args, unsigned long int); 586 else if (cnk->cflags == DP_C_LLONG) 587 cnk->value = (LLONG)va_arg (args, unsigned LLONG); 588 else if (cnk->cflags == DP_C_SIZET) 589 cnk->value = (size_t)va_arg (args, size_t); 590 else 591 cnk->value = (unsigned int)va_arg (args, unsigned int); 592 593 for (i = 1; i < clist[pnum].num; i++) { 594 clist[pnum].chunks[i]->value = cnk->value; 595 } 596 break; 597 598 case CNK_FLOAT: 599 if (cnk->cflags == DP_C_LDOUBLE) 600 cnk->fvalue = va_arg (args, LDOUBLE); 601 else 602 cnk->fvalue = va_arg (args, double); 603 604 for (i = 1; i < clist[pnum].num; i++) { 605 clist[pnum].chunks[i]->fvalue = cnk->fvalue; 606 } 607 break; 608 609 case CNK_CHAR: 610 cnk->value = va_arg (args, int); 611 612 for (i = 1; i < clist[pnum].num; i++) { 613 clist[pnum].chunks[i]->value = cnk->value; 614 } 615 break; 616 617 case CNK_STRING: 618 cnk->strvalue = va_arg (args, char *); 619 if (!cnk->strvalue) cnk->strvalue = "(NULL)"; 620 621 for (i = 1; i < clist[pnum].num; i++) { 622 clist[pnum].chunks[i]->strvalue = cnk->strvalue; 623 } 624 break; 625 626 case CNK_PTR: 627 cnk->strvalue = va_arg (args, void *); 628 for (i = 1; i < clist[pnum].num; i++) { 629 clist[pnum].chunks[i]->strvalue = cnk->strvalue; 630 } 631 break; 632 633 case CNK_NUM: 634 if (cnk->cflags == DP_C_CHAR) 635 cnk->pnum = va_arg (args, char *); 636 else if (cnk->cflags == DP_C_SHORT) 637 cnk->pnum = va_arg (args, short int *); 638 else if (cnk->cflags == DP_C_LONG) 639 cnk->pnum = va_arg (args, long int *); 640 else if (cnk->cflags == DP_C_LLONG) 641 cnk->pnum = va_arg (args, LLONG *); 642 else if (cnk->cflags == DP_C_SIZET) 643 cnk->pnum = va_arg (args, ssize_t *); 644 else 645 cnk->pnum = va_arg (args, int *); 646 647 for (i = 1; i < clist[pnum].num; i++) { 648 clist[pnum].chunks[i]->pnum = cnk->pnum; 649 } 650 break; 651 652 case CNK_PRCNT: 653 break; 654 655 default: 656 /* what ?? */ 657 goto done; 658 } 659 } 660 /* print out the actual string from chunks */ 661 currlen = 0; 662 cnk = chunks; 663 while (cnk) { 664 int len, min, max; 665 666 if (cnk->min_star) min = cnk->min_star->value; 667 else min = cnk->min; 668 if (cnk->max_star) max = cnk->max_star->value; 669 else max = cnk->max; 670 671 switch (cnk->type) { 672 673 case CNK_FMT_STR: 674 if (maxlen != 0 && maxlen > currlen) { 675 if (maxlen > (currlen + cnk->len)) len = cnk->len; 676 else len = maxlen - currlen; 677 678 memcpy(&(buffer[currlen]), &(base[cnk->start]), len); 679 } 680 currlen += cnk->len; 681 682 break; 683 684 case CNK_INT: 685 case CNK_UINT: 686 fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags); 687 break; 688 689 case CNK_OCTAL: 690 fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags); 691 break; 692 693 case CNK_HEX: 694 fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags); 695 break; 696 697 case CNK_FLOAT: 698 fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags); 699 break; 700 701 case CNK_CHAR: 702 dopr_outch (buffer, &currlen, maxlen, cnk->value); 703 break; 704 705 case CNK_STRING: 706 if (max == -1) { 707 max = strlen(cnk->strvalue); 708 } 709 fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max); 710 break; 711 712 case CNK_PTR: 713 fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags); 714 break; 715 716 case CNK_NUM: 717 if (cnk->cflags == DP_C_CHAR) 718 *((char *)(cnk->pnum)) = (char)currlen; 719 else if (cnk->cflags == DP_C_SHORT) 720 *((short int *)(cnk->pnum)) = (short int)currlen; 721 else if (cnk->cflags == DP_C_LONG) 722 *((long int *)(cnk->pnum)) = (long int)currlen; 723 else if (cnk->cflags == DP_C_LLONG) 724 *((LLONG *)(cnk->pnum)) = (LLONG)currlen; 725 else if (cnk->cflags == DP_C_SIZET) 726 *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen; 727 else 728 *((int *)(cnk->pnum)) = (int)currlen; 729 break; 730 731 case CNK_PRCNT: 732 dopr_outch (buffer, &currlen, maxlen, '%'); 733 break; 734 735 default: 736 /* what ?? */ 737 goto done; 738 } 739 cnk = cnk->next; 740 } 741 if (maxlen != 0) { 742 if (currlen < maxlen - 1) 743 buffer[currlen] = '\0'; 744 else if (maxlen > 0) 745 buffer[maxlen - 1] = '\0'; 746 } 747 ret = currlen; 748 749 done: 750 va_end(args); 751 752 while (chunks) { 753 cnk = chunks->next; 754 free(chunks); 755 chunks = cnk; 756 } 757 if (clist) { 758 for (pnum = 0; pnum < max_pos; pnum++) { 759 if (clist[pnum].chunks) free(clist[pnum].chunks); 760 } 761 free(clist); 762 } 763 return ret; 764 } 765 766 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 767 char *value, int flags, int min, int max) 768 { 769 int padlen, strln; /* amount to pad */ 770 int cnt = 0; 771 772 #ifdef DEBUG_SNPRINTF 773 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); 774 #endif 775 if (value == 0) { 776 value = "<NULL>"; 777 } 778 779 for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ 780 padlen = min - strln; 781 if (padlen < 0) 782 padlen = 0; 783 if (flags & DP_F_MINUS) 784 padlen = -padlen; /* Left Justify */ 785 786 while (padlen > 0) { 787 dopr_outch (buffer, currlen, maxlen, ' '); 788 --padlen; 789 } 790 while (*value && (cnt < max)) { 791 dopr_outch (buffer, currlen, maxlen, *value++); 792 ++cnt; 793 } 794 while (padlen < 0) { 795 dopr_outch (buffer, currlen, maxlen, ' '); 796 ++padlen; 797 } 798 } 799 800 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 801 802 static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 803 LLONG value, int base, int min, int max, int flags) 804 { 805 int signvalue = 0; 806 unsigned LLONG uvalue; 807 char convert[22+1]; /* 64-bit value in octal: 22 digits + \0 */ 808 int place = 0; 809 int spadlen = 0; /* amount to space pad */ 810 int zpadlen = 0; /* amount to zero pad */ 811 int caps = 0; 812 813 if (max < 0) 814 max = 0; 815 816 uvalue = value; 817 818 if(!(flags & DP_F_UNSIGNED)) { 819 if( value < 0 ) { 820 signvalue = '-'; 821 uvalue = -value; 822 } else { 823 if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 824 signvalue = '+'; 825 else if (flags & DP_F_SPACE) 826 signvalue = ' '; 827 } 828 } 829 830 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 831 832 do { 833 convert[place++] = 834 (caps? "0123456789ABCDEF":"0123456789abcdef") 835 [uvalue % (unsigned)base ]; 836 uvalue = (uvalue / (unsigned)base ); 837 } while(uvalue && (place < sizeof(convert))); 838 if (place == sizeof(convert)) place--; 839 convert[place] = 0; 840 841 zpadlen = max - place; 842 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 843 if (zpadlen < 0) zpadlen = 0; 844 if (spadlen < 0) spadlen = 0; 845 if (flags & DP_F_ZERO) { 846 zpadlen = MAX(zpadlen, spadlen); 847 spadlen = 0; 848 } 849 if (flags & DP_F_MINUS) 850 spadlen = -spadlen; /* Left Justifty */ 851 852 #ifdef DEBUG_SNPRINTF 853 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", 854 zpadlen, spadlen, min, max, place); 855 #endif 856 857 /* Spaces */ 858 while (spadlen > 0) { 859 dopr_outch (buffer, currlen, maxlen, ' '); 860 --spadlen; 861 } 862 863 /* Sign */ 864 if (signvalue) 865 dopr_outch (buffer, currlen, maxlen, signvalue); 866 867 /* Zeros */ 868 if (zpadlen > 0) { 869 while (zpadlen > 0) { 870 dopr_outch (buffer, currlen, maxlen, '0'); 871 --zpadlen; 872 } 873 } 874 875 /* Digits */ 876 while (place > 0) 877 dopr_outch (buffer, currlen, maxlen, convert[--place]); 878 879 /* Left Justified spaces */ 880 while (spadlen < 0) { 881 dopr_outch (buffer, currlen, maxlen, ' '); 882 ++spadlen; 883 } 884 } 885 886 static LDOUBLE abs_val(LDOUBLE value) 887 { 888 LDOUBLE result = value; 889 890 if (value < 0) 891 result = -value; 892 893 return result; 894 } 895 896 static LDOUBLE POW10(int exp) 897 { 898 LDOUBLE result = 1; 899 900 while (exp) { 901 result *= 10; 902 exp--; 903 } 904 905 return result; 906 } 907 908 static LLONG ROUND(LDOUBLE value) 909 { 910 LLONG intpart; 911 912 intpart = (LLONG)value; 913 value = value - intpart; 914 if (value >= 0.5) intpart++; 915 916 return intpart; 917 } 918 919 /* a replacement for modf that doesn't need the math library. Should 920 be portable, but slow */ 921 static double my_modf(double x0, double *iptr) 922 { 923 int i; 924 LLONG l=0; 925 double x = x0; 926 double f = 1.0; 927 928 for (i=0;i<100;i++) { 929 l = (long)x; 930 if (l <= (x+1) && l >= (x-1)) break; 931 x *= 0.1; 932 f *= 10.0; 933 } 934 935 if (i == 100) { 936 /* yikes! the number is beyond what we can handle. What do we do? */ 937 (*iptr) = 0; 938 return 0; 939 } 940 941 if (i != 0) { 942 double i2; 943 double ret; 944 945 ret = my_modf(x0-l*f, &i2); 946 (*iptr) = l*f + i2; 947 return ret; 948 } 949 950 (*iptr) = l; 951 return x - (*iptr); 952 } 953 954 955 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, 956 LDOUBLE fvalue, int min, int max, int flags) 957 { 958 int signvalue = 0; 959 double ufvalue; 960 char iconvert[311]; 961 char fconvert[311]; 962 int iplace = 0; 963 int fplace = 0; 964 int padlen = 0; /* amount to pad */ 965 int zpadlen = 0; 966 int caps = 0; 967 int idx; 968 double intpart; 969 double fracpart; 970 double temp; 971 972 /* 973 * AIX manpage says the default is 0, but Solaris says the default 974 * is 6, and sprintf on AIX defaults to 6 975 */ 976 if (max < 0) 977 max = 6; 978 979 ufvalue = abs_val (fvalue); 980 981 if (fvalue < 0) { 982 signvalue = '-'; 983 } else { 984 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ 985 signvalue = '+'; 986 } else { 987 if (flags & DP_F_SPACE) 988 signvalue = ' '; 989 } 990 } 991 992 #if 0 993 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 994 #endif 995 996 #if 0 997 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ 998 #endif 999 1000 /* 1001 * Sorry, we only support 9 digits past the decimal because of our 1002 * conversion method 1003 */ 1004 if (max > 9) 1005 max = 9; 1006 1007 /* We "cheat" by converting the fractional part to integer by 1008 * multiplying by a factor of 10 1009 */ 1010 1011 temp = ufvalue; 1012 my_modf(temp, &intpart); 1013 1014 fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); 1015 1016 if (fracpart >= POW10(max)) { 1017 intpart++; 1018 fracpart -= POW10(max); 1019 } 1020 1021 1022 /* Convert integer part */ 1023 do { 1024 temp = intpart*0.1; 1025 my_modf(temp, &intpart); 1026 idx = (int) ((temp -intpart +0.05)* 10.0); 1027 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ 1028 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ 1029 iconvert[iplace++] = 1030 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 1031 } while (intpart && (iplace < 311)); 1032 if (iplace == 311) iplace--; 1033 iconvert[iplace] = 0; 1034 1035 /* Convert fractional part */ 1036 if (fracpart) 1037 { 1038 do { 1039 temp = fracpart*0.1; 1040 my_modf(temp, &fracpart); 1041 idx = (int) ((temp -fracpart +0.05)* 10.0); 1042 /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ 1043 /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ 1044 fconvert[fplace++] = 1045 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 1046 } while(fracpart && (fplace < 311)); 1047 if (fplace == 311) fplace--; 1048 } 1049 fconvert[fplace] = 0; 1050 1051 /* -1 for decimal point, another -1 if we are printing a sign */ 1052 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 1053 zpadlen = max - fplace; 1054 if (zpadlen < 0) zpadlen = 0; 1055 if (padlen < 0) 1056 padlen = 0; 1057 if (flags & DP_F_MINUS) 1058 padlen = -padlen; /* Left Justifty */ 1059 1060 if ((flags & DP_F_ZERO) && (padlen > 0)) { 1061 if (signvalue) { 1062 dopr_outch (buffer, currlen, maxlen, signvalue); 1063 --padlen; 1064 signvalue = 0; 1065 } 1066 while (padlen > 0) { 1067 dopr_outch (buffer, currlen, maxlen, '0'); 1068 --padlen; 1069 } 1070 } 1071 while (padlen > 0) { 1072 dopr_outch (buffer, currlen, maxlen, ' '); 1073 --padlen; 1074 } 1075 if (signvalue) 1076 dopr_outch (buffer, currlen, maxlen, signvalue); 1077 1078 while (iplace > 0) 1079 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); 1080 1081 #ifdef DEBUG_SNPRINTF 1082 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); 1083 #endif 1084 1085 /* 1086 * Decimal point. This should probably use locale to find the correct 1087 * char to print out. 1088 */ 1089 if (max > 0) { 1090 dopr_outch (buffer, currlen, maxlen, '.'); 1091 1092 while (zpadlen > 0) { 1093 dopr_outch (buffer, currlen, maxlen, '0'); 1094 --zpadlen; 1095 } 1096 1097 while (fplace > 0) 1098 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); 1099 } 1100 1101 while (padlen < 0) { 1102 dopr_outch (buffer, currlen, maxlen, ' '); 1103 ++padlen; 1104 } 1105 } 1106 1107 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) 1108 { 1109 if (*currlen < maxlen) { 1110 buffer[(*currlen)] = c; 1111 } 1112 (*currlen)++; 1113 } 1114 1115 static struct pr_chunk *new_chunk(void) { 1116 struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk)); 1117 1118 if (!new_c) 1119 return NULL; 1120 1121 new_c->type = 0; 1122 new_c->num = 0; 1123 new_c->min = 0; 1124 new_c->min_star = NULL; 1125 new_c->max = -1; 1126 new_c->max_star = NULL; 1127 new_c->flags = 0; 1128 new_c->cflags = 0; 1129 new_c->start = 0; 1130 new_c->len = 0; 1131 new_c->value = 0; 1132 new_c->fvalue = 0; 1133 new_c->strvalue = NULL; 1134 new_c->pnum = NULL; 1135 new_c->next = NULL; 1136 1137 return new_c; 1138 } 1139 1140 static int add_cnk_list_entry(struct pr_chunk_x **list, 1141 int max_num, struct pr_chunk *chunk) { 1142 struct pr_chunk_x *l; 1143 struct pr_chunk **c; 1144 int max; 1145 int cnum; 1146 int i, pos; 1147 1148 if (chunk->num > max_num) { 1149 max = chunk->num; 1150 1151 if (*list == NULL) { 1152 l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max); 1153 pos = 0; 1154 } else { 1155 l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max); 1156 pos = max_num; 1157 } 1158 if (l == NULL) { 1159 for (i = 0; i < max; i++) { 1160 if ((*list)[i].chunks) free((*list)[i].chunks); 1161 } 1162 return 0; 1163 } 1164 for (i = pos; i < max; i++) { 1165 l[i].chunks = NULL; 1166 l[i].num = 0; 1167 } 1168 } else { 1169 l = *list; 1170 max = max_num; 1171 } 1172 1173 i = chunk->num - 1; 1174 cnum = l[i].num + 1; 1175 if (l[i].chunks == NULL) { 1176 c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 1177 } else { 1178 c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum); 1179 } 1180 if (c == NULL) { 1181 for (i = 0; i < max; i++) { 1182 if (l[i].chunks) free(l[i].chunks); 1183 } 1184 return 0; 1185 } 1186 c[l[i].num] = chunk; 1187 l[i].chunks = c; 1188 l[i].num = cnum; 1189 1190 *list = l; 1191 return max; 1192 } 1193 1194 int rep_vsnprintf (char *str, size_t count, const char *fmt, va_list args) 1195 { 1196 return dopr(str, count, fmt, args); 1197 } 1198 #endif 1199 1200 /* yes this really must be a ||. Don't muck with this (tridge) 1201 * 1202 * The logic for these two is that we need our own definition if the 1203 * OS *either* has no definition of *sprintf, or if it does have one 1204 * that doesn't work properly according to the autoconf test. 1205 */ 1206 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 1207 int rep_snprintf(char *str,size_t count,const char *fmt,...) 1208 { 1209 size_t ret; 1210 va_list ap; 1211 1212 va_start(ap, fmt); 1213 ret = vsnprintf(str, count, fmt, ap); 1214 va_end(ap); 1215 return ret; 1216 } 1217 #endif 1218 1219 #ifndef HAVE_C99_VSNPRINTF 1220 int rep_printf(const char *fmt, ...) 1221 { 1222 va_list ap; 1223 int ret; 1224 char *s; 1225 1226 s = NULL; 1227 va_start(ap, fmt); 1228 ret = vasprintf(&s, fmt, ap); 1229 va_end(ap); 1230 1231 if (s) { 1232 fwrite(s, 1, strlen(s), stdout); 1233 } 1234 free(s); 1235 1236 return ret; 1237 } 1238 #endif 1239 1240 #ifndef HAVE_C99_VSNPRINTF 1241 int rep_fprintf(FILE *stream, const char *fmt, ...) 1242 { 1243 va_list ap; 1244 int ret; 1245 char *s; 1246 1247 s = NULL; 1248 va_start(ap, fmt); 1249 ret = vasprintf(&s, fmt, ap); 1250 va_end(ap); 1251 1252 if (s) { 1253 fwrite(s, 1, strlen(s), stream); 1254 } 1255 free(s); 1256 1257 return ret; 1258 } 1259 #endif 1260 1261 #endif 1262 1263 #if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) 1264 int rep_vasprintf(char **ptr, const char *format, va_list ap) 1265 { 1266 int ret; 1267 va_list ap2; 1268 1269 VA_COPY(ap2, ap); 1270 ret = vsnprintf(NULL, 0, format, ap2); 1271 va_end(ap2); 1272 if (ret < 0) return ret; 1273 1274 (*ptr) = (char *)malloc(ret+1); 1275 if (!*ptr) return -1; 1276 1277 VA_COPY(ap2, ap); 1278 ret = vsnprintf(*ptr, ret+1, format, ap2); 1279 va_end(ap2); 1280 1281 return ret; 1282 } 1283 #endif 1284 1285 #if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) 1286 int rep_asprintf(char **ptr, const char *format, ...) 1287 { 1288 va_list ap; 1289 int ret; 1290 1291 *ptr = NULL; 1292 va_start(ap, format); 1293 ret = vasprintf(ptr, format, ap); 1294 va_end(ap); 1295 1296 return ret; 1297 } 1298 #endif 1299 1300 #ifdef TEST_SNPRINTF 1301 1302 int sprintf(char *str,const char *fmt,...); 1303 int printf(const char *fmt,...); 1304 1305 int main (void) 1306 { 1307 char buf1[1024]; 1308 char buf2[1024]; 1309 char *buf3; 1310 char *fp_fmt[] = { 1311 "%1.1f", 1312 "%-1.5f", 1313 "%1.5f", 1314 "%123.9f", 1315 "%10.5f", 1316 "% 10.5f", 1317 "%+22.9f", 1318 "%+4.9f", 1319 "%01.3f", 1320 "%4f", 1321 "%3.1f", 1322 "%3.2f", 1323 "%.0f", 1324 "%f", 1325 "%-8.8f", 1326 "%-9.9f", 1327 NULL 1328 }; 1329 double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 1330 0.9996, 1.996, 4.136, 5.030201, 0.00205, 1331 /* END LIST */ 0}; 1332 char *int_fmt[] = { 1333 "%-1.5d", 1334 "%1.5d", 1335 "%123.9d", 1336 "%5.5d", 1337 "%10.5d", 1338 "% 10.5d", 1339 "%+22.33d", 1340 "%01.3d", 1341 "%4d", 1342 "%d", 1343 NULL 1344 }; 1345 long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; 1346 char *str_fmt[] = { 1347 "%10.5s", 1348 "%-10.5s", 1349 "%5.10s", 1350 "%-5.10s", 1351 "%10.1s", 1352 "%0.10s", 1353 "%10.0s", 1354 "%1.10s", 1355 "%s", 1356 "%.1s", 1357 "%.10s", 1358 "%10s", 1359 NULL 1360 }; 1361 char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; 1362 #ifdef HAVE_LONG_LONG 1363 char *ll_fmt[] = { 1364 "%llu", 1365 NULL 1366 }; 1367 LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0}; 1368 #endif 1369 int x, y; 1370 int fail = 0; 1371 int num = 0; 1372 int l1, l2; 1373 char *ss_fmt[] = { 1374 "%zd", 1375 "%zu", 1376 NULL 1377 }; 1378 size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0}; 1379 1380 printf ("Testing snprintf format codes against system sprintf...\n"); 1381 1382 for (x = 0; fp_fmt[x] ; x++) { 1383 for (y = 0; fp_nums[y] != 0 ; y++) { 1384 buf1[0] = buf2[0] = '\0'; 1385 l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); 1386 l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); 1387 buf1[1023] = buf2[1023] = '\0'; 1388 if (strcmp (buf1, buf2) || (l1 != l2)) { 1389 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1390 fp_fmt[x], l1, buf1, l2, buf2); 1391 fail++; 1392 } 1393 num++; 1394 } 1395 } 1396 1397 for (x = 0; int_fmt[x] ; x++) { 1398 for (y = 0; int_nums[y] != 0 ; y++) { 1399 buf1[0] = buf2[0] = '\0'; 1400 l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); 1401 l2 = sprintf (buf2, int_fmt[x], int_nums[y]); 1402 buf1[1023] = buf2[1023] = '\0'; 1403 if (strcmp (buf1, buf2) || (l1 != l2)) { 1404 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1405 int_fmt[x], l1, buf1, l2, buf2); 1406 fail++; 1407 } 1408 num++; 1409 } 1410 } 1411 1412 for (x = 0; str_fmt[x] ; x++) { 1413 for (y = 0; str_vals[y] != 0 ; y++) { 1414 buf1[0] = buf2[0] = '\0'; 1415 l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); 1416 l2 = sprintf (buf2, str_fmt[x], str_vals[y]); 1417 buf1[1023] = buf2[1023] = '\0'; 1418 if (strcmp (buf1, buf2) || (l1 != l2)) { 1419 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1420 str_fmt[x], l1, buf1, l2, buf2); 1421 fail++; 1422 } 1423 num++; 1424 } 1425 } 1426 1427 #ifdef HAVE_LONG_LONG 1428 for (x = 0; ll_fmt[x] ; x++) { 1429 for (y = 0; ll_nums[y] != 0 ; y++) { 1430 buf1[0] = buf2[0] = '\0'; 1431 l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]); 1432 l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]); 1433 buf1[1023] = buf2[1023] = '\0'; 1434 if (strcmp (buf1, buf2) || (l1 != l2)) { 1435 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1436 ll_fmt[x], l1, buf1, l2, buf2); 1437 fail++; 1438 } 1439 num++; 1440 } 1441 } 1442 #endif 1443 1444 #define BUFSZ 2048 1445 1446 buf1[0] = buf2[0] = '\0'; 1447 if ((buf3 = malloc(BUFSZ)) == NULL) { 1448 fail++; 1449 } else { 1450 num++; 1451 memset(buf3, 'a', BUFSZ); 1452 snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3); 1453 buf1[1023] = '\0'; 1454 if (strcmp(buf1, "a") != 0) { 1455 printf("length limit buf1 '%s' expected 'a'\n", buf1); 1456 fail++; 1457 } 1458 } 1459 1460 buf1[0] = buf2[0] = '\0'; 1461 l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); 1462 l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); 1463 buf1[1023] = buf2[1023] = '\0'; 1464 if (strcmp(buf1, buf2) || (l1 != l2)) { 1465 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1466 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); 1467 fail++; 1468 } 1469 1470 buf1[0] = buf2[0] = '\0'; 1471 l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); 1472 l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); 1473 buf1[1023] = buf2[1023] = '\0'; 1474 if (strcmp(buf1, buf2)) { 1475 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1476 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); 1477 fail++; 1478 } 1479 1480 for (x = 0; ss_fmt[x] ; x++) { 1481 for (y = 0; ss_nums[y] != 0 ; y++) { 1482 buf1[0] = buf2[0] = '\0'; 1483 l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]); 1484 l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]); 1485 buf1[1023] = buf2[1023] = '\0'; 1486 if (strcmp (buf1, buf2) || (l1 != l2)) { 1487 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1488 ss_fmt[x], l1, buf1, l2, buf2); 1489 fail++; 1490 } 1491 num++; 1492 } 1493 } 1494 #if 0 1495 buf1[0] = buf2[0] = '\0'; 1496 l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890); 1497 l2 = sprintf(buf2, "%lld", (LLONG)1234567890); 1498 buf1[1023] = buf2[1023] = '\0'; 1499 if (strcmp(buf1, buf2)) { 1500 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1501 "%lld", l1, buf1, l2, buf2); 1502 fail++; 1503 } 1504 1505 buf1[0] = buf2[0] = '\0'; 1506 l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123); 1507 l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123); 1508 buf1[1023] = buf2[1023] = '\0'; 1509 if (strcmp(buf1, buf2)) { 1510 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 1511 "%Lf", l1, buf1, l2, buf2); 1512 fail++; 1513 } 1514 #endif 1515 printf ("%d tests failed out of %d.\n", fail, num); 1516 1517 printf("seeing how many digits we support\n"); 1518 { 1519 double v0 = 0.12345678901234567890123456789012345678901; 1520 for (x=0; x<100; x++) { 1521 double p = pow(10, x); 1522 double r = v0*p; 1523 snprintf(buf1, sizeof(buf1), "%1.1f", r); 1524 sprintf(buf2, "%1.1f", r); 1525 if (strcmp(buf1, buf2)) { 1526 printf("we seem to support %d digits\n", x-1); 1527 break; 1528 } 1529 } 1530 } 1531 1532 return 0; 1533 } 1534 #endif /* TEST_SNPRINTF */ 1535