readint.c: add new function `mrb_int_read`.

Difference from `strtoul(3)`:

* reads `mrb_int` based on configuration
* specifies the end of the string
* no sign interpretation
* base 10 only
parent 14a69c6f
...@@ -100,6 +100,7 @@ struct mrb_state; ...@@ -100,6 +100,7 @@ struct mrb_state;
# define MRB_ENDIAN_LOHI(a,b) b a # define MRB_ENDIAN_LOHI(a,b) b a
#endif #endif
MRB_API mrb_int mrb_int_read(const char *p, const char *e, char **endp);
#ifndef MRB_NO_FLOAT #ifndef MRB_NO_FLOAT
MRB_API double mrb_float_read(const char*, char**); MRB_API double mrb_float_read(const char*, char**);
#ifdef MRB_USE_FLOAT32 #ifdef MRB_USE_FLOAT32
......
...@@ -1234,17 +1234,16 @@ alias: ...@@ -1234,17 +1234,16 @@ alias:
/* read suffix [0-9*_!<>] */ /* read suffix [0-9*_!<>] */
while (tmpl->idx < tlen) { while (tmpl->idx < tlen) {
ch = tptr[tmpl->idx++]; ch = tptr[tmpl->idx];
if (ISDIGIT(ch)) { if (ISDIGIT(ch)) {
count = ch - '0'; char *e;
while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) { mrb_int n = mrb_int_read(tptr+tmpl->idx, tptr+tlen, &e);
if (count+10 > INT_MAX/10) { if (e == NULL || n > INT_MAX) {
mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length");
} }
ch = tptr[tmpl->idx++] - '0'; count = (int)n;
count = count * 10 + ch; tmpl->idx += e - tptr;
} continue;
continue; /* special case */
} else if (ch == '*') { } else if (ch == '*') {
count = -1; count = -1;
} else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') { } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
...@@ -1258,10 +1257,11 @@ alias: ...@@ -1258,10 +1257,11 @@ alias:
} else if (ch == '>') { } else if (ch == '>') {
flags |= PACK_FLAG_GT; flags |= PACK_FLAG_GT;
} }
} else { }
tmpl->idx--; else {
break; break;
} }
tmpl->idx++;
} }
if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) { if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) {
......
...@@ -245,7 +245,6 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len) ...@@ -245,7 +245,6 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len)
#define GETASTER(num) do { \ #define GETASTER(num) do { \
mrb_value tmp_v; \ mrb_value tmp_v; \
t = p++; \ t = p++; \
n = 0; \
GETNUM(n, val); \ GETNUM(n, val); \
if (*p == '$') { \ if (*p == '$') { \
tmp_v = GETPOSARG(n); \ tmp_v = GETPOSARG(n); \
...@@ -260,22 +259,11 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len) ...@@ -260,22 +259,11 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len)
static const char * static const char *
get_num(mrb_state *mrb, const char *p, const char *end, int *valp) get_num(mrb_state *mrb, const char *p, const char *end, int *valp)
{ {
mrb_int next_n = (int)*valp; char *e;
for (; p < end && ISDIGIT(*p); p++) { mrb_int n = mrb_int_read(p, end, &e);
if (mrb_int_mul_overflow(10, next_n, &next_n)) { if (e == NULL || n > INT_MAX) return NULL;
return NULL; *valp = (int)n;
} return e;
if (MRB_INT_MAX - (*p - '0') < next_n) {
return NULL;
}
next_n += *p - '0';
}
if (next_n > INT_MAX || next_n < 0) return NULL;
if (p >= end) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %%*[0-9]");
}
*valp = (int)next_n;
return p;
} }
static void static void
...@@ -665,7 +653,6 @@ retry: ...@@ -665,7 +653,6 @@ retry:
case '1': case '2': case '3': case '4': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
n = 0;
GETNUM(n, width); GETNUM(n, width);
if (*p == '$') { if (*p == '$') {
if (!mrb_undef_p(nextvalue)) { if (!mrb_undef_p(nextvalue)) {
...@@ -722,7 +709,6 @@ retry: ...@@ -722,7 +709,6 @@ retry:
} }
flags |= FPREC|FPREC0; flags |= FPREC|FPREC0;
prec = 0;
p++; p++;
if (*p == '*') { if (*p == '*') {
GETASTER(prec); GETASTER(prec);
...@@ -732,7 +718,6 @@ retry: ...@@ -732,7 +718,6 @@ retry:
p++; p++;
goto retry; goto retry;
} }
GETNUM(prec, precision); GETNUM(prec, precision);
goto retry; goto retry;
......
#include <mruby.h>
#include <mruby/numeric.h>
#include <errno.h>
/* mrb_int_read(): read mrb_int from a string (base 10 only) */
/* const char *p - string to read */
/* const char *e - end of string */
/* char **endp - end of pased integer */
/* if integer overflows, errno will be set to ERANGE */
/* also endp will be set to NULL on overflow */
MRB_API mrb_int
mrb_int_read(const char *p, const char *e, char **endp)
{
mrb_int n = 0;
int ch;
while ((e == NULL || p < e) && ISDIGIT(*p)) {
ch = *p - '0';
if (mrb_int_mul_overflow(n, 10, &n) ||
mrb_int_add_overflow(n, ch, &n)) {
if (endp) *endp = NULL;
errno = ERANGE;
return MRB_INT_MAX;
}
p++;
}
if (endp) *endp = (char*)p;
return n;
}
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