/* ** Check whether a given upvalue from a given closure exists and ** returns its index */ static int checkupval (lua_State *L, int argf, int argnup) { int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, "invalid upvalue index"); return nup; }
LUABIND_API bool is_luabind_function(lua_State* L, int index) { if (!lua_getupvalue(L, index, 2)) return false; bool result = lua_touserdata(L, -1) == &function_tag; lua_pop(L, 1); return result; }
/* error function */ int lf_errorfunc(lua_State *L) { int depth = 0; int frameskip = 1; lua_Debug frame; if(session.report_color) printf("\033[01;31m%s\033[00m\n", lua_tostring(L,-1)); else printf("%s\n", lua_tostring(L,-1)); if(session.lua_backtrace) { printf("backtrace:\n"); while(lua_getstack(L, depth, &frame) == 1) { depth++; lua_getinfo(L, "nlSf", &frame); /* check for functions that just report errors. these frames just confuses more then they help */ if(frameskip && strcmp(frame.short_src, "[C]") == 0 && frame.currentline == -1) continue; frameskip = 0; /* print stack frame */ printf(" %s(%d): %s %s\n", frame.short_src, frame.currentline, frame.name, frame.namewhat); /* print all local variables for the frame */ if(session.lua_locals) { int i; const char *name = 0; i = 1; while((name = lua_getlocal(L, &frame, i)) != NULL) { printf(" %s = ", name); debug_print_lua_value(L,-1); printf("\n"); lua_pop(L,1); i++; } i = 1; while((name = lua_getupvalue(L, -1, i)) != NULL) { printf(" upvalue #%d: %s ", i-1, name); debug_print_lua_value(L, -1); lua_pop(L,1); i++; } } } } return 1; }
static int is_composed( lua_State* L, int i ) { int r = 0; if( lua_tocfunction( L, i ) == composed && lua_getupvalue( L, i, 1 ) ) { r = lua_tointeger( L, -1 ); lua_pop( L, 1 ); } return r; }
/** * @brief Copies the function on the top of src to the top of dst. * * It can be a Lua function or a C function. * * @param src source state * @param dst destination state */ static void sglua_copy_function(lua_State* src, lua_State* dst) { if (lua_iscfunction(src, -1)) { /* it's a C function */ XBT_DEBUG("It's a C function"); sglua_stack_dump("src before copying upvalues: ", src); /* get the function pointer */ int function_index = lua_gettop(src); lua_CFunction f = lua_tocfunction(src, function_index); /* copy the upvalues */ int i = 0; const char* upvalue_name = NULL; do { i++; upvalue_name = lua_getupvalue(src, function_index, i); if (upvalue_name != NULL) { XBT_DEBUG("Upvalue %s", upvalue_name); sglua_move_value(src, dst); } } while (upvalue_name != NULL); sglua_stack_dump("src before copying pointer: ", src); /* set the function */ lua_pushcclosure(dst, f, i - 1); XBT_DEBUG("Function pointer copied"); } else { /* it's a Lua function: dump it from src */ s_sglua_buffer_t buffer; buffer.capacity = 128; /* an empty function uses 77 bytes */ buffer.size = 0; buffer.data = xbt_new(char, buffer.capacity); /* copy the binary chunk from src into a buffer */ _XBT_GNUC_UNUSED int error = lua_dump(src, sglua_memory_writer, &buffer); xbt_assert(!error, "Failed to dump the function from the source state: error %d", error); XBT_DEBUG("Fonction dumped: %zu bytes", buffer.size); /* fwrite(buffer.data, buffer.size, buffer.size, stderr); fprintf(stderr, "\n"); */ /* load the chunk into dst */ error = luaL_loadbuffer(dst, buffer.data, buffer.size, "(dumped function)"); xbt_assert(!error, "Failed to load the function into the destination state: %s", lua_tostring(dst, -1)); } }
/* ** get (if 'get' is true) or set an upvalue from a closure */ static int auxupvalue (lua_State *L, int get) { const char *name; int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); /* no-op if get is false */ return get + 1; }
static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); return get + 1; }
void lua_compat_module_init(lua_State *L){ lua_getglobal(L, "require"); lua_getupvalue(L, -1, 1); lua_pushcclosure(L, ll_module, 1); lua_setglobal(L, "module"); lua_getglobal(L, "package"); lua_pushcfunction(L, ll_seeall); lua_setfield(L, -2, "seeall"); lua_pop(L, 2); }
static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); return get + 1; }
/* copies upvalues between lua states' stacks */ static int luaproc_copyupvalues( lua_State *Lfrom, lua_State *Lto, int funcindex ) { int i = 1; const char *str; size_t len; /* test the type of each upvalue and, if it's supported, copy it */ while ( lua_getupvalue( Lfrom, funcindex, i ) != NULL ) { switch ( lua_type( Lfrom, -1 )) { case LUA_TBOOLEAN: lua_pushboolean( Lto, lua_toboolean( Lfrom, -1 )); break; case LUA_TNUMBER: copynumber( Lto, Lfrom, -1 ); break; case LUA_TSTRING: { str = lua_tolstring( Lfrom, -1, &len ); lua_pushlstring( Lto, str, len ); break; } case LUA_TNIL: lua_pushnil( Lto ); break; /* if upvalue is a table, check whether it is the global environment (_ENV) from the source state Lfrom. in case so, push in the stack of the destination state Lto its own global environment to be set as the corresponding upvalue; otherwise, treat it as a regular non-supported upvalue type. */ case LUA_TTABLE: lua_pushglobaltable( Lfrom ); if ( isequal( Lfrom, -1, -2 )) { lua_pop( Lfrom, 1 ); lua_pushglobaltable( Lto ); break; } lua_pop( Lfrom, 1 ); /* FALLTHROUGH */ default: /* value type not supported: table, function, userdata, etc. */ lua_pushnil( Lfrom ); lua_pushfstring( Lfrom, "failed to copy upvalue of unsupported type " "'%s'", luaL_typename( Lfrom, -2 )); return FALSE; } lua_pop( Lfrom, 1 ); if ( lua_setupvalue( Lto, 1, i ) == NULL ) { lua_pushnil( Lfrom ); lua_pushstring( Lfrom, "failed to set upvalue" ); return FALSE; } i++; } return TRUE; }
static int Lcallback(lua_State *L) { ls_EventSlot *slot = checkslot(L, 1); lua_settop(L, 2); lua_pushvalue(L, 1); setcbinfo(L, slot, 4); lua_getupvalue(L, -1, UV_SELF); if (!lua_isnone(L, 2)) { lua_pushvalue(L, 2); lua_setupvalue(L, -3, UV_CB); } return 1; }
static void recurryf( lua_State* L, int n ) { int req, rec, gaps, i, m; int idx = lua_gettop( L ); luaL_checkstack( L, 4, "curry" ); lua_getupvalue( L, idx, 1 ); lua_getupvalue( L, idx, 2 ); lua_getupvalue( L, idx, 3 ); lua_getupvalue( L, idx, 4 ); req = lua_tointeger( L, -4 ); rec = lua_tointeger( L, -2 ); gaps = lua_tointeger( L, -1 ); m = gaps + ((req > rec) ? req - rec : 0); if( n > m ) { luaL_checkstack( L, rec+1, "curry" ); lua_pushinteger( L, rec-gaps+n ); lua_replace( L, -5 ); for( i = 5; i <= rec+4; ++i ) lua_getupvalue( L, idx, i ); lua_pushcclosure( L, curried, rec+4 ); lua_replace( L, idx ); } else lua_pop( L, 4 ); }
static int debug_getupvalue(lua_State *L, int get) { int32_t n = lj_lib_checkint(L, 2); if (isluafunc(lj_lib_checkfunc(L, 1))) { const char *name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name) { lua_pushstring(L, name); if (!get) return 1; copyTV(L, L->top, L->top-2); L->top++; return 2; } } return 0; }
/** * A function should be used as a function pointer. If this is a C closure * to a library function, we can use that library function's address directly. * This avoids a C closure for a Lua closure, the invocation of which would * look like this: FFI closure -> closure_handler -> lg_call_wrapper -> library * function. * * @return 1 on success, i.e. ar->arg->p has been set to the C function, or 0 * otherwise. */ int lg_use_c_closure(struct argconv_t *ar) { lua_State *L = ar->L; lua_CFunction func = lua_tocfunction(L, ar->index); if (!func || func != &lg_call_wrapper) return 0; // the first upvalue of this closure is a struct fi if (lua_getupvalue(L, ar->index, 1)) { struct func_info *fi = (struct func_info*) lua_touserdata(L, -1); ar->arg->p = fi->func; lua_pop(L, 1); return 1; } return 0; }
bool CMLuaScript::GetScriptEnviroment(lua_State *L) { lua_Debug ar; if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || lua_iscfunction(L, -1)) { lua_pop(L, 1); return false; } const char *env = lua_getupvalue(L, -1, 1); if (!env || mir_strcmp(env, "_ENV") != 0) { lua_pop(L, 1); return false; } return true; }
int luaT_setfenv52(lua_State *L, int iIndex) { int iType = lua_type(L, iIndex); switch(iType) { case LUA_TUSERDATA: lua_setuservalue(L, iIndex); return 1; case LUA_TFUNCTION: if(lua_iscfunction(L, iIndex)) { // Our convention: upvalue at #1 is environment if(lua_setupvalue(L, iIndex, 1) == nullptr) { lua_pop(L, 1); return 0; } return 1; } else { // Language convention: upvalue called _ENV is environment, which // might be shared with other functions. const char* sUpName = nullptr; for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i) { lua_pop(L, 1); // lua_getupvalue puts the value on the stack, but we just want to replace it if(std::strcmp(sUpName, "_ENV") == 0) { luaL_loadstring(L, "local upv = ... return function() return upv end"); lua_insert(L, -2); lua_call(L, 1, 1); lua_upvaluejoin(L, iIndex, i, -1, 1); lua_pop(L, 1); return 1; } } lua_pop(L, 1); return 0; } default: return 0; } }
int find_upvalues(lua_State *L, lua_Debug *ar, const char *var_name) { printf("find upvalus\n"); lua_getinfo(L, "uf", ar); if(lua_isfunction(L, -1) == 0) { printf("not is a function"); return 0; } int i; const char *upname; for(i=1; i<=ar->nups; i++) { upname = lua_getupvalue(L, -1, i); if(upname != NULL && strcmp(upname, var_name) == 0) { return 1; } lua_pop(L, 1); } lua_pop(L, 1); return 0; }
static char * luasandbox_timer_get_cfunction_name(lua_State *L) { static char buffer[1024]; TSRMLS_FETCH(); lua_CFunction f = lua_tocfunction(L, -1); if (!f) { return NULL; } if (f != luasandbox_call_php) { return NULL; } lua_getupvalue(L, -1, 1); #if PHP_VERSION_ID < 70000 zval ** callback_pp = (zval**)lua_touserdata(L, -1); if (!callback_pp || !*callback_pp) { return NULL; } char * callback_name; zend_bool ok = zend_is_callable(*callback_pp, IS_CALLABLE_CHECK_SILENT, &callback_name TSRMLS_CC); #else zval * callback_p = (zval*)lua_touserdata(L, -1); if (!callback_p) { return NULL; } zend_string * callback_name; zend_bool ok = zend_is_callable(callback_p, IS_CALLABLE_CHECK_SILENT, &callback_name); #endif if (ok) { snprintf(buffer, sizeof(buffer), "%s", #if PHP_VERSION_ID < 70000 callback_name #else ZSTR_VAL(callback_name) #endif ); return buffer; } else { return NULL; } }
static void magnet_setfenv_mainfn(lua_State *L, int funcIndex) { /* (-1, 0, -) */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 /* set "_ENV" upvalue, which should be the first upvalue of a "main" lua * function if it uses any global names */ const char* first_upvalue_name = lua_getupvalue(L, funcIndex, 1); if (NULL == first_upvalue_name) return; /* doesn't have any upvalues */ lua_pop(L, 1); /* only need the name of the upvalue, not the value */ if (0 != strcmp(first_upvalue_name, "_ENV")) return; if (NULL == lua_setupvalue(L, funcIndex, 1)) { /* pop value if lua_setupvalue didn't set the (not existing) upvalue */ lua_pop(L, 1); } #else lua_setfenv(L, funcIndex); #endif }
/** * The specified Lua value might contain a closure created with the function * above, or contain a . If so, return the func_info embedded in it, otherwise raise an * error. */ struct func_info *lg_get_closure(lua_State *L, int index) { lua_CFunction f; struct func_info *fi; // verify that this is actually a closure with the correct C function. f = lua_tocfunction(L, index); if (!f) LG_ERROR(2, "Not a C function, but a %s.", lua_typename(L, lua_type(L, index))); if (f != &lg_call_wrapper) LG_ERROR(3, "Invalid closure."); // the first upvalue is the func_info structure. lua_getupvalue(L, index, 1); fi = (struct func_info*) lua_touserdata(L, -1); if (!fi) LG_ERROR(4, "Invalid closure (upvalue 1 not a userdata)"); return fi; }
//***************************************************************************** int LuaBindings::GetUpValue(LuaStack stack) { DebugContext * pDebugContext = GetContextIfPaused(stack); if (pDebugContext != NULL) { int funcindex = lua_tointeger(stack, 2); int uvindex = lua_tointeger(stack, 3); int nlevels = lua_tointeger(stack, 4); int frame = lua_tointeger(stack, 5); lua_Debug debug; LuaDebug pFrameDebug = pDebugContext->GetDebug(); if (frame > 0) { pFrameDebug = &debug; lua_getstack(pDebugContext->pStack, frame, pFrameDebug); } const char *varname = lua_getupvalue(pDebugContext->pStack, funcindex, uvindex); if (varname == NULL) { lua_pushinteger(stack, -1); lua_pushstring(stack, "Invalid variable index."); } else { // output code - 0 => success lua_pushinteger(stack, 0); // upvalue value LuaUtils::TransferValueToStack(pDebugContext->pStack, stack, -1, nlevels, varname); // pop the value of the upvalue // of the stack being debugged!! lua_pop(pDebugContext->pStack, 1); } } return 2; }
int capture_env(struct lua_State *L, int frame) { int i; const char *local; lua_Debug ar; LUA_STACK_MARK(L); if (!lua_getstack(L, frame, &ar)) { return -1; } lua_getinfo(L, "f", &ar); lua_newtable(L); for (i=1; (local = lua_getlocal(L, &ar, i)); ++i) { lua_setfield(L, -2, local); } for (i=1; (local = lua_getupvalue(L, -2, i)); ++i) { lua_setfield(L, -2, local); } lua_newtable(L); lua_getfenv(L, -3); lua_setfield(L, -2, "__index"); lua_getfenv(L, -3); lua_setfield(L, -2, "__newindex"); lua_setmetatable(L, -2); lua_remove(L, -2); LUA_STACK_CHECK(L, 1); return lua_gettop(L); }
/*** Install a signal handler for this signal number. Although this is the same API as signal(2), it uses sigaction for guaranteed semantics. @function signal @see signal.lua @int signum @tparam[opt=SIG_DFL] function handler function, or `SIG_IGN` or `SIG_DFL` constants @param[opt] flags the `sa_flags` element of `struct sigaction` @treturn function previous handler function @see sigaction(2) */ static int Psignal (lua_State *L) { struct sigaction sa, oldsa; int sig = checkint(L, 1), ret; void (*handler)(int) = sig_postpone; checknargs(L, 3); /* Check handler is OK */ switch (lua_type(L, 2)) { case LUA_TNIL: case LUA_TSTRING: handler = Fsigmacros[luaL_checkoption(L, 2, "SIG_DFL", Ssigmacros)]; break; case LUA_TFUNCTION: if (lua_tocfunction(L, 2) == sig_handler_wrap) { lua_getupvalue(L, 2, 1); handler = lua_touserdata(L, -1); lua_pop(L, 1); } break; default: argtypeerror(L, 2, "function, string or nil"); break; } /* Set up C signal handler, getting old handler */ sa.sa_handler = handler; sa.sa_flags = optint(L, 3, 0); sigfillset(&sa.sa_mask); ret = sigaction(sig, &sa, &oldsa); if (ret == -1) return 0; /* Set Lua handler if necessary */ if (handler == sig_postpone) { lua_pushlightuserdata(L, &signalL); /* We could use an upvalue, but we need this for sig_handle anyway. */ lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_rawset(L, -3); lua_pop(L, 1); } /* Push old handler as result */ if (oldsa.sa_handler == sig_postpone) { lua_pushlightuserdata(L, &signalL); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, 1); lua_rawget(L, -2); } else if (oldsa.sa_handler == SIG_DFL) lua_pushstring(L, "SIG_DFL"); else if (oldsa.sa_handler == SIG_IGN) lua_pushstring(L, "SIG_IGN"); else { lua_pushinteger(L, sig); lua_pushlightuserdata(L, oldsa.sa_handler); lua_pushcclosure(L, sig_handler_wrap, 2); } return 1; }
static void pack_value(lua_State *L, mar_Buffer *buf, int val, int *idx) { size_t l; int val_type = lua_type(L, val); buf_write(L, (void*)&val_type, MAR_CHR, buf); switch (val_type) { case LUA_TBOOLEAN: { int int_val = lua_toboolean(L, val); buf_write(L, (void*)&int_val, MAR_CHR, buf); break; } case LUA_TSTRING: { const char *str_val = lua_tolstring(L, val, &l); buf_write(L, (void*)&l, MAR_I32, buf); buf_write(L, str_val, l, buf); break; } case LUA_TNUMBER: { lua_Number num_val = lua_tonumber(L, val); buf_write(L, (void*)&num_val, MAR_I64, buf); break; } case LUA_TTABLE: { int tag, ref; lua_pushvalue(L, val); lua_rawget(L, 2); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); if (luaL_getmetafield(L, val, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, val-1); lua_pushinteger(L, (*idx)++); lua_rawset(L, 2); lua_pushvalue(L, val-1); lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_newtable(L); lua_pushvalue(L, -2); lua_rawseti(L, -2, 1); lua_remove(L, -2); buf_init(L, &rec_buf); mar_pack(L, &rec_buf, idx); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } else { tag = MAR_TVAL; lua_pushvalue(L, val); lua_pushinteger(L, (*idx)++); lua_rawset(L, 2); lua_pushvalue(L, val); buf_init(L, &rec_buf); mar_pack(L, &rec_buf, idx); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data,rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } } break; } case LUA_TFUNCTION: { int tag, ref; lua_pushvalue(L, val); lua_rawget(L, 2); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; int i; lua_Debug ar; lua_pop(L, 1); tag = MAR_TVAL; lua_pushvalue(L, val); lua_pushinteger(L, (*idx)++); lua_rawset(L, 2); lua_pushvalue(L, val); buf_init(L, &rec_buf); lua_dump(L, (lua_Writer)buf_write, &rec_buf); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); lua_pushvalue(L, val); lua_getinfo(L, ">uS", &ar); if (ar.what[0] != 'L') { luaL_error(L, "attempt to persist a C function"); } lua_newtable(L); for (i=1; i <= ar.nups; i++) { lua_getupvalue(L, -2, i); lua_rawseti(L, -2, i); } buf_init(L, &rec_buf); mar_pack(L, &rec_buf, idx); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } break; } case LUA_TUSERDATA: { int tag, ref; lua_pushvalue(L, val); lua_rawget(L, 2); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); if (luaL_getmetafield(L, val, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, val-1); lua_pushinteger(L, (*idx)++); lua_rawset(L, 2); lua_pushvalue(L, val-1); lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_newtable(L); lua_pushvalue(L, -2); lua_rawseti(L, -2, 1); lua_remove(L, -2); buf_init(L, &rec_buf); mar_pack(L, &rec_buf, idx); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } else { tag = MAR_TVAL; buf_write(L, (void*)&tag, MAR_CHR, buf); } } break; } case LUA_TTHREAD: break; /* just give them a nil during unpack */ default: luaL_error(L, "invalid value type"); } }
static inline int _cloneNoTable(lua_State *L, const int idx, lua_State *L_, const int r_lv ) { int ret_= 1; switch(lua_type(L, idx ) ) { case LUA_TSTRING: { size_t l; const char *s= lua_tolstring(L, idx, &l ); lua_pushlstring(L_, s, l ); } break; case LUA_TNUMBER: lua_pushnumber(L_, lua_tonumber(L, idx ) ); break; case LUA_TLIGHTUSERDATA: lua_pushlightuserdata(L_, lua_touserdata(L, idx ) ); break; case LUA_TBOOLEAN: lua_pushboolean(L_, lua_toboolean(L, idx ) ); break; case LUA_TUSERDATA: { // userdata 的 meta 暂时不能拷贝 const size_t l= lua_objlen(L, idx ); memmove(lua_newuserdata(L_, l ), lua_touserdata(L, idx ), l ); if(0) //屏蔽 meta 处理 if(lua_getmetatable(L, idx ) ) { const int k= _cloneRecursion(L, lua_gettop(L ), L_, ((0<= r_lv )? r_lv: -1 ) ); lua_pop(L, 1 ); if((0<= r_lv )&& lua_istable(L_, -1 )&& (0< k ) ) printf("%*.s__{%3d}\n", (r_lv- 1 )* 2, "", k ); lua_setmetatable(L_, -2 ); } } break; case LUA_TFUNCTION: if(lua_iscfunction(L, idx ) ) { int j= 1; lua_CFunction f= lua_tocfunction(L, idx ); for(j= 1; UPVALUE_MAX>= j; ++j ) { //设置函数的 upvalue if(!lua_getupvalue(L, idx, j ) ) break; _cloneRecursion(L, lua_gettop(L ), L_, ((0<= r_lv )? (r_lv+ 1 ): -1 ) ); lua_pop(L, 1 ); } lua_pushcclosure(L_, f, j- 1 ); } else { int j= 1; DUMP_CB ud; memset(&ud, 0, sizeof(ud ) ); lua_pushvalue(L, idx ); lua_dump(L, writer_CB, &ud ); if(ud.p ) { //载入函数到新的栈 lua_load(L_, reader_CB, &ud, (char * )0 ); free(ud.p ); } lua_pop(L, 1 ); for(j= 1; UPVALUE_MAX>= j; ++j ) { //设置函数的 upvalue if(!lua_getupvalue(L, idx, j ) ) break; printf("upvalue %d\n", j ); _cloneRecursion(L, lua_gettop(L ), L_, ((0<= r_lv )? (r_lv+ 1 ): -1 ) ); lua_pop(L, 1 ); lua_setupvalue(L_, -2, j ); } } break; case LUA_TNIL: lua_pushnil(L_ ); break; case LUA_TNONE: case LUA_TTHREAD: //? default: ret_= 0; break; } return ret_; }
const char * LuaDebug::GetUpvalue(int funcindex, int n) const { return lua_getupvalue(L(), funcindex, n); }
static void mar_encode_value(lua_State *L, mar_Buffer *buf, int val, size_t *idx, int nowrap) { size_t l; int val_type = lua_type(L, val); lua_pushvalue(L, val); buf_write(L, (void*)&val_type, MAR_CHR, buf); switch (val_type) { case LUA_TBOOLEAN: { int int_val = lua_toboolean(L, -1); buf_write(L, (void*)&int_val, MAR_CHR, buf); break; } case LUA_TSTRING: { const char *str_val = lua_tolstring(L, -1, &l); buf_write(L, (void*)&l, MAR_I32, buf); buf_write(L, str_val, l, buf); break; } case LUA_TNUMBER: { lua_Number num_val = lua_tonumber(L, -1); buf_write(L, (void*)&num_val, MAR_I64, buf); break; } case LUA_TLIGHTUSERDATA: { if(nowrap) luaL_error(L, "light userdata not permitted"); void * ptr_val = lua_touserdata(L, -1); long long v = (long long)ptr_val; buf_write(L, (char*)&v, MAR_I64, buf); break; } case LUA_TTABLE: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); /* pop nil */ if (luaL_getmetafield(L, -1, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, -2); /* self */ lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_remove(L, -2); /* __persist */ lua_newtable(L); lua_pushvalue(L, -2); /* callback */ lua_rawseti(L, -2, 1); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx, nowrap); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } else { tag = MAR_TVAL; lua_pushvalue(L, -1); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -1); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx, nowrap); lua_pop(L, 1); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data,rec_buf.head, buf); buf_done(L, &rec_buf); } } break; } case LUA_TFUNCTION: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; int i; lua_Debug ar; lua_pop(L, 1); /* pop nil */ lua_pushvalue(L, -1); lua_getinfo(L, ">nuS", &ar); //printf("Function name='%s' type='%s' nups=%d\n",ar.namewhat,ar.what,ar.nups); if (ar.what[0] != 'L') { luaL_error(L, "attempt to persist a C function '%s'", ar.name); } tag = MAR_TVAL; lua_pushvalue(L, -1); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -1); buf_init(L, &rec_buf); lua_dump(L, (lua_Writer)buf_write, &rec_buf); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); lua_newtable(L); for (i=1; i <= ar.nups; i++) { #if LUA_VERSION_NUM > 501 const char * str=lua_getupvalue(L, -2, i); if(!strncmp(str,"_ENV",4)) { //printf("Stripping _ENV\n"); lua_pop(L,1); lua_pushliteral(L,LEDA_ENV_MARKER); } #else lua_getupvalue(L, -2, i); #endif lua_rawseti(L, -2, i); } buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx, nowrap); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } break; } case LUA_TUSERDATA: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); /* pop nil */ if (!nowrap && luaL_getmetafield(L, -1, "__wrap")) { tag = MAR_TUSR; lua_pushvalue(L, -2); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -2); lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__wrap must return a function"); } lua_newtable(L); lua_pushvalue(L, -2); lua_rawseti(L, -2, 1); lua_remove(L, -2); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx, nowrap); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); } else if (luaL_getmetafield(L, -1, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, -2); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -2); lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_newtable(L); lua_pushvalue(L, -2); lua_rawseti(L, -2, 1); lua_remove(L, -2); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx, nowrap); buf_write(L, (void*)&tag, MAR_CHR, buf); buf_write(L, (void*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); } else { luaL_error(L, "attempt to encode userdata (no __wrap hook - or not permited - and no __persist hook)"); } lua_pop(L, 1); } break; } case LUA_TNIL: break; default: luaL_error(L, "invalid value type (%s)", lua_typename(L, val_type)); } lua_pop(L, 1); }
int writeObjectRaw() { lua_State *L = m_L; uint8_t iType; // Save the index to the cache lua_pushvalue(L, 2); lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); lua_settable(L, 1); // Lookup the object in the permanents table lua_pushvalue(L, 2); lua_gettable(L, luaT_upvalueindex(1)); if(lua_type(L, -1) != LUA_TNIL) { // Object is in the permanents table. uint8_t iType = PERSIST_TPERMANENT; writeByteStream(&iType, 1); // Replace self's environment with self (for call to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write the key corresponding to the permanent object writeStackObject(-1); } else { // Object is not in the permanents table. lua_pop(L, 1); switch(lua_type(L, 2)) { // LUA_TNIL handled in writeStackObject // LUA_TBOOLEAN handled in writeStackObject // LUA_TNUMBER handled in writeStackObject case LUA_TSTRING: { iType = LUA_TSTRING; writeByteStream(&iType, 1); // Strings are simple: length and then bytes (not null terminated) size_t iLength; const char *sString = lua_tolstring(L, 2, &iLength); writeVUInt(iLength); writeByteStream(reinterpret_cast<const uint8_t*>(sString), iLength); break; } case LUA_TTABLE: { // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Save env and insert prior to table lua_getfenv(L, 1); lua_insert(L, 2); int iTable = 3; table_reentry: // Handle the metatable if(lua_getmetatable(L, iTable)) { iType = PERSIST_TTABLE_WITH_META; writeByteStream(&iType, 1); writeStackObject(-1); lua_pop(L, 1); } else { iType = LUA_TTABLE; writeByteStream(&iType, 1); } // Write the children as key, value pairs lua_pushnil(L); while(lua_next(L, iTable)) { writeStackObject(-2); // The naive thing to do now would be writeStackObject(-1) // but this can easily lead to Lua's C call stack limit // being hit. To reduce the likelyhood of this happening, // we check to see if about to write another table. if(lua_type(L, -1) == LUA_TTABLE) { lua_pushvalue(L, -1); lua_rawget(L, 2); lua_pushvalue(L, -2); lua_gettable(L, luaT_upvalueindex(1)); if(lua_isnil(L, -1) && lua_isnil(L, -2)) { lua_pop(L, 2); lua_checkstack(L, 10); iTable += 2; lua_pushvalue(L, iTable); lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); lua_settable(L, 2); goto table_reentry; table_resume: iTable -= 2; } else { lua_pop(L, 2); writeStackObject(-1); } } else writeStackObject(-1); lua_pop(L, 1); } // Write a nil to mark the end of the children (as nil is the // only value which cannot be used as a key in a table). iType = LUA_TNIL; writeByteStream(&iType, 1); if(iTable != 3) goto table_resume; break; } case LUA_TFUNCTION: if(lua_iscfunction(L, 2)) { setErrorObject(2); setError("Cannot persist C functions"); } else { iType = LUA_TFUNCTION; writeByteStream(&iType, 1); // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write the prototype (the part of a function which is common across // multiple closures - see LClosure / Proto in Lua's lobject.h). lua_Debug proto_info; lua_pushvalue(L, 2); lua_getinfo(L, ">Su", &proto_info); writePrototype(&proto_info, 2); // Write the values of the upvalues // If available, also write the upvalue IDs (so that in // the future, we could hypothetically rejoin shared // upvalues). An ID is just an opaque sequence of bytes. writeVUInt(proto_info.nups); #if LUA_VERSION_NUM >= 502 writeVUInt(sizeof(void*)); #else writeVUInt(0); #endif for(int i = 1; i <= proto_info.nups; ++i) { lua_getupvalue(L, 2, i); writeStackObject(-1); #if LUA_VERSION_NUM >= 502 void *pUpvalueID = lua_upvalueid(L, 2, i); writeByteStream((uint8_t*)&pUpvalueID, sizeof(void*)); #endif } // Write the environment table lua_getfenv(L, 2); writeStackObject(-1); lua_pop(L, 1); } break; case LUA_TUSERDATA: if(!_checkThatUserdataCanBeDepersisted(2)) break; // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write type, metatable, and then environment iType = LUA_TUSERDATA; writeByteStream(&iType, 1); writeStackObject(-1); lua_getfenv(L, 2); writeStackObject(-1); lua_pop(L, 1); // Write the raw data if(lua_type(L, -1) == LUA_TTABLE) { lua_getfield(L, -1, "__persist"); if(lua_isnil(L, -1)) lua_pop(L, 1); else { lua_pushvalue(L, 2); lua_pushvalue(L, luaT_upvalueindex(2)); lua_call(L, 2, 0); } } writeVUInt((uint64_t)0x42); // sync marker break; default: setError(lua_pushfstring(L, "Cannot persist %s values", luaL_typename(L, 2))); break; } } lua_pushnumber(L, 0); return 1; }
//----------------------------------------------------------------// void MOAIHarness::ReceiveVariableGet(lua_State *L, json_t* node) { // Get the keys to traverse to the target variable json_t* np_keys = json_object_get(node, "Keys"); if (np_keys == NULL || json_typeof(np_keys) != JSON_ARRAY) return; // Check to see if we were actually provided keys size_t keyCount = json_array_size(np_keys); if (keyCount == 0) return; // Get the root key name (which has to be a string) json_t* np_root_key = json_array_get(np_keys, 0); if (json_typeof(np_root_key) != JSON_STRING) return; std::string root(json_string_value(np_root_key)); // Get the stack level to look for loval variables at json_t* np_stack_level = json_object_get(node, "Level"); if (np_stack_level == NULL || json_typeof(np_stack_level) != JSON_INTEGER) return; json_int_t level = json_integer_value(np_stack_level); // Check for the root name in the local namespace bool found = false; lua_Debug ar; if (lua_getstack(L, (int)level, &ar)) { // Look for a local variable match const char* localName; for (int local = 1; (localName = lua_getlocal(L, &ar, local)) != 0; ++local) { if (root == localName) { found = true; break; } lua_pop(L, 1); } if (!found) { // Push the function onto the stack lua_getinfo(L, "f", &ar); // Look for an upvalue match const char* upvalueName; for (int upvalue = 1; (upvalueName = lua_getupvalue(L, -1, upvalue)) != 0; ++upvalue) { if (root == upvalueName) { found = true; break; } lua_pop(L, 1); } // Pop the function off the stack lua_remove(L, found ? -2 : -1); } } // Check for the root name in the global namespace if (!found) { lua_getglobal(L, root.c_str()); } // Traverse through our child keys for (size_t childIndex = 1; !lua_isnil(L, -1) && childIndex < keyCount; ++childIndex) { json_t* np_key = json_array_get(np_keys, childIndex); bool valid = true; // First check for complex type keys if (json_typeof(np_key) == JSON_OBJECT) { // Check for the correct datapair encoding for keys json_t* anticonflict = json_object_get(np_key, JSON_DATAPAIR_ANTICONFLICT_KEY); json_t* np_type = json_object_get(np_key, JSON_DATAPAIR_NAME_KEY); json_t* np_data = json_object_get(np_key, JSON_DATAPAIR_DATA_KEY); bool isDatapair = anticonflict && json_typeof(anticonflict) == JSON_STRING && strcmp(json_string_value(anticonflict), JSON_DATAPAIR_ANTICONFLICT_VALUE) == 0 && np_type && json_typeof(np_type) == JSON_STRING && np_data && json_typeof(np_data) == JSON_INTEGER; if (isDatapair && lua_istable(L, -1)) { // Iterate through the keys of the table, looking for complex // types with the same type and address const char* keyType = json_string_value(np_type); json_int_t keyPtr = json_integer_value(np_data); bool keyFound = false; lua_pushnil(L); while (lua_next(L, -2) != 0) { // If this key is a complex type, compare its // type and address if (const void* ptr = lua_topointer(L, -2)) { int type = lua_type(L, -2); if ((int)ptr == (int)keyPtr && strcmp(keyType, lua_typename(L, type)) == 0) { // Pop the table and key off the stack, leaving the value lua_remove(L, -2); lua_remove(L, -2); keyFound = true; break; } } lua_pop(L, 1); } if (keyFound) { continue; } } valid = false; } // Push the key onto the stack switch (json_typeof(np_key)) { case JSON_STRING: lua_pushstring(L, json_string_value(np_key)); break; case JSON_INTEGER: lua_pushinteger(L, (lua_Integer)json_integer_value(np_key)); break; case JSON_REAL: lua_pushnumber(L, (lua_Number)json_real_value(np_key)); break; case JSON_TRUE: case JSON_FALSE: lua_pushboolean(L, json_typeof(np_key) == JSON_TRUE); break; default: valid = false; break; } // If we don't have a valid key, just pop the table off the // stack and return a nil value if (!valid) { lua_pop(L, 1); lua_pushnil(L); } // Otherwise, call a function to get the table value else { lua_pushcfunction(L, MOAIHarness::VariableGetCallback); lua_insert(L, -3); // If an error occurred getting the value, just push nil if (lua_pcall(L, 2, 1, 0)) { lua_pushnil(L); } } } // Convert the result to a json object json_t* result = MOAIHarness::ConvertStackIndexToJSON(L, -1, true); lua_pop(L, 1); // Return the result to the caller SendVariableGetResult(np_keys, result); json_decref(result); }
void writePrototype(lua_Debug *pProtoInfo, int iInstanceIndex) { lua_State *L = m_L; // Sanity checks if(pProtoInfo->source[0] != '@') { // @ denotes that the source was a file // (http://www.lua.org/manual/5.1/manual.html#lua_Debug) setError("Can only persist Lua functions defined in source files"); return; } if(strcmp(pProtoInfo->what, "Lua") != 0) { // what == "C" should have been caught by writeObjectRaw(). // what == "tail" should be impossible. // Hence "Lua" and "main" should be the only values seen. // NB: Chunks are not functions defined *in* source files, because // chunks *are* source files. setError(lua_pushfstring(L, "Cannot persist entire Lua chunks (%s)", pProtoInfo->source + 1)); lua_pop(L, 1); return; } // Attempt cached lookup (prototypes are not publicly visible Lua objects, // and hence cannot be cached in the normal way of self's environment). lua_getmetatable(L, 1); lua_pushfstring(L, "%s:%d", pProtoInfo->source + 1, pProtoInfo->linedefined); lua_pushvalue(L, -1); lua_rawget(L, -3); if(!lua_isnil(L, -1)) { uint64_t iValue = (uint64_t)lua_tonumber(L, -1); lua_pop(L, 3); writeVUInt(iValue + PERSIST_TCOUNT - 1); return; } lua_pop(L, 1); lua_pushvalue(L, -1); lua_pushnumber(L, (lua_Number)m_iNextIndex++); lua_rawset(L, -4); uint8_t iType = PERSIST_TPROTOTYPE; writeByteStream(&iType, 1); // Write upvalue names writeVUInt(pProtoInfo->nups); for(int i = 1; i <= pProtoInfo->nups; ++i) { lua_pushstring(L, lua_getupvalue(L, iInstanceIndex, i)); writeStackObject(-1); lua_pop(L, 2); } // Write the function's persist name lua_rawgeti(L, -2, 1); lua_replace(L, -3); lua_rawget(L, -2); if(lua_isnil(L, -1)) { setError(lua_pushfstring(L, "Lua functions must be given a unique " "persistable name in order to be persisted (attempt to persist" " %s:%d)", pProtoInfo->source + 1, pProtoInfo->linedefined)); lua_pop(L, 2); return; } writeStackObject(-1); lua_pop(L, 2); }