home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mntlib18 / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  19.0 KB  |  764 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  * and for the sfp004 as well as the TT's 68881
  22.  *      mjr++
  23.  */
  24.  
  25. #ifndef __NO_FLOAT__
  26. static unsigned long
  27.     __notanumber[2] = { 0x7fffffffL, 0xffffffffL }; /* ieee NAN */
  28. #define NAN  (*((double *)&__notanumber[0]))
  29. static unsigned long
  30.     __p_infinity[2] = { 0x7ff00000L, 0x00000000L }; /* ieee NAN */
  31. #define INF  (*((double *)&__p_infinity[0]))
  32. #endif
  33.  
  34. #ifdef LIBC_SCCS
  35. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  36. #endif /* LIBC_SCCS */
  37.  
  38. #include <sys/types.h>
  39. #include <stdarg.h>
  40. #include <stdio.h>
  41. #include <ctype.h>
  42. #include <string.h>
  43. #include <limits.h>
  44. #include <math.h>    /* mjr++    */
  45.  
  46. #ifndef __MINT__    /* mintlib has these typedefs in sys/types.h */
  47. typedef unsigned char u_char;
  48. typedef unsigned long u_long;
  49. #endif
  50.  
  51. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  52. #define    MAXEXP        308
  53.  
  54. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  55. #define    MAXFRACT    39
  56.  
  57. #if defined (__M68881__) && !defined (sfp004) && !defined(__MINT__)
  58. # include <math-68881.h>    /* mjr: use the inline functions */
  59. #endif /* __M68881__ */
  60.  
  61. #define    DEFPREC        6
  62.  
  63. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  64.  
  65. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  66.  
  67. #define ARG(basetype) \
  68.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  69.         flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
  70.         va_arg(argp, int)
  71.  
  72. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  73.  
  74. #define    todigit(c)    ((c) - '0')
  75. #define    tochar(n)    ((n) + '0')
  76.  
  77. #define    LONGINT        0x01        /* long integer */
  78. #define    LONGDBL        0x02        /* long double; unimplemented */
  79. #define    SHORTINT    0x04        /* short integer */
  80. #define    ALT        0x08        /* alternate form */
  81. #define    LADJUST        0x10        /* left adjustment */
  82. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  83. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  84.  
  85. #ifndef __NO_FLOAT__
  86. #define __FLOATS__ 1
  87. #endif
  88.  
  89. #ifdef __FLOATS__
  90. #include "flonum.h"
  91. static char *exponent    __PROTO((char *, int, int));
  92. static char *round    __PROTO((double, int *, char *, char *, int, char *));
  93. static int  cvt        __PROTO((double, int, int, char *, int, char *, char *));
  94. #endif
  95.  
  96. #ifdef __GNUC__
  97. #define _ICONV(NUMBER, BASE, BUF)                 \
  98. {                                \
  99.     short i;                            \
  100.     if(NUMBER <= 65535L)                    \
  101.     {                                \
  102.     do                             \
  103.     {                            \
  104.         __asm__ volatile("  \
  105.          divu    %3,%2;  \
  106.          swap    %0;     \
  107.          movw    %0,%1;  \
  108.          clrw    %0;     \
  109.                 swap    %0"                    \
  110.              : "=d"((long)NUMBER), "=g"(i)            \
  111.          : "0"((long)NUMBER), "g"((short)BASE));    \
  112.         *--BUF = digs[i];                    \
  113.     } while(NUMBER);                    \
  114.     }                                \
  115.     else                            \
  116.     {                                \
  117.     extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */     \
  118.     do                             \
  119.     {                            \
  120.         __asm__ volatile("        \
  121.          movl    %3,sp@-;      \
  122.          movl    %2,sp@-;      \
  123.          jsr    ___udivsi3;    \
  124.          movl    d0,%0;        \
  125.          movw    d1,%1;        \
  126.          addqw    #8,sp"                    \
  127.              : "=g"((long)NUMBER), "=g"(i)            \
  128.          : "0"((long)NUMBER), "g"((long)BASE)        \
  129.              : "d0", "d1", "a0", "a1");            \
  130.         *--BUF = digs[i];                    \
  131.     } while(NUMBER);                    \
  132.     }                                \
  133. }
  134. #endif /* __GNUC__ */
  135.  
  136.  
  137. int _doprnt(fp, fmt0, argp)
  138.     register FILE *fp;
  139.     const char *fmt0;
  140.     va_list argp;
  141. {
  142.     register const u_char *fmt; /* format string */
  143.     register int ch;    /* character from fmt */
  144.     register int cnt;    /* return value accumulator */
  145.     register int n;        /* random handy integer */
  146.     register char *t;    /* buffer pointer */
  147. #ifdef __FLOATS__
  148. /*    double _double; */    /* double precision arguments %[eEfgG] */
  149.     union double_di _dd;    /* double is #defined to be _dd later on */
  150.     char softsign;        /* temporary negative sign for floats */
  151. #endif
  152.     u_long _ulong;        /* integer arguments %[diouxX] */
  153.     short base;        /* base for [diouxX] conversion */
  154.     short dprec;        /* decimal precision in [diouxX] */
  155.     short fieldsz;        /* field size expanded by sign, etc */
  156.     short flags;        /* flags as above */
  157.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  158.     short prec;        /* precision from format (%.3d), or -1 */
  159.     short realsz;        /* field size expanded by decimal precision */
  160.     short size;        /* size of converted field or string */
  161.     short width;        /* width from format (%8d), or 0 */
  162.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  163.     char *digs;        /* digits for [diouxX] conversion */
  164.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  165.  
  166.     t = buf;
  167.     fmt = (const u_char *) fmt0;
  168.     digs = "0123456789abcdef";
  169.     for (cnt = 0;; ++fmt) {
  170.         if (!(ch = *fmt))
  171.             return (cnt);
  172.         if (ch != '%') {
  173.             PUTC(ch);
  174.             cnt++;
  175.             continue;
  176.         }
  177.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  178.         prec = -1;
  179.         sign = '\0';
  180.  
  181. rflag:        switch (*++fmt) {
  182.         case ' ':
  183.             /*
  184.              * ``If the space and + flags both appear, the space
  185.              * flag will be ignored.''
  186.              *    -- ANSI X3J11
  187.              */
  188.             if (!sign)
  189.                 sign = ' ';
  190.             goto rflag;
  191.         case '#':
  192.             flags |= ALT;
  193.             goto rflag;
  194.         case '*':
  195.             /*
  196.              * ``A negative field width argument is taken as a
  197.              * - flag followed by a  positive field width.''
  198.              *    -- ANSI X3J11
  199.              * They don't exclude field widths read from args.
  200.              */
  201.             if ((width = (short)(va_arg(argp, int))) >= 0)
  202.                 goto rflag;
  203.             width = -width;
  204.             /* FALLTHROUGH */
  205.         case '-':
  206.             flags |= LADJUST;
  207.             goto rflag;
  208.         case '+':
  209.             sign = '+';
  210.             goto rflag;
  211.         case '.':
  212.             if (*++fmt == '*')
  213.                 n = va_arg(argp, int);
  214.             else {
  215.                 n = 0;
  216.                 while (isascii(*fmt) && isdigit(*fmt))
  217.                     n = TEN_MUL(n) + todigit(*fmt++);
  218.                 --fmt;
  219.             }
  220.             prec = n < 0 ? -1 : n;
  221.             goto rflag;
  222.         case '0':
  223.             /*
  224.              * ``Note that 0 is taken as a flag, not as the
  225.              * beginning of a field width.''
  226.              *    -- ANSI X3J11
  227.              */
  228.             flags |= ZEROPAD;
  229.             goto rflag;
  230.         case '1': case '2': case '3': case '4':
  231.         case '5': case '6': case '7': case '8': case '9':
  232.             n = 0;
  233.             do {
  234.                 n = TEN_MUL(n) + todigit(*fmt);
  235.             } while (isascii(*++fmt) && isdigit(*fmt));
  236.             width = n;
  237.             --fmt;
  238.             goto rflag;
  239.         case 'L':
  240.             flags |= LONGDBL;
  241.             goto rflag;
  242.         case 'h':
  243.             flags |= SHORTINT;
  244.             goto rflag;
  245.         case 'l':
  246.             flags |= LONGINT;
  247.             goto rflag;
  248.         case 'c':
  249.             *(t = buf) = va_arg(argp, int);
  250.             size = 1;
  251.             sign = '\0';
  252.             goto pforw;
  253.         case 'D':
  254.             flags |= LONGINT;
  255.             /*FALLTHROUGH*/
  256.         case 'd':
  257.         case 'i':
  258.             ARG(int);
  259.             if ((long)_ulong < 0) {
  260.                 _ulong = -_ulong;
  261.                 sign = '-';
  262.             }
  263.             base = 10;
  264.             goto number;
  265. #ifdef __FLOATS__
  266.         case 'e':
  267.         case 'E':
  268.         case 'f':
  269.         case 'g':
  270.         case 'G':
  271.  
  272. /* mjr: check for NANs */
  273. #define    _double _dd.d
  274.             _double = va_arg(argp, double);
  275.             if( (unsigned long)_dd.i[0] == __notanumber[0])    {
  276.                 t = strcpy(t, " Not A Number ");
  277.                 size = strlen(t);
  278.                 goto pforw;
  279.             }
  280.             /*
  281.              * don't do unrealistic precision; just pad it with
  282.              * zeroes later, so buffer size stays rational.
  283.              */
  284.             if (prec > MAXFRACT) {
  285.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  286.                     fpprec = prec - MAXFRACT;
  287.                 prec = MAXFRACT;
  288.             }
  289.             else if (prec == -1)
  290.                 prec = DEFPREC;
  291.             /*
  292.              * softsign avoids negative 0 if _double is < 0 and
  293.              * no significant digits will be shown
  294.              */
  295.             if (_double < 0) {
  296.                 softsign = '-';
  297.                 _double = -_double;
  298.             }
  299.             else
  300.                 softsign = 0;
  301. /* mjr: check for +-INFINITY */
  302.             if(
  303.                 ((unsigned long)_dd.i[0] == __p_infinity[0])
  304. /*              && ((unsigned long)_dd.i[1] == __p_infinity[1]) */
  305. /* mjr: don't test this in order to catch a conversion bug in gcc-as     */
  306.             )    {
  307.             if(softsign == 0)
  308.                 t = strcpy(t, " Infinity ");
  309.             else
  310.                 t = strcpy(t, " -Infinity ");
  311.                 size = strlen(t);
  312.                 goto pforw;
  313.             }
  314.             /*
  315.              * cvt may have to round up past the "start" of the
  316.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  317.              * if the first char isn't NULL, it did.
  318.              */
  319.             *buf = (char)NULL;
  320.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  321.                    *fmt, buf, buf + (int)sizeof(buf)); 
  322.             if (softsign)
  323.                 sign = '-';
  324.             t = *buf ? buf : buf + 1;
  325.             goto pforw;
  326. #endif /* __FLOATS__ */
  327.         case 'n':
  328.             if (flags & LONGINT)
  329.                 *va_arg(argp, long *) = cnt;
  330.             else if (flags & SHORTINT)
  331.                 *va_arg(argp, short *) = cnt;
  332.             else
  333.                 *va_arg(argp, int *) = cnt;
  334.             break;
  335.         case 'O':
  336.             flags |= LONGINT;
  337.             /*FALLTHROUGH*/
  338.         case 'o':
  339.             ARG(unsigned);
  340.             base = 8;
  341.             goto nosign;
  342.         case 'p':
  343.             /*
  344.              * ``The argument shall be a pointer to void.  The
  345.              * value of the pointer is converted to a sequence
  346.              * of printable characters, in an implementation-
  347.              * defined manner.''
  348.              *    -- ANSI X3J11
  349.              */
  350.             /* NOSTRICT */
  351.             _ulong = (u_long)va_arg(argp, void *);
  352.             base = 16;
  353.             goto nosign;
  354.         case 's':
  355.             if (!(t = va_arg(argp, char *)))
  356.                 t = "(null)";
  357.             if (prec >= 0) {
  358.                 /*
  359.                  * can't use strlen; can only look for the
  360.                  * NUL in the first `prec' characters, and
  361.                  * strlen() will go further.
  362.                  */
  363. #ifdef __STDC__
  364.                 char *p;
  365.                 void *memchr(const void *, int, size_t);
  366. #else
  367.                 char *p, *memchr();
  368. #endif
  369.  
  370.                 if (p = (char *)memchr(t, 0, (size_t)prec)) {
  371.                     size = p - t;
  372.                     if (size > prec)
  373.                         size = prec;
  374.                 } else
  375.                     size = prec;
  376.             } else
  377.                 size = (int)strlen(t);
  378.             sign = '\0';
  379.             goto pforw;
  380.         case 'U':
  381.             flags |= LONGINT;
  382.             /*FALLTHROUGH*/
  383.         case 'u':
  384.             ARG(unsigned);
  385.             base = 10;
  386.             goto nosign;
  387.         case 'X':
  388.             digs = "0123456789ABCDEF";
  389.             /* FALLTHROUGH */
  390.         case 'x':
  391.             ARG(unsigned);
  392.             base = 16;
  393.             /* leading 0x/X only if non-zero */
  394.             if (flags & ALT && _ulong != 0)
  395.                 flags |= HEXPREFIX;
  396.  
  397.             /* unsigned conversions */
  398. nosign:            sign = '\0';
  399.             /*
  400.              * ``... diouXx conversions ... if a precision is
  401.              * specified, the 0 flag will be ignored.''
  402.              *    -- ANSI X3J11
  403.              */
  404. number:            if ((dprec = prec) >= 0)
  405.                 flags &= ~ZEROPAD;
  406.  
  407.             /*
  408.              * ``The result of converting a zero value with an
  409.              * explicit precision of zero is no characters.''
  410.              *    -- ANSI X3J11
  411.              */
  412.             t = buf + BUF;
  413.             if (_ulong != 0 || prec != 0) {
  414. #ifndef __GNUC__
  415.                 do {
  416.                     *--t = digs[_ulong % base];
  417.                     _ulong /= base;
  418.                 } while (_ulong);
  419. #else
  420.                 _ICONV(_ulong, base, t);
  421. #endif                
  422.                 digs = "0123456789abcdef";
  423.                 if (flags & ALT && base == 8 && *t != '0')
  424.                     *--t = '0'; /* octal leading 0 */
  425.             }
  426.             size = buf + BUF - t;
  427.  
  428. pforw:
  429.             /*
  430.              * All reasonable formats wind up here.  At this point,
  431.              * `t' points to a string which (if not flags&LADJUST)
  432.              * should be padded out to `width' places.  If
  433.              * flags&ZEROPAD, it should first be prefixed by any
  434.              * sign or other prefix; otherwise, it should be blank
  435.              * padded before the prefix is emitted.  After any
  436.              * left-hand padding and prefixing, emit zeroes
  437.              * required by a decimal [diouxX] precision, then print
  438.              * the string proper, then emit zeroes required by any
  439.              * leftover floating precision; finally, if LADJUST,
  440.              * pad with blanks.
  441.              */
  442.  
  443.             /*
  444.              * compute actual size, so we know how much to pad
  445.              * fieldsz excludes decimal prec; realsz includes it
  446.              */
  447.             fieldsz = size + fpprec;
  448.             if (sign)
  449.                 fieldsz++;
  450.             if (flags & HEXPREFIX)
  451.                 fieldsz += 2;
  452.             realsz = dprec > fieldsz ? dprec : fieldsz;
  453.  
  454.             /* right-adjusting blank padding */
  455.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  456.                 for (n = realsz; n < width; n++)
  457.                     PUTC(' ');
  458.             /* prefix */
  459.             if (sign)
  460.                 PUTC(sign);
  461.             if (flags & HEXPREFIX) {
  462.                 PUTC('0');
  463.                 PUTC((char)*fmt);
  464.             }
  465.             /* right-adjusting zero padding */
  466.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  467.                 for (n = realsz; n < width; n++)
  468.                     PUTC('0');
  469.             /* leading zeroes from decimal precision */
  470.             for (n = fieldsz; n < dprec; n++)
  471.                 PUTC('0');
  472.  
  473.             /* the string or number proper */
  474.             for (n = size; --n >= 0; )
  475.                 PUTC(*t++);
  476.             /* trailing f.p. zeroes */
  477.             while (--fpprec >= 0)
  478.                 PUTC('0');
  479.             /* left-adjusting padding (always blank) */
  480.             if (flags & LADJUST)
  481.                 for (n = realsz; n < width; n++)
  482.                     PUTC(' ');
  483.             /* finally, adjust cnt */
  484.             cnt += width > realsz ? width : realsz;
  485.             break;
  486.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  487.             return (cnt);
  488.         default:
  489.             PUTC((char)*fmt);
  490.             cnt++;
  491.         }
  492.     }
  493.     /* NOTREACHED */
  494. }
  495.  
  496. #ifdef __FLOATS__
  497. static int
  498. cvt(number,prec,flags, signp, fmtch, startp, endp)
  499.     double number;
  500.     register int prec;
  501.     int flags;
  502.     int fmtch;
  503.     char *signp, *startp, *endp;
  504. {
  505.     register char *p, *t;
  506.     register double fract;
  507.     int dotrim, expcnt, gformat;
  508.     double integer, tmp;
  509.     char *exponent __PROTO((char *, int, int)),
  510.          *round __PROTO((double, int *, char *, char *, int, char *));
  511.  
  512.     dotrim = expcnt = gformat = 0;
  513.     fract = modf(number, &integer);
  514.  
  515.     /* get an extra slot for rounding. */
  516.     t = ++startp;
  517.  
  518.     /*
  519.      * get integer portion of number; put into the end of the buffer; the
  520.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  521.      */
  522.     for (p = endp - 1; integer; ++expcnt) {
  523.         tmp = modf(integer / 10, &integer);
  524.         *p-- = tochar((int)((tmp + .01) * 10));
  525.     }
  526.     switch(fmtch) {
  527.     case 'f':
  528.         /* reverse integer into beginning of buffer */
  529.         if (expcnt)
  530.             for (; ++p < endp; *t++ = *p);
  531.         else
  532.             *t++ = '0';
  533.         /*
  534.          * if precision required or alternate flag set, add in a
  535.          * decimal point.
  536.          */
  537.         if (prec || flags&ALT)
  538.             *t++ = '.';
  539.         /* if requires more precision and some fraction left */
  540.         if (fract) {
  541.             if (prec)
  542.                 do {
  543.                     fract = modf(fract * 10, &tmp);
  544.                     *t++ = tochar((int)tmp);
  545.                 } while (--prec && fract);
  546.             if (fract)
  547.                 startp = round(fract, (int *)NULL, startp,
  548.                     t - 1, (char)0, signp);
  549.         }
  550.         for (; prec--; *t++ = '0');
  551.         break;
  552.     case 'e':
  553.     case 'E':
  554. eformat:    if (expcnt) {
  555.             *t++ = *++p;
  556.             if (prec || flags&ALT)
  557.                 *t++ = '.';
  558.             /* if requires more precision and some integer left */
  559.             for (; prec && ++p < endp; --prec)
  560.                 *t++ = *p;
  561.             /*
  562.              * if done precision and more of the integer component,
  563.              * round using it; adjust fract so we don't re-round
  564.              * later.
  565.              */
  566.             if (!prec && ++p < endp) {
  567.                 fract = 0;
  568.                 startp = round((double)0, &expcnt, startp,
  569.                     t - 1, *p, signp);
  570.             }
  571.             /* adjust expcnt for digit in front of decimal */
  572.             --expcnt;
  573.         }
  574.         /* until first fractional digit, decrement exponent */
  575.         else if (fract) {
  576.             /* adjust expcnt for digit in front of decimal */
  577.             for (expcnt = -1;; --expcnt) {
  578.                 fract = modf(fract * 10, &tmp);
  579.                 if (tmp)
  580.                     break;
  581.             }
  582.             *t++ = tochar((int)tmp);
  583.             if (prec || flags&ALT)
  584.                 *t++ = '.';
  585.         }
  586.         else {
  587.             *t++ = '0';
  588.             if (prec || flags&ALT)
  589.                 *t++ = '.';
  590.         }
  591.         /* if requires more precision and some fraction left */
  592.         if (fract) {
  593.             if (prec)
  594.                 do {
  595.                     fract = modf(fract * 10, &tmp);
  596.                     *t++ = tochar((int)tmp);
  597.                 } while (--prec && fract);
  598.             if (fract)
  599.                 startp = round(fract, &expcnt, startp,
  600.                     t - 1, (char)0, signp);
  601.         }
  602.         /* if requires more precision */
  603.         for (; prec--; *t++ = '0');
  604.  
  605.         /* unless alternate flag, trim any g/G format trailing 0's */
  606.         if (gformat && !(flags&ALT)) {
  607.             while (t > startp && *--t == '0');
  608.             if (*t == '.')
  609.                 --t;
  610.             ++t;
  611.         }
  612.         t = exponent(t, expcnt, fmtch);
  613.         break;
  614.     case 'g':
  615.     case 'G':
  616.         /* a precision of 0 is treated as a precision of 1. */
  617.         if (!prec)
  618.             ++prec;
  619.         /*
  620.          * ``The style used depends on the value converted; style e
  621.          * will be used only if the exponent resulting from the
  622.          * conversion is less than -4 or greater than the precision.''
  623.          *    -- ANSI X3J11
  624.          */
  625.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  626.             /*
  627.              * g/G format counts "significant digits, not digits of
  628.              * precision; for the e/E format, this just causes an
  629.              * off-by-one problem, i.e. g/G considers the digit
  630.              * before the decimal point significant and e/E doesn't
  631.              * count it as precision.
  632.              */
  633.             --prec;
  634.             fmtch -= 2;        /* G->E, g->e */
  635.             gformat = 1;
  636.             goto eformat;
  637.         }
  638.         /*
  639.          * reverse integer into beginning of buffer,
  640.          * note, decrement precision
  641.          */
  642.         if (expcnt)
  643.             for (; ++p < endp; *t++ = *p, --prec);
  644.         else
  645.             *t++ = '0';
  646.         /*
  647.          * if precision required or alternate flag set, add in a
  648.          * decimal point.  If no digits yet, add in leading 0.
  649.          */
  650.         if (prec || flags&ALT) {
  651.             dotrim = 1;
  652.             *t++ = '.';
  653.         }
  654.         else
  655.             dotrim = 0;
  656.         /* if requires more precision and some fraction left */
  657.         if (fract) {
  658.             if (prec) {
  659.                 if (0 == expcnt) {
  660.                     /* if no significant digits yet */
  661.                     do {
  662.                         fract = modf(fract * 10, &tmp);
  663.                         *t++ = tochar((int)tmp);
  664.                     } while(!tmp);
  665.                 }
  666.                 while (--prec && fract) {
  667.                     fract = modf(fract * 10, &tmp);
  668.                     *t++ = tochar((int)tmp);
  669.                 }
  670.             }
  671.             if (fract)
  672.                 startp = round(fract, (int *)NULL, startp,
  673.                     t - 1, (char)0, signp);
  674.         }
  675.         /* alternate format, adds 0's for precision, else trim 0's */
  676.         if (flags&ALT)
  677.             for (; prec--; *t++ = '0');
  678.         else if (dotrim) {
  679.             while (t > startp && *--t == '0');
  680.             if (*t != '.')
  681.                 ++t;
  682.         }
  683.     }
  684.     return((int)(t - startp));
  685. }
  686.  
  687. static char *
  688. round(fract, exp, start, end, ch, signp)
  689.     double fract;
  690.     int *exp;
  691.     register char *start, *end;
  692.     int ch;
  693.     char *signp;
  694. {
  695.     double tmp;
  696.  
  697.     if (fract)
  698.         (void)modf(fract * 10, &tmp);
  699.     else
  700.         tmp = todigit(ch);
  701.     if (tmp > 4)
  702.         for (;; --end) {
  703.             if (*end == '.')
  704.                 --end;
  705.             if (++*end <= '9')
  706.                 break;
  707.             *end = '0';
  708.             if (end == start) {
  709.                 if (exp) {    /* e/E; increment exponent */
  710.                     *end = '1';
  711.                     ++*exp;
  712.                 }
  713.                 else {        /* f; add extra digit */
  714.                     *--end = '1';
  715.                     --start;
  716.                 }
  717.                 break;
  718.             }
  719.         }
  720.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  721.     else if (*signp == '-')
  722.         for (;; --end) {
  723.             if (*end == '.')
  724.                 --end;
  725.             if (*end != '0')
  726.                 break;
  727.             if (end == start)
  728.                 *signp = 0;
  729.         }
  730.     return(start);
  731. }
  732.  
  733. static char *
  734. exponent(p, exp, fmtch)
  735.     register char *p;
  736.     register int exp;
  737.     int fmtch;
  738. {
  739.     register char *t;
  740.     char expbuf[MAXEXP];
  741.  
  742.     *p++ = fmtch;
  743.     if (exp < 0) {
  744.         exp = -exp;
  745.         *p++ = '-';
  746.     }
  747.     else
  748.         *p++ = '+';
  749.     t = expbuf + MAXEXP;
  750.     if (exp > 9) {
  751.         do {
  752.             *--t = tochar(exp % 10);
  753.         } while ((exp /= 10) > 9);
  754.         *--t = tochar(exp);
  755.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  756.     }
  757.     else {
  758.         *p++ = '0';
  759.         *p++ = tochar(exp);
  760.     }
  761.     return(p);
  762. }
  763. #endif __FLOATS__
  764.