7ce00d04dda07c13f6708874aec276477e929717
[project/uci.git] / uci_internal.h
1 /*
2 * libuci - Library for the Unified Configuration Interface
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #ifndef __UCI_INTERNAL_H
16 #define __UCI_INTERNAL_H
17
18 #define __private __attribute__((visibility("hidden")))
19 #define __public
20 #ifdef UCI_PLUGIN_SUPPORT
21 #define __plugin extern
22 #else
23 #define __plugin static
24 #endif
25
26 struct uci_parse_context
27 {
28 /* error context */
29 const char *reason;
30 int line;
31 int byte;
32
33 /* private: */
34 struct uci_package *package;
35 struct uci_section *section;
36 bool merge;
37 FILE *file;
38 const char *name;
39 char *buf;
40 int bufsz;
41 };
42
43 __plugin void *uci_malloc(struct uci_context *ctx, size_t size);
44 __plugin void *uci_realloc(struct uci_context *ctx, void *ptr, size_t size);
45 __plugin char *uci_strdup(struct uci_context *ctx, const char *str);
46 __plugin bool uci_validate_str(const char *str, bool name);
47 __plugin void uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, const char *section, const char *option, const char *value);
48 __plugin void uci_free_history(struct uci_history *h);
49 __plugin struct uci_package *uci_alloc_package(struct uci_context *ctx, const char *name);
50
51 __private FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create);
52 __private void uci_close_stream(FILE *stream);
53 __private void uci_getln(struct uci_context *ctx, int offset);
54
55 __private void uci_parse_error(struct uci_context *ctx, char *pos, char *reason);
56 __private void uci_alloc_parse_context(struct uci_context *ctx);
57
58 __private void uci_cleanup(struct uci_context *ctx);
59 __private struct uci_element *uci_lookup_list(struct uci_list *list, const char *name);
60 __private void uci_fixup_section(struct uci_context *ctx, struct uci_section *s);
61 __private void uci_free_package(struct uci_package **package);
62
63 __private int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush);
64
65 static inline bool uci_validate_package(const char *str)
66 {
67 return uci_validate_str(str, false);
68 }
69
70 static inline bool uci_validate_type(const char *str)
71 {
72 return uci_validate_str(str, false);
73 }
74
75 static inline bool uci_validate_name(const char *str)
76 {
77 return uci_validate_str(str, true);
78 }
79
80 /* initialize a list head/item */
81 static inline void uci_list_init(struct uci_list *ptr)
82 {
83 ptr->prev = ptr;
84 ptr->next = ptr;
85 }
86
87 /* inserts a new list entry after a given entry */
88 static inline void uci_list_insert(struct uci_list *list, struct uci_list *ptr)
89 {
90 list->next->prev = ptr;
91 ptr->prev = list;
92 ptr->next = list->next;
93 list->next = ptr;
94 }
95
96 /* inserts a new list entry at the tail of the list */
97 static inline void uci_list_add(struct uci_list *head, struct uci_list *ptr)
98 {
99 /* NB: head->prev points at the tail */
100 uci_list_insert(head->prev, ptr);
101 }
102
103 static inline void uci_list_del(struct uci_list *ptr)
104 {
105 struct uci_list *next, *prev;
106
107 next = ptr->next;
108 prev = ptr->prev;
109
110 prev->next = next;
111 next->prev = prev;
112
113 uci_list_init(ptr);
114 }
115
116
117 extern struct uci_backend uci_file_backend;
118
119 #ifdef UCI_PLUGIN_SUPPORT
120 /**
121 * uci_add_backend: add an extra backend
122 * @ctx: uci context
123 * @name: name of the backend
124 *
125 * The default backend is "file", which uses /etc/config for config storage
126 */
127 __plugin int uci_add_backend(struct uci_context *ctx, struct uci_backend *b);
128
129 /**
130 * uci_add_backend: add an extra backend
131 * @ctx: uci context
132 * @name: name of the backend
133 *
134 * The default backend is "file", which uses /etc/config for config storage
135 */
136 __plugin int uci_del_backend(struct uci_context *ctx, struct uci_backend *b);
137 #endif
138
139 #define UCI_BACKEND(_var, _name, ...) \
140 struct uci_backend _var = { \
141 .e.list = { \
142 .next = &_var.e.list, \
143 .prev = &_var.e.list, \
144 }, \
145 .e.name = _name, \
146 .e.type = UCI_TYPE_BACKEND, \
147 .ptr = &_var, \
148 __VA_ARGS__ \
149 }
150
151
152 /*
153 * functions for debug and error handling, for internal use only
154 */
155
156 #ifdef UCI_DEBUG
157 #define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
158 #else
159 #define DPRINTF(...)
160 #endif
161
162 /*
163 * throw an uci exception and store the error number
164 * in the context.
165 */
166 #define UCI_THROW(ctx, err) do { \
167 DPRINTF("Exception: %s in %s, %s:%d\n", #err, __func__, __FILE__, __LINE__); \
168 longjmp(ctx->trap, err); \
169 } while (0)
170
171 /*
172 * store the return address for handling exceptions
173 * needs to be called in every externally visible library function
174 *
175 * NB: this does not handle recursion at all. Calling externally visible
176 * functions from other uci functions is only allowed at the end of the
177 * calling function, or by wrapping the function call in UCI_TRAP_SAVE
178 * and UCI_TRAP_RESTORE.
179 */
180 #define UCI_HANDLE_ERR(ctx) do { \
181 DPRINTF("ENTER: %s\n", __func__); \
182 int __val = 0; \
183 ctx->err = 0; \
184 if (!ctx) \
185 return UCI_ERR_INVAL; \
186 if (!ctx->internal && !ctx->nested) \
187 __val = setjmp(ctx->trap); \
188 ctx->internal = false; \
189 ctx->nested = false; \
190 if (__val) { \
191 DPRINTF("LEAVE: %s, ret=%d\n", __func__, __val); \
192 ctx->err = __val; \
193 return __val; \
194 } \
195 } while (0)
196
197 /*
198 * In a block enclosed by UCI_TRAP_SAVE and UCI_TRAP_RESTORE, all exceptions
199 * are intercepted and redirected to the label specified in 'handler'
200 * after UCI_TRAP_RESTORE, or when reaching the 'handler' label, the old
201 * exception handler is restored
202 */
203 #define UCI_TRAP_SAVE(ctx, handler) do { \
204 jmp_buf __old_trap; \
205 int __val; \
206 memcpy(__old_trap, ctx->trap, sizeof(ctx->trap)); \
207 __val = setjmp(ctx->trap); \
208 if (__val) { \
209 ctx->err = __val; \
210 memcpy(ctx->trap, __old_trap, sizeof(ctx->trap)); \
211 goto handler; \
212 }
213 #define UCI_TRAP_RESTORE(ctx) \
214 memcpy(ctx->trap, __old_trap, sizeof(ctx->trap)); \
215 } while(0)
216
217 /**
218 * UCI_INTERNAL: Do an internal call of a public API function
219 *
220 * Sets Exception handling to passthrough mode.
221 * Allows API functions to change behavior compared to public use
222 */
223 #define UCI_INTERNAL(func, ctx, ...) do { \
224 ctx->internal = true; \
225 func(ctx, __VA_ARGS__); \
226 } while (0)
227
228 /**
229 * UCI_NESTED: Do an normal nested call of a public API function
230 *
231 * Sets Exception handling to passthrough mode.
232 * Allows API functions to change behavior compared to public use
233 */
234 #define UCI_NESTED(func, ctx, ...) do { \
235 ctx->nested = true; \
236 func(ctx, __VA_ARGS__); \
237 } while (0)
238
239
240 /*
241 * check the specified condition.
242 * throw an invalid argument exception if it's false
243 */
244 #define UCI_ASSERT(ctx, expr) do { \
245 if (!(expr)) { \
246 DPRINTF("[%s:%d] Assertion failed\n", __FILE__, __LINE__); \
247 UCI_THROW(ctx, UCI_ERR_INVAL); \
248 } \
249 } while (0)
250
251 #endif