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