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, formated 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 94#ifndef NO_CONFIG_H 95#include "config.h" 96#else 97#define NULL 0 98#endif 99 100#ifdef TEST_SNPRINTF /* need math library headers for testing */ 101 102/* In test mode, we pretend that this system doesn't have any snprintf 103 * functions, regardless of what config.h says. */ 104# undef HAVE_SNPRINTF 105# undef HAVE_VSNPRINTF 106# undef HAVE_C99_VSNPRINTF 107# undef HAVE_ASPRINTF 108# undef HAVE_VASPRINTF 109# include <math.h> 110#endif /* TEST_SNPRINTF */ 111 112#ifdef HAVE_STRING_H 113#include <string.h> 114#endif 115 116#ifdef HAVE_STRINGS_H 117#include <strings.h> 118#endif 119#ifdef HAVE_CTYPE_H 120#include <ctype.h> 121#endif 122#include <sys/types.h> 123#include <stdarg.h> 124#ifdef HAVE_STDLIB_H 125#include <stdlib.h> 126#endif 127 128#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) 129/* only include stdio.h if we are not re-defining snprintf or vsnprintf */ 130#include <stdio.h> 131 /* make the compiler happy with an empty file */ 132 void dummy_snprintf(void); 133 void dummy_snprintf(void) {} 134#endif /* HAVE_SNPRINTF, etc */ 135 136#ifdef HAVE_LONG_DOUBLE 137#define LDOUBLE long double 138#else 139#define LDOUBLE double 140#endif 141 142#if SIZEOF_LONG_LONG 143#define LLONG long long 144#else 145#define LLONG long 146#endif 147 148#ifndef VA_COPY 149#if defined HAVE_VA_COPY || defined va_copy 150#define VA_COPY(dest, src) va_copy(dest, src) 151#else 152#ifdef HAVE___VA_COPY 153#define VA_COPY(dest, src) __va_copy(dest, src) 154#else 155#define VA_COPY(dest, src) (dest) = (src) 156#endif 157#endif 158 159/* 160 * dopr(): poor man's version of doprintf 161 */ 162 163/* format read states */ 164#define DP_S_DEFAULT 0 165#define DP_S_FLAGS 1 166#define DP_S_MIN 2 167#define DP_S_DOT 3 168#define DP_S_MAX 4 169#define DP_S_MOD 5 170#define DP_S_CONV 6 171#define DP_S_DONE 7 172 173/* format flags - Bits */ 174#define DP_F_MINUS (1 << 0) 175#define DP_F_PLUS (1 << 1) 176#define DP_F_SPACE (1 << 2) 177#define DP_F_NUM (1 << 3) 178#define DP_F_ZERO (1 << 4) 179#define DP_F_UP (1 << 5) 180#define DP_F_UNSIGNED (1 << 6) 181 182/* Conversion Flags */ 183#define DP_C_SHORT 1 184#define DP_C_LONG 2 185#define DP_C_LDOUBLE 3 186#define DP_C_LLONG 4 187 188#define char_to_int(p) ((p)- '0') 189#ifndef MAX 190#define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 191#endif 192 193/* yes this really must be a ||. Don't muck with this (tridge) */ 194#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 195 196static size_t dopr(char *buffer, size_t maxlen, const char *format, 197 va_list args_in); 198static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 199 char *value, int flags, int min, int max); 200static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 201 long value, int base, int min, int max, int flags); 202static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, 203 LDOUBLE fvalue, int min, int max, int flags); 204static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 205 206static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) 207{ 208 char ch; 209 LLONG value; 210 LDOUBLE fvalue; 211 char *strvalue; 212 int min; 213 int max; 214 int state; 215 int flags; 216 int cflags; 217 size_t currlen; 218 va_list args; 219 220 VA_COPY(args, args_in); 221 222 state = DP_S_DEFAULT; 223 currlen = flags = cflags = min = 0; 224 max = -1; 225 ch = *format++; 226 227 while (state != DP_S_DONE) { 228 if (ch == '\0') 229 state = DP_S_DONE; 230 231 switch(state) { 232 case DP_S_DEFAULT: 233 if (ch == '%') 234 state = DP_S_FLAGS; 235 else 236 dopr_outch (buffer, &currlen, maxlen, ch); 237 ch = *format++; 238 break; 239 case DP_S_FLAGS: 240 switch (ch) { 241 case '-': 242 flags |= DP_F_MINUS; 243 ch = *format++; 244 break; 245 case '+': 246 flags |= DP_F_PLUS; 247 ch = *format++; 248 break; 249 case ' ': 250 flags |= DP_F_SPACE; 251 ch = *format++; 252 break; 253 case '#': 254 flags |= DP_F_NUM; 255 ch = *format++; 256 break; 257 case '0': 258 flags |= DP_F_ZERO; 259 ch = *format++; 260 break; 261 default: 262 state = DP_S_MIN; 263 break; 264 } 265 break; 266 case DP_S_MIN: 267 if (isdigit((unsigned char)ch)) { 268 min = 10*min + char_to_int (ch); 269 ch = *format++; 270 } else if (ch == '*') { 271 min = va_arg (args, int); 272 ch = *format++; 273 state = DP_S_DOT; 274 } else { 275 state = DP_S_DOT; 276 } 277 break; 278 case DP_S_DOT: 279 if (ch == '.') { 280 state = DP_S_MAX; 281 ch = *format++; 282 } else { 283 state = DP_S_MOD; 284 } 285 break; 286 case DP_S_MAX: 287 if (isdigit((unsigned char)ch)) { 288 if (max < 0) 289 max = 0; 290 max = 10*max + char_to_int (ch); 291 ch = *format++; 292 } else if (ch == '*') { 293 max = va_arg (args, int); 294 ch = *format++; 295 state = DP_S_MOD; 296 } else { 297 state = DP_S_MOD; 298 } 299 break; 300 case DP_S_MOD: 301 switch (ch) { 302 case 'h': 303 cflags = DP_C_SHORT; 304 ch = *format++; 305 break; 306 case 'l': 307 cflags = DP_C_LONG; 308 ch = *format++; 309 if (ch == 'l') { /* It's a long long */ 310 cflags = DP_C_LLONG; 311 ch = *format++; 312 } 313 break; 314 case 'L': 315 cflags = DP_C_LDOUBLE; 316 ch = *format++; 317 break; 318 default: 319 break; 320 } 321 state = DP_S_CONV; 322 break; 323 case DP_S_CONV: 324 switch (ch) { 325 case 'd': 326 case 'i': 327 if (cflags == DP_C_SHORT) 328 value = va_arg (args, int); 329 else if (cflags == DP_C_LONG) 330 value = va_arg (args, long int); 331 else if (cflags == DP_C_LLONG) 332 value = va_arg (args, LLONG); 333 else 334 value = va_arg (args, int); 335 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 336 break; 337 case 'o': 338 flags |= DP_F_UNSIGNED; 339 if (cflags == DP_C_SHORT) 340 value = va_arg (args, unsigned int); 341 else if (cflags == DP_C_LONG) 342 value = (long)va_arg (args, unsigned long int); 343 else if (cflags == DP_C_LLONG) 344 value = (long)va_arg (args, unsigned LLONG); 345 else 346 value = (long)va_arg (args, unsigned int); 347 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); 348 break; 349 case 'u': 350 flags |= DP_F_UNSIGNED; 351 if (cflags == DP_C_SHORT) 352 value = va_arg (args, unsigned int); 353 else if (cflags == DP_C_LONG) 354 value = (long)va_arg (args, unsigned long int); 355 else if (cflags == DP_C_LLONG) 356 value = (LLONG)va_arg (args, unsigned LLONG); 357 else 358 value = (long)va_arg (args, unsigned int); 359 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 360 break; 361 case 'X': 362 flags |= DP_F_UP; 363 case 'x': 364 flags |= DP_F_UNSIGNED; 365 if (cflags == DP_C_SHORT) 366 value = va_arg (args, unsigned int); 367 else if (cflags == DP_C_LONG) 368 value = (long)va_arg (args, unsigned long int); 369 else if (cflags == DP_C_LLONG) 370 value = (LLONG)va_arg (args, unsigned LLONG); 371 else 372 value = (long)va_arg (args, unsigned int); 373 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); 374 break; 375 case 'f': 376 if (cflags == DP_C_LDOUBLE) 377 fvalue = va_arg (args, LDOUBLE); 378 else 379 fvalue = va_arg (args, double); 380 /* um, floating point? */ 381 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 382 break; 383 case 'E': 384 flags |= DP_F_UP; 385 case 'e': 386 if (cflags == DP_C_LDOUBLE) 387 fvalue = va_arg (args, LDOUBLE); 388 else 389 fvalue = va_arg (args, double); 390 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 391 break; 392 case 'G': 393 flags |= DP_F_UP; 394 case 'g': 395 if (cflags == DP_C_LDOUBLE) 396 fvalue = va_arg (args, LDOUBLE); 397 else 398 fvalue = va_arg (args, double); 399 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 400 break; 401 case 'c': 402 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); 403 break; 404 case 's': 405 strvalue = va_arg (args, char *); 406 if (!strvalue) strvalue = "(NULL)"; 407 if (max == -1) { 408 max = strlen(strvalue); 409 } 410 if (min > 0 && max >= 0 && min > max) max = min; 411 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); 412 break; 413 case 'p': 414 strvalue = va_arg (args, void *); 415 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 416 break; 417 case 'n': 418 if (cflags == DP_C_SHORT) { 419 short int *num; 420 num = va_arg (args, short int *); 421 *num = currlen; 422 } else if (cflags == DP_C_LONG) { 423 long int *num; 424 num = va_arg (args, long int *); 425 *num = (long int)currlen; 426 } else if (cflags == DP_C_LLONG) { 427 LLONG *num; 428 num = va_arg (args, LLONG *); 429 *num = (LLONG)currlen; 430 } else { 431 int *num; 432 num = va_arg (args, int *); 433 *num = currlen; 434 } 435 break; 436 case '%': 437 dopr_outch (buffer, &currlen, maxlen, ch); 438 break; 439 case 'w': 440 /* not supported yet, treat as next char */ 441 ch = *format++; 442 break; 443 default: 444 /* Unknown, skip */ 445 break; 446 } 447 ch = *format++; 448 state = DP_S_DEFAULT; 449 flags = cflags = min = 0; 450 max = -1; 451 break; 452 case DP_S_DONE: 453 break; 454 default: 455 /* hmm? */ 456 break; /* some picky compilers need this */ 457 } 458 } 459 if (maxlen != 0) { 460 if (currlen < maxlen - 1) 461 buffer[currlen] = '\0'; 462 else if (maxlen > 0) 463 buffer[maxlen - 1] = '\0'; 464 } 465 466 return currlen; 467} 468 469static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 470 char *value, int flags, int min, int max) 471{ 472 int padlen, strln; /* amount to pad */ 473 int cnt = 0; 474 475#ifdef DEBUG_SNPRINTF 476 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); 477#endif 478 if (value == 0) { 479 value = "<NULL>"; 480 } 481 482 for (strln = 0; value[strln]; ++strln); /* strlen */ 483 padlen = min - strln; 484 if (padlen < 0) 485 padlen = 0; 486 if (flags & DP_F_MINUS) 487 padlen = -padlen; /* Left Justify */ 488 489 while ((padlen > 0) && (cnt < max)) { 490 dopr_outch (buffer, currlen, maxlen, ' '); 491 --padlen; 492 ++cnt; 493 } 494 while (*value && (cnt < max)) { 495 dopr_outch (buffer, currlen, maxlen, *value++); 496 ++cnt; 497 } 498 while ((padlen < 0) && (cnt < max)) { 499 dopr_outch (buffer, currlen, maxlen, ' '); 500 ++padlen; 501 ++cnt; 502 } 503} 504 505/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 506 507static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 508 long value, int base, int min, int max, int flags) 509{ 510 int signvalue = 0; 511 unsigned long uvalue; 512 char convert[20]; 513 int place = 0; 514 int spadlen = 0; /* amount to space pad */ 515 int zpadlen = 0; /* amount to zero pad */ 516 int caps = 0; 517 518 if (max < 0) 519 max = 0; 520 521 uvalue = value; 522 523 if(!(flags & DP_F_UNSIGNED)) { 524 if( value < 0 ) { 525 signvalue = '-'; 526 uvalue = -value; 527 } else { 528 if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 529 signvalue = '+'; 530 else if (flags & DP_F_SPACE) 531 signvalue = ' '; 532 } 533 } 534 535 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 536 537 do { 538 convert[place++] = 539 (caps? "0123456789ABCDEF":"0123456789abcdef") 540 [uvalue % (unsigned)base ]; 541 uvalue = (uvalue / (unsigned)base ); 542 } while(uvalue && (place < 20)); 543 if (place == 20) place--; 544 convert[place] = 0; 545 546 zpadlen = max - place; 547 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 548 if (zpadlen < 0) zpadlen = 0; 549 if (spadlen < 0) spadlen = 0; 550 if (flags & DP_F_ZERO) { 551 zpadlen = MAX(zpadlen, spadlen); 552 spadlen = 0; 553 } 554 if (flags & DP_F_MINUS) 555 spadlen = -spadlen; /* Left Justifty */ 556 557#ifdef DEBUG_SNPRINTF 558 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", 559 zpadlen, spadlen, min, max, place); 560#endif 561 562 /* Spaces */ 563 while (spadlen > 0) { 564 dopr_outch (buffer, currlen, maxlen, ' '); 565 --spadlen; 566 } 567 568 /* Sign */ 569 if (signvalue) 570 dopr_outch (buffer, currlen, maxlen, signvalue); 571 572 /* Zeros */ 573 if (zpadlen > 0) { 574 while (zpadlen > 0) { 575 dopr_outch (buffer, currlen, maxlen, '0'); 576 --zpadlen; 577 } 578 } 579 580 /* Digits */ 581 while (place > 0) 582 dopr_outch (buffer, currlen, maxlen, convert[--place]); 583 584 /* Left Justified spaces */ 585 while (spadlen < 0) { 586 dopr_outch (buffer, currlen, maxlen, ' '); 587 ++spadlen; 588 } 589} 590 591static LDOUBLE abs_val(LDOUBLE value) 592{ 593 LDOUBLE result = value; 594 595 if (value < 0) 596 result = -value; 597 598 return result; 599} 600 601static LDOUBLE POW10(int exp) 602{ 603 LDOUBLE result = 1; 604 605 while (exp) { 606 result *= 10; 607 exp--; 608 } 609 610 return result; 611} 612 613static LLONG ROUND(LDOUBLE value) 614{ 615 LLONG intpart; 616 617 intpart = (LLONG)value; 618 value = value - intpart; 619 if (value >= 0.5) intpart++; 620 621 return intpart; 622} 623 624/* a replacement for modf that doesn't need the math library. Should 625 be portable, but slow */ 626static double my_modf(double x0, double *iptr) 627{ 628 int i; 629 long l; 630 double x = x0; 631 double f = 1.0; 632 633 for (i=0;i<100;i++) { 634 l = (long)x; 635 if (l <= (x+1) && l >= (x-1)) { 636 if (i != 0) { 637 double i2; 638 double ret; 639 640 ret = my_modf(x0-l*f, &i2); 641 (*iptr) = l*f + i2; 642 return ret; 643 } 644 645 (*iptr) = l; 646 return x - (*iptr); 647 } 648 x *= 0.1; 649 f *= 10.0; 650 } 651 652 /* yikes! the number is beyond what we can handle. What do we do? */ 653 (*iptr) = 0; 654 return 0; 655} 656 657 658static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, 659 LDOUBLE fvalue, int min, int max, int flags) 660{ 661 int signvalue = 0; 662 double ufvalue; 663 char iconvert[311]; 664 char fconvert[311]; 665 int iplace = 0; 666 int fplace = 0; 667 int padlen = 0; /* amount to pad */ 668 int zpadlen = 0; 669 int caps = 0; 670 int idx; 671 double intpart; 672 double fracpart; 673 double temp; 674 675 /* 676 * AIX manpage says the default is 0, but Solaris says the default 677 * is 6, and sprintf on AIX defaults to 6 678 */ 679 if (max < 0) 680 max = 6; 681 682 ufvalue = abs_val (fvalue); 683 684 if (fvalue < 0) { 685 signvalue = '-'; 686 } else { 687 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ 688 signvalue = '+'; 689 } else { 690 if (flags & DP_F_SPACE) 691 signvalue = ' '; 692 } 693 } 694 695#if 0 696 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 697#endif 698 699#if 0 700 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ 701#endif 702 703 /* 704 * Sorry, we only support 16 digits past the decimal because of our 705 * conversion method 706 */ 707 if (max > 16) 708 max = 16; 709 710 /* We "cheat" by converting the fractional part to integer by 711 * multiplying by a factor of 10 712 */ 713 714 temp = ufvalue; 715 my_modf(temp, &intpart); 716 717 fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); 718 719 if (fracpart >= POW10(max)) { 720 intpart++; 721 fracpart -= POW10(max); 722 } 723 724 725 /* Convert integer part */ 726 do { 727 temp = intpart*0.1; 728 my_modf(temp, &intpart); 729 idx = (int) ((temp -intpart +0.05)* 10.0); 730 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ 731 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ 732 iconvert[iplace++] = 733 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 734 } while (intpart && (iplace < 311)); 735 if (iplace == 311) iplace--; 736 iconvert[iplace] = 0; 737 738 /* Convert fractional part */ 739 if (fracpart) 740 { 741 do { 742 temp = fracpart*0.1; 743 my_modf(temp, &fracpart); 744 idx = (int) ((temp -fracpart +0.05)* 10.0); 745 /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ 746 /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ 747 fconvert[fplace++] = 748 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 749 } while(fracpart && (fplace < 311)); 750 if (fplace == 311) fplace--; 751 } 752 fconvert[fplace] = 0; 753 754 /* -1 for decimal point, another -1 if we are printing a sign */ 755 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 756 zpadlen = max - fplace; 757 if (zpadlen < 0) zpadlen = 0; 758 if (padlen < 0) 759 padlen = 0; 760 if (flags & DP_F_MINUS) 761 padlen = -padlen; /* Left Justifty */ 762 763 if ((flags & DP_F_ZERO) && (padlen > 0)) { 764 if (signvalue) { 765 dopr_outch (buffer, currlen, maxlen, signvalue); 766 --padlen; 767 signvalue = 0; 768 } 769 while (padlen > 0) { 770 dopr_outch (buffer, currlen, maxlen, '0'); 771 --padlen; 772 } 773 } 774 while (padlen > 0) { 775 dopr_outch (buffer, currlen, maxlen, ' '); 776 --padlen; 777 } 778 if (signvalue) 779 dopr_outch (buffer, currlen, maxlen, signvalue); 780 781 while (iplace > 0) 782 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); 783 784#ifdef DEBUG_SNPRINTF 785 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); 786#endif 787 788 /* 789 * Decimal point. This should probably use locale to find the correct 790 * char to print out. 791 */ 792 if (max > 0) { 793 dopr_outch (buffer, currlen, maxlen, '.'); 794 795 while (zpadlen > 0) { 796 dopr_outch (buffer, currlen, maxlen, '0'); 797 --zpadlen; 798 } 799 800 while (fplace > 0) 801 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); 802 } 803 804 while (padlen < 0) { 805 dopr_outch (buffer, currlen, maxlen, ' '); 806 ++padlen; 807 } 808} 809 810static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) 811{ 812 if (*currlen < maxlen) { 813 buffer[(*currlen)] = c; 814 } 815 (*currlen)++; 816} 817 818 int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args) 819{ 820 return dopr(str, count, fmt, args); 821} 822#define vsnprintf rsync_vsnprintf 823#endif 824 825/* yes this really must be a ||. Don't muck with this (tridge) 826 * 827 * The logic for these two is that we need our own definition if the 828 * OS *either* has no definition of *sprintf, or if it does have one 829 * that doesn't work properly according to the autoconf test. 830 */ 831#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 832int rsync_snprintf(char *str,size_t count,const char *fmt,...) 833{ 834 size_t ret; 835 va_list ap; 836 837 va_start(ap, fmt); 838 ret = vsnprintf(str, count, fmt, ap); 839 va_end(ap); 840 return ret; 841} 842#define snprintf rsync_snprintf 843#endif 844 845#endif 846 847#ifndef HAVE_VASPRINTF 848 int vasprintf(char **ptr, const char *format, va_list ap) 849{ 850 int ret; 851 va_list ap2; 852 853 VA_COPY(ap2, ap); 854 855 ret = vsnprintf(NULL, 0, format, ap2); 856 if (ret <= 0) return ret; 857 858 (*ptr) = (char *)malloc(ret+1); 859 if (!*ptr) return -1; 860 861 VA_COPY(ap2, ap); 862 863 ret = vsnprintf(*ptr, ret+1, format, ap2); 864 865 return ret; 866} 867#endif 868 869 870#ifndef HAVE_ASPRINTF 871 int asprintf(char **ptr, const char *format, ...) 872{ 873 va_list ap; 874 int ret; 875 876 *ptr = NULL; 877 va_start(ap, format); 878 ret = vasprintf(ptr, format, ap); 879 va_end(ap); 880 881 return ret; 882} 883#endif 884 885#ifdef TEST_SNPRINTF 886 887 int sprintf(char *str,const char *fmt,...); 888 889 int main (void) 890{ 891 char buf1[1024]; 892 char buf2[1024]; 893 char *fp_fmt[] = { 894 "%1.1f", 895 "%-1.5f", 896 "%1.5f", 897 "%123.9f", 898 "%10.5f", 899 "% 10.5f", 900 "%+22.9f", 901 "%+4.9f", 902 "%01.3f", 903 "%4f", 904 "%3.1f", 905 "%3.2f", 906 "%.0f", 907 "%f", 908 "-16.16f", 909 NULL 910 }; 911 double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 912 0.9996, 1.996, 4.136, 5.030201, 0.00205, 913 /* END LIST */ 0}; 914 char *int_fmt[] = { 915 "%-1.5d", 916 "%1.5d", 917 "%123.9d", 918 "%5.5d", 919 "%10.5d", 920 "% 10.5d", 921 "%+22.33d", 922 "%01.3d", 923 "%4d", 924 "%d", 925 NULL 926 }; 927 long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; 928 char *str_fmt[] = { 929 "10.5s", 930 "5.10s", 931 "10.1s", 932 "0.10s", 933 "10.0s", 934 "1.10s", 935 "%s", 936 "%.1s", 937 "%.10s", 938 "%10s", 939 NULL 940 }; 941 char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; 942 int x, y; 943 int fail = 0; 944 int num = 0; 945 946 printf ("Testing snprintf format codes against system sprintf...\n"); 947 948 for (x = 0; fp_fmt[x] ; x++) { 949 for (y = 0; fp_nums[y] != 0 ; y++) { 950 int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]); 951 int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); 952 sprintf (buf2, fp_fmt[x], fp_nums[y]); 953 if (strcmp (buf1, buf2)) { 954 printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 955 fp_fmt[x], buf1, buf2); 956 fail++; 957 } 958 if (l1 != l2) { 959 printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]); 960 fail++; 961 } 962 num++; 963 } 964 } 965 966 for (x = 0; int_fmt[x] ; x++) { 967 for (y = 0; int_nums[y] != 0 ; y++) { 968 int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]); 969 int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); 970 sprintf (buf2, int_fmt[x], int_nums[y]); 971 if (strcmp (buf1, buf2)) { 972 printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 973 int_fmt[x], buf1, buf2); 974 fail++; 975 } 976 if (l1 != l2) { 977 printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]); 978 fail++; 979 } 980 num++; 981 } 982 } 983 984 for (x = 0; str_fmt[x] ; x++) { 985 for (y = 0; str_vals[y] != 0 ; y++) { 986 int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]); 987 int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); 988 sprintf (buf2, str_fmt[x], str_vals[y]); 989 if (strcmp (buf1, buf2)) { 990 printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 991 str_fmt[x], buf1, buf2); 992 fail++; 993 } 994 if (l1 != l2) { 995 printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]); 996 fail++; 997 } 998 num++; 999 } 1000 } 1001 1002 printf ("%d tests failed out of %d.\n", fail, num); 1003 1004 printf("seeing how many digits we support\n"); 1005 { 1006 double v0 = 0.12345678901234567890123456789012345678901; 1007 for (x=0; x<100; x++) { 1008 double p = pow(10, x); 1009 double r = v0*p; 1010 snprintf(buf1, sizeof(buf1), "%1.1f", r); 1011 sprintf(buf2, "%1.1f", r); 1012 if (strcmp(buf1, buf2)) { 1013 printf("we seem to support %d digits\n", x-1); 1014 break; 1015 } 1016 } 1017 } 1018 1019 return 0; 1020} 1021#endif /* TEST_SNPRINTF */ 1022