NetBSD Problem Report #15233

Received: (qmail 22917 invoked from network); 13 Jan 2002 14:23:48 -0000
Message-Id: <200201131423.JAA06315@Sparkle.Rodents.Montreal.QC.CA>
Date: Sun, 13 Jan 2002 09:23:45 -0500 (EST)
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
Reply-To: mouse@Rodents.Montreal.QC.CA
To: gnats-bugs@gnats.netbsd.org
Subject: [dM] make: .if broken inside .for
X-Send-Pr-Version: 3.95

>Number:         15233
>Category:       bin
>Synopsis:       [dM] make: .if broken inside .for
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jan 13 14:25:00 +0000 2002
>Closed-Date:    Sun Dec 21 19:43:56 +0000 2008
>Last-Modified:  Sun Dec 21 19:43:56 +0000 2008
>Originator:     der Mouse
>Release:        1.4T, appears to be present in 1.5
>Organization:
	Dis-
>Environment:
	Any (noticed on SPARC 1.4T, verified present on i386 1.5)
>Description:
	Attempting to use .if to test the control variable of a .for
	loop breaks, complaining about "Malformed conditional".  This
	appears to be because the .if is replicated by the .for and the
	variable expansion occurs then, before the .if is parsed; by
	the time the conditional parser runs, there is no variable
	reference left for it to notice, and it refuses to compare two
	constant strings.  This can be worked around with an empty
	dummy variable, but it's ugly and shouldn't be necessary.
>How-To-Repeat:
	% cat test.make
	.PHONY: test
	test:
	.for x in one two three
	.if $(x) == "one"
		echo one
	.else
		echo default $(x)
	.endif
	.endfor
	% make -n -f test.make
	"test.make", line 1: Malformed conditional (one == "one")
	"test.make", line 1: Need an operator
	"test.make", line 3: if-less else
	"test.make", line 3: Need an operator
	"test.make", line 5: if-less endif
	"test.make", line 5: Need an operator
	"test.make", line 1: Malformed conditional (two == "one")
	"test.make", line 1: Need an operator
	"test.make", line 3: if-less else
	"test.make", line 3: Need an operator
	"test.make", line 5: if-less endif
	"test.make", line 5: Need an operator
	"test.make", line 1: Malformed conditional (three == "one")
	"test.make", line 1: Need an operator
	"test.make", line 3: if-less else
	"test.make", line 3: Need an operator
	"test.make", line 5: if-less endif
	"test.make", line 5: Need an operator
	Fatal errors encountered -- cannot continue
	% 
>Fix:
	The empty variable workaround I referred to above looks like
	this:

	d=
	.PHONY: test
	test:
	.for x in one two three
	.if $(d)$(x) == "one"
		echo one
	.else
		echo default $(x)
	.endif
	.endfor

	I am working on this and expect to have a fix soon, by making
	the conditional parser willing to compare two constant quoted
	strings (which will make it work to use `.if "$(x)" == "one"',
	perhaps not optimal, but better than nothing - as a side
	effect, quoted LHSs will work outside .for loops as well).
	This PR has two purposes; (1) ensure it doesn't get totally
	forgotten if for any reason I don't have a fix as soon as I
	expect and (2) provide something for searches to find if anyone
	else runs into this and searches for related PRs.

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
>Release-Note:
>Audit-Trail:

From: der Mouse <mouse@Rodents.Montreal.QC.CA>
To: gnats-bugs@netbsd.org
Cc:  
Subject: Re: bin/15233: [dM] make: .if broken inside .for
Date: Sun, 13 Jan 2002 10:40:47 -0500 (EST)

 Here's the patch I've developed.  As the first line implies, this is
 for cond.c 1.11; -current is 1.12.  I've looked at cvs diff -r 1.11 -r
 1.12 and the changes are nowhere near the code affected by this; patch
 applies it cleanly except for line number offsets, and the offset is
 exactly what it should be.  (Indeed, I'd send the 1.12 diff except that
 this is the one I've actually been able to test personally.)

 /*	$NetBSD: cond.c,v 1.11 1998/09/18 20:35:11 christos Exp $	*/
 --- OLD/usr.bin/make/cond.c	Thu Jan  1 00:00:00 1970
 +++ NEW/usr.bin/make/cond.c	Thu Jan  1 00:00:00 1970
 @@ -82,6 +82,8 @@
   *	T -> $(varspec) op value
   *	T -> $(varspec) == "string"
   *	T -> $(varspec) != "string"
 + *	T -> "string" == "string"
 + *	T -> "string" != "string"
   *	T -> ( E )
   *	T -> ! T
   *	op -> == | != | > | < | >= | <=
 @@ -570,6 +572,60 @@
  		    Buf_Destroy(buf, FALSE);

  		    doFree = TRUE;
 +		}
 +
 +		if (0) {
 +		    char    *cp, *cp2;
 +		    int	    qt;
 +		    Buffer  buf;
 +	    case '"':
 +		    /*
 +		     * Collect quoted lhs.
 +		     */
 +
 +		    buf = Buf_Init(0);
 +		    qt = 1;
 +
 +		    for (cp = &condExpr[qt];
 +			 (qt ? (*cp != '"')
 +			     : (strchr(" \t)", *cp) == NULL)) &&
 +			 (*cp != '\0'); cp++) {
 +			if ((*cp == '\\') && (cp[1] != '\0')) {
 +			    /*
 +			     * Backslash escapes things -- skip over next
 +			     * character, if it exists.
 +			     */
 +			    cp++;
 +			    Buf_AddByte(buf, (Byte)*cp);
 +			} else if (*cp == '$') {
 +			    int	len;
 +			    Boolean freeIt;
 +
 +			    cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);
 +			    if (cp2 != var_Error) {
 +				Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
 +				if (freeIt) {
 +				    free(cp2);
 +				}
 +				cp += len - 1;
 +			    } else {
 +				Buf_AddByte(buf, (Byte)*cp);
 +			    }
 +			} else {
 +			    Buf_AddByte(buf, (Byte)*cp);
 +			}
 +		    }
 +
 +		    /*
 +		     * At first blush we want to use qt?cp+1:cp here,
 +		     *  but *cp is skippable either way.
 +		     */
 +		    condExpr = cp + 1;
 +
 +		    Buf_AddByte(buf, (Byte)0);
 +
 +		    lhs = (char *)Buf_GetAll(buf, (int *)0);
 +		    Buf_Destroy(buf, FALSE);
  		}

  		/*

 /~\ The ASCII				der Mouse
 \ / Ribbon Campaign
  X  Against HTML	       mouse@rodents.montreal.qc.ca
 / \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
From: David Laight <david@l8s.co.uk>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: bin/15233: ([dM] make: .if broken inside .for)
Date: Sat, 29 Nov 2008 15:07:26 +0000

 This happens because make only does a string comparison if the character
 after .if is '$' or '"' - but the substition of the loop control variable
 has already been done as part of the loop processing.

 cond.c rev 1.48 will also detect the == (or !=) following and do a
 comparison if present.

 The .for loop handling needs fixing though :-)

 	David

 -- 
 David Laight: david@l8s.co.uk

State-Changed-From-To: open->closed
State-Changed-By: dsl@NetBSD.org
State-Changed-When: Sun, 21 Dec 2008 19:43:56 +0000
State-Changed-Why:
The way .for variables are substituted has been changed in for.c rev 1.40
so that the expansion is still a variable.
This makes a lot of things work in the expected way.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.