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