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