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