src/config.c
changeset 100 cfb7776bd6f0
parent 83 c8e2dac08207
child 120 576bab0a1c5a
--- a/src/config.c	Tue Mar 31 23:35:24 2009 +0300
+++ b/src/config.c	Tue Mar 31 23:36:05 2009 +0300
@@ -1,21 +1,140 @@
 #include "config.h"
 
 #include <string.h>
+#include <assert.h>
 
-err_t config_apply (struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err)
+const struct config_option* config_lookup (const struct config_option *options, const char *name, struct error_info *err)
 {
-    struct config_option *option;
+    const struct config_option *option;
 
     // find the matching config opt
     for (option = options; option->name && option->type; option++) {
         if (strcmp(option->name, name) == 0)
+            return option;
+    }
+
+    // not found
+    SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown configuration option");
+
+    return NULL;
+}
+
+/**
+ * Parse a raw value for a CONFIG_IRC_CHAN into an irc_chan
+ */
+static struct irc_chan* config_parse_irc_chan (struct nexus *nexus, char *raw_value, struct error_info *err)
+{
+    const char *network, *channel;
+    struct irc_chan *chan;
+
+    // parse required args
+    if ((network = strsep(&raw_value, "/")) == NULL)
+        JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "invalid <network> for CONFIG_IRC_CHAN value");
+
+    if ((channel = strsep(&raw_value, "/")) == NULL)
+        JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "invalid <channel> for CONFIG_IRC_CHAN value");
+    
+    // extraneous stuff?
+    if (raw_value)
+        JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "trailing data for CONFIG_IRC_CHAN value");
+    
+    // get the channel?
+    if ((chan = irc_client_get_chan(nexus->client, network, channel)) == NULL)
+        JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown network/channel name for CONFIG_IRC_CHAN value");
+    
+    // ok
+    return chan;
+
+error:
+    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)
+{
+    // parse the value 
+    switch (option->type) {
+        case CONFIG_STRING:
+            // simple!
+            value->string = raw_value;
             break;
+
+        case CONFIG_IRC_CHAN:
+            // parse the value
+            if (!(value->irc_chan = config_parse_irc_chan(nexus, raw_value, err)))
+                return ERROR_CODE(err);
+
+            break;
+        
+        default:
+            NOT_REACHED();
     }
 
+    // copy the type
+    value->type = option->type;
+
+    // ok
+    return SUCCESS; 
+}
+
+err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value *value, struct error_info *err)
+{
+    // wrong type?
+    if (option->type != value->type)
+        // XXX: info about type names
+        return SET_ERROR(err, ERR_CONFIG_TYPE);
+
+    // null?
+    if (!value)
+        RETURN_SET_ERROR_STR(err, ERR_CONFIG_REQUIRED, option->name);
+    
+    // call the handler
+    switch (option->type) {
+        case CONFIG_STRING:     return option->func.string(ctx, value->string, err);
+        case CONFIG_IRC_CHAN:   return option->func.irc_chan(ctx, value->irc_chan, err);
+        default:                NOT_REACHED();
+    }
+}
+
+err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value *value, struct error_info *err)
+{
+    const struct config_option *option;
+
     // no matching option found?
-    if (!option)
-        RETURN_SET_ERROR_STR(err, ERR_CONFIG_NAME, name);
+    if (!(option = config_lookup(options, name, err)))
+        return ERROR_CODE(err);
+    
+    // apply it    
+    return config_apply_opt(option, ctx, value, err);
+}
 
-    // call the handler
-    return option->func(ctx, value, err);
+err_t config_apply_string (const struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err)
+{
+    struct config_value conf_value = { CONFIG_STRING, { .string = value } };
+
+    return config_apply(options, ctx, name, &conf_value, err);
 }
+
+err_t config_apply_irc_chan (const struct config_option *options, void *ctx, const char *name, struct irc_chan *value, struct error_info *err)
+{
+    struct config_value conf_value = { CONFIG_STRING, { .irc_chan = value } };
+
+    return config_apply(options, ctx, name, &conf_value, err);
+}
+
+err_t config_apply_raw (const struct config_option *options, struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err)
+{
+    const struct config_option *option;
+    struct config_value value;
+
+    // no matching option found?
+    if (!(option = config_lookup(options, name, err)))
+        return ERROR_CODE(err);
+    
+    // parse it
+    if (config_parse(option, nexus, &value, raw_value, err))
+        return ERROR_CODE(err);
+    
+    // apply it
+    return config_apply_opt(option, ctx, &value, err);
+}
+