Browse Source

ucimap: add callback for validation/conversion and custom data type

Felix Fietkau 14 years ago
parent
commit
8ae8a7fc89
3 changed files with 59 additions and 14 deletions
  1. 23 4
      ucimap-example.c
  2. 32 9
      ucimap.c
  3. 4 1
      ucimap.h

+ 23 - 4
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"));
 

+ 32 - 9
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)

+ 4 - 1
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;