There are 2 things you need to watch:
- ensure the original key is left on the stack before the next call to
lua_next
. luaL_checkstring
will convert non-string keys to strings (as the resulting string is not in the table, it becomes an invalid key.) This is most easily done by passing luaL_checkstring
a copy of the key instead of the original.
- ensure you preserve the stack structure (i.e. pop as many values as you push) on each pass through the loop
Your function will only work for negative values of index
. You are correct that index--;
will ensure that index
still points to the table after pushing the key, but only if index
was negative (i.e. relative to the top of the stack.) If index
is an absolute or pseudo index then it this will cause it to point to the wrong item. The easiest workaround is to push another reference to the table onto the top of the stack.
Here's a minimal C program to demonstrate:
#include <lauxlib.h>
#include <lua.h>
static void iterate_and_print(lua_State *L, int index);
int main(int ac, char **av)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Create a table and put it on the top of the stack
luaL_loadstring(L, "return {one=1,[2]='two',three=3}");
lua_call(L, 0, 1);
iterate_and_print(L, -1);
return 0;
}
static void iterate_and_print(lua_State *L, int index)
{
// Push another reference to the table on top of the stack (so we know
// where it is, and this function can work for negative, positive and
// pseudo indices
lua_pushvalue(L, index);
// stack now contains: -1 => table
lua_pushnil(L);
// stack now contains: -1 => nil; -2 => table
while (lua_next(L, -2))
{
// stack now contains: -1 => value; -2 => key; -3 => table
// copy the key so that lua_tostring does not modify the original
lua_pushvalue(L, -2);
// stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
const char *key = lua_tostring(L, -1);
const char *value = lua_tostring(L, -2);
printf("%s => %s\n", key, value);
// pop value + copy of key, leaving original key
lua_pop(L, 2);
// stack now contains: -1 => key; -2 => table
}
// stack now contains: -1 => table (when lua_next returns 0 it pops the key
// but does not push anything.)
// Pop table
lua_pop(L, 1);
// Stack is now the same as it was on entry to this function
}
Best Answer
In lua 5.1, you can iterate of the characters of a string this in a couple of ways.
The basic loop would be:
But it may be more efficient to use a pattern with
string.gmatch()
to get an iterator over the characters:Or even to use
string.gsub()
to call a function for each char:In all of the above, I've taken advantage of the fact that the
string
module is set as a metatable for all string values, so its functions can be called as members using the:
notation. I've also used the (new to 5.1, IIRC)#
to get the string length.The best answer for your application depends on a lot of factors, and benchmarks are your friend if performance is going to matter.
You might want to evaluate why you need to iterate over the characters, and to look at one of the regular expression modules that have been bound to Lua, or for a modern approach look into Roberto's lpeg module which implements Parsing Expression Grammers for Lua.