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*34669Sbostic static char sccsid[] = "@(#)vfprintf.c 5.33 (Berkeley) 06/07/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 2734624Sbostic #define DEFPREC 6 2834624Sbostic 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] */ 6334624Sbostic int base; /* base for [diouxX] conversion */ 6434624Sbostic int dprec; /* decimal precision in [diouxX] */ 6534624Sbostic 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 */ 6934624Sbostic int realsz; /* field size expanded by decimal precision */ 7034427Sbostic int size; /* size of converted field or string */ 7134624Sbostic int width; /* width from format (%8d), or 0 */ 72*34669Sbostic char sign; /* sign prefix (' ', '+', '-', or \0) */ 73*34669Sbostic char softsign; /* temporary negative sign for floats */ 7434427Sbostic char *digs; /* digits for [diouxX] conversion */ 7534427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 7634226Sbostic 7734428Sbostic if (fp->_flag & _IORW) { 7834428Sbostic fp->_flag |= _IOWRT; 7934428Sbostic fp->_flag &= ~(_IOEOF|_IOREAD); 8034428Sbostic } 8134428Sbostic if ((fp->_flag & _IOWRT) == 0) 8234428Sbostic return (EOF); 8334428Sbostic 8434323Sbostic fmt = fmt0; 8534243Sbostic digs = "0123456789abcdef"; 8634322Sbostic for (cnt = 0;; ++fmt) { 8734318Sbostic n = fp->_cnt; 8834427Sbostic for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; 8934427Sbostic ++cnt, ++fmt) 9034318Sbostic if (--n < 0 9134318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE 9234318Sbostic && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 9334318Sbostic #endif 9434427Sbostic || ch == '\n' && fp->_flag & _IOLBF) { 9534318Sbostic fp->_cnt = n; 9634475Sbostic fp->_ptr = t; 9734427Sbostic (void) _flsbuf((u_char)ch, fp); 9834318Sbostic n = fp->_cnt; 9934427Sbostic t = (char *)fp->_ptr; 10034427Sbostic } else 10134314Sbostic *t++ = ch; 10234318Sbostic fp->_cnt = n; 10334475Sbostic fp->_ptr = t; 10434318Sbostic if (!ch) 10534427Sbostic return (cnt); 10634314Sbostic 10734427Sbostic flags = dprec = fpprec = width = 0; 10834233Sbostic prec = -1; 10934318Sbostic sign = '\0'; 11034226Sbostic 11134318Sbostic rflag: switch (*++fmt) { 11234318Sbostic case ' ': 113*34669Sbostic /* 114*34669Sbostic * ``If the space and + flags both appear, the space 115*34669Sbostic * flag will be ignored.'' 116*34669Sbostic * -- ANSI X3J11 117*34669Sbostic */ 118*34669Sbostic if (!sign) 119*34669Sbostic sign = ' '; 12034318Sbostic goto rflag; 12134233Sbostic case '#': 12234318Sbostic flags |= ALT; 12334318Sbostic goto rflag; 12434233Sbostic case '*': 12534235Sbostic /* 12634235Sbostic * ``A negative field width argument is taken as a 12734235Sbostic * - flag followed by a positive field width.'' 12834235Sbostic * -- ANSI X3J11 12934235Sbostic * They don't exclude field widths read from args. 13034235Sbostic */ 13134235Sbostic if ((width = va_arg(argp, int)) >= 0) 13234318Sbostic goto rflag; 13334235Sbostic width = -width; 13434427Sbostic /* FALLTHROUGH */ 13534235Sbostic case '-': 13634318Sbostic flags |= LADJUST; 13734318Sbostic goto rflag; 13834233Sbostic case '+': 13934314Sbostic sign = '+'; 14034318Sbostic goto rflag; 14134233Sbostic case '.': 14234235Sbostic if (*++fmt == '*') 14334318Sbostic n = va_arg(argp, int); 14434427Sbostic else { 14534318Sbostic n = 0; 14634427Sbostic while (isascii(*fmt) && isdigit(*fmt)) 14734427Sbostic n = 10 * n + todigit(*fmt++); 14834233Sbostic --fmt; 14934226Sbostic } 15034318Sbostic prec = n < 0 ? -1 : n; 15134318Sbostic goto rflag; 15234233Sbostic case '0': 15334427Sbostic /* 15434427Sbostic * ``Note that 0 is taken as a flag, not as the 15534427Sbostic * beginning of a field width.'' 15634427Sbostic * -- ANSI X3J11 15734427Sbostic */ 15834427Sbostic flags |= ZEROPAD; 15934427Sbostic goto rflag; 16034233Sbostic case '1': case '2': case '3': case '4': 16134233Sbostic case '5': case '6': case '7': case '8': case '9': 16234318Sbostic n = 0; 16334233Sbostic do { 16434331Sbostic n = 10 * n + todigit(*fmt); 16534318Sbostic } while (isascii(*++fmt) && isdigit(*fmt)); 16634318Sbostic width = n; 16734233Sbostic --fmt; 16834319Sbostic goto rflag; 16934235Sbostic case 'L': 17034329Sbostic flags |= LONGDBL; 17134318Sbostic goto rflag; 17234235Sbostic case 'h': 17334318Sbostic flags |= SHORTINT; 17434318Sbostic goto rflag; 17534233Sbostic case 'l': 17634318Sbostic flags |= LONGINT; 17734318Sbostic goto rflag; 17834314Sbostic case 'c': 17934427Sbostic *(t = buf) = va_arg(argp, int); 18034314Sbostic size = 1; 18134427Sbostic sign = '\0'; 18234314Sbostic goto pforw; 18334624Sbostic case 'D': 18434624Sbostic flags |= LONGINT; 18534624Sbostic /*FALLTHROUGH*/ 18634314Sbostic case 'd': 18734318Sbostic case 'i': 18834318Sbostic ARG(); 18934318Sbostic if ((long)_ulong < 0) { 19034318Sbostic _ulong = -_ulong; 19134314Sbostic sign = '-'; 19234241Sbostic } 19334241Sbostic base = 10; 19434327Sbostic goto number; 19534261Sbostic case 'e': 19634236Sbostic case 'E': 19734235Sbostic case 'f': 19834261Sbostic case 'g': 19934243Sbostic case 'G': 20034243Sbostic _double = va_arg(argp, double); 20134328Sbostic /* 202*34669Sbostic * don't do unrealistic precision; just pad it with 203*34669Sbostic * zeroes later, so buffer size stays rational. 20434328Sbostic */ 20534328Sbostic if (prec > MAXFRACT) { 20634475Sbostic if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) 20734475Sbostic fpprec = prec - MAXFRACT; 20834328Sbostic prec = MAXFRACT; 20934328Sbostic } 21034624Sbostic else if (prec == -1) 21134624Sbostic prec = DEFPREC; 212*34669Sbostic /* 213*34669Sbostic * softsign avoids negative 0 if _double is < 0 and 214*34669Sbostic * no significant digits will be shown 215*34669Sbostic */ 21634624Sbostic if (_double < 0) { 217*34669Sbostic softsign = '-'; 21834624Sbostic _double = -_double; 21934624Sbostic } 220*34669Sbostic else 221*34669Sbostic softsign = 0; 22234624Sbostic /* 223*34669Sbostic * cvt may have to round up past the "start" of the 22434624Sbostic * buffer, i.e. ``intf("%.2f", (double)9.999);''; 22534624Sbostic * if the first char isn't NULL, it did. 22634624Sbostic */ 22734624Sbostic *buf = NULL; 228*34669Sbostic size = cvt(_double, prec, flags, &softsign, *fmt, buf, 22934624Sbostic buf + sizeof(buf)); 230*34669Sbostic if (softsign) 231*34669Sbostic sign = '-'; 23234624Sbostic t = *buf ? buf : buf + 1; 23334314Sbostic goto pforw; 23434235Sbostic case 'n': 23534427Sbostic if (flags & LONGINT) 23634318Sbostic *va_arg(argp, long *) = cnt; 23734427Sbostic else if (flags & SHORTINT) 23834318Sbostic *va_arg(argp, short *) = cnt; 23934318Sbostic else 24034318Sbostic *va_arg(argp, int *) = cnt; 24134235Sbostic break; 24234624Sbostic case 'O': 24334624Sbostic flags |= LONGINT; 24434624Sbostic /*FALLTHROUGH*/ 24534226Sbostic case 'o': 24634318Sbostic ARG(); 24734226Sbostic base = 8; 24834327Sbostic goto nosign; 24934235Sbostic case 'p': 25034320Sbostic /* 25134321Sbostic * ``The argument shall be a pointer to void. The 25234321Sbostic * value of the pointer is converted to a sequence 25334321Sbostic * of printable characters, in an implementation- 25434321Sbostic * defined manner.'' 25534321Sbostic * -- ANSI X3J11 25634320Sbostic */ 25734427Sbostic /* NOSTRICT */ 25834320Sbostic _ulong = (u_long)va_arg(argp, void *); 25934320Sbostic base = 16; 26034327Sbostic goto nosign; 26134226Sbostic case 's': 26234314Sbostic if (!(t = va_arg(argp, char *))) 26334314Sbostic t = "(null)"; 26434321Sbostic if (prec >= 0) { 26534321Sbostic /* 26634321Sbostic * can't use strlen; can only look for the 26734321Sbostic * NUL in the first `prec' characters, and 26834321Sbostic * strlen() will go further. 26934321Sbostic */ 27034321Sbostic char *p, *memchr(); 27134321Sbostic 27234321Sbostic if (p = memchr(t, 0, prec)) { 27334321Sbostic size = p - t; 27434321Sbostic if (size > prec) 27534321Sbostic size = prec; 27634427Sbostic } else 27734321Sbostic size = prec; 27834427Sbostic } else 27934321Sbostic size = strlen(t); 28034427Sbostic sign = '\0'; 28134328Sbostic goto pforw; 28234624Sbostic case 'U': 28334624Sbostic flags |= LONGINT; 28434624Sbostic /*FALLTHROUGH*/ 28534226Sbostic case 'u': 28634318Sbostic ARG(); 28734226Sbostic base = 10; 28834327Sbostic goto nosign; 28934226Sbostic case 'X': 29034226Sbostic digs = "0123456789ABCDEF"; 29134427Sbostic /* FALLTHROUGH */ 29234226Sbostic case 'x': 29334318Sbostic ARG(); 29434314Sbostic base = 16; 29534326Sbostic /* leading 0x/X only if non-zero */ 29634427Sbostic if (flags & ALT && _ulong != 0) 29734427Sbostic flags |= HEXPREFIX; 29834327Sbostic 29934327Sbostic /* unsigned conversions */ 30034427Sbostic nosign: sign = '\0'; 30134326Sbostic /* 30234330Sbostic * ``... diouXx conversions ... if a precision is 30334330Sbostic * specified, the 0 flag will be ignored.'' 30434330Sbostic * -- ANSI X3J11 30534330Sbostic */ 30634427Sbostic number: if ((dprec = prec) >= 0) 30734427Sbostic flags &= ~ZEROPAD; 30834427Sbostic 30934330Sbostic /* 31034326Sbostic * ``The result of converting a zero value with an 31134326Sbostic * explicit precision of zero is no characters.'' 31234326Sbostic * -- ANSI X3J11 31334326Sbostic */ 31434427Sbostic t = buf + BUF; 31534427Sbostic if (_ulong != 0 || prec != 0) { 31634427Sbostic do { 31734427Sbostic *--t = digs[_ulong % base]; 31834427Sbostic _ulong /= base; 31934427Sbostic } while (_ulong); 32034427Sbostic digs = "0123456789abcdef"; 32134427Sbostic if (flags & ALT && base == 8 && *t != '0') 32234427Sbostic *--t = '0'; /* octal leading 0 */ 32334330Sbostic } 32434427Sbostic size = buf + BUF - t; 32534327Sbostic 32634427Sbostic pforw: 32734427Sbostic /* 32834624Sbostic * All reasonable formats wind up here. At this point, 32934624Sbostic * `t' points to a string which (if not flags&LADJUST) 33034624Sbostic * should be padded out to `width' places. If 33134624Sbostic * flags&ZEROPAD, it should first be prefixed by any 33234624Sbostic * sign or other prefix; otherwise, it should be blank 33334624Sbostic * padded before the prefix is emitted. After any 33434624Sbostic * left-hand padding and prefixing, emit zeroes 33534624Sbostic * required by a decimal [diouxX] precision, then print 33634624Sbostic * the string proper, then emit zeroes required by any 33734624Sbostic * leftover floating precision; finally, if LADJUST, 33834624Sbostic * pad with blanks. 33934427Sbostic */ 34034327Sbostic 34134624Sbostic /* 34234624Sbostic * compute actual size, so we know how much to pad 34334624Sbostic * fieldsz excludes decimal prec; realsz includes it 34434624Sbostic */ 34534427Sbostic fieldsz = size + fpprec; 34634427Sbostic if (sign) 34734427Sbostic fieldsz++; 34834427Sbostic if (flags & HEXPREFIX) 34934427Sbostic fieldsz += 2; 35034427Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 35134327Sbostic 35234427Sbostic /* right-adjusting blank padding */ 35334427Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0 && width) 35434427Sbostic for (n = realsz; n < width; n++) 35534427Sbostic PUTC(' '); 35634427Sbostic /* prefix */ 35734427Sbostic if (sign) 35834427Sbostic PUTC(sign); 35934427Sbostic if (flags & HEXPREFIX) { 36034427Sbostic PUTC('0'); 36134427Sbostic PUTC((char)*fmt); 36234327Sbostic } 36334427Sbostic /* right-adjusting zero padding */ 36434427Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 36534427Sbostic for (n = realsz; n < width; n++) 36634427Sbostic PUTC('0'); 36734427Sbostic /* leading zeroes from decimal precision */ 36834427Sbostic for (n = fieldsz; n < dprec; n++) 36934427Sbostic PUTC('0'); 37034327Sbostic 37134427Sbostic /* the string or number proper */ 37234427Sbostic if (fp->_cnt - (n = size) >= 0 && 37334427Sbostic (fp->_flag & _IOLBF) == 0) { 37434328Sbostic fp->_cnt -= n; 37534427Sbostic bcopy(t, (char *)fp->_ptr, n); 37634328Sbostic fp->_ptr += n; 37734427Sbostic } else 37834427Sbostic while (--n >= 0) 37934427Sbostic PUTC(*t++); 38034427Sbostic /* trailing f.p. zeroes */ 38134427Sbostic while (--fpprec >= 0) 38234328Sbostic PUTC('0'); 38334427Sbostic /* left-adjusting padding (always blank) */ 38434427Sbostic if (flags & LADJUST) 38534427Sbostic for (n = realsz; n < width; n++) 38634328Sbostic PUTC(' '); 38734427Sbostic /* finally, adjust cnt */ 38834427Sbostic cnt += width > realsz ? width : realsz; 38934226Sbostic break; 39034427Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 39134427Sbostic return (cnt); 39234226Sbostic default: 39334427Sbostic PUTC((char)*fmt); 39434427Sbostic cnt++; 39534226Sbostic } 39634226Sbostic } 39734427Sbostic /* NOTREACHED */ 39834226Sbostic } 39934242Sbostic 40034624Sbostic static 401*34669Sbostic cvt(number, prec, flags, signp, fmtch, startp, endp) 40234242Sbostic double number; 40334261Sbostic register int prec; 40434323Sbostic int flags; 40534323Sbostic u_char fmtch; 406*34669Sbostic char *signp, *startp, *endp; 40734242Sbostic { 40834331Sbostic register char *p, *t; 40934248Sbostic double fract, integer, tmp, modf(); 41034624Sbostic int dotrim, expcnt, gformat; 411*34669Sbostic char *exponent(), *round(); 41234242Sbostic 41334624Sbostic dotrim = expcnt = gformat = 0; 41434624Sbostic fract = modf(number, &integer); 41534242Sbostic 41634624Sbostic /* get an extra slot for rounding. */ 41734624Sbostic t = ++startp; 41834624Sbostic 41934624Sbostic /* 42034624Sbostic * get integer portion of number; put into the end of the buffer; the 42134624Sbostic * .01 is added for modf(356.0 / 10, &integer) returning .59999999... 42234624Sbostic */ 42334624Sbostic for (p = endp - 1; integer; ++expcnt) { 42434624Sbostic tmp = modf(integer / 10, &integer); 42534624Sbostic *p-- = tochar((int)((tmp + .01) * 10)); 42634248Sbostic } 42734261Sbostic switch(fmtch) { 42834261Sbostic case 'f': 42934624Sbostic /* reverse integer into beginning of buffer */ 43034624Sbostic if (expcnt) 43134624Sbostic for (; ++p < endp; *t++ = *p); 43234624Sbostic else 43334624Sbostic *t++ = '0'; 43434248Sbostic /* 43534624Sbostic * if precision required or alternate flag set, add in a 43634624Sbostic * decimal point. 43734248Sbostic */ 43834624Sbostic if (prec || flags&ALT) 43934624Sbostic *t++ = '.'; 44034624Sbostic /* if requires more precision and some fraction left */ 44134624Sbostic if (fract) { 44234624Sbostic if (prec) 44334624Sbostic do { 44434624Sbostic fract = modf(fract * 10, &tmp); 44534624Sbostic *t++ = tochar((int)tmp); 44634624Sbostic } while (--prec && fract); 44734624Sbostic if (fract) 448*34669Sbostic startp = round(fract, (int *)NULL, startp, 449*34669Sbostic t - 1, (char)0, signp); 45034624Sbostic } 45134624Sbostic for (; prec--; *t++ = '0'); 45234624Sbostic break; 45334624Sbostic case 'e': 45434624Sbostic case 'E': 45534624Sbostic eformat: if (expcnt) { 45634624Sbostic *t++ = *++p; 45734624Sbostic if (prec || flags&ALT) 45834331Sbostic *t++ = '.'; 45934624Sbostic /* if requires more precision and some integer left */ 46034624Sbostic for (; prec && ++p < endp; --prec) 46134624Sbostic *t++ = *p; 46234624Sbostic /* 46334624Sbostic * if done precision and more of the integer component, 46434624Sbostic * round using it; adjust fract so we don't re-round 46534624Sbostic * later. 46634624Sbostic */ 46734624Sbostic if (!prec && ++p < endp) { 46834248Sbostic fract = 0; 469*34669Sbostic startp = round((double)0, &expcnt, startp, 470*34669Sbostic t - 1, *p, signp); 47134248Sbostic } 47234624Sbostic /* adjust expcnt for digit in front of decimal */ 47334624Sbostic --expcnt; 47434242Sbostic } 47534624Sbostic /* until first fractional digit, decrement exponent */ 47634624Sbostic else if (fract) { 47734624Sbostic /* adjust expcnt for digit in front of decimal */ 47834624Sbostic for (expcnt = -1;; --expcnt) { 47934624Sbostic fract = modf(fract * 10, &tmp); 48034624Sbostic if (tmp) 48134624Sbostic break; 48234248Sbostic } 48334624Sbostic *t++ = tochar((int)tmp); 48434624Sbostic if (prec || flags&ALT) 48534331Sbostic *t++ = '.'; 48634242Sbostic } 48734248Sbostic else { 48834624Sbostic *t++ = '0'; 48934624Sbostic if (prec || flags&ALT) 49034331Sbostic *t++ = '.'; 49134248Sbostic } 49234624Sbostic /* if requires more precision and some fraction left */ 49334624Sbostic if (fract) { 49434624Sbostic if (prec) 49534624Sbostic do { 49634624Sbostic fract = modf(fract * 10, &tmp); 49734624Sbostic *t++ = tochar((int)tmp); 49834624Sbostic } while (--prec && fract); 49934624Sbostic if (fract) 500*34669Sbostic startp = round(fract, &expcnt, startp, 501*34669Sbostic t - 1, (char)0, signp); 50234584Sbostic } 50334624Sbostic /* if requires more precision */ 50434624Sbostic for (; prec--; *t++ = '0'); 50534624Sbostic 50634624Sbostic /* unless alternate flag, trim any g/G format trailing 0's */ 50734624Sbostic if (gformat && !(flags&ALT)) { 50834624Sbostic while (t > startp && *--t == '0'); 50934624Sbostic if (*t == '.') 51034624Sbostic --t; 51134624Sbostic ++t; 51234624Sbostic } 51334624Sbostic t = exponent(t, expcnt, fmtch); 51434624Sbostic break; 51534624Sbostic case 'g': 51634624Sbostic case 'G': 51734624Sbostic /* a precision of 0 is treated as a precision of 1. */ 51834624Sbostic if (!prec) 51934624Sbostic ++prec; 52034624Sbostic /* 52134624Sbostic * ``The style used depends on the value converted; style e 52234624Sbostic * will be used only if the exponent resulting from the 52334624Sbostic * conversion is less than -4 or greater than the precision.'' 52434624Sbostic * -- ANSI X3J11 52534624Sbostic */ 52634624Sbostic if (expcnt > prec || !expcnt && fract && fract < .0001) { 52734624Sbostic /* 52834624Sbostic * g/G format counts "significant digits, not digits of 52934624Sbostic * precision; for the e/E format, this just causes an 53034624Sbostic * off-by-one problem, i.e. g/G considers the digit 53134624Sbostic * before the decimal point significant and e/E doesn't 53234624Sbostic * count it as precision. 53334624Sbostic */ 53434624Sbostic --prec; 53534624Sbostic fmtch -= 2; /* G->E, g->e */ 53634624Sbostic gformat = 1; 53734624Sbostic goto eformat; 53834624Sbostic } 53934624Sbostic /* 54034624Sbostic * reverse integer into beginning of buffer, 54134624Sbostic * note, decrement precision 54234624Sbostic */ 54334624Sbostic if (expcnt) 54434624Sbostic for (; ++p < endp; *t++ = *p, --prec); 54534624Sbostic else 54634624Sbostic *t++ = '0'; 54734624Sbostic /* 54834624Sbostic * if precision required or alternate flag set, add in a 54934624Sbostic * decimal point. If no digits yet, add in leading 0. 55034624Sbostic */ 55134624Sbostic if (prec || flags&ALT) { 55234624Sbostic dotrim = 1; 55334624Sbostic *t++ = '.'; 55434624Sbostic } 55534624Sbostic else 55634624Sbostic dotrim = 0; 55734624Sbostic /* if requires more precision and some fraction left */ 55834624Sbostic if (fract) { 55934624Sbostic if (prec) { 56034624Sbostic do { 56134624Sbostic fract = modf(fract * 10, &tmp); 56234624Sbostic *t++ = tochar((int)tmp); 56334624Sbostic } while(!tmp); 56434624Sbostic while (--prec && fract) { 56534624Sbostic fract = modf(fract * 10, &tmp); 56634624Sbostic *t++ = tochar((int)tmp); 56734248Sbostic } 56834248Sbostic } 56934624Sbostic if (fract) 570*34669Sbostic startp = round(fract, (int *)NULL, startp, 571*34669Sbostic t - 1, (char)0, signp); 57234624Sbostic } 57334624Sbostic /* alternate format, adds 0's for precision, else trim 0's */ 57434624Sbostic if (flags&ALT) 57534624Sbostic for (; prec--; *t++ = '0'); 57634624Sbostic else if (dotrim) { 57734624Sbostic while (t > startp && *--t == '0'); 57834624Sbostic if (*t != '.') 57934624Sbostic ++t; 58034624Sbostic } 58134624Sbostic } 58234624Sbostic return(t - startp); 58334624Sbostic } 58434248Sbostic 58534624Sbostic static char * 586*34669Sbostic round(fract, exp, start, end, ch, signp) 58734624Sbostic double fract; 588*34669Sbostic int *exp; 58934624Sbostic register char *start, *end; 590*34669Sbostic char ch, *signp; 59134624Sbostic { 59234624Sbostic double tmp; 59334248Sbostic 59434624Sbostic if (fract) 59534248Sbostic (void)modf(fract * 10, &tmp); 59634624Sbostic else 59734624Sbostic tmp = todigit(ch); 59834624Sbostic if (tmp > 4) 59934624Sbostic for (;; --end) { 60034624Sbostic if (*end == '.') 60134624Sbostic --end; 60234624Sbostic if (++*end <= '9') 60334624Sbostic break; 60434624Sbostic *end = '0'; 60534624Sbostic if (end == start) { 606*34669Sbostic if (exp) { /* e/E; increment exponent */ 607*34669Sbostic *end = '1'; 608*34669Sbostic ++*exp; 609*34669Sbostic } 610*34669Sbostic else { /* f; add extra digit */ 611*34669Sbostic *--end = '1'; 612*34669Sbostic --start; 613*34669Sbostic } 61434624Sbostic break; 61534242Sbostic } 61634242Sbostic } 617*34669Sbostic /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ 618*34669Sbostic else if (*signp == '-') 619*34669Sbostic for (;; --end) { 620*34669Sbostic if (*end == '.') 621*34669Sbostic --end; 622*34669Sbostic if (*end != '0') 623*34669Sbostic break; 624*34669Sbostic if (end == start) 625*34669Sbostic *signp = 0; 626*34669Sbostic } 62734624Sbostic return(start); 62834624Sbostic } 62934248Sbostic 63034624Sbostic static char * 63134624Sbostic exponent(p, exp, fmtch) 63234624Sbostic register char *p; 63334624Sbostic register int exp; 63434624Sbostic u_char fmtch; 63534624Sbostic { 63634624Sbostic register char *t; 63734624Sbostic char expbuf[MAXEXP]; 63834248Sbostic 63934624Sbostic *p++ = fmtch; 64034624Sbostic if (exp < 0) { 64134624Sbostic exp = -exp; 64234624Sbostic *p++ = '-'; 64334242Sbostic } 64434624Sbostic else 64534624Sbostic *p++ = '+'; 64634624Sbostic t = expbuf + MAXEXP; 64734624Sbostic if (exp > 9) { 64834624Sbostic do { 64934624Sbostic *--t = tochar(exp % 10); 65034624Sbostic } while ((exp /= 10) > 9); 65134624Sbostic *--t = tochar(exp); 65234624Sbostic for (; t < expbuf + MAXEXP; *p++ = *t++); 65334624Sbostic } 65434624Sbostic else { 65534624Sbostic *p++ = '0'; 65634624Sbostic *p++ = tochar(exp); 65734624Sbostic } 65834323Sbostic return(p); 65934242Sbostic } 660