chiark / gitweb /
Commit 2.4.5-5 as unpacked
[innduct.git] / innfeed / configfile.y
1 %{
2 /*  $Id: configfile.y 6372 2003-05-31 19:48:28Z rra $
3 **
4 **  A yacc input file for the innfeed config file.
5 **
6 **  Written by James Brister <brister@vix.com>
7 **
8 **  This file contains the heart of the innfeed configuration parser, written
9 **  in yacc.  It uses an external lexer generated by flex.
10 */
11
12 #include "innfeed.h"
13 #include "config.h"
14 #include "clibrary.h"
15 #include <errno.h>
16 #include <ctype.h>
17 #include <syslog.h>
18
19 #if defined(_HPUX_SOURCE)
20 # include <alloca.h>
21 #endif
22   
23 #include "inn/messages.h"
24 #include "libinn.h"
25
26 #include "configfile.h"
27 #include "misc.h"
28
29 #define UNKNOWN_SCOPE_TYPE "line %d: unknown scope type: %s"
30 #define SYNTAX_ERROR "line %d: syntax error"
31
32 extern int lineCount ;
33 scope *topScope = NULL ;
34 static scope *currScope = NULL ;
35 char *errbuff = NULL ;
36
37 static void appendName (scope *s, char *p, size_t len) ;
38 static char *valueScopedName (value *v) ;
39 static void freeValue (value *v) ;
40 static char *checkName (scope *s, const char *name) ;
41 static void addValue (scope *s, value *v) ;
42 static char *addScope (scope *s, const char *name, scope *val) ;
43 static void printScope (FILE *fp, scope *s, int indent) ;
44 static void printValue (FILE *fp, value *v, int indent) ;
45 static scope *newScope (const char *type) ;
46 #if 0
47 static int strNCaseCmp (const char *a, const char *b, size_t len) ;
48 #endif 
49
50 int yyerror (const char *s) ;
51 int yywrap (void) ;
52 int yyparse (void) ;
53
54
55 #if 0
56 int isString (scope *s, const char *name, int inherit)
57 {
58   value *v = findValue (s,name,inherit) ;
59
60   return (v != NULL && v->type == stringval) ;
61 }
62 #endif 
63
64 int getBool (scope *s, const char *name, int *rval, int inherit)
65 {
66   value *v = findValue (s,name,inherit) ;
67
68   if (v == NULL)
69     return 0 ;
70   else if (v->type != boolval)
71     return 0 ;
72
73   *rval = v->v.bool_val ;
74   return 1 ;
75 }
76
77
78 int getString (scope *s, const char *name, char **rval, int inherit)
79 {
80   value *v = findValue (s,name,inherit) ;
81
82   if (v == NULL)
83     return 0 ;
84   else if (v->type != stringval)
85     return 0 ;
86
87   *rval = xstrdup (v->v.charp_val) ;
88   return 1 ;
89 }
90
91
92 int getReal (scope *s, const char *name, double *rval, int inherit)
93 {
94   value *v = findValue (s,name,inherit) ;
95
96   if (v == NULL)
97     return 0 ;
98   else if (v->type != realval)
99     return 0 ;
100
101   *rval = v->v.real_val ;
102   return 1 ;
103 }
104
105 int getInteger (scope *s, const char *name, long *rval, int inherit)
106 {
107   value *v = findValue (s,name,inherit) ;
108
109   if (v == NULL)
110     return 0 ;
111   else if (v->type != intval)
112     return 0 ;
113
114   *rval = v->v.int_val ;
115   return 1 ;
116 }
117
118 void freeScopeTree (scope *s)
119 {
120   int i ;
121
122   if (s == NULL)
123     return ;
124
125   if (s->parent == NULL && s->me != NULL) 
126     {                           /* top level scope */
127       free (s->me->name) ;
128       free (s->me) ;
129     }
130   
131   
132   for (i = 0 ; i < s->value_idx ; i++)
133     if (s->values[i] != NULL)
134         freeValue (s->values [i]) ;
135
136   free (s->values) ;
137   free (s->scope_type) ;
138
139   s->parent = NULL ;
140   s->values = NULL ;
141
142   free (s) ;
143 }
144
145
146 char *addInteger (scope *s, const char *name, long val) 
147 {
148   value *v ;
149   char *error ;
150   
151   if ((error = checkName (currScope,name)) != NULL)
152     return error ;
153
154   v = (value *) calloc (1,sizeof (value)) ;
155   v->name = xstrdup (name) ;
156   v->type = intval ;
157   v->v.int_val = val ;
158   
159   addValue (s,v) ;
160
161   return NULL ;
162 }
163
164 char *addChar (scope *s, const char *name, char val) 
165 {
166   value *v ;
167   char *error ;
168   
169   if ((error = checkName (currScope,name)) != NULL)
170     return error ;
171
172   v = (value *) calloc (1,sizeof (value)) ;
173   v->name = xstrdup (name) ;
174   v->type = charval ;
175   v->v.char_val = val ;
176   
177   addValue (s,v) ;
178
179   return NULL ;
180 }
181
182 char *addBoolean (scope *s, const char *name, int val) 
183 {
184   value *v ;
185   char *error ;
186   
187   if ((error = checkName (currScope,name)) != NULL)
188     return error ;
189
190   v = (value *) calloc (1,sizeof (value)) ;
191   v->name = xstrdup (name) ;
192   v->type = boolval ;
193   v->v.bool_val = val ;
194   
195   addValue (s,v) ;
196
197   return NULL ;
198 }
199
200 char *addReal (scope *s, const char *name, double val)
201 {
202   value *v ;
203   char *error ;
204
205   if ((error = checkName (currScope,name)) != NULL)
206     return error ;
207
208   v = (value *) calloc (1,sizeof (value)) ;
209   v->name = xstrdup (name) ;
210   v->type = realval ;
211   v->v.real_val = val ;
212   
213   addValue (s,v) ;
214
215   return NULL ;
216 }
217
218 char *addString (scope *s, const char *name, const char *val)
219 {
220   value *v ;
221   char *error ;
222
223   if ((error = checkName (currScope,name)) != NULL)
224     return error ;
225
226   v = (value *) calloc (1,sizeof (value)) ;
227   v->name = xstrdup (name) ;
228   v->type = stringval ;
229   v->v.charp_val = xstrdup (val) ;
230   
231   addValue (s,v) ;
232
233   return NULL ;
234 }
235
236 value *findValue (scope *s, const char *name, int inherit) 
237 {
238   const char *p ;
239   
240   if (name == NULL || *name == '\0')
241     return NULL ;
242
243   if (*name == ':')
244     return findValue (topScope,name + 1,0) ;
245   else if (s == NULL)
246     return findValue (topScope,name,0) ;
247   else 
248     {
249       int i ;
250       
251       if ((p = strchr (name,':')) == NULL)
252         p = name + strlen (name) ;
253
254       for (i = 0 ; i < s->value_idx ; i++)
255         {
256           if (strlen (s->values[i]->name) == (size_t) (p - name) &&
257               strncmp (s->values[i]->name,name,p - name) == 0)
258             {
259               if (*p == '\0')     /* last segment of name */
260                 return s->values[i] ;
261               else if (s->values[i]->type != scopeval)
262                 errbuff = xstrdup ("Component not a scope") ;
263               else
264                 return findValue (s->values[i]->v.scope_val,p + 1,0) ;
265             }
266         }
267
268       /* not in this scope. Go up if inheriting values and only if no ':'
269          in name */
270       if (inherit && *p == '\0')
271         return findValue (s->parent,name,inherit) ;
272     }
273
274   return NULL ;
275 }
276
277 /* find the scope that name belongs to. If mustExist is true then the name
278    must be a fully scoped name of a value. relative scopes start at s.  */
279 scope *findScope (scope *s, const char *name, int mustExist)
280 {
281   scope *p = NULL ;
282   char *q ;
283   int i ;
284
285   
286   if ((q = strchr (name,':')) == NULL)
287     {
288       if (!mustExist)
289         p = s ;
290       else
291         for (i = 0 ; p == NULL && i < s->value_idx ; i++)
292           if (strcmp (s->values[i]->name,name) == 0)
293             p = s ;
294       
295       return p ;
296     }
297   else if (*name == ':')
298     {
299       while (s->parent != NULL)
300         s = s->parent ;
301
302       return findScope (s,name + 1,mustExist) ;
303     }
304   else
305     {
306       for (i = 0 ; i < s->value_idx ; i++)
307         if (strncmp (s->values[i]->name,name,q - name) == 0)
308           if (s->values[i]->type == scopeval)
309             return findScope (s->values[i]->v.scope_val,q + 1,mustExist) ;
310     }
311
312   return NULL ;
313 }
314
315 /****************************************************************************/
316 /*                                                                          */
317 /****************************************************************************/
318
319
320 static void appendName (scope *s, char *p, size_t len)
321 {
322   if (s == NULL)
323     return ;
324   else
325     {
326       appendName (s->parent,p,len) ;
327       strlcat (p,s->me->name,len) ;
328       strlcat (p,":",len) ;
329     }
330 }
331
332 static char *valueScopedName (value *v)
333 {
334   scope *p = v->myscope ;
335   int len = strlen (v->name) ;
336   char *q ;
337   
338   while (p != NULL)
339     {
340       len += strlen (p->me->name) + 1 ;
341       p = p->parent ;
342     }
343   len++;
344
345   q = xmalloc (len) ;
346   q [0] = '\0' ;
347   appendName (v->myscope,q,len) ;
348   strlcat (q,v->name,len) ;
349
350   return q ;
351 }
352
353 static void freeValue (value *v)
354 {
355   free (v->name) ;
356   switch (v->type)
357     {
358       case scopeval:
359         freeScopeTree (v->v.scope_val) ;
360         break ;
361
362       case stringval:
363         free (v->v.charp_val) ;
364         break ;
365
366       default:
367         break ;
368     }
369   free (v) ;
370 }
371
372 static char *checkName (scope *s, const char *name)
373 {
374   int i ;       
375   char *error = NULL ;
376
377   if (s == NULL)
378     return NULL ;
379   
380   for (i = 0 ; i < s->value_idx ; i++)
381     {
382       char *n = NULL ;
383       
384       if (strcmp (name,s->values [i]->name) == 0) {
385         n = valueScopedName (s->values[i]) ;
386         error = concat ("Two definitions of ", n, (char *) 0) ;
387         free (n) ;
388         return error ;
389       }
390     }
391   
392   return error ;
393 }
394
395
396 static void addValue (scope *s, value *v) 
397 {
398   v->myscope = s ;
399   
400   if (s == NULL)
401     return ;
402       
403   if (s->value_count == s->value_idx)
404     {
405       if (s->values == 0)
406         {
407           s->values = (value **) calloc (10,sizeof (value *)) ;
408           s->value_count = 10 ;
409         }
410       else
411         {
412           s->value_count += 10 ;
413           s->values = (value **) realloc (s->values,
414                                           sizeof (value *) * s->value_count);
415         }
416     }
417   
418   s->values [s->value_idx++] = v ;
419 }
420
421
422
423 static char *addScope (scope *s, const char *name, scope *val)
424 {
425   value *v ;
426   char *error ;
427
428   if ((error = checkName (s,name)) != NULL)
429     return error ;
430
431   v = (value *) calloc (1,sizeof (value)) ;
432   v->name = xstrdup (name) ;
433   v->type = scopeval ;
434   v->v.scope_val = val ;
435   val->me = v ;
436   val->parent = s ;
437
438   addValue (s,v) ;
439
440   currScope = val ;
441
442   return NULL ;
443 }
444
445
446 static void printScope (FILE *fp, scope *s, int indent)
447 {
448   int i ;
449   for (i = 0 ; i < s->value_idx ; i++)
450     printValue (fp,s->values [i],indent + 5) ;
451 }
452
453 static void printValue (FILE *fp, value *v, int indent) 
454 {
455   int i ;
456   
457   for (i = 0 ; i < indent ; i++)
458     fputc (' ',fp) ;
459   
460   switch (v->type) 
461     {
462       case intval:
463         fprintf (fp,"%s : %ld # INTEGER\n",v->name,v->v.int_val) ;
464         break ;
465         
466       case stringval:
467         fprintf (fp,"%s : \"",v->name) ;
468         {
469           char *p = v->v.charp_val ;
470           while (*p) 
471             {
472               if (*p == '"' || *p == '\\')
473                 fputc ('\\',fp) ;
474               fputc (*p,fp) ;
475               p++ ;
476             }
477         }
478         fprintf (fp,"\" # STRING\n") ;
479         break ;
480
481       case charval:
482         fprintf (fp,"%s : %c",v->name,047) ;
483         switch (v->v.char_val)
484           {
485             case '\\':
486               fprintf (fp,"\\\\") ;
487               break ;
488
489             default:
490               if (CTYPE (isprint, v->v.char_val))
491                 fprintf (fp,"%c",v->v.char_val) ;
492               else
493                 fprintf (fp,"\\%03o",v->v.char_val) ;
494           }
495         fprintf (fp,"%c # CHARACTER\n",047) ;
496         break ;
497         
498       case realval:
499         fprintf (fp,"%s : %f # REAL\n",v->name,v->v.real_val) ;
500         break ;
501
502       case boolval:
503         fprintf (fp,"%s : %s # BOOLEAN\n",
504                  v->name,(v->v.bool_val ? "true" : "false")) ;
505         break ;
506         
507       case scopeval:
508         fprintf (fp,"%s %s { # SCOPE\n",v->v.scope_val->scope_type,v->name) ;
509         printScope (fp,v->v.scope_val,indent + 5) ;
510         for (i = 0 ; i < indent ; i++)
511           fputc (' ',fp) ;
512         fprintf (fp,"}\n") ;
513         break ;
514
515       default:
516         fprintf (fp,"UNKNOWN value type: %d\n",v->type) ;
517         exit (1) ;
518     }
519 }
520
521   
522
523 static scope *newScope (const char *type)
524 {
525   scope *t ;
526   int i ;
527   
528   t = (scope *) calloc (1,sizeof (scope)) ;
529   t->parent = NULL ;
530   t->scope_type = xstrdup (type) ;
531
532   for (i = 0 ; t->scope_type[i] != '\0' ; i++)
533     t->scope_type[i] = tolower (t->scope_type[i]) ;
534
535   return t ;
536 }
537
538
539
540 #if 0
541 static int strNCaseCmp (const char *a, const char *b, size_t len)
542 {
543   while (a && b && *a && *b && (tolower (*a) == tolower (*b)) && len > 0)
544     a++, b++, len-- ;
545
546   if (a == NULL && b == NULL)
547     return 0 ;
548   else if (a == NULL)
549     return 1 ;
550   else if (b == NULL)
551     return -1 ;
552   else if (*a == '\0' && *b == '\0')
553     return 0 ;
554   else if (*a == '\0')
555     return 1 ;
556   else if (*b == '\0')
557     return -1 ;
558   else if (*a < *b)
559     return 1 ;
560   else if (*a > *b)
561     return -1 ;
562   else
563     return 0 ;
564
565   abort () ;
566 }
567 #endif
568
569 #define BAD_KEY "line %d: illegal key name: %s"
570 #define NON_ALPHA "line %d: keys must start with a letter: %s"
571
572 static char *keyOk (const char *key) 
573 {
574   const char *p = key ;
575   char *rval ;
576
577   if (key == NULL)
578     {
579       rval = xmalloc (strlen ("line : NULL key") + 15) ;
580       sprintf (rval,"line %d: NULL key", lineCount) ;
581       return rval ;
582     }
583   else if (*key == '\0')
584     {
585       rval = xmalloc (strlen ("line : EMPTY KEY") + 15) ;
586       sprintf (rval,"line %d: EMPTY KEY", lineCount) ;
587       return rval ;
588     }
589   
590   if (!CTYPE(isalpha, *p))
591     {
592       rval = xmalloc (strlen (NON_ALPHA) + strlen (key) + 15) ;
593       sprintf (rval,NON_ALPHA,lineCount, key) ;
594       return rval ;
595     }
596
597   p++ ;
598   while (*p)
599     {
600       if (!(CTYPE (isalnum, *p) || *p == '_' || *p == '-'))
601         {
602           rval = xmalloc (strlen (BAD_KEY) + strlen (key) + 15) ;
603           sprintf (rval,BAD_KEY,lineCount,key) ;
604           return rval ;
605         }
606       p++ ;
607     }
608
609   return NULL ;
610 }
611
612 static PFIVP *funcs = NULL ;
613 static void **args = NULL ;
614 static int funcCount ;
615 static int funcIdx ;
616
617 void configAddLoadCallback (PFIVP func,void *arg)
618 {
619   if (func == NULL)
620     return ;
621
622   if (funcIdx == funcCount)
623     {
624       funcCount += 10 ;
625       if (funcs == NULL)
626         {
627           funcs = xmalloc (sizeof (PFIVP) * funcCount);
628           args = xmalloc (sizeof (void *) * funcCount) ;
629         }
630       else
631         {
632           funcs = xrealloc (funcs,sizeof (PFIVP) * funcCount);
633           args = xrealloc (args,sizeof (void *) * funcCount) ;
634         }
635     }
636
637   args [funcIdx] = arg ;
638   funcs [funcIdx++] = func ;
639   
640 }
641
642
643 void configRemoveLoadCallback (PFIVP func)
644 {
645   int i, j ;
646
647   for (i = 0 ; i < funcIdx ; i++)
648     if (funcs [i] == func)
649       break ;
650
651   for (j = i ; j < funcIdx - 1 ; j++)
652     {
653       funcs [j] = funcs [j + 1] ;
654       args [j] = args [j + 1] ;
655     }
656
657   if (funcIdx > 1 && i < funcIdx)
658     {
659       funcs [i - 2] = funcs [i - 1] ;
660       args [i - 2] = args [i - 1] ;
661     }
662
663   if (funcIdx > 0 && i < funcIdx)
664     funcIdx-- ;
665 }
666
667
668 static int doCallbacks (void)
669 {
670   int i ;
671   int rval = 1 ;
672   
673   for (i = 0 ; i < funcIdx ; i++)
674     if (funcs [i] != NULL)
675       rval = (funcs[i](args [i]) && rval) ;
676
677   return rval ;
678 }
679
680
681
682
683
684 static char *key ;
685 %}
686
687 %union{
688     scope *scp ;
689     value *val ;
690     char *name ;
691     int integer ;
692     double real ;
693     char *string ;
694     char chr ;
695 }
696
697 %token PEER
698 %token GROUP
699 %token IVAL
700 %token RVAL
701 %token NAME
702 %token XSTRING
703 %token SCOPE
704 %token COLON
705 %token LBRACE
706 %token RBRACE
707 %token TRUEBVAL
708 %token FALSEBVAL
709 %token CHAR
710 %token WORD
711 %token IP_ADDRESS
712
713 %type <integer> IVAL
714 %type <real> RVAL
715 %type <string> XSTRING
716 %type <chr> CHAR
717 %type <name> TRUEBVAL FALSEBVAL WORD
718
719 %%
720 input: {        
721                 lineCount = 1 ;
722                 addScope (NULL,"",newScope ("")) ;
723                 topScope = currScope ;
724         } entries { if (!doCallbacks()) YYABORT ; } ;
725
726 scope: entries ;
727
728 entries:        
729         | entries entry
730         | entries error {
731                 errbuff = xmalloc (strlen(SYNTAX_ERROR) + 12) ;
732                 sprintf (errbuff,SYNTAX_ERROR,lineCount) ;
733                 YYABORT ;
734         }
735         ;
736
737 entry:  PEER WORD LBRACE {
738                 errbuff = addScope (currScope,$2,newScope ("peer")) ;
739                 free ($2) ;
740                 if (errbuff != NULL) YYABORT ;
741         } scope RBRACE {
742                 currScope = currScope->parent ;
743         }
744         | GROUP WORD LBRACE {
745                 errbuff = addScope (currScope,$2,newScope ("group")) ;
746                 free ($2) ;
747                 if (errbuff != NULL) YYABORT ;
748         } scope RBRACE {
749                 currScope = currScope->parent ;
750         }
751         | WORD WORD LBRACE {
752                 errbuff = xmalloc (strlen(UNKNOWN_SCOPE_TYPE) + 15 +
753                                           strlen ($1)) ;
754                 sprintf (errbuff,UNKNOWN_SCOPE_TYPE,lineCount,$1) ;
755                 free ($1) ;
756                 free ($2) ;
757                 YYABORT ;
758         }
759         | WORD { 
760                 if ((errbuff = keyOk($1)) != NULL) {
761                         YYABORT ;
762                 } else
763                         key = $1 ;
764         } COLON value ;
765
766 value:  WORD {
767                 if ((errbuff = addString (currScope, key, $1)) != NULL)
768                         YYABORT ;
769                 free (key) ;
770                 free ($1) ;
771         }
772         | IVAL {
773                 if ((errbuff = addInteger(currScope, key, $1)) != NULL)
774                         YYABORT; 
775                 free (key) ;
776         }
777         | TRUEBVAL {
778                 if ((errbuff = addBoolean (currScope, key, 1)) != NULL)
779                         YYABORT ; 
780                 free (key) ;
781                 free ($1) ;
782         }
783         | FALSEBVAL {
784                 if ((errbuff = addBoolean (currScope, key, 0)) != NULL)
785                         YYABORT ; 
786                 free (key) ;
787                 free ($1) ;
788         }
789         | RVAL {
790                 if ((errbuff = addReal (currScope, key, $1)) != NULL)
791                         YYABORT ; 
792                 free (key) ;
793         }
794         | XSTRING { 
795                 if ((errbuff = addString (currScope, key, $1)) != NULL)
796                         YYABORT;
797                 free (key) ;
798         }
799         | CHAR {
800                 if ((errbuff = addChar (currScope, key, $1)) != NULL)
801                         YYABORT ;
802                 free (key) ;
803         }
804 ;
805         
806 %%
807
808 int yyerror (const char *s)
809 {
810 #undef FMT
811 #define FMT "line %d: %s"
812   
813   errbuff = xmalloc (strlen (s) + strlen (FMT) + 20) ;
814   sprintf (errbuff,FMT,lineCount,s) ;
815
816   return 0 ;
817 }
818
819 int yywrap (void)
820 {
821   return 1 ;
822 }
823
824 extern FILE *yyin ;
825 int yydebug ;
826
827 #define NO_INHERIT 0
828
829
830 #if ! defined (WANT_MAIN)
831
832 struct peer_table_s
833 {
834     char *peerName ;
835     value *peerValue ;
836 } ;
837
838 static struct peer_table_s *peerTable ;
839 static int peerTableCount ;
840 static int peerTableIdx ;
841
842 void configCleanup (void)
843 {
844   int i ;
845
846   for (i = 0 ; i < peerTableIdx ; i++)
847     free (peerTable[i].peerName) ;
848   free (peerTable) ;
849   
850   freeScopeTree (topScope);
851   free (funcs) ;
852   free (args) ;
853 }
854   
855
856 int buildPeerTable (FILE *fp, scope *s)
857 {
858   int rval = 1 ;
859   int i, j ;
860
861   for (i = 0 ; i < s->value_idx ; i++)
862     {
863       if (ISSCOPE (s->values[i]) && ISPEER (s->values[i]))
864         {
865           for (j = 0 ; j < peerTableIdx ; j++)
866             {
867               if (strcmp (peerTable[j].peerName,s->values[i]->name) == 0)
868                 {
869                   logOrPrint (LOG_ERR,fp,
870                               "ME config: two peers with the same name: %s",
871                               peerTable[j].peerName) ;
872                   rval = 0 ;
873                   break ;
874                 }
875             }
876
877           if (j == peerTableIdx)
878             {
879               if (peerTableCount == peerTableIdx) 
880                 {
881                   peerTableCount += 10 ;
882                   if (peerTable == NULL)
883                     peerTable = xmalloc (sizeof(struct peer_table_s)
884                                          * peerTableCount) ;
885                   else
886                     peerTable = xrealloc (peerTable,
887                                           sizeof(struct peer_table_s)
888                                           * peerTableCount) ;
889                 }
890   
891               peerTable[peerTableIdx].peerName = xstrdup (s->values[i]->name);
892               peerTable[peerTableIdx].peerValue = s->values[i] ;
893               peerTableIdx++ ;
894             }
895         }
896       else if (ISSCOPE (s->values[i]))
897         rval = (buildPeerTable (fp,s->values[i]->v.scope_val) && rval) ;
898     }
899
900   return rval ;  
901 }
902
903
904 /* read the config file. Any errors go to errorDest if it is non-NULL,
905    otherwise they are syslogged. If justCheck is true then return after
906    parsing */
907 static int inited = 0 ;
908 int readConfig (const char *file, FILE *errorDest, int justCheck, int dump)
909 {
910   scope *oldTop = topScope ;
911   FILE *fp ;
912   int rval ;
913
914   if (!inited)
915     {
916       inited = 1 ;
917       yydebug = (getenv ("YYDEBUG") == NULL ? 0 : 1) ;
918       if (yydebug)
919         atexit (configCleanup) ;
920     }
921
922   if (file == NULL || strlen (file) == 0 || !fileExistsP (file))
923     {
924       logOrPrint (LOG_ERR,errorDest,
925                   "ME config aborting, no such config file: %s",
926                   file ? file : "(null)") ;
927       d_printf (1,"No such config file: %s\n", file ? file : "(null)") ;
928       exit (1) ;
929     }
930
931   if ((fp = fopen (file,"r")) == NULL)
932     {
933       logOrPrint (LOG_ERR,errorDest, "ME config aborting fopen %s: %s",
934                   file, strerror (errno)) ;
935       exit (1) ;
936     }
937
938   logOrPrint (LOG_NOTICE,errorDest,"loading %s", file) ;
939
940   yyin = fp ;
941
942   topScope = NULL ;
943
944   rval = yyparse () ;
945
946   fclose (fp) ;
947   
948   if (rval != 0)                /* failure */
949     {
950       freeScopeTree (topScope) ;
951       if (justCheck)
952         freeScopeTree (oldTop) ;
953       else
954         topScope = oldTop ;
955       topScope = NULL ;
956
957       if (errbuff != NULL)
958         {
959           if (errorDest != NULL)
960             fprintf (errorDest,"config file error: %s\n",errbuff) ;
961           else
962             warn ("ME config file error: %s", errbuff) ;
963           
964           free (errbuff) ;
965         }
966       
967       return 0 ;
968     }
969   
970   if (dump)
971     {
972       fprintf (errorDest ? errorDest : stderr,"Parsed config file:\n") ;
973       printScope (errorDest ? errorDest : stderr,topScope,-5) ;
974       fprintf (errorDest ? errorDest : stderr,"\n") ;
975     }
976   
977   if (justCheck)
978     {
979       freeScopeTree (topScope) ;
980       freeScopeTree (oldTop) ;
981
982       topScope = NULL ;
983     }
984   else
985     {
986       for (peerTableIdx-- ; peerTableIdx >= 0 ; peerTableIdx--)
987         {
988           free (peerTable [peerTableIdx].peerName) ;
989           peerTable [peerTableIdx].peerName = NULL ;
990           peerTable [peerTableIdx].peerValue = NULL ;
991         }
992       peerTableIdx = 0 ;
993       
994       if (!buildPeerTable (errorDest,topScope))
995         logAndExit (1,"Failed to build list of peers") ;
996     }
997   
998   return 1 ;
999 }
1000
1001
1002 value *getNextPeer (int *cookie)
1003 {
1004   value *rval ;
1005
1006   if (*cookie < 0 || *cookie >= peerTableIdx)
1007     return NULL ;
1008
1009   rval = peerTable[*cookie].peerValue ;
1010
1011   (*cookie)++ ;
1012
1013   return rval ;
1014 }
1015
1016
1017 value *findPeer (const char *name)
1018 {
1019   value *v = NULL ;
1020   int i ;
1021
1022   for (i = 0 ; i < peerTableIdx ; i++)
1023     if (strcmp (peerTable[i].peerName,name) == 0)
1024       {
1025         v = peerTable[i].peerValue ;
1026         break ;
1027       }
1028   
1029   return v ;
1030 }
1031
1032 #endif
1033
1034 #if defined (WANT_MAIN)
1035 int main (int argc, char **argv) {
1036   if ( yyparse() )
1037     printf ("parsing failed: %s\n",errbuff ? errbuff : "NONE") ;
1038   else
1039     {
1040       printScope (stdout,topScope,-5) ;
1041
1042       if (argc == 3)
1043         {
1044 #if 0
1045           printf ("Looking for %s of type %s: ",argv[2],argv[1]) ;
1046           if (strncmp (argv[1],"int",3) == 0)
1047             {
1048               int i = 0 ;
1049           
1050               if (!getInteger (topScope,argv[2],&i))
1051                 printf ("wasn't found.\n") ;
1052               else
1053                 printf (" %d\n",i) ;
1054             }
1055           else if (strncmp (argv[1],"real",4) == 0)
1056             {
1057               double d = 0.0 ;
1058
1059               if (!getReal (topScope,argv[2],&d))
1060                 printf ("wasn't found.\n") ;
1061               else
1062                 printf (" %0.5f\n",d) ;
1063             }
1064 #else
1065           value *v = findValue (topScope,argv[1],1) ;
1066
1067           if (v == NULL)
1068             printf ("Can't find %s\n",argv[1]) ;
1069           else
1070             {
1071               long ival = 987654 ;
1072               
1073               if (getInteger (v->v.scope_val,argv[2],&ival,1))
1074                 printf ("Getting %s : %ld",argv[2],ival) ;
1075               else
1076                 printf ("Name is not legal: %s\n",argv[2]) ;
1077             }
1078 #endif
1079         }
1080       else if (argc == 2)
1081         {
1082 #if 1
1083           value *v = findValue (topScope,argv[1],1) ;
1084
1085           if (v == NULL)
1086             printf ("Can't find %s\n",argv[1]) ;
1087           else
1088             {
1089               printf ("Getting %s : ",argv[1]) ;
1090               printValue (stdout,v,0) ;
1091             }
1092 #else
1093           if (findScope (topScope,argv[1],1) == NULL)
1094             printf ("Can't find the scope of %s\n",argv[1]) ;
1095 #endif
1096         }
1097     }
1098   
1099   freeScopeTree (topScope) ;
1100
1101   return 0 ;
1102 }
1103 #endif /* defined (WANT_MAIN) */