]> mj.ucw.cz Git - libucw.git/blob - ucw/conf-intr.c
Mainloop: Avoid polling for an empty set of events
[libucw.git] / ucw / conf-intr.c
1 /*
2  *      UCW Library -- Configuration files: interpreter
3  *
4  *      (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5  *      (c) 2003--2014 Martin Mares <mj@ucw.cz>
6  *      (c) 2014 Pavel Charvat <pchar@ucw.cz>
7  *
8  *      This software may be freely distributed and used according to the terms
9  *      of the GNU Lesser General Public License.
10  */
11
12 #include <ucw/lib.h>
13 #include <ucw/conf.h>
14 #include <ucw/getopt.h>
15 #include <ucw/conf-internal.h>
16 #include <ucw/clists.h>
17 #include <ucw/gary.h>
18 #include <ucw/mempool.h>
19 #include <ucw/xtypes.h>
20
21 #include <string.h>
22 #include <stdio.h>
23
24 #define TRY(f)  do { char *_msg = f; if (_msg) return _msg; } while (0)
25
26 /* Register size of and parser for each basic type */
27
28 static char *
29 cf_parse_string(char *str, char **ptr)
30 {
31   *ptr = cf_strdup(str);
32   return NULL;
33 }
34
35 typedef char *cf_basic_parser(char *str, void *ptr);
36 static struct {
37   uint size;
38   void *parser;
39 } parsers[] = {
40   { sizeof(int), cf_parse_int },
41   { sizeof(u64), cf_parse_u64 },
42   { sizeof(double), cf_parse_double },
43   { sizeof(u32), cf_parse_ip },
44   { sizeof(char*), cf_parse_string },
45   { sizeof(int), NULL },                        // lookups are parsed extra
46   { 0, NULL },                                  // user-defined types are parsed extra
47 };
48
49 inline uint
50 cf_type_size(enum cf_type type, const union cf_union *u)
51 {
52   switch (type)
53     {
54       case CT_USER:
55         return u->utype->size;
56       case CT_XTYPE:
57         return u->xtype->size;
58       default:
59         ASSERT(type < ARRAY_SIZE(parsers) - 1);
60         return parsers[type].size;
61     }
62 }
63
64 static char *
65 cf_parse_lookup(char *str, int *ptr, const char * const *t)
66 {
67   const char * const *n = t;
68   uint total_len = 0;
69   while (*n && strcasecmp(*n, str)) {
70     total_len += strlen(*n) + 2;
71     n++;
72   }
73   if (*n) {
74     *ptr = n - t;
75     return NULL;
76   }
77   char *err = cf_malloc(total_len + strlen(str) + 60), *c = err;
78   c += sprintf(err, "Invalid value %s, possible values are: ", str);
79   for (n=t; *n; n++)
80     c+= sprintf(c, "%s, ", *n);
81   if (*t)
82     c[-2] = 0;
83   *ptr = -1;
84   return err;
85 }
86
87 static char *
88 cf_parse_ary(uint number, char **pars, void *ptr, enum cf_type type, union cf_union *u)
89 {
90   for (uint i=0; i<number; i++)
91   {
92     char *msg;
93     uint size = cf_type_size(type, u);
94     if (type < CT_LOOKUP)
95       msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
96     else if (type == CT_LOOKUP)
97       msg = cf_parse_lookup(pars[i], ptr + i * size, u->lookup);
98     else if (type == CT_USER)
99       msg = u->utype->parser(pars[i], ptr + i * size);
100     else if (type == CT_XTYPE)
101       msg = (char *)u->xtype->parse(pars[i], ptr + i * size, cf_get_pool());
102     else
103       ASSERT(0);
104     if (msg)
105       return number > 1 ? cf_printf("Item %d: %s", i+1, msg) : msg;
106   }
107   return NULL;
108 }
109
110 /* Interpreter */
111
112 #define T(x) #x,
113 char *cf_op_names[] = { CF_OPERATIONS };
114 #undef T
115 char *cf_type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user", "xtype" };
116
117 static char *
118 interpret_set_dynamic(struct cf_item *item, int number, char **pars, void **ptr)
119 {
120   enum cf_type type = item->type;
121   uint size = cf_type_size(type, &item->u);
122   cf_journal_block(ptr, sizeof(void*));
123   // boundary checks done by the caller
124   *ptr = gary_init(size, number, mp_get_allocator(cf_get_pool()));
125   return cf_parse_ary(number, pars, *ptr, type, &item->u);
126 }
127
128 static char *
129 interpret_add_dynamic(struct cf_item *item, int number, char **pars, int *processed, void **ptr, enum cf_operation op)
130 {
131   enum cf_type type = item->type;
132   void *old_p = *ptr;
133   uint size = cf_type_size(item->type, &item->u);
134   ASSERT(size >= sizeof(uint));
135   int old_nr = old_p ? GARY_SIZE(old_p) : 0;
136   int taken = MIN(number, ABS(item->number)-old_nr);
137   *processed = taken;
138   // stretch the dynamic array
139   void *new_p = gary_init(size, old_nr + taken, mp_get_allocator(cf_get_pool()));
140   cf_journal_block(ptr, sizeof(void*));
141   *ptr = new_p;
142   if (op == OP_APPEND) {
143     memcpy(new_p, old_p, old_nr * size);
144     return cf_parse_ary(taken, pars, new_p + old_nr * size, type, &item->u);
145   } else if (op == OP_PREPEND) {
146     memcpy(new_p + taken * size, old_p, old_nr * size);
147     return cf_parse_ary(taken, pars, new_p, type, &item->u);
148   } else
149     return cf_printf("Dynamic arrays do not support operation %s", cf_op_names[op]);
150 }
151
152 static char *interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uint allow_dynamic);
153
154 static char *
155 interpret_section(struct cf_section *sec, int number, char **pars, int *processed, void *ptr, uint allow_dynamic)
156 {
157   cf_add_dirty(sec, ptr);
158   *processed = 0;
159   for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
160   {
161     int taken;
162     char *msg = interpret_set_item(ci, number, pars, &taken, ptr + (uintptr_t) ci->ptr, allow_dynamic && !ci[1].cls);
163     if (msg)
164       return cf_printf("Item %s: %s", ci->name, msg);
165     *processed += taken;
166     number -= taken;
167     pars += taken;
168     if (!number)                // stop parsing, because many parsers would otherwise complain that number==0
169       break;
170   }
171   return NULL;
172 }
173
174 static void
175 add_to_list(cnode *where, cnode *new_node, enum cf_operation op)
176 {
177   switch (op)
178   {
179     case OP_EDIT:               // editation has been done in-place
180       break;
181     case OP_REMOVE:
182       CF_JOURNAL_VAR(where->prev->next);
183       CF_JOURNAL_VAR(where->next->prev);
184       clist_remove(where);
185       break;
186     case OP_AFTER:              // implementation dependent (prepend_head = after(list)), and where==list, see clists.h:74
187     case OP_PREPEND:
188     case OP_COPY:
189       CF_JOURNAL_VAR(where->next->prev);
190       CF_JOURNAL_VAR(where->next);
191       clist_insert_after(new_node, where);
192       break;
193     case OP_BEFORE:             // implementation dependent (append_tail = before(list))
194     case OP_APPEND:
195     case OP_SET:
196       CF_JOURNAL_VAR(where->prev->next);
197       CF_JOURNAL_VAR(where->prev);
198       clist_insert_before(new_node, where);
199       break;
200     default:
201       ASSERT(0);
202   }
203 }
204
205 static char *
206 interpret_add_list(struct cf_item *item, int number, char **pars, int *processed, void *ptr, enum cf_operation op)
207 {
208   if (op >= OP_REMOVE)
209     return cf_printf("You have to open a block for operation %s", cf_op_names[op]);
210   if (!number)
211     return "Nothing to add to the list";
212   struct cf_section *sec = item->u.sec;
213   *processed = 0;
214   uint index = 0;
215   while (number > 0)
216   {
217     void *node = cf_malloc(sec->size);
218     cf_init_section(item->name, sec, node, 1);
219     add_to_list(ptr, node, op);
220     int taken;
221     /* If the node contains any dynamic attribute at the end, we suppress
222      * auto-repetition here and pass the flag inside instead.  */
223     index++;
224     char *msg = interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC);
225     if (msg)
226       return sec->flags & SEC_FLAG_DYNAMIC ? msg : cf_printf("Node %d of list %s: %s", index, item->name, msg);
227     *processed += taken;
228     number -= taken;
229     pars += taken;
230     if (sec->flags & SEC_FLAG_DYNAMIC)
231       break;
232   }
233   return NULL;
234 }
235
236 static char *
237 interpret_add_bitmap(struct cf_item *item, int number, char **pars, int *processed, u32 *ptr, enum cf_operation op)
238 {
239   if (op == OP_PREPEND || op == OP_APPEND)
240     op = OP_SET;
241   if (op != OP_SET && op != OP_REMOVE)
242     return cf_printf("Cannot apply operation %s on a bitmap", cf_op_names[op]);
243   else if (item->type != CT_INT && item->type != CT_LOOKUP)
244     return cf_printf("Type %s cannot be used with bitmaps", cf_type_names[item->type]);
245   cf_journal_block(ptr, sizeof(u32));
246   for (int i=0; i<number; i++) {
247     uint idx;
248     if (item->type == CT_INT)
249       TRY( cf_parse_int(pars[i], &idx) );
250     else
251       TRY( cf_parse_lookup(pars[i], &idx, item->u.lookup) );
252     if (idx >= 32)
253       return "Bitmaps only have 32 bits";
254     if (op == OP_SET)
255       *ptr |= 1<<idx;
256     else
257       *ptr &= ~(1<<idx);
258   }
259   *processed = number;
260   return NULL;
261 }
262
263 static char *
264 interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uint allow_dynamic)
265 {
266   int taken;
267   switch (item->cls)
268   {
269     case CC_STATIC:
270       if (!number)
271         return "Missing value";
272       taken = MIN(number, item->number);
273       *processed = taken;
274       uint size = cf_type_size(item->type, &item->u);
275       cf_journal_block(ptr, taken * size);
276       return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
277     case CC_DYNAMIC:
278       if (!allow_dynamic)
279         return "Dynamic array cannot be used here";
280       taken = MIN(number, ABS(item->number));
281       *processed = taken;
282       return interpret_set_dynamic(item, taken, pars, ptr);
283     case CC_PARSER:
284       if (item->number < 0 && !allow_dynamic)
285         return "Parsers with variable number of parameters cannot be used here";
286       if (item->number > 0 && number < item->number)
287         return "Not enough parameters available for the parser";
288       taken = MIN(number, ABS(item->number));
289       *processed = taken;
290       for (int i=0; i<taken; i++)
291         pars[i] = cf_strdup(pars[i]);
292       return item->u.par(taken, pars, ptr);
293     case CC_SECTION:
294       return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
295     case CC_LIST:
296       if (!allow_dynamic)
297         return "Lists cannot be used here";
298       return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
299     case CC_BITMAP:
300       if (!allow_dynamic)
301         return "Bitmaps cannot be used here";
302       return interpret_add_bitmap(item, number, pars, processed, ptr, OP_SET);
303     default:
304       ASSERT(0);
305   }
306 }
307
308 static char *
309 interpret_set_all(struct cf_item *item, void *ptr, enum cf_operation op)
310 {
311   if (item->cls == CC_BITMAP) {
312     cf_journal_block(ptr, sizeof(u32));
313     if (op == OP_CLEAR)
314       * (u32*) ptr = 0;
315     else
316       if (item->type == CT_INT)
317         * (u32*) ptr = ~0u;
318       else {
319         uint nr = -1;
320         while (item->u.lookup[++nr]);
321         * (u32*) ptr = ~0u >> (32-nr);
322       }
323     return NULL;
324   } else if (op != OP_CLEAR)
325     return "The item is not a bitmap";
326
327   if (item->cls == CC_LIST) {
328     cf_journal_block(ptr, sizeof(clist));
329     clist_init(ptr);
330   } else if (item->cls == CC_DYNAMIC) {
331     cf_journal_block(ptr, sizeof(void *));
332     * (void**) ptr = GARY_FOREVER_EMPTY;
333   } else if (item->cls == CC_STATIC && item->type == CT_STRING) {
334     cf_journal_block(ptr, item->number * sizeof(char*));
335     bzero(ptr, item->number * sizeof(char*));
336   } else
337     return "The item is not a list, dynamic array, bitmap, or string";
338   return NULL;
339 }
340
341 static int
342 cmp_items(void *i1, void *i2, struct cf_item *item)
343 {
344   ASSERT(item->cls == CC_STATIC);
345   i1 += (uintptr_t) item->ptr;
346   i2 += (uintptr_t) item->ptr;
347   if (item->type == CT_STRING)
348     return strcmp(* (char**) i1, * (char**) i2);
349   else                          // all numeric types
350     return memcmp(i1, i2, cf_type_size(item->type, &item->u));
351 }
352
353 static void *
354 find_list_node(clist *list, void *query, struct cf_section *sec, u32 mask)
355 {
356   CLIST_FOR_EACH(cnode *, n, *list)
357   {
358     uint found = 1;
359     for (uint i=0; i<32; i++)
360       if (mask & (1<<i))
361         if (cmp_items(n, query, sec->cfg+i))
362         {
363           found = 0;
364           break;
365         }
366     if (found)
367       return n;
368   }
369   return NULL;
370 }
371
372 static char *
373 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
374 {
375   uint nr = sec->flags & SEC_FLAG_NUMBER;
376   if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
377   {
378     uint i = item - sec->cfg;
379     if (i >= 32)
380       return "Cannot select list nodes by this attribute";
381     if (sec->cfg[i].cls != CC_STATIC)
382       return "Selection can only be done based on basic attributes";
383     *mask |= 1 << i;
384   }
385   return NULL;
386 }
387
388 static char *
389 opening_brace(struct cf_context *cc, struct cf_item *item, void *ptr, enum cf_operation op)
390 {
391   if (cc->stack_level >= MAX_STACK_SIZE-1)
392     return "Too many nested sections";
393   enum cf_operation pure_op = op & OP_MASK;
394   cc->stack[++cc->stack_level] = (struct item_stack) {
395     .sec = NULL,
396     .base_ptr = NULL,
397     .op = pure_op,
398     .list = NULL,
399     .mask = 0,
400     .item = NULL,
401   };
402   if (!item)                    // unknown is ignored; we just need to trace recursion
403     return NULL;
404   cc->stack[cc->stack_level].sec = item->u.sec;
405   if (item->cls == CC_SECTION)
406   {
407     if (pure_op != OP_SET)
408       return "Only SET operation can be used with a section";
409     cc->stack[cc->stack_level].base_ptr = ptr;
410     cc->stack[cc->stack_level].op = OP_EDIT | OP_2ND;   // this list operation does nothing
411   }
412   else if (item->cls == CC_LIST)
413   {
414     cc->stack[cc->stack_level].base_ptr = cf_malloc(item->u.sec->size);
415     cf_init_section(item->name, item->u.sec, cc->stack[cc->stack_level].base_ptr, 1);
416     cc->stack[cc->stack_level].list = ptr;
417     cc->stack[cc->stack_level].item = item;
418     if (pure_op == OP_ALL)
419       return "Operation ALL cannot be applied on lists";
420     else if (pure_op < OP_REMOVE) {
421       add_to_list(ptr, cc->stack[cc->stack_level].base_ptr, pure_op);
422       cc->stack[cc->stack_level].op |= OP_2ND;
423     } else
424       cc->stack[cc->stack_level].op |= OP_1ST;
425   }
426   else
427     return "Opening brace can only be used on sections and lists";
428   return NULL;
429 }
430
431 static char *
432 closing_brace(struct cf_context *cc, struct item_stack *st, enum cf_operation op, int number, char **pars)
433 {
434   if (st->op == OP_CLOSE)       // top-level
435     return "Unmatched } parenthesis";
436   if (!st->sec) {               // dummy run on unknown section
437     if (!(op & OP_OPEN))
438       cc->stack_level--;
439     return NULL;
440   }
441   enum cf_operation pure_op = st->op & OP_MASK;
442   if (st->op & OP_1ST)
443   {
444     st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
445     if (!st->list)
446       return "Cannot find a node matching the query";
447     if (pure_op != OP_REMOVE)
448     {
449       if (pure_op == OP_EDIT)
450         st->base_ptr = st->list;
451       else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
452         cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
453       else if (pure_op == OP_COPY) {
454         if (st->sec->flags & SEC_FLAG_CANT_COPY)
455           return cf_printf("Item %s cannot be copied", st->item->name);
456         memcpy(st->base_ptr, st->list, st->sec->size);  // strings and dynamic arrays are shared
457         if (st->sec->copy)
458           TRY( st->sec->copy(st->base_ptr, st->list) );
459       } else
460         ASSERT(0);
461       if (op & OP_OPEN) {       // stay at the same recursion level
462         st->op = (st->op | OP_2ND) & ~OP_1ST;
463         add_to_list(st->list, st->base_ptr, pure_op);
464         return NULL;
465       }
466       int taken;                // parse parameters on 1 line immediately
467       TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
468       number -= taken;
469       pars += taken;
470       // and fall-thru to the 2nd phase
471     }
472     add_to_list(st->list, st->base_ptr, pure_op);
473   }
474   cc->stack_level--;
475   if (number)
476     return "No parameters expected after the }";
477   else if (op & OP_OPEN)
478     return "No { is expected";
479   else
480     return NULL;
481 }
482
483 static struct cf_item *
484 find_item(struct cf_section *curr_sec, const char *name, char **msg, void **ptr)
485 {
486   struct cf_context *cc = cf_get_context();
487   *msg = NULL;
488   if (name[0] == '^')                           // absolute name instead of relative
489     name++, curr_sec = &cc->sections, *ptr = NULL;
490   if (!curr_sec)                                // don't even search in an unknown section
491     return NULL;
492   while (1)
493   {
494     if (curr_sec != &cc->sections)
495       cf_add_dirty(curr_sec, *ptr);
496     char *c = strchr(name, '.');
497     if (c)
498       *c++ = 0;
499     struct cf_item *ci = cf_find_subitem(curr_sec, name);
500     if (!ci->cls)
501     {
502       if (!(curr_sec->flags & SEC_FLAG_UNKNOWN))        // ignore silently unknown top-level sections and unknown attributes in flagged sections
503         *msg = cf_printf("Unknown item %s", name);
504       return NULL;
505     }
506     *ptr += (uintptr_t) ci->ptr;
507     if (!c)
508       return ci;
509     if (ci->cls != CC_SECTION)
510     {
511       *msg = cf_printf("Item %s is not a section", name);
512       return NULL;
513     }
514     curr_sec = ci->u.sec;
515     name = c;
516   }
517 }
518
519 static char *
520 interpret_add(char *name, struct cf_item *item, int number, char **pars, int *takenp, void *ptr, enum cf_operation op)
521 {
522   switch (item->cls) {
523     case CC_DYNAMIC:
524       return interpret_add_dynamic(item, number, pars, takenp, ptr, op);
525     case CC_LIST:
526       return interpret_add_list(item, number, pars, takenp, ptr, op);
527     case CC_BITMAP:
528       return interpret_add_bitmap(item, number, pars, takenp, ptr, op);
529     default:
530       return cf_printf("Operation %s not supported on attribute %s", cf_op_names[op], name);
531   }
532 }
533
534 char *
535 cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars)
536 {
537   char *msg;
538   if ((op & OP_MASK) == OP_CLOSE)
539     return closing_brace(cc, cc->stack+cc->stack_level, op, number, pars);
540   void *ptr = cc->stack[cc->stack_level].base_ptr;
541   struct cf_item *item = find_item(cc->stack[cc->stack_level].sec, name, &msg, &ptr);
542   if (msg)
543     return msg;
544   if (cc->stack[cc->stack_level].op & OP_1ST)
545     TRY( record_selector(item, cc->stack[cc->stack_level].sec, &cc->stack[cc->stack_level].mask) );
546   if (op & OP_OPEN) {           // the operation will be performed after the closing brace
547     if (number)
548       return "Cannot open a block after a parameter has been passed on a line";
549     return opening_brace(cc, item, ptr, op);
550   }
551   if (!item)                    // ignored item in an unknown section
552     return NULL;
553   op &= OP_MASK;
554
555   int taken = 0;                // process as many parameters as possible
556   switch (op) {
557     case OP_CLEAR:
558     case OP_ALL:
559       msg = interpret_set_all(item, ptr, op);
560       break;
561     case OP_SET:
562       msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
563       break;
564     case OP_RESET:
565       msg = interpret_set_all(item, ptr, OP_CLEAR);
566       if (!msg)
567         msg = interpret_add(name, item, number, pars, &taken, ptr, OP_APPEND);
568       break;
569     default:
570       msg = interpret_add(name, item, number, pars, &taken, ptr, op);
571   }
572   if (msg)
573     return msg;
574   if (taken < number)
575     return cf_printf("Too many parameters: %d>%d", number, taken);
576
577   return NULL;
578 }
579
580 char *
581 cf_find_item(const char *name, struct cf_item *item)
582 {
583   struct cf_context *cc = cf_get_context();
584   char *msg;
585   void *ptr = NULL;
586   struct cf_item *ci = find_item(&cc->sections, name, &msg, &ptr);
587   if (msg)
588     return msg;
589   if (ci) {
590     *item = *ci;
591     item->ptr = ptr;
592   } else
593     bzero(item, sizeof(struct cf_item));
594   return NULL;
595 }
596
597 char *
598 cf_modify_item(struct cf_item *item, enum cf_operation op, int number, char **pars)
599 {
600   char *msg;
601   int taken = 0;
602   switch (op) {
603     case OP_SET:
604       msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
605       break;
606     case OP_CLEAR:
607     case OP_ALL:
608       msg = interpret_set_all(item, item->ptr, op);
609       break;
610     case OP_APPEND:
611     case OP_PREPEND:
612       switch (item->cls) {
613         case CC_DYNAMIC:
614           msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
615           break;
616         case CC_LIST:
617           msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
618           break;
619         case CC_BITMAP:
620           msg = interpret_add_bitmap(item, number, pars, &taken, item->ptr, op);
621           break;
622         default:
623           return "The attribute does not support append/prepend";
624       }
625       break;
626     case OP_REMOVE:
627       if (item->cls == CC_BITMAP)
628         msg = interpret_add_bitmap(item, number, pars, &taken, item->ptr, op);
629       else
630         return "Only applicable on bitmaps";
631       break;
632     default:
633       return "Unsupported operation";
634   }
635   if (msg)
636     return msg;
637   if (taken < number)
638     return "Too many parameters";
639   return NULL;
640 }
641
642 void
643 cf_init_stack(struct cf_context *cc)
644 {
645   if (!cc->sections_initialized++) {
646     cc->sections.flags |= SEC_FLAG_UNKNOWN;
647     cc->sections.size = 0;                      // size of allocated array used to be stored here
648     cf_init_section(NULL, &cc->sections, NULL, 0);
649   }
650   cc->stack_level = 0;
651   cc->stack[0] = (struct item_stack) {
652     .sec = &cc->sections,
653     .base_ptr = NULL,
654     .op = OP_CLOSE,
655     .list = NULL,
656     .mask = 0,
657     .item = NULL
658   };
659 }
660
661 int
662 cf_done_stack(struct cf_context *cc)
663 {
664   return (cc->stack_level > 0);
665 }