ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lib_aux.c (12496B)


      1 /*
      2 ** Auxiliary library for the Lua/C API.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 **
      5 ** Lua 5.2 port
      6 ** Copyright (C) 2014 Karel Tuma. See Copyright Notice in luajit.h
      7 **
      8 ** Major parts taken verbatim or adapted from the Lua 5.2.3 interpreter.
      9 ** Copyright (C) 1994-2014 Lua.org, PUC-Rio. See Copyright Notice in lua.h
     10 */
     11 
     12 #include <errno.h>
     13 #include <stdarg.h>
     14 #include <stdio.h>
     15 
     16 #define lib_aux_c
     17 #define LUA_LIB
     18 
     19 #include "lua.h"
     20 #include "lauxlib.h"
     21 
     22 #include "lj_obj.h"
     23 #include "lj_err.h"
     24 #include "lj_state.h"
     25 #include "lj_trace.h"
     26 #include "lj_lib.h"
     27 
     28 #if LJ_TARGET_POSIX
     29 #include <sys/wait.h>
     30 #endif
     31 
     32 /* -- I/O error handling -------------------------------------------------- */
     33 
     34 
     35 LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
     36 {
     37   if (stat) {
     38     setboolV(L->top++, 1);
     39     return 1;
     40   } else {
     41     int en = errno;  /* Lua API calls may change this value. */
     42     setnilV(L->top++);
     43     if (fname)
     44       lua_pushfstring(L, "%s: %s", fname, strerror(en));
     45     else
     46       lua_pushfstring(L, "%s", strerror(en));
     47     setintV(L->top++, en);
     48     lj_trace_abort(G(L));
     49     return 3;
     50   }
     51 }
     52 
     53 LUALIB_API int luaL_execresult(lua_State *L, int stat)
     54 {
     55   if (stat != -1) {
     56 #if LJ_TARGET_POSIX
     57     if (WIFSIGNALED(stat)) {
     58       stat = WTERMSIG(stat);
     59       setnilV(L->top++);
     60       lua_pushliteral(L, "signal");
     61     } else {
     62       if (WIFEXITED(stat))
     63 	stat = WEXITSTATUS(stat);
     64       if (stat == 0)
     65 	setboolV(L->top++, 1);
     66       else
     67 	setnilV(L->top++);
     68       lua_pushliteral(L, "exit");
     69     }
     70 #else
     71     if (stat == 0)
     72       setboolV(L->top++, 1);
     73     else
     74       setnilV(L->top++);
     75     lua_pushliteral(L, "exit");
     76 #endif
     77     setintV(L->top++, stat);
     78     return 3;
     79   }
     80   return luaL_fileresult(L, 0, NULL);
     81 }
     82 
     83 /* -- Module registration ------------------------------------------------- */
     84 
     85 LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
     86 				      const char *fname, int szhint)
     87 {
     88   const char *e;
     89   if (idx) lua_pushvalue(L, idx);
     90   do {
     91     e = strchr(fname, '.');
     92     if (e == NULL) e = fname + strlen(fname);
     93     lua_pushlstring(L, fname, (size_t)(e - fname));
     94     lua_rawget(L, -2);
     95     if (lua_isnil(L, -1)) {  /* no such field? */
     96       lua_pop(L, 1);  /* remove this nil */
     97       lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
     98       lua_pushlstring(L, fname, (size_t)(e - fname));
     99       lua_pushvalue(L, -2);
    100       lua_settable(L, -4);  /* set new table into field */
    101     } else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
    102       lua_pop(L, 2);  /* remove table and value */
    103       return fname;  /* return problematic part of the name */
    104     }
    105     lua_remove(L, -2);  /* remove previous table */
    106     fname = e + 1;
    107   } while (*e == '.');
    108   return NULL;
    109 }
    110 
    111 static int libsize(const luaL_Reg *l)
    112 {
    113   int size = 0;
    114   for (; l->name; l++) size++;
    115   return size;
    116 }
    117 
    118 LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup)
    119 {
    120   lj_state_checkstack(L, nup);
    121   for (; l->name; l++) {
    122     int i;
    123     for (i = 0; i < nup; i++)  /* copy upvalues to the top */
    124       lua_pushvalue(L, -nup);
    125     lua_pushcclosure(L, l->func, nup);
    126     lua_setfield(L, -(nup+2), l->name);
    127   }
    128   lua_pop(L, nup);  /* remove upvalues */
    129 }
    130 
    131 /*
    132 ** Find or create a module table with a given name. The function
    133 ** first looks at the _LOADED table and, if that fails, try a
    134 ** global variable with that name. In any case, leaves on the stack
    135 ** the module table.
    136 */
    137 LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
    138                                  int sizehint) {
    139   luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);  /* get _LOADED table */
    140   lua_getfield(L, -1, modname);  /* get _LOADED[modname] */
    141   if (!lua_istable(L, -1)) {  /* not found? */
    142     lua_pop(L, 1);  /* remove previous result */
    143     /* try global variable (and create one if it does not exist) */
    144     lua_pushglobaltable(L);
    145     if (luaL_findtable(L, 0, modname, sizehint) != NULL)
    146       luaL_error(L, "name conflict for module " LUA_QS, modname);
    147     lua_pushvalue(L, -1);
    148     lua_setfield(L, -3, modname);  /* _LOADED[modname] = new table */
    149   }
    150   lua_remove(L, -2);  /* remove _LOADED table */
    151 }
    152 
    153 
    154 LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
    155 			     const luaL_Reg *l, int nup)
    156 {
    157   lj_lib_checkfpu(L);
    158   if (libname) {
    159     int size = libsize(l);
    160     /* check whether lib already exists */
    161     luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
    162     lua_getfield(L, -1, libname);  /* get _LOADED[libname] */
    163     if (!lua_istable(L, -1)) {  /* not found? */
    164       lua_pop(L, 1);  /* remove previous result */
    165       /* try global variable (and create one if it does not exist) */
    166       if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
    167 	lj_err_callerv(L, LJ_ERR_BADMODN, libname);
    168       lua_pushvalue(L, -1);
    169       lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */
    170     }
    171     lua_remove(L, -2);  /* remove _LOADED table */
    172     lua_insert(L, -(nup+1));  /* move library table to below upvalues */
    173   }
    174   if (l)
    175     luaL_setfuncs(L, l, nup);
    176   else
    177     lua_pop(L, nup);
    178 }
    179 
    180 LUALIB_API void luaL_register(lua_State *L, const char *libname,
    181 			      const luaL_Reg *l)
    182 {
    183   luaL_openlib(L, libname, l, 0);
    184 }
    185 
    186 /*
    187 ** ensure that stack[idx][fname] has a table and push that table
    188 ** into the stack
    189 */
    190 LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
    191   lua_getfield(L, idx, fname);
    192   if (lua_istable(L, -1)) return 1;  /* table already there */
    193   else {
    194     lua_pop(L, 1);  /* remove previous result */
    195     idx = lua_absindex(L, idx);
    196     lua_newtable(L);
    197     lua_pushvalue(L, -1);  /* copy to be left at top */
    198     lua_setfield(L, idx, fname);  /* assign new table to field */
    199     return 0;  /* false, because did not find table there */
    200   }
    201 }
    202 
    203 /*
    204 ** stripped-down 'require'. Calls 'openf' to open a module,
    205 ** registers the result in 'package.loaded' table and, if 'glb'
    206 ** is true, also registers the result in the global table.
    207 ** Leaves resulting module on the top.
    208 */
    209 LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
    210                                lua_CFunction openf, int glb)
    211 {
    212   lua_pushcfunction(L, openf);
    213   lua_pushstring(L, modname);  /* argument to open function */
    214   lua_call(L, 1, 1);  /* open module */
    215   lua_assert(lua_istable(L, -1));
    216   luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
    217   lua_pushvalue(L, -2);  /* make copy of module (call result) */
    218   lua_setfield(L, -2, modname);  /* _LOADED[modname] = module */
    219   lua_pop(L, 1);  /* remove _LOADED table */
    220   if (glb) {
    221     lua_pushvalue(L, -1);  /* copy of 'mod' */
    222     lua_setglobal(L, modname);  /* _G[modname] = module */
    223   }
    224 }
    225 
    226 LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
    227 				 const char *p, const char *r)
    228 {
    229   const char *wild;
    230   size_t l = strlen(p);
    231   luaL_Buffer b;
    232   luaL_buffinit(L, &b);
    233   while ((wild = strstr(s, p)) != NULL) {
    234     luaL_addlstring(&b, s, (size_t)(wild - s));  /* push prefix */
    235     luaL_addstring(&b, r);  /* push replacement in place of pattern */
    236     s = wild + l;  /* continue after `p' */
    237   }
    238   luaL_addstring(&b, s);  /* push last suffix */
    239   luaL_pushresult(&b);
    240   return lua_tostring(L, -1);
    241 }
    242 
    243 /* -- Buffer handling ----------------------------------------------------- */
    244 
    245 #define bufflen(B)	((size_t)((B)->p - (B)->buffer))
    246 #define bufffree(B)	((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
    247 
    248 static int emptybuffer(luaL_Buffer *B)
    249 {
    250   size_t l = bufflen(B);
    251   if (l == 0)
    252     return 0;  /* put nothing on stack */
    253   lua_pushlstring(B->L, B->buffer, l);
    254   B->p = B->buffer;
    255   B->lvl++;
    256   return 1;
    257 }
    258 
    259 static void adjuststack(luaL_Buffer *B)
    260 {
    261   if (B->lvl > 1) {
    262     lua_State *L = B->L;
    263     int toget = 1;  /* number of levels to concat */
    264     size_t toplen = lua_strlen(L, -1);
    265     do {
    266       size_t l = lua_strlen(L, -(toget+1));
    267       if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
    268 	break;
    269       toplen += l;
    270       toget++;
    271     } while (toget < B->lvl);
    272     lua_concat(L, toget);
    273     B->lvl = B->lvl - toget + 1;
    274   }
    275 }
    276 
    277 LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
    278 {
    279   if (emptybuffer(B))
    280     adjuststack(B);
    281   return B->buffer;
    282 }
    283 
    284 LUALIB_API char *luaL_prepbuffsize(luaL_Buffer *B, size_t size)
    285 {
    286   if (size > LUAL_BUFFERSIZE)
    287     luaL_error(B->L, "buffer too big (max LUAL_BUFFERSIZE=%d)", LUAL_BUFFERSIZE);
    288   return luaL_prepbuffer(B);
    289 }
    290 
    291 LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
    292 {
    293   while (l--)
    294     luaL_addchar(B, *s++);
    295 }
    296 
    297 LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
    298 {
    299   luaL_addlstring(B, s, strlen(s));
    300 }
    301 
    302 LUALIB_API void luaL_pushresult(luaL_Buffer *B)
    303 {
    304   emptybuffer(B);
    305   lua_concat(B->L, B->lvl);
    306   B->lvl = 1;
    307 }
    308 
    309 LUALIB_API void luaL_addvalue(luaL_Buffer *B)
    310 {
    311   lua_State *L = B->L;
    312   size_t vl;
    313   const char *s = lua_tolstring(L, -1, &vl);
    314   if (vl <= bufffree(B)) {  /* fit into buffer? */
    315     memcpy(B->p, s, vl);  /* put it there */
    316     B->p += vl;
    317     lua_pop(L, 1);  /* remove from stack */
    318   } else {
    319     if (emptybuffer(B))
    320       lua_insert(L, -2);  /* put buffer before new value */
    321     B->lvl++;  /* add new value into B stack */
    322     adjuststack(B);
    323   }
    324 }
    325 
    326 LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
    327 {
    328   B->L = L;
    329   B->p = B->buffer;
    330   B->lvl = 0;
    331 }
    332 
    333 /* -- Reference management ------------------------------------------------ */
    334 
    335 #define FREELIST_REF	0
    336 
    337 /* Convert a stack index to an absolute index. */
    338 #define abs_index(L, i) \
    339   ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
    340 
    341 LUALIB_API int luaL_ref(lua_State *L, int t)
    342 {
    343   int ref;
    344   t = abs_index(L, t);
    345   if (lua_isnil(L, -1)) {
    346     lua_pop(L, 1);  /* remove from stack */
    347     return LUA_REFNIL;  /* `nil' has a unique fixed reference */
    348   }
    349   lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */
    350   ref = (int)lua_tointeger(L, -1);  /* ref = t[FREELIST_REF] */
    351   lua_pop(L, 1);  /* remove it from stack */
    352   if (ref != 0) {  /* any free element? */
    353     lua_rawgeti(L, t, ref);  /* remove it from list */
    354     lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */
    355   } else {  /* no free elements */
    356     ref = (int)lua_objlen(L, t);
    357     ref++;  /* create new reference */
    358   }
    359   lua_rawseti(L, t, ref);
    360   return ref;
    361 }
    362 
    363 LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
    364 {
    365   if (ref >= 0) {
    366     t = abs_index(L, t);
    367     lua_rawgeti(L, t, FREELIST_REF);
    368     lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */
    369     lua_pushinteger(L, ref);
    370     lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */
    371   }
    372 }
    373 
    374 /* -- Default allocator and panic function -------------------------------- */
    375 
    376 static int panic(lua_State *L)
    377 {
    378   const char *s = lua_tostring(L, -1);
    379   fputs("PANIC: unprotected error in call to Lua API (", stderr);
    380   fputs(s ? s : "?", stderr);
    381   fputc(')', stderr); fputc('\n', stderr);
    382   fflush(stderr);
    383   return 0;
    384 }
    385 
    386 #ifdef LUAJIT_USE_SYSMALLOC
    387 
    388 #if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
    389 #error "Must use builtin allocator for 64 bit target"
    390 #endif
    391 
    392 static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
    393 {
    394   (void)ud;
    395   (void)osize;
    396   if (nsize == 0) {
    397     free(ptr);
    398     return NULL;
    399   } else {
    400     return realloc(ptr, nsize);
    401   }
    402 }
    403 
    404 LUALIB_API lua_State *luaL_newstate(void)
    405 {
    406   lua_State *L = lua_newstate(mem_alloc, NULL);
    407   if (L) G(L)->panic = panic;
    408   return L;
    409 }
    410 
    411 #else
    412 
    413 #include "lj_alloc.h"
    414 
    415 LUALIB_API lua_State *luaL_newstate(void)
    416 {
    417   lua_State *L;
    418   void *ud = lj_alloc_create();
    419   if (ud == NULL) return NULL;
    420 #if LJ_64 && !LJ_GC64
    421   L = lj_state_newstate(lj_alloc_f, ud);
    422 #else
    423   L = lua_newstate(lj_alloc_f, ud);
    424 #endif
    425   if (L) G(L)->panic = panic;
    426   return L;
    427 }
    428 
    429 #if LJ_64 && !LJ_GC64
    430 LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
    431 {
    432   UNUSED(f); UNUSED(ud);
    433   fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
    434   return NULL;
    435 }
    436 #endif
    437 
    438 #endif
    439 
    440 LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
    441   const lua_Number *v = lua_version(L);
    442   if (v != lua_version(NULL))
    443     lj_err_msg(L, LJ_ERR_MULTIVM);
    444   else if (*v != ver)
    445     lj_err_callerv(L, LJ_ERR_BADVER, ver, *v);
    446   /* check conversions number -> integer types */
    447   lua_pushnumber(L, -(lua_Number)0x1234);
    448   if (lua_tointeger(L, -1) != -0x1234 ||
    449       lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
    450     lj_err_callerv(L, LJ_ERR_BADCONV, "number", "int");
    451   lua_pop(L, 1);
    452 }
    453 
    454 LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
    455   luaL_getmetatable(L, tname);
    456   lua_setmetatable(L, -2);
    457 }
    458 
    459