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 
38 struct __config {
40  struct rbtree tree;
41 };
42 
46  struct rbnode node;
48  struct rbtree tree;
49 };
50 
51 static struct rbnode *config_section_create(config_t *config, const char *name);
52 static void config_section_destroy(struct rbnode *node);
53 
54 static const char *config_section_set(
55  struct rbnode *node, const char *key, const char *value);
56 
57 static void config_section_foreach(
58  struct rbnode *node, config_foreach_func_t *func, void *data);
59 
61 struct config_entry {
63  struct rbnode node;
65  char *value;
66 };
67 
68 static struct rbnode *config_entry_create(struct config_section *section,
69  const char *key, const char *value);
70 static void config_entry_destroy(struct rbnode *node);
71 
72 void *
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 
83 void
84 __config_free(void *ptr)
85 {
86  free(ptr);
87 }
88 
89 struct __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 
103 void
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 
114 config_t *
115 config_create(int flags)
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 
132 error_init_config:
133  __config_free(config);
134 error_alloc_config:
135  set_errc(errc);
136  return NULL;
137 }
138 
139 void
141 {
142  if (config) {
143  __config_fini(config);
144  __config_free(config);
145  }
146 }
147 
148 size_t
149 config_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 
165 size_t
166 config_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 
192 const char *
193 config_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 
217 const char *
218 config_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 
237 void
238 config_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 
256 static struct rbnode *
257 config_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 
289 error_alloc_key:
290  free(section);
291 error_alloc_section:
292  set_errc(errc);
293  return NULL;
294 }
295 
296 static void
297 config_section_destroy(struct rbnode *node)
298 {
299  assert(node);
300  struct config_section *section =
301  structof(node, struct config_section, node);
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 
313 static const char *
314 config_section_set(struct rbnode *node, const char *key, const char *value)
315 {
316  assert(node);
317  struct config_section *section =
318  structof(node, struct config_section, node);
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 
333 static void
334 config_section_foreach(
335  struct rbnode *node, config_foreach_func_t *func, void *data)
336 {
337  assert(node);
338  struct config_section *section =
339  structof(node, struct config_section, node);
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 
349 static struct rbnode *
350 config_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 
391 error_alloc_value:
392  free((char *)node->key);
393 error_alloc_key:
394  free(entry);
395 error_alloc_entry:
396  set_errc(errc);
397  return NULL;
398 }
399 
400 static void
401 config_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
rbtree_insert
void rbtree_insert(struct rbtree *tree, struct rbnode *node)
Inserts a node into a red-black tree.
Definition: rbtree.c:108
rbtree_foreach
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
Definition: rbtree.h:234
rbnode_next
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
rbtree
A red-black tree.
Definition: rbtree.h:91
cmp.h
rbtree_first
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
rbtree_find
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
Definition: rbtree.c:306
config_create
config_t * config_create(int flags)
Creates a new configuration struct with an unnamed empty root section.
Definition: config.c:115
string.h
__config::tree
struct rbtree tree
The tree containing the sections.
Definition: config.c:40
config_section
A section in a configuration struct.
Definition: config.c:44
__config
A configuration struct.
Definition: config.c:38
config_destroy
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:140
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
config_foreach
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
util.h
rbtree::cmp
rbtree_cmp_t * cmp
A pointer to the function used to compare two keys.
Definition: rbtree.h:93
config_section::node
struct rbnode node
The node of this section in the tree of sections.
Definition: config.c:46
config_get
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
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
config_entry::value
char * value
The value of the entry.
Definition: config.c:65
errnum.h
rbtree.h
config_entry::node
struct rbnode node
The node of this entry in the tree of entries.
Definition: config.c:63
config_entry
An entry in a configuration section.
Definition: config.c:61
rbnode
A node in a red-black tree.
Definition: rbtree.h:53
config_set
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
config_get_keys
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
rbtree_init
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes a red-black tree.
Definition: rbtree.h:248
rbtree_remove
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
Definition: rbtree.c:187
structof
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
rbnode::key
const void * key
A pointer to the key for this node.
Definition: rbtree.h:59
rbtree_size
size_t rbtree_size(const struct rbtree *tree)
Returns the size (in number of nodes) of a red-black tree.
Definition: rbtree.h:265
config.h
CONFIG_CASE
@ CONFIG_CASE
Section and key names are case-insensitive.
Definition: config.h:37
stdlib.h
config_section::tree
struct rbtree tree
The tree containing the entries.
Definition: config.c:48
config_foreach_func_t
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_get_sections
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