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.9 1999/08/22 17:06:35 millert 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 #ifdef __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 __P((const char *fmt0, va_list ap, 64 va_list **argtable)); 65 static int __grow_type_table __P((unsigned char **typetable, 66 int *tablesize)); 67 68 /* 69 * Flush out all the vectors defined by the given uio, 70 * then reset it so that it can be reused. 71 */ 72 static int 73 __sprint(fp, uio) 74 FILE *fp; 75 register struct __suio *uio; 76 { 77 register int err; 78 79 if (uio->uio_resid == 0) { 80 uio->uio_iovcnt = 0; 81 return (0); 82 } 83 err = __sfvwrite(fp, uio); 84 uio->uio_resid = 0; 85 uio->uio_iovcnt = 0; 86 return (err); 87 } 88 89 /* 90 * Helper function for `fprintf to unbuffered unix file': creates a 91 * temporary buffer. We only work on write-only files; this avoids 92 * worries about ungetc buffers and so forth. 93 */ 94 static int 95 __sbprintf(fp, fmt, ap) 96 register FILE *fp; 97 const char *fmt; 98 va_list ap; 99 { 100 int ret; 101 FILE fake; 102 unsigned char buf[BUFSIZ]; 103 104 /* copy the important variables */ 105 fake._flags = fp->_flags & ~__SNBF; 106 fake._file = fp->_file; 107 fake._cookie = fp->_cookie; 108 fake._write = fp->_write; 109 110 /* set up the buffer */ 111 fake._bf._base = fake._p = buf; 112 fake._bf._size = fake._w = sizeof(buf); 113 fake._lbfsize = 0; /* not actually used, but Just In Case */ 114 115 /* do the work, then copy any error status */ 116 ret = vfprintf(&fake, fmt, ap); 117 if (ret >= 0 && fflush(&fake)) 118 ret = EOF; 119 if (fake._flags & __SERR) 120 fp->_flags |= __SERR; 121 return (ret); 122 } 123 124 125 #ifdef FLOATING_POINT 126 #include <locale.h> 127 #include <math.h> 128 #include "floatio.h" 129 130 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 131 #define DEFPREC 6 132 133 static char *cvt __P((double, int, int, char *, int *, int, int *)); 134 static int exponent __P((char *, int, int)); 135 136 #else /* no FLOATING_POINT */ 137 #define BUF 40 138 #endif /* FLOATING_POINT */ 139 140 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 141 142 143 /* 144 * Macros for converting digits to letters and vice versa 145 */ 146 #define to_digit(c) ((c) - '0') 147 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 148 #define to_char(n) ((n) + '0') 149 150 /* 151 * Flags used during conversion. 152 */ 153 #define ALT 0x001 /* alternate form */ 154 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 155 #define LADJUST 0x004 /* left adjustment */ 156 #define LONGDBL 0x008 /* long double; unimplemented */ 157 #define LONGINT 0x010 /* long integer */ 158 #define QUADINT 0x020 /* quad integer */ 159 #define SHORTINT 0x040 /* short integer */ 160 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 161 #define FPT 0x100 /* Floating point number */ 162 int 163 vfprintf(fp, fmt0, ap) 164 FILE *fp; 165 const char *fmt0; 166 _BSD_VA_LIST_ ap; 167 { 168 register char *fmt; /* format string */ 169 register int ch; /* character from fmt */ 170 register int n, m, n2; /* handy integers (short term usage) */ 171 register char *cp; /* handy char pointer (short term usage) */ 172 register struct __siov *iovp;/* for PRINT macro */ 173 register int flags; /* flags as above */ 174 int ret; /* return value accumulator */ 175 int width; /* width from format (%8d), or 0 */ 176 int prec; /* precision from format (%.3d), or -1 */ 177 char sign; /* sign prefix (' ', '+', '-', or \0) */ 178 wchar_t wc; 179 #ifdef FLOATING_POINT 180 char *decimal_point = localeconv()->decimal_point; 181 char softsign; /* temporary negative sign for floats */ 182 double _double; /* double precision arguments %[eEfgG] */ 183 int expt; /* integer value of exponent */ 184 int expsize; /* character count for expstr */ 185 int ndig; /* actual number of digits returned by cvt */ 186 char expstr[7]; /* buffer for exponent string */ 187 #endif 188 189 #ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */ 190 #define quad_t long long 191 #define u_quad_t unsigned long long 192 #endif 193 194 u_quad_t _uquad; /* integer arguments %[diouxX] */ 195 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 196 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 197 int realsz; /* field size expanded by dprec */ 198 int size; /* size of converted field or string */ 199 char *xdigs; /* digits for [xX] conversion */ 200 #define NIOV 8 201 struct __suio uio; /* output information: summary */ 202 struct __siov iov[NIOV];/* ... and individual io vectors */ 203 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 204 char ox[2]; /* space for 0x hex-prefix */ 205 va_list *argtable; /* args, built due to positional arg */ 206 va_list statargtable[STATIC_ARG_TBL_SIZE]; 207 int nextarg; /* 1-based argument index */ 208 va_list orgap; /* original argument pointer */ 209 210 /* 211 * Choose PADSIZE to trade efficiency vs. size. If larger printf 212 * fields occur frequently, increase PADSIZE and make the initialisers 213 * below longer. 214 */ 215 #define PADSIZE 16 /* pad chunk size */ 216 static char blanks[PADSIZE] = 217 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 218 static char zeroes[PADSIZE] = 219 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 220 221 /* 222 * BEWARE, these `goto error' on error, and PAD uses `n'. 223 */ 224 #define PRINT(ptr, len) do { \ 225 iovp->iov_base = (ptr); \ 226 iovp->iov_len = (len); \ 227 uio.uio_resid += (len); \ 228 iovp++; \ 229 if (++uio.uio_iovcnt >= NIOV) { \ 230 if (__sprint(fp, &uio)) \ 231 goto error; \ 232 iovp = iov; \ 233 } \ 234 } while (0) 235 #define PAD(howmany, with) do { \ 236 if ((n = (howmany)) > 0) { \ 237 while (n > PADSIZE) { \ 238 PRINT(with, PADSIZE); \ 239 n -= PADSIZE; \ 240 } \ 241 PRINT(with, n); \ 242 } \ 243 } while (0) 244 #define FLUSH() do { \ 245 if (uio.uio_resid && __sprint(fp, &uio)) \ 246 goto error; \ 247 uio.uio_iovcnt = 0; \ 248 iovp = iov; \ 249 } while (0) 250 251 /* 252 * To extend shorts properly, we need both signed and unsigned 253 * argument extraction methods. 254 */ 255 #define SARG() \ 256 (flags&QUADINT ? va_arg(ap, quad_t) : \ 257 flags&LONGINT ? GETARG(long) : \ 258 flags&SHORTINT ? (long)(short)GETARG(int) : \ 259 (long)GETARG(int)) 260 #define UARG() \ 261 (flags&QUADINT ? va_arg(ap, u_quad_t) : \ 262 flags&LONGINT ? GETARG(u_long) : \ 263 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 264 (u_long)GETARG(u_int)) 265 266 /* 267 * Get * arguments, including the form *nn$. Preserve the nextarg 268 * that the argument can be gotten once the type is determined. 269 */ 270 #define GETASTER(val) \ 271 n2 = 0; \ 272 cp = fmt; \ 273 while (is_digit(*cp)) { \ 274 n2 = 10 * n2 + to_digit(*cp); \ 275 cp++; \ 276 } \ 277 if (*cp == '$') { \ 278 int hold = nextarg; \ 279 if (argtable == NULL) { \ 280 argtable = statargtable; \ 281 __find_arguments (fmt0, orgap, &argtable); \ 282 } \ 283 nextarg = n2; \ 284 val = GETARG(int); \ 285 nextarg = hold; \ 286 fmt = ++cp; \ 287 } \ 288 else { \ 289 val = GETARG(int); \ 290 } 291 292 /* 293 * Get the argument indexed by nextarg. If the argument table is 294 * built, use it to get the argument. If its not, get the next 295 * argument (and arguments must be gotten sequentially). 296 */ 297 #define GETARG(type) \ 298 (((argtable != NULL) ? (void)(ap = argtable[nextarg]) : (void)0), \ 299 nextarg++, va_arg(ap, type)) 300 301 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 302 if (cantwrite(fp)) { 303 errno = EBADF; 304 return (EOF); 305 } 306 307 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 308 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 309 fp->_file >= 0) 310 return (__sbprintf(fp, fmt0, ap)); 311 312 fmt = (char *)fmt0; 313 argtable = NULL; 314 nextarg = 1; 315 orgap = ap; 316 uio.uio_iov = iovp = iov; 317 uio.uio_resid = 0; 318 uio.uio_iovcnt = 0; 319 ret = 0; 320 321 /* 322 * Scan the format for conversions (`%' character). 323 */ 324 for (;;) { 325 cp = fmt; 326 while ((n = mbtowc(&wc, fmt, MB_CUR_MAX)) > 0) { 327 fmt += n; 328 if (wc == '%') { 329 fmt--; 330 break; 331 } 332 } 333 if ((m = fmt - cp) != 0) { 334 PRINT(cp, m); 335 ret += m; 336 } 337 if (n <= 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 (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 */ 1174