This is probably an easy question, but I am stumped. This is for Lua 5.1.
I have a script which runs in its own environment. In that environment, I have a variable called "plugin" I set from C++ like so:
lua_getfield(L, LUA_REGISTRYINDEX, getScriptId()); // Put script's env table onto the stack -- env_table
lua_pushstring(L, "plugin"); // -- env_table, "plugin"
luaW_push(L, this); // -- env_table, "plugin", *this
lua_rawset(L, -3); // env_table["plugin"] = *this -- env_table
lua_pop(L, -1); // Cleanup -- <<empty stack>>
Before running my Lua script, I set the function environment like so:
lua_getfield(L, LUA_REGISTRYINDEX, getScriptId()); // Push REGISTRY[scriptId] onto stack -- function, table
lua_setfenv(L, -2); // Set that table to be the env for function -- function
When my script runs, it can see and interact with the plugin variable, as expected. So far, so good.
At one point, the Lua script calls a C++ function, and in that function, I want to see if the plugin variable is set.
I have tried many many things, and I can't seem to see the plugin variable. Here are but 4 things I tried:
lua_getfield(L, LUA_ENVIRONINDEX, "plugin");
bool isPlugin = !lua_isnil(L, -1);
lua_pop(L, 1); // Remove the value we just added from the stack
lua_getfield(L, LUA_GLOBALSINDEX, "plugin");
bool isPlugin2 = !lua_isnil(L, -1);
lua_pop(L, 1); // Remove the value we just added from the stack
lua_getglobal(L, "plugin");
bool isPlugin3 = !lua_isnil(L, -1);
lua_pop(L, 1); // Remove the value we just added from the stack
lua_pushstring(L, "plugin");
bool isPlugin4 = lua_isuserdata(L, -1);
lua_pop(L, 1);
Unfortunately, all the isPlugin variables return false. It is as if the C++ function called from Lua cannot see a variable set in a Lua environment.
Any idea how I can see the plugin variable from C++?
Thanks!
Every function in Lua has it's own environment. They don't inherit the environment of whomever calls them. So if your C++ function doesn't use the environment that has this plugin
variable, then it won't see it.
You could pass the environment to the C function as part of the closure (see lua_pushcclosure
). I don't know the kind of setup you have, but I can see three ways this can pan out:
1) Your C function is registered in the same environment as the function - good, will work.
2) Your C function is registered in the global environment but the Lua functions which will call it all reside in one specific environment - will still work if the environment exists when the function is registered (so it can be added to the closure).
3) Your C function is registered in the global environment and can be called by different Lua functions working in different environments - will not work anymore.
If it's 2 or 3, there might be no drawbacks if you change the implementation to use variant 1.
Edit: Alright, so that won't work. There is a way to obtain under-the-hood information if you are willing to stray a bit from the Lua API. DISCLAIMER: I am working with 5.2, so I am trying to adapt my methods for 5.1. I could not test this, and it might not work.
First you will need to #include "lstate.h"
This is the lua_State structure in 5.1:
struct lua_State {
CommonHeader;
lu_byte status;
StkId top; /* first free slot in the stack */
StkId base; /* base of current function */
global_State *l_G;
CallInfo *ci; /* call info for current function */
const Instruction *savedpc; /* `savedpc' of current function */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
CallInfo *end_ci; /* points after end of ci array*/
CallInfo *base_ci; /* array of CallInfo's */
int stacksize;
int size_ci; /* size of array `base_ci' */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
lu_byte allowhook;
int basehookcount;
int hookcount;
lua_Hook hook;
TValue l_gt; /* table of globals */
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
};
Let's assume L is your lua_State*
. As you can see, L->ci
holds the current callinfo, and the callinfo array is contained between L->base_ci
and L->end_ci
.
So the Lua function which called your C function is situated at (L->end_ci-2)
(which should be the same as (L->ci-1)
), and its stack id (StkId) is (L->end_ci-2)->func
. We can trick the Lua API into letting you work with stack ids which are below the current calling function by doing something like this:
StkId saved = L->base;
L->base = L->base_ci->base;
int idx = (L->end_ci-2)->func - L->base+1;
lua_getfenv(L, idx);
L->base = saved;
The environment table should be on top of the stack now.
Edit: The Lua API checks for a valid index are a bit tricky. This should fool them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.