1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
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 #include "sfhdr.h"
23
24 /* Convert a Sfdouble_t value represented in an ASCII format into
25 ** the internal Sfdouble_t representation.
26 **
27 ** Written by Kiem-Phong Vo.
28 */
29
30 #define BATCH (2*sizeof(int)) /* accumulate this many digits at a time */
31 #define IPART 0 /* doing integer part */
32 #define FPART 1 /* doing fractional part */
33 #define EPART 2 /* doing exponent part */
34
35 #if __STD_C
sfpow10(reg int n)36 static Sfdouble_t sfpow10(reg int n)
37 #else
38 static Sfdouble_t sfpow10(n)
39 reg int n;
40 #endif
41 {
42 Sfdouble_t dval;
43
44 switch(n)
45 { case -3: return .001;
46 case -2: return .01;
47 case -1: return .1;
48 case 0: return 1.;
49 case 1: return 10.;
50 case 2: return 100.;
51 case 3: return 1000.;
52 }
53
54 if(n < 0)
55 { dval = .0001;
56 for(n += 4; n < 0; n += 1)
57 dval /= 10.;
58 }
59 else
60 { dval = 10000.;
61 for(n -= 4; n > 0; n -= 1)
62 dval *= 10.;
63 }
64
65 return dval;
66 }
67
68 #if __STD_C
_sfstrtod(reg const char * s,char ** retp)69 Sfdouble_t _sfstrtod(reg const char* s, char** retp)
70 #else
71 Sfdouble_t _sfstrtod(s,retp)
72 reg char* s; /* string to convert */
73 char** retp; /* to return the remainder of string */
74 #endif
75 {
76 reg int n, c, m;
77 reg int mode, fexp, sign, expsign;
78 Sfdouble_t dval;
79 #if _lib_locale
80 int decpoint = 0;
81 int thousand = 0;
82 SFSETLOCALE(&decpoint,&thousand);
83 #else
84 #define decpoint '.'
85 #endif
86
87 /* skip initial blanks */
88 while(isspace(*s))
89 ++s;
90
91 /* get the sign */
92 if((sign = (*s == '-')) || *s == '+')
93 s += 1;
94
95 mode = IPART;
96 fexp = expsign = 0;
97 dval = 0.;
98 while(*s)
99 { /* accumulate a handful of the digits */
100 for(m = BATCH, n = 0; m > 0; --m, ++s)
101 { /* get and process a char */
102 c = *s;
103 if(isdigit(c))
104 n = 10*n + (c - '0');
105 else break;
106 }
107
108 /* number of digits accumulated */
109 m = BATCH-m;
110
111 if(mode == IPART)
112 { /* doing the integer part */
113 if(dval == 0.)
114 dval = (Sfdouble_t)n;
115 else dval = dval*sfpow10(m) + (Sfdouble_t)n;
116 }
117 else if(mode == FPART)
118 { /* doing the fractional part */
119 fexp -= m;
120 if(n > 0)
121 dval += n*sfpow10(fexp);
122 }
123 else if(n)
124 { /* doing the exponent part */
125 if(expsign)
126 n = -n;
127 dval *= sfpow10(n);
128 }
129
130 if(!c)
131 break;
132
133 if(m < BATCH)
134 { /* detected a non-digit */
135 if(c == decpoint)
136 { /* start the fractional part or no match */
137 if(mode != IPART)
138 break;
139 mode = FPART;
140 s += 1;
141 }
142 else if(c == 'e' || c == 'E')
143 { if(mode == EPART)
144 break;
145 mode = EPART;
146 c = *++s;
147 if((expsign = (c == '-')) || c == '+')
148 s += 1;
149 }
150 else break;
151 }
152 }
153
154 if(retp)
155 *retp = (char*)s;
156 return sign ? -dval : dval;
157 }
158