2 * UCW Library -- Reading of configuration files
4 * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2006 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
12 #include "lib/conf2.h"
13 #include "lib/mempool.h"
14 #include "lib/clists.h"
20 /* Memory allocation */
22 struct mempool *cf_pool; // current pool for loading new configuration
23 static struct old_pools {
24 struct old_pools *prev;
26 } *pools; // link-list of older cf_pool's
31 return mp_alloc(cf_pool, size);
35 cf_malloc_zero(uns size)
37 return mp_alloc_zero(cf_pool, size);
43 return mp_strdup(cf_pool, s);
47 cf_printf(char *fmt, ...)
51 byte *res = mp_vprintf(cf_pool, fmt, args);
58 uns cf_need_journal; // some programs do not need journal
59 static struct journal_item {
60 struct journal_item *prev;
67 cf_journal_block(void *ptr, uns len)
71 struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
75 memcpy(ji->copy, ptr, len);
81 // swaps the contents of the memory and the journal, and reverses the list
83 struct journal_item *curr, *prev, *next;
84 for (next=NULL, curr=journal; curr; next=curr, curr=prev)
88 for (uns i=0; i<curr->len; i++)
90 byte x = curr->copy[i];
91 curr->copy[i] = curr->ptr[i];
98 static struct journal_item *
99 journal_new_section(uns new_pool)
102 cf_pool = mp_new(1<<14);
103 struct journal_item *oldj = journal;
109 journal_commit_section(uns new_pool, struct journal_item *oldj)
113 struct old_pools *p = cf_malloc(sizeof(struct old_pools));
120 struct journal_item **j = &journal;
128 journal_rollback_section(uns new_pool, struct journal_item *oldj, byte *msg)
130 if (!cf_need_journal)
131 die("Cannot rollback the configuration, because the journal is disabled. Error: %s", msg);
137 cf_pool = pools ? pools->pool : NULL;
143 #define SEC_FLAG_DYNAMIC 0x80000000 // contains a dynamic attribute
144 #define SEC_FLAG_NUMBER 0x7fffffff // number of entries
146 static struct cf_section sections; // root section
148 static struct cf_item *
149 find_subitem(struct cf_section *sec, byte *name)
151 struct cf_item *ci = sec->cfg;
152 for (; ci->cls; ci++)
153 if (!strcasecmp(ci->name, name))
159 inspect_section(struct cf_section *sec)
163 for (ci=sec->cfg; ci->cls; ci++)
164 if (ci->cls == CC_SECTION) {
165 inspect_section(ci->u.sec);
166 sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
167 } else if (ci->cls == CC_LIST) {
168 inspect_section(ci->u.sec);
169 sec->flags |= SEC_FLAG_DYNAMIC;
170 } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
171 sec->flags |= SEC_FLAG_DYNAMIC;
172 sec->flags |= ci - sec->cfg; // record the number of entries
176 cf_declare_section(byte *name, struct cf_section *sec)
181 sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
183 struct cf_item *ci = find_subitem(§ions, name);
185 die("Cannot register section %s twice", name);
186 ci->cls = CC_SECTION;
191 inspect_section(sec);
193 if (ci - sections.cfg >= (int) sections.size)
195 sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
196 bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
202 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
205 bzero(ptr, sec->size);
206 for (uns i=0; sec->cfg[i].cls; i++)
207 if (sec->cfg[i].cls == CC_SECTION)
208 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
209 else if (sec->cfg[i].cls == CC_LIST)
210 clist_init(sec->cfg[i].ptr);
211 byte *msg = sec->init(ptr);
213 die("Cannot initialize section %s: %s", name, msg);
219 for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
220 cf_init_section(ci->name, ci->u.sec, NULL);
223 static struct cf_item *
224 find_item(struct cf_section *curr_sec, byte *name, byte **msg)
227 if (name[0] == '^') // absolute name instead of relative
228 name++, curr_sec = §ions;
229 if (!curr_sec) // don't even search in an unknown section
233 byte *c = strchr(name, '.');
236 struct cf_item *ci = find_subitem(curr_sec, name);
239 if (curr_sec != §ions) // ignore silently unknown top-level sections
240 *msg = cf_printf("Unknown item %s", name);
245 if (ci->cls != CC_SECTION)
247 *msg = cf_printf("Item %s is not a section", name);
250 curr_sec = ci->u.sec;
255 /* Safe loading and reloading */
257 byte *cf_def_file = DEFAULT_CONFIG;
259 #ifndef DEFAULT_CONFIG
260 #define DEFAULT_CONFIG NULL
263 byte *cfdeffile = DEFAULT_CONFIG;
265 static byte *load_file(byte *file);
266 static byte *load_string(byte *string);
269 cf_reload(byte *file)
272 struct journal_item *oldj = journal_new_section(1);
273 byte *msg = load_file(file);
276 for (struct old_pools *p=pools; p; p=pools)
281 journal_commit_section(1, NULL);
285 journal_rollback_section(1, oldj, msg);
294 struct journal_item *oldj = journal_new_section(1);
295 byte *msg = load_file(file);
297 journal_commit_section(1, oldj);
299 journal_rollback_section(1, oldj, msg);
306 struct journal_item *oldj = journal_new_section(0);
307 byte *msg = load_string(string);
309 journal_commit_section(0, oldj);
311 journal_rollback_section(0, oldj, msg);
315 /* Parsers for standard types */
318 uns name; // one-letter name of the unit
319 uns num, den; // fraction
322 static const struct unit units[] = {
327 { 'g', 1000000000, 1 },
330 { 'G', 1073741824, 1 },
335 static const struct unit *
336 lookup_unit(byte *value, byte *end, byte **msg)
339 if (end == value || end[1] || *end >= '0' && *end <= '9')
340 *msg = "Invalid number";
342 for (const struct unit *u=units; u->name; u++)
345 *msg = "Invalid unit";
351 static char cf_rngerr[] = "Number out of range";
354 cf_parse_int(byte *str, int *ptr)
358 msg = "Missing number";
360 const struct unit *u;
363 uns x = strtoul(str, &end, 0);
366 else if (u = lookup_unit(str, end, &msg)) {
367 u64 y = (u64)x * u->num;
369 msg = "Number is not an integer";
383 cf_parse_u64(byte *str, u64 *ptr)
387 msg = "Missing number";
389 const struct unit *u;
392 u64 x = strtoull(str, &end, 0);
395 else if (u = lookup_unit(str, end, &msg)) {
396 if (x > ~(u64)0 / u->num)
397 msg = "Number out of range";
401 msg = "Number is not an integer";
412 cf_parse_double(byte *str, double *ptr)
416 msg = "Missing number";
418 const struct unit *u;
421 double x = strtoul(str, &end, 0);
424 else if (u = lookup_unit(str, end, &msg))
425 *ptr = x * u->num / u->den;
433 cf_parse_string(byte *str, byte **ptr)
435 *ptr = cf_strdup(str);
439 /* Register size of and parser for each basic type */
441 typedef byte *cf_basic_parser(byte *str, void *ptr);
446 { sizeof(int), cf_parse_int },
447 { sizeof(u64), cf_parse_u64 },
448 { sizeof(double), cf_parse_double },
449 { sizeof(byte*), cf_parse_string }
453 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
455 for (uns i=0; i<number; i++)
457 byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
459 return cf_printf("Cannot parse item %d: %s", i+1, msg);
467 OP_CLOSE, // closing brace finishes previous block
469 OP_SET, // basic attribute (static, dynamic, parsed), section, list
470 OP_APPEND, // dynamic array, list
471 OP_PREPEND, // dynamic array, list
472 OP_REMOVE, // list operations with search follow:
477 #define OP_MASK 0xff // only get the operation
478 #define OP_OPEN 0x100 // here we only get an opening brace instead of parameters
479 #define OP_1ST 0x200 // in the 1st phase selectors are recorded into the mask
480 #define OP_2ND 0x400 // in the 2nd phase real data are entered
483 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
485 enum cf_type type = item->u.type;
486 cf_journal_block(ptr, sizeof(void*));
487 // boundary checks done by the caller
488 *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
489 * (uns*) (*ptr - parsers[type].size) = number;
490 return cf_parse_ary(number, pars, *ptr, type);
494 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum operation op)
496 enum cf_type type = item->u.type;
498 int old_nr = * (int*) (old_p - parsers[type].size);
499 int taken = MIN(number, item->number-old_nr);
501 // stretch the dynamic array
502 void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
503 * (uns*) (new_p - parsers[type].size) = old_nr + taken;
504 cf_journal_block(ptr, sizeof(void*));
508 memcpy(new_p, old_p, old_nr * parsers[type].size);
509 return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
511 else if (op == OP_PREPEND)
513 memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
514 return cf_parse_ary(taken, pars, new_p, type);
517 return cf_printf("Dynamic arrays do not support operation %d", op);
520 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
523 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
526 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
529 byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
531 return cf_printf("Item %s: %s", ci->name, msg);
535 if (!number) // stop parsing, because many parsers would otherwise complain that number==0
542 add_to_list(void *list, struct cnode *node, enum operation op)
544 cf_journal_block(list, sizeof(struct clist)); //FIXME: we should journal the nodes of the list instead
549 clist_add_tail(list, node);
552 clist_add_head(list, node);
557 case OP_EDIT: // edition has been done in-place
559 case OP_AFTER: // here the pointer list is actually a pointer to another node
560 clist_insert_after(node, list);
563 clist_insert_before(node, list);
571 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum operation op)
573 struct cf_section *sec = item->u.sec;
574 /* If the node contains any dynamic attribute at the end, we suppress
575 * auto-repetition here and pass it inside instead. We also suppress it when
576 * the operation works on a found node. */
577 uns only_1_node = (sec->flags & SEC_FLAG_DYNAMIC) || (op >= OP_EDIT);
581 void *node = cf_malloc(sec->size);
582 cf_init_section(item->name, sec, node);
583 add_to_list(ptr, node, op);
585 byte *msg = interpret_section(sec, number, pars, &taken, node, only_1_node);
598 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
604 taken = MIN(number, item->number);
606 cf_journal_block(ptr, taken * parsers[item->u.type].size);
607 return cf_parse_ary(taken, pars, ptr, item->u.type);
610 return "Dynamic array cannot be used here";
611 taken = MIN(number, item->number);
613 return interpret_set_dynamic(item, taken, pars, ptr);
615 if (item->number < 0 && !allow_dynamic)
616 return "Parsers with variable number of parameters cannot be used here";
617 if (item->number > 0 && number < item->number)
618 return "Not enough parameters available for the parser";
619 taken = MIN(number, ABS(item->number));
621 for (int i=0; i<taken; i++)
622 pars[i] = cf_strdup(pars[i]);
623 return item->u.par(taken, pars, ptr);
625 return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
628 return "Lists cannot be used here";
629 return interpret_add_list(item, number, pars, ptr, processed, OP_SET);
636 interpret_clear(struct cf_item *item, void *ptr)
638 if (item->cls == CC_LIST) {
639 cf_journal_block(ptr, sizeof(struct clist));
641 } else if (item->cls == CC_DYNAMIC) {
642 cf_journal_block(ptr, sizeof(void *));
643 * (void**) ptr = NULL;
645 return "The item is not a list or a dynamic array";
650 cmp_items(void *i1, void *i2, struct cf_item *item)
652 ASSERT(item->cls == CC_STATIC);
653 i1 += (addr_int_t) item->ptr;
654 i2 += (addr_int_t) item->ptr;
655 if (item->u.type == CT_STRING)
656 return strcmp(* (byte**) i1, * (byte**) i2);
657 else // all numeric types
658 return memcmp(i1, i2, parsers[item->u.type].size);
662 find_list_node(struct clist *list, void *query, struct cf_section *sec, u32 mask)
668 for (uns i=0; i<32; i++)
670 if (cmp_items(n, query, sec->cfg+i))
682 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
684 uns nr = sec->flags & SEC_FLAG_NUMBER;
685 if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
687 uns i = item - sec->cfg;
689 return "Cannot select list nodes by this attribute";
690 if (sec->cfg[i].cls != CC_STATIC)
691 return "Selection can only be done based on basic attributes";
697 #define MAX_STACK_SIZE 100
698 static struct item_stack {
699 struct cf_section *sec; // nested section
700 void *base_ptr; // because original pointers are often relative
701 enum operation op; // it is performed when a closing brace is encountered
702 void *list; // list the operations should be done on
703 u32 mask; // bit array of selectors searching in a list
704 struct cf_item *item; // cf_item of the list
705 } stack[MAX_STACK_SIZE];
709 opening_brace(struct cf_item *item, void *ptr, enum operation op)
711 if (level >= MAX_STACK_SIZE-1)
712 return "Too many nested sections";
713 stack[++level] = (struct item_stack) {
721 if (!item) // unknown is ignored; we just need to trace recursion
723 stack[level].sec = item->u.sec;
724 if (item->cls == CC_SECTION)
726 stack[level].base_ptr = ptr;
727 stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
729 else if (item->cls == CC_LIST)
731 stack[level].base_ptr = cf_malloc(item->u.sec->size);
732 cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
733 stack[level].list = ptr;
734 stack[level].item = item;
735 stack[level].op |= op < OP_REMOVE ? OP_2ND : OP_1ST;
738 return "Opening brace can only be used on sections and lists";
743 closing_brace(struct item_stack *st, int number, byte **msg)
746 if (!st->sec) { // dummy run on unknown section
750 if (st->op == OP_CLOSE) { // top-level
751 *msg = "Unmatched } parenthese";
754 if (st->op & OP_2ND) // finished the 2nd phase; only for lists
757 add_to_list(st->list, st->base_ptr, st->op & OP_MASK);
760 *msg = "No parameters expected after the }";
761 else if (st->op & OP_OPEN)
762 *msg = "No { is expected";
764 } else { // constructed the query
765 st->op = (st->op | OP_2ND) & ~OP_1ST;
766 st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
768 *msg = "Cannot find a node matching the query";
771 enum operation op = st->op & OP_MASK;
774 else if (op == OP_EDIT)
775 st->base_ptr = st->list;
776 else if (op == OP_AFTER || op == OP_BEFORE)
777 cf_init_section(st->item->name, st->sec, st->base_ptr);
781 if (st->op & OP_OPEN) // stay in the same recursion level
783 return 0; // continue with immediate data
787 interpret_line(byte *name, enum operation op, int number, byte **pars)
790 struct cf_item *item;
792 if (op == OP_CLOSE) {
793 if (closing_brace(stack+level, number, &msg))
795 op = stack[level].op; // operation: edit, after, or before
796 item = stack[level].item;
797 ptr = stack[level].base_ptr;
800 item = find_item(stack[level].sec, name, &msg);
803 if (stack[level].op & OP_1ST) {
804 msg = record_selector(item, stack[level].sec, &stack[level].mask);
808 ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
809 if (op & OP_OPEN) // the operation will be performed after the closing brace
810 return opening_brace(item, ptr, op);
811 if (!item) // ignored item in an unknown section
815 int taken; // process as many parameters as possible
818 taken = 0, msg = interpret_clear(item, ptr);
819 else if (op == OP_SET)
820 msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
821 else if (item->cls == CC_DYNAMIC)
822 msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
823 else if (item->cls == CC_LIST)
824 msg = interpret_add_list(item, number, pars, &taken, ptr, op);
826 return cf_printf("Operation %d not supported on attribute class %d", op, item->cls);
830 return cf_printf("Too many parameters: %d>%d", number, taken);