Refactor `mrb_cstr_to_dbl`; ref
MODIFY
src/load.c
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

MODIFY
src/string.c
src/string.c
@@ -2488,67 +2488,85 @@ 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;
}
- d = mrb_float_read(p, &end);
- if (p == end) {
- if (badcheck) {
-bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%!s)", s);
+ while (p < pend) {
+ if (!*p) {
+ if (badcheck && p < pend) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte");
/* not reached */
}
- return d;
+ pend = p;
+ p = s;
+ goto nocopy;
}
- 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 == '_') {
+ 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, !ISDIGIT(*p))) {
+ if (n == buf || !ISDIGIT(prev) || p == pend) {
if (badcheck) goto bad;
break;
}
}
- prev = *p++;
- if (n < e) *n++ = prev;
+ else if (badcheck && prev == '_' && !ISDIGIT(c)) goto bad;
+ else {
+ *n++ = c;
+ }
+ prev = c;
}
*n = '\0';
p = buf;
-
- if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
- return 0.0;
- }
-
+ pend = n;
+nocopy:
d = mrb_float_read(p, &end);
+ if (p == end) {
if (badcheck) {
- if (!end || p == end) goto bad;
- while (*end && ISSPACE(*end)) end++;
- if (*end) goto bad;
+bad:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%!s)", s);
+ /* not reached */
+ }
+ return d;
}
+ 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 */

Refactor `mrb_cstr_to_dbl`; ref #4920