From: Robert Spalek Date: Fri, 21 Apr 2006 10:40:57 +0000 (+0200) Subject: conf2: resolve an issue concerning variable numbers of parameters X-Git-Tag: holmes-import~645^2~11^2~94 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=136b12a613d9168835ace49bb312e123c4af15ce;p=libucw.git conf2: resolve an issue concerning variable numbers of parameters When a node of a link list is parsed on one line, then the inner section is checked for dynamic attributes at the end. If they are present, the outer node is just parsed once and the flag allowing dynamic parsing is passed inside. If we did not allow this, then an error would have occured anyway, and this behaviour is actually useful. Along the way, I unified the headers and semantics of most interpreters and cleaned up the code. --- diff --git a/lib/conf2.c b/lib/conf2.c index 9e772e16..ca24e565 100644 --- a/lib/conf2.c +++ b/lib/conf2.c @@ -471,33 +471,33 @@ interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr) } static byte * -interpret_add_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum operation op) +interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, 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 "Too many parameters for the dynamic array"; + int taken = MIN(number, item->number-old_nr); + *processed = taken; // 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; + void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size; + * (uns*) (new_p - parsers[type].size) = old_nr + taken; 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); + return cf_parse_ary(taken, 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); + memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size); + return cf_parse_ary(taken, pars, new_p, type); } else ASSERT(0); } -static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr); +static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic); static byte * interpret_subsection(struct cf_section *sec, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr) @@ -506,7 +506,7 @@ interpret_subsection(struct cf_section *sec, int number, byte **pars, int *proce for (struct cf_item *ci=sec->cfg; ci->cls; ci++) { int taken; - byte *msg = interpret_set_item(ci, number, pars, &taken, allow_dynamic && !ci[1].cls, ptr + (addr_int_t) ci->ptr); + byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls); if (msg) return cf_printf("Item %s: %s", ci->name, msg); *processed += taken; @@ -529,25 +529,40 @@ add_to_list(struct clist *list, struct cnode *node, enum operation op) } static byte * -interpret_add_list(struct cf_item *item, int number, byte **pars, void *ptr, enum operation op) +interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum operation op) { + struct cf_item *ci = item; + uns only_1_item = 0; + do + for (ci=ci->u.sec->cfg; ci->cls; ci++); + while ((--ci)->cls == CC_SECTION); + if (ci->cls == CC_DYNAMIC || ci->cls == CC_LIST + || ci->cls == CC_PARSER && ci->number < 0) + only_1_item = 1; + /* If the node contains any dynamic attribute at the end, we suppress + * repetition here and pass it instead inside. */ + struct cf_section *sec = item->u.sec; + *processed = 0; while (number > 0) { - void *node = cf_malloc(item->u.sec->size); - cf_init_section(item->name, item->u.sec, node); + void *node = cf_malloc(sec->size); + cf_init_section(item->name, sec, node); add_to_list(ptr, node, op); int taken; - byte *msg = interpret_subsection(item->u.sec, number, pars, &taken, 0, node); + byte *msg = interpret_subsection(sec, number, pars, &taken, only_1_item, node); if (msg) return msg; + *processed += taken; number -= taken; pars += taken; + if (only_1_item) + break; } return NULL; } static byte * -interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr) +interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic) { int taken; switch (item->cls) @@ -578,8 +593,7 @@ interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed case CC_LIST: if (!allow_dynamic) return "Lists cannot be used here"; - *processed = number; - return interpret_add_list(item, number, pars, ptr, OP_APPEND); + return interpret_add_list(item, number, pars, ptr, processed, OP_APPEND); default: ASSERT(0); } @@ -630,22 +644,21 @@ interpret_line(byte *name, enum operation op, int number, byte **pars) return "The item is not a list"; cf_journal_block(ptr, sizeof(struct clist)); clist_init(ptr); + return NULL; } - else if (op == OP_SET) - { - int taken; - msg = interpret_set_item(item, number, pars, &taken, 1, ptr); - if (msg) - return msg; - if (taken < number) - return "Too many parameters"; - } + int taken; // process as many parameters as possible + if (op == OP_SET) + msg = interpret_set_item(item, number, pars, &taken, ptr, 1); else if (item->cls == CC_DYNAMIC) - return interpret_add_dynamic(item, number, pars, ptr, op); + msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op); else if (item->cls == CC_LIST) - return interpret_add_list(item, number, pars, ptr, op); + msg = interpret_add_list(item, number, pars, &taken, ptr, op); else return cf_printf("Operation %d not supported for class %d", op, item->cls); + if (msg) + return msg; + if (taken < number) + return cf_printf("Too many parameters: %d>%d", number, taken); return NULL; }