Lumiera  0.pre.03
»edit your freedom«
configitem.c
Go to the documentation of this file.
1 /*
2  Configitem - generalised hierarchy of configuration items
3 
4  Copyright (C)
5  2008, Christian Thaeter <ct@pipapo.org>
6  Simeon Voelkel <simeon_voelkel@arcor.de>
7 
8   **Lumiera** is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2 of the License, or (at your
11   option) any later version. See the file COPYING for further details.
12 */
13 
14 
23 #include "include/logging.h"
24 #include "lib/llist.h"
25 #include "lib/safeclib.h"
26 #include "lib/tmpbuf.h"
27 
28 #include "common/config.h"
29 #include "common/configitem.h"
30 #include "common/configentry.h"
31 
32 #include <ctype.h>
33 #include <stdint.h>
34 
35 
36 static LumieraConfigitem parse_directive (LumieraConfigitem self, char* itr);
37 
38 static LumieraConfigitem parse_section (LumieraConfigitem self, char* itr);
39 
40 static LumieraConfigitem parse_configentry (LumieraConfigitem self, char* itr);
41 
42 
43 
44 
45 
46 LumieraConfigitem
47 lumiera_configitem_init (LumieraConfigitem self)
48 {
49  TRACE (configitem_dbg);
50  REQUIRE (self);
51 
52  llist_init (&self->link);
53  self->parent = NULL;
54  llist_init (&self->children);
55 
56  llist_init (&self->lookup);
57 
58  self->line = NULL;
59 
60  self->key = NULL;
61  self->key_size = 0;
62  self->delim = NULL;
63  self->vtable = NULL;
64 
65  return self;
66 }
67 
68 
69 LumieraConfigitem
70 lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup)
71 {
72  TRACE (configitem_dbg);
73 
74  if (self)
75  {
76  LLIST_WHILE_HEAD (&self->children, node)
77  lumiera_configitem_delete ((LumieraConfigitem) node, lookup);
78 
79  ENSURE (llist_is_empty (&self->children), "destructor didn't remove children");
80 
81  if (self->vtable && self->vtable->destroy)
82  self->vtable->destroy (self);
83 
84  if (!llist_is_empty (&self->lookup))
85  lumiera_config_lookup_remove (lookup, self);
86 
87  llist_unlink (&self->link);
88  lumiera_free (self->line);
89  }
90 
91  return self;
92 }
93 
94 
95 LumieraConfigitem
96 lumiera_configitem_new (const char* line)
97 {
98  TRACE (configitem_dbg, "%s", line);
99 
100  lumiera_configitem tmp;
101  lumiera_configitem_init (&tmp);
102 
103  lumiera_configitem_parse (&tmp, line);
104 
105  LumieraConfigitem self = tmp.vtable && tmp.vtable->newitem
106  ? tmp.vtable->newitem (&tmp)
107  : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp);
108 
109  return self;
110 }
111 
112 
113 void
114 lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup)
115 {
116  TRACE (configitem_dbg);
117  lumiera_free (lumiera_configitem_destroy (self, lookup));
118 }
119 
120 
121 LumieraConfigitem
122 lumiera_configitem_set_value (LumieraConfigitem self, const char* delim_value)
123 {
124  REQUIRE (self->key);
125  REQUIRE (self->delim);
126 
127  char* line = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s", self->delim - self->line, self->line, delim_value);
128  lumiera_configitem_parse (self, line);
129 
130  return self;
131 }
132 
133 
134 LumieraConfigitem
135 lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source)
136 {
137  TRACE (configitem_dbg);
138  REQUIRE (self);
139  REQUIRE (source);
140 
141  llist_init (&self->link);
142  llist_insertlist_next (&self->link, &source->link);
143 
144  self->parent = source->parent;
145 
146  llist_init (&self->children);
147  llist_insertlist_next (&self->children, &source->children);
148 
149  llist_init (&self->lookup);
150  llist_insertlist_next (&self->lookup, &source->lookup);
151 
152  self->line = source->line;
153  source->line = NULL;
154 
155  self->key = source->key;
156  self->key_size = source->key_size;
157  self->delim = source->delim;
158  self->vtable = source->vtable;
159 
160  return self;
161 }
162 
163 
164 LumieraConfigitem
165 lumiera_configitem_parse (LumieraConfigitem self, const char* line)
166 {
167  TRACE (configitem_dbg);
168 
169  lumiera_free (self->line);
170  self->line = lumiera_strndup (line, SIZE_MAX);
171 
173 
174  char* itr = self->line;
175 
176  /* skip leading whitespace */
177  while (*itr && isspace (*itr))
178  itr++;
179 
180  /* decide what this line represents */
181  if (!*itr || *itr == '#' )
182  {
183  /* this is an empty line or a a comment */
184  }
185  else if (*itr == '@' )
186  {
187  /* this is a directive */
188  self = parse_directive (self, itr);
189  }
190  else if (*itr == '[' )
191  {
192  /* this is a section */
193  self = parse_section (self, itr);
194  }
195  else
196  {
197  /* this is probably a configentry */
198  self = parse_configentry (self, itr);
199  }
200 
201  return self;
202 }
203 
204 
205 static LumieraConfigitem
206 parse_directive (LumieraConfigitem self, char* itr)
207 {
208  /* itr points now to @ */
209  self->key = itr;
210 
211  /* check whether there are illegal whitespace after @ */
212  itr++;
213  if (*itr && !isspace(*itr))
214  {
215  /* now look for the end of the directive and set the keysize */
216  self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
217 
218  itr += self->key_size;
219 
220  /* we need a key with a length greater than zero and */
221  /* either end of line or whitespace after key */
222 
223  if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
224  {
225  /* look for given arguments */
226 
227  /* skip blanks */
228  while (*itr && isspace (*itr))
229  itr++;
230 
231  if (*itr)
232  {
233  /* there are arguments given, thus set delim */
234  self->delim = itr - 1;
235  }
236  else
237  {
238  /* no arguments were given */
239  self->delim = NULL;
240  }
241  }
242  else
243  {
244  /* malformed lines shall be treated like if they were comments */
245  self->key = NULL;
246  self->key_size = 0;
247 
248  LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line);
249  }
250  }
251  else
252  {
253  /* there occurred already an error right after the @! */
254  /* malformed lines shall be treated like if they were comments */
255  self->key = NULL;
256  self->key_size = 0;
257 
258  LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line);
259  }
260  return self;
261 }
262 
263 
264 static LumieraConfigitem
265 parse_section (LumieraConfigitem self, char* itr)
266 {
267  /* skip blanks before prefix */
268  itr++;
269  while (*itr && isspace(*itr))
270  itr++;
271 
272  /* itr points now to the begin of the key */
273  self->key = itr;
274 
275  /* now look for the end of the key and set the keysize */
276  self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
277 
278  itr += self->key_size;
279 
280  /* if the line ends ends with prefix] delim points to ] */
281  /* and not the last (blank) character before the final square bracket */
282  if (self->key_size && *itr && *itr == ']')
283  {
284  self->delim = itr;
285  TODO("self->vtable = &lumiera_configsection_funcs;");
286  }
287  else if (self->key_size && *itr && isspace(*itr))
288  {
289  /* skip blanks until we reach the suffix or the final square bracket */
290  while (*itr && isspace(*itr))
291  itr++;
292 
293  if (*itr && *itr == ']')
294  {
295  /* final square bracket reached, so place delim one char before the */
296  /* actual position which must be a whitespace: no extra check necessary */
297  self->delim = itr - 1;
298  TODO("self->vtable = &lumiera_configsection_funcs;");
299  }
300  else if (*itr)
301  {
302  TODO("check wheter suffix is made of legal characters");
303 
304  /* delim points to the last whitespace before the actual position; */
305  /* no extra check needed */
306  self->delim = itr - 1;
307  TODO("self->vtable = &lumiera_configsection_funcs;");
308  }
309  else
310  {
311  /* malformed section line, treat this line like a comment */
312  self->key = NULL;
313  self->key_size = 0;
314 
315  LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line);
316  }
317  }
318  else
319  {
320  /* error: either *itr is false, points neither to a blank nor to a closed square */
321  /* bracket or the key_size is zero */
322 
323  /* treat this line like a comment */
324  self->key = NULL;
325  self->key_size = 0;
326 
327  LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line);
328  }
329 
330  return self;
331 }
332 
333 
334 static LumieraConfigitem
335 parse_configentry (LumieraConfigitem self, char* itr)
336 {
337  /* itr points now to the first not-whitespace-character */
338  self->key = itr;
339 
340  /* now look for the end of the key and set the keysize */
341  self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
342 
343  /* skip blanks */
344  itr += self->key_size;
345  while (*itr && isspace (*itr))
346  itr++;
347 
348  if (self->key_size && *itr == '=')
349  {
350  /* this configentry assigns a value to a key */
351  self->delim = itr;
352  self->vtable = &lumiera_configentry_funcs;
353  }
354  else if (self->key_size && *itr == '<')
355  {
356  /* this configentry is a redirect */
357  self->delim = itr;
358  self->vtable = &lumiera_configentry_funcs;
359  }
360  else
361  {
362  /* this is not a valid configentry; treat this line like a comment */
363  self->key = NULL;
364  self->key_size = 0;
365 
366  LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line);
367  }
368 
369  return self;
370 }
371 
372 
373 /*
374 // Local Variables:
375 // mode: C
376 // c-file-style: "gnu"
377 // indent-tabs-mode: nil
378 // End:
379 */
Portable and safe wrappers around some C-Lib functions.
#define LUMIERA_ERROR_SET(flag, err, extra)
Helper macro to raise an error for the current thread.
Definition: error.h:82
Draft for a configuration system (2008).
Draft for a configuration system (2008).
Interface for a lumiera configuration system (draft).
This header is for including and configuring NoBug.
Round robin temporary buffers.
static void lumiera_free(void *mem)
Free previously allocated memory.
Definition: safeclib.h:73
void * lumiera_malloc(size_t size)
Allocate memory.
Definition: safeclib.c:113
LumieraConfigitem lumiera_config_lookup_remove(LumieraConfigLookup self, LumieraConfigitem item)
Remove a config item from a lookup structure.
Intrusive cyclic double linked list There is only one node type which contains a forward and a backwa...
char * lumiera_strndup(const char *str, size_t len)
Duplicate a C string.
Definition: safeclib.c:166
#define LLIST_WHILE_HEAD(list, head)
Consume a list from head.
Definition: llist.h:164
char * lumiera_tmpbuf_snprintf(size_t size, const char *fmt,...)
Construct a string in a tmpbuf.
Definition: tmpbuf.c:116