Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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