- #define CFG_INPUT_SHIFT is used instead of a hardwired value
[sip-router] / cfg / cfg_ctx.c
index e19e65a..b13687f 100644 (file)
  */
 
 #include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "../ut.h"
 #include "cfg_struct.h"
 #include "cfg_ctx.h"
 
+
 /* linked list of all the registered cfg contexts */
 static cfg_ctx_t       *cfg_ctx_list = NULL;
 
@@ -118,33 +122,127 @@ void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
                        ctx->on_declare_cb(&gname, def);
 }
 
-/* convert the value to the requested type
- * (only string->str is implemented currently) */
+/*
+ * Convert an str into signed integer
+ * this function should be moved to ../ut.h
+ */
+static int str2sint(str* _s, int* _r)
+{
+       int i;
+       int sign;
+
+       if (_s->len == 0) return -1;
+
+       *_r = 0;
+       sign = 1;
+       i = 0;
+       if (_s->s[0] == '+') {
+               i++;
+       } else if (_s->s[0] == '-') {
+               sign = -1;
+               i++;
+       }
+       for(; i < _s->len; i++) {
+               if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
+                       *_r *= 10;
+                       *_r += _s->s[i] - '0';
+               } else {
+                       return -1;
+               }
+       }
+       *_r *= sign;
+
+       return 0;
+}
+
+
+/* placeholder for a temporary string */
+static char    *temp_string = NULL;
+
+/* convert the value to the requested type */
 static int convert_val(unsigned int val_type, void *val,
                        unsigned int var_type, void **new_val)
 {
        static str      s;
+       char            *end;
+       int             i;
+       static char     buf[INT2STR_MAX_LEN];
 
-       switch (val_type) {
-               case CFG_VAR_INT:
-                       if (CFG_INPUT_MASK(var_type) != CFG_INPUT_INT)
-                               goto error;
+       /* we have to convert from val_type to var_type */
+       switch (CFG_INPUT_MASK(var_type)) {
+       case CFG_INPUT_INT:
+               if (val_type == CFG_VAR_INT) {
                        *new_val = val;
                        break;
 
-               case CFG_VAR_STRING:
-                       if (CFG_INPUT_MASK(var_type) == CFG_INPUT_STR) {
-                               s.s = val;
-                               s.len = strlen(s.s);
-                               *new_val = (void *)&s;
-                               break;
+               } else if (val_type == CFG_VAR_STRING) {
+                       *new_val = (void *)(long)strtol((char *)val, &end, 10);
+                       if (*end != '\0') {
+                               LOG(L_ERR, "ERROR: convert_val(): "
+                                       "cannot convert string to integer '%s'\n",
+                                       s.s);
+                               return -1;
                        }
-                       if (CFG_INPUT_MASK(var_type) != CFG_INPUT_STRING)
-                               goto error;
+                       break;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       if (str2sint((str *)val, &i)) {
+                               LOG(L_ERR, "ERROR: convert_val(): "
+                                       "cannot convert string to integer '%.*s'\n",
+                                       ((str *)val)->len, ((str *)val)->s);
+                               return -1;
+                       }
+                       *new_val = (void *)(long)i;
+                       break;
+               }
+               goto error;
+
+       case CFG_INPUT_STRING:
+               if (val_type == CFG_VAR_INT) {
+                       buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
+                       *new_val = buf;
+                       break;
+
+               } else if (val_type == CFG_VAR_STRING) {
                        *new_val = val;
                        break;
-               default:
-                       goto error;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       /* the value may not be zero-terminated, thus,
+                       a new variable has to be allocated with larger memory space */
+                       if (temp_string) pkg_free(temp_string);
+                       temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
+                       if (!temp_string) {
+                               LOG(L_ERR, "ERROR: convert_val(): not enough memory\n");
+                               return -1;
+                       }
+                       memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
+                       temp_string[((str *)val)->len] = '\0';
+                       *new_val = (void *)temp_string;
+                       break;
+
+               }
+               goto error;
+
+       case CFG_INPUT_STR:
+               if (val_type == CFG_VAR_INT) {
+                       s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
+                       buf[s.len] = '\0';
+                       s.s = buf;
+                       *new_val = (void *)&s;
+                       break;
+
+               } else if (val_type == CFG_VAR_STRING) {
+                       s.s = (char *)val;
+                       s.len = strlen(s.s);
+                       *new_val = (void *)&s;
+                       break;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       *new_val = val;
+                       break;                  
+               }
+               goto error;
        }
 
        return 0;
@@ -155,6 +253,14 @@ error:
        return -1;
 }
 
+#define convert_val_cleanup() \
+       do { \
+               if (temp_string) { \
+                       pkg_free(temp_string); \
+                       temp_string = NULL; \
+               } \
+       } while(0)
+
 /* sets the value of a variable without the need of commit
  *
  * return value:
@@ -298,13 +404,22 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        group_name->len, group_name->s,
                        var_name->len, var_name->s,
                        (int)(long)val);
-       else
+
+       else if (val_type == CFG_VAR_STRING)
                LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
                        "has been changed to \"%s\"\n",
                        group_name->len, group_name->s,
                        var_name->len, var_name->s,
                        (char *)val);
 
+       else /* str type */
+               LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
+                       "has been changed to \"%.*s\"\n",
+                       group_name->len, group_name->s,
+                       var_name->len, var_name->s,
+                       ((str *)val)->len, ((str *)val)->s);
+
+       convert_val_cleanup();
        return 0;
 
 error:
@@ -318,6 +433,7 @@ error0:
                        var_name->len, var_name->s);
 
 
+       convert_val_cleanup();
        return -1;
 }
 
@@ -333,6 +449,12 @@ int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val
        return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
 }
 
+/* wrapper function for cfg_set_now */
+int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
+{
+       return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
+}
+
 /* returns the size of the variable */
 static int cfg_var_size(cfg_mapping_t *var)
 {
@@ -512,7 +634,8 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        var_name->len, var_name->s,
                        (int)(long)val,
                        ctx);
-       else
+
+       else if (val_type == CFG_VAR_STRING)
                LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
                        "is going to be changed to \"%s\" "
                        "[context=%p]\n",
@@ -521,6 +644,16 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        (char *)val,
                        ctx);
 
+       else /* str type */
+               LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
+                       "is going to be changed to \"%.*s\" "
+                       "[context=%p]\n",
+                       group_name->len, group_name->s,
+                       var_name->len, var_name->s,
+                       ((str *)val)->len, ((str *)val)->s,
+                       ctx);
+
+       convert_val_cleanup();
        return 0;
 
 error:
@@ -531,6 +664,7 @@ error0:
                        group_name->len, group_name->s,
                        var_name->len, var_name->s);
 
+       convert_val_cleanup();
        return -1;
 }
 
@@ -546,6 +680,12 @@ int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char
        return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
 }
 
+/* wrapper function for cfg_set_delayed */
+int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
+{
+       return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
+}
+
 /* commits the previously prepared changes within the context */
 int cfg_commit(cfg_ctx_t *ctx)
 {