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