From owner-freebsd-bugs Tue Jun 2 04:20:40 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id EAA05885 for freebsd-bugs-outgoing; Tue, 2 Jun 1998 04:20:40 -0700 (PDT) (envelope-from owner-freebsd-bugs@FreeBSD.ORG) Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id EAA05862 for ; Tue, 2 Jun 1998 04:20:33 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.8.8/8.8.5) id EAA16840; Tue, 2 Jun 1998 04:20:01 -0700 (PDT) Received: from www.in-design.com (www.in-design.com [206.210.93.16]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id EAA05078 for ; Tue, 2 Jun 1998 04:16:51 -0700 (PDT) (envelope-from nsmart@www.in-design.com) Received: (from nsmart@localhost) by www.in-design.com (8.8.7/8.8.5) id HAA05028; Tue, 2 Jun 1998 07:16:47 -0400 (EDT) Message-Id: <199806021116.HAA05028@www.in-design.com> Date: Tue, 2 Jun 1998 07:16:47 -0400 (EDT) From: njs3@doc.ic.ac.uk Reply-To: njs3@doc.ic.ac.uk To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: bin/6828: [PATCH] make(1) does not handle embedded variable expansion Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >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