|
|
1.1 ! root 1: /* ! 2: Copyright (C) 1993 Free Software Foundation ! 3: ! 4: This file is part of the GNU IO Library. This library is free ! 5: software; you can redistribute it and/or modify it under the ! 6: terms of the GNU General Public License as published by the ! 7: Free Software Foundation; either version 2, or (at your option) ! 8: any later version. ! 9: ! 10: This library is distributed in the hope that it will be useful, ! 11: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 13: GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with GNU CC; see the file COPYING. If not, write to ! 17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 18: ! 19: As a special exception, if you link this library with files ! 20: compiled with a GNU compiler to produce an executable, this does not cause ! 21: the resulting executable to be covered by the GNU General Public License. ! 22: This exception does not however invalidate any other reasons why ! 23: the executable file might be covered by the GNU General Public License. */ ! 24: ! 25: /* ! 26: * Copyright (c) 1990 Regents of the University of California. ! 27: * All rights reserved. ! 28: * ! 29: * Redistribution and use in source and binary forms are permitted ! 30: * provided that the above copyright notice and this paragraph are ! 31: * duplicated in all such forms and that any documentation, ! 32: * advertising materials, and other materials related to such ! 33: * distribution and use acknowledge that the software was developed ! 34: * by the University of California, Berkeley. The name of the ! 35: * University may not be used to endorse or promote products derived ! 36: * from this software without specific prior written permission. ! 37: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 38: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 39: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 40: */ ! 41: ! 42: ! 43: #if defined(LIBC_SCCS) && !defined(lint) ! 44: static char sccsid[] = "%W% (Berkeley) %G%"; ! 45: #endif /* LIBC_SCCS and not lint */ ! 46: ! 47: /* ! 48: * Actual printf innards. ! 49: * ! 50: * This code is large and complicated... ! 51: */ ! 52: ! 53: #include <sys/types.h> ! 54: #include "libioP.h" ! 55: #include <string.h> ! 56: #ifdef __STDC__ ! 57: #include <stdarg.h> ! 58: #else ! 59: #include <varargs.h> ! 60: #endif ! 61: ! 62: /* ! 63: * Define FLOATING_POINT to get floating point. ! 64: */ ! 65: #ifndef NO_FLOATING_POINT ! 66: #define FLOATING_POINT ! 67: #endif ! 68: ! 69: /* end of configuration stuff */ ! 70: ! 71: ! 72: /* ! 73: * Helper "class" for `fprintf to unbuffered': creates a ! 74: * temporary buffer. */ ! 75: ! 76: struct helper_file ! 77: { ! 78: struct _IO_FILE_plus _f; ! 79: _IO_FILE *_put_stream; ! 80: }; ! 81: ! 82: static int ! 83: _IO_helper_overflow (fp, c) ! 84: _IO_FILE *fp; ! 85: int c; ! 86: { ! 87: _IO_FILE *target = ((struct helper_file*)fp)->_put_stream; ! 88: int used = fp->_IO_write_ptr - fp->_IO_write_base; ! 89: if (used) ! 90: { ! 91: _IO_sputn(target, fp->_IO_write_base, used); ! 92: fp->_IO_write_ptr -= used; ! 93: } ! 94: return _IO_putc (c, fp); ! 95: } ! 96: ! 97: static struct _IO_jump_t _IO_helper_jumps = { ! 98: _IO_helper_overflow, ! 99: _IO_default_underflow, ! 100: _IO_default_xsputn, ! 101: _IO_default_xsgetn, ! 102: _IO_default_read, ! 103: _IO_default_write, ! 104: _IO_default_doallocate, ! 105: _IO_default_pbackfail, ! 106: _IO_default_setbuf, ! 107: _IO_default_sync, ! 108: _IO_default_finish, ! 109: _IO_default_close, ! 110: _IO_default_stat, ! 111: _IO_default_seek, ! 112: _IO_default_seekoff, ! 113: _IO_default_seekpos, ! 114: }; ! 115: ! 116: static int ! 117: helper_vfprintf(fp, fmt0, ap) ! 118: register _IO_FILE* fp; ! 119: char const *fmt0; ! 120: _IO_va_list ap; ! 121: { ! 122: char buf[_IO_BUFSIZ]; ! 123: struct helper_file helper; ! 124: register _IO_FILE *hp = (_IO_FILE*)&helper; ! 125: int result, to_flush; ! 126: ! 127: /* initialize helper */ ! 128: helper._put_stream = fp; ! 129: hp->_IO_write_base = buf; ! 130: hp->_IO_write_ptr = buf; ! 131: hp->_IO_write_end = buf+_IO_BUFSIZ; ! 132: hp->_jumps = &_IO_helper_jumps; ! 133: ! 134: /* Now print to helper instead. */ ! 135: result = _IO_vfprintf(hp, fmt0, ap); ! 136: ! 137: /* Now flush anything from the helper to the fp. */ ! 138: if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0) ! 139: { ! 140: if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush) ! 141: return EOF; ! 142: } ! 143: return result; ! 144: } ! 145: ! 146: #ifdef FLOATING_POINT ! 147: ! 148: #include "floatio.h" ! 149: #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ ! 150: #define DEFPREC 6 ! 151: extern double modf _PARAMS((double, double*)); ! 152: ! 153: #else /* no FLOATING_POINT */ ! 154: ! 155: #define BUF 40 ! 156: ! 157: #endif /* FLOATING_POINT */ ! 158: ! 159: ! 160: /* ! 161: * Macros for converting digits to letters and vice versa ! 162: */ ! 163: #define to_digit(c) ((c) - '0') ! 164: #define is_digit(c) ((unsigned)to_digit(c) <= 9) ! 165: #define to_char(n) ((n) + '0') ! 166: ! 167: /* ! 168: * Flags used during conversion. ! 169: */ ! 170: #define LONGINT 0x01 /* long integer */ ! 171: #define LONGDBL 0x02 /* long double; unimplemented */ ! 172: #define SHORTINT 0x04 /* short integer */ ! 173: #define ALT 0x08 /* alternate form */ ! 174: #define LADJUST 0x10 /* left adjustment */ ! 175: #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ ! 176: #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ ! 177: ! 178: int ! 179: _IO_vfprintf(fp, fmt0, ap) ! 180: register _IO_FILE* fp; ! 181: char const *fmt0; ! 182: _IO_va_list ap; ! 183: { ! 184: register const char *fmt; /* format string */ ! 185: register int ch; /* character from fmt */ ! 186: register int n; /* handy integer (short term usage) */ ! 187: register char *cp; /* handy char pointer (short term usage) */ ! 188: const char *fmark; /* for remembering a place in fmt */ ! 189: register int flags; /* flags as above */ ! 190: int ret; /* return value accumulator */ ! 191: int width; /* width from format (%8d), or 0 */ ! 192: int prec; /* precision from format (%.3d), or -1 */ ! 193: char sign; /* sign prefix (' ', '+', '-', or \0) */ ! 194: #ifdef FLOATING_POINT ! 195: int softsign; /* temporary negative sign for floats */ ! 196: double _double; /* double precision arguments %[eEfgG] */ ! 197: #ifndef USE_DTOA ! 198: int fpprec; /* `extra' floating precision in [eEfgG] */ ! 199: #endif ! 200: #endif ! 201: unsigned long _ulong; /* integer arguments %[diouxX] */ ! 202: enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ ! 203: int dprec; /* a copy of prec if [diouxX], 0 otherwise */ ! 204: int dpad; /* extra 0 padding needed for integers */ ! 205: int fieldsz; /* field size expanded by sign, dpad etc */ ! 206: /* The initialization of 'size' is to suppress a warning that ! 207: 'size' might be used unitialized. It seems gcc can't ! 208: quite grok this spaghetti code ... */ ! 209: int size = 0; /* size of converted field or string */ ! 210: char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ ! 211: char ox[2]; /* space for 0x hex-prefix */ ! 212: ! 213: /* ! 214: * BEWARE, these `goto error' on error, and PAD uses `n'. ! 215: */ ! 216: #define PRINT(ptr, len) \ ! 217: do { if (_IO_sputn(fp,ptr, len) != len) goto error; } while (0) ! 218: #define PAD_SP(howmany) if (_IO_padn(fp, ' ', howmany) < (howmany)) goto error; ! 219: #define PAD_0(howmany) if (_IO_padn(fp, '0', howmany) < (howmany)) goto error; ! 220: ! 221: /* ! 222: * To extend shorts properly, we need both signed and unsigned ! 223: * argument extraction methods. ! 224: */ ! 225: #define SARG() \ ! 226: (flags&LONGINT ? va_arg(ap, long) : \ ! 227: flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ ! 228: (long)va_arg(ap, int)) ! 229: #define UARG() \ ! 230: (flags&LONGINT ? va_arg(ap, unsigned long) : \ ! 231: flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ ! 232: (unsigned long)va_arg(ap, unsigned int)) ! 233: ! 234: /* optimise stderr (and other unbuffered Unix files) */ ! 235: if (fp->_IO_file_flags & _IO_UNBUFFERED) ! 236: return helper_vfprintf(fp, fmt0, ap); ! 237: ! 238: fmt = fmt0; ! 239: ret = 0; ! 240: ! 241: /* ! 242: * Scan the format for conversions (`%' character). ! 243: */ ! 244: for (;;) { ! 245: for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) ! 246: /* void */; ! 247: if ((n = fmt - fmark) != 0) { ! 248: PRINT(fmark, n); ! 249: ret += n; ! 250: } ! 251: if (ch == '\0') ! 252: goto done; ! 253: fmt++; /* skip over '%' */ ! 254: ! 255: flags = 0; ! 256: dprec = 0; ! 257: #if defined(FLOATING_POINT) && !defined (USE_DTOA) ! 258: fpprec = 0; ! 259: #endif ! 260: width = 0; ! 261: prec = -1; ! 262: sign = '\0'; ! 263: ! 264: rflag: ch = *fmt++; ! 265: reswitch: switch (ch) { ! 266: case ' ': ! 267: /* ! 268: * ``If the space and + flags both appear, the space ! 269: * flag will be ignored.'' ! 270: * -- ANSI X3J11 ! 271: */ ! 272: if (!sign) ! 273: sign = ' '; ! 274: goto rflag; ! 275: case '#': ! 276: flags |= ALT; ! 277: goto rflag; ! 278: case '*': ! 279: /* ! 280: * ``A negative field width argument is taken as a ! 281: * - flag followed by a positive field width.'' ! 282: * -- ANSI X3J11 ! 283: * They don't exclude field widths read from args. ! 284: */ ! 285: if ((width = va_arg(ap, int)) >= 0) ! 286: goto rflag; ! 287: width = -width; ! 288: /* FALLTHROUGH */ ! 289: case '-': ! 290: flags |= LADJUST; ! 291: flags &= ~ZEROPAD; /* '-' disables '0' */ ! 292: goto rflag; ! 293: case '+': ! 294: sign = '+'; ! 295: goto rflag; ! 296: case '.': ! 297: if ((ch = *fmt++) == '*') { ! 298: n = va_arg(ap, int); ! 299: prec = n < 0 ? -1 : n; ! 300: goto rflag; ! 301: } ! 302: n = 0; ! 303: while (is_digit(ch)) { ! 304: n = 10 * n + to_digit(ch); ! 305: ch = *fmt++; ! 306: } ! 307: prec = n < 0 ? -1 : n; ! 308: goto reswitch; ! 309: case '0': ! 310: /* ! 311: * ``Note that 0 is taken as a flag, not as the ! 312: * beginning of a field width.'' ! 313: * -- ANSI X3J11 ! 314: */ ! 315: if (!(flags & LADJUST)) ! 316: flags |= ZEROPAD; /* '-' disables '0' */ ! 317: goto rflag; ! 318: case '1': case '2': case '3': case '4': ! 319: case '5': case '6': case '7': case '8': case '9': ! 320: n = 0; ! 321: do { ! 322: n = 10 * n + to_digit(ch); ! 323: ch = *fmt++; ! 324: } while (is_digit(ch)); ! 325: width = n; ! 326: goto reswitch; ! 327: #ifdef FLOATING_POINT ! 328: case 'L': ! 329: flags |= LONGDBL; ! 330: goto rflag; ! 331: #endif ! 332: case 'h': ! 333: flags |= SHORTINT; ! 334: goto rflag; ! 335: case 'l': ! 336: flags |= LONGINT; ! 337: goto rflag; ! 338: case 'c': ! 339: *(cp = buf) = va_arg(ap, int); ! 340: size = 1; ! 341: sign = '\0'; ! 342: break; ! 343: case 'D': ! 344: flags |= LONGINT; ! 345: /*FALLTHROUGH*/ ! 346: case 'd': ! 347: case 'i': ! 348: _ulong = SARG(); ! 349: if ((long)_ulong < 0) { ! 350: _ulong = -_ulong; ! 351: sign = '-'; ! 352: } ! 353: base = DEC; ! 354: goto number; ! 355: #ifdef FLOATING_POINT ! 356: case 'e': ! 357: case 'E': ! 358: case 'f': ! 359: case 'F': ! 360: case 'g': ! 361: case 'G': ! 362: _double = va_arg(ap, double); ! 363: #ifdef USE_DTOA ! 364: { ! 365: int fmt_flags = 0; ! 366: int fill = ' '; ! 367: if (flags & ALT) ! 368: fmt_flags |= _IO_SHOWPOINT; ! 369: if (flags & LADJUST) ! 370: fmt_flags |= _IO_LEFT; ! 371: else if (flags & ZEROPAD) ! 372: fmt_flags |= _IO_INTERNAL, fill = '0'; ! 373: n = _IO_outfloat(_double, fp, ch, width, ! 374: prec < 0 ? DEFPREC : prec, ! 375: fmt_flags, sign, fill); ! 376: if (n < 0) ! 377: goto error; ! 378: ret += n; ! 379: } ! 380: /* CHECK ERROR! */ ! 381: continue; ! 382: #else ! 383: /* ! 384: * don't do unrealistic precision; just pad it with ! 385: * zeroes later, so buffer size stays rational. ! 386: */ ! 387: if (prec > MAXFRACT) { ! 388: if ((ch != 'g' && ch != 'G') || (flags&ALT)) ! 389: fpprec = prec - MAXFRACT; ! 390: prec = MAXFRACT; ! 391: } else if (prec == -1) ! 392: prec = DEFPREC; ! 393: /* __cvt_double may have to round up before the ! 394: "start" of its buffer, i.e. ! 395: ``intf("%.2f", (double)9.999);''; ! 396: if the first character is still NUL, it did. ! 397: softsign avoids negative 0 if _double < 0 but ! 398: no significant digits will be shown. */ ! 399: cp = buf; ! 400: *cp = '\0'; ! 401: size = __cvt_double(_double, prec, flags, &softsign, ! 402: ch, cp, buf + sizeof(buf)); ! 403: if (softsign) ! 404: sign = '-'; ! 405: if (*cp == '\0') ! 406: cp++; ! 407: break; ! 408: #endif ! 409: #endif /* FLOATING_POINT */ ! 410: case 'n': ! 411: if (flags & LONGINT) ! 412: *va_arg(ap, long *) = ret; ! 413: else if (flags & SHORTINT) ! 414: *va_arg(ap, short *) = ret; ! 415: else ! 416: *va_arg(ap, int *) = ret; ! 417: continue; /* no output */ ! 418: case 'O': ! 419: flags |= LONGINT; ! 420: /*FALLTHROUGH*/ ! 421: case 'o': ! 422: _ulong = UARG(); ! 423: base = OCT; ! 424: goto nosign; ! 425: case 'p': ! 426: /* ! 427: * ``The argument shall be a pointer to void. The ! 428: * value of the pointer is converted to a sequence ! 429: * of printable characters, in an implementation- ! 430: * defined manner.'' ! 431: * -- ANSI X3J11 ! 432: */ ! 433: /* NOSTRICT */ ! 434: _ulong = (unsigned long)va_arg(ap, void *); ! 435: base = HEX; ! 436: flags |= HEXPREFIX; ! 437: ch = 'x'; ! 438: goto nosign; ! 439: case 's': ! 440: if ((cp = va_arg(ap, char *)) == NULL) ! 441: cp = "(null)"; ! 442: if (prec >= 0) { ! 443: /* ! 444: * can't use strlen; can only look for the ! 445: * NUL in the first `prec' characters, and ! 446: * strlen() will go further. ! 447: */ ! 448: char *p = (char*)memchr(cp, 0, prec); ! 449: ! 450: if (p != NULL) { ! 451: size = p - cp; ! 452: if (size > prec) ! 453: size = prec; ! 454: } else ! 455: size = prec; ! 456: } else ! 457: size = strlen(cp); ! 458: sign = '\0'; ! 459: break; ! 460: case 'U': ! 461: flags |= LONGINT; ! 462: /*FALLTHROUGH*/ ! 463: case 'u': ! 464: _ulong = UARG(); ! 465: base = DEC; ! 466: goto nosign; ! 467: case 'X': ! 468: case 'x': ! 469: _ulong = UARG(); ! 470: base = HEX; ! 471: /* leading 0x/X only if non-zero */ ! 472: if (flags & ALT && _ulong != 0) ! 473: flags |= HEXPREFIX; ! 474: ! 475: /* unsigned conversions */ ! 476: nosign: sign = '\0'; ! 477: /* ! 478: * ``... diouXx conversions ... if a precision is ! 479: * specified, the 0 flag will be ignored.'' ! 480: * -- ANSI X3J11 ! 481: */ ! 482: number: if ((dprec = prec) >= 0) ! 483: flags &= ~ZEROPAD; ! 484: ! 485: /* ! 486: * ``The result of converting a zero value with an ! 487: * explicit precision of zero is no characters.'' ! 488: * -- ANSI X3J11 ! 489: */ ! 490: cp = buf + BUF; ! 491: if (_ulong != 0 || prec != 0) { ! 492: char *xdigs; /* digits for [xX] conversion */ ! 493: /* ! 494: * unsigned mod is hard, and unsigned mod ! 495: * by a constant is easier than that by ! 496: * a variable; hence this switch. ! 497: */ ! 498: switch (base) { ! 499: case OCT: ! 500: do { ! 501: *--cp = to_char(_ulong & 7); ! 502: _ulong >>= 3; ! 503: } while (_ulong); ! 504: /* handle octal leading 0 */ ! 505: if (flags & ALT && *cp != '0') ! 506: *--cp = '0'; ! 507: break; ! 508: ! 509: case DEC: ! 510: /* many numbers are 1 digit */ ! 511: while (_ulong >= 10) { ! 512: *--cp = to_char(_ulong % 10); ! 513: _ulong /= 10; ! 514: } ! 515: *--cp = to_char(_ulong); ! 516: break; ! 517: ! 518: case HEX: ! 519: if (ch == 'X') ! 520: xdigs = "0123456789ABCDEF"; ! 521: else /* ch == 'x' || ch == 'p' */ ! 522: xdigs = "0123456789abcdef"; ! 523: do { ! 524: *--cp = xdigs[_ulong & 15]; ! 525: _ulong >>= 4; ! 526: } while (_ulong); ! 527: break; ! 528: ! 529: default: ! 530: cp = "bug in vform: bad base"; ! 531: goto skipsize; ! 532: } ! 533: } ! 534: size = buf + BUF - cp; ! 535: skipsize: ! 536: break; ! 537: default: /* "%?" prints ?, unless ? is NUL */ ! 538: if (ch == '\0') ! 539: goto done; ! 540: /* pretend it was %c with argument ch */ ! 541: cp = buf; ! 542: *cp = ch; ! 543: size = 1; ! 544: sign = '\0'; ! 545: break; ! 546: } ! 547: ! 548: /* ! 549: * All reasonable formats wind up here. At this point, ! 550: * `cp' points to a string which (if not flags&LADJUST) ! 551: * should be padded out to `width' places. If ! 552: * flags&ZEROPAD, it should first be prefixed by any ! 553: * sign or other prefix; otherwise, it should be blank ! 554: * padded before the prefix is emitted. After any ! 555: * left-hand padding and prefixing, emit zeroes ! 556: * required by a decimal [diouxX] precision, then print ! 557: * the string proper, then emit zeroes required by any ! 558: * leftover floating precision; finally, if LADJUST, ! 559: * pad with blanks. ! 560: */ ! 561: ! 562: /* ! 563: * compute actual size, so we know how much to pad. ! 564: */ ! 565: #if defined(FLOATING_POINT) && !defined (USE_DTOA) ! 566: fieldsz = size + fpprec; ! 567: #else ! 568: fieldsz = size; ! 569: #endif ! 570: dpad = dprec - size; ! 571: if (dpad < 0) ! 572: dpad = 0; ! 573: ! 574: if (sign) ! 575: fieldsz++; ! 576: else if (flags & HEXPREFIX) ! 577: fieldsz += 2; ! 578: fieldsz += dpad; ! 579: ! 580: /* right-adjusting blank padding */ ! 581: if ((flags & (LADJUST|ZEROPAD)) == 0) ! 582: PAD_SP(width - fieldsz); ! 583: ! 584: /* prefix */ ! 585: if (sign) { ! 586: PRINT(&sign, 1); ! 587: } else if (flags & HEXPREFIX) { ! 588: ox[0] = '0'; ! 589: ox[1] = ch; ! 590: PRINT(ox, 2); ! 591: } ! 592: ! 593: /* right-adjusting zero padding */ ! 594: if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) ! 595: PAD_0(width - fieldsz); ! 596: ! 597: /* leading zeroes from decimal precision */ ! 598: PAD_0(dpad); ! 599: ! 600: /* the string or number proper */ ! 601: PRINT(cp, size); ! 602: ! 603: #if defined(FLOATING_POINT) && !defined (USE_DTOA) ! 604: /* trailing f.p. zeroes */ ! 605: PAD_0(fpprec); ! 606: #endif ! 607: ! 608: /* left-adjusting padding (always blank) */ ! 609: if (flags & LADJUST) ! 610: PAD_SP(width - fieldsz); ! 611: ! 612: /* finally, adjust ret */ ! 613: ret += width > fieldsz ? width : fieldsz; ! 614: ! 615: } ! 616: done: ! 617: return ret; ! 618: error: ! 619: return EOF; ! 620: /* NOTREACHED */ ! 621: } ! 622: ! 623: #if defined(FLOATING_POINT) && !defined(USE_DTOA) ! 624: ! 625: static char *exponent(register char *p, register int exp, int fmtch) ! 626: { ! 627: register char *t; ! 628: char expbuf[MAXEXP]; ! 629: ! 630: *p++ = fmtch; ! 631: if (exp < 0) { ! 632: exp = -exp; ! 633: *p++ = '-'; ! 634: } ! 635: else ! 636: *p++ = '+'; ! 637: t = expbuf + MAXEXP; ! 638: if (exp > 9) { ! 639: do { ! 640: *--t = to_char(exp % 10); ! 641: } while ((exp /= 10) > 9); ! 642: *--t = to_char(exp); ! 643: for (; t < expbuf + MAXEXP; *p++ = *t++); ! 644: } ! 645: else { ! 646: *p++ = '0'; ! 647: *p++ = to_char(exp); ! 648: } ! 649: return (p); ! 650: } ! 651: ! 652: static char * round(double fract, int *exp, ! 653: register char *start, register char *end, ! 654: char ch, int *signp) ! 655: { ! 656: double tmp; ! 657: ! 658: if (fract) ! 659: (void)modf(fract * 10, &tmp); ! 660: else ! 661: tmp = to_digit(ch); ! 662: if (tmp > 4) ! 663: for (;; --end) { ! 664: if (*end == '.') ! 665: --end; ! 666: if (++*end <= '9') ! 667: break; ! 668: *end = '0'; ! 669: if (end == start) { ! 670: if (exp) { /* e/E; increment exponent */ ! 671: *end = '1'; ! 672: ++*exp; ! 673: } ! 674: else { /* f; add extra digit */ ! 675: *--end = '1'; ! 676: --start; ! 677: } ! 678: break; ! 679: } ! 680: } ! 681: /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ ! 682: else if (*signp == '-') ! 683: for (;; --end) { ! 684: if (*end == '.') ! 685: --end; ! 686: if (*end != '0') ! 687: break; ! 688: if (end == start) ! 689: *signp = 0; ! 690: } ! 691: return (start); ! 692: } ! 693: ! 694: int __cvt_double(double number, register int prec, int flags, int *signp, ! 695: int fmtch, char *startp, char *endp) ! 696: { ! 697: register char *p, *t; ! 698: register double fract; ! 699: int dotrim = 0, expcnt, gformat = 0; ! 700: double integer, tmp; ! 701: ! 702: expcnt = 0; ! 703: if (number < 0) { ! 704: number = -number; ! 705: *signp = '-'; ! 706: } else ! 707: *signp = 0; ! 708: ! 709: fract = modf(number, &integer); ! 710: ! 711: /* get an extra slot for rounding. */ ! 712: t = ++startp; ! 713: ! 714: /* ! 715: * get integer portion of number; put into the end of the buffer; the ! 716: * .01 is added for modf(356.0 / 10, &integer) returning .59999999... ! 717: */ ! 718: for (p = endp - 1; integer; ++expcnt) { ! 719: tmp = modf(integer / 10, &integer); ! 720: *p-- = to_char((int)((tmp + .01) * 10)); ! 721: } ! 722: switch (fmtch) { ! 723: case 'f': ! 724: case 'F': ! 725: /* reverse integer into beginning of buffer */ ! 726: if (expcnt) ! 727: for (; ++p < endp; *t++ = *p); ! 728: else ! 729: *t++ = '0'; ! 730: /* ! 731: * if precision required or alternate flag set, add in a ! 732: * decimal point. ! 733: */ ! 734: if (prec || flags&ALT) ! 735: *t++ = '.'; ! 736: /* if requires more precision and some fraction left */ ! 737: if (fract) { ! 738: if (prec) ! 739: do { ! 740: fract = modf(fract * 10, &tmp); ! 741: *t++ = to_char((int)tmp); ! 742: } while (--prec && fract); ! 743: if (fract) ! 744: startp = round(fract, (int *)NULL, startp, ! 745: t - 1, (char)0, signp); ! 746: } ! 747: for (; prec--; *t++ = '0'); ! 748: break; ! 749: case 'e': ! 750: case 'E': ! 751: eformat: if (expcnt) { ! 752: *t++ = *++p; ! 753: if (prec || flags&ALT) ! 754: *t++ = '.'; ! 755: /* if requires more precision and some integer left */ ! 756: for (; prec && ++p < endp; --prec) ! 757: *t++ = *p; ! 758: /* ! 759: * if done precision and more of the integer component, ! 760: * round using it; adjust fract so we don't re-round ! 761: * later. ! 762: */ ! 763: if (!prec && ++p < endp) { ! 764: fract = 0; ! 765: startp = round((double)0, &expcnt, startp, ! 766: t - 1, *p, signp); ! 767: } ! 768: /* adjust expcnt for digit in front of decimal */ ! 769: --expcnt; ! 770: } ! 771: /* until first fractional digit, decrement exponent */ ! 772: else if (fract) { ! 773: /* adjust expcnt for digit in front of decimal */ ! 774: for (expcnt = -1;; --expcnt) { ! 775: fract = modf(fract * 10, &tmp); ! 776: if (tmp) ! 777: break; ! 778: } ! 779: *t++ = to_char((int)tmp); ! 780: if (prec || flags&ALT) ! 781: *t++ = '.'; ! 782: } ! 783: else { ! 784: *t++ = '0'; ! 785: if (prec || flags&ALT) ! 786: *t++ = '.'; ! 787: } ! 788: /* if requires more precision and some fraction left */ ! 789: if (fract) { ! 790: if (prec) ! 791: do { ! 792: fract = modf(fract * 10, &tmp); ! 793: *t++ = to_char((int)tmp); ! 794: } while (--prec && fract); ! 795: if (fract) ! 796: startp = round(fract, &expcnt, startp, ! 797: t - 1, (char)0, signp); ! 798: } ! 799: /* if requires more precision */ ! 800: for (; prec--; *t++ = '0'); ! 801: ! 802: /* unless alternate flag, trim any g/G format trailing 0's */ ! 803: if (gformat && !(flags&ALT)) { ! 804: while (t > startp && *--t == '0'); ! 805: if (*t == '.') ! 806: --t; ! 807: ++t; ! 808: } ! 809: t = exponent(t, expcnt, fmtch); ! 810: break; ! 811: case 'g': ! 812: case 'G': ! 813: /* a precision of 0 is treated as a precision of 1. */ ! 814: if (!prec) ! 815: ++prec; ! 816: /* ! 817: * ``The style used depends on the value converted; style e ! 818: * will be used only if the exponent resulting from the ! 819: * conversion is less than -4 or greater than the precision.'' ! 820: * -- ANSI X3J11 ! 821: */ ! 822: if (expcnt > prec || (!expcnt && fract && fract < .0001)) { ! 823: /* ! 824: * g/G format counts "significant digits, not digits of ! 825: * precision; for the e/E format, this just causes an ! 826: * off-by-one problem, i.e. g/G considers the digit ! 827: * before the decimal point significant and e/E doesn't ! 828: * count it as precision. ! 829: */ ! 830: --prec; ! 831: fmtch -= 2; /* G->E, g->e */ ! 832: gformat = 1; ! 833: goto eformat; ! 834: } ! 835: /* ! 836: * reverse integer into beginning of buffer, ! 837: * note, decrement precision ! 838: */ ! 839: if (expcnt) ! 840: for (; ++p < endp; *t++ = *p, --prec); ! 841: else ! 842: *t++ = '0'; ! 843: /* ! 844: * if precision required or alternate flag set, add in a ! 845: * decimal point. If no digits yet, add in leading 0. ! 846: */ ! 847: if (prec || flags&ALT) { ! 848: dotrim = 1; ! 849: *t++ = '.'; ! 850: } ! 851: else ! 852: dotrim = 0; ! 853: /* if requires more precision and some fraction left */ ! 854: if (fract) { ! 855: if (prec) { ! 856: /* If no integer part, don't count initial ! 857: * zeros as significant digits. */ ! 858: do { ! 859: fract = modf(fract * 10, &tmp); ! 860: *t++ = to_char((int)tmp); ! 861: } while(!tmp && !expcnt); ! 862: while (--prec && fract) { ! 863: fract = modf(fract * 10, &tmp); ! 864: *t++ = to_char((int)tmp); ! 865: } ! 866: } ! 867: if (fract) ! 868: startp = round(fract, (int *)NULL, startp, ! 869: t - 1, (char)0, signp); ! 870: } ! 871: /* alternate format, adds 0's for precision, else trim 0's */ ! 872: if (flags&ALT) ! 873: for (; prec--; *t++ = '0'); ! 874: else if (dotrim) { ! 875: while (t > startp && *--t == '0'); ! 876: if (*t != '.') ! 877: ++t; ! 878: } ! 879: } ! 880: return (t - startp); ! 881: } ! 882: ! 883: #endif /* defined(FLOATING_POINT) && !defined(USE_DTOA) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.