OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / stdlib / ldtoa.c
index ca8b9f3..ab27e47 100644 (file)
@@ -1,4 +1,3 @@
-
  /* Extended precision arithmetic functions for long double I/O.
   * This program has been placed in the public domain.
   */
@@ -41,7 +40,10 @@ void _IO_ldtostr(long double *, char *, int, int, char);
  /* The exponent of 1.0 */
  #define EXONE (0x3fff)
 
-/* Control structure for long doublue conversion including rounding precision values.
+ /* Maximum exponent digits - base 10 */
+ #define MAX_EXP_DIGITS 5
+
+/* Control structure for long double conversion including rounding precision values.
  * rndprc can be set to 80 (if NE=6), 64, 56, 53, or 24 bits.
  */
 typedef struct
@@ -77,6 +79,12 @@ static void einfin(register short unsigned int *x, register LDPARMS *ldp);
 static void efloor(short unsigned int *x, short unsigned int *y, LDPARMS *ldp);
 static void etoasc(short unsigned int *x, char *string, int ndigs, int outformat, LDPARMS *ldp);
 
+union uconv
+{
+  unsigned short pe;
+  long double d;
+};
+
 #if LDBL_MANT_DIG == 24
 static void e24toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp);
 #elif LDBL_MANT_DIG == 53
@@ -235,7 +243,7 @@ static char *ermsg[7] = {
  *
  * Exception flags are NOT fully supported.
  *
- * Define INFINITY in mconf.h for support of infinity; otherwise a
+ * Define USE_INFINITY in mconf.h for support of infinity; otherwise a
  * saturation arithmetic is implemented.
  *
  * Define NANS for support of Not-a-Number items; otherwise the
@@ -372,12 +380,12 @@ typedef struct
 #define VOLATILE 
 
 #define NANS
-#define INFINITY
+#define USE_INFINITY
 
 /* NaN's require infinity support. */
 #ifdef NANS
 #ifndef INFINITY
-#define INFINITY
+#define USE_INFINITY
 #endif
 #endif
 
@@ -535,7 +543,7 @@ static void einfin(register short unsigned int *x, register LDPARMS *ldp)
 {
 register int i;
 
-#ifdef INFINITY
+#ifdef USE_INFINITY
 for( i=0; i<NE-1; i++ )
        *x++ = 0;
 *x |= 32767;
@@ -587,7 +595,7 @@ else
 /* get the exponent */
 *q = *p--;
 *q++ &= 0x7fff;        /* delete the sign bit */
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( (*(q-1) & 0x7fff) == 0x7fff )
        {
 #ifdef NANS
@@ -630,7 +638,7 @@ if( i )
        *q-- = *p++ | 0x8000;
 else
        *q-- = *p++;
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( *(p-1) == 0x7fff )
        {
 #ifdef NANS
@@ -711,8 +719,7 @@ return(0);
 
 /* Return nonzero if internal format number is infinite. */
 static int 
-eiisinf (x)
-     unsigned short x[];
+eiisinf (unsigned short x[])
 {
 
 #ifdef NANS
@@ -1164,7 +1171,7 @@ unsigned short r;
 j = enormlz( s );
 
 /* a blank significand could mean either zero or infinity. */
-#ifndef INFINITY
+#ifndef USE_INFINITY
 if( j > NBITS )
        {
        ecleazs( s );
@@ -1172,7 +1179,7 @@ if( j > NBITS )
        }
 #endif
 exp -= j;
-#ifndef INFINITY
+#ifndef USE_INFINITY
 if( exp >= 32767L )
        goto overf;
 #else
@@ -1320,10 +1327,10 @@ mdfin:
 s[NI-1] = 0;
 if( exp >= 32767L )
        {
-#ifndef INFINITY
+#ifndef USE_INFINITY
 overf:
 #endif
-#ifdef INFINITY
+#ifdef USE_INFINITY
        s[1] = 32767;
        for( i=2; i<NI-1; i++ )
                s[i] = 0;
@@ -1396,7 +1403,7 @@ unsigned short ai[NI], bi[NI], ci[NI];
 int i, lost, j, k;
 long lt, lta, ltb;
 
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( eisinf(a) )
        {
        emov(a,c);
@@ -1527,7 +1534,7 @@ if( ((ecmp(a,ezero) == 0) && (ecmp(b,ezero) == 0))
        }
 #endif
 /* Infinity over anything else is infinity. */
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( eisinf(b) )
        {
        if( eisneg(a) ^ eisneg(b) )
@@ -1631,7 +1638,7 @@ if( (eisinf(a) && (ecmp(b,ezero) == 0))
        }
 #endif
 /* Infinity times anything else is infinity. */
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( eisinf(a) || eisinf(b) )
        {
        if( eisneg(a) ^ eisneg(b) )
@@ -1710,7 +1717,7 @@ yy[0] = 0;
 if( r & 0x8000 )
        yy[0] = 0xffff;
 r &= 0x7fff;
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( r == 0x7fff )
        {
 #ifdef NANS
@@ -1856,7 +1863,7 @@ if((yy[NE-1] & 0x7fff) == 0 && (yy[NE-2] & 0x8000) == 0)
     return;
   }
 #endif
-#ifdef INFINITY
+#ifdef USE_INFINITY
 /* Point to the exponent field.  */
 p = &yy[NE-1];
 if( (*p & 0x7fff) == 0x7fff )
@@ -1891,7 +1898,7 @@ if( (*p & 0x7fff) == 0x7fff )
                eneg(y);
        return;
        }
-#endif /* INFINITY */
+#endif /* USE_INFINITY */
 p = yy;
 q = y;
 for( i=0; i<NE; i++ )
@@ -1946,7 +1953,7 @@ else
 for( i=0; i<4; i++ )
        *q++ = *p++;
 #else
-#ifdef INFINITY
+#ifdef USE_INFINITY
 #ifdef IBMPC
 if (eiisinf (a))
         {
@@ -1958,7 +1965,7 @@ if (eiisinf (a))
        return;
        }
 #endif /* IBMPC */
-#endif /* INFINITY */
+#endif /* USE_INFINITY */
 for( i=0; i<4; i++ )
        *q-- = *p++;
 #endif
@@ -2001,7 +2008,7 @@ if( r & 0x8000 )
        yy[0] = 0xffff;
 yy[M] = (r & 0x0f) | 0x10;
 r &= ~0x800f;  /* strip sign and 4 significand bits */
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( r == 0x7ff0 )
        {
 #ifdef NANS
@@ -2111,7 +2118,7 @@ if( *p++ )
 i = *p++;
 if( i >= (unsigned int )2047 )
        {       /* Saturate at largest number less than infinity. */
-#ifdef INFINITY
+#ifdef USE_INFINITY
        *y |= 0x7ff0;
 #ifdef IBMPC
        *(--y) = 0;
@@ -2123,7 +2130,7 @@ if( i >= (unsigned int )2047 )
        *y++ = 0;
        *y++ = 0;
 #endif /* IBMPC */
-#else /* !INFINITY */
+#else /* !USE_INFINITY */
        *y |= (unsigned short )0x7fef;
 #ifdef IBMPC
        *(--y) = 0xffff;
@@ -2135,7 +2142,7 @@ if( i >= (unsigned int )2047 )
        *y++ = 0xffff;
        *y++ = 0xffff;
 #endif
-#endif /* !INFINITY */
+#endif /* !USE_INFINITY */
        return;
        }
 if( i == 0 )
@@ -2193,7 +2200,7 @@ if( r & 0x8000 )
        yy[0] = 0xffff;
 yy[M] = (r & 0x7f) | 0200;
 r &= ~0x807f;  /* strip sign and 7 significand bits */
-#ifdef INFINITY
+#ifdef USE_INFINITY
 if( r == 0x7f80 )
        {
 #ifdef NANS
@@ -2276,7 +2283,7 @@ if( *p++ )
 i = *p++;
 if( i >= 255 )
        {       /* Saturate at largest number less than infinity. */
-#ifdef INFINITY
+#ifdef USE_INFINITY
        *y |= (unsigned short )0x7f80;
 #ifdef IBMPC
        *(--y) = 0;
@@ -2288,7 +2295,7 @@ if( i >= 255 )
        ++y;
        *y = 0;
 #endif
-#else /* !INFINITY */
+#else /* !USE_INFINITY */
        *y |= (unsigned short )0x7f7f;
 #ifdef IBMPC
        *(--y) = 0xffff;
@@ -2300,7 +2307,7 @@ if( i >= 255 )
        ++y;
        *y = 0xffff;
 #endif
-#endif /* !INFINITY */
+#endif /* !USE_INFINITY */
        return;
        }
 if( i == 0 )
@@ -2703,11 +2710,16 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits, int *decpt,
 {
 unsigned short e[NI];
 char *s, *p;
-int k;
+int i, j, k;
+int orig_ndigits;
 LDPARMS rnd;
 LDPARMS *ldp = &rnd;
 char *outstr;
+char outbuf[NDEC + MAX_EXP_DIGITS + 10];
+union uconv du;
+du.d = d;
 
+orig_ndigits = ndigits;
 rnd.rlast = -1;
 rnd.rndprc = NBITS;
 
@@ -2723,13 +2735,13 @@ if (_REENT_MP_RESULT(ptr))
   }
 
 #if LDBL_MANT_DIG == 24
-e24toe( (unsigned short *)&d, e, ldp );
+e24toe( &du.pe, e, ldp );
 #elif LDBL_MANT_DIG == 53
-e53toe( (unsigned short *)&d, e, ldp );
+e53toe( &du.pe, e, ldp );
 #elif LDBL_MANT_DIG == 64
-e64toe( (unsigned short *)&d, e, ldp );
+e64toe( &du.pe, e, ldp );
 #else
-e113toe( (unsigned short *)&d, e, ldp );
+e113toe( &du.pe, e, ldp );
 #endif
 
 if( eisneg(e) )
@@ -2744,18 +2756,14 @@ if( mode != 3 )
    For now, just ask for 20 digits which is enough but sometimes too many.  */
 if( mode == 0 )
         ndigits = 20;
+
 /* This sanity limit must agree with the corresponding one in etoasc, to
    keep straight the returned value of outexpon.  */
 if( ndigits > NDEC )
         ndigits = NDEC;
 
-/* reentrancy addition to use mprec storage pool */
-_REENT_MP_RESULT(ptr) = Balloc (ptr, 3);
-_REENT_MP_RESULT_K(ptr) = 3;
-outstr = (char *)_REENT_MP_RESULT(ptr);
-
-etoasc( e, outstr, ndigits, mode, ldp );
-s =  outstr;
+etoasc( e, outbuf, ndigits, mode, ldp );
+s =  outbuf;
 if( eisinf(e) || eisnan(e) )
         {
         *decpt = 9999;
@@ -2766,7 +2774,7 @@ if( eisinf(e) || eisnan(e) )
 /* Transform the string returned by etoasc into what the caller wants.  */
 
 /* Look for decimal point and delete it from the string. */
-s = outstr;
+s = outbuf;
 while( *s != '\0' )
         {
         if( *s == '.' )
@@ -2787,19 +2795,19 @@ while( *s != '\0' )
 nodecpt:
 
 /* Back up over the exponent field. */
-while( *s != 'E' && s > outstr)
+while( *s != 'E' && s > outbuf)
         --s;
 *s = '\0';
 
 stripspaces:
 
 /* Strip leading spaces and sign. */
-p = outstr;
+p = outbuf;
 while( *p == ' ' || *p == '-')
         ++p;
 
 /* Find new end of string.  */
-s = outstr;
+s = outbuf;
 while( (*s++ = *p++) != '\0' )
         ;
 --s;
@@ -2812,20 +2820,38 @@ else if( ndigits > ldp->outexpon )
 else
         k = ldp->outexpon;
 
-while( *(s-1) == '0' && ((s - outstr) > k))
+while( *(s-1) == '0' && ((s - outbuf) > k))
         *(--s) = '\0';
 
 /* In f format, flush small off-scale values to zero.
    Rounding has been taken care of by etoasc. */
 if( mode == 3 && ((ndigits + ldp->outexpon) < 0))
         {
-        s = outstr;
+        s = outbuf;
         *s = '\0';
         *decpt = 0;
         }
 
+/* reentrancy addition to use mprec storage pool */
+/* we want to have enough space to hold the formatted result */
+
+if (mode == 3) /* f format, account for sign + dec digits + decpt + frac */
+  i = *decpt + orig_ndigits + 3;
+else /* account for sign + max precision digs + E + exp sign + exponent */
+  i = orig_ndigits + MAX_EXP_DIGITS + 4;
+
+j = sizeof (__ULong);
+for (_REENT_MP_RESULT_K(ptr) = 0; sizeof (_Bigint) - sizeof (__ULong) + j <= i; j <<= 1)
+  _REENT_MP_RESULT_K(ptr)++;
+_REENT_MP_RESULT(ptr) = Balloc (ptr, _REENT_MP_RESULT_K(ptr));
+
+/* Copy from internal temporary buffer to permanent buffer.  */
+outstr = (char *)_REENT_MP_RESULT(ptr);
+strcpy (outstr, outbuf);
+
 if( rve )
-        *rve = s;
+        *rve = outstr + (s - outbuf);
+
 return outstr;
 }
 
@@ -2841,17 +2867,19 @@ unsigned short e[NI];
 LDPARMS rnd;
 LDPARMS *ldp = &rnd;
 
+union uconv du;
+
 rnd.rlast = -1;
 rnd.rndprc = NBITS;
-
+du.d = *d;
 #if LDBL_MANT_DIG == 24
-e24toe( (unsigned short *)d, e, ldp );
+e24toe( &du.pe, e, ldp );
 #elif LDBL_MANT_DIG == 53
-e53toe( (unsigned short *)d, e, ldp );
+e53toe( &du.pe, e, ldp );
 #elif LDBL_MANT_DIG == 64
-e64toe( (unsigned short *)d, e, ldp );
+e64toe( &du.pe, e, ldp );
 #else
-e113toe( (unsigned short *)d, e, ldp );
+e113toe( &du.pe, e, ldp );
 #endif
 
 if( (e[NE-1] & 0x7fff) == 0x7fff )
@@ -3124,7 +3152,7 @@ if( digit > 4 )
                emovo( y, t, ldp );
                if( ecmp(t,ezero) != 0 )
                        goto roun;      /* round to nearest */
-               if( (*(s-1) & 1) == 0 )
+               if( ndigs < 0 || (*(s-1-(*(s-1)=='.')) & 1) == 0 )
                        goto doexp;     /* round to even */
                }
 /* Round up and propagate carry-outs */
@@ -3200,7 +3228,7 @@ ldp->outexpon =  expon;
 
 long double _strtold (char *s, char **se)
 {
-  long double x;
+  union uconv x;
   LDPARMS rnd;
   LDPARMS *ldp = &rnd;
   int lenldstr;
@@ -3208,10 +3236,10 @@ long double _strtold (char *s, char **se)
   rnd.rlast = -1;
   rnd.rndprc = NBITS;
 
-  lenldstr = asctoeg( s, (unsigned short *)&x, LDBL_MANT_DIG, ldp );
+  lenldstr = asctoeg( s, &x.pe, LDBL_MANT_DIG, ldp );
   if (se)
     *se = s + lenldstr;
-  return x;
+  return x.d;
 }
 
 #define REASONABLE_LEN 200
@@ -3713,7 +3741,3 @@ switch( size )
 for (i=0; i < n; i++)
        *nan++ = *p++;
 }
-
-
-
-