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*34427Sbostic static char sccsid[] = "@(#)vfprintf.c 5.28 (Berkeley) 05/23/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 2734328Sbostic #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 2834328Sbostic 29*34427Sbostic #define PUTC(ch) (void) putc(ch, fp) 3034236Sbostic 3134318Sbostic #define ARG() \ 3234318Sbostic _ulong = flags&LONGINT ? va_arg(argp, long) : \ 3334318Sbostic flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 3434235Sbostic 3534331Sbostic #define todigit(c) ((c) - '0') 3634331Sbostic #define tochar(n) ((n) + '0') 3734331Sbostic 3834318Sbostic /* have to deal with the negative buffer count kludge */ 3934318Sbostic #define NEGATIVE_COUNT_KLUDGE 4034318Sbostic 4134318Sbostic #define LONGINT 0x01 /* long integer */ 4234318Sbostic #define LONGDBL 0x02 /* long double; unimplemented */ 4334318Sbostic #define SHORTINT 0x04 /* short integer */ 4434318Sbostic #define ALT 0x08 /* alternate form */ 4534318Sbostic #define LADJUST 0x10 /* left adjustment */ 46*34427Sbostic #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ 47*34427Sbostic #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ 4834318Sbostic 4934323Sbostic _doprnt(fmt0, argp, fp) 5034323Sbostic u_char *fmt0; 5134233Sbostic va_list argp; 5234235Sbostic register FILE *fp; 5334226Sbostic { 54*34427Sbostic register u_char *fmt; /* format string */ 55*34427Sbostic register int ch; /* character from fmt */ 56*34427Sbostic register int cnt; /* return value accumulator */ 57*34427Sbostic register int n; /* random handy integer */ 58*34427Sbostic register char *t; /* buffer pointer */ 59*34427Sbostic double _double; /* double precision arguments %[eEfgG] */ 60*34427Sbostic u_long _ulong; /* integer arguments %[diouxX] */ 61*34427Sbostic int flags; /* flags as above */ 62*34427Sbostic int dprec; /* decimal precision in [diouxX] */ 63*34427Sbostic int fpprec; /* `extra' floating precision in [eEfgG] */ 64*34427Sbostic int width; /* width from format (%8d), or 0 */ 65*34427Sbostic int prec; /* precision from format (%.3d), or -1 */ 66*34427Sbostic int size; /* size of converted field or string */ 67*34427Sbostic int fieldsz; /* field size expanded by sign, etc */ 68*34427Sbostic int realsz; /* field size expanded by decimal precision */ 69*34427Sbostic char sign; /* sign prefix (+ - or \0) */ 70*34427Sbostic int base; /* base for [diouxX] conversion */ 71*34427Sbostic char *digs; /* digits for [diouxX] conversion */ 72*34427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 73*34427Sbostic char *_cvt(); /* handles [eEfgG] formats */ 7434226Sbostic 7534323Sbostic fmt = fmt0; 7634243Sbostic digs = "0123456789abcdef"; 7734322Sbostic for (cnt = 0;; ++fmt) { 7834318Sbostic n = fp->_cnt; 79*34427Sbostic for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; 80*34427Sbostic ++cnt, ++fmt) 8134318Sbostic if (--n < 0 8234318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE 8334318Sbostic && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 8434318Sbostic #endif 85*34427Sbostic || ch == '\n' && fp->_flag & _IOLBF) { 8634318Sbostic fp->_cnt = n; 87*34427Sbostic fp->_ptr = (u_char *)t; 88*34427Sbostic (void) _flsbuf((u_char)ch, fp); 8934318Sbostic n = fp->_cnt; 90*34427Sbostic t = (char *)fp->_ptr; 91*34427Sbostic } else 9234314Sbostic *t++ = ch; 9334318Sbostic fp->_cnt = n; 94*34427Sbostic fp->_ptr = (u_char *)t; 9534318Sbostic if (!ch) 96*34427Sbostic return (cnt); 9734314Sbostic 98*34427Sbostic flags = dprec = fpprec = width = 0; 9934233Sbostic prec = -1; 10034318Sbostic sign = '\0'; 10134226Sbostic 10234318Sbostic rflag: switch (*++fmt) { 10334318Sbostic case ' ': 10434318Sbostic sign = ' '; 10534318Sbostic goto rflag; 10634233Sbostic case '#': 10734318Sbostic flags |= ALT; 10834318Sbostic goto rflag; 10934233Sbostic case '*': 11034235Sbostic /* 11134235Sbostic * ``A negative field width argument is taken as a 11234235Sbostic * - flag followed by a positive field width.'' 11334235Sbostic * -- ANSI X3J11 11434235Sbostic * They don't exclude field widths read from args. 11534235Sbostic */ 11634235Sbostic if ((width = va_arg(argp, int)) >= 0) 11734318Sbostic goto rflag; 11834235Sbostic width = -width; 119*34427Sbostic /* FALLTHROUGH */ 12034235Sbostic case '-': 12134318Sbostic flags |= LADJUST; 12234318Sbostic goto rflag; 12334233Sbostic case '+': 12434314Sbostic sign = '+'; 12534318Sbostic goto rflag; 12634233Sbostic case '.': 12734235Sbostic if (*++fmt == '*') 12834318Sbostic n = va_arg(argp, int); 129*34427Sbostic else { 13034318Sbostic n = 0; 131*34427Sbostic while (isascii(*fmt) && isdigit(*fmt)) 132*34427Sbostic n = 10 * n + todigit(*fmt++); 13334233Sbostic --fmt; 13434226Sbostic } 13534318Sbostic prec = n < 0 ? -1 : n; 13634318Sbostic goto rflag; 13734233Sbostic case '0': 138*34427Sbostic /* 139*34427Sbostic * ``Note that 0 is taken as a flag, not as the 140*34427Sbostic * beginning of a field width.'' 141*34427Sbostic * -- ANSI X3J11 142*34427Sbostic */ 143*34427Sbostic flags |= ZEROPAD; 144*34427Sbostic goto rflag; 14534233Sbostic case '1': case '2': case '3': case '4': 14634233Sbostic case '5': case '6': case '7': case '8': case '9': 14734318Sbostic n = 0; 14834233Sbostic do { 14934331Sbostic n = 10 * n + todigit(*fmt); 15034318Sbostic } while (isascii(*++fmt) && isdigit(*fmt)); 15134318Sbostic width = n; 15234233Sbostic --fmt; 15334319Sbostic goto rflag; 15434235Sbostic case 'L': 15534329Sbostic flags |= LONGDBL; 15634318Sbostic goto rflag; 15734235Sbostic case 'h': 15834318Sbostic flags |= SHORTINT; 15934318Sbostic goto rflag; 16034233Sbostic case 'l': 16134318Sbostic flags |= LONGINT; 16234318Sbostic goto rflag; 16334314Sbostic case 'c': 164*34427Sbostic *(t = buf) = va_arg(argp, int); 16534314Sbostic size = 1; 166*34427Sbostic sign = '\0'; 16734314Sbostic goto pforw; 16834314Sbostic case 'd': 16934318Sbostic case 'i': 17034318Sbostic ARG(); 17134318Sbostic if ((long)_ulong < 0) { 17234318Sbostic _ulong = -_ulong; 17334314Sbostic sign = '-'; 17434241Sbostic } 17534241Sbostic base = 10; 17634327Sbostic goto number; 17734261Sbostic case 'e': 17834236Sbostic case 'E': 17934235Sbostic case 'f': 18034261Sbostic case 'g': 18134243Sbostic case 'G': 18234243Sbostic _double = va_arg(argp, double); 18334328Sbostic /* 18434328Sbostic * don't bother to do unrealistic precision; just 18534328Sbostic * pad it with zeroes later. This keeps buffer size 18634328Sbostic * rational. 18734328Sbostic */ 18834328Sbostic if (prec > MAXFRACT) { 18934328Sbostic fpprec = prec - MAXFRACT; 19034328Sbostic prec = MAXFRACT; 19134328Sbostic } 19234319Sbostic t = buf; 193*34427Sbostic size = _cvt(_double, prec, flags, *fmt, &sign, 194*34427Sbostic t, t + sizeof(buf)) - t; 19534314Sbostic goto pforw; 19634235Sbostic case 'n': 197*34427Sbostic if (flags & LONGINT) 19834318Sbostic *va_arg(argp, long *) = cnt; 199*34427Sbostic else if (flags & SHORTINT) 20034318Sbostic *va_arg(argp, short *) = cnt; 20134318Sbostic else 20234318Sbostic *va_arg(argp, int *) = cnt; 20334235Sbostic break; 20434226Sbostic case 'o': 20534318Sbostic ARG(); 20634226Sbostic base = 8; 20734327Sbostic goto nosign; 20834235Sbostic case 'p': 20934320Sbostic /* 21034321Sbostic * ``The argument shall be a pointer to void. The 21134321Sbostic * value of the pointer is converted to a sequence 21234321Sbostic * of printable characters, in an implementation- 21334321Sbostic * defined manner.'' 21434321Sbostic * -- ANSI X3J11 21534320Sbostic */ 216*34427Sbostic /* NOSTRICT */ 21734320Sbostic _ulong = (u_long)va_arg(argp, void *); 21834320Sbostic base = 16; 21934327Sbostic goto nosign; 22034226Sbostic case 's': 22134314Sbostic if (!(t = va_arg(argp, char *))) 22234314Sbostic t = "(null)"; 22334321Sbostic if (prec >= 0) { 22434321Sbostic /* 22534321Sbostic * can't use strlen; can only look for the 22634321Sbostic * NUL in the first `prec' characters, and 22734321Sbostic * strlen() will go further. 22834321Sbostic */ 22934321Sbostic char *p, *memchr(); 23034321Sbostic 23134321Sbostic if (p = memchr(t, 0, prec)) { 23234321Sbostic size = p - t; 23334321Sbostic if (size > prec) 23434321Sbostic size = prec; 235*34427Sbostic } else 23634321Sbostic size = prec; 237*34427Sbostic } else 23834321Sbostic size = strlen(t); 239*34427Sbostic sign = '\0'; 24034328Sbostic goto pforw; 24134226Sbostic case 'u': 24234318Sbostic ARG(); 24334226Sbostic base = 10; 24434327Sbostic goto nosign; 24534226Sbostic case 'X': 24634226Sbostic digs = "0123456789ABCDEF"; 247*34427Sbostic /* FALLTHROUGH */ 24834226Sbostic case 'x': 24934318Sbostic ARG(); 25034314Sbostic base = 16; 25134326Sbostic /* leading 0x/X only if non-zero */ 252*34427Sbostic if (flags & ALT && _ulong != 0) 253*34427Sbostic flags |= HEXPREFIX; 25434327Sbostic 25534327Sbostic /* unsigned conversions */ 256*34427Sbostic nosign: sign = '\0'; 25734326Sbostic /* 25834330Sbostic * ``... diouXx conversions ... if a precision is 25934330Sbostic * specified, the 0 flag will be ignored.'' 26034330Sbostic * -- ANSI X3J11 26134330Sbostic */ 262*34427Sbostic number: if ((dprec = prec) >= 0) 263*34427Sbostic flags &= ~ZEROPAD; 264*34427Sbostic 26534330Sbostic /* 26634326Sbostic * ``The result of converting a zero value with an 26734326Sbostic * explicit precision of zero is no characters.'' 26834326Sbostic * -- ANSI X3J11 26934326Sbostic */ 270*34427Sbostic t = buf + BUF; 271*34427Sbostic if (_ulong != 0 || prec != 0) { 272*34427Sbostic do { 273*34427Sbostic *--t = digs[_ulong % base]; 274*34427Sbostic _ulong /= base; 275*34427Sbostic } while (_ulong); 276*34427Sbostic digs = "0123456789abcdef"; 277*34427Sbostic if (flags & ALT && base == 8 && *t != '0') 278*34427Sbostic *--t = '0'; /* octal leading 0 */ 27934330Sbostic } 280*34427Sbostic size = buf + BUF - t; 28134327Sbostic 282*34427Sbostic pforw: 283*34427Sbostic /* 284*34427Sbostic * All reasonable formats wind up here. At this 285*34427Sbostic * point, `t' points to a string which (if not 286*34427Sbostic * flags&LADJUST) should be padded out to `width' 287*34427Sbostic * places. If flags&ZEROPAD, it should first be 288*34427Sbostic * prefixed by any sign or other prefix; otherwise, 289*34427Sbostic * it should be blank padded before the prefix is 290*34427Sbostic * emitted. After any left-hand padding and 291*34427Sbostic * prefixing, emit zeroes required by a decimal 292*34427Sbostic * [diouxX] precision, then print the string proper, 293*34427Sbostic * then emit zeroes required by any leftover floating 294*34427Sbostic * precision; finally, if LADJUST, pad with blanks. 295*34427Sbostic */ 29634327Sbostic 297*34427Sbostic /* compute actual size, so we know how much to pad */ 298*34427Sbostic /* this code is not terribly satisfactory */ 299*34427Sbostic /* fieldsz excludes decimal prec; realsz includes it */ 300*34427Sbostic fieldsz = size + fpprec; 301*34427Sbostic if (sign) 302*34427Sbostic fieldsz++; 303*34427Sbostic if (flags & HEXPREFIX) 304*34427Sbostic fieldsz += 2; 305*34427Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 30634327Sbostic 307*34427Sbostic /* right-adjusting blank padding */ 308*34427Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0 && width) 309*34427Sbostic for (n = realsz; n < width; n++) 310*34427Sbostic PUTC(' '); 311*34427Sbostic /* prefix */ 312*34427Sbostic if (sign) 313*34427Sbostic PUTC(sign); 314*34427Sbostic if (flags & HEXPREFIX) { 315*34427Sbostic PUTC('0'); 316*34427Sbostic PUTC((char)*fmt); 31734327Sbostic } 318*34427Sbostic /* right-adjusting zero padding */ 319*34427Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 320*34427Sbostic for (n = realsz; n < width; n++) 321*34427Sbostic PUTC('0'); 322*34427Sbostic /* leading zeroes from decimal precision */ 323*34427Sbostic for (n = fieldsz; n < dprec; n++) 324*34427Sbostic PUTC('0'); 32534327Sbostic 326*34427Sbostic /* the string or number proper */ 327*34427Sbostic if (fp->_cnt - (n = size) >= 0 && 328*34427Sbostic (fp->_flag & _IOLBF) == 0) { 32934328Sbostic fp->_cnt -= n; 330*34427Sbostic bcopy(t, (char *)fp->_ptr, n); 33134328Sbostic fp->_ptr += n; 332*34427Sbostic } else 333*34427Sbostic while (--n >= 0) 334*34427Sbostic PUTC(*t++); 335*34427Sbostic /* trailing f.p. zeroes */ 336*34427Sbostic while (--fpprec >= 0) 33734328Sbostic PUTC('0'); 338*34427Sbostic /* left-adjusting padding (always blank) */ 339*34427Sbostic if (flags & LADJUST) 340*34427Sbostic for (n = realsz; n < width; n++) 34134328Sbostic PUTC(' '); 342*34427Sbostic 343*34427Sbostic /* finally, adjust cnt */ 344*34427Sbostic cnt += width > realsz ? width : realsz; 34534226Sbostic break; 346*34427Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 347*34427Sbostic return (cnt); 34834226Sbostic default: 349*34427Sbostic PUTC((char)*fmt); 350*34427Sbostic cnt++; 35134226Sbostic } 35234226Sbostic } 353*34427Sbostic /* NOTREACHED */ 35434226Sbostic } 35534242Sbostic 35634261Sbostic #define EFORMAT 0x01 35734261Sbostic #define FFORMAT 0x02 35834261Sbostic #define GFORMAT 0x04 35934314Sbostic #define DEFPREC 6 36034261Sbostic 36134323Sbostic static char * 362*34427Sbostic _cvt(number, prec, flags, fmtch, sign, startp, endp) 36334242Sbostic double number; 36434261Sbostic register int prec; 36534323Sbostic int flags; 36634323Sbostic u_char fmtch; 367*34427Sbostic char *sign, *startp, *endp; 36834242Sbostic { 36934331Sbostic register char *p, *t; 37034261Sbostic register int expcnt, format; 37134248Sbostic double fract, integer, tmp, modf(); 37234261Sbostic int decpt; 37334331Sbostic char *savep, exponent[MAXEXP]; 37434242Sbostic 37534314Sbostic if (prec == -1) 37634242Sbostic prec = DEFPREC; 37734242Sbostic 37834314Sbostic if (number < 0) { 37934327Sbostic *sign = '-'; 38034248Sbostic number = -number; 38134248Sbostic } 38234242Sbostic 38334261Sbostic switch(fmtch) { 38434261Sbostic case 'e': 38534261Sbostic case 'E': 38634261Sbostic format = EFORMAT; 38734261Sbostic break; 38834261Sbostic case 'f': 38934261Sbostic format = FFORMAT; 39034261Sbostic break; 39134261Sbostic case 'g': 39234261Sbostic case 'G': 39334261Sbostic format = GFORMAT; 39434261Sbostic fmtch -= 2; 39534261Sbostic } 39634261Sbostic 39734248Sbostic /* 39834248Sbostic * if the alternate flag is set, or, at least one digit of precision 39934248Sbostic * was requested, add a decimal point, unless it's the g/G format 40034314Sbostic * in which case we require two digits of precision, as it counts 40134248Sbostic * precision differently. 40234248Sbostic */ 40334318Sbostic decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0); 40434248Sbostic 40534248Sbostic expcnt = 0; 40634323Sbostic p = endp - 1; 40734248Sbostic fract = modf(number, &integer); 40834248Sbostic if (integer) { 40934248Sbostic /* get integer part of number; count decimal places */ 41034248Sbostic for (; integer; ++expcnt) { 41134248Sbostic tmp = modf(integer / 10, &integer); 41234331Sbostic *p-- = tochar((int)((tmp + .03) * 10)); 41334242Sbostic } 41434248Sbostic 41534248Sbostic /* copy, in reverse order, to start of buffer */ 41634331Sbostic t = startp; 41734331Sbostic *t++ = *++p; 41834248Sbostic 41934248Sbostic /* 42034248Sbostic * if the format is g/G, and the resulting exponent will be 42134248Sbostic * greater than the precision, use e/E format. If e/E format, 42234248Sbostic * put in a decimal point as needed, and decrement precision 42334248Sbostic * count for each digit after the decimal point. 42434248Sbostic */ 42534248Sbostic if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) { 42634248Sbostic if (format&GFORMAT) { 42734248Sbostic format |= EFORMAT; 42834248Sbostic 42934248Sbostic /* first digit is precision for g/G format */ 43034248Sbostic if (prec) 43134248Sbostic --prec; 43234248Sbostic } 43334248Sbostic if (decpt) 43434331Sbostic *t++ = '.'; 43534331Sbostic for (; ++p < endp && prec; --prec, *t++ = *p); 43634248Sbostic 43734318Sbostic /* precision ran out, round */ 43834248Sbostic if (p < endp) { 43934248Sbostic if (*p > '4') { 44034331Sbostic for (savep = t--;; *t-- = '0') { 44134331Sbostic if (*t == '.') 44234331Sbostic --t; 44334331Sbostic if (++*t <= '9') 44434248Sbostic break; 44534248Sbostic } 44634331Sbostic t = savep; 44734248Sbostic } 44834248Sbostic fract = 0; 44934248Sbostic } 45034242Sbostic } 45134248Sbostic /* 45234314Sbostic * g/G in f format; if out of precision, replace digits with 45334314Sbostic * zeroes, note, have to round first. 45434248Sbostic */ 45534248Sbostic else if (format&GFORMAT) { 45634331Sbostic for (; ++p < endp && prec; --prec, *t++ = *p); 45734248Sbostic /* precision ran out; round and then add zeroes */ 45834248Sbostic if (p < endp) { 45934248Sbostic if (*p > '4') { 46034331Sbostic for (savep = t--; ++*t > '9'; 46134331Sbostic *t-- = '0'); 46234331Sbostic t = savep; 46334248Sbostic } 46434248Sbostic do { 46534331Sbostic *t++ = '0'; 46634248Sbostic } while (++p < endp); 46734248Sbostic fract = 0; 46834248Sbostic } 46934248Sbostic if (decpt) 47034331Sbostic *t++ = '.'; 47134242Sbostic } 47234248Sbostic /* f format */ 47334248Sbostic else { 47434331Sbostic for (; ++p < endp; *t++ = *p); 47534248Sbostic if (decpt) 47634331Sbostic *t++ = '.'; 47734248Sbostic } 47834331Sbostic p = t; 47934248Sbostic } 48034248Sbostic /* 48134318Sbostic * if no fraction, the number was zero, and if no precision, can't 48234318Sbostic * show anything after the decimal point. 48334248Sbostic */ 48434248Sbostic else if (!fract || !prec) { 48534248Sbostic *startp++ = '0'; 48634318Sbostic if (decpt && !(format&GFORMAT)) 48734248Sbostic *startp++ = '.'; 48834318Sbostic *startp = '\0'; 48934323Sbostic return(startp); 49034248Sbostic } 49134248Sbostic /* 49234248Sbostic * if the format is g/G, and the resulting exponent will be less than 49334248Sbostic * -4 use e/E format. If e/E format, compute exponent value. 49434248Sbostic */ 49534248Sbostic else if (format&GFORMAT && fract < .0001 || format&EFORMAT) { 49634248Sbostic format |= EFORMAT; 49734248Sbostic if (fract) 49834248Sbostic for (p = startp; fract;) { 49934248Sbostic fract = modf(fract * 10, &tmp); 50034248Sbostic if (!tmp) { 50134248Sbostic --expcnt; 50234248Sbostic continue; 50334248Sbostic } 50434331Sbostic *p++ = tochar((int)tmp); 50534248Sbostic break; 50634248Sbostic } 50734242Sbostic else 50834248Sbostic *p++ = '0'; 50934248Sbostic 51034248Sbostic /* g/G format, decrement precision for first digit */ 51134248Sbostic if (format&GFORMAT && prec) 51234248Sbostic --prec; 51334248Sbostic 51434248Sbostic /* add decimal after first non-zero digit */ 51534248Sbostic if (decpt) 51634248Sbostic *p++ = '.'; 51734242Sbostic } 51834248Sbostic /* 51934248Sbostic * f format or g/G printed as f format; don't worry about decimal 52034248Sbostic * point, if g/G format doesn't need it, will get stripped later. 52134248Sbostic */ 52234242Sbostic else { 52334248Sbostic p = startp; 52434248Sbostic *p++ = '0'; 52534248Sbostic *p++ = '.'; 52634248Sbostic } 52734248Sbostic 52834319Sbostic /* finish out requested precision */ 52934319Sbostic while (fract && prec-- > 0) { 53034319Sbostic fract = modf(fract * 10, &tmp); 53134331Sbostic *p++ = tochar((int)tmp); 53234319Sbostic } 53334319Sbostic while (prec-- > 0) 53434319Sbostic *p++ = '0'; 53534248Sbostic 53634248Sbostic /* 53734248Sbostic * if any fractional value left, "round" it back up to the beginning 53834248Sbostic * of the number, fixing the exponent as necessary, and avoiding the 53934248Sbostic * decimal point. 54034248Sbostic */ 54134248Sbostic if (fract) { 54234248Sbostic (void)modf(fract * 10, &tmp); 54334248Sbostic if (tmp > 4) { 54434248Sbostic for (savep = p--;; *p-- = '0') { 54534248Sbostic if (*p == '.') 54634248Sbostic --p; 54734248Sbostic if (p == startp) { 54834248Sbostic *p = '1'; 54934248Sbostic ++expcnt; 55034248Sbostic break; 55134248Sbostic } 55234248Sbostic if (++*p <= '9') 55334248Sbostic break; 55434242Sbostic } 55534248Sbostic p = savep; 55634242Sbostic } 55734248Sbostic } 55834248Sbostic 55934248Sbostic /* 56034248Sbostic * if a g/G format and not alternate flag, lose trailing zeroes, 56134248Sbostic * if e/E or g/G format, and last char is decimal point, lose it. 56234248Sbostic */ 56334318Sbostic if (!(flags&ALT)) { 56434248Sbostic if (format&GFORMAT) 56534248Sbostic for (; p[-1] == '0'; --p); 56634248Sbostic if (format&(GFORMAT|EFORMAT) && p[-1] == '.') 56734248Sbostic --p; 56834248Sbostic } 56934248Sbostic 57034248Sbostic /* if an e/E format, add exponent */ 57134248Sbostic if (format&EFORMAT) { 57234248Sbostic *p++ = fmtch; 57334248Sbostic if (--expcnt < 0) { 57434248Sbostic expcnt = -expcnt; 57534248Sbostic *p++ = '-'; 57634242Sbostic } 57734248Sbostic else 57834248Sbostic *p++ = '+'; 57934331Sbostic t = exponent + MAXEXP; 58034331Sbostic if (expcnt > 9) { 58134331Sbostic do { 58234331Sbostic *--t = tochar(expcnt % 10); 58334331Sbostic } while ((expcnt /= 10) > 9); 58434331Sbostic *--t = tochar(expcnt); 58534331Sbostic for (; t < exponent + MAXEXP; *p++ = *t++); 58634331Sbostic } 58734331Sbostic else { 58834331Sbostic *p++ = '0'; 58934331Sbostic *p++ = tochar(expcnt); 59034331Sbostic } 59134242Sbostic } 59234323Sbostic return(p); 59334242Sbostic } 594