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