4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-06 22:40:36 +08:00

* mingwex/strtold.c (__asctoe64) Reorganise. Fix setting error

codes and handling of special chars.
This commit is contained in:
Danny Smith 2004-02-05 03:12:15 +00:00
parent 120023b090
commit d11508dd22
2 changed files with 120 additions and 87 deletions

View File

@ -1,3 +1,8 @@
2004-02-05 Danny Smith <dannysmith@users.sourceforge.net>
* mingwex/strtold.c (__asctoe64) Reorganise. Fix setting error
codes and handling of special chars.
2004-02-02 Danny Smith <dannysmith@users.sourceforge.net> 2004-02-02 Danny Smith <dannysmith@users.sourceforge.net>
* include/stdio.h (feof): Add inlined definition. * include/stdio.h (feof): Add inlined definition.

View File

@ -20,13 +20,14 @@
* 6 Oct 02 Modified for MinGW by inlining utility routines, * 6 Oct 02 Modified for MinGW by inlining utility routines,
* removing global variables and splitting out strtold * removing global variables and splitting out strtold
* from _IO_ldtoa and _IO_ldtostr. * from _IO_ldtoa and _IO_ldtostr.
* *
* 4 Feb 04 Reorganize __asctoe64 to fix setting error codes,
* and handling special chars.
*
* Danny Smith <dannysmith@users.sourceforge.net> * Danny Smith <dannysmith@users.sourceforge.net>
*/ */
#include "math/cephes_emath.h" #include "math/cephes_emath.h"
#if NE == 10 #if NE == 10
/* 1.0E0 */ /* 1.0E0 */
@ -89,15 +90,19 @@ static const unsigned short __etens[NTEN+1][NE] = {
int __asctoe64(const char * __restrict__ ss, short unsigned int * __restrict__ y) int __asctoe64(const char * __restrict__ ss, short unsigned int * __restrict__ y)
{ {
unsigned short yy[NI], xt[NI], tt[NI]; unsigned short yy[NI], xt[NI], tt[NI];
int esign, decflg, sgnflg, nexp, exp, prec, lost; int esign, decflg, nexp, exp, lost;
int k, trail, c; int k, c;
int valid_lead_string = 0;
int have_non_zero_mant = 0;
int prec = 0;
/* int trail = 0; */
long lexp; long lexp;
unsigned short nsign; unsigned short nsign = 0;
const unsigned short *p; const unsigned short *p;
char *sp, *lstr; char *sp, *lstr;
char *s; char *s;
char dec_sym = *(localeconv ()->decimal_point); const char dec_sym = *(localeconv ()->decimal_point);
int lenldstr = 0; int lenldstr = 0;
@ -119,23 +124,58 @@ for( k=0; k<c; k++ )
*sp = '\0'; *sp = '\0';
s = lstr; s = lstr;
if (*s == '-')
{
nsign = 0xffff;
++s;
}
else if (*s == '+')
{
++s;
}
if (_strnicmp("INF", s , 3) == 0)
{
valid_lead_string = 1;
s += 3;
if ( _strnicmp ("INITY", s, 5) == 0)
s += 5;
__ecleaz(yy);
yy[E] = 0x7fff; /* infinity */
goto aexit;
}
else if(_strnicmp ("NAN", s, 3) == 0)
{
valid_lead_string = 1;
s += 3;
__enan_NI16( yy );
goto aexit;
}
/* FIXME: Handle case of strtold ("NAN(n_char_seq)",endptr) */
/* Now get some digits. */
lost = 0; lost = 0;
nsign = 0;
decflg = 0; decflg = 0;
sgnflg = 0;
nexp = 0; nexp = 0;
exp = 0; exp = 0;
prec = 0;
__ecleaz( yy ); __ecleaz( yy );
trail = 0;
/* Ignore leading zeros */
while (*s == '0')
{
valid_lead_string = 1;
s++;
}
nxtcom: nxtcom:
k = *s - '0'; k = *s - '0';
if( (k >= 0) && (k <= 9) ) if( (k >= 0) && (k <= 9) )
{ {
/* Ignore leading zeros */ #if 0
if( (prec == 0) && (decflg == 0) && (k == 0) ) /* The use of a special char as a flag for trailing zeroes causes problems when input
goto donchr; actually contains the char */
/* Identify and strip trailing zeros after the decimal point. */ /* Identify and strip trailing zeros after the decimal point. */
if( (trail == 0) && (decflg != 0) ) if( (trail == 0) && (decflg != 0) )
{ {
@ -144,11 +184,15 @@ if( (k >= 0) && (k <= 9) )
++sp; ++sp;
--sp; --sp;
while( *sp == '0' ) while( *sp == '0' )
*sp-- = 'z'; {
trail = 1; *sp-- = (char)-1;
if( *s == 'z' ) trail++;
}
if( *s == (char)-1 )
goto donchr; goto donchr;
} }
#endif
/* If enough digits were given to more than fill up the yy register, /* If enough digits were given to more than fill up the yy register,
* continuing until overflow into the high guard word yy[2] * continuing until overflow into the high guard word yy[2]
* guarantees that there will be a roundoff bit at the top * guarantees that there will be a roundoff bit at the top
@ -175,71 +219,37 @@ if( (k >= 0) && (k <= 9) )
if (decflg == 0) if (decflg == 0)
nexp -= 1; nexp -= 1;
} }
prec += 1; have_non_zero_mant |= k;
goto donchr; prec ++;
/* goto donchr; */
} }
if (*s == dec_sym) else if (*s == dec_sym)
{ {
if( decflg ) if( decflg )
goto daldone; goto daldone;
++decflg; ++decflg;
} }
else else if ((*s == 'E') || (*s == 'e') )
switch( *s ) {
{ if (prec || valid_lead_string)
case 'z': goto expnt;
break; else
case 'E': goto daldone;
case 'e': }
goto expnt;
case '-': #if 0
nsign = 0xffff; else if (*s == (char)-1)
if( sgnflg ) goto donchr;
goto daldone; #endif
++sgnflg;
break; else /* an invalid char */
case '+': goto daldone;
if( sgnflg )
goto daldone; /* donchr: */
++sgnflg;
break;
case 'i':
case 'I':
{
s++;
if (*s != 'n' && *s != 'N')
goto zero;
s++;
if (*s != 'f' && *s != 'F')
goto zero;
s++;
if ((*s == 'i' || *s == 'I') && (s[1] == 'n' || s[1] == 'N')
&& (s[2] == 'i' || s[2] == 'I')
&& (s[3] == 't' || s[3] == 'T')
&& (s[4] == 'y' || s[4] == 'Y'))
s += 5;
goto infinite;
}
case 'n':
case 'N':
{
s++;
if (*s != 'a' && *s != 'A')
goto zero;
s++;
if (*s != 'n' && *s != 'N')
goto zero;
s++;
__enan_NI16( yy );
goto aexit;
}
default:
goto daldone;
}
donchr:
++s; ++s;
goto nxtcom; goto nxtcom;
/* Exponent interpretation */ /* Exponent interpretation */
expnt: expnt:
@ -254,31 +264,39 @@ if( *s == '-' )
} }
if( *s == '+' ) if( *s == '+' )
++s; ++s;
while( (*s >= '0') && (*s <= '9') && exp < 4978)
{ while( (*s >= '0') && (*s <= '9') )
exp *= 10; {
exp += *s++ - '0'; /* Stop modifying exp if we are going to overflow anyway,
} but keep parsing the string. */
if (exp < 4978)
{
exp *= 10;
exp += *s - '0';
}
s++;
}
if( esign < 0 ) if( esign < 0 )
exp = -exp; exp = -exp;
if( exp > 4932 )
if (exp > 4977) /* maybe overflow */
{ {
errno = ERANGE;
infinite:
__ecleaz(yy); __ecleaz(yy);
yy[E] = 0x7fff; /* infinity */ if (have_non_zero_mant)
yy[E] = 0x7fff;
goto aexit; goto aexit;
} }
if( exp < -4977 ) else if (exp < -4977) /* underflow */
{ {
errno = ERANGE;
zero:
__ecleaz(yy); __ecleaz(yy);
goto aexit; goto aexit;
} }
daldone: daldone:
nexp = exp - nexp; nexp = exp - nexp;
/* Pad trailing zeros to minimize power of 10, per IEEE spec. */ /* Pad trailing zeros to minimize power of 10, per IEEE spec. */
while( (nexp > 0) && (yy[2] == 0) ) while( (nexp > 0) && (yy[2] == 0) )
{ {
@ -363,8 +381,17 @@ __emdnorm( yy, k, 0, lexp, 64, 64 );
aexit: aexit:
yy[0] = nsign; yy[0] = nsign;
__toe64( yy, y ); __toe64( yy, y );
return (lenldstr + s - lstr);
/* Check for overflow, undeflow */
if (have_non_zero_mant &&
(*((long double*) y) == 0.0L || isinf (*((long double*) y))))
errno = ERANGE;
if (prec || valid_lead_string)
return (lenldstr + (s - lstr));
return 0;
} }
@ -380,5 +407,6 @@ long double strtold (const char * __restrict__ s, char ** __restrict__ se)
lenldstr = __asctoe64( s, xx.us); lenldstr = __asctoe64( s, xx.us);
if (se) if (se)
*se = (char*)s + lenldstr; *se = (char*)s + lenldstr;
return xx.ld; return xx.ld;
} }