summaryrefslogtreecommitdiff
path: root/conf/cf-lex.l
diff options
context:
space:
mode:
authorOndrej Filip <feela@network.cz>2011-09-11 21:21:47 +0200
committerOndrej Filip <feela@network.cz>2011-09-11 21:21:47 +0200
commit48ec367aabaaa5328f4072d237001e245a7363df (patch)
tree9a65d5e1b051ff6aa24cd036ff1930bcb370fb8b /conf/cf-lex.l
parenta98995273bd8788cf525f44479026d5ce6b7dd52 (diff)
Configuration can include other files.
Diffstat (limited to 'conf/cf-lex.l')
-rw-r--r--conf/cf-lex.l89
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);