summaryrefslogtreecommitdiff
path: root/ucimap.h
blob: d0e8ce91c5f56611be8d5db1e67754b478b0d766 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
 * ucimap - library for mapping uci sections into data structures
 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#ifndef __UCIMAP_H
#define __UCIMAP_H

#include <stdbool.h>
#include "uci_list.h"
#include "uci.h"

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif

#define BITFIELD_SIZE(_fields) (((_fields) / 8) + 1)

#define CLR_BIT(_name, _bit) do { \
	_name[(_bit) / 8] &= ~(1 << ((_bit) % 8)); \
} while (0)

#define SET_BIT(_name, _bit) do { \
	_name[(_bit) / 8] |=  (1 << ((_bit) % 8)); \
} while (0)

#define TEST_BIT(_name, _bit) \
	(_name[(_bit) / 8] & (1 << ((_bit) % 8)))

#ifndef __GNUC__

#define __optmap_gen_type(_type, _field) -1

#ifndef likely
#define likely(_expr) !!(_expr)
#endif

#ifndef unlikely
#define unlikely(_expr) !!(_expr)
#endif

#else /* __GNUC__ */

#define __compatible(_type, _field, _newtype) \
	__builtin_types_compatible_p(typeof(&(((_type *)0)->_field)), _newtype *)

#define __list_compatible(_type, _field, __val, __else) \
	__builtin_choose_expr(__compatible(_type, _field, struct ucimap_list *), __val, __else)

#define __int_compatible(_type, _field, __val, __else) \
	__builtin_choose_expr(__compatible(_type, _field, int), __val, \
		__builtin_choose_expr(__compatible(_type, _field, unsigned int), __val, \
			__else))

#define __string_compatible(_type, _field, __val, __else) \
	__builtin_choose_expr(__compatible(_type, _field, char *), __val, \
		__builtin_choose_expr(__compatible(_type, _field, unsigned char *), __val, \
			__builtin_choose_expr(__compatible(_type, _field, const char *), __val, \
				__builtin_choose_expr(__compatible(_type, _field, const unsigned char *), __val, \
					__else))))

#define __bool_compatible(_type, _field, __val, __else) \
	__builtin_choose_expr(__compatible(_type, _field, bool), __val, __else)


#define __optmap_gen_type(_type, _field) \
	__list_compatible(_type, _field, UCIMAP_LIST, \
	__int_compatible(_type, _field, UCIMAP_INT, \
	__string_compatible(_type, _field, UCIMAP_STRING, \
	__bool_compatible(_type, _field, UCIMAP_BOOL, \
	-1))))

#ifndef likely
#define likely(x)   __builtin_expect(!!(x), 1)
#endif

#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif

#endif /* __GNUC__ */

#define UCIMAP_OPTION(_type, _field) \
	.type = UCIMAP_CUSTOM, \
	.name = #_field, \
	.offset = offsetof(_type, _field), \
	.detected_type = __optmap_gen_type(_type, _field), \
	.type_name = #_type


#define UCIMAP_SECTION(_name, _field) \
	.alloc_len = sizeof(_name), \
	.smap_offset = offsetof(_name, _field), \
	.type_name = #_name

struct uci_sectionmap;
struct uci_optmap;
struct ucimap_list;
struct uci_alloc;
struct uci_alloc_custom;

struct uci_map {
	struct uci_sectionmap **sections;
	unsigned int n_sections;
	struct list_head sdata;
	struct list_head fixup;
	struct list_head pending;
	bool parsed;

	void *priv; /* user data */
};

enum ucimap_type {
	/* types */
	UCIMAP_SIMPLE   = 0x00,
	UCIMAP_LIST     = 0x10,
	UCIMAP_TYPE     = 0xf0, /* type mask */

	/* subtypes */
	UCIMAP_STRING   = 0x0,
	UCIMAP_BOOL     = 0x1,
	UCIMAP_INT      = 0x2,
	UCIMAP_SECTION  = 0x3,
	UCIMAP_CUSTOM	= 0x4,
	UCIMAP_SUBTYPE  = 0xf, /* subtype mask */

	/* automatically create lists from
	 * options with space-separated items */
	UCIMAP_LIST_AUTO = 0x0100,
	UCIMAP_FLAGS     = 0xff00, /* flags mask */
};

union ucimap_data {
	int i;
	bool b;
	char *s;
	void *ptr;
	void **data;
	struct ucimap_list *list;
};

struct ucimap_section_data {
	struct list_head list;
	struct uci_map *map;
	struct uci_sectionmap *sm;
	const char *section_name;

	/* list of allocations done by ucimap */
	struct uci_alloc *allocmap;
	struct uci_alloc_custom *alloc_custom;
	unsigned int allocmap_len;
	unsigned int alloc_custom_len;

	/* map for changed fields */
	unsigned char *cmap;
	bool done;
};


struct uci_listmap {
	struct list_head list;
	union ucimap_data data;
};

struct uci_sectionmap {
	/* type string for the uci section */
	const char *type;

	/* length of the struct to map into, filled in by macro */
	unsigned int alloc_len;

	/* sectionmap offset, filled in by macro */
	unsigned int smap_offset;

	/* return a pointer to the section map data (allocate if necessary) */
	struct ucimap_section_data *(*alloc)(struct uci_map *map,
		struct uci_sectionmap *sm, struct uci_section *s);

	/* give the caller time to initialize the preallocated struct */
	int (*init)(struct uci_map *map, void *section, struct uci_section *s);

	/* pass the fully processed struct to the callback after the section end */
	int (*add)(struct uci_map *map, void *section);

	/* let the callback clean up its own stuff in the section */
	int (*free)(struct uci_map *map, void *section);

	/* list of option mappings for this section */
	struct uci_optmap *options;
	unsigned int n_options;
	unsigned int options_size;

	/* internal */
	const char *type_name;
};

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);
	int (*format)(void *section, struct uci_optmap *om, union ucimap_data *data, char **string);
	void (*free)(void *section, struct uci_optmap *om, void *ptr);
	union {
		struct {
			int base;
			int min;
			int max;
		} i;
		struct {
			int maxlen;
		} s;
		struct uci_sectionmap *sm;
	} data;

	/* internal */
	int detected_type;
	const char *type_name;
};

struct ucimap_list {
	int n_items;
	union ucimap_data item[];
};

extern int ucimap_init(struct uci_map *map);
extern void ucimap_cleanup(struct uci_map *map);
extern void ucimap_set_changed(struct ucimap_section_data *sd, void *field);
extern int ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd);
extern void ucimap_parse(struct uci_map *map, struct uci_package *pkg);
extern int ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s);
extern void ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd);

#endif