/* 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 $ */ %{ #define YY_NO_UNPUT #include #include #include #include #include #include int yylex(); namespace ircd { 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 (rb_strcasecmp(ircd_times[i].name, name) == 0 || (ircd_times[i].plural && rb_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 (rb_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; static void add_cur_list_cpt(conf_parm_t *new_) { if (cur_list == NULL) { cur_list = (conf_parm_t *)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_ = (conf_parm_t *)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_); } } // namespace ircd %} %union { int number; char string[1024]; ircd::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 { ircd::conf_start_block($1, NULL); } '{' block_items '}' ';' { if (ircd::conf_cur_block) ircd::conf_end_block(ircd::conf_cur_block); } | string qstring { ircd::conf_start_block($1, $2); } '{' block_items '}' ';' { if (ircd::conf_cur_block) ircd::conf_end_block(ircd::conf_cur_block); } ; block_items: block_items block_item | block_item ; block_item: string '=' itemlist ';' { ircd::conf_call_set(ircd::conf_cur_block, $1, ircd::cur_list); ircd::free_cur_list(ircd::cur_list); ircd::cur_list = NULL; } ; itemlist: itemlist ',' single | single ; single: oneitem { ircd::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) { ircd::conf_report_error("Both arguments in '..' notation must be integers."); break; } else { int i; for (i = $1->v.number; i <= $3->v.number; i++) { ircd::add_cur_list(CF_INT, 0, i); } } } ; oneitem: qstring { $$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t)); $$->type = CF_QSTRING; $$->v.string = rb_strdup($1); } | timespec { $$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t)); $$->type = CF_TIME; $$->v.number = $1; } | number { $$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::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 = ircd::conf_get_yesno_value($1); $$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t)); if (val != -1) { $$->type = CF_YESNO; $$->v.number = val; } else { $$->type = CF_STRING; $$->v.string = rb_strdup($1); } } ; loadmodule: LOADMODULE QSTRING { char *m_bn; m_bn = rb_basename((char *) $2); if (ircd::findmodule_byname(m_bn) == NULL) { ircd::load_one_module($2, MAPI_ORIGIN_EXTENSION, 0); } rb_free(m_bn); } ';' ; qstring: QSTRING { strcpy($$, $1); } ; string: STRING { strcpy($$, $1); } ; number: NUMBER { $$ = $1; } ; timespec: number string { time_t t; if ((t = ircd::conf_find_time($2)) == 0) { ircd::conf_report_error("Unrecognised time type/size '%s'", $2); t = 1; } $$ = $1 * t; } | timespec timespec { $$ = $1 + $2; } | timespec number { $$ = $1 + $2; } ;