diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-01-06 15:40:03 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-01-06 15:52:39 +0900 |
| commit | 2532e625edc2457447369e36e2ecf7882d872ef9 (patch) | |
| tree | e772c9336baf8a3589dc0f380a2e3abd8b648b10 /src | |
| parent | 111045ecada16d3c047b90a26a1ec0af06e5a323 (diff) | |
| download | mruby-2532e625edc2457447369e36e2ecf7882d872ef9.tar.gz mruby-2532e625edc2457447369e36e2ecf7882d872ef9.zip | |
Refactor `mrb_cstr_to_dbl`; ref #4920
Diffstat (limited to 'src')
| -rw-r--r-- | src/load.c | 10 | ||||
| -rw-r--r-- | src/string.c | 92 |
2 files changed, 58 insertions, 44 deletions
diff --git a/src/load.c b/src/load.c index 4184c4753..e624c52d5 100644 --- a/src/load.c +++ b/src/load.c @@ -42,21 +42,17 @@ offset_crc_body(void) } #ifndef MRB_WITHOUT_FLOAT +double mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck); + static double str_to_double(mrb_state *mrb, const char *p, size_t len) { - char buf[64]; - /* `i`, `inf`, `infinity` */ if (len > 0 && p[0] == 'i') return INFINITY; /* `I`, `-inf`, `-infinity` */ if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY; - mrb_assert(len < sizeof(buf)); - strncpy(buf, p, len); - buf[len] = '\0'; - - return mrb_cstr_to_dbl(mrb, buf, TRUE); + return mrb_str_len_to_dbl(mrb, p, len, TRUE); } #endif diff --git a/src/string.c b/src/string.c index 08c14d8e8..15e52fb3c 100644 --- a/src/string.c +++ b/src/string.c @@ -2488,20 +2488,58 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) } #ifndef MRB_WITHOUT_FLOAT -MRB_API double -mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck) +double +mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck) { - const char *p = s; - char *end; char buf[DBL_DIG * 4 + 10]; + const char *p; + const char *pend = s + len; + char *end; + char *n; + char prev = 0; double d; - if (!p) return 0.0; - while (ISSPACE(*p)) p++; + if (!s) return 0.0; + while (ISSPACE(*s)) s++; + p = s; if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { return 0.0; } + while (p < pend) { + if (!*p) { + if (badcheck && p < pend) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); + /* not reached */ + } + pend = p; + p = s; + goto nocopy; + } + if (*p == '_') break; + p++; + } + p = s; + n = buf; + while (p < pend) { + char c = *p++; + if (c == '_') { + /* remove an underscore between digits */ + if (n == buf || !ISDIGIT(prev) || p == pend) { + if (badcheck) goto bad; + break; + } + } + else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad; + else { + *n++ = c; + } + prev = c; + } + *n = '\0'; + p = buf; + pend = n; +nocopy: d = mrb_float_read(p, &end); if (p == end) { if (badcheck) { @@ -2511,44 +2549,24 @@ bad: } return d; } - if (*end) { - char *n = buf; - char *e = buf + sizeof(buf) - 1; - char prev = 0; - - while (p < end && n < e) prev = *n++ = *p++; - while (*p) { - if (*p == '_') { - /* remove an underscore between digits */ - if (n == buf || !ISDIGIT(prev) || (++p, !ISDIGIT(*p))) { - if (badcheck) goto bad; - break; - } - } - prev = *p++; - if (n < e) *n++ = prev; - } - *n = '\0'; - p = buf; - - if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { - return 0.0; - } - - d = mrb_float_read(p, &end); - if (badcheck) { - if (!end || p == end) goto bad; - while (*end && ISSPACE(*end)) end++; - if (*end) goto bad; - } + if (badcheck) { + if (!end || p == end) goto bad; + while (end<pend && ISSPACE(*end)) end++; + if (end<pend) goto bad; } return d; } MRB_API double +mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck) +{ + return mrb_str_len_to_dbl(mrb, s, strlen(s), badcheck); +} + +MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - return mrb_cstr_to_dbl(mrb, RSTRING_CSTR(mrb, str), badcheck); + return mrb_str_len_to_dbl(mrb, RSTRING_PTR(str), RSTRING_LEN(str), badcheck); } /* 15.2.10.5.39 */ |
