]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
conf2: implement clearing a dynamic array
[libucw.git] / lib / conf2.c
1 /*
2  *      UCW Library -- Reading of configuration files
3  *
4  *      (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5  *      (c) 2003--2006 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "lib/lib.h"
12 #include "lib/conf2.h"
13 #include "lib/mempool.h"
14 #include "lib/clists.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19
20 /* Memory allocation */
21
22 struct mempool *cf_pool;        // current pool for loading new configuration
23 static struct old_pools {
24   struct old_pools *prev;
25   struct mempool *pool;
26 } *pools;                       // link-list of older cf_pool's
27
28 void *
29 cf_malloc(uns size)
30 {
31   return mp_alloc(cf_pool, size);
32 }
33
34 void *
35 cf_malloc_zero(uns size)
36 {
37   return mp_alloc_zero(cf_pool, size);
38 }
39
40 byte *
41 cf_strdup(byte *s)
42 {
43   return mp_strdup(cf_pool, s);
44 }
45
46 byte *
47 cf_printf(char *fmt, ...)
48 {
49   va_list args;
50   va_start(args, fmt);
51   byte *res = mp_vprintf(cf_pool, fmt, args);
52   va_end(args);
53   return res;
54 }
55
56 /* Undo journal */
57
58 uns cf_need_journal;            // some programs do not need journal
59 static struct journal_item {
60   struct journal_item *prev;
61   byte *ptr;
62   uns len;
63   byte copy[0];
64 } *journal;
65
66 void
67 cf_journal_block(void *ptr, uns len)
68 {
69   if (!cf_need_journal)
70     return;
71   struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
72   ji->prev = journal;
73   ji->ptr = ptr;
74   ji->len = len;
75   memcpy(ji->copy, ptr, len);
76   journal = ji;
77 }
78
79 static void
80 journal_swap(void)
81   // swaps the contents of the memory and the journal, and reverses the list
82 {
83   struct journal_item *curr, *prev, *next;
84   for (next=NULL, curr=journal; curr; next=curr, curr=prev)
85   {
86     prev = curr->prev;
87     curr->prev = next;
88     for (uns i=0; i<curr->len; i++)
89     {
90       byte x = curr->copy[i];
91       curr->copy[i] = curr->ptr[i];
92       curr->ptr[i] = x;
93     }
94   }
95   journal = next;
96 }
97
98 static struct journal_item *
99 journal_new_section(uns new_pool)
100 {
101   if (new_pool)
102     cf_pool = mp_new(1<<14);
103   struct journal_item *oldj = journal;
104   journal = NULL;
105   return oldj;
106 }
107
108 static void
109 journal_commit_section(uns new_pool, struct journal_item *oldj)
110 {
111   if (new_pool)
112   {
113     struct old_pools *p = cf_malloc(sizeof(struct old_pools));
114     p->prev = pools;
115     p->pool = cf_pool;
116     pools = p;
117   }
118   if (oldj)
119   {
120     struct journal_item **j = &journal;
121     while (*j)
122       j = &(*j)->prev;
123     *j = oldj;
124   }
125 }
126
127 static void
128 journal_rollback_section(uns new_pool, struct journal_item *oldj, byte *msg)
129 {
130   if (!cf_need_journal)
131     die("Cannot rollback the configuration, because the journal is disabled.  Error: %s", msg);
132   journal_swap();
133   journal = oldj;
134   if (new_pool)
135   {
136     mp_delete(cf_pool);
137     cf_pool = pools ? pools->pool : NULL;
138   }
139 }
140
141 /* Initialization */
142
143 #define SEC_FLAG_DYNAMIC        1       // contains a dynamic attribute
144
145 static struct cf_section sections;      // root section
146
147 static struct cf_item *
148 find_subitem(struct cf_section *sec, byte *name)
149 {
150   struct cf_item *ci = sec->cfg;
151   for (; ci->cls; ci++)
152     if (!strcasecmp(ci->name, name))
153       return ci;
154   return ci;
155 }
156
157 static void
158 inspect_section(struct cf_section *sec)
159 {
160   sec->flags = 0;
161   for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
162     if (ci->cls == CC_SECTION) {
163       inspect_section(ci->u.sec);
164       sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
165     } else if (ci->cls == CC_LIST) {
166       inspect_section(ci->u.sec);
167       sec->flags |= SEC_FLAG_DYNAMIC;
168     } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
169       sec->flags |= SEC_FLAG_DYNAMIC;
170 }
171
172 void
173 cf_declare_section(byte *name, struct cf_section *sec)
174 {
175   if (!sections.cfg)
176   {
177     sections.size = 50;
178     sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
179   }
180   struct cf_item *ci = find_subitem(&sections, name);
181   if (ci->cls)
182     die("Cannot register section %s twice", name);
183   ci->cls = CC_SECTION;
184   ci->name = name;
185   ci->number = 1;
186   ci->ptr = NULL;
187   ci->u.sec = sec;
188   inspect_section(sec);
189   ci++;
190   if (ci - sections.cfg >= (int) sections.size)
191   {
192     sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
193     bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
194     sections.size *= 2;
195   }
196 }
197
198 void
199 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
200 {
201   if (sec->size)
202     bzero(ptr, sec->size);
203   for (uns i=0; sec->cfg[i].cls; i++)
204     if (sec->cfg[i].cls == CC_SECTION)
205       cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
206     else if (sec->cfg[i].cls == CC_LIST)
207       clist_init(sec->cfg[i].ptr);
208   byte *msg = sec->init(ptr);
209   if (msg)
210     die("Cannot initialize section %s: %s", name, msg);
211 }
212
213 static void
214 global_init(void)
215 {
216   for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
217     cf_init_section(ci->name, ci->u.sec, NULL);
218 }
219
220 static struct cf_item *
221 find_item(struct cf_section *curr_sec, byte *name, byte **msg)
222 {
223   *msg = NULL;
224   if (name[0] == '.')
225     name++;
226   else if (strchr(name, '.'))
227     curr_sec = &sections;
228   if (!curr_sec)
229     return NULL;
230   byte *c;
231   while ((c = strchr(name, '.')))
232   {
233     *c++ = 0;
234     struct cf_item *ci = find_subitem(curr_sec, name);
235     if (ci->cls != CC_SECTION)
236     {
237       *msg = cf_printf("Item %s %s", name, !ci->cls ? "does not exist" : "is not a section");
238       return NULL;
239     }
240     curr_sec = ci->u.sec;
241     name = c;
242   }
243   struct cf_item *ci = find_subitem(curr_sec, name);
244   if (!ci->cls)
245   {
246     *msg = "Unknown item";
247     return NULL;
248   }
249   return ci;
250 }
251
252 /* Safe loading and reloading */
253
254 byte *cf_def_file = DEFAULT_CONFIG;
255
256 #ifndef DEFAULT_CONFIG
257 #define DEFAULT_CONFIG NULL
258 #endif
259
260 byte *cfdeffile = DEFAULT_CONFIG;
261
262 static byte *load_file(byte *file);
263 static byte *load_string(byte *string);
264
265 byte *
266 cf_reload(byte *file)
267 {
268   journal_swap();
269   struct journal_item *oldj = journal_new_section(1);
270   byte *msg = load_file(file);
271   if (!msg)
272   {
273     for (struct old_pools *p=pools; p; p=pools)
274     {
275       pools = p->prev;
276       mp_delete(p->pool);
277     }
278     journal_commit_section(1, NULL);
279   }
280   else
281   {
282     journal_rollback_section(1, oldj, msg);
283     journal_swap();
284   }
285   return msg;
286 }
287
288 byte *
289 cf_load(byte *file)
290 {
291   struct journal_item *oldj = journal_new_section(1);
292   byte *msg = load_file(file);
293   if (!msg)
294     journal_commit_section(1, oldj);
295   else
296     journal_rollback_section(1, oldj, msg);
297   return msg;
298 }
299
300 byte *
301 cf_set(byte *string)
302 {
303   struct journal_item *oldj = journal_new_section(0);
304   byte *msg = load_string(string);
305   if (!msg)
306     journal_commit_section(0, oldj);
307   else
308     journal_rollback_section(0, oldj, msg);
309   return msg;
310 }
311
312 /* Parsers for standard types */
313
314 struct unit {
315   uns name;                     // one-letter name of the unit
316   uns num, den;                 // fraction
317 };
318
319 static const struct unit units[] = {
320   { 'd', 86400, 1 },
321   { 'h', 3600, 1 },
322   { 'k', 1000, 1 },
323   { 'm', 1000000, 1 },
324   { 'g', 1000000000, 1 },
325   { 'K', 1024, 1 },
326   { 'M', 1048576, 1 },
327   { 'G', 1073741824, 1 },
328   { '%', 1, 100 },
329   { 0, 0, 0 }
330 };
331
332 static const struct unit *
333 lookup_unit(byte *value, byte *end, byte **msg)
334 {
335   if (end && *end) {
336     if (end == value || end[1] || *end >= '0' && *end <= '9')
337       *msg = "Invalid number";
338     else {
339       for (const struct unit *u=units; u->name; u++)
340         if (u->name == *end)
341           return u;
342       *msg = "Invalid unit";
343     }
344   }
345   return NULL;
346 }
347
348 static char cf_rngerr[] = "Number out of range";
349
350 byte *
351 cf_parse_int(byte *str, int *ptr)
352 {
353   byte *msg = NULL;
354   if (!*str)
355     msg = "Missing number";
356   else {
357     const struct unit *u;
358     char *end;
359     errno = 0;
360     uns x = strtoul(str, &end, 0);
361     if (errno == ERANGE)
362       msg = cf_rngerr;
363     else if (u = lookup_unit(str, end, &msg)) {
364       u64 y = (u64)x * u->num;
365       if (y % u->den)
366         msg = "Number is not an integer";
367       else {
368         y /= u->den;
369         if (y > 0xffffffff)
370           msg = cf_rngerr;
371         *ptr = y;
372       }
373     } else
374       *ptr = x;
375   }
376   return msg;
377 }
378
379 byte *
380 cf_parse_u64(byte *str, u64 *ptr)
381 {
382   byte *msg = NULL;
383   if (!*str)
384     msg = "Missing number";
385   else {
386     const struct unit *u;
387     char *end;
388     errno = 0;
389     u64 x = strtoull(str, &end, 0);
390     if (errno == ERANGE)
391       msg = cf_rngerr;
392     else if (u = lookup_unit(str, end, &msg)) {
393       if (x > ~(u64)0 / u->num)
394         msg = "Number out of range";
395       else {
396         x *= u->num;
397         if (x % u->den)
398           msg = "Number is not an integer";
399         else
400           *ptr = x / u->den;
401       }
402     } else
403       *ptr = x;
404   }
405   return msg;
406 }
407
408 byte *
409 cf_parse_double(byte *str, double *ptr)
410 {
411   byte *msg = NULL;
412   if (!*str)
413     msg = "Missing number";
414   else {
415     const struct unit *u;
416     char *end;
417     errno = 0;
418     double x = strtoul(str, &end, 0);
419     if (errno == ERANGE)
420       msg = cf_rngerr;
421     else if (u = lookup_unit(str, end, &msg))
422       *ptr = x * u->num / u->den;
423     else
424       *ptr = x;
425   }
426   return msg;
427 }
428
429 static byte *
430 cf_parse_string(byte *str, byte **ptr)
431 {
432   *ptr = cf_strdup(str);
433   return NULL;
434 }
435
436 /* Register size of and parser for each basic type */
437
438 typedef byte *cf_basic_parser(byte *str, void *ptr);
439 static struct {
440   uns size;
441   void *parser;
442 } parsers[] = {
443   { sizeof(int), cf_parse_int },
444   { sizeof(u64), cf_parse_u64 },
445   { sizeof(double), cf_parse_double },
446   { sizeof(byte*), cf_parse_string }
447 };
448
449 static byte *
450 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
451 {
452   for (uns i=0; i<number; i++)
453   {
454     byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
455     if (msg)
456       return cf_printf("Cannot parse item %d: %s", i+1, msg);
457   }
458   return NULL;
459 }
460
461 /* Interpreter */
462
463 enum operation {
464   OP_CLEAR,                     // list
465   OP_SET,                       // basic attribute (static, dynamic, parsed), section, list
466   OP_APPEND,                    // dynamic array, list
467   OP_PREPEND,                   // dynamic array, list
468   OP_REMOVE,                    // list
469   OP_OPEN = 0x80                // here we only have an opening brace
470 };
471
472 #define MAX_STACK_SIZE  100
473 static struct item_stack {
474   struct cf_section *sec;       // nested section
475   void *base_ptr;               // because original pointers are often relative
476   enum operation op;            // it is performed when a closing brace is encountered
477 } stack[MAX_STACK_SIZE];
478 static uns level;
479
480 static byte *
481 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
482 {
483   enum cf_type type = item->u.type;
484   cf_journal_block(ptr, sizeof(void*));
485   // boundary checks done by the caller
486   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
487   * (uns*) (*ptr - parsers[type].size) = number;
488   return cf_parse_ary(number, pars, *ptr, type);
489 }
490
491 static byte *
492 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum operation op)
493 {
494   enum cf_type type = item->u.type;
495   void *old_p = *ptr;
496   int old_nr = * (int*) (old_p - parsers[type].size);
497   int taken = MIN(number, item->number-old_nr);
498   *processed = taken;
499   // stretch the dynamic array
500   void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
501   * (uns*) (new_p - parsers[type].size) = old_nr + taken;
502   cf_journal_block(ptr, sizeof(void*));
503   *ptr = new_p;
504   if (op == OP_APPEND)
505   {
506     memcpy(new_p, old_p, old_nr * parsers[type].size);
507     return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
508   }
509   else if (op == OP_PREPEND)
510   {
511     memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
512     return cf_parse_ary(taken, pars, new_p, type);
513   }
514   else
515     ASSERT(0);
516 }
517
518 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
519
520 static byte *
521 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
522 {
523   *processed = 0;
524   for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
525   {
526     int taken;
527     byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
528     if (msg)
529       return cf_printf("Item %s: %s", ci->name, msg);
530     *processed += taken;
531     number -= taken;
532     pars += taken;
533     if (!number)                // stop parsing, because many parsers would complain that number==0
534       break;
535   }
536   return NULL;
537 }
538
539 static void
540 add_to_list(struct clist *list, struct cnode *node, enum operation op)
541 {
542   cf_journal_block(list, sizeof(struct clist));
543   if (op == OP_APPEND)
544     clist_add_tail(list, node);
545   else if (op == OP_PREPEND)
546     clist_add_head(list, node);
547   else
548     ASSERT(0);
549 }
550
551 static byte *
552 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum operation op)
553 {
554   /* If the node contains any dynamic attribute at the end, we suppress
555    * repetition here and pass it inside instead.  */
556   struct cf_section *sec = item->u.sec;
557   *processed = 0;
558   while (number > 0)
559   {
560     void *node = cf_malloc(sec->size);
561     cf_init_section(item->name, sec, node);
562     add_to_list(ptr, node, op);
563     int taken;
564     byte *msg = interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC);
565     if (msg)
566       return msg;
567     *processed += taken;
568     number -= taken;
569     pars += taken;
570     if (sec->flags & SEC_FLAG_DYNAMIC)
571       break;
572   }
573   return NULL;
574 }
575
576 static byte *
577 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
578 {
579   int taken;
580   switch (item->cls)
581   {
582     case CC_STATIC:
583       taken = MIN(number, item->number);
584       *processed = taken;
585       cf_journal_block(ptr, taken * parsers[item->u.type].size);
586       return cf_parse_ary(taken, pars, ptr, item->u.type);
587     case CC_DYNAMIC:
588       if (!allow_dynamic)
589         return "Dynamic array cannot be used here";
590       taken = MIN(number, item->number);
591       *processed = taken;
592       return interpret_set_dynamic(item, taken, pars, ptr);
593     case CC_PARSER:
594       if (item->number < 0 && !allow_dynamic)
595         return "Parsers with variable number of parameters cannot be used here";
596       if (item->number > 0 && number < item->number)
597         return "Not enough parameters available for the parser";
598       taken = MIN(number, ABS(item->number));
599       *processed = taken;
600       for (int i=0; i<taken; i++)
601         pars[i] = cf_strdup(pars[i]);
602       return item->u.par(taken, pars, ptr);
603     case CC_SECTION:
604       return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
605     case CC_LIST:
606       if (!allow_dynamic)
607         return "Lists cannot be used here";
608       return interpret_add_list(item, number, pars, ptr, processed, OP_APPEND);
609     default:
610       ASSERT(0);
611   }
612 }
613
614 static byte *
615 interpret_clear(struct cf_item *item, void *ptr)
616 {
617   if (item->cls == CC_LIST) {
618     cf_journal_block(ptr, sizeof(struct clist));
619     clist_init(ptr);
620   } else if (item->cls == CC_DYNAMIC) {
621     cf_journal_block(ptr, sizeof(void *));
622     * (void**) ptr = NULL;
623   } else
624     return "The item is not a list or a dynamic array";
625   return NULL;
626 }
627
628 static byte *
629 increase_stack(struct cf_item *item, enum operation op)
630 {
631   if (level >= MAX_STACK_SIZE-1)
632     return "Too many nested sections";
633   ++level;
634   if (item)                     // fill in the base pointer
635   {
636     if (item->cls == CC_SECTION)
637       stack[level].base_ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
638     else if (item->cls != CC_LIST)
639     {
640       stack[level].base_ptr = cf_malloc(item->u.sec->size);
641       cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
642     }
643     else
644       return "Opening brace can only be used on sections and lists";
645     stack[level].sec = item->u.sec;
646   }
647   else                          // unknown is also handled here, since we need to trace recursion
648   {
649     stack[level].base_ptr = NULL;
650     stack[level].sec = NULL;
651   }
652   stack[level].op = op;
653   return NULL;
654 }
655
656 static byte *
657 interpret_line(byte *name, enum operation op, int number, byte **pars)
658 {
659   byte *msg;
660   struct cf_item *item = find_item(stack[level].sec, name, &msg);
661   if (op & OP_OPEN)             // the operation will be performed after the closing brace
662     return increase_stack(item, op) ? : msg;
663   if (!item)
664     return msg;
665
666   void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
667   int taken;                    // process as many parameters as possible
668   if (op == OP_CLEAR)
669     taken = 0, msg = interpret_clear(item, ptr);
670   else if (op == OP_SET)
671     msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
672   else if (item->cls == CC_DYNAMIC)
673     msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
674   else if (item->cls == CC_LIST)
675     msg = interpret_add_list(item, number, pars, &taken, ptr, op);
676   else
677     return cf_printf("Operation %d not supported for class %d", op, item->cls);
678   if (msg)
679     return msg;
680   if (taken < number)
681     return cf_printf("Too many parameters: %d>%d", number, taken);
682   return NULL;
683 }
684