return several parameter from lua C function - c

I want to get several parameters in Lua from a C function.
I tried to push several arguments on the lua stack:
static int myFunc(lua_State *state)
{
lua_pushnumber(state, 1);
lua_pushnumber(state, 2);
lua_pushnumber(state, 3);
return 1;
}
and call it in Lua like this:
local a,b,c = myFunc()
Unfortunately b and c values are nil. I dont want to write a function for every value I need but to take advantage of Luas capabilities to retrieve several arguments from a function.

The return value of the C function is the number of values returned.
Change it to return 3; and you're good to go.
Here, have a reference from Programming in Lua:
static int l_sin (lua_State *L) {
double d = lua_tonumber(L, 1); /* get argument */
lua_pushnumber(L, sin(d)); /* push result */
return 1; /* number of results */
}

Related

Determine the number of return values expected by Lua from inside a C extension function

Every time a function in Lua is called, the number of return values is immediately known at the call site:
f() --0
local a, b = f() --2
local t = {f()} --LUA_MULTRET
local t = {f(), nil} --1
The same is true for the C API: both lua_call and lua_pcall are always provided with the expected number of return values (or LUA_MULTRET).
Thinking about performance, it might be advantageous for a Lua function to be able to determine the number of expected return values expressed by their callers, so as to avoid computing return values that the caller did not request (if the computation takes a long time):
int getstrings(lua_State *L)
{
if(lua_numresults(L) > 0)
{
lua_pushstring(L, "a");
if(lua_numresults(L) > 1)
{
lua_pushstring(L, "b");
if(lua_numresults(L) > 2)
{
lua_pushstring(L, "c");
return 3
}
return 2;
}
return 1
}
return 0;
}
Assuming a hypothetical lua_numresults returns size_t, this function would produce only the that are really needed and will not take time to compute values that are guaranteed to be lost.
Another interesting example would be functions that return sequences:
int range(lua_State *L)
{
size_t num = lua_numresults(L);
for(size_t i = 1; i <= num; i++)
{
lua_pushinteger(L, i);
}
return num;
}
The sequence is not "lazy" so something like f(range()) cannot be done, but local a, b, c = range() returning 1, 2, 3 etc. might find its uses.
Is there anything like lua_numresults or a way to implement its functionality?
Judging from Lua 5.3 sources, the expected number of results is located in the CallInfo structure. A new call info is created for every Lua call, and the most recent one is stored in lua_State::ci There doesn't appear to be any function that can return this value, but if one has access to the structure, it is fairly straightforward to get it:
#include "lua/lstate.h"
size_t lua_numresults(lua_State *L)
{
return (size_t)L->ci->nresults;
}

Nested lua_CFunction calls

What is the best way to deal with nested lua_CFunction calls? Assume I have two function like this:
static int function2(lua_State *L) {
int i = luaL_checkint(L, 1);
/* do something */
return 1;
};
static int function1(lua_State *L) {
struct udata *u = luaL_checkudata(L, 1, UDATA_METATABLE);
int i = luaL_checkint(L, 2);
/* do something */
/* this does not work, first on call stack is udata, not int */
return function2(L);
};
The function call as above does not work. One option is to modify function2() to use the last element (index -1) on stack, but this is not a sollution in general since function2() might be called from various places with different call stacks.
Another way would be to replace the return function2(L); by
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, 1); /* need to know number of results */
I assume this gives function2() its own call stack so there is no need to modify it. But this sollution seems overly complicated for functions with more parameters since it requires duplicating all of them on the stack.
tl;dr: What is the recommended way/a good way to call a lua_CFunction from inside another one?
In function1 you are expecting the bottom of the stack to be user data.
When you call function2 directly, the LuaState has not changed and therefore the bottom is still user data.
You can successfully call function2 from function1 by ensuring an integer is at index 1.
You could do this by calling lua_insert(L, 1) which will move the top (assuming index 2), to index 1.
You could also do this by popping all values the pushing the integer back on:
lua_pop(L, lua_gettop(L));
lua_pushnumber(L, i);
return function2(L);
lua_CFunction is not fully Lua function. It just a way to create Lua function/closure.
static int function1(lua_State *L) {
....
int top = lua_gettop(L);
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, LUA_MULTRET);
return lua_gettop(L) - 1;
}
The Lua equivalent is
function function1(arg)
return (function(arg) --[[body of f2]] end)(arg)
end
So you create each time new function and call it.
For C function it is quite ok because it no need to compile and you do not need upvalue.
Also Lua 5.2 introduce light function for that.
But if you want equivalent for
int i = 1
local function function2(arg)
i = i + 1
...
end
function function1(arg)
return function2(arg)
end
You need a way to find real Lua function e.g. (not tested)
int f2_ref;
static int function1(lua_State *L) {
...
-- push `function2` on stack
lua_rawgeti(L, LUA_REGISTRYINDEX, f2_ref);
-- as above
}
static int function2(lua_State *L) {
int my_upvalue = lua_tonumber(L, lua_upvalueindex(1));
my_upvalue++;
lua_pushnumber(L, my_upvalue);
lua_replace(L, lua_upvalueindex(1));
...
}
int luaopen_foo(lua_State *L){
-- Here we create instance of Lua function(closure)
lua_pushnumber(L, 1);
lua_pushcclosure(L, function2, 1);
f2_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, function1, 0);
return 1;
}
I'd say that calling it through lua is the recommended way to do that but if you don't want to do that for some reason then Timma's suggestions are the right ones.

Registering a closure with Lua

Instead of using the lua_CFunction signature for writing methods to be called from Lua, I'd like to use my own function signature that simplifies the export process.
void foo(call_t *call)
{
int a;
char *b;
char *c;
table_t *d;
/* reading arguments */
a = read_integer(call);
b = read_string(call);
/* do something... */
/* writing arguments */
write_string(call, c);
write_table(call, d);
}
/* export to Lua */
export("foo", foo);
So far, all I can think of doing is having a single lua_CFunction that calls the wrapper function from a table. However, I don't know how to associate a Lua function with a C function and table index so as to effectively make the Lua function a closure. Something like this:
lua_register_with_data(state, "foo", base_function, FOO_INDEX);
How can I make this happen?
I figured it out after all. I guess this proves how useful rubber duck debugging is.
I just registered the base function along with the actual function index as an upvalue.
function_t table[FUNCTION_COUNT];
/* lookup function using upvalue */
int base_function(lua_State *state)
{
int index;
call_t call;
call.state = state;
call.argument_index = 1;
call.return_count = 0;
index = lua_tointeger(state, lua_upvalueindex(1));
table[index](&call);
/* return_count is incremented by write_* functions */
return(call.return_count);
}
/* register function as closure */
table[FOO_INDEX] = foo;
lua_pushinteger(state, FOO_INDEX);
lua_pushcclosure(state, base_function, 1);
lua_setglobal(state, "foo");

How to retrieve a returned string by C function in Lua script?

I have a Lua script which is calling a C function.
Currently this function is returning nothing.
I want to change this function to return a string, so at the end of this function in C I will push the string into Stack.
Inside the calling Lua script I need to get back the pushed string value.
C initialization and registration with Lua
void cliInitLua( void )
{
void* ud = NULL;
Task task;
// Create a new Lua state
L = lua_newstate(&luaAlloc, ud);
/* load various Lua libraries */
luaL_openlibs(L);
/*Register the function to be called from LUA script to execute commands*/
lua_register(L,"CliCmd",cli_handle_lua_commands);
//lua_close(L);
return;
}
This is my c Function to return a string:
static int cli_handle_lua_commands(lua_State *L){
...
...
char* str = ....; /*Char pointer to some string*/
lua_pushstring(L, str);
retun 1;
}
This is my Lua script
cliCmd("Anything here doesn't matter");
# I want to retreive the string str pushed in the c function.
In C you have something like
static int foo (lua_State *L) {
int n = lua_gettop(L);
//n is the number of arguments, use if needed
lua_pushstring(L, str); //str is the const char* that points to your string
return 1; //we are returning one value, the string
}
In Lua
lua_string = foo()
This assumes you have already registered your function with lua_register
Pleas see the great documentation for more examples on these sorts of tasks.

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