1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)vfprintf.c 5.39 (Berkeley) 06/28/90"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/types.h> 13 #include <varargs.h> 14 #include <stdio.h> 15 #include <ctype.h> 16 17 /* 11-bit exponent (VAX G floating point) is 308 decimal digits */ 18 #define MAXEXP 308 19 /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ 20 #define MAXFRACT 39 21 22 #define DEFPREC 6 23 24 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 25 26 #define PUTC(ch) (void) putc(ch, fp) 27 28 #define ARG(basetype) \ 29 _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \ 30 flags&SHORTINT ? (short basetype)va_arg(argp, int) : \ 31 va_arg(argp, int) 32 33 #define todigit(c) ((c) - '0') 34 #define tochar(n) ((n) + '0') 35 36 /* have to deal with the negative buffer count kludge */ 37 #define NEGATIVE_COUNT_KLUDGE 38 39 #define LONGINT 0x01 /* long integer */ 40 #define LONGDBL 0x02 /* long double; unimplemented */ 41 #define SHORTINT 0x04 /* short integer */ 42 #define ALT 0x08 /* alternate form */ 43 #define LADJUST 0x10 /* left adjustment */ 44 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ 45 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ 46 47 _doprnt(fmt0, argp, fp) 48 u_char *fmt0; 49 va_list argp; 50 register FILE *fp; 51 { 52 register u_char *fmt; /* format string */ 53 register int ch; /* character from fmt */ 54 register int cnt; /* return value accumulator */ 55 register int n; /* random handy integer */ 56 register char *t; /* buffer pointer */ 57 double _double; /* double precision arguments %[eEfgG] */ 58 u_long _ulong; /* integer arguments %[diouxX] */ 59 int base; /* base for [diouxX] conversion */ 60 int dprec; /* decimal precision in [diouxX] */ 61 int fieldsz; /* field size expanded by sign, etc */ 62 int flags; /* flags as above */ 63 int fpprec; /* `extra' floating precision in [eEfgG] */ 64 int prec; /* precision from format (%.3d), or -1 */ 65 int realsz; /* field size expanded by decimal precision */ 66 int size; /* size of converted field or string */ 67 int width; /* width from format (%8d), or 0 */ 68 char sign; /* sign prefix (' ', '+', '-', or \0) */ 69 char softsign; /* temporary negative sign for floats */ 70 char *digs; /* digits for [diouxX] conversion */ 71 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 72 73 if (fp->_flag & _IORW) { 74 fp->_flag |= _IOWRT; 75 fp->_flag &= ~(_IOEOF|_IOREAD); 76 } 77 if ((fp->_flag & _IOWRT) == 0) 78 return (EOF); 79 80 fmt = fmt0; 81 digs = "0123456789abcdef"; 82 for (cnt = 0;; ++fmt) { 83 n = fp->_cnt; 84 for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; 85 ++cnt, ++fmt) 86 if (--n < 0 87 #ifdef NEGATIVE_COUNT_KLUDGE 88 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 89 #endif 90 || ch == '\n' && fp->_flag & _IOLBF) { 91 fp->_cnt = n; 92 fp->_ptr = t; 93 (void) _flsbuf((u_char)ch, fp); 94 n = fp->_cnt; 95 t = (char *)fp->_ptr; 96 } else 97 *t++ = ch; 98 fp->_cnt = n; 99 fp->_ptr = t; 100 if (!ch) 101 return (cnt); 102 103 flags = 0; dprec = 0; fpprec = 0; width = 0; 104 prec = -1; 105 sign = '\0'; 106 107 rflag: switch (*++fmt) { 108 case ' ': 109 /* 110 * ``If the space and + flags both appear, the space 111 * flag will be ignored.'' 112 * -- ANSI X3J11 113 */ 114 if (!sign) 115 sign = ' '; 116 goto rflag; 117 case '#': 118 flags |= ALT; 119 goto rflag; 120 case '*': 121 /* 122 * ``A negative field width argument is taken as a 123 * - flag followed by a positive field width.'' 124 * -- ANSI X3J11 125 * They don't exclude field widths read from args. 126 */ 127 if ((width = va_arg(argp, int)) >= 0) 128 goto rflag; 129 width = -width; 130 /* FALLTHROUGH */ 131 case '-': 132 flags |= LADJUST; 133 goto rflag; 134 case '+': 135 sign = '+'; 136 goto rflag; 137 case '.': 138 if (*++fmt == '*') 139 n = va_arg(argp, int); 140 else { 141 n = 0; 142 while (isascii(*fmt) && isdigit(*fmt)) 143 n = 10 * n + todigit(*fmt++); 144 --fmt; 145 } 146 prec = n < 0 ? -1 : n; 147 goto rflag; 148 case '0': 149 /* 150 * ``Note that 0 is taken as a flag, not as the 151 * beginning of a field width.'' 152 * -- ANSI X3J11 153 */ 154 flags |= ZEROPAD; 155 goto rflag; 156 case '1': case '2': case '3': case '4': 157 case '5': case '6': case '7': case '8': case '9': 158 n = 0; 159 do { 160 n = 10 * n + todigit(*fmt); 161 } while (isascii(*++fmt) && isdigit(*fmt)); 162 width = n; 163 --fmt; 164 goto rflag; 165 case 'L': 166 flags |= LONGDBL; 167 goto rflag; 168 case 'h': 169 flags |= SHORTINT; 170 goto rflag; 171 case 'l': 172 flags |= LONGINT; 173 goto rflag; 174 case 'c': 175 *(t = buf) = va_arg(argp, int); 176 size = 1; 177 sign = '\0'; 178 goto pforw; 179 case 'D': 180 flags |= LONGINT; 181 /*FALLTHROUGH*/ 182 case 'd': 183 case 'i': 184 ARG(int); 185 if ((long)_ulong < 0) { 186 _ulong = -_ulong; 187 sign = '-'; 188 } 189 base = 10; 190 goto number; 191 case 'e': 192 case 'E': 193 case 'f': 194 case 'g': 195 case 'G': 196 _double = va_arg(argp, double); 197 /* 198 * don't do unrealistic precision; just pad it with 199 * zeroes later, so buffer size stays rational. 200 */ 201 if (prec > MAXFRACT) { 202 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) 203 fpprec = prec - MAXFRACT; 204 prec = MAXFRACT; 205 } 206 else if (prec == -1) 207 prec = DEFPREC; 208 /* 209 * softsign avoids negative 0 if _double is < 0 and 210 * no significant digits will be shown 211 */ 212 if (_double < 0) { 213 softsign = '-'; 214 _double = -_double; 215 } 216 else 217 softsign = 0; 218 /* 219 * cvt may have to round up past the "start" of the 220 * buffer, i.e. ``intf("%.2f", (double)9.999);''; 221 * if the first char isn't NULL, it did. 222 */ 223 *buf = NULL; 224 size = cvt(_double, prec, flags, &softsign, *fmt, buf, 225 buf + sizeof(buf)); 226 if (softsign) 227 sign = '-'; 228 t = *buf ? buf : buf + 1; 229 goto pforw; 230 case 'n': 231 if (flags & LONGINT) 232 *va_arg(argp, long *) = cnt; 233 else if (flags & SHORTINT) 234 *va_arg(argp, short *) = cnt; 235 else 236 *va_arg(argp, int *) = cnt; 237 break; 238 case 'O': 239 flags |= LONGINT; 240 /*FALLTHROUGH*/ 241 case 'o': 242 ARG(unsigned); 243 base = 8; 244 goto nosign; 245 case 'p': 246 /* 247 * ``The argument shall be a pointer to void. The 248 * value of the pointer is converted to a sequence 249 * of printable characters, in an implementation- 250 * defined manner.'' 251 * -- ANSI X3J11 252 */ 253 /* NOSTRICT */ 254 _ulong = (u_long)va_arg(argp, void *); 255 base = 16; 256 goto nosign; 257 case 's': 258 if (!(t = va_arg(argp, char *))) 259 t = "(null)"; 260 if (prec >= 0) { 261 /* 262 * can't use strlen; can only look for the 263 * NUL in the first `prec' characters, and 264 * strlen() will go further. 265 */ 266 char *p, *memchr(); 267 268 if (p = memchr(t, 0, prec)) { 269 size = p - t; 270 if (size > prec) 271 size = prec; 272 } else 273 size = prec; 274 } else 275 size = strlen(t); 276 sign = '\0'; 277 goto pforw; 278 case 'U': 279 flags |= LONGINT; 280 /*FALLTHROUGH*/ 281 case 'u': 282 ARG(unsigned); 283 base = 10; 284 goto nosign; 285 case 'X': 286 digs = "0123456789ABCDEF"; 287 /* FALLTHROUGH */ 288 case 'x': 289 ARG(unsigned); 290 base = 16; 291 /* leading 0x/X only if non-zero */ 292 if (flags & ALT && _ulong != 0) 293 flags |= HEXPREFIX; 294 295 /* unsigned conversions */ 296 nosign: sign = '\0'; 297 /* 298 * ``... diouXx conversions ... if a precision is 299 * specified, the 0 flag will be ignored.'' 300 * -- ANSI X3J11 301 */ 302 number: if ((dprec = prec) >= 0) 303 flags &= ~ZEROPAD; 304 305 /* 306 * ``The result of converting a zero value with an 307 * explicit precision of zero is no characters.'' 308 * -- ANSI X3J11 309 */ 310 t = buf + BUF; 311 if (_ulong != 0 || prec != 0) { 312 do { 313 *--t = digs[_ulong % base]; 314 _ulong /= base; 315 } while (_ulong); 316 digs = "0123456789abcdef"; 317 if (flags & ALT && base == 8 && *t != '0') 318 *--t = '0'; /* octal leading 0 */ 319 } 320 size = buf + BUF - t; 321 322 pforw: 323 /* 324 * All reasonable formats wind up here. At this point, 325 * `t' points to a string which (if not flags&LADJUST) 326 * should be padded out to `width' places. If 327 * flags&ZEROPAD, it should first be prefixed by any 328 * sign or other prefix; otherwise, it should be blank 329 * padded before the prefix is emitted. After any 330 * left-hand padding and prefixing, emit zeroes 331 * required by a decimal [diouxX] precision, then print 332 * the string proper, then emit zeroes required by any 333 * leftover floating precision; finally, if LADJUST, 334 * pad with blanks. 335 */ 336 337 /* 338 * compute actual size, so we know how much to pad 339 * fieldsz excludes decimal prec; realsz includes it 340 */ 341 fieldsz = size + fpprec; 342 if (sign) 343 fieldsz++; 344 if (flags & HEXPREFIX) 345 fieldsz += 2; 346 realsz = dprec > fieldsz ? dprec : fieldsz; 347 348 /* right-adjusting blank padding */ 349 if ((flags & (LADJUST|ZEROPAD)) == 0 && width) 350 for (n = realsz; n < width; n++) 351 PUTC(' '); 352 /* prefix */ 353 if (sign) 354 PUTC(sign); 355 if (flags & HEXPREFIX) { 356 PUTC('0'); 357 PUTC((char)*fmt); 358 } 359 /* right-adjusting zero padding */ 360 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 361 for (n = realsz; n < width; n++) 362 PUTC('0'); 363 /* leading zeroes from decimal precision */ 364 for (n = fieldsz; n < dprec; n++) 365 PUTC('0'); 366 367 /* the string or number proper */ 368 n = size; 369 if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) { 370 fp->_cnt -= n; 371 bcopy(t, (char *)fp->_ptr, n); 372 fp->_ptr += n; 373 } else 374 while (--n >= 0) 375 PUTC(*t++); 376 /* trailing f.p. zeroes */ 377 while (--fpprec >= 0) 378 PUTC('0'); 379 /* left-adjusting padding (always blank) */ 380 if (flags & LADJUST) 381 for (n = realsz; n < width; n++) 382 PUTC(' '); 383 /* finally, adjust cnt */ 384 cnt += width > realsz ? width : realsz; 385 break; 386 case '\0': /* "%?" prints ?, unless ? is NULL */ 387 return (cnt); 388 default: 389 PUTC((char)*fmt); 390 cnt++; 391 } 392 } 393 /* NOTREACHED */ 394 } 395 396 static 397 cvt(number, prec, flags, signp, fmtch, startp, endp) 398 double number; 399 register int prec; 400 int flags; 401 u_char fmtch; 402 char *signp, *startp, *endp; 403 { 404 register char *p, *t; 405 register double fract; 406 int dotrim, expcnt, gformat; 407 double integer, tmp, modf(); 408 char *exponent(), *round(); 409 410 #ifdef hp300 411 if (expcnt = isspecial(number, startp, signp)) 412 return(expcnt); 413 #endif 414 415 dotrim = expcnt = gformat = 0; 416 fract = modf(number, &integer); 417 418 /* get an extra slot for rounding. */ 419 t = ++startp; 420 421 /* 422 * get integer portion of number; put into the end of the buffer; the 423 * .01 is added for modf(356.0 / 10, &integer) returning .59999999... 424 */ 425 for (p = endp - 1; integer; ++expcnt) { 426 tmp = modf(integer / 10, &integer); 427 *p-- = tochar((int)((tmp + .01) * 10)); 428 } 429 switch(fmtch) { 430 case 'f': 431 /* reverse integer into beginning of buffer */ 432 if (expcnt) 433 for (; ++p < endp; *t++ = *p); 434 else 435 *t++ = '0'; 436 /* 437 * if precision required or alternate flag set, add in a 438 * decimal point. 439 */ 440 if (prec || flags&ALT) 441 *t++ = '.'; 442 /* if requires more precision and some fraction left */ 443 if (fract) { 444 if (prec) 445 do { 446 fract = modf(fract * 10, &tmp); 447 *t++ = tochar((int)tmp); 448 } while (--prec && fract); 449 if (fract) 450 startp = round(fract, (int *)NULL, startp, 451 t - 1, (char)0, signp); 452 } 453 for (; prec--; *t++ = '0'); 454 break; 455 case 'e': 456 case 'E': 457 eformat: if (expcnt) { 458 *t++ = *++p; 459 if (prec || flags&ALT) 460 *t++ = '.'; 461 /* if requires more precision and some integer left */ 462 for (; prec && ++p < endp; --prec) 463 *t++ = *p; 464 /* 465 * if done precision and more of the integer component, 466 * round using it; adjust fract so we don't re-round 467 * later. 468 */ 469 if (!prec && ++p < endp) { 470 fract = 0; 471 startp = round((double)0, &expcnt, startp, 472 t - 1, *p, signp); 473 } 474 /* adjust expcnt for digit in front of decimal */ 475 --expcnt; 476 } 477 /* until first fractional digit, decrement exponent */ 478 else if (fract) { 479 /* adjust expcnt for digit in front of decimal */ 480 for (expcnt = -1;; --expcnt) { 481 fract = modf(fract * 10, &tmp); 482 if (tmp) 483 break; 484 } 485 *t++ = tochar((int)tmp); 486 if (prec || flags&ALT) 487 *t++ = '.'; 488 } 489 else { 490 *t++ = '0'; 491 if (prec || flags&ALT) 492 *t++ = '.'; 493 } 494 /* if requires more precision and some fraction left */ 495 if (fract) { 496 if (prec) 497 do { 498 fract = modf(fract * 10, &tmp); 499 *t++ = tochar((int)tmp); 500 } while (--prec && fract); 501 if (fract) 502 startp = round(fract, &expcnt, startp, 503 t - 1, (char)0, signp); 504 } 505 /* if requires more precision */ 506 for (; prec--; *t++ = '0'); 507 508 /* unless alternate flag, trim any g/G format trailing 0's */ 509 if (gformat && !(flags&ALT)) { 510 while (t > startp && *--t == '0'); 511 if (*t == '.') 512 --t; 513 ++t; 514 } 515 t = exponent(t, expcnt, fmtch); 516 break; 517 case 'g': 518 case 'G': 519 /* a precision of 0 is treated as a precision of 1. */ 520 if (!prec) 521 ++prec; 522 /* 523 * ``The style used depends on the value converted; style e 524 * will be used only if the exponent resulting from the 525 * conversion is less than -4 or greater than the precision.'' 526 * -- ANSI X3J11 527 */ 528 if (expcnt > prec || !expcnt && fract && fract < .0001) { 529 /* 530 * g/G format counts "significant digits, not digits of 531 * precision; for the e/E format, this just causes an 532 * off-by-one problem, i.e. g/G considers the digit 533 * before the decimal point significant and e/E doesn't 534 * count it as precision. 535 */ 536 --prec; 537 fmtch -= 2; /* G->E, g->e */ 538 gformat = 1; 539 goto eformat; 540 } 541 /* 542 * reverse integer into beginning of buffer, 543 * note, decrement precision 544 */ 545 if (expcnt) 546 for (; ++p < endp; *t++ = *p, --prec); 547 else 548 *t++ = '0'; 549 /* 550 * if precision required or alternate flag set, add in a 551 * decimal point. If no digits yet, add in leading 0. 552 */ 553 if (prec || flags&ALT) { 554 dotrim = 1; 555 *t++ = '.'; 556 } 557 else 558 dotrim = 0; 559 /* if requires more precision and some fraction left */ 560 if (fract) { 561 if (prec) { 562 do { 563 fract = modf(fract * 10, &tmp); 564 *t++ = tochar((int)tmp); 565 } while(!tmp); 566 while (--prec && fract) { 567 fract = modf(fract * 10, &tmp); 568 *t++ = tochar((int)tmp); 569 } 570 } 571 if (fract) 572 startp = round(fract, (int *)NULL, startp, 573 t - 1, (char)0, signp); 574 } 575 /* alternate format, adds 0's for precision, else trim 0's */ 576 if (flags&ALT) 577 for (; prec--; *t++ = '0'); 578 else if (dotrim) { 579 while (t > startp && *--t == '0'); 580 if (*t != '.') 581 ++t; 582 } 583 } 584 return(t - startp); 585 } 586 587 static char * 588 round(fract, exp, start, end, ch, signp) 589 double fract; 590 int *exp; 591 register char *start, *end; 592 char ch, *signp; 593 { 594 double tmp; 595 596 if (fract) 597 (void)modf(fract * 10, &tmp); 598 else 599 tmp = todigit(ch); 600 if (tmp > 4) 601 for (;; --end) { 602 if (*end == '.') 603 --end; 604 if (++*end <= '9') 605 break; 606 *end = '0'; 607 if (end == start) { 608 if (exp) { /* e/E; increment exponent */ 609 *end = '1'; 610 ++*exp; 611 } 612 else { /* f; add extra digit */ 613 *--end = '1'; 614 --start; 615 } 616 break; 617 } 618 } 619 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ 620 else if (*signp == '-') 621 for (;; --end) { 622 if (*end == '.') 623 --end; 624 if (*end != '0') 625 break; 626 if (end == start) 627 *signp = 0; 628 } 629 return(start); 630 } 631 632 static char * 633 exponent(p, exp, fmtch) 634 register char *p; 635 register int exp; 636 u_char fmtch; 637 { 638 register char *t; 639 char expbuf[MAXEXP]; 640 641 *p++ = fmtch; 642 if (exp < 0) { 643 exp = -exp; 644 *p++ = '-'; 645 } 646 else 647 *p++ = '+'; 648 t = expbuf + MAXEXP; 649 if (exp > 9) { 650 do { 651 *--t = tochar(exp % 10); 652 } while ((exp /= 10) > 9); 653 *--t = tochar(exp); 654 for (; t < expbuf + MAXEXP; *p++ = *t++); 655 } 656 else { 657 *p++ = '0'; 658 *p++ = tochar(exp); 659 } 660 return(p); 661 } 662 663 #ifdef hp300 664 isspecial(d, bufp, signp) 665 double d; 666 char *bufp, *signp; 667 { 668 register struct IEEEdp { 669 unsigned sign:1; 670 unsigned exp:11; 671 unsigned manh:20; 672 unsigned manl:32; 673 } *ip = (struct IEEEdp *)&d; 674 675 if (ip->exp != 0x7ff) 676 return(0); 677 if (ip->manh || ip->manl) 678 (void)strcpy(bufp, "NaN"); 679 else 680 (void)strcpy(bufp, "Inf"); 681 return(3); 682 } 683 #endif 684