1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19*b30d1939SAndy Fiddaman *                   Phong Vo <kpv@research.att.com>                    *
20*b30d1939SAndy Fiddaman *                                                                      *
21*b30d1939SAndy Fiddaman ***********************************************************************/
22*b30d1939SAndy Fiddaman /*
23*b30d1939SAndy Fiddaman  * AT&T Research
24*b30d1939SAndy Fiddaman  * Glenn Fowler & Phong Vo
25*b30d1939SAndy Fiddaman  *
26*b30d1939SAndy Fiddaman  * common header and implementation for
27*b30d1939SAndy Fiddaman  *
28*b30d1939SAndy Fiddaman  *	strtof		strtod		strtold		_sfdscan
29*b30d1939SAndy Fiddaman  *	strntof		strntod		strntold
30*b30d1939SAndy Fiddaman  *
31*b30d1939SAndy Fiddaman  * define these macros to instantiate an implementation:
32*b30d1939SAndy Fiddaman  *
33*b30d1939SAndy Fiddaman  *	S2F_function	the function name
34*b30d1939SAndy Fiddaman  *	S2F_static	<0:export =0:extern >0:static
35*b30d1939SAndy Fiddaman  *	S2F_type	0:float 1:double 2:long.double
36*b30d1939SAndy Fiddaman  *	S2F_qualifier	1 for optional [fFlL] qualifier suffix
37*b30d1939SAndy Fiddaman  *	S2F_size	1 for interface with size_t second arg
38*b30d1939SAndy Fiddaman  *	S2F_scan	1 for alternate interface with these arguments:
39*b30d1939SAndy Fiddaman  *				void* handle
40*b30d1939SAndy Fiddaman  *				int (*getchar)(void* handle, int flag)
41*b30d1939SAndy Fiddaman  *			exactly one extra (*getchar)() is done, i.e.,
42*b30d1939SAndy Fiddaman  *			the caller must do the pushback
43*b30d1939SAndy Fiddaman  *				flag==0		get next char
44*b30d1939SAndy Fiddaman  *				flag==1		no number seen
45*b30d1939SAndy Fiddaman  *			return 0 on error or EOF
46*b30d1939SAndy Fiddaman  */
47*b30d1939SAndy Fiddaman 
48*b30d1939SAndy Fiddaman #include "sfhdr.h"
49*b30d1939SAndy Fiddaman #include "FEATURE/float"
50*b30d1939SAndy Fiddaman 
51*b30d1939SAndy Fiddaman /*
52*b30d1939SAndy Fiddaman  * the default is _sfdscan for standalone sfio compatibility
53*b30d1939SAndy Fiddaman  */
54*b30d1939SAndy Fiddaman 
55*b30d1939SAndy Fiddaman #if !defined(S2F_function)
56*b30d1939SAndy Fiddaman #define S2F_function	_sfdscan
57*b30d1939SAndy Fiddaman #define S2F_static	1
58*b30d1939SAndy Fiddaman #define S2F_type	2
59*b30d1939SAndy Fiddaman #define S2F_scan	1
60*b30d1939SAndy Fiddaman #ifndef elementsof
61*b30d1939SAndy Fiddaman #define elementsof(a)	(sizeof(a)/sizeof(a[0]))
62*b30d1939SAndy Fiddaman #endif
63*b30d1939SAndy Fiddaman #endif
64*b30d1939SAndy Fiddaman 
65*b30d1939SAndy Fiddaman #if S2F_type == 2 && _ast_fltmax_double
66*b30d1939SAndy Fiddaman #undef	S2F_type
67*b30d1939SAndy Fiddaman #define S2F_type	1
68*b30d1939SAndy Fiddaman #endif
69*b30d1939SAndy Fiddaman 
70*b30d1939SAndy Fiddaman #if S2F_type == 0
71*b30d1939SAndy Fiddaman #define S2F_number	float
72*b30d1939SAndy Fiddaman #define S2F_ldexp	ldexp
73*b30d1939SAndy Fiddaman #define S2F_pow10	_Sffpow10
74*b30d1939SAndy Fiddaman #define S2F_inf		_Sffinf
75*b30d1939SAndy Fiddaman #define S2F_nan		_Sffnan
76*b30d1939SAndy Fiddaman #define S2F_min		(FLT_MIN)
77*b30d1939SAndy Fiddaman #define S2F_max		(FLT_MAX)
78*b30d1939SAndy Fiddaman #define S2F_exp_10_min	(FLT_MIN_10_EXP)
79*b30d1939SAndy Fiddaman #define S2F_exp_10_max	(FLT_MAX_10_EXP)
80*b30d1939SAndy Fiddaman #define S2F_exp_2_min	(FLT_MIN_EXP)
81*b30d1939SAndy Fiddaman #define S2F_exp_2_max	(FLT_MAX_EXP)
82*b30d1939SAndy Fiddaman #endif
83*b30d1939SAndy Fiddaman #if S2F_type == 1
84*b30d1939SAndy Fiddaman #define S2F_number	double
85*b30d1939SAndy Fiddaman #define S2F_ldexp	ldexp
86*b30d1939SAndy Fiddaman #define S2F_pow10	_Sfdpow10
87*b30d1939SAndy Fiddaman #define S2F_inf		_Sfdinf
88*b30d1939SAndy Fiddaman #define S2F_nan		_Sfdnan
89*b30d1939SAndy Fiddaman #define S2F_min		(DBL_MIN)
90*b30d1939SAndy Fiddaman #define S2F_max		(DBL_MAX)
91*b30d1939SAndy Fiddaman #define S2F_exp_10_min	(DBL_MIN_10_EXP)
92*b30d1939SAndy Fiddaman #define S2F_exp_10_max	(DBL_MAX_10_EXP)
93*b30d1939SAndy Fiddaman #define S2F_exp_2_min	(DBL_MIN_EXP)
94*b30d1939SAndy Fiddaman #define S2F_exp_2_max	(DBL_MAX_EXP)
95*b30d1939SAndy Fiddaman #endif
96*b30d1939SAndy Fiddaman #if S2F_type == 2
97*b30d1939SAndy Fiddaman #define S2F_number	long double
98*b30d1939SAndy Fiddaman #define S2F_ldexp	ldexpl
99*b30d1939SAndy Fiddaman #define S2F_pow10	_Sflpow10
100*b30d1939SAndy Fiddaman #define S2F_inf		_Sflinf
101*b30d1939SAndy Fiddaman #define S2F_nan		_Sflnan
102*b30d1939SAndy Fiddaman #define S2F_min		(LDBL_MIN)
103*b30d1939SAndy Fiddaman #define S2F_max		(LDBL_MAX)
104*b30d1939SAndy Fiddaman #define S2F_exp_10_min	(LDBL_MIN_10_EXP)
105*b30d1939SAndy Fiddaman #define S2F_exp_10_max	(LDBL_MAX_10_EXP)
106*b30d1939SAndy Fiddaman #define S2F_exp_2_min	(LDBL_MIN_EXP)
107*b30d1939SAndy Fiddaman #define S2F_exp_2_max	(LDBL_MAX_EXP)
108*b30d1939SAndy Fiddaman #endif
109*b30d1939SAndy Fiddaman 
110*b30d1939SAndy Fiddaman #if -S2F_exp_10_min < S2F_exp_10_max
111*b30d1939SAndy Fiddaman #define S2F_exp_10_abs	(-S2F_exp_10_min)
112*b30d1939SAndy Fiddaman #else
113*b30d1939SAndy Fiddaman #define S2F_exp_10_abs	S2F_exp_10_max
114*b30d1939SAndy Fiddaman #endif
115*b30d1939SAndy Fiddaman 
116*b30d1939SAndy Fiddaman #define S2F_batch	_ast_flt_unsigned_max_t
117*b30d1939SAndy Fiddaman 
118*b30d1939SAndy Fiddaman #undef	ERR		/* who co-opted this namespace? */
119*b30d1939SAndy Fiddaman 
120*b30d1939SAndy Fiddaman #if S2F_scan
121*b30d1939SAndy Fiddaman 
122*b30d1939SAndy Fiddaman typedef int (*S2F_get_f)_ARG_((void*, int));
123*b30d1939SAndy Fiddaman 
124*b30d1939SAndy Fiddaman #define ERR(e)
125*b30d1939SAndy Fiddaman #define GET(p)		(*get)(p,0)
126*b30d1939SAndy Fiddaman #define NON(p)		(*get)(p,1)
127*b30d1939SAndy Fiddaman #define PUT(p)
128*b30d1939SAndy Fiddaman #define REV(p,t,b)
129*b30d1939SAndy Fiddaman #define SET(p,t,b)
130*b30d1939SAndy Fiddaman 
131*b30d1939SAndy Fiddaman #else
132*b30d1939SAndy Fiddaman 
133*b30d1939SAndy Fiddaman #define ERR(e)		(errno=(e))
134*b30d1939SAndy Fiddaman #define NON(p)
135*b30d1939SAndy Fiddaman 
136*b30d1939SAndy Fiddaman #if S2F_size
137*b30d1939SAndy Fiddaman #define GET(p)		(((p)<(z))?(*p++):(back=0))
138*b30d1939SAndy Fiddaman #define PUT(p)		(end?(*end=(char*)p-back):(char*)0)
139*b30d1939SAndy Fiddaman #define REV(p,t,b)	(p=t,back=b)
140*b30d1939SAndy Fiddaman #define SET(p,t,b)	(t=p,b=back)
141*b30d1939SAndy Fiddaman #else
142*b30d1939SAndy Fiddaman #define GET(p)		(*p++)
143*b30d1939SAndy Fiddaman #define PUT(p)		(end?(*end=(char*)p-1):(char*)0)
144*b30d1939SAndy Fiddaman #define REV(p,t,b)	(p=t)
145*b30d1939SAndy Fiddaman #define SET(p,t,b)	(t=p)
146*b30d1939SAndy Fiddaman #endif
147*b30d1939SAndy Fiddaman 
148*b30d1939SAndy Fiddaman #endif
149*b30d1939SAndy Fiddaman 
150*b30d1939SAndy Fiddaman typedef struct S2F_part_s
151*b30d1939SAndy Fiddaman {
152*b30d1939SAndy Fiddaman 	S2F_batch	batch;
153*b30d1939SAndy Fiddaman 	int		digits;
154*b30d1939SAndy Fiddaman } S2F_part_t;
155*b30d1939SAndy Fiddaman 
156*b30d1939SAndy Fiddaman #if !defined(ERANGE)
157*b30d1939SAndy Fiddaman #define ERANGE		EINVAL
158*b30d1939SAndy Fiddaman #endif
159*b30d1939SAndy Fiddaman 
160*b30d1939SAndy Fiddaman #if S2F_static > 0
161*b30d1939SAndy Fiddaman static
162*b30d1939SAndy Fiddaman #else
163*b30d1939SAndy Fiddaman #if S2F_static < 0 || !defined(S2F_static)
164*b30d1939SAndy Fiddaman #if defined(__EXPORT__)
165*b30d1939SAndy Fiddaman #define extern		__EXPORT__
166*b30d1939SAndy Fiddaman #endif
167*b30d1939SAndy Fiddaman extern
168*b30d1939SAndy Fiddaman #undef	extern
169*b30d1939SAndy Fiddaman #endif
170*b30d1939SAndy Fiddaman #endif
171*b30d1939SAndy Fiddaman S2F_number
172*b30d1939SAndy Fiddaman #if S2F_scan
173*b30d1939SAndy Fiddaman #if __STD_C
S2F_function(void * s,S2F_get_f get)174*b30d1939SAndy Fiddaman S2F_function(void* s, S2F_get_f get)
175*b30d1939SAndy Fiddaman #else
176*b30d1939SAndy Fiddaman S2F_function(s, get) void* s; S2F_get_f get;
177*b30d1939SAndy Fiddaman #endif
178*b30d1939SAndy Fiddaman #else
179*b30d1939SAndy Fiddaman #if S2F_size
180*b30d1939SAndy Fiddaman #if __STD_C
181*b30d1939SAndy Fiddaman S2F_function(const char* str, size_t size, char** end)
182*b30d1939SAndy Fiddaman #else
183*b30d1939SAndy Fiddaman S2F_function(str, size, end) char* str; size_t size; char** end;
184*b30d1939SAndy Fiddaman #endif
185*b30d1939SAndy Fiddaman #else
186*b30d1939SAndy Fiddaman #if __STD_C
187*b30d1939SAndy Fiddaman S2F_function(const char* str, char** end)
188*b30d1939SAndy Fiddaman #else
189*b30d1939SAndy Fiddaman S2F_function(str, end) char* str; char** end;
190*b30d1939SAndy Fiddaman #endif
191*b30d1939SAndy Fiddaman #endif
192*b30d1939SAndy Fiddaman #endif
193*b30d1939SAndy Fiddaman {
194*b30d1939SAndy Fiddaman #if !S2F_scan
195*b30d1939SAndy Fiddaman 	register unsigned char*	s = (unsigned char*)str;
196*b30d1939SAndy Fiddaman #if S2F_size
197*b30d1939SAndy Fiddaman 	register unsigned char*	z = s + size;
198*b30d1939SAndy Fiddaman 	int			back = 1;
199*b30d1939SAndy Fiddaman 	int			b;
200*b30d1939SAndy Fiddaman #endif
201*b30d1939SAndy Fiddaman 	unsigned char*		t;
202*b30d1939SAndy Fiddaman #endif
203*b30d1939SAndy Fiddaman 	register S2F_batch	n;
204*b30d1939SAndy Fiddaman 	register int		c;
205*b30d1939SAndy Fiddaman 	register int		digits;
206*b30d1939SAndy Fiddaman 	register int		m;
207*b30d1939SAndy Fiddaman 	register unsigned char*	cv;
208*b30d1939SAndy Fiddaman 	int			negative;
209*b30d1939SAndy Fiddaman 	int			enegative;
210*b30d1939SAndy Fiddaman 	int			fraction;
211*b30d1939SAndy Fiddaman 	int			decimal = 0;
212*b30d1939SAndy Fiddaman 	int			thousand = 0;
213*b30d1939SAndy Fiddaman 	int			part = 0;
214*b30d1939SAndy Fiddaman 	int			back_part;
215*b30d1939SAndy Fiddaman 	S2F_batch		back_n;
216*b30d1939SAndy Fiddaman 	S2F_number		v;
217*b30d1939SAndy Fiddaman 	S2F_number		p;
218*b30d1939SAndy Fiddaman 	S2F_part_t		parts[16];
219*b30d1939SAndy Fiddaman 
220*b30d1939SAndy Fiddaman 	/*
221*b30d1939SAndy Fiddaman 	 * radix char and thousands separator are locale specific
222*b30d1939SAndy Fiddaman 	 */
223*b30d1939SAndy Fiddaman 
224*b30d1939SAndy Fiddaman 	SFSETLOCALE(&decimal, &thousand);
225*b30d1939SAndy Fiddaman 	SFCVINIT();
226*b30d1939SAndy Fiddaman 
227*b30d1939SAndy Fiddaman 	/*
228*b30d1939SAndy Fiddaman 	 * skip initial blanks
229*b30d1939SAndy Fiddaman 	 */
230*b30d1939SAndy Fiddaman 
231*b30d1939SAndy Fiddaman 	do c = GET(s); while (isspace(c));
232*b30d1939SAndy Fiddaman 	SET(s, t, b);
233*b30d1939SAndy Fiddaman 
234*b30d1939SAndy Fiddaman 	/*
235*b30d1939SAndy Fiddaman 	 * get the sign
236*b30d1939SAndy Fiddaman 	 */
237*b30d1939SAndy Fiddaman 
238*b30d1939SAndy Fiddaman 	if ((negative = (c == '-')) || c == '+')
239*b30d1939SAndy Fiddaman 		c = GET(s);
240*b30d1939SAndy Fiddaman 
241*b30d1939SAndy Fiddaman 	/*
242*b30d1939SAndy Fiddaman 	 * drop leading 0's
243*b30d1939SAndy Fiddaman 	 */
244*b30d1939SAndy Fiddaman 
245*b30d1939SAndy Fiddaman 	digits = 0;
246*b30d1939SAndy Fiddaman 	fraction = -1;
247*b30d1939SAndy Fiddaman 	if (c == '0')
248*b30d1939SAndy Fiddaman 	{
249*b30d1939SAndy Fiddaman 		c = GET(s);
250*b30d1939SAndy Fiddaman 		if (c == 'x' || c == 'X')
251*b30d1939SAndy Fiddaman 		{
252*b30d1939SAndy Fiddaman 			/*
253*b30d1939SAndy Fiddaman 			 * hex floating point -- easy
254*b30d1939SAndy Fiddaman 			 */
255*b30d1939SAndy Fiddaman 
256*b30d1939SAndy Fiddaman 			cv = _Sfcv36;
257*b30d1939SAndy Fiddaman 			v = 0;
258*b30d1939SAndy Fiddaman 			for (;;)
259*b30d1939SAndy Fiddaman 			{
260*b30d1939SAndy Fiddaman 				c = GET(s);
261*b30d1939SAndy Fiddaman 				if ((part = cv[c]) < 16)
262*b30d1939SAndy Fiddaman 				{
263*b30d1939SAndy Fiddaman 					digits++;
264*b30d1939SAndy Fiddaman 					v *= 16;
265*b30d1939SAndy Fiddaman 					v += part;
266*b30d1939SAndy Fiddaman 				}
267*b30d1939SAndy Fiddaman 				else if (c == decimal)
268*b30d1939SAndy Fiddaman 				{
269*b30d1939SAndy Fiddaman 					decimal = -1;
270*b30d1939SAndy Fiddaman 					fraction = digits;
271*b30d1939SAndy Fiddaman 				}
272*b30d1939SAndy Fiddaman 				else
273*b30d1939SAndy Fiddaman 					break;
274*b30d1939SAndy Fiddaman 			}
275*b30d1939SAndy Fiddaman 			m = 0;
276*b30d1939SAndy Fiddaman 			if (c == 'p' || c == 'P')
277*b30d1939SAndy Fiddaman 			{
278*b30d1939SAndy Fiddaman 				c = GET(s);
279*b30d1939SAndy Fiddaman 				if ((enegative = c == '-') || c == '+')
280*b30d1939SAndy Fiddaman 					c = GET(s);
281*b30d1939SAndy Fiddaman 				while (c >= '0' && c <= '9')
282*b30d1939SAndy Fiddaman 				{
283*b30d1939SAndy Fiddaman 					m = (m << 3) + (m << 1) + (c - '0');
284*b30d1939SAndy Fiddaman 					c = GET(s);
285*b30d1939SAndy Fiddaman 				}
286*b30d1939SAndy Fiddaman 				if (enegative)
287*b30d1939SAndy Fiddaman 					m = -m;
288*b30d1939SAndy Fiddaman 			}
289*b30d1939SAndy Fiddaman 
290*b30d1939SAndy Fiddaman #if S2F_qualifier
291*b30d1939SAndy Fiddaman 
292*b30d1939SAndy Fiddaman 			/*
293*b30d1939SAndy Fiddaman 			 * consume the optional suffix
294*b30d1939SAndy Fiddaman 			 */
295*b30d1939SAndy Fiddaman 
296*b30d1939SAndy Fiddaman 			switch (c)
297*b30d1939SAndy Fiddaman 			{
298*b30d1939SAndy Fiddaman 			case 'f':
299*b30d1939SAndy Fiddaman 			case 'F':
300*b30d1939SAndy Fiddaman 			case 'l':
301*b30d1939SAndy Fiddaman 			case 'L':
302*b30d1939SAndy Fiddaman 				c = GET(s);
303*b30d1939SAndy Fiddaman 				break;
304*b30d1939SAndy Fiddaman 			}
305*b30d1939SAndy Fiddaman #endif
306*b30d1939SAndy Fiddaman 			PUT(s);
307*b30d1939SAndy Fiddaman 			if (v == 0)
308*b30d1939SAndy Fiddaman 				return negative ? -v : v;
309*b30d1939SAndy Fiddaman 			if (fraction >= 0)
310*b30d1939SAndy Fiddaman 				m -= 4 * (digits - fraction);
311*b30d1939SAndy Fiddaman 			if (m < S2F_exp_2_min)
312*b30d1939SAndy Fiddaman 			{
313*b30d1939SAndy Fiddaman 				if ((m -= S2F_exp_2_min) < S2F_exp_2_min)
314*b30d1939SAndy Fiddaman 				{
315*b30d1939SAndy Fiddaman 					ERR(ERANGE);
316*b30d1939SAndy Fiddaman 					return 0;
317*b30d1939SAndy Fiddaman 				}
318*b30d1939SAndy Fiddaman 				v = S2F_ldexp(v, S2F_exp_2_min);
319*b30d1939SAndy Fiddaman 			}
320*b30d1939SAndy Fiddaman 			else if (m > S2F_exp_2_max)
321*b30d1939SAndy Fiddaman 			{
322*b30d1939SAndy Fiddaman 				ERR(ERANGE);
323*b30d1939SAndy Fiddaman 				return negative ? -S2F_inf : S2F_inf;
324*b30d1939SAndy Fiddaman 			}
325*b30d1939SAndy Fiddaman 			v = S2F_ldexp(v, m);
326*b30d1939SAndy Fiddaman 			goto check;
327*b30d1939SAndy Fiddaman 		}
328*b30d1939SAndy Fiddaman 		while (c == '0')
329*b30d1939SAndy Fiddaman 			c = GET(s);
330*b30d1939SAndy Fiddaman 	}
331*b30d1939SAndy Fiddaman 	else if (c == decimal)
332*b30d1939SAndy Fiddaman 	{
333*b30d1939SAndy Fiddaman 		decimal = -1;
334*b30d1939SAndy Fiddaman 		fraction = 0;
335*b30d1939SAndy Fiddaman 		for (;;)
336*b30d1939SAndy Fiddaman 		{
337*b30d1939SAndy Fiddaman 			c = GET(s);
338*b30d1939SAndy Fiddaman 			if (c != '0')
339*b30d1939SAndy Fiddaman 				break;
340*b30d1939SAndy Fiddaman 			digits++;
341*b30d1939SAndy Fiddaman 		}
342*b30d1939SAndy Fiddaman 	}
343*b30d1939SAndy Fiddaman 	else if (c == 'i' || c == 'I')
344*b30d1939SAndy Fiddaman 	{
345*b30d1939SAndy Fiddaman 		if ((c = GET(s)) != 'n' && c != 'N' ||
346*b30d1939SAndy Fiddaman 		    (c = GET(s)) != 'f' && c != 'F')
347*b30d1939SAndy Fiddaman 		{
348*b30d1939SAndy Fiddaman 			REV(s, t, b);
349*b30d1939SAndy Fiddaman 			PUT(s);
350*b30d1939SAndy Fiddaman 			return 0;
351*b30d1939SAndy Fiddaman 		}
352*b30d1939SAndy Fiddaman 		c = GET(s);
353*b30d1939SAndy Fiddaman 		SET(s, t, b);
354*b30d1939SAndy Fiddaman 		if (((c)          == 'i' || c == 'I') &&
355*b30d1939SAndy Fiddaman 		    ((c = GET(s)) == 'n' || c == 'N') &&
356*b30d1939SAndy Fiddaman 		    ((c = GET(s)) == 'i' || c == 'I') &&
357*b30d1939SAndy Fiddaman 		    ((c = GET(s)) == 't' || c == 'T') &&
358*b30d1939SAndy Fiddaman 		    ((c = GET(s)) == 'y' || c == 'Y'))
359*b30d1939SAndy Fiddaman 		{
360*b30d1939SAndy Fiddaman 			c = GET(s);
361*b30d1939SAndy Fiddaman 			SET(s, t, b);
362*b30d1939SAndy Fiddaman 		}
363*b30d1939SAndy Fiddaman 		REV(s, t, b);
364*b30d1939SAndy Fiddaman 		PUT(s);
365*b30d1939SAndy Fiddaman 		return negative ? -S2F_inf : S2F_inf;
366*b30d1939SAndy Fiddaman 	}
367*b30d1939SAndy Fiddaman 	else if (c == 'n' || c == 'N')
368*b30d1939SAndy Fiddaman 	{
369*b30d1939SAndy Fiddaman 		if ((c = GET(s)) != 'a' && c != 'A' ||
370*b30d1939SAndy Fiddaman 		    (c = GET(s)) != 'n' && c != 'N')
371*b30d1939SAndy Fiddaman 		{
372*b30d1939SAndy Fiddaman 			REV(s, t, b);
373*b30d1939SAndy Fiddaman 			PUT(s);
374*b30d1939SAndy Fiddaman 			return 0;
375*b30d1939SAndy Fiddaman 		}
376*b30d1939SAndy Fiddaman 		do c = GET(s); while (c && !isspace(c));
377*b30d1939SAndy Fiddaman 		PUT(s);
378*b30d1939SAndy Fiddaman 		return negative ? -S2F_nan : S2F_nan;
379*b30d1939SAndy Fiddaman 	}
380*b30d1939SAndy Fiddaman 	else if (c < '1' || c > '9')
381*b30d1939SAndy Fiddaman 	{
382*b30d1939SAndy Fiddaman 		REV(s, t, b);
383*b30d1939SAndy Fiddaman 		PUT(s);
384*b30d1939SAndy Fiddaman 		NON(s);
385*b30d1939SAndy Fiddaman 		return 0;
386*b30d1939SAndy Fiddaman 	}
387*b30d1939SAndy Fiddaman 
388*b30d1939SAndy Fiddaman 	/*
389*b30d1939SAndy Fiddaman 	 * consume the integral and fractional parts
390*b30d1939SAndy Fiddaman 	 */
391*b30d1939SAndy Fiddaman 
392*b30d1939SAndy Fiddaman 	n = 0;
393*b30d1939SAndy Fiddaman 	m = 0;
394*b30d1939SAndy Fiddaman 	for (;;)
395*b30d1939SAndy Fiddaman 	{
396*b30d1939SAndy Fiddaman 		if (c >= '0' && c <= '9')
397*b30d1939SAndy Fiddaman 		{
398*b30d1939SAndy Fiddaman 			digits++;
399*b30d1939SAndy Fiddaman 			n = (n << 3) + (n << 1) + (c - '0');
400*b30d1939SAndy Fiddaman 			if (n >= ((~((S2F_batch)0)) / 10) && part < elementsof(parts))
401*b30d1939SAndy Fiddaman 			{
402*b30d1939SAndy Fiddaman 				parts[part].batch = n;
403*b30d1939SAndy Fiddaman 				n = 0;
404*b30d1939SAndy Fiddaman 				parts[part].digits = digits;
405*b30d1939SAndy Fiddaman 				part++;
406*b30d1939SAndy Fiddaman 			}
407*b30d1939SAndy Fiddaman 		}
408*b30d1939SAndy Fiddaman 		else if (m && (digits - m) != 3)
409*b30d1939SAndy Fiddaman 			break;
410*b30d1939SAndy Fiddaman 		else if (c == decimal)
411*b30d1939SAndy Fiddaman 		{
412*b30d1939SAndy Fiddaman 			decimal = -1;
413*b30d1939SAndy Fiddaman 			thousand = -1;
414*b30d1939SAndy Fiddaman 			m = 0;
415*b30d1939SAndy Fiddaman 			fraction = digits;
416*b30d1939SAndy Fiddaman 		}
417*b30d1939SAndy Fiddaman 		else if (c != thousand || (c == thousand && decimal == -1))
418*b30d1939SAndy Fiddaman 			break;
419*b30d1939SAndy Fiddaman 		else if (!(m = digits))
420*b30d1939SAndy Fiddaman 		{
421*b30d1939SAndy Fiddaman 			SET(s, t, b);
422*b30d1939SAndy Fiddaman 			break;
423*b30d1939SAndy Fiddaman 		}
424*b30d1939SAndy Fiddaman 		else
425*b30d1939SAndy Fiddaman 		{
426*b30d1939SAndy Fiddaman 			SET(s, t, b);
427*b30d1939SAndy Fiddaman 			back_n = n;
428*b30d1939SAndy Fiddaman 			back_part = part;
429*b30d1939SAndy Fiddaman 		}
430*b30d1939SAndy Fiddaman 		c = GET(s);
431*b30d1939SAndy Fiddaman 	}
432*b30d1939SAndy Fiddaman 	if (m && (digits - m) != 3)
433*b30d1939SAndy Fiddaman 	{
434*b30d1939SAndy Fiddaman 		REV(s, t, b);
435*b30d1939SAndy Fiddaman 		n = back_n;
436*b30d1939SAndy Fiddaman 		part = back_part;
437*b30d1939SAndy Fiddaman 	}
438*b30d1939SAndy Fiddaman 
439*b30d1939SAndy Fiddaman 	/*
440*b30d1939SAndy Fiddaman 	 * don't forget the last part
441*b30d1939SAndy Fiddaman 	 */
442*b30d1939SAndy Fiddaman 
443*b30d1939SAndy Fiddaman 	if (n && part < elementsof(parts))
444*b30d1939SAndy Fiddaman 	{
445*b30d1939SAndy Fiddaman 		parts[part].batch = n;
446*b30d1939SAndy Fiddaman 		parts[part].digits = digits;
447*b30d1939SAndy Fiddaman 		part++;
448*b30d1939SAndy Fiddaman 	}
449*b30d1939SAndy Fiddaman 
450*b30d1939SAndy Fiddaman 	/*
451*b30d1939SAndy Fiddaman 	 * consume the exponent
452*b30d1939SAndy Fiddaman 	 */
453*b30d1939SAndy Fiddaman 
454*b30d1939SAndy Fiddaman 	if (fraction >= 0)
455*b30d1939SAndy Fiddaman 		digits = fraction;
456*b30d1939SAndy Fiddaman 	if (c == 'e' || c == 'E')
457*b30d1939SAndy Fiddaman 	{
458*b30d1939SAndy Fiddaman 		c = GET(s);
459*b30d1939SAndy Fiddaman 		if ((enegative = (c == '-')) || c == '+')
460*b30d1939SAndy Fiddaman 			c = GET(s);
461*b30d1939SAndy Fiddaman 		n = 0;
462*b30d1939SAndy Fiddaman 		while (c >= '0' && c <= '9')
463*b30d1939SAndy Fiddaman 		{
464*b30d1939SAndy Fiddaman 			n = (n << 3) + (n << 1) + (c - '0');
465*b30d1939SAndy Fiddaman 			c = GET(s);
466*b30d1939SAndy Fiddaman 		}
467*b30d1939SAndy Fiddaman 		if (enegative)
468*b30d1939SAndy Fiddaman 			digits -= n;
469*b30d1939SAndy Fiddaman 		else
470*b30d1939SAndy Fiddaman 			digits += n;
471*b30d1939SAndy Fiddaman 	}
472*b30d1939SAndy Fiddaman 
473*b30d1939SAndy Fiddaman #if S2F_qualifier
474*b30d1939SAndy Fiddaman 
475*b30d1939SAndy Fiddaman 	/*
476*b30d1939SAndy Fiddaman 	 * consume the optional suffix
477*b30d1939SAndy Fiddaman 	 */
478*b30d1939SAndy Fiddaman 
479*b30d1939SAndy Fiddaman 	switch (c)
480*b30d1939SAndy Fiddaman 	{
481*b30d1939SAndy Fiddaman 	case 'f':
482*b30d1939SAndy Fiddaman 	case 'F':
483*b30d1939SAndy Fiddaman 	case 'l':
484*b30d1939SAndy Fiddaman 	case 'L':
485*b30d1939SAndy Fiddaman 		c = GET(s);
486*b30d1939SAndy Fiddaman 		break;
487*b30d1939SAndy Fiddaman 	}
488*b30d1939SAndy Fiddaman #endif
489*b30d1939SAndy Fiddaman 	PUT(s);
490*b30d1939SAndy Fiddaman 
491*b30d1939SAndy Fiddaman 	/*
492*b30d1939SAndy Fiddaman 	 * adjust for at most one multiply per part
493*b30d1939SAndy Fiddaman 	 * and at most one divide overall
494*b30d1939SAndy Fiddaman 	 */
495*b30d1939SAndy Fiddaman 
496*b30d1939SAndy Fiddaman 	v = 0;
497*b30d1939SAndy Fiddaman 	if (!part)
498*b30d1939SAndy Fiddaman 		return negative ? -v : v;
499*b30d1939SAndy Fiddaman 	else if ((m = parts[part-1].digits - digits) > 0)
500*b30d1939SAndy Fiddaman 		digits += m;
501*b30d1939SAndy Fiddaman 	else
502*b30d1939SAndy Fiddaman 		m = 0;
503*b30d1939SAndy Fiddaman 
504*b30d1939SAndy Fiddaman 	/*
505*b30d1939SAndy Fiddaman 	 * combine the parts
506*b30d1939SAndy Fiddaman 	 */
507*b30d1939SAndy Fiddaman 
508*b30d1939SAndy Fiddaman 	while (part--)
509*b30d1939SAndy Fiddaman 	{
510*b30d1939SAndy Fiddaman 		p = parts[part].batch;
511*b30d1939SAndy Fiddaman 		c = digits - parts[part].digits;
512*b30d1939SAndy Fiddaman 		if (c > S2F_exp_10_max)
513*b30d1939SAndy Fiddaman 		{
514*b30d1939SAndy Fiddaman 			ERR(ERANGE);
515*b30d1939SAndy Fiddaman 			return negative ? -S2F_inf : S2F_inf;
516*b30d1939SAndy Fiddaman 		}
517*b30d1939SAndy Fiddaman 		if (c > 0)
518*b30d1939SAndy Fiddaman 		{
519*b30d1939SAndy Fiddaman #if _ast_mpy_overflow_fpe
520*b30d1939SAndy Fiddaman 			if ((S2F_max / p) < S2F_pow10[c])
521*b30d1939SAndy Fiddaman 			{
522*b30d1939SAndy Fiddaman 				ERR(ERANGE);
523*b30d1939SAndy Fiddaman 				return negative ? -S2F_inf : S2F_inf;
524*b30d1939SAndy Fiddaman 			}
525*b30d1939SAndy Fiddaman #endif
526*b30d1939SAndy Fiddaman 			p *= S2F_pow10[c];
527*b30d1939SAndy Fiddaman 		}
528*b30d1939SAndy Fiddaman 		v += p;
529*b30d1939SAndy Fiddaman 	}
530*b30d1939SAndy Fiddaman 	if (m)
531*b30d1939SAndy Fiddaman 	{
532*b30d1939SAndy Fiddaman 		while (m > S2F_exp_10_max)
533*b30d1939SAndy Fiddaman 		{
534*b30d1939SAndy Fiddaman 			m -= S2F_exp_10_max;
535*b30d1939SAndy Fiddaman 			v /= S2F_pow10[S2F_exp_10_max];
536*b30d1939SAndy Fiddaman 		}
537*b30d1939SAndy Fiddaman #if _ast_div_underflow_fpe
538*b30d1939SAndy Fiddaman 		if ((S2F_min * p) > S2F_pow10[c])
539*b30d1939SAndy Fiddaman 		{
540*b30d1939SAndy Fiddaman 			ERR(ERANGE);
541*b30d1939SAndy Fiddaman 			return negative ? -S2F_inf : S2F_inf;
542*b30d1939SAndy Fiddaman 		}
543*b30d1939SAndy Fiddaman #endif
544*b30d1939SAndy Fiddaman 		v /= S2F_pow10[m];
545*b30d1939SAndy Fiddaman 	}
546*b30d1939SAndy Fiddaman 
547*b30d1939SAndy Fiddaman 	/*
548*b30d1939SAndy Fiddaman 	 * check the range
549*b30d1939SAndy Fiddaman 	 */
550*b30d1939SAndy Fiddaman 
551*b30d1939SAndy Fiddaman  check:
552*b30d1939SAndy Fiddaman 	if (v < S2F_min)
553*b30d1939SAndy Fiddaman 	{
554*b30d1939SAndy Fiddaman 		ERR(ERANGE);
555*b30d1939SAndy Fiddaman 		v = 0;
556*b30d1939SAndy Fiddaman 	}
557*b30d1939SAndy Fiddaman 	else if (v > S2F_max)
558*b30d1939SAndy Fiddaman 	{
559*b30d1939SAndy Fiddaman 		ERR(ERANGE);
560*b30d1939SAndy Fiddaman 		v = S2F_inf;
561*b30d1939SAndy Fiddaman 	}
562*b30d1939SAndy Fiddaman 
563*b30d1939SAndy Fiddaman 	/*
564*b30d1939SAndy Fiddaman 	 * done
565*b30d1939SAndy Fiddaman 	 */
566*b30d1939SAndy Fiddaman 
567*b30d1939SAndy Fiddaman 	return negative ? -v : v;
568*b30d1939SAndy Fiddaman }
569