summaryrefslogtreecommitdiffhomepage
path: root/src/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/string.c')
-rw-r--r--src/string.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/src/string.c b/src/string.c
index 266db4989..0bee35d0e 100644
--- a/src/string.c
+++ b/src/string.c
@@ -1952,10 +1952,10 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
mrb_value
mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
{
- char *end;
+ const char *p;
char sign = 1;
- int c;
- unsigned long n;
+ int c, us;
+ unsigned long n = 0;
mrb_int val;
#undef ISDIGIT
@@ -2042,7 +2042,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break;
} /* end of switch (base) { */
if (*str == '0') { /* squeeze preceeding 0s */
- int us = 0;
+ us = 0;
while ((c = *++str) == '0' || c == '_') {
if (c == '_') {
if (++us >= 2)
@@ -2060,15 +2060,32 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
return mrb_fixnum_value(0);
}
- n = strtoul((char*)str, &end, base);
+ us = 0;
+ for (p=str;*p;p++) {
+ if (*p == '_') {
+ if (us == 0) {
+ us++;
+ continue;
+ }
+ if (badcheck) goto bad;
+ break;
+ }
+ c = conv_digit(*p);
+ if (c < 0 || c >= base) {
+ if (badcheck) goto bad;
+ break;
+ }
+ n *= base;
+ n += c;
+ }
if (n > MRB_INT_MAX) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str));
}
val = n;
if (badcheck) {
- if (end == str) goto bad; /* no number */
- while (*end && ISSPACE(*end)) end++;
- if (*end) goto bad; /* trailing garbage */
+ if (p == str) goto bad; /* no number */
+ while (*p && ISSPACE(*p)) p++;
+ if (*p) goto bad; /* trailing garbage */
}
return mrb_fixnum_value(sign ? val : -val);