Annotation of embedaddon/rsync/lib/snprintf.c, revision 1.1
1.1 ! misho 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:
! 196: static size_t dopr(char *buffer, size_t maxlen, const char *format,
! 197: va_list args_in);
! 198: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
! 199: char *value, int flags, int min, int max);
! 200: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
! 201: long value, int base, int min, int max, int flags);
! 202: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
! 203: LDOUBLE fvalue, int min, int max, int flags);
! 204: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
! 205:
! 206: static 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:
! 469: static 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:
! 507: static 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:
! 591: static LDOUBLE abs_val(LDOUBLE value)
! 592: {
! 593: LDOUBLE result = value;
! 594:
! 595: if (value < 0)
! 596: result = -value;
! 597:
! 598: return result;
! 599: }
! 600:
! 601: static 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:
! 613: static 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 */
! 626: static 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:
! 658: static 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:
! 810: static 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)
! 832: int 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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>