Refactor `mrb_cstr_to_dbl`; ref #4920

parent 111045ec
......@@ -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
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment