From 48ec367aabaaa5328f4072d237001e245a7363df Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Sun, 11 Sep 2011 21:21:47 +0200 Subject: Configuration can include other files. --- conf/cf-lex.l | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ conf/conf.c | 7 +++-- conf/conf.h | 23 ++++++++++++--- 3 files changed, 103 insertions(+), 16 deletions(-) (limited to 'conf') diff --git a/conf/cf-lex.l b/conf/cf-lex.l index a5f70ff..79dbab2 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -63,19 +63,27 @@ struct sym_scope { }; static struct sym_scope *conf_this_scope; -int conf_lino; +#define MAX_INCLUDE_DEPTH 5 + +static struct include_file_stack *ifs_head; +static int ifs_depth; static int cf_hash(byte *c); static struct symbol *cf_find_sym(byte *c, unsigned int h0); linpool *cfg_mem; -int (*cf_read_hook)(byte *buf, unsigned int max); +int (*cf_read_hook)(byte *buf, unsigned int max, int fd); +int (*cf_open_hook)(char *filename); -#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max); +#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->conf_fd); #define YY_NO_UNPUT #define YY_FATAL_ERROR(msg) cf_error(msg) +static void new_include(void); +static int check_eof(void); +static struct include_file_stack *new_stack(struct include_file_stack *old); + %} %option noyywrap @@ -90,8 +98,10 @@ DIGIT [0-9] XIGIT [0-9a-fA-F] ALNUM [a-zA-Z_0-9] WHITE [ \t] +include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; %% +{include} { if(cf_open_hook) new_include(); } {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { #ifdef IPV6 @@ -188,11 +198,11 @@ else: { ["][^"\n]*\n cf_error("Unterminated string"); -<> return END; +<> { if(check_eof()) return END; } {WHITE}+ -\n conf_lino++; +\n ifs->conf_lino++; # BEGIN(COMMENT); @@ -201,14 +211,14 @@ else: { . cf_error("Unknown character"); \n { - conf_lino++; + ifs->conf_lino++; BEGIN(INITIAL); } . \*\/ BEGIN(INITIAL); -\n conf_lino++; +\n ifs->conf_lino++; \/\* cf_error("Comment nesting not supported"); <> cf_error("Unterminated comment"); . @@ -234,6 +244,50 @@ cf_hash(byte *c) return h; } +/* Open included file with properly swapped buffers */ +static void +new_include(void) +{ + char *fname, *p = NULL; + + if ((fname = strchr(yytext, '"')) != NULL) { + + if ((p = strchr(++fname, '"')) != NULL) *p = '\0'; + + if (ifs_depth >= MAX_INCLUDE_DEPTH) + cf_error("Max include depth reached."); + + /* Save current stack */ + ifs->stack = YY_CURRENT_BUFFER; + /* Prepare new stack */ + ifs->next = new_stack(ifs); + ifs = ifs->next; + strcpy(ifs->conf_fname, fname); /* XXX: strlcpy should be here */ + ifs->conf_fd = cf_open_hook(fname); + + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + } +} + +static int +check_eof(void) +{ + if (ifs == ifs_head) { + /* EOF in main config file */ + ifs->conf_lino = 1; + return 1; + } + + ifs_depth--; + close(ifs->conf_fd); + ifs = ifs->prev; + ifs->next = NULL; + + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(ifs->stack); + return 0; +} + static struct symbol * cf_new_sym(byte *c, unsigned int h) { @@ -359,6 +413,16 @@ cf_lex_init_kh(void) kw_hash_inited = 1; } +static struct include_file_stack * +new_stack(struct include_file_stack *old) +{ + struct include_file_stack *ret; + ret = cfg_allocz(sizeof(struct include_file_stack)); + ret->conf_lino = 1; + ret->prev = old; + return ret; +} + /** * cf_lex_init - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration @@ -367,11 +431,18 @@ cf_lex_init_kh(void) * parsing of a new input. */ void -cf_lex_init(int is_cli) +cf_lex_init(int is_cli, struct config *c) { if (!kw_hash_inited) cf_lex_init_kh(); - conf_lino = 1; + ifs_head = new_stack(NULL); + ifs = ifs_head; + ifs_depth = 0; + if (!is_cli) { + ifs->conf_fd = c->file_fd; + ifs_depth = 1; + strcpy(ifs->conf_fname, c->file_name); + } yyrestart(NULL); if (is_cli) BEGIN(CLI); diff --git a/conf/conf.c b/conf/conf.c index 604a412..5bdeece 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -108,7 +108,7 @@ config_parse(struct config *c) cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) return 0; - cf_lex_init(0); + cf_lex_init(0, c); sysdep_preconfig(c); protos_preconfig(c); rt_preconfig(c); @@ -138,7 +138,7 @@ cli_parse(struct config *c) cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) return 0; - cf_lex_init(1); + cf_lex_init(1, c); cf_parse(); return 1; } @@ -355,7 +355,8 @@ cf_error(char *msg, ...) if (bvsnprintf(buf, sizeof(buf), msg, args) < 0) strcpy(buf, ""); new_config->err_msg = cfg_strdup(buf); - new_config->err_lino = conf_lino; + new_config->err_lino = ifs->conf_lino; + new_config->err_file_name = ifs->conf_fname; longjmp(conf_jmpbuf, 1); } diff --git a/conf/conf.h b/conf/conf.h index 6c784d7..df77268 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -12,6 +12,8 @@ #include "lib/resource.h" #include "lib/timer.h" +#define BIRD_FNAME_MAX 255 /* Would be better to use some UNIX define */ + /* Configuration structure */ struct config { @@ -38,7 +40,9 @@ struct config { int cli_debug; /* Tracing of CLI connections and commands */ char *err_msg; /* Parser error message */ int err_lino; /* Line containing error */ - char *file_name; /* Name of configuration file */ + char *err_file_name; /* File name containing error */ + char *file_name; /* Name of main configuration file */ + int file_fd; /* File descriptor of main configuration file */ struct symbol **sym_hash; /* Lexer: symbol hash table */ struct symbol **sym_fallback; /* Lexer: fallback symbol hash table */ int obstacle_count; /* Number of items blocking freeing of this config */ @@ -83,7 +87,8 @@ char *cfg_strdup(char *c); /* Lexer */ -extern int (*cf_read_hook)(byte *buf, unsigned int max); +extern int (*cf_read_hook)(byte *buf, unsigned int max, int fd); +extern int (*cf_open_hook)(char *filename); struct symbol { struct symbol *next; @@ -106,10 +111,20 @@ struct symbol { #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ -extern int conf_lino; +struct include_file_stack { + void *stack; /* Internal lexer state */ + unsigned int conf_lino; /* Current file lineno (at include) */ + char conf_fname[BIRD_FNAME_MAX]; /* Current file name */ + int conf_fd; /* Current file descriptor */ + struct include_file_stack *prev; + struct include_file_stack *next; +}; + +struct include_file_stack *ifs; + int cf_lex(void); -void cf_lex_init(int is_cli); +void cf_lex_init(int is_cli, struct config *c); struct symbol *cf_find_symbol(byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); -- cgit v1.2.3