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