start implementing multiple args for lua_module_conf
authorTero Marttila <terom@fixme.fi>
Fri, 10 Apr 2009 22:43:49 +0300
changeset 122 52ffbdb6bba1
parent 121 4682ebbc5644
child 123 dc80e4599fb8
start implementing multiple args for lua_module_conf
src/config.c
src/config.h
src/lua_objs.c
--- a/src/config.c	Wed Apr 08 02:25:30 2009 +0300
+++ b/src/config.c	Fri Apr 10 22:43:49 2009 +0300
@@ -19,6 +19,18 @@
     return NULL;
 }
 
+int config_params_count (const struct config_option *option)
+{
+    const struct config_param *param;
+    int count = 0;
+
+    // handle each param
+    for (param = option->params; param->name && param->type; param++)
+        count++;
+
+    return count;
+}
+
 /**
  * Parse a raw value for a CONFIG_IRC_CHAN into an irc_chan
  */
@@ -51,15 +63,8 @@
     return NULL;    
 }
 
-err_t config_parse (const struct config_option *option, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err)
+err_t config_parse_param (const struct config_param *param, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err)
 {
-    // use the first param
-    const struct config_param *param = &option->params[0];
-
-    // must have exactly one param
-    if (!param->type || (param + 1)->type)
-        return SET_ERROR(err, ERR_CONFIG_PARAMS);
-
     // parse the value 
     switch (param->type) {
         case CONFIG_STRING:
@@ -74,6 +79,10 @@
 
             break;
         
+        case CONFIG_USER:
+            // fail
+            return SET_ERROR_STR(err, ERR_CONFIG_TYPE, "user type can't be parsed");
+
         default:
             NOT_REACHED();
     }
@@ -85,6 +94,19 @@
     return SUCCESS; 
 }
 
+err_t config_parse (const struct config_option *option, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err)
+{
+    // use the first param
+    const struct config_param *param = &option->params[0];
+
+    // must have exactly one param
+    if (!param->type || (param + 1)->type)
+        return SET_ERROR(err, ERR_CONFIG_PARAMS);
+    
+    // parse it
+    return config_parse_param(param, nexus, value, raw_value, err);
+}
+
 err_t config_check_param (const struct config_param *param, const struct config_value *value, struct error_info *err)
 {
     // no value given?
--- a/src/config.h	Wed Apr 08 02:25:30 2009 +0300
+++ b/src/config.h	Fri Apr 10 22:43:49 2009 +0300
@@ -168,16 +168,30 @@
  */
 const struct config_option* config_lookup (const struct config_option *options, const char *name, struct error_info *err);
 
+/**
+ * Returns the number of params that an option has
+ *
+ * @param option the option to count
+ * @return the number of params
+ */
+int config_params_count (const struct config_option *option);
+
 // XXX: move this into nexus
 #include "nexus.h"
 /**
- * Parse a raw value into a suitable configuration value for a single-param option, based on the config option type.
+ * Parse a raw value into a suitable configuration value for the given param, based on its type.
  *
  * Since this needs to access the application state, you need to pass in the nexus as an argument.
  *
  * Formats supported:
  *  CONFIG_IRC_CHAN         - uses a '<network>/<channel>' format and irc_client_get_chan
  *
+ */
+err_t config_parse_param (const struct config_param *param, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err);
+
+/**
+ * Parse a raw value into a suitable configuration value for a single-param option, based on the config option type.
+ *
  * @param option the option to parse the value for, use config_lookup to find it
  * @param nexus the application state
  * @param value the returned value, if succesfull
--- a/src/lua_objs.c	Wed Apr 08 02:25:30 2009 +0300
+++ b/src/lua_objs.c	Fri Apr 10 22:43:49 2009 +0300
@@ -103,92 +103,121 @@
     return 0;
 }
 
-/**
- * Parse and apply the given config option value as a raw value to the given module's option
- */
-static int _lua_module_conf_raw_str (lua_State *L, struct lua_module *lua_module, struct nexus *nexus, 
-        const struct config_option *option, const char *conf_value)
-{
-    struct config_value value;
-    struct error_info err;
-
-    // mutable version of the conf_value
-    char conf_value_buf[strlen(conf_value) + 1];
-    strcpy(conf_value_buf, conf_value);
-
-    // parse it as a raw value
-    if (config_parse(option, nexus, &value, conf_value_buf, &err))
-        return luaL_error(L, "config_parse: %s/%s: %s", option->name, conf_value_buf, error_msg(&err));
-    
-    // apply it while conf_value_buf is still in scope
-    if (module_conf(lua_module->module, option, &value, &err))
-        return luaL_error(L, "module_conf: %s/%s: %s", module_name(lua_module->module), option->name, error_msg(&err));
-    
-    // ok
-    return 0;
-}
-
 static int lua_module_conf (lua_State *L)
 {
     struct lua_module *lua_module = lua_obj_get_obj(L, __func__, "spbot.module");
     const struct config_option *option;
-    struct config_value values[2] = {
-        CONFIG_VALUE_END,
-        CONFIG_VALUE_END
-    }, *value = &values[0];
+    struct config_value values[CONFIG_VALUES_MAX], *value = values;
+    char *value_bufs[CONFIG_VALUES_MAX], **value_buf = value_bufs;
     struct error_info err;
+    bool is_err = true;
+
+    // number of arguments given
+    int nargs = lua_gettop(L), argidx = 2;
+
+    // init to zero
+    memset(values, 0, sizeof(values));
+    memset(value_bufs, 0, sizeof(value_bufs));
 
     // XXX: come up with some better way...
     struct nexus *nexus = lua_module->module->modules->nexus;
 
     // the config name
-    const char *conf_name = luaL_checkstring(L, 2);
+    const char *conf_name = luaL_checkstring(L, argidx++);
 
     // look it up
     if ((option = module_conf_lookup(lua_module->module, conf_name, &err)) == NULL)
         return luaL_error(L, "module_conf_lookup: %s/%s: %s", module_name(lua_module->module), conf_name, error_msg(&err));
- 
-    // the config value
-    switch (lua_type(L, 3)) {
-        case LUA_TSTRING:
-            // parse+apply it as a raw string
-            return _lua_module_conf_raw_str(L, lua_module, nexus, option, lua_tostring(L, 3));
-
-        case LUA_TUSERDATA:
-            // some kind of userdata, use its metatable to figure out what type it is
-            if (!lua_getmetatable(L, 3))
-                return luaL_error(L, "config value is userdata without metatable");
-
-            // get the target metatable
-            lua_getfield(L, LUA_REGISTRYINDEX, "evirc.chan");
 
-            // is it a chan?
-            if (!lua_rawequal(L, -1, -2))
-                return luaL_error(L, "config value is userdata of unknown type");
-
-            // pop the metatables
-            lua_pop(L, 2);
+    // maximum number of arguments accepted
+    int maxargs = config_params_count(option);
 
-            // get the irc_chan
-            struct lua_chan *lua_chan = lua_touserdata(L, 3);
+    // too many arguments?
+    if (nargs > maxargs)
+        return luaL_error(L, "lua_module_conf: too many arguments (>%d) given (%d)", maxargs, nargs - 3);
+    
+    // the current param
+    const struct config_param *param = option->params;
 
-            // build the value
-            value->type = CONFIG_IRC_CHAN;
-            value->irc_chan = lua_chan->chan;
+    // apply each given argument
+    for (; argidx <= nargs; argidx++, value++, param++) {
+        // the config value
+        switch (lua_type(L, argidx)) {
+            case LUA_TSTRING: {
+                // string arg
+                const char *arg_str = lua_tostring(L, argidx);
+
+                // copy it as a mutable string buffer
+                if ((*value_buf = strdup(arg_str)) == NULL) {
+                    lua_pushfstring(L, "strdup");
+                    goto error;
+                }
+
+                // parse it as a raw value
+                if (config_parse_param(param, nexus, value, *value_buf, &err)) {
+                    lua_pushfstring(L, "config_parse: %s/%s: %s", option->name, *value_buf, error_msg(&err));
+                    goto error;
+                }
+
+                // seek to next value_buf
+                value_buf++;
+
+            } break;
+    
+            case LUA_TUSERDATA:
+                // some kind of userdata, use its metatable to figure out what type it is
+                if (!lua_getmetatable(L, argidx)) {
+                    lua_pushfstring(L, "config value is userdata without metatable");
+                    goto error;
+                }
+
+                // get the target metatable
+                lua_getfield(L, LUA_REGISTRYINDEX, "evirc.chan");
+
+                // is it a chan?
+                if (!lua_rawequal(L, -1, -2)) {
+                    lua_pushfstring(L, "config value is userdata of unknown type");
+                    goto error;
+                }
+
+                // pop the metatables
+                lua_pop(L, 2);
+
+                // get the irc_chan
+                struct lua_chan *lua_chan = lua_touserdata(L, argidx);
+
+                // build the value
+                value->type = CONFIG_IRC_CHAN;
+                value->irc_chan = lua_chan->chan;
+                
+                break;
             
-            break;
-        
-        default:
-            return luaL_error(L, "config value is of unknown lua type '%s'", lua_typename(L, 3));
+            default:
+                lua_pushfstring(L, "config value is of unknown lua type '%s'", lua_typename(L, argidx));
+                goto error;
 
+        }
+    }
+
+    // apply it
+    if (module_conf(lua_module->module, option, values, &err)) {
+        lua_pushfstring(L, "module_conf: %s/%s: %s", module_name(lua_module->module), option->name, error_msg(&err));
+        goto error;
     }
     
-    // apply it
-    if (module_conf(lua_module->module, option, values, &err))
-        return luaL_error(L, "module_conf: %s/%s: %s", module_name(lua_module->module), option->name, error_msg(&err));
-   
     // ok
-    return 0;
+    is_err = false;
+
+error:
+    // release any allocated strings
+    for (value_buf = value_bufs; value_buf <= value_bufs + CONFIG_VALUES_MAX && *value_buf; value_buf++)
+        free(*value_buf);
+    
+    // either error or successful return
+    if (is_err)
+        return lua_error(L);
+    else
+        return 0;
 }
 
 static int lua_module_unload (lua_State *L)