From: Felix Fietkau Date: Sat, 29 Aug 2009 18:14:19 +0000 (+0200) Subject: ucimap: add callback for validation/conversion and custom data type X-Git-Url: http://pilppa.org/gitweb/?p=uci.git;a=commitdiff_plain;h=8ae8a7fc893e18676d6a35193f8a74c87ceb7b7f ucimap: add callback for validation/conversion and custom data type --- diff --git a/ucimap-example.c b/ucimap-example.c index ca55931..0ad31d6 100644 --- a/ucimap-example.c +++ b/ucimap-example.c @@ -26,7 +26,7 @@ struct uci_network { const char *name; const char *proto; const char *ifname; - const char *ipaddr; + unsigned char ipaddr[4]; int test; bool enabled; struct ucimap_list *aliases; @@ -39,6 +39,23 @@ struct uci_alias { struct uci_network *interface; }; +static int +network_parse_ip(void *section, struct uci_optmap *om, union ucimap_data *data, const char *str) +{ + struct uci_network *net = section; + unsigned char *target = data->s; + unsigned int tmp[4]; + int i; + + if (sscanf(str, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3]) != 4) + return -1; + + for (i = 0; i < 4; i++) + target[i] = (char) tmp[i]; + + return 0; +} + static int network_init_interface(struct uci_map *map, void *section, struct uci_section *s) { @@ -109,8 +126,9 @@ static struct my_optmap network_interface_options[] = { { .map = { UCIMAP_OPTION(struct uci_network, ipaddr), - .type = UCIMAP_STRING, + .type = UCIMAP_CUSTOM, .name = "ipaddr", + .parse = network_parse_ip, } }, { @@ -196,13 +214,14 @@ int main(int argc, char **argv) printf("New network section '%s'\n" " type: %s\n" " ifname: %s\n" - " ipaddr: %s\n" + " ipaddr: %d.%d.%d.%d\n" " test: %d\n" " enabled: %s\n", net->name, net->proto, net->ifname, - net->ipaddr, + net->ipaddr[0], net->ipaddr[1], + net->ipaddr[2], net->ipaddr[3], net->test, (net->enabled ? "on" : "off")); diff --git a/ucimap.c b/ucimap.c index 191c97c..8fdeed2 100644 --- a/ucimap.c +++ b/ucimap.c @@ -93,12 +93,25 @@ ucimap_is_list(enum ucimap_type type) return ((type & UCIMAP_TYPE) == UCIMAP_LIST); } +static inline bool +ucimap_is_custom(enum ucimap_type type) +{ + return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM); +} + +static inline void * +ucimap_section_ptr(struct uci_sectmap_data *sd) +{ + void *data = sd + 1; + return data; +} + static inline union ucimap_data * ucimap_get_data(struct uci_sectmap_data *sd, struct uci_optmap *om) { void *data; - data = (char *) sd + sizeof(struct uci_sectmap_data) + om->offset; + data = (char *) ucimap_section_ptr(sd) + om->offset; return data; } @@ -132,10 +145,10 @@ ucimap_add_alloc(struct uci_sectmap_data *sd, void *ptr) static void ucimap_free_section(struct uci_map *map, struct uci_sectmap_data *sd) { - void *section = sd; + void *section; int i; - section = (char *) section + sizeof(struct uci_sectmap_data); + section = ucimap_section_ptr(sd); if (!list_empty(&sd->list)) list_del(&sd->list); @@ -181,13 +194,13 @@ ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap static void ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sectmap_data *sd, const char *str) { - union ucimap_data *tdata = data; + union ucimap_data tdata = *data; char *eptr = NULL; char *s; int val; if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) - tdata = &data->list->item[data->list->n_items++]; + data = &data->list->item[data->list->n_items++]; switch(om->type & UCIMAP_SUBTYPE) { case UCIMAP_STRING: @@ -196,7 +209,7 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sect return; s = strdup(str); - tdata->s = s; + tdata.s = s; ucimap_add_alloc(sd, s); break; case UCIMAP_BOOL: @@ -216,19 +229,29 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sect if (val == -1) return; - tdata->b = val; + tdata.b = val; break; case UCIMAP_INT: val = strtol(str, &eptr, om->data.i.base); if (!eptr || *eptr == '\0') - tdata->i = val; + tdata.i = val; else return; break; case UCIMAP_SECTION: ucimap_add_fixup(sd->map, data, om, str); + return; + case UCIMAP_CUSTOM: + tdata.s = (char *) data; break; } + if (om->parse) { + if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0) + return; + } + if (ucimap_is_custom(om->type)) + return; + memcpy(data, &tdata, sizeof(union ucimap_data)); } @@ -339,7 +362,7 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list); } - section = (char *)sd + sizeof(struct uci_sectmap_data); + section = ucimap_section_ptr(sd); err = sm->init(map, section, s); if (err) diff --git a/ucimap.h b/ucimap.h index 865c45a..2aedc78 100644 --- a/ucimap.h +++ b/ucimap.h @@ -33,6 +33,7 @@ (_name[(_bit) / 8] & (1 << ((_bit) % 8))) #define UCIMAP_OPTION(_type, _field) \ + .type = UCIMAP_CUSTOM, \ .name = #_field, \ .offset = offsetof(_type, _field) @@ -60,13 +61,14 @@ enum ucimap_type { UCIMAP_BOOL = 0x1, UCIMAP_INT = 0x2, UCIMAP_SECTION = 0x3, + UCIMAP_CUSTOM = 0x4, UCIMAP_SUBTYPE = 0xf, /* subtype mask */ }; union ucimap_data { int i; bool b; - const char *s; + char *s; void *section; struct ucimap_list *list; }; @@ -102,6 +104,7 @@ struct uci_optmap { unsigned int offset; const char *name; enum ucimap_type type; + int (*parse)(void *section, struct uci_optmap *om, union ucimap_data *data, const char *string); union { struct { int base;