1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	Convert a Sfdouble_t value represented in an ASCII format into
25**	the internal Sfdouble_t representation.
26**
27**	Written by Kiem-Phong Vo.
28*/
29
30#define BATCH	(2*sizeof(int))	/* accumulate this many digits at a time */
31#define IPART		0	/* doing integer part */
32#define FPART		1	/* doing fractional part */
33#define EPART		2	/* doing exponent part */
34
35#if __STD_C
36static Sfdouble_t sfpow10(reg int n)
37#else
38static Sfdouble_t sfpow10(n)
39reg int	n;
40#endif
41{
42	Sfdouble_t	dval;
43
44	switch(n)
45	{	case -3:	return .001;
46		case -2:	return .01;
47		case -1:	return .1;
48		case  0:	return 1.;
49		case  1:	return 10.;
50		case  2:	return 100.;
51		case  3:	return 1000.;
52	}
53
54	if(n < 0)
55	{	dval = .0001;
56		for(n += 4; n < 0; n += 1)
57			dval /= 10.;
58	}
59	else
60	{	dval = 10000.;
61		for(n -= 4; n > 0; n -= 1)
62			dval *= 10.;
63	}
64
65	return dval;
66}
67
68#if __STD_C
69Sfdouble_t _sfstrtod(reg const char* s, char** retp)
70#else
71Sfdouble_t _sfstrtod(s,retp)
72reg char*	s;	/* string to convert */
73char**		retp;	/* to return the remainder of string */
74#endif
75{
76	reg int		n, c, m;
77	reg int		mode, fexp, sign, expsign;
78	Sfdouble_t	dval;
79#if _lib_locale
80	int		decpoint = 0;
81	int		thousand = 0;
82	SFSETLOCALE(&decpoint,&thousand);
83#else
84#define decpoint	'.'
85#endif
86
87	/* skip initial blanks */
88	while(isspace(*s))
89		++s;
90
91	/* get the sign */
92	if((sign = (*s == '-')) || *s == '+')
93		s += 1;
94
95	mode = IPART;
96	fexp = expsign = 0;
97	dval = 0.;
98	while(*s)
99	{	/* accumulate a handful of the digits */
100		for(m = BATCH, n = 0; m > 0; --m, ++s)
101		{	/* get and process a char */
102			c = *s;
103			if(isdigit(c))
104				n = 10*n + (c - '0');
105			else	break;
106		}
107
108		/* number of digits accumulated */
109		m = BATCH-m;
110
111		if(mode == IPART)
112		{	/* doing the integer part */
113			if(dval == 0.)
114				dval = (Sfdouble_t)n;
115			else	dval = dval*sfpow10(m) + (Sfdouble_t)n;
116		}
117		else if(mode == FPART)
118		{	/* doing the fractional part */
119			fexp -= m;
120			if(n > 0)
121				dval += n*sfpow10(fexp);
122		}
123		else if(n)
124		{	/* doing the exponent part */
125			if(expsign)
126				n = -n;
127			dval *= sfpow10(n);
128		}
129
130		if(!c)
131			break;
132
133		if(m < BATCH)
134		{	/* detected a non-digit */
135			if(c == decpoint)
136			{	/* start the fractional part or no match */
137				if(mode != IPART)
138					break;
139				mode = FPART;
140				s += 1;
141			}
142			else if(c == 'e' || c == 'E')
143			{	if(mode == EPART)
144					break;
145				mode = EPART;
146				c = *++s;
147				if((expsign = (c == '-')) || c == '+')
148					s += 1;
149			}
150			else	break;
151		}
152	}
153
154	if(retp)
155		*retp = (char*)s;
156	return sign ? -dval : dval;
157}
158