Subject: Patch to config(8) to allow inclusions relative to the file being included
To: None <tech-kern@netbsd.org>
From: Jason Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 09/03/2003 11:55:24
--Apple-Mail-3-556261988
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

Hi folks...

The following patch allows file inclusions relative to the file being 
included.  This is useful if, say, you have a config file with multiple 
fragments that is kept outside the kernel source tree.  It allows you 
to e.g.:

include "arch/i386/conf/GENERIC"
include "./CONFIG.frag1"
include "./CONFIG.frag2"
include "./../../feature/config.feature"

...and "config.feature" would be able to say:

include "./../someotherfeature/config.someotherfeature"

What the change does is track the "current directory" of the file 
currently being parsed, and when it encouters "./" at the beginning of 
an include'd file name, interprets the remainder of the file name as 
relative to the "current directory".

I decided on the "./" as the trigger mostly to avoid changing the 
syntax for traditional include directives.  In a perfect world, 
srcdir-relative includes would be include <...> and curdir-relative 
includes would be include "...", but alas, we do not live in a perfect 
world at the moment.

Since the change is simple, and does not affect any existing config 
file or fragment, I'll check it in now.

         -- Jason R. Thorpe <thorpej@wasabisystems.com>

--Apple-Mail-3-556261988
Content-Disposition: attachment;
	filename=config-include.diff
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="config-include.diff"

Index: defs.h
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/defs.h,v
retrieving revision 1.12
diff -c -r1.12 defs.h
*** defs.h	2003/08/07 11:25:15	1.12
--- defs.h	2003/09/03 18:39:57
***************
*** 394,399 ****
--- 394,400 ----
  
  SLIST_HEAD(, prefix)	prefixes,	/* prefix stack */
  			allprefixes;	/* all prefixes used (after popped) */
+ SLIST_HEAD(, prefix)	curdirs;	/* curdir stack */
  
  struct	devi **packed;		/* arrayified table for packed devi's */
  int	npacked;		/* size of packed table, <= ndevi */
Index: scan.l
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/scan.l,v
retrieving revision 1.38
diff -c -r1.38 scan.l
*** scan.l	2003/08/07 11:25:17	1.38
--- scan.l	2003/09/03 18:39:57
***************
*** 193,198 ****
--- 193,238 ----
  
  int interesting = 1;
  
+ static int
+ curdir_push(const char *fname)
+ {
+ 	struct prefix *pf;
+ 	char *p, *d, *f;
+ 
+ 	/* Set up the initial "current directory" for include directives. */
+ 	d = dirname(f = estrdup(fname));
+ 	free(f);
+ 	if (*d == '/')
+ 		p = estrdup(d);
+ 	else {
+ 		char *cwd, buf[PATH_MAX];
+ 
+ 		if ((cwd = getcwd(buf, sizeof(buf))) == NULL)
+ 			return (-1);
+ 		p = emalloc(strlen(cwd) + strlen(d) + 2);
+ 		sprintf(p, "%s/%s", cwd, d);
+ 	}
+ 	pf = emalloc(sizeof(*pf));
+ 	pf->pf_prefix = p;
+ 	SLIST_INSERT_HEAD(&curdirs, pf, pf_next);
+ 
+ 	return (0);
+ }
+ 
+ static void
+ curdir_pop(void)
+ {
+ 	struct prefix *pf;
+ 
+ 	pf = SLIST_FIRST(&curdirs);
+ 	SLIST_REMOVE_HEAD(&curdirs, pf_next);
+ 	if (SLIST_EMPTY(&curdirs))
+ 		panic("curdirs is empty");
+ 	/* LINTED cast away const (pf_prefix is malloc'd for curdirs) */
+ 	free((void *)pf->pf_prefix);
+ 	free(pf);
+ }
+ 
  /*
   * Open the "main" file (conffile).
   */
***************
*** 206,211 ****
--- 246,255 ----
  	if ((yyin = fopen(fname, "r")) == NULL)
  #endif
  		return (-1);
+ 
+ 	if (curdir_push(fname) == -1)
+ 		return (-1);
+ 
  	yyfile = conffile = fname;
  	yyline = 1;
  	return (0);
***************
*** 261,267 ****
  		setupdirs();
  	}
  
! 	s = (*fname == '/') ? estrdup(fname) : sourcepath(fname);
  	if ((fp = fopen(s, "r")) == NULL) {
  		if (conditional == 0)
  			error("cannot open %s for reading: %s\n", s,
--- 305,318 ----
  		setupdirs();
  	}
  
! 	if (fname[0] == '/')
! 		s = estrdup(fname);
! 	else if (fname[0] == '.' && fname[1] == '/') {
! 		struct prefix *pf = SLIST_FIRST(&curdirs);
! 		s = emalloc(strlen(pf->pf_prefix) + strlen(fname));
! 		sprintf(s, "%s/%s", pf->pf_prefix, fname + 2);
! 	} else
! 		s = sourcepath(fname);
  	if ((fp = fopen(s, "r")) == NULL) {
  		if (conditional == 0)
  			error("cannot open %s for reading: %s\n", s,
***************
*** 272,277 ****
--- 323,334 ----
  		free(s);
  		return (-1);
  	}
+ 	if (curdir_push(s) == -1) {
+ 		error("cannot record current working directory for %s\n", s);
+ 		fclose(fp);
+ 		free(s);
+ 		return (-1);
+ 	}
  	in = emalloc(sizeof *in);
  	in->in_prev = incl;
  	in->in_buf = YY_CURRENT_BUFFER;
***************
*** 299,304 ****
--- 356,362 ----
  	struct incl *in;
  	int ateof;
  
+ 	curdir_pop();
  	if ((in = incl) == NULL)
  		panic("endinclude");
  	incl = in->in_prev;

--Apple-Mail-3-556261988--