%{ /* * configlexer.lex - lexical analyzer for unbound config file * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include "util/configyyrename.h" #include "util/config_file.h" #include "util/configparser.h" void ub_c_error(const char *message); #define YY_NO_UNPUT #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif struct inc_state { char* filename; int line; }; static struct inc_state parse_stack[MAXINCLUDES]; static YY_BUFFER_STATE include_stack[MAXINCLUDES]; static int config_include_stack_ptr = 0; static void config_start_include(const char* filename) { FILE *input; if(strlen(filename) == 0) { ub_c_error_msg("empty include file name"); return; } if(config_include_stack_ptr >= MAXINCLUDES) { ub_c_error_msg("includes nested too deeply, skipped (>%d)", MAXINCLUDES); return; } input = fopen(filename, "r"); if(!input) { ub_c_error_msg("cannot open include file '%s': %s", filename, strerror(errno)); return; } LEXOUT(("switch_to_include_file(%s) ", filename)); parse_stack[config_include_stack_ptr].filename = cfg_parser->filename; parse_stack[config_include_stack_ptr].line = cfg_parser->line; include_stack[config_include_stack_ptr] = YY_CURRENT_BUFFER; cfg_parser->filename = strdup(filename); cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); ++config_include_stack_ptr; } static void config_end_include(void) { --config_include_stack_ptr; free(cfg_parser->filename); cfg_parser->filename = parse_stack[config_include_stack_ptr].filename; cfg_parser->line = parse_stack[config_include_stack_ptr].line; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(include_stack[config_include_stack_ptr]); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif %} SPACE [ \t] LETTER [a-zA-Z] UNQUOTEDLETTER [^\"\n\r \t\\]|\\. NEWLINE [\r\n] COMMENT \# COLON \: ANY [^\"\n\r\\]|\\. %x quotedstring include include_quoted %% {SPACE}* { LEXOUT(("SP ")); /* ignore */ } {SPACE}*{COMMENT}.* { LEXOUT(("comment(%s) ", yytext)); /* ignore */ } server{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} num-threads{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NUM_THREADS;} verbosity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;} port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;} outgoing-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_PORT;} outgoing-range{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_RANGE;} outgoing-num-tcp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_NUM_TCP;} do-ip4{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;} do-ip6{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;} do-udp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_UDP;} do-tcp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_TCP;} forward-to{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_FORWARD_TO;} forward-to-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_FORWARD_TO_PORT;} interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_INTERFACE;} chroot{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;} username{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;} directory{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DIRECTORY;} logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;} pidfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;} msg-cache-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MSG_CACHE_SIZE;} msg-cache-slabs{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MSG_CACHE_SLABS;} rrset-cache-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRSET_CACHE_SIZE;} rrset-cache-slabs{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRSET_CACHE_SLABS;} num-queries-per-thread{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NUM_QUERIES_PER_THREAD;} {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} /* Quoted strings. Strip leading and ending quotes */ \" { BEGIN(quotedstring); LEXOUT(("QS ")); } <> { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("STR(%s) ", yytext)); yymore(); } \n { cfg_parser->line++; yymore(); } \" { LEXOUT(("QE ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; yylval.str = strdup(yytext); if(!yylval.str) yyerror("out of memory"); return STRING; } /* include: directive */ include{COLON} { LEXOUT(("v(%s) ", yytext)); BEGIN(include); } <> { yyerror("EOF inside include directive"); BEGIN(INITIAL); } {SPACE}* { LEXOUT(("ISP ")); /* ignore */ } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} \" { LEXOUT(("IQS ")); BEGIN(include_quoted); } {UNQUOTEDLETTER}* { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include(yytext); BEGIN(INITIAL); } <> { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } {NEWLINE} { cfg_parser->line++; yymore(); } \" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; config_start_include(yytext); BEGIN(INITIAL); } <> { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (config_include_stack_ptr == 0) { yyterminate(); } else { fclose(yyin); config_end_include(); } } {UNQUOTEDLETTER}* { LEXOUT(("unquotedstr(%s) ", yytext)); yylval.str = strdup(yytext); return STRING; } %%