sfstrtod.c revision 1
1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#include "sfhdr.h"
1N/A
1N/A/* Convert a Sfdouble_t value represented in an ASCII format into
1N/A** the internal Sfdouble_t representation.
1N/A**
1N/A** Written by Kiem-Phong Vo.
1N/A*/
1N/A
1N/A#define BATCH (2*sizeof(int)) /* accumulate this many digits at a time */
1N/A#define IPART 0 /* doing integer part */
1N/A#define FPART 1 /* doing fractional part */
1N/A#define EPART 2 /* doing exponent part */
1N/A
1N/A#if __STD_C
1N/Astatic Sfdouble_t sfpow10(reg int n)
1N/A#else
1N/Astatic Sfdouble_t sfpow10(n)
1N/Areg int n;
1N/A#endif
1N/A{
1N/A Sfdouble_t dval;
1N/A
switch(n)
{ case -3: return .001;
case -2: return .01;
case -1: return .1;
case 0: return 1.;
case 1: return 10.;
case 2: return 100.;
case 3: return 1000.;
}
if(n < 0)
{ dval = .0001;
for(n += 4; n < 0; n += 1)
dval /= 10.;
}
else
{ dval = 10000.;
for(n -= 4; n > 0; n -= 1)
dval *= 10.;
}
return dval;
}
#if __STD_C
Sfdouble_t _sfstrtod(reg const char* s, char** retp)
#else
Sfdouble_t _sfstrtod(s,retp)
reg char* s; /* string to convert */
char** retp; /* to return the remainder of string */
#endif
{
reg int n, c, m;
reg int mode, fexp, sign, expsign;
Sfdouble_t dval;
#if _lib_locale
int decpoint = 0;
int thousand = 0;
SFSETLOCALE(&decpoint,&thousand);
#else
#define decpoint '.'
#endif
/* skip initial blanks */
while(isspace(*s))
++s;
/* get the sign */
if((sign = (*s == '-')) || *s == '+')
s += 1;
mode = IPART;
fexp = expsign = 0;
dval = 0.;
while(*s)
{ /* accumulate a handful of the digits */
for(m = BATCH, n = 0; m > 0; --m, ++s)
{ /* get and process a char */
c = *s;
if(isdigit(c))
n = 10*n + (c - '0');
else break;
}
/* number of digits accumulated */
m = BATCH-m;
if(mode == IPART)
{ /* doing the integer part */
if(dval == 0.)
dval = (Sfdouble_t)n;
else dval = dval*sfpow10(m) + (Sfdouble_t)n;
}
else if(mode == FPART)
{ /* doing the fractional part */
fexp -= m;
if(n > 0)
dval += n*sfpow10(fexp);
}
else if(n)
{ /* doing the exponent part */
if(expsign)
n = -n;
dval *= sfpow10(n);
}
if(!c)
break;
if(m < BATCH)
{ /* detected a non-digit */
if(c == decpoint)
{ /* start the fractional part or no match */
if(mode != IPART)
break;
mode = FPART;
s += 1;
}
else if(c == 'e' || c == 'E')
{ if(mode == EPART)
break;
mode = EPART;
c = *++s;
if((expsign = (c == '-')) || c == '+')
s += 1;
}
else break;
}
}
if(retp)
*retp = (char*)s;
return sign ? -dval : dval;
}