Accessing a Lua table within a table from C++ - c++

I have a Lua function that returns a dictionary table, and one of the values that's put into the returned table is another table as demonstrated in the following Lua function.
function tableWithinTable()
local ret = {}
ret["a"] = 1
ret["b"] = {1,2,3}
ret["c"] = 3
return ret
end
How would I go about accessing that inner table?
I know I can get to the table, because I can enter the following if statement. My current attempt at reading the table is included as well.
lua_pushstring("b");
lua_gettable(lua,1);
if(lua_istable(lua,-1))
{
//whatever is in here is executed.
lua_pushnumber(lua,1);
lua_gettable(lua,-1); //crashes to desktop here
std::cout << lua_tonumber(lua,-1) << std::endl;
lua_pop(lua,1);
}
I'm pretty sure there's an easy solution to this, but I'm totally stumped. Any help would be much appreciated.

After you push the index, the table is one more slot away in the stack. So something like this should work:
if(lua_istable(lua,-1)) {
lua_pushnumber(lua,1);
lua_gettable(lua,-2);
...

It is generally easier to use functions lua_getfield (for string indexes) or lua_rawgeti (for numerical indexes) than the raw lua_gettable function.
In particular, that avoids the extra value on the stack that causes your indexing error.
The example could be rewritten as :
lua_getfield(lua, 1, "b");
if(lua_istable(lua, -1))
{
lua_rawgeti(lua, -1, 1);
std::cout << lua_tonumber(lua,-1) << std::endl;
lua_pop(lua, 1);
}

Related

Accessing a Lua table within a table from C++ side

I'm trying to transfer a table where there may be nested tables from the lua and write to a .ini file. But I just can not how I need to go on the stack to get data from nested tables. This code does not work as it should. Function setData work not correctly. What could be the problem?
C++ code
int sasl::LuaUtilities::luaWriteIni(LuaState inOutState)
{
string path;
boost::property_tree::ptree iniTree;
LUA_CHECK_NARG_EQ(inOutState, 2);
LUA_GET_PARAM(inOutState, 1, path);
int nargs = lua_gettop(inOutState);
for (int i = 1; i <= nargs; i++) {
if (lua_istable(inOutState, nargs)) {
setData(inOutState, nargs, iniTree);
}
}
return 0;
}
void sasl::LuaUtilities::setData(LuaState inOutState, int index, boost::property_tree::ptree & inIniTree)
{
// Push an initial nil to init lua_next
lua_pushnil(inOutState);
// Parse the table at index
while (lua_next(inOutState, index))
{
if (lua_istable(inOutState, index))
{
setData(inOutState, index, inIniTree);
}
else
{
string key = lua_tostring(inOutState, -2);
string value = lua_tostring(inOutState, -1);
}
// Pop value, keep key
lua_pop(inOutState, 1);
}
return;
}
Lua code
t = {}
local fileName = findResourceFile("test.ini")
t = readINI(fileName)
writeINI(fileName, t) --this not work in c++ side
There are two problems. lua_istable(inOutState, index) is wrong, because index is not the value of the key retrieved by next. That index is always the table you're iterating over. So you'll infinitely recurse over the same table when you call setData with that index.
In fact, passing index to setData itself is almost certainly wrong. Or at least, it's probably not right. You want to use relative indices here, but calling next pushes an extra value onto the stack.
What you probably want to do is have setData assume that the table to iterate over is at index -1 (ie: the top of the stack). That way, you're just calling lua_next(state, -2) (this is -2 because the key to get the next one for is at the top). And when you recursively call setData for a table value, you don't need to provide an index, because the table value is already at the top of the stack.
The second problem is that you never write the key/value pairs. You also never check to see if the value is something which can be converted to a string. It could be a Lua userdata.

How to pass a table parameter from lua to C++ through a lightuserdata object?

I have registered a function that creates a lightuserdata to be used by C++ and lua. that part is working fine when I tested using simple variables, ints and strings. I can create my lightuserdata in lua without errors when it's strings and ints. however when I try to use tables it gets more complicated
std::string aString = lua_tostring(lua,-4);
first parameter being correct as it is supposed to be a string
if (lua_type(lua,-3 == LUA_TTABLE)) //is true so i know it recognizes it as a table
{
auto t = lua_gettable(lua, -3);
size_t tableLen = lua_rawlen(lua, -3); // also gives me the correct size
lua_settop(lua, 1); //this discards the rest right? which i don't want.
//luaL_checktype(lua, 1, LUA_TTABLE); //using this crashes the application expecting
// table but getting string
lua_getfield(lua, 1, "a");
lua_getfield(lua, 1, "b");
lua_getfield(lua, 1, "c");
lua_getfield(lua, 1, "d");
lua_getfield(lua, 1, "e");
std::cout << lua_gettop(lua) << std::endl; //after using the getfields i get the new table size
//correctly (i assume, it turns 1 more value than expected, i think it's the table itself.
//int a = luaL_checkinteger(lua, -5); //these don't work as they expect numbers but get nil
//int b = luaL_checkinteger(lua, -4);
//int c = luaL_checkinteger(lua, -3);
//int d = luaL_checkinteger(lua, -2);
//int e = luaL_checkinteger(lua, -1);
std::cout << lua_tointeger(lua, -2) << std::endl; //returns always 0
}
Trying to ignore the table and get the rest of the stack gives me an violation error on 0x000000, though the 3rd value debugs correctly as what is supposed to be and the 4th is empty, even though it passes correctly if i don't use table.
is What I'm trying to do possible proceeding like this?
any comment to the right direction would be appreciated.
also, what should I use if I don't know the name of the key in the table?
if (lua_type(lua,-3 == LUA_TTABLE)) //is true so i know it recognizes it as a table
Big error here, or you didn't post the actual code.
You're not checking the type of the value under index -3, you're asking the type of the value under index false, since -3 == LUA_TTABLE is clearly false.
Whatever crash that happens after that "check" - is a result of this error. It will recognize as a table anything that is not nil.

Abstract Data Type Pass as a parameter

Hey so I'm trying to pass a hash table as a parameter in c++, when I call the function that I am trying to run i get an error message that i do not understand.
So this is the function:
string getRandomKey(int tableNumber, int tableSize, HashTable<string>* table, int random){
random *= rand() % tableSize + 1;
string randKey = to_string(tableNumber) + to_string(random);
if((table->find(randKey)) == true){
cout << "Key: " << randKey << " found ";
return randKey;
}
return "";
}
This is by no means the final version I'm just trying to test it. Some context is that I have a couple of hash tables, and a separate integer variable that has the number of elements that i have predetermined. The keys are set to be one of the random numbers.
Anyway so here is where I call the function:
table1->print(getRandomkey(1, sizes[2], table1*, 1));
And I get this error:
error: expected expression
table1->print(getRandomKey(1, sizes[2], table1*, 1));
^
1 error generated.
So, I'm not sure what I need to change or if I messed something up somewhere else. Thanks for any help you guys can give!
It appears that table1 is a pointer to a HashTable so when you
make the call to getRandomKey the term table1* should just be table1.
table1->print(getRandomkey(1, sizes[2], table1, 1));

How to create and push table(with key/value pair) to lua from C++?

I wanted to return table(with key/value pair) which contains functions to lua from C++ function.
On the lua side, return value of the function was table. But, table was empty.
I tried string instead of function, but it didn't worked, too.
If I use index instead of key, it works. But I want to put a key, not a index.
lua_newtable(L);
for(list<NativeFunction_t>::iterator it = nativeFuncs.begin(); it != nativeFuncs.end(); it++)
{
NativeFunction_t tmp = *it;
cout << "Loading " << tmp.Name << " to lua...";
lua_pushstring(L, tmp.Name);
//If I do lua_pushstring(L, (Index)) instead of above, it works.
//lua_pushstring(L, tmp.Name);
lua_pushcfunction(L, tmp.Func);
lua_settable(L, -3);
cout << "Success" << endl;
}
//lua_setglobal(L, loadAs);
cout << "Done" << endl;
return 1;
Is something wrong with the way I create and return the table?
And here is lua code.
print("Loading NativeLoader...")
NativeLoader = require("Module")
print("Loading library...")
NativeLoader.Load("Hello", "TestLibrary")
print("Looking library...")
print("TestLibrary: " ..#TestLibrary)
for n, item in ipairs(TestLibrary) do
print(item)
end
--t.hello()
--t.bye()
It looks like you are using string keys in the table.
ipairs only traverses through integer keys from 1 to n.
As suggested by siffejoe in the comments, you should be using pairs instead.
However you should note that pairs does not loop through the elements in the order they were inserted in the table.
If you need the elements to be in a specific order, you might want to return an additional table containing the string keys in the specific order. Or you may want to make the original table you return into an array that contains tables that contain the name and the function at different table keys.
Also note that the length operator only works on sequences of integer keys.
So for your tables using only string keys it would always return 0.
I suggest you read through the lua reference manual for the length operator, pairs and ipairs. Here are links for lua 5.3 manual:
http://www.lua.org/manual/5.3/manual.html#3.4.7
http://www.lua.org/manual/5.3/manual.html#pdf-pairs
http://www.lua.org/manual/5.3/manual.html#pdf-ipairs

Simple lua example of passing a table to c/c++

I am struggling finding and understanding how to pass a table from lua to c++
What I have:
Lua File:
-- lua script for sending table data
io.write("lua table to send")
tableexample = {x = 1, y = 2, z = 100}
return tableexample
c/c++ side
L = lua_open();
luaL_openfile(L, "luafile");
... call the function...
luaLdofile(L, luafile);
int result;
result = lua_pcall(L,0, LUA_MULTRET,0);
if(result){
fprintf(stderr, "failed %s\n", lua_tostring(L,-1));
if(lua_istable(L,-1)){
lua_gettable(L,-1);
x = lua_tonumber(L,-2);
y = lua_tonumber(L,-3);
z = lua_tonumber(L,-4);
}
else
printf("fail");
the result comes back with a failure "attempt to call a table value"
I've looked at many different tutorials/examples but haven't found a simple tutorial that doesn't have 100 other things going on and am getting myself confused
some references that are similar - but too complex for what I am looking for
Iterating through a Lua table from C++?
Your use of lua_gettable is wrong.
Have a look at the Lua manual:
void lua_gettable (lua_State *L, int index);
Pushes onto the stack the value t[k], where t is the value at the
given index and k is the value at the top of the stack.
This function pops the key from the stack (putting the resulting value
in its place).
In your example, the value at the top of the stack is the table itself, so you are doing the equivalent of a tableexample[tableexample] lookup.
The shortest way to achieve what you want is to use lua_getfield instead, which allows accessing table elements by string keys:
lua_getfield(L, -1, "x");
Alternatively, push a Lua value of type string on the stack first and use lua_gettable for the lookup.
lua_pushliteral(L, "x");
lua_gettable(L, -2);
Don't forget to keep your stack balanced. Every value that you push on the stack needs to be popped properly. The Lua manual specifies how each API call changes the stack by the numbers in the \[ \] brackets on the right side of each function name.