1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)vfprintf.c 5.44 (Berkeley) 02/16/91"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 /* 16 * Actual printf innards. 17 * 18 * This code is large and complicated... 19 */ 20 21 #include <sys/types.h> 22 #include <stdio.h> 23 #include <string.h> 24 #if __STDC__ 25 #include <stdarg.h> 26 #else 27 #include <varargs.h> 28 #endif 29 #include "local.h" 30 #include "fvwrite.h" 31 32 /* 33 * Define FLOATING_POINT to get floating point. 34 * Define CSH to get a csh-specific version (grr). 35 */ 36 #ifndef CSH 37 #define FLOATING_POINT 38 #endif 39 40 /* end of configuration stuff */ 41 42 43 #ifdef CSH 44 /* 45 * C shell hacks. Ick, gag. 46 */ 47 #undef BUFSIZ 48 #include "sh.h" 49 50 #if __STDC__ 51 int 52 printf(const char *fmt, ...) { 53 FILE f; 54 55 f._flags = __SWR; 56 return (vfprintf(&f, fmt, (va_list)(&fmt + 1))); 57 } 58 #else 59 int 60 printf(fmt, args) 61 char *fmt; 62 { 63 FILE f; 64 65 f._flags = __SWR; 66 f._write = NULL; 67 return (vfprintf(&f, fmt, &args)); 68 } 69 #endif 70 71 int 72 __sprint(fp, uio) 73 FILE *fp; 74 register struct __suio *uio; 75 { 76 register char *p; 77 register int n, ch, iovcnt; 78 register struct __siov *iov; 79 80 /* must allow sprintf to work, might as well allow others too */ 81 if (fp->_write || fp->_flags & __SSTR) { 82 if (uio->uio_resid == 0) { 83 uio->uio_iovcnt = 0; 84 return (0); 85 } 86 n = __sfvwrite(fp, uio); 87 uio->uio_resid = 0; 88 uio->uio_iovcnt = 0; 89 return (n); 90 } 91 iov = uio->uio_iov; 92 for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) { 93 for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) { 94 #ifdef CSHPUTCHAR 95 ch = *p++; 96 CSHPUTCHAR; /* this horrid macro uses `ch' */ 97 #else 98 #undef putchar 99 putchar(*p++); 100 #endif 101 } 102 } 103 uio->uio_resid = 0; 104 uio->uio_iovcnt = 0; 105 return (0); 106 } 107 108 #else /* CSH */ 109 110 /* 111 * Flush out all the vectors defined by the given uio, 112 * then reset it so that it can be reused. 113 */ 114 static int 115 __sprint(fp, uio) 116 FILE *fp; 117 register struct __suio *uio; 118 { 119 register int err; 120 121 if (uio->uio_resid == 0) { 122 uio->uio_iovcnt = 0; 123 return (0); 124 } 125 err = __sfvwrite(fp, uio); 126 uio->uio_resid = 0; 127 uio->uio_iovcnt = 0; 128 return (err); 129 } 130 131 /* 132 * Helper function for `fprintf to unbuffered unix file': creates a 133 * temporary buffer. We only work on write-only files; this avoids 134 * worries about ungetc buffers and so forth. 135 */ 136 static int 137 __sbprintf(fp, fmt, ap) 138 register FILE *fp; 139 const char *fmt; 140 va_list ap; 141 { 142 int ret; 143 FILE fake; 144 unsigned char buf[BUFSIZ]; 145 146 /* copy the important variables */ 147 fake._flags = fp->_flags & ~__SNBF; 148 fake._file = fp->_file; 149 fake._cookie = fp->_cookie; 150 fake._write = fp->_write; 151 152 /* set up the buffer */ 153 fake._bf._base = fake._p = buf; 154 fake._bf._size = fake._w = sizeof(buf); 155 fake._lbfsize = 0; /* not actually used, but Just In Case */ 156 157 /* do the work, then copy any error status */ 158 ret = vfprintf(&fake, fmt, ap); 159 if (ret >= 0 && fflush(&fake)) 160 ret = EOF; 161 if (fake._flags & __SERR) 162 fp->_flags |= __SERR; 163 return (ret); 164 } 165 166 #endif /* CSH */ 167 168 169 #ifdef FLOATING_POINT 170 #include "floatio.h" 171 172 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 173 #define DEFPREC 6 174 175 static int cvt(); 176 #if defined(hp300) || defined(sparc) 177 static char *isspecial(); 178 #endif 179 180 #else /* no FLOATING_POINT */ 181 182 #define BUF 40 183 184 #endif /* FLOATING_POINT */ 185 186 187 /* 188 * Macros for converting digits to letters and vice versa 189 */ 190 #define to_digit(c) ((c) - '0') 191 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 192 #define to_char(n) ((n) + '0') 193 194 /* 195 * Flags used during conversion. 196 */ 197 #define LONGINT 0x01 /* long integer */ 198 #define LONGDBL 0x02 /* long double; unimplemented */ 199 #define SHORTINT 0x04 /* short integer */ 200 #define ALT 0x08 /* alternate form */ 201 #define LADJUST 0x10 /* left adjustment */ 202 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ 203 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ 204 205 int 206 vfprintf(fp, fmt0, ap) 207 FILE *fp; 208 const char *fmt0; 209 #if tahoe 210 register /* technically illegal, since we do not know what type va_list is */ 211 #endif 212 va_list ap; 213 { 214 register char *fmt; /* format string */ 215 register int ch; /* character from fmt */ 216 register int n; /* handy integer (short term usage) */ 217 register char *cp; /* handy char pointer (short term usage) */ 218 register struct __siov *iovp;/* for PRINT macro */ 219 register int flags; /* flags as above */ 220 int ret; /* return value accumulator */ 221 int width; /* width from format (%8d), or 0 */ 222 int prec; /* precision from format (%.3d), or -1 */ 223 char sign; /* sign prefix (' ', '+', '-', or \0) */ 224 #ifdef FLOATING_POINT 225 char softsign; /* temporary negative sign for floats */ 226 double _double; /* double precision arguments %[eEfgG] */ 227 int fpprec; /* `extra' floating precision in [eEfgG] */ 228 #endif 229 u_long _ulong; /* integer arguments %[diouxX] */ 230 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 231 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 232 int fieldsz; /* field size expanded by sign, etc */ 233 int realsz; /* field size expanded by dprec */ 234 int size; /* size of converted field or string */ 235 char *xdigs; /* digits for [xX] conversion */ 236 #define NIOV 8 237 struct __suio uio; /* output information: summary */ 238 struct __siov iov[NIOV];/* ... and individual io vectors */ 239 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 240 char ox[2]; /* space for 0x hex-prefix */ 241 242 /* 243 * Choose PADSIZE to trade efficiency vs size. If larger 244 * printf fields occur frequently, increase PADSIZE (and make 245 * the initialisers below longer). 246 */ 247 #define PADSIZE 16 /* pad chunk size */ 248 static char blanks[PADSIZE] = 249 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 250 static char zeroes[PADSIZE] = 251 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 252 253 /* 254 * BEWARE, these `goto error' on error, and PAD uses `n'. 255 */ 256 #define PRINT(ptr, len) { \ 257 iovp->iov_base = (ptr); \ 258 iovp->iov_len = (len); \ 259 uio.uio_resid += (len); \ 260 iovp++; \ 261 if (++uio.uio_iovcnt >= NIOV) { \ 262 if (__sprint(fp, &uio)) \ 263 goto error; \ 264 iovp = iov; \ 265 } \ 266 } 267 #define PAD(howmany, with) { \ 268 if ((n = (howmany)) > 0) { \ 269 while (n > PADSIZE) { \ 270 PRINT(with, PADSIZE); \ 271 n -= PADSIZE; \ 272 } \ 273 PRINT(with, n); \ 274 } \ 275 } 276 #define FLUSH() { \ 277 if (uio.uio_resid && __sprint(fp, &uio)) \ 278 goto error; \ 279 uio.uio_iovcnt = 0; \ 280 iovp = iov; \ 281 } 282 283 /* 284 * To extend shorts properly, we need both signed and unsigned 285 * argument extraction methods. 286 */ 287 #define SARG() \ 288 (flags&LONGINT ? va_arg(ap, long) : \ 289 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 290 (long)va_arg(ap, int)) 291 #define UARG() \ 292 (flags&LONGINT ? va_arg(ap, u_long) : \ 293 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 294 (u_long)va_arg(ap, u_int)) 295 296 #ifndef CSH 297 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 298 if (cantwrite(fp)) 299 return (EOF); 300 301 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 302 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 303 fp->_file >= 0) 304 return (__sbprintf(fp, fmt0, ap)); 305 #endif /* CSH */ 306 307 fmt = (char *)fmt0; 308 uio.uio_iov = iovp = iov; 309 uio.uio_resid = 0; 310 uio.uio_iovcnt = 0; 311 ret = 0; 312 313 /* 314 * Scan the format for conversions (`%' character). 315 */ 316 for (;;) { 317 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 318 /* void */; 319 if ((n = fmt - cp) != 0) { 320 PRINT(cp, n); 321 ret += n; 322 } 323 if (ch == '\0') 324 goto done; 325 fmt++; /* skip over '%' */ 326 327 flags = 0; 328 dprec = 0; 329 #ifdef FLOATING_POINT 330 fpprec = 0; 331 #endif 332 width = 0; 333 prec = -1; 334 sign = '\0'; 335 336 rflag: ch = *fmt++; 337 reswitch: switch (ch) { 338 case ' ': 339 /* 340 * ``If the space and + flags both appear, the space 341 * flag will be ignored.'' 342 * -- ANSI X3J11 343 */ 344 if (!sign) 345 sign = ' '; 346 goto rflag; 347 case '#': 348 flags |= ALT; 349 goto rflag; 350 case '*': 351 /* 352 * ``A negative field width argument is taken as a 353 * - flag followed by a positive field width.'' 354 * -- ANSI X3J11 355 * They don't exclude field widths read from args. 356 */ 357 if ((width = va_arg(ap, int)) >= 0) 358 goto rflag; 359 width = -width; 360 /* FALLTHROUGH */ 361 case '-': 362 flags |= LADJUST; 363 goto rflag; 364 case '+': 365 sign = '+'; 366 goto rflag; 367 case '.': 368 if ((ch = *fmt++) == '*') { 369 n = va_arg(ap, int); 370 prec = n < 0 ? -1 : n; 371 goto rflag; 372 } 373 n = 0; 374 while (is_digit(ch)) { 375 n = 10 * n + to_digit(ch); 376 ch = *fmt++; 377 } 378 prec = n < 0 ? -1 : n; 379 goto reswitch; 380 case '0': 381 /* 382 * ``Note that 0 is taken as a flag, not as the 383 * beginning of a field width.'' 384 * -- ANSI X3J11 385 */ 386 flags |= ZEROPAD; 387 goto rflag; 388 case '1': case '2': case '3': case '4': 389 case '5': case '6': case '7': case '8': case '9': 390 n = 0; 391 do { 392 n = 10 * n + to_digit(ch); 393 ch = *fmt++; 394 } while (is_digit(ch)); 395 width = n; 396 goto reswitch; 397 #ifdef FLOATING_POINT 398 case 'L': 399 flags |= LONGDBL; 400 goto rflag; 401 #endif 402 case 'h': 403 flags |= SHORTINT; 404 goto rflag; 405 case 'l': 406 flags |= LONGINT; 407 goto rflag; 408 case 'c': 409 *(cp = buf) = va_arg(ap, int); 410 size = 1; 411 sign = '\0'; 412 break; 413 case 'D': 414 flags |= LONGINT; 415 /*FALLTHROUGH*/ 416 case 'd': 417 case 'i': 418 _ulong = SARG(); 419 if ((long)_ulong < 0) { 420 _ulong = -_ulong; 421 sign = '-'; 422 } 423 base = DEC; 424 goto number; 425 #ifdef FLOATING_POINT 426 case 'e': 427 case 'E': 428 case 'f': 429 case 'g': 430 case 'G': 431 _double = va_arg(ap, double); 432 #if defined(hp300) || defined(sparc) 433 /* do this before tricky precision changes */ 434 if ((cp = isspecial(_double, &sign)) != NULL) { 435 size = strlen(cp); 436 break; 437 } 438 #endif 439 /* 440 * don't do unrealistic precision; just pad it with 441 * zeroes later, so buffer size stays rational. 442 */ 443 if (prec > MAXFRACT) { 444 if (ch != 'g' && ch != 'G' || (flags&ALT)) 445 fpprec = prec - MAXFRACT; 446 prec = MAXFRACT; 447 } else if (prec == -1) 448 prec = DEFPREC; 449 /* 450 * cvt may have to round up before the "start" of 451 * its buffer, i.e. ``intf("%.2f", (double)9.999);''; 452 * if the first character is still NUL, it did. 453 * softsign avoids negative 0 if _double < 0 but 454 * no significant digits will be shown. 455 */ 456 cp = buf; 457 *cp = '\0'; 458 size = cvt(_double, prec, flags, &softsign, ch, 459 cp, buf + sizeof(buf)); 460 if (softsign) 461 sign = '-'; 462 if (*cp == '\0') 463 cp++; 464 break; 465 #endif /* FLOATING_POINT */ 466 case 'n': 467 if (flags & LONGINT) 468 *va_arg(ap, long *) = ret; 469 else if (flags & SHORTINT) 470 *va_arg(ap, short *) = ret; 471 else 472 *va_arg(ap, int *) = ret; 473 continue; /* no output */ 474 case 'O': 475 flags |= LONGINT; 476 /*FALLTHROUGH*/ 477 case 'o': 478 _ulong = UARG(); 479 base = OCT; 480 goto nosign; 481 case 'p': 482 /* 483 * ``The argument shall be a pointer to void. The 484 * value of the pointer is converted to a sequence 485 * of printable characters, in an implementation- 486 * defined manner.'' 487 * -- ANSI X3J11 488 */ 489 /* NOSTRICT */ 490 _ulong = (u_long)va_arg(ap, void *); 491 base = HEX; 492 xdigs = "0123456789abcdef"; 493 flags |= HEXPREFIX; 494 ch = 'x'; 495 goto nosign; 496 case 's': 497 if ((cp = va_arg(ap, char *)) == NULL) 498 cp = "(null)"; 499 if (prec >= 0) { 500 /* 501 * can't use strlen; can only look for the 502 * NUL in the first `prec' characters, and 503 * strlen() will go further. 504 */ 505 char *p = memchr(cp, 0, prec); 506 507 if (p != NULL) { 508 size = p - cp; 509 if (size > prec) 510 size = prec; 511 } else 512 size = prec; 513 } else 514 size = strlen(cp); 515 sign = '\0'; 516 break; 517 case 'U': 518 flags |= LONGINT; 519 /*FALLTHROUGH*/ 520 case 'u': 521 _ulong = UARG(); 522 base = DEC; 523 goto nosign; 524 case 'X': 525 xdigs = "0123456789ABCDEF"; 526 goto hex; 527 case 'x': 528 xdigs = "0123456789abcdef"; 529 hex: _ulong = UARG(); 530 base = HEX; 531 /* leading 0x/X only if non-zero */ 532 if (flags & ALT && _ulong != 0) 533 flags |= HEXPREFIX; 534 535 /* unsigned conversions */ 536 nosign: sign = '\0'; 537 /* 538 * ``... diouXx conversions ... if a precision is 539 * specified, the 0 flag will be ignored.'' 540 * -- ANSI X3J11 541 */ 542 number: if ((dprec = prec) >= 0) 543 flags &= ~ZEROPAD; 544 545 /* 546 * ``The result of converting a zero value with an 547 * explicit precision of zero is no characters.'' 548 * -- ANSI X3J11 549 */ 550 cp = buf + BUF; 551 if (_ulong != 0 || prec != 0) { 552 /* 553 * unsigned mod is hard, and unsigned mod 554 * by a constant is easier than that by 555 * a variable; hence this switch. 556 */ 557 switch (base) { 558 case OCT: 559 do { 560 *--cp = to_char(_ulong & 7); 561 _ulong >>= 3; 562 } while (_ulong); 563 /* handle octal leading 0 */ 564 if (flags & ALT && *cp != '0') 565 *--cp = '0'; 566 break; 567 568 case DEC: 569 /* many numbers are 1 digit */ 570 while (_ulong >= 10) { 571 *--cp = to_char(_ulong % 10); 572 _ulong /= 10; 573 } 574 *--cp = to_char(_ulong); 575 break; 576 577 case HEX: 578 do { 579 *--cp = xdigs[_ulong & 15]; 580 _ulong >>= 4; 581 } while (_ulong); 582 break; 583 584 default: 585 cp = "bug in vfprintf: bad base"; 586 size = strlen(cp); 587 goto skipsize; 588 } 589 } 590 size = buf + BUF - cp; 591 skipsize: 592 break; 593 default: /* "%?" prints ?, unless ? is NUL */ 594 if (ch == '\0') 595 goto done; 596 /* pretend it was %c with argument ch */ 597 cp = buf; 598 *cp = ch; 599 size = 1; 600 sign = '\0'; 601 break; 602 } 603 604 /* 605 * All reasonable formats wind up here. At this point, 606 * `cp' points to a string which (if not flags&LADJUST) 607 * should be padded out to `width' places. If 608 * flags&ZEROPAD, it should first be prefixed by any 609 * sign or other prefix; otherwise, it should be blank 610 * padded before the prefix is emitted. After any 611 * left-hand padding and prefixing, emit zeroes 612 * required by a decimal [diouxX] precision, then print 613 * the string proper, then emit zeroes required by any 614 * leftover floating precision; finally, if LADJUST, 615 * pad with blanks. 616 */ 617 618 /* 619 * compute actual size, so we know how much to pad. 620 * fieldsz excludes decimal prec; realsz includes it 621 */ 622 #ifdef FLOATING_POINT 623 fieldsz = size + fpprec; 624 #else 625 fieldsz = size; 626 #endif 627 if (sign) 628 fieldsz++; 629 else if (flags & HEXPREFIX) 630 fieldsz += 2; 631 realsz = dprec > fieldsz ? dprec : fieldsz; 632 633 /* right-adjusting blank padding */ 634 if ((flags & (LADJUST|ZEROPAD)) == 0) 635 PAD(width - realsz, blanks); 636 637 /* prefix */ 638 if (sign) { 639 PRINT(&sign, 1); 640 } else if (flags & HEXPREFIX) { 641 ox[0] = '0'; 642 ox[1] = ch; 643 PRINT(ox, 2); 644 } 645 646 /* right-adjusting zero padding */ 647 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 648 PAD(width - realsz, zeroes); 649 650 /* leading zeroes from decimal precision */ 651 PAD(dprec - fieldsz, zeroes); 652 653 /* the string or number proper */ 654 PRINT(cp, size); 655 656 #ifdef FLOATING_POINT 657 /* trailing f.p. zeroes */ 658 PAD(fpprec, zeroes); 659 #endif 660 661 /* left-adjusting padding (always blank) */ 662 if (flags & LADJUST) 663 PAD(width - realsz, blanks); 664 665 /* finally, adjust ret */ 666 ret += width > realsz ? width : realsz; 667 668 FLUSH(); /* copy out the I/O vectors */ 669 } 670 done: 671 FLUSH(); 672 error: 673 return (__sferror(fp) ? EOF : ret); 674 /* NOTREACHED */ 675 } 676 677 #ifdef FLOATING_POINT 678 #include <math.h> 679 680 static char *exponent(); 681 static char *round(); 682 683 #if defined(hp300) || defined(sparc) 684 /* 685 * Check for special IEEE format values (NaN, Inf). 686 */ 687 static char * 688 isspecial(d, signp) 689 double d; 690 char *signp; 691 { 692 register struct IEEEdp { 693 unsigned sign:1; 694 unsigned exp:11; 695 unsigned manh:20; 696 unsigned manl:32; 697 } *ip = (struct IEEEdp *)&d; 698 699 if (ip->exp != 0x7ff) 700 return (NULL); 701 if (ip->sign) 702 *signp = '-'; 703 return (ip->manh || ip->manl ? "NaN" : "Inf"); 704 } 705 #endif /* hp300 or sparc */ 706 707 static int 708 cvt(number, prec, flags, signp, fmtch, startp, endp) 709 double number; 710 register int prec; 711 int flags; 712 char *signp; 713 int fmtch; 714 char *startp, *endp; 715 { 716 register char *p, *t; 717 register double fract; 718 int dotrim, expcnt, gformat; 719 double integer, tmp; 720 721 dotrim = expcnt = gformat = 0; 722 if (number < 0) { 723 number = -number; 724 *signp = '-'; 725 } else 726 *signp = 0; 727 728 fract = modf(number, &integer); 729 730 /* get an extra slot for rounding. */ 731 t = ++startp; 732 733 /* 734 * get integer portion of number; put into the end of the buffer; the 735 * .01 is added for modf(356.0 / 10, &integer) returning .59999999... 736 */ 737 for (p = endp - 1; integer; ++expcnt) { 738 tmp = modf(integer / 10, &integer); 739 *p-- = to_char((int)((tmp + .01) * 10)); 740 } 741 switch (fmtch) { 742 case 'f': 743 /* reverse integer into beginning of buffer */ 744 if (expcnt) 745 for (; ++p < endp; *t++ = *p); 746 else 747 *t++ = '0'; 748 /* 749 * if precision required or alternate flag set, add in a 750 * decimal point. 751 */ 752 if (prec || flags&ALT) 753 *t++ = '.'; 754 /* if requires more precision and some fraction left */ 755 if (fract) { 756 if (prec) 757 do { 758 fract = modf(fract * 10, &tmp); 759 *t++ = to_char((int)tmp); 760 } while (--prec && fract); 761 if (fract) 762 startp = round(fract, (int *)NULL, startp, 763 t - 1, (char)0, signp); 764 } 765 for (; prec--; *t++ = '0'); 766 break; 767 case 'e': 768 case 'E': 769 eformat: if (expcnt) { 770 *t++ = *++p; 771 if (prec || flags&ALT) 772 *t++ = '.'; 773 /* if requires more precision and some integer left */ 774 for (; prec && ++p < endp; --prec) 775 *t++ = *p; 776 /* 777 * if done precision and more of the integer component, 778 * round using it; adjust fract so we don't re-round 779 * later. 780 */ 781 if (!prec && ++p < endp) { 782 fract = 0; 783 startp = round((double)0, &expcnt, startp, 784 t - 1, *p, signp); 785 } 786 /* adjust expcnt for digit in front of decimal */ 787 --expcnt; 788 } 789 /* until first fractional digit, decrement exponent */ 790 else if (fract) { 791 /* adjust expcnt for digit in front of decimal */ 792 for (expcnt = -1;; --expcnt) { 793 fract = modf(fract * 10, &tmp); 794 if (tmp) 795 break; 796 } 797 *t++ = to_char((int)tmp); 798 if (prec || flags&ALT) 799 *t++ = '.'; 800 } 801 else { 802 *t++ = '0'; 803 if (prec || flags&ALT) 804 *t++ = '.'; 805 } 806 /* if requires more precision and some fraction left */ 807 if (fract) { 808 if (prec) 809 do { 810 fract = modf(fract * 10, &tmp); 811 *t++ = to_char((int)tmp); 812 } while (--prec && fract); 813 if (fract) 814 startp = round(fract, &expcnt, startp, 815 t - 1, (char)0, signp); 816 } 817 /* if requires more precision */ 818 for (; prec--; *t++ = '0'); 819 820 /* unless alternate flag, trim any g/G format trailing 0's */ 821 if (gformat && !(flags&ALT)) { 822 while (t > startp && *--t == '0'); 823 if (*t == '.') 824 --t; 825 ++t; 826 } 827 t = exponent(t, expcnt, fmtch); 828 break; 829 case 'g': 830 case 'G': 831 /* a precision of 0 is treated as a precision of 1. */ 832 if (!prec) 833 ++prec; 834 /* 835 * ``The style used depends on the value converted; style e 836 * will be used only if the exponent resulting from the 837 * conversion is less than -4 or greater than the precision.'' 838 * -- ANSI X3J11 839 */ 840 if (expcnt > prec || !expcnt && fract && fract < .0001) { 841 /* 842 * g/G format counts "significant digits, not digits of 843 * precision; for the e/E format, this just causes an 844 * off-by-one problem, i.e. g/G considers the digit 845 * before the decimal point significant and e/E doesn't 846 * count it as precision. 847 */ 848 --prec; 849 fmtch -= 2; /* G->E, g->e */ 850 gformat = 1; 851 goto eformat; 852 } 853 /* 854 * reverse integer into beginning of buffer, 855 * note, decrement precision 856 */ 857 if (expcnt) 858 for (; ++p < endp; *t++ = *p, --prec); 859 else 860 *t++ = '0'; 861 /* 862 * if precision required or alternate flag set, add in a 863 * decimal point. If no digits yet, add in leading 0. 864 */ 865 if (prec || flags&ALT) { 866 dotrim = 1; 867 *t++ = '.'; 868 } 869 else 870 dotrim = 0; 871 /* if requires more precision and some fraction left */ 872 if (fract) { 873 if (prec) { 874 do { 875 fract = modf(fract * 10, &tmp); 876 *t++ = to_char((int)tmp); 877 } while(!tmp); 878 while (--prec && fract) { 879 fract = modf(fract * 10, &tmp); 880 *t++ = to_char((int)tmp); 881 } 882 } 883 if (fract) 884 startp = round(fract, (int *)NULL, startp, 885 t - 1, (char)0, signp); 886 } 887 /* alternate format, adds 0's for precision, else trim 0's */ 888 if (flags&ALT) 889 for (; prec--; *t++ = '0'); 890 else if (dotrim) { 891 while (t > startp && *--t == '0'); 892 if (*t != '.') 893 ++t; 894 } 895 } 896 return (t - startp); 897 } 898 899 static char * 900 round(fract, exp, start, end, ch, signp) 901 double fract; 902 int *exp; 903 register char *start, *end; 904 char ch, *signp; 905 { 906 double tmp; 907 908 if (fract) 909 (void)modf(fract * 10, &tmp); 910 else 911 tmp = to_digit(ch); 912 if (tmp > 4) 913 for (;; --end) { 914 if (*end == '.') 915 --end; 916 if (++*end <= '9') 917 break; 918 *end = '0'; 919 if (end == start) { 920 if (exp) { /* e/E; increment exponent */ 921 *end = '1'; 922 ++*exp; 923 } 924 else { /* f; add extra digit */ 925 *--end = '1'; 926 --start; 927 } 928 break; 929 } 930 } 931 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ 932 else if (*signp == '-') 933 for (;; --end) { 934 if (*end == '.') 935 --end; 936 if (*end != '0') 937 break; 938 if (end == start) 939 *signp = 0; 940 } 941 return (start); 942 } 943 944 static char * 945 exponent(p, exp, fmtch) 946 register char *p; 947 register int exp; 948 int fmtch; 949 { 950 register char *t; 951 char expbuf[MAXEXP]; 952 953 *p++ = fmtch; 954 if (exp < 0) { 955 exp = -exp; 956 *p++ = '-'; 957 } 958 else 959 *p++ = '+'; 960 t = expbuf + MAXEXP; 961 if (exp > 9) { 962 do { 963 *--t = to_char(exp % 10); 964 } while ((exp /= 10) > 9); 965 *--t = to_char(exp); 966 for (; t < expbuf + MAXEXP; *p++ = *t++); 967 } 968 else { 969 *p++ = '0'; 970 *p++ = to_char(exp); 971 } 972 return (p); 973 } 974 #endif /* FLOATING_POINT */ 975