lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Thanks! That got me past the user data question. My next question is to see if I understand how to work with tables from within the C API.

Here's a C function that should take a string and a table.
1. Error if the first argument is not a string.
2. Error if the second argument is not a table.
3. Error if there is not a "name" field in the table.
4. Append the string to the "name" field in the table.
5. If there is not a "type" field in the table, add a "type" field with the value of "default".

When I run the script, I get the results that I'm expecting. Is my approach from the C side a sound approach?

------------------------------------------------------------
-- lua script. src is set to a class from the API
--
t = {name="foo"}
print("t.name", t.name)
print("t.type", t.type)
src:SillyFunc("x", t)
print("t.name", t.name)
print("t.type", t.type)


------------------------------------------------------------
-- output
--
t.name  foo
t.type  nil
silly: suffix is 'x'
silly: top of stack is 'foo'
silly: concat stack is 'foox'
silly: field  stack is 'name'
silly:        stack is 'foox'
silly: field  stack is 'foox'
silly:        stack is 'name'
silly: not of stack is 'foox'
t.name  foox
t.type  default


//----------------------------------------------------------
// C API
//----------------------------------------------------------
// SillyFunc(string, table)
//
int CSV_silly(lua_State *L) {
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}

     // first argument must be self
     myCSV *csv = (myCSV *)luaL_checkudata(L, 1, libName);

     // second argument must be string
     const char *suffix = luaL_checkstring(L, 2);
     printf("silly: suffix is '%s'\n", suffix);

     // third argument must be table
     if (!lua_istable(L, 3)) {
          error(L, "we demand table for 3rd parameter");
          return 0;
     }

     const char *key = "name";

     // get field value from the table
     lua_pushstring(L, key);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "name"

     lua_gettable(L, 3);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> table.foo which is string "foo"

     // confirm that we have a value for that field
     printf("silly: top of stack is '%s'\n", luaL_checkstring(L, -1));
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foo"

     // concatenate the suffix to the field
     lua_pushstring(L, suffix);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foo"
     //      : 5 -> string "x"
     lua_concat(L, 2);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foox"

     // confirm that the concat worked
     printf("silly: concat stack is '%s'\n", luaL_checkstring(L, -1));
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foox"

     // update the table with the concat'd value

     // push the field name
     lua_pushstring(L, key);
     printf("silly: field  stack is '%s'\n", luaL_checkstring(L, -1));
     printf("silly:        stack is '%s'\n", luaL_checkstring(L, -2));
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foox"
     //      : 5 -> string "name"

     // settable expects the top of the stack to have the value,
     // then the field name. we're the other way around, so swap
     // them
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "foox"      -- field value
     //      : 5 -> string "name"      -- field name
     lua_insert(L, -2);
     printf("silly: field  stack is '%s'\n", luaL_checkstring(L, -1));
     printf("silly:        stack is '%s'\n", luaL_checkstring(L, -2));
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foo"}
     //      : 4 -> string "name"      -- field name
     //      : 5 -> string "foox"      -- field value

     // now call settable to update the table on the stack
     lua_settable(L, 3);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}

     // get field value from the table
     lua_pushstring(L, key);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}
     //      : 4 -> string "name"

     lua_gettable(L, 3);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}
     //      : 4 -> table.foo which is string "foo"

     // confirm that we have a value for that field
     printf("silly: not of stack is '%s'\n", luaL_checkstring(L, -1));

     // get rid of the value from the stack
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}
     //      : 4 -> string "foox"
     lua_pop(L, 1);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}

     // check to see if the table has a field "type"
     key = "type";
     lua_pushstring(L, key);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}
     //      : 4 -> string "type"

     lua_gettable(L, 3);
     // stack: 1 -> table  myCSV
     //      : 2 -> string "x"
     //      : 3 -> table  {name="foox"}
     //      : 4 -> table.type which is nil

     if (lua_isnil(L, -1)) {
           // no value, so provide a default value for the type field in the table
           // stack: 1 -> table  myCSV
           //      : 2 -> string "x"
           //      : 3 -> table  {name="foox"}
           //      : 4 -> nil

           // get rid of that value since we won't use it
           lua_pop(L, 1);
           // stack: 1 -> table  myCSV
           //      : 2 -> string "x"
           //      : 3 -> table  {name="foox"}

           // push the field name to update
           lua_pushstring(L, key);
           // stack: 1 -> table  myCSV
           //      : 2 -> string "x"
           //      : 3 -> table  {name="foox"}
           //      : 4 -> string "type"

           // push the default value
           lua_pushstring(L, "default");
           // stack: 1 -> table  myCSV
           //      : 2 -> string "x"
           //      : 3 -> table  {name="foox"}
           //      : 4 -> string "type"
           //      : 5 -> string "default"

           // call settable to update the table on the stack
           lua_settable(L, 3);
           // stack: 1 -> table  myCSV
           //      : 2 -> string "x"
           //      : 3 -> table  {name="foox", type="default"}
     }

     return 0;
}