#include <string.h>
#include <stdlib.h>
#include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
#include "ucimap.h"
struct uci_alloc {
}
static inline bool
+ucimap_is_list_auto(enum ucimap_type type)
+{
+ return ucimap_is_list(type) && !!(type & UCIMAP_LIST_AUTO);
+}
+
+static inline bool
ucimap_is_custom(enum ucimap_type type)
{
return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
f->name = str;
f->type = om->type;
f->data = data;
- list_add(&f->list, &map->fixup);
+ list_add_tail(&f->list, &map->fixup);
}
static void
{
union ucimap_data tdata = *data;
char *eptr = NULL;
+ long lval;
char *s;
int val;
ucimap_add_alloc(sd, s);
break;
case UCIMAP_BOOL:
- val = -1;
- if (strcmp(str, "on"))
+ if (!strcmp(str, "on"))
val = true;
- else if (strcmp(str, "1"))
+ else if (!strcmp(str, "1"))
val = true;
- else if (strcmp(str, "enabled"))
+ else if (!strcmp(str, "enabled"))
val = true;
- else if (strcmp(str, "off"))
+ else if (!strcmp(str, "off"))
val = false;
- else if (strcmp(str, "0"))
+ else if (!strcmp(str, "0"))
val = false;
- else if (strcmp(str, "disabled"))
+ else if (!strcmp(str, "disabled"))
val = false;
- if (val == -1)
+ else
return;
tdata.b = val;
break;
case UCIMAP_INT:
- val = strtol(str, &eptr, om->data.i.base);
+ lval = strtol(str, &eptr, om->data.i.base);
+ if (lval < INT_MIN || lval > INT_MAX)
+ return;
+
if (!eptr || *eptr == '\0')
- tdata.i = val;
+ tdata.i = (int) lval;
else
return;
break;
}
+static void
+ucimap_convert_list(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
+{
+ char *s, *p;
+
+ s = strdup(str);
+ if (!s)
+ return;
+
+ ucimap_add_alloc(sd, s);
+
+ do {
+ while (isspace(*s))
+ s++;
+
+ if (!*s)
+ break;
+
+ p = s;
+ while (*s && !isspace(*s))
+ s++;
+
+ if (isspace(*s)) {
+ *s = 0;
+ s++;
+ }
+
+ ucimap_add_value(data, om, sd, p);
+ } while (*s);
+}
+
static int
ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
{
uci_foreach_element(&o->v.list, l) {
ucimap_add_value(data, om, sd, l->name);
}
+ } else if ((o->type == UCI_TYPE_STRING) && ucimap_is_list_auto(om->type)) {
+ ucimap_convert_list(data, om, sd, o->v.string);
}
}
int n_alloc = 2;
int err;
- sd = malloc(sm->alloc_len);
+ if (sm->alloc) {
+ sd = sm->alloc(map, sm, s);
+ memset(sd, 0, sizeof(struct ucimap_section_data));
+ } else {
+ sd = malloc(sm->alloc_len);
+ memset(sd, 0, sm->alloc_len);
+ }
+
if (!sd)
return UCI_ERR_MEM;
- memset(sd, 0, sm->alloc_len);
INIT_LIST_HEAD(&sd->list);
sd->map = map;
sd->sm = sm;
if (strcmp(e->name, om->name) != 0)
continue;
- uci_foreach_element(&o->v.list, tmp) {
- n_elements++;
+ if (o->type == UCI_TYPE_LIST) {
+ uci_foreach_element(&o->v.list, tmp) {
+ n_elements++;
+ }
+ } else if ((o->type == UCI_TYPE_STRING) &&
+ ucimap_is_list_auto(om->type)) {
+ const char *data = o->v.string;
+ do {
+ while (isspace(*data))
+ data++;
+
+ if (!*data)
+ break;
+
+ n_elements++;
+
+ while (*data && !isspace(*data))
+ data++;
+ } while (*data);
+
+ /* for the duplicated data string */
+ if (n_elements > 0)
+ n_alloc++;
}
break;
}
+ /* add one more for the ucimap_list */
n_alloc += n_elements + 1;
size = sizeof(struct ucimap_list) +
n_elements * sizeof(union ucimap_data);
}
int
-ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
+ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
{
- char *sptr = (char *)section - sizeof(struct ucimap_section_data);
- struct ucimap_section_data *sd = (struct ucimap_section_data *) sptr;
struct uci_sectionmap *sm = sd->sm;
struct uci_section *s = NULL;
struct uci_optmap *om;
ucimap_foreach_option(sm, om) {
union ucimap_data *data;
static char buf[32];
- const char *str = NULL;
+ char *str = NULL;
+ i++;
if (ucimap_is_list(om->type))
continue;
data = ucimap_get_data(sd, om);
- if (!TEST_BIT(sd->cmap, i))
+ if (!TEST_BIT(sd->cmap, i - 1))
continue;
ucimap_fill_ptr(&ptr, s, om->name);
sprintf(buf, "%d", !!data->b);
str = buf;
break;
+ case UCIMAP_CUSTOM:
+ break;
default:
continue;
}
+ if (om->format) {
+ union ucimap_data tdata, *data;
+
+ data = ucimap_get_data(sd, om);
+ if (ucimap_is_custom(om->type)) {
+ tdata.s = (char *)data;
+ data = &tdata;
+ }
+
+ if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
+ continue;
+ }
+ if (!str)
+ continue;
ptr.value = str;
ret = uci_set(s->package->ctx, &ptr);
if (ret)
return ret;
- CLR_BIT(sd->cmap, i);
- i++;
+ CLR_BIT(sd->cmap, i - 1);
}
return 0;