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