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