diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-12-27 16:00:38 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-12-27 16:00:38 -0200 |
| commit | aa6faa6331e3e5e326bf5830474ffd9b04425678 (patch) | |
| tree | ea8db67fabdda7fbaa9a5c30a8d2613b473430d0 | |
| parent | 0b3f4e254e52f7497b813098c79619a4aaa83c4d (diff) | |
| download | lua-aa6faa6331e3e5e326bf5830474ffd9b04425678.tar.gz lua-aa6faa6331e3e5e326bf5830474ffd9b04425678.tar.bz2 lua-aa6faa6331e3e5e326bf5830474ffd9b04425678.zip | |
own implementation of 'tunumber', so that it works correctly with
numbers outside the 'int' range
| -rw-r--r-- | lbaselib.c | 42 |
1 files changed, 24 insertions, 18 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lbaselib.c,v 1.255 2010/12/13 16:38:00 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.256 2010/12/17 15:14:58 roberto Exp roberto $ |
| 3 | ** Basic library | 3 | ** Basic library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -47,33 +47,39 @@ static int luaB_print (lua_State *L) { | |||
| 47 | 47 | ||
| 48 | static int luaB_tonumber (lua_State *L) { | 48 | static int luaB_tonumber (lua_State *L) { |
| 49 | int base = luaL_optint(L, 2, 10); | 49 | int base = luaL_optint(L, 2, 10); |
| 50 | luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); | ||
| 50 | if (base == 10) { /* standard conversion */ | 51 | if (base == 10) { /* standard conversion */ |
| 51 | luaL_checkany(L, 1); | 52 | luaL_checkany(L, 1); |
| 52 | if (lua_isnumber(L, 1)) { | 53 | if (lua_isnumber(L, 1)) { |
| 53 | lua_pushnumber(L, lua_tonumber(L, 1)); | 54 | lua_pushnumber(L, lua_tonumber(L, 1)); |
| 54 | return 1; | 55 | return 1; |
| 55 | } | 56 | } /* else not a number */ |
| 56 | } | 57 | } |
| 57 | else { | 58 | else { |
| 58 | size_t l1; | 59 | size_t l; |
| 59 | const char *s1 = luaL_checklstring(L, 1, &l1); | 60 | const char *s = luaL_checklstring(L, 1, &l); |
| 60 | const char *e1 = s1 + l1; | 61 | const char *e = s + l; /* end point for 's' */ |
| 61 | char *s2; | ||
| 62 | unsigned long n; | ||
| 63 | int neg = 0; | 62 | int neg = 0; |
| 64 | luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); | 63 | s += strspn(s, SPACECHARS); /* skip initial spaces */ |
| 65 | s1 += strspn(s1, SPACECHARS); /* skip initial spaces */ | 64 | if (*s == '-') { s++; neg = 1; } /* handle signal */ |
| 66 | if (*s1 == '-') { s1++; neg = 1; } | 65 | else if (*s == '+') s++; |
| 67 | n = strtoul(s1, &s2, base); | 66 | if (isalnum((unsigned char)*s)) { |
| 68 | if (s1 != s2) { /* at least one valid digit? */ | 67 | lua_Number n = 0; |
| 69 | s2 += strspn(s2, SPACECHARS); /* skip trailing spaces */ | 68 | do { |
| 70 | if (s2 == e1) { /* no invalid trailing characters? */ | 69 | int digit = (isdigit((unsigned char)*s)) ? *s - '0' |
| 71 | lua_pushnumber(L, (neg) ? -(lua_Number)n : (lua_Number)n); | 70 | : toupper((unsigned char)*s) - 'A' + 10; |
| 71 | if (digit >= base) break; /* invalid numeral; force a fail */ | ||
| 72 | n = n * (lua_Number)base + (lua_Number)digit; | ||
| 73 | s++; | ||
| 74 | } while (isalnum((unsigned char)*s)); | ||
| 75 | s += strspn(s, SPACECHARS); /* skip trailing spaces */ | ||
| 76 | if (s == e) { /* no invalid trailing characters? */ | ||
| 77 | lua_pushnumber(L, (neg) ? -n : n); | ||
| 72 | return 1; | 78 | return 1; |
| 73 | } | 79 | } /* else not a number */ |
| 74 | } | 80 | } /* else not a number */ |
| 75 | } | 81 | } |
| 76 | lua_pushnil(L); /* else not a number */ | 82 | lua_pushnil(L); /* not a number */ |
| 77 | return 1; | 83 | return 1; |
| 78 | } | 84 | } |
| 79 | 85 | ||
