home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / ansi / stdio / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-13  |  20.2 KB  |  844 lines

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