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