Lely core libraries 2.3.4
config.c
Go to the documentation of this file.
1
24#include "util.h"
25
26#if !LELY_NO_MALLOC
27
28#include <lely/util/cmp.h>
29#include <lely/util/config.h>
30#include <lely/util/errnum.h>
31#include <lely/util/rbtree.h>
32
33#include <assert.h>
34#include <stdlib.h>
35#include <string.h>
36
38struct __config {
40 struct rbtree tree;
41};
42
46 struct rbnode node;
48 struct rbtree tree;
49};
50
51static struct rbnode *config_section_create(config_t *config, const char *name);
52static void config_section_destroy(struct rbnode *node);
53
54static const char *config_section_set(
55 struct rbnode *node, const char *key, const char *value);
56
57static void config_section_foreach(
58 struct rbnode *node, config_foreach_func_t *func, void *data);
59
63 struct rbnode node;
65 char *value;
66};
67
68static struct rbnode *config_entry_create(struct config_section *section,
69 const char *key, const char *value);
70static void config_entry_destroy(struct rbnode *node);
71
72void *
73__config_alloc(void)
74{
75 void *ptr = malloc(sizeof(struct __config));
76#if !LELY_NO_ERRNO
77 if (ptr)
78 set_errc(errno2c(errno));
79#endif
80 return ptr;
81}
82
83void
84__config_free(void *ptr)
85{
86 free(ptr);
87}
88
89struct __config *
90__config_init(struct __config *config, int flags)
91{
92 assert(config);
93
94 rbtree_init(&config->tree,
95 (flags & CONFIG_CASE) ? &str_case_cmp : &str_cmp);
96
97 if (!config_section_create(config, ""))
98 return NULL;
99
100 return config;
101}
102
103void
104__config_fini(struct __config *config)
105{
106 assert(config);
107
108 rbtree_foreach (&config->tree, node) {
109 rbtree_remove(&config->tree, node);
110 config_section_destroy(node);
111 }
112}
113
114config_t *
116{
117 int errc = 0;
118
119 config_t *config = __config_alloc();
120 if (!config) {
121 errc = get_errc();
122 goto error_alloc_config;
123 }
124
125 if (!__config_init(config, flags)) {
126 errc = get_errc();
127 goto error_init_config;
128 }
129
130 return config;
131
132error_init_config:
133 __config_free(config);
134error_alloc_config:
135 set_errc(errc);
136 return NULL;
137}
138
139void
141{
142 if (config) {
143 __config_fini(config);
144 __config_free(config);
145 }
146}
147
148size_t
149config_get_sections(const config_t *config, size_t n, const char **sections)
150{
151 assert(config);
152
153 if (!sections)
154 n = 0;
155
156 if (n) {
157 struct rbnode *node = rbtree_first(&config->tree);
158 for (size_t i = 0; node && i < n; node = rbnode_next(node), i++)
159 sections[i] = node->key;
160 }
161
162 return rbtree_size(&config->tree);
163}
164
165size_t
166config_get_keys(const config_t *config, const char *section, size_t n,
167 const char **keys)
168{
169 assert(config);
170
171 if (!section)
172 section = "";
173
174 struct rbnode *node = rbtree_find(&config->tree, section);
175 if (!node)
176 return 0;
177 struct rbtree *tree =
178 &structof(node, struct config_section, node)->tree;
179
180 if (!keys)
181 n = 0;
182
183 if (n) {
184 node = rbtree_first(tree);
185 for (size_t i = 0; node && i < n; node = rbnode_next(node), i++)
186 keys[i] = node->key;
187 }
188
189 return rbtree_size(tree);
190}
191
192const char *
193config_get(const config_t *config, const char *section, const char *key)
194{
195 assert(config);
196
197 if (!section)
198 section = "";
199
200 if (!key)
201 return NULL;
202
203 const struct rbtree *tree = &config->tree;
204 struct rbnode *node;
205
206 node = rbtree_find(tree, section);
207 if (!node)
208 return NULL;
209 tree = &structof(node, struct config_section, node)->tree;
210
211 node = rbtree_find(tree, key);
212 if (!node)
213 return NULL;
214 return structof(node, struct config_entry, node)->value;
215}
216
217const char *
218config_set(config_t *config, const char *section, const char *key,
219 const char *value)
220{
221 assert(config);
222
223 if (!section)
224 section = "";
225
226 if (!key)
227 return NULL;
228
229 struct rbnode *node = rbtree_find(&config->tree, section);
230 // Only create a section if we are not removing an entry.
231 if (!node && value)
232 node = config_section_create(config, section);
233
234 return node ? config_section_set(node, key, value) : NULL;
235}
236
237void
238config_foreach(const config_t *config, config_foreach_func_t *func, void *data)
239{
240 assert(config);
241
242 // Start with the root section.
243 struct rbnode *node = rbtree_find(&config->tree, "");
244 if (node)
245 config_section_foreach(node, func, data);
246
247 rbtree_foreach (&config->tree, node) {
248 const char *section = node->key;
249 // Skip the root section.
250 if (!section || !*section)
251 continue;
252 config_section_foreach(node, func, data);
253 }
254}
255
256static struct rbnode *
257config_section_create(config_t *config, const char *name)
258{
259 assert(config);
260 assert(name);
261
262 int errc = 0;
263
264 struct config_section *section = malloc(sizeof(*section));
265 if (!section) {
266#if !LELY_NO_ERRNO
267 errc = errno2c(errno);
268#endif
269 goto error_alloc_section;
270 }
271
272 struct rbnode *node = &section->node;
273
274 node->key = malloc(strlen(name) + 1);
275 if (!node->key) {
276#if !LELY_NO_ERRNO
277 errc = errno2c(errno);
278#endif
279 goto error_alloc_key;
280 }
281 strcpy((char *)node->key, name);
282
283 rbtree_init(&section->tree, config->tree.cmp);
284
285 rbtree_insert(&config->tree, node);
286
287 return node;
288
289error_alloc_key:
290 free(section);
291error_alloc_section:
292 set_errc(errc);
293 return NULL;
294}
295
296static void
297config_section_destroy(struct rbnode *node)
298{
299 assert(node);
300 struct config_section *section =
302
303 free((char *)node->key);
304
305 rbtree_foreach (&section->tree, node) {
306 rbtree_remove(&section->tree, node);
307 config_entry_destroy(node);
308 }
309
310 free(section);
311}
312
313static const char *
314config_section_set(struct rbnode *node, const char *key, const char *value)
315{
316 assert(node);
317 struct config_section *section =
319
320 // Remove the existing entry.
321 node = rbtree_find(&section->tree, key);
322 if (node) {
323 rbtree_remove(&section->tree, node);
324 config_entry_destroy(node);
325 }
326 if (!value)
327 return NULL;
328
329 node = config_entry_create(section, key, value);
330 return node ? structof(node, struct config_entry, node)->value : NULL;
331}
332
333static void
334config_section_foreach(
335 struct rbnode *node, config_foreach_func_t *func, void *data)
336{
337 assert(node);
338 struct config_section *section =
340 assert(func);
341
342 rbtree_foreach (&section->tree, node) {
343 struct config_entry *entry =
344 structof(node, struct config_entry, node);
345 func(section->node.key, entry->node.key, entry->value, data);
346 }
347}
348
349static struct rbnode *
350config_entry_create(struct config_section *section, const char *key,
351 const char *value)
352{
353 assert(section);
354 assert(key);
355
356 int errc = 0;
357
358 struct config_entry *entry = malloc(sizeof(*entry));
359 if (!entry) {
360#if !LELY_NO_ERRNO
361 errc = errno2c(errno);
362#endif
363 goto error_alloc_entry;
364 }
365
366 struct rbnode *node = &entry->node;
367
368 node->key = malloc(strlen(key) + 1);
369 if (!node->key) {
370#if !LELY_NO_ERRNO
371 errc = errno2c(errno);
372#endif
373 goto error_alloc_key;
374 }
375 strcpy((char *)node->key, key);
376
377 entry->value = malloc(strlen(value) + 1);
378 if (!entry->value) {
379#if !LELY_NO_ERRNO
380 errc = errno2c(errno);
381#endif
382 goto error_alloc_value;
383 }
384 strcpy(entry->value, value);
385
386 rbtree_insert(&section->tree, node);
387
388 // cppcheck-suppress memleak symbolName=entry.value
389 return node;
390
391error_alloc_value:
392 free((char *)node->key);
393error_alloc_key:
394 free(entry);
395error_alloc_entry:
396 set_errc(errc);
397 return NULL;
398}
399
400static void
401config_entry_destroy(struct rbnode *node)
402{
403 assert(node);
404 struct config_entry *entry = structof(node, struct config_entry, node);
405
406 free((char *)node->key);
407
408 free(entry->value);
409 free(entry);
410}
411
412#endif // !LELY_NO_MALLOC
This header file is part of the utilities library; it contains the comparison function definitions.
const char * config_set(config_t *config, const char *section, const char *key, const char *value)
Sets a key in or removes a key from a configuration struct.
Definition: config.c:218
void config_foreach(const config_t *config, config_foreach_func_t *func, void *data)
Invokes a function for each key in a configuration struct.
Definition: config.c:238
size_t config_get_sections(const config_t *config, size_t n, const char **sections)
Retrieves a list of section names from a configuration struct.
Definition: config.c:149
config_t * config_create(int flags)
Creates a new configuration struct with an unnamed empty root section.
Definition: config.c:115
size_t config_get_keys(const config_t *config, const char *section, size_t n, const char **keys)
Retrieves a list of key names from a section in a configuration struct.
Definition: config.c:166
const char * config_get(const config_t *config, const char *section, const char *key)
Retrieves a key from a configuration struct.
Definition: config.c:193
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:140
This header file is part of the utilities library; it contains the configuration functions.
void config_foreach_func_t(const char *section, const char *key, const char *value, void *data)
The type of a function called by config_foreach() for each key in a configuration struct.
Definition: config.h:56
@ CONFIG_CASE
Section and key names are case-insensitive.
Definition: config.h:37
This header file is part of the utilities library; it contains the native and platform-independent er...
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
This header file is part of the utilities library; it contains the red-black tree declarations.
void rbtree_insert(struct rbtree *tree, struct rbnode *node)
Inserts a node into a red-black tree.
Definition: rbtree.c:108
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
Definition: rbtree.c:306
struct rbnode * rbtree_first(const struct rbtree *tree)
Returns a pointer to the first (leftmost) node in a red-black tree.
Definition: rbtree.c:335
struct rbnode * rbnode_next(const struct rbnode *node)
Returns a pointer to the next (in-order) node in a red-black tree with respect to node.
Definition: rbtree.c:91
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes a red-black tree.
Definition: rbtree.h:248
size_t rbtree_size(const struct rbtree *tree)
Returns the size (in number of nodes) of a red-black tree.
Definition: rbtree.h:265
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
Definition: rbtree.c:187
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
Definition: rbtree.h:234
This is the internal header file of the utilities library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
A configuration struct.
Definition: config.c:38
struct rbtree tree
The tree containing the sections.
Definition: config.c:40
An entry in a configuration section.
Definition: config.c:61
char * value
The value of the entry.
Definition: config.c:65
struct rbnode node
The node of this entry in the tree of entries.
Definition: config.c:63
A section in a configuration struct.
Definition: config.c:44
struct rbnode node
The node of this section in the tree of sections.
Definition: config.c:46
struct rbtree tree
The tree containing the entries.
Definition: config.c:48
A node in a red-black tree.
Definition: rbtree.h:53
const void * key
A pointer to the key for this node.
Definition: rbtree.h:59
A red-black tree.
Definition: rbtree.h:91
rbtree_cmp_t * cmp
A pointer to the function used to compare two keys.
Definition: rbtree.h:93