/** Check if stack value is a C function. * @param idx stack index of value * @return true if value is a C function, false otherwise */ bool LuaContext::is_cfunction(int idx) { return lua_iscfunction(__L, idx); }
/* Class index function * If the object is a userdata (ie, an object), it searches the field in * the alternative table stored in the corresponding "ubox" table. */ static int class_index_event (lua_State* L) { int t = lua_type(L,1); if (t == LUA_TUSERDATA) { /* Access alternative table */ #ifdef LUA_VERSION_NUM /* new macro on version 5.1 */ lua_getfenv(L,1); if (!lua_rawequal(L, -1, TOLUA_NOPEER)) { lua_pushvalue(L, 2); /* key */ lua_gettable(L, -2); /* on lua 5.1, we trade the "tolua_peers" lookup for a gettable call */ if (!lua_isnil(L, -1)) return 1; }; #else lua_pushstring(L,"tolua_peers"); lua_rawget(L,LUA_REGISTRYINDEX); /* stack: obj key ubox */ lua_pushvalue(L,1); lua_rawget(L,-2); /* stack: obj key ubox ubox[u] */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); /* key */ lua_rawget(L,-2); /* stack: obj key ubox ubox[u] value */ if (!lua_isnil(L,-1)) return 1; } #endif lua_settop(L,2); /* stack: obj key */ /* Try metatables */ lua_pushvalue(L,1); /* stack: obj key obj */ while (lua_getmetatable(L,-1)) { /* stack: obj key obj mt */ lua_remove(L,-2); /* stack: obj key mt */ if (lua_isnumber(L,2)) /* check if key is a numeric value */ { /* try operator[] */ lua_pushstring(L,".geti"); lua_rawget(L,-2); /* stack: obj key mt func */ if (lua_isfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,2); lua_call(L,2,1); return 1; } } else { lua_pushvalue(L,2); /* stack: obj key mt key */ lua_rawget(L,-2); /* stack: obj key mt value */ if (!lua_isnil(L,-1)) return 1; else lua_pop(L,1); /* try C/C++ variable */ lua_pushstring(L,".get"); lua_rawget(L,-2); /* stack: obj key mt tget */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); lua_rawget(L,-2); /* stack: obj key mt value */ if (lua_iscfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,2); lua_call(L,2,1); return 1; } else if (lua_istable(L,-1)) { /* deal with array: create table to be returned and cache it in ubox */ void* u = *((void**)lua_touserdata(L,1)); lua_newtable(L); /* stack: obj key mt value table */ lua_pushstring(L,".self"); lua_pushlightuserdata(L,u); lua_rawset(L,-3); /* store usertype in ".self" */ lua_insert(L,-2); /* stack: obj key mt table value */ lua_setmetatable(L,-2); /* set stored value as metatable */ lua_pushvalue(L,-1); /* stack: obj key met table table */ lua_pushvalue(L,2); /* stack: obj key mt table table key */ lua_insert(L,-2); /* stack: obj key mt table key table */ storeatubox(L,1); /* stack: obj key mt table */ return 1; } } } lua_settop(L,3); } lua_pushnil(L); return 1; } else if (t== LUA_TTABLE) { module_index_event(L); return 1; } lua_pushnil(L); return 1; }
lua_CFunction lua_getcfunction(lua_Object object) { if (!lua_iscfunction(object)) return NULL; else return fvalue(luaA_protovalue(Address(object))); }
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx) { lua_State *mt; /* the main thread */ lua_State *co; /* new coroutine to be created */ ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); mt = lmcf->lua; /* create new coroutine on root Lua state, so it always yields * to main Lua thread */ co = lua_newthread(mt); ngx_http_lua_probe_user_coroutine_create(r, L, co); coctx = ngx_http_lua_create_co_ctx(r, ctx); if (coctx == NULL) { return luaL_error(L, "out of memory"); } coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_xmove(L, co, 1); lua_replace(co, LUA_GLOBALSINDEX); lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ lua_pushvalue(L, 1); /* copy entry function to top of L*/ lua_xmove(L, co, 1); /* move entry function from L to co */ if (pcoctx) { *pcoctx = coctx; } if (pctx) { *pctx = ctx; } if (pr) { *pr = r; } return 1; /* return new coroutine to Lua */ }
/* Class index function * If the object is a userdata (ie, an object), it searches the field in * the alternative table stored in the corresponding "peer" table. */ static int class_index_event (lua_State* L) { int t = lua_type(L,1); if (t == LUA_TUSERDATA) { /* Access alternative table */ lua_pushstring(L,"tolua_peer"); lua_rawget(L,LUA_REGISTRYINDEX); /* stack: obj key peer */ lua_pushvalue(L,1); lua_rawget(L,-2); /* stack: obj key peer peer[u] */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); /* key */ lua_rawget(L,-2); /* stack: obj key peer peer[u] value */ if (!lua_isnil(L,-1)) return 1; } lua_settop(L,2); /* stack: obj key */ /* Try metatables */ lua_pushvalue(L,1); /* stack: obj key obj */ while (lua_getmetatable(L,-1)) { /* stack: obj key obj mt */ lua_remove(L,-2); /* stack: obj key mt */ if (lua_isnumber(L,2)) /* check if key is a numeric value */ { /* try operator[] */ lua_pushstring(L,".geti"); lua_rawget(L,-2); /* stack: obj key mt func */ if (lua_isfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,2); lua_call(L,2,1); return 1; } } else { lua_pushvalue(L,2); /* stack: obj key mt key */ lua_rawget(L,-2); /* stack: obj key mt value */ if (!lua_isnil(L,-1)) return 1; else lua_pop(L,1); /* try C/C++ variable */ lua_pushstring(L,".get"); lua_rawget(L,-2); /* stack: obj key mt tget */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); lua_rawget(L,-2); /* stack: obj key mt value */ if (lua_iscfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,2); lua_call(L,2,1); return 1; } else if (lua_istable(L,-1)) { /* deal with array: create table to be returned and cache it in peer */ void* u = *((void**)lua_touserdata(L,1)); lua_newtable(L); /* stack: obj key mt value table */ lua_pushstring(L,".self"); lua_pushlightuserdata(L,u); lua_rawset(L,-3); /* store usertype in ".self" */ lua_insert(L,-2); /* stack: obj key mt table value */ lua_setmetatable(L,-2); /* set stored value as metatable */ lua_pushvalue(L,-1); /* stack: obj key met table table */ lua_pushvalue(L,2); /* stack: obj key mt table table key */ lua_insert(L,-2); /* stack: obj key mt table key table */ storeatpeer(L,1); /* stack: obj key mt table */ return 1; } } } lua_settop(L,3); } lua_pushnil(L); return 1; } else if (t== LUA_TTABLE) { module_index_event(L); return 1; } lua_pushnil(L); return 1; }
int LuaUtils_Introduce(lua_State *L) { int n = LuaUtils_CheckParameter2(L, 1, 2, LuaUtils_IntroduceUsage); if (!lua_istable(L, 1)) return LuaUtils_Error(L, "Not a table"); if (n >= 2) { bool found = false; lua_pushstring(L, "__intrinsic"); lua_gettable(L, -3); if (lua_islightuserdata(L, -1)) { const RegisterItem *items = lua_touserdata(L, -1); const char *library = items[0].name; const char *function = lua_tostring(L, 2); const char *usage = 0; for (const RegisterItem *item = items + 1; item->type; item++) { if (strcmp(function, "introduce") == 0) usage = LuaUtils_IntroduceUsage; if (strcmp(function, item->name) == 0) usage = item->usage; if (usage) break; } if (usage) { luaL_Buffer buffer; luaL_buffinit(L, &buffer); ExpandUsageToBuffer(&buffer, usage, library, function); luaL_pushresult(&buffer); } else { lua_pushstring(L, function); lua_gettable(L, -4); if (lua_isfunction(L, -1) && !lua_iscfunction(L, -1)) { Proto *proto = ((LClosure*) lua_topointer(L, -1))->p; luaL_Buffer buffer; luaL_buffinit(L, &buffer); luaL_addstring(&buffer, "[\""); luaL_addstring(&buffer, library); luaL_addchar(&buffer, '.'); luaL_addstring(&buffer, function); luaL_addchar(&buffer, '('); for (uint16_t i = 0; i < proto->numparams; i++) { if (i) luaL_addchar(&buffer, ','); luaL_addstring(&buffer, getstr(proto->locvars[i].varname)); } if (proto->is_vararg) { if (proto->numparams) luaL_addchar(&buffer, ','); luaL_addstring(&buffer, "..."); } luaL_addstring(&buffer, ")\"]"); luaL_pushresult(&buffer); } else lua_pushstring(L, "<unknown>"); } } } else { luaL_Buffer buffer; luaL_buffinit(L, &buffer); luaL_addchar(&buffer, '['); uint16_t i = 0; { lua_pushnil(L); while (lua_next(L, -2)) { switch (lua_type(L, -1)) { case LUA_TBOOLEAN : // {"name":boolean}, if (i++) luaL_addchar(&buffer, ','); luaL_addstring(&buffer, "{\""); luaL_addstring(&buffer, lua_tostring(L, -2)); luaL_addstring(&buffer, "\":"); luaL_addstring(&buffer, lua_toboolean(L, -1) ? "true" : "false"); luaL_addchar(&buffer, '}'); break; case LUA_TNUMBER : // {"name":number}, if (i++) luaL_addchar(&buffer, ','); luaL_addstring(&buffer, "{\""); luaL_addstring(&buffer, lua_tostring(L, -2)); luaL_addstring(&buffer, "\":"); luaL_addstring(&buffer, lua_tostring(L, -1)); luaL_addchar(&buffer, '}'); break; case LUA_TUSERDATA : case LUA_TLIGHTUSERDATA : // "name", if (i++) luaL_addchar(&buffer, ','); luaL_addchar(&buffer, '"'); luaL_addstring(&buffer, lua_tostring(L, -2)); luaL_addchar(&buffer, '"'); break; } lua_pop(L, 1); } } { lua_pushnil(L); while (lua_next(L, -2)) { if (lua_type(L, -1) == LUA_TFUNCTION) { // "name()", if (i++) luaL_addchar(&buffer, ','); luaL_addchar(&buffer, '"'); luaL_addstring(&buffer, lua_tostring(L, -2)); luaL_addstring(&buffer, "()\""); // TODO Hier "Usage" } lua_pop(L, 1); } } { lua_pushnil(L); while (lua_next(L, -2)) { if (lua_type(L, -1) == LUA_TTABLE) { // "name", if (i++) luaL_addchar(&buffer, ','); luaL_addchar(&buffer, '"'); luaL_addstring(&buffer, lua_tostring(L, -2)); luaL_addstring(&buffer, ".*\""); } lua_pop(L, 1); } } luaL_addchar(&buffer, ']'); luaL_pushresult(&buffer); } return 1; }
MethodBase *LSProfiler::getTopMethod(lua_State *L) { int top = lua_gettop(L); lua_Debug stack; // if we get a null result here, we are out of stack if (!lua_getstack(L, 0, &stack)) { lua_settop(L, top); return NULL; } if (!lua_getinfo(L, "f", &stack)) { lua_settop(L, top); return NULL; } bool iscfunc = false; if (lua_iscfunction(L, -1)) { iscfunc = true; } #ifdef LOOM_ENABLE_JIT // We do not receive line return hooks for native calls under JIT :( // So, if we want to profile native methods, we need to be under interpreted VM if (iscfunc) { lua_settop(L, top); return NULL; } #endif lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMETHODLOOKUP); lua_pushvalue(L, -2); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_settop(L, top); return NULL; } MethodBase *methodBase = (MethodBase *)lua_topointer(L, -1); lua_settop(L, top); if (iscfunc && !methodBase->isNative()) { return NULL; } if (shouldFilterFunction(methodBase->getFullMemberName())) { return NULL; } return methodBase; }
lsb_err_value preserve_global_data(lsb_lua_sandbox *lsb) { if (!lsb->lua || !lsb->state_file) { return NULL; } lua_sethook(lsb->lua, NULL, 0, 0); // make sure the string library is loaded before we start lua_getglobal(lsb->lua, LUA_STRLIBNAME); if (!lua_istable(lsb->lua, -1)) { lua_getglobal(lsb->lua, "require"); if (!lua_iscfunction(lsb->lua, -1)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data 'require' function not found"); return LSB_ERR_LUA; } lua_pushstring(lsb->lua, LUA_STRLIBNAME); if (lua_pcall(lsb->lua, 1, 1, 0)) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data failed loading 'string'"); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } return LSB_ERR_LUA; } } lua_pop(lsb->lua, 1); lua_pushvalue(lsb->lua, LUA_GLOBALSINDEX); FILE *fh = fopen(lsb->state_file, "wb"); if (fh == NULL) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data could not open: %s", lsb->state_file); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } return LSB_ERR_LUA;; } lsb_err_value ret = NULL; serialization_data data; data.fh = fh; // Clear the sandbox limits during preservation. #ifdef LUA_JIT lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, 0); #else // size_t limit = lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]; lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = 0; #endif // size_t cur_output_size = lsb->output.size; // size_t max_output_size = lsb->output.maxsize; lsb->output.maxsize = 0; // end clear data.tables.size = 64; data.tables.pos = 0; data.tables.array = malloc(data.tables.size * sizeof(table_ref)); if (data.tables.array == NULL || lsb_init_output_buffer(&data.keys, 0)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "preserve_global_data out of memory"); ret = LSB_ERR_UTIL_OOM; } else { fprintf(data.fh, "if %s and %s ~= %d then return end\n", preservation_version, preservation_version, get_preservation_version(lsb->lua)); ret = lsb_outputs(&data.keys, "_G", 2); if (!ret) { data.keys.pos += 1; // preserve the NUL in this use case data.globals = lua_topointer(lsb->lua, -1); lua_checkstack(lsb->lua, 2); lua_pushnil(lsb->lua); while (!ret && lua_next(lsb->lua, -2) != 0) { ret = serialize_kvp(lsb, &data, 0); lua_pop(lsb->lua, 1); } } lua_pop(lsb->lua, lua_gettop(lsb->lua)); // Wipe the entire Lua stack. Since incremental cleanup on failure // was added the stack should only contain table _G. } free(data.tables.array); lsb_free_output_buffer(&data.keys); fclose(fh); if (ret) remove(lsb->state_file); // Uncomment if we start preserving state when not destroying the sandbox // Note: serialization uses the output buffer, inprogress output can be // destroyed if the user was collecting output between calls. /* // Restore the sandbox limits after preservation #ifdef LUA_JIT lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]); #else lua_gc(lsb->lua, LUA_GCCOLLECT, 0); lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = limit; lsb->usage[LSB_UT_MEMORY][LSB_US_MAXIMUM] = lsb->usage[LSB_UT_MEMORY][LSB_US_CURRENT]; #endif lsb->output.maxsize = max_output_size; lsb_clear_output_buffer(lsb->output); if (lsb->output.size > cur_output_size) { void* ptr = realloc(lsb->output.data, cur_output_size); if (!ptr) return 1; lsb->output.data = ptr; lsb->output.size = cur_output_size; } // end restore */ return ret; }
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx) { lua_State *vm; /* the Lua VM */ lua_State *co; /* new coroutine to be created */ ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_SSL_CERT); vm = ngx_http_lua_get_lua_vm(r, ctx); /* create new coroutine on root Lua state, so it always yields * to main Lua thread */ co = lua_newthread(vm); ngx_http_lua_probe_user_coroutine_create(r, L, co); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { coctx = ngx_http_lua_create_co_ctx(r, ctx); if (coctx == NULL) { return luaL_error(L, "no memory"); } } else { ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t)); coctx->co_ref = LUA_NOREF; } coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ lua_pushvalue(L, 1); /* copy entry function to top of L*/ lua_xmove(L, co, 1); /* move entry function from L to co */ if (pcoctx) { *pcoctx = coctx; } #ifdef NGX_LUA_USE_ASSERT coctx->co_top = 1; #endif return 1; /* return new coroutine to Lua */ }
int NativeDelegate::__op_minusassignment(lua_State *L) { NativeDelegate *delegate = (NativeDelegate *)lualoom_getnativepointer(L, 1, "system.NativeDelegate"); if (!delegate) { LSError("Unable to get native delegate on += operator"); } if (!delegate->_callbackCount) { return 0; } delegate->setVM(L); delegate->getCallbacks(L); int tidx = lua_gettop(L); if (!lua_istable(L, tidx)) { LSError("Bad native delegates table"); } if (lua_isfunction(L, 2) || lua_iscfunction(L, 2)) { int idx = -1; for (int i = 0; i < delegate->_callbackCount; i++) { lua_rawgeti(L, tidx, i); if (lua_equal(L, 2, -1)) { idx = i; lua_pop(L, 1); break; } lua_pop(L, 1); } // this function was never added in the first place if (idx == -1) { return 0; } // shift the other delegates down lua_pushnumber(L, (double)idx); lua_pushnil(L); lua_settable(L, tidx); int ntable = 0; if (delegate->_callbackCount > 1) { // temp table lua_newtable(L); ntable = lua_gettop(L); int c = 0; for (int nidx = 0; nidx < delegate->_callbackCount; nidx++) { lua_pushnumber(L, (double)nidx); lua_gettable(L, tidx); if (lua_isnil(L, -1)) { lua_pop(L, 1); continue; } lua_pushnumber(L, (double)c); lua_pushvalue(L, -2); lua_settable(L, ntable); // pop lua_function lua_pop(L, 1); c++; } } // clear it delegate->_callbackCount--; // and copy from new temp table for (int nidx = 0; nidx < delegate->_callbackCount; nidx++) { lua_pushnumber(L, (double)nidx); lua_pushnumber(L, (double)nidx); lua_gettable(L, ntable); lua_settable(L, tidx); } } else { LSError("Unknown type on NativeDelegate -= operator"); } return 0; }
bool LuaInterface::isCFunction(int index) { assert(hasIndex(index)); return lua_iscfunction(L, index); }
int Thermal::help(lua_State* L) { if(lua_gettop(L) == 0) { lua_pushstring(L, "Generates a the random thermal field of a *SpinSystem*"); lua_pushstring(L, "1 *3Vector* or *SpinSystem*, 1 Optional *Random*: System Size and built in RNG"); lua_pushstring(L, ""); //output, empty return 3; } if(lua_istable(L, 1)) { return 0; } if(!lua_iscfunction(L, 1)) { return luaL_error(L, "help expect zero arguments or 1 function."); } lua_CFunction func = lua_tocfunction(L, 1); if(func == l_apply) { lua_pushstring(L, "Generates a the random thermal field of a *SpinSystem*"); lua_pushstring(L, "1 *SpinSystem*, 1 Optional *Random*,: The first argument is the spin system which will receive the field. The second optional argument is a random number generator that is used as a source of random values, if absent then the RNG supplied in the constructor will be used."); lua_pushstring(L, ""); return 3; } if(func == l_scalesite) { lua_pushstring(L, "Scale the thermal field at a site. This allows non-uniform thermal effects over a lattice."); lua_pushstring(L, "1 *3Vector*, 1 Number: The vectors define the lattice sites that will have a scaled thermal effect, the number is the how the thermal field is scaled."); lua_pushstring(L, ""); return 3; } if(func == l_settemp) { lua_pushstring(L, "Sets the base value of the temperature. "); lua_pushstring(L, "1 number: temperature of the system."); lua_pushstring(L, ""); return 3; } if(func == l_gettemp) { lua_pushstring(L, "Gets the base value of the temperature. "); lua_pushstring(L, ""); lua_pushstring(L, "1 number: temperature of the system."); return 3; } if(func == l_getscalearray) { lua_pushstring(L, "Get an array representing the thermal scale at each site. This array is connected to the Operator so changes to the returned array will change the Operator."); lua_pushstring(L, ""); lua_pushstring(L, "1 Array: The thermal scale of the sites."); return 3; } if(func == l_setscalearray) { lua_pushstring(L, "Set an array representing the new thermal scale at each site."); lua_pushstring(L, "1 Array: The thermal scale of the sites."); lua_pushstring(L, ""); return 3; } if(func == l_rng) { lua_pushstring(L, "Get the *Random* number generator supplied at initialization"); lua_pushstring(L, ""); lua_pushstring(L, "1 *Random* or 1 nil: RNG"); return 3; } return SpinOperation::help(L); }
bool Environment::isCFunction(int index) { return lua_iscfunction(L, index); }
void ShipType::Init() { static bool isInitted = false; if (isInitted) return; isInitted = true; // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with_ci(info.GetPath(), ".json")) { const std::string id(info.GetName().substr(0, info.GetName().size()-5)); try { ShipType st = ShipType(id, info.GetPath()); types.insert(std::make_pair(st.id, st)); // assign the names to the various lists switch( st.tag ) { case TAG_SHIP: player_ships.push_back(id); break; case TAG_STATIC_SHIP: static_ships.push_back(id); break; case TAG_MISSILE: missile_ships.push_back(id); break; break; case TAG_NONE: default: break; } } catch (ShipTypeLoadError) { // TODO: Actual error handling would be nice. Error("Error while loading Ship data (check stdout/output.txt).\n"); } } } #if ALLOW_LUA_SHIP_DEF lua_State *l = luaL_newstate(); LUA_DEBUG_START(l); luaL_requiref(l, "_G", &luaopen_base, 1); luaL_requiref(l, LUA_DBLIBNAME, &luaopen_debug, 1); luaL_requiref(l, LUA_MATHLIBNAME, &luaopen_math, 1); lua_pop(l, 3); LuaConstants::Register(l); LuaVector::Register(l); LUA_DEBUG_CHECK(l, 0); // provide shortcut vector constructor: v = vector.new lua_getglobal(l, LuaVector::LibName); lua_getfield(l, -1, "new"); assert(lua_iscfunction(l, -1)); lua_setglobal(l, "v"); lua_pop(l, 1); // pop the vector library table LUA_DEBUG_CHECK(l, 0); // register ship definition functions lua_register(l, "define_ship", define_ship); lua_register(l, "define_static_ship", define_static_ship); lua_register(l, "define_missile", define_missile); LUA_DEBUG_CHECK(l, 0); // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with_ci(info.GetPath(), ".lua")) { const std::string name = info.GetName(); s_currentShipFile = name.substr(0, name.size() - 4); if (ShipType::types.find(s_currentShipFile) == ShipType::types.end()) { pi_lua_dofile(l, info.GetPath()); s_currentShipFile.clear(); } } } LUA_DEBUG_END(l, 0); lua_close(l); #endif //remove unbuyable ships from player ship list ShipType::player_ships.erase( std::remove_if(ShipType::player_ships.begin(), ShipType::player_ships.end(), ShipIsUnbuyable), ShipType::player_ships.end()); if (ShipType::player_ships.empty()) Error("No playable ships have been defined! The game cannot run."); }
void LSProfiler::getCurrentStack(lua_State *L, utStack<MethodBase *>& stack) { int top = lua_gettop(L); lua_Debug lstack; int stackFrame = 0; MethodBase *lastMethod = NULL; while (true) { // if we get a null result here, we are out of stack if (!lua_getstack(L, stackFrame++, &lstack)) { lua_settop(L, top); return; } // something bad in denmark if (!lua_getinfo(L, "f", &lstack)) { lua_settop(L, top); return; } bool cfunc = false; if (lua_iscfunction(L, -1)) { cfunc = true; } lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMETHODLOOKUP); lua_pushvalue(L, -2); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_settop(L, top); continue; } MethodBase *methodBase = (MethodBase *)lua_topointer(L, -1); lua_settop(L, top); #ifdef LOOM_ENABLE_JIT // We do not receive line return hooks for native calls under JIT :( // So, don't add to initial stack if (cfunc) { continue; } #endif if (shouldFilterFunction(methodBase->getFullMemberName())) { continue; } // we only want the root call, not the pcall wrapper if (cfunc && (lastMethod == methodBase)) { continue; } lastMethod = methodBase; stack.push(methodBase); } }
//***************************************************************************** bool LuaUtils::TransferValueToStack(LuaStack inStack, LuaStack outStack, int ntop, int levels, const char *varname) { if (levels < 0) return false; // convert relative to absolute indexing if necessary if (ntop < 0) ntop = (lua_gettop(inStack) + 1 + ntop); lua_newtable(outStack); // push variable name if (varname != NULL) { lua_pushstring(outStack, varname); lua_setfield(outStack, -2, "name"); } // push the variable type int top_type = lua_type(inStack, ntop); lua_pushstring(outStack, lua_typename(inStack, top_type)); lua_setfield(outStack, -2, "type"); // finally push the value if (lua_isnil(inStack, ntop)) { lua_pushnil(outStack); lua_setfield(outStack, -2, "value"); } else if (lua_isboolean(inStack, ntop)) { lua_pushboolean(outStack, lua_toboolean(inStack, ntop)); lua_setfield(outStack, -2, "value"); } else if (lua_isnumber(inStack, ntop)) { lua_pushnumber(outStack, lua_tonumber(inStack, ntop)); lua_setfield(outStack, -2, "value"); } else if (lua_isstring(inStack, ntop)) { lua_pushstring(outStack, lua_tostring(inStack, ntop)); lua_setfield(outStack, -2, "value"); } else if (lua_islightuserdata(inStack, ntop)) { lua_pushlightuserdata(outStack, lua_touserdata(inStack, ntop)); lua_setfield(outStack, -2, "value"); } else if (lua_isuserdata(inStack, ntop) || lua_iscfunction(inStack, ntop) || lua_isfunction(inStack, ntop) || lua_isthread(inStack, ntop)) { lua_pushfstring(outStack, "%p", lua_topointer(inStack, ntop)); lua_setfield(outStack, -2, "value"); } else if (lua_istable(inStack, ntop)) { if (levels == 0) { lua_pushboolean(outStack, true); lua_setfield(outStack, -2, "raw"); // whether to send only a summary! lua_pushfstring(outStack, "%p", lua_topointer(inStack, ntop)); } else { lua_newtable(outStack); int index = 1; lua_pushnil(inStack); while (lua_next(inStack, ntop) != 0) { // printf("%s - %s\n", lua_typename(inStack, lua_type(inStack, -2)), lua_typename(inStack, lua_type(inStack, -1))); int newtop = lua_gettop(inStack); int keyindex = newtop - 1; int valindex = newtop; lua_pushinteger(outStack, index++); lua_newtable(outStack); // uses 'key' at index top-1 and 'value' at index top if (LuaUtils::TransferValueToStack(inStack, outStack, keyindex, 0)) { lua_setfield(outStack, -2, "key"); if (LuaUtils::TransferValueToStack(inStack, outStack, valindex, levels - 1)) lua_setfield(outStack, -2, "value"); } lua_settable(outStack, -3); // remove 'value', keeps 'key' for next iteration lua_pop(inStack, 1); } } lua_setfield(outStack, -2, "value"); } else { lua_pushstring(outStack, "Unknown type."); lua_setfield(outStack, -2, "value"); } return true; }
static int tek_lib_exec_run(lua_State *L) { struct LuaExecTask *lexec = tek_lib_exec_check(L); struct TExecBase *TExecBase = lexec->exec; struct LuaExecChild *ctx; const char *fname = TNULL; const char *chunk = TNULL; const char *taskname = TNULL; size_t extralen = 0; struct THook hook; TTAGITEM tags[2]; int nremove = 1; TBOOL abort = TTRUE; for (;;) { if (lua_istable(L, 1)) { lua_getfield(L, 1, "abort"); if (lua_isboolean(L, -1)) abort = lua_toboolean(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "taskname"); taskname = lua_tostring(L, -1); nremove = 2; lua_getfield(L, 1, "func"); if (!lua_isnoneornil(L, -1)) break; lua_pop(L, 1); lua_getfield(L, 1, "filename"); if (!lua_isnoneornil(L, -1)) break; lua_pop(L, 1); lua_getfield(L, 1, "chunk"); if (!lua_isnoneornil(L, -1)) { chunk = luaL_checklstring(L, -1, &extralen); break; } luaL_error(L, "required argument missing"); } lua_pushvalue(L, 1); break; } if (!chunk) { if (lua_type(L, -1) == LUA_TSTRING) fname = luaL_checklstring(L, -1, &extralen); else if (lua_isfunction(L, -1) && !lua_iscfunction(L, -1)) chunk = tek_lib_exec_dump(L, &extralen); else luaL_error(L, "not a Lua function, filename or table"); } ctx = lua_newuserdata(L, sizeof(struct LuaExecChild) + extralen + 1); memset(ctx, 0, sizeof *ctx); ctx->exec = lexec->exec; ctx->parent = lexec; ctx->taskname = tek_lib_exec_taskname(ctx->atomname, taskname); ctx->abort = abort; if (fname) { ctx->fname = (char *) (ctx + 1); strcpy(ctx->fname, (char *) fname); } else if (chunk) { memcpy(ctx + 1, chunk, extralen); ctx->chunklen = extralen; } /* remove arguments under userdata */ while (nremove--) lua_remove(L, -2); ctx->numargs = lua_gettop(L) - 2; /* push arg[0] on the stack, will be extraarg */ lua_getglobal(L, "arg"); if (lua_istable(L, -1)) { lua_rawgeti(L, -1, 0); lua_remove(L, -2); } if (lua_type(L, -1) != LUA_TSTRING) { lua_pop(L, 1); lua_pushnil(L); } ctx->args = tek_lib_exec_getargs(L, TExecBase, 2, ctx->numargs++, 1); lua_pop(L, 1); ctx->L = lua_newstate(tek_lib_exec_allocf, TExecBase); if (ctx->L == TNULL) { tek_lib_exec_freeargs(TExecBase, ctx->args, ctx->numargs); luaL_error(L, "cannot create interpreter"); } tags[0].tti_Tag = TTask_UserData; tags[0].tti_Value = (TTAG) ctx; tags[1].tti_Tag = TTAG_DONE; TInitHook(&hook, tek_lib_exec_run_dispatch, ctx); ctx->task = TCreateTask(&hook, tags); if (ctx->task == TNULL) { tek_lib_exec_freectxargs(ctx); lua_pop(L, 1); lua_pushnil(L); return 1; } lua_getfield(L, LUA_REGISTRYINDEX, TEK_LIB_TASK_CLASSNAME); lua_setmetatable(L, -2); lua_pushvalue(L, -1); ctx->ref = luaL_ref(L, lua_upvalueindex(2)); if (ctx->abort) tek_lib_exec_register_task_hook(L, TExecBase); return 1; }
static int ngx_http_lua_ngx_timer_at(lua_State *L) { int nargs, co_ref; u_char *p; lua_State *vm; /* the main thread */ lua_State *co; ngx_msec_t delay; ngx_event_t *ev = NULL; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; ngx_http_lua_ctx_t *ctx; #if 0 ngx_http_connection_t *hc; #endif ngx_http_lua_timer_ctx_t *tctx = NULL; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; #endif nargs = lua_gettop(L); if (nargs < 2) { return luaL_error(L, "expecting at least 2 arguments but got %d", nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ngx_exiting && delay > 0) { lua_pushnil(L); lua_pushliteral(L, "process exiting"); return 2; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (lmcf->pending_timers >= lmcf->max_pending_timers) { lua_pushnil(L); lua_pushliteral(L, "too many pending timers"); return 2; } if (lmcf->watcher == NULL) { /* create the watcher fake connection */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua creating fake watcher connection"); if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (lmcf->watcher == NULL) { return luaL_error(L, "no memory"); } /* to work around the -1 check in ngx_worker_process_cycle: */ lmcf->watcher->fd = (ngx_socket_t) -2; lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; } vm = ngx_http_lua_get_lua_vm(r, ctx); co = lua_newthread(vm); /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ ngx_http_lua_get_globals_table(co); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); /* co stack: <empty> */ dd("stack top: %d", lua_gettop(L)); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ /* L stack: time func [args] thread */ /* vm stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ /* L stack: time func [args] thread */ /* co stack: func */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); /* L stack: time func [args] thread */ if (nargs > 2) { lua_pop(L, 1); /* L stack: time func [args] */ lua_xmove(L, co, nargs - 2); /* L stack: time func */ /* co stack: func [args] */ } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { goto nomem; } ev = (ngx_event_t *) p; ngx_memzero(ev, sizeof(ngx_event_t)); p += sizeof(ngx_event_t); tctx = (ngx_http_lua_timer_ctx_t *) p; tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; tctx->main_conf = r->main_conf; tctx->srv_conf = r->srv_conf; tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; tctx->pool = ngx_create_pool(128, ngx_cycle->log); if (tctx->pool == NULL) { goto nomem; } if (r->connection) { tctx->listening = r->connection->listening; } else { tctx->listening = NULL; } if (r->connection->addr_text.len) { tctx->client_addr_text.data = ngx_palloc(tctx->pool, r->connection->addr_text.len); if (tctx->client_addr_text.data == NULL) { goto nomem; } ngx_memcpy(tctx->client_addr_text.data, r->connection->addr_text.data, r->connection->addr_text.len); tctx->client_addr_text.len = r->connection->addr_text.len; } else { tctx->client_addr_text.len = 0; tctx->client_addr_text.data = NULL; } if (ctx && ctx->vm_state) { tctx->vm_state = ctx->vm_state; tctx->vm_state->count++; } else { tctx->vm_state = NULL; } ev->handler = ngx_http_lua_timer_handler; ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; ngx_add_timer(ev, delay, NGX_FUNC_LINE); lua_pushinteger(L, 1); return 1; nomem: if (tctx && tctx->pool) { ngx_destroy_pool(tctx->pool); } if (ev) { ngx_free(ev); } lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); return luaL_error(L, "no memory"); }
void ShipType::Init() { static bool isInitted = false; if (isInitted) return; isInitted = true; lua_State *l = luaL_newstate(); LUA_DEBUG_START(l); luaL_requiref(l, "_G", &luaopen_base, 1); luaL_requiref(l, LUA_DBLIBNAME, &luaopen_debug, 1); luaL_requiref(l, LUA_MATHLIBNAME, &luaopen_math, 1); lua_pop(l, 3); LuaConstants::Register(l); LuaVector::Register(l); LUA_DEBUG_CHECK(l, 0); // provide shortcut vector constructor: v = vector.new lua_getglobal(l, LuaVector::LibName); lua_getfield(l, -1, "new"); assert(lua_iscfunction(l, -1)); lua_setglobal(l, "v"); lua_pop(l, 1); // pop the vector library table LUA_DEBUG_CHECK(l, 0); // register ship definition functions lua_register(l, "define_ship", define_ship); lua_register(l, "define_static_ship", define_static_ship); lua_register(l, "define_missile", define_missile); LUA_DEBUG_CHECK(l, 0); // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with(info.GetPath(), ".lua")) { const std::string name = info.GetName(); s_currentShipFile = name.substr(0, name.size()-4); pi_lua_dofile(l, info.GetPath()); s_currentShipFile.clear(); } } LUA_DEBUG_END(l, 0); lua_close(l); //remove unbuyable ships from player ship list ShipType::player_ships.erase( std::remove_if(ShipType::player_ships.begin(), ShipType::player_ships.end(), ShipIsUnbuyable), ShipType::player_ships.end()); if (ShipType::player_ships.empty()) Error("No playable ships have been defined! The game cannot run."); //collect ships that can fit atmospheric shields for (std::vector<ShipType::Id>::const_iterator it = ShipType::player_ships.begin(); it != ShipType::player_ships.end(); ++it) { const ShipType &ship = ShipType::types[*it]; if (ship.equipSlotCapacity[Equip::SLOT_ATMOSHIELD] != 0) ShipType::playable_atmospheric_ships.push_back(*it); } if (ShipType::playable_atmospheric_ships.empty()) Error("No ships can fit atmospheric shields! The game cannot run."); }
lsb_err_value lsb_init(lsb_lua_sandbox *lsb, const char *state_file) { if (!lsb) { return LSB_ERR_UTIL_NULL; } if (lsb->state != LSB_UNKNOWN) { lsb_terminate(lsb, LSB_ERR_INIT); return LSB_ERR_INIT; } if (state_file && strlen(state_file) > 0) { lsb->state_file = malloc(strlen(state_file) + 1); if (!lsb->state_file) { lsb_terminate(lsb, LSB_ERR_UTIL_OOM); return LSB_ERR_UTIL_OOM; } strcpy(lsb->state_file, state_file); } #ifndef LUA_JIT size_t mem_limit = lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]; lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = 0; #endif preload_modules(lsb->lua); // load package module lua_pushcfunction(lsb->lua, luaopen_package); lua_pushstring(lsb->lua, LUA_LOADLIBNAME); lua_call(lsb->lua, 1, 1); lua_newtable(lsb->lua); lua_setmetatable(lsb->lua, -2); lua_pop(lsb->lua, 1); // load base module lua_getglobal(lsb->lua, "require"); if (!lua_iscfunction(lsb->lua, -1)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "lsb_init() 'require' not found"); lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } lua_pushstring(lsb->lua, LUA_BASELIBNAME); if (lua_pcall(lsb->lua, 1, 0, 0)) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "lsb_init %s", lua_tostring(lsb->lua, -1)); lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } if (lsb->usage[LSB_UT_INSTRUCTION][LSB_US_LIMIT] != 0) { lua_sethook(lsb->lua, instruction_manager, LUA_MASKCOUNT, (int)lsb->usage[LSB_UT_INSTRUCTION][LSB_US_LIMIT]); } else { lua_sethook(lsb->lua, NULL, 0, 0); } #ifdef LUA_JIT // todo limit lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, (int)lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]); #else lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = mem_limit; #endif lua_CFunction pf = lua_atpanic(lsb->lua, unprotected_panic); int jump = setjmp(g_jbuf); if (jump || luaL_dofile(lsb->lua, lsb->lua_file) != 0) { int len = snprintf(lsb->error_message, LSB_ERROR_SIZE, "%s", lua_tostring(lsb->lua, -1)); if (len >= LSB_ERROR_SIZE || len < 0) { lsb->error_message[LSB_ERROR_SIZE - 1] = 0; } lsb_terminate(lsb, NULL); return LSB_ERR_LUA; } else { lua_gc(lsb->lua, LUA_GCCOLLECT, 0); lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT] = instruction_usage(lsb); if (lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT] > lsb->usage[LSB_UT_INSTRUCTION][LSB_US_MAXIMUM]) { lsb->usage[LSB_UT_INSTRUCTION][LSB_US_MAXIMUM] = lsb->usage[LSB_UT_INSTRUCTION][LSB_US_CURRENT]; } lsb->state = LSB_RUNNING; if (lsb->state_file) { lsb_err_value ret = restore_global_data(lsb); if (ret) return ret; } } lua_atpanic(lsb->lua, pf); return NULL; }
/* Newindex function * It first searches for a C/C++ varaible to be set. * Then, it either stores it in the alternative ubox table (in the case it is * an object) or in the own table (that represents the class or module). */ static int class_newindex_event (lua_State* L) { int t = lua_type(L,1); if (t == LUA_TUSERDATA) { /* Try accessing a C/C++ variable to be set */ lua_getmetatable(L,1); while (lua_istable(L,-1)) /* stack: t k v mt */ { if (lua_isnumber(L,2)) /* check if key is a numeric value */ { /* try operator[] */ lua_pushstring(L,".seti"); lua_rawget(L,-2); /* stack: obj key mt func */ if (lua_isfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,2); lua_pushvalue(L,3); lua_call(L,3,0); return 0; } } else { lua_pushstring(L,".set"); lua_rawget(L,-2); /* stack: t k v mt tset */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); lua_rawget(L,-2); /* stack: t k v mt tset func */ if (lua_iscfunction(L,-1)) { lua_pushvalue(L,1); lua_pushvalue(L,3); lua_call(L,2,0); return 0; } lua_pop(L,1); /* stack: t k v mt tset */ } lua_pop(L,1); /* stack: t k v mt */ if (!lua_getmetatable(L,-1)) /* stack: t k v mt mt */ lua_pushnil(L); lua_remove(L,-2); /* stack: t k v mt */ } } lua_settop(L,3); /* stack: t k v */ /* then, store as a new field */ storeatubox(L,1); } else if (t== LUA_TTABLE) { lua_getmetatable(L,1); /* stack: t k v mt */ lua_pushstring(L,".set"); lua_rawget(L,-2); /* stack: t k v mt tset */ if (lua_istable(L,-1)) { lua_pushvalue(L,2); /* stack: t k v mt tset k */ lua_rawget(L,-2); if (lua_iscfunction(L,-1)) { /* ... func */ lua_pushvalue(L,1); /* ... func t */ lua_pushvalue(L,3); /* ... func t v */ lua_call(L,2,0); return 0; } } lua_settop(L,3); class_backup_before_newindex(L); lua_settop(L,3); lua_getmetatable(L,1); /* stack: t k v mt */ lua_replace(L, 1); /* stack: mt k v */ lua_rawset(L,1); } return 0; }