diff options
author | Ondrej Filip <feela@network.cz> | 2011-09-11 21:21:47 +0200 |
---|---|---|
committer | Ondrej Filip <feela@network.cz> | 2011-09-11 21:21:47 +0200 |
commit | 48ec367aabaaa5328f4072d237001e245a7363df (patch) | |
tree | 9a65d5e1b051ff6aa24cd036ff1930bcb370fb8b /conf/cf-lex.l | |
parent | a98995273bd8788cf525f44479026d5ce6b7dd52 (diff) |
Configuration can include other files.
Diffstat (limited to 'conf/cf-lex.l')
-rw-r--r-- | conf/cf-lex.l | 89 |
1 files changed, 80 insertions, 9 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l index a5f70fff..79dbab29 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"); -<INITIAL,COMMENT><<EOF>> return END; +<INITIAL,COMMENT><<EOF>> { if(check_eof()) return END; } {WHITE}+ -\n conf_lino++; +\n ifs->conf_lino++; # BEGIN(COMMENT); @@ -201,14 +211,14 @@ else: { . cf_error("Unknown character"); <COMMENT>\n { - conf_lino++; + ifs->conf_lino++; BEGIN(INITIAL); } <COMMENT>. <CCOMM>\*\/ BEGIN(INITIAL); -<CCOMM>\n conf_lino++; +<CCOMM>\n ifs->conf_lino++; <CCOMM>\/\* cf_error("Comment nesting not supported"); <CCOMM><<EOF>> cf_error("Unterminated comment"); <CCOMM>. @@ -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); |