Lua 5.2 LUA_GLOBALSINDEX Alternative - c

I have a program that embeds Lua and implements a form of lazy function lookup.
The way it worked in Lua 5.1, whenever a symbol was undefined the interpreter would call a global function hook that would then resolve the symbol.
This is a small portion of C code that implemented this lazy function lookup:
int function_hook(lua_State *pLuaState)
{
// do the function lookup here
....
return 1;
}
......
//-- create table containing the hook details
lua_newtable(pLuaState);
lua_pushstring(pLuaState, "__index");
lua_pushcfunction(pLuaState, function_hook);
lua_settable(pLuaState, -3);
//-- set global index callback hook
lua_setmetatable(pLuaState, LUA_GLOBALSINDEX);
I'm now trying to move this code to Lua 5.2 and have run into a problem.
In Lua 5.2 the LUA_GLOBALSINDEX value is no longer defined so this line of code no longer compiles.
//-- set global call back hook
lua_setmetatable(pLuaState, LUA_GLOBALSINDEX);
There is a reference to this change to LUA_GLOBALSINDEX but unfortunately it has not helped.
What would be the best way to re-write this one line of code to have the interpreter call the function_hook whenever it finds an unresolved symbol?

The global environment is now stored at a special index in the registry. Try:
//-- get global environment table from registry
lua_rawgeti(pLuaState, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
//-- create table containing the hook details
lua_newtable(pLuaState);
lua_pushstring(pLuaState, "__index");
lua_pushcfunction(pLuaState, function_hook);
lua_settable(pLuaState, -3);
//-- set global index callback hook
lua_setmetatable(pLuaState, -2);
//-- remove the global environment table from the stack
lua_pop(pLuaState, 1);

here is patch:
http://lua-users.org/lists/lua-l/2013-01/msg00352.html
lua_pushvalue(L,LUA_GLOBALSINDEX);
=>
lua_pushglobaltable(L);
len = luaL_getn(L, -1);
=>
len = lua_rawlen(L, -1);
lua_getfenv(L, lo);
=>
lua_getuservalue(L, lo);
lua_setfenv(L, lo);
=>
lua_setuservalue(L, lo);

Related

Fake Function Framework not working with STM32 HAL functions

I am using FFF - Fake Function Framework to stub out some calls in my unit tests. This is working fine in many instances. I can stub out any of the functions I have written myself, as well as any calls to FreeRTOS functions. When I call these functions from within a test, it is the Fake that is called. However, I cannot get it to work with the STM32 HAL functions - these function calls always call the real function.
I am defining fakes in the test source file, as follows:
FAKE_VALUE_FUNC(BaseType_t, xTaskCreate, TaskFunction_t, const char *, configSTACK_DEPTH_TYPE, void *, UBaseType_t, TaskHandle_t *);
FAKE_VALUE_FUNC(HAL_StatusTypeDef, HAL_TIM_Base_Init, TIM_HandleTypeDef*);
Then the first test, which works just fine, is as follows:
TEST(HeaterTestGroup, WHEN_BothTaskCreationsFail_THEN_HeaterInitFails)
{
ADC_HandleTypeDef TestADC;
BaseType_t taskCreateOutcomes[2] = { pdFAIL, pdFAIL };
SET_RETURN_SEQ(xTaskCreate, taskCreateOutcomes, 2);
CHECK_EQUAL(Heater_init(&TestADC), ERROR);
}
The function under test, HeaterInit() calls two functions:
InitialiseHeater1Task(hadc);
InitialiseHeater2Task(hadc);
Each of which contains a similar call to create a FreeRTOS task:
taskCreationSuccess = xTaskCreate( ControlTask, // Function that implements the task.
"Heater1ControlTask", // Text name for the task.
128, // Stack size in words, not bytes
(void *) &heater1, // Parameter passed into the task.
1, // Priority at which the task is created.
&taskHandle); // Used to pass out the created task's handle.
When I step through this code in debug mode, I can see that it is the fake version of xCreateTask which is being called, and the return sequence is exactly as I have specified.
However, the second test, which is not working, is as follows:
TEST(HeaterTestGroup, InitPWMTest)
{
TIM_HandleTypeDef pTimer;
HAL_StatusTypeDef halReturnOK = HAL_OK;
SET_RETURN_SEQ(HAL_TIM_Base_Init, &halReturnOK, 1);
CHECK_EQUAL(InitialisePwmTimer(&pTimer), SUCCESS);
}
This function under test, contains the following:
ErrorStatus InitialisePwmTimer(TIM_HandleTypeDef* const pTimerHandle)
{
ErrorStatus PWMInitState = SUCCESS;
pTimerHandle->Init.Prescaler = 1;
pTimerHandle->Init.CounterMode = TIM_COUNTERMODE_UP;
pTimerHandle->Init.Period = PWMPeriod;
pTimerHandle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
pTimerHandle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(pTimerHandle) != HAL_OK)
{
PWMInitState = ERROR;
}
...
If I step through this test in debug mode, I can see that the function calls the real function, defined in stm32f1xx_hal_tim.c, instead of calling my Fake.
I cannot see any reason why one of these would work and the other would not. Could anyone suggest a reason?
It seems that the issue is that you are calling the test function HAL_TIM_Base_Init (which you mocked) from another function - which I assume is located on ANOTHER c/cpp file and not in the same cpp file as where you defined FAKE_VALUE_FUNC(HAL_StatusTypeDef, HAL_TIM_Base_Init, TIM_HandleTypeDef*);
The issue is that by using FAKE_VALUE_FUNC you are declaring the mock function only locally in that file. However, the original function is still in your code. and is visible to all the files in your code that included the header file that declares the original function. So when you call InitialisePwmTimer you leave the test file and go "out" to the rest of the code where the original HAL_TIM_Base_Init prevails.
I offer two solutions:
Exclude from your unit tests project the C file that contains the definition (implementation) of the original function and if that is not possible try just wrapping the function with #ifdef so that it won't be included in the unit test project. But in any case, keep the header file. Then replace the use of FAKE_VALUE_FUNC with DECLARE_FAKE_VALUE_FUNC and DEFINE_FAKE_VALUE_FUNC (read more about it here: FFF Primer). This will cause your mock function to take preference and be called from outside the test file as well.
You can just use function pointer substitution. I wrote more extensively about it here: Function Pointer Substitution With FFF

Lua c API change library after creation

I am trying to wrap ncurses in Lua using the C API. I am working with the stdscr pointer: This is NULL before initscr is called, and initscr is called from Lua by design of my bindings. So in the driver function I do this:
// Driver function
LUALIB_API int luaopen_liblncurses(lua_State* L){
luaL_newlib(L, lncurseslib);
// This will start off as NULL
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
lua_pushstring(L, VERSION);
lua_setglobal(L, "_LNCURSES_VERSION");
return 1;
}
This works as intended. The trouble comes when I need to modify stdscr. initscr is bound like this:
/*
** Put the terminal in curses mode
*/
static int lncurses_initscr(lua_State* L){
initscr();
return 0;
}
I need to moify the stdscr in the library to no longer be null. Example code from Lua side:
lncurses = require("liblncurses");
lncurses.initscr();
lncurses.keypad(lncurses.stdscr, true);
lncurses.getch();
lncurses.endwin();
But, lncurses.stdscr is NULL, so the it's essentially running the c equivalent of keypad(NULL, true);
My question being, how do I modify library values in Lua after the library is created?
You can use the registry.
Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it must take care to choose keys that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, or any Lua object created by your code. As with variable names, string keys starting with an underscore followed by uppercase letters are reserved for Lua.
Store a reference to the module table in the registry on creation.
LUALIB_API int luaopen_liblncurses(lua_State* L) {
luaL_newlib(L, lncurseslib);
// This will start off as NULL
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
lua_pushstring(L, VERSION);
lua_setglobal(L, "_LNCURSES_VERSION");
// Create a reference to the module table in the registry
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "lncurses");
return 1;
}
Then when you initscr, update the field.
static int lncurses_initscr(lua_State* L) {
initscr();
// Update "stdscr" in the module table
lua_getfield(L, LUA_REGISTRYINDEX, "lncurses");
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
return 0;
}

How to set a "require" to return a table/module from Lua C API?

I want to add a requireable module solely from the C API.
--lua.lua
local c_module = require("c_module")
c_module.doWork()
What API functions do I have to use to make this possible?
When loading a shared library with require, Lua looks for a a function named luaopen_<name> where <name> is the module name with the dots replaced with underscores (so require "foo.bar" will look for luaopen_foo_bar, but hyphens get special treatment; see the Lua manual).
This function should be a regular lua_CFunction; that is, it takes a lua_State* as an argument and returns an int. require calls this function with the package name as an argument, and the value you return from the function is what require stores and returns.
Here's an example for a module named foo:
static int bar(lua_State* L) {
// ...
}
int luaopen_foo(lua_State* L) {
lua_newtable(L); // Create package table
// Push and assign each function
lua_pushcfunction(L, &bar);
lua_setfield(L, -2, "bar");
// ...
// Return package table
return 1;
}
(This is for Lua 5.1, though the equivalent code for 5.2 should be very similar, if not the same. Also be sure that the luaopen_ function is exported from the shared library.)
The full behavior of the C loader can be found here: http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders

Lua C API code not calling __newindex functions but calling other functions

I have written some code to separate registering custom functions and the __newindex and __index functions into 2 separate functions. The goal of my code is to have functions and variables visible to the Lua script writer that are organized based upon sublevels of specificity. For example, the user would have available the following commands:
orc.chief.attack();
orc.chief.flee();
orc.chief.hp = 100;
orc.pawn.attack();
elf.wood.attack();
elf.wood.hp = 200;
So basically a system with 2 tiers and then a function call or a variable. If I understand Lua correctly, that is a metatable in a table in a table. When the user sets the variable, it should trip a __newindex call (not only to handle setting the value but to access a physical object that will animate through motors). I also assume that the chief table in the table orc just sees lots of functions assigned to it regardless whether it is attack or __newindex. To make it easier to add new variables and functions as the code develops, I have created 2 functions: one to create a function and one to create a variable. The function create just registers the functions and the variable create just makes a new table element and registers the functions for __newindex and __index. Below is the code:
int orcChiefhp;
luaL_Reg Orc_Module[] = {
{"attack", OrcAttack},
{"flee", OrcFlee},
{NULL, NULL}};
const luaL_Reg orcChief_metareg[] = {
{"__index", orcChief__index},
{"__newindex", orcChief__newindex},
{NULL, NULL}};
int OrcAttack(lua_State *L)
{
//code to cause the motors to swing the weapon...
return 0;//0 parameters come back as the data
}
int orcChief__newindex(lua_State *L)
{
const char *idx;
if(lua_isstring(L,2))
{
idx = lua_tostring(L,2);//gets the string so we can get the variable of the struct
if(strcmp(idx, "hp")==0)
{
lua_pushnumber(L, orcChiefhp);
}
else
lua_pushnil(L);
}
return 1;
}
void registerFunctions(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *funcs)
{
int isitnil;
lua_getglobal(L, libname);
isitnil = lua_isnil(L, -1);
if(isitnil)
{
lua_pop(L, 1);
lua_newtable(L); // create 'libname' table
}
// no sublib: just import our library functions directly into lib and we're done
if (sublibname == NULL)
{
luaL_setfuncs(L, funcs, 0);
}
// sublib: create a table for it, import functions to it, add to parent lib
else
{
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
lua_setfield(L, -2, sublibname);
}
if(isitnil)
lua_setglobal(L, libname);//this will pop off the global table.
else
lua_pop(L, 1);//the global table is still on the stack, pop it off
}
void registerIntegerVariable(lua_State *L, const char *libname, const char *sublibname, const char *variableName,
const char *metatableName, const luaL_Reg *metatableFuncs, int defaultValue)
{
int isLibnameNil;
int isSubnameNil;
lua_getglobal(L, libname);//get the libname
isLibnameNil = lua_isnil(L, -1);//check to see if it exists
if(isLibnameNil)//if it doesn't exist, create a new one
{
lua_pop(L, 1);//pop off the nil
lua_newtable(L); // create 'libname' table
}
// no sublib: just import our library functions directly into lib and we're done
if (sublibname == NULL)//if we want the functions at the lib level then just set the functions
{
lua_pushstring(L, variableName);//push the variable name
lua_pushnumber(L, defaultValue);//push the default value on the stack
lua_rawset(L, -3);//add the variable to the table (rawset is like settable but doesn't call __index)
luaL_newmetatable(L, metatableName);//create the metatable
luaL_setfuncs(L, metatableFuncs, 0);//set the metatable functions for __newindex and __index
lua_setmetatable(L, -2);//set the metatable to the libtable
}
// otherwise we need to create a table for the sublibname, import functions to it, add to parent lib.
else
{
lua_getfield(L, -1, sublibname);//see if the sublibname is under the global libname
isSubnameNil = lua_isnil(L, -1);//is it a nil
if(isSubnameNil)//if it is, then we need to create the sublibname
{
lua_pop(L, 1);//pop off the nil
lua_newtable(L);//creates the new sublibname table
}
lua_pushstring(L, variableName);//push the variable name
lua_pushnumber(L, defaultValue);//push the default value on the stack
lua_rawset(L, -3);//add the variable to the table and push it (rawset is like settable but doesn't call __index)
luaL_newmetatable(L, metatableName);//create the metatable
luaL_setfuncs(L, metatableFuncs, 0);//add the metamethods
lua_setmetatable(L, -2);//set the metatable to the sublibname
if(isSubnameNil)
lua_setfield(L, -2, sublibname);//now we need to add the sublibname to the libname
}
if(isLibnameNil)
lua_setglobal(L, libname);//set the global name if it was new
else
lua_pop(L, 1);
}
Then, in my main() I call the functions like this:
execContext = luaL_newstate();
//adding lua basic library
luaL_openlibs(execContext);
//now register all the functions with Lua
registerFunctions(execContext, "orc", "chief", Orc_Module);
registerFunctions(execContext, "orc", "pawn", Orc_Module);
registerFunctions(execContext, "elf", "wood", Elf_Module);
//now register all the variables with Lua
registerIntegerVariable(execContext, "orc", "chief", "hp", "chief_meta", orcChief_metareg, 0);
When I run the code and pump in Lua scripts, orc.chief.attack() calls my OrcAttack() function but orc.chief.hp = 100 never calls my orcChief__newindex() function. I have even commented out the registerFunctions calls in case they were interfering somehow and just the registerIntegerVariable by itself still won't trigger the orcChief__newindex(). Any ideas?
__newindex is not called when you set a field in a table. It is called when you set a new field in a table. If the field already exists, __newindex will not be called.
If you want __newindex to be called for every set operation on a table, you can't allow set operations to actually modify that table. This is generally done by creating an empty table, called a proxy table, which the user uses. The proxy table is actually empty and must always remain so; you intercept all of the get and set calls, piping them to an internal table that the user never sees don't have access to.
Or you use some userdata instead of a table. __newindex is always called for them.

Push lua function as table member from C API

Well there are no problems to push C function as function member or register C function as lua function with lua_register(L, lua_func_name, c_func);
But how tell lua what i want to pass luaFoo() as function callback param for "foober" from C?
lua_pushcfunction - pushes C function, lua_pushstring pushes just a plain string, so callback field became a string, not a function.
Lua Code:
CALLBACKS = {};
FOO = 0;
function luaFoo()
FOO = FOO + 1;
end;
function addCallback(_name, _callback)
CALLBACKS[_name] = _callback;
end;
function doCallback(_name)
CALLBACKS[_name]();
end;
C code:
static int c_foo(lua_State* l)
{
printf("FOO\n");
return 0;
}
/*load lua script*/;
lua_State* l = /*get lua state*/;
lua_getglobal(l, "addCallback");
lua_pushstring(l, "foober");
//What push for luaFoo()
lua_pushcfunction(l, c_foo);
lua_call(l, 2, 0);
lua_getglobal(l, "doCallback");
lua_pushstring(l, "foober");
lua_call(l, 1, 0);
Similiar - if i get C functions which already registered with lua_register, how pass them as callback param from C. So we register c_foo => c_foo exist as lua function, how to tell what we want to pass "c_foo" as callback func param.
Remember that:
function luaFoo()
...
end
is equivalent to this, in Lua:
luaFoo = function()
...
end
Therefore, your question ultimately boils down to, "I have a value in the global table. How do I push it onto the stack?" The fact that this value is a function is irrelevant; a function value in Lua is no different from an integer value, which is no different than a string value. Obviously you can do different things with them, but you just want to copy them around. That works the same regardless of what the value is.
The function you're looking for is lua_getglobal.
As for your second question, you can do it in one of two ways. You can either get the function value you registered from the global table, or you can simply re-register it with lua_pushcfunction. Since you're not using upvalues, re-registering it doesn't really have any downsides.
Oh, and one more thing, on code style. Lua doesn't require ; at the end of statements. You can do it (to make C-native programmers feel more comfortable), but it's not necessary.

Resources