Merge branch 'master' into stable
[mruby.git] / src / readfloat.c
blob80d438ba9500d8ba626c41b82e25620a8b96e548
1 #include <mruby.h>
3 #ifndef MRB_NO_FLOAT
4 /*
5 * strtod implementation.
6 * author: Yasuhiro Matsumoto (@mattn)
7 * license: public domain
8 */
11 The original code can be found in https://github.com/mattn/strtod
13 I modified the routine for mruby:
15 * renamed the function `vim_strtod` -> `mrb_read_float`
16 * simplified the code
17 * changed the API
19 My modifications in this file are also placed in the public domain.
21 Matz (Yukihiro Matsumoto)
24 #include <string.h>
25 #include <math.h>
27 MRB_API mrb_bool
28 mrb_read_float(const char *str, char **endp, double *fp)
30 double d = 0.0;
31 int sign;
32 int n = 0;
33 const char *p, *a;
35 a = p = str;
36 while (ISSPACE(*p))
37 p++;
39 /* decimal part */
40 sign = 1;
41 if (*p == '-') {
42 sign = -1;
43 p++;
45 else if (*p == '+')
46 p++;
47 if (ISDIGIT(*p)) {
48 d = (double)(*p++ - '0');
49 while (*p && ISDIGIT(*p)) {
50 d = d * 10.0 + (double)(*p - '0');
51 p++;
52 n++;
54 a = p;
56 else if (*p != '.')
57 goto done;
58 d *= sign;
60 /* fraction part */
61 if (*p == '.') {
62 double f = 0.0;
63 double base = 0.1;
64 p++;
66 if (ISDIGIT(*p)) {
67 while (*p && ISDIGIT(*p)) {
68 f += base * (*p - '0');
69 base /= 10.0;
70 p++;
71 n++;
74 d += f * sign;
75 a = p;
78 /* exponential part */
79 if ((*p == 'E') || (*p == 'e')) {
80 int e = 0;
82 p++;
83 sign = 1;
84 if (*p == '-') {
85 sign = -1;
86 p++;
88 else if (*p == '+')
89 p++;
91 if (ISDIGIT(*p)) {
92 while (*p == '0')
93 p++;
94 if (*p == '\0') --p;
95 e = (int)(*p++ - '0');
96 for (; *p && ISDIGIT(*p); p++) {
97 if (e < 10000)
98 e = e * 10 + (*p - '0');
100 e *= sign;
102 else if (!ISDIGIT(*(a-1))) {
103 return FALSE;
105 else if (*p == 0)
106 goto done;
107 d *= pow(10.0, (double)e);
108 a = p;
110 else if (p > str && !ISDIGIT(*(p-1))) {
111 goto done;
114 done:
115 *fp = d;
116 if (endp) *endp = (char*)a;
117 if (str == a) return FALSE;
118 return TRUE;
120 #endif