From e1b0cf62838f853e2eb8694ce1e8979be142c7df Mon Sep 17 00:00:00 2001 From: Robert Spalek Date: Fri, 21 Apr 2006 00:56:54 +0200 Subject: [PATCH] implemented parser of a single line and top-level sections unified - we store registered sections in the same format as subsections so that we can search/process them in a uniform way - implemented find_item() that can parse both absolute and relative paths - all parsers of basic types simplified to take care of only 1 value; arrays are handled by the caller - implemented a part of the interpretter: it gets parsed line (attribute name, desired operations, and parameters) and loads the values into memory. since declarations can be nested and they can span over multiple lines, the interpretter operates on a stack --- lib/conf2.c | 431 ++++++++++++++++++++++++++++++++++++++++------------ lib/conf2.h | 6 +- 2 files changed, 334 insertions(+), 103 deletions(-) diff --git a/lib/conf2.c b/lib/conf2.c index b82210bd..594ad757 100644 --- a/lib/conf2.c +++ b/lib/conf2.c @@ -140,24 +140,41 @@ journal_rollback_section(uns new_pool, struct journal_item *oldj, byte *msg) /* Initialization */ -static struct section { - struct section *prev; - byte *name; - struct cf_section *sec; -} *sections; +static struct cf_section sections; // root section + +static struct cf_item * +find_subitem(struct cf_section *sec, byte *name) +{ + struct cf_item *ci = sec->cfg; + for (; ci->cls; ci++) + if (!strcasecmp(ci->name, name)) + return ci; + return ci; +} void cf_declare_section(byte *name, struct cf_section *sec) { - struct section *s = sections; - for (; s; s=s->prev) - if (!strcasecmp(s->name, name)) - die("Cannot register cf_section %s twice", name); - s = xmalloc(sizeof(struct section)); - s->prev = sections; - s->name = name; - s->sec = sec; - sections = s; + if (!sections.cfg) + { + sections.size = 50; + sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item)); + } + struct cf_item *ci = find_subitem(§ions, name); + if (ci->cls) + die("Cannot register section %s twice", name); + ci->cls = CC_SECTION; + ci->name = name; + ci->number = 1; + ci->ptr = NULL; + ci->u.sec = sec; + ci++; + if (ci - sections.cfg >= (int) sections.size) + { + sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item)); + bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item)); + sections.size *= 2; + } } void @@ -178,14 +195,52 @@ cf_init_section(byte *name, struct cf_section *sec, void *ptr) static void global_init(void) { - for (struct section *s=sections; s; s=s->prev) - cf_init_section(s->name, s->sec, NULL); + for (struct cf_item *ci=sections.cfg; ci->cls; ci++) + cf_init_section(ci->name, ci->u.sec, NULL); +} + +static struct cf_item * +find_item(struct cf_section *curr_sec, byte *name, byte **msg) +{ + *msg = NULL; + if (name[0] == '.') + name++; + else if (strchr(name, '.')) + curr_sec = §ions; + if (!curr_sec) + return NULL; + byte *c; + while ((c = strchr(name, '.'))) + { + *c++ = 0; + struct cf_item *ci = find_subitem(curr_sec, name); + if (ci->cls != CC_SECTION) + { + *msg = cf_printf("Item %s %s", name, !ci->cls ? "does not exist" : "is not a subsection"); + return NULL; + } + curr_sec = ci->u.sec; + name = c; + } + struct cf_item *ci = find_subitem(curr_sec, name); + if (!ci->cls) + { + *msg = "Unknown item"; + return NULL; + } + return ci; } /* Safe loading and reloading */ byte *cf_def_file = DEFAULT_CONFIG; +#ifndef DEFAULT_CONFIG +#define DEFAULT_CONFIG NULL +#endif + +byte *cfdeffile = DEFAULT_CONFIG; + static byte *load_file(byte *file); static byte *load_string(byte *string); @@ -275,108 +330,94 @@ lookup_unit(byte *value, byte *end, byte **msg) static char cf_rngerr[] = "Number out of range"; byte * -cf_parse_int(uns number, byte **pars, int *ptr) +cf_parse_int(byte *str, int *ptr) { - for (uns i=0; inum; - if (y % u->den) - msg = "Number is not an integer"; - else { - y /= u->den; - if (y > 0xffffffff) - msg = cf_rngerr; - ptr[i] = y; - } - } else - ptr[i] = x; - } - if (msg) - return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg); + byte *msg = NULL; + if (!*str) + msg = "Missing number"; + else { + const struct unit *u; + char *end; + errno = 0; + uns x = strtoul(str, &end, 0); + if (errno == ERANGE) + msg = cf_rngerr; + else if (u = lookup_unit(str, end, &msg)) { + u64 y = (u64)x * u->num; + if (y % u->den) + msg = "Number is not an integer"; + else { + y /= u->den; + if (y > 0xffffffff) + msg = cf_rngerr; + *ptr = y; + } + } else + *ptr = x; } - return NULL; + return msg; } byte * -cf_parse_u64(uns number, byte **pars, u64 *ptr) +cf_parse_u64(byte *str, u64 *ptr) { - for (uns i=0; i ~(u64)0 / u->num) - msg = "Number out of range"; - else { - x *= u->num; - if (x % u->den) - msg = "Number is not an integer"; - else - ptr[i] = x / u->den; - } - } else - ptr[i] = x; - } - if (msg) - return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg); + byte *msg = NULL; + if (!*str) + msg = "Missing number"; + else { + const struct unit *u; + char *end; + errno = 0; + u64 x = strtoull(str, &end, 0); + if (errno == ERANGE) + msg = cf_rngerr; + else if (u = lookup_unit(str, end, &msg)) { + if (x > ~(u64)0 / u->num) + msg = "Number out of range"; + else { + x *= u->num; + if (x % u->den) + msg = "Number is not an integer"; + else + *ptr = x / u->den; + } + } else + *ptr = x; } - return NULL; + return msg; } byte * -cf_parse_double(uns number, byte **pars, double *ptr) +cf_parse_double(byte *str, double *ptr) { - for (uns i=0; inum / u->den; - else - ptr[i] = x; - } - if (msg) - return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg); + byte *msg = NULL; + if (!*str) + msg = "Missing number"; + else { + const struct unit *u; + char *end; + errno = 0; + double x = strtoul(str, &end, 0); + if (errno == ERANGE) + msg = cf_rngerr; + else if (u = lookup_unit(str, end, &msg)) + *ptr = x * u->num / u->den; + else + *ptr = x; } - return NULL; + return msg; } static byte * -cf_parse_string(uns number, byte **pars, byte **ptr) +cf_parse_string(byte *str, byte **ptr) { - for (uns i=0; iu.type; + if (number > item->number) + return "Expecting shorter array"; cf_journal_block(ptr, sizeof(void*)); *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size; * (uns*) (*ptr - parsers[type].size) = number; - return ((cf_parser*) parsers[type].parser) (number, pars, *ptr); + return cf_parse_ary(number, pars, *ptr, type); +} + +static byte * +add_to_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum operation op) +{ + enum cf_type type = item->u.type; + void *old_p = *ptr; + int old_nr = * (int*) (old_p - parsers[type].size); + if (old_nr + number > item->number) + return "Cannot enlarge dynamic array"; + // stretch the dynamic array + void *new_p = cf_malloc((old_nr + number + 1) * parsers[type].size) + parsers[type].size; + * (uns*) (new_p - parsers[type].size) = old_nr + number; + cf_journal_block(ptr, sizeof(void*)); + *ptr = new_p; + if (op == OP_APPEND) + { + memcpy(new_p, old_p, old_nr * parsers[type].size); + return cf_parse_ary(number, pars, new_p + old_nr * parsers[type].size, type); + } + else if (op == OP_PREPEND) + { + memcpy(new_p + number * parsers[type].size, old_p, old_nr * parsers[type].size); + return cf_parse_ary(number, pars, new_p, type); + } + else + ASSERT(0); +} + +static byte * +parse_subsection(struct cf_section *sec, int number, byte **pars, void *ptr) +{ + struct cf_item *ci; + for (ci=sec->cfg; ci->cls; ci++) + { + if (ci->cls == CC_DYNAMIC && !ci[1].cls) + break; + if (ci->cls != CC_STATIC) + return "Only sections consisting entirely of basic attributes can be written on 1 line"; + if (number) + { + if (number <= ci->number) + return "The number of parameters does not fit the section attributes"; + void *p = ptr + (addr_int_t) ci->ptr; + cf_journal_block(p, ci->number * parsers[ci->u.type].size); + byte *msg = cf_parse_ary(ci->number, pars, p, ci->u.type); + if (msg) + return cf_printf("Attribute %s: %s", ci->name, msg); + number -= ci->number; + pars += ci->number; + } + } + if (ci->cls == CC_DYNAMIC) + return parse_dynamic(ci, number, pars, ptr + (addr_int_t) ci->ptr); + else if (number) + return "Too many parameters for this section"; + return NULL; +} + +static void +add_to_list(struct clist *list, struct cnode *node, enum operation op) +{ + cf_journal_block(list, sizeof(struct clist)); + if (op == OP_APPEND || op == OP_SET) + clist_add_tail(list, node); + else if (op == OP_PREPEND) + clist_add_head(list, node); + else + ASSERT(0); +} + +static byte * +increase_stack(struct cf_item *item, enum operation op) +{ + if (level >= MAX_STACK_SIZE-1) + return "Too many nested sections"; + ++level; + if (item) // fill in the base pointer + { + if (item->cls == CC_SECTION) + stack[level].base_ptr = stack[level].base_ptr + (addr_int_t) item->ptr; + else if (item->cls != CC_LIST) + { + stack[level].base_ptr = cf_malloc(item->u.sec->size); + cf_init_section(item->name, item->u.sec, stack[level].base_ptr); + } + else + return "Opening brace can only be used on sections and lists"; + stack[level].sec = item->u.sec; + } + else // unknown is also handled here, since we need to trace recursion + { + stack[level].base_ptr = NULL; + stack[level].sec = NULL; + } + stack[level].op = op; + return NULL; +} + +static byte * +interpret_item(byte *name, enum operation op, int number, byte **pars) +{ + byte *msg; + struct cf_item *item = find_item(stack[level].sec, name, &msg); + if (op & OP_OPEN) // the operation will be performed after the closing brace + return increase_stack(item, op) ? : msg; + if (!item) + return msg; + + void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr; + if (op == OP_CLEAR) // clear link-list + { + if (item->cls != CC_LIST) + return "The item is not a list"; + cf_journal_block(ptr, sizeof(struct clist)); + clist_init(ptr); + } + else if (op == OP_SET && item->cls != CC_LIST) + switch (item->cls) // setting regular variables + { + case CC_STATIC: + if (number != item->number) + return item->number==1 ? "Expecting one scalar value, not array" : "Expecting array of different length"; + cf_journal_block(ptr, number * parsers[item->u.type].size); + return cf_parse_ary(number, pars, ptr, item->u.type); + case CC_DYNAMIC: + return parse_dynamic(item, number, pars, ptr); + case CC_PARSER: + if (item->number >= 0) + { + if (number != item->number) + return "Expecting different number of parameters"; + } else { + if (number > -item->number) + return "Expecting less parameters"; + } + return item->u.par(number, pars, ptr); + case CC_SECTION: // setting a subsection at once + return parse_subsection(item->u.sec, number, pars, ptr); + default: + ASSERT(0); + } + else if (item->cls == CC_DYNAMIC) + return add_to_dynamic(item, number, pars, ptr, op); + else if (item->cls == CC_LIST) + { // adding to a list at once + void *node = cf_malloc(item->u.sec->size); + cf_init_section(item->name, item->u.sec, node); + msg = parse_subsection(item->u.sec, number, pars, node); + if (msg) + return msg; + add_to_list(ptr, node, op); + } + else + ASSERT(0); + return NULL; } diff --git a/lib/conf2.h b/lib/conf2.h index 94e85160..2a2281ff 100644 --- a/lib/conf2.h +++ b/lib/conf2.h @@ -115,8 +115,8 @@ byte *cf_load(byte *file); byte *cf_set(byte *string); /* Parsers for basic types */ -byte *cf_parse_int(uns number, byte **pars, int *ptr); -byte *cf_parse_u64(uns number, byte **pars, u64 *ptr); -byte *cf_parse_double(uns number, byte **pars, double *ptr); +byte *cf_parse_int(byte *str, int *ptr); +byte *cf_parse_u64(byte *str, u64 *ptr); +byte *cf_parse_double(byte *str, double *ptr); #endif -- 2.39.2