Implemented a set of assignment modifiers. These solve obscure
problems such as using modifiers on .for loop iterators derived from local variables (eg .TARGET). Unless the variable already exists in a global context, these assignments are local to the current context (this is usually what is wanted).
This commit is contained in:
parent
b8cb7f6356
commit
339f702f71
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: make.1,v 1.40 2000/04/29 12:18:52 sjg Exp $
|
||||
.\" $NetBSD: make.1,v 1.41 2000/05/30 02:32:21 sjg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -664,6 +664,46 @@ is the value.
|
|||
.It Cm sh
|
||||
If the variable is non-empty it is run as a command and the output
|
||||
becomes the new value.
|
||||
.It Cm = Ar str
|
||||
The variable is assigned the value
|
||||
.Ar str
|
||||
after substitution. This modifier and its variations are useful in
|
||||
obscure situations such as wanting to apply modifiers to
|
||||
.Cm \&.for
|
||||
loop iteration variables which won't work due to the way
|
||||
.Cm \&.for
|
||||
loops are implemented. These assignment modifiers always expand to
|
||||
nothing, so if appearing in a rule line by themselves should be
|
||||
preceded with something to keep
|
||||
.Nm
|
||||
happy. As in:
|
||||
.Bd -literal
|
||||
use_foo: \&.USE
|
||||
\&.for i in ${\&.TARGET} ${\&.TARGET:R}\&.gz
|
||||
@: ${t:=$i}
|
||||
@echo t:R:T=${t:R:T}
|
||||
\&.endfor
|
||||
|
||||
.Ed
|
||||
While [?+!]= might look better than =[?+!], given that substitution is
|
||||
always done before the assignment they are more like variations on
|
||||
.Cm :=
|
||||
rather than
|
||||
.Cm =
|
||||
in normal variable assignments. Coupled with the obscurity of their
|
||||
use, the extra complexity in implementing [?+!]= is unwarranted.
|
||||
.It Cm =? Ar str
|
||||
As for
|
||||
.Cm =
|
||||
but only if the variable does not already have a value.
|
||||
.It Cm =+ Ar str
|
||||
Append
|
||||
.Ar str
|
||||
to the variable.
|
||||
.It Cm =! Ar cmd
|
||||
Assign the output of
|
||||
.Ar cmd
|
||||
to the variable.
|
||||
.El
|
||||
.El
|
||||
.Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: var.c,v 1.43 2000/05/14 15:14:41 sjg Exp $ */
|
||||
/* $NetBSD: var.c,v 1.44 2000/05/30 02:32:21 sjg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1989, 1990, 1993
|
||||
|
@ -39,14 +39,14 @@
|
|||
*/
|
||||
|
||||
#ifdef MAKE_BOOTSTRAP
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.43 2000/05/14 15:14:41 sjg Exp $";
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.44 2000/05/30 02:32:21 sjg Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.43 2000/05/14 15:14:41 sjg Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.44 2000/05/30 02:32:21 sjg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
@ -1856,6 +1856,29 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr)
|
|||
* the form '${x:P}'.
|
||||
* :!<cmd>! Run cmd much the same as :sh run's the
|
||||
* current value of the variable.
|
||||
* The := modifiers, actually assign a value to the variable.
|
||||
* Their main purpose is in supporting modifiers of .for loop
|
||||
* iterators and other obscure uses. They always expand to
|
||||
* nothing. In a target rule that would otherwise expand to an
|
||||
* empty line they can be preceded with @: to keep make happy.
|
||||
* Eg.
|
||||
*
|
||||
* foo: .USE
|
||||
* .for i in ${.TARGET} ${.TARGET:R}.gz
|
||||
* @: ${t:=$i}
|
||||
* @echo blah ${t:T}
|
||||
* .endfor
|
||||
*
|
||||
* It would be neater if :=[+?!] were :[+?!]= but that would be
|
||||
* much messier to implement given the existing ! and ? modifiers.
|
||||
* Also the fact that substitution is always done on <str> makes
|
||||
* these modifiers more like variations on the normal ':=' assignment.
|
||||
* :=<str> Assigns <str> as the new value of variable.
|
||||
* :=?<str> Assigns <str> as value of variable if
|
||||
* it was not already set.
|
||||
* :=+<str> Appends <str> to variable.
|
||||
* :=!<cmd> Assigns output of <cmd> as the new value of
|
||||
* variable.
|
||||
*/
|
||||
if ((str != (char *)NULL) && haveModifier) {
|
||||
/*
|
||||
|
@ -1870,6 +1893,85 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr)
|
|||
printf("Applying :%c to \"%s\"\n", *tstr, str);
|
||||
}
|
||||
switch (*tstr) {
|
||||
case '=':
|
||||
{
|
||||
GNode *v_ctxt; /* context where v belongs */
|
||||
char *emsg;
|
||||
VarPattern pattern;
|
||||
int how;
|
||||
|
||||
if (v->flags & VAR_JUNK) {
|
||||
/*
|
||||
* JUNK vars get name = &str[1]
|
||||
* we want the full name here.
|
||||
*/
|
||||
v->name--;
|
||||
/*
|
||||
* We need to strdup() it incase
|
||||
* VarGetPattern() recurses.
|
||||
*/
|
||||
v->name = strdup(v->name);
|
||||
v_ctxt = ctxt;
|
||||
} else if (ctxt != VAR_GLOBAL) {
|
||||
if (VarFind(v->name, ctxt, 0) == (Var *)NIL)
|
||||
v_ctxt = VAR_GLOBAL;
|
||||
else
|
||||
v_ctxt = ctxt;
|
||||
}
|
||||
|
||||
switch ((how = tstr[1])) {
|
||||
case '+':
|
||||
case '?':
|
||||
case '!':
|
||||
cp = &tstr[2];
|
||||
break;
|
||||
default:
|
||||
cp = ++tstr;
|
||||
break;
|
||||
}
|
||||
delim = '}';
|
||||
pattern.flags = 0;
|
||||
|
||||
if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim,
|
||||
NULL, &pattern.rightLen, NULL)) == NULL) {
|
||||
if (v->flags & VAR_JUNK) {
|
||||
free(v->name);
|
||||
v->name = str;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
termc = *--cp;
|
||||
delim = '\0';
|
||||
|
||||
switch (how) {
|
||||
case '+':
|
||||
Var_Append(v->name, pattern.rhs, v_ctxt);
|
||||
break;
|
||||
case '!':
|
||||
newStr = Cmd_Exec (pattern.rhs, &emsg);
|
||||
if (emsg)
|
||||
Error (emsg, str);
|
||||
else
|
||||
Var_Set(v->name, newStr, v_ctxt);
|
||||
if (newStr)
|
||||
free(newStr);
|
||||
break;
|
||||
case '?':
|
||||
if ((v->flags & VAR_JUNK) == 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
Var_Set(v->name, pattern.rhs, v_ctxt);
|
||||
break;
|
||||
}
|
||||
if (v->flags & VAR_JUNK) {
|
||||
free(v->name);
|
||||
v->name = str;
|
||||
}
|
||||
free(pattern.rhs);
|
||||
newStr = var_Error;
|
||||
break;
|
||||
}
|
||||
case '@':
|
||||
{
|
||||
VarLoop_t loop;
|
||||
|
|
Loading…
Reference in New Issue