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