2 /* $Id: configfile.y 6372 2003-05-31 19:48:28Z rra $
4 ** A yacc input file for the innfeed config file.
6 ** Written by James Brister <brister@vix.com>
8 ** This file contains the heart of the innfeed configuration parser, written
9 ** in yacc. It uses an external lexer generated by flex.
19 #if defined(_HPUX_SOURCE)
23 #include "inn/messages.h"
26 #include "configfile.h"
29 #define UNKNOWN_SCOPE_TYPE "line %d: unknown scope type: %s"
30 #define SYNTAX_ERROR "line %d: syntax error"
32 extern int lineCount ;
33 scope *topScope = NULL ;
34 static scope *currScope = NULL ;
35 char *errbuff = NULL ;
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) ;
47 static int strNCaseCmp (const char *a, const char *b, size_t len) ;
50 int yyerror (const char *s) ;
56 int isString (scope *s, const char *name, int inherit)
58 value *v = findValue (s,name,inherit) ;
60 return (v != NULL && v->type == stringval) ;
64 int getBool (scope *s, const char *name, int *rval, int inherit)
66 value *v = findValue (s,name,inherit) ;
70 else if (v->type != boolval)
73 *rval = v->v.bool_val ;
78 int getString (scope *s, const char *name, char **rval, int inherit)
80 value *v = findValue (s,name,inherit) ;
84 else if (v->type != stringval)
87 *rval = xstrdup (v->v.charp_val) ;
92 int getReal (scope *s, const char *name, double *rval, int inherit)
94 value *v = findValue (s,name,inherit) ;
98 else if (v->type != realval)
101 *rval = v->v.real_val ;
105 int getInteger (scope *s, const char *name, long *rval, int inherit)
107 value *v = findValue (s,name,inherit) ;
111 else if (v->type != intval)
114 *rval = v->v.int_val ;
118 void freeScopeTree (scope *s)
125 if (s->parent == NULL && s->me != NULL)
126 { /* top level scope */
132 for (i = 0 ; i < s->value_idx ; i++)
133 if (s->values[i] != NULL)
134 freeValue (s->values [i]) ;
137 free (s->scope_type) ;
146 char *addInteger (scope *s, const char *name, long val)
151 if ((error = checkName (currScope,name)) != NULL)
154 v = (value *) calloc (1,sizeof (value)) ;
155 v->name = xstrdup (name) ;
164 char *addChar (scope *s, const char *name, char val)
169 if ((error = checkName (currScope,name)) != NULL)
172 v = (value *) calloc (1,sizeof (value)) ;
173 v->name = xstrdup (name) ;
175 v->v.char_val = val ;
182 char *addBoolean (scope *s, const char *name, int val)
187 if ((error = checkName (currScope,name)) != NULL)
190 v = (value *) calloc (1,sizeof (value)) ;
191 v->name = xstrdup (name) ;
193 v->v.bool_val = val ;
200 char *addReal (scope *s, const char *name, double val)
205 if ((error = checkName (currScope,name)) != NULL)
208 v = (value *) calloc (1,sizeof (value)) ;
209 v->name = xstrdup (name) ;
211 v->v.real_val = val ;
218 char *addString (scope *s, const char *name, const char *val)
223 if ((error = checkName (currScope,name)) != NULL)
226 v = (value *) calloc (1,sizeof (value)) ;
227 v->name = xstrdup (name) ;
228 v->type = stringval ;
229 v->v.charp_val = xstrdup (val) ;
236 value *findValue (scope *s, const char *name, int inherit)
240 if (name == NULL || *name == '\0')
244 return findValue (topScope,name + 1,0) ;
246 return findValue (topScope,name,0) ;
251 if ((p = strchr (name,':')) == NULL)
252 p = name + strlen (name) ;
254 for (i = 0 ; i < s->value_idx ; i++)
256 if (strlen (s->values[i]->name) == (size_t) (p - name) &&
257 strncmp (s->values[i]->name,name,p - name) == 0)
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") ;
264 return findValue (s->values[i]->v.scope_val,p + 1,0) ;
268 /* not in this scope. Go up if inheriting values and only if no ':'
270 if (inherit && *p == '\0')
271 return findValue (s->parent,name,inherit) ;
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)
286 if ((q = strchr (name,':')) == NULL)
291 for (i = 0 ; p == NULL && i < s->value_idx ; i++)
292 if (strcmp (s->values[i]->name,name) == 0)
297 else if (*name == ':')
299 while (s->parent != NULL)
302 return findScope (s,name + 1,mustExist) ;
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) ;
315 /****************************************************************************/
317 /****************************************************************************/
320 static void appendName (scope *s, char *p, size_t len)
326 appendName (s->parent,p,len) ;
327 strlcat (p,s->me->name,len) ;
328 strlcat (p,":",len) ;
332 static char *valueScopedName (value *v)
334 scope *p = v->myscope ;
335 int len = strlen (v->name) ;
340 len += strlen (p->me->name) + 1 ;
347 appendName (v->myscope,q,len) ;
348 strlcat (q,v->name,len) ;
353 static void freeValue (value *v)
359 freeScopeTree (v->v.scope_val) ;
363 free (v->v.charp_val) ;
372 static char *checkName (scope *s, const char *name)
380 for (i = 0 ; i < s->value_idx ; i++)
384 if (strcmp (name,s->values [i]->name) == 0) {
385 n = valueScopedName (s->values[i]) ;
386 error = concat ("Two definitions of ", n, (char *) 0) ;
396 static void addValue (scope *s, value *v)
403 if (s->value_count == s->value_idx)
407 s->values = (value **) calloc (10,sizeof (value *)) ;
408 s->value_count = 10 ;
412 s->value_count += 10 ;
413 s->values = (value **) realloc (s->values,
414 sizeof (value *) * s->value_count);
418 s->values [s->value_idx++] = v ;
423 static char *addScope (scope *s, const char *name, scope *val)
428 if ((error = checkName (s,name)) != NULL)
431 v = (value *) calloc (1,sizeof (value)) ;
432 v->name = xstrdup (name) ;
434 v->v.scope_val = val ;
446 static void printScope (FILE *fp, scope *s, int indent)
449 for (i = 0 ; i < s->value_idx ; i++)
450 printValue (fp,s->values [i],indent + 5) ;
453 static void printValue (FILE *fp, value *v, int indent)
457 for (i = 0 ; i < indent ; i++)
463 fprintf (fp,"%s : %ld # INTEGER\n",v->name,v->v.int_val) ;
467 fprintf (fp,"%s : \"",v->name) ;
469 char *p = v->v.charp_val ;
472 if (*p == '"' || *p == '\\')
478 fprintf (fp,"\" # STRING\n") ;
482 fprintf (fp,"%s : %c",v->name,047) ;
483 switch (v->v.char_val)
486 fprintf (fp,"\\\\") ;
490 if (CTYPE (isprint, v->v.char_val))
491 fprintf (fp,"%c",v->v.char_val) ;
493 fprintf (fp,"\\%03o",v->v.char_val) ;
495 fprintf (fp,"%c # CHARACTER\n",047) ;
499 fprintf (fp,"%s : %f # REAL\n",v->name,v->v.real_val) ;
503 fprintf (fp,"%s : %s # BOOLEAN\n",
504 v->name,(v->v.bool_val ? "true" : "false")) ;
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++)
516 fprintf (fp,"UNKNOWN value type: %d\n",v->type) ;
523 static scope *newScope (const char *type)
528 t = (scope *) calloc (1,sizeof (scope)) ;
530 t->scope_type = xstrdup (type) ;
532 for (i = 0 ; t->scope_type[i] != '\0' ; i++)
533 t->scope_type[i] = tolower (t->scope_type[i]) ;
541 static int strNCaseCmp (const char *a, const char *b, size_t len)
543 while (a && b && *a && *b && (tolower (*a) == tolower (*b)) && len > 0)
546 if (a == NULL && b == NULL)
552 else if (*a == '\0' && *b == '\0')
569 #define BAD_KEY "line %d: illegal key name: %s"
570 #define NON_ALPHA "line %d: keys must start with a letter: %s"
572 static char *keyOk (const char *key)
574 const char *p = key ;
579 rval = xmalloc (strlen ("line : NULL key") + 15) ;
580 sprintf (rval,"line %d: NULL key", lineCount) ;
583 else if (*key == '\0')
585 rval = xmalloc (strlen ("line : EMPTY KEY") + 15) ;
586 sprintf (rval,"line %d: EMPTY KEY", lineCount) ;
590 if (!CTYPE(isalpha, *p))
592 rval = xmalloc (strlen (NON_ALPHA) + strlen (key) + 15) ;
593 sprintf (rval,NON_ALPHA,lineCount, key) ;
600 if (!(CTYPE (isalnum, *p) || *p == '_' || *p == '-'))
602 rval = xmalloc (strlen (BAD_KEY) + strlen (key) + 15) ;
603 sprintf (rval,BAD_KEY,lineCount,key) ;
612 static PFIVP *funcs = NULL ;
613 static void **args = NULL ;
614 static int funcCount ;
617 void configAddLoadCallback (PFIVP func,void *arg)
622 if (funcIdx == funcCount)
627 funcs = xmalloc (sizeof (PFIVP) * funcCount);
628 args = xmalloc (sizeof (void *) * funcCount) ;
632 funcs = xrealloc (funcs,sizeof (PFIVP) * funcCount);
633 args = xrealloc (args,sizeof (void *) * funcCount) ;
637 args [funcIdx] = arg ;
638 funcs [funcIdx++] = func ;
643 void configRemoveLoadCallback (PFIVP func)
647 for (i = 0 ; i < funcIdx ; i++)
648 if (funcs [i] == func)
651 for (j = i ; j < funcIdx - 1 ; j++)
653 funcs [j] = funcs [j + 1] ;
654 args [j] = args [j + 1] ;
657 if (funcIdx > 1 && i < funcIdx)
659 funcs [i - 2] = funcs [i - 1] ;
660 args [i - 2] = args [i - 1] ;
663 if (funcIdx > 0 && i < funcIdx)
668 static int doCallbacks (void)
673 for (i = 0 ; i < funcIdx ; i++)
674 if (funcs [i] != NULL)
675 rval = (funcs[i](args [i]) && rval) ;
715 %type <string> XSTRING
717 %type <name> TRUEBVAL FALSEBVAL WORD
722 addScope (NULL,"",newScope ("")) ;
723 topScope = currScope ;
724 } entries { if (!doCallbacks()) YYABORT ; } ;
731 errbuff = xmalloc (strlen(SYNTAX_ERROR) + 12) ;
732 sprintf (errbuff,SYNTAX_ERROR,lineCount) ;
737 entry: PEER WORD LBRACE {
738 errbuff = addScope (currScope,$2,newScope ("peer")) ;
740 if (errbuff != NULL) YYABORT ;
742 currScope = currScope->parent ;
744 | GROUP WORD LBRACE {
745 errbuff = addScope (currScope,$2,newScope ("group")) ;
747 if (errbuff != NULL) YYABORT ;
749 currScope = currScope->parent ;
752 errbuff = xmalloc (strlen(UNKNOWN_SCOPE_TYPE) + 15 +
754 sprintf (errbuff,UNKNOWN_SCOPE_TYPE,lineCount,$1) ;
760 if ((errbuff = keyOk($1)) != NULL) {
767 if ((errbuff = addString (currScope, key, $1)) != NULL)
773 if ((errbuff = addInteger(currScope, key, $1)) != NULL)
778 if ((errbuff = addBoolean (currScope, key, 1)) != NULL)
784 if ((errbuff = addBoolean (currScope, key, 0)) != NULL)
790 if ((errbuff = addReal (currScope, key, $1)) != NULL)
795 if ((errbuff = addString (currScope, key, $1)) != NULL)
800 if ((errbuff = addChar (currScope, key, $1)) != NULL)
808 int yyerror (const char *s)
811 #define FMT "line %d: %s"
813 errbuff = xmalloc (strlen (s) + strlen (FMT) + 20) ;
814 sprintf (errbuff,FMT,lineCount,s) ;
830 #if ! defined (WANT_MAIN)
838 static struct peer_table_s *peerTable ;
839 static int peerTableCount ;
840 static int peerTableIdx ;
842 void configCleanup (void)
846 for (i = 0 ; i < peerTableIdx ; i++)
847 free (peerTable[i].peerName) ;
850 freeScopeTree (topScope);
856 int buildPeerTable (FILE *fp, scope *s)
861 for (i = 0 ; i < s->value_idx ; i++)
863 if (ISSCOPE (s->values[i]) && ISPEER (s->values[i]))
865 for (j = 0 ; j < peerTableIdx ; j++)
867 if (strcmp (peerTable[j].peerName,s->values[i]->name) == 0)
869 logOrPrint (LOG_ERR,fp,
870 "ME config: two peers with the same name: %s",
871 peerTable[j].peerName) ;
877 if (j == peerTableIdx)
879 if (peerTableCount == peerTableIdx)
881 peerTableCount += 10 ;
882 if (peerTable == NULL)
883 peerTable = xmalloc (sizeof(struct peer_table_s)
886 peerTable = xrealloc (peerTable,
887 sizeof(struct peer_table_s)
891 peerTable[peerTableIdx].peerName = xstrdup (s->values[i]->name);
892 peerTable[peerTableIdx].peerValue = s->values[i] ;
896 else if (ISSCOPE (s->values[i]))
897 rval = (buildPeerTable (fp,s->values[i]->v.scope_val) && rval) ;
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
907 static int inited = 0 ;
908 int readConfig (const char *file, FILE *errorDest, int justCheck, int dump)
910 scope *oldTop = topScope ;
917 yydebug = (getenv ("YYDEBUG") == NULL ? 0 : 1) ;
919 atexit (configCleanup) ;
922 if (file == NULL || strlen (file) == 0 || !fileExistsP (file))
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)") ;
931 if ((fp = fopen (file,"r")) == NULL)
933 logOrPrint (LOG_ERR,errorDest, "ME config aborting fopen %s: %s",
934 file, strerror (errno)) ;
938 logOrPrint (LOG_NOTICE,errorDest,"loading %s", file) ;
948 if (rval != 0) /* failure */
950 freeScopeTree (topScope) ;
952 freeScopeTree (oldTop) ;
959 if (errorDest != NULL)
960 fprintf (errorDest,"config file error: %s\n",errbuff) ;
962 warn ("ME config file error: %s", errbuff) ;
972 fprintf (errorDest ? errorDest : stderr,"Parsed config file:\n") ;
973 printScope (errorDest ? errorDest : stderr,topScope,-5) ;
974 fprintf (errorDest ? errorDest : stderr,"\n") ;
979 freeScopeTree (topScope) ;
980 freeScopeTree (oldTop) ;
986 for (peerTableIdx-- ; peerTableIdx >= 0 ; peerTableIdx--)
988 free (peerTable [peerTableIdx].peerName) ;
989 peerTable [peerTableIdx].peerName = NULL ;
990 peerTable [peerTableIdx].peerValue = NULL ;
994 if (!buildPeerTable (errorDest,topScope))
995 logAndExit (1,"Failed to build list of peers") ;
1002 value *getNextPeer (int *cookie)
1006 if (*cookie < 0 || *cookie >= peerTableIdx)
1009 rval = peerTable[*cookie].peerValue ;
1017 value *findPeer (const char *name)
1022 for (i = 0 ; i < peerTableIdx ; i++)
1023 if (strcmp (peerTable[i].peerName,name) == 0)
1025 v = peerTable[i].peerValue ;
1034 #if defined (WANT_MAIN)
1035 int main (int argc, char **argv) {
1037 printf ("parsing failed: %s\n",errbuff ? errbuff : "NONE") ;
1040 printScope (stdout,topScope,-5) ;
1045 printf ("Looking for %s of type %s: ",argv[2],argv[1]) ;
1046 if (strncmp (argv[1],"int",3) == 0)
1050 if (!getInteger (topScope,argv[2],&i))
1051 printf ("wasn't found.\n") ;
1053 printf (" %d\n",i) ;
1055 else if (strncmp (argv[1],"real",4) == 0)
1059 if (!getReal (topScope,argv[2],&d))
1060 printf ("wasn't found.\n") ;
1062 printf (" %0.5f\n",d) ;
1065 value *v = findValue (topScope,argv[1],1) ;
1068 printf ("Can't find %s\n",argv[1]) ;
1071 long ival = 987654 ;
1073 if (getInteger (v->v.scope_val,argv[2],&ival,1))
1074 printf ("Getting %s : %ld",argv[2],ival) ;
1076 printf ("Name is not legal: %s\n",argv[2]) ;
1083 value *v = findValue (topScope,argv[1],1) ;
1086 printf ("Can't find %s\n",argv[1]) ;
1089 printf ("Getting %s : ",argv[1]) ;
1090 printValue (stdout,v,0) ;
1093 if (findScope (topScope,argv[1],1) == NULL)
1094 printf ("Can't find the scope of %s\n",argv[1]) ;
1099 freeScopeTree (topScope) ;
1103 #endif /* defined (WANT_MAIN) */