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