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