/* This code is in the public domain. * $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $ * $Id: ircd_parser.y 871 2006-02-18 21:56:00Z nenolod $ */ %{ #include #include #include #include #include #include #include #define WE_ARE_MEMORY_C #include "stdinc.h" #include "setup.h" #include "common.h" #include "ircd_defs.h" #include "config.h" #include "client.h" #include "modules.h" #include "newconf.h" #define YY_NO_UNPUT int yyparse(void); void yyerror(const char *); int yylex(void); static time_t conf_find_time(char*); static struct { const char * name; const char * plural; time_t val; } ircd_times[] = { {"second", "seconds", 1}, {"minute", "minutes", 60}, {"hour", "hours", 60 * 60}, {"day", "days", 60 * 60 * 24}, {"week", "weeks", 60 * 60 * 24 * 7}, {"fortnight", "fortnights", 60 * 60 * 24 * 14}, {"month", "months", 60 * 60 * 24 * 7 * 4}, {"year", "years", 60 * 60 * 24 * 365}, /* ok-- we now do sizes here too. they aren't times, but it's close enough */ {"byte", "bytes", 1}, {"kb", NULL, 1024}, {"kbyte", "kbytes", 1024}, {"kilobyte", "kilebytes", 1024}, {"mb", NULL, 1024 * 1024}, {"mbyte", "mbytes", 1024 * 1024}, {"megabyte", "megabytes", 1024 * 1024}, {NULL, NULL, 0}, }; time_t conf_find_time(char *name) { int i; for (i = 0; ircd_times[i].name; i++) { if (strcasecmp(ircd_times[i].name, name) == 0 || (ircd_times[i].plural && strcasecmp(ircd_times[i].plural, name) == 0)) return ircd_times[i].val; } return 0; } static struct { const char *word; int yesno; } yesno[] = { {"yes", 1}, {"no", 0}, {"true", 1}, {"false", 0}, {"on", 1}, {"off", 0}, {NULL, 0} }; static int conf_get_yesno_value(char *str) { int i; for (i = 0; yesno[i].word; i++) { if (strcasecmp(str, yesno[i].word) == 0) { return yesno[i].yesno; } } return -1; } static void free_cur_list(conf_parm_t* list) { if (list->type == CF_STRING || list->type == CF_QSTRING) { rb_free(list->v.string); } else if (list->type == CF_FLIST) { /* Even though CF_FLIST is a flag, comparing with == is valid * because conf_parm_t.type must be either a type or one flag. */ free_cur_list(list->v.list); } if (list->next) { free_cur_list(list->next); } rb_free(list); } conf_parm_t * cur_list = NULL; static void add_cur_list_cpt(conf_parm_t *new) { if (cur_list == NULL) { cur_list = rb_malloc(sizeof(conf_parm_t)); cur_list->type = CF_FLIST; cur_list->v.list = new; } else { new->next = cur_list->v.list; cur_list->v.list = new; } } static void add_cur_list(int type, char *str, int number) { conf_parm_t *new; new = rb_malloc(sizeof(conf_parm_t)); new->next = NULL; new->type = type; switch(type) { case CF_INT: case CF_TIME: case CF_YESNO: new->v.number = number; break; case CF_STRING: case CF_QSTRING: new->v.string = rb_strdup(str); break; } add_cur_list_cpt(new); } %} %union { int number; char string[1024]; conf_parm_t * conf_parm; } %token LOADMODULE TWODOTS %token QSTRING STRING %token NUMBER %type qstring string %type number timespec %type oneitem single itemlist %start conf %% conf: | conf conf_item | error ; conf_item: block | loadmodule ; block: string { conf_start_block($1, NULL); } '{' block_items '}' ';' { if (conf_cur_block) conf_end_block(conf_cur_block); } | string qstring { conf_start_block($1, $2); } '{' block_items '}' ';' { if (conf_cur_block) conf_end_block(conf_cur_block); } ; block_items: block_items block_item | block_item ; block_item: string '=' itemlist ';' { conf_call_set(conf_cur_block, $1, cur_list); free_cur_list(cur_list); cur_list = NULL; } ; itemlist: itemlist ',' single | single ; single: oneitem { add_cur_list_cpt($1); } | oneitem TWODOTS oneitem { /* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */ if ($1->type != CF_INT || $3->type != CF_INT) { conf_report_error("Both arguments in '..' notation must be integers."); break; } else { int i; for (i = $1->v.number; i <= $3->v.number; i++) { add_cur_list(CF_INT, 0, i); } } } ; oneitem: qstring { $$ = rb_malloc(sizeof(conf_parm_t)); $$->type = CF_QSTRING; $$->v.string = rb_strdup($1); } | timespec { $$ = rb_malloc(sizeof(conf_parm_t)); $$->type = CF_TIME; $$->v.number = $1; } | number { $$ = rb_malloc(sizeof(conf_parm_t)); $$->type = CF_INT; $$->v.number = $1; } | string { /* a 'string' could also be a yes/no value .. so pass it as that, if so */ int val = conf_get_yesno_value($1); $$ = rb_malloc(sizeof(conf_parm_t)); if (val != -1) { $$->type = CF_YESNO; $$->v.number = val; } else { $$->type = CF_STRING; $$->v.string = rb_strdup($1); } } ; loadmodule: LOADMODULE QSTRING { #ifndef STATIC_MODULES char *m_bn; m_bn = rb_basename((char *) $2); if (findmodule_byname(m_bn) == -1) load_one_module($2, 0); rb_free(m_bn); #endif } ';' ; qstring: QSTRING { strcpy($$, $1); } ; string: STRING { strcpy($$, $1); } ; number: NUMBER { $$ = $1; } ; timespec: number string { time_t t; if ((t = conf_find_time($2)) == 0) { conf_report_error("Unrecognised time type/size '%s'", $2); t = 1; } $$ = $1 * t; } | timespec timespec { $$ = $1 + $2; } | timespec number { $$ = $1 + $2; } ;