134226Sbostic /* 234233Sbostic * Copyright (c) 1988 Regents of the University of California. 334233Sbostic * All rights reserved. 434226Sbostic * 542631Sbostic * %sccs.include.redist.c% 634226Sbostic */ 734226Sbostic 834233Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*44426Sbostic static char sccsid[] = "@(#)vfprintf.c 5.39 (Berkeley) 06/28/90"; 1034233Sbostic #endif /* LIBC_SCCS and not lint */ 1134233Sbostic 1234261Sbostic #include <sys/types.h> 1334233Sbostic #include <varargs.h> 1434226Sbostic #include <stdio.h> 1534233Sbostic #include <ctype.h> 1634226Sbostic 1734328Sbostic /* 11-bit exponent (VAX G floating point) is 308 decimal digits */ 1834328Sbostic #define MAXEXP 308 1934328Sbostic /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ 2034328Sbostic #define MAXFRACT 39 2134226Sbostic 2234624Sbostic #define DEFPREC 6 2334624Sbostic 2434328Sbostic #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 2534328Sbostic 2634427Sbostic #define PUTC(ch) (void) putc(ch, fp) 2734236Sbostic 2836090Sbostic #define ARG(basetype) \ 2936090Sbostic _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \ 3036090Sbostic flags&SHORTINT ? (short basetype)va_arg(argp, int) : \ 3136090Sbostic va_arg(argp, int) 3234235Sbostic 3334331Sbostic #define todigit(c) ((c) - '0') 3434331Sbostic #define tochar(n) ((n) + '0') 3534331Sbostic 3634318Sbostic /* have to deal with the negative buffer count kludge */ 3734318Sbostic #define NEGATIVE_COUNT_KLUDGE 3834318Sbostic 3934318Sbostic #define LONGINT 0x01 /* long integer */ 4034318Sbostic #define LONGDBL 0x02 /* long double; unimplemented */ 4134318Sbostic #define SHORTINT 0x04 /* short integer */ 4234318Sbostic #define ALT 0x08 /* alternate form */ 4334318Sbostic #define LADJUST 0x10 /* left adjustment */ 4434427Sbostic #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ 4534427Sbostic #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ 4634318Sbostic 4734323Sbostic _doprnt(fmt0, argp, fp) 4834323Sbostic u_char *fmt0; 4934233Sbostic va_list argp; 5034235Sbostic register FILE *fp; 5134226Sbostic { 5234427Sbostic register u_char *fmt; /* format string */ 5334427Sbostic register int ch; /* character from fmt */ 5434427Sbostic register int cnt; /* return value accumulator */ 5534427Sbostic register int n; /* random handy integer */ 5634427Sbostic register char *t; /* buffer pointer */ 5734427Sbostic double _double; /* double precision arguments %[eEfgG] */ 5834427Sbostic u_long _ulong; /* integer arguments %[diouxX] */ 5934624Sbostic int base; /* base for [diouxX] conversion */ 6034624Sbostic int dprec; /* decimal precision in [diouxX] */ 6134624Sbostic int fieldsz; /* field size expanded by sign, etc */ 6234427Sbostic int flags; /* flags as above */ 6334427Sbostic int fpprec; /* `extra' floating precision in [eEfgG] */ 6434427Sbostic int prec; /* precision from format (%.3d), or -1 */ 6534624Sbostic int realsz; /* field size expanded by decimal precision */ 6634427Sbostic int size; /* size of converted field or string */ 6734624Sbostic int width; /* width from format (%8d), or 0 */ 6834669Sbostic char sign; /* sign prefix (' ', '+', '-', or \0) */ 6934669Sbostic char softsign; /* temporary negative sign for floats */ 7034427Sbostic char *digs; /* digits for [diouxX] conversion */ 7134427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 7234226Sbostic 7334428Sbostic if (fp->_flag & _IORW) { 7434428Sbostic fp->_flag |= _IOWRT; 7534428Sbostic fp->_flag &= ~(_IOEOF|_IOREAD); 7634428Sbostic } 7734428Sbostic if ((fp->_flag & _IOWRT) == 0) 7834428Sbostic return (EOF); 7934428Sbostic 8034323Sbostic fmt = fmt0; 8134243Sbostic digs = "0123456789abcdef"; 8234322Sbostic for (cnt = 0;; ++fmt) { 8334318Sbostic n = fp->_cnt; 8434427Sbostic for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; 8534427Sbostic ++cnt, ++fmt) 8634318Sbostic if (--n < 0 8734318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE 8834318Sbostic && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 8934318Sbostic #endif 9034427Sbostic || ch == '\n' && fp->_flag & _IOLBF) { 9134318Sbostic fp->_cnt = n; 9234475Sbostic fp->_ptr = t; 9334427Sbostic (void) _flsbuf((u_char)ch, fp); 9434318Sbostic n = fp->_cnt; 9534427Sbostic t = (char *)fp->_ptr; 9634427Sbostic } else 9734314Sbostic *t++ = ch; 9834318Sbostic fp->_cnt = n; 9934475Sbostic fp->_ptr = t; 10034318Sbostic if (!ch) 10134427Sbostic return (cnt); 10234314Sbostic 10334672Sbostic flags = 0; dprec = 0; fpprec = 0; width = 0; 10434233Sbostic prec = -1; 10534318Sbostic sign = '\0'; 10634226Sbostic 10734318Sbostic rflag: switch (*++fmt) { 10834318Sbostic case ' ': 10934669Sbostic /* 11034669Sbostic * ``If the space and + flags both appear, the space 11134669Sbostic * flag will be ignored.'' 11234669Sbostic * -- ANSI X3J11 11334669Sbostic */ 11434669Sbostic if (!sign) 11534669Sbostic sign = ' '; 11634318Sbostic goto rflag; 11734233Sbostic case '#': 11834318Sbostic flags |= ALT; 11934318Sbostic goto rflag; 12034233Sbostic case '*': 12134235Sbostic /* 12234235Sbostic * ``A negative field width argument is taken as a 12334235Sbostic * - flag followed by a positive field width.'' 12434235Sbostic * -- ANSI X3J11 12534235Sbostic * They don't exclude field widths read from args. 12634235Sbostic */ 12734235Sbostic if ((width = va_arg(argp, int)) >= 0) 12834318Sbostic goto rflag; 12934235Sbostic width = -width; 13034427Sbostic /* FALLTHROUGH */ 13134235Sbostic case '-': 13234318Sbostic flags |= LADJUST; 13334318Sbostic goto rflag; 13434233Sbostic case '+': 13534314Sbostic sign = '+'; 13634318Sbostic goto rflag; 13734233Sbostic case '.': 13834235Sbostic if (*++fmt == '*') 13934318Sbostic n = va_arg(argp, int); 14034427Sbostic else { 14134318Sbostic n = 0; 14234427Sbostic while (isascii(*fmt) && isdigit(*fmt)) 14334427Sbostic n = 10 * n + todigit(*fmt++); 14434233Sbostic --fmt; 14534226Sbostic } 14634318Sbostic prec = n < 0 ? -1 : n; 14734318Sbostic goto rflag; 14834233Sbostic case '0': 14934427Sbostic /* 15034427Sbostic * ``Note that 0 is taken as a flag, not as the 15134427Sbostic * beginning of a field width.'' 15234427Sbostic * -- ANSI X3J11 15334427Sbostic */ 15434427Sbostic flags |= ZEROPAD; 15534427Sbostic goto rflag; 15634233Sbostic case '1': case '2': case '3': case '4': 15734233Sbostic case '5': case '6': case '7': case '8': case '9': 15834318Sbostic n = 0; 15934233Sbostic do { 16034331Sbostic n = 10 * n + todigit(*fmt); 16134318Sbostic } while (isascii(*++fmt) && isdigit(*fmt)); 16234318Sbostic width = n; 16334233Sbostic --fmt; 16434319Sbostic goto rflag; 16534235Sbostic case 'L': 16634329Sbostic flags |= LONGDBL; 16734318Sbostic goto rflag; 16834235Sbostic case 'h': 16934318Sbostic flags |= SHORTINT; 17034318Sbostic goto rflag; 17134233Sbostic case 'l': 17234318Sbostic flags |= LONGINT; 17334318Sbostic goto rflag; 17434314Sbostic case 'c': 17534427Sbostic *(t = buf) = va_arg(argp, int); 17634314Sbostic size = 1; 17734427Sbostic sign = '\0'; 17834314Sbostic goto pforw; 17934624Sbostic case 'D': 18034624Sbostic flags |= LONGINT; 18134624Sbostic /*FALLTHROUGH*/ 18234314Sbostic case 'd': 18334318Sbostic case 'i': 18436090Sbostic ARG(int); 18534318Sbostic if ((long)_ulong < 0) { 18634318Sbostic _ulong = -_ulong; 18734314Sbostic sign = '-'; 18834241Sbostic } 18934241Sbostic base = 10; 19034327Sbostic goto number; 19134261Sbostic case 'e': 19234236Sbostic case 'E': 19334235Sbostic case 'f': 19434261Sbostic case 'g': 19534243Sbostic case 'G': 19634243Sbostic _double = va_arg(argp, double); 19734328Sbostic /* 19834669Sbostic * don't do unrealistic precision; just pad it with 19934669Sbostic * zeroes later, so buffer size stays rational. 20034328Sbostic */ 20134328Sbostic if (prec > MAXFRACT) { 20234475Sbostic if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) 20334475Sbostic fpprec = prec - MAXFRACT; 20434328Sbostic prec = MAXFRACT; 20534328Sbostic } 20634624Sbostic else if (prec == -1) 20734624Sbostic prec = DEFPREC; 20834669Sbostic /* 20934669Sbostic * softsign avoids negative 0 if _double is < 0 and 21034669Sbostic * no significant digits will be shown 21134669Sbostic */ 21234624Sbostic if (_double < 0) { 21334669Sbostic softsign = '-'; 21434624Sbostic _double = -_double; 21534624Sbostic } 21634669Sbostic else 21734669Sbostic softsign = 0; 21834624Sbostic /* 21934669Sbostic * cvt may have to round up past the "start" of the 22034624Sbostic * buffer, i.e. ``intf("%.2f", (double)9.999);''; 22134624Sbostic * if the first char isn't NULL, it did. 22234624Sbostic */ 22334624Sbostic *buf = NULL; 22434669Sbostic size = cvt(_double, prec, flags, &softsign, *fmt, buf, 22534624Sbostic buf + sizeof(buf)); 22634669Sbostic if (softsign) 22734669Sbostic sign = '-'; 22834624Sbostic t = *buf ? buf : buf + 1; 22934314Sbostic goto pforw; 23034235Sbostic case 'n': 23134427Sbostic if (flags & LONGINT) 23234318Sbostic *va_arg(argp, long *) = cnt; 23334427Sbostic else if (flags & SHORTINT) 23434318Sbostic *va_arg(argp, short *) = cnt; 23534318Sbostic else 23634318Sbostic *va_arg(argp, int *) = cnt; 23734235Sbostic break; 23834624Sbostic case 'O': 23934624Sbostic flags |= LONGINT; 24034624Sbostic /*FALLTHROUGH*/ 24134226Sbostic case 'o': 24236090Sbostic ARG(unsigned); 24334226Sbostic base = 8; 24434327Sbostic goto nosign; 24534235Sbostic case 'p': 24634320Sbostic /* 24734321Sbostic * ``The argument shall be a pointer to void. The 24834321Sbostic * value of the pointer is converted to a sequence 24934321Sbostic * of printable characters, in an implementation- 25034321Sbostic * defined manner.'' 25134321Sbostic * -- ANSI X3J11 25234320Sbostic */ 25334427Sbostic /* NOSTRICT */ 25434320Sbostic _ulong = (u_long)va_arg(argp, void *); 25534320Sbostic base = 16; 25634327Sbostic goto nosign; 25734226Sbostic case 's': 25834314Sbostic if (!(t = va_arg(argp, char *))) 25934314Sbostic t = "(null)"; 26034321Sbostic if (prec >= 0) { 26134321Sbostic /* 26234321Sbostic * can't use strlen; can only look for the 26334321Sbostic * NUL in the first `prec' characters, and 26434321Sbostic * strlen() will go further. 26534321Sbostic */ 26634321Sbostic char *p, *memchr(); 26734321Sbostic 26834321Sbostic if (p = memchr(t, 0, prec)) { 26934321Sbostic size = p - t; 27034321Sbostic if (size > prec) 27134321Sbostic size = prec; 27234427Sbostic } else 27334321Sbostic size = prec; 27434427Sbostic } else 27534321Sbostic size = strlen(t); 27634427Sbostic sign = '\0'; 27734328Sbostic goto pforw; 27834624Sbostic case 'U': 27934624Sbostic flags |= LONGINT; 28034624Sbostic /*FALLTHROUGH*/ 28134226Sbostic case 'u': 28236090Sbostic ARG(unsigned); 28334226Sbostic base = 10; 28434327Sbostic goto nosign; 28534226Sbostic case 'X': 28634226Sbostic digs = "0123456789ABCDEF"; 28734427Sbostic /* FALLTHROUGH */ 28834226Sbostic case 'x': 28936090Sbostic ARG(unsigned); 29034314Sbostic base = 16; 29134326Sbostic /* leading 0x/X only if non-zero */ 29234427Sbostic if (flags & ALT && _ulong != 0) 29334427Sbostic flags |= HEXPREFIX; 29434327Sbostic 29534327Sbostic /* unsigned conversions */ 29634427Sbostic nosign: sign = '\0'; 29734326Sbostic /* 29834330Sbostic * ``... diouXx conversions ... if a precision is 29934330Sbostic * specified, the 0 flag will be ignored.'' 30034330Sbostic * -- ANSI X3J11 30134330Sbostic */ 30234427Sbostic number: if ((dprec = prec) >= 0) 30334427Sbostic flags &= ~ZEROPAD; 30434427Sbostic 30534330Sbostic /* 30634326Sbostic * ``The result of converting a zero value with an 30734326Sbostic * explicit precision of zero is no characters.'' 30834326Sbostic * -- ANSI X3J11 30934326Sbostic */ 31034427Sbostic t = buf + BUF; 31134427Sbostic if (_ulong != 0 || prec != 0) { 31234427Sbostic do { 31334427Sbostic *--t = digs[_ulong % base]; 31434427Sbostic _ulong /= base; 31534427Sbostic } while (_ulong); 31634427Sbostic digs = "0123456789abcdef"; 31734427Sbostic if (flags & ALT && base == 8 && *t != '0') 31834427Sbostic *--t = '0'; /* octal leading 0 */ 31934330Sbostic } 32034427Sbostic size = buf + BUF - t; 32134327Sbostic 32234427Sbostic pforw: 32334427Sbostic /* 32434624Sbostic * All reasonable formats wind up here. At this point, 32534624Sbostic * `t' points to a string which (if not flags&LADJUST) 32634624Sbostic * should be padded out to `width' places. If 32734624Sbostic * flags&ZEROPAD, it should first be prefixed by any 32834624Sbostic * sign or other prefix; otherwise, it should be blank 32934624Sbostic * padded before the prefix is emitted. After any 33034624Sbostic * left-hand padding and prefixing, emit zeroes 33134624Sbostic * required by a decimal [diouxX] precision, then print 33234624Sbostic * the string proper, then emit zeroes required by any 33334624Sbostic * leftover floating precision; finally, if LADJUST, 33434624Sbostic * pad with blanks. 33534427Sbostic */ 33634327Sbostic 33734624Sbostic /* 33834624Sbostic * compute actual size, so we know how much to pad 33934624Sbostic * fieldsz excludes decimal prec; realsz includes it 34034624Sbostic */ 34134427Sbostic fieldsz = size + fpprec; 34234427Sbostic if (sign) 34334427Sbostic fieldsz++; 34434427Sbostic if (flags & HEXPREFIX) 34534427Sbostic fieldsz += 2; 34634427Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 34734327Sbostic 34834427Sbostic /* right-adjusting blank padding */ 34934427Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0 && width) 35034427Sbostic for (n = realsz; n < width; n++) 35134427Sbostic PUTC(' '); 35234427Sbostic /* prefix */ 35334427Sbostic if (sign) 35434427Sbostic PUTC(sign); 35534427Sbostic if (flags & HEXPREFIX) { 35634427Sbostic PUTC('0'); 35734427Sbostic PUTC((char)*fmt); 35834327Sbostic } 35934427Sbostic /* right-adjusting zero padding */ 36034427Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 36134427Sbostic for (n = realsz; n < width; n++) 36234427Sbostic PUTC('0'); 36334427Sbostic /* leading zeroes from decimal precision */ 36434427Sbostic for (n = fieldsz; n < dprec; n++) 36534427Sbostic PUTC('0'); 36634327Sbostic 36734427Sbostic /* the string or number proper */ 36837234Sbostic n = size; 36937234Sbostic if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) { 37034328Sbostic fp->_cnt -= n; 37134427Sbostic bcopy(t, (char *)fp->_ptr, n); 37234328Sbostic fp->_ptr += n; 37334427Sbostic } else 37434427Sbostic while (--n >= 0) 37534427Sbostic PUTC(*t++); 37634427Sbostic /* trailing f.p. zeroes */ 37734427Sbostic while (--fpprec >= 0) 37834328Sbostic PUTC('0'); 37934427Sbostic /* left-adjusting padding (always blank) */ 38034427Sbostic if (flags & LADJUST) 38134427Sbostic for (n = realsz; n < width; n++) 38234328Sbostic PUTC(' '); 38334427Sbostic /* finally, adjust cnt */ 38434427Sbostic cnt += width > realsz ? width : realsz; 38534226Sbostic break; 38634427Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 38734427Sbostic return (cnt); 38834226Sbostic default: 38934427Sbostic PUTC((char)*fmt); 39034427Sbostic cnt++; 39134226Sbostic } 39234226Sbostic } 39334427Sbostic /* NOTREACHED */ 39434226Sbostic } 39534242Sbostic 39634624Sbostic static 39734669Sbostic cvt(number, prec, flags, signp, fmtch, startp, endp) 39834242Sbostic double number; 39934261Sbostic register int prec; 40034323Sbostic int flags; 40134323Sbostic u_char fmtch; 40234669Sbostic char *signp, *startp, *endp; 40334242Sbostic { 40434331Sbostic register char *p, *t; 40534672Sbostic register double fract; 40634624Sbostic int dotrim, expcnt, gformat; 40734672Sbostic double integer, tmp, modf(); 40834669Sbostic char *exponent(), *round(); 40934242Sbostic 410*44426Sbostic #ifdef hp300 411*44426Sbostic if (expcnt = isspecial(number, startp, signp)) 412*44426Sbostic return(expcnt); 413*44426Sbostic #endif 414*44426Sbostic 41534624Sbostic dotrim = expcnt = gformat = 0; 41634624Sbostic fract = modf(number, &integer); 41734242Sbostic 41834624Sbostic /* get an extra slot for rounding. */ 41934624Sbostic t = ++startp; 42034624Sbostic 42134624Sbostic /* 42234624Sbostic * get integer portion of number; put into the end of the buffer; the 42334624Sbostic * .01 is added for modf(356.0 / 10, &integer) returning .59999999... 42434624Sbostic */ 42534624Sbostic for (p = endp - 1; integer; ++expcnt) { 42634624Sbostic tmp = modf(integer / 10, &integer); 42734624Sbostic *p-- = tochar((int)((tmp + .01) * 10)); 42834248Sbostic } 42934261Sbostic switch(fmtch) { 43034261Sbostic case 'f': 43134624Sbostic /* reverse integer into beginning of buffer */ 43234624Sbostic if (expcnt) 43334624Sbostic for (; ++p < endp; *t++ = *p); 43434624Sbostic else 43534624Sbostic *t++ = '0'; 43634248Sbostic /* 43734624Sbostic * if precision required or alternate flag set, add in a 43834624Sbostic * decimal point. 43934248Sbostic */ 44034624Sbostic if (prec || flags&ALT) 44134624Sbostic *t++ = '.'; 44234624Sbostic /* if requires more precision and some fraction left */ 44334624Sbostic if (fract) { 44434624Sbostic if (prec) 44534624Sbostic do { 44634624Sbostic fract = modf(fract * 10, &tmp); 44734624Sbostic *t++ = tochar((int)tmp); 44834624Sbostic } while (--prec && fract); 44934624Sbostic if (fract) 45034669Sbostic startp = round(fract, (int *)NULL, startp, 45134669Sbostic t - 1, (char)0, signp); 45234624Sbostic } 45334624Sbostic for (; prec--; *t++ = '0'); 45434624Sbostic break; 45534624Sbostic case 'e': 45634624Sbostic case 'E': 45734624Sbostic eformat: if (expcnt) { 45834624Sbostic *t++ = *++p; 45934624Sbostic if (prec || flags&ALT) 46034331Sbostic *t++ = '.'; 46134624Sbostic /* if requires more precision and some integer left */ 46234624Sbostic for (; prec && ++p < endp; --prec) 46334624Sbostic *t++ = *p; 46434624Sbostic /* 46534624Sbostic * if done precision and more of the integer component, 46634624Sbostic * round using it; adjust fract so we don't re-round 46734624Sbostic * later. 46834624Sbostic */ 46934624Sbostic if (!prec && ++p < endp) { 47034248Sbostic fract = 0; 47134669Sbostic startp = round((double)0, &expcnt, startp, 47234669Sbostic t - 1, *p, signp); 47334248Sbostic } 47434624Sbostic /* adjust expcnt for digit in front of decimal */ 47534624Sbostic --expcnt; 47634242Sbostic } 47734624Sbostic /* until first fractional digit, decrement exponent */ 47834624Sbostic else if (fract) { 47934624Sbostic /* adjust expcnt for digit in front of decimal */ 48034624Sbostic for (expcnt = -1;; --expcnt) { 48134624Sbostic fract = modf(fract * 10, &tmp); 48234624Sbostic if (tmp) 48334624Sbostic break; 48434248Sbostic } 48534624Sbostic *t++ = tochar((int)tmp); 48634624Sbostic if (prec || flags&ALT) 48734331Sbostic *t++ = '.'; 48834242Sbostic } 48934248Sbostic else { 49034624Sbostic *t++ = '0'; 49134624Sbostic if (prec || flags&ALT) 49234331Sbostic *t++ = '.'; 49334248Sbostic } 49434624Sbostic /* if requires more precision and some fraction left */ 49534624Sbostic if (fract) { 49634624Sbostic if (prec) 49734624Sbostic do { 49834624Sbostic fract = modf(fract * 10, &tmp); 49934624Sbostic *t++ = tochar((int)tmp); 50034624Sbostic } while (--prec && fract); 50134624Sbostic if (fract) 50234669Sbostic startp = round(fract, &expcnt, startp, 50334669Sbostic t - 1, (char)0, signp); 50434584Sbostic } 50534624Sbostic /* if requires more precision */ 50634624Sbostic for (; prec--; *t++ = '0'); 50734624Sbostic 50834624Sbostic /* unless alternate flag, trim any g/G format trailing 0's */ 50934624Sbostic if (gformat && !(flags&ALT)) { 51034624Sbostic while (t > startp && *--t == '0'); 51134624Sbostic if (*t == '.') 51234624Sbostic --t; 51334624Sbostic ++t; 51434624Sbostic } 51534624Sbostic t = exponent(t, expcnt, fmtch); 51634624Sbostic break; 51734624Sbostic case 'g': 51834624Sbostic case 'G': 51934624Sbostic /* a precision of 0 is treated as a precision of 1. */ 52034624Sbostic if (!prec) 52134624Sbostic ++prec; 52234624Sbostic /* 52334624Sbostic * ``The style used depends on the value converted; style e 52434624Sbostic * will be used only if the exponent resulting from the 52534624Sbostic * conversion is less than -4 or greater than the precision.'' 52634624Sbostic * -- ANSI X3J11 52734624Sbostic */ 52834624Sbostic if (expcnt > prec || !expcnt && fract && fract < .0001) { 52934624Sbostic /* 53034624Sbostic * g/G format counts "significant digits, not digits of 53134624Sbostic * precision; for the e/E format, this just causes an 53234624Sbostic * off-by-one problem, i.e. g/G considers the digit 53334624Sbostic * before the decimal point significant and e/E doesn't 53434624Sbostic * count it as precision. 53534624Sbostic */ 53634624Sbostic --prec; 53734624Sbostic fmtch -= 2; /* G->E, g->e */ 53834624Sbostic gformat = 1; 53934624Sbostic goto eformat; 54034624Sbostic } 54134624Sbostic /* 54234624Sbostic * reverse integer into beginning of buffer, 54334624Sbostic * note, decrement precision 54434624Sbostic */ 54534624Sbostic if (expcnt) 54634624Sbostic for (; ++p < endp; *t++ = *p, --prec); 54734624Sbostic else 54834624Sbostic *t++ = '0'; 54934624Sbostic /* 55034624Sbostic * if precision required or alternate flag set, add in a 55134624Sbostic * decimal point. If no digits yet, add in leading 0. 55234624Sbostic */ 55334624Sbostic if (prec || flags&ALT) { 55434624Sbostic dotrim = 1; 55534624Sbostic *t++ = '.'; 55634624Sbostic } 55734624Sbostic else 55834624Sbostic dotrim = 0; 55934624Sbostic /* if requires more precision and some fraction left */ 56034624Sbostic if (fract) { 56134624Sbostic if (prec) { 56234624Sbostic do { 56334624Sbostic fract = modf(fract * 10, &tmp); 56434624Sbostic *t++ = tochar((int)tmp); 56534624Sbostic } while(!tmp); 56634624Sbostic while (--prec && fract) { 56734624Sbostic fract = modf(fract * 10, &tmp); 56834624Sbostic *t++ = tochar((int)tmp); 56934248Sbostic } 57034248Sbostic } 57134624Sbostic if (fract) 57234669Sbostic startp = round(fract, (int *)NULL, startp, 57334669Sbostic t - 1, (char)0, signp); 57434624Sbostic } 57534624Sbostic /* alternate format, adds 0's for precision, else trim 0's */ 57634624Sbostic if (flags&ALT) 57734624Sbostic for (; prec--; *t++ = '0'); 57834624Sbostic else if (dotrim) { 57934624Sbostic while (t > startp && *--t == '0'); 58034624Sbostic if (*t != '.') 58134624Sbostic ++t; 58234624Sbostic } 58334624Sbostic } 58434624Sbostic return(t - startp); 58534624Sbostic } 58634248Sbostic 58734624Sbostic static char * 58834669Sbostic round(fract, exp, start, end, ch, signp) 58934624Sbostic double fract; 59034669Sbostic int *exp; 59134624Sbostic register char *start, *end; 59234669Sbostic char ch, *signp; 59334624Sbostic { 59434624Sbostic double tmp; 59534248Sbostic 59634624Sbostic if (fract) 59734248Sbostic (void)modf(fract * 10, &tmp); 59834624Sbostic else 59934624Sbostic tmp = todigit(ch); 60034624Sbostic if (tmp > 4) 60134624Sbostic for (;; --end) { 60234624Sbostic if (*end == '.') 60334624Sbostic --end; 60434624Sbostic if (++*end <= '9') 60534624Sbostic break; 60634624Sbostic *end = '0'; 60734624Sbostic if (end == start) { 60834669Sbostic if (exp) { /* e/E; increment exponent */ 60934669Sbostic *end = '1'; 61034669Sbostic ++*exp; 61134669Sbostic } 61234669Sbostic else { /* f; add extra digit */ 61334669Sbostic *--end = '1'; 61434669Sbostic --start; 61534669Sbostic } 61634624Sbostic break; 61734242Sbostic } 61834242Sbostic } 61934669Sbostic /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ 62034669Sbostic else if (*signp == '-') 62134669Sbostic for (;; --end) { 62234669Sbostic if (*end == '.') 62334669Sbostic --end; 62434669Sbostic if (*end != '0') 62534669Sbostic break; 62634669Sbostic if (end == start) 62734669Sbostic *signp = 0; 62834669Sbostic } 62934624Sbostic return(start); 63034624Sbostic } 63134248Sbostic 63234624Sbostic static char * 63334624Sbostic exponent(p, exp, fmtch) 63434624Sbostic register char *p; 63534624Sbostic register int exp; 63634624Sbostic u_char fmtch; 63734624Sbostic { 63834624Sbostic register char *t; 63934624Sbostic char expbuf[MAXEXP]; 64034248Sbostic 64134624Sbostic *p++ = fmtch; 64234624Sbostic if (exp < 0) { 64334624Sbostic exp = -exp; 64434624Sbostic *p++ = '-'; 64534242Sbostic } 64634624Sbostic else 64734624Sbostic *p++ = '+'; 64834624Sbostic t = expbuf + MAXEXP; 64934624Sbostic if (exp > 9) { 65034624Sbostic do { 65134624Sbostic *--t = tochar(exp % 10); 65234624Sbostic } while ((exp /= 10) > 9); 65334624Sbostic *--t = tochar(exp); 65434624Sbostic for (; t < expbuf + MAXEXP; *p++ = *t++); 65534624Sbostic } 65634624Sbostic else { 65734624Sbostic *p++ = '0'; 65834624Sbostic *p++ = tochar(exp); 65934624Sbostic } 66034323Sbostic return(p); 66134242Sbostic } 662*44426Sbostic 663*44426Sbostic #ifdef hp300 664*44426Sbostic isspecial(d, bufp, signp) 665*44426Sbostic double d; 666*44426Sbostic char *bufp, *signp; 667*44426Sbostic { 668*44426Sbostic register struct IEEEdp { 669*44426Sbostic unsigned sign:1; 670*44426Sbostic unsigned exp:11; 671*44426Sbostic unsigned manh:20; 672*44426Sbostic unsigned manl:32; 673*44426Sbostic } *ip = (struct IEEEdp *)&d; 674*44426Sbostic 675*44426Sbostic if (ip->exp != 0x7ff) 676*44426Sbostic return(0); 677*44426Sbostic if (ip->manh || ip->manl) 678*44426Sbostic (void)strcpy(bufp, "NaN"); 679*44426Sbostic else 680*44426Sbostic (void)strcpy(bufp, "Inf"); 681*44426Sbostic return(3); 682*44426Sbostic } 683*44426Sbostic #endif 684