]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
conf2: implemented a command-line parser and sections supporting unknown items
[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 #include "lib/fastbuf.h"
16 #include "lib/chartype.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <stdarg.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24
25 #define TRY(f)  do { byte *_msg = f; if (_msg) return _msg; } while (0)
26
27 /* Memory allocation */
28
29 struct mempool *cf_pool;        // current pool for loading new configuration
30 static struct old_pools {
31   struct old_pools *prev;
32   struct mempool *pool;
33 } *pools;                       // link-list of older cf_pool's
34
35 void *
36 cf_malloc(uns size)
37 {
38   return mp_alloc(cf_pool, size);
39 }
40
41 void *
42 cf_malloc_zero(uns size)
43 {
44   return mp_alloc_zero(cf_pool, size);
45 }
46
47 byte *
48 cf_strdup(byte *s)
49 {
50   return mp_strdup(cf_pool, s);
51 }
52
53 byte *
54 cf_printf(char *fmt, ...)
55 {
56   va_list args;
57   va_start(args, fmt);
58   byte *res = mp_vprintf(cf_pool, fmt, args);
59   va_end(args);
60   return res;
61 }
62
63 /* Undo journal */
64
65 uns cf_need_journal;            // some programs do not need journal
66 static struct journal_item {
67   struct journal_item *prev;
68   byte *ptr;
69   uns len;
70   byte copy[0];
71 } *journal;
72
73 void
74 cf_journal_block(void *ptr, uns len)
75 {
76   if (!cf_need_journal)
77     return;
78   struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
79   ji->prev = journal;
80   ji->ptr = ptr;
81   ji->len = len;
82   memcpy(ji->copy, ptr, len);
83   journal = ji;
84 }
85
86 static void
87 journal_swap(void)
88   // swaps the contents of the memory and the journal, and reverses the list
89 {
90   struct journal_item *curr, *prev, *next;
91   for (next=NULL, curr=journal; curr; next=curr, curr=prev)
92   {
93     prev = curr->prev;
94     curr->prev = next;
95     for (uns i=0; i<curr->len; i++)
96     {
97       byte x = curr->copy[i];
98       curr->copy[i] = curr->ptr[i];
99       curr->ptr[i] = x;
100     }
101   }
102   journal = next;
103 }
104
105 static struct journal_item *
106 journal_new_section(uns new_pool)
107 {
108   if (new_pool)
109     cf_pool = mp_new(1<<14);
110   struct journal_item *oldj = journal;
111   journal = NULL;
112   return oldj;
113 }
114
115 static void
116 journal_commit_section(uns new_pool, struct journal_item *oldj)
117 {
118   if (new_pool)
119   {
120     struct old_pools *p = cf_malloc(sizeof(struct old_pools));
121     p->prev = pools;
122     p->pool = cf_pool;
123     pools = p;
124   }
125   if (oldj)
126   {
127     struct journal_item **j = &journal;
128     while (*j)
129       j = &(*j)->prev;
130     *j = oldj;
131   }
132 }
133
134 static void
135 journal_rollback_section(uns new_pool, struct journal_item *oldj)
136 {
137   if (!cf_need_journal)
138     die("Cannot rollback the configuration, because the journal is disabled.");
139   journal_swap();
140   journal = oldj;
141   if (new_pool)
142   {
143     mp_delete(cf_pool);
144     cf_pool = pools ? pools->pool : NULL;
145   }
146 }
147
148 /* Initialization */
149
150 #define SEC_FLAG_DYNAMIC 0x80000000     // contains a dynamic attribute
151 #define SEC_FLAG_UNKNOWN 0x40000000     // ignore unknown entriies
152 #define SEC_FLAG_NUMBER 0x3fffffff      // number of entries
153
154 static struct cf_section sections;      // root section
155
156 static struct cf_item *
157 find_subitem(struct cf_section *sec, byte *name)
158 {
159   struct cf_item *ci = sec->cfg;
160   for (; ci->cls; ci++)
161     if (!strcasecmp(ci->name, name))
162       return ci;
163   return ci;
164 }
165
166 static void
167 inspect_section(struct cf_section *sec)
168 {
169   sec->flags = 0;
170   struct cf_item *ci;
171   for (ci=sec->cfg; ci->cls; ci++)
172     if (ci->cls == CC_SECTION) {
173       inspect_section(ci->u.sec);
174       sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
175     } else if (ci->cls == CC_LIST) {
176       inspect_section(ci->u.sec);
177       sec->flags |= SEC_FLAG_DYNAMIC;
178     } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
179       sec->flags |= SEC_FLAG_DYNAMIC;
180   sec->flags |= ci - sec->cfg;          // record the number of entries
181 }
182
183 void
184 cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown)
185 {
186   if (!sections.cfg)
187   {
188     sections.size = 50;
189     sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
190   }
191   struct cf_item *ci = find_subitem(&sections, name);
192   if (ci->cls)
193     die("Cannot register section %s twice", name);
194   ci->cls = CC_SECTION;
195   ci->name = name;
196   ci->number = 1;
197   ci->ptr = NULL;
198   ci->u.sec = sec;
199   inspect_section(sec);
200   if (allow_unknown)
201     sec->flags |= SEC_FLAG_UNKNOWN;
202   ci++;
203   if (ci - sections.cfg >= (int) sections.size)
204   {
205     sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
206     bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
207     sections.size *= 2;
208   }
209 }
210
211 void
212 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
213 {
214   if (sec->size)
215     bzero(ptr, sec->size);
216   for (uns i=0; sec->cfg[i].cls; i++)
217     if (sec->cfg[i].cls == CC_SECTION)
218       cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
219     else if (sec->cfg[i].cls == CC_LIST)
220       clist_init(sec->cfg[i].ptr);
221   byte *msg = sec->init(ptr);
222   if (msg)
223     die("Cannot initialize section %s: %s", name, msg);
224 }
225
226 static void
227 global_init(void)
228 {
229   static uns initialized = 0;
230   if (initialized++)
231     return;
232   sections.flags |= SEC_FLAG_UNKNOWN;
233   for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
234     cf_init_section(ci->name, ci->u.sec, NULL);
235 }
236
237 static struct cf_item *
238 find_item(struct cf_section *curr_sec, byte *name, byte **msg)
239 {
240   *msg = NULL;
241   if (name[0] == '^')                           // absolute name instead of relative
242     name++, curr_sec = &sections;
243   if (!curr_sec)                                // don't even search in an unknown section
244     return NULL;
245   while (1)
246   {
247     byte *c = strchr(name, '.');
248     if (c)
249       *c++ = 0;
250     struct cf_item *ci = find_subitem(curr_sec, name);
251     if (!ci->cls)
252     {
253       if (!(curr_sec->flags & SEC_FLAG_UNKNOWN))        // ignore silently unknown top-level sections and unknown attributes in flagged sections
254         *msg = cf_printf("Unknown item %s", name);
255       return NULL;
256     }
257     if (!c)
258       return ci;
259     if (ci->cls != CC_SECTION)
260     {
261       *msg = cf_printf("Item %s is not a section", name);
262       return NULL;
263     }
264     curr_sec = ci->u.sec;
265     name = c;
266   }
267 }
268
269 /* Safe loading and reloading */
270
271 static int load_file(byte *file);
272 static int load_string(byte *string);
273
274 int
275 cf_reload(byte *file)
276 {
277   journal_swap();
278   struct journal_item *oldj = journal_new_section(1);
279   int err = load_file(file);
280   if (!err)
281   {
282     for (struct old_pools *p=pools; p; p=pools)
283     {
284       pools = p->prev;
285       mp_delete(p->pool);
286     }
287     journal_commit_section(1, NULL);
288   }
289   else
290   {
291     journal_rollback_section(1, oldj);
292     journal_swap();
293   }
294   return err;
295 }
296
297 int
298 cf_load(byte *file)
299 {
300   struct journal_item *oldj = journal_new_section(1);
301   int err = load_file(file);
302   if (!err)
303     journal_commit_section(1, oldj);
304   else
305     journal_rollback_section(1, oldj);
306   return err;
307 }
308
309 int
310 cf_set(byte *string)
311 {
312   struct journal_item *oldj = journal_new_section(0);
313   int err = load_string(string);
314   if (!err)
315     journal_commit_section(0, oldj);
316   else
317     journal_rollback_section(0, oldj);
318   return err;
319 }
320
321 /* Parsers for standard types */
322
323 struct unit {
324   uns name;                     // one-letter name of the unit
325   uns num, den;                 // fraction
326 };
327
328 static const struct unit units[] = {
329   { 'd', 86400, 1 },
330   { 'h', 3600, 1 },
331   { 'k', 1000, 1 },
332   { 'm', 1000000, 1 },
333   { 'g', 1000000000, 1 },
334   { 'K', 1024, 1 },
335   { 'M', 1048576, 1 },
336   { 'G', 1073741824, 1 },
337   { '%', 1, 100 },
338   { 0, 0, 0 }
339 };
340
341 static const struct unit *
342 lookup_unit(byte *value, byte *end, byte **msg)
343 {
344   if (end && *end) {
345     if (end == value || end[1] || *end >= '0' && *end <= '9')
346       *msg = "Invalid number";
347     else {
348       for (const struct unit *u=units; u->name; u++)
349         if (u->name == *end)
350           return u;
351       *msg = "Invalid unit";
352     }
353   }
354   return NULL;
355 }
356
357 static char cf_rngerr[] = "Number out of range";
358
359 //FIXME: parsers should handle well empty strings, unwanted suffixes etc.
360 byte *
361 cf_parse_int(byte *str, int *ptr)
362 {
363   byte *msg = NULL;
364   if (!*str)
365     msg = "Missing number";
366   else {
367     const struct unit *u;
368     char *end;
369     errno = 0;
370     uns x = strtoul(str, &end, 0);
371     if (errno == ERANGE)
372       msg = cf_rngerr;
373     else if (u = lookup_unit(str, end, &msg)) {
374       u64 y = (u64)x * u->num;
375       if (y % u->den)
376         msg = "Number is not an integer";
377       else {
378         y /= u->den;
379         if (y > 0xffffffff)
380           msg = cf_rngerr;
381         *ptr = y;
382       }
383     } else
384       *ptr = x;
385   }
386   return msg;
387 }
388
389 byte *
390 cf_parse_u64(byte *str, u64 *ptr)
391 {
392   byte *msg = NULL;
393   if (!*str)
394     msg = "Missing number";
395   else {
396     const struct unit *u;
397     char *end;
398     errno = 0;
399     u64 x = strtoull(str, &end, 0);
400     if (errno == ERANGE)
401       msg = cf_rngerr;
402     else if (u = lookup_unit(str, end, &msg)) {
403       if (x > ~(u64)0 / u->num)
404         msg = "Number out of range";
405       else {
406         x *= u->num;
407         if (x % u->den)
408           msg = "Number is not an integer";
409         else
410           *ptr = x / u->den;
411       }
412     } else
413       *ptr = x;
414   }
415   return msg;
416 }
417
418 byte *
419 cf_parse_double(byte *str, double *ptr)
420 {
421   byte *msg = NULL;
422   if (!*str)
423     msg = "Missing number";
424   else {
425     const struct unit *u;
426     char *end;
427     errno = 0;
428     double x = strtoul(str, &end, 0);
429     if (errno == ERANGE)
430       msg = cf_rngerr;
431     else if (u = lookup_unit(str, end, &msg))
432       *ptr = x * u->num / u->den;
433     else
434       *ptr = x;
435   }
436   return msg;
437 }
438
439 byte *
440 cf_parse_ip(byte *p, u32 *varp)
441 {
442   if (!*p)
443     return "Missing IP address";
444   uns x = 0;
445   if (*p == '0' && p[1] | 32 == 'X') {
446     errno = 0;
447     x = strtoul(p + 2, NULL, 16);
448     if (errno == ERANGE || x > 0xffffffff)
449       goto error;
450   }
451   else
452     for (uns i = 0; i < 4; i++) {
453       if (i) {
454         if (*p++ != '.')
455           goto error;
456       }
457       errno = 0;
458       char *p2;
459       uns y = strtoul(p, &p2, 10);
460       p = p2;
461       if (errno == ERANGE || y > 255)
462         goto error;
463       x = (x << 8) + y;
464     }
465   *varp = x;
466   return NULL;
467 error:
468   return "Invalid IP address";
469 }
470
471 static byte *
472 cf_parse_string(byte *str, byte **ptr)
473 {
474   *ptr = cf_strdup(str);
475   return NULL;
476 }
477
478 /* Register size of and parser for each basic type */
479
480 typedef byte *cf_basic_parser(byte *str, void *ptr);
481 static struct {
482   uns size;
483   void *parser;
484 } parsers[] = {
485   { sizeof(int), cf_parse_int },
486   { sizeof(u64), cf_parse_u64 },
487   { sizeof(double), cf_parse_double },
488   { sizeof(u32), cf_parse_ip },
489   { sizeof(byte*), cf_parse_string }
490 };
491
492 static byte *
493 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
494 {
495   for (uns i=0; i<number; i++)
496   {
497     byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
498     if (msg)
499       return cf_printf("Cannot parse item %d: %s", i+1, msg);
500   }
501   return NULL;
502 }
503
504 /* Interpreter */
505
506 #define OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \
507   T(REMOVE) T(EDIT) T(AFTER) T(BEFORE)
508   /* Closing brace finishes previous block.
509    * Basic attributes (static, dynamic, parsed) can be used with SET.
510    * Dynamic arrays can be used with SET, APPEND, PREPEND.
511    * Sections can be used with SET.
512    * Lists can be used with everything. */
513 #define T(x) OP_##x,
514 enum operation {
515   OPERATIONS
516 };
517 #undef T
518 #define T(x) #x,
519 static byte *op_names[] = {
520   OPERATIONS
521 };
522 #undef T
523
524 #define OP_MASK 0xff            // only get the operation
525 #define OP_OPEN 0x100           // here we only get an opening brace instead of parameters
526 #define OP_1ST 0x200            // in the 1st phase selectors are recorded into the mask
527 #define OP_2ND 0x400            // in the 2nd phase real data are entered
528
529 static byte *
530 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
531 {
532   enum cf_type type = item->u.type;
533   cf_journal_block(ptr, sizeof(void*));
534   // boundary checks done by the caller
535   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
536   * (uns*) (*ptr - parsers[type].size) = number;
537   return cf_parse_ary(number, pars, *ptr, type);
538 }
539
540 static byte *
541 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum operation op)
542 {
543   enum cf_type type = item->u.type;
544   void *old_p = *ptr;
545   int old_nr = * (int*) (old_p - parsers[type].size);
546   int taken = MIN(number, item->number-old_nr);
547   *processed = taken;
548   // stretch the dynamic array
549   void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
550   * (uns*) (new_p - parsers[type].size) = old_nr + taken;
551   cf_journal_block(ptr, sizeof(void*));
552   *ptr = new_p;
553   if (op == OP_APPEND) {
554     memcpy(new_p, old_p, old_nr * parsers[type].size);
555     return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
556   } else if (op == OP_PREPEND) {
557     memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
558     return cf_parse_ary(taken, pars, new_p, type);
559   } else
560     return cf_printf("Dynamic arrays do not support operation %s", op_names[op]);
561 }
562
563 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
564
565 static byte *
566 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
567 {
568   *processed = 0;
569   for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
570   {
571     int taken;
572     byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
573     if (msg)
574       return cf_printf("Item %s: %s", ci->name, msg);
575     *processed += taken;
576     number -= taken;
577     pars += taken;
578     if (!number)                // stop parsing, because many parsers would otherwise complain that number==0
579       break;
580   }
581   return NULL;
582 }
583
584 static void
585 add_to_list(void *list, struct cnode *node, enum operation op)
586 {
587   cf_journal_block(list, sizeof(struct clist));         //FIXME: we should journal the nodes of the list instead
588   switch (op)
589   {
590     case OP_SET:
591     case OP_APPEND:
592       clist_add_tail(list, node);
593       break;
594     case OP_PREPEND:
595       clist_add_head(list, node);
596       break;
597     case OP_REMOVE:
598       clist_remove(list);
599       break;
600     case OP_EDIT:               // edition has been done in-place
601       break;
602     case OP_AFTER:              // here the pointer list is actually a pointer to another node
603       clist_insert_after(node, list);
604       break;
605     case OP_BEFORE:
606       clist_insert_before(node, list);
607       break;
608     default:
609       ASSERT(0);
610   }
611 }
612
613 static byte *
614 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum operation op)
615 {
616   if (!number)
617     return "Missing value";
618   ASSERT(op < OP_REMOVE);
619   struct cf_section *sec = item->u.sec;
620   *processed = 0;
621   while (number > 0)
622   {
623     void *node = cf_malloc(sec->size);
624     cf_init_section(item->name, sec, node);
625     add_to_list(ptr, node, op);
626     int taken;
627     /* If the node contains any dynamic attribute at the end, we suppress
628      * auto-repetition here and pass the flag inside instead.  */
629     TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
630     *processed += taken;
631     number -= taken;
632     pars += taken;
633     if (sec->flags & SEC_FLAG_DYNAMIC)
634       break;
635   }
636   return NULL;
637 }
638
639 static byte *
640 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
641 {
642   int taken;
643   switch (item->cls)
644   {
645     case CC_STATIC:
646       if (!number)
647         return "Missing value";
648       taken = MIN(number, item->number);
649       *processed = taken;
650       cf_journal_block(ptr, taken * parsers[item->u.type].size);
651       return cf_parse_ary(taken, pars, ptr, item->u.type);
652     case CC_DYNAMIC:
653       if (!allow_dynamic)
654         return "Dynamic array cannot be used here";
655       taken = MIN(number, item->number);
656       *processed = taken;
657       return interpret_set_dynamic(item, taken, pars, ptr);
658     case CC_PARSER:
659       if (item->number < 0 && !allow_dynamic)
660         return "Parsers with variable number of parameters cannot be used here";
661       if (item->number > 0 && number < item->number)
662         return "Not enough parameters available for the parser";
663       taken = MIN(number, ABS(item->number));
664       *processed = taken;
665       for (int i=0; i<taken; i++)
666         pars[i] = cf_strdup(pars[i]);
667       return item->u.par(taken, pars, ptr);
668     case CC_SECTION:
669       return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
670     case CC_LIST:
671       if (!allow_dynamic)
672         return "Lists cannot be used here";
673       return interpret_add_list(item, number, pars, ptr, processed, OP_SET);
674     default:
675       ASSERT(0);
676   }
677 }
678
679 static byte *
680 interpret_clear(struct cf_item *item, void *ptr)
681 {
682   if (item->cls == CC_LIST) {
683     cf_journal_block(ptr, sizeof(struct clist));
684     clist_init(ptr);
685   } else if (item->cls == CC_DYNAMIC) {
686     cf_journal_block(ptr, sizeof(void *));
687     * (void**) ptr = NULL;
688   } else
689     return "The item is not a list or a dynamic array";
690   return NULL;
691 }
692
693 static int
694 cmp_items(void *i1, void *i2, struct cf_item *item)
695 {
696   ASSERT(item->cls == CC_STATIC);
697   i1 += (addr_int_t) item->ptr;
698   i2 += (addr_int_t) item->ptr;
699   if (item->u.type == CT_STRING)
700     return strcmp(* (byte**) i1, * (byte**) i2);
701   else                          // all numeric types
702     return memcmp(i1, i2, parsers[item->u.type].size);
703 }
704
705 static void *
706 find_list_node(struct clist *list, void *query, struct cf_section *sec, u32 mask)
707 {
708   struct cnode *n;
709   CLIST_WALK(n, *list)
710   {
711     uns found = 1;
712     for (uns i=0; i<32; i++)
713       if (mask & (1<<i))
714         if (cmp_items(n, query, sec->cfg+i))
715         {
716           found = 0;
717           break;
718         }
719     if (found)
720       return n;
721   }
722   return NULL;
723 }
724
725 static byte *
726 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
727 {
728   uns nr = sec->flags & SEC_FLAG_NUMBER;
729   if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
730   {
731     uns i = item - sec->cfg;
732     if (i >= 32)
733       return "Cannot select list nodes by this attribute";
734     if (sec->cfg[i].cls != CC_STATIC)
735       return "Selection can only be done based on basic attributes";
736     *mask |= 1 << i;
737   }
738   return NULL;
739 }
740
741 #define MAX_STACK_SIZE  100
742 static struct item_stack {
743   struct cf_section *sec;       // nested section
744   void *base_ptr;               // because original pointers are often relative
745   enum operation op;            // it is performed when a closing brace is encountered
746   void *list;                   // list the operations should be done on
747   u32 mask;                     // bit array of selectors searching in a list
748   struct cf_item *item;         // cf_item of the list
749 } stack[MAX_STACK_SIZE];
750 static uns level;
751
752 static byte *
753 opening_brace(struct cf_item *item, void *ptr, enum operation op)
754 {
755   if (level >= MAX_STACK_SIZE-1)
756     return "Too many nested sections";
757   stack[++level] = (struct item_stack) {
758     .sec = NULL,
759     .base_ptr = NULL,
760     .op = op,
761     .list = NULL,
762     .mask = 0,
763     .item = NULL,
764   };
765   if (!item)                    // unknown is ignored; we just need to trace recursion
766     return NULL;
767   stack[level].sec = item->u.sec;
768   if (item->cls == CC_SECTION)
769   {
770     stack[level].base_ptr = ptr;
771     stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
772   }
773   else if (item->cls == CC_LIST)
774   {
775     stack[level].base_ptr = cf_malloc(item->u.sec->size);
776     cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
777     stack[level].list = ptr;
778     stack[level].item = item;
779     stack[level].op |= op < OP_REMOVE ? OP_2ND : OP_1ST;
780   }
781   else
782     return "Opening brace can only be used on sections and lists";
783   return NULL;
784 }
785
786 static byte *
787 closing_brace(struct item_stack *st, int number, byte **pars)
788 {
789   if (st->op == OP_CLOSE)       // top-level
790     return "Unmatched } parenthese";
791   if (!st->sec) {               // dummy run on unknown section
792     level--;
793     return NULL;
794   }
795   enum operation op = st->op & OP_MASK;
796   if (st->op & OP_1ST)
797   {
798     st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
799     if (!st->list)
800       return "Cannot find a node matching the query";
801     if (op != OP_REMOVE)
802     {
803       if (op == OP_EDIT)
804         st->base_ptr = st->list;
805       else if (op == OP_AFTER || op == OP_BEFORE)
806         cf_init_section(st->item->name, st->sec, st->base_ptr);
807       else
808         ASSERT(0);
809       if (st->op & OP_OPEN) {   // stay at the same recursion level
810         st->op = (st->op | OP_2ND) & ~OP_1ST;
811         return NULL;
812       }
813       int taken;                // parse parameters on 1 line immediately
814       TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
815       number -= taken;
816       pars += taken;
817       // and fall-thru to the 2nd phase
818     }
819   }
820   add_to_list(st->list, st->base_ptr, op);
821   level--;
822   if (number)
823     return "No parameters expected after the }";
824   else if (st->op & OP_OPEN)
825     return "No { is expected";
826   else
827     return NULL;
828 }
829
830 static byte *
831 interpret_line(byte *name, enum operation op, int number, byte **pars)
832 {
833   byte *msg;
834   if (op == OP_CLOSE)
835     return closing_brace(stack+level, number, pars);
836   struct cf_item *item = find_item(stack[level].sec, name, &msg);
837   if (msg)
838     return msg;
839   if (stack[level].op & OP_1ST)
840     TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
841   void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
842   if (op & OP_OPEN)             // the operation will be performed after the closing brace
843     return opening_brace(item, ptr, op);
844   if (!item)                    // ignored item in an unknown section
845     return NULL;
846   op &= OP_MASK;
847
848   int taken;                    // process as many parameters as possible
849   if (op == OP_CLEAR)
850     taken = 0, msg = interpret_clear(item, ptr);
851   else if (op == OP_SET)
852     msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
853   else if (item->cls == CC_DYNAMIC)
854     msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
855   else if (item->cls == CC_LIST)
856     msg = interpret_add_list(item, number, pars, &taken, ptr, op);
857   else
858     return cf_printf("Operation %s not supported on attribute class %d", op_names[op], item->cls);
859   if (msg)
860     return msg;
861   if (taken < number)
862     return cf_printf("Too many parameters: %d>%d", number, taken);
863
864   return NULL;
865 }
866
867 static void
868 init_stack(void)
869 {
870   global_init();
871   level = 0;
872   stack[0] = (struct item_stack) {
873     .sec = &sections,
874     .base_ptr = NULL,
875     .op = OP_CLOSE,
876     .list = NULL,
877     .mask = 0,
878     .item = NULL
879   };
880 }
881
882 static int
883 done_stack(void)
884 {
885   if (level > 0) {
886     log(L_ERROR, "Unterminated block");
887     return 1;
888   }
889   return 0;
890 }
891
892 /* Text file parser */
893
894 static struct fastbuf *parse_fb;
895 static uns line_num;
896
897 #define MAX_LINE        4096
898 static byte line_buf[MAX_LINE];
899 static byte *line = line_buf;
900
901 #include "lib/bbuf.h"
902 static bb_t copy_buf;
903 static uns copied;
904
905 #define GBUF_TYPE       uns
906 #define GBUF_PREFIX(x)  split_##x
907 #include "lib/gbuf.h"
908 static split_t word_buf;
909 static uns words;
910 static uns ends_by_brace;               // the line is ended by "{"
911
912 static int
913 get_line(void)
914 {
915   if (!bgets(parse_fb, line_buf, MAX_LINE))
916     return 0;
917   line_num++;
918   line = line_buf;
919   while (Cblank(*line))
920     line++;
921   return 1;
922 }
923
924 static void
925 append(byte *start, byte *end)
926 {
927   uns len = end - start;
928   bb_grow(&copy_buf, copied + len + 1);
929   memcpy(copy_buf.ptr + copied, start, len);
930   copied += len + 1;
931   copy_buf.ptr[copied-1] = 0;
932 }
933
934 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
935   // these characters separate words like blanks
936
937 static byte *
938 get_word(uns stop_at_equal)
939 {
940   // promised that *line is non-null and non-blank
941   if (*line == '\'') {
942     line++;
943     while (1) {
944       byte *start = line;
945       while (*line && *line != '\'')
946         line++;
947       append(start, line);
948       if (*line)
949         break;
950       copy_buf.ptr[copied-1] = '\n';
951       if (!get_line())
952         return "Unterminated apostrophe word at the end";
953     }
954     line++;
955   } else if (*line == '"') {
956     line++;
957     while (1) {
958       byte *start = line;
959       uns escape = 0;
960       while (*line) {
961         if (*line == '"' && !escape)
962           break;
963         else if (*line == '\\')
964           escape ^= 1;
965         else
966           escape = 0;
967         line++;
968       }
969       append(start, line);
970       if (*line)
971         break;
972       if (!escape)
973         copy_buf.ptr[copied-1] = '\n';
974       else // merge two lines
975         copied -= 2;
976       if (!get_line())
977         return "Unterminated quoted word at the end";
978     }
979     line++;
980   } else {
981     byte *start = line;
982     while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
983         && (*line != '=' || !stop_at_equal))
984       line++;
985     if (*line == '=') {                         // nice for setting from a command-line
986       if (line == start)
987         return "Assignment without a variable";
988       *line = ' ';
989     }
990     if (CONTROL_CHAR(*line))                    // already the first char is control
991       line++;
992     append(start, line);
993   }
994   while (Cblank(*line))
995     line++;
996   return NULL;
997 }
998
999 static byte *
1000 split_line(void)
1001 {
1002   words = 0;
1003   copied = 0;
1004   ends_by_brace = 0;
1005   while (!*line || *line == '#')
1006   {
1007     if (!get_line())
1008       return NULL;
1009     while (*line == ';'                         // empty trash at the beginning
1010         || (*line == '\\' && !line[1])) {
1011       TRY( get_word(0) );
1012       copied = 0;
1013     }
1014     if (*line == '{')                           // only one opening brace
1015       return "Unexpected opening brace";
1016   }
1017   /* We have got a non-null, non-blank, non-;, non-merge, and non-{ character.  */
1018   while (1)
1019   {
1020     split_grow(&word_buf, words+1);
1021     word_buf.ptr[words++] = copied;
1022     TRY( get_word(!words) );
1023     if (!*line)
1024       break;
1025     else if (*line == '}' || *line == ';')      // end of line now and preserve the char
1026       break;
1027     else if (*line == '{') {                    // discard the char and end the line
1028 discard_brace:
1029       ends_by_brace = 1;
1030       TRY( get_word(0) );
1031       break;
1032     } else if (*line == '\\' && !line[1]) {     // merge two lines
1033       if (!get_line())
1034         return "Last line ends by a backslash";
1035       if (!*line || *line == '#') {
1036         log(L_WARN, "The line following the backslash is empty");
1037         break;
1038       } else if (*line == '{')
1039         goto discard_brace;
1040     }
1041   }
1042   return NULL;
1043 }
1044
1045 /* Parsing multiple files */
1046
1047 static byte *
1048 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1049 {
1050   byte *msg;
1051   parse_fb = fb;
1052   line_num = 0;
1053   line = line_buf;
1054   *line = 0;
1055   while (1)
1056   {
1057     msg = split_line();
1058     if (msg)
1059       goto error;
1060     if (!words)
1061       return NULL;
1062     byte *name = copy_buf.ptr + word_buf.ptr[0];
1063     byte *pars[words-1];
1064     for (uns i=1; i<words; i++)
1065       pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1066     if (!strcasecmp(name, "#include"))
1067     {
1068       if (words != 2) {
1069         msg = "Expecting one filename";
1070         goto error;
1071       }
1072       if (depth > 8) {
1073         msg = "Too many nested files";
1074         goto error;
1075       }
1076       parse_fb = bopen(pars[0], O_RDONLY, 1<<14);
1077       uns ll = line_num;
1078       msg = parse_fastbuf(pars[0], parse_fb, depth+1);
1079       bclose(parse_fb);
1080       if (msg)
1081         goto error;
1082       line_num = ll;
1083       parse_fb = fb;
1084     }
1085     enum operation op;
1086     byte *c = strchr(name, ':');
1087     if (!c)
1088       op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1089     else {
1090       *c++ = 0;
1091       switch (Clocase(*c)) {
1092         case 's': op = OP_SET; break;
1093         case 'c': op = OP_CLEAR; break;
1094         case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1095         case 'p': op = OP_PREPEND; break;
1096         case 'r': op = OP_REMOVE; break;
1097         case 'e': op = OP_EDIT; break;
1098         case 'b': op = OP_BEFORE; break;
1099         default: op = OP_SET; break;
1100       }
1101       if (strcasecmp(c, op_names[op])) {
1102         msg = cf_printf("Unknown operation %s", c);
1103         goto error;
1104       }
1105     }
1106     if (ends_by_brace)
1107       op |= OP_OPEN;
1108     msg = interpret_line(name, op, words-1, pars);
1109     if (msg)
1110       goto error;
1111   }
1112 error:
1113   log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1114   return "included from here";
1115 }
1116
1117 #ifndef DEFAULT_CONFIG
1118 #define DEFAULT_CONFIG NULL
1119 #endif
1120 byte *cf_def_file = DEFAULT_CONFIG;
1121
1122 static int
1123 load_file(byte *file)
1124 {
1125   cf_def_file = NULL;
1126   init_stack();
1127   struct fastbuf *fb = bopen(file, O_RDONLY, 1<<14);
1128   byte *msg = parse_fastbuf(file, fb, 0);
1129   bclose(fb);
1130   return !!msg || done_stack();
1131 }
1132
1133 static int
1134 load_string(byte *string)
1135 {
1136   init_stack();
1137   struct fastbuf fb;
1138   fbbuf_init_read(&fb, string, strlen(string), 0);
1139   byte *msg = parse_fastbuf("memory string", &fb, 0);
1140   return !!msg || done_stack();
1141 }
1142
1143 /* Command-line parser */
1144
1145 static void
1146 load_default(void)
1147 {
1148   if (cf_def_file)
1149     if (cf_load(cf_def_file))
1150       die("Cannot load default config %s", optarg);
1151 }
1152
1153 int
1154 cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
1155 {
1156   static int other_options = 0;
1157   while (1) {
1158     int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
1159     if (res == 'S' || res == 'C')
1160     {
1161       if (other_options)
1162         die("The -S and -C options must precede all other arguments");
1163       if (res == 'S') {
1164         load_default();
1165         if (cf_set(optarg))
1166           die("Cannot set %s", optarg);
1167       } else {
1168         if (cf_load(optarg))
1169           die("Cannot load %s", optarg);
1170       }
1171     } else {
1172       /* unhandled option or end of options */
1173       load_default();
1174       other_options++;
1175       return res;
1176     }
1177   }
1178 }