1

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.

idbrii
  • 10,975
  • 5
  • 66
  • 107
halm
  • 104
  • 3
  • 10
  • I've tried doing that too some time ago and ended up writing https://github.com/d-led/luastackcrawler . Once you crawl the stack, you can get out the table, taking care of circular references as well, but I do not have a sufficient test yet to show that it works. You might want to contribute. Try it out :). The place to start: [luavalue.h](https://github.com/d-led/luastackcrawler/blob/master/luatablestack/luavalue.h) – Dmitry Ledentsov Jun 07 '13 at 10:15

1 Answers1

6

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.

idbrii
  • 10,975
  • 5
  • 66
  • 107
Enigma
  • 1,699
  • 10
  • 14
  • which means that cmd1 and cmd2 should also range from [1..2] – Enigma Jun 07 '13 at 06:53
  • Thank you SO much. I *think* I understand ... will try it out tomorrow and then hopefully I *will* understand. Thanks again. – halm Jun 07 '13 at 07:09
  • Thanks *Enigma* ... that worked perfectly ... no changes at all to what you suggested. Better still, I think it understand it. Thanks for adding comments to your suggested code. – halm Jun 07 '13 at 21:49
  • Dmitri ... I'll see if I can use what I've learned from *Enigma* and contribute. – halm Jun 07 '13 at 21:51