Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

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