diff options
-rw-r--r-- | usr.bin/make/Makefile.boot | 8 | ||||
-rw-r--r-- | usr.bin/make/buf.c | 8 | ||||
-rw-r--r-- | usr.bin/make/buf.h | 6 | ||||
-rw-r--r-- | usr.bin/make/compat.c | 22 | ||||
-rw-r--r-- | usr.bin/make/dir.c | 31 | ||||
-rw-r--r-- | usr.bin/make/main.c | 47 | ||||
-rw-r--r-- | usr.bin/make/make.1 | 70 | ||||
-rw-r--r-- | usr.bin/make/make.c | 149 | ||||
-rw-r--r-- | usr.bin/make/make.h | 35 | ||||
-rw-r--r-- | usr.bin/make/parse.c | 21 | ||||
-rw-r--r-- | usr.bin/make/targ.c | 9 | ||||
-rw-r--r-- | usr.bin/make/util.c | 74 | ||||
-rw-r--r-- | usr.bin/make/var.c | 570 |
13 files changed, 788 insertions, 262 deletions
diff --git a/usr.bin/make/Makefile.boot b/usr.bin/make/Makefile.boot index 02bb006d454..c51fb1e01e2 100644 --- a/usr.bin/make/Makefile.boot +++ b/usr.bin/make/Makefile.boot @@ -1,5 +1,5 @@ -# $OpenBSD: Makefile.boot,v 1.3 1996/11/30 21:08:48 millert Exp $ -# $NetBSD: Makefile.boot,v 1.7 1996/08/30 17:59:37 thorpej Exp $ +# $OpenBSD: Makefile.boot,v 1.4 1997/04/01 07:28:02 millert Exp $ +# $NetBSD: Makefile.boot,v 1.8 1996/12/31 17:52:23 christos Exp $ # # a very simple makefile... # @@ -7,6 +7,10 @@ # # modify MACHINE and MACHINE_ARCH as appropriate for your target architecture # + +.c.o: + ${CC} ${CFLAGS} -c $< -o $@ + MACHINE=sun MACHINE_ARCH=sparc CFLAGS= -I. -DMACHINE=\"${MACHINE}\" -DMACHINE_ARCH=\"${MACHINE_ARCH}\" \ diff --git a/usr.bin/make/buf.c b/usr.bin/make/buf.c index 7d95b9d86d3..c9feb117f37 100644 --- a/usr.bin/make/buf.c +++ b/usr.bin/make/buf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: buf.c,v 1.4 1996/11/30 21:08:50 millert Exp $ */ -/* $NetBSD: buf.c,v 1.8 1996/11/06 17:59:00 christos Exp $ */ +/* $OpenBSD: buf.c,v 1.5 1997/04/01 07:28:05 millert Exp $ */ +/* $NetBSD: buf.c,v 1.9 1996/12/31 17:53:21 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93"; #else -static char rcsid[] = "$OpenBSD: buf.c,v 1.4 1996/11/30 21:08:50 millert Exp $"; +static char rcsid[] = "$OpenBSD: buf.c,v 1.5 1997/04/01 07:28:05 millert Exp $"; #endif #endif /* not lint */ @@ -459,7 +459,7 @@ Buf_Destroy (buf, freeData) void Buf_ReplaceLastByte (buf, byte) Buffer buf; /* buffer to augment */ - Byte byte; /* byte to be written */ + int byte; /* byte to be written */ { if (buf->inPtr == buf->outPtr) Buf_AddByte(buf, byte); diff --git a/usr.bin/make/buf.h b/usr.bin/make/buf.h index 52899a37a2c..bc753c78549 100644 --- a/usr.bin/make/buf.h +++ b/usr.bin/make/buf.h @@ -1,5 +1,5 @@ -/* $OpenBSD: buf.h,v 1.3 1996/11/30 21:08:51 millert Exp $ */ -/* $NetBSD: buf.h,v 1.6 1996/11/06 17:59:00 christos Exp $ */ +/* $OpenBSD: buf.h,v 1.4 1997/04/01 07:28:07 millert Exp $ */ +/* $NetBSD: buf.h,v 1.7 1996/12/31 17:53:22 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -79,6 +79,6 @@ void Buf_Discard __P((Buffer, int)); int Buf_Size __P((Buffer)); Buffer Buf_Init __P((int)); void Buf_Destroy __P((Buffer, Boolean)); -void Buf_ReplaceLastByte __P((Buffer, Byte)); +void Buf_ReplaceLastByte __P((Buffer, int)); #endif /* _BUF_H */ diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c index 8cffa92288c..a7e63cc19ce 100644 --- a/usr.bin/make/compat.c +++ b/usr.bin/make/compat.c @@ -1,5 +1,5 @@ -/* $OpenBSD: compat.c,v 1.4 1996/11/30 21:08:51 millert Exp $ */ -/* $NetBSD: compat.c,v 1.14 1996/11/06 17:59:01 christos Exp $ */ +/* $OpenBSD: compat.c,v 1.5 1997/04/01 07:28:09 millert Exp $ */ +/* $NetBSD: compat.c,v 1.18 1997/03/28 22:31:22 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; #else -static char rcsid[] = "$OpenBSD: compat.c,v 1.4 1996/11/30 21:08:51 millert Exp $"; +static char rcsid[] = "$OpenBSD: compat.c,v 1.5 1997/04/01 07:28:09 millert Exp $"; #endif #endif /* not lint */ @@ -366,9 +366,13 @@ CompatMake (gnp, pgnp) { GNode *gn = (GNode *) gnp; GNode *pgn = (GNode *) pgnp; - if (gn->type & OP_USE) { - Make_HandleUse(gn, pgn); - } else if (gn->made == UNMADE) { + + if (pgn->type & OP_MADE) { + (void) Dir_MTime(gn); + gn->made = UPTODATE; + } + + if (gn->made == UNMADE) { /* * First mark ourselves to be made, then apply whatever transformations * the suffix module thinks are necessary. Once that's done, we can @@ -628,6 +632,12 @@ Compat_Run(targs) } /* + * Expand .USE nodes right now, because they can modify the structure + * of the tree. + */ + Lst_Destroy(Make_ExpandUse(targs), NOFREE); + + /* * For each entry in the list of targets to create, call CompatMake on * it to create the thing. CompatMake will leave the 'made' field of gn * in one of several states: diff --git a/usr.bin/make/dir.c b/usr.bin/make/dir.c index 79622bcedf1..185c3207025 100644 --- a/usr.bin/make/dir.c +++ b/usr.bin/make/dir.c @@ -1,5 +1,5 @@ -/* $OpenBSD: dir.c,v 1.6 1996/11/30 21:08:53 millert Exp $ */ -/* $NetBSD: dir.c,v 1.12 1996/11/06 17:59:04 christos Exp $ */ +/* $OpenBSD: dir.c,v 1.7 1997/04/01 07:28:11 millert Exp $ */ +/* $NetBSD: dir.c,v 1.14 1997/03/29 16:51:26 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; #else -static char rcsid[] = "$OpenBSD: dir.c,v 1.6 1996/11/30 21:08:53 millert Exp $"; +static char rcsid[] = "$OpenBSD: dir.c,v 1.7 1997/04/01 07:28:11 millert Exp $"; #endif #endif /* not lint */ @@ -285,6 +285,11 @@ DirFindName (p, dname) *----------------------------------------------------------------------- * Dir_HasWildcards -- * see if the given name has any wildcard characters in it + * be careful not to expand unmatching brackets or braces. + * XXX: This code is not 100% correct. ([^]] fails etc.) + * I really don't think that make(1) should be expanding + * patterns, because then you have to set a mechanism for + * escaping the expansion! * * Results: * returns TRUE if the word should be expanded, FALSE otherwise @@ -298,17 +303,33 @@ Dir_HasWildcards (name) char *name; /* name to check */ { register char *cp; + int wild = 0, brace = 0, bracket = 0; for (cp = name; *cp; cp++) { switch(*cp) { case '{': + brace++; + wild = 1; + break; + case '}': + brace--; + break; case '[': + bracket++; + wild = 1; + break; + case ']': + bracket--; + break; case '?': case '*': - return (TRUE); + wild = 1; + break; + default: + break; } } - return (FALSE); + return (wild && bracket == 0 && brace == 0); } /*- diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index 5adbb274c19..a57654ef4dc 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -1,5 +1,5 @@ -/* $OpenBSD: main.c,v 1.11 1997/01/27 05:24:09 briggs Exp $ */ -/* $NetBSD: main.c,v 1.31 1996/11/06 17:59:12 christos Exp $ */ +/* $OpenBSD: main.c,v 1.12 1997/04/01 07:28:13 millert Exp $ */ +/* $NetBSD: main.c,v 1.34 1997/03/24 20:56:36 gwr Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -49,7 +49,7 @@ static char copyright[] = #if 0 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; #else -static char rcsid[] = "$OpenBSD: main.c,v 1.11 1997/01/27 05:24:09 briggs Exp $"; +static char rcsid[] = "$OpenBSD: main.c,v 1.12 1997/04/01 07:28:13 millert Exp $"; #endif #endif /* not lint */ @@ -86,14 +86,15 @@ static char rcsid[] = "$OpenBSD: main.c,v 1.11 1997/01/27 05:24:09 briggs Exp $" #include <sys/resource.h> #include <sys/signal.h> #include <sys/stat.h> -#ifndef MACHINE +#ifndef MAKE_BOOTSTRAP #include <sys/utsname.h> #endif #include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> -#if __STDC__ +#include <stdlib.h> +#ifdef __STDC__ #include <stdarg.h> #else #include <varargs.h> @@ -444,6 +445,7 @@ main(argc, argv) char obpath[MAXPATHLEN + 1]; char cdpath[MAXPATHLEN + 1]; char *machine = getenv("MACHINE"); + char *machine_arch = getenv("MACHINE_ARCH"); Lst sysMkPath; /* Path of sys.mk */ char *cp = NULL, *start; /* avoid faults on read-only strings */ @@ -490,12 +492,11 @@ main(argc, argv) * so we can share an executable for similar machines. * (i.e. m68k: amiga hp300, mac68k, sun3, ...) * - * Note that both MACHINE and MACHINE_ARCH can be overridden - * by environment variables. MACHINE through the getenv() - * above and MACHINE_ARCH, below. + * Note that both MACHINE and MACHINE_ARCH are decided at + * run-time. */ - if (!machine) { -#ifndef MACHINE + if (!machine) { +#ifndef MAKE_BOOTSTRAP struct utsname utsname; if (uname(&utsname) == -1) { @@ -508,6 +509,14 @@ main(argc, argv) #endif } + if (!machine_arch) { +#ifndef MACHINE_ARCH + machine_arch = "unknown"; /* XXX: no uname -p yet */ +#else + machine_arch = MACHINE_ARCH; +#endif + } + /* * If the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory * exists, change into it and build there. (If a .${MACHINE} suffix @@ -599,11 +608,7 @@ main(argc, argv) Var_Set(MAKEFLAGS, "", VAR_GLOBAL); Var_Set("MFLAGS", "", VAR_GLOBAL); Var_Set("MACHINE", machine, VAR_GLOBAL); -#ifdef MACHINE_ARCH - if (NULL == getenv("MACHINE_ARCH")) { - Var_Set("MACHINE_ARCH", MACHINE_ARCH, VAR_GLOBAL); - } -#endif + Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); /* * First snag any flags out of the MAKE environment variable. @@ -1021,7 +1026,7 @@ bad: */ /* VARARGS */ void -#if __STDC__ +#ifdef __STDC__ Error(char *fmt, ...) #else Error(va_alist) @@ -1029,7 +1034,7 @@ Error(va_alist) #endif { va_list ap; -#if __STDC__ +#ifdef __STDC__ va_start(ap, fmt); #else char *fmt; @@ -1056,7 +1061,7 @@ Error(va_alist) */ /* VARARGS */ void -#if __STDC__ +#ifdef __STDC__ Fatal(char *fmt, ...) #else Fatal(va_alist) @@ -1064,7 +1069,7 @@ Fatal(va_alist) #endif { va_list ap; -#if __STDC__ +#ifdef __STDC__ va_start(ap, fmt); #else char *fmt; @@ -1098,7 +1103,7 @@ Fatal(va_alist) */ /* VARARGS */ void -#if __STDC__ +#ifdef __STDC__ Punt(char *fmt, ...) #else Punt(va_alist) @@ -1106,7 +1111,7 @@ Punt(va_alist) #endif { va_list ap; -#if __STDC__ +#ifdef __STDC__ va_start(ap, fmt); #else char *fmt; diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1 index 45975a87564..d514dcf3b7a 100644 --- a/usr.bin/make/make.1 +++ b/usr.bin/make/make.1 @@ -1,5 +1,5 @@ -.\" $OpenBSD: make.1,v 1.9 1996/11/30 21:08:59 millert Exp $ -.\" $NetBSD: make.1,v 1.16 1996/11/06 17:59:13 christos Exp $ +.\" $OpenBSD: make.1,v 1.10 1997/04/01 07:28:15 millert Exp $ +.\" $NetBSD: make.1,v 1.18 1997/03/10 21:19:53 christos Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -506,30 +506,38 @@ This is identical to .Ql Cm M , but selects all words which do not match the rest of the modifier. +.It Cm Q +Quotes every shell meta-character in the variable, so that it can be passed +safely through recursive invocations of +.Nm . .It Cm R Replaces each word in the variable with everything but its suffix. .Sm off -.It Cm S No \&/ Ar old_pattern Xo -.No \&/ Ar new_pattern -.No \&/ Op Cm g +.It Cm S No \&/ Ar old_string Xo +.No \&/ Ar new_string +.No \&/ Op Cm 1g .Xc .Sm on Modify the first occurrence of -.Ar old_pattern -in each word to be replaced with -.Ar new_pattern . +.Ar old_string +in the variable's value, replacing it with +.Ar new_string . If a .Ql g is appended to the last slash of the pattern, all occurrences in each word are replaced. +If a +.Ql 1 +is appended to the last slash of the pattern, only the first word +is affected. If -.Ar old_pattern -begins with a carat +.Ar old_string +begins with a caret .Pq Ql ^ , -.Ar old_pattern +.Ar old_string is anchored at the beginning of each word. If -.Ar old_pattern +.Ar old_string ends with a dollar sign .Pq Ql \&$ , it is anchored at the end of each word. @@ -538,7 +546,11 @@ Inside an ampersand .Pq Ql & is replaced by -.Ar old_pattern . +.Ar old_string +(without any +.Ql ^ +or +.Ql \&$ ) . Any character may be used as a delimiter for the parts of the modifier string. The anchoring, ampersand and delimiter characters may be escaped with a @@ -551,8 +563,36 @@ and .Ar new_string with the single exception that a backslash is used to prevent the expansion of a dollar sign -.Pq Ql \&$ +.Pq Ql \&$ , not a preceding dollar sign as is usual. +.Sm off +.It Cm C No \&/ Ar pattern Xo +.No \&/ Ar replacement +.No \&/ Op Cm 1g +.Xc +.Sm on +The +.Cm C +modifier is just like the +.Cm S +modifier except that the the old and new strings, instead of being +simple strings, are a regular expression (see +.Xr regex 3 ) +and an +.Xr ed 1 Ns \-style +replacement string. Normally, the first occurrence of the pattern in +each word of the value is changed. The +.Ql 1 +modifier causes the substitution to apply to at most one word; the +.Ql g +modifier causes the substitution to apply to as many instances of the +search pattern as occur in the word or words it is found in. Note that +.Ql 1 +and +.Ql g +are orthogonal; the former specifies whether multiple words are +potentially affected, the latter whether multiple substitutions can +potentially occur within each affected word. .It Cm T Replaces each word in the variable with its last component. .It Ar old_string=new_string @@ -814,6 +854,8 @@ command line, and continue to the end of the line. Ignore any errors from the commands associated with this target, exactly as if they all were preceded by a dash .Pq Ql \- . +.It Ic .MADE +Mark all sources of this target as being up-to-date. .It Ic .MAKE Execute the commands associated with this target even if the .Fl n diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c index 11887103adc..f84b75d756f 100644 --- a/usr.bin/make/make.c +++ b/usr.bin/make/make.c @@ -1,5 +1,5 @@ -/* $OpenBSD: make.c,v 1.4 1996/11/30 21:09:00 millert Exp $ */ -/* $NetBSD: make.c,v 1.10 1996/11/06 17:59:15 christos Exp $ */ +/* $OpenBSD: make.c,v 1.5 1997/04/01 07:28:17 millert Exp $ */ +/* $NetBSD: make.c,v 1.14 1997/03/28 22:31:21 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; #else -static char rcsid[] = "$OpenBSD: make.c,v 1.4 1996/11/30 21:09:00 millert Exp $"; +static char rcsid[] = "$OpenBSD: make.c,v 1.5 1997/04/01 07:28:17 millert Exp $"; #endif #endif /* not lint */ @@ -75,8 +75,11 @@ static char rcsid[] = "$OpenBSD: make.c,v 1.4 1996/11/30 21:09:00 millert Exp $" * * Make_OODate Determine if a target is out-of-date. * - * Make_HandleUse See if a child is a .USE node for a parent + * Make_HandleUse See if a child is a .USE node for a parent * and perform the .USE actions if so. + * + * Make_ExpandUse Expand .USE nodes and return the new list of + * targets. */ #include "make.h" @@ -94,6 +97,7 @@ static int numNodes; /* Number of nodes to be processed. If this * TRUE, there's a cycle in the graph */ static int MakeAddChild __P((ClientData, ClientData)); +static int MakeFindChild __P((ClientData, ClientData)); static int MakeAddAllSrc __P((ClientData, ClientData)); static int MakeTimeStamp __P((ClientData, ClientData)); static int MakeHandleUse __P((ClientData, ClientData)); @@ -129,7 +133,7 @@ MakeTimeStamp (pgn, cgn) ClientData pgn; /* the current parent */ ClientData cgn; /* the child we've just examined */ { - return Make_TimeStamp((GNode *) pgn, (GNode *) cgn); + return (Make_TimeStamp((GNode *) pgn, (GNode *) cgn)); } /*- @@ -296,12 +300,43 @@ MakeAddChild (gnp, lp) { GNode *gn = (GNode *) gnp; Lst l = (Lst) lp; + if (!gn->make && !(gn->type & OP_USE)) { (void)Lst_EnQueue (l, (ClientData)gn); } return (0); } + +/*- + *----------------------------------------------------------------------- + * MakeFindChild -- + * Function used by Make_Run to find the pathname of a child + * that was already made. + * + * Results: + * Always returns 0 + * + * Side Effects: + * The path and mtime of the node and the cmtime of the parent are + * updated + *----------------------------------------------------------------------- + */ +static int +MakeFindChild (gnp, pgnp) + ClientData gnp; /* the node to find */ + ClientData pgnp; +{ + GNode *gn = (GNode *) gnp; + GNode *pgn = (GNode *) pgnp; + + (void) Dir_MTime(gn); + if (pgn->cmtime < gn->mtime) + pgn->cmtime = gn->mtime; + gn->made = UPTODATE; + return (0); +} + /*- *----------------------------------------------------------------------- * Make_HandleUse -- @@ -330,7 +365,6 @@ Make_HandleUse (cgn, pgn) register GNode *cgn; /* The .USE node */ register GNode *pgn; /* The target of the .USE node */ { - register GNode *gn; /* A child of the .USE node */ register LstNode ln; /* An element in the children list */ if (cgn->type & (OP_USE|OP_TRANSFORM)) { @@ -344,7 +378,27 @@ Make_HandleUse (cgn, pgn) if (Lst_Open (cgn->children) == SUCCESS) { while ((ln = Lst_Next (cgn->children)) != NILLNODE) { - gn = (GNode *)Lst_Datum (ln); + register GNode *tgn, *gn = (GNode *)Lst_Datum (ln); + + /* + * Expand variables in the .USE node's name + * and save the unexpanded form. + * We don't need to do this for commands. + * They get expanded properly when we execute. + */ + if (gn->uname == NULL) { + gn->uname = gn->name; + } else { + if (gn->name) + free(gn->name); + } + gn->name = Var_Subst(NULL, gn->uname, pgn, FALSE); + if (gn->name && gn->uname && strcmp(gn->name, gn->uname) != 0) { + /* See if we have a target for this node. */ + tgn = Targ_FindNode(gn->name, TARG_NOCREATE); + if (tgn != NILGNODE) + gn = tgn; + } if (Lst_Member (pgn->children, gn) == NILLNODE) { (void) Lst_AtEnd (pgn->children, gn); @@ -364,8 +418,10 @@ Make_HandleUse (cgn, pgn) * children the parent has. This is used by Make_Run to decide * whether to queue the parent or examine its children... */ - if (cgn->type & OP_USE) { - pgn->unmade -= 1; + if ((cgn->type & OP_USE) && + (ln = Lst_Member (pgn->children, (ClientData) cgn)) != NILLNODE) { + Lst_Remove(pgn->children, ln); + pgn->unmade--; } } return (0); @@ -375,7 +431,7 @@ MakeHandleUse (pgn, cgn) ClientData pgn; /* the current parent */ ClientData cgn; /* the child we've just examined */ { - return Make_HandleUse((GNode *) pgn, (GNode *) cgn); + return (Make_HandleUse((GNode *) pgn, (GNode *) cgn)); } /*- @@ -581,14 +637,14 @@ MakeAddAllSrc (cgnp, pgnp) char *child; char *p1 = NULL; - if (OP_NOP(cgn->type)) { + if (OP_NOP(cgn->type) || + (child = Var_Value(TARGET, cgn, &p1)) == NULL) { /* * this node is only source; use the specific pathname for it */ child = cgn->path ? cgn->path : cgn->name; } - else - child = Var_Value(TARGET, cgn, &p1); + Var_Append (ALLSRC, child, pgn); if (pgn->type & OP_JOIN) { if (cgn->made == MADE) { @@ -804,36 +860,27 @@ MakePrintStatus(gnp, cyclep) return (0); } + /*- *----------------------------------------------------------------------- - * Make_Run -- - * Initialize the nodes to remake and the list of nodes which are - * ready to be made by doing a breadth-first traversal of the graph - * starting from the nodes in the given list. Once this traversal - * is finished, all the 'leaves' of the graph are in the toBeMade - * queue. - * Using this queue and the Job module, work back up the graph, - * calling on MakeStartJobs to keep the job table as full as - * possible. - * + * Make_ExpandUse -- + * Expand .USE nodes and create a new targets list * Results: - * TRUE if work was done. FALSE otherwise. + * The new list of targets. * * Side Effects: - * The make field of all nodes involved in the creation of the given - * targets is set to 1. The toBeMade list is set to contain all the - * 'leaves' of these subgraphs. + * numNodes is set to the number of elements in the list of targets. *----------------------------------------------------------------------- */ -Boolean -Make_Run (targs) +Lst +Make_ExpandUse (targs) Lst targs; /* the initial list of targets */ { register GNode *gn; /* a temporary pointer */ register Lst examine; /* List of targets to examine */ - int errors; /* Number of errors the Job module reports */ + register Lst ntargs; /* List of new targets to be made */ - toBeMade = Lst_Init (FALSE); + ntargs = Lst_Init (FALSE); examine = Lst_Duplicate(targs, NOCOPY); numNodes = 0; @@ -856,19 +903,55 @@ Make_Run (targs) /* * Apply any .USE rules before looking for implicit dependencies * to make sure everything has commands that should... + * Make sure that the TARGET is set, so that we can make + * expansions. */ + Var_Set (TARGET, gn->name, gn); Lst_ForEach (gn->children, MakeHandleUse, (ClientData)gn); Suff_FindDeps (gn); - if (gn->unmade != 0) { + if (gn->unmade != 0 && (gn->type & OP_MADE) == 0) { Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine); } else { - (void)Lst_EnQueue (toBeMade, (ClientData)gn); + (void)Lst_EnQueue (ntargs, (ClientData)gn); + if (gn->type & OP_MADE) + Lst_ForEach (gn->children, MakeFindChild, (ClientData)gn); } } } Lst_Destroy (examine, NOFREE); + return (ntargs); +} + +/*- + *----------------------------------------------------------------------- + * Make_Run -- + * Initialize the nodes to remake and the list of nodes which are + * ready to be made by doing a breadth-first traversal of the graph + * starting from the nodes in the given list. Once this traversal + * is finished, all the 'leaves' of the graph are in the toBeMade + * queue. + * Using this queue and the Job module, work back up the graph, + * calling on MakeStartJobs to keep the job table as full as + * possible. + * + * Results: + * TRUE if work was done. FALSE otherwise. + * + * Side Effects: + * The make field of all nodes involved in the creation of the given + * targets is set to 1. The toBeMade list is set to contain all the + * 'leaves' of these subgraphs. + *----------------------------------------------------------------------- + */ +Boolean +Make_Run (targs) + Lst targs; /* the initial list of targets */ +{ + int errors; /* Number of errors the Job module reports */ + + toBeMade = Make_ExpandUse (targs); if (queryFlag) { /* diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h index aa21d9e6c8b..ab47ff09fc4 100644 --- a/usr.bin/make/make.h +++ b/usr.bin/make/make.h @@ -1,5 +1,5 @@ -/* $OpenBSD: make.h,v 1.7 1996/11/30 21:09:00 millert Exp $ */ -/* $NetBSD: make.h,v 1.11 1996/11/06 17:59:17 christos Exp $ */ +/* $OpenBSD: make.h,v 1.8 1997/04/01 07:28:19 millert Exp $ */ +/* $NetBSD: make.h,v 1.15 1997/03/10 21:20:00 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -50,20 +50,29 @@ #define _MAKE_H_ #include <sys/types.h> +#include <sys/param.h> #include <stdio.h> #include <string.h> #include <ctype.h> -#if !defined(MAKE_BOOTSTRAP) && defined(BSD) -#include <sys/cdefs.h> -#else -#ifndef __P -#if defined(__STDC__) || defined(__cplusplus) -#define __P(protos) protos /* full-blown ANSI C */ + +#if !defined(MAKE_BOOTSTRAP) && defined(BSD4_4) +# include <sys/cdefs.h> #else -#define __P(protos) () /* traditional C preprocessor */ -#endif -#endif +# ifndef __P +# if defined(__STDC__) || defined(__cplusplus) +# define __P(protos) protos /* full-blown ANSI C */ +# else +# define __P(protos) () /* traditional C preprocessor */ +# endif +# endif +# ifndef const +# define const +# endif +# ifndef volatile +# define volatile +# endif #endif + #if __STDC__ #include <stdlib.h> #include <unistd.h> @@ -103,6 +112,7 @@ */ typedef struct GNode { char *name; /* The target's name */ + char *uname; /* The unexpanded name of a .USE node */ char *path; /* The full pathname of the file */ int type; /* Its type (see the OP flags, below) */ int order; /* Its wait weight */ @@ -193,6 +203,8 @@ typedef struct GNode { * state of the -n or -t flags */ #define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its * children was out-of-date */ +#define OP_MADE 0x00000800 /* Assume the node is already made; even if + * it really is out of date */ #define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents. * I.e. it doesn't show up in the parents's * local variables. */ @@ -366,6 +378,7 @@ extern int debug; int Make_TimeStamp __P((GNode *, GNode *)); Boolean Make_OODate __P((GNode *)); +Lst Make_ExpandUse __P((Lst)); int Make_HandleUse __P((GNode *, GNode *)); void Make_Update __P((GNode *)); void Make_DoAllVar __P((GNode *)); diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index 934d27af81e..9c930d6d950 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,5 +1,5 @@ -/* $OpenBSD: parse.c,v 1.12 1997/03/26 17:46:44 deraadt Exp $ */ -/* $NetBSD: parse.c,v 1.27 1996/11/06 17:59:20 christos Exp $ */ +/* $OpenBSD: parse.c,v 1.13 1997/04/01 07:28:21 millert Exp $ */ +/* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; #else -static char rcsid[] = "$OpenBSD: parse.c,v 1.12 1997/03/26 17:46:44 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: parse.c,v 1.13 1997/04/01 07:28:21 millert Exp $"; #endif #endif /* not lint */ @@ -211,6 +211,7 @@ static struct { { ".INVISIBLE", Attribute, OP_INVISIBLE }, { ".JOIN", Attribute, OP_JOIN }, { ".LIBS", Libs, 0 }, +{ ".MADE", Attribute, OP_MADE }, { ".MAIN", Main, 0 }, { ".MAKE", Attribute, OP_MAKE }, { ".MAKEFLAGS", MFlags, 0 }, @@ -466,7 +467,7 @@ ParseDoOp (gnp, opp) * *--------------------------------------------------------------------- */ -int +static int ParseAddDep(pp, sp) ClientData pp; ClientData sp; @@ -2574,18 +2575,18 @@ Parse_End() Lst Parse_MainName() { - Lst listmain; /* result list */ + Lst main; /* result list */ - listmain = Lst_Init (FALSE); + main = Lst_Init (FALSE); if (mainNode == NILGNODE) { Punt ("no target to make."); /*NOTREACHED*/ } else if (mainNode->type & OP_DOUBLEDEP) { - (void) Lst_AtEnd (listmain, (ClientData)mainNode); - Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW); + (void) Lst_AtEnd (main, (ClientData)mainNode); + Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); } else - (void) Lst_AtEnd (listmain, (ClientData)mainNode); - return (listmain); + (void) Lst_AtEnd (main, (ClientData)mainNode); + return (main); } diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c index 48b492350af..80a9293362c 100644 --- a/usr.bin/make/targ.c +++ b/usr.bin/make/targ.c @@ -1,5 +1,5 @@ -/* $OpenBSD: targ.c,v 1.5 1996/11/30 21:09:05 millert Exp $ */ -/* $NetBSD: targ.c,v 1.10 1996/11/06 17:59:27 christos Exp $ */ +/* $OpenBSD: targ.c,v 1.6 1997/04/01 07:28:24 millert Exp $ */ +/* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94"; #else -static char *rcsid = "$OpenBSD: targ.c,v 1.5 1996/11/30 21:09:05 millert Exp $"; +static char *rcsid = "$OpenBSD: targ.c,v 1.6 1997/04/01 07:28:24 millert Exp $"; #endif #endif /* not lint */ @@ -166,6 +166,7 @@ Targ_NewGN (name) gn = (GNode *) emalloc (sizeof (GNode)); gn->name = estrdup (name); + gn->uname = NULL; gn->path = (char *) 0; if (name[0] == '-' && name[1] == 'l') { gn->type = OP_LIB; @@ -215,6 +216,8 @@ TargFreeGN (gnp) free(gn->name); + if (gn->uname) + free(gn->uname); if (gn->path) free(gn->path); diff --git a/usr.bin/make/util.c b/usr.bin/make/util.c index 4032472dcc6..929391b5c23 100644 --- a/usr.bin/make/util.c +++ b/usr.bin/make/util.c @@ -1,16 +1,17 @@ -/* $OpenBSD: util.c,v 1.5 1996/11/30 21:09:06 millert Exp $ */ -/* $NetBSD: util.c,v 1.9 1996/11/11 15:16:10 christos Exp $ */ +/* $OpenBSD: util.c,v 1.6 1997/04/01 07:28:26 millert Exp $ */ +/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */ /* * Missing stuff from OS's */ #ifndef lint -static char rcsid[] = "$OpenBSD: util.c,v 1.5 1996/11/30 21:09:06 millert Exp $"; +static char rcsid[] = "$OpenBSD: util.c,v 1.6 1997/04/01 07:28:26 millert Exp $"; #endif #include <stdio.h> #include "make.h" +#include <sys/param.h> #if !__STDC__ # ifndef const @@ -351,3 +352,70 @@ signal(s, a)) () } #endif + +#ifndef BSD4_4 +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifdef _IOSTRG +#define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ +#else +#define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ +#endif + +int +vsnprintf(s, n, fmt, args) + char *s; + size_t n; + const char *fmt; + va_list args; +{ + FILE fakebuf; + + fakebuf._flag = STRFLAG; + /* + * Some os's are char * _ptr, others are unsigned char *_ptr... + * We cast to void * to make everyone happy. + */ + fakebuf._ptr = (void *) s; + fakebuf._cnt = n-1; + fakebuf._file = -1; + _doprnt(fmt, args, &fakebuf); + fakebuf._cnt++; + putc('\0', &fakebuf); + if (fakebuf._cnt<0) + fakebuf._cnt = 0; + return (n-fakebuf._cnt-1); +} + +int +#ifdef __STDC__ +snprintf(char *s, size_t n, const char *fmt, ...) +#else +snprintf(va_alist) + va_dcl +#endif +{ + va_list ap; + int rv; +#ifdef __STDC__ + va_start(ap, fmt); +#else + char *s; + size_t n; + const char *fmt; + + va_start(ap); + + s = va_arg(ap, char *); + n = va_arg(ap, size_t); + fmt = va_arg(ap, const char *); +#endif + rv = vsnprintf(s, n, fmt, ap); + va_end(ap); + return rv; +} +#endif diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index 642c07c0be2..fdd8051ce6c 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -1,5 +1,5 @@ -/* $OpenBSD: var.c,v 1.5 1996/11/30 21:09:07 millert Exp $ */ -/* $NetBSD: var.c,v 1.15 1996/11/06 17:59:29 christos Exp $ */ +/* $OpenBSD: var.c,v 1.6 1997/04/01 07:28:28 millert Exp $ */ +/* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else -static char rcsid[] = "$OpenBSD: var.c,v 1.5 1996/11/30 21:09:07 millert Exp $"; +static char rcsid[] = "$OpenBSD: var.c,v 1.6 1997/04/01 07:28:28 millert Exp $"; #endif #endif /* not lint */ @@ -90,6 +90,10 @@ static char rcsid[] = "$OpenBSD: var.c,v 1.5 1996/11/30 21:09:07 millert Exp $"; */ #include <ctype.h> +#ifndef MAKE_BOOTSTRAP +#include <regex.h> +#endif +#include <stdlib.h> #include "make.h" #include "buf.h" @@ -145,17 +149,31 @@ typedef struct Var { * modified variables */ } Var; +/* Var*Pattern flags */ +#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ +#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ +#define VAR_SUB_MATCHED 0x04 /* There was a match */ +#define VAR_MATCH_START 0x08 /* Match at start of word */ +#define VAR_MATCH_END 0x10 /* Match at end of word */ + typedef struct { char *lhs; /* String to match */ int leftLen; /* Length of string */ char *rhs; /* Replacement string (w/ &'s removed) */ int rightLen; /* Length of replacement */ int flags; -#define VAR_SUB_GLOBAL 1 /* Apply substitution globally */ -#define VAR_MATCH_START 2 /* Match at start of word */ -#define VAR_MATCH_END 4 /* Match at end of word */ } VarPattern; +#ifndef MAKE_BOOTSTRAP +typedef struct { + regex_t re; + int nsub; + regmatch_t *matches; + char *replace; + int flags; +} VarREPattern; +#endif + static int VarCmp __P((ClientData, ClientData)); static Var *VarFind __P((char *, GNode *, int)); static void VarAdd __P((char *, char *, GNode *)); @@ -169,7 +187,14 @@ static Boolean VarMatch __P((char *, Boolean, Buffer, ClientData)); static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, ClientData)); #endif static Boolean VarNoMatch __P((char *, Boolean, Buffer, ClientData)); +#ifndef MAKE_BOOTSTRAP +static void VarREError __P((int, regex_t *, const char *)); +static Boolean VarRESubstitute __P((char *, Boolean, Buffer, ClientData)); +#endif static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData)); +static char *VarGetPattern __P((GNode *, int, char **, int, int *, int *, + VarPattern *)); +static char *VarQuote __P((char *)); static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, ClientData), ClientData)); @@ -891,9 +916,10 @@ VarSubstitute (word, addSpace, buf, patternp) VarPattern *pattern = (VarPattern *) patternp; wordLen = strlen(word); - if (1) { /* substitute in each word of the variable */ + if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != + (VAR_SUB_ONE|VAR_SUB_MATCHED)) { /* - * Break substitution down into simple anchored cases + * Still substituting -- break it down into simple anchored cases * and if none of them fits, perform the general substitution case. */ if ((pattern->flags & VAR_MATCH_START) && @@ -916,6 +942,7 @@ VarSubstitute (word, addSpace, buf, patternp) Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); } + pattern->flags |= VAR_SUB_MATCHED; } else if (pattern->flags & VAR_MATCH_END) { /* * Doesn't match to end -- copy word wholesale @@ -934,6 +961,7 @@ VarSubstitute (word, addSpace, buf, patternp) Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); Buf_AddBytes(buf, wordLen - pattern->leftLen, (Byte *)(word + pattern->leftLen)); + pattern->flags |= VAR_SUB_MATCHED; } } else if (pattern->flags & VAR_MATCH_START) { /* @@ -964,6 +992,7 @@ VarSubstitute (word, addSpace, buf, patternp) } Buf_AddBytes(buf, cp - word, (Byte *)word); Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); + pattern->flags |= VAR_SUB_MATCHED; } else { /* * Had to match at end and didn't. Copy entire word. @@ -1001,6 +1030,7 @@ VarSubstitute (word, addSpace, buf, patternp) if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){ done = TRUE; } + pattern->flags |= VAR_SUB_MATCHED; } else { done = TRUE; } @@ -1018,10 +1048,6 @@ VarSubstitute (word, addSpace, buf, patternp) */ return ((Buf_Size(buf) != origSize) || addSpace); } - /* - * Common code for anchored substitutions: - * addSpace was set TRUE if characters were added to the buffer. - */ return (addSpace); } nosub: @@ -1032,6 +1058,158 @@ VarSubstitute (word, addSpace, buf, patternp) return(TRUE); } +#ifndef MAKE_BOOTSTRAP +/*- + *----------------------------------------------------------------------- + * VarREError -- + * Print the error caused by a regcomp or regexec call. + * + * Results: + * None. + * + * Side Effects: + * An error gets printed. + * + *----------------------------------------------------------------------- + */ +static void +VarREError(err, pat, str) + int err; + regex_t *pat; + const char *str; +{ + char *errbuf; + int errlen; + + errlen = regerror(err, pat, 0, 0); + errbuf = emalloc(errlen); + regerror(err, pat, errbuf, errlen); + Error("%s: %s", str, errbuf); + free(errbuf); +} + +/*- + *----------------------------------------------------------------------- + * VarRESubstitute -- + * Perform a regex substitution on the given word, placing the + * result in the passed buffer. + * + * Results: + * TRUE if a space is needed before more characters are added. + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------- + */ +static Boolean +VarRESubstitute(word, addSpace, buf, patternp) + char *word; + Boolean addSpace; + Buffer buf; + ClientData patternp; +{ + VarREPattern *pat; + int xrv; + char *wp; + char *rp; + int added; + +#define MAYBE_ADD_SPACE() \ + if (addSpace && !added) \ + Buf_AddByte(buf, ' '); \ + added = 1 + + added = 0; + wp = word; + pat = patternp; + + if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == + (VAR_SUB_ONE|VAR_SUB_MATCHED)) + xrv = REG_NOMATCH; + else { + tryagain: + xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0); + } + + switch (xrv) { + case 0: + pat->flags |= VAR_SUB_MATCHED; + if (pat->matches[0].rm_so > 0) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, pat->matches[0].rm_so, wp); + } + + for (rp = pat->replace; *rp; rp++) { + if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf,rp[1]); + rp++; + } + else if ((*rp == '&') || ((*rp == '\\') && isdigit(rp[1]))) { + int n; + char *subbuf; + char zsub; + int sublen; + char errstr[3]; + + if (*rp == '&') { + n = 0; + errstr[0] = '&'; + errstr[1] = '\0'; + } else { + n = rp[1] - '0'; + errstr[0] = '\\'; + errstr[1] = rp[1]; + errstr[2] = '\0'; + rp++; + } + + if (n > pat->nsub) { + Error("No subexpression %s", &errstr[0]); + subbuf = ""; + sublen = 0; + } else if ((pat->matches[n].rm_so == -1) && + (pat->matches[n].rm_eo == -1)) { + Error("No match for subexpression %s", &errstr[0]); + subbuf = ""; + sublen = 0; + } else { + subbuf = wp + pat->matches[n].rm_so; + sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; + } + + if (sublen > 0) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, sublen, subbuf); + } + } else { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, *rp); + } + } + wp += pat->matches[0].rm_eo; + if (pat->flags & VAR_SUB_GLOBAL) + goto tryagain; + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, strlen(wp), wp); + } + break; + default: + VarREError(xrv, &pat->re, "Unexpected regex error"); + /* fall through */ + case REG_NOMATCH: + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf,strlen(wp),wp); + } + break; + } + return(addSpace||added); +} +#endif + /*- *----------------------------------------------------------------------- * VarModify -- @@ -1076,6 +1254,141 @@ VarModify (str, modProc, datum) /*- *----------------------------------------------------------------------- + * VarGetPattern -- + * Pass through the tstr looking for 1) escaped delimiters, + * '$'s and backslashes (place the escaped character in + * uninterpreted) and 2) unescaped $'s that aren't before + * the delimiter (expand the variable substitution). + * Return the expanded string or NULL if the delimiter was missing + * If pattern is specified, handle escaped ampersants, and replace + * unescaped ampersands with the lhs of the pattern. + * + * Results: + * A string of all the words modified appropriately. + * If length is specified, return the string length of the buffer + * If flags is specified and the last character of the pattern is a + * $ set the VAR_MATCH_END bit of flags. + * + * Side Effects: + * None. + *----------------------------------------------------------------------- + */ +static char * +VarGetPattern(ctxt, err, tstr, delim, flags, length, pattern) + GNode *ctxt; + int err; + char **tstr; + int delim; + int *flags; + int *length; + VarPattern *pattern; +{ + char *cp; + Buffer buf = Buf_Init(0); + int junk; + if (length == NULL) + length = &junk; + +#define IS_A_MATCH(cp, delim) \ + ((cp[0] == '\\') && ((cp[1] == delim) || \ + (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&')))) + + /* + * Skim through until the matching delimiter is found; + * pick up variable substitutions on the way. Also allow + * backslashes to quote the delimiter, $, and \, but don't + * touch other backslashes. + */ + for (cp = *tstr; *cp && (*cp != delim); cp++) { + if (IS_A_MATCH(cp, delim)) { + Buf_AddByte(buf, (Byte) cp[1]); + cp++; + } else if (*cp == '$') { + if (cp[1] == delim) { + if (flags == NULL) + Buf_AddByte(buf, (Byte) *cp); + else + /* + * Unescaped $ at end of pattern => anchor + * pattern at end. + */ + *flags |= VAR_MATCH_END; + } + else { + char *cp2; + int len; + Boolean freeIt; + + /* + * If unescaped dollar sign not before the + * delimiter, assume it's a variable + * substitution and recurse. + */ + cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); + Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2); + if (freeIt) + free(cp2); + cp += len - 1; + } + } + else if (pattern && *cp == '&') + Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs); + else + Buf_AddByte(buf, (Byte) *cp); + } + + Buf_AddByte(buf, (Byte) '\0'); + + if (*cp != delim) { + *tstr = cp; + *length = 0; + return NULL; + } + else { + *tstr = ++cp; + cp = (char *) Buf_GetAll(buf, length); + *length -= 1; /* Don't count the NULL */ + Buf_Destroy(buf, FALSE); + return cp; + } +} + +/*- + *----------------------------------------------------------------------- + * VarQuote -- + * Quote shell meta-characters in the string + * + * Results: + * The quoted string + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------- + */ +static char * +VarQuote(str) + char *str; +{ + + Buffer buf; + /* This should cover most shells :-( */ + static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; + + buf = Buf_Init (MAKE_BSIZE); + for (; *str; str++) { + if (strchr(meta, *str) != NULL) + Buf_AddByte(buf, (Byte)'\\'); + Buf_AddByte(buf, (Byte)*str); + } + Buf_AddByte(buf, (Byte) '\0'); + str = (char *)Buf_GetAll (buf, (int *)NULL); + Buf_Destroy (buf, FALSE); + return str; +} + +/*- + *----------------------------------------------------------------------- * Var_Parse -- * Given the start of a variable invocation, extract the variable * name and find its value, then modify it according to the @@ -1104,7 +1417,7 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) { register char *tstr; /* Pointer into str */ Var *v; /* Variable in invocation */ - register char *cp; /* Secondary pointer into str (place marker + char *cp; /* Secondary pointer into str (place marker * for tstr) */ Boolean haveModifier;/* TRUE if have modifiers for the variable */ register char endc; /* Ending character when variable in parens @@ -1114,6 +1427,7 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) int cnt; /* Used to count brace pairs when variable in * in parens or braces */ char *start; + char delim; Boolean dynamic; /* TRUE if the variable is local and we're * expanding it in a non-local context. This * is done to support dynamic sources. The @@ -1348,6 +1662,8 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) * wildcarding form. * :S<d><pat1><d><pat2><d>[g] * Substitute <pat2> for <pat1> in the value + * :C<d><pat1><d><pat2><d>[g] + * Substitute <pat2> for regex <pat1> in the value * :H Substitute the head of each word * :T Substitute the tail of each word * :E Substitute the extension (minus '.') of @@ -1426,12 +1742,11 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) case 'S': { VarPattern pattern; - register char delim; - Buffer buf; /* Buffer for patterns */ pattern.flags = 0; delim = tstr[1]; tstr += 2; + /* * If pattern begins with '^', it is anchored to the * start of the word -- skip over it and flag pattern. @@ -1441,159 +1756,112 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) tstr += 1; } - buf = Buf_Init(0); + cp = tstr; + if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim, + &pattern.flags, &pattern.leftLen, NULL)) == NULL) + goto cleanup; + + if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim, + NULL, &pattern.rightLen, &pattern)) == NULL) + goto cleanup; /* - * Pass through the lhs looking for 1) escaped delimiters, - * '$'s and backslashes (place the escaped character in - * uninterpreted) and 2) unescaped $'s that aren't before - * the delimiter (expand the variable substitution). - * The result is left in the Buffer buf. + * Check for global substitution. If 'g' after the final + * delimiter, substitution is global and is marked that + * way. */ - for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { - if ((*cp == '\\') && - ((cp[1] == delim) || - (cp[1] == '$') || - (cp[1] == '\\'))) - { - Buf_AddByte(buf, (Byte)cp[1]); - cp++; - } else if (*cp == '$') { - if (cp[1] != delim) { - /* - * If unescaped dollar sign not before the - * delimiter, assume it's a variable - * substitution and recurse. - */ - char *cp2; - int len; - Boolean freeIt; - - cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - if (freeIt) { - free(cp2); - } - cp += len - 1; - } else { - /* - * Unescaped $ at end of pattern => anchor - * pattern at end. - */ - pattern.flags |= VAR_MATCH_END; - } - } else { - Buf_AddByte(buf, (Byte)*cp); + for (;; cp++) { + switch (*cp) { + case 'g': + pattern.flags |= VAR_SUB_GLOBAL; + continue; + case '1': + pattern.flags |= VAR_SUB_ONE; + continue; } + break; } - Buf_AddByte(buf, (Byte)'\0'); + termc = *cp; + newStr = VarModify(str, VarSubstitute, + (ClientData)&pattern); /* - * If lhs didn't end with the delimiter, complain and - * return NULL + * Free the two strings. */ - if (*cp != delim) { - *lengthPtr = cp - start + 1; - if (*freePtr) { - free(str); - } - Buf_Destroy(buf, TRUE); - Error("Unclosed substitution for %s (%c missing)", - v->name, delim); - return (var_Error); - } + free(pattern.lhs); + free(pattern.rhs); + break; + } +#ifndef MAKE_BOOTSTRAP + case 'C': + { + VarREPattern pattern; + char *re; + int error; - /* - * Fetch pattern and destroy buffer, but preserve the data - * in it, since that's our lhs. Note that Buf_GetAll - * will return the actual number of bytes, which includes - * the null byte, so we have to decrement the length by - * one. - */ - pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); - pattern.leftLen--; - Buf_Destroy(buf, FALSE); + pattern.flags = 0; + delim = tstr[1]; + tstr += 2; - /* - * Now comes the replacement string. Three things need to - * be done here: 1) need to compress escaped delimiters and - * ampersands and 2) need to replace unescaped ampersands - * with the l.h.s. (since this isn't regexp, we can do - * it right here) and 3) expand any variable substitutions. - */ - buf = Buf_Init(0); - - tstr = cp + 1; - for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { - if ((*cp == '\\') && - ((cp[1] == delim) || - (cp[1] == '&') || - (cp[1] == '\\') || - (cp[1] == '$'))) - { - Buf_AddByte(buf, (Byte)cp[1]); - cp++; - } else if ((*cp == '$') && (cp[1] != delim)) { - char *cp2; - int len; - Boolean freeIt; - - cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - cp += len - 1; - if (freeIt) { - free(cp2); - } - } else if (*cp == '&') { - Buf_AddBytes(buf, pattern.leftLen, - (Byte *)pattern.lhs); - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } + cp = tstr; - Buf_AddByte(buf, (Byte)'\0'); + if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL, + NULL, NULL)) == NULL) + goto cleanup; - /* - * If didn't end in delimiter character, complain - */ - if (*cp != delim) { - *lengthPtr = cp - start + 1; - if (*freePtr) { - free(str); + if ((pattern.replace = VarGetPattern(ctxt, err, &cp, + delim, NULL, NULL, NULL)) == NULL) { + free(re); + goto cleanup; + } + + for (;; cp++) { + switch (*cp) { + case 'g': + pattern.flags |= VAR_SUB_GLOBAL; + continue; + case '1': + pattern.flags |= VAR_SUB_ONE; + continue; } - Buf_Destroy(buf, TRUE); - Error("Unclosed substitution for %s (%c missing)", - v->name, delim); - return (var_Error); + break; } - pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); - pattern.rightLen--; - Buf_Destroy(buf, FALSE); + termc = *cp; - /* - * Check for global substitution. If 'g' after the final - * delimiter, substitution is global and is marked that - * way. - */ - cp++; - if (*cp == 'g') { - pattern.flags |= VAR_SUB_GLOBAL; - cp++; + error = regcomp(&pattern.re, re, REG_EXTENDED); + free(re); + if (error) { + *lengthPtr = cp - start + 1; + VarREError(error, &pattern.re, "RE substitution error"); + free(pattern.replace); + return (var_Error); } - termc = *cp; - newStr = VarModify(str, VarSubstitute, - (ClientData)&pattern); - /* - * Free the two strings. - */ - free(pattern.lhs); - free(pattern.rhs); + pattern.nsub = pattern.re.re_nsub + 1; + if (pattern.nsub < 1) + pattern.nsub = 1; + if (pattern.nsub > 10) + pattern.nsub = 10; + pattern.matches = emalloc(pattern.nsub * + sizeof(regmatch_t)); + newStr = VarModify(str, VarRESubstitute, + (ClientData) &pattern); + regfree(&pattern.re); + free(pattern.replace); + free(pattern.matches); break; } +#endif + case 'Q': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarQuote (str); + cp = tstr + 1; + termc = *cp; + break; + } + /*FALLTHRU*/ case 'T': if (tstr[1] == endc || tstr[1] == ':') { newStr = VarModify (str, VarTail, (ClientData)0); @@ -1784,6 +2052,14 @@ Var_Parse (str, ctxt, err, lengthPtr, freePtr) } } return (str); + +cleanup: + *lengthPtr = cp - start + 1; + if (*freePtr) + free(str); + Error("Unclosed substitution for %s (%c missing)", + v->name, delim); + return (var_Error); } /*- |