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