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 static struct cf_section sections; // root section
145 static struct cf_item *
146 find_subitem(struct cf_section *sec, byte *name)
148 struct cf_item *ci = sec->cfg;
149 for (; ci->cls; ci++)
150 if (!strcasecmp(ci->name, name))
156 cf_declare_section(byte *name, struct cf_section *sec)
161 sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
163 struct cf_item *ci = find_subitem(§ions, name);
165 die("Cannot register section %s twice", name);
166 ci->cls = CC_SECTION;
172 if (ci - sections.cfg >= (int) sections.size)
174 sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
175 bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
181 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
184 bzero(ptr, sec->size);
185 for (uns i=0; sec->cfg[i].cls; i++)
186 if (sec->cfg[i].cls == CC_SECTION)
187 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
188 else if (sec->cfg[i].cls == CC_LIST)
189 clist_init(sec->cfg[i].ptr);
190 byte *msg = sec->init(ptr);
192 die("Cannot initialize section %s: %s", name, msg);
198 for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
199 cf_init_section(ci->name, ci->u.sec, NULL);
202 static struct cf_item *
203 find_item(struct cf_section *curr_sec, byte *name, byte **msg)
208 else if (strchr(name, '.'))
209 curr_sec = §ions;
213 while ((c = strchr(name, '.')))
216 struct cf_item *ci = find_subitem(curr_sec, name);
217 if (ci->cls != CC_SECTION)
219 *msg = cf_printf("Item %s %s", name, !ci->cls ? "does not exist" : "is not a subsection");
222 curr_sec = ci->u.sec;
225 struct cf_item *ci = find_subitem(curr_sec, name);
228 *msg = "Unknown item";
234 /* Safe loading and reloading */
236 byte *cf_def_file = DEFAULT_CONFIG;
238 #ifndef DEFAULT_CONFIG
239 #define DEFAULT_CONFIG NULL
242 byte *cfdeffile = DEFAULT_CONFIG;
244 static byte *load_file(byte *file);
245 static byte *load_string(byte *string);
248 cf_reload(byte *file)
251 struct journal_item *oldj = journal_new_section(1);
252 byte *msg = load_file(file);
255 for (struct old_pools *p=pools; p; p=pools)
260 journal_commit_section(1, NULL);
264 journal_rollback_section(1, oldj, msg);
273 struct journal_item *oldj = journal_new_section(1);
274 byte *msg = load_file(file);
276 journal_commit_section(1, oldj);
278 journal_rollback_section(1, oldj, msg);
285 struct journal_item *oldj = journal_new_section(0);
286 byte *msg = load_string(string);
288 journal_commit_section(0, oldj);
290 journal_rollback_section(0, oldj, msg);
294 /* Parsers for standard types */
297 uns name; // one-letter name of the unit
298 uns num, den; // fraction
301 static const struct unit units[] = {
306 { 'g', 1000000000, 1 },
309 { 'G', 1073741824, 1 },
314 static const struct unit *
315 lookup_unit(byte *value, byte *end, byte **msg)
318 if (end == value || end[1] || *end >= '0' && *end <= '9')
319 *msg = "Invalid number";
321 for (const struct unit *u=units; u->name; u++)
324 *msg = "Invalid unit";
330 static char cf_rngerr[] = "Number out of range";
333 cf_parse_int(byte *str, int *ptr)
337 msg = "Missing number";
339 const struct unit *u;
342 uns x = strtoul(str, &end, 0);
345 else if (u = lookup_unit(str, end, &msg)) {
346 u64 y = (u64)x * u->num;
348 msg = "Number is not an integer";
362 cf_parse_u64(byte *str, u64 *ptr)
366 msg = "Missing number";
368 const struct unit *u;
371 u64 x = strtoull(str, &end, 0);
374 else if (u = lookup_unit(str, end, &msg)) {
375 if (x > ~(u64)0 / u->num)
376 msg = "Number out of range";
380 msg = "Number is not an integer";
391 cf_parse_double(byte *str, double *ptr)
395 msg = "Missing number";
397 const struct unit *u;
400 double x = strtoul(str, &end, 0);
403 else if (u = lookup_unit(str, end, &msg))
404 *ptr = x * u->num / u->den;
412 cf_parse_string(byte *str, byte **ptr)
414 *ptr = cf_strdup(str);
418 /* Register size of and parser for each basic type */
420 typedef byte *cf_basic_parser(byte *str, void *ptr);
425 { sizeof(int), cf_parse_int },
426 { sizeof(u64), cf_parse_u64 },
427 { sizeof(double), cf_parse_double },
428 { sizeof(byte*), cf_parse_string }
432 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
434 for (uns i=0; i<number; i++)
436 byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
438 return cf_printf("Cannot parse item %d: %s", i+1, msg);
447 OP_SET, // basic attribute (static, dynamic, parsed), section, list
448 OP_APPEND, // dynamic array, list
449 OP_PREPEND, // dynamic array, list
451 OP_OPEN = 0x80 // here we only have an opening brace
454 #define MAX_STACK_SIZE 100
455 static struct item_stack {
456 struct cf_section *sec; // nested section
457 void *base_ptr; // because original pointers are often relative
458 enum operation op; // it is performed when a closing brace is encountered
459 } stack[MAX_STACK_SIZE];
463 parse_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
465 enum cf_type type = item->u.type;
466 if (number > item->number)
467 return "Expecting shorter array";
468 cf_journal_block(ptr, sizeof(void*));
469 *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
470 * (uns*) (*ptr - parsers[type].size) = number;
471 return cf_parse_ary(number, pars, *ptr, type);
475 add_to_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum operation op)
477 enum cf_type type = item->u.type;
479 int old_nr = * (int*) (old_p - parsers[type].size);
480 if (old_nr + number > item->number)
481 return "Cannot enlarge dynamic array";
482 // stretch the dynamic array
483 void *new_p = cf_malloc((old_nr + number + 1) * parsers[type].size) + parsers[type].size;
484 * (uns*) (new_p - parsers[type].size) = old_nr + number;
485 cf_journal_block(ptr, sizeof(void*));
489 memcpy(new_p, old_p, old_nr * parsers[type].size);
490 return cf_parse_ary(number, pars, new_p + old_nr * parsers[type].size, type);
492 else if (op == OP_PREPEND)
494 memcpy(new_p + number * parsers[type].size, old_p, old_nr * parsers[type].size);
495 return cf_parse_ary(number, pars, new_p, type);
502 parse_subsection(struct cf_section *sec, int number, byte **pars, void *ptr)
505 for (ci=sec->cfg; ci->cls; ci++)
507 if (ci->cls == CC_DYNAMIC && !ci[1].cls)
509 if (ci->cls != CC_STATIC)
510 return "Only sections consisting entirely of basic attributes can be written on 1 line";
513 if (number < ci->number)
514 return "The number of parameters does not fit the section attributes";
515 void *p = ptr + (addr_int_t) ci->ptr;
516 cf_journal_block(p, ci->number * parsers[ci->u.type].size);
517 byte *msg = cf_parse_ary(ci->number, pars, p, ci->u.type);
519 return cf_printf("Attribute %s: %s", ci->name, msg);
520 number -= ci->number;
524 if (ci->cls == CC_DYNAMIC)
525 return parse_dynamic(ci, number, pars, ptr + (addr_int_t) ci->ptr);
527 return "Too many parameters for this section";
532 add_to_list(struct clist *list, struct cnode *node, enum operation op)
534 cf_journal_block(list, sizeof(struct clist));
535 if (op == OP_APPEND || op == OP_SET)
536 clist_add_tail(list, node);
537 else if (op == OP_PREPEND)
538 clist_add_head(list, node);
544 increase_stack(struct cf_item *item, enum operation op)
546 if (level >= MAX_STACK_SIZE-1)
547 return "Too many nested sections";
549 if (item) // fill in the base pointer
551 if (item->cls == CC_SECTION)
552 stack[level].base_ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
553 else if (item->cls != CC_LIST)
555 stack[level].base_ptr = cf_malloc(item->u.sec->size);
556 cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
559 return "Opening brace can only be used on sections and lists";
560 stack[level].sec = item->u.sec;
562 else // unknown is also handled here, since we need to trace recursion
564 stack[level].base_ptr = NULL;
565 stack[level].sec = NULL;
567 stack[level].op = op;
572 interpret_item(byte *name, enum operation op, int number, byte **pars)
575 struct cf_item *item = find_item(stack[level].sec, name, &msg);
576 if (op & OP_OPEN) // the operation will be performed after the closing brace
577 return increase_stack(item, op) ? : msg;
581 void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
582 if (op == OP_CLEAR) // clear link-list
584 if (item->cls != CC_LIST)
585 return "The item is not a list";
586 cf_journal_block(ptr, sizeof(struct clist));
589 else if (op == OP_SET && item->cls != CC_LIST)
590 switch (item->cls) // setting regular variables
593 if (number != item->number)
594 return item->number==1 ? "Expecting one scalar value, not an array" : "Expecting array of different length";
595 cf_journal_block(ptr, number * parsers[item->u.type].size);
596 return cf_parse_ary(number, pars, ptr, item->u.type);
598 return parse_dynamic(item, number, pars, ptr);
600 if (item->number >= 0)
602 if (number != item->number)
603 return "Expecting different number of parameters";
605 if (number > -item->number)
606 return "Expecting less parameters";
608 for (int i=0; i<number; i++)
609 pars[i] = cf_strdup(pars[i]);
610 return item->u.par(number, pars, ptr);
611 case CC_SECTION: // setting a subsection at once
612 return parse_subsection(item->u.sec, number, pars, ptr);
616 else if (item->cls == CC_DYNAMIC)
617 return add_to_dynamic(item, number, pars, ptr, op);
618 else if (item->cls == CC_LIST)
619 { // adding to a list at once
620 void *node = cf_malloc(item->u.sec->size);
621 cf_init_section(item->name, item->u.sec, node);
622 msg = parse_subsection(item->u.sec, number, pars, node);
625 add_to_list(ptr, node, op);