uci/lua: add explicit close() method
[project/uci.git] / lua / uci.c
index 6382900..22055cb 100644 (file)
--- a/lua/uci.c
+++ b/lua/uci.c
 #define DPRINTF(...) do {} while (0)
 #endif
 
+#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
+
+/*
+ * ** Adapted from Lua 5.2.0
+ * */
+static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+       luaL_checkstack(L, nup+1, "too many upvalues");
+       for (; l->name != NULL; l++) {  /* fill the table with given functions */
+               int i;
+               lua_pushstring(L, l->name);
+               for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+                       lua_pushvalue(L, -(nup+1));
+               lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
+               lua_settable(L, -(nup + 3));
+       }
+       lua_pop(L, nup);  /* remove upvalues */
+}
+
+#define lua_rawlen(L, i) lua_objlen(L, i)
+
+#endif
+
 static struct uci_context *global_ctx = NULL;
 
 static struct uci_context *
@@ -91,11 +113,8 @@ find_package(lua_State *L, struct uci_context *ctx, const char *str, bool al)
                goto done;
        }
 
-       if (al == true)
+       if (al)
                uci_load(ctx, name, &p);
-       else if (al) {
-               uci_load(ctx, name, &p);
-       }
 
 done:
        if (name != str)
@@ -281,7 +300,7 @@ uci_lua_foreach(lua_State *L)
        ctx = find_context(L, &offset);
        package = luaL_checkstring(L, 1 + offset);
 
-       if (lua_isnil(L, 2))
+       if (lua_isnil(L, 2 + offset))
                type = NULL;
        else
                type = luaL_checkstring(L, 2 + offset);
@@ -566,7 +585,7 @@ uci_lua_set(lua_State *L)
        case 4:
                /* Format: uci.set("p", "s", "o", "v") */
                if (lua_istable(L, nargs)) {
-                       if (lua_objlen(L, nargs) < 1)
+                       if (lua_rawlen(L, nargs) < 1)
                                return luaL_error(L, "Cannot set an uci option to an empty table value");
                        lua_rawgeti(L, nargs, 1);
                        ptr.value = luaL_checkstring(L, -1);
@@ -596,7 +615,7 @@ uci_lua_set(lua_State *L)
        }
 
        if (istable) {
-               if (lua_objlen(L, nargs) == 1) {
+               if (lua_rawlen(L, nargs) == 1) {
                        i = 1;
                        if (ptr.o) {
                                v = ptr.value;
@@ -613,7 +632,7 @@ uci_lua_set(lua_State *L)
                                goto error;
                }
 
-               for (; i <= lua_objlen(L, nargs); i++) {
+               for (; i <= lua_rawlen(L, nargs); i++) {
                        lua_rawgeti(L, nargs, i);
                        ptr.value = luaL_checkstring(L, -1);
                        err = uci_add_list(ctx, &ptr);
@@ -753,7 +772,7 @@ uci_lua_add_change(lua_State *L, struct uci_element *e)
                         * list_add, append this value to table */
                        } else {
                                lua_pushstring(L, value);
-                               lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
+                               lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
                        }
 
                /* non-list change, simply set/replace field */
@@ -892,10 +911,41 @@ uci_lua_set_savedir(lua_State *L)
 }
 
 static int
+uci_lua_list_configs(lua_State *L)
+{
+       struct uci_context *ctx;
+       char **configs = NULL;
+       char **ptr;
+       int i = 1;
+
+       ctx = find_context(L, NULL);
+       if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs)
+               return uci_push_status(L, ctx, false);
+       lua_newtable(L);
+       for (ptr = configs; *ptr; ptr++) {
+               lua_pushstring(L, *ptr);
+               lua_rawseti(L, -2, i++);
+       }
+       free(configs);
+       return 1;
+}
+
+static int
 uci_lua_gc(lua_State *L)
 {
-       struct uci_context *ctx = find_context(L, NULL);
-       uci_free_context(ctx);
+       struct uci_context **ctx;
+
+       if (!lua_isuserdata(L, 1)) {
+               if (!global_ctx)
+                       return 0;
+               ctx = &global_ctx;
+       } else {
+               ctx = luaL_checkudata(L, 1, METANAME);
+               if (!*ctx)
+                       return 0;
+       }
+       uci_free_context(*ctx);
+       *ctx = NULL;
        return 0;
 }
 
@@ -931,6 +981,7 @@ uci_lua_cursor(lua_State *L)
 
 static const luaL_Reg uci[] = {
        { "__gc", uci_lua_gc },
+       { "close", uci_lua_gc },
        { "cursor", uci_lua_cursor },
        { "load", uci_lua_load },
        { "unload", uci_lua_unload },
@@ -952,6 +1003,7 @@ static const luaL_Reg uci[] = {
        { "set_confdir", uci_lua_set_confdir },
        { "get_savedir", uci_lua_get_savedir },
        { "set_savedir", uci_lua_set_savedir },
+       { "list_configs", uci_lua_list_configs },
        { NULL, NULL },
 };
 
@@ -967,11 +1019,14 @@ luaopen_uci(lua_State *L)
        lua_setfield(L, -2, "__index");
 
        /* fill metatable */
-       luaL_register(L, NULL, uci);
+       luaL_setfuncs(L, uci, 0);
        lua_pop(L, 1);
 
        /* create module */
-       luaL_register(L, MODNAME, uci);
+       lua_newtable(L);
+       lua_pushvalue(L, -1);
+       luaL_setfuncs(L, uci, 0);
+       lua_setglobal(L, MODNAME);
 
-       return 0;
+       return 1;
 }