1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. 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 8.1 (Berkeley) 06/04/93"; 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 23 #include <limits.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #if __STDC__ 29 #include <stdarg.h> 30 #else 31 #include <varargs.h> 32 #endif 33 34 #include "local.h" 35 #include "fvwrite.h" 36 37 /* Define FLOATING_POINT to get floating point. */ 38 #define FLOATING_POINT 39 40 /* 41 * Flush out all the vectors defined by the given uio, 42 * then reset it so that it can be reused. 43 */ 44 static int 45 __sprint(fp, uio) 46 FILE *fp; 47 register struct __suio *uio; 48 { 49 register int err; 50 51 if (uio->uio_resid == 0) { 52 uio->uio_iovcnt = 0; 53 return (0); 54 } 55 err = __sfvwrite(fp, uio); 56 uio->uio_resid = 0; 57 uio->uio_iovcnt = 0; 58 return (err); 59 } 60 61 /* 62 * Helper function for `fprintf to unbuffered unix file': creates a 63 * temporary buffer. We only work on write-only files; this avoids 64 * worries about ungetc buffers and so forth. 65 */ 66 static int 67 __sbprintf(fp, fmt, ap) 68 register FILE *fp; 69 const char *fmt; 70 va_list ap; 71 { 72 int ret; 73 FILE fake; 74 unsigned char buf[BUFSIZ]; 75 76 /* copy the important variables */ 77 fake._flags = fp->_flags & ~__SNBF; 78 fake._file = fp->_file; 79 fake._cookie = fp->_cookie; 80 fake._write = fp->_write; 81 82 /* set up the buffer */ 83 fake._bf._base = fake._p = buf; 84 fake._bf._size = fake._w = sizeof(buf); 85 fake._lbfsize = 0; /* not actually used, but Just In Case */ 86 87 /* do the work, then copy any error status */ 88 ret = vfprintf(&fake, fmt, ap); 89 if (ret >= 0 && fflush(&fake)) 90 ret = EOF; 91 if (fake._flags & __SERR) 92 fp->_flags |= __SERR; 93 return (ret); 94 } 95 96 /* 97 * Macros for converting digits to letters and vice versa 98 */ 99 #define to_digit(c) ((c) - '0') 100 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 101 #define to_char(n) ((n) + '0') 102 103 /* 104 * Convert an unsigned long to ASCII for printf purposes, returning 105 * a pointer to the first character of the string representation. 106 * Octal numbers can be forced to have a leading zero; hex numbers 107 * use the given digits. 108 */ 109 static char * 110 __ultoa(val, endp, base, octzero, xdigs) 111 register u_long val; 112 char *endp; 113 int base, octzero; 114 char *xdigs; 115 { 116 register char *cp = endp; 117 register long sval; 118 119 /* 120 * Handle the three cases separately, in the hope of getting 121 * better/faster code. 122 */ 123 switch (base) { 124 case 10: 125 if (val < 10) { /* many numbers are 1 digit */ 126 *--cp = to_char(val); 127 return (cp); 128 } 129 /* 130 * On many machines, unsigned arithmetic is harder than 131 * signed arithmetic, so we do at most one unsigned mod and 132 * divide; this is sufficient to reduce the range of 133 * the incoming value to where signed arithmetic works. 134 */ 135 if (val > LONG_MAX) { 136 *--cp = to_char(val % 10); 137 sval = val / 10; 138 } else 139 sval = val; 140 do { 141 *--cp = to_char(sval % 10); 142 sval /= 10; 143 } while (sval != 0); 144 break; 145 146 case 8: 147 do { 148 *--cp = to_char(val & 7); 149 val >>= 3; 150 } while (val); 151 if (octzero && *cp != '0') 152 *--cp = '0'; 153 break; 154 155 case 16: 156 do { 157 *--cp = xdigs[val & 15]; 158 val >>= 4; 159 } while (val); 160 break; 161 162 default: /* oops */ 163 abort(); 164 } 165 return (cp); 166 } 167 168 /* Identical to __ultoa, but for quads. */ 169 static char * 170 __uqtoa(val, endp, base, octzero, xdigs) 171 register u_quad_t val; 172 char *endp; 173 int base, octzero; 174 char *xdigs; 175 { 176 register char *cp = endp; 177 register quad_t sval; 178 179 /* quick test for small values; __ultoa is typically much faster */ 180 /* (perhaps instead we should run until small, then call __ultoa?) */ 181 if (val <= ULONG_MAX) 182 return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 183 switch (base) { 184 case 10: 185 if (val < 10) { 186 *--cp = to_char(val % 10); 187 return (cp); 188 } 189 if (val > QUAD_MAX) { 190 *--cp = to_char(val % 10); 191 sval = val / 10; 192 } else 193 sval = val; 194 do { 195 *--cp = to_char(sval % 10); 196 sval /= 10; 197 } while (sval != 0); 198 break; 199 200 case 8: 201 do { 202 *--cp = to_char(val & 7); 203 val >>= 3; 204 } while (val); 205 if (octzero && *cp != '0') 206 *--cp = '0'; 207 break; 208 209 case 16: 210 do { 211 *--cp = xdigs[val & 15]; 212 val >>= 4; 213 } while (val); 214 break; 215 216 default: 217 abort(); 218 } 219 return (cp); 220 } 221 222 #ifdef FLOATING_POINT 223 #include <math.h> 224 #include "floatio.h" 225 226 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 227 #define DEFPREC 6 228 229 static char *cvt __P((double, int, int, char *, int *, int, int *)); 230 static int exponent __P((char *, int, int)); 231 232 #else /* no FLOATING_POINT */ 233 234 #define BUF 68 235 236 #endif /* FLOATING_POINT */ 237 238 239 /* 240 * Flags used during conversion. 241 */ 242 #define ALT 0x001 /* alternate form */ 243 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 244 #define LADJUST 0x004 /* left adjustment */ 245 #define LONGDBL 0x008 /* long double; unimplemented */ 246 #define LONGINT 0x010 /* long integer */ 247 #define QUADINT 0x020 /* quad integer */ 248 #define SHORTINT 0x040 /* short integer */ 249 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 250 #define FPT 0x100 /* Floating point number */ 251 int 252 vfprintf(fp, fmt0, ap) 253 FILE *fp; 254 const char *fmt0; 255 va_list ap; 256 { 257 register char *fmt; /* format string */ 258 register int ch; /* character from fmt */ 259 register int n; /* handy integer (short term usage) */ 260 register char *cp; /* handy char pointer (short term usage) */ 261 register struct __siov *iovp;/* for PRINT macro */ 262 register int flags; /* flags as above */ 263 int ret; /* return value accumulator */ 264 int width; /* width from format (%8d), or 0 */ 265 int prec; /* precision from format (%.3d), or -1 */ 266 char sign; /* sign prefix (' ', '+', '-', or \0) */ 267 #ifdef FLOATING_POINT 268 char softsign; /* temporary negative sign for floats */ 269 double _double; /* double precision arguments %[eEfgG] */ 270 int expt; /* integer value of exponent */ 271 int expsize; /* character count for expstr */ 272 int ndig; /* actual number of digits returned by cvt */ 273 char expstr[7]; /* buffer for exponent string */ 274 #endif 275 u_long ulval; /* integer arguments %[diouxX] */ 276 u_quad_t uqval; /* %q integers */ 277 int base; /* base for [diouxX] conversion */ 278 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 279 int fieldsz; /* field size expanded by sign, etc */ 280 int realsz; /* field size expanded by dprec */ 281 int size; /* size of converted field or string */ 282 char *xdigs; /* digits for [xX] conversion */ 283 #define NIOV 8 284 struct __suio uio; /* output information: summary */ 285 struct __siov iov[NIOV];/* ... and individual io vectors */ 286 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 287 char ox[2]; /* space for 0x hex-prefix */ 288 289 /* 290 * Choose PADSIZE to trade efficiency vs. size. If larger printf 291 * fields occur frequently, increase PADSIZE and make the initialisers 292 * below longer. 293 */ 294 #define PADSIZE 16 /* pad chunk size */ 295 static char blanks[PADSIZE] = 296 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 297 static char zeroes[PADSIZE] = 298 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 299 300 /* 301 * BEWARE, these `goto error' on error, and PAD uses `n'. 302 */ 303 #define PRINT(ptr, len) { \ 304 iovp->iov_base = (ptr); \ 305 iovp->iov_len = (len); \ 306 uio.uio_resid += (len); \ 307 iovp++; \ 308 if (++uio.uio_iovcnt >= NIOV) { \ 309 if (__sprint(fp, &uio)) \ 310 goto error; \ 311 iovp = iov; \ 312 } \ 313 } 314 #define PAD(howmany, with) { \ 315 if ((n = (howmany)) > 0) { \ 316 while (n > PADSIZE) { \ 317 PRINT(with, PADSIZE); \ 318 n -= PADSIZE; \ 319 } \ 320 PRINT(with, n); \ 321 } \ 322 } 323 #define FLUSH() { \ 324 if (uio.uio_resid && __sprint(fp, &uio)) \ 325 goto error; \ 326 uio.uio_iovcnt = 0; \ 327 iovp = iov; \ 328 } 329 330 /* 331 * To extend shorts properly, we need both signed and unsigned 332 * argument extraction methods. 333 */ 334 #define SARG() \ 335 (flags&LONGINT ? va_arg(ap, long) : \ 336 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 337 (long)va_arg(ap, int)) 338 #define UARG() \ 339 (flags&LONGINT ? va_arg(ap, u_long) : \ 340 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 341 (u_long)va_arg(ap, u_int)) 342 343 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 344 if (cantwrite(fp)) 345 return (EOF); 346 347 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 348 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 349 fp->_file >= 0) 350 return (__sbprintf(fp, fmt0, ap)); 351 352 fmt = (char *)fmt0; 353 uio.uio_iov = iovp = iov; 354 uio.uio_resid = 0; 355 uio.uio_iovcnt = 0; 356 ret = 0; 357 358 /* 359 * Scan the format for conversions (`%' character). 360 */ 361 for (;;) { 362 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 363 /* void */; 364 if ((n = fmt - cp) != 0) { 365 PRINT(cp, n); 366 ret += n; 367 } 368 if (ch == '\0') 369 goto done; 370 fmt++; /* skip over '%' */ 371 372 flags = 0; 373 dprec = 0; 374 width = 0; 375 prec = -1; 376 sign = '\0'; 377 378 rflag: ch = *fmt++; 379 reswitch: switch (ch) { 380 case ' ': 381 /* 382 * ``If the space and + flags both appear, the space 383 * flag will be ignored.'' 384 * -- ANSI X3J11 385 */ 386 if (!sign) 387 sign = ' '; 388 goto rflag; 389 case '#': 390 flags |= ALT; 391 goto rflag; 392 case '*': 393 /* 394 * ``A negative field width argument is taken as a 395 * - flag followed by a positive field width.'' 396 * -- ANSI X3J11 397 * They don't exclude field widths read from args. 398 */ 399 if ((width = va_arg(ap, int)) >= 0) 400 goto rflag; 401 width = -width; 402 /* FALLTHROUGH */ 403 case '-': 404 flags |= LADJUST; 405 goto rflag; 406 case '+': 407 sign = '+'; 408 goto rflag; 409 case '.': 410 if ((ch = *fmt++) == '*') { 411 n = va_arg(ap, int); 412 prec = n < 0 ? -1 : n; 413 goto rflag; 414 } 415 n = 0; 416 while (is_digit(ch)) { 417 n = 10 * n + to_digit(ch); 418 ch = *fmt++; 419 } 420 prec = n < 0 ? -1 : n; 421 goto reswitch; 422 case '0': 423 /* 424 * ``Note that 0 is taken as a flag, not as the 425 * beginning of a field width.'' 426 * -- ANSI X3J11 427 */ 428 flags |= ZEROPAD; 429 goto rflag; 430 case '1': case '2': case '3': case '4': 431 case '5': case '6': case '7': case '8': case '9': 432 n = 0; 433 do { 434 n = 10 * n + to_digit(ch); 435 ch = *fmt++; 436 } while (is_digit(ch)); 437 width = n; 438 goto reswitch; 439 #ifdef FLOATING_POINT 440 case 'L': 441 flags |= LONGDBL; 442 goto rflag; 443 #endif 444 case 'h': 445 flags |= SHORTINT; 446 goto rflag; 447 case 'l': 448 flags |= LONGINT; 449 goto rflag; 450 case 'q': 451 flags |= QUADINT; 452 goto rflag; 453 case 'c': 454 *(cp = buf) = va_arg(ap, int); 455 size = 1; 456 sign = '\0'; 457 break; 458 case 'D': 459 flags |= LONGINT; 460 /*FALLTHROUGH*/ 461 case 'd': 462 case 'i': 463 if (flags & QUADINT) { 464 uqval = va_arg(ap, quad_t); 465 if ((quad_t)uqval < 0) { 466 uqval = -uqval; 467 sign = '-'; 468 } 469 } else { 470 ulval = SARG(); 471 if ((long)ulval < 0) { 472 ulval = -ulval; 473 sign = '-'; 474 } 475 } 476 base = 10; 477 goto number; 478 #ifdef FLOATING_POINT 479 case 'e': /* anomalous precision */ 480 case 'E': 481 prec = (prec == -1) ? 482 DEFPREC + 1 : prec + 1; 483 /* FALLTHROUGH */ 484 goto fp_begin; 485 case 'f': /* always print trailing zeroes */ 486 if (prec != 0) 487 flags |= ALT; 488 case 'g': 489 case 'G': 490 if (prec == -1) 491 prec = DEFPREC; 492 fp_begin: _double = va_arg(ap, double); 493 /* do this before tricky precision changes */ 494 if (isinf(_double)) { 495 if (_double < 0) 496 sign = '-'; 497 cp = "Inf"; 498 size = 3; 499 break; 500 } 501 if (isnan(_double)) { 502 cp = "NaN"; 503 size = 3; 504 break; 505 } 506 flags |= FPT; 507 cp = cvt(_double, prec, flags, &softsign, 508 &expt, ch, &ndig); 509 if (ch == 'g' || ch == 'G') { 510 if (expt <= -4 || expt > prec) 511 ch = (ch == 'g') ? 'e' : 'E'; 512 else 513 ch = 'g'; 514 } 515 if (ch <= 'e') { /* 'e' or 'E' fmt */ 516 --expt; 517 expsize = exponent(expstr, expt, ch); 518 size = expsize + ndig; 519 if (ndig > 1 || flags & ALT) 520 ++size; 521 } else if (ch == 'f') { /* f fmt */ 522 if (expt > 0) { 523 size = expt; 524 if (prec || flags & ALT) 525 size += prec + 1; 526 } else /* "0.X" */ 527 size = prec + 2; 528 } else if (expt >= ndig) { /* fixed g fmt */ 529 size = expt; 530 if (flags & ALT) 531 ++size; 532 } else 533 size = ndig + (expt > 0 ? 534 1 : 2 - expt); 535 536 if (softsign) 537 sign = '-'; 538 break; 539 #endif /* FLOATING_POINT */ 540 case 'n': 541 if (flags & QUADINT) 542 *va_arg(ap, quad_t *) = ret; 543 else if (flags & LONGINT) 544 *va_arg(ap, long *) = ret; 545 else if (flags & SHORTINT) 546 *va_arg(ap, short *) = ret; 547 else 548 *va_arg(ap, int *) = ret; 549 continue; /* no output */ 550 case 'O': 551 flags |= LONGINT; 552 /*FALLTHROUGH*/ 553 case 'o': 554 if (flags & QUADINT) 555 uqval = va_arg(ap, u_quad_t); 556 else 557 ulval = UARG(); 558 base = 8; 559 goto nosign; 560 case 'p': 561 /* 562 * ``The argument shall be a pointer to void. The 563 * value of the pointer is converted to a sequence 564 * of printable characters, in an implementation- 565 * defined manner.'' 566 * -- ANSI X3J11 567 */ 568 ulval = (u_long)va_arg(ap, void *); 569 base = 16; 570 xdigs = "0123456789abcdef"; 571 flags = (flags & ~QUADINT) | HEXPREFIX; 572 ch = 'x'; 573 goto nosign; 574 case 's': 575 if ((cp = va_arg(ap, char *)) == NULL) 576 cp = "(null)"; 577 if (prec >= 0) { 578 /* 579 * can't use strlen; can only look for the 580 * NUL in the first `prec' characters, and 581 * strlen() will go further. 582 */ 583 char *p = memchr(cp, 0, prec); 584 585 if (p != NULL) { 586 size = p - cp; 587 if (size > prec) 588 size = prec; 589 } else 590 size = prec; 591 } else 592 size = strlen(cp); 593 sign = '\0'; 594 break; 595 case 'U': 596 flags |= LONGINT; 597 /*FALLTHROUGH*/ 598 case 'u': 599 if (flags & QUADINT) 600 uqval = va_arg(ap, u_quad_t); 601 else 602 ulval = UARG(); 603 base = 10; 604 goto nosign; 605 case 'X': 606 xdigs = "0123456789ABCDEF"; 607 goto hex; 608 case 'x': 609 xdigs = "0123456789abcdef"; 610 hex: if (flags & QUADINT) 611 uqval = va_arg(ap, u_quad_t); 612 else 613 ulval = UARG(); 614 base = 16; 615 /* leading 0x/X only if non-zero */ 616 if (flags & ALT && 617 (flags & QUADINT ? uqval != 0 : ulval != 0)) 618 flags |= HEXPREFIX; 619 620 /* unsigned conversions */ 621 nosign: sign = '\0'; 622 /* 623 * ``... diouXx conversions ... if a precision is 624 * specified, the 0 flag will be ignored.'' 625 * -- ANSI X3J11 626 */ 627 number: if ((dprec = prec) >= 0) 628 flags &= ~ZEROPAD; 629 630 /* 631 * ``The result of converting a zero value with an 632 * explicit precision of zero is no characters.'' 633 * -- ANSI X3J11 634 */ 635 cp = buf + BUF; 636 if (flags & QUADINT) { 637 if (uqval != 0 || prec != 0) 638 cp = __uqtoa(uqval, cp, base, 639 flags & ALT, xdigs); 640 } else { 641 if (ulval != 0 || prec != 0) 642 cp = __ultoa(ulval, cp, base, 643 flags & ALT, xdigs); 644 } 645 size = buf + BUF - cp; 646 break; 647 default: /* "%?" prints ?, unless ? is NUL */ 648 if (ch == '\0') 649 goto done; 650 /* pretend it was %c with argument ch */ 651 cp = buf; 652 *cp = ch; 653 size = 1; 654 sign = '\0'; 655 break; 656 } 657 658 /* 659 * All reasonable formats wind up here. At this point, `cp' 660 * points to a string which (if not flags&LADJUST) should be 661 * padded out to `width' places. If flags&ZEROPAD, it should 662 * first be prefixed by any sign or other prefix; otherwise, 663 * it should be blank padded before the prefix is emitted. 664 * After any left-hand padding and prefixing, emit zeroes 665 * required by a decimal [diouxX] precision, then print the 666 * string proper, then emit zeroes required by any leftover 667 * floating precision; finally, if LADJUST, pad with blanks. 668 * 669 * Compute actual size, so we know how much to pad. 670 * fieldsz excludes decimal prec; realsz includes it. 671 */ 672 fieldsz = size; 673 if (sign) 674 fieldsz++; 675 else if (flags & HEXPREFIX) 676 fieldsz += 2; 677 realsz = dprec > fieldsz ? dprec : fieldsz; 678 679 /* right-adjusting blank padding */ 680 if ((flags & (LADJUST|ZEROPAD)) == 0) 681 PAD(width - realsz, blanks); 682 683 /* prefix */ 684 if (sign) { 685 PRINT(&sign, 1); 686 } else if (flags & HEXPREFIX) { 687 ox[0] = '0'; 688 ox[1] = ch; 689 PRINT(ox, 2); 690 } 691 692 /* right-adjusting zero padding */ 693 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 694 PAD(width - realsz, zeroes); 695 696 /* leading zeroes from decimal precision */ 697 PAD(dprec - fieldsz, zeroes); 698 699 /* the string or number proper */ 700 #ifdef FLOATING_POINT 701 if ((flags & FPT) == 0) { 702 PRINT(cp, size); 703 } else { /* glue together f_p fragments */ 704 if (ch >= 'f') { /* 'f' or 'g' */ 705 if (_double == 0) { 706 /* kludge for __dtoa irregularity */ 707 if (prec == 0 || 708 (flags & ALT) == 0) { 709 PRINT("0", 1); 710 } else { 711 PRINT("0.", 2); 712 PAD(ndig - 1, zeroes); 713 } 714 } else if (expt <= 0) { 715 PRINT("0.", 2); 716 PAD(-expt, zeroes); 717 PRINT(cp, ndig); 718 } else if (expt >= ndig) { 719 PRINT(cp, ndig); 720 PAD(expt - ndig, zeroes); 721 if (flags & ALT) 722 PRINT(".", 1); 723 } else { 724 PRINT(cp, expt); 725 cp += expt; 726 PRINT(".", 1); 727 PRINT(cp, ndig-expt); 728 } 729 } else { /* 'e' or 'E' */ 730 if (ndig > 1 || flags & ALT) { 731 ox[0] = *cp++; 732 ox[1] = '.'; 733 PRINT(ox, 2); 734 if (_double || flags & ALT == 0) { 735 PRINT(cp, ndig-1); 736 } else /* 0.[0..] */ 737 /* __dtoa irregularity */ 738 PAD(ndig - 1, zeroes); 739 } else /* XeYYY */ 740 PRINT(cp, 1); 741 PRINT(expstr, expsize); 742 } 743 } 744 #else 745 PRINT(cp, size); 746 #endif 747 /* left-adjusting padding (always blank) */ 748 if (flags & LADJUST) 749 PAD(width - realsz, blanks); 750 751 /* finally, adjust ret */ 752 ret += width > realsz ? width : realsz; 753 754 FLUSH(); /* copy out the I/O vectors */ 755 } 756 done: 757 FLUSH(); 758 error: 759 return (__sferror(fp) ? EOF : ret); 760 /* NOTREACHED */ 761 } 762 763 #ifdef FLOATING_POINT 764 765 extern char *__dtoa __P((double, int, int, int *, int *, char **)); 766 767 static char * 768 cvt(value, ndigits, flags, sign, decpt, ch, length) 769 double value; 770 int ndigits, flags, *decpt, ch, *length; 771 char *sign; 772 { 773 int mode, dsgn; 774 char *digits, *bp, *rve; 775 776 if (ch == 'f') 777 mode = 3; 778 else { 779 mode = 2; 780 } 781 if (value < 0) { 782 value = -value; 783 *sign = '-'; 784 } else 785 *sign = '\000'; 786 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 787 if (flags & ALT) { /* Print trailing zeros */ 788 bp = digits + ndigits; 789 if (ch == 'f') { 790 if (*digits == '0' && value) 791 *decpt = -ndigits + 1; 792 bp += *decpt; 793 } 794 if (value == 0) /* kludge for __dtoa irregularity */ 795 rve = bp; 796 while (rve < bp) 797 *rve++ = '0'; 798 } 799 *length = rve - digits; 800 return (digits); 801 } 802 803 static int 804 exponent(p0, exp, fmtch) 805 char *p0; 806 int exp, fmtch; 807 { 808 register char *p, *t; 809 char expbuf[MAXEXP]; 810 811 p = p0; 812 *p++ = fmtch; 813 if (exp < 0) { 814 exp = -exp; 815 *p++ = '-'; 816 } 817 else 818 *p++ = '+'; 819 t = expbuf + MAXEXP; 820 if (exp > 9) { 821 do { 822 *--t = to_char(exp % 10); 823 } while ((exp /= 10) > 9); 824 *--t = to_char(exp); 825 for (; t < expbuf + MAXEXP; *p++ = *t++); 826 } 827 else { 828 *p++ = '0'; 829 *p++ = to_char(exp); 830 } 831 return (p - p0); 832 } 833 #endif /* FLOATING_POINT */ 834