lua-users home
lua-l archive

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


> maybe someone has done something like this before and there is am easy
and
> tried way to do it...

> I need to register some C functions from a lib into a table. But this
table
> is not in the global table, but a sub-table.

> so I need to register function foo() as lib.myname.foo()

> please see below for details.

I know why you want to do this. I don't think it is a good idea. LTN11 is
better.

However, it is easy enough to do. Just copy the code from luaL_openlib,
with the obvious substitutions.

For the pure pleasure of coding, here it is, typed straight into the
message so no guarantees that it will compile, work, or save humanity from
extinction:

/*
   Expects a table to be on the top of the stack, just underneath
   the upvalues.

   A more self-protective function might check for this.

   On return, the upvalues are popped and the table is still on
   top of the stack.

   This could be tail-called from a function which will return to Lua,
   so it conveniently returns 1.
*/

int put_closures_in_table(lua_State* L, const luaL_reg *list, int
nupvalues) {
  for (; list->name; list++) {
    int i;
    lua_pushstring(L, list->name);
    for (i = 0; i < nupvalues; i++) {
      lua_pushvalue(L, nupvalues + 1);
    }
    lua_pushcclosure(L, list->func, nupvalues);
    lua_settable(L, -(nupvalues+3));
  }
  lua_pop(L, nupvalues);
  return 1;
}


The above would be sufficient for the case where you are returning the
table and letting the caller decide where to put it, or where you are
memoising the table somewhere, and also returning it to the user. If you
were memoising, you might just want to use the whole dotted expression as a
key (why not?) but I have the sinking feeling that you will insist on
breaking into a nested table structure in which case, you will also want
the following:

/*
   The top of the stack should have a base table and then a string.
   The string is parsed into components separated by dots, and
   each component is looked up in the base table, creating a
   sub-table if necessary. No checking is made for valid names.
   It probably should be. The arguments are popped from the stack,
   and are replaced with the last table found or created.
*/

int get_subtable_from_dotted_string(lua_State* L) {
  const char* limit;
  const char* s = lua_tostring(L, -1);
  if (s == NULL) {
    luaL_typeerror(L, lua_gettop(L) - 1, "string");
  }
  limit = s + lua_strlen(L, -1);
  for (;;) {
    const char* e = strchr(s, '.');
    lua_pushlstring(L, s, (e ? e : limit) - s);
    lua_pushvalue(L, -1);   /* S: ... table string word word */
    lua_gettable(L, -4);    /* S: ... table string word sub-or-nil */
    if (lua_isnil(L, -1)) {
      lua_pop(L, 1);        /* S: ... table string word nil */
      lua_newtable(L);      /* S: ... table string word new */
      lua_pushvalue(L, -1);
      lua_insert(L, -3);    /* S: ... table string new word new */
      lua_settable(L, -5);  /* S: ... table string new */
      lua_replace(L, -3);   /* S: ... new string */
    } else {                /* S: ... table string word sub */
      lua_replace(L, -4);   /* S: ... sub string word */
      lua_pop(L, 1);        /* S: ... sub string */
    }
    if (e == NULL) break;
    s = e + 1;
  }
  lua_pop(L, 1);
  return 1;
}