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