Get lua table entry from C via integer key - c++

I am currently using the following code to get a value from a table (cstring = const char*):
template<>
cstring luaTable::get(cstring name) {
prep_get(name); // puts table[name] at -1 in stack
cstring result;
if(!lua_isstring(L, -1)) {
report(name, "is not a string");
result = "";
}
else {
result = lua_tostring(L, -1);
}
lua_pop(L, 1);
return result;
}
void luaTable::prep_get(cstring name) {
lua_pushstring(L, name); // name at -1, table at -2
lua_gettable(L, -2);
// table[name] is now at position -1 in stack
}
This works perfectly for tables of form table = {a=10, b=2}. How can I modify it to get values from tables without keys such as table = {10, 2}?
I'm sure I'm missing something simple but can't seem to find the answer.
Thanks in advance,
Ben
Edit: added some pops

Okay sorry to answer my own question so soon - but a quick flash of inspiration lead to:
void luaTable::prep_get(cstring name) {
lua_pushstring(L, name); // name string at -1
if(lua_isnumber(L, -1)) { // call prep_get("i") for ith element etc
int key = lua_tonumber(L, -1);
lua_pop(L, 1); // remove the name string from -1
lua_pushnumber(L, key); // push name number to -1
}
lua_gettable(L, -2);
// result is now at position -1 in stack
}
which works as desired.

#user1483596 I don't think that solution would work. lua_isnumber will only return true if the value is of type number, and you just pushed a string, so it will always return false.
Instead, try something like this:
void luaTable::prep_get(cstring name) {
int num = strtol(name, 0, 0);
if (num > 0) {
lua_pushnumber(L, num);
} else {
lua_pushstring(L, name);
}
lua_gettable(L, -2);
}
Bear in mind though that it won't handle a special case. In Lua a[1] and a["1"] are different. If you use this function, you'll always treat numbers as array indices, even if they're not.
If you want to differentiate both cases, then you could overload prep_get and take a number.

Related

C++ Lua embedding, pushing table to a function that on arguments

so i was trying to push a table on a function inside arguments
*lua
function test1(varlist)
print(varlist[1])
print(varlist[2])
print(varlist[3])
end
addHook("string", "string2", test1)
*cpp
static int lua_addHook(lua_State* L) {
if (lua_isstring(L, 1) && lua_isstring(L, 2) && lua_isfunction(L, 3)) {
lua_newtable(L);
lua_newtable(L);
for (size_t i = 0; i < 3; ++i) {
lua_pushinteger(L, i + 1);
lua_pushstring(L, string("string varlist: " + to_string(i)).c_str());
lua_settable(L, -3);
}
if (lua_pcall(L, 1, 0, 0) != 0) {
printf("error: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
}
return 1;
}
so it should printing
string varlist: 0
string varlist: 1
string varlist: 2
but i keep getting error "attempt to call a table value"
u know what the problem is?
The stack looks like this at the point of lua_pcall:
table (constructed by the loop above) # STACK TOP and arg1 to function call
table (empty) # interpreted as the function to call
function test1
string "string1"
string "string"
Getting rid of one of the lua_newtable calls should fix it.

Problem with lua_isstring iterating for table in table

I try to write a table to an ini file, everything worked until I added a line lua_tostring(L, -2) then lua_next(L, -2) began to give out an error. How this line can influence, in my understanding, I just take the value from the stack and no more. How I can fix it?
{
// Push an initial nil to init lua_next
lua_pushnil(inOutState);
// Parse the table at index
while (lua_next(inOutState, -2))
{
if (lua_isstring(inOutState, -1)) {
string key = lua_tostring(inOutState, -2);
string value = lua_tostring(inOutState, -1);
inIniTree.put(suffix + key, value);
}
else if (lua_istable(inOutState, -1)) {
suffix += lua_tostring(inOutState, -2); !!!!!! without this line function is working well !!!!!!!
setDataInIni(inOutState, inIniTree, suffix);
}
// Pop value, keep key
lua_pop(inOutState, 1);
}
return;
}
lua_tostring() replaces value in stack if value is not of type string. It means you changed key for lua_next(). You must copy value with lua_pushvalue() and then convert it to string.
if (lua_isstring(inOutState, -1)) {
lua_pushvalue(inOutState, -2);
string key = lua_tostring(inOutState, -1);
lua_pop(L, 1);
string value = lua_tostring(inOutState, -1);
inIniTree.put(suffix + key, value);
}
else if (lua_istable(inOutState, -1)) {
lua_pushvalue(inOutState, -2);
suffix += lua_tostring(inOutState, -1);
lua_pop(L, 1);
setDataInIni(inOutState, inIniTree, suffix);
}

Using lua_call a lot of times in c++ function

first of all I'm sorry for my english.
My question is about how to use lua_call more than one time in C++ function. I have a program that uses lua as primary language, but it accept c++ plugins to add functionalities. I want to call a LUA function from c++, and call that c++ function in LUA Runtime.
I want to write a c++ function with a progress while is working, then pass this progress to a LUA function which is responsible to show that progress to user.
For now I've a test function in LUA:
function ShowText(text)
Dialog.Message("Hi", text);
return true;
end
and a c++ function:
static int Test(lua_State *L){
lua_pushstring(L, "Hi There");
lua_call(L, 1, 1);
lua_pushstring(L, "Again");
lua_call(L, 1, 1);
return 0;
}
Then i call this function from LUA using:
Test.Test(ShowText);
All works fine with the first lua_call but then the LUA pile is cleared, function dissapear and the second lua_call try to use the return boolean of first call instead function.
i want something like this:
static int Test(lua_State *L){
int total = 10;
for (int j; j<total; j++){
lua_pushnumber(L, j);
lua_pushnumber(L, j);
lua_call(L, 2, 1);
bool continue = IRLUA_PLUGIN_CheckBoolean(L, -1);
lua_pop(L, 1); //Delete the last boolean
if (continue == false){
break;
}
}
return 0;
}
and in LUA:
function ShowProgress(actual, final)
local percent = (actual/final)*100;
Dialog.Message("Working", "I'm in "..actual.." from "..final.." ("..percent.."%)");
return true;
end
NOTES:
Dialog.Message is a function of the program tha i'm using to show a message. Is like MessageBox(NULL, Text, Title, MB_OK); in c++.
IRLUA_PLUGIN_CheckBoolean is a function of plugin SDK that check if argument is booleand and return its value, or return an error if not.
I can do it with lua_getfield(L, LUA_GLOBALSINDEX , "FunctionName");, but is not what i want.
Someone knows how to do it?
You have understood the problem well. Here is how you fix it.
In your first example, lua_call pops the function from the stack so you need to duplicate it first. Also, the boolean returned by the function is useless, so you need to pop it or just not ask it to lua_call by setting the last argument to 0:
static int Test(lua_State *L) {
lua_pushvalue(L, 1); /* duplicate function */
lua_pushstring(L, "Hi There");
lua_call(L, 1, 0);
lua_pushstring(L, "Again");
lua_call(L, 1, 0);
return 0;
}
Now applying that to your second example:
static int Test(lua_State *L) {
int total = 10;
for (int j = 0; j<total; j++) {
lua_pushvalue(L, 1); /* duplicate function */
lua_pushnumber(L, j);
lua_pushnumber(L, total);
lua_call(L, 2, 1);
bool keep_going = IRLUA_PLUGIN_CheckBoolean(L, -1);
lua_pop(L, 1); /* pop the boolean */
if (keep_going == false) {
break;
}
}
return 0;
}
(I have fixed a few other issues with your code: the second number passed should probably be total, not j, you don't want to use continue as a variable name...)

Reading Lua nested tables in C++

I'm creating a C/C++ function which will be called from Lua. My function must call a library function who's signature is like this:
void libFunction( int val1, int val2, tSETTINGS * pSettings );
I'm given these C/C++ structs:
typedef struct
{
int cmd;
int arg;
} tCOMMAND;
typedef struct
{
int numberCommands;
int id;
tCOMMAND commands[1];
} tSETTINGS;
Maybe my thinking is all wrong on this, but from Lua I'm calling like this:
id = 42
val1 = 1
val2 = 2
cmd1 = { 3, 4 }
cmd2 = { 5, 6 }
commands = { cmd1, cmd2 }
settings = { #commands, id, commands }
mycfunction( val1, val2, settings )
I'm sure that I'm still not understanding the Lua stack as referenced from C++, since what I'm trying just doesn't work. My solution is able to retrieve val1, val2, #commands and id, but when I try to retrieve commands[0] and commands[1] I get {1, 2} and {2, 42} respectively.
My C++ is essentially like this (for this sample I'm discarding the values). I've already retrieved val1 and val2:
int stkNdx = 1;
lua_rawgeti(L, 3, stkNdx++ );
int numcmds = lua_tointeger(L, -1); // this successfully retrieves numberCommands 2
lua_pop(L, 1);
lua_rawgeti(L, 3, stkNdx++ );
int id = lua_tointeger(L, -1); // this successfully retrieves id 42
lua_pop(L, 1);
lua_pushvalue(L, -1 );
lua_pushnil(L);
int cmdNbr = 0;
for( lua_next(L, -2); cmdNbr < numcmds; cmdNbr++ )
{
lua_pushvalue(L, -2);
int cmd = lua_tointeger(L, -1);
int arg = lua_tointeger(L, -1);
lua_pop(L, 2);
lua_next(L, -2);
}
lua_pop(L, 1);
I've tried various permutations of lua_rawgeti() followed by lua_tonumber() and lua_pop(), with basically the same result.
This seems similar to this question, and my solution is modeled after that with no success.
Experimenting more I inserted this:
lua_pushnil(L);
while( lua_next(L, -2) )
{
if( ! lua_istable(L, -1) )
{
int v = lua_tointeger(L, -1);
}
lua_pop(L, 1);
}
This loop executes 4 times. The first 2 times the values 2 and 42 are assigned to v. The next 2 iterations skip the assignment (lua_istable returned true). So it seems that although I've already retrieved numcmds and id, they're still there on the stack. I also clearly don't understand how to iterate over the subtables when they're encountered.
Lua table indices range from [1 .. N] instead of [0 .. N-1].
Your loop should be:
int cmdNbr = 1;
for( lua_next(L, -2); cmdNbr <= numcmds; cmdNbr++ )
{
...
}
or as I prefer it:
lua_rawgeti(L, 3, 2 );
int id = lua_tointeger(L, -1); // this successfully retrieves id 42
lua_pop(L, 1);
lua_rawgeti(L, 3, 3);
{
// commands table at stack top
size_t N = lua_objlen(L,-1); // size of the table
for (int i = 1; i <= N; ++i)
{
lua_rawgeti(L,-1, i); // cmd# at stack top
{
lua_rawgeti(L,-1,1); // first entry
int cmd = lua_tointeger(L,-1);
lua_pop(L,1);
lua_rawgeti(L,-1,2); // second entry
int arg = lua_tointeger(L,-1);
lua_pop(L,1);
}
lua_pop(L, 1); // pop cmd#
}
}
lua_pop(L, 1); // pop commands table
Note that, with the function lua_objlen(L,idx), it's not necessary to pass numcmds.

Pass pure lua object to C function and get value

In Lua Code
Test = {}
function Test:new()
local obj = {}
setmetatable(obj, self)
self.__index = self
return obj
end
local a = Test:new()
a.ID = "abc123"
callCfunc(a)
In C Code
int callCfunc(lua_State * l)
{
void* obj = lua_topointer(l, 1); //I hope get lua's a variable
lua_pushlightuserdata(l, obj);
lua_getfield(l, 1, "ID");
std::string id = lua_tostring(l, 1); //I hoe get the value "abc123"
...
return 0;
}
But My C result is
id = null
Why? How to modify code to work fine ?
PS: I don't hope create C Test Class mapping to lua
==== update1 ====
In addition, I have added the test code to confirm correct incoming parameters.
int callCfunc(lua_State * l)
{
std::string typeName = lua_typename(l, lua_type(l, 1)); // the typeName=="table"
void* obj = lua_topointer(l, 1); //I hope get lua's a variable
lua_pushlightuserdata(l, obj);
lua_getfield(l, 1, "ID");
std::string id = lua_tostring(l, 1); //I hoe get the value "abc123"
...
return 0;
}
the result
typeName == "table"
so incoming parameter type is Correct
I found the reason
Correct c code should is ...
In C Code
int callCfunc(lua_State * l)
{
lua_getfield(l, 1, "ID");
std::string id = lua_tostring(l, -1); //-1
...
return 0;
}
Maybe this - haven't tested sorry - don't have a compiler handy
Input is the table from lua on top of the stack, so getfield(l,1, "ID") should get the field ID from the table at the top of the stack - which in this case is your input table. It then pushes the result to the top of the stack
int callCfunc(lua_State * l)
{
lua_getfield(l, 1, "ID");
std::string id = lua_tostring(l, 1); //I hoe get the value "abc123"
...
return 0;
}