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