Import release 0.1.5
[secnet] / conffile.c
CommitLineData
2fe58dfd
SE
1/*
2 * $Log$
3 */
4
5/* conffile.c - process the configuration file */
6
7/* #define DUMP_PARSE_TREE */
8
8689b3a9 9#include "secnet.h"
2fe58dfd 10#include <stdio.h>
2fe58dfd 11#include <string.h>
2fe58dfd
SE
12#include "conffile.h"
13#include "conffile_internal.h"
14#include "util.h"
15#include "modules.h"
16
17static struct cloc no_loc={"none",0};
18
19struct atomlist {
20 struct atomlist *next;
21 atom_t a;
22};
23
24struct entry {
25 struct entry *next;
26 atom_t key;
27 list_t *val;
28};
29
30struct searchlist {
31 struct dict *d;
32 struct searchlist *next;
33};
34
35struct dict {
36 struct dict *parent;
37 struct searchlist *search;
38 struct entry *entries;
39 uint32_t size;
40};
41
42static struct atomlist *atoms=NULL;
43
44static void process_alist(dict_t *context, struct p_node *c);
45static list_t *process_invocation(dict_t *context, struct p_node *i);
46
47static list_t *dict_ilookup_primitive(dict_t *dict, atom_t key)
48{
49 struct entry *i;
50 for (i=dict->entries; i; i=i->next) {
51 if (key==i->key) return i->val;
52 }
53 return NULL;
54}
55
56static list_t *dict_ilookup(dict_t *dict, atom_t key)
57{
58 dict_t *d;
59 list_t *v;
60
61 v=dict_ilookup_primitive(dict, key);
62 if (v) return v;
63 /* Check dictionaries in search path */
64/* XXX */
65 /* Check lexical parents */
66 for (d=dict; d; d=d->parent) {
67 v=dict_ilookup_primitive(d, key);
68 if (v) return v;
69 }
70 return NULL;
71}
72
73static void dict_iadd(dict_t *dict, atom_t key, list_t *val)
74{
75 struct entry *e;
76 /* XXX May want to permit redefinition of keys in the future */
77 /* (although it could be very confusing) */
78 if (dict_ilookup_primitive(dict, key)) {
79 fatal("duplicate key \"%s\" in dictionary\n",key);
80 }
81 e=safe_malloc(sizeof(*e),"dict_add");
82 e->next=dict->entries;
83 e->key=key;
84 e->val=val;
85 dict->entries=e;
86 dict->size++;
87}
88
89/***** Functions beyond this point are private to the config system *****/
90
91static dict_t *dict_new(dict_t *parent)
92{
93 dict_t *d;
94
95 d=safe_malloc(sizeof(*d),"dict_new");
96 d->parent=parent;
97 d->search=NULL;
98 d->entries=NULL;
99 d->size=0;
100 return d;
101}
102
103static struct p_node *node_copy(struct p_node *n)
104{
105 struct p_node *r;
106 r=safe_malloc(sizeof(*r),"node_copy");
107 *r=*n;
108 return r;
109}
110
111static struct p_node *list_reverse(struct p_node *list)
112{
113 struct p_node *rl=NULL, *i, *n;
114
115 for (i=list; i; i=i->r) {
116 n=node_copy(i);
117 n->r=rl;
118 rl=n;
119 }
120 return rl;
121}
122
123/* Since we use left-recursion in the parser for efficiency, sequences
124 end up "backwards" in the parse tree. Rather than have complicated
125 code for, eg. processing assignments in the right order, we reverse
126 these sequences here. */
127static void ptree_mangle(struct p_node *t)
128{
129 if (!t) return;
130 ptree_mangle(t->l);
131 ptree_mangle(t->r);
132 switch (t->type) {
133 case T_DICT:
134 /* ASSERT !t->l || t->l->type==T_ALIST */
135 /* ASSERT !t->r || t->r->type==T_LISTITEM */
136 t->l=list_reverse(t->l);
137 t->r=list_reverse(t->r);
138 break;
139 case T_ASSIGNMENT:
140 /* ASSERT t->l->type==T_KEY */
141 /* ASSERT t->r->type==T_LISTITEM */
142 t->r=list_reverse(t->r);
143 break;
144 case T_ABSPATH:
145 case T_RELPATH:
146 /* ASSERT t->l==NULL */
147 /* ASSERT t->r->type==T_PATHELEM */
148 t->r=list_reverse(t->r);
149 break;
150 case T_EXEC:
151 /* ASSERT t->l */
152 /* ASSERT t->r->type==T_LISTITEM */
153 t->r=list_reverse(t->r);
154 break;
155 }
156}
157
158#ifdef DUMP_PARSE_TREE
159/* Convert a node type to a string, for parse tree dump */
160static string_t ntype(uint32_t type)
161{
162 switch(type) {
163 case T_STRING: return "T_STRING";
164 case T_NUMBER: return "T_NUMBER";
165 case T_KEY: return "T_KEY";
166 case T_ASSIGNMENT: return "T_ASSIGNMENT";
167 case T_LISTITEM: return "T_LISTITEM";
168 case T_EXEC: return "T_EXEC";
169 case T_PATHELEM: return "T_PATHELEM";
170 case T_ABSPATH: return "T_ABSPATH";
171 case T_RELPATH: return "T_RELPATH";
172 case T_DICT: return "T_DICT";
173 case T_ALIST: return "T_ALIST";
174 case T_ERROR: return "T_ERROR";
175 }
176 return "**unknown**";
177}
178
179static void ptree_indent(uint32_t amount)
180{
181 uint32_t i;
182 for (i=0; i<amount; i++) printf(" . ");
183}
184
185static void ptree_dump(struct p_node *n, uint32_t d)
186{
187 if (!n) {
188 printf("NULL\n");
189 return;
190 }
191
192 if (n->type<10) {
193 switch(n->type) {
194 case T_STRING: printf("T_STRING: \"%s\" (%s line %d)\n",
195 n->data.string,n->loc.file,n->loc.line); break;
196 case T_NUMBER: printf("T_NUMBER: %d (%s line %d)\n",
197 n->data.number, n->loc.file,n->loc.line); break;
198 case T_KEY: printf("T_KEY: %s (%s line %d)\n",
199 n->data.key, n->loc.file,n->loc.line); break;
200 default: printf("**unknown primitive type**\n"); break;
201 }
202 } else {
203 printf("%s: (%s line %d)\n",ntype(n->type),n->loc.file,n->loc.line);
204 ptree_indent(d);
205 printf(" |-"); ptree_dump(n->l, d+1);
206 ptree_indent(d);
207 printf(" +-"); ptree_dump(n->r, d+1);
208 }
209}
210
211#endif /* DUMP_PARSE_TREE */
212
213static dict_t *dict_find_root(dict_t *d)
214{
215 dict_t *i;
216
217 for (i=d; i->parent; i=i->parent);
218 return i;
219}
220
221static list_t *dict_lookup_path(dict_t *context, struct p_node *p)
222{
223 dict_t *i;
224 list_t *l;
225
226 /* ASSERT p->type==T_PATHELEM */
227 /* ASSERT p->l->type==T_KEY */
228 l=dict_ilookup(context, p->l->data.key);
229 if (!l) {
230 cfgfatal(p->loc,"conffile","can't find key %s\n",
231 p->l->data.key);
232 }
233
234 while (p->r) {
235 if (l->item->type != t_dict) {
236 cfgfatal(p->loc,"conffile","path element \"%s\" "
237 "is not a dictionary\n",p->l->data.key);
238 }
239 i=l->item->data.dict; /* First thing in list */
240
241 p=p->r;
242 l=dict_ilookup_primitive(i, p->l->data.key);
243 if (!l) {
244 cfgfatal(p->loc,"conffile","can't find key %s\n",
245 p->l->data.key);
246 }
247 }
248 return l;
249}
250
251static item_t *new_item(enum types type, struct cloc loc)
252{
253 item_t *i;
254
255 i=safe_malloc(sizeof(*i),"new_item");
256 i->type=type;
257 i->loc=loc;
258 return i;
259}
260
261static list_t *process_item(dict_t *context, struct p_node *i)
262{
263 item_t *item=NULL;
264
265 switch (i->type) {
266 case T_STRING:
267 item=new_item(t_string, i->loc);
268 item->data.string=i->data.string; /* XXX maybe strcpy */
269 break;
270 case T_NUMBER:
271 item=new_item(t_number, i->loc);
272 item->data.number=i->data.number;
273 break;
274 case T_ABSPATH:
275 context=dict_find_root(context);
276 /* falls through */
277 case T_RELPATH:
278 return dict_lookup_path(context, i->r);
279 /* returns immediately */
280 break;
281 case T_DICT:
282 item=new_item(t_dict, i->loc);
283 item->data.dict=dict_new(context);
284/* XXX dict_add_searchpath(context,process_ilist(context, i->r)); */
285 process_alist(item->data.dict, i->l);
286 break;
287 case T_EXEC:
288 return process_invocation(context, i);
289 /* returns immediately */
290 break;
291 default:
292#ifdef DUMP_PARSE_TREE
293 ptree_dump(i,0);
294 fatal("process_item: invalid node type for a list item (%s)\n",
295 ntype(i->type));
296#else
297 fatal("process_item: list item has invalid node type %d - recompile "
298 "with DUMP_PARSE_TREE defined in conffile.c for more "
299 "detailed debug output",i->type);
300#endif /* DUMP_PARSE_TREE */
301 break;
302 }
303 return list_append(NULL,item);
304}
305
306static list_t *process_ilist(dict_t *context, struct p_node *l)
307{
308 struct p_node *i;
309 list_t *r;
310
311 /* ASSERT l->type==T_LISTITEM */
312
313 r=list_new();
314
315 for (i=l; i; i=i->r) {
316 r=list_append_list(r,process_item(context,i->l));
317 }
318 return r;
319}
320
321static list_t *process_invocation(dict_t *context, struct p_node *i)
322{
323 list_t *cll;
324 item_t *cl;
325 list_t *args;
326
327 /* ASSERT i->type==T_EXEC */
328 /* ASSERT i->r->type==T_LISTITEM */
329 /* XXX it might be null too */
330 cll=process_item(context,i->l);
331 cl=cll->item;
332 if (cl->type != t_closure) {
333 cfgfatal(i->l->loc,"conffile","only closures can be invoked\n");
334 }
335 args=process_ilist(context, i->r);
336 return cl->data.closure->apply(cl->data.closure, i->loc, context, args);
337}
338
339static void process_alist(dict_t *context, struct p_node *c)
340{
341 struct p_node *i;
342 atom_t k;
343 list_t *l;
344
345 if (!c) return; /* NULL assignment lists are valid (empty dictionary) */
346
347 /* ASSERT c->type==T_ALIST */
348 if (c->type!=T_ALIST) {
349 fatal("invalid node type in assignment list\n");
350 }
351
352 for (i=c; i; i=i->r) {
353 /* ASSERT i->l && i->l->type==T_ASSIGNMENT */
354 /* ASSERT i->l->l->type==T_KEY */
355 /* ASSERT i->l->r->type==T_LISTITEM */
356 k=i->l->l->data.key;
357 l=process_ilist(context, i->l->r);
358 dict_iadd(context, k, l);
359 }
360}
361
362/* Take a list of items; turn any dictionaries in this list into lists */
363static list_t *makelist(closure_t *self, struct cloc loc,
364 dict_t *context, list_t *args)
365{
366 list_t *r=NULL, *i;
367 struct entry *e;
368
369 for (i=args; i; i=i->next) {
370 if (i->item->type==t_dict) {
371 /* Convert */
372 for (e=i->item->data.dict->entries; e; e=e->next) {
373 r=list_append_list(r, e->val);
374 }
375 } else {
376 r=list_append_list(r, list_append(NULL,i->item));
377 }
378 }
379 return r;
380}
381
9d3a4132
SE
382/* Take a list consisting of a closure and some other things. Apply the
383 closure to the other things, and return the resulting list */
384static list_t *map(closure_t *self, struct cloc loc, dict_t *context,
385 list_t *args)
386{
387 list_t *r=NULL, *al;
388 item_t *ci;
389 closure_t *cl;
390 list_t se;
391
392 ci=list_elem(args,0);
393 if (ci && ci->type==t_closure) {
394 cl=ci->data.closure;
395 if (!cl->apply) {
396 cfgfatal(loc,"map","closure cannot be applied\n");
397 }
398 for (al=args->next; al; al=al->next) {
399 /* Construct a single-element list */
400 se.next=NULL;
401 se.item=al->item;
402 /* Invoke the closure, append its result to the output */
403 r=list_append_list(r,cl->apply(cl,loc,context,&se));
404 }
405 } else {
406 cfgfatal(loc,"map","you must supply a closure as the "
407 "first argument\n");
408 }
409 return r;
410}
411
2fe58dfd
SE
412/* Read a file and turn it into a string */
413static list_t *readfile(closure_t *self, struct cloc loc,
414 dict_t *context, list_t *args)
415{
416 FILE *f;
417 string_t filename;
418 long length;
419 item_t *r;
420
421 r=list_elem(args,0);
422 if (!r) {
423 cfgfatal(loc,"readfile","you must supply a filename\n");
424 }
425 if (r->type!=t_string) {
426 cfgfatal(loc,"readfile","filename must be a string\n");
427 }
428 filename=r->data.string;
429 f=fopen(filename,"rb");
430 if (!f) {
431 fatal_perror("readfile (%s:%d): cannot open file \"%s\"",
432 loc.file,loc.line, filename);
433 }
434 if (fseek(f, 0, SEEK_END)!=0) {
435 fatal_perror("readfile (%s:%d): fseek(SEEK_END)",loc.file,loc.line);
436 }
437 length=ftell(f);
438 if (length<0) {
439 fatal_perror("readfile (%s:%d): ftell()",loc.file,loc.line);
440 }
441 if (fseek(f, 0, SEEK_SET)!=0) {
442 fatal_perror("readfile (%s:%d): fseek(SEEK_SET)",loc.file,loc.line);
443 }
444 r=new_item(t_string,loc);
445 r->data.string=safe_malloc(length+1,"readfile");
446 if (fread(r->data.string,length,1,f)!=1) {
447 fatal("readfile (%s:%d): fread: could not read all of file\n",
448 loc.file,loc.line);
449 }
450 r->data.string[length]=0;
451 if (fclose(f)!=0) {
452 fatal_perror("readfile (%s:%d): fclose",loc.file,loc.line);
453 }
454 return list_append(NULL,r);
455}
456
457static dict_t *process_config(struct p_node *c)
458{
459 dict_t *root;
460 dict_t *context;
461 item_t *i;
462 list_t *false;
463 list_t *true;
464
465 root=dict_new(NULL);
466 context=root;
467
468 /* Predefined keys for boolean values */
469 i=new_item(t_bool,no_loc);
470 i->data.bool=False;
471 false=list_append(NULL,i);
472 i=new_item(t_bool,no_loc);
473 i->data.bool=True;
474 true=list_append(NULL,i);
475 dict_add(root,"false",false);
476 dict_add(root,"False",false);
477 dict_add(root,"FALSE",false);
478 dict_add(root,"no",false);
479 dict_add(root,"No",false);
480 dict_add(root,"NO",false);
481 dict_add(root,"true",true);
482 dict_add(root,"True",true);
483 dict_add(root,"TRUE",true);
484 dict_add(root,"yes",true);
485 dict_add(root,"Yes",true);
486 dict_add(root,"YES",true);
487
488 add_closure(root,"makelist",makelist);
489 add_closure(root,"readfile",readfile);
9d3a4132 490 add_closure(root,"map",map);
2fe58dfd
SE
491
492 init_builtin_modules(root);
493
494 process_alist(context, c);
495
496 return root;
497}
498
499/***** Externally accessible functions */
500
501atom_t intern(string_t s)
502{
503 struct atomlist *i;
504
505 for (i=atoms; i; i=i->next) {
506 if (strcmp(i->a, s)==0) break;
507 }
508
509 if (!i) {
510 /* Did't find it; create a new one */
511 i=safe_malloc(sizeof(*i),"intern: alloc list entry");
512 i->a=safe_strdup(s,"intern: alloc string");
513 i->next=atoms;
514 atoms=i;
515 }
516 return i->a;
517}
518
519list_t *dict_lookup(dict_t *dict, string_t key)
520{
521 return dict_ilookup(dict, intern(key));
522}
523
524list_t *dict_lookup_primitive(dict_t *dict, string_t key)
525{
526 return dict_ilookup_primitive(dict, intern(key));
527}
528
529void dict_add(dict_t *dict, string_t key, list_t *val)
530{
531 dict_iadd(dict,intern(key),val);
532}
533
534string_t *dict_keys(dict_t *dict)
535{
536 atom_t *r, *j;
537 struct entry *i;
538 r=safe_malloc(sizeof(*r)*(dict->size+1),"dict_keys");
539 for (i=dict->entries, j=r; i; i=i->next, j++) {
540 *j=i->key;
541 }
542 *j=NULL;
543 return r;
544}
545
546
547/* List-related functions */
548
549list_t *list_new(void)
550{
551 return NULL;
552}
553
b2a56f7c
SE
554uint32_t list_length(list_t *a)
555{
556 uint32_t l=0;
557 list_t *i;
558 for (i=a; i; i=i->next) l++;
559 return l;
560}
561
3454dce4
SE
562list_t *list_copy(list_t *a)
563{
564 list_t *r, *i, *b, *l;
565
566 if (!a) return NULL;
567 l=NULL;
568 r=NULL;
569 for (i=a; i; i=i->next) {
570 b=safe_malloc(sizeof(*b),"list_copy");
571 if (l) l->next=b; else r=b;
572 l=b;
573 b->item=i->item;
574 b->next=NULL;
575 }
576 return r;
577}
578
2fe58dfd
SE
579list_t *list_append_list(list_t *a, list_t *b)
580{
581 list_t *i;
582
3454dce4 583 b=list_copy(b);
2fe58dfd
SE
584 if (!a) return b;
585 for (i=a; i->next; i=i->next);
586 i->next=b;
587 return a;
588}
589
590list_t *list_append(list_t *list, item_t *item)
591{
592 list_t *l;
593
594 l=safe_malloc(sizeof(*l),"list_append");
595 l->item=item;
596 l->next=NULL;
597
598 return list_append_list(list,l);
599}
600
601item_t *list_elem(list_t *l, uint32_t index)
602{
603 if (!l) return NULL;
604 if (index==0) return l->item;
605 return list_elem(l->next, index-1);
606}
607
608list_t *new_closure(closure_t *cl)
609{
610 item_t *i;
611
612 i=new_item(t_closure,no_loc);
613 i->data.closure=cl;
614 return list_append(NULL,i);
615}
616
617void add_closure(dict_t *dict, string_t name, apply_fn apply)
618{
619 closure_t *c;
620 c=safe_malloc(sizeof(*c),"add_closure");
621 c->description=name;
622 c->apply=apply;
623 c->interface=NULL;
624
625 dict_add(dict,name,new_closure(c));
626}
627
628void *find_cl_if(dict_t *dict, string_t name, uint32_t type,
629 bool_t fail_if_invalid, string_t desc, struct cloc loc)
630{
631 list_t *l;
632 item_t *i;
633 closure_t *cl;
634
635 l=dict_lookup(dict,name);
636 if (!l) {
637 if (!fail_if_invalid) return NULL;
638 cfgfatal(loc,desc,"closure \"%s\" not found\n",name);
639 }
640 i=list_elem(l,0);
641 if (i->type!=t_closure) {
642 if (!fail_if_invalid) return NULL;
643 cfgfatal(loc,desc,"\"%s\" must be a closure\n",name);
644 }
645 cl=i->data.closure;
646 if (cl->type!=type) {
647 if (!fail_if_invalid) return NULL;
648 cfgfatal(loc,desc,"\"%s\" is the wrong type of closure\n",name);
649 }
650 return cl->interface;
651}
652
653/* Convenience functions for modules reading configuration dictionaries */
654item_t *dict_find_item(dict_t *dict, string_t key, bool_t required,
655 string_t desc, struct cloc loc)
656{
657 list_t *l;
658 item_t *i;
659
660 l=dict_lookup(dict,key);
661 if (!l) {
662 if (!required) return NULL;
663 cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key);
664 }
665 i=list_elem(l,0);
666 return i;
667}
668
669string_t dict_read_string(dict_t *dict, string_t key, bool_t required,
670 string_t desc, struct cloc loc)
671{
672 item_t *i;
673 string_t r;
674
675 i=dict_find_item(dict,key,required,desc,loc);
676 if (!i) return NULL;
677 if (i->type!=t_string) {
678 cfgfatal(loc,desc,"\"%s\" must be a string\n",key);
679 }
680 r=i->data.string;
681 return r;
682}
683
684uint32_t dict_read_number(dict_t *dict, string_t key, bool_t required,
685 string_t desc, struct cloc loc, uint32_t def)
686{
687 item_t *i;
688 uint32_t r;
689
690 i=dict_find_item(dict,key,required,desc,loc);
691 if (!i) return def;
692 if (i->type!=t_number) {
693 cfgfatal(loc,desc,"\"%s\" must be a number\n",key);
694 }
695 r=i->data.number;
696 return r;
697}
698
699bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required,
700 string_t desc, struct cloc loc, bool_t def)
701{
702 item_t *i;
703 bool_t r;
704
705 i=dict_find_item(dict,key,required,desc,loc);
706 if (!i) return def;
707 if (i->type!=t_bool) {
708 cfgfatal(loc,desc,"\"%s\" must be a boolean\n",key);
709 }
710 r=i->data.bool;
711 return r;
712}
713
714static struct subnet string_to_subnet(item_t *i, string_t desc)
715{
716 struct subnet s;
717 uint32_t a, b, c, d, n;
718 uint32_t match;
719
720 /* i is not guaranteed to be a string */
721 if (i->type!=t_string) {
722 cfgfatal(i->loc,desc,"expecting a string (subnet specification)\n");
723 }
724
725 /* We expect strings of the form "a.b.c.d[/n]", i.e. the dots are
726 NOT optional. The subnet mask is optional; if missing it is assumed
727 to be /32. */
728 match=sscanf(i->data.string,"%u.%u.%u.%u/%u", &a, &b, &c, &d, &n);
729 if (match<4) {
730 cfgfatal(i->loc,desc,"\"%s\" is not a valid "
731 "subnet specification\n",i->data.string);
732 }
733 if (match<5) {
734 n=32;
735 }
736 if (a>255 || b>255 || c>255 || d>255 || n>32) {
737 cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
738 }
739 s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
740 s.mask=(~0UL << (32-n));
70dc107b 741 s.len=n;
2fe58dfd
SE
742 if (s.prefix & ~s.mask) {
743 cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
744 "in mask\n",i->data.string);
745 }
746 return s;
747}
748
749uint32_t string_to_ipaddr(item_t *i, string_t desc)
750{
751 uint32_t a, b, c, d;
752 uint32_t match;
753
754 /* i is not guaranteed to be a string */
755 if (i->type!=t_string) {
756 cfgfatal(i->loc,desc,"expecting a string (IP address)\n");
757 }
758
759 match=sscanf(i->data.string,"%u.%u.%u.%u", &a, &b, &c, &d);
760 if (match<4) {
761 cfgfatal(i->loc,desc,"\"%s\" is not a valid "
762 "IP address\n",i->data.string);
763 }
764 if (a>255 || b>255 || c>255 || d>255) {
765 cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
766 }
767 return (a<<24)|(b<<16)|(c<<8)|(d);
768}
769
770void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required,
771 string_t desc, struct cloc loc,
772 struct subnet_list *sl)
773{
774 list_t *l, *li;
775 item_t *i;
776 uint32_t e=0;
777
778 sl->entries=0;
779 sl->list=NULL;
780 l=dict_lookup(dict, key);
781 if (!l) {
782 if (!required) return;
783 cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key);
784 }
785 /* Count the items in the list */
786 for (li=l; li; li=li->next) e++;
787 if (e==0) return;
788 sl->entries=e;
789 sl->list=safe_malloc(sizeof(struct subnet)*e, "dict_read_subnet_list");
790 e=0;
791 /* Fill in the list */
792 for (li=l; li; li=li->next) {
793 i=li->item;
794 if (i->type!=t_string) {
795 cfgfatal(loc,desc,"parameter \"%s\": all elements must "
796 "be strings\n",key);
797 }
798 sl->list[e++]=string_to_subnet(i,desc);
799 }
800}
801
b2a56f7c
SE
802uint32_t string_to_word(string_t s, struct cloc loc,
803 struct flagstr *f, string_t desc)
804{
805 struct flagstr *j;
806 for (j=f; j->name; j++)
807 if (strcmp(s,j->name)==0)
808 return j->value;
809 cfgfatal(loc,desc,"option \"%s\" not known\n",s);
810 return 0;
811}
812
9d3a4132
SE
813uint32_t string_list_to_word(list_t *l, struct flagstr *f, string_t desc)
814{
815 list_t *i;
816 uint32_t r=0;
817 struct flagstr *j;
818
819 for (i=l; i; i=i->next) {
820 if (i->item->type!=t_string) {
821 cfgfatal(i->item->loc,desc,"all elements of list must be "
822 "strings\n");
823 }
824 for (j=f; j->name; j++)
b2a56f7c 825 r|=string_to_word(i->item->data.string,i->item->loc,f,desc);
9d3a4132
SE
826 }
827 return r;
828}
829
2fe58dfd
SE
830dict_t *read_conffile(char *name)
831{
832 FILE *conffile;
833 struct p_node *config;
834
835 if (strcmp(name,"-")==0) {
836 conffile=stdin;
837 } else {
838 conffile=fopen(name,"r");
839 if (!conffile)
840 fatal_perror("Cannot open configuration file \"%s\"",name);
841 }
842 config_lineno=1;
843 config_file=name;
844 config=parse_conffile(conffile);
845 fclose(conffile);
846
847#ifdef DUMP_PARSE_TREE
848 printf("*** config file parse tree BEFORE MANGLE\n");
849 ptree_dump(config,0);
850#endif /* DUMP_PARSE_TREE */
851 /* The root of the configuration is a T_ALIST, which needs reversing
852 before we mangle because it isn't the child of a T_DICT. */
853 config=list_reverse(config);
854 ptree_mangle(config);
855#ifdef DUMP_PARSE_TREE
856 printf("\n\n*** config file parse tree AFTER MANGLE\n");
857 ptree_dump(config,0);
858#endif /* DUMP_PARSE_TREE */
859 return process_config(config);
860}