summaryrefslogtreecommitdiffhomepage
path: root/src/string.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2020-01-06 15:40:03 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2020-01-06 15:52:39 +0900
commit2532e625edc2457447369e36e2ecf7882d872ef9 (patch)
treee772c9336baf8a3589dc0f380a2e3abd8b648b10 /src/string.c
parent111045ecada16d3c047b90a26a1ec0af06e5a323 (diff)
downloadmruby-2532e625edc2457447369e36e2ecf7882d872ef9.tar.gz
mruby-2532e625edc2457447369e36e2ecf7882d872ef9.zip
Refactor `mrb_cstr_to_dbl`; ref #4920
Diffstat (limited to 'src/string.c')
-rw-r--r--src/string.c92
1 files changed, 55 insertions, 37 deletions
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 */