Lely core libraries  2.2.5
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 
35 struct __config {
37  struct rbtree tree;
38 };
39 
43  struct rbnode node;
45  struct rbtree tree;
46 };
47 
48 static struct rbnode *config_section_create(config_t *config, const char *name);
49 static void config_section_destroy(struct rbnode *node);
50 
51 static const char *config_section_set(
52  struct rbnode *node, const char *key, const char *value);
53 
54 static void config_section_foreach(
55  struct rbnode *node, config_foreach_func_t *func, void *data);
56 
58 struct config_entry {
60  struct rbnode node;
62  char *value;
63 };
64 
65 static struct rbnode *config_entry_create(struct config_section *section,
66  const char *key, const char *value);
67 static void config_entry_destroy(struct rbnode *node);
68 
69 void *
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 
78 void
79 __config_free(void *ptr)
80 {
81  free(ptr);
82 }
83 
84 struct __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 
98 void
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 
109 config_t *
110 config_create(int flags)
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 
127 error_init_config:
128  __config_free(config);
129 error_alloc_config:
130  set_errc(errc);
131  return NULL;
132 }
133 
134 void
136 {
137  if (config) {
138  __config_fini(config);
139  __config_free(config);
140  }
141 }
142 
143 size_t
144 config_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 
160 size_t
161 config_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 
187 const char *
188 config_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 
212 const char *
213 config_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 
232 void
233 config_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 
251 static struct rbnode *
252 config_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 
280 error_alloc_key:
281  free(section);
282 error_alloc_section:
283  set_errc(errc);
284  return NULL;
285 }
286 
287 static void
288 config_section_destroy(struct rbnode *node)
289 {
290  assert(node);
291  struct config_section *section =
292  structof(node, struct config_section, node);
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 
304 static const char *
305 config_section_set(struct rbnode *node, const char *key, const char *value)
306 {
307  assert(node);
308  struct config_section *section =
309  structof(node, struct config_section, node);
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 
324 static void
325 config_section_foreach(
326  struct rbnode *node, config_foreach_func_t *func, void *data)
327 {
328  assert(node);
329  struct config_section *section =
330  structof(node, struct config_section, node);
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 
340 static struct rbnode *
341 config_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  // cppcheck-suppress memleak symbolName=entry.value
374  return node;
375 
376 error_alloc_value:
377  free((char *)node->key);
378 error_alloc_key:
379  free(entry);
380 error_alloc_entry:
381  set_errc(errc);
382  return NULL;
383 }
384 
385 static void
386 config_entry_destroy(struct rbnode *node)
387 {
388  assert(node);
389  struct config_entry *entry = structof(node, struct config_entry, node);
390 
391  free((char *)node->key);
392 
393  free(entry->value);
394  free(entry);
395 }
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:226
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:90
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:322
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:110
string.h
__config::tree
struct rbtree tree
The tree containing the sections.
Definition: config.c:37
config_section
A section in a configuration struct.
Definition: config.c:41
__config
A configuration struct.
Definition: config.c:35
config_destroy
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:135
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:947
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
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:233
util.h
rbtree::cmp
rbtree_cmp_t * cmp
A pointer to the function used to compare two keys.
Definition: rbtree.h:92
config_section::node
struct rbnode node
The node of this section in the tree of sections.
Definition: config.c:43
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:188
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
config_entry::value
char * value
The value of the entry.
Definition: config.c:62
errnum.h
rbtree.h
config_entry::node
struct rbnode node
The node of this entry in the tree of entries.
Definition: config.c:60
config_entry
An entry in a configuration section.
Definition: config.c:58
rbnode
A node in a red-black tree.
Definition: rbtree.h:52
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:213
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:161
rbtree_init
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes a red-black tree.
Definition: rbtree.h:238
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:58
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:252
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:45
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:144