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