-# $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...
#
#
# 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}\" \
-/* $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.
#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 */
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);
-/* $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.
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 */
-/* $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.
#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 */
{
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
}
}
+ /*
+ * 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
-/* $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.
#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 */
*-----------------------------------------------------------------------
* 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
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);
}
/*-
-/* $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
#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 */
#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>
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 */
* 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) {
#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
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.
*/
/* VARARGS */
void
-#if __STDC__
+#ifdef __STDC__
Error(char *fmt, ...)
#else
Error(va_alist)
#endif
{
va_list ap;
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
char *fmt;
*/
/* VARARGS */
void
-#if __STDC__
+#ifdef __STDC__
Fatal(char *fmt, ...)
#else
Fatal(va_alist)
#endif
{
va_list ap;
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
char *fmt;
*/
/* VARARGS */
void
-#if __STDC__
+#ifdef __STDC__
Punt(char *fmt, ...)
#else
Punt(va_alist)
#endif
{
va_list ap;
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
char *fmt;
-.\" $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.
.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.
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
.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
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
-/* $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
#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 */
*
* 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"
* 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));
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));
}
\f
/*-
{
GNode *gn = (GNode *) gnp;
Lst l = (Lst) lp;
+
if (!gn->make && !(gn->type & OP_USE)) {
(void)Lst_EnQueue (l, (ClientData)gn);
}
return (0);
}
+\f
+/*-
+ *-----------------------------------------------------------------------
+ * 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);
+}
+\f
/*-
*-----------------------------------------------------------------------
* Make_HandleUse --
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)) {
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);
* 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);
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));
}
\f
/*-
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) {
return (0);
}
\f
+
/*-
*-----------------------------------------------------------------------
- * 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;
/*
* 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) {
/*
-/* $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
#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>
*/
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 */
* 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. */
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 *));
-/* $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
#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 */
{ ".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 },
*
*---------------------------------------------------------------------
*/
-int
+static int
ParseAddDep(pp, sp)
ClientData pp;
ClientData sp;
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);
}
-/* $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
#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 */
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;
free(gn->name);
+ if (gn->uname)
+ free(gn->uname);
if (gn->path)
free(gn->path);
-/* $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
}
#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
-/* $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
#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 */
*/
#include <ctype.h>
+#ifndef MAKE_BOOTSTRAP
+#include <regex.h>
+#endif
+#include <stdlib.h>
#include "make.h"
#include "buf.h"
* 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 *));
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));
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) &&
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
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) {
/*
}
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.
if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
done = TRUE;
}
+ pattern->flags |= VAR_SUB_MATCHED;
} else {
done = TRUE;
}
*/
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:
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 --
return (str);
}
+/*-
+ *-----------------------------------------------------------------------
+ * 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 --
{
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
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
* 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
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.
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);
}
}
return (str);
+
+cleanup:
+ *lengthPtr = cp - start + 1;
+ if (*freePtr)
+ free(str);
+ Error("Unclosed substitution for %s (%c missing)",
+ v->name, delim);
+ return (var_Error);
}
/*-