vfprintf.c (27391B)
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 #define FLOATING_POINT 1 38 #include <math.h> 39 40 extern int vx32_isnan(double); 41 42 #if defined(LIBC_SCCS) && !defined(lint) 43 static char *rcsid = "$OpenBSD: vfprintf.c,v 1.8 1998/08/14 21:39:42 deraadt Exp $"; 44 #endif /* LIBC_SCCS and not lint */ 45 46 /* 47 * Actual printf innards. 48 * 49 * This code is large and complicated... 50 */ 51 52 #include <sys/types.h> 53 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <errno.h> 58 59 #ifdef __STDC__ 60 #include <stdarg.h> 61 #else 62 #include <varargs.h> 63 #endif 64 65 #include "local.h" 66 #include "fvwrite.h" 67 68 static void __find_arguments __P((const char *fmt0, va_list ap, 69 va_list **argtable)); 70 static int __grow_type_table __P((unsigned char **typetable, 71 int *tablesize)); 72 73 /* 74 * Flush out all the vectors defined by the given uio, 75 * then reset it so that it can be reused. 76 */ 77 static int 78 __sprint(fp, uio) 79 FILE *fp; 80 register struct __suio *uio; 81 { 82 register int err; 83 84 if (uio->uio_resid == 0) { 85 uio->uio_iovcnt = 0; 86 return (0); 87 } 88 err = __sfvwrite(fp, uio); 89 uio->uio_resid = 0; 90 uio->uio_iovcnt = 0; 91 return (err); 92 } 93 94 /* 95 * Helper function for `fprintf to unbuffered unix file': creates a 96 * temporary buffer. We only work on write-only files; this avoids 97 * worries about ungetc buffers and so forth. 98 */ 99 static int 100 __sbprintf(fp, fmt, ap) 101 register FILE *fp; 102 const char *fmt; 103 va_list ap; 104 { 105 int ret; 106 FILE fake; 107 unsigned char buf[BUFSIZ]; 108 109 /* copy the important variables */ 110 fake._flags = fp->_flags & ~__SNBF; 111 fake._file = fp->_file; 112 fake._cookie = fp->_cookie; 113 fake._write = fp->_write; 114 115 /* set up the buffer */ 116 fake._bf._base = fake._p = buf; 117 fake._bf._size = fake._w = sizeof(buf); 118 fake._lbfsize = 0; /* not actually used, but Just In Case */ 119 120 /* do the work, then copy any error status */ 121 ret = vfprintf(&fake, fmt, ap); 122 if (ret >= 0 && fflush(&fake)) 123 ret = EOF; 124 if (fake._flags & __SERR) 125 fp->_flags |= __SERR; 126 return (ret); 127 } 128 129 130 #ifdef FLOATING_POINT 131 #include <locale.h> 132 #include <math.h> 133 #include "floatio.h" 134 135 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 136 #define DEFPREC 6 137 138 static char *cvt __P((double, int, int, char *, int *, int, int *)); 139 static int exponent __P((char *, int, int)); 140 141 #else /* no FLOATING_POINT */ 142 #define BUF 40 143 #endif /* FLOATING_POINT */ 144 145 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 146 147 148 /* 149 * Macros for converting digits to letters and vice versa 150 */ 151 #define to_digit(c) ((c) - '0') 152 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 153 #define to_char(n) ((n) + '0') 154 155 /* 156 * Flags used during conversion. 157 */ 158 #define ALT 0x001 /* alternate form */ 159 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 160 #define LADJUST 0x004 /* left adjustment */ 161 #define LONGDBL 0x008 /* long double; unimplemented */ 162 #define LONGINT 0x010 /* long integer */ 163 #define QUADINT 0x020 /* quad integer */ 164 #define SHORTINT 0x040 /* short integer */ 165 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 166 #define FPT 0x100 /* Floating point number */ 167 int 168 vfprintf(fp, fmt0, ap) 169 FILE *fp; 170 const char *fmt0; 171 _BSD_VA_LIST_ ap; 172 { 173 register char *fmt; /* format string */ 174 register int ch; /* character from fmt */ 175 register int n, m, n2; /* handy integers (short term usage) */ 176 register char *cp; /* handy char pointer (short term usage) */ 177 register struct __siov *iovp;/* for PRINT macro */ 178 register int flags; /* flags as above */ 179 int ret; /* return value accumulator */ 180 int width; /* width from format (%8d), or 0 */ 181 int prec; /* precision from format (%.3d), or -1 */ 182 char sign; /* sign prefix (' ', '+', '-', or \0) */ 183 wchar_t wc; 184 #ifdef FLOATING_POINT 185 char *decimal_point = "."; 186 char softsign; /* temporary negative sign for floats */ 187 double _double; /* double precision arguments %[eEfgG] */ 188 int expt; /* integer value of exponent */ 189 int expsize; /* character count for expstr */ 190 int ndig; /* actual number of digits returned by cvt */ 191 char expstr[7]; /* buffer for exponent string */ 192 #endif 193 194 #ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */ 195 #define quad_t long long 196 #define u_quad_t unsigned long long 197 #endif 198 199 u_quad_t _uquad; /* integer arguments %[diouxX] */ 200 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 201 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 202 int realsz; /* field size expanded by dprec */ 203 int size; /* size of converted field or string */ 204 char *xdigs; /* digits for [xX] conversion */ 205 #define NIOV 8 206 struct __suio uio; /* output information: summary */ 207 struct __siov iov[NIOV];/* ... and individual io vectors */ 208 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 209 char ox[2]; /* space for 0x hex-prefix */ 210 va_list *argtable; /* args, built due to positional arg */ 211 va_list statargtable[STATIC_ARG_TBL_SIZE]; 212 int nextarg; /* 1-based argument index */ 213 va_list orgap; /* original argument pointer */ 214 215 /* 216 * Choose PADSIZE to trade efficiency vs. size. If larger printf 217 * fields occur frequently, increase PADSIZE and make the initialisers 218 * below longer. 219 */ 220 #define PADSIZE 16 /* pad chunk size */ 221 static char blanks[PADSIZE] = 222 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 223 static char zeroes[PADSIZE] = 224 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 225 226 /* 227 * BEWARE, these `goto error' on error, and PAD uses `n'. 228 */ 229 #define PRINT(ptr, len) { \ 230 iovp->iov_base = (ptr); \ 231 iovp->iov_len = (len); \ 232 uio.uio_resid += (len); \ 233 iovp++; \ 234 if (++uio.uio_iovcnt >= NIOV) { \ 235 if (__sprint(fp, &uio)) \ 236 goto error; \ 237 iovp = iov; \ 238 } \ 239 } 240 #define PAD(howmany, with) { \ 241 if ((n = (howmany)) > 0) { \ 242 while (n > PADSIZE) { \ 243 PRINT(with, PADSIZE); \ 244 n -= PADSIZE; \ 245 } \ 246 PRINT(with, n); \ 247 } \ 248 } 249 #define FLUSH() { \ 250 if (uio.uio_resid && __sprint(fp, &uio)) \ 251 goto error; \ 252 uio.uio_iovcnt = 0; \ 253 iovp = iov; \ 254 } 255 256 /* 257 * To extend shorts properly, we need both signed and unsigned 258 * argument extraction methods. 259 */ 260 #define SARG() \ 261 (flags&QUADINT ? va_arg(ap, quad_t) : \ 262 flags&LONGINT ? GETARG(long) : \ 263 flags&SHORTINT ? (long)(short)GETARG(int) : \ 264 (long)GETARG(int)) 265 #define UARG() \ 266 (flags&QUADINT ? va_arg(ap, u_quad_t) : \ 267 flags&LONGINT ? GETARG(u_long) : \ 268 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 269 (u_long)GETARG(u_int)) 270 271 /* 272 * Get * arguments, including the form *nn$. Preserve the nextarg 273 * that the argument can be gotten once the type is determined. 274 */ 275 #define GETASTER(val) \ 276 n2 = 0; \ 277 cp = fmt; \ 278 while (is_digit(*cp)) { \ 279 n2 = 10 * n2 + to_digit(*cp); \ 280 cp++; \ 281 } \ 282 if (*cp == '$') { \ 283 int hold = nextarg; \ 284 if (argtable == NULL) { \ 285 argtable = statargtable; \ 286 __find_arguments (fmt0, orgap, &argtable); \ 287 } \ 288 nextarg = n2; \ 289 val = GETARG(int); \ 290 nextarg = hold; \ 291 fmt = ++cp; \ 292 } \ 293 else { \ 294 val = GETARG(int); \ 295 } 296 297 /* 298 * Get the argument indexed by nextarg. If the argument table is 299 * built, use it to get the argument. If its not, get the next 300 * argument (and arguments must be gotten sequentially). 301 */ 302 #define GETARG(type) \ 303 (((argtable != NULL) ? (void)(ap = argtable[nextarg]) : (void)0), \ 304 nextarg++, va_arg(ap, type)) 305 306 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 307 if (cantwrite(fp)) { 308 errno = EBADF; 309 return (EOF); 310 } 311 312 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 313 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 314 fp->_file >= 0) 315 return (__sbprintf(fp, fmt0, ap)); 316 317 fmt = (char *)fmt0; 318 argtable = NULL; 319 nextarg = 1; 320 orgap = ap; 321 uio.uio_iov = iovp = iov; 322 uio.uio_resid = 0; 323 uio.uio_iovcnt = 0; 324 ret = 0; 325 326 /* 327 * Scan the format for conversions (`%' character). 328 */ 329 for (;;) { 330 cp = fmt; 331 while ((wc = *fmt) != 0 && wc != '%') 332 fmt++; 333 if ((m = fmt - cp) != 0) { 334 PRINT(cp, m); 335 ret += m; 336 } 337 if (wc == 0) 338 goto done; 339 fmt++; /* skip over '%' */ 340 341 flags = 0; 342 dprec = 0; 343 width = 0; 344 prec = -1; 345 sign = '\0'; 346 347 rflag: ch = *fmt++; 348 reswitch: switch (ch) { 349 case ' ': 350 /* 351 * ``If the space and + flags both appear, the space 352 * flag will be ignored.'' 353 * -- ANSI X3J11 354 */ 355 if (!sign) 356 sign = ' '; 357 goto rflag; 358 case '#': 359 flags |= ALT; 360 goto rflag; 361 case '*': 362 /* 363 * ``A negative field width argument is taken as a 364 * - flag followed by a positive field width.'' 365 * -- ANSI X3J11 366 * They don't exclude field widths read from args. 367 */ 368 GETASTER(width); 369 if (width >= 0) 370 goto rflag; 371 width = -width; 372 /* FALLTHROUGH */ 373 case '-': 374 flags |= LADJUST; 375 goto rflag; 376 case '+': 377 sign = '+'; 378 goto rflag; 379 case '.': 380 if ((ch = *fmt++) == '*') { 381 GETASTER(n); 382 prec = n < 0 ? -1 : n; 383 goto rflag; 384 } 385 n = 0; 386 while (is_digit(ch)) { 387 n = 10 * n + to_digit(ch); 388 ch = *fmt++; 389 } 390 if (ch == '$') { 391 nextarg = n; 392 if (argtable == NULL) { 393 argtable = statargtable; 394 __find_arguments(fmt0, orgap, 395 &argtable); 396 } 397 goto rflag; 398 } 399 prec = n < 0 ? -1 : n; 400 goto reswitch; 401 case '0': 402 /* 403 * ``Note that 0 is taken as a flag, not as the 404 * beginning of a field width.'' 405 * -- ANSI X3J11 406 */ 407 flags |= ZEROPAD; 408 goto rflag; 409 case '1': case '2': case '3': case '4': 410 case '5': case '6': case '7': case '8': case '9': 411 n = 0; 412 do { 413 n = 10 * n + to_digit(ch); 414 ch = *fmt++; 415 } while (is_digit(ch)); 416 if (ch == '$') { 417 nextarg = n; 418 if (argtable == NULL) { 419 argtable = statargtable; 420 __find_arguments (fmt0, orgap, 421 &argtable); 422 } 423 goto rflag; 424 } 425 width = n; 426 goto reswitch; 427 #ifdef FLOATING_POINT 428 case 'L': 429 flags |= LONGDBL; 430 goto rflag; 431 #endif 432 case 'h': 433 flags |= SHORTINT; 434 goto rflag; 435 case 'l': 436 if (*fmt == 'l') { 437 fmt++; 438 flags |= QUADINT; 439 } else { 440 flags |= LONGINT; 441 } 442 goto rflag; 443 case 'q': 444 flags |= QUADINT; 445 goto rflag; 446 case 'c': 447 *(cp = buf) = GETARG(int); 448 size = 1; 449 sign = '\0'; 450 break; 451 case 'D': 452 flags |= LONGINT; 453 /*FALLTHROUGH*/ 454 case 'd': 455 case 'i': 456 _uquad = SARG(); 457 if ((quad_t)_uquad < 0) { 458 _uquad = -_uquad; 459 sign = '-'; 460 } 461 base = DEC; 462 goto number; 463 #ifdef FLOATING_POINT 464 case 'e': 465 case 'E': 466 case 'f': 467 case 'g': 468 case 'G': 469 if (prec == -1) { 470 prec = DEFPREC; 471 } else if ((ch == 'g' || ch == 'G') && prec == 0) { 472 prec = 1; 473 } 474 475 if (flags & LONGDBL) { 476 _double = (double) GETARG(long double); 477 } else { 478 _double = GETARG(double); 479 } 480 481 /* do this before tricky precision changes */ 482 if (isinf(_double)) { 483 if (_double < 0) 484 sign = '-'; 485 cp = "Inf"; 486 size = 3; 487 break; 488 } 489 if (vx32_isnan(_double)) { 490 cp = "NaN"; 491 size = 3; 492 break; 493 } 494 495 flags |= FPT; 496 cp = cvt(_double, prec, flags, &softsign, 497 &expt, ch, &ndig); 498 if (ch == 'g' || ch == 'G') { 499 if (expt <= -4 || expt > prec) 500 ch = (ch == 'g') ? 'e' : 'E'; 501 else 502 ch = 'g'; 503 } 504 if (ch <= 'e') { /* 'e' or 'E' fmt */ 505 --expt; 506 expsize = exponent(expstr, expt, ch); 507 size = expsize + ndig; 508 if (ndig > 1 || flags & ALT) 509 ++size; 510 } else if (ch == 'f') { /* f fmt */ 511 if (expt > 0) { 512 size = expt; 513 if (prec || flags & ALT) 514 size += prec + 1; 515 } else /* "0.X" */ 516 size = prec + 2; 517 } else if (expt >= ndig) { /* fixed g fmt */ 518 size = expt; 519 if (flags & ALT) 520 ++size; 521 } else 522 size = ndig + (expt > 0 ? 523 1 : 2 - expt); 524 525 if (softsign) 526 sign = '-'; 527 break; 528 #endif /* FLOATING_POINT */ 529 case 'n': 530 if (flags & QUADINT) 531 *GETARG(quad_t *) = ret; 532 else if (flags & LONGINT) 533 *GETARG(long *) = ret; 534 else if (flags & SHORTINT) 535 *GETARG(short *) = ret; 536 else 537 *GETARG(int *) = ret; 538 continue; /* no output */ 539 case 'O': 540 flags |= LONGINT; 541 /*FALLTHROUGH*/ 542 case 'o': 543 _uquad = UARG(); 544 base = OCT; 545 goto nosign; 546 case 'p': 547 /* 548 * ``The argument shall be a pointer to void. The 549 * value of the pointer is converted to a sequence 550 * of printable characters, in an implementation- 551 * defined manner.'' 552 * -- ANSI X3J11 553 */ 554 /* NOSTRICT */ 555 _uquad = (u_long)GETARG(void *); 556 base = HEX; 557 xdigs = "0123456789abcdef"; 558 flags |= HEXPREFIX; 559 ch = 'x'; 560 goto nosign; 561 case 's': 562 if ((cp = GETARG(char *)) == NULL) 563 cp = "(null)"; 564 if (prec >= 0) { 565 /* 566 * can't use strlen; can only look for the 567 * NUL in the first `prec' characters, and 568 * strlen() will go further. 569 */ 570 char *p = memchr(cp, 0, prec); 571 572 if (p != NULL) { 573 size = p - cp; 574 if (size > prec) 575 size = prec; 576 } else 577 size = prec; 578 } else 579 size = strlen(cp); 580 sign = '\0'; 581 break; 582 case 'U': 583 flags |= LONGINT; 584 /*FALLTHROUGH*/ 585 case 'u': 586 _uquad = UARG(); 587 base = DEC; 588 goto nosign; 589 case 'X': 590 xdigs = "0123456789ABCDEF"; 591 goto hex; 592 case 'x': 593 xdigs = "0123456789abcdef"; 594 hex: _uquad = UARG(); 595 base = HEX; 596 /* leading 0x/X only if non-zero */ 597 if (flags & ALT && _uquad != 0) 598 flags |= HEXPREFIX; 599 600 /* unsigned conversions */ 601 nosign: sign = '\0'; 602 /* 603 * ``... diouXx conversions ... if a precision is 604 * specified, the 0 flag will be ignored.'' 605 * -- ANSI X3J11 606 */ 607 number: if ((dprec = prec) >= 0) 608 flags &= ~ZEROPAD; 609 610 /* 611 * ``The result of converting a zero value with an 612 * explicit precision of zero is no characters.'' 613 * -- ANSI X3J11 614 */ 615 cp = buf + BUF; 616 if (_uquad != 0 || prec != 0) { 617 /* 618 * Unsigned mod is hard, and unsigned mod 619 * by a constant is easier than that by 620 * a variable; hence this switch. 621 */ 622 switch (base) { 623 case OCT: 624 do { 625 *--cp = to_char(_uquad & 7); 626 _uquad >>= 3; 627 } while (_uquad); 628 /* handle octal leading 0 */ 629 if (flags & ALT && *cp != '0') 630 *--cp = '0'; 631 break; 632 633 case DEC: 634 /* many numbers are 1 digit */ 635 while (_uquad >= 10) { 636 *--cp = to_char(_uquad % 10); 637 _uquad /= 10; 638 } 639 *--cp = to_char(_uquad); 640 break; 641 642 case HEX: 643 do { 644 *--cp = xdigs[_uquad & 15]; 645 _uquad >>= 4; 646 } while (_uquad); 647 break; 648 649 default: 650 cp = "bug in vfprintf: bad base"; 651 size = strlen(cp); 652 goto skipsize; 653 } 654 } 655 size = buf + BUF - cp; 656 skipsize: 657 break; 658 default: /* "%?" prints ?, unless ? is NUL */ 659 if (ch == '\0') 660 goto done; 661 /* pretend it was %c with argument ch */ 662 cp = buf; 663 *cp = ch; 664 size = 1; 665 sign = '\0'; 666 break; 667 } 668 669 /* 670 * All reasonable formats wind up here. At this point, `cp' 671 * points to a string which (if not flags&LADJUST) should be 672 * padded out to `width' places. If flags&ZEROPAD, it should 673 * first be prefixed by any sign or other prefix; otherwise, 674 * it should be blank padded before the prefix is emitted. 675 * After any left-hand padding and prefixing, emit zeroes 676 * required by a decimal [diouxX] precision, then print the 677 * string proper, then emit zeroes required by any leftover 678 * floating precision; finally, if LADJUST, pad with blanks. 679 * 680 * Compute actual size, so we know how much to pad. 681 * size excludes decimal prec; realsz includes it. 682 */ 683 realsz = dprec > size ? dprec : size; 684 if (sign) 685 realsz++; 686 else if (flags & HEXPREFIX) 687 realsz+= 2; 688 689 /* right-adjusting blank padding */ 690 if ((flags & (LADJUST|ZEROPAD)) == 0) 691 PAD(width - realsz, blanks); 692 693 /* prefix */ 694 if (sign) { 695 PRINT(&sign, 1); 696 } else if (flags & HEXPREFIX) { 697 ox[0] = '0'; 698 ox[1] = ch; 699 PRINT(ox, 2); 700 } 701 702 /* right-adjusting zero padding */ 703 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 704 PAD(width - realsz, zeroes); 705 706 /* leading zeroes from decimal precision */ 707 PAD(dprec - size, zeroes); 708 709 /* the string or number proper */ 710 #ifdef FLOATING_POINT 711 if ((flags & FPT) == 0) { 712 PRINT(cp, size); 713 } else { /* glue together f_p fragments */ 714 if (ch >= 'f') { /* 'f' or 'g' */ 715 if (_double == 0) { 716 /* kludge for __dtoa irregularity */ 717 PRINT("0", 1); 718 if (expt < ndig || (flags & ALT) != 0) { 719 PRINT(decimal_point, 1); 720 PAD(ndig - 1, zeroes); 721 } 722 } else if (expt <= 0) { 723 PRINT("0", 1); 724 PRINT(decimal_point, 1); 725 PAD(-expt, zeroes); 726 PRINT(cp, ndig); 727 } else if (expt >= ndig) { 728 PRINT(cp, ndig); 729 PAD(expt - ndig, zeroes); 730 if (flags & ALT) 731 PRINT(".", 1); 732 } else { 733 PRINT(cp, expt); 734 cp += expt; 735 PRINT(".", 1); 736 PRINT(cp, ndig-expt); 737 } 738 } else { /* 'e' or 'E' */ 739 if (ndig > 1 || flags & ALT) { 740 ox[0] = *cp++; 741 ox[1] = '.'; 742 PRINT(ox, 2); 743 if (_double || flags & ALT == 0) { 744 PRINT(cp, ndig-1); 745 } else /* 0.[0..] */ 746 /* __dtoa irregularity */ 747 PAD(ndig - 1, zeroes); 748 } else /* XeYYY */ 749 PRINT(cp, 1); 750 PRINT(expstr, expsize); 751 } 752 } 753 #else 754 PRINT(cp, size); 755 #endif 756 /* left-adjusting padding (always blank) */ 757 if (flags & LADJUST) 758 PAD(width - realsz, blanks); 759 760 /* finally, adjust ret */ 761 ret += width > realsz ? width : realsz; 762 763 FLUSH(); /* copy out the I/O vectors */ 764 } 765 done: 766 FLUSH(); 767 error: 768 if ((argtable != NULL) && (argtable != statargtable)) 769 free (argtable); 770 return (__sferror(fp) ? EOF : ret); 771 /* NOTREACHED */ 772 } 773 774 /* 775 * Type ids for argument type table. 776 */ 777 #define T_UNUSED 0 778 #define T_SHORT 1 779 #define T_U_SHORT 2 780 #define TP_SHORT 3 781 #define T_INT 4 782 #define T_U_INT 5 783 #define TP_INT 6 784 #define T_LONG 7 785 #define T_U_LONG 8 786 #define TP_LONG 9 787 #define T_QUAD 10 788 #define T_U_QUAD 11 789 #define TP_QUAD 12 790 #define T_DOUBLE 13 791 #define T_LONG_DOUBLE 14 792 #define TP_CHAR 15 793 #define TP_VOID 16 794 795 /* 796 * Find all arguments when a positional parameter is encountered. Returns a 797 * table, indexed by argument number, of pointers to each arguments. The 798 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 799 * It will be replaces with a malloc-ed on if it overflows. 800 */ 801 static void 802 __find_arguments (fmt0, ap, argtable) 803 const char *fmt0; 804 va_list ap; 805 va_list **argtable; 806 { 807 register char *fmt; /* format string */ 808 register int ch; /* character from fmt */ 809 register int n, n2; /* handy integer (short term usage) */ 810 register char *cp; /* handy char pointer (short term usage) */ 811 register int flags; /* flags as above */ 812 unsigned char *typetable; /* table of types */ 813 unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; 814 int tablesize; /* current size of type table */ 815 int tablemax; /* largest used index in table */ 816 int nextarg; /* 1-based argument index */ 817 818 /* 819 * Add an argument type to the table, expanding if necessary. 820 */ 821 #define ADDTYPE(type) \ 822 ((nextarg >= tablesize) ? \ 823 __grow_type_table(&typetable, &tablesize) : 0, \ 824 typetable[nextarg++] = type, \ 825 (nextarg > tablemax) ? tablemax = nextarg : 0) 826 827 #define ADDSARG() \ 828 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 829 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) 830 831 #define ADDUARG() \ 832 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 833 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) 834 835 /* 836 * Add * arguments to the type array. 837 */ 838 #define ADDASTER() \ 839 n2 = 0; \ 840 cp = fmt; \ 841 while (is_digit(*cp)) { \ 842 n2 = 10 * n2 + to_digit(*cp); \ 843 cp++; \ 844 } \ 845 if (*cp == '$') { \ 846 int hold = nextarg; \ 847 nextarg = n2; \ 848 ADDTYPE (T_INT); \ 849 nextarg = hold; \ 850 fmt = ++cp; \ 851 } else { \ 852 ADDTYPE (T_INT); \ 853 } 854 fmt = (char *)fmt0; 855 typetable = stattypetable; 856 tablesize = STATIC_ARG_TBL_SIZE; 857 tablemax = 0; 858 nextarg = 1; 859 memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 860 861 /* 862 * Scan the format for conversions (`%' character). 863 */ 864 for (;;) { 865 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 866 /* void */; 867 if (ch == '\0') 868 goto done; 869 fmt++; /* skip over '%' */ 870 871 flags = 0; 872 873 rflag: ch = *fmt++; 874 reswitch: switch (ch) { 875 case ' ': 876 case '#': 877 goto rflag; 878 case '*': 879 ADDASTER (); 880 goto rflag; 881 case '-': 882 case '+': 883 goto rflag; 884 case '.': 885 if ((ch = *fmt++) == '*') { 886 ADDASTER (); 887 goto rflag; 888 } 889 while (is_digit(ch)) { 890 ch = *fmt++; 891 } 892 goto reswitch; 893 case '0': 894 goto rflag; 895 case '1': case '2': case '3': case '4': 896 case '5': case '6': case '7': case '8': case '9': 897 n = 0; 898 do { 899 n = 10 * n + to_digit(ch); 900 ch = *fmt++; 901 } while (is_digit(ch)); 902 if (ch == '$') { 903 nextarg = n; 904 goto rflag; 905 } 906 goto reswitch; 907 #ifdef FLOATING_POINT 908 case 'L': 909 flags |= LONGDBL; 910 goto rflag; 911 #endif 912 case 'h': 913 flags |= SHORTINT; 914 goto rflag; 915 case 'l': 916 flags |= LONGINT; 917 goto rflag; 918 case 'q': 919 flags |= QUADINT; 920 goto rflag; 921 case 'c': 922 ADDTYPE(T_INT); 923 break; 924 case 'D': 925 flags |= LONGINT; 926 /*FALLTHROUGH*/ 927 case 'd': 928 case 'i': 929 if (flags & QUADINT) { 930 ADDTYPE(T_QUAD); 931 } else { 932 ADDSARG(); 933 } 934 break; 935 #ifdef FLOATING_POINT 936 case 'e': 937 case 'E': 938 case 'f': 939 case 'g': 940 case 'G': 941 if (flags & LONGDBL) 942 ADDTYPE(T_LONG_DOUBLE); 943 else 944 ADDTYPE(T_DOUBLE); 945 break; 946 #endif /* FLOATING_POINT */ 947 case 'n': 948 if (flags & QUADINT) 949 ADDTYPE(TP_QUAD); 950 else if (flags & LONGINT) 951 ADDTYPE(TP_LONG); 952 else if (flags & SHORTINT) 953 ADDTYPE(TP_SHORT); 954 else 955 ADDTYPE(TP_INT); 956 continue; /* no output */ 957 case 'O': 958 flags |= LONGINT; 959 /*FALLTHROUGH*/ 960 case 'o': 961 if (flags & QUADINT) 962 ADDTYPE(T_U_QUAD); 963 else 964 ADDUARG(); 965 break; 966 case 'p': 967 ADDTYPE(TP_VOID); 968 break; 969 case 's': 970 ADDTYPE(TP_CHAR); 971 break; 972 case 'U': 973 flags |= LONGINT; 974 /*FALLTHROUGH*/ 975 case 'u': 976 if (flags & QUADINT) 977 ADDTYPE(T_U_QUAD); 978 else 979 ADDUARG(); 980 break; 981 case 'X': 982 case 'x': 983 if (flags & QUADINT) 984 ADDTYPE(T_U_QUAD); 985 else 986 ADDUARG(); 987 break; 988 default: /* "%?" prints ?, unless ? is NUL */ 989 if (ch == '\0') 990 goto done; 991 break; 992 } 993 } 994 done: 995 /* 996 * Build the argument table. 997 */ 998 if (tablemax >= STATIC_ARG_TBL_SIZE) { 999 *argtable = (va_list *) 1000 malloc (sizeof (va_list) * (tablemax + 1)); 1001 } 1002 1003 #if 0 1004 /* XXX is this required? */ 1005 (*argtable) [0] = NULL; 1006 #endif 1007 for (n = 1; n <= tablemax; n++) { 1008 (*argtable) [n] = ap; 1009 switch (typetable [n]) { 1010 case T_UNUSED: 1011 (void) va_arg (ap, int); 1012 break; 1013 case T_SHORT: 1014 (void) va_arg (ap, int); 1015 break; 1016 case T_U_SHORT: 1017 (void) va_arg (ap, int); 1018 break; 1019 case TP_SHORT: 1020 (void) va_arg (ap, short *); 1021 break; 1022 case T_INT: 1023 (void) va_arg (ap, int); 1024 break; 1025 case T_U_INT: 1026 (void) va_arg (ap, unsigned int); 1027 break; 1028 case TP_INT: 1029 (void) va_arg (ap, int *); 1030 break; 1031 case T_LONG: 1032 (void) va_arg (ap, long); 1033 break; 1034 case T_U_LONG: 1035 (void) va_arg (ap, unsigned long); 1036 break; 1037 case TP_LONG: 1038 (void) va_arg (ap, long *); 1039 break; 1040 case T_QUAD: 1041 (void) va_arg (ap, quad_t); 1042 break; 1043 case T_U_QUAD: 1044 (void) va_arg (ap, u_quad_t); 1045 break; 1046 case TP_QUAD: 1047 (void) va_arg (ap, quad_t *); 1048 break; 1049 case T_DOUBLE: 1050 (void) va_arg (ap, double); 1051 break; 1052 case T_LONG_DOUBLE: 1053 (void) va_arg (ap, long double); 1054 break; 1055 case TP_CHAR: 1056 (void) va_arg (ap, char *); 1057 break; 1058 case TP_VOID: 1059 (void) va_arg (ap, void *); 1060 break; 1061 } 1062 } 1063 1064 if ((typetable != NULL) && (typetable != stattypetable)) 1065 free (typetable); 1066 } 1067 1068 /* 1069 * Increase the size of the type table. 1070 */ 1071 static int 1072 __grow_type_table(typetable, tablesize) 1073 unsigned char **typetable; 1074 int *tablesize; 1075 { 1076 unsigned char *oldtable = *typetable; 1077 int newsize = *tablesize * 2; 1078 1079 if (*tablesize == STATIC_ARG_TBL_SIZE) { 1080 *typetable = (unsigned char *) 1081 malloc (sizeof (unsigned char) * newsize); 1082 bcopy (oldtable, *typetable, *tablesize); 1083 } else { 1084 *typetable = (unsigned char *) 1085 realloc (typetable, sizeof (unsigned char) * newsize); 1086 /* XXX unchecked */ 1087 } 1088 memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize)); 1089 1090 *tablesize = newsize; 1091 return(0); 1092 } 1093 1094 1095 #ifdef FLOATING_POINT 1096 1097 extern char *__dtoa __P((double, int, int, int *, int *, char **)); 1098 1099 static char * 1100 cvt(value, ndigits, flags, sign, decpt, ch, length) 1101 double value; 1102 int ndigits, flags, *decpt, ch, *length; 1103 char *sign; 1104 { 1105 int mode, dsgn; 1106 char *digits, *bp, *rve; 1107 1108 if (ch == 'f') { 1109 mode = 3; /* ndigits after the decimal point */ 1110 } else { 1111 /* To obtain ndigits after the decimal point for the 'e' 1112 * and 'E' formats, round to ndigits + 1 significant 1113 * figures. 1114 */ 1115 if (ch == 'e' || ch == 'E') { 1116 ndigits++; 1117 } 1118 mode = 2; /* ndigits significant digits */ 1119 } 1120 1121 if (value < 0) { 1122 value = -value; 1123 *sign = '-'; 1124 } else 1125 *sign = '\000'; 1126 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 1127 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ 1128 bp = digits + ndigits; 1129 if (ch == 'f') { 1130 if (*digits == '0' && value) 1131 *decpt = -ndigits + 1; 1132 bp += *decpt; 1133 } 1134 if (value == 0) /* kludge for __dtoa irregularity */ 1135 rve = bp; 1136 while (rve < bp) 1137 *rve++ = '0'; 1138 } 1139 *length = rve - digits; 1140 return (digits); 1141 } 1142 1143 static int 1144 exponent(p0, exp, fmtch) 1145 char *p0; 1146 int exp, fmtch; 1147 { 1148 register char *p, *t; 1149 char expbuf[MAXEXP]; 1150 1151 p = p0; 1152 *p++ = fmtch; 1153 if (exp < 0) { 1154 exp = -exp; 1155 *p++ = '-'; 1156 } 1157 else 1158 *p++ = '+'; 1159 t = expbuf + MAXEXP; 1160 if (exp > 9) { 1161 do { 1162 *--t = to_char(exp % 10); 1163 } while ((exp /= 10) > 9); 1164 *--t = to_char(exp); 1165 for (; t < expbuf + MAXEXP; *p++ = *t++); 1166 } 1167 else { 1168 *p++ = '0'; 1169 *p++ = to_char(exp); 1170 } 1171 return (p - p0); 1172 } 1173 #endif /* FLOATING_POINT */