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"
15 #include "lib/fastbuf.h"
16 #include "lib/chartype.h"
26 #define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
28 /* Memory allocation */
30 struct mempool *cf_pool; // current pool for loading new configuration
31 static struct old_pools {
32 struct old_pools *prev;
34 } *pools; // link-list of older cf_pool's
39 return mp_alloc(cf_pool, size);
43 cf_malloc_zero(uns size)
45 return mp_alloc_zero(cf_pool, size);
51 return mp_strdup(cf_pool, s);
55 cf_printf(char *fmt, ...)
59 byte *res = mp_vprintf(cf_pool, fmt, args);
66 uns cf_need_journal = 1; // some programs do not need journal
67 static struct journal_item {
68 struct journal_item *prev;
75 cf_journal_block(void *ptr, uns len)
79 struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
83 memcpy(ji->copy, ptr, len);
89 // swaps the contents of the memory and the journal, and reverses the list
91 struct journal_item *curr, *prev, *next;
92 for (next=NULL, curr=journal; curr; next=curr, curr=prev)
96 for (uns i=0; i<curr->len; i++)
98 byte x = curr->copy[i];
99 curr->copy[i] = curr->ptr[i];
106 static struct journal_item *
107 journal_new_section(uns new_pool)
110 cf_pool = mp_new(1<<10);
111 struct journal_item *oldj = journal;
117 journal_commit_section(uns new_pool, struct journal_item *oldj)
121 struct old_pools *p = cf_malloc(sizeof(struct old_pools));
128 struct journal_item **j = &journal;
136 journal_rollback_section(uns new_pool, struct journal_item *oldj)
138 if (!cf_need_journal)
139 die("Cannot rollback the configuration, because the journal is disabled.");
145 cf_pool = pools ? pools->pool : NULL;
151 #define SEC_FLAG_DYNAMIC 0x80000000 // contains a dynamic attribute
152 #define SEC_FLAG_UNKNOWN 0x40000000 // ignore unknown entriies
153 #define SEC_FLAG_NUMBER 0x0fffffff // number of entries
155 static struct cf_section sections; // root section
157 static struct cf_item *
158 find_subitem(struct cf_section *sec, byte *name)
160 struct cf_item *ci = sec->cfg;
161 for (; ci->cls; ci++)
162 if (!strcasecmp(ci->name, name))
168 inspect_section(struct cf_section *sec)
172 for (ci=sec->cfg; ci->cls; ci++)
173 if (ci->cls == CC_SECTION) {
174 inspect_section(ci->u.sec);
175 sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
176 } else if (ci->cls == CC_LIST) {
177 inspect_section(ci->u.sec);
178 sec->flags |= SEC_FLAG_DYNAMIC;
179 } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
180 sec->flags |= SEC_FLAG_DYNAMIC;
181 sec->flags |= ci - sec->cfg; // record the number of entries
185 cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown)
190 sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
192 struct cf_item *ci = find_subitem(§ions, name);
194 die("Cannot register section %s twice", name);
195 ci->cls = CC_SECTION;
200 inspect_section(sec);
202 sec->flags |= SEC_FLAG_UNKNOWN;
204 if (ci - sections.cfg >= (int) sections.size)
206 sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
207 bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
213 cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero)
217 bzero(ptr, sec->size);
219 for (uns i=0; sec->cfg[i].cls; i++)
220 if (sec->cfg[i].cls == CC_SECTION)
221 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr, 0);
222 else if (sec->cfg[i].cls == CC_LIST)
223 clist_init(sec->cfg[i].ptr);
225 byte *msg = sec->init(ptr);
227 die("Cannot initialize section %s: %s", name, msg);
234 static uns initialized = 0;
237 sections.flags |= SEC_FLAG_UNKNOWN;
238 sections.size = 0; // size of allocated array used to be stored here
239 cf_init_section("top-level", §ions, NULL, 0);
243 commit_section(byte *name, struct cf_section *sec, void *ptr)
246 for (ci=sec->cfg; ci->cls; ci++)
247 if (ci->cls == CC_SECTION) {
248 if (commit_section(ci->name, ci->u.sec, ptr + (addr_int_t) ci->ptr)) {
249 if (sec != §ions)
250 log(L_ERROR, "It was in section %s", name);
253 } else if (ci->cls == CC_LIST) {
256 CLIST_WALK(n, * (clist*) (ptr + (addr_int_t) ci->ptr))
257 if (idx++, commit_section(ci->name, ci->u.sec, n)) {
258 log(L_ERROR, "It was in the node #%d of list %s", idx, name);
263 byte *msg = sec->commit(ptr);
265 log(L_ERROR, "Cannot commit section %s: %s", name, msg);
272 static struct cf_item *
273 find_item(struct cf_section *curr_sec, byte *name, byte **msg, void **ptr)
276 if (name[0] == '^') // absolute name instead of relative
277 name++, curr_sec = §ions, *ptr = NULL;
278 if (!curr_sec) // don't even search in an unknown section
282 byte *c = strchr(name, '.');
285 struct cf_item *ci = find_subitem(curr_sec, name);
288 if (!(curr_sec->flags & SEC_FLAG_UNKNOWN)) // ignore silently unknown top-level sections and unknown attributes in flagged sections
289 *msg = cf_printf("Unknown item %s", name);
292 *ptr += (addr_int_t) ci->ptr;
295 if (ci->cls != CC_SECTION)
297 *msg = cf_printf("Item %s is not a section", name);
300 curr_sec = ci->u.sec;
306 cf_find_item(byte *name, struct cf_item *item)
310 struct cf_item *ci = find_item(§ions, name, &msg, &ptr);
318 /* Safe loading and reloading */
320 static int load_file(byte *file);
321 static int load_string(byte *string);
324 cf_reload(byte *file)
327 struct journal_item *oldj = journal_new_section(1);
328 int err = load_file(file);
331 for (struct old_pools *p=pools; p; p=pools)
336 journal_commit_section(1, NULL);
340 journal_rollback_section(1, oldj);
349 struct journal_item *oldj = journal_new_section(1);
350 int err = load_file(file);
352 journal_commit_section(1, oldj);
354 journal_rollback_section(1, oldj);
361 struct journal_item *oldj = journal_new_section(0);
362 int err = load_string(string);
364 journal_commit_section(0, oldj);
366 journal_rollback_section(0, oldj);
370 /* Parsers for standard types */
373 uns name; // one-letter name of the unit
374 uns num, den; // fraction
377 static const struct unit units[] = {
382 { 'g', 1000000000, 1 },
385 { 'G', 1073741824, 1 },
390 static const struct unit *
391 lookup_unit(byte *value, byte *end, byte **msg)
394 if (end == value || end[1] || *end >= '0' && *end <= '9')
395 *msg = "Invalid number";
397 for (const struct unit *u=units; u->name; u++)
400 *msg = "Invalid unit";
406 static char cf_rngerr[] = "Number out of range";
409 cf_parse_int(byte *str, int *ptr)
413 msg = "Missing number";
415 const struct unit *u;
418 uns x = strtoul(str, &end, 0);
421 else if (u = lookup_unit(str, end, &msg)) {
422 u64 y = (u64)x * u->num;
424 msg = "Number is not an integer";
438 cf_parse_u64(byte *str, u64 *ptr)
442 msg = "Missing number";
444 const struct unit *u;
447 u64 x = strtoull(str, &end, 0);
450 else if (u = lookup_unit(str, end, &msg)) {
451 if (x > ~(u64)0 / u->num)
452 msg = "Number out of range";
456 msg = "Number is not an integer";
467 cf_parse_double(byte *str, double *ptr)
471 msg = "Missing number";
473 const struct unit *u;
476 if (sscanf(str, "%lf%n", &x, &read_chars) != 1)
477 msg = "Invalid number";
478 else if (u = lookup_unit(str, str + read_chars, &msg))
479 *ptr = x * u->num / u->den;
487 cf_parse_ip(byte *p, u32 *varp)
490 return "Missing IP address";
493 if (*p == '0' && p[1] | 32 == 'X') {
495 x = strtoul(p + 2, &p2, 16);
496 if (errno == ERANGE || p2 == (char*) (p+2) || x > 0xffffffff)
501 for (uns i = 0; i < 4; i++) {
507 uns y = strtoul(p, &p2, 10);
508 if (errno == ERANGE || p2 == (char*) p || y > 255)
514 return *p ? "Trailing characters" : NULL;
516 return "Invalid IP address";
520 cf_parse_string(byte *str, byte **ptr)
522 *ptr = cf_strdup(str);
526 /* Register size of and parser for each basic type */
528 typedef byte *cf_basic_parser(byte *str, void *ptr);
533 { sizeof(int), cf_parse_int },
534 { sizeof(u64), cf_parse_u64 },
535 { sizeof(double), cf_parse_double },
536 { sizeof(u32), cf_parse_ip },
537 { sizeof(byte*), cf_parse_string }
541 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
543 for (uns i=0; i<number; i++)
545 byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
547 return cf_printf("Cannot parse item %d: %s", i+1, msg);
555 static byte *op_names[] = { CF_OPERATIONS };
558 #define OP_MASK 0xff // only get the operation
559 #define OP_OPEN 0x100 // here we only get an opening brace instead of parameters
560 #define OP_1ST 0x200 // in the 1st phase selectors are recorded into the mask
561 #define OP_2ND 0x400 // in the 2nd phase real data are entered
564 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
566 enum cf_type type = item->u.type;
567 cf_journal_block(ptr, sizeof(void*));
568 // boundary checks done by the caller
569 *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
570 * (uns*) (*ptr - parsers[type].size) = number;
571 return cf_parse_ary(number, pars, *ptr, type);
575 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum cf_operation op)
577 enum cf_type type = item->u.type;
579 int old_nr = * (int*) (old_p - parsers[type].size);
580 int taken = MIN(number, item->number-old_nr);
582 // stretch the dynamic array
583 void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
584 * (uns*) (new_p - parsers[type].size) = old_nr + taken;
585 cf_journal_block(ptr, sizeof(void*));
587 if (op == OP_APPEND) {
588 memcpy(new_p, old_p, old_nr * parsers[type].size);
589 return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
590 } else if (op == OP_PREPEND) {
591 memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
592 return cf_parse_ary(taken, pars, new_p, type);
594 return cf_printf("Dynamic arrays do not support operation %s", op_names[op]);
597 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
600 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
603 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
606 byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
608 return cf_printf("Item %s: %s", ci->name, msg);
612 if (!number) // stop parsing, because many parsers would otherwise complain that number==0
619 add_to_list(struct cnode *where, struct cnode *new_node, enum cf_operation op)
623 case OP_EDIT: // edition has been done in-place
626 cf_journal_block(&where->prev->next, sizeof(void*));
627 cf_journal_block(&where->next->prev, sizeof(void*));
630 case OP_AFTER: // implementation dependend (prepend_head = after(list)), and where==list, see clists.h:74
632 cf_journal_block(&where->next->prev, sizeof(void*));
633 cf_journal_block(&where->next, sizeof(void*));
634 clist_insert_after(new_node, where);
636 case OP_BEFORE: // implementation dependend (append_tail = before(list))
639 cf_journal_block(&where->prev->next, sizeof(void*));
640 cf_journal_block(&where->prev, sizeof(void*));
641 clist_insert_before(new_node, where);
649 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum cf_operation op)
652 return cf_printf("You have to open a block for operation %s", op_names[op]);
654 return "Nothing to add to the list";
655 struct cf_section *sec = item->u.sec;
659 void *node = cf_malloc(sec->size);
660 cf_init_section(item->name, sec, node, 1);
661 add_to_list(ptr, node, op);
663 /* If the node contains any dynamic attribute at the end, we suppress
664 * auto-repetition here and pass the flag inside instead. */
665 TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
669 if (sec->flags & SEC_FLAG_DYNAMIC)
676 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
683 return "Missing value";
684 taken = MIN(number, item->number);
686 cf_journal_block(ptr, taken * parsers[item->u.type].size);
687 return cf_parse_ary(taken, pars, ptr, item->u.type);
690 return "Dynamic array cannot be used here";
691 taken = MIN(number, item->number);
693 return interpret_set_dynamic(item, taken, pars, ptr);
695 if (item->number < 0 && !allow_dynamic)
696 return "Parsers with variable number of parameters cannot be used here";
697 if (item->number > 0 && number < item->number)
698 return "Not enough parameters available for the parser";
699 taken = MIN(number, ABS(item->number));
701 for (int i=0; i<taken; i++)
702 pars[i] = cf_strdup(pars[i]);
703 return item->u.par(taken, pars, ptr);
705 return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
708 return "Lists cannot be used here";
709 return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
716 interpret_clear(struct cf_item *item, void *ptr)
718 if (item->cls == CC_LIST) {
719 cf_journal_block(ptr, sizeof(struct clist));
721 } else if (item->cls == CC_DYNAMIC) {
722 cf_journal_block(ptr, sizeof(void *));
723 * (void**) ptr = NULL;
725 return "The item is not a list or a dynamic array";
730 cmp_items(void *i1, void *i2, struct cf_item *item)
732 ASSERT(item->cls == CC_STATIC);
733 i1 += (addr_int_t) item->ptr;
734 i2 += (addr_int_t) item->ptr;
735 if (item->u.type == CT_STRING)
736 return strcmp(* (byte**) i1, * (byte**) i2);
737 else // all numeric types
738 return memcmp(i1, i2, parsers[item->u.type].size);
742 find_list_node(struct clist *list, void *query, struct cf_section *sec, u32 mask)
748 for (uns i=0; i<32; i++)
750 if (cmp_items(n, query, sec->cfg+i))
762 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
764 uns nr = sec->flags & SEC_FLAG_NUMBER;
765 if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
767 uns i = item - sec->cfg;
769 return "Cannot select list nodes by this attribute";
770 if (sec->cfg[i].cls != CC_STATIC)
771 return "Selection can only be done based on basic attributes";
777 #define MAX_STACK_SIZE 100
778 static struct item_stack {
779 struct cf_section *sec; // nested section
780 void *base_ptr; // because original pointers are often relative
781 enum cf_operation op; // it is performed when a closing brace is encountered
782 void *list; // list the operations should be done on
783 u32 mask; // bit array of selectors searching in a list
784 struct cf_item *item; // cf_item of the list
785 } stack[MAX_STACK_SIZE];
789 opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
791 if (level >= MAX_STACK_SIZE-1)
792 return "Too many nested sections";
793 stack[++level] = (struct item_stack) {
801 if (!item) // unknown is ignored; we just need to trace recursion
803 stack[level].sec = item->u.sec;
804 if (item->cls == CC_SECTION)
806 stack[level].base_ptr = ptr;
807 stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
809 else if (item->cls == CC_LIST)
811 stack[level].base_ptr = cf_malloc(item->u.sec->size);
812 cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
813 stack[level].list = ptr;
814 stack[level].item = item;
815 stack[level].op |= (op & OP_MASK) < OP_REMOVE ? OP_2ND : OP_1ST;
818 return "Opening brace can only be used on sections and lists";
823 closing_brace(struct item_stack *st, enum cf_operation op, int number, byte **pars)
825 if (st->op == OP_CLOSE) // top-level
826 return "Unmatched } parenthesis";
827 if (!st->sec) { // dummy run on unknown section
832 enum cf_operation pure_op = st->op & OP_MASK;
835 st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
837 return "Cannot find a node matching the query";
838 if (pure_op != OP_REMOVE)
840 if (pure_op == OP_EDIT)
841 st->base_ptr = st->list;
842 else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
843 cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
846 if (op & OP_OPEN) { // stay at the same recursion level
847 st->op = (st->op | OP_2ND) & ~OP_1ST;
850 int taken; // parse parameters on 1 line immediately
851 TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
854 // and fall-thru to the 2nd phase
857 add_to_list(st->list, st->base_ptr, pure_op);
860 return "No parameters expected after the }";
861 else if (op & OP_OPEN)
862 return "No { is expected";
868 interpret_line(byte *name, enum cf_operation op, int number, byte **pars)
871 if ((op & OP_MASK) == OP_CLOSE)
872 return closing_brace(stack+level, op, number, pars);
873 void *ptr = stack[level].base_ptr;
874 struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
877 if (stack[level].op & OP_1ST)
878 TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
879 if (op & OP_OPEN) // the operation will be performed after the closing brace
880 return opening_brace(item, ptr, op);
881 if (!item) // ignored item in an unknown section
885 int taken; // process as many parameters as possible
887 taken = 0, msg = interpret_clear(item, ptr);
888 else if (op == OP_SET)
889 msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
890 else if (item->cls == CC_DYNAMIC)
891 msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
892 else if (item->cls == CC_LIST)
893 msg = interpret_add_list(item, number, pars, &taken, ptr, op);
895 return cf_printf("Operation %s not supported on attribute %s", op_names[op], name);
899 return cf_printf("Too many parameters: %d>%d", number, taken);
905 cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
911 msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
915 msg = interpret_clear(item, item->ptr);
919 if (item->cls == CC_DYNAMIC)
920 msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
921 else if (item->cls == CC_LIST)
922 msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
924 return "The attribute class does not support append/prepend";
927 return "Unsupported operation";
932 return "Too many parameters";
941 stack[0] = (struct item_stack) {
955 log(L_ERROR, "Unterminated block");
958 if (commit_section("top-level", §ions, NULL))
963 /* Text file parser */
965 static byte *name_parse_fb;
966 static struct fastbuf *parse_fb;
969 #define MAX_LINE 4096
970 static byte line_buf[MAX_LINE];
971 static byte *line = line_buf;
973 #include "lib/bbuf.h"
974 static bb_t copy_buf;
977 #define GBUF_TYPE uns
978 #define GBUF_PREFIX(x) split_##x
979 #include "lib/gbuf.h"
980 static split_t word_buf;
982 static uns ends_by_brace; // the line is ended by "{"
987 if (!bgets(parse_fb, line_buf, MAX_LINE))
991 while (Cblank(*line))
997 append(byte *start, byte *end)
999 uns len = end - start;
1000 bb_grow(©_buf, copied + len + 1);
1001 memcpy(copy_buf.ptr + copied, start, len);
1003 copy_buf.ptr[copied-1] = 0;
1006 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
1007 // these characters separate words like blanks
1010 get_word(uns is_command_name)
1012 if (*line == '\'') {
1016 while (*line && *line != '\'')
1018 append(start, line);
1021 copy_buf.ptr[copied-1] = '\n';
1023 return "Unterminated apostrophe word at the end";
1027 } else if (*line == '"') {
1029 uns start_copy = copied;
1034 if (*line == '"' && !escape)
1036 else if (*line == '\\')
1042 append(start, line);
1046 copy_buf.ptr[copied-1] = '\n';
1047 else // merge two lines
1050 return "Unterminated quoted word at the end";
1054 for (byte *c=copy_buf.ptr+start_copy; *c; c++)
1057 return "Formating sequences are not allowed";
1061 byte *tmp = cf_printf(copy_buf.ptr + start_copy);
1062 uns l = strlen(tmp);
1063 bb_grow(©_buf, start_copy + l + 1);
1064 strcpy(copy_buf.ptr + start_copy, tmp);
1065 copied = start_copy + l + 1;
1068 // promised that *line is non-null and non-blank
1070 while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
1071 && (*line != '=' || !is_command_name))
1073 if (*line == '=') { // nice for setting from a command-line
1075 return "Assignment without a variable";
1078 if (line == start) // already the first char is control
1080 append(start, line);
1082 while (Cblank(*line))
1088 get_token(uns is_command_name, byte **msg)
1092 if (!*line || *line == '#') {
1093 if (!is_command_name || !get_line())
1095 } else if (*line == ';') {
1097 if (!is_command_name || *msg)
1099 } else if (*line == '\\' && !line[1]) {
1101 *msg = "Last line ends by a backslash";
1104 if (!*line || *line == '#')
1105 log(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb, line_num);
1107 split_grow(&word_buf, words+1);
1109 word_buf.ptr[words++] = copied;
1110 *msg = get_word(is_command_name);
1111 return *msg ? NULL : copy_buf.ptr + start;
1119 words = copied = ends_by_brace = 0;
1120 byte *msg, *start_word;
1121 if (!(start_word = get_token(1, &msg)))
1123 if (*start_word == '{') // only one opening brace
1124 return "Unexpected opening brace";
1125 while (*line != '}') // stays for the next time
1127 if (!(start_word = get_token(0, &msg)))
1129 if (*start_word == '{') {
1130 words--; // discard the brace
1138 /* Parsing multiple files */
1140 static struct fastbuf *
1141 bopen_safe(byte *name)
1143 int fd = sh_open(name, O_RDONLY);
1145 log(L_ERROR, "Cannot open %s", name);
1148 return bopen(name, O_RDONLY, 1<<14);
1152 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1155 name_parse_fb = name_fb;
1162 msg = split_command();
1167 byte *name = copy_buf.ptr + word_buf.ptr[0];
1168 byte *pars[words-1];
1169 for (uns i=1; i<words; i++)
1170 pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1171 if (!strcasecmp(name, "include"))
1174 msg = "Expecting one filename";
1178 msg = "Too many nested files";
1181 struct fastbuf *new_fb = bopen_safe(pars[0]);
1183 msg = "Cannot open file";
1187 msg = parse_fastbuf(pars[0], new_fb, depth+1);
1194 enum cf_operation op;
1195 byte *c = strchr(name, ':');
1197 op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1200 switch (Clocase(*c)) {
1201 case 's': op = OP_SET; break;
1202 case 'c': op = OP_CLEAR; break;
1203 case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1204 case 'p': op = OP_PREPEND; break;
1205 case 'r': op = OP_REMOVE; break;
1206 case 'e': op = OP_EDIT; break;
1207 case 'b': op = OP_BEFORE; break;
1208 default: op = OP_SET; break;
1210 if (strcasecmp(c, op_names[op])) {
1211 msg = cf_printf("Unknown operation %s", c);
1217 msg = interpret_line(name, op, words-1, pars);
1222 log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1223 return "included from here";
1226 #ifndef DEFAULT_CONFIG
1227 #define DEFAULT_CONFIG NULL
1229 byte *cf_def_file = DEFAULT_CONFIG;
1232 load_file(byte *file)
1235 struct fastbuf *fb = bopen_safe(file);
1238 byte *msg = parse_fastbuf(file, fb, 0);
1240 int err = !!msg || done_stack();
1247 load_string(byte *string)
1251 fbbuf_init_read(&fb, string, strlen(string), 0);
1252 byte *msg = parse_fastbuf("memory string", &fb, 0);
1253 return !!msg || done_stack();
1256 /* Command-line parser */
1262 if (cf_load(cf_def_file))
1263 die("Cannot load default config %s", cf_def_file);
1267 cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
1269 static int other_options = 0;
1271 int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
1272 if (res == 'S' || res == 'C')
1275 die("The -S and -C options must precede all other arguments");
1279 die("Cannot set %s", optarg);
1281 if (cf_load(optarg))
1282 die("Cannot load %s", optarg);
1285 /* unhandled option or end of options */
1296 spaces(struct fastbuf *fb, uns nr)
1298 for (uns i=0; i<nr; i++)
1303 dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type)
1306 case CT_INT: bprintf(fb, "%d ", *(uns*)ptr); break;
1307 case CT_U64: bprintf(fb, "%llu ", *(u64*)ptr); break;
1308 case CT_DOUBLE: bprintf(fb, "%lg ", *(double*)ptr); break;
1309 case CT_IP: bprintf(fb, "%08x ", *(uns*)ptr); break;
1310 case CT_STRING: bprintf(fb, "'%s' ", *(byte**)ptr); break;
1314 static void dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr);
1317 dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
1319 ptr += (addr_int_t) item->ptr;
1320 enum cf_type type = item->u.type;
1323 bprintf(fb, "%s: c%d #%d ", item->name, item->cls, item->number);
1324 if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC)
1325 bprintf(fb, "t%d ", type);
1326 if (item->cls == CC_STATIC) {
1327 for (i=0; i<item->number; i++)
1328 dump_basic(fb, ptr + i * parsers[type].size, type);
1329 } else if (item->cls == CC_DYNAMIC) {
1330 ptr = * (void**) ptr;
1332 int real_nr = * (int*) (ptr - parsers[type].size);
1333 bprintf(fb, "##%d ", real_nr);
1334 for (i=0; i<real_nr; i++)
1335 dump_basic(fb, ptr + i * parsers[type].size, type);
1337 bprintf(fb, "NULL ");
1340 if (item->cls == CC_SECTION)
1341 dump_section(fb, item->u.sec, level+1, ptr);
1342 else if (item->cls == CC_LIST) {
1345 CLIST_WALK(n, * (clist*) ptr) {
1346 spaces(fb, level+1);
1347 bprintf(fb, "item %d\n", ++idx);
1348 dump_section(fb, item->u.sec, level+2, n);
1354 dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr)
1357 bprintf(fb, "S%d F%x:\n", sec->size, sec->flags);
1358 for (struct cf_item *item=sec->cfg; item->cls; item++)
1359 dump_item(fb, item, level, ptr);
1363 cf_dump_sections(struct fastbuf *fb)
1365 dump_section(fb, §ions, 0, NULL);