*/
#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;
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;
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:
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:
var_name->len, var_name->s);
+ convert_val_cleanup();
return -1;
}
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)
{
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",
(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:
group_name->len, group_name->s,
var_name->len, var_name->s);
+ convert_val_cleanup();
return -1;
}
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)
{