/* ** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lobject_c #define LUA_CORE #include "lua.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "lvm.h" const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; /* ** converts an integer to a "floating point byte", represented as ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* expoent */ while (x >= 16) { x = (x+1) >> 1; e++; } if (x < 8) return x; else return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { int e = (x >> 3) & 31; if (e == 0) return x; else return ((x & 7)+8) << (e - 1); } int luaO_log2 (unsigned int x) { static const lu_byte log_2[256] = { 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, 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, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; int l = -1; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; } int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); default: lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); } } /* BENILLA: the end of the decimal numeral at the head of `s` (spaces, a sign, digits with at ** most one `.`, then an exponent marker, a sign and digits only when a digit follows), or `s` ** when it has no digit: the grammar of the 1.12.1 client's strtod (0x741e39, its state machine ** 0x4111f0), which its luaO_str2d (0x6f5900) calls. Its exponent marker is `e`, `E`, `d` or `D` ** (0x4112d1-0x4112f1), and `*dexp` is set to a `d`/`D` one, which a C99 strtod does not read. A ** C99 strtod also reads further, into hexadecimal ("0x10", "0x1p4") and "inf"/"nan", none of ** which that client reads as a number. See third_party/lua-src/BENILLA.md. */ static const char *decimal_end (const char *s, const char **dexp) { const char *p = s; int digits = 0; *dexp = NULL; while (isspace(cast(unsigned char, *p))) p++; if (*p == '+' || *p == '-') p++; while (isdigit(cast(unsigned char, *p))) { p++; digits++; } if (*p == '.') { p++; while (isdigit(cast(unsigned char, *p))) { p++; digits++; } } if (digits == 0) return s; if (*p == 'e' || *p == 'E' || *p == 'd' || *p == 'D') { const char *e = p + 1; if (*e == '+' || *e == '-') e++; if (isdigit(cast(unsigned char, *e))) { while (isdigit(cast(unsigned char, *e))) e++; if (*p == 'd' || *p == 'D') *dexp = p; p = e; } } return p; } int luaO_str2d (const char *s, lua_Number *result) { char *endptr; const char *dexp; const char *end = decimal_end(s, &dexp); /* BENILLA: see decimal_end */ if (end == s) return 0; /* conversion failed */ if (dexp != NULL) { /* BENILLA: the numeral again with its `d` exponent spelled `e`, for the platform's strtod */ size_t n = cast(size_t, end - s); char small[64]; char *buf = n < sizeof(small) ? small : cast(char *, malloc(n + 1)); int whole; if (buf == NULL) return 0; memcpy(buf, s, n); buf[n] = '\0'; buf[dexp - s] = 'e'; *result = lua_str2number(buf, &endptr); whole = (endptr == buf + n); if (buf != small) free(buf); if (!whole) return 0; endptr = cast(char *, end); } else *result = lua_str2number(s, &endptr); /* BENILLA: 5.1's hexadecimal branch (`strtoul(s, &endptr, 16)` on a trailing `x`) is gone, as ** 0x6f5900 has none. A strtod that read past the decimal numeral read hexadecimal, whose ** decimal head "0" is followed by an `x`: an invalid trailing character there. */ if (endptr != end) return 0; if (*endptr == '\0') return 1; /* most common case */ while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ return 1; } static void pushstr (lua_State *L, const char *str) { setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 1; pushstr(L, ""); for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s); break; } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); buff[1] = '\0'; pushstr(L, buff); break; } case 'd': { setnvalue(L->top, cast_num(va_arg(argp, int))); incr_top(L); break; } case 'f': { setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); incr_top(L); break; } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ sprintf(buff, "%p", va_arg(argp, void *)); pushstr(L, buff); break; } case '%': { pushstr(L, "%"); break; } default: { char buff[3]; buff[0] = '%'; buff[1] = *(e+1); buff[2] = '\0'; pushstr(L, buff); break; } } n += 2; fmt = e+2; } pushstr(L, fmt); luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); return msg; } void luaO_chunkid (char *out, const char *source, size_t bufflen) { if (*source == '=') { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } else { /* out = "source", or "...source" */ if (*source == '@') { size_t l; source++; /* skip the `@' */ bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); if (l > bufflen) { source += (l-bufflen); /* get last part of file name */ strcat(out, "..."); } strcat(out, source); } else { /* out = [string "string"] */ size_t len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); if (source[len] != '\0') { /* must truncate? */ strncat(out, source, len); strcat(out, "..."); } else strcat(out, source); strcat(out, "\"]"); } } }