2 * UCW Library -- Configuration files: interpreter
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.
13 #include "lib/getopt.h"
14 #include "lib/conf-internal.h"
15 #include "lib/clists.h"
20 #define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
22 /* Register size of and parser for each basic type */
25 cf_parse_string(byte *str, byte **ptr)
27 *ptr = cf_strdup(str);
31 typedef byte *cf_basic_parser(byte *str, void *ptr);
36 { sizeof(int), cf_parse_int },
37 { sizeof(u64), cf_parse_u64 },
38 { sizeof(double), cf_parse_double },
39 { sizeof(u32), cf_parse_ip },
40 { sizeof(byte*), cf_parse_string },
41 { sizeof(int), NULL }, // lookups are parsed extra
42 { 0, NULL }, // user-defined types are parsed extra
46 cf_type_size(enum cf_type type, struct cf_user_type *utype)
49 return parsers[type].size;
55 cf_parse_lookup(byte *str, int *ptr, byte **t)
59 while (*n && strcasecmp(*n, str)) {
60 total_len += strlen(*n) + 2;
67 byte *err = cf_malloc(total_len + strlen(str) + 60), *c = err;
68 c += sprintf(err, "Invalid value %s, possible values are: ", str);
70 c+= sprintf(c, "%s, ", *n);
78 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type, union cf_union *u)
80 for (uns i=0; i<number; i++)
83 uns size = cf_type_size(type, u->utype);
85 msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
86 else if (type == CT_LOOKUP)
87 msg = cf_parse_lookup(pars[i], ptr + i * size, u->lookup);
88 else if (type == CT_USER)
89 msg = u->utype->parser(pars[i], ptr + i * size);
93 return cf_printf("Cannot parse item %d: %s", i+1, msg);
101 byte *cf_op_names[] = { CF_OPERATIONS };
105 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
107 enum cf_type type = item->type;
108 cf_journal_block(ptr, sizeof(void*));
109 // boundary checks done by the caller
110 uns size = cf_type_size(item->type, item->u.utype);
111 ASSERT(size >= sizeof(uns));
112 *ptr = cf_malloc((number+1) * size) + size;
113 * (uns*) (*ptr - size) = number;
114 return cf_parse_ary(number, pars, *ptr, type, &item->u);
118 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum cf_operation op)
120 enum cf_type type = item->type;
122 uns size = cf_type_size(item->type, item->u.utype);
123 ASSERT(size >= sizeof(uns));
124 int old_nr = old_p ? * (int*) (old_p - size) : 0;
125 int taken = MIN(number, ABS(item->number)-old_nr);
127 // stretch the dynamic array
128 void *new_p = cf_malloc((old_nr + taken + 1) * size) + size;
129 * (uns*) (new_p - size) = old_nr + taken;
130 cf_journal_block(ptr, sizeof(void*));
132 if (op == OP_APPEND) {
133 memcpy(new_p, old_p, old_nr * size);
134 return cf_parse_ary(taken, pars, new_p + old_nr * size, type, &item->u);
135 } else if (op == OP_PREPEND) {
136 memcpy(new_p + taken * size, old_p, old_nr * size);
137 return cf_parse_ary(taken, pars, new_p, type, &item->u);
139 return cf_printf("Dynamic arrays do not support operation %s", cf_op_names[op]);
142 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
145 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
147 cf_add_dirty(sec, ptr);
149 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
152 byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
154 return cf_printf("Item %s: %s", ci->name, msg);
158 if (!number) // stop parsing, because many parsers would otherwise complain that number==0
165 add_to_list(cnode *where, cnode *new_node, enum cf_operation op)
169 case OP_EDIT: // edition has been done in-place
172 CF_JOURNAL_VAR(where->prev->next);
173 CF_JOURNAL_VAR(where->next->prev);
176 case OP_AFTER: // implementation dependend (prepend_head = after(list)), and where==list, see clists.h:74
179 CF_JOURNAL_VAR(where->next->prev);
180 CF_JOURNAL_VAR(where->next);
181 clist_insert_after(new_node, where);
183 case OP_BEFORE: // implementation dependend (append_tail = before(list))
186 CF_JOURNAL_VAR(where->prev->next);
187 CF_JOURNAL_VAR(where->prev);
188 clist_insert_before(new_node, where);
196 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum cf_operation op)
199 return cf_printf("You have to open a block for operation %s", cf_op_names[op]);
201 return "Nothing to add to the list";
202 struct cf_section *sec = item->u.sec;
206 void *node = cf_malloc(sec->size);
207 cf_init_section(item->name, sec, node, 1);
208 add_to_list(ptr, node, op);
210 /* If the node contains any dynamic attribute at the end, we suppress
211 * auto-repetition here and pass the flag inside instead. */
212 TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
216 if (sec->flags & SEC_FLAG_DYNAMIC)
223 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
230 return "Missing value";
231 taken = MIN(number, item->number);
233 uns size = cf_type_size(item->type, item->u.utype);
234 cf_journal_block(ptr, taken * size);
235 return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
238 return "Dynamic array cannot be used here";
239 taken = MIN(number, ABS(item->number));
241 return interpret_set_dynamic(item, taken, pars, ptr);
243 if (item->number < 0 && !allow_dynamic)
244 return "Parsers with variable number of parameters cannot be used here";
245 if (item->number > 0 && number < item->number)
246 return "Not enough parameters available for the parser";
247 taken = MIN(number, ABS(item->number));
249 for (int i=0; i<taken; i++)
250 pars[i] = cf_strdup(pars[i]);
251 return item->u.par(taken, pars, ptr);
253 return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
256 return "Lists cannot be used here";
257 return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
264 interpret_clear(struct cf_item *item, void *ptr)
266 if (item->cls == CC_LIST) {
267 cf_journal_block(ptr, sizeof(clist));
269 } else if (item->cls == CC_DYNAMIC) {
270 cf_journal_block(ptr, sizeof(void *));
271 * (void**) ptr = NULL;
272 } else if (item->cls == CC_STATIC && item->type == CT_STRING) {
273 cf_journal_block(ptr, item->number * sizeof(byte*));
274 bzero(ptr, item->number * sizeof(byte*));
276 return "The item is not a list, dynamic array, or string";
281 cmp_items(void *i1, void *i2, struct cf_item *item)
283 ASSERT(item->cls == CC_STATIC);
284 i1 += (addr_int_t) item->ptr;
285 i2 += (addr_int_t) item->ptr;
286 if (item->type == CT_STRING)
287 return strcmp(* (byte**) i1, * (byte**) i2);
288 else // all numeric types
289 return memcmp(i1, i2, cf_type_size(item->type, item->u.utype));
293 find_list_node(clist *list, void *query, struct cf_section *sec, u32 mask)
295 CLIST_FOR_EACH(cnode *, n, *list)
298 for (uns i=0; i<32; i++)
300 if (cmp_items(n, query, sec->cfg+i))
312 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
314 uns nr = sec->flags & SEC_FLAG_NUMBER;
315 if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
317 uns i = item - sec->cfg;
319 return "Cannot select list nodes by this attribute";
320 if (sec->cfg[i].cls != CC_STATIC)
321 return "Selection can only be done based on basic attributes";
327 #define MAX_STACK_SIZE 10
328 static struct item_stack {
329 struct cf_section *sec; // nested section
330 void *base_ptr; // because original pointers are often relative
331 enum cf_operation op; // it is performed when a closing brace is encountered
332 void *list; // list the operations should be done on
333 u32 mask; // bit array of selectors searching in a list
334 struct cf_item *item; // cf_item of the list
335 } stack[MAX_STACK_SIZE];
339 opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
341 if (level >= MAX_STACK_SIZE-1)
342 return "Too many nested sections";
343 stack[++level] = (struct item_stack) {
351 if (!item) // unknown is ignored; we just need to trace recursion
353 stack[level].sec = item->u.sec;
354 if (item->cls == CC_SECTION)
356 stack[level].base_ptr = ptr;
357 stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
359 else if (item->cls == CC_LIST)
361 stack[level].base_ptr = cf_malloc(item->u.sec->size);
362 cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
363 stack[level].list = ptr;
364 stack[level].item = item;
365 if ((op & OP_MASK) < OP_REMOVE) {
366 add_to_list(ptr, stack[level].base_ptr, op & OP_MASK);
367 stack[level].op |= OP_2ND;
369 stack[level].op |= OP_1ST;
372 return "Opening brace can only be used on sections and lists";
377 closing_brace(struct item_stack *st, enum cf_operation op, int number, byte **pars)
379 if (st->op == OP_CLOSE) // top-level
380 return "Unmatched } parenthesis";
381 if (!st->sec) { // dummy run on unknown section
386 enum cf_operation pure_op = st->op & OP_MASK;
389 st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
391 return "Cannot find a node matching the query";
392 if (pure_op != OP_REMOVE)
394 if (pure_op == OP_EDIT)
395 st->base_ptr = st->list;
396 else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
397 cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
398 else if (pure_op == OP_COPY) {
399 if (st->sec->flags & SEC_FLAG_CANT_COPY)
400 return cf_printf("Item %s cannot be copied", st->item->name);
401 memcpy(st->base_ptr, st->list, st->sec->size); // strings and dynamic arrays are shared
403 TRY( st->sec->copy(st->base_ptr, st->list) );
406 if (op & OP_OPEN) { // stay at the same recursion level
407 st->op = (st->op | OP_2ND) & ~OP_1ST;
408 add_to_list(st->list, st->base_ptr, pure_op);
411 int taken; // parse parameters on 1 line immediately
412 TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
415 // and fall-thru to the 2nd phase
417 add_to_list(st->list, st->base_ptr, pure_op);
421 return "No parameters expected after the }";
422 else if (op & OP_OPEN)
423 return "No { is expected";
428 static struct cf_item *
429 find_item(struct cf_section *curr_sec, byte *name, byte **msg, void **ptr)
432 if (name[0] == '^') // absolute name instead of relative
433 name++, curr_sec = &cf_sections, *ptr = NULL;
434 if (!curr_sec) // don't even search in an unknown section
438 if (curr_sec != &cf_sections)
439 cf_add_dirty(curr_sec, *ptr);
440 byte *c = strchr(name, '.');
443 struct cf_item *ci = cf_find_subitem(curr_sec, name);
446 if (!(curr_sec->flags & SEC_FLAG_UNKNOWN)) // ignore silently unknown top-level sections and unknown attributes in flagged sections
447 *msg = cf_printf("Unknown item %s", name);
450 *ptr += (addr_int_t) ci->ptr;
453 if (ci->cls != CC_SECTION)
455 *msg = cf_printf("Item %s is not a section", name);
458 curr_sec = ci->u.sec;
464 cf_interpret_line(byte *name, enum cf_operation op, int number, byte **pars)
467 if ((op & OP_MASK) == OP_CLOSE)
468 return closing_brace(stack+level, op, number, pars);
469 void *ptr = stack[level].base_ptr;
470 struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
473 if (stack[level].op & OP_1ST)
474 TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
475 if (op & OP_OPEN) { // the operation will be performed after the closing brace
477 return "Cannot open a block after a parameter has been passed on a line";
478 return opening_brace(item, ptr, op);
480 if (!item) // ignored item in an unknown section
484 int taken; // process as many parameters as possible
486 taken = 0, msg = interpret_clear(item, ptr);
487 else if (op == OP_SET)
488 msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
489 else if (item->cls == CC_DYNAMIC)
490 msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
491 else if (item->cls == CC_LIST)
492 msg = interpret_add_list(item, number, pars, &taken, ptr, op);
494 return cf_printf("Operation %s not supported on attribute %s", cf_op_names[op], name);
498 return cf_printf("Too many parameters: %d>%d", number, taken);
504 cf_find_item(byte *name, struct cf_item *item)
508 struct cf_item *ci = find_item(&cf_sections, name, &msg, &ptr);
515 bzero(item, sizeof(struct cf_item));
520 cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
526 msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
530 msg = interpret_clear(item, item->ptr);
534 if (item->cls == CC_DYNAMIC)
535 msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
536 else if (item->cls == CC_LIST)
537 msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
539 return "The attribute class does not support append/prepend";
542 return "Unsupported operation";
547 return "Too many parameters";
554 static uns initialized = 0;
555 if (!initialized++) {
556 cf_sections.flags |= SEC_FLAG_UNKNOWN;
557 cf_sections.size = 0; // size of allocated array used to be stored here
558 cf_init_section(NULL, &cf_sections, NULL, 0);
561 stack[0] = (struct item_stack) {
575 log(L_ERROR, "Unterminated block");