lua-users home
lua-l archive

Re: Install __newindex for _G in C

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Flyer31 Test once stated:
> Hi,
> I would like to install a metatable for global environment _G from C code.
> 
> http://lua-users.org/wiki/DetectingUndefinedVariables
> 
> gives a way to do this in Lua code (see the function GLOBAL_lock) on this page.
> 
> function GLOBAL_lock(t)
> local mt = getmetatable(t) or {}
> mt.__newindex = lock_new_index
> setmetatable(t, mt)
> end
> 
> I tried to use the following code in my C program:
> 
> void GLOBAL_lock (lua_State *L) {
> luaL_newmetatable( L, "_G"));
> lua_pushvalue(L, -1); /* duplicate the metatable */
> lua_setfield(L, -2, "__index");
> lua_pushcfunction( L, lock_new_index);
> lua_setfield( L, -2, "__newindex");
> luaL_setmetatable( L, "_G");
> }
> 
> This compiles fine, and if I check lua_gettop at end of this function,
> also all fine, also luaL_getmetatable will then return me some table
> for "_G"... . So it looks as if it has worked.
> 
> But my function lock_new_index (int lock_new_index( lua_State *L) {
> ... } ) is never invoked.
> 
> Can anybody give me some hint, what code in my C program might be
> wrong / missing to get this run?
 The solution you want is (assuming Lua 5.2 or higher here):
	static int foo___index (lua_State *L);
	static int foo___newindex(lua_State *L);
	static luaL_Reg const metatable[] =
	{
	 { "__index" , foo___index } ,
	 { "__newindex" , foo___newindex } ,
	 /* other metatable methods as required */
	 { NULL , NULL }
	};
	/*-----------------------------------------------------------------
	; Obtain the global table. We don't use "_G" as this is just a
	; convenience value and one I wouldn't fully rely upon. Following
	; the Lua manual, a reference to the global table is stored in the
	; registry. So we get it from there.
	;------------------------------------------------------------------*/
	lua_geti(L,LUA_REGISTRYINDEX,LUA_RIDX_GLOBALS); /* obtain _G */
	luaL_newlib(L,metatable);			/* create metatable */
	lua_setmetatable(L,-2);				/* and set it */
 The functions luaL_setmetatable() and lual_getmetatable() are really meant
to be used for userdata. The name parameter isn't the name of a global
variable, but instead a name indentifying that particular metatable. For
example, I create a new userdata type foo and associate a metatable for it:
	static int foo___index (lua_State *L);
	static int foo___newindex (lua_State *L);
	static int foo___len (lua_State *L);
	static luaL_Reg const foo_metatable[] =
	{
	 { "__index" , foo___index } ,
	 { "__newindex" , foo___newindex } ,
	 { "__len" , foo___len } ,
	 { NULL , NULL }
	};
	luaL_newmetatable(L,"TYPE_FOO");
	luaL_setfuncs(L,foo_metatable,0);
 Then, when a new foo is created:
	Foo *foo = luaL_newuserdata(L,sizeof(Foo));
	luaL_setmetatable(L,"TYPE_FOO");
 Alternatively (to remain compatible with Lua 5.1):
	Foo * foo = luaL_newuserdata(L,sizeof(Foo));
	luaL_getmetatable(L,"TYPE_FOO");
	lua_setmetatable(L,-2);
 -spc (Hope that clears it up some)

AltStyle によって変換されたページ (->オリジナル) /