Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Jun 1998 07:16:47 -0400 (EDT)
From:      njs3@doc.ic.ac.uk
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/6828: [PATCH] make(1) does not handle embedded variable expansion
Message-ID:  <199806021116.HAA05028@www.in-design.com>

next in thread | raw e-mail | index | archive | help

>Number:         6828
>Category:       bin
>Synopsis:       [PATCH] make(1) does not handle embedded variable expansion
>Confidential:   yes
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun  2 04:20:01 PDT 1998
>Last-Modified:
>Originator:     nsmart
>Organization:
Hierarchial
>Release:        FreeBSD 2.2.5-RELEASE i386
>Environment:

>Description:

make(1) does not handle embedded variable expansion, e.g:

FOO	= bar
BAR	= FOO

all:
	echo ${${BAR}}

>How-To-Repeat:

>Fix:
	
Here is a patch based on one used by NetBSD.  I'd let it stew in -current
for a couple of days at least.  The NetBSD folks have lots of other nice
stuff in their make if anyone fancies merging it.  Don't import the change
they made to the behaviour of ${.PREFIX} though (contact me for details).

*** var.c	Mon Sep 29 00:00:00 1997
--- var.c	Sun May 31 18:49:48 1998
***************
*** 1114,1119 ****
--- 1117,1124 ----
  				 * expanding it in a non-local context. This
  				 * is done to support dynamic sources. The
  				 * result is just the invocation, unaltered */
+     int		vlen;		/* length of variable name, after embedded variable
+ 				 * expansion */
  
      *freePtr = FALSE;
      dynamic = FALSE;
***************
*** 1165,1187 ****
  	    endc = str[1];
  	}
      } else {
  	startc = str[1];
  	endc = startc == '(' ? ')' : '}';
  
  	/*
! 	 * Skip to the end character or a colon, whichever comes first.
  	 */
! 	for (tstr = str + 2;
! 	     *tstr != '\0' && *tstr != endc && *tstr != ':';
! 	     tstr++)
! 	{
! 	    continue;
! 	}
! 	if (*tstr == ':') {
! 	    haveModifier = TRUE;
! 	} else if (*tstr != '\0') {
! 	    haveModifier = FALSE;
! 	} else {
  	    /*
  	     * If we never did find the end character, return NULL
  	     * right now, setting the length to be the distance to
--- 1170,1203 ----
  	    endc = str[1];
  	}
      } else {
+ 	/* build up expanded variable name in this buffer */
+ 	Buffer	buf = Buf_Init(MAKE_BSIZE);
+ 
  	startc = str[1];
  	endc = startc == '(' ? ')' : '}';
  
  	/*
! 	 * Skip to the end character or a colon, whichever comes first,
! 	 * replacing embedded variables as we go.
  	 */
! 	for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':'; tstr++)
! 		if (*tstr == '$') {
! 			int	rlen;
! 			Boolean	rfree;
! 			char*	rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);
!                 
! 			if (rval == var_Error) {
! 				Fatal("Error expanding embedded variable.");
! 			} else if (rval != NULL) {
! 				Buf_AddBytes(buf, strlen(rval), (Byte *) rval);
! 				if (rfree)
! 					free(rval);
! 			}
! 			tstr += rlen - 1;
! 		} else
! 			Buf_AddByte(buf, (Byte) *tstr);
! 	
! 	if (*tstr == '\0') {
  	    /*
  	     * If we never did find the end character, return NULL
  	     * right now, setting the length to be the distance to
***************
*** 1190,1206 ****
  	    *lengthPtr = tstr - str;
  	    return (var_Error);
  	}
  	*tstr = '\0';
  
! 	v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
  	if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
! 	    ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D'))
  	{
  	    /*
  	     * Check for bogus D and F forms of local variables since we're
  	     * in a local context and the name is the right length.
  	     */
! 	    switch(str[2]) {
  		case '@':
  		case '%':
  		case '*':
--- 1206,1228 ----
  	    *lengthPtr = tstr - str;
  	    return (var_Error);
  	}
+ 	
+ 	haveModifier = (*tstr == ':');
  	*tstr = '\0';
  
! 	Buf_AddByte(buf, (Byte) '\0');
! 	str = Buf_GetAll(buf, NULL);
! 	vlen = strlen(str);
! 
! 	v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
  	if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
! 	    (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
  	{
  	    /*
  	     * Check for bogus D and F forms of local variables since we're
  	     * in a local context and the name is the right length.
  	     */
! 	    switch(str[0]) {
  		case '@':
  		case '%':
  		case '*':
***************
*** 1214,1220 ****
  		    /*
  		     * Well, it's local -- go look for it.
  		     */
! 		    vname[0] = str[2];
  		    vname[1] = '\0';
  		    v = VarFind(vname, ctxt, 0);
  
--- 1236,1242 ----
  		    /*
  		     * Well, it's local -- go look for it.
  		     */
! 		    vname[0] = str[0];
  		    vname[1] = '\0';
  		    v = VarFind(vname, ctxt, 0);
  
***************
*** 1222,1232 ****
  			/*
  			 * No need for nested expansion or anything, as we're
  			 * the only one who sets these things and we sure don't
! 			 * but nested invocations in them...
  			 */
  			val = (char *)Buf_GetAll(v->val, (int *)NULL);
  
! 			if (str[3] == 'D') {
  			    val = VarModify(val, VarHead, (ClientData)0);
  			} else {
  			    val = VarModify(val, VarTail, (ClientData)0);
--- 1244,1254 ----
  			/*
  			 * No need for nested expansion or anything, as we're
  			 * the only one who sets these things and we sure don't
! 			 * put nested invocations in them...
  			 */
  			val = (char *)Buf_GetAll(v->val, (int *)NULL);
  
! 			if (str[1] == 'D') {
  			    val = VarModify(val, VarHead, (ClientData)0);
  			} else {
  			    val = VarModify(val, VarTail, (ClientData)0);
***************
*** 1238,1243 ****
--- 1260,1266 ----
  			*freePtr = TRUE;
  			*lengthPtr = tstr-start+1;
  			*tstr = endc;
+ 			Buf_Destroy(buf, TRUE);
  			return(val);
  		    }
  		    break;
***************
*** 1246,1254 ****
  	}
  
  	if (v == (Var *)NIL) {
! 	    if ((((tstr-str) == 3) ||
! 		 ((((tstr-str) == 4) && (str[3] == 'F' ||
! 					 str[3] == 'D')))) &&
  		((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  	    {
  		/*
--- 1269,1277 ----
  	}
  
  	if (v == (Var *)NIL) {
! 	    if (((vlen == 1) ||
! 		 (((vlen == 2) && (str[1] == 'F' ||
! 					 str[1] == 'D')))) &&
  		((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  	    {
  		/*
***************
*** 1260,1266 ****
  		 * specially as they are the only four that will be set
  		 * when dynamic sources are expanded.
  		 */
! 		switch (str[2]) {
  		    case '@':
  		    case '%':
  		    case '*':
--- 1283,1289 ----
  		 * specially as they are the only four that will be set
  		 * when dynamic sources are expanded.
  		 */
! 		switch (str[0]) {
  		    case '@':
  		    case '%':
  		    case '*':
***************
*** 1268,1284 ****
  			dynamic = TRUE;
  			break;
  		}
! 	    } else if (((tstr-str) > 4) && (str[2] == '.') &&
! 		       isupper((unsigned char) str[3]) &&
  		       ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  	    {
  		int	len;
  
! 		len = (tstr-str) - 3;
! 		if ((strncmp(str+2, ".TARGET", len) == 0) ||
! 		    (strncmp(str+2, ".ARCHIVE", len) == 0) ||
! 		    (strncmp(str+2, ".PREFIX", len) == 0) ||
! 		    (strncmp(str+2, ".MEMBER", len) == 0))
  		{
  		    dynamic = TRUE;
  		}
--- 1291,1307 ----
  			dynamic = TRUE;
  			break;
  		}
! 	    } else if ((vlen > 2) && (str[0] == '.') &&
! 		       isupper((unsigned char) str[1]) &&
  		       ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  	    {
  		int	len;
  
! 		len = vlen - 1;
! 		if ((strncmp(str, ".TARGET", len) == 0) ||
! 		    (strncmp(str, ".ARCHIVE", len) == 0) ||
! 		    (strncmp(str, ".PREFIX", len) == 0) ||
! 		    (strncmp(str, ".MEMBER", len) == 0))
  		{
  		    dynamic = TRUE;
  		}
***************
*** 1296,1303 ****
--- 1319,1328 ----
  		    strncpy(str, start, *lengthPtr);
  		    str[*lengthPtr] = '\0';
  		    *freePtr = TRUE;
+ 		    Buf_Destroy(buf, TRUE);
  		    return(str);
  		} else {
+ 		    Buf_Destroy(buf, TRUE);
  		    return (err ? var_Error : varNoError);
  		}
  	    } else {
***************
*** 1311,1316 ****
--- 1336,1342 ----
  		v->flags = VAR_JUNK;
  	    }
  	}
+ 	Buf_Destroy(buf, TRUE);
      }
  
      if (v->flags & VAR_IN_USE) {
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199806021116.HAA05028>