+ PUTC(*fmt);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+#define EFORMAT 0x01
+#define FFORMAT 0x02
+#define GFORMAT 0x04
+#define DEFPREC 6
+
+static char *
+_cvt(number, prec, flags, fmtch, padc, sign, startp, endp)
+ double number;
+ register int prec;
+ int flags;
+ u_char fmtch;
+ char padc, *sign, *startp, *endp;
+{
+ register char *p, *t;
+ register int expcnt, format;
+ double fract, integer, tmp, modf();
+ int decpt;
+ char *savep, exponent[MAXEXP];
+
+ if (prec == -1)
+ prec = DEFPREC;
+
+ if (number < 0) {
+ *sign = '-';
+ number = -number;
+ }
+
+ /* if blank padded, add sign in as part of the number */
+ if (*sign && padc == ' ')
+ *startp++ = *sign;
+
+ switch(fmtch) {
+ case 'e':
+ case 'E':
+ format = EFORMAT;
+ break;
+ case 'f':
+ format = FFORMAT;
+ break;
+ case 'g':
+ case 'G':
+ format = GFORMAT;
+ fmtch -= 2;
+ }
+
+ /*
+ * if the alternate flag is set, or, at least one digit of precision
+ * was requested, add a decimal point, unless it's the g/G format
+ * in which case we require two digits of precision, as it counts
+ * precision differently.
+ */
+ decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0);
+
+ expcnt = 0;
+ p = endp - 1;
+ fract = modf(number, &integer);
+ if (integer) {
+ /* get integer part of number; count decimal places */
+ for (; integer; ++expcnt) {
+ tmp = modf(integer / 10, &integer);
+ *p-- = tochar((int)((tmp + .03) * 10));
+ }
+
+ /* copy, in reverse order, to start of buffer */
+ t = startp;
+ *t++ = *++p;
+
+ /*
+ * if the format is g/G, and the resulting exponent will be
+ * greater than the precision, use e/E format. If e/E format,
+ * put in a decimal point as needed, and decrement precision
+ * count for each digit after the decimal point.
+ */
+ if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) {
+ if (format&GFORMAT) {
+ format |= EFORMAT;
+
+ /* first digit is precision for g/G format */
+ if (prec)
+ --prec;
+ }
+ if (decpt)
+ *t++ = '.';
+ for (; ++p < endp && prec; --prec, *t++ = *p);
+
+ /* precision ran out, round */
+ if (p < endp) {
+ if (*p > '4') {
+ for (savep = t--;; *t-- = '0') {
+ if (*t == '.')
+ --t;
+ if (++*t <= '9')
+ break;
+ }
+ t = savep;
+ }
+ fract = 0;
+ }
+ }
+ /*
+ * g/G in f format; if out of precision, replace digits with
+ * zeroes, note, have to round first.
+ */
+ else if (format&GFORMAT) {
+ for (; ++p < endp && prec; --prec, *t++ = *p);
+ /* precision ran out; round and then add zeroes */
+ if (p < endp) {
+ if (*p > '4') {
+ for (savep = t--; ++*t > '9';
+ *t-- = '0');
+ t = savep;
+ }
+ do {
+ *t++ = '0';
+ } while (++p < endp);
+ fract = 0;
+ }
+ if (decpt)
+ *t++ = '.';
+ }
+ /* f format */
+ else {
+ for (; ++p < endp; *t++ = *p);
+ if (decpt)
+ *t++ = '.';
+ }
+ p = t;
+ }
+ /*
+ * if no fraction, the number was zero, and if no precision, can't
+ * show anything after the decimal point.
+ */
+ else if (!fract || !prec) {
+ *startp++ = '0';
+ if (decpt && !(format&GFORMAT))
+ *startp++ = '.';
+ *startp = '\0';
+ return(startp);
+ }
+ /*
+ * if the format is g/G, and the resulting exponent will be less than
+ * -4 use e/E format. If e/E format, compute exponent value.
+ */
+ else if (format&GFORMAT && fract < .0001 || format&EFORMAT) {
+ format |= EFORMAT;
+ if (fract)
+ for (p = startp; fract;) {
+ fract = modf(fract * 10, &tmp);
+ if (!tmp) {
+ --expcnt;
+ continue;
+ }
+ *p++ = tochar((int)tmp);
+ break;
+ }
+ else
+ *p++ = '0';
+
+ /* g/G format, decrement precision for first digit */
+ if (format&GFORMAT && prec)
+ --prec;
+
+ /* add decimal after first non-zero digit */
+ if (decpt)
+ *p++ = '.';
+ }
+ /*
+ * f format or g/G printed as f format; don't worry about decimal
+ * point, if g/G format doesn't need it, will get stripped later.
+ */
+ else {
+ p = startp;
+ *p++ = '0';
+ *p++ = '.';
+ }
+
+ /* finish out requested precision */
+ while (fract && prec-- > 0) {
+ fract = modf(fract * 10, &tmp);
+ *p++ = tochar((int)tmp);
+ }
+ while (prec-- > 0)
+ *p++ = '0';
+
+ /*
+ * if any fractional value left, "round" it back up to the beginning
+ * of the number, fixing the exponent as necessary, and avoiding the
+ * decimal point.
+ */
+ if (fract) {
+ (void)modf(fract * 10, &tmp);
+ if (tmp > 4) {
+ for (savep = p--;; *p-- = '0') {
+ if (*p == '.')
+ --p;
+ if (p == startp) {
+ *p = '1';
+ ++expcnt;
+ break;
+ }
+ if (++*p <= '9')
+ break;
+ }
+ p = savep;
+ }
+ }
+
+ /*
+ * if a g/G format and not alternate flag, lose trailing zeroes,
+ * if e/E or g/G format, and last char is decimal point, lose it.
+ */
+ if (!(flags&ALT)) {
+ if (format&GFORMAT)
+ for (; p[-1] == '0'; --p);
+ if (format&(GFORMAT|EFORMAT) && p[-1] == '.')
+ --p;
+ }
+
+ /* if an e/E format, add exponent */
+ if (format&EFORMAT) {
+ *p++ = fmtch;
+ if (--expcnt < 0) {
+ expcnt = -expcnt;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = exponent + MAXEXP;
+ if (expcnt > 9) {
+ do {
+ *--t = tochar(expcnt % 10);
+ } while ((expcnt /= 10) > 9);
+ *--t = tochar(expcnt);
+ for (; t < exponent + MAXEXP; *p++ = *t++);
+ }
+ else {
+ *p++ = '0';
+ *p++ = tochar(expcnt);