xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfstrtof.h (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin /*
234887Schin  * AT&T Research
244887Schin  * Glenn Fowler & Phong Vo
254887Schin  *
264887Schin  * common header and implementation for
274887Schin  *
284887Schin  *	strtof		strtod		strtold		_sfdscan
294887Schin  *	strntof		strntod		strntold
304887Schin  *
314887Schin  * define these macros to instantiate an implementation:
324887Schin  *
334887Schin  *	S2F_function	the function name
344887Schin  *	S2F_static	<0:export =0:extern >0:static
354887Schin  *	S2F_type	0:float 1:double 2:long.double
3610898Sroland.mainz@nrubsig.org  *	S2F_qualifier	1 for optional [fFlL] qualifier suffix
374887Schin  *	S2F_size	1 for interface with size_t second arg
384887Schin  *	S2F_scan	1 for alternate interface with these arguments:
394887Schin  *				void* handle
404887Schin  *				int (*getchar)(void* handle, int flag)
414887Schin  *			exactly one extra (*getchar)() is done, i.e.,
424887Schin  *			the caller must do the pushback
434887Schin  *				flag==0		get next char
444887Schin  *				flag==1		no number seen
454887Schin  *			return 0 on error or EOF
464887Schin  */
474887Schin 
484887Schin #include "sfhdr.h"
494887Schin #include "FEATURE/float"
504887Schin 
514887Schin /*
524887Schin  * the default is _sfdscan for standalone sfio compatibility
534887Schin  */
544887Schin 
554887Schin #if !defined(S2F_function)
564887Schin #define S2F_function	_sfdscan
574887Schin #define S2F_static	1
584887Schin #define S2F_type	2
594887Schin #define S2F_scan	1
604887Schin #ifndef elementsof
614887Schin #define elementsof(a)	(sizeof(a)/sizeof(a[0]))
624887Schin #endif
634887Schin #endif
644887Schin 
654887Schin #if S2F_type == 2 && _ast_fltmax_double
664887Schin #undef	S2F_type
674887Schin #define S2F_type	1
684887Schin #endif
694887Schin 
704887Schin #if S2F_type == 0
714887Schin #define S2F_number	float
724887Schin #define S2F_ldexp	ldexp
734887Schin #define S2F_pow10	_Sffpow10
744887Schin #define S2F_inf		_Sffinf
754887Schin #define S2F_nan		_Sffnan
764887Schin #define S2F_min		(FLT_MIN)
774887Schin #define S2F_max		(FLT_MAX)
784887Schin #define S2F_exp_10_min	(FLT_MIN_10_EXP)
794887Schin #define S2F_exp_10_max	(FLT_MAX_10_EXP)
804887Schin #define S2F_exp_2_min	(FLT_MIN_EXP)
814887Schin #define S2F_exp_2_max	(FLT_MAX_EXP)
824887Schin #endif
834887Schin #if S2F_type == 1
844887Schin #define S2F_number	double
854887Schin #define S2F_ldexp	ldexp
864887Schin #define S2F_pow10	_Sfdpow10
874887Schin #define S2F_inf		_Sfdinf
884887Schin #define S2F_nan		_Sfdnan
894887Schin #define S2F_min		(DBL_MIN)
904887Schin #define S2F_max		(DBL_MAX)
914887Schin #define S2F_exp_10_min	(DBL_MIN_10_EXP)
924887Schin #define S2F_exp_10_max	(DBL_MAX_10_EXP)
934887Schin #define S2F_exp_2_min	(DBL_MIN_EXP)
944887Schin #define S2F_exp_2_max	(DBL_MAX_EXP)
954887Schin #endif
964887Schin #if S2F_type == 2
974887Schin #define S2F_number	long double
984887Schin #define S2F_ldexp	ldexpl
994887Schin #define S2F_pow10	_Sflpow10
1004887Schin #define S2F_inf		_Sflinf
1014887Schin #define S2F_nan		_Sflnan
1024887Schin #define S2F_min		(LDBL_MIN)
1034887Schin #define S2F_max		(LDBL_MAX)
1044887Schin #define S2F_exp_10_min	(LDBL_MIN_10_EXP)
1054887Schin #define S2F_exp_10_max	(LDBL_MAX_10_EXP)
1064887Schin #define S2F_exp_2_min	(LDBL_MIN_EXP)
1074887Schin #define S2F_exp_2_max	(LDBL_MAX_EXP)
1084887Schin #endif
1094887Schin 
1104887Schin #if -S2F_exp_10_min < S2F_exp_10_max
1114887Schin #define S2F_exp_10_abs	(-S2F_exp_10_min)
1124887Schin #else
1134887Schin #define S2F_exp_10_abs	S2F_exp_10_max
1144887Schin #endif
1154887Schin 
1164887Schin #define S2F_batch	_ast_flt_unsigned_max_t
1174887Schin 
1184887Schin #undef	ERR		/* who co-opted this namespace? */
1194887Schin 
1204887Schin #if S2F_scan
1214887Schin 
1224887Schin typedef int (*S2F_get_f)_ARG_((void*, int));
1234887Schin 
1244887Schin #define ERR(e)
1254887Schin #define GET(p)		(*get)(p,0)
1264887Schin #define NON(p)		(*get)(p,1)
1274887Schin #define PUT(p)
1284887Schin #define REV(p,t,b)
1294887Schin #define SET(p,t,b)
1304887Schin 
1314887Schin #else
1324887Schin 
1334887Schin #define ERR(e)		(errno=(e))
1344887Schin #define NON(p)
1354887Schin 
1364887Schin #if S2F_size
1374887Schin #define GET(p)		(((p)<(z))?(*p++):(back=0))
1384887Schin #define PUT(p)		(end?(*end=(char*)p-back):(char*)0)
1394887Schin #define REV(p,t,b)	(p=t,back=b)
1404887Schin #define SET(p,t,b)	(t=p,b=back)
1414887Schin #else
1424887Schin #define GET(p)		(*p++)
1434887Schin #define PUT(p)		(end?(*end=(char*)p-1):(char*)0)
1444887Schin #define REV(p,t,b)	(p=t)
1454887Schin #define SET(p,t,b)	(t=p)
1464887Schin #endif
1474887Schin 
1484887Schin #endif
1494887Schin 
1504887Schin typedef struct S2F_part_s
1514887Schin {
1524887Schin 	S2F_batch	batch;
1534887Schin 	int		digits;
1544887Schin } S2F_part_t;
1554887Schin 
1564887Schin #if !defined(ERANGE)
1574887Schin #define ERANGE		EINVAL
1584887Schin #endif
1594887Schin 
1604887Schin #if S2F_static > 0
1614887Schin static
1624887Schin #else
1634887Schin #if S2F_static < 0 || !defined(S2F_static)
1644887Schin #if defined(__EXPORT__)
1654887Schin #define extern		__EXPORT__
1664887Schin #endif
1674887Schin extern
1684887Schin #undef	extern
1694887Schin #endif
1704887Schin #endif
1714887Schin S2F_number
1724887Schin #if S2F_scan
1734887Schin #if __STD_C
S2F_function(void * s,S2F_get_f get)1744887Schin S2F_function(void* s, S2F_get_f get)
1754887Schin #else
1764887Schin S2F_function(s, get) void* s; S2F_get_f get;
1774887Schin #endif
1784887Schin #else
1794887Schin #if S2F_size
1804887Schin #if __STD_C
1814887Schin S2F_function(const char* str, size_t size, char** end)
1824887Schin #else
1834887Schin S2F_function(str, size, end) char* str; size_t size; char** end;
1844887Schin #endif
1854887Schin #else
1864887Schin #if __STD_C
1874887Schin S2F_function(const char* str, char** end)
1884887Schin #else
1894887Schin S2F_function(str, end) char* str; char** end;
1904887Schin #endif
1914887Schin #endif
1924887Schin #endif
1934887Schin {
1944887Schin #if !S2F_scan
1954887Schin 	register unsigned char*	s = (unsigned char*)str;
1964887Schin #if S2F_size
1974887Schin 	register unsigned char*	z = s + size;
1984887Schin 	int			back = 1;
1994887Schin 	int			b;
2004887Schin #endif
2014887Schin 	unsigned char*		t;
2024887Schin #endif
2034887Schin 	register S2F_batch	n;
2044887Schin 	register int		c;
2054887Schin 	register int		digits;
2064887Schin 	register int		m;
2074887Schin 	register unsigned char*	cv;
2084887Schin 	int			negative;
2094887Schin 	int			enegative;
2104887Schin 	int			fraction;
2114887Schin 	int			decimal = 0;
2124887Schin 	int			thousand = 0;
2134887Schin 	int			part = 0;
2144887Schin 	S2F_number		v;
2154887Schin 	S2F_number		p;
2164887Schin 	S2F_part_t		parts[16];
2174887Schin 
2184887Schin 	/*
2194887Schin 	 * radix char and thousands separator are locale specific
2204887Schin 	 */
2214887Schin 
2224887Schin 	SFSETLOCALE(&decimal, &thousand);
2234887Schin 	SFCVINIT();
2244887Schin 
2254887Schin 	/*
2264887Schin 	 * skip initial blanks
2274887Schin 	 */
2284887Schin 
2294887Schin 	do c = GET(s); while (isspace(c));
2304887Schin 	SET(s, t, b);
2314887Schin 
2324887Schin 	/*
2334887Schin 	 * get the sign
2344887Schin 	 */
2354887Schin 
2364887Schin 	if ((negative = (c == '-')) || c == '+')
2374887Schin 		c = GET(s);
2384887Schin 
2394887Schin 	/*
2404887Schin 	 * drop leading 0's
2414887Schin 	 */
2424887Schin 
2434887Schin 	digits = 0;
2444887Schin 	fraction = -1;
2454887Schin 	if (c == '0')
2464887Schin 	{
2474887Schin 		c = GET(s);
2484887Schin 		if (c == 'x' || c == 'X')
2494887Schin 		{
2504887Schin 			/*
2514887Schin 			 * hex floating point -- easy
2524887Schin 			 */
2534887Schin 
2544887Schin 			cv = _Sfcv36;
2554887Schin 			v = 0;
2564887Schin 			for (;;)
2574887Schin 			{
2584887Schin 				c = GET(s);
2594887Schin 				if ((part = cv[c]) < 16)
2604887Schin 				{
2614887Schin 					digits++;
2624887Schin 					v *= 16;
2634887Schin 					v += part;
2644887Schin 				}
2654887Schin 				else if (c == decimal)
2664887Schin 				{
2674887Schin 					decimal = -1;
2684887Schin 					fraction = digits;
2694887Schin 				}
2704887Schin 				else
2714887Schin 					break;
2724887Schin 			}
2734887Schin 			m = 0;
2744887Schin 			if (c == 'p' || c == 'P')
2754887Schin 			{
2764887Schin 				c = GET(s);
2774887Schin 				if ((enegative = c == '-') || c == '+')
2784887Schin 					c = GET(s);
2794887Schin 				while (c >= '0' && c <= '9')
2804887Schin 				{
2814887Schin 					m = (m << 3) + (m << 1) + (c - '0');
2824887Schin 					c = GET(s);
2834887Schin 				}
2844887Schin 				if (enegative)
2854887Schin 					m = -m;
2864887Schin 			}
2874887Schin 
28810898Sroland.mainz@nrubsig.org #if S2F_qualifier
28910898Sroland.mainz@nrubsig.org 
2904887Schin 			/*
2914887Schin 			 * consume the optional suffix
2924887Schin 			 */
2934887Schin 
2944887Schin 			switch (c)
2954887Schin 			{
2964887Schin 			case 'f':
2974887Schin 			case 'F':
2984887Schin 			case 'l':
2994887Schin 			case 'L':
3004887Schin 				c = GET(s);
3014887Schin 				break;
3024887Schin 			}
30310898Sroland.mainz@nrubsig.org #endif
3044887Schin 			PUT(s);
3054887Schin 			if (v == 0)
3068462SApril.Chin@Sun.COM 				return negative ? -v : v;
3074887Schin 			if (fraction >= 0)
3084887Schin 				m -= 4 * (digits - fraction);
3094887Schin 			if (m < S2F_exp_2_min)
3104887Schin 			{
3114887Schin 				if ((m -= S2F_exp_2_min) < S2F_exp_2_min)
3124887Schin 				{
3134887Schin 					ERR(ERANGE);
3144887Schin 					return 0;
3154887Schin 				}
3164887Schin 				v = S2F_ldexp(v, S2F_exp_2_min);
3174887Schin 			}
3184887Schin 			else if (m > S2F_exp_2_max)
3194887Schin 			{
3204887Schin 				ERR(ERANGE);
3214887Schin 				return negative ? -S2F_inf : S2F_inf;
3224887Schin 			}
3234887Schin 			v = S2F_ldexp(v, m);
3244887Schin 			goto check;
3254887Schin 		}
3264887Schin 		while (c == '0')
3274887Schin 			c = GET(s);
3284887Schin 	}
3294887Schin 	else if (c == decimal)
3304887Schin 	{
3314887Schin 		decimal = -1;
3324887Schin 		fraction = 0;
3334887Schin 		for (;;)
3344887Schin 		{
3354887Schin 			c = GET(s);
3364887Schin 			if (c != '0')
3374887Schin 				break;
3384887Schin 			digits++;
3394887Schin 		}
3404887Schin 	}
3414887Schin 	else if (c == 'i' || c == 'I')
3424887Schin 	{
3434887Schin 		if ((c = GET(s)) != 'n' && c != 'N' ||
3444887Schin 		    (c = GET(s)) != 'f' && c != 'F')
3454887Schin 		{
3464887Schin 			REV(s, t, b);
3474887Schin 			PUT(s);
3484887Schin 			return 0;
3494887Schin 		}
3504887Schin 		c = GET(s);
3514887Schin 		SET(s, t, b);
3524887Schin 		if (((c)          == 'i' || c == 'I') &&
3534887Schin 		    ((c = GET(s)) == 'n' || c == 'N') &&
3544887Schin 		    ((c = GET(s)) == 'i' || c == 'I') &&
3554887Schin 		    ((c = GET(s)) == 't' || c == 'T') &&
3564887Schin 		    ((c = GET(s)) == 'y' || c == 'Y'))
3574887Schin 		{
3584887Schin 			c = GET(s);
3594887Schin 			SET(s, t, b);
3604887Schin 		}
3614887Schin 		REV(s, t, b);
3624887Schin 		PUT(s);
3634887Schin 		return negative ? -S2F_inf : S2F_inf;
3644887Schin 	}
3654887Schin 	else if (c == 'n' || c == 'N')
3664887Schin 	{
3674887Schin 		if ((c = GET(s)) != 'a' && c != 'A' ||
3684887Schin 		    (c = GET(s)) != 'n' && c != 'N')
3694887Schin 		{
3704887Schin 			REV(s, t, b);
3714887Schin 			PUT(s);
3724887Schin 			return 0;
3734887Schin 		}
3744887Schin 		do c = GET(s); while (c && !isspace(c));
3754887Schin 		PUT(s);
3768462SApril.Chin@Sun.COM 		return negative ? -S2F_nan : S2F_nan;
3774887Schin 	}
3784887Schin 	else if (c < '1' || c > '9')
3794887Schin 	{
3804887Schin 		REV(s, t, b);
3814887Schin 		PUT(s);
3824887Schin 		NON(s);
3834887Schin 		return 0;
3844887Schin 	}
3854887Schin 
3864887Schin 	/*
3874887Schin 	 * consume the integral and fractional parts
3884887Schin 	 */
3894887Schin 
3904887Schin 	n = 0;
3914887Schin 	m = 0;
3924887Schin 	for (;;)
3934887Schin 	{
3944887Schin 		if (c >= '0' && c <= '9')
3954887Schin 		{
3964887Schin 			digits++;
3974887Schin 			n = (n << 3) + (n << 1) + (c - '0');
3984887Schin 			if (n >= ((~((S2F_batch)0)) / 10) && part < elementsof(parts))
3994887Schin 			{
4004887Schin 				parts[part].batch = n;
4014887Schin 				n = 0;
4024887Schin 				parts[part].digits = digits;
4034887Schin 				part++;
4044887Schin 			}
4054887Schin 		}
4064887Schin 		else if (m && (digits - m) != 3)
4074887Schin 			break;
4084887Schin 		else if (c == decimal)
4094887Schin 		{
4104887Schin 			decimal = -1;
4114887Schin 			thousand = -1;
4124887Schin 			m = 0;
4134887Schin 			fraction = digits;
4144887Schin 		}
4154887Schin 		else if (c != thousand)
4164887Schin 			break;
4174887Schin 		else if (!(m = digits))
4184887Schin 			break;
4194887Schin 		c = GET(s);
4204887Schin 	}
4214887Schin 
4224887Schin 	/*
4234887Schin 	 * don't forget the last part
4244887Schin 	 */
4254887Schin 
4264887Schin 	if (n && part < elementsof(parts))
4274887Schin 	{
4284887Schin 		parts[part].batch = n;
4294887Schin 		parts[part].digits = digits;
4304887Schin 		part++;
4314887Schin 	}
4324887Schin 
4334887Schin 	/*
4344887Schin 	 * consume the exponent
4354887Schin 	 */
4364887Schin 
4374887Schin 	if (fraction >= 0)
4384887Schin 		digits = fraction;
4394887Schin 	if (c == 'e' || c == 'E')
4404887Schin 	{
4414887Schin 		c = GET(s);
4424887Schin 		if ((enegative = (c == '-')) || c == '+')
4434887Schin 			c = GET(s);
4444887Schin 		n = 0;
4454887Schin 		while (c >= '0' && c <= '9')
4464887Schin 		{
4474887Schin 			n = (n << 3) + (n << 1) + (c - '0');
4484887Schin 			c = GET(s);
4494887Schin 		}
4504887Schin 		if (enegative)
4514887Schin 			digits -= n;
4524887Schin 		else
4534887Schin 			digits += n;
4544887Schin 	}
4554887Schin 
45610898Sroland.mainz@nrubsig.org #if S2F_qualifier
45710898Sroland.mainz@nrubsig.org 
4584887Schin 	/*
4594887Schin 	 * consume the optional suffix
4604887Schin 	 */
4614887Schin 
4624887Schin 	switch (c)
4634887Schin 	{
4644887Schin 	case 'f':
4654887Schin 	case 'F':
4664887Schin 	case 'l':
4674887Schin 	case 'L':
4684887Schin 		c = GET(s);
4694887Schin 		break;
4704887Schin 	}
47110898Sroland.mainz@nrubsig.org #endif
4724887Schin 	PUT(s);
4734887Schin 
4744887Schin 	/*
4754887Schin 	 * adjust for at most one multiply per part
4764887Schin 	 * and at most one divide overall
4774887Schin 	 */
4784887Schin 
4798462SApril.Chin@Sun.COM 	v = 0;
4804887Schin 	if (!part)
4818462SApril.Chin@Sun.COM 		return negative ? -v : v;
4824887Schin 	else if ((m = parts[part-1].digits - digits) > 0)
4834887Schin 		digits += m;
4844887Schin 	else
4854887Schin 		m = 0;
4864887Schin 
4874887Schin 	/*
4884887Schin 	 * combine the parts
4894887Schin 	 */
4904887Schin 
4914887Schin 	while (part--)
4924887Schin 	{
4934887Schin 		p = parts[part].batch;
4944887Schin 		c = digits - parts[part].digits;
4954887Schin 		if (c > S2F_exp_10_max)
4964887Schin 		{
4974887Schin 			ERR(ERANGE);
4984887Schin 			return negative ? -S2F_inf : S2F_inf;
4994887Schin 		}
5004887Schin 		if (c > 0)
5014887Schin 		{
5024887Schin #if _ast_mpy_overflow_fpe
5034887Schin 			if ((S2F_max / p) < S2F_pow10[c])
5044887Schin 			{
5054887Schin 				ERR(ERANGE);
5064887Schin 				return negative ? -S2F_inf : S2F_inf;
5074887Schin 			}
5084887Schin #endif
5094887Schin 			p *= S2F_pow10[c];
5104887Schin 		}
5114887Schin 		v += p;
5124887Schin 	}
5134887Schin 	if (m)
5144887Schin 	{
5154887Schin 		while (m > S2F_exp_10_max)
5164887Schin 		{
5174887Schin 			m -= S2F_exp_10_max;
5184887Schin 			v /= S2F_pow10[S2F_exp_10_max];
5194887Schin 		}
5204887Schin #if _ast_div_underflow_fpe
5214887Schin 		if ((S2F_min * p) > S2F_pow10[c])
5224887Schin 		{
5234887Schin 			ERR(ERANGE);
5244887Schin 			return negative ? -S2F_inf : S2F_inf;
5254887Schin 		}
5264887Schin #endif
5274887Schin 		v /= S2F_pow10[m];
5284887Schin 	}
5294887Schin 
5304887Schin 	/*
5314887Schin 	 * check the range
5324887Schin 	 */
5334887Schin 
5344887Schin  check:
5354887Schin 	if (v < S2F_min)
5364887Schin 	{
5374887Schin 		ERR(ERANGE);
5384887Schin 		v = 0;
5394887Schin 	}
5404887Schin 	else if (v > S2F_max)
5414887Schin 	{
5424887Schin 		ERR(ERANGE);
5434887Schin 		v = S2F_inf;
5444887Schin 	}
5454887Schin 
5464887Schin 	/*
5474887Schin 	 * done
5484887Schin 	 */
5494887Schin 
5504887Schin 	return negative ? -v : v;
5514887Schin }
552