]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
conf2: added interface for accessing cf_items from outside
[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, void **ptr)
239 {
240   *msg = NULL;
241   if (name[0] == '^')                           // absolute name instead of relative
242     name++, curr_sec = &sections, *ptr = NULL;
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     *ptr += (addr_int_t) ci->ptr;
258     if (!c)
259       return ci;
260     if (ci->cls != CC_SECTION)
261     {
262       *msg = cf_printf("Item %s is not a section", name);
263       return NULL;
264     }
265     curr_sec = ci->u.sec;
266     name = c;
267   }
268 }
269
270 byte *
271 cf_find_item(byte *name, struct cf_item *item)
272 {
273   byte *msg;
274   void *ptr;
275   struct cf_item *ci = find_item(&sections, name, &msg, &ptr);
276   if (msg)
277     return msg;
278   *item = *ci;
279   item->ptr = ptr;
280   return NULL;
281 }
282
283 /* Safe loading and reloading */
284
285 static int load_file(byte *file);
286 static int load_string(byte *string);
287
288 int
289 cf_reload(byte *file)
290 {
291   journal_swap();
292   struct journal_item *oldj = journal_new_section(1);
293   int err = load_file(file);
294   if (!err)
295   {
296     for (struct old_pools *p=pools; p; p=pools)
297     {
298       pools = p->prev;
299       mp_delete(p->pool);
300     }
301     journal_commit_section(1, NULL);
302   }
303   else
304   {
305     journal_rollback_section(1, oldj);
306     journal_swap();
307   }
308   return err;
309 }
310
311 int
312 cf_load(byte *file)
313 {
314   struct journal_item *oldj = journal_new_section(1);
315   int err = load_file(file);
316   if (!err)
317     journal_commit_section(1, oldj);
318   else
319     journal_rollback_section(1, oldj);
320   return err;
321 }
322
323 int
324 cf_set(byte *string)
325 {
326   struct journal_item *oldj = journal_new_section(0);
327   int err = load_string(string);
328   if (!err)
329     journal_commit_section(0, oldj);
330   else
331     journal_rollback_section(0, oldj);
332   return err;
333 }
334
335 /* Parsers for standard types */
336
337 struct unit {
338   uns name;                     // one-letter name of the unit
339   uns num, den;                 // fraction
340 };
341
342 static const struct unit units[] = {
343   { 'd', 86400, 1 },
344   { 'h', 3600, 1 },
345   { 'k', 1000, 1 },
346   { 'm', 1000000, 1 },
347   { 'g', 1000000000, 1 },
348   { 'K', 1024, 1 },
349   { 'M', 1048576, 1 },
350   { 'G', 1073741824, 1 },
351   { '%', 1, 100 },
352   { 0, 0, 0 }
353 };
354
355 static const struct unit *
356 lookup_unit(byte *value, byte *end, byte **msg)
357 {
358   if (end && *end) {
359     if (end == value || end[1] || *end >= '0' && *end <= '9')
360       *msg = "Invalid number";
361     else {
362       for (const struct unit *u=units; u->name; u++)
363         if (u->name == *end)
364           return u;
365       *msg = "Invalid unit";
366     }
367   }
368   return NULL;
369 }
370
371 static char cf_rngerr[] = "Number out of range";
372
373 //FIXME: parsers should handle well empty strings, unwanted suffixes etc.
374 byte *
375 cf_parse_int(byte *str, int *ptr)
376 {
377   byte *msg = NULL;
378   if (!*str)
379     msg = "Missing number";
380   else {
381     const struct unit *u;
382     char *end;
383     errno = 0;
384     uns x = strtoul(str, &end, 0);
385     if (errno == ERANGE)
386       msg = cf_rngerr;
387     else if (u = lookup_unit(str, end, &msg)) {
388       u64 y = (u64)x * u->num;
389       if (y % u->den)
390         msg = "Number is not an integer";
391       else {
392         y /= u->den;
393         if (y > 0xffffffff)
394           msg = cf_rngerr;
395         *ptr = y;
396       }
397     } else
398       *ptr = x;
399   }
400   return msg;
401 }
402
403 byte *
404 cf_parse_u64(byte *str, u64 *ptr)
405 {
406   byte *msg = NULL;
407   if (!*str)
408     msg = "Missing number";
409   else {
410     const struct unit *u;
411     char *end;
412     errno = 0;
413     u64 x = strtoull(str, &end, 0);
414     if (errno == ERANGE)
415       msg = cf_rngerr;
416     else if (u = lookup_unit(str, end, &msg)) {
417       if (x > ~(u64)0 / u->num)
418         msg = "Number out of range";
419       else {
420         x *= u->num;
421         if (x % u->den)
422           msg = "Number is not an integer";
423         else
424           *ptr = x / u->den;
425       }
426     } else
427       *ptr = x;
428   }
429   return msg;
430 }
431
432 byte *
433 cf_parse_double(byte *str, double *ptr)
434 {
435   byte *msg = NULL;
436   if (!*str)
437     msg = "Missing number";
438   else {
439     const struct unit *u;
440     char *end;
441     errno = 0;
442     double x = strtoul(str, &end, 0);
443     if (errno == ERANGE)
444       msg = cf_rngerr;
445     else if (u = lookup_unit(str, end, &msg))
446       *ptr = x * u->num / u->den;
447     else
448       *ptr = x;
449   }
450   return msg;
451 }
452
453 byte *
454 cf_parse_ip(byte *p, u32 *varp)
455 {
456   if (!*p)
457     return "Missing IP address";
458   uns x = 0;
459   if (*p == '0' && p[1] | 32 == 'X') {
460     errno = 0;
461     x = strtoul(p + 2, NULL, 16);
462     if (errno == ERANGE || x > 0xffffffff)
463       goto error;
464   }
465   else
466     for (uns i = 0; i < 4; i++) {
467       if (i) {
468         if (*p++ != '.')
469           goto error;
470       }
471       errno = 0;
472       char *p2;
473       uns y = strtoul(p, &p2, 10);
474       p = p2;
475       if (errno == ERANGE || y > 255)
476         goto error;
477       x = (x << 8) + y;
478     }
479   *varp = x;
480   return NULL;
481 error:
482   return "Invalid IP address";
483 }
484
485 static byte *
486 cf_parse_string(byte *str, byte **ptr)
487 {
488   *ptr = cf_strdup(str);
489   return NULL;
490 }
491
492 /* Register size of and parser for each basic type */
493
494 typedef byte *cf_basic_parser(byte *str, void *ptr);
495 static struct {
496   uns size;
497   void *parser;
498 } parsers[] = {
499   { sizeof(int), cf_parse_int },
500   { sizeof(u64), cf_parse_u64 },
501   { sizeof(double), cf_parse_double },
502   { sizeof(u32), cf_parse_ip },
503   { sizeof(byte*), cf_parse_string }
504 };
505
506 static byte *
507 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
508 {
509   for (uns i=0; i<number; i++)
510   {
511     byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
512     if (msg)
513       return cf_printf("Cannot parse item %d: %s", i+1, msg);
514   }
515   return NULL;
516 }
517
518 /* Interpreter */
519
520 #define T(x) #x,
521 static byte *op_names[] = { CF_OPERATIONS };
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   void *ptr = stack[level].base_ptr;
837   struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
838   if (msg)
839     return msg;
840   if (stack[level].op & OP_1ST)
841     TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
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 byte *
868 cf_write_item(struct cf_item *item, enum operation op, int number, byte **pars)
869 {
870   byte *msg;
871   int taken;
872   switch (op) {
873     case OP_SET:
874       msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
875       break;
876     case OP_CLEAR:
877       taken = 0;
878       msg = interpret_clear(item, item->ptr);
879       break;
880     case OP_APPEND:
881     case OP_PREPEND:
882       if (item->cls == CC_DYNAMIC)
883         msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
884       else if (item->cls == CC_LIST)
885         msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
886       else
887         return "The attribute class does not support append/prepend";
888       break;
889     default:
890       return "Unsupported operation";
891   }
892   if (msg)
893     return msg;
894   if (taken < number)
895     return "Too many parameters";
896   return NULL;
897 }
898
899 static void
900 init_stack(void)
901 {
902   global_init();
903   level = 0;
904   stack[0] = (struct item_stack) {
905     .sec = &sections,
906     .base_ptr = NULL,
907     .op = OP_CLOSE,
908     .list = NULL,
909     .mask = 0,
910     .item = NULL
911   };
912 }
913
914 static int
915 done_stack(void)
916 {
917   if (level > 0) {
918     log(L_ERROR, "Unterminated block");
919     return 1;
920   }
921   return 0;
922 }
923
924 /* Text file parser */
925
926 static struct fastbuf *parse_fb;
927 static uns line_num;
928
929 #define MAX_LINE        4096
930 static byte line_buf[MAX_LINE];
931 static byte *line = line_buf;
932
933 #include "lib/bbuf.h"
934 static bb_t copy_buf;
935 static uns copied;
936
937 #define GBUF_TYPE       uns
938 #define GBUF_PREFIX(x)  split_##x
939 #include "lib/gbuf.h"
940 static split_t word_buf;
941 static uns words;
942 static uns ends_by_brace;               // the line is ended by "{"
943
944 static int
945 get_line(void)
946 {
947   if (!bgets(parse_fb, line_buf, MAX_LINE))
948     return 0;
949   line_num++;
950   line = line_buf;
951   while (Cblank(*line))
952     line++;
953   return 1;
954 }
955
956 static void
957 append(byte *start, byte *end)
958 {
959   uns len = end - start;
960   bb_grow(&copy_buf, copied + len + 1);
961   memcpy(copy_buf.ptr + copied, start, len);
962   copied += len + 1;
963   copy_buf.ptr[copied-1] = 0;
964 }
965
966 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
967   // these characters separate words like blanks
968
969 static byte *
970 get_word(uns stop_at_equal)
971 {
972   // promised that *line is non-null and non-blank
973   if (*line == '\'') {
974     line++;
975     while (1) {
976       byte *start = line;
977       while (*line && *line != '\'')
978         line++;
979       append(start, line);
980       if (*line)
981         break;
982       copy_buf.ptr[copied-1] = '\n';
983       if (!get_line())
984         return "Unterminated apostrophe word at the end";
985     }
986     line++;
987   } else if (*line == '"') {
988     line++;
989     while (1) {
990       byte *start = line;
991       uns escape = 0;
992       while (*line) {
993         if (*line == '"' && !escape)
994           break;
995         else if (*line == '\\')
996           escape ^= 1;
997         else
998           escape = 0;
999         line++;
1000       }
1001       append(start, line);
1002       if (*line)
1003         break;
1004       if (!escape)
1005         copy_buf.ptr[copied-1] = '\n';
1006       else // merge two lines
1007         copied -= 2;
1008       if (!get_line())
1009         return "Unterminated quoted word at the end";
1010     }
1011     line++;
1012   } else {
1013     byte *start = line;
1014     while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
1015         && (*line != '=' || !stop_at_equal))
1016       line++;
1017     if (*line == '=') {                         // nice for setting from a command-line
1018       if (line == start)
1019         return "Assignment without a variable";
1020       *line = ' ';
1021     }
1022     if (CONTROL_CHAR(*line))                    // already the first char is control
1023       line++;
1024     append(start, line);
1025   }
1026   while (Cblank(*line))
1027     line++;
1028   return NULL;
1029 }
1030
1031 static byte *
1032 split_line(void)
1033 {
1034   words = 0;
1035   copied = 0;
1036   ends_by_brace = 0;
1037   while (!*line || *line == '#')
1038   {
1039     if (!get_line())
1040       return NULL;
1041     while (*line == ';'                         // empty trash at the beginning
1042         || (*line == '\\' && !line[1])) {
1043       TRY( get_word(0) );
1044       copied = 0;
1045     }
1046     if (*line == '{')                           // only one opening brace
1047       return "Unexpected opening brace";
1048   }
1049   /* We have got a non-null, non-blank, non-;, non-merge, and non-{ character.  */
1050   while (1)
1051   {
1052     split_grow(&word_buf, words+1);
1053     word_buf.ptr[words++] = copied;
1054     TRY( get_word(!words) );
1055     if (!*line)
1056       break;
1057     else if (*line == '}' || *line == ';')      // end of line now and preserve the char
1058       break;
1059     else if (*line == '{') {                    // discard the char and end the line
1060 discard_brace:
1061       ends_by_brace = 1;
1062       TRY( get_word(0) );
1063       break;
1064     } else if (*line == '\\' && !line[1]) {     // merge two lines
1065       if (!get_line())
1066         return "Last line ends by a backslash";
1067       if (!*line || *line == '#') {
1068         log(L_WARN, "The line following the backslash is empty");
1069         break;
1070       } else if (*line == '{')
1071         goto discard_brace;
1072     }
1073   }
1074   return NULL;
1075 }
1076
1077 /* Parsing multiple files */
1078
1079 static byte *
1080 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1081 {
1082   byte *msg;
1083   parse_fb = fb;
1084   line_num = 0;
1085   line = line_buf;
1086   *line = 0;
1087   while (1)
1088   {
1089     msg = split_line();
1090     if (msg)
1091       goto error;
1092     if (!words)
1093       return NULL;
1094     byte *name = copy_buf.ptr + word_buf.ptr[0];
1095     byte *pars[words-1];
1096     for (uns i=1; i<words; i++)
1097       pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1098     if (!strcasecmp(name, "#include"))
1099     {
1100       if (words != 2) {
1101         msg = "Expecting one filename";
1102         goto error;
1103       }
1104       if (depth > 8) {
1105         msg = "Too many nested files";
1106         goto error;
1107       }
1108       parse_fb = bopen(pars[0], O_RDONLY, 1<<14);
1109       uns ll = line_num;
1110       msg = parse_fastbuf(pars[0], parse_fb, depth+1);
1111       bclose(parse_fb);
1112       if (msg)
1113         goto error;
1114       line_num = ll;
1115       parse_fb = fb;
1116     }
1117     enum operation op;
1118     byte *c = strchr(name, ':');
1119     if (!c)
1120       op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1121     else {
1122       *c++ = 0;
1123       switch (Clocase(*c)) {
1124         case 's': op = OP_SET; break;
1125         case 'c': op = OP_CLEAR; break;
1126         case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1127         case 'p': op = OP_PREPEND; break;
1128         case 'r': op = OP_REMOVE; break;
1129         case 'e': op = OP_EDIT; break;
1130         case 'b': op = OP_BEFORE; break;
1131         default: op = OP_SET; break;
1132       }
1133       if (strcasecmp(c, op_names[op])) {
1134         msg = cf_printf("Unknown operation %s", c);
1135         goto error;
1136       }
1137     }
1138     if (ends_by_brace)
1139       op |= OP_OPEN;
1140     msg = interpret_line(name, op, words-1, pars);
1141     if (msg)
1142       goto error;
1143   }
1144 error:
1145   log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1146   return "included from here";
1147 }
1148
1149 #ifndef DEFAULT_CONFIG
1150 #define DEFAULT_CONFIG NULL
1151 #endif
1152 byte *cf_def_file = DEFAULT_CONFIG;
1153
1154 static int
1155 load_file(byte *file)
1156 {
1157   cf_def_file = NULL;
1158   init_stack();
1159   struct fastbuf *fb = bopen(file, O_RDONLY, 1<<14);
1160   byte *msg = parse_fastbuf(file, fb, 0);
1161   bclose(fb);
1162   return !!msg || done_stack();
1163 }
1164
1165 static int
1166 load_string(byte *string)
1167 {
1168   init_stack();
1169   struct fastbuf fb;
1170   fbbuf_init_read(&fb, string, strlen(string), 0);
1171   byte *msg = parse_fastbuf("memory string", &fb, 0);
1172   return !!msg || done_stack();
1173 }
1174
1175 /* Command-line parser */
1176
1177 static void
1178 load_default(void)
1179 {
1180   if (cf_def_file)
1181     if (cf_load(cf_def_file))
1182       die("Cannot load default config %s", optarg);
1183 }
1184
1185 int
1186 cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
1187 {
1188   static int other_options = 0;
1189   while (1) {
1190     int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
1191     if (res == 'S' || res == 'C')
1192     {
1193       if (other_options)
1194         die("The -S and -C options must precede all other arguments");
1195       if (res == 'S') {
1196         load_default();
1197         if (cf_set(optarg))
1198           die("Cannot set %s", optarg);
1199       } else {
1200         if (cf_load(optarg))
1201           die("Cannot load %s", optarg);
1202       }
1203     } else {
1204       /* unhandled option or end of options */
1205       load_default();
1206       other_options++;
1207       return res;
1208     }
1209   }
1210 }