[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: How to traverse a Lua table in C?
- From: David Jeske <jeske@...>
- Date: Wed, 2 Dec 1998 13:44:14 -0800
On Wed, Dec 02, 1998 at 06:28:14PM -0200, Jon Kleiser wrote:
> I'm about to write some C functions to provide Mac Lua with some
> (hopefully) flexible dialog boxes. My idea was to let my Lua script define
> the dialog box on the fly through a Lua table/list of item specs, somewhat
> like this:
>
> name, pwd = dialog{{type=btn, name="OK"},{type=btn, name="Cancel"},
> {type=fld, name="Name"},{type=pwfld, name="Password"}}
You should look at the Lua/Tk binding for ideas..
> In "5.5 - How do I traverse a table in C?*" in the Lua FAQ, the suggestion is:
>
> lua_pushobject(table);
> lua_pushcfunction(f);
> lua_call("foreach");
>
> I'm suspecting, however, that this technique may not be very useful to me.
> Will it be safe to have a Lua script call a C function that in turn calls
> lua_call("foreach") ? If it is safe, I may just end up with a lot of
> smaller units on lua2C, instead of a table ...
>
> (I guess the proper name for "lua_call" is now "lua_callfunction".)
The method above is much simpler than what you have to do if you want
to walk the table entirely from C-code. I have some loops in my
software which do just this, and they are pretty nasty. The problem is
that you have to convert lots of stuff to lua_refs to make sure the
pointer dosn't get pulled out from under you.
I've attached a snipppit of code which I use to walk a lua table and
pull out data. I'd love to come up with a more structured way to do
this on the C side, but so far I've not come up with it. Here is the
small code snippit, and the attachment contains the whole method it
came from:
// count the entries (table_len), remember to account
// for the index string
next_fn = lua_getglobal("next"); // get the "next(a,b);" function
temp_ref = LUA_NOOBJECT; // set to nil
do {
lua_beginblock();
lua_pushobject(lua_getref(table_ref));
if (temp_ref == LUA_NOOBJECT) {
lua_pushnil();
} else {
lua_pushobject(lua_getref(temp_ref));
}
if (lua_callfunction(next_fn)) {
// an error occured!!!
lua_error("error calling next() builtin Lua function");
}
// now get off the two return values
tbl_idx = lua_getresult(1); // index, should be a string
// or number
tbl_val = lua_getresult(2); // value, should be a table,
// unless it's the indexname
if (lua_istable(tbl_val)) {
// the value is another table, so store and count it
table_len++;
}
if (!lua_isnil(tbl_idx)) {
// we're not going to exit the loop this time!
lua_pushobject(tbl_idx);
temp_ref = lua_ref(0); // not locked
}
lua_endblock();
} while (!lua_isnil(tbl_idx));
--
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@chat.net
void SpriteType::parseSpriteTable(SPRITECHUNK **dest, lua_Object a_tbl) {
lua_Object next_fn, temp_ref, tbl_idx, tbl_val;
int table_len = 0;
int curindex = 0;
int cur_count = 0;
int index_ref, value_ref;
int table_ref;
char *index_string;
IMAGELIST *a_list = NULL; // in case this is a list
IMAGE *an_image = NULL; // in case this is an image
// check that we have a table
dbgMsg(c_excessive,"SpriteType::parseSpriteType() entered.\n");
if (!lua_istable(a_tbl)) {
lua_error("SpriteType::parseSpriteTable() passed non-table.");
}
lua_pushobject(a_tbl);
table_ref = lua_ref(0);
// get the index string
{
lua_Object index_string_obj;
lua_pushobject(lua_getref(table_ref));
lua_pushstring("IndexedBy");
if (lua_isstring(index_string_obj = lua_gettable())) {
index_string = lua_getstring(index_string_obj);
} else {
index_string = NULL;
}
}
// count the entries (table_len), remember to account for the index string
next_fn = lua_getglobal("next"); // get the "next(a,b);" function
temp_ref = LUA_NOOBJECT; // set to nil
do {
lua_beginblock();
lua_pushobject(lua_getref(table_ref));
if (temp_ref == LUA_NOOBJECT) {
lua_pushnil();
} else {
lua_pushobject(lua_getref(temp_ref));
}
if (lua_callfunction(next_fn)) {
// an error occured!!!
lua_error("error calling next() builtin Lua function");
}
// now get off the two return values
tbl_idx = lua_getresult(1); // index, should be a string or number
tbl_val = lua_getresult(2); // value, should be a table, unless it's the indexname
if (lua_istable(tbl_val)) {
// the value is another table, so store and count it
table_len++;
}
if (!lua_isnil(tbl_idx)) {
// we're not going to exit the loop this time!
lua_pushobject(tbl_idx);
temp_ref = lua_ref(0); // not locked
}
lua_endblock();
} while (!lua_isnil(tbl_idx));
// check if we have another sprite chunk or an actual image
if (index_string) {
// we have another list of sprite chunks
printf("Table(IndexedBy = %s) with %d elements\n",index_string,table_len);
// allocate the table!!!
// should this be "table_len - 1" below???
(*dest) = (SPRITECHUNK *)malloc(sizeof(SPRITECHUNK) + (sizeof(IMAGELISTENTRY) * table_len));
(*dest)->content_type = TYPE_IMAGELIST;
a_list = &((*dest)->content.im_list);
a_list->list_len = table_len;
// check if the index is a builtin
if (index_string[0] == '@') {
// it's a builtin!
a_list->index_type = PREDEF_INDEX;
a_list->predef_index_type = lookup_builtin(index_string);
} else {
// it's a lua variable
a_list->index_type = LUA_VAR;
if (strlen(index_string) > sizeof(a_list->luavar_name)) {
lua_error("IndexedBy name too big in table"); // should do better than this
}
strcpy(a_list->luavar_name, index_string);
}
// now go through the table AGAIN and do something which each element
dbgMsg(c_excessive,"starting table parse\n");
temp_ref = LUA_NOOBJECT; // set to nil
curindex = 0;
cur_count = 0;
int reached_end = 0;
do {
lua_beginblock();
lua_pushobject(lua_getref(table_ref));
if (cur_count++ == 0) {
dbgMsg(c_excessive,"DrawAt(): pushed nil\n");
lua_pushnil();
} else {
lua_pushobject(lua_getref(temp_ref));
}
if (lua_callfunction(next_fn)) {
// an error occured!!!
lua_error("error calling next() builtin Lua function");
}
// now get off the two return values
tbl_idx = lua_getresult(1); // index, should be a string or number
tbl_val = lua_getresult(2); // value, should be a table, unless it's the indexname
lua_pushobject(tbl_idx);
index_ref = lua_ref(0);
lua_pushobject(tbl_val);
value_ref = lua_ref(0);
if (lua_isnil(tbl_idx)) {
// no more elements in the table...
dbgMsg(c_excessive,"end of table reached\n");
break; // exit the while loop!
}
if (lua_isstring(tbl_idx)) {
reached_end = lua_isnil(lua_getref(index_ref)); // what's with this?
dbgMsg(c_excessive,"handle element(%d/%d/%d): %s\n",curindex,table_len,
reached_end,lua_getstring(lua_getref(index_ref)));
// don't count it because it's a string
}
if (lua_istable(lua_getref(value_ref))) {
//the value is another table, so store and count it
if (curindex < table_len) {
if (lua_isstring(lua_getref(index_ref))) {
strcpy(a_list->list[curindex].name,lua_getstring(lua_getref(index_ref))); // size check!!
lua_beginblock();
this->parseSpriteTable(&(a_list->list[curindex].ptr),lua_getref(value_ref)); // recurse
lua_endblock();
} else {
dbgMsg(c_error,"non-string index on sprite chunk!\n");
lua_error("can't allow sprite chunk with non-string index currently");
}
}
curindex++;
}
temp_ref = index_ref;
dbgMsg(c_excessive,"Finished parse (%d/%d/%d)\n",
curindex,table_len,lua_isnil(lua_getref(temp_ref)));
lua_endblock();
} while ((!lua_isnil(lua_getref(temp_ref))) && (curindex < table_len));
// and sort them
} else {
// we have an actual image
char *image_name;
// print it out !
// lua_pushobject(a_table);
// lua_call("printTables");
lua_pushobject(lua_getref(table_ref));
lua_pushnumber(1.0f);
if ((image_name = lua_getstring(lua_gettable())) != NULL) {
dbgMsg(c_excessive,"Loading image [%s]...\n",image_name);
} else {
lua_error("Failed loading image, first element not string");
}
// allocate the image
(*dest) = (SPRITECHUNK *)malloc(sizeof(SPRITECHUNK));
(*dest)->content_type = TYPE_IMAGE;
an_image = &((*dest)->content.im_data);
this->loadImage(an_image,image_name);
}
return;