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