-
Notifications
You must be signed in to change notification settings - Fork 0
/
strtonum.c
204 lines (182 loc) · 4.48 KB
/
strtonum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <float.h>
#include <string.h>
#ifdef CONV_64BIT
#define FLOAT_TYPE double
#define FLOAT_LONGER_TYPE long double
#define FLOAT_MAX DBL_MAX
#define FLOAT_EXPS DBL_MAX_10_EXP
#define FLOAT_CONV_NAME strtodouble
#define ITYPE int64_t
#define IMAX INT64_MAX
#define IMIN INT64_MIN
#define ICONV_NAME strtoint64
#else
#define FLOAT_TYPE float
#define FLOAT_MAX FLT_MAX
#define FLOAT_EXPS FLT_MAX_10_EXP
#define FLOAT_CONV_NAME strtofloat
#define FLOAT_LONGER_TYPE double
#define ITYPE int32_t
#define IMAX INT32_MAX
#define IMIN INT32_MIN
#define ICONV_NAME strtoint32
#endif /* CONV_64BIT */
static inline FLOAT_TYPE FLOAT_CONV_NAME (const char *cur_pos, char **end_pos)
{
FLOAT_LONGER_TYPE sign = 1;
FLOAT_LONGER_TYPE val = 0;
FLOAT_LONGER_TYPE savedval = 0;
const char *periodpos=0, *periodendpos=0;
const char *pos = cur_pos;
const char zero = '0';
const char zerom1 = '0'-1;
const char ninep1 = '9'+1;
const FLOAT_LONGER_TYPE toobig = FLOAT_MAX / 20.0;
int seenexp = 0;
int seenexpsign = 0;
char c;
static int generated_exps = 0;
static FLOAT_LONGER_TYPE exps[FLOAT_EXPS*4 + 1];
int i, e = 0;
if (!generated_exps) {
generated_exps = 1;
for (i=0; i<(FLOAT_EXPS*4+1); i++) {
exps[i] = powl(10, i-(FLOAT_EXPS*2));
}
}
if (*pos == '+') pos++;
else if (*pos == '-') { sign = -1; pos++; }
for (; *pos; pos++) {
c = *pos;
if ((c > zerom1) && (c < ninep1)) {
if (val < toobig)
val = val*10.0 + (c-zero);
else
e++;
}
else if (c == '.') {
if (seenexp) break;
periodpos = pos;
}
else if (c == 'e' || c == 'E') {
if (seenexp) break;
savedval = val;
seenexp = 1;
val = 0;
periodendpos = pos;
}
else if (c == '+') {
if (!seenexp || seenexpsign || ((pos - periodendpos)>1)) break;
seenexpsign = 1;
}
else if (c == '-') {
if (!seenexp || seenexpsign || ((pos - periodendpos)>1)) break;
seenexpsign = -1;
}
//Handle NaN
else if ((c=='n' || c=='N') && (pos[1]=='a' || pos[1]=='A') &&
(pos[2]=='n' || pos[2]=='N') &&
(pos[3]==0 || pos[3]==' ' || pos[3]=='\t' || pos[3]=='\n')) {
if (end_pos) *end_pos = ((char *)pos)+3;
return 0;
}
//Handle Inf
else if ((c=='i' || c=='I') && (pos[1]=='n' || pos[1]=='N') &&
(pos[2]=='f' || pos[2]=='F') &&
(pos[3]==0 || pos[3]==' ' || pos[3]=='\t' || pos[3]=='\n')) {
if (end_pos) *end_pos = ((char *)pos)+3;
return copysign(FLOAT_MAX,sign);
}
else break;
}
if (end_pos) *end_pos = (char *)pos;
if (!seenexp) {
savedval = val;
} else {
if (seenexpsign) val = copysign(val, seenexpsign);
e += val;
}
if (periodpos) {
if (!periodendpos) periodendpos = pos;
e -= periodendpos - periodpos - 1;
}
if (savedval==0) return copysign(0, sign);
if (e > (FLOAT_EXPS*2)) {
if (sign > 0) return FLOAT_MAX;
else return -FLOAT_MAX;
}
else if (e < -(FLOAT_EXPS*2))
return copysign(0,sign);
return (copysign(savedval*exps[e+(FLOAT_EXPS*2)], sign));
}
static inline ITYPE ICONV_NAME (const char *cur_pos, char **end_pos)
{
int sign = 1;
ITYPE val = 0;
const char *pos = cur_pos;
const char zero = '0';
const char zerom1 = '0'-1;
const char ninep1 = '9'+1;
const ITYPE toobig = (IMAX / 10);
const char *exppos = 0;
char c;
int toobig_flag = 0;
int seen_period = 0, seen_exp = 0;
if (*pos == '+') pos++;
else if (*pos == '-') { sign = -1; pos++; }
for (; *pos; pos++) {
c = *pos;
if ((c > zerom1) && (c < ninep1)) {
if (val < toobig)
val = val*10 + (c-zero);
else
toobig_flag = 1;
}
else if (c == '.') {
seen_period = 1;
pos++;
break;
}
else if (c == 'e' || c == 'E') {
seen_exp = 1;
exppos = pos;
pos++;
break;
}
else break;
}
if (seen_period || seen_exp) {
for (; *pos; pos++) {
c = *pos;
if ((c > zerom1) && (c < ninep1)) continue;
if (c == 'e' || c == 'E') {
if (seen_exp) break;
seen_exp = 1;
exppos = pos;
continue;
}
if (c == '+' || c == '-') {
if (!seen_exp || (pos - exppos)>1) break;
continue;
}
break;
}
}
if (end_pos) *end_pos = (char *)pos;
if (toobig_flag)
return ((sign>0) ? IMAX : IMIN);
return sign*val;
}
#undef FLOAT_TYPE
#undef FLOAT_LONGER_TYPE
#undef FLOAT_MAX
#undef FLOAT_EXPS
#undef FLOAT_CONV_NAME
#undef ITYPE
#undef IMAX
#undef IMIN
#undef ICONV_NAME