
Property changes on: .
___________________________________________________________________
Added: svn:mergeinfo
   Merged /:r4874

Index: conf/conf.c
===================================================================
--- conf/conf.c	(revision 4962)
+++ conf/conf.c	(working copy)
@@ -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(c, 0);
   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(c, 1);
   cf_parse();
   return 1;
 }
@@ -356,6 +356,7 @@ cf_error(char *msg, ...)
     strcpy(buf, "<bug: error message too long>");
   new_config->err_msg = cfg_strdup(buf);
   new_config->err_lino = conf_lino;
+  new_config->err_fname = conf_fname;
   longjmp(conf_jmpbuf, 1);
 }
 
Index: conf/cf-lex.l
===================================================================
--- conf/cf-lex.l	(revision 4962)
+++ conf/cf-lex.l	(working copy)
@@ -30,6 +30,9 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgen.h>
 
 #define PARSER 1
 
@@ -64,18 +67,36 @@ struct sym_scope {
 static struct sym_scope *conf_this_scope;
 
 int conf_lino;
+char conf_fname[255];
+int conf_fd;
 
+char conf_base[255];
+
 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);
 
-#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
-#define YY_NO_UNPUT
+#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, STACK(conf_fd));
 #define YY_FATAL_ERROR(msg) cf_error(msg)
 
+#define MAX_INCLUDE_DEPTH	42
+struct include_file_stack {
+	YY_BUFFER_STATE	stack; /* Internal lexer state */
+	unsigned int	conf_lino; /* Current file lineno (at include) */
+	char		conf_fname[255]; /* Current file name */
+	int		conf_fd; /* Current file descriptor */
+};
+
+static struct include_file_stack ifs[MAX_INCLUDE_DEPTH];
+static int ifs_ind; /* Current stack depth */
+#define STACK(x)	ifs[ifs_ind].x
+
+static void dispatch_include(void);
+static int check_eof(void);
+
 %}
 
 %option noyywrap
@@ -90,9 +111,12 @@ DIGIT [0-9]
 XIGIT [0-9a-fA-F]
 ALNUM [a-zA-Z_0-9]
 WHITE [ \t]
+include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
 
 %%
 
+{include} { dispatch_include(); }
+
 {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
 #ifdef IPV6
   if (ipv4_pton_u32(yytext, &cf_lval.i32))
@@ -188,7 +212,7 @@ else: {
 
 ["][^"\n]*\n	cf_error("Unterminated string");
 
-<INITIAL,COMMENT><<EOF>>	return END;
+<INITIAL,COMMENT><<EOF>>	{ if (check_eof()) return END; }
 
 {WHITE}+
 
@@ -224,7 +248,69 @@ else: {
 
 %%
 
+/* Open included file with properly swapped buffers */
+static void
+dispatch_include(void)
+{
+	char *fname, *p = NULL, full_name[255];
+	int fd;
+
+	if ((fname = strchr(yytext, '"')) != NULL) {
+		if ((p = strchr(++fname, '"')) != NULL)
+			*p = '\0';
+
+		if (*fname == '/')
+			snprintf(full_name, sizeof(full_name), "%s", fname);
+		else
+			snprintf(full_name, sizeof(full_name), "%s/%s", conf_base, fname);
+
+		if (ifs_ind >= MAX_INCLUDE_DEPTH)
+			cf_error("Max include depth (%d) reached on file %s", MAX_INCLUDE_DEPTH, fname);
+
+		if ((fd = open(full_name, O_RDONLY)) == -1)
+			cf_error("Error opening included file %s", full_name);
+
+		/* Save current stack */
+		STACK(conf_lino) = conf_lino;
+		STACK(stack) = YY_CURRENT_BUFFER;
+		/* Prepare new stack */
+		ifs_ind++;
+		STACK(conf_lino) = 1;
+		strcpy(STACK(conf_fname), fname); /* XXX: strlcpy should be here */
+		STACK(conf_fd) = fd;
+		/* Export to global variables */
+		conf_lino = STACK(conf_lino);
+		conf_fd = STACK(conf_fd);
+		strcpy(conf_fname, STACK(conf_fname));
+
+		printf("DDD %s:%d switch %s:%d\n", __FUNCTION__, __LINE__, conf_fname, conf_lino);
+
+		yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+	}
+}
+
 static int
+check_eof(void)
+{
+	if (ifs_ind > 0)
+		close(STACK(conf_fd));
+	if (--ifs_ind < 0) {
+		/* EOF in main config file */
+		ifs_ind = 0;
+		conf_lino = 1;
+		return 1;
+	}
+
+	/* switch buffer */
+	conf_lino = STACK(conf_lino);
+	conf_fd = STACK(conf_fd);
+	strcpy(conf_fname, STACK(conf_fname));
+	yy_delete_buffer(YY_CURRENT_BUFFER);
+	yy_switch_to_buffer(STACK(stack));
+	return 0;
+}
+
+static int
 cf_hash(byte *c)
 {
   unsigned int h = 13;
@@ -367,11 +453,28 @@ cf_lex_init_kh(void)
  * parsing of a new input.
  */
 void
-cf_lex_init(int is_cli)
+cf_lex_init(struct config *c, int is_cli)
 {
   if (!kw_hash_inited)
     cf_lex_init_kh();
   conf_lino = 1;
+  /* Zero stack */
+  memset(ifs, 0, sizeof(ifs));
+  memset(conf_base, 0, sizeof(conf_base));
+  ifs_ind = 0;
+  if (!is_cli) {
+    /* Fill in level 0 */
+    STACK(conf_lino) = 1;
+    STACK(conf_fd) = c->file_fd;
+    strcpy(STACK(conf_fname), c->file_name);
+    /* Save config directory path */
+    strcpy(conf_base, dirname(STACK(conf_fname)));
+  }
+  /* Export to global variables */
+  conf_lino = STACK(conf_lino);
+  conf_fd = STACK(conf_fd);
+  strcpy(conf_fname, STACK(conf_fname));
+
   yyrestart(NULL);
   if (is_cli)
     BEGIN(CLI);
Index: conf/conf.h
===================================================================
--- conf/conf.h	(revision 4962)
+++ conf/conf.h	(working copy)
@@ -38,7 +38,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 *err_fname;			/* File name containing error */
   char *file_name;			/* Name of configuration file */
+  int file_fd;				/* Config file descriptor */
   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 +85,7 @@ 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);
 
 struct symbol {
   struct symbol *next;
@@ -107,9 +109,10 @@ struct symbol {
 #define SYM_VARIABLE 0x100	/* 0x100-0x1ff are variable types */
 
 extern int conf_lino;
+extern char conf_fname[255];
 
 int cf_lex(void);
-void cf_lex_init(int is_cli);
+void cf_lex_init(struct config *c, int is_cli);
 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);
Index: doc/bird.conf.example
===================================================================
--- doc/bird.conf.example	(revision 4962)
+++ doc/bird.conf.example	(working copy)
@@ -22,6 +22,9 @@
 #	else reject;
 #}
 
+# Write more filters in included config file(s):
+#include "filters.conf";
+
 #filter sink { reject; }
 #filter okay { accept; }
 
Index: sysdep/unix/main.c
===================================================================
--- sysdep/unix/main.c	(revision 4962)
+++ sysdep/unix/main.c	(working copy)
@@ -149,13 +149,12 @@ read_iproute_table(char *file, char *prefix, int m
 #endif // PATH_IPROUTE_DIR
 
 
-static int conf_fd;
 static char *config_name = PATH_CONFIG;
 
 static int
-cf_read(byte *dest, unsigned int len)
+cf_read(byte *dest, unsigned int len, int fd)
 {
-  int l = read(conf_fd, dest, len);
+  int l = read(fd, dest, len);
   if (l < 0)
     cf_error("Read error");
   return l;
@@ -185,15 +184,15 @@ static int
 unix_read_config(struct config **cp, char *name)
 {
   struct config *conf = config_alloc(name);
-  int ret;
+  int ret, fd;
 
   *cp = conf;
-  conf_fd = open(name, O_RDONLY);
-  if (conf_fd < 0)
+  if ((fd = open(name, O_RDONLY)) == -1)
     return 0;
+  conf->file_fd = fd;
   cf_read_hook = cf_read;
   ret = config_parse(conf);
-  close(conf_fd);
+  close(fd);
   return ret;
 }
 
@@ -205,7 +204,7 @@ read_config(void)
   if (!unix_read_config(&conf, config_name))
     {
       if (conf->err_msg)
-	die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
+	die("%s, line %d: %s", conf->err_fname, conf->err_lino, conf->err_msg);
       else
 	die("Unable to open configuration file %s: %m", config_name);
     }
@@ -221,7 +220,7 @@ async_config(void)
   if (!unix_read_config(&conf, config_name))
     {
       if (conf->err_msg)
-	log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
+	log(L_ERR "%s, line %d: %s", conf->err_fname, conf->err_lino, conf->err_msg);
       else
 	log(L_ERR "Unable to open configuration file %s: %m", config_name);
       config_free(conf);
@@ -244,7 +243,7 @@ cmd_reconfig(char *name, int type)
   if (!unix_read_config(&conf, name))
     {
       if (conf->err_msg)
-	cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
+	cli_msg(8002, "%s, line %d: %s", conf->err_fname, conf->err_lino, conf->err_msg);
       else
 	cli_msg(8002, "%s: %m", name);
       config_free(conf);
