1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A/*
1N/A * AT&T Research
1N/A * Glenn Fowler & Phong Vo
1N/A *
1N/A * common header and implementation for
1N/A *
1N/A * strtof strtod strtold _sfdscan
1N/A * strntof strntod strntold
1N/A *
1N/A * define these macros to instantiate an implementation:
1N/A *
1N/A * S2F_function the function name
1N/A * S2F_static <0:export =0:extern >0:static
1N/A * S2F_type 0:float 1:double 2:long.double
1N/A * S2F_qualifier 1 for optional [fFlL] qualifier suffix
1N/A * S2F_size 1 for interface with size_t second arg
1N/A * S2F_scan 1 for alternate interface with these arguments:
1N/A * void* handle
1N/A * int (*getchar)(void* handle, int flag)
1N/A * exactly one extra (*getchar)() is done, i.e.,
1N/A * the caller must do the pushback
1N/A * flag==0 get next char
1N/A * flag==1 no number seen
1N/A * return 0 on error or EOF
1N/A */
1N/A
1N/A#include "sfhdr.h"
1N/A#include "FEATURE/float"
1N/A
1N/A/*
1N/A * the default is _sfdscan for standalone sfio compatibility
1N/A */
1N/A
1N/A#if !defined(S2F_function)
1N/A#define S2F_function _sfdscan
1N/A#define S2F_static 1
1N/A#define S2F_type 2
1N/A#define S2F_scan 1
1N/A#ifndef elementsof
1N/A#define elementsof(a) (sizeof(a)/sizeof(a[0]))
1N/A#endif
1N/A#endif
1N/A
1N/A#if S2F_type == 2 && _ast_fltmax_double
1N/A#undef S2F_type
1N/A#define S2F_type 1
1N/A#endif
1N/A
1N/A#if S2F_type == 0
1N/A#define S2F_number float
1N/A#define S2F_ldexp ldexp
1N/A#define S2F_pow10 _Sffpow10
1N/A#define S2F_inf _Sffinf
1N/A#define S2F_nan _Sffnan
1N/A#define S2F_min (FLT_MIN)
1N/A#define S2F_max (FLT_MAX)
1N/A#define S2F_exp_10_min (FLT_MIN_10_EXP)
1N/A#define S2F_exp_10_max (FLT_MAX_10_EXP)
1N/A#define S2F_exp_2_min (FLT_MIN_EXP)
1N/A#define S2F_exp_2_max (FLT_MAX_EXP)
1N/A#endif
1N/A#if S2F_type == 1
1N/A#define S2F_number double
1N/A#define S2F_ldexp ldexp
1N/A#define S2F_pow10 _Sfdpow10
1N/A#define S2F_inf _Sfdinf
1N/A#define S2F_nan _Sfdnan
1N/A#define S2F_min (DBL_MIN)
1N/A#define S2F_max (DBL_MAX)
1N/A#define S2F_exp_10_min (DBL_MIN_10_EXP)
1N/A#define S2F_exp_10_max (DBL_MAX_10_EXP)
1N/A#define S2F_exp_2_min (DBL_MIN_EXP)
1N/A#define S2F_exp_2_max (DBL_MAX_EXP)
1N/A#endif
1N/A#if S2F_type == 2
1N/A#define S2F_number long double
1N/A#define S2F_ldexp ldexpl
1N/A#define S2F_pow10 _Sflpow10
1N/A#define S2F_inf _Sflinf
1N/A#define S2F_nan _Sflnan
1N/A#define S2F_min (LDBL_MIN)
1N/A#define S2F_max (LDBL_MAX)
1N/A#define S2F_exp_10_min (LDBL_MIN_10_EXP)
1N/A#define S2F_exp_10_max (LDBL_MAX_10_EXP)
1N/A#define S2F_exp_2_min (LDBL_MIN_EXP)
1N/A#define S2F_exp_2_max (LDBL_MAX_EXP)
1N/A#endif
1N/A
1N/A#if -S2F_exp_10_min < S2F_exp_10_max
1N/A#define S2F_exp_10_abs (-S2F_exp_10_min)
1N/A#else
1N/A#define S2F_exp_10_abs S2F_exp_10_max
1N/A#endif
1N/A
1N/A#define S2F_batch _ast_flt_unsigned_max_t
1N/A
1N/A#undef ERR /* who co-opted this namespace? */
1N/A
1N/A#if S2F_scan
1N/A
1N/Atypedef int (*S2F_get_f)_ARG_((void*, int));
1N/A
1N/A#define ERR(e)
1N/A#define GET(p) (*get)(p,0)
1N/A#define NON(p) (*get)(p,1)
1N/A#define PUT(p)
1N/A#define REV(p,t,b)
1N/A#define SET(p,t,b)
1N/A
1N/A#else
1N/A
1N/A#define ERR(e) (errno=(e))
1N/A#define NON(p)
1N/A
1N/A#if S2F_size
1N/A#define GET(p) (((p)<(z))?(*p++):(back=0))
1N/A#define PUT(p) (end?(*end=(char*)p-back):(char*)0)
1N/A#define REV(p,t,b) (p=t,back=b)
1N/A#define SET(p,t,b) (t=p,b=back)
1N/A#else
1N/A#define GET(p) (*p++)
1N/A#define PUT(p) (end?(*end=(char*)p-1):(char*)0)
1N/A#define REV(p,t,b) (p=t)
1N/A#define SET(p,t,b) (t=p)
1N/A#endif
1N/A
1N/A#endif
1N/A
1N/Atypedef struct S2F_part_s
1N/A{
1N/A S2F_batch batch;
1N/A int digits;
1N/A} S2F_part_t;
1N/A
1N/A#if !defined(ERANGE)
1N/A#define ERANGE EINVAL
1N/A#endif
1N/A
1N/A#if S2F_static > 0
1N/Astatic
1N/A#else
1N/A#if S2F_static < 0 || !defined(S2F_static)
1N/A#if defined(__EXPORT__)
1N/A#define extern __EXPORT__
1N/A#endif
1N/Aextern
1N/A#undef extern
1N/A#endif
1N/A#endif
1N/AS2F_number
1N/A#if S2F_scan
1N/A#if __STD_C
1N/AS2F_function(void* s, S2F_get_f get)
1N/A#else
1N/AS2F_function(s, get) void* s; S2F_get_f get;
1N/A#endif
1N/A#else
1N/A#if S2F_size
1N/A#if __STD_C
1N/AS2F_function(const char* str, size_t size, char** end)
1N/A#else
1N/AS2F_function(str, size, end) char* str; size_t size; char** end;
1N/A#endif
1N/A#else
1N/A#if __STD_C
1N/AS2F_function(const char* str, char** end)
1N/A#else
1N/AS2F_function(str, end) char* str; char** end;
1N/A#endif
1N/A#endif
1N/A#endif
1N/A{
1N/A#if !S2F_scan
1N/A register unsigned char* s = (unsigned char*)str;
1N/A#if S2F_size
1N/A register unsigned char* z = s + size;
1N/A int back = 1;
1N/A int b;
1N/A#endif
1N/A unsigned char* t;
1N/A#endif
1N/A register S2F_batch n;
1N/A register int c;
1N/A register int digits;
1N/A register int m;
1N/A register unsigned char* cv;
1N/A int negative;
1N/A int enegative;
1N/A int fraction;
1N/A int decimal = 0;
1N/A int thousand = 0;
1N/A int part = 0;
1N/A int back_part;
1N/A S2F_batch back_n;
1N/A S2F_number v;
1N/A S2F_number p;
1N/A S2F_part_t parts[16];
1N/A
1N/A /*
1N/A * radix char and thousands separator are locale specific
1N/A */
1N/A
1N/A SFSETLOCALE(&decimal, &thousand);
1N/A SFCVINIT();
1N/A
1N/A /*
1N/A * skip initial blanks
1N/A */
1N/A
1N/A do c = GET(s); while (isspace(c));
1N/A SET(s, t, b);
1N/A
1N/A /*
1N/A * get the sign
1N/A */
1N/A
1N/A if ((negative = (c == '-')) || c == '+')
1N/A c = GET(s);
1N/A
1N/A /*
1N/A * drop leading 0's
1N/A */
1N/A
1N/A digits = 0;
1N/A fraction = -1;
1N/A if (c == '0')
1N/A {
1N/A c = GET(s);
1N/A if (c == 'x' || c == 'X')
1N/A {
1N/A /*
1N/A * hex floating point -- easy
1N/A */
1N/A
1N/A cv = _Sfcv36;
1N/A v = 0;
1N/A for (;;)
1N/A {
1N/A c = GET(s);
1N/A if ((part = cv[c]) < 16)
1N/A {
1N/A digits++;
1N/A v *= 16;
1N/A v += part;
1N/A }
1N/A else if (c == decimal)
1N/A {
1N/A decimal = -1;
1N/A fraction = digits;
1N/A }
1N/A else
1N/A break;
1N/A }
1N/A m = 0;
1N/A if (c == 'p' || c == 'P')
1N/A {
1N/A c = GET(s);
1N/A if ((enegative = c == '-') || c == '+')
1N/A c = GET(s);
1N/A while (c >= '0' && c <= '9')
1N/A {
1N/A m = (m << 3) + (m << 1) + (c - '0');
1N/A c = GET(s);
1N/A }
1N/A if (enegative)
1N/A m = -m;
1N/A }
1N/A
1N/A#if S2F_qualifier
1N/A
1N/A /*
1N/A * consume the optional suffix
1N/A */
1N/A
1N/A switch (c)
1N/A {
1N/A case 'f':
1N/A case 'F':
1N/A case 'l':
1N/A case 'L':
1N/A c = GET(s);
1N/A break;
1N/A }
1N/A#endif
1N/A PUT(s);
1N/A if (v == 0)
1N/A return negative ? -v : v;
1N/A if (fraction >= 0)
1N/A m -= 4 * (digits - fraction);
1N/A if (m < S2F_exp_2_min)
1N/A {
1N/A if ((m -= S2F_exp_2_min) < S2F_exp_2_min)
1N/A {
1N/A ERR(ERANGE);
1N/A return 0;
1N/A }
1N/A v = S2F_ldexp(v, S2F_exp_2_min);
1N/A }
1N/A else if (m > S2F_exp_2_max)
1N/A {
1N/A ERR(ERANGE);
1N/A return negative ? -S2F_inf : S2F_inf;
1N/A }
1N/A v = S2F_ldexp(v, m);
1N/A goto check;
1N/A }
1N/A while (c == '0')
1N/A c = GET(s);
1N/A }
1N/A else if (c == decimal)
1N/A {
1N/A decimal = -1;
1N/A fraction = 0;
1N/A for (;;)
1N/A {
1N/A c = GET(s);
1N/A if (c != '0')
1N/A break;
1N/A digits++;
1N/A }
1N/A }
1N/A else if (c == 'i' || c == 'I')
1N/A {
1N/A if ((c = GET(s)) != 'n' && c != 'N' ||
1N/A (c = GET(s)) != 'f' && c != 'F')
1N/A {
1N/A REV(s, t, b);
1N/A PUT(s);
1N/A return 0;
1N/A }
1N/A c = GET(s);
1N/A SET(s, t, b);
1N/A if (((c) == 'i' || c == 'I') &&
1N/A ((c = GET(s)) == 'n' || c == 'N') &&
1N/A ((c = GET(s)) == 'i' || c == 'I') &&
1N/A ((c = GET(s)) == 't' || c == 'T') &&
1N/A ((c = GET(s)) == 'y' || c == 'Y'))
1N/A {
1N/A c = GET(s);
1N/A SET(s, t, b);
1N/A }
1N/A REV(s, t, b);
1N/A PUT(s);
1N/A return negative ? -S2F_inf : S2F_inf;
1N/A }
1N/A else if (c == 'n' || c == 'N')
1N/A {
1N/A if ((c = GET(s)) != 'a' && c != 'A' ||
1N/A (c = GET(s)) != 'n' && c != 'N')
1N/A {
1N/A REV(s, t, b);
1N/A PUT(s);
1N/A return 0;
1N/A }
1N/A do c = GET(s); while (c && !isspace(c));
1N/A PUT(s);
1N/A return negative ? -S2F_nan : S2F_nan;
1N/A }
1N/A else if (c < '1' || c > '9')
1N/A {
1N/A REV(s, t, b);
1N/A PUT(s);
1N/A NON(s);
1N/A return 0;
1N/A }
1N/A
1N/A /*
1N/A * consume the integral and fractional parts
1N/A */
1N/A
1N/A n = 0;
1N/A m = 0;
1N/A for (;;)
1N/A {
1N/A if (c >= '0' && c <= '9')
1N/A {
1N/A digits++;
1N/A n = (n << 3) + (n << 1) + (c - '0');
1N/A if (n >= ((~((S2F_batch)0)) / 10) && part < elementsof(parts))
1N/A {
1N/A parts[part].batch = n;
1N/A n = 0;
1N/A parts[part].digits = digits;
1N/A part++;
1N/A }
1N/A }
1N/A else if (m && (digits - m) != 3)
1N/A break;
1N/A else if (c == decimal)
1N/A {
1N/A decimal = -1;
1N/A thousand = -1;
1N/A m = 0;
1N/A fraction = digits;
1N/A }
1N/A else if (c != thousand)
1N/A break;
1N/A else if (!(m = digits))
1N/A {
1N/A SET(s, t, b);
1N/A break;
1N/A }
1N/A else
1N/A {
1N/A SET(s, t, b);
1N/A back_n = n;
1N/A back_part = part;
1N/A }
1N/A c = GET(s);
1N/A }
1N/A if (m && (digits - m) != 3)
1N/A {
1N/A REV(s, t, b);
1N/A n = back_n;
1N/A part = back_part;
1N/A }
1N/A
1N/A /*
1N/A * don't forget the last part
1N/A */
1N/A
1N/A if (n && part < elementsof(parts))
1N/A {
1N/A parts[part].batch = n;
1N/A parts[part].digits = digits;
1N/A part++;
1N/A }
1N/A
1N/A /*
1N/A * consume the exponent
1N/A */
1N/A
1N/A if (fraction >= 0)
1N/A digits = fraction;
1N/A if (c == 'e' || c == 'E')
1N/A {
1N/A c = GET(s);
1N/A if ((enegative = (c == '-')) || c == '+')
1N/A c = GET(s);
1N/A n = 0;
1N/A while (c >= '0' && c <= '9')
1N/A {
1N/A n = (n << 3) + (n << 1) + (c - '0');
1N/A c = GET(s);
1N/A }
1N/A if (enegative)
1N/A digits -= n;
1N/A else
1N/A digits += n;
1N/A }
1N/A
1N/A#if S2F_qualifier
1N/A
1N/A /*
1N/A * consume the optional suffix
1N/A */
1N/A
1N/A switch (c)
1N/A {
1N/A case 'f':
1N/A case 'F':
1N/A case 'l':
1N/A case 'L':
1N/A c = GET(s);
1N/A break;
1N/A }
1N/A#endif
1N/A PUT(s);
1N/A
1N/A /*
1N/A * adjust for at most one multiply per part
1N/A * and at most one divide overall
1N/A */
1N/A
1N/A v = 0;
1N/A if (!part)
1N/A return negative ? -v : v;
1N/A else if ((m = parts[part-1].digits - digits) > 0)
1N/A digits += m;
1N/A else
1N/A m = 0;
1N/A
1N/A /*
1N/A * combine the parts
1N/A */
1N/A
1N/A while (part--)
1N/A {
1N/A p = parts[part].batch;
1N/A c = digits - parts[part].digits;
1N/A if (c > S2F_exp_10_max)
1N/A {
1N/A ERR(ERANGE);
1N/A return negative ? -S2F_inf : S2F_inf;
1N/A }
1N/A if (c > 0)
1N/A {
1N/A#if _ast_mpy_overflow_fpe
1N/A if ((S2F_max / p) < S2F_pow10[c])
1N/A {
1N/A ERR(ERANGE);
1N/A return negative ? -S2F_inf : S2F_inf;
1N/A }
1N/A#endif
1N/A p *= S2F_pow10[c];
1N/A }
1N/A v += p;
1N/A }
1N/A if (m)
1N/A {
1N/A while (m > S2F_exp_10_max)
1N/A {
1N/A m -= S2F_exp_10_max;
1N/A v /= S2F_pow10[S2F_exp_10_max];
1N/A }
1N/A#if _ast_div_underflow_fpe
1N/A if ((S2F_min * p) > S2F_pow10[c])
1N/A {
1N/A ERR(ERANGE);
1N/A return negative ? -S2F_inf : S2F_inf;
1N/A }
1N/A#endif
1N/A v /= S2F_pow10[m];
1N/A }
1N/A
1N/A /*
1N/A * check the range
1N/A */
1N/A
1N/A check:
1N/A if (v < S2F_min)
1N/A {
1N/A ERR(ERANGE);
1N/A v = 0;
1N/A }
1N/A else if (v > S2F_max)
1N/A {
1N/A ERR(ERANGE);
1N/A v = S2F_inf;
1N/A }
1N/A
1N/A /*
1N/A * done
1N/A */
1N/A
1N/A return negative ? -v : v;
1N/A}