134226Sbostic /* 234233Sbostic * Copyright (c) 1988 Regents of the University of California. 334233Sbostic * All rights reserved. 434226Sbostic * 534233Sbostic * Redistribution and use in source and binary forms are permitted 634233Sbostic * provided that this notice is preserved and that due credit is given 734233Sbostic * to the University of California at Berkeley. The name of the University 834233Sbostic * may not be used to endorse or promote products derived from this 934233Sbostic * software without specific prior written permission. This software 1034233Sbostic * is provided ``as is'' without express or implied warranty. 1134226Sbostic */ 1234226Sbostic 1334233Sbostic #if defined(LIBC_SCCS) && !defined(lint) 14*34624Sbostic static char sccsid[] = "@(#)vfprintf.c 5.32 (Berkeley) 06/03/88"; 1534233Sbostic #endif /* LIBC_SCCS and not lint */ 1634233Sbostic 1734261Sbostic #include <sys/types.h> 1834233Sbostic #include <varargs.h> 1934226Sbostic #include <stdio.h> 2034233Sbostic #include <ctype.h> 2134226Sbostic 2234328Sbostic /* 11-bit exponent (VAX G floating point) is 308 decimal digits */ 2334328Sbostic #define MAXEXP 308 2434328Sbostic /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ 2534328Sbostic #define MAXFRACT 39 2634226Sbostic 27*34624Sbostic #define DEFPREC 6 28*34624Sbostic 2934328Sbostic #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 3034328Sbostic 3134427Sbostic #define PUTC(ch) (void) putc(ch, fp) 3234236Sbostic 3334318Sbostic #define ARG() \ 3434318Sbostic _ulong = flags&LONGINT ? va_arg(argp, long) : \ 3534318Sbostic flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 3634235Sbostic 3734331Sbostic #define todigit(c) ((c) - '0') 3834331Sbostic #define tochar(n) ((n) + '0') 3934331Sbostic 4034318Sbostic /* have to deal with the negative buffer count kludge */ 4134318Sbostic #define NEGATIVE_COUNT_KLUDGE 4234318Sbostic 4334318Sbostic #define LONGINT 0x01 /* long integer */ 4434318Sbostic #define LONGDBL 0x02 /* long double; unimplemented */ 4534318Sbostic #define SHORTINT 0x04 /* short integer */ 4634318Sbostic #define ALT 0x08 /* alternate form */ 4734318Sbostic #define LADJUST 0x10 /* left adjustment */ 4834427Sbostic #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ 4934427Sbostic #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ 5034318Sbostic 5134323Sbostic _doprnt(fmt0, argp, fp) 5234323Sbostic u_char *fmt0; 5334233Sbostic va_list argp; 5434235Sbostic register FILE *fp; 5534226Sbostic { 5634427Sbostic register u_char *fmt; /* format string */ 5734427Sbostic register int ch; /* character from fmt */ 5834427Sbostic register int cnt; /* return value accumulator */ 5934427Sbostic register int n; /* random handy integer */ 6034427Sbostic register char *t; /* buffer pointer */ 6134427Sbostic double _double; /* double precision arguments %[eEfgG] */ 6234427Sbostic u_long _ulong; /* integer arguments %[diouxX] */ 63*34624Sbostic int base; /* base for [diouxX] conversion */ 64*34624Sbostic int dprec; /* decimal precision in [diouxX] */ 65*34624Sbostic int fieldsz; /* field size expanded by sign, etc */ 6634427Sbostic int flags; /* flags as above */ 6734427Sbostic int fpprec; /* `extra' floating precision in [eEfgG] */ 6834427Sbostic int prec; /* precision from format (%.3d), or -1 */ 69*34624Sbostic int realsz; /* field size expanded by decimal precision */ 7034427Sbostic int size; /* size of converted field or string */ 71*34624Sbostic int width; /* width from format (%8d), or 0 */ 7234427Sbostic char sign; /* sign prefix (+ - or \0) */ 7334427Sbostic char *digs; /* digits for [diouxX] conversion */ 7434427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 7534226Sbostic 7634428Sbostic if (fp->_flag & _IORW) { 7734428Sbostic fp->_flag |= _IOWRT; 7834428Sbostic fp->_flag &= ~(_IOEOF|_IOREAD); 7934428Sbostic } 8034428Sbostic if ((fp->_flag & _IOWRT) == 0) 8134428Sbostic return (EOF); 8234428Sbostic 8334323Sbostic fmt = fmt0; 8434243Sbostic digs = "0123456789abcdef"; 8534322Sbostic for (cnt = 0;; ++fmt) { 8634318Sbostic n = fp->_cnt; 8734427Sbostic for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; 8834427Sbostic ++cnt, ++fmt) 8934318Sbostic if (--n < 0 9034318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE 9134318Sbostic && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 9234318Sbostic #endif 9334427Sbostic || ch == '\n' && fp->_flag & _IOLBF) { 9434318Sbostic fp->_cnt = n; 9534475Sbostic fp->_ptr = t; 9634427Sbostic (void) _flsbuf((u_char)ch, fp); 9734318Sbostic n = fp->_cnt; 9834427Sbostic t = (char *)fp->_ptr; 9934427Sbostic } else 10034314Sbostic *t++ = ch; 10134318Sbostic fp->_cnt = n; 10234475Sbostic fp->_ptr = t; 10334318Sbostic if (!ch) 10434427Sbostic return (cnt); 10534314Sbostic 10634427Sbostic flags = dprec = fpprec = width = 0; 10734233Sbostic prec = -1; 10834318Sbostic sign = '\0'; 10934226Sbostic 11034318Sbostic rflag: switch (*++fmt) { 11134318Sbostic case ' ': 11234318Sbostic sign = ' '; 11334318Sbostic goto rflag; 11434233Sbostic case '#': 11534318Sbostic flags |= ALT; 11634318Sbostic goto rflag; 11734233Sbostic case '*': 11834235Sbostic /* 11934235Sbostic * ``A negative field width argument is taken as a 12034235Sbostic * - flag followed by a positive field width.'' 12134235Sbostic * -- ANSI X3J11 12234235Sbostic * They don't exclude field widths read from args. 12334235Sbostic */ 12434235Sbostic if ((width = va_arg(argp, int)) >= 0) 12534318Sbostic goto rflag; 12634235Sbostic width = -width; 12734427Sbostic /* FALLTHROUGH */ 12834235Sbostic case '-': 12934318Sbostic flags |= LADJUST; 13034318Sbostic goto rflag; 13134233Sbostic case '+': 13234314Sbostic sign = '+'; 13334318Sbostic goto rflag; 13434233Sbostic case '.': 13534235Sbostic if (*++fmt == '*') 13634318Sbostic n = va_arg(argp, int); 13734427Sbostic else { 13834318Sbostic n = 0; 13934427Sbostic while (isascii(*fmt) && isdigit(*fmt)) 14034427Sbostic n = 10 * n + todigit(*fmt++); 14134233Sbostic --fmt; 14234226Sbostic } 14334318Sbostic prec = n < 0 ? -1 : n; 14434318Sbostic goto rflag; 14534233Sbostic case '0': 14634427Sbostic /* 14734427Sbostic * ``Note that 0 is taken as a flag, not as the 14834427Sbostic * beginning of a field width.'' 14934427Sbostic * -- ANSI X3J11 15034427Sbostic */ 15134427Sbostic flags |= ZEROPAD; 15234427Sbostic goto rflag; 15334233Sbostic case '1': case '2': case '3': case '4': 15434233Sbostic case '5': case '6': case '7': case '8': case '9': 15534318Sbostic n = 0; 15634233Sbostic do { 15734331Sbostic n = 10 * n + todigit(*fmt); 15834318Sbostic } while (isascii(*++fmt) && isdigit(*fmt)); 15934318Sbostic width = n; 16034233Sbostic --fmt; 16134319Sbostic goto rflag; 16234235Sbostic case 'L': 16334329Sbostic flags |= LONGDBL; 16434318Sbostic goto rflag; 16534235Sbostic case 'h': 16634318Sbostic flags |= SHORTINT; 16734318Sbostic goto rflag; 16834233Sbostic case 'l': 16934318Sbostic flags |= LONGINT; 17034318Sbostic goto rflag; 17134314Sbostic case 'c': 17234427Sbostic *(t = buf) = va_arg(argp, int); 17334314Sbostic size = 1; 17434427Sbostic sign = '\0'; 17534314Sbostic goto pforw; 176*34624Sbostic case 'D': 177*34624Sbostic flags |= LONGINT; 178*34624Sbostic /*FALLTHROUGH*/ 17934314Sbostic case 'd': 18034318Sbostic case 'i': 18134318Sbostic ARG(); 18234318Sbostic if ((long)_ulong < 0) { 18334318Sbostic _ulong = -_ulong; 18434314Sbostic sign = '-'; 18534241Sbostic } 18634241Sbostic base = 10; 18734327Sbostic goto number; 18834261Sbostic case 'e': 18934236Sbostic case 'E': 19034235Sbostic case 'f': 19134261Sbostic case 'g': 19234243Sbostic case 'G': 19334243Sbostic _double = va_arg(argp, double); 19434328Sbostic /* 19534328Sbostic * don't bother to do unrealistic precision; just 19634328Sbostic * pad it with zeroes later. This keeps buffer size 19734328Sbostic * rational. 19834328Sbostic */ 19934328Sbostic if (prec > MAXFRACT) { 20034475Sbostic if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) 20134475Sbostic fpprec = prec - MAXFRACT; 20234328Sbostic prec = MAXFRACT; 20334328Sbostic } 204*34624Sbostic else if (prec == -1) 205*34624Sbostic prec = DEFPREC; 206*34624Sbostic if (_double < 0) { 207*34624Sbostic sign = '-'; 208*34624Sbostic _double = -_double; 209*34624Sbostic } 210*34624Sbostic /* 211*34624Sbostic * _cvt may have to round up past the "start" of the 212*34624Sbostic * buffer, i.e. ``intf("%.2f", (double)9.999);''; 213*34624Sbostic * if the first char isn't NULL, it did. 214*34624Sbostic */ 215*34624Sbostic *buf = NULL; 216*34624Sbostic size = _cvt(_double, prec, flags, *fmt, buf, 217*34624Sbostic buf + sizeof(buf)); 218*34624Sbostic t = *buf ? buf : buf + 1; 21934314Sbostic goto pforw; 22034235Sbostic case 'n': 22134427Sbostic if (flags & LONGINT) 22234318Sbostic *va_arg(argp, long *) = cnt; 22334427Sbostic else if (flags & SHORTINT) 22434318Sbostic *va_arg(argp, short *) = cnt; 22534318Sbostic else 22634318Sbostic *va_arg(argp, int *) = cnt; 22734235Sbostic break; 228*34624Sbostic case 'O': 229*34624Sbostic flags |= LONGINT; 230*34624Sbostic /*FALLTHROUGH*/ 23134226Sbostic case 'o': 23234318Sbostic ARG(); 23334226Sbostic base = 8; 23434327Sbostic goto nosign; 23534235Sbostic case 'p': 23634320Sbostic /* 23734321Sbostic * ``The argument shall be a pointer to void. The 23834321Sbostic * value of the pointer is converted to a sequence 23934321Sbostic * of printable characters, in an implementation- 24034321Sbostic * defined manner.'' 24134321Sbostic * -- ANSI X3J11 24234320Sbostic */ 24334427Sbostic /* NOSTRICT */ 24434320Sbostic _ulong = (u_long)va_arg(argp, void *); 24534320Sbostic base = 16; 24634327Sbostic goto nosign; 24734226Sbostic case 's': 24834314Sbostic if (!(t = va_arg(argp, char *))) 24934314Sbostic t = "(null)"; 25034321Sbostic if (prec >= 0) { 25134321Sbostic /* 25234321Sbostic * can't use strlen; can only look for the 25334321Sbostic * NUL in the first `prec' characters, and 25434321Sbostic * strlen() will go further. 25534321Sbostic */ 25634321Sbostic char *p, *memchr(); 25734321Sbostic 25834321Sbostic if (p = memchr(t, 0, prec)) { 25934321Sbostic size = p - t; 26034321Sbostic if (size > prec) 26134321Sbostic size = prec; 26234427Sbostic } else 26334321Sbostic size = prec; 26434427Sbostic } else 26534321Sbostic size = strlen(t); 26634427Sbostic sign = '\0'; 26734328Sbostic goto pforw; 268*34624Sbostic case 'U': 269*34624Sbostic flags |= LONGINT; 270*34624Sbostic /*FALLTHROUGH*/ 27134226Sbostic case 'u': 27234318Sbostic ARG(); 27334226Sbostic base = 10; 27434327Sbostic goto nosign; 27534226Sbostic case 'X': 27634226Sbostic digs = "0123456789ABCDEF"; 27734427Sbostic /* FALLTHROUGH */ 27834226Sbostic case 'x': 27934318Sbostic ARG(); 28034314Sbostic base = 16; 28134326Sbostic /* leading 0x/X only if non-zero */ 28234427Sbostic if (flags & ALT && _ulong != 0) 28334427Sbostic flags |= HEXPREFIX; 28434327Sbostic 28534327Sbostic /* unsigned conversions */ 28634427Sbostic nosign: sign = '\0'; 28734326Sbostic /* 28834330Sbostic * ``... diouXx conversions ... if a precision is 28934330Sbostic * specified, the 0 flag will be ignored.'' 29034330Sbostic * -- ANSI X3J11 29134330Sbostic */ 29234427Sbostic number: if ((dprec = prec) >= 0) 29334427Sbostic flags &= ~ZEROPAD; 29434427Sbostic 29534330Sbostic /* 29634326Sbostic * ``The result of converting a zero value with an 29734326Sbostic * explicit precision of zero is no characters.'' 29834326Sbostic * -- ANSI X3J11 29934326Sbostic */ 30034427Sbostic t = buf + BUF; 30134427Sbostic if (_ulong != 0 || prec != 0) { 30234427Sbostic do { 30334427Sbostic *--t = digs[_ulong % base]; 30434427Sbostic _ulong /= base; 30534427Sbostic } while (_ulong); 30634427Sbostic digs = "0123456789abcdef"; 30734427Sbostic if (flags & ALT && base == 8 && *t != '0') 30834427Sbostic *--t = '0'; /* octal leading 0 */ 30934330Sbostic } 31034427Sbostic size = buf + BUF - t; 31134327Sbostic 31234427Sbostic pforw: 31334427Sbostic /* 314*34624Sbostic * All reasonable formats wind up here. At this point, 315*34624Sbostic * `t' points to a string which (if not flags&LADJUST) 316*34624Sbostic * should be padded out to `width' places. If 317*34624Sbostic * flags&ZEROPAD, it should first be prefixed by any 318*34624Sbostic * sign or other prefix; otherwise, it should be blank 319*34624Sbostic * padded before the prefix is emitted. After any 320*34624Sbostic * left-hand padding and prefixing, emit zeroes 321*34624Sbostic * required by a decimal [diouxX] precision, then print 322*34624Sbostic * the string proper, then emit zeroes required by any 323*34624Sbostic * leftover floating precision; finally, if LADJUST, 324*34624Sbostic * pad with blanks. 32534427Sbostic */ 32634327Sbostic 327*34624Sbostic /* 328*34624Sbostic * compute actual size, so we know how much to pad 329*34624Sbostic * fieldsz excludes decimal prec; realsz includes it 330*34624Sbostic */ 33134427Sbostic fieldsz = size + fpprec; 33234427Sbostic if (sign) 33334427Sbostic fieldsz++; 33434427Sbostic if (flags & HEXPREFIX) 33534427Sbostic fieldsz += 2; 33634427Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 33734327Sbostic 33834427Sbostic /* right-adjusting blank padding */ 33934427Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0 && width) 34034427Sbostic for (n = realsz; n < width; n++) 34134427Sbostic PUTC(' '); 34234427Sbostic /* prefix */ 34334427Sbostic if (sign) 34434427Sbostic PUTC(sign); 34534427Sbostic if (flags & HEXPREFIX) { 34634427Sbostic PUTC('0'); 34734427Sbostic PUTC((char)*fmt); 34834327Sbostic } 34934427Sbostic /* right-adjusting zero padding */ 35034427Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 35134427Sbostic for (n = realsz; n < width; n++) 35234427Sbostic PUTC('0'); 35334427Sbostic /* leading zeroes from decimal precision */ 35434427Sbostic for (n = fieldsz; n < dprec; n++) 35534427Sbostic PUTC('0'); 35634327Sbostic 35734427Sbostic /* the string or number proper */ 35834427Sbostic if (fp->_cnt - (n = size) >= 0 && 35934427Sbostic (fp->_flag & _IOLBF) == 0) { 36034328Sbostic fp->_cnt -= n; 36134427Sbostic bcopy(t, (char *)fp->_ptr, n); 36234328Sbostic fp->_ptr += n; 36334427Sbostic } else 36434427Sbostic while (--n >= 0) 36534427Sbostic PUTC(*t++); 36634427Sbostic /* trailing f.p. zeroes */ 36734427Sbostic while (--fpprec >= 0) 36834328Sbostic PUTC('0'); 36934427Sbostic /* left-adjusting padding (always blank) */ 37034427Sbostic if (flags & LADJUST) 37134427Sbostic for (n = realsz; n < width; n++) 37234328Sbostic PUTC(' '); 37334427Sbostic /* finally, adjust cnt */ 37434427Sbostic cnt += width > realsz ? width : realsz; 37534226Sbostic break; 37634427Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 37734427Sbostic return (cnt); 37834226Sbostic default: 37934427Sbostic PUTC((char)*fmt); 38034427Sbostic cnt++; 38134226Sbostic } 38234226Sbostic } 38334427Sbostic /* NOTREACHED */ 38434226Sbostic } 38534242Sbostic 386*34624Sbostic static 387*34624Sbostic _cvt(number, prec, flags, fmtch, startp, endp) 38834242Sbostic double number; 38934261Sbostic register int prec; 39034323Sbostic int flags; 39134323Sbostic u_char fmtch; 392*34624Sbostic char *startp, *endp; 39334242Sbostic { 39434331Sbostic register char *p, *t; 39534248Sbostic double fract, integer, tmp, modf(); 396*34624Sbostic int dotrim, expcnt, gformat; 397*34624Sbostic char *exponent(), *eround(), *fround(); 39834242Sbostic 399*34624Sbostic dotrim = expcnt = gformat = 0; 400*34624Sbostic fract = modf(number, &integer); 40134242Sbostic 402*34624Sbostic /* get an extra slot for rounding. */ 403*34624Sbostic t = ++startp; 404*34624Sbostic 405*34624Sbostic /* 406*34624Sbostic * get integer portion of number; put into the end of the buffer; the 407*34624Sbostic * .01 is added for modf(356.0 / 10, &integer) returning .59999999... 408*34624Sbostic */ 409*34624Sbostic for (p = endp - 1; integer; ++expcnt) { 410*34624Sbostic tmp = modf(integer / 10, &integer); 411*34624Sbostic *p-- = tochar((int)((tmp + .01) * 10)); 41234248Sbostic } 41334261Sbostic switch(fmtch) { 41434261Sbostic case 'f': 415*34624Sbostic /* reverse integer into beginning of buffer */ 416*34624Sbostic if (expcnt) 417*34624Sbostic for (; ++p < endp; *t++ = *p); 418*34624Sbostic else 419*34624Sbostic *t++ = '0'; 42034248Sbostic /* 421*34624Sbostic * if precision required or alternate flag set, add in a 422*34624Sbostic * decimal point. 42334248Sbostic */ 424*34624Sbostic if (prec || flags&ALT) 425*34624Sbostic *t++ = '.'; 426*34624Sbostic /* if requires more precision and some fraction left */ 427*34624Sbostic if (fract) { 428*34624Sbostic if (prec) 429*34624Sbostic do { 430*34624Sbostic fract = modf(fract * 10, &tmp); 431*34624Sbostic *t++ = tochar((int)tmp); 432*34624Sbostic } while (--prec && fract); 433*34624Sbostic if (fract) 434*34624Sbostic startp = fround(startp, t - 1, fract); 435*34624Sbostic } 436*34624Sbostic for (; prec--; *t++ = '0'); 437*34624Sbostic break; 438*34624Sbostic case 'e': 439*34624Sbostic case 'E': 440*34624Sbostic eformat: if (expcnt) { 441*34624Sbostic *t++ = *++p; 442*34624Sbostic if (prec || flags&ALT) 44334331Sbostic *t++ = '.'; 444*34624Sbostic /* if requires more precision and some integer left */ 445*34624Sbostic for (; prec && ++p < endp; --prec) 446*34624Sbostic *t++ = *p; 447*34624Sbostic /* 448*34624Sbostic * if done precision and more of the integer component, 449*34624Sbostic * round using it; adjust fract so we don't re-round 450*34624Sbostic * later. 451*34624Sbostic */ 452*34624Sbostic if (!prec && ++p < endp) { 453*34624Sbostic startp = eround(startp, t - 1, (double)0, 454*34624Sbostic *p, &expcnt); 45534248Sbostic fract = 0; 45634248Sbostic } 457*34624Sbostic /* adjust expcnt for digit in front of decimal */ 458*34624Sbostic --expcnt; 45934242Sbostic } 460*34624Sbostic /* until first fractional digit, decrement exponent */ 461*34624Sbostic else if (fract) { 462*34624Sbostic /* adjust expcnt for digit in front of decimal */ 463*34624Sbostic for (expcnt = -1;; --expcnt) { 464*34624Sbostic fract = modf(fract * 10, &tmp); 465*34624Sbostic if (tmp) 466*34624Sbostic break; 46734248Sbostic } 468*34624Sbostic *t++ = tochar((int)tmp); 469*34624Sbostic if (prec || flags&ALT) 47034331Sbostic *t++ = '.'; 47134242Sbostic } 47234248Sbostic else { 473*34624Sbostic *t++ = '0'; 474*34624Sbostic if (prec || flags&ALT) 47534331Sbostic *t++ = '.'; 47634248Sbostic } 477*34624Sbostic /* if requires more precision and some fraction left */ 478*34624Sbostic if (fract) { 479*34624Sbostic if (prec) 480*34624Sbostic do { 481*34624Sbostic fract = modf(fract * 10, &tmp); 482*34624Sbostic *t++ = tochar((int)tmp); 483*34624Sbostic } while (--prec && fract); 484*34624Sbostic if (fract) 485*34624Sbostic startp = eround(startp, t - 1, fract, 486*34624Sbostic (char)0, &expcnt); 48734584Sbostic } 488*34624Sbostic /* if requires more precision */ 489*34624Sbostic for (; prec--; *t++ = '0'); 490*34624Sbostic 491*34624Sbostic /* unless alternate flag, trim any g/G format trailing 0's */ 492*34624Sbostic if (gformat && !(flags&ALT)) { 493*34624Sbostic while (t > startp && *--t == '0'); 494*34624Sbostic if (*t == '.') 495*34624Sbostic --t; 496*34624Sbostic ++t; 497*34624Sbostic } 498*34624Sbostic t = exponent(t, expcnt, fmtch); 499*34624Sbostic break; 500*34624Sbostic case 'g': 501*34624Sbostic case 'G': 502*34624Sbostic /* a precision of 0 is treated as a precision of 1. */ 503*34624Sbostic if (!prec) 504*34624Sbostic ++prec; 505*34624Sbostic /* 506*34624Sbostic * ``The style used depends on the value converted; style e 507*34624Sbostic * will be used only if the exponent resulting from the 508*34624Sbostic * conversion is less than -4 or greater than the precision.'' 509*34624Sbostic * -- ANSI X3J11 510*34624Sbostic */ 511*34624Sbostic if (expcnt > prec || !expcnt && fract && fract < .0001) { 512*34624Sbostic /* 513*34624Sbostic * g/G format counts "significant digits, not digits of 514*34624Sbostic * precision; for the e/E format, this just causes an 515*34624Sbostic * off-by-one problem, i.e. g/G considers the digit 516*34624Sbostic * before the decimal point significant and e/E doesn't 517*34624Sbostic * count it as precision. 518*34624Sbostic */ 519*34624Sbostic --prec; 520*34624Sbostic fmtch -= 2; /* G->E, g->e */ 521*34624Sbostic gformat = 1; 522*34624Sbostic goto eformat; 523*34624Sbostic } 524*34624Sbostic /* 525*34624Sbostic * reverse integer into beginning of buffer, 526*34624Sbostic * note, decrement precision 527*34624Sbostic */ 528*34624Sbostic if (expcnt) 529*34624Sbostic for (; ++p < endp; *t++ = *p, --prec); 530*34624Sbostic else 531*34624Sbostic *t++ = '0'; 532*34624Sbostic /* 533*34624Sbostic * if precision required or alternate flag set, add in a 534*34624Sbostic * decimal point. If no digits yet, add in leading 0. 535*34624Sbostic */ 536*34624Sbostic if (prec || flags&ALT) { 537*34624Sbostic dotrim = 1; 538*34624Sbostic *t++ = '.'; 539*34624Sbostic } 540*34624Sbostic else 541*34624Sbostic dotrim = 0; 542*34624Sbostic /* if requires more precision and some fraction left */ 543*34624Sbostic if (fract) { 544*34624Sbostic if (prec) { 545*34624Sbostic do { 546*34624Sbostic fract = modf(fract * 10, &tmp); 547*34624Sbostic *t++ = tochar((int)tmp); 548*34624Sbostic } while(!tmp); 549*34624Sbostic while (--prec && fract) { 550*34624Sbostic fract = modf(fract * 10, &tmp); 551*34624Sbostic *t++ = tochar((int)tmp); 55234248Sbostic } 55334248Sbostic } 554*34624Sbostic if (fract) 555*34624Sbostic startp = fround(startp, t - 1, fract); 556*34624Sbostic } 557*34624Sbostic /* alternate format, adds 0's for precision, else trim 0's */ 558*34624Sbostic if (flags&ALT) 559*34624Sbostic for (; prec--; *t++ = '0'); 560*34624Sbostic else if (dotrim) { 561*34624Sbostic while (t > startp && *--t == '0'); 562*34624Sbostic if (*t != '.') 563*34624Sbostic ++t; 564*34624Sbostic } 565*34624Sbostic } 566*34624Sbostic return(t - startp); 567*34624Sbostic } 56834248Sbostic 569*34624Sbostic static char * 570*34624Sbostic fround(start, end, fract) 571*34624Sbostic register char *start, *end; 572*34624Sbostic double fract; 573*34624Sbostic { 574*34624Sbostic double tmp; 57534248Sbostic 576*34624Sbostic (void)modf(fract * 10, &tmp); 577*34624Sbostic if (tmp > 4) 578*34624Sbostic for (;; --end) { 579*34624Sbostic if (*end == '.') 580*34624Sbostic --end; 581*34624Sbostic if (++*end <= '9') 582*34624Sbostic break; 583*34624Sbostic *end = '0'; 584*34624Sbostic /* add extra digit to round past buffer beginning */ 585*34624Sbostic if (end == start) { 586*34624Sbostic *--end = '1'; 587*34624Sbostic --start; 588*34624Sbostic break; 589*34624Sbostic } 590*34624Sbostic } 591*34624Sbostic return(start); 592*34624Sbostic } 59334248Sbostic 594*34624Sbostic static char * 595*34624Sbostic eround(start, end, fract, ch, exp) 596*34624Sbostic register char *start, *end; 597*34624Sbostic double fract; 598*34624Sbostic char ch; 599*34624Sbostic int *exp; 600*34624Sbostic { 601*34624Sbostic double tmp; 60234248Sbostic 603*34624Sbostic if (fract) 60434248Sbostic (void)modf(fract * 10, &tmp); 605*34624Sbostic else 606*34624Sbostic tmp = todigit(ch); 607*34624Sbostic if (tmp > 4) 608*34624Sbostic for (;; --end) { 609*34624Sbostic if (*end == '.') 610*34624Sbostic --end; 611*34624Sbostic if (++*end <= '9') 612*34624Sbostic break; 613*34624Sbostic *end = '0'; 614*34624Sbostic /* increment exponent to round past buffer beginning */ 615*34624Sbostic if (end == start) { 616*34624Sbostic *end = '1'; 617*34624Sbostic ++*exp; 618*34624Sbostic break; 61934242Sbostic } 62034242Sbostic } 621*34624Sbostic return(start); 622*34624Sbostic } 62334248Sbostic 624*34624Sbostic static char * 625*34624Sbostic exponent(p, exp, fmtch) 626*34624Sbostic register char *p; 627*34624Sbostic register int exp; 628*34624Sbostic u_char fmtch; 629*34624Sbostic { 630*34624Sbostic register char *t; 631*34624Sbostic char expbuf[MAXEXP]; 63234248Sbostic 633*34624Sbostic *p++ = fmtch; 634*34624Sbostic if (exp < 0) { 635*34624Sbostic exp = -exp; 636*34624Sbostic *p++ = '-'; 63734242Sbostic } 638*34624Sbostic else 639*34624Sbostic *p++ = '+'; 640*34624Sbostic t = expbuf + MAXEXP; 641*34624Sbostic if (exp > 9) { 642*34624Sbostic do { 643*34624Sbostic *--t = tochar(exp % 10); 644*34624Sbostic } while ((exp /= 10) > 9); 645*34624Sbostic *--t = tochar(exp); 646*34624Sbostic for (; t < expbuf + MAXEXP; *p++ = *t++); 647*34624Sbostic } 648*34624Sbostic else { 649*34624Sbostic *p++ = '0'; 650*34624Sbostic *p++ = tochar(exp); 651*34624Sbostic } 65234323Sbostic return(p); 65334242Sbostic } 654