diff options
Diffstat (limited to 'libs/liblua/src/lobject.c')
-rw-r--r-- | libs/liblua/src/lobject.c | 149 |
1 files changed, 100 insertions, 49 deletions
diff --git a/libs/liblua/src/lobject.c b/libs/liblua/src/lobject.c index 6a24aff95d..a44b3850fc 100644 --- a/libs/liblua/src/lobject.c +++ b/libs/liblua/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.101 2014/12/26 14:43:45 roberto Exp $ +** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -10,6 +10,8 @@ #include "lprefix.h" +#include <locale.h> +#include <math.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -39,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; int luaO_int2fb (unsigned int x) { int e = 0; /* exponent */ if (x < 8) return x; - while (x >= 0x10) { - x = (x+1) >> 1; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ e++; } return ((e+1) << 3) | (cast_int(x) - 8); @@ -49,14 +55,15 @@ int luaO_int2fb (unsigned int x) { /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 0x1f; - if (e == 0) return x; - else return ((x & 7) + 8) << (e - 1); + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); } +/* +** Computes ceil(log2(x)) +*/ int luaO_ceillog2 (unsigned int x) { - static const lu_byte log_2[256] = { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, @@ -149,13 +156,13 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, } /* could not perform raw operation; try metamethod */ lua_assert(L != NULL); /* should not fail when folding (compile time) */ - luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD)); + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); } int luaO_hexavalue (int c) { if (lisdigit(c)) return c - '0'; - else return ltolower(c) - 'a' + 10; + else return (ltolower(c) - 'a') + 10; } @@ -172,9 +179,8 @@ static int isneg (const char **s) { ** Lua's implementation for 'lua_strx2number' ** =================================================================== */ -#if !defined(lua_strx2number) -#include <math.h> +#if !defined(lua_strx2number) /* maximum number of significant digits to read (to avoid overflows even with single floats) */ @@ -185,21 +191,22 @@ static int isneg (const char **s) { ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { + int dot = lua_getlocaledecpoint(); lua_Number r = 0.0; /* result (accumulator) */ int sigdig = 0; /* number of significant digits */ int nosigdig = 0; /* number of non-significant digits */ int e = 0; /* exponent correction */ int neg; /* 1 if number is negative */ - int dot = 0; /* true after seen a dot */ + int hasdot = 0; /* true after seen a dot */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ for (s += 2; ; s++) { /* skip '0x' and read numeral */ - if (*s == '.') { - if (dot) break; /* second dot? stop loop */ - else dot = 1; + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; } else if (lisxdigit(cast_uchar(*s))) { if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ @@ -207,7 +214,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ r = (r * cast_num(16.0)) + luaO_hexavalue(*s); else e++; /* too many digits; ignore, but still count for exponent */ - if (dot) e--; /* decimal digit? correct exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ } else break; /* neither a dot nor a digit */ } @@ -236,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { /* }====================================================== */ -static const char *l_str2d (const char *s, lua_Number *result) { +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { char *endptr; - if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL +** on fail or the address of the ending '\0' on success. +** 'pmode' points to (and 'mode' contains) special things in the string: +** - 'x'/'X' means an hexadecimal numeral +** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) +** - '.' just optimizes the search for the common case (nothing special) +** This function accepts both the current locale or a dot as the radix +** mark. If the convertion fails, it may mean number has a dot but +** locale accepts something else. In that case, the code copies 's' +** to a buffer (because 's' is read-only), changes the dot to the +** current locale radix mark, and tries to convert again. +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ return NULL; - else if (strpbrk(s, "xX")) /* hex? */ - *result = lua_strx2number(s, &endptr); - else - *result = lua_str2number(s, &endptr); - if (endptr == s) return 0; /* nothing recognized */ - while (lisspace(cast_uchar(*endptr))) endptr++; - return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */ + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + char *pdot = strchr(s, '.'); + if (strlen(s) > L_MAXLENNUM || pdot == NULL) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; } +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + static const char *l_str2int (const char *s, lua_Integer *result) { lua_Unsigned a = 0; int empty = 1; @@ -266,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) { } else { /* decimal */ for (; lisdigit(cast_uchar(*s)); s++) { - a = a * 10 + *s - '0'; + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; empty = 0; } } @@ -290,7 +339,7 @@ size_t luaO_str2num (const char *s, TValue *o) { } else return 0; /* conversion failed */ - return (e - s + 1); /* success; return string size */ + return (e - s) + 1; /* success; return string size */ } @@ -324,12 +373,12 @@ void luaO_tostring (lua_State *L, StkId obj) { size_t len; lua_assert(ttisnumber(obj)); if (ttisinteger(obj)) - len = lua_integer2str(buff, ivalue(obj)); + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); else { - len = lua_number2str(buff, fltvalue(obj)); + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); #if !defined(LUA_COMPAT_FLOATSTRING) if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ - buff[len++] = '.'; + buff[len++] = lua_getlocaledecpoint(); buff[len++] = '0'; /* adds '.0' to result */ } #endif @@ -339,27 +388,29 @@ void luaO_tostring (lua_State *L, StkId obj) { static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); + luaD_inctop(L); } -/* this function handles only '%d', '%c', '%f', '%p', and '%s' - conventional formats, plus Lua-specific '%I' and '%U' */ +/* +** this function handles only '%d', '%c', '%f', '%p', and '%s' + conventional formats, plus Lua-specific '%I' and '%U' +*/ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - luaD_checkstack(L, 2); /* fmt + item */ pushstr(L, fmt, e - fmt); switch (*(e+1)) { - case 's': { + case 's': { /* zero-terminated string */ const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s, strlen(s)); break; } - case 'c': { + case 'c': { /* an 'int' as a character */ char buff = cast(char, va_arg(argp, int)); if (lisprint(cast_uchar(buff))) pushstr(L, &buff, 1); @@ -367,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); break; } - case 'd': { - setivalue(L->top++, va_arg(argp, int)); - luaO_tostring(L, L->top - 1); - break; + case 'd': { /* an 'int' */ + setivalue(L->top, va_arg(argp, int)); + goto top2str; } - case 'I': { - setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt))); - luaO_tostring(L, L->top - 1); - break; + case 'I': { /* a 'lua_Integer' */ + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; } - case 'f': { - setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); + case 'f': { /* a 'lua_Number' */ + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: /* convert the top element to a string */ + luaD_inctop(L); luaO_tostring(L, L->top - 1); break; } - case 'p': { + case 'p': { /* a pointer */ char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ - int l = sprintf(buff, "%p", va_arg(argp, void *)); + int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } - case 'U': { + case 'U': { /* an 'int' as a UTF-8 sequence */ char buff[UTF8BUFFSZ]; int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); pushstr(L, buff + UTF8BUFFSZ - l, l); |