summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoerg <joerg@pkgsrc.org>2008-03-09 19:39:31 +0000
committerjoerg <joerg@pkgsrc.org>2008-03-09 19:39:31 +0000
commit769645f8708288a32de4868bc43933c70b1cee91 (patch)
treecd14ac3f66acef3a7718d5f9b73a2cde91013e19
parentdd9795f0fb057a1bd9582255e0213beeb0774196 (diff)
downloadpkgsrc-769645f8708288a32de4868bc43933c70b1cee91.tar.gz
Import bmake-20080215
-rw-r--r--devel/bmake/files/ChangeLog127
-rw-r--r--devel/bmake/files/FILES6
-rw-r--r--devel/bmake/files/Makefile.in45
-rw-r--r--devel/bmake/files/arch.c60
-rw-r--r--devel/bmake/files/bmake.cat1190
-rwxr-xr-xdevel/bmake/files/boot-strap65
-rw-r--r--devel/bmake/files/buf.c6
-rw-r--r--devel/bmake/files/buf.h2
-rw-r--r--devel/bmake/files/compat.c88
-rw-r--r--devel/bmake/files/cond.c377
-rw-r--r--devel/bmake/files/config.h.in17
-rwxr-xr-xdevel/bmake/files/configure55
-rw-r--r--devel/bmake/files/configure.in37
-rw-r--r--devel/bmake/files/dir.c121
-rw-r--r--devel/bmake/files/dir.h2
-rw-r--r--devel/bmake/files/for.c35
-rw-r--r--devel/bmake/files/job.c2168
-rw-r--r--devel/bmake/files/job.h112
-rw-r--r--devel/bmake/files/lst.h16
-rw-r--r--devel/bmake/files/lst.lib/Makefile4
-rw-r--r--devel/bmake/files/lst.lib/lstAppend.c14
-rw-r--r--devel/bmake/files/lst.lib/lstAtEnd.c8
-rw-r--r--devel/bmake/files/lst.lib/lstAtFront.c8
-rw-r--r--devel/bmake/files/lst.lib/lstClose.c8
-rw-r--r--devel/bmake/files/lst.lib/lstConcat.c10
-rw-r--r--devel/bmake/files/lst.lib/lstDatum.c8
-rw-r--r--devel/bmake/files/lst.lib/lstDeQueue.c10
-rw-r--r--devel/bmake/files/lst.lib/lstDestroy.c8
-rw-r--r--devel/bmake/files/lst.lib/lstDupl.c8
-rw-r--r--devel/bmake/files/lst.lib/lstEnQueue.c10
-rw-r--r--devel/bmake/files/lst.lib/lstFindFrom.c12
-rw-r--r--devel/bmake/files/lst.lib/lstFirst.c8
-rw-r--r--devel/bmake/files/lst.lib/lstForEach.c10
-rw-r--r--devel/bmake/files/lst.lib/lstForEachFrom.c15
-rw-r--r--devel/bmake/files/lst.lib/lstInit.c8
-rw-r--r--devel/bmake/files/lst.lib/lstInsert.c14
-rw-r--r--devel/bmake/files/lst.lib/lstInt.h14
-rw-r--r--devel/bmake/files/lst.lib/lstIsAtEnd.c8
-rw-r--r--devel/bmake/files/lst.lib/lstLast.c8
-rw-r--r--devel/bmake/files/lst.lib/lstMember.c10
-rw-r--r--devel/bmake/files/lst.lib/lstNext.c10
-rw-r--r--devel/bmake/files/lst.lib/lstOpen.c12
-rw-r--r--devel/bmake/files/lst.lib/lstPrev.c79
-rw-r--r--devel/bmake/files/lst.lib/lstRemove.c10
-rw-r--r--devel/bmake/files/lst.lib/lstReplace.c8
-rw-r--r--devel/bmake/files/lst.lib/lstSucc.c8
-rw-r--r--devel/bmake/files/lst.lib/makefile.boot.in6
-rw-r--r--devel/bmake/files/main.c537
-rw-r--r--devel/bmake/files/make-conf.h13
-rw-r--r--devel/bmake/files/make.1167
-rw-r--r--devel/bmake/files/make.c704
-rw-r--r--devel/bmake/files/make.h90
-rw-r--r--devel/bmake/files/makefile.boot.in14
-rw-r--r--devel/bmake/files/missing/sys/cdefs.h20
-rw-r--r--devel/bmake/files/nonints.h21
-rw-r--r--devel/bmake/files/os.sh7
-rw-r--r--devel/bmake/files/parse.c1655
-rw-r--r--devel/bmake/files/sigcompat.c9
-rw-r--r--devel/bmake/files/str.c16
-rw-r--r--devel/bmake/files/suff.c556
-rw-r--r--devel/bmake/files/targ.c292
-rw-r--r--devel/bmake/files/trace.c10
-rw-r--r--devel/bmake/files/trace.h2
-rw-r--r--devel/bmake/files/unit-tests/Makefile.in16
-rw-r--r--devel/bmake/files/unit-tests/dotwait61
-rw-r--r--devel/bmake/files/unit-tests/export22
-rw-r--r--devel/bmake/files/unit-tests/export-all11
-rw-r--r--devel/bmake/files/unit-tests/moderrs31
-rw-r--r--devel/bmake/files/unit-tests/modmisc33
-rw-r--r--devel/bmake/files/unit-tests/modorder4
-rw-r--r--devel/bmake/files/unit-tests/test.exp74
-rw-r--r--devel/bmake/files/util.c56
-rw-r--r--devel/bmake/files/var.c2544
73 files changed, 5708 insertions, 5122 deletions
diff --git a/devel/bmake/files/ChangeLog b/devel/bmake/files/ChangeLog
index c865b948667..d9244b5bf8d 100644
--- a/devel/bmake/files/ChangeLog
+++ b/devel/bmake/files/ChangeLog
@@ -1,3 +1,130 @@
+2008-02-15 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * merge some patches from NetBSD pkgsrc.
+
+ * makefile.boot.in (BOOTSTRAP_SYS_PATH): Allow better control of
+ the MAKSYSPATH used during bootstrap.
+
+ * Makefile.in (BMAKE_VERSION): bump version to 20080215
+ * Merge with NetBSD make, pick up:
+ o warn if non-space chars follow 'empty' in a conditional.
+
+2008-01-18 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump version to 20080118
+ * Merge with NetBSD make, pick up:
+ o consider dependencies read from .depend as optional - dsl
+ o remember when buffer for reading makefile grows - dsl
+ o add -dl (aka LOUD) - David O'Brien
+
+2007-10-22 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump version to 20071022
+ * Merge with NetBSD make, pick up:
+ o Allow .PATH<suffix> to be used for .include ""
+
+ * boot-strap: source default settings from .bmake-boot-strap.rc
+
+2007-10-16 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in: fix maninstall on various systems
+ provided that our man.mk is used.
+ For non-BSD systems we install the preformatted page
+ into $MANDIR/cat1
+
+2007-10-15 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * boot-strap: make bmake.1 too, so maninstall works.
+
+2007-10-14 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump version to 20071014
+ * Merge with NetBSD make, pick up:
+ o revamped handling of defshell - configure no longer needs to
+ know the content of the shells array - apb
+ o stop Var_Subst modifying its input - apb
+ o avoid calling ParseTrackInput too often - dsl
+
+2007-10-11 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump version to 20071011
+ * Merge with NetBSD make, pick up:
+ o fix Shell_Init for case that _BASENAME_DEFSHELL is absolute path.
+
+ * sigcompat.c: some tweaks for HP-UX 11.x based on
+ patch from Tobias Nygren
+
+ * configure.in: update handling of --with-defshell to match
+ new make behavior. --with-defshell=/usr/xpg4/bin/sh
+ will now do what one might hope - provided the chosen shell
+ behaves enough like sh.
+
+2007-10-08 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20071008
+ * Merge with NetBSD make, pick up:
+ o .MAKE.JOB.PREFIX - control the token output before jobs - sjg
+ o .export/.MAKE.EXPORTED - export of variables - sjg
+ o .MAKE.MAKEFILES - track all makefiles read - sjg
+ o performance improvements - dsl
+ o revamp parallel job scheduling - dsl
+
+2006-07-28 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060728
+ * Merge with NetBSD make, pick up:
+ o extra debug info during variable and cond processing - sjg
+ o shell definition now covers newline - rillig
+ o minor mem leak in PrintOnError - sjg
+
+2006-05-11 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060511
+ * Merge with NetBSD make, pick up:
+ o more memory leaks - coverity
+ o possible overflow in ArchFindMember - coverity
+ o extract variable modifier code out of Var_Parse()
+ so it can be called recursively - sjg
+ o unit-tests/moderrs - sjg
+
+2006-04-12 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060412
+ * Merge with NetBSD make, pick up:
+ o fixes for some memory leaks - coverity
+ o only read first sys.mk etc when searching sysIncPath - sjg
+
+ * main.c (ReadMakefile): remove hack for __INTERIX that prevented
+ setting ${MAKEFILE} - OBATA Akio
+
+2006-03-18 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060318
+ * Merge with NetBSD make, pick up:
+ o cleanup of job.c to remove remote handling, distcc is more
+ useful and this code was likely bit-rotting - dsl
+ o fix for :P modifier - sjg
+ * boot-strap: set default prefix to something reasonable
+ (for me anyway).
+
+2006-03-01 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060301
+ * Merge with NetBSD make, pick up:
+ o make .WAIT apply recursively, document and test case - apb
+ o allow variable modifiers in a variable appear anywhere in
+ modifier list, document and test case - sjg
+
+2006-02-22 Simon J. Gerraty <sjg@void.crufty.net>
+
+ * Makefile.in (BMAKE_VERSION): bump to 20060222
+ * Merge with NetBSD make, pick up:
+ o improved job token handling - dsl
+ o SIG_DFL the correct signal before exec - dsl
+ o more debug info during parsing - dsl
+ o allow variable modifiers to be specified via variable - sjg
+ * boot-strap: explain why we died if no mksrc
+
2005-11-05 Simon J. Gerraty <sjg@void.crufty.net>
* Makefile.in (BMAKE_VERSION): bump to 20051105
diff --git a/devel/bmake/files/FILES b/devel/bmake/files/FILES
index a2ceb926dc1..2558b1710c3 100644
--- a/devel/bmake/files/FILES
+++ b/devel/bmake/files/FILES
@@ -56,6 +56,7 @@ lst.lib/lstLast.c
lst.lib/lstMember.c
lst.lib/lstNext.c
lst.lib/lstOpen.c
+lst.lib/lstPrev.c
lst.lib/lstRemove.c
lst.lib/lstReplace.c
lst.lib/lstSucc.c
@@ -84,6 +85,9 @@ wait.h
unit-tests/Makefile.in
unit-tests/cond1
unit-tests/comment
+unit-tests/export
+unit-tests/export-all
+unit-tests/moderrs
unit-tests/modmatch
unit-tests/modorder
unit-tests/modts
@@ -92,3 +96,5 @@ unit-tests/posix
unit-tests/ternary
unit-tests/test.exp
unit-tests/varcmd
+unit-tests/modmisc
+unit-tests/dotwait
diff --git a/devel/bmake/files/Makefile.in b/devel/bmake/files/Makefile.in
index 898dbb0c036..4e5b671b7d6 100644
--- a/devel/bmake/files/Makefile.in
+++ b/devel/bmake/files/Makefile.in
@@ -1,7 +1,7 @@
-# $NetBSD: Makefile.in,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $
+# $NetBSD: Makefile.in,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $
# @(#)Makefile 5.2 (Berkeley) 12/28/90
-# $Id: Makefile.in,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $
+# $Id: Makefile.in,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $
PROG= bmake
SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \
@@ -11,6 +11,7 @@ SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \
lstFind.c lstFindFrom.c lstFirst.c lstForEach.c lstForEachFrom.c \
lstInit.c lstInsert.c lstIsAtEnd.c lstIsEmpty.c lstLast.c \
lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c
+SRCS += lstPrev.c
.if !empty(LIBOBJS)
SRCS+= ${LIBOBJS:.o=.c}
@@ -22,14 +23,15 @@ srcdir= @srcdir@
CC?= @CC@
# Base version on src date
-BMAKE_VERSION= 20051105
+BMAKE_VERSION= 20080215
# knowing when it was built is also handy
BUILD_DATE!= date +%Y%m%d
MAKE_VERSION:= bmake-${BMAKE_VERSION} build-${BUILD_DATE}
MACHINE=@machine@
MACHINE_ARCH=@machine_arch@
+DEFAULT_SYS_PATH = @default_sys_path@
-CFLAGS+= -D_PATH_DEFSYSPATH=\"@default_sys_path@\"
+CFLAGS+= -D_PATH_DEFSYSPATH=\"${DEFAULT_SYS_PATH}\"
CFLAGS+= -I. -I${srcdir} @DEFS@ @CPPFLAGS@ ${XDEFS} -DMAKE_NATIVE
CFLAGS+= ${CFLAGS_${.TARGET:T}}
CFLAGS_main.o= "-DMAKE_VERSION=\"${MAKE_VERSION}\""
@@ -50,7 +52,7 @@ isBSD44= NetBSD FreeBSD OpenBSD DragonFly
# Don't set these for anyone else since we don't know what the effect may be.
# On FreeBSD WARNS=2 sets a bunch of -W flags that make does not handle.
WFORMAT= 1
-WARNS=3
+WARNS=4
.NOPATH: bmake.cat1
.if make(install) && exists(${DESTDIR}/usr/share/doc)
SUBDIR= PSD.doc
@@ -61,7 +63,7 @@ SUBDIR= PSD.doc
# XXX not sure if we still want this given that configure
# lets us force or not the definition of MACHINE.
CFLAGS_main.o+= "-DFORCE_MACHINE=\"${MACHINE}\""
-NOMAN=no
+MANTARGET=cat
SRCS+= getenv.c
INSTALL?=${srcdir}/install-sh
.if (${MACHINE} == "sun386")
@@ -96,6 +98,20 @@ ${MAN}: make.1
.endif
+.if !empty(isBSD44:M${OS})
+.if "${OS}" != "NetBSD"
+MAN1=${MAN}
+.endif
+MANTARGET?=man
+.endif
+
+MANTARGET?= cat
+MANDEST?= ${MANDIR}/${MANTARGET}1
+
+.if ${MANTARGET} == "cat"
+_mfromdir=${srcdir}
+.endif
+
.if exists(${srcdir}/../Makefile.inc)
.include "${srcdir}/../Makefile.inc"
.endif
@@ -111,15 +127,6 @@ ${MAN}: make.1
BINDIR= ${prefix}/bin
MANDIR= ${prefix}/man
-.if "${OS}" != "NetBSD" && !empty(isBSD44:M${OS})
-# freebsd's bsd.man.mk works differently
-MAN1=${MAN}
-MANDIR= ${prefix}/man/man
-MANDEST= ${MANDIR}1
-.NOPATH: bmake.cat1
-.endif
-MANDEST?= ${MANDIR}
-
arch.o: config.h
# make sure that MAKE_VERSION gets updated.
main.o: ${SRCS} ${MAKEFILE}
@@ -142,6 +149,14 @@ install-mk:
@echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false
.endif
+.ifdef TOOLDIR
+# this is a native netbsd build,
+# use libutil rather than the local emalloc etc.
+CPPFLAGS+= -DHAVE_EMALLOC
+LDADD+=-lutil
+DPADD+=${LIBUTIL}
+.endif
+
# A simple unit-test driver to help catch regressions
accept test:
cd ${.CURDIR}/unit-tests && ${.MAKE:S,^./,${.CURDIR}/,} TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET}
diff --git a/devel/bmake/files/arch.c b/devel/bmake/files/arch.c
index 3119a51b627..98be9f25c20 100644
--- a/devel/bmake/files/arch.c
+++ b/devel/bmake/files/arch.c
@@ -1,4 +1,4 @@
-/* $NetBSD: arch.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: arch.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: arch.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: arch.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
#else
-__RCSID("$NetBSD: arch.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: arch.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -288,19 +288,18 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
* so we can safely advance beyond it...
*/
int length;
- Boolean freeIt;
+ void *freeIt;
char *result;
- result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ if (freeIt)
+ free(freeIt);
if (result == var_Error) {
return(FAILURE);
} else {
subLibName = TRUE;
}
- if (freeIt) {
- free(result);
- }
cp += length-1;
}
}
@@ -330,19 +329,18 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
* so we can safely advance beyond it...
*/
int length;
- Boolean freeIt;
+ void *freeIt;
char *result;
- result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
+ if (freeIt)
+ free(freeIt);
if (result == var_Error) {
return(FAILURE);
} else {
doSubst = TRUE;
}
- if (freeIt) {
- free(result);
- }
cp += length;
} else {
cp++;
@@ -412,7 +410,7 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
return(FAILURE);
} else {
gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, (ClientData)gn);
+ (void)Lst_AtEnd(nodeLst, gn);
}
} else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
/*
@@ -454,7 +452,7 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
* end of the provided list.
*/
gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, (ClientData)gn);
+ (void)Lst_AtEnd(nodeLst, gn);
}
}
Lst_Destroy(members, NOFREE);
@@ -476,7 +474,7 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
* provided list.
*/
gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, (ClientData)gn);
+ (void)Lst_AtEnd(nodeLst, gn);
}
}
if (doSubst) {
@@ -578,7 +576,7 @@ ArchStatMember(char *archive, char *member, Boolean hash)
member = cp + 1;
}
- ln = Lst_Find(archives, (ClientData) archive, ArchFindArchive);
+ ln = Lst_Find(archives, archive, ArchFindArchive);
if (ln != NILLNODE) {
ar = (Arch *)Lst_Datum(ln);
@@ -589,7 +587,7 @@ ArchStatMember(char *archive, char *member, Boolean hash)
} else {
/* Try truncated name */
char copy[AR_MAX_NAME_LEN+1];
- int len = strlen(member);
+ size_t len = strlen(member);
if (len > AR_MAX_NAME_LEN) {
len = AR_MAX_NAME_LEN;
@@ -711,7 +709,7 @@ ArchStatMember(char *archive, char *member, Boolean hash)
memName[elen] = '\0';
fseek(arch, -elen, SEEK_CUR);
if (DEBUG(ARCH) || DEBUG(MAKE)) {
- printf("ArchStat: Extended format entry for %s\n", memName);
+ fprintf(debug_file, "ArchStat: Extended format entry for %s\n", memName);
}
}
#endif
@@ -725,7 +723,7 @@ ArchStatMember(char *archive, char *member, Boolean hash)
fclose(arch);
- (void)Lst_AtEnd(archives, (ClientData) ar);
+ (void)Lst_AtEnd(archives, ar);
/*
* Now that the archive has been read and cached, we can look into
@@ -782,7 +780,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch)
if (ar->fnametab != NULL) {
if (DEBUG(ARCH)) {
- printf("Attempted to redefine an SVR4 name table\n");
+ fprintf(debug_file, "Attempted to redefine an SVR4 name table\n");
}
return -1;
}
@@ -796,7 +794,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch)
if (fread(ar->fnametab, size, 1, arch) != 1) {
if (DEBUG(ARCH)) {
- printf("Reading an SVR4 name table failed\n");
+ fprintf(debug_file, "Reading an SVR4 name table failed\n");
}
return -1;
}
@@ -815,7 +813,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch)
break;
}
if (DEBUG(ARCH)) {
- printf("Found svr4 archive name table with %lu entries\n",
+ fprintf(debug_file, "Found svr4 archive name table with %lu entries\n",
(u_long)entry);
}
return 0;
@@ -827,20 +825,20 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch)
entry = (size_t)strtol(&name[1], &eptr, 0);
if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) {
if (DEBUG(ARCH)) {
- printf("Could not parse SVR4 name %s\n", name);
+ fprintf(debug_file, "Could not parse SVR4 name %s\n", name);
}
return 2;
}
if (entry >= ar->fnamesize) {
if (DEBUG(ARCH)) {
- printf("SVR4 entry offset %s is greater than %lu\n",
+ fprintf(debug_file, "SVR4 entry offset %s is greater than %lu\n",
name, (u_long)ar->fnamesize);
}
return 2;
}
if (DEBUG(ARCH)) {
- printf("Replaced %s with %s\n", name, &ar->fnametab[entry]);
+ fprintf(debug_file, "Replaced %s with %s\n", name, &ar->fnametab[entry]);
}
(void)strncpy(name, &ar->fnametab[entry], MAXPATHLEN);
@@ -882,7 +880,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr,
int size; /* Size of archive member */
char *cp; /* Useful character pointer */
char magic[SARMAG];
- int len, tlen;
+ size_t len, tlen;
arch = fopen(archive, mode);
if (arch == NULL) {
@@ -954,7 +952,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr,
isdigit((unsigned char)arhPtr->AR_NAME[sizeof(AR_EFMT1) - 1])) {
unsigned int elen = atoi(&arhPtr->AR_NAME[sizeof(AR_EFMT1)-1]);
- char ename[MAXPATHLEN];
+ char ename[MAXPATHLEN + 1];
if (elen > MAXPATHLEN) {
fclose(arch);
@@ -966,7 +964,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr,
}
ename[elen] = '\0';
if (DEBUG(ARCH) || DEBUG(MAKE)) {
- printf("ArchFind: Extended format entry for %s\n", ename);
+ fprintf(debug_file, "ArchFind: Extended format entry for %s\n", ename);
}
if (strncmp(ename, member, len) == 0) {
/* Found as extended name */
@@ -1290,7 +1288,7 @@ Arch_LibOODate(GNode *gn)
modTimeTOC = (int)strtol(arhPtr->AR_DATE, NULL, 10);
if (DEBUG(ARCH) || DEBUG(MAKE)) {
- printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
+ fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
}
oodate = (gn->cmtime > modTimeTOC);
} else {
@@ -1298,7 +1296,7 @@ Arch_LibOODate(GNode *gn)
* A library w/o a table of contents is out-of-date
*/
if (DEBUG(ARCH) || DEBUG(MAKE)) {
- printf("No t.o.c....");
+ fprintf(debug_file, "No t.o.c....");
}
oodate = TRUE;
}
diff --git a/devel/bmake/files/bmake.cat1 b/devel/bmake/files/bmake.cat1
index a1c12d8d22f..ab7cddc458f 100644
--- a/devel/bmake/files/bmake.cat1
+++ b/devel/bmake/files/bmake.cat1
@@ -1,7 +1,7 @@
-MAKE(1) NetBSD General Commands Manual MAKE(1)
+MAKE(1) BSD General Commands Manual MAKE(1)
NNAAMMEE
- bbmmaakkee - maintain program dependencies
+ bbmmaakkee -- maintain program dependencies
SSYYNNOOPPSSIISS
bbmmaakkee [--BBeeiikkNNnnqqrrssttWWXX] [--DD _v_a_r_i_a_b_l_e] [--dd _f_l_a_g_s] [--ff _m_a_k_e_f_i_l_e]
@@ -11,15 +11,18 @@ SSYYNNOOPPSSIISS
DDEESSCCRRIIPPTTIIOONN
bbmmaakkee is a program designed to simplify the maintenance of other pro-
grams. Its input is a list of specifications as to the files upon which
- programs and other files depend. If the file `_m_a_k_e_f_i_l_e' exists, it is
- read for this list of specifications. If it does not exist, the file
- `_M_a_k_e_f_i_l_e' is read. If the file `_._d_e_p_e_n_d' exists, it is read (see
+ programs and other files depend. If no --ff _m_a_k_e_f_i_l_e makefile option is
+ given, bbmmaakkee will try to open `_m_a_k_e_f_i_l_e' then `_M_a_k_e_f_i_l_e' in order to find
+ the specifications. If the file `_._d_e_p_e_n_d' exists, it is read (see
mkdep(1)).
This manual page is intended as a reference document only. For a more
thorough description of bbmmaakkee and makefiles, please refer to _M_a_k_e _- _A
_T_u_t_o_r_i_a_l.
+ bbmmaakkee will prepend the contents of the _M_A_K_E_F_L_A_G_S environment variable to
+ the command line arguments before parsing them.
+
The options are as follows:
--BB Try to be backwards compatible by executing a single shell per
@@ -29,10 +32,12 @@ DDEESSCCRRIIPPTTIIOONN
--DD _v_a_r_i_a_b_l_e
Define _v_a_r_i_a_b_l_e to be 1, in the global context.
- --dd _f_l_a_g_s
+ --dd _[_-_]_f_l_a_g_s
Turn on debugging, and specify which portions of bbmmaakkee are to
- print debugging information. _F_l_a_g_s is one or more of the follow-
- ing:
+ print debugging information. Unless the flags are preceded by
+ `-' they are added to the _M_A_K_E_F_L_A_G_S environment variable and will
+ be processed by any child make processes. _F_l_a_g_s is one or more
+ of the following:
_A Print all possible debugging information; equivalent to
specifying all of the debugging flags.
@@ -48,6 +53,10 @@ DDEESSCCRRIIPPTTIIOONN
_e Print debugging information about failed commands and
targets.
+ _F Use the rest of `flags' as the name of the file to which
+ the debug output is written. If the filename ends `.%d'
+ then the `%d' is replaced by the pid.
+
_f Print debugging information about loop evaluation.
_g_1 Print the input graph before making anything.
@@ -60,9 +69,20 @@ DDEESSCCRRIIPPTTIIOONN
_j Print debugging information about running multiple
shells.
+ _l Print commands in Makefiles regardless of whether or not
+ they are prefixed by `@' or other "quiet" flags. Also
+ known as "loud" behavior.
+
_m Print debugging information about making targets, includ-
ing modification dates.
+ _n Don't delete the temporary command scripts created in
+ _/_t_m_p when running commands. These are created via
+ mkstemp(3) and have names of the form _/_t_m_p_/_m_a_k_e_X_X_X_X_X.
+ _N_O_T_E: This can create many file in _/_t_m_p so use with care.
+
+ _p Print debugging information about makefile parsing.
+
_s Print debugging information about suffix-transformation
rules.
@@ -243,7 +263,9 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
::== Assign with expansion, i.e. expand the value before assigning it
to the variable. Normally, expansion is not done until the vari-
- able is referenced.
+ able is referenced. _N_O_T_E: References to undefined variables are
+ _n_o_t expanded. This can cause problems when variable modifiers
+ are used.
!!== Expand the value and pass it to the shell for execution and
assign the result to the variable. Any newlines in the result
@@ -322,15 +344,37 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
evaluated during Makefile parsing, lists only those tar-
gets encountered thus far.
- _._C_U_R_D_I_R A path to the directory where bbmmaakkee was executed.
+ _._C_U_R_D_I_R A path to the directory where bbmmaakkee was executed. Refer
+ to the description of `PWD' for more details.
MAKE The name that bbmmaakkee was executed with (_a_r_g_v_[_0_]). For
- compatibily bbmmaakkee also sets _._M_A_K_E with the same value.
+ compatibility bbmmaakkee also sets _._M_A_K_E with the same value.
The preferred variable to use is the environment variable
MAKE because it is more compatible with other versions of
bbmmaakkee and cannot be confused with the special target with
the same name.
+ _._M_A_K_E_._E_X_P_O_R_T_E_D The list of variables exported by bbmmaakkee.
+
+ _._M_A_K_E_._M_A_K_E_F_I_L_E_S
+ The list of makefiles read by bbmmaakkee, which is useful for
+ tracking dependencies. Each makefile is recorded only
+ once, regardless of the number of times read.
+
+ _._M_A_K_E_._P_I_D The process-id of bbmmaakkee.
+
+ _._M_A_K_E_._P_P_I_D The parent process-id of bbmmaakkee.
+
+ _._M_A_K_E_._J_O_B_._P_R_E_F_I_X
+ If bbmmaakkee is run with _j then output for each target is
+ prefixed with a token `--- target ---' the first part of
+ which can be controlled via _._M_A_K_E_._J_O_B_._P_R_E_F_I_X.
+ For example:
+ .MAKE.JOB.PREFIX=${.newline}---${.MAKE:T}[${.MAKE.PID}]
+ would produce tokens like `---make[1234] target ---' mak-
+ ing it easier to track the degree of parallelism being
+ achieved.
+
MAKEFLAGS The environment variable `MAKEFLAGS' may contain anything
that may be specified on bbmmaakkee's command line. Anything
specified on bbmmaakkee's command line is appended to the
@@ -358,7 +402,37 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
`_M_A_K_E___P_R_I_N_T___V_A_R___O_N___E_R_R_O_R' could be done as
${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}.
- _._O_B_J_D_I_R A path to the directory where the targets are built.
+ _._O_B_J_D_I_R A path to the directory where the targets are built. Its
+ value is determined by trying to chdir(2) to the follow-
+ ing directories in order and using the first match:
+
+ 1. ${MAKEOBJDIRPREFIX}${.CURDIR}
+
+ (Only if `MAKEOBJDIRPREFIX' is set in the environ-
+ ment or on the command line.)
+
+ 2. ${MAKEOBJDIR}
+
+ (Only if `MAKEOBJDIR' is set in the environment or
+ on the command line.)
+
+ 3. ${.CURDIR}_/_o_b_j_.${MACHINE}
+
+ 4. ${.CURDIR}_/_o_b_j
+
+ 5. _/_u_s_r_/_o_b_j_/${.CURDIR}
+
+ 6. ${.CURDIR}
+
+ Variable expansion is performed on the value before it's
+ used, so expressions such as
+ ${.CURDIR:C,^/usr/src,/var/obj,}
+ may be used.
+
+ `_._O_B_J_D_I_R' may be modified in the makefile as a global
+ variable. In all cases, bbmmaakkee will chdir(2) to `_._O_B_J_D_I_R'
+ and set `PWD' to that directory before executing any tar-
+ gets.
_._P_A_R_S_E_D_I_R A path to the directory of the current `_M_a_k_e_f_i_l_e' being
parsed.
@@ -377,19 +451,31 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
However, if the environment variable `PWD' is set and
gives a path to the current directory, then bbmmaakkee sets
`_._C_U_R_D_I_R' to the value of `PWD' instead. This behaviour
- is disabled if `MAKEOBJDIRPREFIX' is set. `PWD' is set
- to the value of `_._O_B_J_D_I_R' for all programs which bbmmaakkee
- executes.
+ is disabled if `MAKEOBJDIRPREFIX' is set or `MAKEOBJDIR'
+ contains a variable transform. `PWD' is set to the value
+ of `_._O_B_J_D_I_R' for all programs which bbmmaakkee executes.
VVaarriiaabbllee mmooddiiffiieerrss
Variable expansion may be modified to select or modify each word of the
variable (where a ``word'' is white-space delimited sequence of charac-
ters). The general format of a variable expansion is as follows:
- {variable[:modifier[:...]]}
+ ${variable[:modifier[:...]]}
Each modifier begins with a colon, which may be escaped with a backslash
- (`\'). The supported modifiers are:
+ (`\').
+
+ A set of modifiers can be specified via a variable, as follows:
+
+ modifier_variable=modifier[:...]
+ ${variable:${modifier_variable}[:...]}
+
+ In this case the first modifier in the modifier_variable does not start
+ with a colon, since that must appear in the referencing variable. If any
+ of the modifiers in the modifier_variable contain a dollar sign (`$'),
+ these must be doubled to avoid early expansion.
+
+ The supported modifiers are:
::EE Replaces each word in the variable with its suffix.
@@ -620,6 +706,13 @@ IINNCCLLUUDDEE SSTTAATTEEMMEENNTTSS,, CCOONNDDIITTIIOO
Conditional expressions are also preceded by a single dot as the first
character of a line. The possible conditionals are as follows:
+ ..eexxppoorrtt _v_a_r_i_a_b_l_e
+ Export the specified global variable. If no variable is pro-
+ vided, all globals are exported except for internal variables
+ (those that start with `.' ). This is not affected by the --XX
+ flag, so should be used with caution. Appending a variable name
+ to _._M_A_K_E_._E_X_P_O_R_T_E_D is equivalent to exporting a variable.
+
..uunnddeeff _v_a_r_i_a_b_l_e
Un-define the specified global variable. Only global variables
may be un-defined.
@@ -733,7 +826,7 @@ IINNCCLLUUDDEE SSTTAATTEEMMEENNTTSS,, CCOONNDDIITTIIOO
CCOOMMMMEENNTTSS
Comments begin with a hash (`#') character, anywhere but in a shell com-
- mand line, and continue to the end of the line.
+ mand line, and continue to the end of an unescaped new line.
SSPPEECCIIAALL SSOOUURRCCEESS ((AATTTTRRIIBBUUTTEESS))
..EEXXEECC Target is never out of date, but always execute commands any-
@@ -765,8 +858,9 @@ SSPPEECCIIAALL SSOOUURRCCEESS ((AATTTTRRIIBBUUTTEESS))
--tt option.
..PPRREECCIIOOUUSS
- When bbmmaakkee is interrupted, it removes any partially made tar-
- gets. This source prevents the target from being removed.
+ When bbmmaakkee is interrupted, it normally removes any partially
+ made targets. This source prevents the target from being
+ removed.
..RREECCUURRSSIIVVEE
Synonym for ..MMAAKKEE.
@@ -786,8 +880,23 @@ SSPPEECCIIAALL SSOOUURRCCEESS ((AATTTTRRIIBBUUTTEESS))
..WWAAIITT If ..WWAAIITT appears in a dependency line, the sources that precede
it are made before the sources that succeed it in the line.
- Loops are not detected and targets that form loops will be
- silently ignored.
+ Since the dependents of files are not made until the file
+ itself could be made, this also stops the dependents being
+ built unless they are needed for another branch of the depen-
+ dency tree. So given:
+
+ x: a .WAIT b
+ echo x
+ a:
+ echo a
+ b: b1
+ echo b
+ b1:
+ echo b1
+
+ the output is always `b1', `b', `a', `x'.
+ The ordering imposed by ..WWAAIITT is only relevant for parallel
+ makes.
SSPPEECCIIAALL TTAARRGGEETTSS
Special targets may not be included with other targets, i.e. they must be
@@ -831,7 +940,17 @@ SSPPEECCIIAALL TTAARRGGEETTSS
Synonym for ..NNOOTTPPAARRAALLLLEELL, for compatibility with other pmake
variants.
- ..OORRDDEERR The named targets are made in sequence.
+ ..OORRDDEERR The named targets are made in sequence. This ordering does not
+ add targets to the list of targets to be made. Since the depen-
+ dents of a target do not get built until the target itself could
+ be built, unless `a' is built by another part of the dependency
+ graph, the following is a dependency loop:
+
+ .ORDER a b
+ b: a
+
+ The ordering imposed by ..OORRDDEERR is only relevant for parallel
+ makes.
..PPAATTHH The sources are directories which are to be searched for files
not found in the current directory. If no sources are speci-
@@ -872,12 +991,16 @@ SSPPEECCIIAALL TTAARRGGEETTSS
_e_c_h_o_F_l_a_g The flag to pass the shell to enable command echo-
ing.
+
+ _n_e_w_l_i_n_e The string literal to pass the shell that results in
+ a single newline character when used outside of any
+ quoting characters.
Example:
.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \
check="set -e" ignore="set +e" \
echo="set -v" quiet="set +v" filter="set +v" \
- echoFlag=v errFlag=e
+ echoFlag=v errFlag=e newline="'\n'"
..SSIILLEENNTT Apply the ..SSIILLEENNTT attribute to any specified sources. If no
sources are specified, the ..SSIILLEENNTT attribute is applied to every
@@ -892,11 +1015,9 @@ EENNVVIIRROONNMMEENNTT
MACHINE_ARCH, MAKE, MAKEFLAGS, MAKEOBJDIR, MAKEOBJDIRPREFIX, MAKESYSPATH,
and PWD.
- If MAKEOBJDIRPREFIX is set, then bbmmaakkee will chdir(2) to ${MAKEOBJDIRPRE-
- FIX}${.CURDIR} if it exists. Otherwise if MAKEOBJDIR and the named
- directory exists bbmmaakkee will chdir(2) to it. These actions are taken
- before any makefiles are read which is why they need to be set in the
- environment.
+ MAKEOBJDIRPREFIX and MAKEOBJDIR may only be set in the environment or on
+ the command line to bbmmaakkee and not as makefile variables; see the descrip-
+ tion of `_._O_B_J_D_I_R' for more details.
FFIILLEESS
.depend list of dependencies
@@ -905,6 +1026,15 @@ FFIILLEESS
sys.mk system makefile
/usr/share/mk system makefile directory
+CCOOMMPPAATTIIBBIILLIITTYY
+ The basic make syntax is compatible between different versions of make,
+ however the special variables, variable modifiers and conditionals are
+ not.
+
+ The way that parallel makes are scheduled changed in NetBSD 4.0 so that
+ .ORDER and .WAIT apply recursively to the dependant nodes. The algo-
+ rithms used may change again in the future.
+
SSEEEE AALLSSOO
mkdep(1)
@@ -912,4 +1042,4 @@ HHIISSTTOORRYY
bbmmaakkee is derived from NetBSD's make(1). It uses autoconf to facilitate
portability to other platforms.
-NetBSD 2.0 June 1, 2005 NetBSD 2.0
+BSD November 19, 2006 BSD
diff --git a/devel/bmake/files/boot-strap b/devel/bmake/files/boot-strap
index c9c014f5f8c..57f66b2cf6e 100755
--- a/devel/bmake/files/boot-strap
+++ b/devel/bmake/files/boot-strap
@@ -14,6 +14,19 @@
# (http://www.crufty.net/FreeWare/configs.html), $prefix/bin
# and a suitable ~/*bin directory.
#
+# Options:
+#
+# -c "rc"
+# Pick up settings from "rc".
+# We look for '.bmake-boot-strap.rc' before processing
+# options.
+#
+# -m "mksrc"
+# Indicate where the mk files can be found.
+# Default is ./mk or ../mk, set to 'none' to force
+# building without "mksrc" but in that case a sys.mk
+# needs to exist in the default syspath ($prefix/share/mk)
+#
# Possibly useful configure_args:
#
# --with-machine="machine"
@@ -38,7 +51,7 @@
# Simon J. Gerraty <sjg@crufty.net>
# RCSid:
-# $Id: boot-strap,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $
+# $Id: boot-strap,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $
#
# @(#) Copyright (c) 2001 Simon J. Gerraty
#
@@ -73,14 +86,31 @@ Error() {
exit 1
}
+source_rc() {
+ rc=$1; shift
+ for d in ${*:-""}
+ do
+ r=${d:+$d/}$rc
+ [ -f $r -a -s $r ] || continue
+ echo "NOTE: reading $r"
+ . $r
+ break
+ done
+}
CONFIGURE_ARGS=
-prefix=
+# pick a useful default prefix (for me at least ;-)
+for prefix in /opt/$HOST_TARGET $HOME/$HOST_TARGET /usr/pkg /usr/local ""
+do
+ [ -d ${prefix:-.} ] && break
+done
srcdir=
mksrc=
objdir=
quiet=:
+source_rc .bmake-boot-strap.rc . $Mydir/.. $HOME
+
while :
do
case "$1" in
@@ -93,6 +123,7 @@ do
-m|--mksrc) mksrc=$2; shift 2;;
-o|--objdir) objdir=$2; shift 2;;
-q) quiet=; shift;;
+ -c) source_rc $2; shift 2;;
--*) CONFIGURE_ARGS="$CONFIGURE_ARGS $1"; shift;;
*=*) eval "$1"; export `IFS="="; set -- $1; echo $1`; shift;;
*) break;;
@@ -133,7 +164,7 @@ none|-) # we don't want it
;;
*) # guess we want mksrc...
mksrc=`GetDir /mk $mksrc $3 ./mk* $srcdir/mk* $srcdir/../mk*`
- [ -d ${mksrc:-/dev/null} ] || Usage
+ [ -d ${mksrc:-/dev/null} ] || Usage "Use '-m none' to build without mksrc"
;;
esac
@@ -148,7 +179,12 @@ case "$CONFIGURE_ARGS" in
*--with-prefix-sys-path*) ;; # skip
*) AddConfigure --with-default-sys-path= $prefix/share/mk;;
esac
-[ "$mksrc" ] && AddConfigure --with-mksrc= $mksrc
+if [ "$mksrc" ]; then
+ AddConfigure --with-mksrc= $mksrc
+ # not all cc's support this
+ export CFLAGS_MF=
+fi
+
$srcdir/configure $CONFIGURE_ARGS || exit 1
${MAKE:-make} -f makefile.boot clean
${MAKE:-make} -f makefile.boot bootstrap || exit 1
@@ -159,15 +195,24 @@ $quiet exit 0
make_version=`./bmake -m ./mk -m /usr/share/mk -f ./Makefile -V MAKE_VERSION | ( read one two; echo $one )`
install_prefix() {
- bdir=$1/bin
+ bindir=$1/bin
+ mandir=$1/share/man
+ mkdir=${2:-$1}/share/mk
echo
echo Commands to install into $1/
echo
- echo mkdir -p $bdir
- echo cp $objdir/bmake $bdir/$make_version
- echo rm -f $bdir/bmake
- echo ln -s $make_version $bdir/bmake
- [ "$mksrc" ] && echo $mksrc/install-mk $1/share/mk
+ echo mkdir -p $bindir
+ echo cp $objdir/bmake $bindir/$make_version
+ echo rm -f $bindir/bmake
+ echo ln -s $make_version $bindir/bmake
+ if [ -s bmake.cat1 ]; then
+ echo mkdir -p $mandir/man1
+ echo cp $srcdir/bmake.1 $mandir/man1
+ else
+ echo mkdir -p $mandir/cat1
+ echo cp $srcdir/bmake.cat1 $mandir/cat1/bmake.1
+ fi
+ [ "$mksrc" ] && echo $mksrc/install-mk $mkdir
}
case $prefix/ in
diff --git a/devel/bmake/files/buf.c b/devel/bmake/files/buf.c
index 88892914bb2..91d810426b3 100644
--- a/devel/bmake/files/buf.c
+++ b/devel/bmake/files/buf.c
@@ -1,4 +1,4 @@
-/* $NetBSD: buf.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: buf.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: buf.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: buf.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: buf.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: buf.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $");
#endif
#endif /* not lint */
#endif
diff --git a/devel/bmake/files/buf.h b/devel/bmake/files/buf.h
index 9d2077fd485..2712571339c 100644
--- a/devel/bmake/files/buf.h
+++ b/devel/bmake/files/buf.h
@@ -1,4 +1,4 @@
-/* $NetBSD: buf.h,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: buf.h,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
diff --git a/devel/bmake/files/compat.c b/devel/bmake/files/compat.c
index 4de01f63a57..76c0305d7c8 100644
--- a/devel/bmake/files/compat.c
+++ b/devel/bmake/files/compat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compat.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: compat.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: compat.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: compat.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: compat.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: compat.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -210,35 +210,29 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
char *cmdStart; /* Start of expanded command */
char *cp, *bp;
Boolean silent, /* Don't print command */
- doIt, /* Execute even if -n */
- errCheck; /* Check errors */
+ doIt; /* Execute even if -n */
+ volatile Boolean errCheck; /* Check errors */
WAIT_T reason; /* Reason for child's death */
- int status; /* Description of child's death */
+ int status; /* Description of child's death */
int cpid; /* Child actually found */
ReturnStatus retstat; /* Status of fork */
LstNode cmdNode; /* Node where current command is located */
- const char **av; /* Argument vector for thing to exec */
+ const char ** volatile av; /* Argument vector for thing to exec */
+ char ** volatile mav;/* Copy of the argument vector for freeing */
int argc; /* Number of arguments in av or 0 if not
* dynamically allocated */
Boolean local; /* TRUE if command should be executed
* locally */
- char *cmd = (char *)cmdp;
+ Boolean useShell; /* TRUE if command should be executed
+ * using a shell */
+ char * volatile cmd = (char *)cmdp;
GNode *gn = (GNode *)gnp;
- /*
- * Avoid clobbered variable warnings by forcing the compiler
- * to ``unregister'' variables
- */
-#if __GNUC__
- (void) &av;
- (void) &errCheck;
- (void) &cmd;
-#endif
silent = gn->type & OP_SILENT;
errCheck = !(gn->type & OP_IGNORE);
doIt = FALSE;
- cmdNode = Lst_Member(gn->commands, (ClientData)cmd);
+ cmdNode = Lst_Member(gn->commands, cmd);
cmdStart = Var_Subst(NULL, cmd, gn, FALSE);
/*
@@ -255,10 +249,10 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
} else {
cmd = cmdStart;
}
- Lst_Replace(cmdNode, (ClientData)cmdStart);
+ Lst_Replace(cmdNode, cmdStart);
if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
- (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
+ (void)Lst_AtEnd(ENDNode->commands, cmdStart);
return(0);
} else if (strcmp(cmdStart, "...") == 0) {
gn->type |= OP_SAVE_CMDS;
@@ -268,7 +262,7 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) {
switch (*cmd) {
case '@':
- silent = TRUE;
+ silent = DEBUG(LOUD) ? FALSE : TRUE;
break;
case '-':
errCheck = FALSE;
@@ -285,6 +279,15 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
while (isspace((unsigned char)*cmd))
cmd++;
+#if !defined(MAKE_NATIVE)
+ /*
+ * In a non-native build, the host environment might be weird enough
+ * that it's necessary to go through a shell to get the correct
+ * behaviour. Or perhaps the shell has been replaced with something
+ * that does extra logging, and that should not be bypassed.
+ */
+ useShell = TRUE;
+#else
/*
* Search for meta characters in the command. If there are no meta
* characters, there's no need to execute a shell to execute the
@@ -293,6 +296,8 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
continue;
}
+ useShell = (*cp != '\0');
+#endif
/*
* Print the command before echoing if we're not supposed to be quiet for
@@ -311,10 +316,10 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
return (0);
}
- if (*cp != '\0') {
+ if (useShell) {
/*
- * If *cp isn't the null character, we hit a "meta" character and
- * need to pass the command off to the shell.
+ * We need to pass the command off to the shell, typically
+ * because the command contains a "meta" character.
*/
static const char *shargv[4];
@@ -331,12 +336,14 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
av = shargv;
argc = 0;
bp = NULL;
+ mav = NULL;
} else {
/*
* No meta-characters, so no need to exec a shell. Break the command
* into words to form an argument vector we can execute.
*/
- av = (const char **)brk_string(cmd, &argc, TRUE, &bp);
+ mav = brk_string(cmd, &argc, TRUE, &bp);
+ av = (const char **)mav;
}
local = TRUE;
@@ -350,6 +357,7 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
}
if (cpid == 0) {
Check_Cwd(av);
+ Var_ExportVars();
if (local)
(void)execvp(av[0], (char *const *)UNCONST(av));
else
@@ -357,11 +365,11 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
execError("exec", av[0]);
_exit(1);
}
- if (bp) {
- free(av);
+ if (mav)
+ free(mav);
+ if (bp)
free(bp);
- }
- Lst_Replace(cmdNode, (ClientData) NULL);
+ Lst_Replace(cmdNode, NULL);
/*
* The child is off and running. Now all we can do is wait...
@@ -381,21 +389,21 @@ CompatRunCommand(ClientData cmdp, ClientData gnp)
status = WEXITSTATUS(reason); /* exited */
if (status != 0) {
if (DEBUG(ERROR)) {
- printf("\n*** Failed target: %s\n*** Failed command: ",
+ fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ",
gn->name);
for (cp = cmd; *cp; ) {
if (isspace((unsigned char)*cp)) {
- putchar(' ');
+ fprintf(debug_file, " ");
while (isspace((unsigned char)*cp))
cp++;
} else {
- putchar(*cp);
+ fprintf(debug_file, "%c", *cp);
cp++;
}
}
- printf("\n");
+ fprintf(debug_file, "\n");
}
- printf("*** Error code %d", status);
+ fprintf(debug_file, "*** Error code %d", status);
}
} else {
status = WTERMSIG(reason); /* signaled */
@@ -471,7 +479,7 @@ Compat_Make(ClientData gnp, ClientData pgnp)
gn->made = BEINGMADE;
if ((gn->type & OP_MADE) == 0)
Suff_FindDeps(gn);
- Lst_ForEach(gn->children, Compat_Make, (ClientData)gn);
+ Lst_ForEach(gn->children, Compat_Make, gn);
if ((gn->flags & REMAKE) == 0) {
gn->made = ABORTED;
pgn->flags &= ~REMAKE;
@@ -492,16 +500,16 @@ Compat_Make(ClientData gnp, ClientData pgnp)
* Make_OODate function.
*/
if (DEBUG(MAKE)) {
- printf("Examining %s...", gn->name);
+ fprintf(debug_file, "Examining %s...", gn->name);
}
if (! Make_OODate(gn)) {
gn->made = UPTODATE;
if (DEBUG(MAKE)) {
- printf("up-to-date.\n");
+ fprintf(debug_file, "up-to-date.\n");
}
goto cohorts;
} else if (DEBUG(MAKE)) {
- printf("out-of-date.\n");
+ fprintf(debug_file, "out-of-date.\n");
}
/*
@@ -537,7 +545,7 @@ Compat_Make(ClientData gnp, ClientData pgnp)
*/
if (!touchFlag || (gn->type & OP_MAKE)) {
curTarg = gn;
- Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
+ Lst_ForEach(gn->commands, CompatRunCommand, gn);
curTarg = NILGNODE;
} else {
Job_Touch(gn, gn->type & OP_SILENT);
@@ -663,7 +671,7 @@ Compat_Run(Lst targs)
* Expand .USE nodes right now, because they can modify the structure
* of the tree.
*/
- Lst_Destroy(Make_ExpandUse(targs), NOFREE);
+ Make_ExpandUse(targs);
/*
* For each entry in the list of targets to create, call Compat_Make on
diff --git a/devel/bmake/files/cond.c b/devel/bmake/files/cond.c
index 504d907d188..78d2abefba2 100644
--- a/devel/bmake/files/cond.c
+++ b/devel/bmake/files/cond.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cond.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: cond.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: cond.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: cond.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
#else
-__RCSID("$NetBSD: cond.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: cond.c,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -152,17 +152,17 @@ static Token CondT(Boolean);
static Token CondF(Boolean);
static Token CondE(Boolean);
-static struct If {
+static const struct If {
const char *form; /* Form of if */
int formlen; /* Length of form */
Boolean doNot; /* TRUE if default function should be negated */
Boolean (*defProc)(int, char *); /* Default function to apply */
} ifs[] = {
- { "ifdef", 5, FALSE, CondDoDefined },
- { "ifndef", 6, TRUE, CondDoDefined },
- { "ifmake", 6, FALSE, CondDoMake },
- { "ifnmake", 7, TRUE, CondDoMake },
- { "if", 2, FALSE, CondDoDefined },
+ { "def", 3, FALSE, CondDoDefined },
+ { "ndef", 4, TRUE, CondDoDefined },
+ { "make", 4, FALSE, CondDoMake },
+ { "nmake", 5, TRUE, CondDoMake },
+ { "", 0, FALSE, CondDoDefined },
{ NULL, 0, FALSE, NULL }
};
@@ -172,14 +172,8 @@ static char *condExpr; /* The expression to parse */
static Token condPushBack=None; /* Single push-back token used in
* parsing */
-#define MAXIF 64 /* greatest depth of #if'ing */
-
-static Boolean finalElse[MAXIF+1][MAXIF+1]; /* Seen final else (stack) */
-static Boolean condStack[MAXIF]; /* Stack of conditionals's values */
-static int condTop = MAXIF; /* Top-most conditional */
-static int skipIfLevel=0; /* Depth of skipped conditionals */
-static Boolean skipLine = FALSE; /* Whether the parse module is skipping
- * lines */
+static unsigned int cond_depth = 0; /* current .if nesting level */
+static unsigned int cond_min_depth = 0; /* depth at makefile open */
static int
istoken(const char *str, const char *tok, size_t len)
@@ -251,7 +245,7 @@ CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
* than hitting the user with a warning message every time s/he uses
* the word 'make' or 'defined' at the beginning of a symbol...
*/
- *argPtr = cp;
+ *argPtr = NULL;
return (0);
}
@@ -275,14 +269,12 @@ CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
*/
char *cp2;
int len;
- Boolean doFree;
-
- cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
+ void *freeIt;
+ cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt);
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
- if (doFree) {
- free(cp2);
- }
+ if (freeIt)
+ free(freeIt);
cp += len;
} else {
Buf_AddByte(buf, (Byte)*cp);
@@ -384,7 +376,7 @@ CondDoMake(int argLen, char *arg)
Boolean result;
arg[argLen] = '\0';
- if (Lst_Find(create, (ClientData)arg, CondStrMatch) == NILLNODE) {
+ if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) {
result = FALSE;
} else {
result = TRUE;
@@ -422,6 +414,10 @@ CondDoExists(int argLen, char *arg)
result = FALSE;
}
arg[argLen] = savec;
+ if (DEBUG(COND)) {
+ fprintf(debug_file, "exists(%s) result is \"%s\"\n",
+ arg, path ? path : "");
+ }
return (result);
}
@@ -540,7 +536,7 @@ CondCvtArg(char *str, double *value)
* string. This is called for the lhs and rhs of string compares.
*
* Results:
- * Sets doFree if needed,
+ * Sets freeIt if needed,
* Sets quoted if string was quoted,
* Returns NULL on error,
* else returns string - absent any quotes.
@@ -551,8 +547,9 @@ CondCvtArg(char *str, double *value)
*
*-----------------------------------------------------------------------
*/
+/* coverity:[+alloc : arg-*2] */
static char *
-CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree)
+CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
{
Buffer buf;
char *cp;
@@ -563,6 +560,7 @@ CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree)
buf = Buf_Init(0);
str = NULL;
+ *freeIt = NULL;
*quoted = qt = *condExpr == '"' ? 1 : 0;
if (qt)
condExpr++;
@@ -596,8 +594,12 @@ CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree)
case '$':
/* if we are in quotes, then an undefined variable is ok */
str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
- &len, doFree);
+ &len, freeIt);
if (str == var_Error) {
+ if (*freeIt) {
+ free(*freeIt);
+ *freeIt = NULL;
+ }
/*
* Even if !doEval, we still report syntax errors, which
* is what getting var_Error back with !doEval means.
@@ -623,9 +625,10 @@ CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree)
for (cp = str; *cp; cp++) {
Buf_AddByte(buf, (Byte)*cp);
}
- if (*doFree)
- free(str);
- *doFree = FALSE;
+ if (*freeIt) {
+ free(*freeIt);
+ *freeIt = NULL;
+ }
str = NULL; /* not finished yet */
condExpr--; /* don't skip over next char */
break;
@@ -637,7 +640,7 @@ CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree)
got_str:
Buf_AddByte(buf, (Byte)'\0');
str = (char *)Buf_GetAll(buf, NULL);
- *doFree = TRUE;
+ *freeIt = str;
cleanup:
Buf_Destroy(buf, FALSE);
return str;
@@ -702,8 +705,8 @@ CondToken(Boolean doEval)
char *lhs;
char *rhs;
char *op;
- Boolean lhsFree;
- Boolean rhsFree;
+ void *lhsFree;
+ void *rhsFree;
Boolean lhsQuoted;
Boolean rhsQuoted;
@@ -717,8 +720,11 @@ CondToken(Boolean doEval)
*/
t = Err;
lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
- if (!lhs)
+ if (!lhs) {
+ if (lhsFree)
+ free(lhsFree);
return Err;
+ }
/*
* Skip whitespace to get to the operator
*/
@@ -760,8 +766,13 @@ CondToken(Boolean doEval)
goto error;
}
rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
- if (!rhs)
+ if (!rhs) {
+ if (lhsFree)
+ free(lhsFree);
+ if (rhsFree)
+ free(rhsFree);
return Err;
+ }
do_compare:
if (rhsQuoted || lhsQuoted) {
do_string_compare:
@@ -772,7 +783,7 @@ do_string_compare:
}
if (DEBUG(COND)) {
- printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
+ fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
lhs, rhs, op);
}
/*
@@ -799,7 +810,7 @@ do_string_compare:
goto do_string_compare;
if (DEBUG(COND)) {
- printf("left = %f, right = %f, op = %.2s\n", left,
+ fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
right, op);
}
switch(op[0]) {
@@ -837,16 +848,16 @@ do_string_compare:
}
error:
if (lhsFree)
- free(lhs);
+ free(lhsFree);
if (rhsFree)
- free(rhs);
+ free(rhsFree);
break;
}
default: {
Boolean (*evalProc)(int, char *);
Boolean invert = FALSE;
- char *arg;
- int arglen;
+ char *arg = NULL;
+ int arglen = 0;
if (istoken(condExpr, "defined", 7)) {
/*
@@ -892,20 +903,28 @@ error:
* Use Var_Parse to parse the spec in parens and return
* True if the resulting string is empty.
*/
- int length;
- Boolean doFree;
+ int did_warn, length;
+ void *freeIt;
char *val;
condExpr += 5;
- for (arglen = 0;
- condExpr[arglen] != '(' && condExpr[arglen] != '\0';
- arglen += 1)
- continue;
+ did_warn = 0;
+ for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) {
+ if (condExpr[arglen] == '(')
+ break;
+ if (!isspace((unsigned char)condExpr[arglen]) &&
+ !did_warn) {
+
+ Parse_Error(PARSE_WARNING,
+ "Extra characters after \"empty\"");
+ did_warn = 1;
+ }
+ }
if (condExpr[arglen] != '\0') {
val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
- FALSE, &length, &doFree);
+ FALSE, &length, &freeIt);
if (val == var_Error) {
t = Err;
} else {
@@ -918,8 +937,8 @@ error:
continue;
t = (*p == '\0') ? True : False;
}
- if (doFree) {
- free(val);
+ if (freeIt) {
+ free(freeIt);
}
/*
* Advance condExpr to beyond the closing ). Note that
@@ -979,7 +998,8 @@ error:
t = (!doEval || (* evalProc) (arglen, arg) ?
(invert ? False : True) :
(invert ? True : False));
- free(arg);
+ if (arg)
+ free(arg);
break;
}
}
@@ -1199,7 +1219,7 @@ err:
* Cond_Eval --
* Evaluate the conditional in the passed line. The line
* looks like this:
- * #<cond-type> <expr>
+ * .<cond-type> <expr>
* where <cond-type> is any of if, ifmake, ifnmake, ifdef,
* ifndef, elif, elifmake, elifnmake, elifdef, elifndef
* and <expr> consists of &&, ||, !, make(target), defined(variable)
@@ -1216,157 +1236,147 @@ err:
* Side Effects:
* None.
*
+ * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
+ * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
+ * otherwise .else could be treated as '.elif 1'.
+ *
*-----------------------------------------------------------------------
*/
int
Cond_Eval(char *line)
{
- struct If *ifp;
- Boolean isElse;
- Boolean value = FALSE;
+ #define MAXIF 64 /* maximum depth of .if'ing */
+ enum if_states {
+ IF_ACTIVE, /* .if or .elif part active */
+ ELSE_ACTIVE, /* .else part active */
+ SEARCH_FOR_ELIF, /* searching for .elif/else to execute */
+ SKIP_TO_ELSE, /* has been true, but not seen '.else' */
+ SKIP_TO_ENDIF /* nothing else to execute */
+ };
+ static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
+
+ const struct If *ifp;
+ Boolean isElif;
+ Boolean value;
int level; /* Level at which to report errors. */
+ enum if_states state;
level = PARSE_FATAL;
- for (line++; *line == ' ' || *line == '\t'; line++) {
+ /* skip leading character (the '.') and any whitespace */
+ for (line++; *line == ' ' || *line == '\t'; line++)
continue;
- }
- /*
- * Find what type of if we're dealing with. The result is left
- * in ifp and isElse is set TRUE if it's an elif line.
- */
- if (line[0] == 'e' && line[1] == 'l') {
- line += 2;
- isElse = TRUE;
- } else if (istoken(line, "endif", 5)) {
- /*
- * End of a conditional section. If skipIfLevel is non-zero, that
- * conditional was skipped, so lines following it should also be
- * skipped. Hence, we return COND_SKIP. Otherwise, the conditional
- * was read so succeeding lines should be parsed (think about it...)
- * so we return COND_PARSE, unless this endif isn't paired with
- * a decent if.
- */
- finalElse[condTop][skipIfLevel] = FALSE;
- if (skipIfLevel != 0) {
- skipIfLevel -= 1;
- return (COND_SKIP);
- } else {
- if (condTop == MAXIF) {
+ /* Find what type of if we're dealing with. */
+ if (line[0] == 'e') {
+ if (line[1] != 'l') {
+ if (!istoken(line + 1, "ndif", 4))
+ return COND_INVALID;
+ /* End of conditional section */
+ if (cond_depth == cond_min_depth) {
Parse_Error(level, "if-less endif");
- return (COND_INVALID);
- } else {
- skipLine = FALSE;
- condTop += 1;
- return (COND_PARSE);
+ return COND_PARSE;
}
+ /* Return state for previous conditional */
+ cond_depth--;
+ return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
}
- } else {
- isElse = FALSE;
- }
+
+ /* Quite likely this is 'else' or 'elif' */
+ line += 2;
+ if (istoken(line, "se", 2)) {
+ /* It is else... */
+ if (cond_depth == cond_min_depth) {
+ Parse_Error(level, "if-less else");
+ return COND_INVALID;
+ }
+
+ state = cond_state[cond_depth];
+ switch (state) {
+ case SEARCH_FOR_ELIF:
+ state = ELSE_ACTIVE;
+ break;
+ case ELSE_ACTIVE:
+ case SKIP_TO_ENDIF:
+ Parse_Error(PARSE_WARNING, "extra else");
+ /* FALLTHROUGH */
+ default:
+ case IF_ACTIVE:
+ case SKIP_TO_ELSE:
+ state = SKIP_TO_ENDIF;
+ break;
+ }
+ cond_state[cond_depth] = state;
+ return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
+ }
+ /* Assume for now it is an elif */
+ isElif = TRUE;
+ } else
+ isElif = FALSE;
+
+ if (line[0] != 'i' || line[1] != 'f')
+ /* Not an ifxxx or elifxxx line */
+ return COND_INVALID;
/*
* Figure out what sort of conditional it is -- what its default
* function is, etc. -- by looking in the table of valid "ifs"
*/
- for (ifp = ifs; ifp->form != NULL; ifp++) {
+ line += 2;
+ for (ifp = ifs; ; ifp++) {
+ if (ifp->form == NULL)
+ return COND_INVALID;
if (istoken(ifp->form, line, ifp->formlen)) {
+ line += ifp->formlen;
break;
}
}
- if (ifp->form == NULL) {
- /*
- * Nothing fit. If the first word on the line is actually
- * "else", it's a valid conditional whose value is the inverse
- * of the previous if we parsed.
- */
- if (isElse && istoken(line, "se", 2)) {
- if (finalElse[condTop][skipIfLevel]) {
- Parse_Error(PARSE_WARNING, "extra else");
- } else {
- finalElse[condTop][skipIfLevel] = TRUE;
- }
- if (condTop == MAXIF) {
- Parse_Error(level, "if-less else");
- return (COND_INVALID);
- } else if (skipIfLevel == 0) {
- value = !condStack[condTop];
- } else {
- return (COND_SKIP);
- }
- } else {
- /*
- * Not a valid conditional type. No error...
- */
- return (COND_INVALID);
+ /* Now we know what sort of 'if' it is... */
+ state = cond_state[cond_depth];
+
+ if (isElif) {
+ if (cond_depth == cond_min_depth) {
+ Parse_Error(level, "if-less elif");
+ return COND_INVALID;
+ }
+ if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE)
+ Parse_Error(PARSE_WARNING, "extra elif");
+ if (state != SEARCH_FOR_ELIF) {
+ /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
+ cond_state[cond_depth] = SKIP_TO_ELSE;
+ return COND_SKIP;
}
} else {
- if (isElse) {
- if (condTop == MAXIF) {
- Parse_Error(level, "if-less elif");
- return (COND_INVALID);
- } else if (skipIfLevel != 0) {
- /*
- * If skipping this conditional, just ignore the whole thing.
- * If we don't, the user might be employing a variable that's
- * undefined, for which there's an enclosing ifdef that
- * we're skipping...
- */
- return(COND_SKIP);
- }
- } else if (skipLine) {
- /*
- * Don't even try to evaluate a conditional that's not an else if
- * we're skipping things...
- */
- skipIfLevel += 1;
- if (skipIfLevel >= MAXIF) {
- Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
- return (COND_INVALID);
- }
- finalElse[condTop][skipIfLevel] = FALSE;
- return(COND_SKIP);
+ if (cond_depth >= MAXIF) {
+ Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
+ return COND_INVALID;
+ }
+ cond_depth++;
+ if (state > ELSE_ACTIVE) {
+ /* If we aren't parsing the data, treat as always false */
+ cond_state[cond_depth] = SKIP_TO_ELSE;
+ return COND_SKIP;
}
+ }
- /*
- * Initialize file-global variables for parsing
- */
- condDefProc = ifp->defProc;
- condInvert = ifp->doNot;
+ /* Initialize file-global variables for parsing the expression */
+ condDefProc = ifp->defProc;
+ condInvert = ifp->doNot;
- line += ifp->formlen;
- if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID)
- return COND_INVALID;
- }
- if (!isElse) {
- condTop -= 1;
- finalElse[condTop][skipIfLevel] = FALSE;
- } else if ((skipIfLevel != 0) || condStack[condTop]) {
- /*
- * If this is an else-type conditional, it should only take effect
- * if its corresponding if was evaluated and FALSE. If its if was
- * TRUE or skipped, we return COND_SKIP (and start skipping in case
- * we weren't already), leaving the stack unmolested so later elif's
- * don't screw up...
- */
- skipLine = TRUE;
- return (COND_SKIP);
+ /* And evaluate the conditional expresssion */
+ if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
+ /* Although we get make to reprocess the line, set a state */
+ cond_state[cond_depth] = SEARCH_FOR_ELIF;
+ return COND_INVALID;
}
- if (condTop < 0) {
- /*
- * This is the one case where we can definitely proclaim a fatal
- * error. If we don't, we're hosed.
- */
- Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
- return (COND_INVALID);
- } else {
- condStack[condTop] = value;
- skipLine = !value;
- return (value ? COND_PARSE : COND_SKIP);
+ if (!value) {
+ cond_state[cond_depth] = SEARCH_FOR_ELIF;
+ return COND_SKIP;
}
+ cond_state[cond_depth] = IF_ACTIVE;
+ return COND_PARSE;
}
@@ -1385,11 +1395,24 @@ Cond_Eval(char *line)
*-----------------------------------------------------------------------
*/
void
-Cond_End(void)
+Cond_restore_depth(unsigned int saved_depth)
{
- if (condTop != MAXIF) {
- Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,
- MAXIF-condTop == 1 ? "" : "s");
+ int open_conds = cond_depth - cond_min_depth;
+
+ if (open_conds != 0 || saved_depth > cond_depth) {
+ Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
+ open_conds == 1 ? "" : "s");
+ cond_depth = cond_min_depth;
}
- condTop = MAXIF;
+
+ cond_min_depth = saved_depth;
+}
+
+unsigned int
+Cond_save_depth(void)
+{
+ int depth = cond_min_depth;
+
+ cond_min_depth = cond_depth;
+ return depth;
}
diff --git a/devel/bmake/files/config.h.in b/devel/bmake/files/config.h.in
index 96bddc2133e..02ff11323a2 100644
--- a/devel/bmake/files/config.h.in
+++ b/devel/bmake/files/config.h.in
@@ -1,7 +1,10 @@
/* config.h.in. Generated from configure.in by autoheader. */
+/* Path of default shell */
+#undef DEFSHELL_CUSTOM
+
/* Shell spec to use by default */
-#undef DEFSHELL
+#undef DEFSHELL_INDEX
/* Define to 1 if you have the <ar.h> header file. */
#undef HAVE_AR_H
@@ -20,6 +23,12 @@
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
+/* Define to 1 if you have the `emalloc' function. */
+#undef HAVE_EMALLOC
+
+/* Define to 1 if you have the `estrndup' function. */
+#undef HAVE_ESTRNDUP
+
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
@@ -98,6 +107,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
/* Define to 1 if you have the `strtod' function. */
#undef HAVE_STRTOD
@@ -143,6 +155,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H
diff --git a/devel/bmake/files/configure b/devel/bmake/files/configure
index 9e461f1f992..9f16efbc2f6 100755
--- a/devel/bmake/files/configure
+++ b/devel/bmake/files/configure
@@ -308,7 +308,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA ac_exe_suffix LIBOBJS machine force_machine machine_arch mksrc default_sys_path prefix_sys_path INSTALL GCC diff_u LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA ac_exe_suffix LIBOBJS machine force_machine machine_arch mksrc default_sys_path INSTALL GCC diff_u LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -846,7 +846,7 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-defshell=SHELL explicitly set DEFSHELL to either /bin/sh or /bin/ksh
+ --with-defshell=SHELL use SHELL by default - must be sh compatible, use sh or ksh to pick the internal definitions
--with-machine=MACHINE explicitly set MACHINE
--with-force-machine=MACHINE set FORCE_MACHINE
--with-force-machine-arch=MACHINE set FORCE_MACHINE_ARCH
@@ -1285,27 +1285,14 @@ yes) { { echo "$as_me:$LINENO: error: bad value ${withval} given for bmake DEF
echo "$as_me: error: bad value ${withval} given for bmake DEFSHELL" >&2;}
{ (exit 1); exit 1; }; } ;;
no) ;;
-*) case "/$with_defshell" in
- */csh) DEFSHELL=0;; # kidding right?
- */sh) DEFSHELL=1;;
- */ksh) DEFSHELL=2;;
- *) { { echo "$as_me:$LINENO: error: bad value ${withval} given for bmake DEFSHELL - only /bin/sh and /bin/ksh are valid" >&5
-echo "$as_me: error: bad value ${withval} given for bmake DEFSHELL - only /bin/sh and /bin/ksh are valid" >&2;}
- { (exit 1); exit 1; }; } ;;
- esac
- case "$with_defshell" in
- /bin/*) ;;
- /*) { { echo "$as_me:$LINENO: error: bad value ${withval} - DEFSHELL must reside in /bin" >&5
-echo "$as_me: error: bad value ${withval} - DEFSHELL must reside in /bin" >&2;}
- { (exit 1); exit 1; }; };;
+*) case "$with_defshell" in
+ sh) DEFSHELL_INDEX=DEFSHELL_INDEX_SH;; # it's the default anyway
+ ksh) DEFSHELL_INDEX=DEFSHELL_INDEX_KSH;;
+ csh) DEFSHELL_INDEX=DEFSHELL_INDEX_CSH;; # kidding right?
+ *) defshell_path=$with_defshell;; # better be sh compatible!
esac
-
-cat >>confdefs.h <<_ACEOF
-#define DEFSHELL ${DEFSHELL:-1}
-_ACEOF
-
;;
-esac
+ esac
fi;
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -5427,8 +5414,13 @@ fi
+
+
+
+
for ac_func in \
asprintf \
+ emalloc \
getcwd \
getenv \
getopt \
@@ -5441,10 +5433,13 @@ for ac_func in \
sigvec \
snprintf \
strdup \
+ estrndup \
+ strndup \
strerror \
strftime \
strtod \
strtol \
+ unsetenv \
vasprintf \
vsnprintf \
wait3 \
@@ -5927,7 +5922,24 @@ do
done
mksrc=`echo $mksrc | sed "s,$srcdir,\\\${srcdir},"`
echo "Using: MKSRC=$mksrc" 1>&6
+if test -x /usr/xpg4/bin/sh; then
+ defshell_path=${defshell_path:-/usr/xpg4/bin/sh}
+fi
+if test -n "$defshell_path"; then
+ echo "Using: SHELL=$defshell_path" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define DEFSHELL_CUSTOM "$defshell_path"
+_ACEOF
+fi
+if test -n "$DEFSHELL_INDEX"; then
+
+cat >>confdefs.h <<_ACEOF
+#define DEFSHELL_INDEX $DEFSHELL_INDEX
+_ACEOF
+
+fi
@@ -6569,7 +6581,6 @@ s,@force_machine@,$force_machine,;t t
s,@machine_arch@,$machine_arch,;t t
s,@mksrc@,$mksrc,;t t
s,@default_sys_path@,$default_sys_path,;t t
-s,@prefix_sys_path@,$prefix_sys_path,;t t
s,@INSTALL@,$INSTALL,;t t
s,@GCC@,$GCC,;t t
s,@diff_u@,$diff_u,;t t
diff --git a/devel/bmake/files/configure.in b/devel/bmake/files/configure.in
index 7df068ca508..ebcc8ee603c 100644
--- a/devel/bmake/files/configure.in
+++ b/devel/bmake/files/configure.in
@@ -1,6 +1,6 @@
dnl
dnl RCSid:
-dnl $Id: configure.in,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $
+dnl $Id: configure.in,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $
dnl
dnl Process this file with autoconf to produce a configure script
dnl
@@ -9,23 +9,19 @@ AC_CONFIG_HEADER(config.h)
dnl
AC_ARG_WITH(defshell,
-[ --with-defshell=SHELL explicitly set DEFSHELL to either /bin/sh or /bin/ksh],
+[ --with-defshell=SHELL use SHELL by default - must be sh compatible, use sh or ksh to pick the internal definitions],
[case "${withval}" in
yes) AC_MSG_ERROR(bad value ${withval} given for bmake DEFSHELL) ;;
no) ;;
-*) case "/$with_defshell" in
- */csh) DEFSHELL=0;; # kidding right?
- */sh) DEFSHELL=1;;
- */ksh) DEFSHELL=2;;
- *) AC_MSG_ERROR(bad value ${withval} given for bmake DEFSHELL - only /bin/sh and /bin/ksh are valid) ;;
+*) case "$with_defshell" in
+ sh) DEFSHELL_INDEX=DEFSHELL_INDEX_SH;; # it's the default anyway
+ ksh) DEFSHELL_INDEX=DEFSHELL_INDEX_KSH;;
+ csh) DEFSHELL_INDEX=DEFSHELL_INDEX_CSH;; # kidding right?
+ *) defshell_path=$with_defshell;; # better be sh compatible!
esac
- case "$with_defshell" in
- /bin/*) ;;
- /*) AC_MSG_ERROR(bad value ${withval} - DEFSHELL must reside in /bin);;
- esac
- AC_DEFINE_UNQUOTED(DEFSHELL, ${DEFSHELL:-1}, Shell spec to use by default)
;;
-esac])
+ esac])
+dnl
dnl
dnl Checks for programs.
AC_PROG_CC
@@ -97,6 +93,7 @@ AC_FUNC_WAIT3
dnl Keep this list sorted
AC_CHECK_FUNCS( \
asprintf \
+ emalloc \
getcwd \
getenv \
getopt \
@@ -109,10 +106,13 @@ AC_CHECK_FUNCS( \
sigvec \
snprintf \
strdup \
+ estrndup \
+ strndup \
strerror \
strftime \
strtod \
strtol \
+ unsetenv \
vasprintf \
vsnprintf \
wait3 \
@@ -277,6 +277,17 @@ do
done
mksrc=`echo $mksrc | sed "s,$srcdir,\\\${srcdir},"`
echo "Using: MKSRC=$mksrc" 1>&6
+dnl On some systems we want a different default shell by default
+if test -x /usr/xpg4/bin/sh; then
+ defshell_path=${defshell_path:-/usr/xpg4/bin/sh}
+fi
+if test -n "$defshell_path"; then
+ echo "Using: SHELL=$defshell_path" >&6
+ AC_DEFINE_UNQUOTED(DEFSHELL_CUSTOM, "$defshell_path", Path of default shell)
+fi
+if test -n "$DEFSHELL_INDEX"; then
+ AC_DEFINE_UNQUOTED(DEFSHELL_INDEX, $DEFSHELL_INDEX, Shell spec to use by default)
+fi
dnl
AC_SUBST(machine)
AC_SUBST(force_machine)
diff --git a/devel/bmake/files/dir.c b/devel/bmake/files/dir.c
index 7cc5dd07001..530d70c7b64 100644
--- a/devel/bmake/files/dir.c
+++ b/devel/bmake/files/dir.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dir.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: dir.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: dir.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: dir.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
#else
-__RCSID("$NetBSD: dir.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: dir.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -303,7 +303,7 @@ Dir_InitCur(const char *cdname)
* We've been here before, cleanup.
*/
cur->refCount -= 1;
- Dir_Destroy((ClientData) cur);
+ Dir_Destroy(cur);
}
cur = p;
}
@@ -329,7 +329,7 @@ Dir_InitDot(void)
LstNode ln;
/* Remove old entry from openDirectories, but do not destroy. */
- ln = Lst_Member(openDirectories, (ClientData)dot);
+ ln = Lst_Member(openDirectories, dot);
(void)Lst_Remove(openDirectories, ln);
}
@@ -366,12 +366,12 @@ Dir_End(void)
#ifdef CLEANUP
if (cur) {
cur->refCount -= 1;
- Dir_Destroy((ClientData) cur);
+ Dir_Destroy(cur);
}
dot->refCount -= 1;
dotLast->refCount -= 1;
- Dir_Destroy((ClientData) dotLast);
- Dir_Destroy((ClientData) dot);
+ Dir_Destroy(dotLast);
+ Dir_Destroy(dot);
Dir_ClearPath(dirSearchPath);
Lst_Destroy(dirSearchPath, NOFREE);
Dir_ClearPath(openDirectories);
@@ -726,7 +726,7 @@ DirExpandInt(const char *word, Lst path, Lst expansions)
static int
DirPrintWord(ClientData word, ClientData dummy)
{
- printf("%s ", (char *)word);
+ fprintf(debug_file, "%s ", (char *)word);
return(dummy ? 0 : 0);
}
@@ -757,7 +757,7 @@ Dir_Expand(const char *word, Lst path, Lst expansions)
const char *cp;
if (DEBUG(DIR)) {
- printf("Expanding \"%s\"... ", word);
+ fprintf(debug_file, "Expanding \"%s\"... ", word);
}
cp = strchr(word, '{');
@@ -841,8 +841,8 @@ Dir_Expand(const char *word, Lst path, Lst expansions)
}
}
if (DEBUG(DIR)) {
- Lst_ForEach(expansions, DirPrintWord, (ClientData) 0);
- fputc('\n', stdout);
+ Lst_ForEach(expansions, DirPrintWord, NULL);
+ fprintf(debug_file, "\n");
}
}
@@ -866,7 +866,7 @@ DirLookup(Path *p, const char *name __unused, const char *cp,
char *file; /* the current filename to check */
if (DEBUG(DIR)) {
- printf(" %s ...\n", p->name);
+ fprintf(debug_file, " %s ...\n", p->name);
}
if (Hash_FindEntry(&p->files, cp) == NULL)
@@ -874,7 +874,7 @@ DirLookup(Path *p, const char *name __unused, const char *cp,
file = str_concat(p->name, cp, STR_ADDSLASH);
if (DEBUG(DIR)) {
- printf(" returning %s\n", file);
+ fprintf(debug_file, " returning %s\n", file);
}
p->hits += 1;
hits += 1;
@@ -913,7 +913,7 @@ DirLookupSubdir(Path *p, const char *name)
}
if (DEBUG(DIR)) {
- printf("checking %s ...\n", file);
+ fprintf(debug_file, "checking %s ...\n", file);
}
if (stat(file, &stb) == 0) {
@@ -922,7 +922,7 @@ DirLookupSubdir(Path *p, const char *name)
* to fetch it again.
*/
if (DEBUG(DIR)) {
- printf(" Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
+ fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
file);
}
entry = Hash_CreateEntry(&mtimes, (char *)file, NULL);
@@ -956,7 +956,7 @@ DirLookupAbs(Path *p, const char *name, const char *cp)
const char *p2; /* pointer into name */
if (DEBUG(DIR)) {
- printf(" %s ...\n", p->name);
+ fprintf(debug_file, " %s ...\n", p->name);
}
/*
@@ -974,7 +974,7 @@ DirLookupAbs(Path *p, const char *name, const char *cp)
if (Hash_FindEntry(&p->files, cp) == NULL) {
if (DEBUG(DIR)) {
- printf(" must be here but isn't -- returning\n");
+ fprintf(debug_file, " must be here but isn't -- returning\n");
}
/* Return empty string: terminates search */
return estrdup("");
@@ -983,7 +983,7 @@ DirLookupAbs(Path *p, const char *name, const char *cp)
p->hits += 1;
hits += 1;
if (DEBUG(DIR)) {
- printf(" returning %s\n", name);
+ fprintf(debug_file, " returning %s\n", name);
}
return (estrdup(name));
}
@@ -1007,7 +1007,7 @@ DirFindDot(Boolean hasSlash __unused, const char *name, const char *cp)
if (Hash_FindEntry(&dot->files, cp) != NULL) {
if (DEBUG(DIR)) {
- printf(" in '.'\n");
+ fprintf(debug_file, " in '.'\n");
}
hits += 1;
dot->hits += 1;
@@ -1016,7 +1016,7 @@ DirFindDot(Boolean hasSlash __unused, const char *name, const char *cp)
if (cur &&
Hash_FindEntry(&cur->files, cp) != NULL) {
if (DEBUG(DIR)) {
- printf(" in ${.CURDIR} = %s\n", cur->name);
+ fprintf(debug_file, " in ${.CURDIR} = %s\n", cur->name);
}
hits += 1;
cur->hits += 1;
@@ -1054,7 +1054,7 @@ Dir_FindFile(const char *name, Lst path)
LstNode ln; /* a list element */
char *file; /* the current filename to check */
Path *p; /* current path member */
- const char *cp; /* index of first slash, if any */
+ const char *cp; /* Terminal name of file */
Boolean hasLastDot = FALSE; /* true we should search dot last */
Boolean hasSlash; /* true if 'name' contains a / */
struct stat stb; /* Buffer for stat, if necessary */
@@ -1074,12 +1074,12 @@ Dir_FindFile(const char *name, Lst path)
}
if (DEBUG(DIR)) {
- printf("Searching for %s ...", name);
+ fprintf(debug_file, "Searching for %s ...", name);
}
if (Lst_Open(path) == FAILURE) {
if (DEBUG(DIR)) {
- printf("couldn't open path, file not found\n");
+ fprintf(debug_file, "couldn't open path, file not found\n");
}
misses += 1;
return (NULL);
@@ -1090,11 +1090,11 @@ Dir_FindFile(const char *name, Lst path)
if (p == dotLast) {
hasLastDot = TRUE;
if (DEBUG(DIR))
- printf("[dot last]...");
+ fprintf(debug_file, "[dot last]...");
}
}
if (DEBUG(DIR)) {
- printf("\n");
+ fprintf(debug_file, "\n");
}
/*
@@ -1102,7 +1102,7 @@ Dir_FindFile(const char *name, Lst path)
* directory component is exactly `./', consult the cached contents
* of each of the directories on the search path.
*/
- if ((!hasSlash || (cp - name == 2 && *name == '.'))) {
+ if (!hasSlash || (cp - name == 2 && *name == '.')) {
/*
* We look through all the directories on the path seeking one which
* contains the final component of the given name. If such a beast
@@ -1129,7 +1129,7 @@ Dir_FindFile(const char *name, Lst path)
continue;
if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
Lst_Close(path);
- return file;
+ return file;
}
}
@@ -1157,7 +1157,7 @@ Dir_FindFile(const char *name, Lst path)
*/
if (!hasSlash) {
if (DEBUG(DIR)) {
- printf(" failed.\n");
+ fprintf(debug_file, " failed.\n");
}
misses += 1;
return (NULL);
@@ -1167,7 +1167,7 @@ Dir_FindFile(const char *name, Lst path)
Boolean checkedDot = FALSE;
if (DEBUG(DIR)) {
- printf(" Trying subdirectories...\n");
+ fprintf(debug_file, " Trying subdirectories...\n");
}
if (!hasLastDot) {
@@ -1213,7 +1213,7 @@ Dir_FindFile(const char *name, Lst path)
* so no point in proceeding...
*/
if (DEBUG(DIR)) {
- printf(" Checked . already, returning NULL\n");
+ fprintf(debug_file, " Checked . already, returning NULL\n");
}
return(NULL);
}
@@ -1230,7 +1230,7 @@ Dir_FindFile(const char *name, Lst path)
* returning an empty string.
*/
if (DEBUG(DIR)) {
- printf(" Trying exact path matches...\n");
+ fprintf(debug_file, " Trying exact path matches...\n");
}
if (!hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL)
@@ -1289,27 +1289,27 @@ Dir_FindFile(const char *name, Lst path)
}
#else /* !notdef */
if (DEBUG(DIR)) {
- printf(" Looking for \"%s\" ...\n", name);
+ fprintf(debug_file, " Looking for \"%s\" ...\n", name);
}
bigmisses += 1;
entry = Hash_FindEntry(&mtimes, name);
if (entry != NULL) {
if (DEBUG(DIR)) {
- printf(" got it (in mtime cache)\n");
+ fprintf(debug_file, " got it (in mtime cache)\n");
}
return(estrdup(name));
} else if (stat(name, &stb) == 0) {
entry = Hash_CreateEntry(&mtimes, name, NULL);
if (DEBUG(DIR)) {
- printf(" Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
+ fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
name);
}
Hash_SetValue(entry, (long)stb.st_mtime);
return (estrdup(name));
} else {
if (DEBUG(DIR)) {
- printf(" failed. Returning NULL\n");
+ fprintf(debug_file, " failed. Returning NULL\n");
}
return (NULL);
}
@@ -1428,8 +1428,12 @@ Dir_MTime(GNode *gn)
} else if (gn->path == NULL) {
if (gn->type & OP_NOPATH)
fullName = NULL;
- else
+ else {
fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
+ if (DEBUG(DIR))
+ fprintf(debug_file, "Found '%s' as '%s'\n",
+ gn->name, fullName ? fullName : "(not found)" );
+ }
} else {
fullName = gn->path;
}
@@ -1446,7 +1450,7 @@ Dir_MTime(GNode *gn)
* to the file system.
*/
if (DEBUG(DIR)) {
- printf("Using cached time %s for %s\n",
+ fprintf(debug_file, "Using cached time %s for %s\n",
Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName);
}
stb.st_mtime = (time_t)(long)Hash_GetValue(entry);
@@ -1497,27 +1501,26 @@ Dir_AddDir(Lst path, const char *name)
struct dirent *dp; /* entry in directory */
if (strcmp(name, ".DOTLAST") == 0) {
- ln = Lst_Find(path, (ClientData)UNCONST(name), DirFindName);
+ ln = Lst_Find(path, UNCONST(name), DirFindName);
if (ln != NILLNODE)
return (Path *)Lst_Datum(ln);
else {
dotLast->refCount += 1;
- (void)Lst_AtFront(path, (ClientData)dotLast);
+ (void)Lst_AtFront(path, dotLast);
}
}
if (path)
- ln = Lst_Find(openDirectories, (ClientData)UNCONST(name), DirFindName);
+ ln = Lst_Find(openDirectories, UNCONST(name), DirFindName);
if (ln != NILLNODE) {
p = (Path *)Lst_Datum(ln);
- if (Lst_Member(path, (ClientData)p) == NILLNODE) {
+ if (path && Lst_Member(path, p) == NILLNODE) {
p->refCount += 1;
- (void)Lst_AtEnd(path, (ClientData)p);
+ (void)Lst_AtEnd(path, p);
}
} else {
if (DEBUG(DIR)) {
- printf("Caching %s ...", name);
- fflush(stdout);
+ fprintf(debug_file, "Caching %s ...", name);
}
if ((d = opendir(name)) != NULL) {
@@ -1541,12 +1544,12 @@ Dir_AddDir(Lst path, const char *name)
(void)Hash_CreateEntry(&p->files, dp->d_name, NULL);
}
(void)closedir(d);
- (void)Lst_AtEnd(openDirectories, (ClientData)p);
+ (void)Lst_AtEnd(openDirectories, p);
if (path != NULL)
- (void)Lst_AtEnd(path, (ClientData)p);
+ (void)Lst_AtEnd(path, p);
}
if (DEBUG(DIR)) {
- printf("done\n");
+ fprintf(debug_file, "done\n");
}
}
return p;
@@ -1571,7 +1574,7 @@ Dir_CopyDir(ClientData p)
{
((Path *)p)->refCount += 1;
- return ((ClientData)p);
+ return (p);
}
/*-
@@ -1646,7 +1649,7 @@ Dir_Destroy(ClientData pp)
if (p->refCount == 0) {
LstNode ln;
- ln = Lst_Member(openDirectories, (ClientData)p);
+ ln = Lst_Member(openDirectories, p);
(void)Lst_Remove(openDirectories, ln);
Hash_DeleteTable(&p->files);
@@ -1678,7 +1681,7 @@ Dir_ClearPath(Lst path)
Path *p;
while (!Lst_IsEmpty(path)) {
p = (Path *)Lst_DeQueue(path);
- Dir_Destroy((ClientData) p);
+ Dir_Destroy(p);
}
}
@@ -1709,9 +1712,9 @@ Dir_Concat(Lst path1, Lst path2)
for (ln = Lst_First(path2); ln != NILLNODE; ln = Lst_Succ(ln)) {
p = (Path *)Lst_Datum(ln);
- if (Lst_Member(path1, (ClientData)p) == NILLNODE) {
+ if (Lst_Member(path1, p) == NILLNODE) {
p->refCount += 1;
- (void)Lst_AtEnd(path1, (ClientData)p);
+ (void)Lst_AtEnd(path1, p);
}
}
}
@@ -1723,16 +1726,16 @@ Dir_PrintDirectories(void)
LstNode ln;
Path *p;
- printf("#*** Directory Cache:\n");
- printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
+ fprintf(debug_file, "#*** Directory Cache:\n");
+ fprintf(debug_file, "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
hits, misses, nearmisses, bigmisses,
(hits+bigmisses+nearmisses ?
hits * 100 / (hits + bigmisses + nearmisses) : 0));
- printf("# %-20s referenced\thits\n", "directory");
+ fprintf(debug_file, "# %-20s referenced\thits\n", "directory");
if (Lst_Open(openDirectories) == SUCCESS) {
while ((ln = Lst_Next(openDirectories)) != NILLNODE) {
p = (Path *)Lst_Datum(ln);
- printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
+ fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
}
Lst_Close(openDirectories);
}
@@ -1741,12 +1744,12 @@ Dir_PrintDirectories(void)
static int
DirPrintDir(ClientData p, ClientData dummy)
{
- printf("%s ", ((Path *)p)->name);
+ fprintf(debug_file, "%s ", ((Path *)p)->name);
return (dummy ? 0 : 0);
}
void
Dir_PrintPath(Lst path)
{
- Lst_ForEach(path, DirPrintDir, (ClientData)0);
+ Lst_ForEach(path, DirPrintDir, NULL);
}
diff --git a/devel/bmake/files/dir.h b/devel/bmake/files/dir.h
index 852e32da017..48c9e221ff3 100644
--- a/devel/bmake/files/dir.h
+++ b/devel/bmake/files/dir.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dir.h,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: dir.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
diff --git a/devel/bmake/files/for.c b/devel/bmake/files/for.c
index a47fb77bceb..085c49cf012 100644
--- a/devel/bmake/files/for.c
+++ b/devel/bmake/files/for.c
@@ -1,4 +1,4 @@
-/* $NetBSD: for.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: for.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1992, The Regents of the University of California.
@@ -30,14 +30,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: for.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $";
+static char rcsid[] = "$NetBSD: for.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: for.c,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $");
+__RCSID("$NetBSD: for.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -164,7 +164,7 @@ For_Eval(char *line)
* a for.
*/
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
- !isspace((unsigned char) ptr[3]))
+ !isspace((unsigned char) ptr[3]))
return FALSE;
ptr += 3;
@@ -228,7 +228,7 @@ For_Eval(char *line)
#define ADDWORD() \
Buf_AddBytes(buf, ptr - wrd, (Byte *)wrd), \
Buf_AddByte(buf, (Byte)'\0'), \
- Lst_AtFront(accumFor.lst, (ClientData)Buf_GetAll(buf, &varlen)), \
+ Lst_AtFront(accumFor.lst, Buf_GetAll(buf, &varlen)), \
Buf_Destroy(buf, FALSE)
for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)
@@ -245,9 +245,9 @@ For_Eval(char *line)
if (DEBUG(FOR)) {
int i;
for (i = 0; i < accumFor.nvars; i++) {
- (void)fprintf(stderr, "For: variable %s\n", accumFor.vars[i]);
+ (void)fprintf(debug_file, "For: variable %s\n", accumFor.vars[i]);
}
- (void)fprintf(stderr, "For: list %s\n", sub);
+ (void)fprintf(debug_file, "For: list %s\n", sub);
}
if (ptr - wrd > 0)
ADDWORD();
@@ -259,25 +259,25 @@ For_Eval(char *line)
forLevel++;
return 1;
}
- else if (*ptr == '.') {
+
+ if (*ptr == '.') {
for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
continue;
if (strncmp(ptr, "endfor", 6) == 0 &&
- (isspace((unsigned char) ptr[6]) || !ptr[6])) {
+ (isspace((unsigned char) ptr[6]) || !ptr[6])) {
if (DEBUG(FOR))
- (void)fprintf(stderr, "For: end for %d\n", forLevel);
+ (void)fprintf(debug_file, "For: end for %d\n", forLevel);
if (--forLevel < 0) {
Parse_Error(level, "for-less endfor");
return 0;
}
- }
- else if (strncmp(ptr, "for", 3) == 0 &&
+ } else if (strncmp(ptr, "for", 3) == 0 &&
isspace((unsigned char) ptr[3])) {
forLevel++;
if (DEBUG(FOR))
- (void)fprintf(stderr, "For: new loop %d\n", forLevel);
+ (void)fprintf(debug_file, "For: new loop %d\n", forLevel);
}
}
@@ -286,9 +286,8 @@ For_Eval(char *line)
Buf_AddByte(accumFor.buf, (Byte)'\n');
return 1;
}
- else {
- return 0;
- }
+
+ return 0;
}
@@ -351,7 +350,7 @@ For_Run(int lineno)
for (i = 0; i < arg.nvars; i++) {
Var_Set(arg.vars[i], values[i], VAR_GLOBAL, 0);
if (DEBUG(FOR))
- (void)fprintf(stderr, "--- %s = %s\n", arg.vars[i],
+ (void)fprintf(debug_file, "--- %s = %s\n", arg.vars[i],
values[i]);
}
@@ -372,7 +371,7 @@ For_Run(int lineno)
if (old_guy != orig_guy)
free(old_guy);
}
- Parse_FromString(guy, lineno);
+ Parse_SetInput(NULL, lineno, -1, guy);
for (i = 0; i < arg.nvars; i++)
Var_Delete(arg.vars[i], VAR_GLOBAL);
diff --git a/devel/bmake/files/job.c b/devel/bmake/files/job.c
index de48ea09fb5..abf015cdb22 100644
--- a/devel/bmake/files/job.c
+++ b/devel/bmake/files/job.c
@@ -1,4 +1,4 @@
-/* $NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: job.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: job.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: job.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -94,8 +94,6 @@ __RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
* frequently to keep the whole make going at
* a decent clip, since job table entries aren't
* removed until their process is caught this way.
- * Its single argument is TRUE if the function
- * should block waiting for a child to terminate.
*
* Job_CatchOutput Print any output our children have produced.
* Should also be called fairly frequently to
@@ -112,9 +110,6 @@ __RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
*
* Job_End Cleanup any memory used.
*
- * Job_Empty Return TRUE if the job table is completely
- * empty.
- *
* Job_ParseShell Given the line following a .SHELL target, parse
* the line as a shell specification. Returns
* FAILURE if the spec was incorrect.
@@ -149,7 +144,6 @@ __RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
#include <errno.h>
#include <fcntl.h>
-#ifndef RMT_WILL_WATCH
#if !defined(USE_SELECT) && defined(HAVE_POLL_H)
#include <poll.h>
#else
@@ -160,7 +154,6 @@ __RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
# include <sys/select.h>
#endif
#endif
-#endif
#include <signal.h>
#include <stdio.h>
#include <string.h>
@@ -175,12 +168,7 @@ __RCSID("$NetBSD: job.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
#include "job.h"
#include "pathnames.h"
#include "trace.h"
-#ifdef REMOTE
-#include "rmt.h"
-# define STATIC
-#else
# define STATIC static
-#endif
/*
* error handling variables
@@ -190,6 +178,13 @@ static int aborting = 0; /* why is the make aborting? */
#define ABORT_ERROR 1 /* Because of an error */
#define ABORT_INTERRUPT 2 /* Because it was interrupted */
#define ABORT_WAIT 3 /* Waiting for jobs to finish */
+#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */
+
+/*
+ * this tracks the number of tokens currently "out" to build jobs.
+ */
+int jobTokensRunning = 0;
+int not_parallel = 0; /* set if .NOT_PARALLEL */
/*
* XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
@@ -215,25 +210,54 @@ static int numCommands; /* The number of commands actually printed
#define JOB_RUNNING 0 /* Job is running */
#define JOB_ERROR 1 /* Error in starting the job */
#define JOB_FINISHED 2 /* The job is already finished */
-#define JOB_STOPPED 3 /* The job is stopped */
-
-
/*
* Descriptions for various shells.
+ *
+ * The build environment may set DEFSHELL_INDEX to one of
+ * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to
+ * select one of the prefedined shells as the default shell.
+ *
+ * Alternatively, the build environment may set DEFSHELL_CUSTOM to the
+ * name or the full path of a sh-compatible shell, which will be used as
+ * the default shell.
+ *
+ * ".SHELL" lines in Makefiles can choose the default shell from the
+ # set defined here, or add additional shells.
*/
+
+#ifdef DEFSHELL_CUSTOM
+#define DEFSHELL_INDEX_CUSTOM 0
+#define DEFSHELL_INDEX_SH 1
+#define DEFSHELL_INDEX_KSH 2
+#define DEFSHELL_INDEX_CSH 3
+#else /* !DEFSHELL_CUSTOM */
+#define DEFSHELL_INDEX_SH 0
+#define DEFSHELL_INDEX_KSH 1
+#define DEFSHELL_INDEX_CSH 2
+#endif /* !DEFSHELL_CUSTOM */
+
+#ifndef DEFSHELL_INDEX
+#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */
+#endif /* !DEFSHELL_INDEX */
+
static Shell shells[] = {
+#ifdef DEFSHELL_CUSTOM
/*
- * CSH description. The csh can do echo control by playing
- * with the setting of the 'echo' shell variable. Sadly,
- * however, it is unable to do error control nicely.
+ * An sh-compatible shell with a non-standard name.
+ *
+ * Keep this in sync with the "sh" description below, but avoid
+ * non-portable features that might not be supplied by all
+ * sh-compatible shells.
*/
{
- "csh",
- TRUE, "unset verbose", "set verbose", "unset verbose", 10,
- FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", '#',
- "v", "e",
+ DEFSHELL_CUSTOM,
+ FALSE, "", "", "", 0,
+ FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
+ "",
+ "",
},
+#endif /* DEFSHELL_CUSTOM */
/*
* SH description. Echo control is also possible and, under
* sun UNIX anyway, one can even control error checking.
@@ -241,8 +265,8 @@ static Shell shells[] = {
{
"sh",
FALSE, "", "", "", 0,
- FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", '#',
-#ifdef __NetBSD__
+ FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
+#if defined(MAKE_NATIVE) && defined(__NetBSD__)
"q",
#else
"",
@@ -255,21 +279,32 @@ static Shell shells[] = {
{
"ksh",
TRUE, "set +v", "set -v", "set +v", 6,
- FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", '#',
+ FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
"v",
"",
},
/*
+ * CSH description. The csh can do echo control by playing
+ * with the setting of the 'echo' shell variable. Sadly,
+ * however, it is unable to do error control nicely.
+ */
+{
+ "csh",
+ TRUE, "unset verbose", "set verbose", "unset verbose", 10,
+ FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#',
+ "v", "e",
+},
+ /*
* UNKNOWN.
*/
{
NULL,
FALSE, NULL, NULL, NULL, 0,
- FALSE, NULL, NULL, NULL, 0,
+ FALSE, NULL, NULL, NULL, NULL, 0,
NULL, NULL,
}
};
-static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to
+static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to
* which we pass all
* commands in the Makefile.
* It is set by the
@@ -280,108 +315,55 @@ const char *shellPath = NULL, /* full pathname of
static const char *shellArgv = NULL; /* Custom shell args */
-static int maxJobs; /* The most children we can run at once */
-static int maxLocal; /* The most local ones we can have */
-STATIC int nJobs; /* The number of children currently running */
-STATIC int nLocal; /* The number of local children */
-STATIC Lst jobs; /* The structures that describe them */
-static Boolean wantToken; /* we want a token */
+STATIC Job *job_table; /* The structures that describe them */
+STATIC Job *job_table_end; /* job_table + maxJobs */
+static int wantToken; /* we want a token */
+static int lurking_children = 0;
+static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */
/*
* Set of descriptors of pipes connected to
* the output channels of children
*/
-#ifndef RMT_WILL_WATCH
static struct pollfd *fds = NULL;
static Job **jobfds = NULL;
static int nfds = 0;
-static int maxfds = 0;
static void watchfd(Job *);
static void clearfd(Job *);
static int readyfd(Job *);
-#define JBSTART 256
-#define JBFACTOR 2
-#endif
STATIC GNode *lastNode; /* The node for which output was most recently
* produced. */
STATIC const char *targFmt; /* Format string to use to head output from a
* job when it's not the most-recent job heard
* from */
+static char *targPrefix = NULL; /* What we print at the start of targFmt */
static Job tokenWaitJob; /* token wait pseudo-job */
-int job_pipe[2] = { -1, -1 }; /* job server pipes. */
static Job childExitJob; /* child exit pseudo-job */
-int exit_pipe[2] = { -1, -1 }; /* child exit signal pipe. */
-
-#ifdef REMOTE
-# define TARG_FMT "--- %s at %s ---\n" /* Default format */
-# define MESSAGE(fp, gn) \
- (void)fprintf(fp, targFmt, gn->name, gn->rem.hname)
-#else
-# define TARG_FMT "--- %s ---\n" /* Default format */
-# define MESSAGE(fp, gn) \
- (void)fprintf(fp, targFmt, gn->name)
-#endif
-
-/*
- * When JobStart attempts to run a job remotely but can't, and isn't allowed
- * to run the job locally, or when Job_CatchChildren detects a job that has
- * been migrated home, the job is placed on the stoppedJobs queue to be run
- * when the next job finishes.
- */
-STATIC Lst stoppedJobs; /* Lst of Job structures describing
- * jobs that were stopped due to concurrency
- * limits or migration home */
+#define CHILD_EXIT "."
+#define DO_JOB_RESUME "R"
+#define TARG_FMT "%s %s ---\n" /* Default format */
+#define MESSAGE(fp, gn) \
+ (void)fprintf(fp, targFmt, targPrefix, gn->name)
-sigset_t caught_signals; /* Set of signals we handle */
-
-#if defined(USE_PGRP)
-# if defined(HAVE_KILLPG)
-# define KILL(pid, sig) killpg((pid), (sig))
-# else
-# define KILL(pid, sig) kill(-(pid), (sig))
-# endif
+static sigset_t caught_signals; /* Set of signals we handle */
+#if defined(SYSV)
+#define KILLPG(pid, sig) kill(-(pid), (sig))
#else
-# define KILL(pid, sig) kill((pid), (sig))
-#endif
-
-/*
- * Grmpf... There is no way to set bits of the wait structure
- * anymore with the stupid W*() macros. I liked the union wait
- * stuff much more. So, we devise our own macros... This is
- * really ugly, use dramamine sparingly. You have been warned.
- */
-#ifndef W_STOPCODE
-#define W_STOPCODE(sig) (((sig) << 8) | 0177)
+#define KILLPG(pid, sig) killpg((pid), (sig))
#endif
-#ifndef W_EXITCODE
-#define W_EXITCODE(ret, sig) ((ret << 8) | (sig))
-#endif
-static int JobCondPassSig(ClientData, ClientData);
-static void JobPassSig(int);
static void JobChildSig(int);
-#ifdef USE_PGRP
static void JobContinueSig(int);
-#endif
-static int JobCmpPid(ClientData, ClientData);
+static Job *JobFindPid(int, int);
static int JobPrintCommand(ClientData, ClientData);
static int JobSaveCommand(ClientData, ClientData);
static void JobClose(Job *);
-#ifdef REMOTE
-static int JobCmpRmtID(ClientData, ClientData);
-# ifdef RMT_WILL_WATCH
-static void JobLocalInput(int, Job *);
-# endif
-#else
-static void JobFinish(Job *, WAIT_T);
static void JobExec(Job *, char **);
-#endif
static void JobMakeArgv(Job *, char **);
-static int JobRestart(Job *);
-static int JobStart(GNode *, int, Job *);
+static int JobStart(GNode *, int);
static char *JobOutput(Job *, char *, char *, int);
static void JobDoOutput(Job *, Boolean);
static Shell *JobMatchShell(const char *);
@@ -392,7 +374,19 @@ static void JobSigLock(sigset_t *);
static void JobSigUnlock(sigset_t *);
static void JobSigReset(void);
+const char *malloc_options="A";
+
+static void
+job_table_dump(const char *where)
+{
+ Job *job;
+ fprintf(debug_file, "job table @ %s\n", where);
+ for (job = job_table; job < job_table_end; job++) {
+ fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n",
+ (int)(job - job_table), job->job_state, job->flags, job->pid);
+ }
+}
/*
* JobSigLock/JobSigUnlock
@@ -404,7 +398,7 @@ static void JobSigLock(sigset_t *omaskp)
{
if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) {
Punt("JobSigLock: sigprocmask: %s", strerror(errno));
- sigemptyset(omaskp);
+ sigemptyset(omaskp);
}
}
@@ -413,49 +407,69 @@ static void JobSigUnlock(sigset_t *omaskp)
(void)sigprocmask(SIG_SETMASK, omaskp, NULL);
}
+static void
+JobCreatePipe(Job *job, int minfd)
+{
+ int i, fd;
+
+ if (pipe(job->jobPipe) == -1)
+ Punt("Cannot create pipe: %s", strerror(errno));
+
+ /* Set close-on-exec flag for both */
+ (void)fcntl(job->jobPipe[0], F_SETFD, 1);
+ (void)fcntl(job->jobPipe[1], F_SETFD, 1);
+
+ /*
+ * We mark the input side of the pipe non-blocking; we poll(2) the
+ * pipe when we're waiting for a job token, but we might lose the
+ * race for the token when a new one becomes available, so the read
+ * from the pipe should not block.
+ */
+ fcntl(job->jobPipe[0], F_SETFL,
+ fcntl(job->jobPipe[0], F_GETFL, 0) | O_NONBLOCK);
+
+ for (i = 0; i < 2; i++) {
+ /* Avoid using low numbered fds */
+ fd = fcntl(job->jobPipe[i], F_DUPFD, minfd);
+ if (fd != -1) {
+ close(job->jobPipe[i]);
+ job->jobPipe[i] = fd;
+ }
+ }
+}
+
/*-
*-----------------------------------------------------------------------
* JobCondPassSig --
- * Pass a signal to a job if the job is remote or if USE_PGRP
- * is defined.
+ * Pass a signal to a job
*
* Input:
- * jobp Job to biff
* signop Signal to send it
*
- * Results:
- * === 0
- *
* Side Effects:
* None, except the job may bite it.
*
*-----------------------------------------------------------------------
*/
-static int
-JobCondPassSig(ClientData jobp, ClientData signop)
+static void
+JobCondPassSig(int signo)
{
- Job *job = (Job *)jobp;
- int signo = *(int *)signop;
-#ifdef RMT_WANTS_SIGNALS
- if (job->flags & JOB_REMOTE) {
- (void)Rmt_Signal(job, signo);
- } else {
- KILL(job->pid, signo);
- }
-#else
- /*
- * Assume that sending the signal to job->pid will signal any remote
- * job as well.
- */
+ Job *job;
+
if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "JobCondPassSig passing signal %d to child %d.\n",
- signo, job->pid);
- (void)fflush(stdout);
+ (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo);
+ }
+
+ for (job = job_table; job < job_table_end; job++) {
+ if (job->job_state != JOB_ST_RUNNING)
+ continue;
+ if (DEBUG(JOB)) {
+ (void)fprintf(debug_file,
+ "JobCondPassSig passing signal %d to child %d.\n",
+ signo, job->pid);
+ }
+ KILLPG(job->pid, signo);
}
- KILL(job->pid, signo);
-#endif
- return 0;
}
/*-
@@ -478,11 +492,10 @@ JobCondPassSig(ClientData jobp, ClientData signop)
static void
JobChildSig(int signo __unused)
{
- write(exit_pipe[1], ".", 1);
+ write(childExitJob.outPipe, CHILD_EXIT, 1);
}
-#ifdef USE_PGRP
/*-
*-----------------------------------------------------------------------
* JobContinueSig --
@@ -502,15 +515,17 @@ JobChildSig(int signo __unused)
static void
JobContinueSig(int signo __unused)
{
- JobRestartJobs();
+ /*
+ * Defer sending to SIGCONT to our stopped children until we return
+ * from the signal handler.
+ */
+ write(childExitJob.outPipe, DO_JOB_RESUME, 1);
}
-#endif
/*-
*-----------------------------------------------------------------------
* JobPassSig --
- * Pass a signal on to all remote jobs and to all local jobs if
- * USE_PGRP is defined, then die ourselves.
+ * Pass a signal on to all jobs, then resend to ourselves.
*
* Input:
* signo The signal number we've received
@@ -524,39 +539,31 @@ JobContinueSig(int signo __unused)
*-----------------------------------------------------------------------
*/
static void
-JobPassSig(int signo)
+JobPassSig_int(int signo)
+{
+ /* Run .INTERRUPT target then exit */
+ JobInterrupt(TRUE, signo);
+}
+
+static void
+JobPassSig_term(int signo)
+{
+ /* Dont run .INTERRUPT target then exit */
+ JobInterrupt(FALSE, signo);
+}
+
+static void
+JobPassSig_suspend(int signo)
{
sigset_t nmask, omask;
struct sigaction act;
- int sigcont;
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "JobPassSig(%d) called.\n", signo);
- (void)fflush(stdout);
- }
- Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
-
- /*
- * Deal with proper cleanup based on the signal received. We only run
- * the .INTERRUPT target if the signal was in fact an interrupt. The other
- * three termination signals are more of a "get out *now*" command.
- */
- if (signo == SIGINT) {
- JobInterrupt(TRUE, signo);
- } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {
- JobInterrupt(FALSE, signo);
- }
+ /* Suppress job started/continued messages */
+ make_suspended = 1;
- /*
- * Leave gracefully if SIGQUIT, rather than core dumping.
- */
- if (signo == SIGQUIT) {
- Finish(0);
- }
+ /* Pass the signal onto every job */
+ JobCondPassSig(signo);
- if (signo == SIGTSTP) {
- Job_CatchChildren(FALSE);
- }
/*
* Send ourselves the signal now we've given the message to everyone else.
* Note we block everything else possible while we're getting the signal.
@@ -573,71 +580,67 @@ JobPassSig(int signo)
(void)sigaction(signo, &act, NULL);
if (DEBUG(JOB)) {
- (void)fprintf(stdout,
+ (void)fprintf(debug_file,
"JobPassSig passing signal %d to self.\n", signo);
- (void)fflush(stdout);
}
(void)kill(getpid(), signo);
- if (signo != SIGTSTP) {
- sigcont = SIGCONT;
- Lst_ForEach(jobs, JobCondPassSig, (ClientData) &sigcont);
- }
+
+ /*
+ * We've been continued.
+ *
+ * A whole host of signals continue to happen!
+ * SIGCHLD for any processes that actually suspended themselves.
+ * SIGCHLD for any processes that exited while we were alseep.
+ * The SIGCONT that actually caused us to wakeup.
+ *
+ * Since we defer passing the SIGCONT on to our children until
+ * the main processing loop, we can be sure that all the SIGCHLD
+ * events will have happened by then - and that the waitpid() will
+ * collect the child 'suspended' events.
+ * For correct sequencing we just need to ensure we process the
+ * waitpid() before passign on the SIGCONT.
+ *
+ * In any case nothing else is needed here.
+ */
/* Restore handler and signal mask */
- act.sa_handler = JobPassSig;
+ act.sa_handler = JobPassSig_suspend;
(void)sigaction(signo, &act, NULL);
(void)sigprocmask(SIG_SETMASK, &omask, NULL);
}
/*-
*-----------------------------------------------------------------------
- * JobCmpPid --
+ * JobFindPid --
* Compare the pid of the job with the given pid and return 0 if they
- * are equal. This function is called from Job_CatchChildren via
- * Lst_Find to find the job descriptor of the finished job.
+ * are equal. This function is called from Job_CatchChildren
+ * to find the job descriptor of the finished job.
*
* Input:
* job job to examine
* pid process id desired
*
* Results:
- * 0 if the pid's match
+ * Job with matching pid
*
* Side Effects:
* None
*-----------------------------------------------------------------------
*/
-static int
-JobCmpPid(ClientData job, ClientData pid)
+static Job *
+JobFindPid(int pid, int status)
{
- return *(int *)pid - ((Job *)job)->pid;
-}
+ Job *job;
-#ifdef REMOTE
-/*-
- *-----------------------------------------------------------------------
- * JobCmpRmtID --
- * Compare the rmtID of the job with the given rmtID and return 0 if they
- * are equal.
- *
- * Input:
- * job job to examine
- * rmtID remote id desired
- *
- * Results:
- * 0 if the rmtID's match
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-static int
-JobCmpRmtID(ClientData job, ClientData rmtID)
-{
- return(*(int *)rmtID - ((Job *)job)->rmtID);
+ for (job = job_table; job < job_table_end; job++) {
+ if ((job->job_state == status) && job->pid == pid)
+ return job;
+ }
+ if (DEBUG(JOB))
+ job_table_dump("no pid");
+ return NULL;
}
-#endif
/*-
*-----------------------------------------------------------------------
@@ -696,15 +699,14 @@ JobPrintCommand(ClientData cmdp, ClientData jobp)
job->node->type |= OP_SAVE_CMDS;
if ((job->flags & JOB_IGNDOTS) == 0) {
job->tailCmds = Lst_Succ(Lst_Member(job->node->commands,
- (ClientData)cmd));
+ cmd));
return 1;
}
return 0;
}
#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \
- (void)fprintf(stdout, fmt, arg); \
- (void)fflush(stdout); \
+ (void)fprintf(debug_file, fmt, arg); \
} \
(void)fprintf(job->cmdFILE, fmt, arg); \
(void)fflush(job->cmdFILE);
@@ -721,7 +723,7 @@ JobPrintCommand(ClientData cmdp, ClientData jobp)
while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) {
switch (*cmd) {
case '@':
- shutUp = TRUE;
+ shutUp = DEBUG(LOUD) ? FALSE : TRUE;
break;
case '-':
errOff = TRUE;
@@ -732,7 +734,7 @@ JobPrintCommand(ClientData cmdp, ClientData jobp)
* We're not actually executing anything...
* but this one needs to be - use compat mode just for it.
*/
- CompatRunCommand(cmdp, (ClientData)job->node);
+ CompatRunCommand(cmdp, job->node);
return 0;
}
break;
@@ -907,7 +909,7 @@ JobPrintCommand(ClientData cmdp, ClientData jobp)
static int
JobSaveCommand(ClientData cmd, ClientData gn)
{
- cmd = (ClientData)Var_Subst(NULL, (char *)cmd, (GNode *)gn, FALSE);
+ cmd = Var_Subst(NULL, (char *)cmd, (GNode *)gn, FALSE);
(void)Lst_AtEnd(postCommands->commands, cmd);
return(0);
}
@@ -929,21 +931,13 @@ JobSaveCommand(ClientData cmd, ClientData gn)
static void
JobClose(Job *job)
{
- if (usePipes && (job->flags & JOB_FIRST)) {
-#ifdef RMT_WILL_WATCH
- Rmt_Ignore(job->inPipe);
-#else
- clearfd(job);
-#endif
- if (job->outPipe != job->inPipe) {
- (void)close(job->outPipe);
- }
- JobDoOutput(job, TRUE);
- (void)close(job->inPipe);
- } else {
- (void)close(job->outFd);
- JobDoOutput(job, TRUE);
- }
+ clearfd(job);
+ (void)close(job->outPipe);
+ job->outPipe = -1;
+
+ JobDoOutput(job, TRUE);
+ (void)close(job->inPipe);
+ job->inPipe = -1;
}
/*-
@@ -976,10 +970,15 @@ JobClose(Job *job)
static void
JobFinish (Job *job, WAIT_T status)
{
- Boolean done;
+ Boolean done, return_job_token;
+
+ if (DEBUG(JOB)) {
+ fprintf(debug_file, "Jobfinish: %d [%s], status %d\n",
+ job->pid, job->node->name, status);
+ }
if ((WIFEXITED(status) &&
- (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) ||
+ (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) ||
WIFSIGNALED(status))
{
/*
@@ -990,19 +989,12 @@ JobFinish (Job *job, WAIT_T status)
* cases, finish out the job's output before printing the exit
* status...
*/
-#ifdef REMOTE
- KILL(job->pid, SIGCONT);
-#endif
JobClose(job);
if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
(void)fclose(job->cmdFILE);
job->cmdFILE = NULL;
}
done = TRUE;
-#ifdef REMOTE
- if (job->flags & JOB_REMOTE)
- Rmt_Done(job->rmtID, job->node);
-#endif
} else if (WIFEXITED(status)) {
/*
* Deal with ignored errors in -B mode. We need to print a message
@@ -1019,10 +1011,6 @@ JobFinish (Job *job, WAIT_T status)
* stuff?
*/
JobClose(job);
-#ifdef REMOTE
- if (job->flags & JOB_REMOTE)
- Rmt_Done(job->rmtID, job->node);
-#endif /* REMOTE */
} else {
/*
* No need to close things down or anything.
@@ -1030,187 +1018,54 @@ JobFinish (Job *job, WAIT_T status)
done = FALSE;
}
- if (done ||
- WIFSTOPPED(status) ||
- (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)))
- {
- FILE *out;
-
- if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) {
- /*
- * If output is going to a file and this job is ignoring
- * errors, arrange to have the exit status sent to the
- * output file as well.
- */
- out = fdopen(job->outFd, "w");
- if (out == NULL)
- Punt("Cannot fdopen");
- } else {
- out = stdout;
- }
-
+ if (done) {
if (WIFEXITED(status)) {
if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Process %d [%s] exited.\n",
+ (void)fprintf(debug_file, "Process %d [%s] exited.\n",
job->pid, job->node->name);
- (void)fflush(stdout);
}
if (WEXITSTATUS(status) != 0) {
- if (usePipes && job->node != lastNode) {
- MESSAGE(out, job->node);
+ if (job->node != lastNode) {
+ MESSAGE(stdout, job->node);
lastNode = job->node;
}
- (void)fprintf(out, "*** [%s] Error code %d%s\n",
+ (void)printf("*** [%s] Error code %d%s\n",
job->node->name,
WEXITSTATUS(status),
(job->flags & JOB_IGNERR) ? "(ignored)" : "");
-
- if (job->flags & JOB_IGNERR) {
+ if (job->flags & JOB_IGNERR)
WAIT_STATUS(status) = 0;
- }
} else if (DEBUG(JOB)) {
- if (usePipes && job->node != lastNode) {
- MESSAGE(out, job->node);
+ if (job->node != lastNode) {
+ MESSAGE(stdout, job->node);
lastNode = job->node;
}
- (void)fprintf(out, "*** [%s] Completed successfully\n",
+ (void)printf("*** [%s] Completed successfully\n",
job->node->name);
}
- } else if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGCONT) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Process %d (%s) stopped.\n",
- job->pid, job->node->name);
- (void)fflush(stdout);
- }
- if (usePipes && job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- if (!(job->flags & JOB_REMIGRATE)) {
- switch (WSTOPSIG(status)) {
- case SIGTSTP:
- (void)fprintf(out, "*** [%s] Suspended\n",
- job->node->name);
- break;
- case SIGSTOP:
- (void)fprintf(out, "*** [%s] Stopped\n",
- job->node->name);
- break;
- default:
- (void)fprintf(out, "*** [%s] Stopped -- signal %d\n",
- job->node->name, WSTOPSIG(status));
- }
- }
- job->flags |= JOB_RESUME;
- (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
-#ifdef REMOTE
- if (job->flags & JOB_REMIGRATE)
- JobRestart(job);
-#endif
- (void)fflush(out);
- return;
- } else if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGCONT) {
- /*
- * If the beastie has continued, shift the Job from the stopped
- * list to the running one (or re-stop it if concurrency is
- * exceeded) and go and get another child.
- */
- if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {
- if (usePipes && job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out, "*** [%s] Continued\n", job->node->name);
- }
- if (!(job->flags & JOB_CONTINUING)) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "Warning: process %d [%s] was not continuing.\n",
- job->pid, job->node->name);
- (void)fflush(stdout);
- }
-#ifdef notdef
- /*
- * We don't really want to restart a job from scratch just
- * because it continued, especially not without killing the
- * continuing process! That's why this is ifdef'ed out.
- * FD - 9/17/90
- */
- JobRestart(job);
-#endif
- }
- job->flags &= ~JOB_CONTINUING;
- Lst_AtEnd(jobs, (ClientData)job);
- nJobs += 1;
- if (!(job->flags & JOB_REMOTE)) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "Process %d is continuing locally.\n",
- job->pid);
- (void)fflush(stdout);
- }
- nLocal += 1;
- }
- (void)fflush(out);
- return;
} else {
- if (usePipes && job->node != lastNode) {
- MESSAGE(out, job->node);
+ if (job->node != lastNode) {
+ MESSAGE(stdout, job->node);
lastNode = job->node;
}
- (void)fprintf(out, "*** [%s] Signal %d\n",
+ (void)printf("*** [%s] Signal %d\n",
job->node->name, WTERMSIG(status));
}
-
- (void)fflush(out);
+ (void)fflush(stdout);
}
- /*
- * Now handle the -B-mode stuff. If the beast still isn't finished,
- * try and restart the job on the next command. If JobStart says it's
- * ok, it's ok. If there's an error, this puppy is done.
- */
- if (compatMake && (WIFEXITED(status) &&
- !Lst_IsAtEnd(job->node->commands))) {
- switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) {
- case JOB_RUNNING:
- done = FALSE;
- break;
- case JOB_ERROR:
- done = TRUE;
- WSET_EXITCODE(status, 1, 0);
- break;
- case JOB_FINISHED:
- /*
- * If we got back a JOB_FINISHED code, JobStart has already
- * called Make_Update and freed the job descriptor. We set
- * done to false here to avoid fake cycles and double frees.
- * JobStart needs to do the update so we can proceed up the
- * graph when given the -n flag..
- */
- done = FALSE;
- break;
- }
- } else {
- done = TRUE;
- }
+ return_job_token = FALSE;
- if (done) {
- Trace_Log(JOBEND, job);
- if (!compatMake && !(job->flags & JOB_SPECIAL)) {
- if ((WAIT_STATUS(status) != 0) ||
- (aborting == ABORT_ERROR) ||
- (aborting == ABORT_INTERRUPT))
- Job_TokenReturn();
- }
-
+ Trace_Log(JOBEND, job);
+ if (!(job->flags & JOB_SPECIAL)) {
+ if ((WAIT_STATUS(status) != 0) ||
+ (aborting == ABORT_ERROR) ||
+ (aborting == ABORT_INTERRUPT))
+ return_job_token = TRUE;
}
- if (done &&
- (aborting != ABORT_ERROR) &&
- (aborting != ABORT_INTERRUPT) &&
- (WAIT_STATUS(status) == 0))
- {
+ if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) &&
+ (WAIT_STATUS(status) == 0)) {
/*
* As long as we aren't aborting and the job didn't return a non-zero
* status that we shouldn't ignore, we call Make_Update to update
@@ -1220,18 +1075,17 @@ JobFinish (Job *job, WAIT_T status)
if (job->tailCmds != NILLNODE) {
Lst_ForEachFrom(job->node->commands, job->tailCmds,
JobSaveCommand,
- (ClientData)job->node);
+ job->node);
}
job->node->made = MADE;
if (!(job->flags & JOB_SPECIAL))
- Job_TokenReturn();
+ return_job_token = TRUE;
Make_Update(job->node);
- free(job);
+ job->job_state = JOB_ST_FREE;
} else if (WAIT_STATUS(status)) {
errors += 1;
- free(job);
+ job->job_state = JOB_ST_FREE;
}
- JobRestartJobs();
/*
* Set aborting if any error.
@@ -1245,7 +1099,10 @@ JobFinish (Job *job, WAIT_T status)
aborting = ABORT_ERROR;
}
- if ((aborting == ABORT_ERROR) && Job_Empty()) {
+ if (return_job_token)
+ Job_TokenReturn();
+
+ if (aborting == ABORT_ERROR && jobTokensRunning == 0) {
/*
* If we are aborting and the job table is now empty, we finish.
*/
@@ -1354,7 +1211,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
* commands
*/
if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands) &&
- (gn->type & OP_SPECIAL) == 0) {
+ (gn->type & OP_SPECIAL) == 0) {
char *p1;
/*
* Make only looks for a .DEFAULT if the node was never the
@@ -1379,6 +1236,12 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
*/
static const char msg[] = ": don't know how to make";
+ if (gn->flags & FROM_DEPEND) {
+ fprintf(stdout, "%s: ignoring stale .depend for %s\n",
+ progname, gn->name);
+ return TRUE;
+ }
+
if (gn->type & OP_OPTIONAL) {
(void)fprintf(stdout, "%s%s %s(ignored)\n", progname,
msg, gn->name);
@@ -1396,37 +1259,11 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
}
return TRUE;
}
-#ifdef RMT_WILL_WATCH
-/*-
- *-----------------------------------------------------------------------
- * JobLocalInput --
- * Handle a pipe becoming readable. Callback function for Rmt_Watch
- *
- * Input:
- * stream Stream that's ready (ignored)
- * job Job to which the stream belongs
- *
- * Results:
- * None
- *
- * Side Effects:
- * JobDoOutput is called.
- *
- *-----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static void
-JobLocalInput(int stream, Job *job)
-{
- JobDoOutput(job, FALSE);
-}
-#endif /* RMT_WILL_WATCH */
/*-
*-----------------------------------------------------------------------
* JobExec --
- * Execute the shell for the given job. Called from JobStart and
- * JobRestart.
+ * Execute the shell for the given job. Called from JobStart
*
* Input:
* job Job to execute
@@ -1451,14 +1288,12 @@ JobExec(Job *job, char **argv)
if (DEBUG(JOB)) {
int i;
- (void)fprintf(stdout, "Running %s %sly\n", job->node->name,
- job->flags&JOB_REMOTE?"remote":"local");
- (void)fprintf(stdout, "\tCommand: ");
+ (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local");
+ (void)fprintf(debug_file, "\tCommand: ");
for (i = 0; argv[i] != NULL; i++) {
- (void)fprintf(stdout, "%s ", argv[i]);
+ (void)fprintf(debug_file, "%s ", argv[i]);
}
- (void)fprintf(stdout, "\n");
- (void)fflush(stdout);
+ (void)fprintf(debug_file, "\n");
}
/*
@@ -1467,24 +1302,23 @@ JobExec(Job *job, char **argv)
* banner with their name in it never appears). This is an attempt to
* provide that feedback, even if nothing follows it.
*/
- if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&
- !(job->flags & JOB_SILENT)) {
+ if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) {
MESSAGE(stdout, job->node);
lastNode = job->node;
}
-#ifdef RMT_NO_EXEC
- if (job->flags & JOB_REMOTE) {
- goto jobExecFinish;
- }
-#endif /* RMT_NO_EXEC */
-
/* No interruptions until this job is on the `jobs' list */
JobSigLock(&mask);
- if ((cpid = vfork()) == -1) {
+ /* Pre-emptively mark job running, pid still zero though */
+ job->job_state = JOB_ST_RUNNING;
+
+ cpid = vfork();
+ if (cpid == -1)
Punt("Cannot vfork: %s", strerror(errno));
- } else if (cpid == 0) {
+
+ if (cpid == 0) {
+ /* Child */
/*
* Reset all signal handlers; this is necessary because we also
@@ -1512,29 +1346,17 @@ JobExec(Job *job, char **argv)
/*
* Pass job token pipe to submakes.
*/
- fcntl(job_pipe[0], F_SETFD, 0);
- fcntl(job_pipe[1], F_SETFD, 0);
+ fcntl(tokenWaitJob.inPipe, F_SETFD, 0);
+ fcntl(tokenWaitJob.outPipe, F_SETFD, 0);
}
- if (usePipes) {
- /*
- * Set up the child's output to be routed through the pipe
- * we've created for it.
- */
- if (dup2(job->outPipe, 1) == -1) {
- execError("dup2", "job->outPipe");
- _exit(1);
- }
- } else {
- /*
- * We're capturing output in a file, so we duplicate the
- * descriptor to the temporary file into the standard
- * output.
- */
- if (dup2(job->outFd, 1) == -1) {
- execError("dup2", "job->outFd");
- _exit(1);
- }
+ /*
+ * Set up the child's output to be routed through the pipe
+ * we've created for it.
+ */
+ if (dup2(job->outPipe, 1) == -1) {
+ execError("dup2", "job->outPipe");
+ _exit(1);
}
/*
* The output channels are marked close on exec. This bit was
@@ -1548,79 +1370,51 @@ JobExec(Job *job, char **argv)
_exit(1);
}
-#ifdef USE_PGRP
/*
* We want to switch the child into a different process family so
* we can kill it and all its descendants in one fell swoop,
* by killing its process family, but not commit suicide.
*/
-# if defined(SYSV)
+#if defined(SYSV)
+ /* XXX: dsl - I'm sure this should be setpgrp()... */
(void)setsid();
-# else
+#else
(void)setpgid(0, getpid());
-# endif
-#endif /* USE_PGRP */
+#endif
-#ifdef REMOTE
- if (job->flags & JOB_REMOTE) {
- Rmt_Exec(shellPath, argv, FALSE);
- } else
-#endif /* REMOTE */
- {
- (void)execv(shellPath, argv);
- execError("exec", shellPath);
- }
+ Var_ExportVars();
+
+ (void)execv(shellPath, argv);
+ execError("exec", shellPath);
_exit(1);
- } else {
- job->pid = cpid;
+ }
- Trace_Log(JOBSTART, job);
+ /* Parent, continuing after the child exec */
+ job->pid = cpid;
- if (usePipes && (job->flags & JOB_FIRST)) {
- /*
- * The first time a job is run for a node, we set the current
- * position in the buffer to the beginning and mark another
- * stream to watch in the outputs mask
- */
- job->curPos = 0;
+ Trace_Log(JOBSTART, job);
-#ifdef RMT_WILL_WATCH
- Rmt_Watch(job->inPipe, JobLocalInput, job);
-#else
- watchfd(job);
-#endif /* RMT_WILL_WATCH */
- }
+ /*
+ * Set the current position in the buffer to the beginning
+ * and mark another stream to watch in the outputs mask
+ */
+ job->curPos = 0;
- if (job->flags & JOB_REMOTE) {
-#ifndef REMOTE
- job->rmtID = 0;
-#else
- job->rmtID = Rmt_LastID(job->pid);
-#endif /* REMOTE */
- } else {
- nLocal += 1;
- /*
- * XXX: Used to not happen if REMOTE. Why?
- */
- if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
- (void)fclose(job->cmdFILE);
- job->cmdFILE = NULL;
- }
- }
+ watchfd(job);
+
+ if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
+ (void)fclose(job->cmdFILE);
+ job->cmdFILE = NULL;
}
-#ifdef RMT_NO_EXEC
-jobExecFinish:
-#endif
/*
* Now the job is actually running, add it to the table.
*/
if (DEBUG(JOB)) {
- printf("JobExec(%s): pid %d added to jobs table\n",
+ fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n",
job->node->name, job->pid);
+ job_table_dump("job started");
}
- nJobs += 1;
- (void)Lst_AtEnd(jobs, (ClientData)job);
JobSigUnlock(&mask);
}
@@ -1679,232 +1473,6 @@ JobMakeArgv(Job *job, char **argv)
/*-
*-----------------------------------------------------------------------
- * JobRestart --
- * Restart a job that stopped for some reason.
- *
- * Input:
- * job Job to restart
- *
- * Results:
- * 1 if max number of running jobs has been reached, 0 otherwise.
- *
- *-----------------------------------------------------------------------
- */
-static int
-JobRestart(Job *job)
-{
-#ifdef REMOTE
- int host;
-#endif
-
- if (job->flags & JOB_REMIGRATE) {
- if (
-#ifdef REMOTE
- verboseRemigrates ||
-#endif
- DEBUG(JOB)) {
- (void)fprintf(stdout, "*** remigrating %x(%s)\n",
- job->pid, job->node->name);
- (void)fflush(stdout);
- }
-
-#ifdef REMOTE
- if (!Rmt_ReExport(job->pid, job->node, &host)) {
- if (verboseRemigrates || DEBUG(JOB)) {
- (void)fprintf(stdout, "*** couldn't migrate...\n");
- (void)fflush(stdout);
- }
-#endif
- if (nLocal != maxLocal) {
- /*
- * Job cannot be remigrated, but there's room on the local
- * machine, so resume the job and note that another
- * local job has started.
- */
- if (
-#ifdef REMOTE
- verboseRemigrates ||
-#endif
- DEBUG(JOB)) {
- (void)fprintf(stdout, "*** resuming on local machine\n");
- (void)fflush(stdout);
- }
- KILL(job->pid, SIGCONT);
- nLocal +=1;
-#ifdef REMOTE
- job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE);
- job->flags |= JOB_CONTINUING;
-#else
- job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
-#endif
- } else {
- /*
- * Job cannot be restarted. Mark the table as full and
- * place the job back on the list of stopped jobs.
- */
- if (
-#ifdef REMOTE
- verboseRemigrates ||
-#endif
- DEBUG(JOB)) {
- (void)fprintf(stdout, "*** holding\n");
- (void)fflush(stdout);
- }
- (void)Lst_AtFront(stoppedJobs, (ClientData)job);
- return 1;
- }
-#ifdef REMOTE
- } else {
- /*
- * Clear out the remigrate and resume flags. Set the continuing
- * flag so we know later on that the process isn't exiting just
- * because of a signal.
- */
- job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
- job->flags |= JOB_CONTINUING;
- job->rmtID = host;
- }
-#endif
-
- (void)Lst_AtEnd(jobs, (ClientData)job);
- nJobs += 1;
- } else if (job->flags & JOB_RESTART) {
- /*
- * Set up the control arguments to the shell. This is based on the
- * flags set earlier for this job. If the JOB_IGNERR flag is clear,
- * the 'exit' flag of the commandShell is used to cause it to exit
- * upon receiving an error. If the JOB_SILENT flag is clear, the
- * 'echo' flag of the commandShell is used to get it to start echoing
- * as soon as it starts processing commands.
- */
- char *argv[10];
-
- JobMakeArgv(job, argv);
-
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Restarting %s...", job->node->name);
- (void)fflush(stdout);
- }
-#ifdef REMOTE
- if ((job->node->type & OP_NOEXPORT) ||
- (nLocal < maxLocal && runLocalFirst)
-# ifdef RMT_NO_EXEC
- || !Rmt_Export(shellPath, argv, job)
-# else
- || !Rmt_Begin(shellPath, argv, job->node)
-# endif
- )
-#endif
- {
- if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) {
- /*
- * Can't be exported and not allowed to run locally -- put it
- * back on the hold queue and mark the table full
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "holding\n");
- (void)fflush(stdout);
- }
- (void)Lst_AtFront(stoppedJobs, (ClientData)job);
- return 1;
- } else {
- /*
- * Job may be run locally.
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "running locally\n");
- (void)fflush(stdout);
- }
- job->flags &= ~JOB_REMOTE;
- }
- }
-#ifdef REMOTE
- else {
- /*
- * Can be exported. Hooray!
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "exporting\n");
- (void)fflush(stdout);
- }
- job->flags |= JOB_REMOTE;
- }
-#endif
- JobExec(job, argv);
- } else {
- /*
- * The job has stopped and needs to be restarted. Why it stopped,
- * we don't know...
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Resuming %s...", job->node->name);
- (void)fflush(stdout);
- }
- if ((nJobs != maxJobs) &&
- ((job->flags & JOB_REMOTE) ||
- (nLocal < maxLocal) ||
- ((maxLocal == 0) &&
- ((job->flags & JOB_SPECIAL)
-#ifdef REMOTE
- && (job->node->type & OP_NOEXPORT)
-#endif
- ))))
- {
- /*
- * If the job is remote, it's ok to resume it as long as the
- * maximum concurrency won't be exceeded. If it's local and
- * we haven't reached the local concurrency limit already (or the
- * job must be run locally and maxLocal is 0), it's also ok to
- * resume it.
- */
- Boolean error;
- WAIT_T status;
-
-#ifdef RMT_WANTS_SIGNALS
- if (job->flags & JOB_REMOTE) {
- error = !Rmt_Signal(job, SIGCONT);
- } else
-#endif /* RMT_WANTS_SIGNALS */
- error = (KILL(job->pid, SIGCONT) != 0);
-
- if (!error) {
- /*
- * Make sure the user knows we've continued the beast and
- * actually put the thing in the job table.
- */
- job->flags |= JOB_CONTINUING;
- WSET_STOPCODE(status, SIGCONT);
- JobFinish(job, status);
-
- job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "done\n");
- (void)fflush(stdout);
- }
- } else {
- Error("couldn't resume %s: %s",
- job->node->name, strerror(errno));
- WSET_EXITCODE(status, 1, 0);
- JobFinish(job, status);
- }
- } else {
- /*
- * Job cannot be restarted. Mark the table as full and
- * place the job back on the list of stopped jobs.
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "table full\n");
- (void)fflush(stdout);
- }
- (void)Lst_AtFront(stoppedJobs, (ClientData)job);
- return 1;
- }
- }
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
* JobStart --
* Start a target-creation process going for the target described
* by the graph node gn.
@@ -1923,28 +1491,30 @@ JobRestart(Job *job)
* Side Effects:
* A new Job node is created and added to the list of running
* jobs. PMake is forked and a child shell created.
+ *
+ * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set
+ * JOB_IGNDOTS is never set (dsl)
+ * Also the return value is ignored by everyone.
*-----------------------------------------------------------------------
*/
static int
-JobStart(GNode *gn, int flags, Job *previous)
+JobStart(GNode *gn, int flags)
{
Job *job; /* new job descriptor */
char *argv[10]; /* Argument vector to shell */
Boolean cmdsOK; /* true if the nodes commands were all right */
- Boolean local; /* Set true if the job was run locally */
Boolean noExec; /* Set true if we decide not to run the job */
int tfd; /* File descriptor to the temp file */
- if (previous != NULL) {
- previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
- job = previous;
- } else {
- job = emalloc(sizeof(Job));
- if (job == NULL) {
- Punt("JobStart out of memory");
- }
- flags |= JOB_FIRST;
+ for (job = job_table; job < job_table_end; job++) {
+ if (job->job_state == JOB_ST_FREE)
+ break;
}
+ if (job >= job_table_end)
+ Punt("JobStart no job slots vacant");
+
+ memset(job, 0, sizeof *job);
+ job->job_state = JOB_ST_SETUP;
if (gn->type & OP_SPECIAL)
flags |= JOB_SPECIAL;
@@ -1969,15 +1539,9 @@ JobStart(GNode *gn, int flags, Job *previous)
* Check the commands now so any attributes from .DEFAULT have a chance
* to migrate to the node
*/
- if (!compatMake && job->flags & JOB_FIRST) {
- cmdsOK = Job_CheckCommands(gn, Error);
- } else {
- cmdsOK = TRUE;
- }
+ cmdsOK = Job_CheckCommands(gn, Error);
-#ifndef RMT_WILL_WATCH
job->inPollfd = NULL;
-#endif
/*
* If the -n flag wasn't given, we open up OUR (not the child's)
* temporary file to stuff commands in it. The thing is rd/wr so we don't
@@ -1985,7 +1549,7 @@ JobStart(GNode *gn, int flags, Job *previous)
* we just set the file to be stdout. Cute, huh?
*/
if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) ||
- (!noExecute && !touchFlag)) {
+ (!noExecute && !touchFlag)) {
/*
* tfile is the name of a file into which all shell commands are
* put. It is used over by removing it before the child shell is
@@ -2022,59 +1586,17 @@ JobStart(GNode *gn, int flags, Job *previous)
noExec = FALSE;
/*
- * used to be backwards; replace when start doing multiple commands
- * per shell.
+ * We can do all the commands at once. hooray for sanity
*/
- if (compatMake) {
- /*
- * Be compatible: If this is the first time for this node,
- * verify its commands are ok and open the commands list for
- * sequential access by later invocations of JobStart.
- * Once that is done, we take the next command off the list
- * and print it to the command file. If the command was an
- * ellipsis, note that there's nothing more to execute.
- */
- if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){
- cmdsOK = FALSE;
- } else {
- LstNode ln = Lst_Next(gn->commands);
-
- if ((ln == NILLNODE) ||
- JobPrintCommand((ClientData)Lst_Datum(ln),
- (ClientData) job))
- {
- noExec = TRUE;
- Lst_Close(gn->commands);
- }
- if (noExec && !(job->flags & JOB_FIRST)) {
- /*
- * If we're not going to execute anything, the job
- * is done and we need to close down the various
- * file descriptors we've opened for output, then
- * call JobDoOutput to catch the final characters or
- * send the file to the screen... Note that the i/o streams
- * are only open if this isn't the first job.
- * Note also that this could not be done in
- * Job_CatchChildren b/c it wasn't clear if there were
- * more commands to execute or not...
- */
- JobClose(job);
- }
- }
- } else {
- /*
- * We can do all the commands at once. hooray for sanity
- */
- numCommands = 0;
- Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
+ numCommands = 0;
+ Lst_ForEach(gn->commands, JobPrintCommand, job);
- /*
- * If we didn't print out any commands to the shell script,
- * there's not much point in executing the shell, is there?
- */
- if (numCommands == 0) {
- noExec = TRUE;
- }
+ /*
+ * If we didn't print out any commands to the shell script,
+ * there's not much point in executing the shell, is there?
+ */
+ if (numCommands == 0) {
+ noExec = TRUE;
}
} else if (NoExecute(gn)) {
/*
@@ -2092,7 +1614,7 @@ JobStart(GNode *gn, int flags, Job *previous)
* doesn't do any harm in this case and may do some good.
*/
if (cmdsOK) {
- Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
+ Lst_ForEach(gn->commands, JobPrintCommand, job);
}
/*
* Don't execute the shell, thank you.
@@ -2109,11 +1631,15 @@ JobStart(GNode *gn, int flags, Job *previous)
Job_Touch(gn, job->flags&JOB_SILENT);
noExec = TRUE;
}
+ /* Just in case it isn't already... */
+ (void)fflush(job->cmdFILE);
/*
* If we're not supposed to execute a shell, don't.
*/
if (noExec) {
+ if (!(job->flags & JOB_SPECIAL))
+ Job_TokenReturn();
/*
* Unlink and close the command file if we opened one
*/
@@ -2122,34 +1648,23 @@ JobStart(GNode *gn, int flags, Job *previous)
(void)fclose(job->cmdFILE);
job->cmdFILE = NULL;
}
- } else {
- (void)fflush(stdout);
}
/*
* We only want to work our way up the graph if we aren't here because
* the commands for the job were no good.
*/
- if (cmdsOK) {
- if (aborting == 0) {
- if (job->tailCmds != NILLNODE) {
- Lst_ForEachFrom(job->node->commands, job->tailCmds,
- JobSaveCommand,
- (ClientData)job->node);
- }
- if (!(job->flags & JOB_SPECIAL))
- Job_TokenReturn();
- job->node->made = MADE;
- Make_Update(job->node);
+ if (cmdsOK && aborting == 0) {
+ if (job->tailCmds != NILLNODE) {
+ Lst_ForEachFrom(job->node->commands, job->tailCmds,
+ JobSaveCommand,
+ job->node);
}
- free(job);
- return(JOB_FINISHED);
- } else {
- free(job);
- return(JOB_ERROR);
+ job->node->made = MADE;
+ Make_Update(job->node);
}
- } else {
- (void)fflush(job->cmdFILE);
+ job->job_state = JOB_ST_FREE;
+ return cmdsOK ? JOB_FINISHED : JOB_ERROR;
}
/*
@@ -2158,66 +1673,10 @@ JobStart(GNode *gn, int flags, Job *previous)
*/
JobMakeArgv(job, argv);
- /*
- * If we're using pipes to catch output, create the pipe by which we'll
- * get the shell's output. If we're using files, print out that we're
- * starting a job and then set up its temporary-file name.
- */
- if (!compatMake || (job->flags & JOB_FIRST)) {
- if (usePipes) {
- int fd[2];
- if (pipe(fd) == -1)
- Punt("Cannot create pipe: %s", strerror(errno));
- job->inPipe = fd[0];
- job->outPipe = fd[1];
- (void)fcntl(job->inPipe, F_SETFD, 1);
- (void)fcntl(job->outPipe, F_SETFD, 1);
- } else {
- (void)fprintf(stdout, "Remaking `%s'\n", gn->name);
- (void)fflush(stdout);
- (void)strcpy(job->outFile, TMPPAT);
- job->outFd = mkstemp(job->outFile);
- (void)fcntl(job->outFd, F_SETFD, 1);
- }
- }
+ /* Create the pipe by which we'll get the shell's output. */
+ JobCreatePipe(job, 3);
-#ifdef REMOTE
- if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) {
-#ifdef RMT_NO_EXEC
- local = !Rmt_Export(shellPath, argv, job);
-#else
- local = !Rmt_Begin(shellPath, argv, job->node);
-#endif /* RMT_NO_EXEC */
- if (!local) {
- job->flags |= JOB_REMOTE;
- }
- } else
-#endif
- local = TRUE;
-
- if (local && (((nLocal >= maxLocal) &&
- !(job->flags & JOB_SPECIAL) &&
-#ifdef REMOTE
- (!(gn->type & OP_NOEXPORT) || (maxLocal != 0))
-#else
- (maxLocal != 0)
-#endif
- )))
- {
- /*
- * The job can only be run locally, but we've hit the limit of
- * local concurrency, so put the job on hold until some other job
- * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)
- * may be run locally even when the local limit has been reached
- * (e.g. when maxLocal == 0), though they will be exported if at
- * all possible. In addition, any target marked with .NOEXPORT will
- * be run locally if maxLocal is 0.
- */
- job->flags |= JOB_RESTART;
- (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
- } else {
- JobExec(job, argv);
- }
+ JobExec(job, argv);
return(JOB_RUNNING);
}
@@ -2231,7 +1690,7 @@ JobOutput(Job *job, char *cp, char *endp, int msg)
while (ecp != NULL) {
if (cp != ecp) {
*ecp = '\0';
- if (msg && job->node != lastNode) {
+ if (!beSilent && msg && job->node != lastNode) {
MESSAGE(stdout, job->node);
lastNode = job->node;
}
@@ -2306,170 +1765,124 @@ JobDoOutput(Job *job, Boolean finish)
int max; /* limit for i (end of current data) */
int nRead; /* (Temporary) number of bytes read */
- FILE *oFILE; /* Stream pointer to shell's output file */
- char inLine[132];
-
-
- if (usePipes) {
- /*
- * Read as many bytes as will fit in the buffer.
- */
+ /*
+ * Read as many bytes as will fit in the buffer.
+ */
end_loop:
- gotNL = FALSE;
- fbuf = FALSE;
+ gotNL = FALSE;
+ fbuf = FALSE;
- nRead = read(job->inPipe, &job->outBuf[job->curPos],
- JOB_BUFSIZE - job->curPos);
- if (nRead < 0) {
- if (DEBUG(JOB)) {
- perror("JobDoOutput(piperead)");
- }
- nr = 0;
- } else {
- nr = nRead;
- }
-
- /*
- * If we hit the end-of-file (the job is dead), we must flush its
- * remaining output, so pretend we read a newline if there's any
- * output remaining in the buffer.
- * Also clear the 'finish' flag so we stop looping.
- */
- if ((nr == 0) && (job->curPos != 0)) {
- job->outBuf[job->curPos] = '\n';
- nr = 1;
- finish = FALSE;
- } else if (nr == 0) {
- finish = FALSE;
+ nRead = read(job->inPipe, &job->outBuf[job->curPos],
+ JOB_BUFSIZE - job->curPos);
+ if (nRead < 0) {
+ if (errno == EAGAIN)
+ return;
+ if (DEBUG(JOB)) {
+ perror("JobDoOutput(piperead)");
}
+ nr = 0;
+ } else {
+ nr = nRead;
+ }
- /*
- * Look for the last newline in the bytes we just got. If there is
- * one, break out of the loop with 'i' as its index and gotNL set
- * TRUE.
- */
- max = job->curPos + nr;
- for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
- if (job->outBuf[i] == '\n') {
- gotNL = TRUE;
- break;
- } else if (job->outBuf[i] == '\0') {
- /*
- * Why?
- */
- job->outBuf[i] = ' ';
- }
- }
+ /*
+ * If we hit the end-of-file (the job is dead), we must flush its
+ * remaining output, so pretend we read a newline if there's any
+ * output remaining in the buffer.
+ * Also clear the 'finish' flag so we stop looping.
+ */
+ if ((nr == 0) && (job->curPos != 0)) {
+ job->outBuf[job->curPos] = '\n';
+ nr = 1;
+ finish = FALSE;
+ } else if (nr == 0) {
+ finish = FALSE;
+ }
- if (!gotNL) {
- job->curPos += nr;
- if (job->curPos == JOB_BUFSIZE) {
- /*
- * If we've run out of buffer space, we have no choice
- * but to print the stuff. sigh.
- */
- fbuf = TRUE;
- i = job->curPos;
- }
- }
- if (gotNL || fbuf) {
+ /*
+ * Look for the last newline in the bytes we just got. If there is
+ * one, break out of the loop with 'i' as its index and gotNL set
+ * TRUE.
+ */
+ max = job->curPos + nr;
+ for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
+ if (job->outBuf[i] == '\n') {
+ gotNL = TRUE;
+ break;
+ } else if (job->outBuf[i] == '\0') {
/*
- * Need to send the output to the screen. Null terminate it
- * first, overwriting the newline character if there was one.
- * So long as the line isn't one we should filter (according
- * to the shell description), we print the line, preceded
- * by a target banner if this target isn't the same as the
- * one for which we last printed something.
- * The rest of the data in the buffer are then shifted down
- * to the start of the buffer and curPos is set accordingly.
+ * Why?
*/
- job->outBuf[i] = '\0';
- if (i >= job->curPos) {
- char *cp;
-
- cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE);
-
- /*
- * There's still more in that thar buffer. This time, though,
- * we know there's no newline at the end, so we add one of
- * our own free will.
- */
- if (*cp != '\0') {
- if (job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
- (void)fflush(stdout);
- }
- }
- if (i < max - 1) {
- /* shift the remaining characters down */
- (void)memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
- job->curPos = max - (i + 1);
-
- } else {
- /*
- * We have written everything out, so we just start over
- * from the start of the buffer. No copying. No nothing.
- */
- job->curPos = 0;
- }
+ job->outBuf[i] = ' ';
}
- if (finish) {
+ }
+
+ if (!gotNL) {
+ job->curPos += nr;
+ if (job->curPos == JOB_BUFSIZE) {
/*
- * If the finish flag is true, we must loop until we hit
- * end-of-file on the pipe. This is guaranteed to happen
- * eventually since the other end of the pipe is now closed
- * (we closed it explicitly and the child has exited). When
- * we do get an EOF, finish will be set FALSE and we'll fall
- * through and out.
+ * If we've run out of buffer space, we have no choice
+ * but to print the stuff. sigh.
*/
- goto end_loop;
+ fbuf = TRUE;
+ i = job->curPos;
}
- } else {
+ }
+ if (gotNL || fbuf) {
/*
- * We've been called to retrieve the output of the job from the
- * temporary file where it's been squirreled away. This consists of
- * opening the file, reading the output line by line, being sure not
- * to print the noPrint line for the shell we used, then close and
- * remove the temporary file. Very simple.
- *
- * Change to read in blocks and do FindSubString type things as for
- * pipes? That would allow for "@echo -n..."
+ * Need to send the output to the screen. Null terminate it
+ * first, overwriting the newline character if there was one.
+ * So long as the line isn't one we should filter (according
+ * to the shell description), we print the line, preceded
+ * by a target banner if this target isn't the same as the
+ * one for which we last printed something.
+ * The rest of the data in the buffer are then shifted down
+ * to the start of the buffer and curPos is set accordingly.
*/
- oFILE = fopen(job->outFile, "r");
- if (oFILE != NULL) {
- (void)fprintf(stdout, "Results of making %s:\n", job->node->name);
- (void)fflush(stdout);
- while (fgets(inLine, sizeof(inLine), oFILE) != NULL) {
- char *cp, *endp, *oendp;
+ job->outBuf[i] = '\0';
+ if (i >= job->curPos) {
+ char *cp;
- cp = inLine;
- oendp = endp = inLine + strlen(inLine);
- if (endp[-1] == '\n') {
- *--endp = '\0';
- }
- cp = JobOutput(job, inLine, endp, FALSE);
+ cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE);
- /*
- * There's still more in that thar buffer. This time, though,
- * we know there's no newline at the end, so we add one of
- * our own free will.
- */
- (void)fprintf(stdout, "%s", cp);
- (void)fflush(stdout);
- if (endp != oendp) {
- (void)fprintf(stdout, "\n");
- (void)fflush(stdout);
+ /*
+ * There's still more in that thar buffer. This time, though,
+ * we know there's no newline at the end, so we add one of
+ * our own free will.
+ */
+ if (*cp != '\0') {
+ if (!beSilent && job->node != lastNode) {
+ MESSAGE(stdout, job->node);
+ lastNode = job->node;
}
+ (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
+ (void)fflush(stdout);
}
- (void)fclose(oFILE);
- (void)eunlink(job->outFile);
+ }
+ if (i < max - 1) {
+ /* shift the remaining characters down */
+ (void)memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
+ job->curPos = max - (i + 1);
+
} else {
- Punt("Cannot open `%s'", job->outFile);
+ /*
+ * We have written everything out, so we just start over
+ * from the start of the buffer. No copying. No nothing.
+ */
+ job->curPos = 0;
}
}
+ if (finish) {
+ /*
+ * If the finish flag is true, we must loop until we hit
+ * end-of-file on the pipe. This is guaranteed to happen
+ * eventually since the other end of the pipe is now closed
+ * (we closed it explicitly and the child has exited). When
+ * we do get an EOF, finish will be set FALSE and we'll fall
+ * through and out.
+ */
+ goto end_loop;
+ }
}
static void
@@ -2485,12 +1898,9 @@ JobRun(GNode *targ)
Lst_AtEnd(lst, targ);
(void)Make_Run(lst);
Lst_Destroy(lst, NOFREE);
- JobStart(targ, JOB_SPECIAL, NULL);
- while (nJobs) {
+ JobStart(targ, JOB_SPECIAL);
+ while (jobTokensRunning) {
Job_CatchOutput();
-#ifndef RMT_WILL_WATCH
- Job_CatchChildren(!usePipes);
-#endif /* RMT_WILL_WATCH */
}
#else
Compat_Make(targ, targ);
@@ -2518,67 +1928,62 @@ JobRun(GNode *targ)
* Notes:
* We do waits, blocking or not, according to the wisdom of our
* caller, until there are no more children to report. For each
- * job, call JobFinish to finish things off. This will take care of
- * putting jobs on the stoppedJobs queue.
+ * job, call JobFinish to finish things off.
*
*-----------------------------------------------------------------------
*/
+
void
-Job_CatchChildren(Boolean block)
+Job_CatchChildren(void)
{
int pid; /* pid of dead child */
Job *job; /* job descriptor for dead child */
- LstNode jnode; /* list element for finding job */
WAIT_T status; /* Exit/termination status */
/*
* Don't even bother if we know there's no one around.
*/
- if (nLocal == 0) {
+ if (jobTokensRunning == 0)
return;
- }
- while ((pid = waitpid((pid_t) -1, &status,
- (block?0:WNOHANG)|WUNTRACED)) > 0)
- {
+ while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) {
if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Process %d exited or stopped %x.\n", pid,
+ (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid,
WAIT_STATUS(status));
- (void)fflush(stdout);
}
- jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid);
- if (jnode == NILLNODE) {
- if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGCONT)) {
- jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);
- if (jnode == NILLNODE) {
- Error("Resumed child (%d) not in table", pid);
- continue;
- }
- job = (Job *)Lst_Datum(jnode);
- (void)Lst_Remove(stoppedJobs, jnode);
- } else {
- Error("Child (%d) not in table?", pid);
- continue;
+ job = JobFindPid(pid, JOB_ST_RUNNING);
+ if (job == NULL) {
+ if (!lurking_children)
+ Error("Child (%d) status %x not in table?", pid, status);
+ continue;
+ }
+ if (WIFSTOPPED(status)) {
+ if (DEBUG(JOB)) {
+ (void)fprintf(debug_file, "Process %d (%s) stopped.\n",
+ job->pid, job->node->name);
}
- } else {
- job = (Job *)Lst_Datum(jnode);
- (void)Lst_Remove(jobs, jnode);
- nJobs -= 1;
-#ifdef REMOTE
- if (!(job->flags & JOB_REMOTE)) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "Job queue has one fewer local process.\n");
- (void)fflush(stdout);
- }
- nLocal -= 1;
+ if (!make_suspended) {
+ switch (WSTOPSIG(status)) {
+ case SIGTSTP:
+ (void)printf("*** [%s] Suspended\n", job->node->name);
+ break;
+ case SIGSTOP:
+ (void)printf("*** [%s] Stopped\n", job->node->name);
+ break;
+ default:
+ (void)printf("*** [%s] Stopped -- signal %d\n",
+ job->node->name, WSTOPSIG(status));
+ }
+ job->job_suspended = 1;
}
-#else
- nLocal -= 1;
-#endif
+ (void)fflush(stdout);
+ continue;
}
+ job->job_state = JOB_ST_FINISHED;
+ job->exit_status = WAIT_STATUS(status);
+
JobFinish(job, status);
}
}
@@ -2602,67 +2007,39 @@ Job_CatchChildren(Boolean block)
void
Job_CatchOutput(void)
{
- int nready;
- LstNode ln;
- Job *job;
-#ifdef RMT_WILL_WATCH
- int pnJobs; /* Previous nJobs */
-#endif
+ int nready;
+ Job *job;
+ int i;
(void)fflush(stdout);
- Job_TokenFlush();
-#ifdef RMT_WILL_WATCH
- pnJobs = nJobs;
- /*
- * It is possible for us to be called with nJobs equal to 0. This happens
- * if all the jobs finish and a job that is stopped cannot be run
- * locally (eg if maxLocal is 0) and cannot be exported. The job will
- * be placed back on the stoppedJobs queue, Job_Empty() will return false,
- * Make_Run will call us again when there's nothing for which to wait.
- * nJobs never changes, so we loop forever. Hence the check. It could
- * be argued that we should sleep for a bit so as not to swamp the
- * exportation system with requests. Perhaps we should.
- *
- * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren
- * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.
- * It may use the variable nLocal to determine if it needs to call
- * Job_CatchChildren(if nLocal is 0, there's nothing for which to
- * wait...)
- */
- while (nJobs != 0 && pnJobs == nJobs) {
- Rmt_Wait();
+ /* The first fd in the list is the job token pipe */
+ nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC);
+
+ if (nready < 0 || readyfd(&childExitJob)) {
+ char token = 0;
+ nready -= 1;
+ (void)read(childExitJob.inPipe, &token, 1);
+ if (token == DO_JOB_RESUME[0])
+ /* Complete relay requested from our SIGCONT handler */
+ JobRestartJobs();
+ Job_CatchChildren();
}
-#else
- if (usePipes) {
- if ((nready = poll((wantToken ? fds : (fds + 1)),
- (wantToken ? nfds : (nfds - 1)), POLL_MSEC)) <= 0) {
- return;
- } else {
- sigset_t mask;
- JobSigLock(&mask);
- if (Lst_Open(jobs) == FAILURE) {
- Punt("Cannot open job table");
- }
- if (readyfd(&childExitJob)) {
- char token;
- (void)read(childExitJob.inPipe, &token, 1);
- nready -= 1;
- }
+ if (nready <= 0)
+ return;
- while (nready && (ln = Lst_Next(jobs)) != NILLNODE) {
- job = (Job *)Lst_Datum(ln);
- if (readyfd(job)) {
- JobDoOutput(job, FALSE);
- nready -= 1;
- }
- }
- Lst_Close(jobs);
- JobSigUnlock(&mask);
- }
+ if (wantToken && readyfd(&tokenWaitJob))
+ nready--;
+
+ for (i = 2; i < nfds; i++) {
+ if (!fds[i].revents)
+ continue;
+ job = jobfds[i];
+ if (job->job_state != JOB_ST_RUNNING)
+ continue;
+ JobDoOutput(job, FALSE);
}
-#endif /* RMT_WILL_WATCH */
}
/*-
@@ -2682,21 +2059,25 @@ Job_CatchOutput(void)
void
Job_Make(GNode *gn)
{
- (void)JobStart(gn, 0, NULL);
+ (void)JobStart(gn, 0);
}
void
-Shell_Init()
+Shell_Init(void)
{
if (shellPath == NULL) {
/*
- * The user didn't specify a shell to use, so we are using the
- * default one... Both the absolute path and the last component
- * must be set. The last component is taken from the 'name' field
- * of the default shell description pointed-to by commandShell.
- * All default shells are located in _PATH_DEFSHELLDIR.
+ * We are using the default shell, which may be an absolute
+ * path if DEFSHELL_CUSTOM is defined.
*/
shellName = commandShell->name;
+#ifdef DEFSHELL_CUSTOM
+ if (*shellName == '/') {
+ shellPath = shellName;
+ shellName = strrchr(shellPath, '/');
+ shellName++;
+ } else
+#endif
shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
}
if (commandShell->exit == NULL) {
@@ -2708,15 +2089,35 @@ Shell_Init()
}
/*-
+ * Returns the string literal that is used in the current command shell
+ * to produce a newline character.
+ */
+const char *
+Shell_GetNewline(void)
+{
+
+ return commandShell->newline;
+}
+
+void
+Job_SetPrefix(void)
+{
+
+ if (targPrefix) {
+ free(targPrefix);
+ } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) {
+ Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL, 0);
+ }
+
+ targPrefix = Var_Subst(NULL, "${" MAKE_JOB_PREFIX "}", VAR_GLOBAL, 0);
+}
+
+/*-
*-----------------------------------------------------------------------
* Job_Init --
* Initialize the process module
*
* Input:
- * maxproc the greatest number of jobs which may be running
- * at one time
- * maxlocal the greatest number of jobs which may be running
- * at once
*
* Results:
* none
@@ -2726,28 +2127,22 @@ Shell_Init()
*-----------------------------------------------------------------------
*/
void
-Job_Init(int maxproc, int maxlocal)
+Job_Init(void)
{
GNode *begin; /* node for commands to do at the very start */
- jobs = Lst_Init(FALSE);
- stoppedJobs = Lst_Init(FALSE);
- maxJobs = maxproc;
- maxLocal = maxlocal;
- nJobs = 0;
- nLocal = 0;
- wantToken = FALSE;
+ /* Allocate space for all the job info */
+ job_table = emalloc(maxJobs * sizeof *job_table);
+ memset(job_table, 0, maxJobs * sizeof *job_table);
+ job_table_end = job_table + maxJobs;
+ wantToken = 0;
aborting = 0;
errors = 0;
lastNode = NILGNODE;
- if (maxJobs == 1
-#ifdef REMOTE
- || noMessages
-#endif
- ) {
+ if (maxJobs == 1) {
/*
* If only one job can run at a time, there's no need for a banner,
* is there?
@@ -2757,14 +2152,34 @@ Job_Init(int maxproc, int maxlocal)
targFmt = TARG_FMT;
}
+ /*
+ * There is a non-zero chance that we already have children.
+ * eg after 'make -f- <<EOF'
+ * Since their termination causes a 'Child (pid) not in table' message,
+ * Collect the status of any that are already dead, and suppress the
+ * error message if there are any undead ones.
+ */
+ for (;;) {
+ int rval, status;
+ rval = waitpid((pid_t) -1, &status, WNOHANG);
+ if (rval > 0)
+ continue;
+ if (rval == 0)
+ lurking_children = 1;
+ break;
+ }
+
Shell_Init();
- if (pipe(exit_pipe) < 0)
- Fatal("error in pipe: %s", strerror(errno));
- fcntl(exit_pipe[0], F_SETFD, 1);
- fcntl(exit_pipe[1], F_SETFD, 1);
+ JobCreatePipe(&childExitJob, 3);
- childExitJob.inPipe = exit_pipe[0];
+ /* We can only need to wait for tokens, children and output from each job */
+ fds = emalloc(sizeof (*fds) * (2 + maxJobs));
+ jobfds = emalloc(sizeof (*jobfds) * (2 + maxJobs));
+
+ /* These are permanent entries and take slots 0 and 1 */
+ watchfd(&tokenWaitJob);
+ watchfd(&childExitJob);
sigemptyset(&caught_signals);
/*
@@ -2783,10 +2198,10 @@ Job_Init(int maxproc, int maxlocal)
* Catch the four signals that POSIX specifies if they aren't ignored.
* JobPassSig will take care of calling JobInterrupt if appropriate.
*/
- ADDSIG(SIGINT, JobPassSig)
- ADDSIG(SIGHUP, JobPassSig)
- ADDSIG(SIGTERM, JobPassSig)
- ADDSIG(SIGQUIT, JobPassSig)
+ ADDSIG(SIGINT, JobPassSig_int)
+ ADDSIG(SIGHUP, JobPassSig_term)
+ ADDSIG(SIGTERM, JobPassSig_term)
+ ADDSIG(SIGQUIT, JobPassSig_term)
/*
* There are additional signals that need to be caught and passed if
@@ -2794,13 +2209,11 @@ Job_Init(int maxproc, int maxlocal)
* we're giving each job its own process group (since then it won't get
* signals from the terminal driver as we own the terminal)
*/
-#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
- ADDSIG(SIGTSTP, JobPassSig)
- ADDSIG(SIGTTOU, JobPassSig)
- ADDSIG(SIGTTIN, JobPassSig)
- ADDSIG(SIGWINCH, JobPassSig)
+ ADDSIG(SIGTSTP, JobPassSig_suspend)
+ ADDSIG(SIGTTOU, JobPassSig_suspend)
+ ADDSIG(SIGTTIN, JobPassSig_suspend)
+ ADDSIG(SIGWINCH, JobCondPassSig)
ADDSIG(SIGCONT, JobContinueSig)
-#endif
#undef ADDSIG
begin = Targ_FindNode(".BEGIN", TARG_NOCREATE);
@@ -2819,61 +2232,24 @@ static void JobSigReset(void)
{
#define DELSIG(s) \
if (sigismember(&caught_signals, s)) { \
- (void)signal(SIGINT, SIG_DFL); \
+ (void)signal(s, SIG_DFL); \
}
DELSIG(SIGINT)
DELSIG(SIGHUP)
DELSIG(SIGQUIT)
DELSIG(SIGTERM)
-#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
DELSIG(SIGTSTP)
DELSIG(SIGTTOU)
DELSIG(SIGTTIN)
DELSIG(SIGWINCH)
DELSIG(SIGCONT)
-#endif
#undef DELSIG
(void)signal(SIGCHLD, SIG_DFL);
}
/*-
*-----------------------------------------------------------------------
- * Job_Empty --
- * See if the job table is empty. Because the local concurrency may
- * be set to 0, it is possible for the job table to become empty,
- * while the list of stoppedJobs remains non-empty. In such a case,
- * we want to restart as many jobs as we can.
- *
- * Results:
- * TRUE if it is. FALSE if it ain't.
- *
- * Side Effects:
- * None.
- *
- * -----------------------------------------------------------------------
- */
-Boolean
-Job_Empty(void)
-{
- if (nJobs == 0) {
- if (!Lst_IsEmpty(stoppedJobs) && !aborting) {
- /*
- * The job table is obviously not full if it has no jobs in
- * it...Try and restart the stopped jobs.
- */
- JobRestartJobs();
- return(FALSE);
- } else {
- return(TRUE);
- }
- } else {
- return(FALSE);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
* JobMatchShell --
* Find a shell in 'shells' given its name.
*
@@ -2932,6 +2308,7 @@ JobMatchShell(const char *name)
* echoFlag Flag to turn echoing on at the start
* errFlag Flag to turn error checking on at the start
* hasErrCtl True if shell has error checking control
+ * newline String literal to represent a newline char
* check Command to turn on error checking if hasErrCtl
* is TRUE or template of command to echo a command
* for which error checking is off if hasErrCtl is
@@ -2990,6 +2367,8 @@ Job_ParseShell(char *line)
char c = argv[0][10];
newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
(c != 'T') && (c != 't'));
+ } else if (strncmp(*argv, "newline=", 8) == 0) {
+ newShell.newline = &argv[0][8];
} else if (strncmp(*argv, "check=", 6) == 0) {
newShell.errCheck = &argv[0][6];
} else if (strncmp(*argv, "ignore=", 7) == 0) {
@@ -3105,20 +2484,19 @@ Job_ParseShell(char *line)
static void
JobInterrupt(int runINTERRUPT, int signo)
{
- LstNode ln; /* element in job table */
Job *job; /* job descriptor in that element */
GNode *interrupt; /* the node describing the .INTERRUPT target */
sigset_t mask;
+ GNode *gn;
aborting = ABORT_INTERRUPT;
JobSigLock(&mask);
- (void)Lst_Open(jobs);
- while ((ln = Lst_Next(jobs)) != NILLNODE) {
- GNode *gn;
+ for (job = job_table; job < job_table_end; job++) {
+ if (job->job_state != JOB_ST_RUNNING)
+ continue;
- job = (Job *)Lst_Datum(ln);
gn = job->node;
if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) {
@@ -3127,99 +2505,15 @@ JobInterrupt(int runINTERRUPT, int signo)
Error("*** %s removed", file);
}
}
-#ifdef RMT_WANTS_SIGNALS
- if (job->flags & JOB_REMOTE) {
- /*
- * If job is remote, let the Rmt module do the killing.
- */
- if (!Rmt_Signal(job, signo)) {
- /*
- * If couldn't kill the thing, finish it out now with an
- * error code, since no exit report will come in likely.
- */
- WAIT_T status;
-
- WSET_EXITCODE(status, 1, 0);
- JobFinish(job, status);
- }
- } else if (job->pid) {
- KILL(job->pid, signo);
- }
-#else
if (job->pid) {
if (DEBUG(JOB)) {
- (void)fprintf(stdout,
+ (void)fprintf(debug_file,
"JobInterrupt passing signal %d to child %d.\n",
signo, job->pid);
- (void)fflush(stdout);
}
- KILL(job->pid, signo);
+ KILLPG(job->pid, signo);
}
-#endif /* RMT_WANTS_SIGNALS */
}
- Lst_Close(jobs);
-
-#ifdef REMOTE
- (void)Lst_Open(stoppedJobs);
- while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) {
- GNode *gn;
-
- job = (Job *)Lst_Datum(ln);
- gn = job->node;
-
- if (job->flags & JOB_RESTART) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "%s%s",
- "JobInterrupt skipping job on stopped queue",
- "-- it was waiting to be restarted.\n");
- (void)fflush(stdout);
- }
- continue;
- }
- if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) {
- char *file = (gn->path == NULL ? gn->name : gn->path);
- if (eunlink(file) == 0) {
- Error("*** %s removed", file);
- }
- }
- /*
- * Resume the thing so it will take the signal.
- */
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "JobInterrupt passing CONT to stopped child %d.\n",
- job->pid);
- (void)fflush(stdout);
- }
- KILL(job->pid, SIGCONT);
-#ifdef RMT_WANTS_SIGNALS
- if (job->flags & JOB_REMOTE) {
- /*
- * If job is remote, let the Rmt module do the killing.
- */
- if (!Rmt_Signal(job, SIGINT)) {
- /*
- * If couldn't kill the thing, finish it out now with an
- * error code, since no exit report will come in likely.
- */
- WAIT_T status;
-
- WSET_EXITCODE(status, 1, 0);
- JobFinish(job, status);
- }
- } else if (job->pid) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "JobInterrupt passing interrupt to stopped child %d.\n",
- job->pid);
- (void)fflush(stdout);
- }
- KILL(job->pid, SIGINT);
- }
-#endif /* RMT_WANTS_SIGNALS */
- }
- Lst_Close(stoppedJobs);
-#endif /* REMOTE */
JobSigUnlock(&mask);
@@ -3257,7 +2551,6 @@ Job_Finish(void)
JobRun(postCommands);
}
}
- Job_TokenFlush();
return(errors);
}
@@ -3300,13 +2593,9 @@ void
Job_Wait(void)
{
aborting = ABORT_WAIT;
- while (nJobs != 0) {
+ while (jobTokensRunning != 0) {
Job_CatchOutput();
-#ifndef RMT_WILL_WATCH
- Job_CatchChildren(!usePipes);
-#endif /* RMT_WILL_WATCH */
}
- Job_TokenFlush();
aborting = 0;
}
@@ -3327,39 +2616,22 @@ Job_Wait(void)
void
Job_AbortAll(void)
{
- LstNode ln; /* element in job table */
Job *job; /* the job descriptor in that element */
WAIT_T foo;
- sigset_t mask;
aborting = ABORT_ERROR;
- if (nJobs) {
-
- JobSigLock(&mask);
- (void)Lst_Open(jobs);
- while ((ln = Lst_Next(jobs)) != NILLNODE) {
- job = (Job *)Lst_Datum(ln);
-
+ if (jobTokensRunning) {
+ for (job = job_table; job < job_table_end; job++) {
+ if (job->job_state != JOB_ST_RUNNING)
+ continue;
/*
* kill the child process with increasingly drastic signals to make
* darn sure it's dead.
*/
-#ifdef RMT_WANTS_SIGNALS
- if (job->flags & JOB_REMOTE) {
- (void)Rmt_Signal(job, SIGINT);
- (void)Rmt_Signal(job, SIGKILL);
- } else {
- KILL(job->pid, SIGINT);
- KILL(job->pid, SIGKILL);
- }
-#else
- KILL(job->pid, SIGINT);
- KILL(job->pid, SIGKILL);
-#endif /* RMT_WANTS_SIGNALS */
+ KILLPG(job->pid, SIGINT);
+ KILLPG(job->pid, SIGKILL);
}
- Lst_Close(jobs);
- JobSigUnlock(&mask);
}
/*
@@ -3369,123 +2641,54 @@ Job_AbortAll(void)
continue;
}
-#ifdef REMOTE
-/*-
- *-----------------------------------------------------------------------
- * JobFlagForMigration --
- * Handle the eviction of a child. Called from RmtStatusChange.
- * Flags the child as remigratable and then suspends it.
- *
- * Input:
- * hostID ID of host we used, for matching children
- *
- * Results:
- * none.
- *
- * Side Effects:
- * The job descriptor is flagged for remigration.
- *
- *-----------------------------------------------------------------------
- */
-void
-JobFlagForMigration(int hostID)
-{
- Job *job; /* job descriptor for dead child */
- LstNode jnode; /* list element for finding job */
-
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID);
- (void)fflush(stdout);
- }
- jnode = Lst_Find(jobs, (ClientData)&hostID, JobCmpRmtID);
-
- if (jnode == NILLNODE) {
- jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID);
- if (jnode == NILLNODE) {
- if (DEBUG(JOB)) {
- Error("Evicting host(%d) not in table", hostID);
- }
- return;
- }
- }
- job = (Job *)Lst_Datum(jnode);
-
- if (DEBUG(JOB)) {
- (void)fprintf(stdout,
- "JobFlagForMigration(%d) found job '%s'.\n", hostID,
- job->node->name);
- (void)fflush(stdout);
- }
-
- KILL(job->pid, SIGSTOP);
-
- job->flags |= JOB_REMIGRATE;
-}
-
-#endif
/*-
*-----------------------------------------------------------------------
* JobRestartJobs --
* Tries to restart stopped jobs if there are slots available.
- * Note that this tries to restart them regardless of pending errors.
- * It's not good to leave stopped jobs lying around!
+ * Called in process context in response to a SIGCONT.
*
* Results:
* None.
*
* Side Effects:
- * Resumes(and possibly migrates) jobs.
+ * Resumes jobs.
*
*-----------------------------------------------------------------------
*/
static void
JobRestartJobs(void)
{
- sigset_t mask;
+ Job *job;
- JobSigLock(&mask);
- while (!Lst_IsEmpty(stoppedJobs)) {
- if (DEBUG(JOB)) {
- (void)fprintf(stdout, "Restarting a stopped job.\n");
- (void)fflush(stdout);
+ for (job = job_table; job < job_table_end; job++) {
+ if (job->job_state == JOB_ST_RUNNING &&
+ (make_suspended || job->job_suspended)) {
+ if (DEBUG(JOB)) {
+ (void)fprintf(debug_file, "Restarting stopped job pid %d.\n",
+ job->pid);
+ }
+ if (job->job_suspended) {
+ (void)printf("*** [%s] Continued\n", job->node->name);
+ (void)fflush(stdout);
+ }
+ job->job_suspended = 0;
+ if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) {
+ fprintf(debug_file, "Failed to send SIGCONT to %d\n", job->pid);
+ }
}
- if (JobRestart((Job *)Lst_DeQueue(stoppedJobs)) != 0)
- break;
+ if (job->job_state == JOB_ST_FINISHED)
+ /* Job exit deferred after calling waitpid() in a signal handler */
+ JobFinish(job, job->exit_status);
}
- JobSigUnlock(&mask);
+ make_suspended = 0;
}
-#ifndef RMT_WILL_WATCH
static void
watchfd(Job *job)
{
- int i;
if (job->inPollfd != NULL)
Punt("Watching watched job");
- if (fds == NULL) {
- maxfds = JBSTART;
- fds = emalloc(sizeof(struct pollfd) * maxfds);
- jobfds = emalloc(sizeof(Job **) * maxfds);
-
- fds[0].fd = job_pipe[0];
- fds[0].events = POLLIN;
- jobfds[0] = &tokenWaitJob;
- tokenWaitJob.inPollfd = &fds[0];
- nfds++;
-
- fds[1].fd = exit_pipe[0];
- fds[1].events = POLLIN;
- jobfds[1] = &childExitJob;
- childExitJob.inPollfd = &fds[1];
- nfds++;
- } else if (nfds == maxfds) {
- maxfds *= JBFACTOR;
- fds = erealloc(fds, sizeof(struct pollfd) * maxfds);
- jobfds = erealloc(jobfds, sizeof(Job **) * maxfds);
- for (i = 0; i < nfds; i++)
- jobfds[i]->inPollfd = &fds[i];
- }
fds[nfds].fd = job->inPipe;
fds[nfds].events = POLLIN;
@@ -3520,7 +2723,6 @@ readyfd(Job *job)
Punt("Polling unwatched job");
return (job->inPollfd->revents & POLLIN) != 0;
}
-#endif
/*-
*-----------------------------------------------------------------------
@@ -3537,10 +2739,16 @@ readyfd(Job *job)
static void
JobTokenAdd(void)
{
+ char tok = JOB_TOKENS[aborting], tok1;
+
+ /* If we are depositing an error token flush everything else */
+ while (tok != '+' && read(tokenWaitJob.inPipe, &tok1, 1) == 1)
+ continue;
if (DEBUG(JOB))
- printf("deposit token\n");
- write(job_pipe[1], "+", 1);
+ fprintf(debug_file, "(%d) aborting %d, deposit token %c\n",
+ getpid(), aborting, JOB_TOKENS[aborting]);
+ write(tokenWaitJob.outPipe, &tok, 1);
}
/*-
@@ -3552,53 +2760,38 @@ JobTokenAdd(void)
*/
void
-Job_ServerStart(int maxproc)
+Job_ServerStart(int max_tokens, int jp_0, int jp_1)
{
- int i, flags;
+ int i;
char jobarg[64];
- if (pipe(job_pipe) < 0)
- Fatal("error in pipe: %s", strerror(errno));
-
- /*
- * We mark the input side of the pipe non-blocking; we poll(2) the
- * pipe when we're waiting for a job token, but we might lose the
- * race for the token when a new one becomes available, so the read
- * from the pipe should not block.
- */
- flags = fcntl(job_pipe[0], F_GETFL, 0);
- flags |= O_NONBLOCK;
- fcntl(job_pipe[0], F_SETFL, flags);
+ if (jp_0 >= 0 && jp_1 >= 0) {
+ /* Pipe passed in from parent */
+ tokenWaitJob.inPipe = jp_0;
+ tokenWaitJob.outPipe = jp_1;
+ return;
+ }
- /*
- * Mark job pipes as close-on-exec.
- * Note that we will clear this when executing submakes.
- */
- fcntl(job_pipe[0], F_SETFD, 1);
- fcntl(job_pipe[1], F_SETFD, 1);
+ JobCreatePipe(&tokenWaitJob, 15);
- snprintf(jobarg, sizeof(jobarg), "%d,%d", job_pipe[0], job_pipe[1]);
+ snprintf(jobarg, sizeof(jobarg), "%d,%d",
+ tokenWaitJob.inPipe, tokenWaitJob.outPipe);
Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
Var_Append(MAKEFLAGS, jobarg, VAR_GLOBAL);
-
+
/*
- * Preload job_pipe with one token per job, save the one
+ * Preload the job pipe with one token per job, save the one
* "extra" token for the primary job.
*
- * XXX should clip maxJobs against PIPE_BUF -- if maxJobs is
+ * XXX should clip maxJobs against PIPE_BUF -- if max_tokens is
* larger than the write buffer size of the pipe, we will
* deadlock here.
*/
- for (i=1; i < maxproc; i++)
+ for (i = 1; i < max_tokens; i++)
JobTokenAdd();
}
-/*
- * this tracks the number of tokens currently "out" to build jobs.
- */
-int jobTokensRunning = 0;
-int jobTokensFree = 0;
/*-
*-----------------------------------------------------------------------
* Job_TokenReturn --
@@ -3613,8 +2806,8 @@ Job_TokenReturn(void)
jobTokensRunning--;
if (jobTokensRunning < 0)
Punt("token botch");
- if (jobTokensRunning)
- jobTokensFree++;
+ if (jobTokensRunning || JOB_TOKENS[aborting] != '+')
+ JobTokenAdd();
}
/*-
@@ -3637,62 +2830,51 @@ Job_TokenReturn(void)
Boolean
Job_TokenWithdraw(void)
{
- char tok;
+ char tok, tok1;
int count;
- wantToken = FALSE;
+ wantToken = 0;
+ if (DEBUG(JOB))
+ fprintf(debug_file, "Job_TokenWithdraw(%d): aborting %d, running %d\n",
+ getpid(), aborting, jobTokensRunning);
- if (aborting)
- return FALSE;
+ if (aborting || (jobTokensRunning >= maxJobs))
+ return FALSE;
- if (jobTokensRunning == 0) {
- if (DEBUG(JOB))
- printf("first one's free\n");
- jobTokensRunning++;
- return TRUE;
- }
- if (jobTokensFree > 0) {
- jobTokensFree--;
- jobTokensRunning++;
- return TRUE;
- }
- count = read(job_pipe[0], &tok, 1);
+ count = read(tokenWaitJob.inPipe, &tok, 1);
if (count == 0)
Fatal("eof on job pipe!");
- else if (count < 0) {
+ if (count < 0 && jobTokensRunning != 0) {
if (errno != EAGAIN) {
Fatal("job pipe read: %s", strerror(errno));
}
if (DEBUG(JOB))
- printf("blocked for token\n");
- wantToken = TRUE;
+ fprintf(debug_file, "(%d) blocked for token\n", getpid());
+ wantToken = 1;
return FALSE;
}
+
+ if (count == 1 && tok != '+') {
+ /* make being abvorted - remove any other job tokens */
+ if (DEBUG(JOB))
+ fprintf(debug_file, "(%d) aborted by token %c\n", getpid(), tok);
+ while (read(tokenWaitJob.inPipe, &tok1, 1) == 1)
+ continue;
+ /* And put the stopper back */
+ write(tokenWaitJob.outPipe, &tok, 1);
+ Fatal("A failure has been detected in another branch of the parallel make");
+ }
+
+ if (count == 1 && jobTokensRunning == 0)
+ /* We didn't want the token really */
+ write(tokenWaitJob.outPipe, &tok, 1);
+
jobTokensRunning++;
if (DEBUG(JOB))
- printf("withdrew token\n");
+ fprintf(debug_file, "(%d) withdrew token\n", getpid());
return TRUE;
}
-/*-
- *-----------------------------------------------------------------------
- * Job_TokenFlush --
- * Return free tokens to the pool.
- *
- *-----------------------------------------------------------------------
- */
-
-void
-Job_TokenFlush(void)
-{
- if (compatMake) return;
-
- while (jobTokensFree > 0) {
- JobTokenAdd();
- jobTokensFree--;
- }
-}
-
#ifdef USE_SELECT
int
emul_poll(struct pollfd *fd, int nfd, int timeout)
diff --git a/devel/bmake/files/job.h b/devel/bmake/files/job.h
index 4e2f53efd47..92c02a62b2c 100644
--- a/devel/bmake/files/job.h
+++ b/devel/bmake/files/job.h
@@ -1,4 +1,4 @@
-/* $NetBSD: job.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: job.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -76,7 +76,6 @@
/*-
* job.h --
* Definitions pertaining to the running of jobs in parallel mode.
- * Exported from job.c for the use of remote-execution modules.
*/
#ifndef _JOB_H_
#define _JOB_H_
@@ -123,30 +122,18 @@ emul_poll(struct pollfd *fd, int nfd, int timeout);
* commands.
* 4) An FILE* for writing out the commands. This is only
* used before the job is actually started.
- * 5) A union of things used for handling the shell's output. Different
- * parts of the union are used based on the value of the usePipes
- * flag. If it is true, the output is being caught via a pipe and
+ * 5) The output is being caught via a pipe and
* the descriptors of our pipe, an array in which output is line
* buffered and the current position in that buffer are all
- * maintained for each job. If, on the other hand, usePipes is false,
- * the output is routed to a temporary file and all that is kept
- * is the name of the file and the descriptor open to the file.
- * 6) An identifier provided by and for the exclusive use of the
- * Rmt module.
- * 7) A word of flags which determine how the module handles errors,
+ * maintained for each job.
+ * 6) A word of flags which determine how the module handles errors,
* echoing, etc. for the job
*
- * The job "table" is kept as a linked Lst in 'jobs', with the number of
- * active jobs maintained in the 'nJobs' variable. At no time will this
- * exceed the value of 'maxJobs', initialized by the Job_Init function.
- *
* When a job is finished, the Make_Update function is called on each of the
* parents of the node which was just remade. This takes care of the upward
* traversal of the dependency graph.
*/
-#ifndef RMT_WILL_WATCH
struct pollfd;
-#endif
#define JOB_BUFSIZE 1024
typedef struct Job {
@@ -156,7 +143,13 @@ typedef struct Job {
* saved when the job has been run */
FILE *cmdFILE; /* When creating the shell script, this is
* where the commands go */
- int rmtID; /* ID returned from Rmt module */
+ int exit_status; /* from wait4() in signal handler */
+ char job_state; /* status of the job entry */
+#define JOB_ST_FREE 0 /* Job is available */
+#define JOB_ST_SETUP 1 /* Job is allocated but otherwise invalid */
+#define JOB_ST_RUNNING 3 /* Job is running, pid valid */
+#define JOB_ST_FINISHED 4 /* Job is done (ie after SIGCHILD) */
+ char job_suspended;
short flags; /* Flags to control treatment of job */
#define JOB_IGNERR 0x001 /* Ignore non-zero exits */
#define JOB_SILENT 0x002 /* no output */
@@ -164,53 +157,18 @@ typedef struct Job {
* if we can't export it and maxLocal is 0 */
#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing
* commands */
-#define JOB_REMOTE 0x010 /* Job is running remotely */
-#define JOB_FIRST 0x020 /* Job is first job for the node */
-#define JOB_REMIGRATE 0x040 /* Job needs to be remigrated */
-#define JOB_RESTART 0x080 /* Job needs to be completely restarted */
-#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped,
- * for some reason */
-#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job.
- * Used to avoid infinite recursion between
- * JobFinish and JobRestart */
#define JOB_TRACED 0x400 /* we've sent 'set -x' */
- union {
- struct {
- int op_inPipe; /* Input side of pipe associated
- * with job's output channel */
-#ifndef RMT_WILL_WATCH
- struct pollfd *op_inPollfd; /* pollfd associated with inPipe */
-#endif
- int op_outPipe; /* Output side of pipe associated with
- * job's output channel */
- char op_outBuf[JOB_BUFSIZE + 1];
- /* Buffer for storing the output of the
- * job, line by line */
- int op_curPos; /* Current position in op_outBuf */
- } o_pipe; /* data used when catching the output via
- * a pipe */
- struct {
- char of_outFile[sizeof(TMPPAT)+2];
- /* Name of file to which shell output
- * was rerouted */
- int of_outFd; /* Stream open to the output
- * file. Used to funnel all
- * from a single job to one file
- * while still allowing
- * multiple shell invocations */
- } o_file; /* Data used when catching the output in
- * a temporary file */
- } output; /* Data for tracking a shell's output */
+ int jobPipe[2]; /* Pipe for readind output from job */
+ struct pollfd *inPollfd; /* pollfd associated with inPipe */
+ char outBuf[JOB_BUFSIZE + 1];
+ /* Buffer for storing the output of the
+ * job, line by line */
+ int curPos; /* Current position in op_outBuf */
} Job;
-#define outPipe output.o_pipe.op_outPipe
-#define inPipe output.o_pipe.op_inPipe
-#define inPollfd output.o_pipe.op_inPollfd
-#define outBuf output.o_pipe.op_outBuf
-#define curPos output.o_pipe.op_curPos
-#define outFile output.o_file.of_outFile
-#define outFd output.o_file.of_outFd
+#define inPipe jobPipe[0]
+#define outPipe jobPipe[1]
/*-
@@ -262,6 +220,9 @@ typedef struct Shell {
const char *errCheck; /* string to turn error checking on */
const char *ignErr; /* string to turn off error checking */
const char *errOut; /* string to use for testing exit code */
+ const char *newline; /* string literal that results in a newline
+ * character when it appears outside of any
+ * 'quote' or "quote" characters */
char commentChar; /* character used by shell for comment lines */
/*
@@ -274,33 +235,18 @@ typedef struct Shell {
extern const char *shellPath;
extern const char *shellName;
-extern int job_pipe[2]; /* token pipe for jobs. */
extern int jobTokensRunning; /* tokens currently "out" */
-extern int jobTokensFree; /* tokens free but not yet released to pipe */
-
-#ifdef REMOTE
-extern char *targFmt; /* Format string for banner that separates
- * output from multiple jobs. Contains a
- * single %s where the name of the node being
- * made should be put. */
-extern GNode *lastNode; /* Last node for which a banner was printed.
- * If Rmt module finds it necessary to print
- * a banner, it should set this to the node
- * for which the banner was printed */
-extern int nJobs; /* Number of jobs running (local and remote) */
-extern int nLocal; /* Number of jobs running locally */
-extern Lst jobs; /* List of active job descriptors */
-extern Lst stoppedJobs; /* List of jobs that are stopped or didn't
- * quite get started */
-#endif
+extern int maxJobs; /* Max jobs we can run */
void Shell_Init(void);
+const char *Shell_GetNewline(void);
void Job_Touch(GNode *, Boolean);
Boolean Job_CheckCommands(GNode *, void (*abortProc )(const char *, ...));
-void Job_CatchChildren(Boolean);
+#define CATCH_BLOCK 1
+void Job_CatchChildren(void);
void Job_CatchOutput(void);
void Job_Make(GNode *);
-void Job_Init(int, int);
+void Job_Init(void);
Boolean Job_Full(void);
Boolean Job_Empty(void);
ReturnStatus Job_ParseShell(char *);
@@ -310,8 +256,8 @@ void Job_Wait(void);
void Job_AbortAll(void);
void JobFlagForMigration(int);
void Job_TokenReturn(void);
-void Job_TokenFlush(void);
Boolean Job_TokenWithdraw(void);
-void Job_ServerStart(int);
+void Job_ServerStart(int, int, int);
+void Job_SetPrefix(void);
#endif /* _JOB_H_ */
diff --git a/devel/bmake/files/lst.h b/devel/bmake/files/lst.h
index 223d159703e..5205294a542 100644
--- a/devel/bmake/files/lst.h
+++ b/devel/bmake/files/lst.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lst.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lst.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -89,8 +89,8 @@
* basic typedef. This is what the Lst_ functions handle
*/
-typedef struct Lst *Lst;
-typedef struct LstNode *LstNode;
+typedef struct List *Lst;
+typedef struct ListNode *LstNode;
typedef ClientData DuplicateProc(ClientData);
typedef void FreeProc(ClientData);
@@ -125,9 +125,9 @@ Boolean Lst_IsEmpty(Lst);
* Functions to modify a list
*/
/* Insert an element before another */
-ReturnStatus Lst_Insert(Lst, LstNode, ClientData);
+ReturnStatus Lst_InsertBefore(Lst, LstNode, ClientData);
/* Insert an element after another */
-ReturnStatus Lst_Append(Lst, LstNode, ClientData);
+ReturnStatus Lst_InsertAfter(Lst, LstNode, ClientData);
/* Place an element at the front of a lst. */
ReturnStatus Lst_AtFront(Lst, ClientData);
/* Place an element at the end of a lst. */
@@ -148,6 +148,8 @@ LstNode Lst_First(Lst);
LstNode Lst_Last(Lst);
/* Return successor to given element */
LstNode Lst_Succ(LstNode);
+/* Return predecessor to given element */
+LstNode Lst_Prev(LstNode);
/* Get datum from LstNode */
ClientData Lst_Datum(LstNode);
@@ -165,13 +167,13 @@ LstNode Lst_FindFrom(Lst, LstNode, ClientData,
*/
LstNode Lst_Member(Lst, ClientData);
/* Apply a function to all elements of a lst */
-void Lst_ForEach(Lst, int (*)(ClientData, ClientData), ClientData);
+int Lst_ForEach(Lst, int (*)(ClientData, ClientData), ClientData);
/*
* Apply a function to all elements of a lst starting from a certain point.
* If the list is circular, the application will wrap around to the
* beginning of the list again.
*/
-void Lst_ForEachFrom(Lst, LstNode, int (*)(ClientData, ClientData),
+int Lst_ForEachFrom(Lst, LstNode, int (*)(ClientData, ClientData),
ClientData);
/*
* these functions are for dealing with a list as a table, of sorts.
diff --git a/devel/bmake/files/lst.lib/Makefile b/devel/bmake/files/lst.lib/Makefile
index eec86e6665b..1f49ba4fd53 100644
--- a/devel/bmake/files/lst.lib/Makefile
+++ b/devel/bmake/files/lst.lib/Makefile
@@ -1,10 +1,10 @@
-# $NetBSD: Makefile,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $NetBSD: Makefile,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $
OBJ=lstAppend.o lstDupl.o lstInit.o lstOpen.o lstAtEnd.o lstEnQueue.o \
lstInsert.o lstAtFront.o lstIsAtEnd.o lstClose.o lstFind.o lstIsEmpty.o \
lstRemove.o lstConcat.o lstFindFrom.o lstLast.o lstReplace.o lstFirst.o \
lstDatum.o lstForEach.o lstMember.o lstSucc.o lstDeQueue.o \
- lstForEachFrom.o lstDestroy.o lstNext.o
+ lstForEachFrom.o lstDestroy.o lstNext.o lstPrev.o
CPPFLAGS=-I${.CURDIR}/..
all: ${OBJ}
diff --git a/devel/bmake/files/lst.lib/lstAppend.c b/devel/bmake/files/lst.lib/lstAppend.c
index f033c14a79a..97b1bbae1b0 100644
--- a/devel/bmake/files/lst.lib/lstAppend.c
+++ b/devel/bmake/files/lst.lib/lstAppend.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstAppend.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstAppend.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAppend.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstAppend.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstAppend.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstAppend.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstAppend.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -54,7 +54,7 @@ __RCSID("$NetBSD: lstAppend.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
/*-
*-----------------------------------------------------------------------
- * Lst_Append --
+ * Lst_InsertAfter --
* Create a new node and add it to the given list after the given node.
*
* Input:
@@ -74,7 +74,7 @@ __RCSID("$NetBSD: lstAppend.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
*-----------------------------------------------------------------------
*/
ReturnStatus
-Lst_Append(Lst l, LstNode ln, ClientData d)
+Lst_InsertAfter(Lst l, LstNode ln, ClientData d)
{
List list;
ListNode lNode;
@@ -89,8 +89,8 @@ Lst_Append(Lst l, LstNode ln, ClientData d)
}
ok:
- list = (List)l;
- lNode = (ListNode)ln;
+ list = l;
+ lNode = ln;
PAlloc (nLNode, ListNode);
nLNode->datum = d;
diff --git a/devel/bmake/files/lst.lib/lstAtEnd.c b/devel/bmake/files/lst.lib/lstAtEnd.c
index 8f870caa64d..cbc926fb01a 100644
--- a/devel/bmake/files/lst.lib/lstAtEnd.c
+++ b/devel/bmake/files/lst.lib/lstAtEnd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstAtEnd.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -75,5 +75,5 @@ Lst_AtEnd(Lst l, ClientData d)
LstNode end;
end = Lst_Last(l);
- return (Lst_Append(l, end, d));
+ return (Lst_InsertAfter(l, end, d));
}
diff --git a/devel/bmake/files/lst.lib/lstAtFront.c b/devel/bmake/files/lst.lib/lstAtFront.c
index 58abff7ad40..3bf37a9c07f 100644
--- a/devel/bmake/files/lst.lib/lstAtFront.c
+++ b/devel/bmake/files/lst.lib/lstAtFront.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstAtFront.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstAtFront.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAtFront.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstAtFront.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstAtFront.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstAtFront.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstAtFront.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -72,5 +72,5 @@ Lst_AtFront(Lst l, ClientData d)
LstNode front;
front = Lst_First(l);
- return (Lst_Insert(l, front, d));
+ return (Lst_InsertBefore(l, front, d));
}
diff --git a/devel/bmake/files/lst.lib/lstClose.c b/devel/bmake/files/lst.lib/lstClose.c
index 2e58dfa234d..42f852612b5 100644
--- a/devel/bmake/files/lst.lib/lstClose.c
+++ b/devel/bmake/files/lst.lib/lstClose.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstClose.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstClose.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstClose.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstClose.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstClose.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstClose.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstClose.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -76,7 +76,7 @@ __RCSID("$NetBSD: lstClose.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
void
Lst_Close(Lst l)
{
- List list = (List) l;
+ List list = l;
if (LstValid(l) == TRUE) {
list->isOpen = FALSE;
diff --git a/devel/bmake/files/lst.lib/lstConcat.c b/devel/bmake/files/lst.lib/lstConcat.c
index 1561148f64c..6c15e4704c5 100644
--- a/devel/bmake/files/lst.lib/lstConcat.c
+++ b/devel/bmake/files/lst.lib/lstConcat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstConcat.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstConcat.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstConcat.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstConcat.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstConcat.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstConcat.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstConcat.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -82,8 +82,8 @@ Lst_Concat(Lst l1, Lst l2, int flags)
ListNode nln; /* new LstNode */
ListNode last; /* the last element in the list. Keeps
* bookkeeping until the end */
- List list1 = (List)l1;
- List list2 = (List)l2;
+ List list1 = l1;
+ List list2 = l2;
if (!LstValid (l1) || !LstValid (l2)) {
return (FAILURE);
diff --git a/devel/bmake/files/lst.lib/lstDatum.c b/devel/bmake/files/lst.lib/lstDatum.c
index 697766788f5..06d841a11ca 100644
--- a/devel/bmake/files/lst.lib/lstDatum.c
+++ b/devel/bmake/files/lst.lib/lstDatum.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstDatum.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstDatum.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDatum.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstDatum.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstDatum.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstDatum.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstDatum.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -69,7 +69,7 @@ ClientData
Lst_Datum(LstNode ln)
{
if (ln != NILLNODE) {
- return (((ListNode)ln)->datum);
+ return ((ln)->datum);
} else {
return ((ClientData) NIL);
}
diff --git a/devel/bmake/files/lst.lib/lstDeQueue.c b/devel/bmake/files/lst.lib/lstDeQueue.c
index e506806ef21..92bb4149cbe 100644
--- a/devel/bmake/files/lst.lib/lstDeQueue.c
+++ b/devel/bmake/files/lst.lib/lstDeQueue.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstDeQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstDeQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDeQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstDeQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstDeQueue.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstDeQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstDeQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -72,13 +72,13 @@ Lst_DeQueue(Lst l)
ClientData rd;
ListNode tln;
- tln = (ListNode) Lst_First(l);
+ tln = Lst_First(l);
if (tln == NilListNode) {
return ((ClientData) NIL);
}
rd = tln->datum;
- if (Lst_Remove(l, (LstNode)tln) == FAILURE) {
+ if (Lst_Remove(l, tln) == FAILURE) {
return ((ClientData) NIL);
} else {
return (rd);
diff --git a/devel/bmake/files/lst.lib/lstDestroy.c b/devel/bmake/files/lst.lib/lstDestroy.c
index 1152a9fcc83..67d6563e06f 100644
--- a/devel/bmake/files/lst.lib/lstDestroy.c
+++ b/devel/bmake/files/lst.lib/lstDestroy.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstDestroy.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstDestroy.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDestroy.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstDestroy.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstDestroy.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstDestroy.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstDestroy.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -72,7 +72,7 @@ Lst_Destroy(Lst l, FreeProc *freeProc)
{
ListNode ln;
ListNode tln = NilListNode;
- List list = (List)l;
+ List list = l;
if (l == NILLST || ! l) {
/*
diff --git a/devel/bmake/files/lst.lib/lstDupl.c b/devel/bmake/files/lst.lib/lstDupl.c
index 14a5dd85097..a4a65f34924 100644
--- a/devel/bmake/files/lst.lib/lstDupl.c
+++ b/devel/bmake/files/lst.lib/lstDupl.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstDupl.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstDupl.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDupl.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstDupl.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstDupl.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstDupl.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstDupl.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -75,7 +75,7 @@ Lst_Duplicate(Lst l, DuplicateProc *copyProc)
{
Lst nl;
ListNode ln;
- List list = (List)l;
+ List list = l;
if (!LstValid (l)) {
return (NILLST);
diff --git a/devel/bmake/files/lst.lib/lstEnQueue.c b/devel/bmake/files/lst.lib/lstEnQueue.c
index 0ecf5b368f0..6832b79ac20 100644
--- a/devel/bmake/files/lst.lib/lstEnQueue.c
+++ b/devel/bmake/files/lst.lib/lstEnQueue.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstEnQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstEnQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstEnQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstEnQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstEnQueue.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstEnQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstEnQueue.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -58,7 +58,7 @@ __RCSID("$NetBSD: lstEnQueue.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
* Add the datum to the tail of the given list.
*
* Results:
- * SUCCESS or FAILURE as returned by Lst_Append.
+ * SUCCESS or FAILURE as returned by Lst_InsertAfter.
*
* Side Effects:
* the lastPtr field is altered all the time and the firstPtr field
@@ -73,6 +73,6 @@ Lst_EnQueue(Lst l, ClientData d)
return (FAILURE);
}
- return (Lst_Append(l, Lst_Last(l), d));
+ return (Lst_InsertAfter(l, Lst_Last(l), d));
}
diff --git a/devel/bmake/files/lst.lib/lstFindFrom.c b/devel/bmake/files/lst.lib/lstFindFrom.c
index c0fe531e98e..271f310ca67 100644
--- a/devel/bmake/files/lst.lib/lstFindFrom.c
+++ b/devel/bmake/files/lst.lib/lstFindFrom.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstFindFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstFindFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstFindFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstFindFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstFindFrom.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstFindFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstFindFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -78,7 +78,7 @@ Lst_FindFrom(Lst l, LstNode ln, ClientData d,
return (NILLNODE);
}
- tln = (ListNode)ln;
+ tln = ln;
do {
if ((*cProc) (tln->datum, d) == 0) {
@@ -87,10 +87,10 @@ Lst_FindFrom(Lst l, LstNode ln, ClientData d,
} else {
tln = tln->nextPtr;
}
- } while (tln != (ListNode)ln && tln != NilListNode);
+ } while (tln != ln && tln != NilListNode);
if (found) {
- return ((LstNode)tln);
+ return (tln);
} else {
return (NILLNODE);
}
diff --git a/devel/bmake/files/lst.lib/lstFirst.c b/devel/bmake/files/lst.lib/lstFirst.c
index 14d1a59e535..4539f8b22f8 100644
--- a/devel/bmake/files/lst.lib/lstFirst.c
+++ b/devel/bmake/files/lst.lib/lstFirst.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstFirst.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstFirst.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstFirst.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstFirst.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstFirst.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstFirst.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstFirst.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -71,7 +71,7 @@ Lst_First(Lst l)
if (!LstValid (l) || LstIsEmpty (l)) {
return (NILLNODE);
} else {
- return ((LstNode)((List)l)->firstPtr);
+ return (l->firstPtr);
}
}
diff --git a/devel/bmake/files/lst.lib/lstForEach.c b/devel/bmake/files/lst.lib/lstForEach.c
index 92be4a7388c..cca3dd80f5d 100644
--- a/devel/bmake/files/lst.lib/lstForEach.c
+++ b/devel/bmake/files/lst.lib/lstForEach.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstForEach.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstForEach.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstForEach.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstForEach.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstForEach.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstForEach.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstForEach.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -68,9 +68,9 @@ __RCSID("$NetBSD: lstForEach.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
*-----------------------------------------------------------------------
*/
/*VARARGS2*/
-void
+int
Lst_ForEach(Lst l, int (*proc)(ClientData, ClientData), ClientData d)
{
- Lst_ForEachFrom(l, Lst_First(l), proc, d);
+ return Lst_ForEachFrom(l, Lst_First(l), proc, d);
}
diff --git a/devel/bmake/files/lst.lib/lstForEachFrom.c b/devel/bmake/files/lst.lib/lstForEachFrom.c
index 59fba8b53ca..c65a60043a3 100644
--- a/devel/bmake/files/lst.lib/lstForEachFrom.c
+++ b/devel/bmake/files/lst.lib/lstForEachFrom.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstForEachFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstForEachFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstForEachFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstForEachFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstForEachFrom.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstForEachFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstForEachFrom.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -69,18 +69,18 @@ __RCSID("$NetBSD: lstForEachFrom.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
*-----------------------------------------------------------------------
*/
/*VARARGS2*/
-void
+int
Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(ClientData, ClientData),
ClientData d)
{
- ListNode tln = (ListNode)ln;
- List list = (List)l;
+ ListNode tln = ln;
+ List list = l;
ListNode next;
Boolean done;
int result;
if (!LstValid (list) || LstIsEmpty (list)) {
- return;
+ return 0;
}
do {
@@ -120,5 +120,6 @@ Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(ClientData, ClientData),
tln = next;
} while (!result && !LstIsEmpty(list) && !done);
+ return result;
}
diff --git a/devel/bmake/files/lst.lib/lstInit.c b/devel/bmake/files/lst.lib/lstInit.c
index d63642a35b4..a82d127cca8 100644
--- a/devel/bmake/files/lst.lib/lstInit.c
+++ b/devel/bmake/files/lst.lib/lstInit.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstInit.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstInit.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstInit.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstInit.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstInit.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstInit.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstInit.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -81,5 +81,5 @@ Lst_Init(Boolean circ)
nList->isCirc = circ;
nList->atEnd = Unknown;
- return ((Lst)nList);
+ return (nList);
}
diff --git a/devel/bmake/files/lst.lib/lstInsert.c b/devel/bmake/files/lst.lib/lstInsert.c
index a63bbb4de70..c60022efdfa 100644
--- a/devel/bmake/files/lst.lib/lstInsert.c
+++ b/devel/bmake/files/lst.lib/lstInsert.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstInsert.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstInsert.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstInsert.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstInsert.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstInsert.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstInsert.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstInsert.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -54,7 +54,7 @@ __RCSID("$NetBSD: lstInsert.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
/*-
*-----------------------------------------------------------------------
- * Lst_Insert --
+ * Lst_InsertBefore --
* Insert a new node with the given piece of data before the given
* node in the given list.
*
@@ -73,11 +73,11 @@ __RCSID("$NetBSD: lstInsert.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
*-----------------------------------------------------------------------
*/
ReturnStatus
-Lst_Insert(Lst l, LstNode ln, ClientData d)
+Lst_InsertBefore(Lst l, LstNode ln, ClientData d)
{
ListNode nLNode; /* new lnode for d */
- ListNode lNode = (ListNode)ln;
- List list = (List)l;
+ ListNode lNode = ln;
+ List list = l;
/*
diff --git a/devel/bmake/files/lst.lib/lstInt.h b/devel/bmake/files/lst.lib/lstInt.h
index 69ac2e1b3db..a6ee812e403 100644
--- a/devel/bmake/files/lst.lib/lstInt.h
+++ b/devel/bmake/files/lst.lib/lstInt.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lstInt.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstInt.h,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -47,7 +47,7 @@
typedef struct ListNode {
struct ListNode *prevPtr; /* previous element in list */
struct ListNode *nextPtr; /* next in list */
- short useCount:8, /* Count of functions using the node.
+ unsigned int useCount:8, /* Count of functions using the node.
* node may not be deleted until count
* goes to 0 */
flags:8; /* Node status flags */
@@ -64,7 +64,7 @@ typedef enum {
Head, Middle, Tail, Unknown
} Where;
-typedef struct {
+typedef struct List {
ListNode firstPtr; /* first node in list */
ListNode lastPtr; /* last node in list */
Boolean isCirc; /* true if the list should be considered
@@ -86,24 +86,24 @@ typedef struct {
* PAlloc (var, ptype) --
* Allocate a pointer-typedef structure 'ptype' into the variable 'var'
*/
-#define PAlloc(var,ptype) var = (ptype) emalloc(sizeof (*var))
+#define PAlloc(var,ptype) var = (ptype) emalloc(sizeof *(var))
/*
* LstValid (l) --
* Return TRUE if the list l is valid
*/
-#define LstValid(l) (((Lst)l == NILLST) ? FALSE : TRUE)
+#define LstValid(l) ((Lst)(l) != NILLST)
/*
* LstNodeValid (ln, l) --
* Return TRUE if the LstNode ln is valid with respect to l
*/
-#define LstNodeValid(ln, l) ((((LstNode)ln) == NILLNODE) ? FALSE : TRUE)
+#define LstNodeValid(ln, l) ((ln) != NILLNODE)
/*
* LstIsEmpty (l) --
* TRUE if the list l is empty.
*/
-#define LstIsEmpty(l) (((List)l)->firstPtr == NilListNode)
+#define LstIsEmpty(l) (((List)(l))->firstPtr == NilListNode)
#endif /* _LSTINT_H_ */
diff --git a/devel/bmake/files/lst.lib/lstIsAtEnd.c b/devel/bmake/files/lst.lib/lstIsAtEnd.c
index 385fd82f152..fb09223c3ce 100644
--- a/devel/bmake/files/lst.lib/lstIsAtEnd.c
+++ b/devel/bmake/files/lst.lib/lstIsAtEnd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstIsAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstIsAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstIsAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstIsAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstIsAtEnd.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstIsAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstIsAtEnd.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -79,7 +79,7 @@ __RCSID("$NetBSD: lstIsAtEnd.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
Boolean
Lst_IsAtEnd(Lst l)
{
- List list = (List) l;
+ List list = l;
return (!LstValid (l) || !list->isOpen ||
(list->atEnd == Head) || (list->atEnd == Tail));
diff --git a/devel/bmake/files/lst.lib/lstLast.c b/devel/bmake/files/lst.lib/lstLast.c
index fc88aa52851..47cc372cebb 100644
--- a/devel/bmake/files/lst.lib/lstLast.c
+++ b/devel/bmake/files/lst.lib/lstLast.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstLast.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstLast.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstLast.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstLast.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstLast.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstLast.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstLast.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -71,7 +71,7 @@ Lst_Last(Lst l)
if (!LstValid(l) || LstIsEmpty (l)) {
return (NILLNODE);
} else {
- return ((LstNode)((List)l)->lastPtr);
+ return (l->lastPtr);
}
}
diff --git a/devel/bmake/files/lst.lib/lstMember.c b/devel/bmake/files/lst.lib/lstMember.c
index 8356e3b4c21..a023ac97248 100644
--- a/devel/bmake/files/lst.lib/lstMember.c
+++ b/devel/bmake/files/lst.lib/lstMember.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstMember.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstMember.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstMember.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstMember.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstMember.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstMember.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstMember.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -55,7 +55,7 @@ __RCSID("$NetBSD: lstMember.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
LstNode
Lst_Member(Lst l, ClientData d)
{
- List list = (List) l;
+ List list = l;
ListNode lNode;
lNode = list->firstPtr;
@@ -65,7 +65,7 @@ Lst_Member(Lst l, ClientData d)
do {
if (lNode->datum == d) {
- return (LstNode)lNode;
+ return lNode;
}
lNode = lNode->nextPtr;
} while (lNode != NilListNode && lNode != list->firstPtr);
diff --git a/devel/bmake/files/lst.lib/lstNext.c b/devel/bmake/files/lst.lib/lstNext.c
index e20ade15ab4..f28e467c0c1 100644
--- a/devel/bmake/files/lst.lib/lstNext.c
+++ b/devel/bmake/files/lst.lib/lstNext.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstNext.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstNext.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstNext.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstNext.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstNext.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstNext.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstNext.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -76,7 +76,7 @@ LstNode
Lst_Next(Lst l)
{
ListNode tln;
- List list = (List)l;
+ List list = l;
if ((LstValid (l) == FALSE) ||
(list->isOpen == FALSE)) {
@@ -115,6 +115,6 @@ Lst_Next(Lst l)
}
}
- return ((LstNode)tln);
+ return (tln);
}
diff --git a/devel/bmake/files/lst.lib/lstOpen.c b/devel/bmake/files/lst.lib/lstOpen.c
index ee0b3e390e8..9208b35ac3b 100644
--- a/devel/bmake/files/lst.lib/lstOpen.c
+++ b/devel/bmake/files/lst.lib/lstOpen.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstOpen.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstOpen.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstOpen.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstOpen.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstOpen.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstOpen.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstOpen.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -78,9 +78,9 @@ Lst_Open(Lst l)
if (LstValid (l) == FALSE) {
return (FAILURE);
}
- ((List) l)->isOpen = TRUE;
- ((List) l)->atEnd = LstIsEmpty (l) ? Head : Unknown;
- ((List) l)->curPtr = NilListNode;
+ (l)->isOpen = TRUE;
+ (l)->atEnd = LstIsEmpty (l) ? Head : Unknown;
+ (l)->curPtr = NilListNode;
return (SUCCESS);
}
diff --git a/devel/bmake/files/lst.lib/lstPrev.c b/devel/bmake/files/lst.lib/lstPrev.c
new file mode 100644
index 00000000000..7ea030338ec
--- /dev/null
+++ b/devel/bmake/files/lst.lib/lstPrev.c
@@ -0,0 +1,79 @@
+/* $NetBSD: lstPrev.c,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $ */
+
+/*
+ * Copyright (c) 1988, 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam de Boor.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MAKE_NATIVE
+static char rcsid[] = "$NetBSD: lstPrev.c,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $";
+#else
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: lstPrev.c,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $");
+#endif
+#endif /* not lint */
+#endif
+
+/*-
+ * LstPrev.c --
+ * return the predecessor to a given node
+ */
+
+#include "lstInt.h"
+
+/*-
+ *-----------------------------------------------------------------------
+ * Lst_Prev --
+ * Return the predecessor to the given node on its list.
+ *
+ * Results:
+ * The predecessor of the node, if it exists (note that on a circular
+ * list, if the node is the only one in the list, it is its own
+ * predecessor).
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------
+ */
+LstNode
+Lst_Prev(LstNode ln)
+{
+ if (ln == NILLNODE) {
+ return (NILLNODE);
+ } else {
+ return (ln->prevPtr);
+ }
+}
+
diff --git a/devel/bmake/files/lst.lib/lstRemove.c b/devel/bmake/files/lst.lib/lstRemove.c
index 8a0a14cb811..37c949a627a 100644
--- a/devel/bmake/files/lst.lib/lstRemove.c
+++ b/devel/bmake/files/lst.lib/lstRemove.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstRemove.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstRemove.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstRemove.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstRemove.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstRemove.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstRemove.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -70,8 +70,8 @@ __RCSID("$NetBSD: lstRemove.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
ReturnStatus
Lst_Remove(Lst l, LstNode ln)
{
- List list = (List) l;
- ListNode lNode = (ListNode) ln;
+ List list = l;
+ ListNode lNode = ln;
if (!LstValid (l) ||
!LstNodeValid (ln, l)) {
diff --git a/devel/bmake/files/lst.lib/lstReplace.c b/devel/bmake/files/lst.lib/lstReplace.c
index a728145d03f..c7aa48aad5c 100644
--- a/devel/bmake/files/lst.lib/lstReplace.c
+++ b/devel/bmake/files/lst.lib/lstReplace.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstReplace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstReplace.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstReplace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstReplace.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstReplace.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstReplace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstReplace.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -71,7 +71,7 @@ Lst_Replace(LstNode ln, ClientData d)
if (ln == NILLNODE) {
return (FAILURE);
} else {
- ((ListNode) ln)->datum = d;
+ (ln)->datum = d;
return (SUCCESS);
}
}
diff --git a/devel/bmake/files/lst.lib/lstSucc.c b/devel/bmake/files/lst.lib/lstSucc.c
index 6d668a0f42b..497bac25967 100644
--- a/devel/bmake/files/lst.lib/lstSucc.c
+++ b/devel/bmake/files/lst.lib/lstSucc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstSucc.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: lstSucc.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstSucc.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: lstSucc.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstSucc.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: lstSucc.c,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -73,7 +73,7 @@ Lst_Succ(LstNode ln)
if (ln == NILLNODE) {
return (NILLNODE);
} else {
- return ((LstNode) ((ListNode) ln)->nextPtr);
+ return (ln->nextPtr);
}
}
diff --git a/devel/bmake/files/lst.lib/makefile.boot.in b/devel/bmake/files/lst.lib/makefile.boot.in
index 8d55f920f00..a87e5c59f3f 100644
--- a/devel/bmake/files/lst.lib/makefile.boot.in
+++ b/devel/bmake/files/lst.lib/makefile.boot.in
@@ -1,5 +1,5 @@
# RCSid:
-# $Id: makefile.boot.in,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $Id: makefile.boot.in,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $
srcdir=@srcdir@
VPATH=.:$(srcdir)
@@ -8,9 +8,9 @@ OBJ=lstAppend.o lstDupl.o lstInit.o lstOpen.o lstAtEnd.o lstEnQueue.o \
lstInsert.o lstAtFront.o lstIsAtEnd.o lstClose.o lstFind.o lstIsEmpty.o \
lstRemove.o lstConcat.o lstFindFrom.o lstLast.o lstReplace.o lstFirst.o \
lstDatum.o lstForEach.o lstMember.o lstSucc.o lstDeQueue.o \
- lstForEachFrom.o lstDestroy.o lstNext.o
+ lstForEachFrom.o lstDestroy.o lstNext.o lstPrev.o
-CFLAGS=-I..
+CFLAGS=@CFLAGS@ -I..
all: ${OBJ}
depend:
diff --git a/devel/bmake/files/main.c b/devel/bmake/files/main.c
index e270d435443..fdf171b23b2 100644
--- a/devel/bmake/files/main.c
+++ b/devel/bmake/files/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: main.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,7 +69,7 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: main.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: main.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
@@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\n\
#if 0
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: main.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: main.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -156,7 +156,7 @@ static Lst makefiles; /* ordered list of makefiles to read */
static Boolean printVars; /* print value of one or more vars */
static Lst variables; /* list of variables to print */
int maxJobs; /* -j argument */
-static int maxLocal; /* -L argument */
+static int maxJobTokens; /* -j argument */
Boolean compatMake; /* -B argument */
int debug; /* -d argument */
Boolean noExecute; /* -n flag */
@@ -164,14 +164,15 @@ Boolean noRecursiveExecute; /* -N flag */
Boolean keepgoing; /* -k flag */
Boolean queryFlag; /* -q flag */
Boolean touchFlag; /* -t flag */
-Boolean usePipes; /* !-P flag */
Boolean ignoreErrors; /* -i flag */
Boolean beSilent; /* -s flag */
Boolean oldVars; /* variable substitution style */
Boolean checkEnvFirst; /* -e flag */
Boolean parseWarnFatal; /* -W flag */
Boolean jobServer; /* -J flag */
+static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
Boolean varNoExportEnv; /* -X flag */
+Boolean doing_depend; /* Set while reading .depend */
static Boolean jobsRunning; /* TRUE if the jobs might be running */
static const char * tracefile;
#ifndef NO_CHECK_MAKE_CHDIR
@@ -198,6 +199,116 @@ Boolean forceJobs = FALSE;
extern Lst parseIncPath;
+static void
+parse_debug_options(const char *argvalue)
+{
+ const char *modules;
+ const char *mode;
+ char *fname;
+ int len;
+
+ for (modules = argvalue; *modules; ++modules) {
+ switch (*modules) {
+ case 'A':
+ debug = ~0;
+ break;
+ case 'a':
+ debug |= DEBUG_ARCH;
+ break;
+ case 'c':
+ debug |= DEBUG_COND;
+ break;
+ case 'd':
+ debug |= DEBUG_DIR;
+ break;
+ case 'e':
+ debug |= DEBUG_ERROR;
+ break;
+ case 'f':
+ debug |= DEBUG_FOR;
+ break;
+ case 'g':
+ if (modules[1] == '1') {
+ debug |= DEBUG_GRAPH1;
+ ++modules;
+ }
+ else if (modules[1] == '2') {
+ debug |= DEBUG_GRAPH2;
+ ++modules;
+ }
+ else if (modules[1] == '3') {
+ debug |= DEBUG_GRAPH3;
+ ++modules;
+ }
+ break;
+ case 'j':
+ debug |= DEBUG_JOB;
+ break;
+ case 'l':
+ debug |= DEBUG_LOUD;
+ break;
+ case 'm':
+ debug |= DEBUG_MAKE;
+ break;
+ case 'n':
+ debug |= DEBUG_SCRIPT;
+ break;
+ case 'p':
+ debug |= DEBUG_PARSE;
+ break;
+ case 's':
+ debug |= DEBUG_SUFF;
+ break;
+ case 't':
+ debug |= DEBUG_TARG;
+ break;
+ case 'v':
+ debug |= DEBUG_VAR;
+ break;
+ case 'x':
+ debug |= DEBUG_SHELL;
+ break;
+ case 'F':
+ if (debug_file != stdout && debug_file != stderr)
+ fclose(debug_file);
+ if (*++modules == '+')
+ mode = "a";
+ else {
+ if (!strcmp(modules, "stdout")) {
+ debug_file = stdout;
+ return;
+ }
+ if (!strcmp(modules, "stderr")) {
+ debug_file = stderr;
+ return;
+ }
+ mode = "w";
+ }
+ len = strlen(modules);
+ fname = malloc(len + 20);
+ memcpy(fname, modules, len + 1);
+ /* Let the filename be modified by the pid */
+ if (strcmp(fname + len - 3, ".%d") == 0)
+ snprintf(fname + len - 2, 20, "%d", getpid());
+ debug_file = fopen(fname, mode);
+ if (!debug_file) {
+ fprintf(stderr, "Cannot open debug file %s\n",
+ fname);
+ usage();
+ }
+ free(fname);
+ /* Have this non-buffered */
+ setbuf(debug_file, NULL);
+ return;
+ default:
+ (void)fprintf(stderr,
+ "%s: illegal argument to d option -- %c\n",
+ progname, *modules);
+ usage();
+ }
+ }
+}
+
/*-
* MainParseArgs --
* Parse a given argument vector. Called from main() and from
@@ -216,7 +327,7 @@ static void
MainParseArgs(int argc, char **argv)
{
char *p;
- int c;
+ int c = '?';
int arginc;
char *argvalue;
const char *getopt_def;
@@ -224,13 +335,7 @@ MainParseArgs(int argc, char **argv)
Boolean inOption, dashDash = FALSE;
char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */
-#ifdef REMOTE
-# define OPTFLAGS "BD:I:J:L:NPST:V:WXd:ef:ij:km:nqrst"
-#else
-# define OPTFLAGS "BD:I:J:NPST:V:WXd:ef:ij:km:nqrst"
-#endif
-#undef optarg
-#define optarg argvalue
+#define OPTFLAGS "BD:I:J:NST:V:WXd:ef:ij:km:nqrst"
/* Can't actually use getopt(3) because rescanning is not portable */
getopt_def = OPTFLAGS;
@@ -264,13 +369,8 @@ rearg:
arginc = 1;
argvalue = optscan;
if(*argvalue == '\0') {
- if (argc < 3) {
- (void)fprintf(stderr,
- "%s: option requires "
- "an argument -- %c\n",
- progname, c);
- usage();
- }
+ if (argc < 3)
+ goto noarg;
argvalue = argv[2];
arginc = 2;
}
@@ -287,74 +387,63 @@ rearg:
Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
break;
case 'D':
- Var_Set(optarg, "1", VAR_GLOBAL, 0);
+ if (argvalue == NULL) goto noarg;
+ Var_Set(argvalue, "1", VAR_GLOBAL, 0);
Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
break;
case 'I':
- Parse_AddIncludeDir(optarg);
+ if (argvalue == NULL) goto noarg;
+ Parse_AddIncludeDir(argvalue);
Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
break;
case 'J':
- if (sscanf(optarg, "%d,%d", &job_pipe[0], &job_pipe[1]) != 2) {
- /* backslash to avoid trigraph ??) */
+ if (argvalue == NULL) goto noarg;
+ if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) {
(void)fprintf(stderr,
- "%s: internal error -- J option malformed (%s?\?)\n",
- progname, optarg);
+ "%s: internal error -- J option malformed (%s)\n",
+ progname, argvalue);
usage();
}
- if ((fcntl(job_pipe[0], F_GETFD, 0) < 0) ||
- (fcntl(job_pipe[1], F_GETFD, 0) < 0)) {
+ if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
+ (fcntl(jp_1, F_GETFD, 0) < 0)) {
#if 0
(void)fprintf(stderr,
- "%s: warning -- J descriptors were closed!\n",
+ "%s: ###### warning -- J descriptors were closed!\n",
progname);
+ exit(2);
#endif
- job_pipe[0] = -1;
- job_pipe[1] = -1;
+ jp_0 = -1;
+ jp_1 = -1;
compatMake = TRUE;
} else {
Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
jobServer = TRUE;
}
break;
-#ifdef REMOTE
- case 'L':
- maxLocal = strtol(optarg, &p, 0);
- if (*p != '\0' || maxLocal < 1) {
- (void)fprintf(stderr, "%s: illegal argument to -L -- must be positive integer!\n",
- progname);
- exit(1);
- }
- Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
- break;
-#endif
case 'N':
noExecute = TRUE;
noRecursiveExecute = TRUE;
Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL);
break;
- case 'P':
- usePipes = FALSE;
- Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL);
- break;
case 'S':
keepgoing = FALSE;
Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
break;
case 'T':
- tracefile = estrdup(optarg);
+ if (argvalue == NULL) goto noarg;
+ tracefile = estrdup(argvalue);
Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
break;
case 'V':
+ if (argvalue == NULL) goto noarg;
printVars = TRUE;
- (void)Lst_AtEnd(variables, (ClientData)optarg);
+ (void)Lst_AtEnd(variables, argvalue);
Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
break;
case 'W':
parseWarnFatal = TRUE;
@@ -363,116 +452,60 @@ rearg:
varNoExportEnv = TRUE;
Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL);
break;
- case 'd': {
- char *modules = optarg;
-
- for (; *modules; ++modules)
- switch (*modules) {
- case 'A':
- debug = ~0;
- break;
- case 'a':
- debug |= DEBUG_ARCH;
- break;
- case 'c':
- debug |= DEBUG_COND;
- break;
- case 'd':
- debug |= DEBUG_DIR;
- break;
- case 'e':
- debug |= DEBUG_ERROR;
- break;
- case 'f':
- debug |= DEBUG_FOR;
- break;
- case 'g':
- if (modules[1] == '1') {
- debug |= DEBUG_GRAPH1;
- ++modules;
- }
- else if (modules[1] == '2') {
- debug |= DEBUG_GRAPH2;
- ++modules;
- }
- else if (modules[1] == '3') {
- debug |= DEBUG_GRAPH3;
- ++modules;
- }
- break;
- case 'j':
- debug |= DEBUG_JOB;
- break;
- case 'm':
- debug |= DEBUG_MAKE;
- break;
- case 'n':
- debug |= DEBUG_SCRIPT;
- break;
- case 's':
- debug |= DEBUG_SUFF;
- break;
- case 't':
- debug |= DEBUG_TARG;
- break;
- case 'v':
- debug |= DEBUG_VAR;
- break;
- case 'x':
- debug |= DEBUG_SHELL;
- break;
- default:
- (void)fprintf(stderr,
- "%s: illegal argument to d option -- %c\n",
- progname, *modules);
- usage();
- }
- Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ case 'd':
+ if (argvalue == NULL) goto noarg;
+ /* If '-d-opts' don't pass to children */
+ if (argvalue[0] == '-')
+ argvalue++;
+ else {
+ Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
+ }
+ parse_debug_options(argvalue);
break;
- }
case 'e':
checkEnvFirst = TRUE;
Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
break;
case 'f':
- (void)Lst_AtEnd(makefiles, (ClientData)optarg);
+ if (argvalue == NULL) goto noarg;
+ (void)Lst_AtEnd(makefiles, argvalue);
break;
case 'i':
ignoreErrors = TRUE;
Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
break;
case 'j':
+ if (argvalue == NULL) goto noarg;
forceJobs = TRUE;
- maxJobs = strtol(optarg, &p, 0);
+ maxJobs = strtol(argvalue, &p, 0);
if (*p != '\0' || maxJobs < 1) {
(void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n",
progname);
exit(1);
}
-#ifndef REMOTE
- maxLocal = maxJobs;
-#endif
Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
+ maxJobTokens = maxJobs;
break;
case 'k':
keepgoing = TRUE;
Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
break;
case 'm':
+ if (argvalue == NULL) goto noarg;
/* look for magic parent directory search string */
- if (strncmp(".../", optarg, 4) == 0) {
- if (!Dir_FindHereOrAbove(curdir, optarg+4,
+ if (strncmp(".../", argvalue, 4) == 0) {
+ if (!Dir_FindHereOrAbove(curdir, argvalue+4,
found_path, sizeof(found_path)))
break; /* nothing doing */
(void)Dir_AddDir(sysIncPath, found_path);
} else {
- (void)Dir_AddDir(sysIncPath, optarg);
+ (void)Dir_AddDir(sysIncPath, argvalue);
}
Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
+ Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
break;
case 'n':
noExecute = TRUE;
@@ -525,8 +558,14 @@ rearg:
Punt("illegal (null) argument.");
if (*argv[1] == '-' && !dashDash)
goto rearg;
- (void)Lst_AtEnd(create, (ClientData)estrdup(argv[1]));
+ (void)Lst_AtEnd(create, estrdup(argv[1]));
}
+
+ return;
+noarg:
+ (void)fprintf(stderr, "%s: option requires an argument -- %c\n",
+ progname, c);
+ usage();
}
/*-
@@ -629,6 +668,18 @@ Main_SetObjdir(const char *path)
return rc;
}
+/*-
+ * ReadAllMakefiles --
+ * wrapper around ReadMakefile() to read all.
+ *
+ * Results:
+ * TRUE if ok, FALSE on error
+ */
+static int
+ReadAllMakefiles(ClientData p, ClientData q)
+{
+ return (ReadMakefile(p, q) == 0);
+}
/*-
* main --
@@ -651,7 +702,7 @@ int
main(int argc, char **argv)
{
Lst targs; /* target nodes to create -- passed to Make_Init */
- Boolean outOfDate = TRUE; /* FALSE if all targets up to date */
+ Boolean outOfDate = FALSE; /* FALSE if all targets up to date */
struct stat sb, sa;
char *p1, *path, *pwd;
char mdpath[MAXPATHLEN];
@@ -668,6 +719,12 @@ main(int argc, char **argv)
static char defsyspath[] = _PATH_DEFSYSPATH;
char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */
struct timeval rightnow; /* to initialize random seed */
+#ifdef MAKE_NATIVE
+ struct utsname utsname;
+#endif
+
+ /* default to writing debug to stdout */
+ debug_file = stdout;
/*
* Set the seed to produce a different random sequences
@@ -739,8 +796,6 @@ main(int argc, char **argv)
*/
if (!machine) {
#ifdef MAKE_NATIVE
- struct utsname utsname;
-
if (uname(&utsname) == -1) {
(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
strerror(errno));
@@ -820,16 +875,11 @@ main(int argc, char **argv)
queryFlag = FALSE; /* This is not just a check-run */
noBuiltins = FALSE; /* Read the built-in rules */
touchFlag = FALSE; /* Actually update targets */
- usePipes = TRUE; /* Catch child output in pipes */
debug = 0; /* No debug verbosity, please. */
jobsRunning = FALSE;
- maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */
-#ifdef REMOTE
- maxJobs = DEFMAXJOBS; /* Set default max concurrency */
-#else
- maxJobs = maxLocal;
-#endif
+ maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */
+ maxJobTokens = maxJobs;
compatMake = FALSE; /* No compat mode */
@@ -854,6 +904,19 @@ main(int argc, char **argv)
Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0);
/*
+ * Set some other useful macros
+ */
+ {
+ char tmp[64];
+
+ snprintf(tmp, sizeof(tmp), "%u", getpid());
+ Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0);
+ snprintf(tmp, sizeof(tmp), "%u", getppid());
+ Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0);
+ }
+ Job_SetPrefix();
+
+ /*
* First snag any flags out of the MAKE environment variable.
* (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
* in a different format).
@@ -914,7 +977,7 @@ main(int argc, char **argv)
if (syspath == NULL || *syspath == '\0')
syspath = defsyspath;
else
- syspath = strdup(syspath);
+ syspath = estrdup(syspath);
for (start = syspath; *start != '\0'; start = cp) {
for (cp = start; *cp != '\0' && *cp != ':'; cp++)
@@ -950,8 +1013,8 @@ main(int argc, char **argv)
if (Lst_IsEmpty(sysMkPath))
Fatal("%s: no system rules (%s).", progname,
_PATH_DEFSYSMK);
- ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile);
- if (ln != NILLNODE)
+ ln = Lst_Find(sysMkPath, NULL, ReadMakefile);
+ if (ln == NILLNODE)
Fatal("%s: cannot open %s.", progname,
(char *)Lst_Datum(ln));
}
@@ -959,24 +1022,29 @@ main(int argc, char **argv)
if (!Lst_IsEmpty(makefiles)) {
LstNode ln;
- ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);
+ ln = Lst_Find(makefiles, NULL, ReadAllMakefiles);
if (ln != NILLNODE)
Fatal("%s: cannot open %s.", progname,
(char *)Lst_Datum(ln));
- } else if (!ReadMakefile(UNCONST("makefile"), NULL))
+ } else if (ReadMakefile(UNCONST("makefile"), NULL) != 0)
(void)ReadMakefile(UNCONST("Makefile"), NULL);
- (void)ReadMakefile(UNCONST(".depend"), NULL);
+ /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
+ if (!noBuiltins || !printVars) {
+ doing_depend = TRUE;
+ (void)ReadMakefile(UNCONST(".depend"), NULL);
+ doing_depend = FALSE;
+ }
Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
if (p1)
free(p1);
- if (!jobServer && !compatMake)
- Job_ServerStart(maxJobs);
+ if (!compatMake)
+ Job_ServerStart(maxJobTokens, jp_0, jp_1);
if (DEBUG(JOB))
- printf("job_pipe %d %d, maxjobs %d maxlocal %d compat %d\n", job_pipe[0], job_pipe[1], maxJobs,
- maxLocal, compatMake);
+ fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
+ jp_0, jp_1, maxJobs, maxJobTokens, compatMake);
Main_ExportMAKEFLAGS(TRUE); /* initial export */
@@ -1049,40 +1117,40 @@ main(int argc, char **argv)
if (p1)
free(p1);
}
- }
-
- /*
- * Have now read the entire graph and need to make a list of targets
- * to create. If none was given on the command line, we consult the
- * parsing module to find the main target(s) to create.
- */
- if (Lst_IsEmpty(create))
- targs = Parse_MainName();
- else
- targs = Targ_FindList(create, TARG_CREATE);
-
- if (!compatMake && !printVars) {
+ } else {
/*
- * Initialize job module before traversing the graph, now that
- * any .BEGIN and .END targets have been read. This is done
- * only if the -q flag wasn't given (to prevent the .BEGIN from
- * being executed should it exist).
+ * Have now read the entire graph and need to make a list of
+ * targets to create. If none was given on the command line,
+ * we consult the parsing module to find the main target(s)
+ * to create.
*/
- if (!queryFlag) {
- if (maxLocal == -1)
- maxLocal = maxJobs;
- Job_Init(maxJobs, maxLocal);
- jobsRunning = TRUE;
- }
+ if (Lst_IsEmpty(create))
+ targs = Parse_MainName();
+ else
+ targs = Targ_FindList(create, TARG_CREATE);
+
+ if (!compatMake) {
+ /*
+ * Initialize job module before traversing the graph
+ * now that any .BEGIN and .END targets have been read.
+ * This is done only if the -q flag wasn't given
+ * (to prevent the .BEGIN from being executed should
+ * it exist).
+ */
+ if (!queryFlag) {
+ Job_Init();
+ jobsRunning = TRUE;
+ }
- /* Traverse the graph, checking on all the targets */
- outOfDate = Make_Run(targs);
- } else if (!printVars) {
- /*
- * Compat_Init will take care of creating all the targets as
- * well as initializing the module.
- */
- Compat_Run(targs);
+ /* Traverse the graph, checking on all the targets */
+ outOfDate = Make_Run(targs);
+ } else {
+ /*
+ * Compat_Init will take care of creating all the
+ * targets as well as initializing the module.
+ */
+ Compat_Run(targs);
+ }
}
#ifdef CLEANUP
@@ -1107,10 +1175,7 @@ main(int argc, char **argv)
Job_End();
Trace_End();
- if (queryFlag && outOfDate)
- return(1);
- else
- return(0);
+ return outOfDate ? 1 : 0;
}
/*-
@@ -1118,34 +1183,25 @@ main(int argc, char **argv)
* Open and parse the given makefile.
*
* Results:
- * TRUE if ok. FALSE if couldn't open file.
+ * 0 if ok. -1 if couldn't open file.
*
* Side Effects:
* lots
*/
-static Boolean
+static int
ReadMakefile(ClientData p, ClientData q __unused)
{
char *fname = p; /* makefile to read */
- FILE *stream;
+ int fd;
size_t len = MAXPATHLEN;
char *name, *path = emalloc(len);
int setMAKEFILE;
if (!strcmp(fname, "-")) {
- Parse_File("(stdin)", stdin);
+ Parse_File("(stdin)", dup(fileno(stdin)));
Var_Set("MAKEFILE", "", VAR_GLOBAL, 0);
} else {
-#ifdef __INTERIX
- /*
- * XXX Hack from tv:
- * This system has broken filesystem support - can't
- * always distinguish b/w [Mm]akefile.
- */
- setMAKEFILE = FALSE;
-#else
setMAKEFILE = strcmp(fname, ".depend");
-#endif
/* if we've chdir'd, rebuild the path name */
if (strcmp(curdir, objdir) && *fname != '/') {
@@ -1154,7 +1210,8 @@ ReadMakefile(ClientData p, ClientData q __unused)
path = erealloc(path, len = 2 * plen);
(void)snprintf(path, len, "%s/%s", curdir, fname);
- if ((stream = fopen(path, "r")) != NULL) {
+ fd = open(path, O_RDONLY);
+ if (fd != -1) {
fname = path;
goto found;
}
@@ -1164,20 +1221,26 @@ ReadMakefile(ClientData p, ClientData q __unused)
if (len < plen)
path = erealloc(path, len = 2 * plen);
(void)snprintf(path, len, "%s/%s", objdir, fname);
- if ((stream = fopen(path, "r")) != NULL) {
+ fd = open(path, O_RDONLY);
+ if (fd != -1) {
fname = path;
goto found;
}
- } else if ((stream = fopen(fname, "r")) != NULL)
- goto found;
+ } else {
+ fd = open(fname, O_RDONLY);
+ if (fd != -1)
+ goto found;
+ }
/* look in -I and system include directories. */
name = Dir_FindFile(fname, parseIncPath);
if (!name)
name = Dir_FindFile(fname,
Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
- if (!name || !(stream = fopen(name, "r"))) {
+ if (!name || (fd = open(name, O_RDONLY)) == -1) {
+ if (name)
+ free(name);
free(path);
- return(FALSE);
+ return(-1);
}
fname = name;
/*
@@ -1188,11 +1251,10 @@ ReadMakefile(ClientData p, ClientData q __unused)
found:
if (setMAKEFILE)
Var_Set("MAKEFILE", fname, VAR_GLOBAL, 0);
- Parse_File(fname, stream);
- (void)fclose(stream);
+ Parse_File(fname, fd);
}
free(path);
- return(TRUE);
+ return(0);
}
@@ -1278,7 +1340,7 @@ Check_Cwd_av(int ac, char **av, int copy)
n = strlen(av[i]);
cp = &(av[i])[n - 1];
- if (strspn(av[i], "|&;") == n) {
+ if (strspn(av[i], "|&;") == (size_t)n) {
next_cmd = 1;
continue;
} else if (*cp == ';' || *cp == '&' || *cp == '|' || *cp == ')') {
@@ -1364,10 +1426,10 @@ Check_Cwd_Cmd(const char *cmd)
bp = NULL;
}
cp = Check_Cwd_av(ac, av, 1);
- if (bp) {
- free(av);
+ if (bp)
free(bp);
- }
+ if (av)
+ free(av);
return cp;
}
@@ -1400,13 +1462,13 @@ Check_Cwd(const char **argv)
*
* Results:
* A string containing the output of the command, or the empty string
- * If err is not NULL, it contains the reason for the command failure
+ * If errnum is not NULL, it contains the reason for the command failure
*
* Side Effects:
* The string must be freed by the caller.
*/
char *
-Cmd_Exec(const char *cmd, const char **err)
+Cmd_Exec(const char *cmd, const char **errnum)
{
const char *args[4]; /* Args for invoking the shell */
int fds[2]; /* Pipe streams */
@@ -1419,7 +1481,7 @@ Cmd_Exec(const char *cmd, const char **err)
int cc;
- *err = NULL;
+ *errnum = NULL;
if (!shellName)
Shell_Init();
@@ -1435,7 +1497,7 @@ Cmd_Exec(const char *cmd, const char **err)
* Open a pipe for fetching its output
*/
if (pipe(fds) == -1) {
- *err = "Couldn't create pipe for \"%s\"";
+ *errnum = "Couldn't create pipe for \"%s\"";
goto bad;
}
@@ -1457,12 +1519,14 @@ Cmd_Exec(const char *cmd, const char **err)
(void)dup2(fds[1], 1);
(void)close(fds[1]);
+ Var_ExportVars();
+
(void)execv(shellPath, UNCONST(args));
_exit(1);
/*NOTREACHED*/
case -1:
- *err = "Couldn't exec \"%s\"";
+ *errnum = "Couldn't exec \"%s\"";
goto bad;
default:
@@ -1471,7 +1535,7 @@ Cmd_Exec(const char *cmd, const char **err)
*/
(void)close(fds[1]);
- buf = Buf_Init(MAKE_BSIZE);
+ buf = Buf_Init(0);
do {
char result[BUFSIZ];
@@ -1489,17 +1553,17 @@ Cmd_Exec(const char *cmd, const char **err)
/*
* Wait for the process to exit.
*/
- while(((pid = wait(&status)) != cpid) && (pid >= 0))
+ while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0))
continue;
res = (char *)Buf_GetAll(buf, &cc);
Buf_Destroy(buf, FALSE);
if (cc == 0)
- *err = "Couldn't read shell's output for \"%s\"";
+ *errnum = "Couldn't read shell's output for \"%s\"";
if (WAIT_STATUS(status))
- *err = "\"%s\" returned non-zero status";
+ *errnum = "\"%s\" returned non-zero status";
/*
* Null-terminate the result, convert newlines to spaces and
@@ -1573,7 +1637,6 @@ Fatal(const char *fmt, ...)
va_start(ap, fmt);
if (jobsRunning)
Job_Wait();
- Job_TokenFlush();
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
@@ -1656,6 +1719,7 @@ Finish(int errors)
Fatal("%d error%s", errors, errors == 1 ? "" : "s");
}
+#ifndef HAVE_EMALLOC
/*
* emalloc --
* malloc, but die on error.
@@ -1685,6 +1749,20 @@ estrdup(const char *str)
}
/*
+ * estrndup --
+ * strndup, but die on error.
+ */
+char *
+estrndup(const char *str, size_t len)
+{
+ char *p;
+
+ if ((p = strndup(str, len)) == NULL)
+ enomem();
+ return(p);
+}
+
+/*
* erealloc --
* realloc, but die on error.
*/
@@ -1706,6 +1784,7 @@ enomem(void)
(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
exit(2);
}
+#endif
/*
* enunlink --
@@ -1786,16 +1865,20 @@ void
PrintOnError(const char *s)
{
char tmp[64];
-
+ char *cp;
+
if (s)
printf("%s", s);
printf("\n%s: stopped in %s\n", progname, curdir);
strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
sizeof(tmp) - 1);
- s = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
- if (s && *s)
- printf("%s", s);
+ cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+ if (cp) {
+ if (*cp)
+ printf("%s", cp);
+ free(cp);
+ }
}
void
diff --git a/devel/bmake/files/make-conf.h b/devel/bmake/files/make-conf.h
index 5fbb4f15594..6dc0164c376 100644
--- a/devel/bmake/files/make-conf.h
+++ b/devel/bmake/files/make-conf.h
@@ -1,4 +1,4 @@
-/* $NetBSD: make-conf.h,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $ */
+/* $NetBSD: make-conf.h,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -72,10 +72,6 @@
* from: @(#)config.h 8.1 (Berkeley) 6/6/93
*/
-#ifndef DEFSHELL
-#define DEFSHELL 1 /* Bourne shell */
-#endif
-
/*
* DEFMAXJOBS
* DEFMAXLOCAL
@@ -146,13 +142,6 @@
#define SUNSHCMD
/*
- * USE_PGRP
- * Kill the process group of the job so that all the progeny of the
- * current job dies, instead of just the one forked.
- */
-#define USE_PGRP
-
-/*
* USE_IOVEC
* We have writev(2)
*/
diff --git a/devel/bmake/files/make.1 b/devel/bmake/files/make.1
index f0ef8bedc0b..b861a916508 100644
--- a/devel/bmake/files/make.1
+++ b/devel/bmake/files/make.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+.\" $NetBSD: make.1,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd June 27, 2005
+.Dd November 19, 2006
.Dt MAKE 1
.Os
.Sh NAME
@@ -74,12 +74,15 @@
is a program designed to simplify the maintenance of other programs.
Its input is a list of specifications as to the files upon which programs
and other files depend.
-If the file
+If no
+.Fl f Ar makefile
+makefile option is given,
+.Nm
+will try to open
.Ql Pa makefile
-exists, it is read for this list of specifications.
-If it does not exist, the file
+then
.Ql Pa Makefile
-is read.
+in order to find the specifications.
If the file
.Ql Pa .depend
exists, it is read (see
@@ -91,6 +94,11 @@ For a more thorough description of
and makefiles, please refer to
.%T "Make \- A Tutorial" .
.Pp
+.Nm
+will prepend the contents of the
+.Va MAKEFLAGS
+environment variable to the command line arguments before parsing them.
+.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl B
@@ -100,10 +108,15 @@ by executing the commands to make the sources of a dependency line in sequence.
Define
.Ar variable
to be 1, in the global context.
-.It Fl d Ar flags
+.It Fl d Ar [-]flags
Turn on debugging, and specify which portions of
.Nm
are to print debugging information.
+Unless the flags are preceded by
+.Ql -
+they are added to the
+.Va MAKEFLAGS
+environment variable and will be processed by any child make processes.
.Ar Flags
is one or more of the following:
.Bl -tag -width Ds
@@ -118,6 +131,15 @@ Print debugging information about conditional evaluation.
Print debugging information about directory searching and caching.
.It Ar e
Print debugging information about failed commands and targets.
+.It Ar F
+Use the rest of
+.Ql flags
+as the name of the file to which the debug output is written.
+If the filename ends
+.Ql .%d
+then the
+.Ql %d
+is replaced by the pid.
.It Ar f
Print debugging information about loop evaluation.
.It Ar "g1"
@@ -129,6 +151,11 @@ on error.
Print the input graph before exiting on error.
.It Ar j
Print debugging information about running multiple shells.
+.It Ar l
+Print commands in Makefiles regardless of whether or not they are prefixed by
+.Ql @
+or other "quiet" flags.
+Also known as "loud" behavior.
.It Ar m
Print debugging information about making targets, including modification
dates.
@@ -140,8 +167,12 @@ These are created via
.Xr mkstemp 3
and have names of the form
.Pa /tmp/makeXXXXX .
-.Em NOTE:
-This can create many file in /tmp so use with care.
+.Em NOTE :
+This can create many file in
+.Pa /tmp
+so use with care.
+.It Ar p
+Print debugging information about makefile parsing.
.It Ar s
Print debugging information about suffix-transformation rules.
.It Ar t
@@ -413,6 +444,11 @@ Assign the value to the variable if it is not already defined.
Assign with expansion, i.e. expand the value before assigning it
to the variable.
Normally, expansion is not done until the variable is referenced.
+.Em NOTE :
+References to undefined variables are
+.Em not
+expanded.
+This can cause problems when variable modifiers are used.
.It Ic \&!=
Expand the value and pass it to the shell for execution and assign
the result to the variable.
@@ -539,7 +575,7 @@ The name that
.Nm
was executed with
.Pq Va argv[0] .
-For compatibily
+For compatibility
.Nm
also sets
.Va .MAKE
@@ -549,6 +585,35 @@ The preferred variable to use is the environment variable
because it is more compatible with other versions of
.Nm
and cannot be confused with the special target with the same name.
+.It Va .MAKE.EXPORTED
+The list of variables exported by
+.Nm .
+.It Va .MAKE.MAKEFILES
+The list of makefiles read by
+.Nm ,
+which is useful for tracking dependencies.
+Each makefile is recorded only once, regardless of the number of times read.
+.It Va .MAKE.PID
+The process-id of
+.Nm .
+.It Va .MAKE.PPID
+The parent process-id of
+.Nm .
+.It Va .MAKE.JOB.PREFIX
+If
+.Nm
+is run with
+.Ar j
+then output for each target is prefixed with a token
+.Ql --- target ---
+the first part of which can be controlled via
+.Va .MAKE.JOB.PREFIX .
+.br
+For example:
+.Li .MAKE.JOB.PREFIX=${.newline}---${.MAKE:T}[${.MAKE.PID}]
+would produce tokens like
+.Ql ---make[1234] target ---
+making it easier to track the degree of parallelism being achieved.
.It Ev MAKEFLAGS
The environment variable
.Ql Ev MAKEFLAGS
@@ -692,11 +757,24 @@ Variable expansion may be modified to select or modify each word of the
variable (where a ``word'' is white-space delimited sequence of characters).
The general format of a variable expansion is as follows:
.Pp
-.Dl {variable[:modifier[:...]]}
+.Dl ${variable[:modifier[:...]]}
.Pp
Each modifier begins with a colon,
which may be escaped with a backslash
.Pq Ql \e .
+.Pp
+A set of modifiers can be specified via a variable, as follows:
+.Pp
+.Dl modifier_variable=modifier[:...]
+.Dl ${variable:${modifier_variable}[:...]}
+.Pp
+In this case the first modifier in the modifier_variable does not
+start with a colon, since that must appear in the referencing
+variable.
+If any of the modifiers in the modifier_variable contain a dollar sign
+.Pq Ql $ ,
+these must be doubled to avoid early expansion.
+.Pp
The supported modifiers are:
.Bl -tag -width EEE
.It Cm \&:E
@@ -1117,6 +1195,18 @@ Conditional expressions are also preceded by a single dot as the first
character of a line.
The possible conditionals are as follows:
.Bl -tag -width Ds
+.It Ic .export Ar variable
+Export the specified global variable.
+If no variable is provided, all globals are exported
+except for internal variables (those that start with
+.Ql \&.
+).
+This is not affected by the
+.Fl X
+flag, so should be used with caution.
+Appending a variable name to
+.Va .MAKE.EXPORTED
+is equivalent to exporting a variable.
.It Ic .undef Ar variable
Un-define the specified global variable.
Only global variables may be un-defined.
@@ -1380,7 +1470,7 @@ option.
.It Ic .PRECIOUS
When
.Nm
-is interrupted, it removes any partially made targets.
+is interrupted, it normally removes any partially made targets.
This source prevents the target from being removed.
.It Ic .RECURSIVE
Synonym for
@@ -1413,8 +1503,30 @@ If
.Ic .WAIT
appears in a dependency line, the sources that precede it are
made before the sources that succeed it in the line.
-Loops are not
-detected and targets that form loops will be silently ignored.
+Since the dependents of files are not made until the file itself
+could be made, this also stops the dependents being built unless they
+are needed for another branch of the dependency tree.
+So given:
+.Bd -literal
+x: a .WAIT b
+ echo x
+a:
+ echo a
+b: b1
+ echo b
+b1:
+ echo b1
+
+.Ed
+the output is always
+.Ql b1 ,
+.Ql b ,
+.Ql a ,
+.Ql x .
+.br
+The ordering imposed by
+.Ic .WAIT
+is only relevant for parallel makes.
.El
.Sh SPECIAL TARGETS
Special targets may not be included with other targets, i.e. they must be
@@ -1480,6 +1592,20 @@ Synonym for
for compatibility with other pmake variants.
.It Ic .ORDER
The named targets are made in sequence.
+This ordering does not add targets to the list of targets to be made.
+Since the dependents of a target do not get built until the target itself
+could be built, unless
+.Ql a
+is built by another part of the dependency graph,
+the following is a dependency loop:
+.Bd -literal
+\&.ORDER a b
+b: a
+.Ed
+.Pp
+The ordering imposed by
+.Ic .ORDER
+is only relevant for parallel makes.
.\" XXX: NOT YET!!!!
.\" .It Ic .PARALLEL
.\" The named targets are executed in parallel mode.
@@ -1543,13 +1669,16 @@ It is typically identical to
The flag to pass the shell to enable error checking.
.It Ar echoFlag
The flag to pass the shell to enable command echoing.
+.It Ar newline
+The string literal to pass the shell that results in a single newline
+character when used outside of any quoting characters.
.El
Example:
.Bd -literal
\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \\
check="set -e" ignore="set +e" \\
echo="set -v" quiet="set +v" filter="set +v" \\
- echoFlag=v errFlag=e
+ echoFlag=v errFlag=e newline="'\\n'"
.Ed
.It Ic .SILENT
Apply the
@@ -1599,6 +1728,14 @@ system makefile
.It /usr/share/mk
system makefile directory
.El
+.Sh COMPATIBILITY
+The basic make syntax is compatible between different versions of make,
+however the special variables, variable modifiers and conditionals are not.
+.Pp
+The way that parallel makes are scheduled changed in
+.Nx 4.0
+so that .ORDER and .WAIT apply recursively to the dependant nodes.
+The algorithms used may change again in the future.
.Sh SEE ALSO
.Xr mkdep 1
.Sh HISTORY
diff --git a/devel/bmake/files/make.c b/devel/bmake/files/make.c
index 1661b7d0de6..d313208b2e2 100644
--- a/devel/bmake/files/make.c
+++ b/devel/bmake/files/make.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: make.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: make.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: make.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: make.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: make.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -112,8 +112,7 @@ __RCSID("$NetBSD: make.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
* 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.
+ * Make_ExpandUse Expand .USE nodes
*/
#include "make.h"
@@ -121,14 +120,12 @@ __RCSID("$NetBSD: make.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
#include "dir.h"
#include "job.h"
+static unsigned int checked = 1;/* Sequence # to detect recursion */
static Lst toBeMade; /* The current fringe of the graph. These
* are nodes which await examination by
* MakeOODate. It is added to by
* Make_Update and subtracted from by
* MakeStartJobs */
-static int numNodes; /* Number of nodes to be processed. If this
- * is non-zero when Job_Empty() returns
- * TRUE, there's a cycle in the graph */
static int MakeAddChild(ClientData, ClientData);
static int MakeFindChild(ClientData, ClientData);
@@ -138,6 +135,22 @@ static int MakeTimeStamp(ClientData, ClientData);
static int MakeHandleUse(ClientData, ClientData);
static Boolean MakeStartJobs(void);
static int MakePrintStatus(ClientData, ClientData);
+static int MakeCheckOrder(ClientData, ClientData);
+static int MakeBuildChild(ClientData, ClientData);
+static int MakeBuildParent(ClientData, ClientData);
+
+static void
+make_abort(GNode *gn, int line)
+{
+ static int two = 2;
+
+ fprintf(debug_file, "make_abort from line %d\n", line);
+ Targ_PrintNode(gn, &two);
+ Lst_ForEach(toBeMade, Targ_PrintNode, &two);
+ Targ_PrintGraph(3);
+ abort();
+}
+
/*-
*-----------------------------------------------------------------------
* Make_TimeStamp --
@@ -211,9 +224,9 @@ Make_OODate(GNode *gn)
(void)Dir_MTime(gn);
if (DEBUG(MAKE)) {
if (gn->mtime != 0) {
- printf("modified %s...", Targ_FmtTime(gn->mtime));
+ fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime));
} else {
- printf("non-existent...");
+ fprintf(debug_file, "non-existent...");
}
}
}
@@ -238,13 +251,13 @@ Make_OODate(GNode *gn)
* no matter *what*.
*/
if (DEBUG(MAKE)) {
- printf(".USE node...");
+ fprintf(debug_file, ".USE node...");
}
oodate = FALSE;
} else if ((gn->type & OP_LIB) &&
((gn->mtime==0) || Arch_IsLib(gn))) {
if (DEBUG(MAKE)) {
- printf("library...");
+ fprintf(debug_file, "library...");
}
/*
@@ -259,10 +272,10 @@ Make_OODate(GNode *gn)
* out-of-date if any of its children was out-of-date.
*/
if (DEBUG(MAKE)) {
- printf(".JOIN node...");
+ fprintf(debug_file, ".JOIN node...");
}
if (DEBUG(MAKE)) {
- printf("source %smade...", gn->flags & CHILDMADE ? "" : "not ");
+ fprintf(debug_file, "source %smade...", gn->flags & CHILDMADE ? "" : "not ");
}
oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE;
} else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
@@ -272,11 +285,11 @@ Make_OODate(GNode *gn)
*/
if (DEBUG(MAKE)) {
if (gn->type & OP_FORCE) {
- printf("! operator...");
+ fprintf(debug_file, "! operator...");
} else if (gn->type & OP_PHONY) {
- printf(".PHONY node...");
+ fprintf(debug_file, ".PHONY node...");
} else {
- printf(".EXEC node...");
+ fprintf(debug_file, ".EXEC node...");
}
}
oodate = TRUE;
@@ -294,11 +307,11 @@ Make_OODate(GNode *gn)
*/
if (DEBUG(MAKE)) {
if (gn->mtime < gn->cmtime) {
- printf("modified before source...");
+ fprintf(debug_file, "modified before source...");
} else if (gn->mtime == 0) {
- printf("non-existent and no sources...");
+ fprintf(debug_file, "non-existent and no sources...");
} else {
- printf(":: operator and no sources...");
+ fprintf(debug_file, ":: operator and no sources...");
}
}
oodate = TRUE;
@@ -312,7 +325,7 @@ Make_OODate(GNode *gn)
*/
if (DEBUG(MAKE)) {
if (gn->flags & FORCE)
- printf("non existing child...");
+ fprintf(debug_file, "non existing child...");
}
oodate = (gn->flags & FORCE) ? TRUE : FALSE;
}
@@ -325,7 +338,7 @@ Make_OODate(GNode *gn)
* thinking they're out-of-date.
*/
if (!oodate) {
- Lst_ForEach(gn->parents, MakeTimeStamp, (ClientData)gn);
+ Lst_ForEach(gn->parents, MakeTimeStamp, gn);
}
return (oodate);
@@ -355,7 +368,10 @@ MakeAddChild(ClientData gnp, ClientData lp)
Lst l = (Lst) lp;
if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) {
- (void)Lst_EnQueue(l, (ClientData)gn);
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "MakeAddChild: need to examine %s%s\n",
+ gn->name, gn->cohort_num);
+ (void)Lst_EnQueue(l, gn);
}
return (0);
}
@@ -422,7 +438,7 @@ Make_HandleUse(GNode *cgn, GNode *pgn)
#ifdef DEBUG_SRC
if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) {
- printf("Make_HandleUse: called for plain node %s\n", cgn->name);
+ fprintf(debug_file, "Make_HandleUse: called for plain node %s\n", cgn->name);
return;
}
#endif
@@ -525,7 +541,7 @@ MakeHandleUse(ClientData cgnp, ClientData pgnp)
* children the parent has. This is used by Make_Run to decide
* whether to queue the parent or examine its children...
*/
- if ((ln = Lst_Member(pgn->children, (ClientData) cgn)) != NILLNODE) {
+ if ((ln = Lst_Member(pgn->children, cgn)) != NILLNODE) {
Lst_Remove(pgn->children, ln);
pgn->unmade--;
}
@@ -605,17 +621,17 @@ Make_Recheck(GNode *gn)
* the target is made now. Otherwise archives with ... rules
* don't work!
*/
- if (NoExecute(gn) ||
- (gn->type & OP_SAVE_CMDS) || mtime == 0) {
+ if (NoExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
+ (mtime == 0 && !(gn->type & OP_WAIT))) {
if (DEBUG(MAKE)) {
- printf(" recheck(%s): update time to now: %s\n",
+ fprintf(debug_file, " recheck(%s): update time from %s to now\n",
gn->name, Targ_FmtTime(gn->mtime));
}
gn->mtime = now;
}
else {
if (DEBUG(MAKE)) {
- printf(" recheck(%s): current update time: %s\n",
+ fprintf(debug_file, " recheck(%s): current update time: %s\n",
gn->name, Targ_FmtTime(gn->mtime));
}
}
@@ -665,10 +681,16 @@ Make_Update(GNode *cgn)
Lst parents;
GNode *centurion;
+ /* It is save to re-examine any nodes again */
+ checked++;
+
cname = Var_Value(TARGET, cgn, &p1);
if (p1)
free(p1);
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
+
/*
* If the child was actually made, see what its modification time is
* now -- some rules won't actually update the file. If the file still
@@ -684,27 +706,50 @@ Make_Update(GNode *cgn)
*/
if ((centurion = cgn->centurion) != NULL) {
if (!Lst_IsEmpty(cgn->parents))
- Punt("%s: cohort has parents", cgn->name);
+ Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num);
centurion->unmade_cohorts -= 1;
if (centurion->unmade_cohorts < 0)
Error("Graph cycles through centurion %s", centurion->name);
- parents = centurion->parents;
} else {
centurion = cgn;
- parents = cgn->parents;
}
+ parents = centurion->parents;
+
+ /* If this was a .ORDER node, schedule the RHS */
+ Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade));
+
+ /* Now mark all the parents as having one less unmade child */
if (Lst_Open(parents) == SUCCESS) {
while ((ln = Lst_Next(parents)) != NILLNODE) {
pgn = (GNode *)Lst_Datum(ln);
- if (mtime == 0)
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "inspect parent %s%s: flags %x, "
+ "type %x, made %d, unmade %d ",
+ pgn->name, pgn->cohort_num, pgn->flags,
+ pgn->type, pgn->made, pgn->unmade-1);
+
+ if (!(pgn->flags & REMAKE)) {
+ /* This parent isn't needed */
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "- not needed\n");
+ continue;
+ }
+ if (mtime == 0 && !(cgn->type & OP_WAIT))
pgn->flags |= FORCE;
+
/*
- * If the parent has the .MADE attribute, it has already
- * been queued on the `toBeMade' list in Make_ExpandUse()
- * and its unmade children counter is zero.
+ * If the parent has the .MADE attribute, its timestamp got
+ * updated to that of its newest child, and its unmake
+ * child count got set to zero in Make_ExpandUse().
+ * However other things might cause us to build one of its
+ * children - and so we mustn't do any processing here when
+ * the child build finishes.
*/
- if ((pgn->flags & REMAKE) == 0 || (pgn->type & OP_MADE) != 0)
+ if (pgn->type & OP_MADE) {
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "- .MADE\n");
continue;
+ }
if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) {
if (cgn->made == MADE)
@@ -716,40 +761,60 @@ Make_Update(GNode *cgn)
* A parent must wait for the completion of all instances
* of a `::' dependency.
*/
- if (centurion->unmade_cohorts != 0 || centurion->made == UNMADE)
+ if (centurion->unmade_cohorts != 0 || centurion->made < MADE) {
+ if (DEBUG(MAKE))
+ fprintf(debug_file,
+ "- centurion made %d, %d unmade cohorts\n",
+ centurion->made, centurion->unmade_cohorts);
continue;
+ }
/* One more child of this parent is now made */
pgn->unmade -= 1;
- if (pgn->unmade == 0) {
+ if (pgn->unmade < 0) {
+ if (DEBUG(MAKE)) {
+ fprintf(debug_file, "Graph cycles through %s%s\n",
+ pgn->name, pgn->cohort_num);
+ Targ_PrintGraph(2);
+ }
+ Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num);
+ }
+
+ /* We must always rescan the parents of .WAIT and .ORDER nodes. */
+ if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
+ && !(centurion->flags & DONE_ORDER)) {
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "- unmade children\n");
+ continue;
+ }
+ if (pgn->made != DEFERRED) {
/*
- * Queue the node up -- any unmade predecessors will
- * be dealt with in MakeStartJobs.
+ * Either this parent is on a different branch of the tree,
+ * or it on the RHS of a .WAIT directive
+ * or it is already on the toBeMade list.
*/
- (void)Lst_EnQueue(toBeMade, (ClientData)pgn);
- } else if (pgn->unmade < 0) {
- Error("Graph cycles through %s", pgn->name);
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "- not deferred\n");
+ continue;
}
+ if (pgn->order_pred
+ && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) {
+ /* A .ORDER rule stops us building this */
+ continue;
+ }
+ if (DEBUG(MAKE)) {
+ static int two = 2;
+ fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n",
+ cgn->name, cgn->cohort_num,
+ pgn->name, pgn->cohort_num, pgn->made);
+ Targ_PrintNode(pgn, &two);
+ }
+ /* Ok, we can schedule the parent again */
+ pgn->made = REQUESTED;
+ (void)Lst_EnQueue(toBeMade, pgn);
}
Lst_Close(parents);
}
- /*
- * Deal with successor nodes. If any is marked for making and has an unmade
- * count of 0, has not been made and isn't in the examination queue,
- * it means we need to place it in the queue as it restrained itself
- * before.
- */
- for (ln = Lst_First(centurion->successors); ln != NILLNODE;
- ln = Lst_Succ(ln)) {
- GNode *succ = (GNode *)Lst_Datum(ln);
-
- if ((succ->flags & REMAKE) != 0 && succ->unmade == 0 &&
- succ->made == UNMADE &&
- Lst_Member(toBeMade, (ClientData)succ) == NILLNODE)
- {
- (void)Lst_EnQueue(toBeMade, (ClientData)succ);
- }
- }
/*
* Set the .PREFIX and .IMPSRC variables for all the implied parents
@@ -893,8 +958,8 @@ MakeAddAllSrc(ClientData cgnp, ClientData pgnp)
void
Make_DoAllVar(GNode *gn)
{
- Lst_ForEach(gn->children, MakeUnmark, (ClientData) gn);
- Lst_ForEach(gn->children, MakeAddAllSrc, (ClientData) gn);
+ Lst_ForEach(gn->children, MakeUnmark, gn);
+ Lst_ForEach(gn->children, MakeAddAllSrc, gn);
if (!Var_Exists (OODATE, gn)) {
Var_Set(OODATE, "", gn, 0);
@@ -927,63 +992,136 @@ Make_DoAllVar(GNode *gn)
*
*-----------------------------------------------------------------------
*/
+
+static int
+MakeCheckOrder(ClientData v_bn, ClientData ignore __unused)
+{
+ GNode *bn = v_bn;
+
+ if (bn->made >= MADE || !(bn->flags & REMAKE))
+ return 0;
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "MakeCheckOrder: Waiting for .ORDER node %s%s\n",
+ bn->name, bn->cohort_num);
+ return 1;
+}
+
+static int
+MakeBuildChild(ClientData v_cn, ClientData toBeMade_next)
+{
+ GNode *cn = v_cn;
+
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "MakeBuildChild: inspect %s%s, made %d, type %x\n",
+ cn->name, cn->cohort_num, cn->made, cn->type);
+ if (cn->made > DEFERRED)
+ return 0;
+
+ /* If this node is on the RHS of a .ORDER, check LHSs. */
+ if (cn->order_pred && Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) {
+ /* Can't build this (or anything else in this child list) yet */
+ cn->made = DEFERRED;
+ return 1;
+ }
+
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "MakeBuildChild: schedule %s%s\n",
+ cn->name, cn->cohort_num);
+
+ cn->made = REQUESTED;
+ if (toBeMade_next == NILLNODE)
+ Lst_AtEnd(toBeMade, cn);
+ else
+ Lst_InsertBefore(toBeMade, toBeMade_next, cn);
+
+ if (cn->unmade_cohorts != 0)
+ Lst_ForEach(cn->cohorts, MakeBuildChild, toBeMade_next);
+
+ /*
+ * If this node is a .WAIT node with unmade chlidren
+ * then don't add the next sibling.
+ */
+ return cn->type & OP_WAIT && cn->unmade > 0;
+}
+
+/* When a .ORDER RHS node completes we do this on each LHS */
+static int
+MakeBuildParent(ClientData v_pn, ClientData toBeMade_next)
+{
+ GNode *pn = v_pn;
+
+ if (pn->made != DEFERRED)
+ return 0;
+
+ if (MakeBuildChild(pn, toBeMade_next) == 0) {
+ /* Mark so that when this node is built we reschedule its parents */
+ pn->flags |= DONE_ORDER;
+ }
+
+ return 0;
+}
+
static Boolean
MakeStartJobs(void)
{
GNode *gn;
+ int have_token = 0;
while (!Lst_IsEmpty (toBeMade)) {
+ /* Get token now to avoid cycling job-list when we only have 1 token */
+ if (!have_token && !Job_TokenWithdraw())
+ break;
+ have_token = 1;
+
gn = (GNode *)Lst_DeQueue(toBeMade);
- if (DEBUG(MAKE)) {
- printf("Examining %s...", gn->name);
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "Examining %s%s...\n",
+ gn->name, gn->cohort_num);
+
+ if (gn->made != REQUESTED) {
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "state %d\n", gn->made);
+
+ make_abort(gn, __LINE__);
}
- /*
- * Make sure any and all predecessors that are going to be made,
- * have been.
- */
- if (!Lst_IsEmpty(gn->preds)) {
- LstNode ln;
-
- for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){
- GNode *pgn = (GNode *)Lst_Datum(ln);
-
- if ((pgn->flags & REMAKE) &&
- (pgn->made == UNMADE || pgn->unmade_cohorts != 0)) {
- if (DEBUG(MAKE)) {
- printf("predecessor %s not made yet.\n", pgn->name);
- }
- break;
- }
- }
- /*
- * If ln isn't nil, there's a predecessor as yet unmade, so we
- * just drop this node on the floor. When the node in question
- * has been made, it will notice this node as being ready to
- * make but as yet unmade and will place the node on the queue.
- */
- if (ln != NILLNODE) {
- continue;
- }
+
+ if (gn->checked == checked) {
+ /* We've already looked at this node since a job finished... */
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "already checked %s%s\n",
+ gn->name, gn->cohort_num);
+ gn->made = DEFERRED;
+ continue;
}
+ gn->checked = checked;
- if (!Job_TokenWithdraw()) {
- Lst_AtFront(toBeMade, gn);
- break;
+ if (gn->unmade != 0) {
+ /*
+ * We can't build this yet, add all unmade children to toBeMade,
+ * just before the current first element.
+ */
+ gn->made = DEFERRED;
+ Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade));
+ /* and drop this node on the floor */
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "dropped %s%s\n", gn->name, gn->cohort_num);
+ continue;
}
- numNodes--;
+ gn->made = BEINGMADE;
if (Make_OODate(gn)) {
if (DEBUG(MAKE)) {
- printf("out-of-date\n");
+ fprintf(debug_file, "out-of-date\n");
}
if (queryFlag) {
return (TRUE);
}
Make_DoAllVar(gn);
Job_Make(gn);
+ have_token = 0;
} else {
if (DEBUG(MAKE)) {
- printf("up-to-date\n");
+ fprintf(debug_file, "up-to-date\n");
}
gn->made = UPTODATE;
if (gn->type & OP_JOIN) {
@@ -995,10 +1133,13 @@ MakeStartJobs(void)
*/
Make_DoAllVar(gn);
}
- Job_TokenReturn();
Make_Update(gn);
}
}
+
+ if (have_token)
+ Job_TokenReturn();
+
return (FALSE);
}
@@ -1024,39 +1165,97 @@ MakeStartJobs(void)
*-----------------------------------------------------------------------
*/
static int
-MakePrintStatus(ClientData gnp, ClientData cyclep)
+MakePrintStatusOrder(ClientData ognp, ClientData gnp)
+{
+ GNode *ogn = ognp;
+ GNode *gn = gnp;
+
+ if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED)
+ /* not waiting for this one */
+ return 0;
+
+ printf(" `%s%s' has .ORDER dependency against %s%s "
+ "(made %d, flags %x, type %x)\n",
+ gn->name, gn->cohort_num,
+ ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
+ if (DEBUG(MAKE) && debug_file != stdout)
+ fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s "
+ "(made %d, flags %x, type %x)\n",
+ gn->name, gn->cohort_num,
+ ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
+ return 0;
+}
+
+static int
+MakePrintStatus(ClientData gnp, ClientData v_errors)
{
GNode *gn = (GNode *)gnp;
- Boolean cycle = *(Boolean *)cyclep;
- if (gn->made == UPTODATE) {
- printf("`%s' is up to date.\n", gn->name);
- } else if (gn->unmade != 0) {
- if (cycle) {
- Boolean t = TRUE;
- /*
- * If printing cycles and came to one that has unmade children,
- * print out the cycle by recursing on its children. Note a
- * cycle like:
- * a : b
- * b : c
- * c : b
- * will cause this to erroneously complain about a being in
- * the cycle, but this is a good approximation.
- */
- if (gn->made == CYCLE) {
- Error("Graph cycles through `%s'", gn->name);
- gn->made = ENDCYCLE;
- Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);
- gn->made = UNMADE;
- } else if (gn->made != ENDCYCLE) {
- gn->made = CYCLE;
- Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);
- }
- } else {
- printf("`%s' not remade because of errors.\n", gn->name);
+ int *errors = v_errors;
+
+ if (gn->flags & DONECYCLE)
+ /* We've completely processed this node before, don't do it again. */
+ return 0;
+
+ if (gn->unmade == 0) {
+ gn->flags |= DONECYCLE;
+ switch (gn->made) {
+ case UPTODATE:
+ printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num);
+ break;
+ case MADE:
+ break;
+ case UNMADE:
+ case DEFERRED:
+ case REQUESTED:
+ case BEINGMADE:
+ (*errors)++;
+ printf("`%s%s' was not built (made %d, flags %x, type %x)!\n",
+ gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
+ if (DEBUG(MAKE) && debug_file != stdout)
+ fprintf(debug_file,
+ "`%s%s' was not built (made %d, flags %x, type %x)!\n",
+ gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
+ /* Most likely problem is actually caused by .ORDER */
+ Lst_ForEach(gn->order_pred, MakePrintStatusOrder, gn);
+ break;
+ default:
+ /* Errors - already counted */
+ printf("`%s%s' not remade because of errors.\n",
+ gn->name, gn->cohort_num);
+ if (DEBUG(MAKE) && debug_file != stdout)
+ fprintf(debug_file, "`%s%s' not remade because of errors.\n",
+ gn->name, gn->cohort_num);
+ break;
}
+ return 0;
}
- return (0);
+
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "MakePrintStatus: %s%s has %d unmade children\n",
+ gn->name, gn->cohort_num, gn->unmade);
+ /*
+ * If printing cycles and came to one that has unmade children,
+ * print out the cycle by recursing on its children.
+ */
+ if (!(gn->flags & CYCLE)) {
+ /* Fist time we've seen this node, check all children */
+ gn->flags |= CYCLE;
+ Lst_ForEach(gn->children, MakePrintStatus, errors);
+ /* Mark that this node needn't be processed again */
+ gn->flags |= DONECYCLE;
+ return 0;
+ }
+
+ /* Only output the error once per node */
+ gn->flags |= DONECYCLE;
+ Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
+ if ((*errors)++ > 100)
+ /* Abandon the whole error report */
+ return 1;
+
+ /* Reporting for our children will give the rest of the loop */
+ Lst_ForEach(gn->children, MakePrintStatus, errors);
+ return 0;
}
@@ -1068,24 +1267,16 @@ MakePrintStatus(ClientData gnp, ClientData cyclep)
* Input:
* targs the initial list of targets
*
- * Results:
- * The new list of targets.
- *
* Side Effects:
- * numNodes is set to the number of elements in the list of targets.
*-----------------------------------------------------------------------
*/
-Lst
+void
Make_ExpandUse(Lst targs)
{
GNode *gn; /* a temporary pointer */
Lst examine; /* List of targets to examine */
- Lst ntargs; /* List of new targets to be made */
-
- ntargs = Lst_Init(FALSE);
examine = Lst_Duplicate(targs, NOCOPY);
- numNodes = 0;
/*
* Make an initial downward pass over the graph, marking nodes to be made
@@ -1097,63 +1288,174 @@ Make_ExpandUse(Lst targs)
*/
while (!Lst_IsEmpty (examine)) {
gn = (GNode *)Lst_DeQueue(examine);
+
+ if (gn->flags & REMAKE)
+ /* We've looked at this one already */
+ continue;
+ gn->flags |= REMAKE;
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "Make_ExpandUse: examine %s%s\n",
+ gn->name, gn->cohort_num);
if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) {
+ /* Append all the 'cohorts' to the list of things to examine */
Lst new;
new = Lst_Duplicate(gn->cohorts, NOCOPY);
Lst_Concat(new, examine, LST_CONCLINK);
examine = new;
}
-
- if ((gn->flags & REMAKE) == 0) {
- gn->flags |= REMAKE;
- numNodes++;
- /*
- * 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.
- */
- if (gn->type & OP_ARCHV) {
- char *eoa, *eon;
- eoa = strchr(gn->name, '(');
- eon = strchr(gn->name, ')');
- if (eoa == NULL || eon == NULL)
- continue;
- *eoa = '\0';
- *eon = '\0';
- Var_Set(MEMBER, eoa + 1, gn, 0);
- Var_Set(ARCHIVE, gn->name, gn, 0);
- *eoa = '(';
- *eon = ')';
- }
+ /*
+ * 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.
+ */
+ if (gn->type & OP_ARCHV) {
+ char *eoa, *eon;
+ eoa = strchr(gn->name, '(');
+ eon = strchr(gn->name, ')');
+ if (eoa == NULL || eon == NULL)
+ continue;
+ *eoa = '\0';
+ *eon = '\0';
+ Var_Set(MEMBER, eoa + 1, gn, 0);
+ Var_Set(ARCHIVE, gn->name, gn, 0);
+ *eoa = '(';
+ *eon = ')';
+ }
- (void)Dir_MTime(gn);
- Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
- Lst_ForEach(gn->children, MakeUnmark, (ClientData)gn);
- Lst_ForEach(gn->children, MakeHandleUse, (ClientData)gn);
-
- if ((gn->type & OP_MADE) == 0)
- Suff_FindDeps(gn);
- else {
- /* Pretend we made all this node's children */
- Lst_ForEach(gn->children, MakeFindChild, (ClientData)gn);
- if (gn->unmade != 0)
- printf("Warning: %s still has %d unmade children\n",
- gn->name, gn->unmade);
- }
+ (void)Dir_MTime(gn);
+ Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
+ Lst_ForEach(gn->children, MakeUnmark, gn);
+ Lst_ForEach(gn->children, MakeHandleUse, gn);
+
+ if ((gn->type & OP_MADE) == 0)
+ Suff_FindDeps(gn);
+ else {
+ /* Pretend we made all this node's children */
+ Lst_ForEach(gn->children, MakeFindChild, gn);
+ if (gn->unmade != 0)
+ printf("Warning: %s%s still has %d unmade children\n",
+ gn->name, gn->cohort_num, gn->unmade);
+ }
+
+ if (gn->unmade != 0)
+ Lst_ForEach(gn->children, MakeAddChild, examine);
+ }
+
+ Lst_Destroy(examine, NOFREE);
+}
- if (gn->unmade != 0) {
- Lst_ForEach(gn->children, MakeAddChild, (ClientData)examine);
+/*-
+ *-----------------------------------------------------------------------
+ * Make_ProcessWait --
+ * Convert .WAIT nodes into dependencies
+ *
+ * Input:
+ * targs the initial list of targets
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static int
+link_parent(ClientData cnp, ClientData pnp)
+{
+ GNode *cn = cnp;
+ GNode *pn = pnp;
+
+ Lst_AtEnd(pn->children, cn);
+ Lst_AtEnd(cn->parents, pn);
+ pn->unmade++;
+ return 0;
+}
+
+static int
+add_wait_dep(void *v_cn, void *v_wn)
+{
+ GNode *cn = v_cn;
+ GNode *wn = v_wn;
+
+ if (cn == wn)
+ return 1;
+
+ if (cn == NULL || wn == NULL) {
+ printf("bad wait dep %p %p\n", cn, wn);
+ exit(4);
+ }
+ if (DEBUG(MAKE))
+ fprintf(debug_file, ".WAIT: add dependency %s%s -> %s\n",
+ cn->name, cn->cohort_num, wn->name);
+
+ Lst_AtEnd(wn->children, cn);
+ wn->unmade++;
+ Lst_AtEnd(cn->parents, wn);
+ return 0;
+}
+
+static void
+Make_ProcessWait(Lst targs)
+{
+ GNode *pgn; /* 'parent' node we are examining */
+ GNode *cgn; /* Each child in turn */
+ LstNode owln; /* Previous .WAIT node */
+ Lst examine; /* List of targets to examine */
+ LstNode ln;
+
+ /*
+ * We need all the nodes to have a common parent in order for the
+ * .WAIT and .ORDER scheduling to work.
+ * Perhaps this should be done earlier...
+ */
+
+ pgn = Targ_NewGN(".MAIN");
+ pgn->flags = REMAKE;
+ pgn->type = OP_PHONY | OP_DEPENDS;
+ /* Get it displayed in the diag dumps */
+ Lst_AtFront(Targ_List(), pgn);
+
+ Lst_ForEach(targs, link_parent, pgn);
+
+ /* Start building with the 'dummy' .MAIN' node */
+ MakeBuildChild(pgn, NILLNODE);
+
+ examine = Lst_Init(FALSE);
+ Lst_AtEnd(examine, pgn);
+
+ while (!Lst_IsEmpty (examine)) {
+ pgn = Lst_DeQueue(examine);
+
+ /* We only want to process each child-list once */
+ if (pgn->flags & DONE_WAIT)
+ continue;
+ pgn->flags |= DONE_WAIT;
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "Make_ProcessWait: examine %s\n", pgn->name);
+
+ if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) {
+ /* Append all the 'cohorts' to the list of things to examine */
+ Lst new;
+ new = Lst_Duplicate(pgn->cohorts, NOCOPY);
+ Lst_Concat(new, examine, LST_CONCLINK);
+ examine = new;
+ }
+
+ owln = Lst_First(pgn->children);
+ Lst_Open(pgn->children);
+ for (; (ln = Lst_Next(pgn->children)) != NILLNODE; ) {
+ cgn = Lst_Datum(ln);
+ if (cgn->type & OP_WAIT) {
+ /* Make the .WAIT node depend on the previous children */
+ Lst_ForEachFrom(pgn->children, owln, add_wait_dep, cgn);
+ owln = ln;
} else {
- (void)Lst_EnQueue(ntargs, (ClientData)gn);
+ Lst_AtEnd(examine, cgn);
}
}
+ Lst_Close(pgn->children);
}
Lst_Destroy(examine, NOFREE);
- return ntargs;
}
/*-
@@ -1185,7 +1487,16 @@ Make_Run(Lst targs)
{
int errors; /* Number of errors the Job module reports */
- toBeMade = Make_ExpandUse(targs);
+ /* Start trying to make the current targets... */
+ toBeMade = Lst_Init(FALSE);
+
+ Make_ExpandUse(targs);
+ Make_ProcessWait(targs);
+
+ if (DEBUG(MAKE)) {
+ fprintf(debug_file, "#***# full graph\n");
+ Targ_PrintGraph(1);
+ }
if (queryFlag) {
/*
@@ -1194,16 +1505,15 @@ Make_Run(Lst targs)
* to see if any of the targets was out of date)
*/
return (MakeStartJobs());
- } else {
- /*
- * Initialization. At the moment, no jobs are running and until some
- * get started, nothing will happen since the remaining upward
- * traversal of the graph is performed by the routines in job.c upon
- * the finishing of a job. So we fill the Job table as much as we can
- * before going into our loop.
- */
- (void)MakeStartJobs();
}
+ /*
+ * Initialization. At the moment, no jobs are running and until some
+ * get started, nothing will happen since the remaining upward
+ * traversal of the graph is performed by the routines in job.c upon
+ * the finishing of a job. So we fill the Job table as much as we can
+ * before going into our loop.
+ */
+ (void)MakeStartJobs();
/*
* Main Loop: The idea here is that the ending of jobs will take
@@ -1215,9 +1525,8 @@ Make_Run(Lst targs)
* Note that the Job module will exit if there were any errors unless the
* keepgoing flag was given.
*/
- while (!Lst_IsEmpty(toBeMade) || !Job_Empty ()) {
+ while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) {
Job_CatchOutput();
- Job_CatchChildren(!usePipes);
(void)MakeStartJobs();
}
@@ -1227,8 +1536,15 @@ Make_Run(Lst targs)
* Print the final status of each target. E.g. if it wasn't made
* because some inferior reported an error.
*/
- errors = ((errors == 0) && (numNodes != 0));
- Lst_ForEach(targs, MakePrintStatus, (ClientData) &errors);
-
- return (TRUE);
+ if (DEBUG(MAKE))
+ fprintf(debug_file, "done: errors %d\n", errors);
+ if (errors == 0) {
+ Lst_ForEach(targs, MakePrintStatus, &errors);
+ if (DEBUG(MAKE)) {
+ fprintf(debug_file, "done: errors %d\n", errors);
+ if (errors)
+ Targ_PrintGraph(4);
+ }
+ }
+ return errors != 0;
}
diff --git a/devel/bmake/files/make.h b/devel/bmake/files/make.h
index aeff250e283..46e752fe9b7 100644
--- a/devel/bmake/files/make.h
+++ b/devel/bmake/files/make.h
@@ -1,4 +1,4 @@
-/* $NetBSd: make.h,v 1.53 2005/05/01 01:25:36 christos Exp $ */
+/* $NetBSD: make.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -145,20 +145,25 @@
* 7) the number of its children that are, as yet, unmade
* 8) its modification time
* 9) the modification time of its youngest child (qv. make.c)
- * 10) a list of nodes for which this is a source
- * 11) a list of nodes on which this depends
+ * 10) a list of nodes for which this is a source (parents)
+ * 11) a list of nodes on which this depends (children)
* 12) a list of nodes that depend on this, as gleaned from the
- * transformation rules.
- * 13) a list of nodes of the same name created by the :: operator
- * 14) a list of nodes that must be made (if they're made) before
- * this node can be, but that do no enter into the datedness of
+ * transformation rules (iParents)
+ * 13) a list of ancestor nodes, which includes parents, iParents,
+ * and recursive parents of parents
+ * 14) a list of nodes of the same name created by the :: operator
+ * 15) a list of nodes that must be made (if they're made) before
+ * this node can be, but that do not enter into the datedness of
* this node.
- * 15) a list of nodes that must be made (if they're made) after
+ * 16) a list of nodes that must be made (if they're made) before
+ * this node or any child of this node can be, but that do not
+ * enter into the datedness of this node.
+ * 17) a list of nodes that must be made (if they're made) after
* this node is, but that do not depend on this node, in the
* normal sense.
- * 16) a Lst of ``local'' variables that are specific to this target
+ * 18) a Lst of ``local'' variables that are specific to this target
* and this target only (qv. var.c [$@ $< $?, etc.])
- * 17) a Lst of strings that are commands to be given to a shell
+ * 19) a Lst of strings that are commands to be given to a shell
* to create this target.
*/
typedef struct GNode {
@@ -166,34 +171,32 @@ typedef struct GNode {
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 */
int flags;
-#define REMAKE 0x1 /* this target needs to be remade */
+#define REMAKE 0x1 /* this target needs to be (re)made */
#define CHILDMADE 0x2 /* children of this target were made */
#define FORCE 0x4 /* children don't exist, and we pretend made */
- enum {
- UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED,
- CYCLE, ENDCYCLE
+#define DONE_WAIT 0x8 /* Set by Make_ProcessWait() */
+#define DONE_ORDER 0x10 /* Build requested by .ORDER processing */
+#define FROM_DEPEND 0x20 /* Node created from .depend */
+#define CYCLE 0x1000 /* Used by MakePrintStatus */
+#define DONECYCLE 0x2000 /* Used by MakePrintStatus */
+ enum enum_made {
+ UNMADE, DEFERRED, REQUESTED, BEINGMADE,
+ MADE, UPTODATE, ERROR, ABORTED
} made; /* Set to reflect the state of processing
* on this node:
* UNMADE - Not examined yet
+ * DEFERRED - Examined once (building child)
+ * REQUESTED - on toBeMade list
* BEINGMADE - Target is already being made.
- * Indicates a cycle in the graph. (compat
- * mode only)
+ * Indicates a cycle in the graph.
* MADE - Was out-of-date and has been made
* UPTODATE - Was already up-to-date
* ERROR - An error occurred while it was being
* made (used only in compat mode)
* ABORTED - The target was aborted due to
* an error making an inferior (compat).
- * CYCLE - Marked as potentially being part of
- * a graph cycle. If we come back to a
- * node marked this way, it is printed
- * and 'made' is changed to ENDCYCLE.
- * ENDCYCLE - the cycle has been completely
- * printed. Go back and unmark all its
- * members.
*/
int unmade; /* The number of unmade children */
@@ -206,12 +209,15 @@ typedef struct GNode {
Lst cohorts; /* Other nodes for the :: operator */
Lst parents; /* Nodes that depend on this one */
Lst children; /* Nodes on which this one depends */
- Lst successors; /* Nodes that must be made after this one */
- Lst preds; /* Nodes that must be made before this one */
+ Lst order_pred; /* .ORDER nodes we need made */
+ Lst order_succ; /* .ORDER nodes who need us */
+
+ char cohort_num[8]; /* #n for this cohort */
int unmade_cohorts;/* # of unmade instances on the
cohorts list */
struct GNode *centurion; /* Pointer to the first instance of a ::
node; only set when on a cohorts list */
+ unsigned int checked; /* Last time we tried to makle this node */
Hash_Table context; /* The local variables */
Lst commands; /* Creation commands */
@@ -219,7 +225,7 @@ typedef struct GNode {
struct _Suff *suffix; /* Suffix for the node (determined by
* Suff_FindDeps and opaque to everyone
* but the Suff module) */
- char *fname; /* filename where the GNode got defined */
+ const char *fname; /* filename where the GNode got defined */
int lineno; /* line number where the GNode got defined */
} GNode;
@@ -272,6 +278,7 @@ typedef struct GNode {
* target' processing in parse.c */
#define OP_PHONY 0x00010000 /* Not a file target; run always */
#define OP_NOPATH 0x00020000 /* Don't search for file in the path */
+#define OP_WAIT 0x00040000 /* .WAIT phony node */
/* Attributes applied by PMake */
#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */
#define OP_MEMBER 0x40000000 /* Target is a member of an archive */
@@ -301,19 +308,9 @@ typedef struct GNode {
* table of all targets and its address returned. If TARG_NOCREATE is given,
* a NIL pointer will be returned.
*/
-#define TARG_CREATE 0x01 /* create node if not found */
#define TARG_NOCREATE 0x00 /* don't create it */
-
-/*
- * There are several places where expandable buffers are used (parse.c and
- * var.c). This constant is merely the starting point for those buffers. If
- * lines tend to be much shorter than this, it would be best to reduce BSIZE.
- * If longer, it should be increased. Reducing it will cause more copying to
- * be done for longer lines, but will save space for shorter ones. In any
- * case, it ought to be a power of two simply because most storage allocation
- * schemes allocate in powers of two.
- */
-#define MAKE_BSIZE 256 /* starting size for expandable buffers */
+#define TARG_CREATE 0x01 /* create node if not found */
+#define TARG_NOHASH 0x02 /* don't look in/add to hash table */
/*
* These constants are all used by the Str_Concat function to decide how the
@@ -380,13 +377,10 @@ extern Boolean keepgoing; /* True if should continue on unaffected
* in one portion */
extern Boolean touchFlag; /* TRUE if targets should just be 'touched'
* if out of date. Set by the -t flag */
-extern Boolean usePipes; /* TRUE if should capture the output of
- * subshells by means of pipes. Otherwise it
- * is routed to temporary files from which it
- * is retrieved when the shell exits */
extern Boolean queryFlag; /* TRUE if we aren't supposed to really make
* anything, just see if the targets are out-
* of-date */
+extern Boolean doing_depend; /* TRUE if processing .depend */
extern Boolean checkEnvFirst; /* TRUE if environment should be searched for
* variables before the global context */
@@ -421,12 +415,16 @@ extern char *progname; /* The program name */
#define MAKEFLAGS ".MAKEFLAGS"
#define MAKEOVERRIDES ".MAKEOVERRIDES"
+#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */
+#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */
+#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all the makefiles we read */
/*
* debug control:
* There is one bit per module. It is up to the module what debug
* information to print.
*/
+FILE *debug_file; /* Output written here - default stdout */
extern int debug;
#define DEBUG_ARCH 0x0001
#define DEBUG_COND 0x0002
@@ -441,8 +439,10 @@ extern int debug;
#define DEBUG_FOR 0x0400
#define DEBUG_SHELL 0x0800
#define DEBUG_ERROR 0x1000
-#define DEBUG_GRAPH3 0x10000
+#define DEBUG_LOUD 0x2000
+#define DEBUG_GRAPH3 0x10000
#define DEBUG_SCRIPT 0x20000
+#define DEBUG_PARSE 0x40000
#define CONCAT(a,b) a##b
@@ -456,7 +456,7 @@ extern int debug;
int Make_TimeStamp(GNode *, GNode *);
Boolean Make_OODate(GNode *);
-Lst Make_ExpandUse(Lst);
+void Make_ExpandUse(Lst);
time_t Make_Recheck(GNode *);
void Make_HandleUse(GNode *, GNode *);
void Make_Update(GNode *);
diff --git a/devel/bmake/files/makefile.boot.in b/devel/bmake/files/makefile.boot.in
index 2967b8c67b4..8c576611443 100644
--- a/devel/bmake/files/makefile.boot.in
+++ b/devel/bmake/files/makefile.boot.in
@@ -1,5 +1,5 @@
# RCSid:
-# $Id: makefile.boot.in,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $Id: makefile.boot.in,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $
#
# modify MACHINE and MACHINE_ARCH as appropriate for your target architecture
@@ -13,17 +13,23 @@ MKDEP=$(srcdir)/mkdeps.sh -n -i/usr/include
MKDEP_OPTS=-A
MK=${prefix}/share/mk
MKSRC=@mksrc@
-DEFAULT_MAKESYSPATH=/usr/share/mk:/usr/local/share/mk:/opt/share/mk
-CFLAGS=-I. -I$(srcdir) @DEFS@ @CPPFLAGS@ ${XDEFS} -D_PATH_DEFSYSPATH=\"@default_sys_path@\"
+# this is what we build into bmake
+DEFAULT_SYS_PATH = @default_sys_path@
+# this is what we might use during bootstrap
+BOOTSTRAP_SYS_PATH= `pwd`/mk:${MK}:${MKSRC}:${DEFAULT_SYS_PATH}:/usr/share/mk:/usr/local/share/mk:/opt/share/mk
+
+CFLAGS= @CFLAGS@ -I. -I$(srcdir) @DEFS@ @CPPFLAGS@ ${XDEFS} \
+ -D_PATH_DEFSYSPATH=\"${DEFAULT_SYS_PATH}\"
MDEFS="-D@force_machine@MACHINE=\"@machine@\"" "-DMACHINE_ARCH=\"@machine_arch@\""
OBJ=arch.o buf.o compat.o cond.o dir.o for.o hash.o job.o main.o make.o \
parse.o str.o suff.o targ.o trace.o var.o util.o getopt.o sigcompat.o @LIBOBJS@
-BMAKE_ENV= CC="$(CC)" LIBC= MAKEFLAGS= MAKESYSPATH=`pwd`/mk:${MKSRC}:${MK}:${DEFAULT_MAKESYSPATH}
+BMAKE_ENV= CC="$(CC)" LIBC= MAKEFLAGS= MAKESYSPATH=${BOOTSTRAP_SYS_PATH}
bootstrap: bmake.boot .mk.done
${BMAKE_ENV} ./bmake.boot -f Makefile
+ ${BMAKE_ENV} ./bmake.boot -f Makefile bmake.1
${BMAKE_ENV} `pwd`/bmake -f Makefile test
bmake: bmake.boot
diff --git a/devel/bmake/files/missing/sys/cdefs.h b/devel/bmake/files/missing/sys/cdefs.h
index b9fb16e13c4..19611ed63b5 100644
--- a/devel/bmake/files/missing/sys/cdefs.h
+++ b/devel/bmake/files/missing/sys/cdefs.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cdefs.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: cdefs.h,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $ */
/*
* Copyright (c) 1991, 1993
@@ -73,11 +73,19 @@
#endif
#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS };
+# ifndef __BEGIN_DECLS
+# define __BEGIN_DECLS extern "C" {
+# endif
+# ifndef __END_DECLS
+# define __END_DECLS };
+# endif
#else
-#define __BEGIN_DECLS
-#define __END_DECLS
+# ifndef __BEGIN_DECLS
+# define __BEGIN_DECLS
+# endif
+# ifndef __END_DECLS
+# define __END_DECLS
+# endif
#endif
/*
@@ -89,7 +97,9 @@
*/
#if defined(__STDC__) || defined(__cplusplus)
#define __P(protos) protos /* full-blown ANSI C */
+#ifndef __CONCAT
#define __CONCAT(x,y) x ## y
+#endif
#define __STRING(x) #x
#define __const const /* define reserved names to standard */
diff --git a/devel/bmake/files/nonints.h b/devel/bmake/files/nonints.h
index 812b5015406..c6468fb65c6 100644
--- a/devel/bmake/files/nonints.h
+++ b/devel/bmake/files/nonints.h
@@ -1,4 +1,4 @@
-/* $NetBSD: nonints.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: nonints.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*-
* Copyright (c) 1988, 1989, 1990, 1993
@@ -97,7 +97,8 @@ int Compat_Make(ClientData, ClientData);
/* cond.c */
int Cond_EvalExpression(int, char *, Boolean *, int);
int Cond_Eval(char *);
-void Cond_End(void);
+void Cond_restore_depth(unsigned int);
+unsigned int Cond_save_depth(void);
/* for.c */
int For_Eval(char *);
@@ -115,10 +116,16 @@ void Punt(const char *, ...)
void DieHorribly(void) __attribute__((__noreturn__));
int PrintAddr(ClientData, ClientData);
void Finish(int);
+#ifndef HAVE_EMALLOC
char *estrdup(const char *);
+char *strndup(const char *, size_t);
+char *estrndup(const char *, size_t);
void *emalloc(size_t);
void *erealloc(void *, size_t);
void enomem(void);
+#else
+#include <util.h>
+#endif
int eunlink(const char *);
void execError(const char *, const char *);
@@ -129,10 +136,10 @@ Boolean Parse_AnyExport(void);
Boolean Parse_IsVar(char *);
void Parse_DoVar(char *, GNode *);
void Parse_AddIncludeDir(char *);
-void Parse_File(const char *, FILE *);
+void Parse_File(const char *, int);
void Parse_Init(void);
void Parse_End(void);
-void Parse_FromString(char *, int);
+void Parse_SetInput(const char *, int, int, char *);
Lst Parse_MainName(void);
/* str.c */
@@ -172,10 +179,12 @@ Boolean Targ_Silent(GNode *);
Boolean Targ_Precious(GNode *);
void Targ_SetMain(GNode *);
int Targ_PrintCmd(ClientData, ClientData);
+int Targ_PrintNode(ClientData, ClientData);
char *Targ_FmtTime(time_t);
void Targ_PrintType(int);
void Targ_PrintGraph(int);
void Targ_Propagate(void);
+void Targ_Propagate_Wait(void);
/* var.c */
void Var_Delete(const char *, GNode *);
@@ -183,10 +192,12 @@ void Var_Set(const char *, const char *, GNode *, int);
void Var_Append(const char *, const char *, GNode *);
Boolean Var_Exists(const char *, GNode *);
char *Var_Value(const char *, GNode *, char **);
-char *Var_Parse(const char *, GNode *, Boolean, int *, Boolean *);
+char *Var_Parse(const char *, GNode *, Boolean, int *, void **);
char *Var_Subst(const char *, const char *, GNode *, Boolean);
char *Var_GetTail(const char *);
char *Var_GetHead(const char *);
void Var_Init(void);
void Var_End(void);
void Var_Dump(GNode *);
+void Var_ExportVars(void);
+void Var_Export(char *, int);
diff --git a/devel/bmake/files/os.sh b/devel/bmake/files/os.sh
index 6e9d6c41e8b..33512d98d6a 100644
--- a/devel/bmake/files/os.sh
+++ b/devel/bmake/files/os.sh
@@ -17,7 +17,7 @@
# Simon J. Gerraty <sjg@crufty.net>
# RCSid:
-# $Id: os.sh,v 1.1.1.1 2005/12/02 00:02:59 sjg Exp $
+# $Id: os.sh,v 1.1.1.2 2008/03/09 19:39:32 joerg Exp $
#
# @(#) Copyright (c) 1994 Simon J. Gerraty
#
@@ -172,6 +172,11 @@ Linux)
PS_AXC=axc
[ -x /usr/bin/md5sum ] && { MD5=/usr/bin/md5sum; export MD5; }
;;
+QNX)
+ case $MACHINE in
+ x86pc) MACHINE_ARCH=i386;;
+ esac
+ ;;
esac
HOSTNAME=${HOSTNAME:-`( hostname ) 2>/dev/null`}
diff --git a/devel/bmake/files/parse.c b/devel/bmake/files/parse.c
index 0b6a0edec7e..2a41b85f5c7 100644
--- a/devel/bmake/files/parse.c
+++ b/devel/bmake/files/parse.c
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: parse.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: parse.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: parse.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: parse.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: parse.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -91,8 +91,8 @@ __RCSID("$NetBSD: parse.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
* module.
*
* Most important structures are kept in Lsts. Directories for
- * the #include "..." function are kept in the 'parseIncPath' Lst, while
- * those for the #include <...> are kept in the 'sysIncPath' Lst. The
+ * the .include "..." function are kept in the 'parseIncPath' Lst, while
+ * those for the .include <...> are kept in the 'sysIncPath' Lst. The
* targets currently being defined are kept in the 'targets' Lst.
*
* The variables 'fname' and 'lineno' are used to track the name
@@ -125,6 +125,7 @@ __RCSID("$NetBSD: parse.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
@@ -148,32 +149,31 @@ static Lst targCmds; /* command lines for targets */
#endif
static Boolean inLine; /* true if currently in a dependency
* line or its commands */
-typedef struct {
- char *str;
- char *ptr;
-} PTR;
-
static int fatals = 0;
static GNode *mainNode; /* The main target to create. This is the
* first target on the first dependency
* line in the first makefile */
typedef struct IFile {
- char *fname; /* name of previous file */
- int lineno; /* saved line number */
- FILE * F; /* the open stream */
- PTR * P; /* the char pointer */
+ const char *fname; /* name of file */
+ int lineno; /* line number in file */
+ int fd; /* the open file */
+ int cond_depth; /* 'if' nesting when file opened */
+ char *P_str; /* point to base of string buffer */
+ char *P_ptr; /* point to next char of string buffer */
+ char *P_end; /* point to the end of string buffer */
+ int P_buflen; /* current size of file buffer */
} IFile;
-static IFile curFile;
+#define IFILE_BUFLEN 0x8000
+static IFile *curFile;
/*
* Definitions for handling #include specifications
*/
-static Lst includes; /* stack of IFiles generated by
- * #includes */
+static Lst includes; /* stack of IFiles generated by .includes */
Lst parseIncPath; /* list of directories for "..." includes */
Lst sysIncPath; /* list of directories for <...> includes */
Lst defIncPath; /* default directories for <...> includes */
@@ -218,7 +218,6 @@ typedef enum {
} ParseSpecial;
static ParseSpecial specType;
-static int waiting;
#define LPAREN '('
#define RPAREN ')'
@@ -280,42 +279,28 @@ static struct {
{ ".WAIT", Wait, 0 },
};
-/*
- * Used by ParseDoSpecialSrc()
- */
-typedef struct {
- int op;
- char *src;
- Lst allsrc;
-} SpecialSrc;
-
static int ParseIsEscaped(const char *, const char *);
-static void ParseErrorInternal(char *, size_t, int, const char *, ...)
+static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
__attribute__((__format__(__printf__, 4, 5)));
-static void ParseVErrorInternal(char *, size_t, int, const char *, va_list)
- __attribute__((__format__(__printf__, 4, 0)));
-static int ParseFindKeyword(char *);
+static void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list)
+ __attribute__((__format__(__printf__, 5, 0)));
+static int ParseFindKeyword(const char *);
static int ParseLinkSrc(ClientData, ClientData);
static int ParseDoOp(ClientData, ClientData);
-static int ParseAddDep(ClientData, ClientData);
-static int ParseDoSpecialSrc(ClientData, ClientData);
-static void ParseDoSrc(int, char *, Lst, Boolean);
+static void ParseDoSrc(int, const char *);
static int ParseFindMain(ClientData, ClientData);
static int ParseAddDir(ClientData, ClientData);
static int ParseClearPath(ClientData, ClientData);
static void ParseDoDependency(char *);
static int ParseAddCmd(ClientData, ClientData);
-static __inline int ParseReadc(void);
-static void ParseUnreadc(int);
static void ParseHasCommands(ClientData);
static void ParseDoInclude(char *);
-static void ParseSetParseFile(char *);
+static void ParseSetParseFile(const char *);
#ifdef SYSVINCLUDE
static void ParseTraditionalInclude(char *);
#endif
-static int ParseEOF(int);
+static int ParseEOF(void);
static char *ParseReadLine(void);
-static char *ParseSkipLine(int, int);
static void ParseFinishLine(void);
static void ParseMark(GNode *);
@@ -363,7 +348,7 @@ ParseIsEscaped(const char *line, const char *c)
*----------------------------------------------------------------------
*/
static int
-ParseFindKeyword(char *str)
+ParseFindKeyword(const char *str)
{
int start, end, cur;
int diff;
@@ -400,14 +385,14 @@ ParseFindKeyword(char *str)
*/
/* VARARGS */
static void
-ParseVErrorInternal(char *cfname, size_t clineno, int type, const char *fmt,
- va_list ap)
+ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type,
+ const char *fmt, va_list ap)
{
static Boolean fatal_warning_error_printed = FALSE;
- (void)fprintf(stderr, "%s: \"", progname);
+ (void)fprintf(f, "%s: \"", progname);
- if (*cfname != '/') {
+ if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) {
char *cp;
const char *dir;
@@ -422,16 +407,16 @@ ParseVErrorInternal(char *cfname, size_t clineno, int type, const char *fmt,
if (dir == NULL)
dir = ".";
- (void)fprintf(stderr, "%s/%s", dir, cfname);
+ (void)fprintf(f, "%s/%s", dir, cfname);
} else
- (void)fprintf(stderr, "%s", cfname);
+ (void)fprintf(f, "%s", cfname);
- (void)fprintf(stderr, "\" line %d: ", (int)clineno);
+ (void)fprintf(f, "\" line %d: ", (int)clineno);
if (type == PARSE_WARNING)
- (void)fprintf(stderr, "warning: ");
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- (void)fflush(stderr);
+ (void)fprintf(f, "warning: ");
+ (void)vfprintf(f, fmt, ap);
+ (void)fprintf(f, "\n");
+ (void)fflush(f);
if (type == PARSE_FATAL || parseWarnFatal)
fatals += 1;
if (parseWarnFatal && !fatal_warning_error_printed) {
@@ -452,13 +437,20 @@ ParseVErrorInternal(char *cfname, size_t clineno, int type, const char *fmt,
*/
/* VARARGS */
static void
-ParseErrorInternal(char *cfname, size_t clineno, int type, const char *fmt, ...)
+ParseErrorInternal(const char *cfname, size_t clineno, int type,
+ const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- ParseVErrorInternal(cfname, clineno, type, fmt, ap);
+ ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
va_end(ap);
+
+ if (debug_file != stderr && debug_file != stdout) {
+ va_start(ap, fmt);
+ ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap);
+ va_end(ap);
+ }
}
/*-
@@ -479,8 +471,16 @@ Parse_Error(int type, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- ParseVErrorInternal(curFile.fname, curFile.lineno, type, fmt, ap);
+ ParseVErrorInternal(stderr, curFile->fname, curFile->lineno,
+ type, fmt, ap);
va_end(ap);
+
+ if (debug_file != stderr && debug_file != stdout) {
+ va_start(ap, fmt);
+ ParseVErrorInternal(debug_file, curFile->fname, curFile->lineno,
+ type, fmt, ap);
+ va_end(ap);
+ }
}
/*-
@@ -511,10 +511,15 @@ ParseLinkSrc(ClientData pgnp, ClientData cgnp)
if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts))
pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts));
- (void)Lst_AtEnd(pgn->children, (ClientData)cgn);
+ (void)Lst_AtEnd(pgn->children, cgn);
if (specType == Not)
- (void)Lst_AtEnd(cgn->parents, (ClientData)pgn);
+ (void)Lst_AtEnd(cgn->parents, pgn);
pgn->unmade += 1;
+ if (DEBUG(PARSE)) {
+ fprintf(debug_file, "# ParseLinkSrc: added child %s - %s\n", pgn->name, cgn->name);
+ Targ_PrintNode(pgn, 0);
+ Targ_PrintNode(cgn, 0);
+ }
return (0);
}
@@ -572,7 +577,7 @@ ParseDoOp(ClientData gnp, ClientData opp)
*/
gn->type |= op & ~OP_OPMASK;
- cohort = Targ_NewGN(gn->name);
+ cohort = Targ_FindNode(gn->name, TARG_NOHASH);
/*
* Make the cohort invisible as well to avoid duplicating it into
* other variables. True, parents of this target won't tend to do
@@ -581,9 +586,11 @@ ParseDoOp(ClientData gnp, ClientData opp)
* traversals will no longer see this node anyway. -mycroft)
*/
cohort->type = op | OP_INVISIBLE;
- (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
+ (void)Lst_AtEnd(gn->cohorts, cohort);
cohort->centurion = gn;
gn->unmade_cohorts += 1;
+ snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
+ gn->unmade_cohorts);
} else {
/*
* We don't want to nuke any previous flags (whatever they were) so we
@@ -597,117 +604,6 @@ ParseDoOp(ClientData gnp, ClientData opp)
/*-
*---------------------------------------------------------------------
- * ParseAddDep --
- * Check if the pair of GNodes given needs to be synchronized.
- * This has to be when two nodes are on different sides of a
- * .WAIT directive.
- *
- * Results:
- * Returns 1 if the two targets need to be ordered, 0 otherwise.
- * If it returns 1, the search can stop
- *
- * Side Effects:
- * A dependency can be added between the two nodes.
- *
- *---------------------------------------------------------------------
- */
-static int
-ParseAddDep(ClientData pp, ClientData sp)
-{
- GNode *p = (GNode *)pp;
- GNode *s = (GNode *)sp;
-
- if (p->order < s->order) {
- /*
- * XXX: This can cause loops, and loops can cause unmade targets,
- * but checking is tedious, and the debugging output can show the
- * problem
- */
- (void)Lst_AtEnd(p->successors, (ClientData)s);
- (void)Lst_AtEnd(s->preds, (ClientData)p);
- return 0;
- }
- else
- return 1;
-}
-
-/* -
- *---------------------------------------------------------------------
- * ParseDoSpecialSrc --
- * ParseDoSrc struck an unexpanded variable in a src.
- * The most likely reason is a src that refers to .TARGET or
- * .PREFIX so we get called to set those for each target
- * and then call ParseDoSrc again to do the real work.
- *
- * Input:
- * tp A target GNode *
- * sp A SpecialSrc * which contains the args we need
- * for ParseDoSrc.
- *
- * Results:
- * Goodness
- *
- * Side Effects:
- * The target GNode will have .TARGET and .PREFIX set, this seems
- * harmless.
- */
-static int
-ParseDoSpecialSrc(ClientData tp, ClientData sp)
-{
- GNode *tn = (GNode *)tp;
- GNode *gn;
- SpecialSrc *ss = (SpecialSrc *)sp;
- char *cp;
- char *cp2;
- char *pref;
-
- /*
- * If the target is a suffix rule, leave it alone.
- */
- if (Suff_IsTransform(tn->name)) {
- ParseDoSrc(ss->op, ss->src, ss->allsrc, FALSE); /* don't come back */
- return 0;
- }
- Var_Set(TARGET, tn->name, tn, 0);
- if ((pref = strrchr(tn->name, '/')))
- pref++;
- else
- pref = tn->name;
- if ((cp2 = strchr(pref, '.')) > pref) {
- cp = estrdup(pref);
- cp[cp2 - pref] = '\0';
- Var_Set(PREFIX, cp, tn, 0);
- free(cp);
- } else
- Var_Set(PREFIX, pref, tn, 0);
- cp = Var_Subst(NULL, ss->src, tn, FALSE);
- if (strchr(cp, '$')) {
- Parse_Error(PARSE_WARNING, "Cannot resolve '%s' here", ss->src);
- ParseDoSrc(ss->op, ss->src, ss->allsrc, FALSE); /* don't come back */
- return 1; /* stop list traversal */
- }
- /*
- * We don't want to make every target dependent on sources for
- * other targets. This is the bit of ParseDoSrc which is relevant.
- * The main difference is we don't link the resolved src to all targets.
- */
- gn = Targ_FindNode(cp, TARG_CREATE);
- if (ss->op) {
- gn->type |= ss->op;
- } else {
- ParseLinkSrc((ClientData)tn, (ClientData)gn);
- }
- gn->order = waiting;
- (void)Lst_AtEnd(ss->allsrc, (ClientData)gn);
- if (waiting) {
- Lst_ForEach(ss->allsrc, ParseAddDep, (ClientData)gn);
- }
- return 0;
-}
-
-
-/*-
- *---------------------------------------------------------------------
* ParseDoSrc --
* Given the name of a source, figure out if it is an attribute
* and apply it to the targets if it is. Else decide if there is
@@ -718,8 +614,6 @@ ParseDoSpecialSrc(ClientData tp, ClientData sp)
* Input:
* tOp operator (if any) from special targets
* src name of the source to handle
- * allsrc List of all sources to wait for
- * resolve boolean - should we try and resolve .TARGET refs.
*
* Results:
* None
@@ -730,20 +624,34 @@ ParseDoSpecialSrc(ClientData tp, ClientData sp)
*---------------------------------------------------------------------
*/
static void
-ParseDoSrc(int tOp, char *src, Lst allsrc, Boolean resolve)
+ParseDoSrc(int tOp, const char *src)
{
GNode *gn = NULL;
+ static int wait_number = 0;
+ char wait_src[16];
if (*src == '.' && isupper ((unsigned char)src[1])) {
int keywd = ParseFindKeyword(src);
if (keywd != -1) {
int op = parseKeywords[keywd].op;
if (op != 0) {
- Lst_ForEach(targets, ParseDoOp, (ClientData)&op);
+ Lst_ForEach(targets, ParseDoOp, &op);
return;
}
if (parseKeywords[keywd].spec == Wait) {
- waiting++;
+ /*
+ * We add a .WAIT node in the dependency list.
+ * After any dynamic dependencies (and filename globbing)
+ * have happened, it is given a dependency on the each
+ * previous child back to and previous .WAIT node.
+ * The next child won't be scheduled until the .WAIT node
+ * is built.
+ * We give each .WAIT node a unique name (mainly for diag).
+ */
+ snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
+ gn = Targ_FindNode(wait_src, TARG_NOHASH);
+ gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
+ Lst_ForEach(targets, ParseLinkSrc, gn);
return;
}
}
@@ -759,9 +667,9 @@ ParseDoSrc(int tOp, char *src, Lst allsrc, Boolean resolve)
* invoked if the user didn't specify a target on the command
* line. This is to allow #ifmake's to succeed, or something...
*/
- (void)Lst_AtEnd(create, (ClientData)estrdup(src));
+ (void)Lst_AtEnd(create, estrdup(src));
/*
- * Add the name to the .TARGETS variable as well, so the user cna
+ * Add the name to the .TARGETS variable as well, so the user can
* employ that, if desired.
*/
Var_Append(".TARGETS", src, VAR_GLOBAL);
@@ -774,8 +682,14 @@ ParseDoSrc(int tOp, char *src, Lst allsrc, Boolean resolve)
*/
gn = Targ_FindNode(src, TARG_CREATE);
if (predecessor != NILGNODE) {
- (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
- (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
+ (void)Lst_AtEnd(predecessor->order_succ, gn);
+ (void)Lst_AtEnd(gn->order_pred, predecessor);
+ if (DEBUG(PARSE)) {
+ fprintf(debug_file, "# ParseDoSrc: added Order dependency %s - %s\n",
+ predecessor->name, gn->name);
+ Targ_PrintNode(predecessor, 0);
+ Targ_PrintNode(gn, 0);
+ }
}
/*
* The current source now becomes the predecessor for the next one.
@@ -795,34 +709,16 @@ ParseDoSrc(int tOp, char *src, Lst allsrc, Boolean resolve)
* the 'cohorts' list of the node) or all the cohorts are linked
* to all the targets.
*/
- if (resolve && strchr(src, '$')) {
- SpecialSrc ss;
- ss.op = tOp;
- ss.src = src;
- ss.allsrc = allsrc;
-
- /*
- * If src cannot be fully resolved, we'll be called again
- * with resolve==FALSE.
- */
- Lst_ForEach(targets, ParseDoSpecialSrc, (ClientData)&ss);
- return;
- }
+ /* Find/create the 'src' node and attach to all targets */
gn = Targ_FindNode(src, TARG_CREATE);
if (tOp) {
gn->type |= tOp;
} else {
- Lst_ForEach(targets, ParseLinkSrc, (ClientData)gn);
+ Lst_ForEach(targets, ParseLinkSrc, gn);
}
break;
}
-
- gn->order = waiting;
- (void)Lst_AtEnd(allsrc, (ClientData)gn);
- if (waiting) {
- Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);
- }
}
/*-
@@ -947,26 +843,22 @@ ParseDoDependency(char *line)
* expansion */
Lst curTargs; /* list of target names to be found and added
* to the targets list */
- Lst curSrcs; /* list of sources in order */
char *lstart = line;
- Boolean hasWait; /* is .WAIT present in srcs */
+ if (DEBUG(PARSE))
+ fprintf(debug_file, "ParseDoDependency(%s)\n", line);
tOp = 0;
specType = Not;
- waiting = 0;
paths = (Lst)NULL;
curTargs = Lst_Init(FALSE);
- curSrcs = Lst_Init(FALSE);
do {
- for (cp = line;
- *cp && (ParseIsEscaped(lstart, cp) ||
- (!isspace ((unsigned char)*cp) &&
- (*cp != '!') && (*cp != ':') && (*cp != LPAREN)));
- cp++)
- {
+ for (cp = line; *cp && (ParseIsEscaped(lstart, cp) ||
+ !(isspace((unsigned char)*cp) ||
+ *cp == '!' || *cp == ':' || *cp == LPAREN));
+ cp++) {
if (*cp == '$') {
/*
* Must be a dynamic source (would have been expanded
@@ -976,18 +868,16 @@ ParseDoDependency(char *line)
* in the initial Var_Subst and we wouldn't be here.
*/
int length;
- Boolean freeIt;
+ void *freeIt;
char *result;
- result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
-
- if (freeIt) {
- free(result);
- }
+ result = Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
+ if (freeIt)
+ free(freeIt);
cp += length-1;
}
- continue;
}
+
if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) {
/*
* Archives must be handled specially to make sure the OP_ARCHV
@@ -1002,7 +892,7 @@ ParseDoDependency(char *line)
if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) {
Parse_Error(PARSE_FATAL,
"Error in archive specification: \"%s\"", line);
- return;
+ goto out;
} else {
continue;
}
@@ -1022,9 +912,10 @@ ParseDoDependency(char *line)
"Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
else
Parse_Error(PARSE_FATAL, "Need an operator");
- return;
+ goto out;
}
*cp = '\0';
+
/*
* Have a word in line. See if it's a special target and set
* specType to match it.
@@ -1038,7 +929,7 @@ ParseDoDependency(char *line)
if (keywd != -1) {
if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
Parse_Error(PARSE_FATAL, "Mismatched special targets");
- return;
+ goto out;
}
specType = parseKeywords[keywd].spec;
@@ -1078,7 +969,7 @@ ParseDoDependency(char *line)
if (paths == NULL) {
paths = Lst_Init(FALSE);
}
- (void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
+ (void)Lst_AtEnd(paths, dirSearchPath);
break;
case Main:
if (!Lst_IsEmpty(create)) {
@@ -1090,19 +981,17 @@ ParseDoDependency(char *line)
case Interrupt:
gn = Targ_FindNode(line, TARG_CREATE);
gn->type |= OP_NOTMAIN|OP_SPECIAL;
- (void)Lst_AtEnd(targets, (ClientData)gn);
+ (void)Lst_AtEnd(targets, gn);
break;
case Default:
gn = Targ_NewGN(".DEFAULT");
gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
- (void)Lst_AtEnd(targets, (ClientData)gn);
+ (void)Lst_AtEnd(targets, gn);
DEFAULT = gn;
break;
case NotParallel:
- {
maxJobs = 1;
break;
- }
case SingleShell:
compatMake = TRUE;
break;
@@ -1126,12 +1015,12 @@ ParseDoDependency(char *line)
Parse_Error(PARSE_FATAL,
"Suffix '%s' not defined (yet)",
&line[5]);
- return;
+ goto out;
} else {
if (paths == (Lst)NULL) {
paths = Lst_Init(FALSE);
}
- (void)Lst_AtEnd(paths, (ClientData)path);
+ (void)Lst_AtEnd(paths, path);
}
}
}
@@ -1158,7 +1047,7 @@ ParseDoDependency(char *line)
* No wildcards, but we want to avoid code duplication,
* so create a list with the word on it.
*/
- (void)Lst_AtEnd(curTargs, (ClientData)line);
+ (void)Lst_AtEnd(curTargs, line);
}
while(!Lst_IsEmpty(curTargs)) {
@@ -1170,7 +1059,7 @@ ParseDoDependency(char *line)
gn = Suff_AddTransform(targName);
}
- (void)Lst_AtEnd(targets, (ClientData)gn);
+ (void)Lst_AtEnd(targets, gn);
}
} else if (specType == ExPath && *line != '.' && *line != '\0') {
Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
@@ -1182,17 +1071,17 @@ ParseDoDependency(char *line)
* allow on this line...
*/
if (specType != Not && specType != ExPath) {
- Boolean warn = FALSE;
+ Boolean warning = FALSE;
while (*cp && (ParseIsEscaped(lstart, cp) ||
((*cp != '!') && (*cp != ':')))) {
if (ParseIsEscaped(lstart, cp) ||
(*cp != ' ' && *cp != '\t')) {
- warn = TRUE;
+ warning = TRUE;
}
cp++;
}
- if (warn) {
+ if (warning) {
Parse_Error(PARSE_WARNING, "Extra target ignored");
}
} else {
@@ -1208,6 +1097,7 @@ ParseDoDependency(char *line)
* Don't need the list of target names anymore...
*/
Lst_Destroy(curTargs, NOFREE);
+ curTargs = NULL;
if (!Lst_IsEmpty(targets)) {
switch(specType) {
@@ -1245,12 +1135,12 @@ ParseDoDependency(char *line)
}
} else {
Parse_Error(PARSE_FATAL, "Missing dependency operator");
- return;
+ goto out;
}
cp++; /* Advance beyond operator */
- Lst_ForEach(targets, ParseDoOp, (ClientData)&op);
+ Lst_ForEach(targets, ParseDoOp, &op);
/*
* Get to the first source
@@ -1284,7 +1174,7 @@ ParseDoDependency(char *line)
beSilent = TRUE;
break;
case ExPath:
- Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
+ Lst_ForEach(paths, ParseClearPath, NULL);
Dir_SetPATH();
break;
#ifdef POSIX
@@ -1306,7 +1196,7 @@ ParseDoDependency(char *line)
} else if (specType == ExShell) {
if (Job_ParseShell(line) != SUCCESS) {
Parse_Error(PARSE_FATAL, "improper shell specification");
- return;
+ goto out;
}
*line = '\0';
} else if ((specType == NotParallel) || (specType == SingleShell)) {
@@ -1358,7 +1248,7 @@ ParseDoDependency(char *line)
Suff_AddSuffix(line, &mainNode);
break;
case ExPath:
- Lst_ForEach(paths, ParseAddDir, (ClientData)line);
+ Lst_ForEach(paths, ParseAddDir, line);
break;
case Includes:
Suff_AddInclude(line);
@@ -1390,18 +1280,13 @@ ParseDoDependency(char *line)
if (specType == ExPath)
Dir_SetPATH();
} else {
- /*
- * We don't need ParseDoSpecialSrc unless .WAIT is present.
- */
- hasWait = (strstr(line, ".WAIT") != NULL);
-
while (*line) {
/*
* The targets take real sources, so we must beware of archive
* specifications (i.e. things with left parentheses in them)
* and handle them accordingly.
*/
- while (*cp && !isspace ((unsigned char)*cp)) {
+ for (; *cp && !isspace ((unsigned char)*cp); cp++) {
if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) {
/*
* Only stop for a left parenthesis if it isn't at the
@@ -1410,8 +1295,6 @@ ParseDoDependency(char *line)
* source).
*/
break;
- } else {
- cp++;
}
}
@@ -1420,12 +1303,12 @@ ParseDoDependency(char *line)
if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) {
Parse_Error(PARSE_FATAL,
"Error in source archive spec \"%s\"", line);
- return;
+ goto out;
}
while (!Lst_IsEmpty (sources)) {
gn = (GNode *)Lst_DeQueue(sources);
- ParseDoSrc(tOp, gn->name, curSrcs, hasWait);
+ ParseDoSrc(tOp, gn->name);
}
Lst_Destroy(sources, NOFREE);
cp = line;
@@ -1435,7 +1318,7 @@ ParseDoDependency(char *line)
cp += 1;
}
- ParseDoSrc(tOp, line, curSrcs, hasWait);
+ ParseDoSrc(tOp, line);
}
while (*cp && isspace ((unsigned char)*cp)) {
cp++;
@@ -1451,13 +1334,12 @@ ParseDoDependency(char *line)
* the first dependency line that is actually a real target
* (i.e. isn't a .USE or .EXEC rule) to be made.
*/
- Lst_ForEach(targets, ParseFindMain, (ClientData)0);
+ Lst_ForEach(targets, ParseFindMain, NULL);
}
- /*
- * Finally, destroy the list of sources
- */
- Lst_Destroy(curSrcs, NOFREE);
+out:
+ if (curTargs)
+ Lst_Destroy(curTargs, NOFREE);
}
/*-
@@ -1597,14 +1479,6 @@ Parse_DoVar(char *line, GNode *ctxt)
Boolean freeCp = FALSE; /* TRUE if cp needs to be freed,
* i.e. if any variable expansion was
* performed */
- /*
- * Avoid clobbered variable warnings by forcing the compiler
- * to ``unregister'' variables
- */
-#if __GNUC__
- (void) &cp;
- (void) &line;
-#endif
/*
* Skip to variable name
@@ -1706,7 +1580,7 @@ Parse_DoVar(char *line, GNode *ctxt)
Var_Set(line, cp, ctxt, 0);
} else if (type == VAR_SHELL) {
char *res;
- const char *err;
+ const char *error;
if (strchr(cp, '$') != NULL) {
/*
@@ -1718,12 +1592,12 @@ Parse_DoVar(char *line, GNode *ctxt)
freeCp = TRUE;
}
- res = Cmd_Exec(cp, &err);
+ res = Cmd_Exec(cp, &error);
Var_Set(line, res, ctxt, 0);
free(res);
- if (err)
- Parse_Error(PARSE_WARNING, err, cp);
+ if (error)
+ Parse_Error(PARSE_WARNING, error, cp);
} else {
/*
* Normal assignment -- just do it.
@@ -1740,6 +1614,10 @@ Parse_DoVar(char *line, GNode *ctxt)
*/
Dir_InitCur(cp);
Dir_SetPATH();
+ } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) {
+ Job_SetPrefix();
+ } else if (strcmp(line, MAKE_EXPORTED) == 0) {
+ Var_Export(cp, 0);
}
if (freeCp)
free(cp);
@@ -1764,9 +1642,12 @@ static int
ParseAddCmd(ClientData gnp, ClientData cmd)
{
GNode *gn = (GNode *)gnp;
- /* if target already supplied, ignore commands */
+
+ /* Add to last (ie current) cohort for :: targets */
if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts));
+
+ /* if target already supplied, ignore commands */
if (!(gn->type & OP_HAS_COMMANDS)) {
(void)Lst_AtEnd(gn->commands, cmd);
ParseMark(gn);
@@ -1859,72 +1740,24 @@ Parse_AddIncludeDir(char *dir)
* fname and curFILE are altered for the new file
*---------------------------------------------------------------------
*/
+
static void
-ParseDoInclude(char *line)
+Parse_include_file(char *file, Boolean isSystem, int silent)
{
char *fullname; /* full pathname of file */
- IFile *oldFile; /* state associated with current file */
- char endc; /* the character which ends the file spec */
- char *cp; /* current position in file spec */
- Boolean isSystem; /* TRUE if makefile is a system makefile */
- int silent = (*line != 'i') ? 1 : 0;
- char *file = &line[7 + silent];
-
- /*
- * Skip to delimiter character so we know where to look
- */
- while ((*file == ' ') || (*file == '\t')) {
- file++;
- }
-
- if ((*file != '"') && (*file != '<')) {
- Parse_Error(PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
- return;
- }
-
- /*
- * Set the search path on which to find the include file based on the
- * characters which bracket its name. Angle-brackets imply it's
- * a system Makefile while double-quotes imply it's a user makefile
- */
- if (*file == '<') {
- isSystem = TRUE;
- endc = '>';
- } else {
- isSystem = FALSE;
- endc = '"';
- }
-
- /*
- * Skip to matching delimiter
- */
- for (cp = ++file; *cp && *cp != endc; cp++) {
- continue;
- }
-
- if (*cp != endc) {
- Parse_Error(PARSE_FATAL,
- "Unclosed %cinclude filename. '%c' expected",
- '.', endc);
- return;
- }
- *cp = '\0';
-
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- file = Var_Subst(NULL, file, VAR_CMD, FALSE);
+ char *newName;
+ char *prefEnd, *incdir;
+ int fd;
+ int i;
/*
* Now we know the file's name and its search path, we attempt to
* find the durn thing. A return of NULL indicates the file don't
* exist.
*/
- fullname = NULL;
+ fullname = file[0] == '/' ? estrdup(file) : NULL;
- if (!isSystem) {
+ if (fullname == NULL && !isSystem) {
/*
* Include files contained in double-quotes are first searched for
* relative to the including file's location. We don't want to
@@ -1932,42 +1765,49 @@ ParseDoInclude(char *line)
* leading path components and call Dir_FindFile to see if
* we can locate the beast.
*/
- char *prefEnd, *Fname;
-
- /* Make a temporary copy of this, to be safe. */
- Fname = estrdup(curFile.fname);
- prefEnd = strrchr(Fname, '/');
+ incdir = estrdup(curFile->fname);
+ prefEnd = strrchr(incdir, '/');
if (prefEnd != NULL) {
- char *newName;
-
*prefEnd = '\0';
- if (file[0] == '/')
- newName = estrdup(file);
- else
- newName = str_concat(Fname, file, STR_ADDSLASH);
+ /* Now do lexical processing of leading "../" on the filename */
+ for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
+ prefEnd = strrchr(incdir + 1, '/');
+ if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0)
+ break;
+ *prefEnd = '\0';
+ }
+ newName = str_concat(incdir, file + i, STR_ADDSLASH);
fullname = Dir_FindFile(newName, parseIncPath);
- if (fullname == NULL) {
+ if (fullname == NULL)
fullname = Dir_FindFile(newName, dirSearchPath);
- }
free(newName);
- *prefEnd = '/';
- } else {
- fullname = NULL;
}
- free(Fname);
- if (fullname == NULL) {
+ free(incdir);
+
+ if (fullname == NULL) {
/*
* Makefile wasn't found in same directory as included makefile.
* Search for it first on the -I search path,
* then on the .PATH search path, if not found in a -I directory.
- * XXX: Suffix specific?
+ * If we have a suffix specific path we should use that.
*/
- fullname = Dir_FindFile(file, parseIncPath);
+ char *suff;
+ Lst suffPath = NILLST;
+
+ if ((suff = strrchr(file, '.'))) {
+ suffPath = Suff_GetPath(suff);
+ if (suffPath != NILLST) {
+ fullname = Dir_FindFile(file, suffPath);
+ }
+ }
if (fullname == NULL) {
- fullname = Dir_FindFile(file, dirSearchPath);
+ fullname = Dir_FindFile(file, parseIncPath);
+ if (fullname == NULL) {
+ fullname = Dir_FindFile(file, dirSearchPath);
+ }
}
- }
+ }
}
/* Looking for a system file or file still not found */
@@ -1975,53 +1815,78 @@ ParseDoInclude(char *line)
/*
* Look for it on the system path
*/
- fullname = Dir_FindFile(file, Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
+ fullname = Dir_FindFile(file,
+ Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
}
if (fullname == NULL) {
- *cp = endc;
if (!silent)
Parse_Error(PARSE_FATAL, "Could not find %s", file);
return;
}
- free(file);
+ /* Actually open the file... */
+ fd = open(fullname, O_RDONLY);
+ if (fd == -1) {
+ if (!silent)
+ Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
+ free(fullname);
+ return;
+ }
- /*
- * Once we find the absolute path to the file, we get to save all the
- * state from the current file before we can start reading this
- * include file. The state is stored in an IFile structure which
- * is placed on a list with other IFile structures. The list makes
- * a very nice stack to track how we got here...
- */
- oldFile = emalloc(sizeof(IFile));
+ /* Start reading from this file next */
+ Parse_SetInput(fullname, 0, fd, NULL);
+}
- memcpy(oldFile, &curFile, sizeof(IFile));
+static void
+ParseDoInclude(char *line)
+{
+ char endc; /* the character which ends the file spec */
+ char *cp; /* current position in file spec */
+ int silent = (*line != 'i') ? 1 : 0;
+ char *file = &line[7 + silent];
- (void)Lst_AtFront(includes, (ClientData)oldFile);
+ /* Skip to delimiter character so we know where to look */
+ while (*file == ' ' || *file == '\t')
+ file++;
+
+ if (*file != '"' && *file != '<') {
+ Parse_Error(PARSE_FATAL,
+ ".include filename must be delimited by '\"' or '<'");
+ return;
+ }
/*
- * Once the previous state has been saved, we can get down to reading
- * the new file. We set up the name of the file to be the absolute
- * name of the include file so error messages refer to the right
- * place. Naturally enough, we start reading at line number 0.
+ * Set the search path on which to find the include file based on the
+ * characters which bracket its name. Angle-brackets imply it's
+ * a system Makefile while double-quotes imply it's a user makefile
*/
- curFile.fname = fullname;
- curFile.lineno = 0;
-
- ParseSetParseFile(curFile.fname);
+ if (*file == '<') {
+ endc = '>';
+ } else {
+ endc = '"';
+ }
- curFile.F = fopen(fullname, "r");
- curFile.P = NULL;
+ /* Skip to matching delimiter */
+ for (cp = ++file; *cp && *cp != endc; cp++)
+ continue;
- if (curFile.F == (FILE * ) NULL) {
- if (!silent)
- Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
- /*
- * Pop to previous file
- */
- (void)ParseEOF(0);
+ if (*cp != endc) {
+ Parse_Error(PARSE_FATAL,
+ "Unclosed %cinclude filename. '%c' expected",
+ '.', endc);
+ return;
}
+ *cp = '\0';
+
+ /*
+ * Substitute for any variables in the file name before trying to
+ * find the thing.
+ */
+ file = Var_Subst(NULL, file, VAR_CMD, FALSE);
+
+ Parse_include_file(file, endc == '>', silent);
+ free(file);
}
@@ -2040,56 +1905,127 @@ ParseDoInclude(char *line)
*---------------------------------------------------------------------
*/
static void
-ParseSetParseFile(char *filename)
+ParseSetParseFile(const char *filename)
{
char *slash;
+ char *dirname;
+ int len;
slash = strrchr(filename, '/');
- if (slash == 0) {
+ if (slash == NULL) {
Var_Set(".PARSEDIR", ".", VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", filename, VAR_GLOBAL, 0);
} else {
- *slash = '\0';
- Var_Set(".PARSEDIR", filename, VAR_GLOBAL, 0);
+ len = slash - filename;
+ dirname = emalloc(len + 1);
+ memcpy(dirname, filename, len);
+ dirname[len] = 0;
+ Var_Set(".PARSEDIR", dirname, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", slash+1, VAR_GLOBAL, 0);
- *slash = '/';
+ free(dirname);
+ }
+}
+
+/*
+ * Track the makefiles we read - so makefiles can
+ * set dependencies on them.
+ * Avoid adding anything more than once.
+ */
+
+static void
+ParseTrackInput(const char *name)
+{
+ char *old;
+ char *fp = NULL;
+ size_t name_len = strlen(name);
+
+ old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp);
+ if (old) {
+ /* does it contain name? */
+ for (; old != NULL; old = strchr(old, ' ')) {
+ if (*old == ' ')
+ old++;
+ if (memcmp(old, name, name_len) == 0
+ && (old[name_len] == 0 || old[name_len] == ' '))
+ goto cleanup;
+ }
+ }
+ Var_Append (MAKE_MAKEFILES, name, VAR_GLOBAL);
+ cleanup:
+ if (fp) {
+ free(fp);
}
}
/*-
*---------------------------------------------------------------------
- * Parse_FromString --
- * Start Parsing from the given string
+ * Parse_setInput --
+ * Start Parsing from the given source
*
* Results:
* None
*
* Side Effects:
* A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
+ * fname and curFile are altered for the new file
*---------------------------------------------------------------------
*/
void
-Parse_FromString(char *str, int lineno)
+Parse_SetInput(const char *name, int line, int fd, char *buf)
{
- IFile *oldFile; /* state associated with this file */
+ if (name == NULL)
+ name = curFile->fname;
+ else
+ ParseTrackInput(name);
- if (DEBUG(FOR))
- (void)fprintf(stderr, "%s\n---- at line %d\n", str, lineno);
+ if (DEBUG(PARSE))
+ fprintf(debug_file, "Parse_SetInput: file %s, line %d, fd %d, buf %p\n",
+ name, line, fd, buf);
- oldFile = emalloc(sizeof(IFile));
- memcpy(oldFile, &curFile, sizeof(IFile));
+ if (fd == -1 && buf == NULL)
+ /* sanity */
+ return;
- (void)Lst_AtFront(includes, (ClientData)oldFile);
+ if (curFile != NULL)
+ /* Save exiting file info */
+ Lst_AtFront(includes, curFile);
- curFile.F = NULL;
- curFile.P = emalloc(sizeof(PTR));
- curFile.P->str = curFile.P->ptr = str;
- curFile.lineno = lineno;
- curFile.fname = estrdup(curFile.fname);
-}
+ /* Allocate and fill in new structure */
+ curFile = emalloc(sizeof *curFile);
+
+ /*
+ * Once the previous state has been saved, we can get down to reading
+ * the new file. We set up the name of the file to be the absolute
+ * name of the include file so error messages refer to the right
+ * place.
+ */
+ curFile->fname = name;
+ curFile->lineno = line;
+ curFile->fd = fd;
+ curFile->cond_depth = Cond_save_depth();
+ ParseSetParseFile(name);
+
+ if (buf == NULL) {
+ /*
+ * Allocate a 32k data buffer (as stdio seems to).
+ * Set pointers so that first ParseReadc has to do a file read.
+ */
+ buf = emalloc(IFILE_BUFLEN);
+ buf[0] = 0;
+ curFile->P_str = buf;
+ curFile->P_ptr = buf;
+ curFile->P_end = buf;
+ curFile->P_buflen = IFILE_BUFLEN;
+ } else {
+ /* Start reading from the start of the buffer */
+ curFile->P_str = buf;
+ curFile->P_ptr = buf;
+ curFile->P_end = NULL;
+ }
+
+}
#ifdef SYSVINCLUDE
/*-
@@ -2111,18 +2047,15 @@ Parse_FromString(char *str, int lineno)
static void
ParseTraditionalInclude(char *line)
{
- char *fullname; /* full pathname of file */
- IFile *oldFile; /* state associated with current file */
char *cp; /* current position in file spec */
- char *prefEnd;
int done = 0;
int silent = (line[0] != 'i') ? 1 : 0;
char *file = &line[silent + 7];
- char *cfname;
- size_t clineno;
+ char *all_files;
- cfname = curFile.fname;
- clineno = curFile.lineno;
+ if (DEBUG(PARSE)) {
+ fprintf(debug_file, "ParseTraditionalInclude: %s\n", file);
+ }
/*
* Skip over whitespace
@@ -2130,16 +2063,20 @@ ParseTraditionalInclude(char *line)
while (isspace((unsigned char)*file))
file++;
+ /*
+ * Substitute for any variables in the file name before trying to
+ * find the thing.
+ */
+ all_files = Var_Subst(NULL, file, VAR_CMD, FALSE);
+
if (*file == '\0') {
Parse_Error(PARSE_FATAL,
"Filename missing from \"include\"");
return;
}
- for (; !done; file = cp + 1) {
- /*
- * Skip to end of line or next whitespace
- */
+ for (file = all_files; !done; file = cp + 1) {
+ /* Skip to end of line or next whitespace */
for (cp = file; *cp && !isspace((unsigned char) *cp); cp++)
continue;
@@ -2148,105 +2085,9 @@ ParseTraditionalInclude(char *line)
else
done = 1;
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- file = Var_Subst(NULL, file, VAR_CMD, FALSE);
-
- /*
- * Now we know the file's name, we attempt to find the durn thing.
- * A return of NULL indicates the file don't exist.
- *
- * Include files are first searched for relative to the including
- * file's location. We don't want to cd there, of course, so we
- * just tack on the old file's leading path components and call
- * Dir_FindFile to see if we can locate the beast.
- * XXX - this *does* search in the current directory, right?
- */
-
- prefEnd = strrchr(cfname, '/');
- if (prefEnd != NULL) {
- char *newName;
-
- *prefEnd = '\0';
- newName = str_concat(cfname, file, STR_ADDSLASH);
- fullname = Dir_FindFile(newName, parseIncPath);
- if (fullname == NULL) {
- fullname = Dir_FindFile(newName, dirSearchPath);
- }
- free(newName);
- *prefEnd = '/';
- } else {
- fullname = NULL;
- }
-
- if (fullname == NULL) {
- /*
- * System makefile or makefile wasn't found in same directory as
- * included makefile. Search for it first on the -I search path,
- * then on the .PATH search path, if not found in a
- * -I directory. XXX: Suffix specific?
- */
- fullname = Dir_FindFile(file, parseIncPath);
- if (fullname == NULL) {
- fullname = Dir_FindFile(file, dirSearchPath);
- }
- }
-
- if (fullname == NULL) {
- /*
- * Still haven't found the makefile. Look for it on the system
- * path as a last resort.
- */
- fullname = Dir_FindFile(file,
- Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
- }
-
- if (fullname == NULL) {
- if (!silent)
- ParseErrorInternal(cfname, clineno, PARSE_FATAL,
- "Could not find %s", file);
- free(file);
- continue;
- }
-
- free(file);
-
- /*
- * Once we find the absolute path to the file, we get to save all
- * the state from the current file before we can start reading this
- * include file. The state is stored in an IFile structure which
- * is placed on a list with other IFile structures. The list makes
- * a very nice stack to track how we got here...
- */
- oldFile = emalloc(sizeof(IFile));
- memcpy(oldFile, &curFile, sizeof(IFile));
-
- (void)Lst_AtFront(includes, (ClientData)oldFile);
-
- /*
- * Once the previous state has been saved, we can get down to
- * reading the new file. We set up the name of the file to be the
- * absolute name of the include file so error messages refer to the
- * right place. Naturally enough, we start reading at line number 0.
- */
- curFile.fname = fullname;
- curFile.lineno = 0;
-
- curFile.F = fopen(fullname, "r");
- curFile.P = NULL;
-
- if (curFile.F == NULL) {
- if (!silent)
- ParseErrorInternal(cfname, clineno, PARSE_FATAL,
- "Cannot open %s", fullname);
- /*
- * Pop to previous file
- */
- (void)ParseEOF(1);
- }
+ Parse_include_file(file, FALSE, silent);
}
+ free(all_files);
}
#endif
@@ -2266,149 +2107,236 @@ ParseTraditionalInclude(char *line)
*---------------------------------------------------------------------
*/
static int
-ParseEOF(int opened)
+ParseEOF(void)
{
- IFile *ifile; /* the state on the top of the includes stack */
+ /* Ensure the makefile (or loop) didn't have mismatched conditionals */
+ Cond_restore_depth(curFile->cond_depth);
- if (Lst_IsEmpty(includes)) {
- Var_Delete(".PARSEDIR", VAR_GLOBAL);
- Var_Delete(".PARSEFILE", VAR_GLOBAL);
- return (DONE);
- }
+ /* Dispose of curFile info */
+ /* Leak curFile->fname because all the gnodes have pointers to it */
+ if (curFile->fd != -1)
+ close(curFile->fd);
+ free(curFile->P_str);
+ free(curFile);
- ifile = (IFile *)Lst_DeQueue(includes);
+ curFile = Lst_DeQueue(includes);
- /* XXX dispose of curFile info */
- free( curFile.fname);
- if (opened && curFile.F)
- (void)fclose(curFile.F);
- if (curFile.P) {
- free(curFile.P->str);
- free(curFile.P);
+ if (curFile == (IFile *)NIL) {
+ /* We've run out of input */
+ Var_Delete(".PARSEDIR", VAR_GLOBAL);
+ Var_Delete(".PARSEFILE", VAR_GLOBAL);
+ return DONE;
}
- memcpy(&curFile, ifile, sizeof(IFile));
+ if (DEBUG(PARSE))
+ fprintf(debug_file, "ParseEOF: returning to file %s, line %d, fd %d\n",
+ curFile->fname, curFile->lineno, curFile->fd);
- free(ifile);
-
- /* pop the PARSEDIR/PARSEFILE variables */
- ParseSetParseFile(curFile.fname);
+ /* Restore the PARSEDIR/PARSEFILE variables */
+ ParseSetParseFile(curFile->fname);
return (CONTINUE);
}
-/*-
- *---------------------------------------------------------------------
- * ParseReadc --
- * Read a character from the current file
- *
- * Results:
- * The character that was read
- *
- * Side Effects:
- *---------------------------------------------------------------------
- */
-static __inline int
-ParseReadc(void)
+#define PARSE_RAW 1
+#define PARSE_SKIP 2
+
+static char *
+ParseGetLine(int flags, int *length)
{
- if (curFile.F)
- return fgetc(curFile.F);
+ IFile *cf = curFile;
+ char *ptr;
+ char ch;
+ char *line;
+ char *line_end;
+ char *escaped;
+ char *comment;
+ char *tp;
+ int len, dist;
- if (curFile.P && *curFile.P->ptr)
- return *curFile.P->ptr++;
- return EOF;
-}
+ /* Loop through blank lines and comment lines */
+ for (;;) {
+ cf->lineno++;
+ line = cf->P_ptr;
+ ptr = line;
+ line_end = line;
+ escaped = NULL;
+ comment = NULL;
+ for (;;) {
+ ch = *ptr;
+ if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
+ if (cf->P_end == NULL)
+ /* End of string (aka for loop) data */
+ break;
+ /* End of data read from file, read more data */
+ if (ptr != cf->P_end && (ch != '\\' || ptr + 1 != cf->P_end)) {
+ Parse_Error(PARSE_FATAL, "Zero byte read from file");
+ return NULL;
+ }
+ /* Move existing data to (near) start of file buffer */
+ len = cf->P_end - cf->P_ptr;
+ tp = cf->P_str + 32;
+ memmove(tp, cf->P_ptr, len);
+ dist = cf->P_ptr - tp;
+ /* Update all pointers to reflect moved data */
+ ptr -= dist;
+ line -= dist;
+ line_end -= dist;
+ if (escaped)
+ escaped -= dist;
+ if (comment)
+ comment -= dist;
+ cf->P_ptr = tp;
+ tp += len;
+ cf->P_end = tp;
+ /* Try to read more data from file into buffer space */
+ len = cf->P_str + cf->P_buflen - tp - 32;
+ if (len <= 0) {
+ /* We need a bigger buffer to hold this line */
+ tp = erealloc(cf->P_str, cf->P_buflen + IFILE_BUFLEN);
+ cf->P_end = cf->P_end - cf->P_str + tp;
+ ptr = ptr - cf->P_str + tp;
+ line = line - cf->P_str + tp;
+ line_end = line_end - cf->P_str + tp;
+ if (escaped)
+ escaped = escaped - cf->P_str + tp;
+ if (comment)
+ comment = comment - cf->P_str + tp;
+ cf->P_str = tp;
+ tp = cf->P_end;
+ len += IFILE_BUFLEN;
+ cf->P_buflen += IFILE_BUFLEN;
+ }
+ len = read(cf->fd, tp, len);
+ if (len <= 0) {
+ if (len < 0) {
+ Parse_Error(PARSE_FATAL, "Makefile read error: %s",
+ strerror(errno));
+ return NULL;
+ }
+ /* End of file */
+ break;
+ }
+ /* 0 terminate the data, and update end pointer */
+ tp += len;
+ cf->P_end = tp;
+ *tp = 0;
+ /* Process newly read characters */
+ continue;
+ }
+ if (ch == '\\') {
+ /* Don't treat next character as special, remember first one */
+ if (escaped == NULL)
+ escaped = ptr;
+ if (ptr[1] == '\n')
+ cf->lineno++;
+ ptr += 2;
+ line_end = ptr;
+ continue;
+ }
+ if (ch == '#' && comment == NULL) {
+ /* Remember first '#' for comment stripping */
+ comment = line_end;
+ }
+ ptr++;
+ if (ch == '\n')
+ break;
+ if (!isspace((unsigned char)ch))
+ /* We are not interested in trailing whitespace */
+ line_end = ptr;
+ }
-/*-
- *---------------------------------------------------------------------
- * ParseUnreadc --
- * Put back a character to the current file
- *
- * Results:
- * None.
- *
- * Side Effects:
- *---------------------------------------------------------------------
- */
-static void
-ParseUnreadc(int c)
-{
- if (curFile.F) {
- ungetc(c, curFile.F);
- return;
+ /* Save next 'to be processed' location */
+ cf->P_ptr = ptr;
+
+ /* Check we have a non-comment, non-blank line */
+ if (line_end == line || comment == line) {
+ if (ch == 0)
+ /* At end of file */
+ return NULL;
+ /* Parse another line */
+ continue;
+ }
+
+ /* We now have a line of data */
+ *line_end = 0;
+
+ if (flags & PARSE_RAW) {
+ /* Leave '\' (etc) in line buffer (eg 'for' lines) */
+ *length = line_end - line;
+ return line;
+ }
+
+ if (flags & PARSE_SKIP) {
+ /* Completely ignore non-directives */
+ if (line[0] != '.')
+ continue;
+ /* We could do more of the .else/.elif/.endif checks here */
+ }
+ break;
}
- if (curFile.P) {
- *--(curFile.P->ptr) = c;
- return;
+
+ /* Brutally ignore anything after a non-escaped '#' in non-commands */
+ if (comment != NULL && line[0] != '\t') {
+ line_end = comment;
+ *line_end = 0;
+ }
+
+ /* If we didn't see a '\\' then the in-situ data is fine */
+ if (escaped == NULL) {
+ *length = line_end - line;
+ return line;
}
-}
+ /* Remove escapes from '\n' and '#' */
+ tp = ptr = escaped;
+ escaped = line;
+ for (; ; *tp++ = ch) {
+ ch = *ptr++;
+ if (ch != '\\') {
+ if (ch == 0)
+ break;
+ continue;
+ }
-/* ParseSkipLine():
- * Grab the next line
- *
- * Input:
- * skip Skip lines that don't start with .
- * keep_newline Keep newline character as is.
- *
- */
-static char *
-ParseSkipLine(int skip, int keep_newline)
-{
- char *line;
- int c, lastc, lineLength = 0;
- Buffer buf;
+ ch = *ptr++;
+ if (ch == 0) {
+ /* Delete '\\' at end of buffer */
+ tp--;
+ break;
+ }
- buf = Buf_Init(MAKE_BSIZE);
+ if (ch == '#' && line[0] != '\t')
+ /* Delete '\\' from before '#' on non-command lines */
+ continue;
- do {
- Buf_Discard(buf, lineLength);
- lastc = '\0';
-
- while (((c = ParseReadc()) != '\n' || lastc == '\\')
- && c != EOF) {
- if (c == '\n') {
- if (keep_newline)
- Buf_AddByte(buf, (Byte)c);
- else
- Buf_ReplaceLastByte(buf, (Byte)' ');
- curFile.lineno++;
-
- while ((c = ParseReadc()) == ' ' || c == '\t');
-
- if (c == EOF)
- break;
- }
-
- Buf_AddByte(buf, (Byte)c);
- lastc = c;
- }
-
- if (c == EOF) {
- Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop");
- Buf_Destroy(buf, TRUE);
- return(NULL);
- }
-
- curFile.lineno++;
- Buf_AddByte(buf, (Byte)'\0');
- line = (char *)Buf_GetAll(buf, &lineLength);
- } while (skip == 1 && line[0] != '.');
-
- Buf_Destroy(buf, FALSE);
+ if (ch != '\n') {
+ /* Leave '\\' in buffer for later */
+ *tp++ = '\\';
+ /* Make sure we don't delete an escaped ' ' from the line end */
+ escaped = tp + 1;
+ continue;
+ }
+
+ /* Escaped '\n' replace following whitespace with a single ' ' */
+ while (ptr[0] == ' ' || ptr[0] == '\t')
+ ptr++;
+ ch = ' ';
+ }
+
+ /* Delete any trailing spaces - eg from empty continuations */
+ while (tp > escaped && isspace((unsigned char)tp[-1]))
+ tp--;
+
+ *tp = 0;
+ *length = tp - line;
return line;
}
-
/*-
*---------------------------------------------------------------------
* ParseReadLine --
* Read an entire line from the input file. Called only by Parse_File.
- * To facilitate escaped newlines and what have you, a character is
- * buffered in 'lastc', which is '\0' when no characters have been
- * read. When we break out of the loop, c holds the terminating
- * character and lastc holds a character that should be added to
- * the line (unless we don't read anything but a terminator).
*
* Results:
* A line w/o its newline
@@ -2420,255 +2348,52 @@ ParseSkipLine(int skip, int keep_newline)
static char *
ParseReadLine(void)
{
- Buffer buf; /* Buffer for current line */
- int c; /* the current character */
- int lastc; /* The most-recent character */
- Boolean semiNL; /* treat semi-colons as newlines */
- Boolean ignDepOp; /* TRUE if should ignore dependency operators
- * for the purposes of setting semiNL */
- Boolean ignComment; /* TRUE if should ignore comments (in a
- * shell command */
char *line; /* Result */
- char *ep; /* to strip trailing blanks */
int lineLength; /* Length of result */
int lineno; /* Saved line # */
- semiNL = FALSE;
- ignDepOp = FALSE;
- ignComment = FALSE;
-
- /*
- * Handle special-characters at the beginning of the line. Either a
- * leading tab (shell command) or pound-sign (possible conditional)
- * forces us to ignore comments and dependency operators and treat
- * semi-colons as semi-colons (by leaving semiNL FALSE). This also
- * discards completely blank lines.
- */
for (;;) {
- c = ParseReadc();
-
- if (c == '\t') {
- ignComment = ignDepOp = TRUE;
- break;
- } else if (c == '\n') {
- curFile.lineno++;
- } else if (c == '#') {
- ParseUnreadc(c);
- break;
- } else {
- /*
- * Anything else breaks out without doing anything
- */
- break;
- }
- }
+ line = ParseGetLine(0, &lineLength);
+ if (line == NULL)
+ return NULL;
- if (c != EOF) {
- lastc = c;
- buf = Buf_Init(MAKE_BSIZE);
-
- while (((c = ParseReadc()) != '\n' || (lastc == '\\')) &&
- (c != EOF))
- {
-test_char:
- switch(c) {
- case '\n':
- /*
- * Escaped newline: read characters until a non-space or an
- * unescaped newline and replace them all by a single space.
- * This is done by storing the space over the backslash and
- * dropping through with the next nonspace. If it is a
- * semi-colon and semiNL is TRUE, it will be recognized as a
- * newline in the code below this...
- */
- curFile.lineno++;
- lastc = ' ';
- while ((c = ParseReadc()) == ' ' || c == '\t') {
- continue;
- }
- if (c == EOF || c == '\n') {
- goto line_read;
- } else {
- /*
- * Check for comments, semiNL's, etc. -- easier than
- * ParseUnreadc(c); continue;
- */
- goto test_char;
- }
- /*NOTREACHED*/
- break;
-
- case ';':
- /*
- * Semi-colon: Need to see if it should be interpreted as a
- * newline
- */
- if (semiNL) {
- /*
- * To make sure the command that may be following this
- * semi-colon begins with a tab, we push one back into the
- * input stream. This will overwrite the semi-colon in the
- * buffer. If there is no command following, this does no
- * harm, since the newline remains in the buffer and the
- * whole line is ignored.
- */
- ParseUnreadc('\t');
- goto line_read;
- }
- break;
- case '=':
- if (!semiNL) {
- /*
- * Haven't seen a dependency operator before this, so this
- * must be a variable assignment -- don't pay attention to
- * dependency operators after this.
- */
- ignDepOp = TRUE;
- } else if (lastc == ':' || lastc == '!') {
- /*
- * Well, we've seen a dependency operator already, but it
- * was the previous character, so this is really just an
- * expanded variable assignment. Revert semi-colons to
- * being just semi-colons again and ignore any more
- * dependency operators.
- *
- * XXX: Note that a line like "foo : a:=b" will blow up,
- * but who'd write a line like that anyway?
- */
- ignDepOp = TRUE; semiNL = FALSE;
- }
- break;
- case '#':
- if (!ignComment) {
- if (
-#if 0
- compatMake &&
-#endif
- (lastc != '\\')) {
- /*
- * If the character is a hash mark and it isn't escaped
- * (or we're being compatible), the thing is a comment.
- * Skip to the end of the line.
- */
- do {
- c = ParseReadc();
- /*
- * If we found a backslash not escaped
- * itself it means that the comment is
- * going to continue in the next line.
- */
- if (c == '\\')
- ParseReadc();
- } while ((c != '\n') && (c != EOF));
- goto line_read;
- } else {
- /*
- * Don't add the backslash. Just let the # get copied
- * over.
- */
- lastc = c;
- continue;
- }
- }
- break;
- case ':':
- case '!':
- if (!ignDepOp && (c == ':' || c == '!')) {
- /*
- * A semi-colon is recognized as a newline only on
- * dependency lines. Dependency lines are lines with a
- * colon or an exclamation point. Ergo...
- */
- semiNL = TRUE;
- }
- break;
- }
- /*
- * Copy in the previous character and save this one in lastc.
- */
- Buf_AddByte(buf, (Byte)lastc);
- lastc = c;
-
- }
- line_read:
- curFile.lineno++;
-
- if (lastc != '\0') {
- Buf_AddByte(buf, (Byte)lastc);
- }
- Buf_AddByte(buf, (Byte)'\0');
- line = (char *)Buf_GetAll(buf, &lineLength);
- Buf_Destroy(buf, FALSE);
+ if (line[0] != '.')
+ return line;
/*
- * Strip trailing blanks and tabs from the line.
- * Do not strip a blank or tab that is preceded by
- * a '\'
+ * The line might be a conditional. Ask the conditional module
+ * about it and act accordingly
*/
- ep = line;
- while (*ep)
- ++ep;
- while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {
- if (ep > line + 1 && ep[-2] == '\\')
+ switch (Cond_Eval(line)) {
+ case COND_SKIP:
+ /* Skip to next conditional that evaluates to COND_PARSE. */
+ do {
+ line = ParseGetLine(PARSE_SKIP, &lineLength);
+ } while (line && Cond_Eval(line) != COND_PARSE);
+ if (line == NULL)
break;
- --ep;
- }
- *ep = 0;
-
- if (line[0] == '.') {
- /*
- * The line might be a conditional. Ask the conditional module
- * about it and act accordingly
- */
- switch (Cond_Eval(line)) {
- case COND_SKIP:
- /*
- * Skip to next conditional that evaluates to COND_PARSE.
- */
- do {
- free(line);
- line = ParseSkipLine(1, 0);
- } while (line && Cond_Eval(line) != COND_PARSE);
- if (line == NULL)
- break;
- /*FALLTHRU*/
- case COND_PARSE:
- free(line);
- line = ParseReadLine();
+ continue;
+ case COND_PARSE:
+ continue;
+ case COND_INVALID: /* Not a conditional line */
+ if (!For_Eval(line))
break;
- case COND_INVALID:
- lineno = curFile.lineno;
- if (For_Eval(line)) {
- int ok;
- free(line);
- do {
- /*
- * Skip after the matching end
- */
- line = ParseSkipLine(0, 1);
- if (line == NULL) {
- Parse_Error(PARSE_FATAL,
- "Unexpected end of file in for loop.\n");
- break;
- }
- ok = For_Eval(line);
- free(line);
- }
- while (ok);
- if (line != NULL)
- For_Run(lineno);
- line = ParseReadLine();
+ lineno = curFile->lineno;
+ /* Skip after the matching end */
+ do {
+ line = ParseGetLine(PARSE_RAW, &lineLength);
+ if (line == NULL) {
+ Parse_Error(PARSE_FATAL,
+ "Unexpected end of file in for loop.\n");
+ break;
}
- break;
- }
+ } while (For_Eval(line));
+ /* Stash each iteration as a new 'input file' */
+ For_Run(lineno);
+ /* Read next line from for-loop buffer */
+ continue;
}
return (line);
-
- } else {
- /*
- * Hit end-of-file, so return a NULL line to indicate this.
- */
- return(NULL);
}
}
@@ -2689,7 +2414,7 @@ static void
ParseFinishLine(void)
{
if (inLine) {
- Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
+ Lst_ForEach(targets, Suff_EndTransform, NULL);
Lst_Destroy(targets, ParseHasCommands);
targets = NULL;
inLine = FALSE;
@@ -2706,190 +2431,190 @@ ParseFinishLine(void)
*
* Input:
* name the name of the file being read
- * stream Stream open to makefile to parse
+ * fd Open file to makefile to parse
*
* Results:
* None
*
* Side Effects:
+ * closes fd.
* Loads. Nodes are added to the list of all targets, nodes and links
* are added to the dependency graph. etc. etc. etc.
*---------------------------------------------------------------------
*/
void
-Parse_File(const char *name, FILE *stream)
+Parse_File(const char *name, int fd)
{
- char *cp, /* pointer into the line */
- *line; /* the line we're working on */
+ char *cp; /* pointer into the line */
+ char *line; /* the line we're working on */
inLine = FALSE;
fatals = 0;
- curFile.fname = UNCONST(name);
- curFile.F = stream;
- curFile.lineno = 0;
-
- ParseSetParseFile(curFile.fname);
+ Parse_SetInput(name, 0, fd, NULL);
do {
- while ((line = ParseReadLine()) != NULL) {
+ for (; (line = ParseReadLine()) != NULL; ) {
+ if (DEBUG(PARSE))
+ fprintf(debug_file, "ParseReadLine (%d): '%s'\n",
+ curFile->lineno, line);
if (*line == '.') {
/*
* Lines that begin with the special character are either
* include or undef directives.
*/
- for (cp = line + 1; isspace ((unsigned char)*cp); cp++) {
+ for (cp = line + 1; isspace((unsigned char)*cp); cp++) {
continue;
}
if (strncmp(cp, "include", 7) == 0 ||
- ((cp[0] == 's' || cp[0] == '-') &&
- strncmp(&cp[1], "include", 7) == 0)) {
+ ((cp[0] == 's' || cp[0] == '-') &&
+ strncmp(&cp[1], "include", 7) == 0)) {
ParseDoInclude(cp);
- goto nextLine;
- } else if (strncmp(cp, "undef", 5) == 0) {
+ continue;
+ }
+ if (strncmp(cp, "undef", 5) == 0) {
char *cp2;
- for (cp += 5; isspace((unsigned char) *cp); cp++) {
+ for (cp += 5; isspace((unsigned char) *cp); cp++)
continue;
- }
-
for (cp2 = cp; !isspace((unsigned char) *cp2) &&
- (*cp2 != '\0'); cp2++) {
+ (*cp2 != '\0'); cp2++)
continue;
- }
-
*cp2 = '\0';
-
Var_Delete(cp, VAR_GLOBAL);
- goto nextLine;
+ continue;
+ } else if (strncmp(cp, "export", 6) == 0) {
+ for (cp += 6; isspace((unsigned char) *cp); cp++)
+ continue;
+ Var_Export(cp, 1);
+ continue;
}
}
- if (*line == '#') {
- /* If we're this far, the line must be a comment. */
- goto nextLine;
- }
if (*line == '\t') {
/*
* If a line starts with a tab, it can only hope to be
* a creation command.
*/
-#ifndef POSIX
- shellCommand:
-#endif
- for (cp = line + 1; isspace ((unsigned char)*cp); cp++) {
+ cp = line + 1;
+ shellCommand:
+ for (; isspace ((unsigned char)*cp); cp++) {
continue;
}
if (*cp) {
- if (inLine) {
- /*
- * So long as it's not a blank line and we're actually
- * in a dependency spec, add the command to the list of
- * commands of all targets in the dependency spec
- */
- Lst_ForEach(targets, ParseAddCmd, cp);
-#ifdef CLEANUP
- Lst_AtEnd(targCmds, (ClientData) line);
-#endif
- continue;
- } else {
+ if (!inLine)
Parse_Error(PARSE_FATAL,
"Unassociated shell command \"%s\"",
cp);
+ /*
+ * So long as it's not a blank line and we're actually
+ * in a dependency spec, add the command to the list of
+ * commands of all targets in the dependency spec
+ */
+ if (targets) {
+ cp = estrdup(cp);
+ Lst_ForEach(targets, ParseAddCmd, cp);
+#ifdef CLEANUP
+ Lst_AtEnd(targCmds, cp);
+#endif
}
}
+ continue;
+ }
+
#ifdef SYSVINCLUDE
- } else if (((strncmp(line, "include", 7) == 0 &&
- isspace((unsigned char) line[7])) ||
- ((line[0] == 's' || line[0] == '-') &&
- strncmp(&line[1], "include", 7) == 0 &&
- isspace((unsigned char) line[8]))) &&
- strchr(line, ':') == NULL) {
+ if (((strncmp(line, "include", 7) == 0 &&
+ isspace((unsigned char) line[7])) ||
+ ((line[0] == 's' || line[0] == '-') &&
+ strncmp(&line[1], "include", 7) == 0 &&
+ isspace((unsigned char) line[8]))) &&
+ strchr(line, ':') == NULL) {
/*
* It's an S3/S5-style "include".
*/
ParseTraditionalInclude(line);
- goto nextLine;
+ continue;
+ }
#endif
- } else if (Parse_IsVar(line)) {
+ if (Parse_IsVar(line)) {
ParseFinishLine();
Parse_DoVar(line, VAR_GLOBAL);
- } else {
- /*
- * We now know it's a dependency line so it needs to have all
- * variables expanded before being parsed. Tell the variable
- * module to complain if some variable is undefined...
- * To make life easier on novices, if the line is indented we
- * first make sure the line has a dependency operator in it.
- * If it doesn't have an operator and we're in a dependency
- * line's script, we assume it's actually a shell command
- * and add it to the current list of targets.
- */
-#ifndef POSIX
- Boolean nonSpace = FALSE;
-#endif
+ continue;
+ }
- cp = line;
- if (isspace((unsigned char) line[0])) {
- while ((*cp != '\0') && isspace((unsigned char) *cp)) {
- cp++;
- }
- if (*cp == '\0') {
- goto nextLine;
- }
#ifndef POSIX
- while (*cp && (ParseIsEscaped(line, cp) ||
+ /*
+ * To make life easier on novices, if the line is indented we
+ * first make sure the line has a dependency operator in it.
+ * If it doesn't have an operator and we're in a dependency
+ * line's script, we assume it's actually a shell command
+ * and add it to the current list of targets.
+ */
+ cp = line;
+ if (isspace((unsigned char) line[0])) {
+ while ((*cp != '\0') && isspace((unsigned char) *cp))
+ cp++;
+ while (*cp && (ParseIsEscaped(line, cp) ||
(*cp != ':') && (*cp != '!'))) {
- nonSpace = TRUE;
- cp++;
- }
-#endif
+ cp++;
}
-
-#ifndef POSIX
if (*cp == '\0') {
if (inLine) {
Parse_Error(PARSE_WARNING,
"Shell command needs a leading tab");
goto shellCommand;
- } else if (nonSpace) {
- Parse_Error(PARSE_FATAL, "Missing operator");
}
- } else {
+ }
+ }
#endif
- ParseFinishLine();
+ ParseFinishLine();
- cp = Var_Subst(NULL, line, VAR_CMD, TRUE);
- free(line);
- line = cp;
-
- /*
- * Need a non-circular list for the target nodes
- */
- if (targets)
- Lst_Destroy(targets, NOFREE);
-
- targets = Lst_Init(FALSE);
- inLine = TRUE;
-
- ParseDoDependency(line);
-#ifndef POSIX
+ /*
+ * For some reason - probably to make the parser impossible -
+ * a ';' can be used to separate commands from dependencies.
+ * No attempt is made to avoid ';' inside substitution patterns.
+ */
+ for (cp = line; *cp != 0; cp++) {
+ if (*cp == '\\' && cp[1] != 0) {
+ cp++;
+ continue;
}
-#endif
+ if (*cp == ';')
+ break;
}
+ if (*cp != 0)
+ /* Terminate the dependency list at the ';' */
+ *cp++ = 0;
+ else
+ cp = NULL;
+
+ /*
+ * We now know it's a dependency line so it needs to have all
+ * variables expanded before being parsed. Tell the variable
+ * module to complain if some variable is undefined...
+ */
+ line = Var_Subst(NULL, line, VAR_CMD, TRUE);
- nextLine:
+ /*
+ * Need a non-circular list for the target nodes
+ */
+ if (targets)
+ Lst_Destroy(targets, NOFREE);
+ targets = Lst_Init(FALSE);
+ inLine = TRUE;
+
+ ParseDoDependency(line);
free(line);
+
+ /* If there were commands after a ';', add them now */
+ if (cp != NULL) {
+ goto shellCommand;
+ }
}
/*
* Reached EOF, but it may be just EOF of an include file...
*/
- } while (ParseEOF(1) == CONTINUE);
-
- /*
- * Make sure conditionals are clean
- */
- Cond_End();
+ } while (ParseEOF() == CONTINUE);
if (fatals) {
(void)fprintf(stderr,
@@ -2965,11 +2690,11 @@ Parse_MainName(void)
Punt("no target to make.");
/*NOTREACHED*/
} else if (mainNode->type & OP_DOUBLEDEP) {
- (void)Lst_AtEnd(mainList, (ClientData)mainNode);
+ (void)Lst_AtEnd(mainList, mainNode);
Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW);
}
else
- (void)Lst_AtEnd(mainList, (ClientData)mainNode);
+ (void)Lst_AtEnd(mainList, mainNode);
Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
return (mainList);
}
@@ -2988,6 +2713,6 @@ Parse_MainName(void)
static void
ParseMark(GNode *gn)
{
- gn->fname = strdup(curFile.fname);
- gn->lineno = curFile.lineno;
+ gn->fname = curFile->fname;
+ gn->lineno = curFile->lineno;
}
diff --git a/devel/bmake/files/sigcompat.c b/devel/bmake/files/sigcompat.c
index b196ac995b6..e62aea1296d 100644
--- a/devel/bmake/files/sigcompat.c
+++ b/devel/bmake/files/sigcompat.c
@@ -89,6 +89,9 @@
# include "config.h"
#endif
#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#if defined(sun) && !(defined(__svr4__) || defined(__SVR4))
# define NO_SIGCOMPAT
@@ -98,7 +101,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)sigcompat.c 5.3 (Berkeley) 2/24/91";*/
-static char *rcsid = "$Id: sigcompat.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char *rcsid = "$Id: sigcompat.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#endif /* LIBC_SCCS and not lint */
#undef signal
@@ -126,14 +129,14 @@ static char *rcsid = "$Id: sigcompat.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
#endif
#ifndef MASK_T
-# ifdef __hpux__
+# if defined(__hpux__) || defined(__hpux)
# define MASK_T long
# else
# define MASK_T int
# endif
#endif
/* I just hate HPsUX */
-#if defined(__HPUX_VERSION) && __HPUX_VERSION > 9
+#if (defined(__HPUX_VERSION) && __HPUX_VERSION > 9) || defined(__hpux)
# define PAUSE_MASK_T int
#else
# define PAUSE_MASK_T MASK_T
diff --git a/devel/bmake/files/str.c b/devel/bmake/files/str.c
index 217f5efb48f..04f27863bfe 100644
--- a/devel/bmake/files/str.c
+++ b/devel/bmake/files/str.c
@@ -1,4 +1,4 @@
-/* $NetBSD: str.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: str.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*-
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: str.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: str.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
#else
-__RCSID("$NetBSD: str.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: str.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -128,8 +128,14 @@ str_concat(const char *s1, const char *s2, int flags)
* spaces) taking quotation marks into account. Leading tabs/spaces
* are ignored.
*
+ * If expand is TRUE, quotes are removed and escape sequences
+ * such as \r, \t, etc... are expanded.
+ *
* returns --
* Pointer to the array of pointers to the words.
+ * Memory containing the actual words in *buffer.
+ * Both of these must be free'd by the caller.
+ * Number of words in *store_argc.
*/
char **
brk_string(const char *str, int *store_argc, Boolean expand, char **buffer)
@@ -170,6 +176,8 @@ brk_string(const char *str, int *store_argc, Boolean expand, char **buffer)
/* Don't miss "" or '' */
if (start == NULL && p[1] == inquote) {
start = t + 1;
+ p++;
+ inquote = '\0';
break;
}
}
@@ -211,6 +219,8 @@ brk_string(const char *str, int *store_argc, Boolean expand, char **buffer)
if (!start)
start = t;
*t++ = '\\';
+ if (*(p+1) == '\0') // catch '\' at end of line
+ continue;
ch = *++p;
break;
}
diff --git a/devel/bmake/files/suff.c b/devel/bmake/files/suff.c
index 79dd0b005e2..acfd62214e6 100644
--- a/devel/bmake/files/suff.c
+++ b/devel/bmake/files/suff.c
@@ -1,4 +1,4 @@
-/* $NetBSD: suff.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: suff.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: suff.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: suff.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
#else
-__RCSID("$NetBSD: suff.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: suff.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -230,7 +230,8 @@ static int SuffRemoveSrc(Lst);
static void SuffAddLevel(Lst, Src *);
static Src *SuffFindThem(Lst, Lst);
static Src *SuffFindCmds(Src *, Lst);
-static int SuffExpandChildren(LstNode, GNode *);
+static void SuffExpandChildren(LstNode, GNode *);
+static void SuffExpandWildcards(LstNode, GNode *);
static Boolean SuffApplyTransform(GNode *, GNode *, Suff *, Suff *);
static void SuffFindDeps(GNode *, Lst);
static void SuffFindArchiveDeps(GNode *, Lst);
@@ -464,10 +465,10 @@ SuffFree(ClientData sp)
static void
SuffRemove(Lst l, Suff *s)
{
- SuffUnRef((ClientData) l, (ClientData) s);
+ SuffUnRef(l, s);
if (s->refCount == 0) {
- SuffUnRef((ClientData) sufflist, (ClientData) s);
- SuffFree((ClientData) s);
+ SuffUnRef(sufflist, s);
+ SuffFree(s);
}
}
@@ -506,24 +507,24 @@ SuffInsert(Lst l, Suff *s)
Lst_Close(l);
if (DEBUG(SUFF)) {
- printf("inserting %s(%d)...", s->name, s->sNum);
+ fprintf(debug_file, "inserting %s(%d)...", s->name, s->sNum);
}
if (ln == NILLNODE) {
if (DEBUG(SUFF)) {
- printf("at end of list\n");
+ fprintf(debug_file, "at end of list\n");
}
- (void)Lst_AtEnd(l, (ClientData)s);
+ (void)Lst_AtEnd(l, s);
s->refCount++;
- (void)Lst_AtEnd(s->ref, (ClientData) l);
+ (void)Lst_AtEnd(s->ref, l);
} else if (s2->sNum != s->sNum) {
if (DEBUG(SUFF)) {
- printf("before %s(%d)\n", s2->name, s2->sNum);
+ fprintf(debug_file, "before %s(%d)\n", s2->name, s2->sNum);
}
- (void)Lst_Insert(l, ln, (ClientData)s);
+ (void)Lst_InsertBefore(l, ln, s);
s->refCount++;
- (void)Lst_AtEnd(s->ref, (ClientData) l);
+ (void)Lst_AtEnd(s->ref, l);
} else if (DEBUG(SUFF)) {
- printf("already there\n");
+ fprintf(debug_file, "already there\n");
}
}
@@ -596,9 +597,9 @@ SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr)
*/
for (;;) {
if (srcLn == NILLNODE) {
- srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix);
+ srcLn = Lst_Find(sufflist, str, SuffSuffIsPrefix);
} else {
- srcLn = Lst_FindFrom(sufflist, Lst_Succ(srcLn), (ClientData)str,
+ srcLn = Lst_FindFrom(sufflist, Lst_Succ(srcLn), str,
SuffSuffIsPrefix);
}
if (srcLn == NILLNODE) {
@@ -627,7 +628,7 @@ SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr)
single = src;
singleLn = srcLn;
} else {
- targLn = Lst_Find(sufflist, (ClientData)str2, SuffSuffHasNameP);
+ targLn = Lst_Find(sufflist, str2, SuffSuffHasNameP);
if (targLn != NILLNODE) {
*srcPtr = src;
*targPtr = (Suff *)Lst_Datum(targLn);
@@ -687,14 +688,14 @@ Suff_AddTransform(char *line)
*t; /* target suffix */
LstNode ln; /* Node for existing transformation */
- ln = Lst_Find(transforms, (ClientData)line, SuffGNHasNameP);
+ ln = Lst_Find(transforms, line, SuffGNHasNameP);
if (ln == NILLNODE) {
/*
* Make a new graph node for the transformation. It will be filled in
* by the Parse module.
*/
gn = Targ_NewGN(line);
- (void)Lst_AtEnd(transforms, (ClientData)gn);
+ (void)Lst_AtEnd(transforms, gn);
} else {
/*
* New specification for transformation rule. Just nuke the old list
@@ -717,7 +718,7 @@ Suff_AddTransform(char *line)
* link the two together in the proper relationship and order
*/
if (DEBUG(SUFF)) {
- printf("defining transformation from `%s' to `%s'\n",
+ fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
s->name, t->name);
}
SuffInsert(t->children, s);
@@ -767,7 +768,7 @@ Suff_EndTransform(ClientData gnp, ClientData dummy)
Lst p;
if (DEBUG(SUFF)) {
- printf("deleting transformation from `%s' to `%s'\n",
+ fprintf(debug_file, "deleting transformation from `%s' to `%s'\n",
s->name, t->name);
}
@@ -792,7 +793,7 @@ Suff_EndTransform(ClientData gnp, ClientData dummy)
SuffRemove(p, t);
}
} else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) {
- printf("transformation %s complete\n", gn->name);
+ fprintf(debug_file, "transformation %s complete\n", gn->name);
}
return(dummy ? 0 : 0);
@@ -836,7 +837,7 @@ SuffRebuildGraph(ClientData transformp, ClientData sp)
*/
cp = SuffStrIsPrefix(s->name, transform->name);
if (cp != NULL) {
- ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, cp, SuffSuffHasNameP);
if (ln != NILLNODE) {
/*
* Found target. Link in and return, since it can't be anything
@@ -860,7 +861,7 @@ SuffRebuildGraph(ClientData transformp, ClientData sp)
* Null-terminate the source suffix in order to find it.
*/
cp[1] = '\0';
- ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, transform->name, SuffSuffHasNameP);
/*
* Replace the start of the target suffix
*/
@@ -908,7 +909,7 @@ SuffScanTargets(ClientData targetp, ClientData gsp)
return 1;
}
- if (target->type == OP_TRANSFORM)
+ if ((unsigned int)target->type == OP_TRANSFORM)
return 0;
if ((ptr = strstr(target->name, gs->s->name)) == NULL ||
@@ -928,7 +929,7 @@ SuffScanTargets(ClientData targetp, ClientData gsp)
* link the two together in the proper relationship and order
*/
if (DEBUG(SUFF)) {
- printf("defining transformation from `%s' to `%s'\n",
+ fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
s->name, t->name);
}
SuffInsert(t->children, s);
@@ -963,7 +964,7 @@ Suff_AddSuffix(char *str, GNode **gn)
LstNode ln;
GNodeSuff gs;
- ln = Lst_Find(sufflist, (ClientData)str, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, str, SuffSuffHasNameP);
if (ln == NILLNODE) {
s = emalloc(sizeof(Suff));
@@ -977,7 +978,7 @@ Suff_AddSuffix(char *str, GNode **gn)
s->flags = 0;
s->refCount = 1;
- (void)Lst_AtEnd(sufflist, (ClientData)s);
+ (void)Lst_AtEnd(sufflist, s);
/*
* We also look at our existing targets list to see if adding
* this suffix will make one of our current targets mutate into
@@ -987,12 +988,12 @@ Suff_AddSuffix(char *str, GNode **gn)
gs.gn = gn;
gs.s = s;
gs.r = FALSE;
- Lst_ForEach(Targ_List(), SuffScanTargets, (ClientData) &gs);
+ Lst_ForEach(Targ_List(), SuffScanTargets, &gs);
/*
* Look for any existing transformations from or to this suffix.
* XXX: Only do this after a Suff_ClearSuffixes?
*/
- Lst_ForEach(transforms, SuffRebuildGraph, (ClientData) s);
+ Lst_ForEach(transforms, SuffRebuildGraph, s);
}
}
@@ -1015,7 +1016,7 @@ Suff_GetPath(char *sname)
LstNode ln;
Suff *s;
- ln = Lst_Find(sufflist, (ClientData)sname, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
if (ln == NILLNODE) {
return (NILLST);
} else {
@@ -1113,7 +1114,7 @@ Suff_AddInclude(char *sname)
LstNode ln;
Suff *s;
- ln = Lst_Find(sufflist, (ClientData)sname, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
if (ln != NILLNODE) {
s = (Suff *)Lst_Datum(ln);
s->flags |= SUFF_INCLUDE;
@@ -1145,7 +1146,7 @@ Suff_AddLib(char *sname)
LstNode ln;
Suff *s;
- ln = Lst_Find(sufflist, (ClientData)sname, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
if (ln != NILLNODE) {
s = (Suff *)Lst_Datum(ln);
s->flags |= SUFF_LIBRARY;
@@ -1197,13 +1198,13 @@ SuffAddSrc(ClientData sp, ClientData lsp)
s->refCount++;
s2->children = 0;
targ->children += 1;
- (void)Lst_AtEnd(ls->l, (ClientData)s2);
+ (void)Lst_AtEnd(ls->l, s2);
#ifdef DEBUG_SRC
s2->cp = Lst_Init(FALSE);
- Lst_AtEnd(targ->cp, (ClientData) s2);
- printf("1 add %x %x to %x:", targ, s2, ls->l);
- Lst_ForEach(ls->l, PrintAddr, (ClientData) 0);
- printf("\n");
+ Lst_AtEnd(targ->cp, s2);
+ fprintf(debug_file, "1 add %x %x to %x:", targ, s2, ls->l);
+ Lst_ForEach(ls->l, PrintAddr, NULL);
+ fprintf(debug_file, "\n");
#endif
}
s2 = emalloc(sizeof(Src));
@@ -1215,13 +1216,13 @@ SuffAddSrc(ClientData sp, ClientData lsp)
s->refCount++;
s2->children = 0;
targ->children += 1;
- (void)Lst_AtEnd(ls->l, (ClientData)s2);
+ (void)Lst_AtEnd(ls->l, s2);
#ifdef DEBUG_SRC
s2->cp = Lst_Init(FALSE);
- Lst_AtEnd(targ->cp, (ClientData) s2);
- printf("2 add %x %x to %x:", targ, s2, ls->l);
- Lst_ForEach(ls->l, PrintAddr, (ClientData) 0);
- printf("\n");
+ Lst_AtEnd(targ->cp, s2);
+ fprintf(debug_file, "2 add %x %x to %x:", targ, s2, ls->l);
+ Lst_ForEach(ls->l, PrintAddr, NULL);
+ fprintf(debug_file, "\n");
#endif
return(0);
@@ -1251,7 +1252,7 @@ SuffAddLevel(Lst l, Src *targ)
ls.s = targ;
ls.l = l;
- Lst_ForEach(targ->suff->children, SuffAddSrc, (ClientData)&ls);
+ Lst_ForEach(targ->suff->children, SuffAddSrc, &ls);
}
/*-
@@ -1277,9 +1278,9 @@ SuffRemoveSrc(Lst l)
return 0;
}
#ifdef DEBUG_SRC
- printf("cleaning %lx: ", (unsigned long) l);
- Lst_ForEach(l, PrintAddr, (ClientData) 0);
- printf("\n");
+ fprintf(debug_file, "cleaning %lx: ", (unsigned long) l);
+ Lst_ForEach(l, PrintAddr, NULL);
+ fprintf(debug_file, "\n");
#endif
@@ -1291,14 +1292,14 @@ SuffRemoveSrc(Lst l)
free(s->pref);
else {
#ifdef DEBUG_SRC
- LstNode ln = Lst_Member(s->parent->cp, (ClientData)s);
+ LstNode ln = Lst_Member(s->parent->cp, s);
if (ln != NILLNODE)
Lst_Remove(s->parent->cp, ln);
#endif
--s->parent->children;
}
#ifdef DEBUG_SRC
- printf("free: [l=%x] p=%x %d\n", l, s, s->children);
+ fprintf(debug_file, "free: [l=%x] p=%x %d\n", l, s, s->children);
Lst_Destroy(s->cp, NOFREE);
#endif
Lst_Remove(l, ln);
@@ -1309,9 +1310,9 @@ SuffRemoveSrc(Lst l)
}
#ifdef DEBUG_SRC
else {
- printf("keep: [l=%x] p=%x %d: ", l, s, s->children);
- Lst_ForEach(s->cp, PrintAddr, (ClientData) 0);
- printf("\n");
+ fprintf(debug_file, "keep: [l=%x] p=%x %d: ", l, s, s->children);
+ Lst_ForEach(s->cp, PrintAddr, NULL);
+ fprintf(debug_file, "\n");
}
#endif
}
@@ -1349,7 +1350,7 @@ SuffFindThem(Lst srcs, Lst slst)
s = (Src *)Lst_DeQueue(srcs);
if (DEBUG(SUFF)) {
- printf("\ttrying %s...", s->file);
+ fprintf(debug_file, "\ttrying %s...", s->file);
}
/*
@@ -1358,7 +1359,7 @@ SuffFindThem(Lst srcs, Lst slst)
*/
if (Targ_FindNode(s->file, TARG_NOCREATE) != NILGNODE) {
#ifdef DEBUG_SRC
- printf("remove %x from %x\n", s, srcs);
+ fprintf(debug_file, "remove %x from %x\n", s, srcs);
#endif
rs = s;
break;
@@ -1367,22 +1368,22 @@ SuffFindThem(Lst srcs, Lst slst)
if ((ptr = Dir_FindFile(s->file, s->suff->searchPath)) != NULL) {
rs = s;
#ifdef DEBUG_SRC
- printf("remove %x from %x\n", s, srcs);
+ fprintf(debug_file, "remove %x from %x\n", s, srcs);
#endif
free(ptr);
break;
}
if (DEBUG(SUFF)) {
- printf("not there\n");
+ fprintf(debug_file, "not there\n");
}
SuffAddLevel(srcs, s);
- Lst_AtEnd(slst, (ClientData) s);
+ Lst_AtEnd(slst, s);
}
if (DEBUG(SUFF) && rs) {
- printf("got it\n");
+ fprintf(debug_file, "got it\n");
}
return (rs);
}
@@ -1428,6 +1429,17 @@ SuffFindCmds(Src *targ, Lst slst)
}
s = (GNode *)Lst_Datum(ln);
+ if (s->type & OP_OPTIONAL && Lst_IsEmpty(t->commands)) {
+ /*
+ * We haven't looked to see if .OPTIONAL files exist yet, so
+ * don't use one as the implicit source.
+ * This allows us to use .OPTIONAL in .depend files so make won't
+ * complain "don't know how to make xxx.h' when a dependant file
+ * has been moved/deleted.
+ */
+ continue;
+ }
+
cp = strrchr(s->name, '/');
if (cp == NULL) {
cp = s->name;
@@ -1440,7 +1452,7 @@ SuffFindCmds(Src *targ, Lst slst)
* The node matches the prefix ok, see if it has a known
* suffix.
*/
- ln = Lst_Find(sufflist, (ClientData)&cp[prefLen],
+ ln = Lst_Find(sufflist, &cp[prefLen],
SuffSuffHasNameP);
if (ln == NILLNODE)
continue;
@@ -1452,7 +1464,7 @@ SuffFindCmds(Src *targ, Lst slst)
*/
suff = (Suff *)Lst_Datum(ln);
- if (Lst_Member(suff->parents, (ClientData)targ->suff) != NILLNODE)
+ if (Lst_Member(suff->parents, targ->suff) != NILLNODE)
break;
}
@@ -1473,12 +1485,12 @@ SuffFindCmds(Src *targ, Lst slst)
targ->children += 1;
#ifdef DEBUG_SRC
ret->cp = Lst_Init(FALSE);
- printf("3 add %x %x\n", targ, ret);
- Lst_AtEnd(targ->cp, (ClientData) ret);
+ fprintf(debug_file, "3 add %x %x\n", targ, ret);
+ Lst_AtEnd(targ->cp, ret);
#endif
- Lst_AtEnd(slst, (ClientData) ret);
+ Lst_AtEnd(slst, ret);
if (DEBUG(SUFF)) {
- printf("\tusing existing source %s\n", s->name);
+ fprintf(debug_file, "\tusing existing source %s\n", s->name);
}
return (ret);
}
@@ -1490,7 +1502,7 @@ SuffFindCmds(Src *targ, Lst slst)
* variable invocations or file wildcards into actual targets.
*
* Input:
- * prevLN Child to examine
+ * cln Child to examine
* pgn Parent node being processed
*
* Results:
@@ -1503,183 +1515,203 @@ SuffFindCmds(Src *targ, Lst slst)
*
*-----------------------------------------------------------------------
*/
-static int
-SuffExpandChildren(LstNode prevLN, GNode *pgn)
+static void
+SuffExpandChildren(LstNode cln, GNode *pgn)
{
- GNode *cgn = (GNode *)Lst_Datum(prevLN);
+ GNode *cgn = (GNode *)Lst_Datum(cln);
GNode *gn; /* New source 8) */
char *cp; /* Expanded value */
+ if (!Lst_IsEmpty(cgn->order_pred) || !Lst_IsEmpty(cgn->order_succ))
+ /* It is all too hard to process the result of .ORDER */
+ return;
+
+ if (cgn->type & OP_WAIT)
+ /* Ignore these (& OP_PHONY ?) */
+ return;
+
/*
* First do variable expansion -- this takes precedence over
* wildcard expansion. If the result contains wildcards, they'll be gotten
* to later since the resulting words are tacked on to the end of
* the children list.
*/
- if (strchr(cgn->name, '$') != NULL) {
- if (DEBUG(SUFF)) {
- printf("Expanding \"%s\"...", cgn->name);
- }
- cp = Var_Subst(NULL, cgn->name, pgn, TRUE);
+ if (strchr(cgn->name, '$') == NULL) {
+ SuffExpandWildcards(cln, pgn);
+ return;
+ }
- if (cp != NULL) {
- Lst members = Lst_Init(FALSE);
+ if (DEBUG(SUFF)) {
+ fprintf(debug_file, "Expanding \"%s\"...", cgn->name);
+ }
+ cp = Var_Subst(NULL, cgn->name, pgn, TRUE);
- if (cgn->type & OP_ARCHV) {
- /*
- * Node was an archive(member) target, so we want to call
- * on the Arch module to find the nodes for us, expanding
- * variables in the parent's context.
- */
- char *sacrifice = cp;
+ if (cp != NULL) {
+ Lst members = Lst_Init(FALSE);
- (void)Arch_ParseArchive(&sacrifice, members, pgn);
- } else {
- /*
- * Break the result into a vector of strings whose nodes
- * we can find, then add those nodes to the members list.
- * Unfortunately, we can't use brk_string b/c it
- * doesn't understand about variable specifications with
- * spaces in them...
- */
- char *start;
- char *initcp = cp; /* For freeing... */
-
- for (start = cp; *start == ' ' || *start == '\t'; start++)
- continue;
- for (cp = start; *cp != '\0'; cp++) {
- if (*cp == ' ' || *cp == '\t') {
- /*
- * White-space -- terminate element, find the node,
- * add it, skip any further spaces.
- */
- *cp++ = '\0';
- gn = Targ_FindNode(start, TARG_CREATE);
- (void)Lst_AtEnd(members, (ClientData)gn);
- while (*cp == ' ' || *cp == '\t') {
- cp++;
- }
- /*
- * Adjust cp for increment at start of loop, but
- * set start to first non-space.
- */
- start = cp--;
- } else if (*cp == '$') {
- /*
- * Start of a variable spec -- contact variable module
- * to find the end so we can skip over it.
- */
- char *junk;
- int len;
- Boolean doFree;
-
- junk = Var_Parse(cp, pgn, TRUE, &len, &doFree);
- if (junk != var_Error) {
- cp += len - 1;
- }
-
- if (doFree) {
- free(junk);
- }
- } else if (*cp == '\\' && *cp != '\0') {
- /*
- * Escaped something -- skip over it
- */
+ if (cgn->type & OP_ARCHV) {
+ /*
+ * Node was an archive(member) target, so we want to call
+ * on the Arch module to find the nodes for us, expanding
+ * variables in the parent's context.
+ */
+ char *sacrifice = cp;
+
+ (void)Arch_ParseArchive(&sacrifice, members, pgn);
+ } else {
+ /*
+ * Break the result into a vector of strings whose nodes
+ * we can find, then add those nodes to the members list.
+ * Unfortunately, we can't use brk_string b/c it
+ * doesn't understand about variable specifications with
+ * spaces in them...
+ */
+ char *start;
+ char *initcp = cp; /* For freeing... */
+
+ for (start = cp; *start == ' ' || *start == '\t'; start++)
+ continue;
+ for (cp = start; *cp != '\0'; cp++) {
+ if (*cp == ' ' || *cp == '\t') {
+ /*
+ * White-space -- terminate element, find the node,
+ * add it, skip any further spaces.
+ */
+ *cp++ = '\0';
+ gn = Targ_FindNode(start, TARG_CREATE);
+ (void)Lst_AtEnd(members, gn);
+ while (*cp == ' ' || *cp == '\t') {
cp++;
}
- }
+ /*
+ * Adjust cp for increment at start of loop, but
+ * set start to first non-space.
+ */
+ start = cp--;
+ } else if (*cp == '$') {
+ /*
+ * Start of a variable spec -- contact variable module
+ * to find the end so we can skip over it.
+ */
+ char *junk;
+ int len;
+ void *freeIt;
+
+ junk = Var_Parse(cp, pgn, TRUE, &len, &freeIt);
+ if (junk != var_Error) {
+ cp += len - 1;
+ }
- if (cp != start) {
+ if (freeIt)
+ free(freeIt);
+ } else if (*cp == '\\' && *cp != '\0') {
/*
- * Stuff left over -- add it to the list too
+ * Escaped something -- skip over it
*/
- gn = Targ_FindNode(start, TARG_CREATE);
- (void)Lst_AtEnd(members, (ClientData)gn);
+ cp++;
}
- /*
- * Point cp back at the beginning again so the variable value
- * can be freed.
- */
- cp = initcp;
}
- /*
- * Add all elements of the members list to the parent node.
- */
- while(!Lst_IsEmpty(members)) {
- gn = (GNode *)Lst_DeQueue(members);
- if (DEBUG(SUFF)) {
- printf("%s...", gn->name);
- }
- if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
- (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
- prevLN = Lst_Succ(prevLN);
- (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
- pgn->unmade++;
- }
+ if (cp != start) {
+ /*
+ * Stuff left over -- add it to the list too
+ */
+ gn = Targ_FindNode(start, TARG_CREATE);
+ (void)Lst_AtEnd(members, gn);
}
- Lst_Destroy(members, NOFREE);
/*
- * Free the result
+ * Point cp back at the beginning again so the variable value
+ * can be freed.
*/
- free(cp);
- }
- /*
- * Now the source is expanded, remove it from the list of children to
- * keep it from being processed.
- */
- if (DEBUG(SUFF)) {
- printf("\n");
+ cp = initcp;
}
- return(1);
- } else if (Dir_HasWildcards(cgn->name)) {
- Lst explist; /* List of expansions */
/*
- * Expand the word along the chosen path
+ * Add all elements of the members list to the parent node.
*/
- explist = Lst_Init(FALSE);
- Dir_Expand(cgn->name, Suff_FindPath(cgn), explist);
-
- while (!Lst_IsEmpty(explist)) {
- /*
- * Fetch next expansion off the list and find its GNode
- */
- cp = (char *)Lst_DeQueue(explist);
+ while(!Lst_IsEmpty(members)) {
+ gn = (GNode *)Lst_DeQueue(members);
if (DEBUG(SUFF)) {
- printf("%s...", cp);
- }
- gn = Targ_FindNode(cp, TARG_CREATE);
-
- /*
- * If gn isn't already a child of the parent, make it so and
- * up the parent's count of unmade children.
- */
- if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
- (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
- prevLN = Lst_Succ(prevLN);
- (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
- pgn->unmade++;
+ fprintf(debug_file, "%s...", gn->name);
}
+ /* Add gn to the parents child list before the original child */
+ (void)Lst_InsertBefore(pgn->children, cln, gn);
+ (void)Lst_AtEnd(gn->parents, pgn);
+ pgn->unmade++;
+ /* Expand wildcards on new node */
+ SuffExpandWildcards(Lst_Prev(cln), pgn);
}
+ Lst_Destroy(members, NOFREE);
/*
- * Nuke what's left of the list
+ * Free the result
*/
- Lst_Destroy(explist, NOFREE);
+ free(cp);
+ }
+ if (DEBUG(SUFF)) {
+ fprintf(debug_file, "\n");
+ }
+ /*
+ * Now the source is expanded, remove it from the list of children to
+ * keep it from being processed.
+ */
+ pgn->unmade--;
+ Lst_Remove(pgn->children, cln);
+ Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
+}
+
+static void
+SuffExpandWildcards(LstNode cln, GNode *pgn)
+{
+ GNode *cgn = (GNode *)Lst_Datum(cln);
+ GNode *gn; /* New source 8) */
+ char *cp; /* Expanded value */
+ Lst explist; /* List of expansions */
+
+ if (!Dir_HasWildcards(cgn->name))
+ return;
+
+ /*
+ * Expand the word along the chosen path
+ */
+ explist = Lst_Init(FALSE);
+ Dir_Expand(cgn->name, Suff_FindPath(cgn), explist);
+
+ while (!Lst_IsEmpty(explist)) {
/*
- * Now the source is expanded, remove it from the list of children to
- * keep it from being processed.
+ * Fetch next expansion off the list and find its GNode
*/
+ cp = (char *)Lst_DeQueue(explist);
+
if (DEBUG(SUFF)) {
- printf("\n");
+ fprintf(debug_file, "%s...", cp);
}
- return(1);
+ gn = Targ_FindNode(cp, TARG_CREATE);
+
+ /* Add gn to the parents child list before the original child */
+ (void)Lst_InsertBefore(pgn->children, cln, gn);
+ (void)Lst_AtEnd(gn->parents, pgn);
+ pgn->unmade++;
}
- return(0);
+ /*
+ * Nuke what's left of the list
+ */
+ Lst_Destroy(explist, NOFREE);
+
+ if (DEBUG(SUFF)) {
+ fprintf(debug_file, "\n");
+ }
+
+ /*
+ * Now the source is expanded, remove it from the list of children to
+ * keep it from being processed.
+ */
+ pgn->unmade--;
+ Lst_Remove(pgn->children, cln);
+ Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
}
/*-
@@ -1712,10 +1744,10 @@ Suff_FindPath(GNode* gn)
LstNode ln;
sd.len = strlen(gn->name);
sd.ename = gn->name + sd.len;
- ln = Lst_Find(sufflist, (ClientData)&sd, SuffSuffIsSuffixP);
+ ln = Lst_Find(sufflist, &sd, SuffSuffIsSuffixP);
if (DEBUG(SUFF)) {
- printf("Wildcard expanding \"%s\"...", gn->name);
+ fprintf(debug_file, "Wildcard expanding \"%s\"...", gn->name);
}
if (ln != NILLNODE)
suff = (Suff *)Lst_Datum(ln);
@@ -1724,7 +1756,7 @@ Suff_FindPath(GNode* gn)
if (suff != NULL) {
if (DEBUG(SUFF)) {
- printf("suffix is \"%s\"...", suff->name);
+ fprintf(debug_file, "suffix is \"%s\"...", suff->name);
}
return suff->searchPath;
} else {
@@ -1769,15 +1801,15 @@ SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s)
/*
* Form the proper links between the target and source.
*/
- (void)Lst_AtEnd(tGn->children, (ClientData)sGn);
- (void)Lst_AtEnd(sGn->parents, (ClientData)tGn);
+ (void)Lst_AtEnd(tGn->children, sGn);
+ (void)Lst_AtEnd(sGn->parents, tGn);
tGn->unmade += 1;
/*
* Locate the transformation rule itself
*/
tname = str_concat(s->name, t->name, 0);
- ln = Lst_Find(transforms, (ClientData)tname, SuffGNHasNameP);
+ ln = Lst_Find(transforms, tname, SuffGNHasNameP);
free(tname);
if (ln == NILLNODE) {
@@ -1792,7 +1824,7 @@ SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s)
gn = (GNode *)Lst_Datum(ln);
if (DEBUG(SUFF)) {
- printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
+ fprintf(debug_file, "\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
}
/*
@@ -1808,22 +1840,16 @@ SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s)
/*
* Deal with wildcards and variables in any acquired sources
*/
- ln = Lst_Succ(ln);
- while (ln != NILLNODE) {
- if (SuffExpandChildren(ln, tGn)) {
- nln = Lst_Succ(ln);
- tGn->unmade--;
- Lst_Remove(tGn->children, ln);
- ln = nln;
- } else
- ln = Lst_Succ(ln);
+ for (ln = Lst_Succ(ln); ln != NILLNODE; ln = nln) {
+ nln = Lst_Succ(ln);
+ SuffExpandChildren(ln, tGn);
}
/*
* Keep track of another parent to which this beast is transformed so
* the .IMPSRC variable can be set correctly for the parent.
*/
- (void)Lst_AtEnd(sGn->iParents, (ClientData)tGn);
+ (void)Lst_AtEnd(sGn->iParents, tGn);
return(TRUE);
}
@@ -1885,8 +1911,8 @@ SuffFindArchiveDeps(GNode *gn, Lst slst)
/*
* Create the link between the two nodes right off
*/
- (void)Lst_AtEnd(gn->children, (ClientData)mem);
- (void)Lst_AtEnd(mem->parents, (ClientData)gn);
+ (void)Lst_AtEnd(gn->children, mem);
+ (void)Lst_AtEnd(mem->parents, gn);
gn->unmade += 1;
/*
@@ -1906,7 +1932,7 @@ SuffFindArchiveDeps(GNode *gn, Lst slst)
* Didn't know what it was -- use .NULL suffix if not in make mode
*/
if (DEBUG(SUFF)) {
- printf("using null suffix\n");
+ fprintf(debug_file, "using null suffix\n");
}
ms = suffNull;
}
@@ -1942,7 +1968,7 @@ SuffFindArchiveDeps(GNode *gn, Lst slst)
if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&
DEBUG(SUFF))
{
- printf("\tNo transformation from %s -> %s\n",
+ fprintf(debug_file, "\tNo transformation from %s -> %s\n",
ms->name, ((Suff *)Lst_Datum(ln))->name);
}
}
@@ -2074,7 +2100,7 @@ SuffFindNormalDeps(GNode *gn, Lst slst)
/*
* Record the target so we can nuke it
*/
- (void)Lst_AtEnd(targs, (ClientData)targ);
+ (void)Lst_AtEnd(targs, targ);
/*
* Search from this suffix's successor...
@@ -2088,7 +2114,7 @@ SuffFindNormalDeps(GNode *gn, Lst slst)
*/
if (Lst_IsEmpty(targs) && suffNull != NULL) {
if (DEBUG(SUFF)) {
- printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
+ fprintf(debug_file, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
}
targ = emalloc(sizeof(Src));
@@ -2113,13 +2139,13 @@ SuffFindNormalDeps(GNode *gn, Lst slst)
SuffAddLevel(srcs, targ);
else {
if (DEBUG(SUFF))
- printf("not ");
+ fprintf(debug_file, "not ");
}
if (DEBUG(SUFF))
- printf("adding suffix rules\n");
+ fprintf(debug_file, "adding suffix rules\n");
- (void)Lst_AtEnd(targs, (ClientData)targ);
+ (void)Lst_AtEnd(targs, targ);
}
/*
@@ -2156,20 +2182,14 @@ SuffFindNormalDeps(GNode *gn, Lst slst)
* Now we've got the important local variables set, expand any sources
* that still contain variables or wildcards in their names.
*/
- ln = Lst_First(gn->children);
- while (ln != NILLNODE) {
- if (SuffExpandChildren(ln, gn)) {
- nln = Lst_Succ(ln);
- gn->unmade--;
- Lst_Remove(gn->children, ln);
- ln = nln;
- } else
- ln = Lst_Succ(ln);
+ for (ln = Lst_First(gn->children); ln != NILLNODE; ln = nln) {
+ nln = Lst_Succ(ln);
+ SuffExpandChildren(ln, gn);
}
if (targ == NULL) {
if (DEBUG(SUFF)) {
- printf("\tNo valid suffix on %s\n", gn->name);
+ fprintf(debug_file, "\tNo valid suffix on %s\n", gn->name);
}
sfnd_abort:
@@ -2254,8 +2274,8 @@ sfnd_abort:
* up to, but not including, the parent node.
*/
while (bottom && bottom->parent != NULL) {
- if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) {
- Lst_AtEnd(slst, (ClientData) bottom);
+ if (Lst_Member(slst, bottom) == NILLNODE) {
+ Lst_AtEnd(slst, bottom);
}
bottom = bottom->parent;
}
@@ -2330,8 +2350,8 @@ sfnd_abort:
*/
sfnd_return:
if (bottom)
- if (Lst_Member(slst, (ClientData) bottom) == NILLNODE)
- Lst_AtEnd(slst, (ClientData) bottom);
+ if (Lst_Member(slst, bottom) == NILLNODE)
+ Lst_AtEnd(slst, bottom);
while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs))
continue;
@@ -2398,7 +2418,7 @@ SuffFindDeps(GNode *gn, Lst slst)
}
if (DEBUG(SUFF)) {
- printf("SuffFindDeps (%s)\n", gn->name);
+ fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
}
if (gn->type & OP_ARCHV) {
@@ -2415,7 +2435,7 @@ SuffFindDeps(GNode *gn, Lst slst)
LstNode ln;
Suff *s;
- ln = Lst_Find(sufflist, (ClientData)UNCONST(LIBSUFF),
+ ln = Lst_Find(sufflist, UNCONST(LIBSUFF),
SuffSuffHasNameP);
if (gn->suffix)
gn->suffix->refCount--;
@@ -2464,7 +2484,7 @@ Suff_SetNull(char *name)
Suff *s;
LstNode ln;
- ln = Lst_Find(sufflist, (ClientData)name, SuffSuffHasNameP);
+ ln = Lst_Find(sufflist, name, SuffSuffHasNameP);
if (ln != NILLNODE) {
s = (Suff *)Lst_Datum(ln);
if (suffNull != NULL) {
@@ -2556,7 +2576,7 @@ Suff_End(void)
static int SuffPrintName(ClientData s, ClientData dummy)
{
- printf("%s ", ((Suff *)s)->name);
+ fprintf(debug_file, "%s ", ((Suff *)s)->name);
return (dummy ? 0 : 0);
}
@@ -2567,38 +2587,38 @@ SuffPrintSuff(ClientData sp, ClientData dummy)
int flags;
int flag;
- printf("# `%s' [%d] ", s->name, s->refCount);
+ fprintf(debug_file, "# `%s' [%d] ", s->name, s->refCount);
flags = s->flags;
if (flags) {
- fputs(" (", stdout);
+ fputs(" (", debug_file);
while (flags) {
flag = 1 << (ffs(flags) - 1);
flags &= ~flag;
switch (flag) {
case SUFF_NULL:
- printf("NULL");
+ fprintf(debug_file, "NULL");
break;
case SUFF_INCLUDE:
- printf("INCLUDE");
+ fprintf(debug_file, "INCLUDE");
break;
case SUFF_LIBRARY:
- printf("LIBRARY");
+ fprintf(debug_file, "LIBRARY");
break;
}
- fputc(flags ? '|' : ')', stdout);
+ fputc(flags ? '|' : ')', debug_file);
}
}
- fputc('\n', stdout);
- printf("#\tTo: ");
- Lst_ForEach(s->parents, SuffPrintName, (ClientData)0);
- fputc('\n', stdout);
- printf("#\tFrom: ");
- Lst_ForEach(s->children, SuffPrintName, (ClientData)0);
- fputc('\n', stdout);
- printf("#\tSearch Path: ");
+ fputc('\n', debug_file);
+ fprintf(debug_file, "#\tTo: ");
+ Lst_ForEach(s->parents, SuffPrintName, NULL);
+ fputc('\n', debug_file);
+ fprintf(debug_file, "#\tFrom: ");
+ Lst_ForEach(s->children, SuffPrintName, NULL);
+ fputc('\n', debug_file);
+ fprintf(debug_file, "#\tSearch Path: ");
Dir_PrintPath(s->searchPath);
- fputc('\n', stdout);
+ fputc('\n', debug_file);
return (dummy ? 0 : 0);
}
@@ -2607,20 +2627,20 @@ SuffPrintTrans(ClientData tp, ClientData dummy)
{
GNode *t = (GNode *)tp;
- printf("%-16s: ", t->name);
+ fprintf(debug_file, "%-16s: ", t->name);
Targ_PrintType(t->type);
- fputc('\n', stdout);
- Lst_ForEach(t->commands, Targ_PrintCmd, (ClientData)0);
- fputc('\n', stdout);
+ fputc('\n', debug_file);
+ Lst_ForEach(t->commands, Targ_PrintCmd, NULL);
+ fputc('\n', debug_file);
return(dummy ? 0 : 0);
}
void
Suff_PrintAll(void)
{
- printf("#*** Suffixes:\n");
- Lst_ForEach(sufflist, SuffPrintSuff, (ClientData)0);
+ fprintf(debug_file, "#*** Suffixes:\n");
+ Lst_ForEach(sufflist, SuffPrintSuff, NULL);
- printf("#*** Transformations:\n");
- Lst_ForEach(transforms, SuffPrintTrans, (ClientData)0);
+ fprintf(debug_file, "#*** Transformations:\n");
+ Lst_ForEach(transforms, SuffPrintTrans, NULL);
}
diff --git a/devel/bmake/files/targ.c b/devel/bmake/files/targ.c
index 3d8606885cb..18e1ce545fd 100644
--- a/devel/bmake/files/targ.c
+++ b/devel/bmake/files/targ.c
@@ -1,4 +1,4 @@
-/* $NetBSD: targ.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: targ.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: targ.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: targ.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: targ.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: targ.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -118,6 +118,11 @@ __RCSID("$NetBSD: targ.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
* Targ_Precious Return TRUE if the target is precious and
* should not be removed if we are interrupted.
*
+ * Targ_Propagate Propagate information between related
+ * nodes. Should be called after the
+ * makefiles are parsed but before any
+ * action is taken.
+ *
* Debugging:
* Targ_PrintGraph Print out the entire graphm all variables
* and statistics for the directory cache. Should
@@ -141,7 +146,6 @@ static Hash_Table targets; /* a hash table of same */
static int TargPrintOnlySrc(ClientData, ClientData);
static int TargPrintName(ClientData, ClientData);
-static int TargPrintNode(ClientData, ClientData);
#ifdef CLEANUP
static void TargFreeGN(ClientData);
#endif
@@ -240,17 +244,18 @@ Targ_NewGN(const char *name)
}
gn->unmade = 0;
gn->unmade_cohorts = 0;
+ gn->cohort_num[0] = 0;
gn->centurion = NULL;
gn->made = UNMADE;
gn->flags = 0;
- gn->order = 0;
+ gn->checked = 0;
gn->mtime = gn->cmtime = 0;
gn->iParents = Lst_Init(FALSE);
gn->cohorts = Lst_Init(FALSE);
gn->parents = Lst_Init(FALSE);
gn->children = Lst_Init(FALSE);
- gn->successors = Lst_Init(FALSE);
- gn->preds = Lst_Init(FALSE);
+ gn->order_pred = Lst_Init(FALSE);
+ gn->order_succ = Lst_Init(FALSE);
Hash_InitTable(&gn->context, 0);
gn->commands = Lst_Init(FALSE);
gn->suffix = NULL;
@@ -260,7 +265,7 @@ Targ_NewGN(const char *name)
#ifdef CLEANUP
if (allGNs == NULL)
allGNs = Lst_Init(FALSE);
- Lst_AtEnd(allGNs, (ClientData) gn);
+ Lst_AtEnd(allGNs, gn);
#endif
return (gn);
@@ -290,15 +295,14 @@ TargFreeGN(ClientData gnp)
free(gn->uname);
if (gn->path)
free(gn->path);
- if (gn->fname)
- free(gn->fname);
+ /* gn->fname points to name allocated when file was opened, don't free */
Lst_Destroy(gn->iParents, NOFREE);
Lst_Destroy(gn->cohorts, NOFREE);
Lst_Destroy(gn->parents, NOFREE);
Lst_Destroy(gn->children, NOFREE);
- Lst_Destroy(gn->successors, NOFREE);
- Lst_Destroy(gn->preds, NOFREE);
+ Lst_Destroy(gn->order_succ, NOFREE);
+ Lst_Destroy(gn->order_pred, NOFREE);
Hash_DeleteTable(&gn->context);
Lst_Destroy(gn->commands, NOFREE);
free(gn);
@@ -329,28 +333,31 @@ GNode *
Targ_FindNode(const char *name, int flags)
{
GNode *gn; /* node in that element */
- Hash_Entry *he; /* New or used hash entry for node */
+ Hash_Entry *he = NULL; /* New or used hash entry for node */
Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
/* an entry for the node */
-
- if (flags & TARG_CREATE) {
- he = Hash_CreateEntry(&targets, name, &isNew);
- if (isNew) {
- gn = Targ_NewGN(name);
- Hash_SetValue(he, gn);
- Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
- (void)Lst_AtEnd(allTargets, (ClientData)gn);
- }
- } else {
+ if (!(flags & (TARG_CREATE | TARG_NOHASH))) {
he = Hash_FindEntry(&targets, name);
+ if (he == NULL)
+ return (NILGNODE);
+ return (GNode *)Hash_GetValue(he);
}
- if (he == NULL) {
- return (NILGNODE);
- } else {
- return ((GNode *)Hash_GetValue(he));
+ if (!(flags & TARG_NOHASH)) {
+ he = Hash_CreateEntry(&targets, name, &isNew);
+ if (!isNew)
+ return (GNode *)Hash_GetValue(he);
}
+
+ gn = Targ_NewGN(name);
+ if (!(flags & TARG_NOHASH))
+ Hash_SetValue(he, gn);
+ Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
+ (void)Lst_AtEnd(allTargets, gn);
+ if (doing_depend)
+ gn->flags |= FROM_DEPEND;
+ return gn;
}
/*-
@@ -394,7 +401,7 @@ Targ_FindList(Lst names, int flags)
* are added to the list in the order in which they were
* encountered in the makefile.
*/
- (void)Lst_AtEnd(nodes, (ClientData)gn);
+ (void)Lst_AtEnd(nodes, gn);
} else if (flags == TARG_NOCREATE) {
Error("\"%s\" -- target unknown.", name);
}
@@ -504,28 +511,20 @@ Targ_SetMain(GNode *gn)
}
static int
-TargPrintName(ClientData gnp, ClientData ppath)
+TargPrintName(ClientData gnp, ClientData pflags __unused)
{
GNode *gn = (GNode *)gnp;
- printf("%s ", gn->name);
-#ifdef notdef
- if (ppath) {
- if (gn->path) {
- printf("[%s] ", gn->path);
- }
- if (gn == mainTarg) {
- printf("(MAIN NAME) ");
- }
- }
-#endif /* notdef */
- return (ppath ? 0 : 0);
+
+ fprintf(debug_file, "%s%s ", gn->name, gn->cohort_num);
+
+ return 0;
}
int
Targ_PrintCmd(ClientData cmd, ClientData dummy)
{
- printf("\t%s\n", (char *)cmd);
+ fprintf(debug_file, "\t%s\n", (char *)cmd);
return (dummy ? 0 : 0);
}
@@ -571,8 +570,8 @@ Targ_PrintType(int type)
{
int tbit;
-#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
-#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))printf("." #attr " "); break
+#define PRINTBIT(attr) case CONCAT(OP_,attr): fprintf(debug_file, "." #attr " "); break
+#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))fprintf(debug_file, "." #attr " "); break
type &= ~OP_OPMASK;
@@ -593,7 +592,7 @@ Targ_PrintType(int type)
PRINTBIT(NOTMAIN);
PRINTDBIT(LIB);
/*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
- case OP_MEMBER: if (DEBUG(TARG))printf(".MEMBER "); break;
+ case OP_MEMBER: if (DEBUG(TARG))fprintf(debug_file, ".MEMBER "); break;
PRINTDBIT(ARCHV);
PRINTDBIT(MADE);
PRINTDBIT(PHONY);
@@ -601,74 +600,103 @@ Targ_PrintType(int type)
}
}
+static const char *
+made_name(enum enum_made made)
+{
+ switch (made) {
+ case UNMADE: return "unmade";
+ case DEFERRED: return "deferred";
+ case REQUESTED: return "requested";
+ case BEINGMADE: return "being made";
+ case MADE: return "made";
+ case UPTODATE: return "up-to-date";
+ case ERROR: return "error when made";
+ case ABORTED: return "aborted";
+ default: return "unknown enum_made value";
+ }
+}
+
/*-
*-----------------------------------------------------------------------
* TargPrintNode --
* print the contents of a node
*-----------------------------------------------------------------------
*/
-static int
-TargPrintNode(ClientData gnp, ClientData passp)
+int
+Targ_PrintNode(ClientData gnp, ClientData passp)
{
GNode *gn = (GNode *)gnp;
- int pass = *(int *)passp;
+ int pass = passp ? *(int *)passp : 0;
+
+ fprintf(debug_file, "# %s%s, flags %x, type %x, made %d\n",
+ gn->name, gn->cohort_num, gn->flags, gn->type, gn->made);
+ if (gn->flags == 0)
+ return 0;
+
if (!OP_NOP(gn->type)) {
- printf("#\n");
+ fprintf(debug_file, "#\n");
if (gn == mainTarg) {
- printf("# *** MAIN TARGET ***\n");
+ fprintf(debug_file, "# *** MAIN TARGET ***\n");
}
- if (pass == 2) {
+ if (pass >= 2) {
if (gn->unmade) {
- printf("# %d unmade children\n", gn->unmade);
+ fprintf(debug_file, "# %d unmade children\n", gn->unmade);
} else {
- printf("# No unmade children\n");
+ fprintf(debug_file, "# No unmade children\n");
}
if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
if (gn->mtime != 0) {
- printf("# last modified %s: %s\n",
+ fprintf(debug_file, "# last modified %s: %s\n",
Targ_FmtTime(gn->mtime),
- (gn->made == UNMADE ? "unmade" :
- (gn->made == MADE ? "made" :
- (gn->made == UPTODATE ? "up-to-date" :
- "error when made"))));
+ made_name(gn->made));
} else if (gn->made != UNMADE) {
- printf("# non-existent (maybe): %s\n",
- (gn->made == MADE ? "made" :
- (gn->made == UPTODATE ? "up-to-date" :
- (gn->made == ERROR ? "error when made" :
- "aborted"))));
+ fprintf(debug_file, "# non-existent (maybe): %s\n",
+ made_name(gn->made));
} else {
- printf("# unmade\n");
+ fprintf(debug_file, "# unmade\n");
}
}
if (!Lst_IsEmpty (gn->iParents)) {
- printf("# implicit parents: ");
- Lst_ForEach(gn->iParents, TargPrintName, (ClientData)0);
- fputc('\n', stdout);
+ fprintf(debug_file, "# implicit parents: ");
+ Lst_ForEach(gn->iParents, TargPrintName, NULL);
+ fprintf(debug_file, "\n");
}
+ } else {
+ if (gn->unmade)
+ fprintf(debug_file, "# %d unmade children\n", gn->unmade);
}
if (!Lst_IsEmpty (gn->parents)) {
- printf("# parents: ");
- Lst_ForEach(gn->parents, TargPrintName, (ClientData)0);
- fputc('\n', stdout);
+ fprintf(debug_file, "# parents: ");
+ Lst_ForEach(gn->parents, TargPrintName, NULL);
+ fprintf(debug_file, "\n");
+ }
+ if (!Lst_IsEmpty (gn->order_pred)) {
+ fprintf(debug_file, "# order_pred: ");
+ Lst_ForEach(gn->order_pred, TargPrintName, NULL);
+ fprintf(debug_file, "\n");
+ }
+ if (!Lst_IsEmpty (gn->order_succ)) {
+ fprintf(debug_file, "# order_succ: ");
+ Lst_ForEach(gn->order_succ, TargPrintName, NULL);
+ fprintf(debug_file, "\n");
}
- printf("%-16s", gn->name);
+ fprintf(debug_file, "%-16s", gn->name);
switch (gn->type & OP_OPMASK) {
case OP_DEPENDS:
- printf(": "); break;
+ fprintf(debug_file, ": "); break;
case OP_FORCE:
- printf("! "); break;
+ fprintf(debug_file, "! "); break;
case OP_DOUBLEDEP:
- printf(":: "); break;
+ fprintf(debug_file, ":: "); break;
}
Targ_PrintType(gn->type);
- Lst_ForEach(gn->children, TargPrintName, (ClientData)0);
- fputc('\n', stdout);
- Lst_ForEach(gn->commands, Targ_PrintCmd, (ClientData)0);
- printf("\n\n");
+ Lst_ForEach(gn->children, TargPrintName, NULL);
+ fprintf(debug_file, "\n");
+ Lst_ForEach(gn->commands, Targ_PrintCmd, NULL);
+ fprintf(debug_file, "\n\n");
if (gn->type & OP_DOUBLEDEP) {
- Lst_ForEach(gn->cohorts, TargPrintNode, (ClientData)&pass);
+ Lst_ForEach(gn->cohorts, Targ_PrintNode, &pass);
}
}
return (0);
@@ -688,13 +716,18 @@ TargPrintNode(ClientData gnp, ClientData passp)
*-----------------------------------------------------------------------
*/
static int
-TargPrintOnlySrc(ClientData gnp, ClientData dummy)
+TargPrintOnlySrc(ClientData gnp, ClientData dummy __unused)
{
GNode *gn = (GNode *)gnp;
- if (OP_NOP(gn->type))
- printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
+ if (!OP_NOP(gn->type))
+ return 0;
- return (dummy ? 0 : 0);
+ fprintf(debug_file, "#\t%s [%s] ",
+ gn->name, gn->path ? gn->path : gn->name);
+ Targ_PrintType(gn->type);
+ fprintf(debug_file, "\n");
+
+ return 0;
}
/*-
@@ -716,42 +749,99 @@ TargPrintOnlySrc(ClientData gnp, ClientData dummy)
void
Targ_PrintGraph(int pass)
{
- printf("#*** Input graph:\n");
- Lst_ForEach(allTargets, TargPrintNode, (ClientData)&pass);
- printf("\n\n");
- printf("#\n# Files that are only sources:\n");
- Lst_ForEach(allTargets, TargPrintOnlySrc, (ClientData) 0);
- printf("#*** Global Variables:\n");
+ fprintf(debug_file, "#*** Input graph:\n");
+ Lst_ForEach(allTargets, Targ_PrintNode, &pass);
+ fprintf(debug_file, "\n\n");
+ fprintf(debug_file, "#\n# Files that are only sources:\n");
+ Lst_ForEach(allTargets, TargPrintOnlySrc, NULL);
+ fprintf(debug_file, "#*** Global Variables:\n");
Var_Dump(VAR_GLOBAL);
- printf("#*** Command-line Variables:\n");
+ fprintf(debug_file, "#*** Command-line Variables:\n");
Var_Dump(VAR_CMD);
- printf("\n");
+ fprintf(debug_file, "\n");
Dir_PrintDirectories();
- printf("\n");
+ fprintf(debug_file, "\n");
Suff_PrintAll();
}
+/*-
+ *-----------------------------------------------------------------------
+ * TargPropagateNode --
+ * Propagate information from a single node to related nodes if
+ * appropriate.
+ *
+ * Input:
+ * gnp The node that we are processing.
+ *
+ * Results:
+ * Always returns 0, for the benefit of Lst_ForEach().
+ *
+ * Side Effects:
+ * Information is propagated from this node to cohort or child
+ * nodes.
+ *
+ * If the node was defined with "::", then TargPropagateCohort()
+ * will be called for each cohort node.
+ *
+ * If the node has recursive predecessors, then
+ * TargPropagateRecpred() will be called for each recursive
+ * predecessor.
+ *-----------------------------------------------------------------------
+ */
static int
-TargPropagateCohort(ClientData cgnp, ClientData pgnp)
+TargPropagateNode(ClientData gnp, ClientData junk __unused)
{
- GNode *cgn = (GNode *)cgnp;
- GNode *pgn = (GNode *)pgnp;
+ GNode *gn = (GNode *)gnp;
- cgn->type |= pgn->type & ~OP_OPMASK;
+ if (gn->type & OP_DOUBLEDEP)
+ Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
return (0);
}
+/*-
+ *-----------------------------------------------------------------------
+ * TargPropagateCohort --
+ * Propagate some bits in the type mask from a node to
+ * a related cohort node.
+ *
+ * Input:
+ * cnp The node that we are processing.
+ * gnp Another node that has cnp as a cohort.
+ *
+ * Results:
+ * Always returns 0, for the benefit of Lst_ForEach().
+ *
+ * Side Effects:
+ * cnp's type bitmask is modified to incorporate some of the
+ * bits from gnp's type bitmask. (XXX need a better explanation.)
+ *-----------------------------------------------------------------------
+ */
static int
-TargPropagateNode(ClientData gnp, ClientData junk __unused)
+TargPropagateCohort(ClientData cgnp, ClientData pgnp)
{
- GNode *gn = (GNode *)gnp;
- if (gn->type & OP_DOUBLEDEP)
- Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
+ GNode *cgn = (GNode *)cgnp;
+ GNode *pgn = (GNode *)pgnp;
+
+ cgn->type |= pgn->type & ~OP_OPMASK;
return (0);
}
+/*-
+ *-----------------------------------------------------------------------
+ * Targ_Propagate --
+ * Propagate information between related nodes. Should be called
+ * after the makefiles are parsed but before any action is taken.
+ *
+ * Results:
+ * none
+ *
+ * Side Effects:
+ * Information is propagated between related nodes throughout the
+ * graph.
+ *-----------------------------------------------------------------------
+ */
void
Targ_Propagate(void)
{
- Lst_ForEach(allTargets, TargPropagateNode, (ClientData)0);
+ Lst_ForEach(allTargets, TargPropagateNode, NULL);
}
diff --git a/devel/bmake/files/trace.c b/devel/bmake/files/trace.c
index bc5b91eb9ec..37992f5508b 100644
--- a/devel/bmake/files/trace.c
+++ b/devel/bmake/files/trace.c
@@ -1,4 +1,4 @@
-/* $NetBSD: trace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: trace.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -38,11 +38,11 @@
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: trace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: trace.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: trace.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: trace.c,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $");
#endif /* not lint */
#endif
@@ -103,9 +103,9 @@ Trace_Log(TrEvent event, Job *job)
gettimeofday(&rightnow, NULL);
- fprintf(trfile, "%ld.%06d %d %d %s %d %s",
+ fprintf(trfile, "%ld.%06d %d %s %d %s",
rightnow.tv_sec, (int)rightnow.tv_usec,
- jobTokensRunning, jobTokensFree,
+ jobTokensRunning,
evname[event], trpid, trwd);
if (job != NULL) {
fprintf(trfile, " %s %d %x %x", job->node->name,
diff --git a/devel/bmake/files/trace.h b/devel/bmake/files/trace.h
index 0f1acc9787f..3391c068de9 100644
--- a/devel/bmake/files/trace.h
+++ b/devel/bmake/files/trace.h
@@ -1,4 +1,4 @@
-/* $NetBSD: trace.h,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: trace.h,v 1.1.1.2 2008/03/09 19:39:33 joerg Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
diff --git a/devel/bmake/files/unit-tests/Makefile.in b/devel/bmake/files/unit-tests/Makefile.in
index d24ff7838bb..b28e2a97b6f 100644
--- a/devel/bmake/files/unit-tests/Makefile.in
+++ b/devel/bmake/files/unit-tests/Makefile.in
@@ -1,6 +1,6 @@
-# $Id: Makefile.in,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $Id: Makefile.in,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $
#
-# $NetBSD: Makefile.in,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $NetBSD: Makefile.in,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $
#
# Unit tests for make(1)
# The main targets are:
@@ -25,7 +25,12 @@ UNIT_TESTS:= ${srcdir}
SUBFILES= \
comment \
cond1 \
+ export \
+ export-all \
+ dotwait \
+ moderrs \
modmatch \
+ modmisc \
modorder \
modts \
modword \
@@ -37,6 +42,7 @@ all: ${SUBFILES}
# the tests are actually done with sub-makes.
.PHONY: ${SUBFILES}
+.PRECIOUS: ${SUBFILES}
${SUBFILES}:
-@${.MAKE} -k -f ${UNIT_TESTS}/$@
@@ -55,10 +61,10 @@ TEST_MAKE?= ${.MAKE}
test:
@echo "${TEST_MAKE} -f ${MAKEFILE} > ${.TARGET}.out 2>&1"
@cd ${.OBJDIR} && ${TEST_MAKE} -f ${MAKEFILE} 2>&1 | \
- sed -e 's,^${TEST_MAKE:T}:,make:,' \
+ sed -e 's,^${TEST_MAKE:T:C/\./\\\./g}:,make:,' \
-e '/stopped/s, /.*, unit-tests,' \
- -e 's,${.CURDIR}/,,g' \
- -e 's,${UNIT_TESTS}/,,g' > ${.TARGET}.out || { \
+ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
+ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' > ${.TARGET}.out || { \
tail ${.TARGET}.out; mv ${.TARGET}.out ${.TARGET}.fail; exit 1; }
diff @diff_u@ ${UNIT_TESTS}/${.TARGET}.exp ${.TARGET}.out
diff --git a/devel/bmake/files/unit-tests/dotwait b/devel/bmake/files/unit-tests/dotwait
new file mode 100644
index 00000000000..8ae49950bf8
--- /dev/null
+++ b/devel/bmake/files/unit-tests/dotwait
@@ -0,0 +1,61 @@
+# $NetBSD: dotwait,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $
+
+THISMAKEFILE:= ${.PARSEDIR}/${.PARSEFILE}
+
+TESTS= simple recursive shared cycle
+PAUSE= sleep 1
+
+# Use a .for loop rather than dependencies here, to ensure
+# that the tests are run one by one, with parallelism
+# only within tests.
+# Ignore "--- target ---" lines printed by parallel make.
+all:
+.for t in ${TESTS}
+ @${.MAKE} -f ${THISMAKEFILE} -j4 $t | grep -v "^--- "
+.endfor
+
+#
+# Within each test, the names of the sub-targets follow these
+# conventions:
+# * If it's expected that two or more targets may be made in parallel,
+# then the target names will differ only in an alphabetic component
+# such as ".a" or ".b".
+# * If it's expected that two or more targets should be made in sequence
+# then the target names will differ in numeric components, such that
+# lexical ordering of the target names matches the expected order
+# in which the targets should be made.
+#
+# Targets may echo ${PARALLEL_TARG} to print a modified version
+# of their own name, in which alphabetic components like ".a" or ".b"
+# are converted to ".*". Two targets that are expected to
+# be made in parallel will thus print the same strings, so that the
+# output is independent of the order in which these targets are made.
+#
+PARALLEL_TARG= ${.TARGET:C/\.[a-z]/.*/g:Q}
+.DEFAULT:
+ @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
+_ECHOUSE: .USE
+ @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
+
+# simple: no recursion, no cycles
+simple: simple.1 .WAIT simple.2
+
+# recursive: all children of the left hand side of the .WAIT
+# must be made before any child of the right hand side.
+recursive: recursive.1.99 .WAIT recursive.2.99
+recursive.1.99: recursive.1.1.a recursive.1.1.b _ECHOUSE
+recursive.2.99: recursive.2.1.a recursive.2.1.b _ECHOUSE
+
+# shared: both shared.1.99 and shared.2.99 depend on shared.0.
+# shared.0 must be made first, even though it is a child of
+# the right hand side of the .WAIT.
+shared: shared.1.99 .WAIT shared.2.99
+shared.1.99: shared.0 _ECHOUSE
+shared.2.99: shared.2.1 shared.0 _ECHOUSE
+
+# cycle: the cyclic dependency must not cause infinite recursion
+# leading to stack overflow and a crash.
+cycle: cycle.1.99 .WAIT cycle.2.99
+cycle.2.99: cycle.2.98 _ECHOUSE
+cycle.2.98: cycle.2.97 _ECHOUSE
+cycle.2.97: cycle.2.99 _ECHOUSE
diff --git a/devel/bmake/files/unit-tests/export b/devel/bmake/files/unit-tests/export
new file mode 100644
index 00000000000..1b34677a626
--- /dev/null
+++ b/devel/bmake/files/unit-tests/export
@@ -0,0 +1,22 @@
+# $Id: export,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $
+
+UT_TEST=export
+UT_FOO=foo${BAR}
+UT_FU=fubar
+UT_ZOO=hoopie
+UT_NO=all
+# belive it or not, we expect this one to come out with $UT_FU unexpanded.
+UT_DOLLAR= This is $$UT_FU
+
+.export UT_FU UT_FOO
+.export UT_DOLLAR
+# this one will be ignored
+.export .MAKE.PID
+
+BAR=bar is ${UT_FU}
+
+.MAKE.EXPORTED+= UT_ZOO UT_TEST
+
+all:
+ @env | grep '^UT_' | sort
+
diff --git a/devel/bmake/files/unit-tests/export-all b/devel/bmake/files/unit-tests/export-all
new file mode 100644
index 00000000000..14d394ce2c9
--- /dev/null
+++ b/devel/bmake/files/unit-tests/export-all
@@ -0,0 +1,11 @@
+# $Id: export-all,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $
+
+UT_OK=good
+UT_F=fine
+
+.export
+
+.include "export"
+
+UT_TEST=export-all
+UT_ALL=even this gets exported
diff --git a/devel/bmake/files/unit-tests/moderrs b/devel/bmake/files/unit-tests/moderrs
new file mode 100644
index 00000000000..f9c28d91bf6
--- /dev/null
+++ b/devel/bmake/files/unit-tests/moderrs
@@ -0,0 +1,31 @@
+# $Id: moderrs,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $
+#
+# various modifier error tests
+
+VAR=TheVariable
+# incase we have to change it ;-)
+MOD_UNKN=Z
+MOD_TERM=S,V,v
+MOD_S:= ${MOD_TERM},
+
+all: modunkn modunknV varterm vartermV modtermV
+
+modunkn:
+ @echo "Expect: Unknown modifier 'Z'"
+ @echo "VAR:Z=${VAR:Z}"
+
+modunknV:
+ @echo "Expect: Unknown modifier 'Z'"
+ @echo "VAR:${MOD_UNKN}=${VAR:${MOD_UNKN}}"
+
+varterm:
+ @echo "Expect: Unclosed variable specification for VAR"
+ @echo VAR:S,V,v,=${VAR:S,V,v,
+
+vartermV:
+ @echo "Expect: Unclosed variable specification for VAR"
+ @echo VAR:${MOD_TERM},=${VAR:${MOD_S}
+
+modtermV:
+ @echo "Expect: Unclosed substitution for VAR (, missing)"
+ -@echo "VAR:${MOD_TERM}=${VAR:${MOD_TERM}}"
diff --git a/devel/bmake/files/unit-tests/modmisc b/devel/bmake/files/unit-tests/modmisc
new file mode 100644
index 00000000000..98daa95a998
--- /dev/null
+++ b/devel/bmake/files/unit-tests/modmisc
@@ -0,0 +1,33 @@
+# $Id: modmisc,v 1.1.1.1 2008/03/09 19:39:35 joerg Exp $
+#
+# miscellaneous modifier tests
+
+path=:/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.
+# strip cwd from path.
+MOD_NODOT=S/:/ /g:N.:ts:
+# and decorate, note that $'s need to be doubled. Also note that
+# the modifier_variable can be used with other modifiers.
+MOD_NODOTX=S/:/ /g:N.:@d@'$$d'@
+# another mod - pretend it is more interesting
+MOD_HOMES=S,/home/,/homes/,
+MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
+MOD_SEP=S,:, ,g
+
+all: modvar modvarloop
+
+modvar:
+ @echo "path='${path}'"
+ @echo "path='${path:${MOD_NODOT}}'"
+ @echo "path='${path:S,home,homes,:${MOD_NODOT}}'"
+ @echo "path=${path:${MOD_NODOTX}:ts:}"
+ @echo "path=${path:${MOD_HOMES}:${MOD_NODOTX}:ts:}"
+
+.for d in ${path:${MOD_SEP}:N.} /usr/xbin
+path_$d?= ${d:${MOD_OPT}:${MOD_HOMES}}/
+paths+= ${d:${MOD_OPT}:${MOD_HOMES}}
+.endfor
+
+modvarloop:
+ @echo "path_/usr/xbin=${path_/usr/xbin}"
+ @echo "paths=${paths}"
+ @echo "PATHS=${paths:tu}"
diff --git a/devel/bmake/files/unit-tests/modorder b/devel/bmake/files/unit-tests/modorder
index 276fa9eccfa..c4310b44c7f 100644
--- a/devel/bmake/files/unit-tests/modorder
+++ b/devel/bmake/files/unit-tests/modorder
@@ -1,6 +1,6 @@
-# $NetBSD: modorder,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+# $NetBSD: modorder,v 1.1.1.2 2008/03/09 19:39:35 joerg Exp $
-LIST= one two three four five six seven eigth nine ten
+LIST= one two three four five six seven eight nine ten
LISTX= ${LIST:Ox}
LISTSX:= ${LIST:Ox}
TEST_RESULT= && echo Ok || echo Failed
diff --git a/devel/bmake/files/unit-tests/test.exp b/devel/bmake/files/unit-tests/test.exp
index c21619bca86..3433f838042 100644
--- a/devel/bmake/files/unit-tests/test.exp
+++ b/devel/bmake/files/unit-tests/test.exp
@@ -20,6 +20,64 @@ Passed:
4 is not prime
5 is prime
+UT_DOLLAR=This is $UT_FU
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_TEST=export
+UT_ZOO=hoopie
+UT_ALL=even this gets exported
+UT_DOLLAR=This is $UT_FU
+UT_F=fine
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_NO=all
+UT_OK=good
+UT_TEST=export-all
+UT_ZOO=hoopie
+simple.1
+simple.1
+simple.2
+simple.2
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.99
+recursive.1.99
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.99
+recursive.2.99
+shared.0
+shared.0
+shared.1.99
+shared.1.99
+shared.2.1
+shared.2.1
+shared.2.99
+shared.2.99
+make: Graph cycles through `cycle.2.99'
+make: Graph cycles through `cycle.2.98'
+make: Graph cycles through `cycle.2.97'
+cycle.1.99
+cycle.1.99
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification for VAR
+VAR:S,V,v,=Thevariable
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification for VAR
+VAR:S,V,v,=Thevariable
+Expect: Unclosed substitution for VAR (, missing)
+make: Unclosed substitution for VAR (, missing)
+VAR:S,V,v=
LIB=a X_LIBS:M${LIB${LIB:tu}} is "/tmp/liba.a"
LIB=a X_LIBS:M*/lib${LIB}.a is "/tmp/liba.a"
LIB=a X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBA.A"
@@ -35,12 +93,16 @@ LIB=d X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBD.A"
LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
-LIST = one two three four five six seven eigth nine ten
-LIST:O = eigth five four nine one seven six ten three two
-# Note that 1 in every 10! trials two independently generated
-# randomized orderings will be the same. The test framework doesn't
-# support checking probabilistic output, so we accept that the test
-# will incorrectly fail with probability 2.8E-7.
+path=':/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.'
+path='/bin:/usr/bin:/sbin:/usr/sbin:/home/user/bin'
+path='/bin:/usr/bin:/sbin:/usr/sbin:/homes/user/bin'
+path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/home/user/bin'
+path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/homes/user/bin'
+path_/usr/xbin=/opt/xbin/
+paths=/bin /usr/bin /sbin /usr/sbin /homes/user/bin /opt/xbin
+PATHS=/BIN /USR/BIN /SBIN /USR/SBIN /HOMES/USER/BIN /OPT/XBIN
+LIST = one two three four five six seven eight nine ten
+LIST:O = eight five four nine one seven six ten three two
LIST:Ox = Ok
LIST:O:Ox = Ok
LISTX = Ok
diff --git a/devel/bmake/files/util.c b/devel/bmake/files/util.c
index f2a5024895e..86fae960fed 100644
--- a/devel/bmake/files/util.c
+++ b/devel/bmake/files/util.c
@@ -1,18 +1,18 @@
-/* $NetBSD: util.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: util.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*
* Missing stuff from OS's
*
- * $Id: util.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $
+ * $Id: util.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $
*/
#include "make.h"
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: util.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: util.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $";
#else
#ifndef lint
-__RCSID("$NetBSD: util.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: util.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif
@@ -59,6 +59,33 @@ strdup(const char *str)
}
#endif
+#if !defined(HAVE_EMALLOC) && !defined(HAVE_STRNDUP)
+#include <string.h>
+
+/* strndup
+ *
+ * Make a duplicate of a string, up to a maximum length.
+ * For systems which lack this function.
+ */
+char *
+strndup(const char *str, size_t maxlen)
+{
+ size_t len;
+ char *p;
+
+ if (str == NULL)
+ return NULL;
+ len = strlen(str);
+ if (len > maxlen)
+ len = maxlen;
+ p = emalloc(len + 1);
+
+ memcpy(p, str, len);
+ p[len] = '\0';
+ return p;
+}
+#endif
+
#if !defined(HAVE_SETENV)
int
setenv(const char *name, const char *value, int dum)
@@ -90,6 +117,14 @@ setenv(const char *name, const char *value, int dum)
}
#endif
+#if !defined(HAVE_UNSETENV)
+int
+unsetenv(const char *name)
+{
+ return -1; /* XXX not worth it? */
+}
+#endif
+
#if defined(__hpux__) || defined(__hpux)
/* strrcpy():
* Like strcpy, going backwards and returning the new pointer
@@ -145,14 +180,11 @@ char *sys_siglist[] = {
#if defined(__hpux__) || defined(__hpux)
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/syscall.h>
#include <sys/signal.h>
#include <sys/stat.h>
-#include <stdio.h>
#include <dirent.h>
#include <sys/time.h>
-#include <time.h>
#include <unistd.h>
int
@@ -510,3 +542,13 @@ strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
}
}
#endif
+
+#if !defined(HAVE_KILLPG)
+#if !defined(__hpux__) && !defined(__hpux)
+int
+killpg(int pid, int sig)
+{
+ return kill(-pid, sig);
+}
+#endif
+#endif
diff --git a/devel/bmake/files/var.c b/devel/bmake/files/var.c
index ead8dbaac59..24e01a7b115 100644
--- a/devel/bmake/files/var.c
+++ b/devel/bmake/files/var.c
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $ */
+/* $NetBSD: var.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.1.1.2 2008/03/09 19:39:34 joerg 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.1.1.1 2005/12/02 00:03:00 sjg Exp $");
+__RCSID("$NetBSD: var.c,v 1.1.1.2 2008/03/09 19:39:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -133,6 +133,8 @@ __RCSID("$NetBSD: var.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
#include "make.h"
#include "buf.h"
+#include "dir.h"
+#include "job.h"
/*
* This is a harmless return value for Var_Parse that can be used by Var_Subst
@@ -142,7 +144,7 @@ __RCSID("$NetBSD: var.c,v 1.1.1.1 2005/12/02 00:03:00 sjg Exp $");
char var_Error[] = "";
/*
- * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
+ * Similar to var_Error, but returned when the 'errnum' flag for Var_Parse is
* set false. Why not just use a constant? Well, gcc likes to condense
* identical string instances...
*/
@@ -185,8 +187,24 @@ typedef struct Var {
#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found
* a use for it in some modifier and
* the value is therefore valid */
+#define VAR_EXPORTED 16 /* Variable is exported */
+#define VAR_REEXPORT 32 /* Indicate if var needs re-export.
+ * This would be true if it contains $'s
+ */
} Var;
+/*
+ * Exporting vars is expensive so skip it if we can
+ */
+#define VAR_EXPORTED_NONE 0
+#define VAR_EXPORTED_YES 1
+#define VAR_EXPORTED_ALL 2
+static int var_exportedVars = VAR_EXPORTED_NONE;
+/*
+ * We pass this to Var_Export when doing the initial export
+ * or after updating an exported var.
+ */
+#define VAR_EXPORT_FORCE 1
/* Var*Pattern flags */
#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */
@@ -230,7 +248,7 @@ typedef struct {
int tvarLen;
char *str; /* string to expand */
int strLen;
- int err; /* err for not defined */
+ int errnum; /* errnum for not defined */
} VarLoop_t;
#ifndef NO_REGEX
@@ -291,8 +309,6 @@ static char *VarUniq(const char *);
static int VarWordCompare(const void *, const void *);
static void VarPrintVar(ClientData);
-#define WR(a) ((char *)UNCONST(a))
-
#define BROPEN '{'
#define BRCLOSE '}'
#define PROPEN '('
@@ -387,7 +403,7 @@ VarFind(const char *name, GNode *ctxt, int flags)
len = strlen(env);
- v->val = Buf_Init(len);
+ v->val = Buf_Init(len + 1);
Buf_AddBytes(v->val, len, (Byte *)env);
v->flags = VAR_FROM_ENV;
@@ -413,6 +429,33 @@ VarFind(const char *name, GNode *ctxt, int flags)
/*-
*-----------------------------------------------------------------------
+ * VarFreeEnv --
+ * If the variable is an environment variable, free it
+ *
+ * Input:
+ * v the variable
+ * destroy true if the value buffer should be destroyed.
+ *
+ * Results:
+ * 1 if it is an environment variable 0 ow.
+ *
+ * Side Effects:
+ * The variable is free'ed if it is an environent variable.
+ *-----------------------------------------------------------------------
+ */
+static Boolean
+VarFreeEnv(Var *v, Boolean destroy)
+{
+ if ((v->flags & VAR_FROM_ENV) == 0)
+ return FALSE;
+ free(v->name);
+ Buf_Destroy(v->val, destroy);
+ free(v);
+ return TRUE;
+}
+
+/*-
+ *-----------------------------------------------------------------------
* VarAdd --
* Add a new variable of name name and value val to the given context
*
@@ -449,7 +492,7 @@ VarAdd(const char *name, const char *val, GNode *ctxt)
Hash_SetValue(h, v);
v->name = h->name;
if (DEBUG(VAR)) {
- printf("%s:%s = %s\n", ctxt->name, name, val);
+ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
}
}
@@ -471,14 +514,18 @@ Var_Delete(const char *name, GNode *ctxt)
{
Hash_Entry *ln;
+ ln = Hash_FindEntry(&ctxt->context, name);
if (DEBUG(VAR)) {
- printf("%s:delete %s\n", ctxt->name, name);
+ fprintf(debug_file, "%s:delete %s%s\n",
+ ctxt->name, name, ln ? "" : " (not found)");
}
- ln = Hash_FindEntry(&ctxt->context, name);
if (ln != NULL) {
Var *v;
v = (Var *)Hash_GetValue(ln);
+ if ((v->flags & VAR_EXPORTED)) {
+ unsetenv(v->name);
+ }
if (v->name != ln->name)
free(v->name);
Hash_DeleteEntry(&ctxt->context, ln);
@@ -487,6 +534,177 @@ Var_Delete(const char *name, GNode *ctxt)
}
}
+
+/*
+ * Export a var.
+ * We ignore make internal variables (those which start with '.')
+ * Also we jump through some hoops to avoid calling setenv
+ * more than necessary since it can leak.
+ */
+static int
+Var_Export1(const char *name, int force)
+{
+ char tmp[BUFSIZ];
+ Var *v;
+ char *val = NULL;
+ int n;
+
+ if (*name == '.')
+ return 0; /* skip internals */
+ if (!name[1]) {
+ /*
+ * A single char.
+ * If it is one of the vars that should only appear in
+ * local context, skip it, else we can get Var_Subst
+ * into a loop.
+ */
+ switch (name[0]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ return 0;
+ }
+ }
+ v = VarFind(name, VAR_GLOBAL, 0);
+ if (v == (Var *)NIL) {
+ return 0;
+ }
+ if (!force &&
+ (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
+ return 0; /* nothing to do */
+ }
+ val = (char *)Buf_GetAll(v->val, NULL);
+ if (strchr(val, '$')) {
+ /* Flag this as something we need to re-export */
+ v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
+ if (force) {
+ /*
+ * No point actually exporting it now though,
+ * the child can do it at the last minute.
+ */
+ return 1;
+ }
+ n = snprintf(tmp, sizeof(tmp), "${%s}", name);
+ if (n < sizeof(tmp)) {
+ val = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+ setenv(name, val, 1);
+ free(val);
+ }
+ } else {
+ v->flags &= ~VAR_REEXPORT; /* once will do */
+ if (force || !(v->flags & VAR_EXPORTED)) {
+ setenv(name, val, 1);
+ }
+ }
+ /*
+ * This is so Var_Set knows to call Var_Export again...
+ */
+ v->flags |= VAR_EXPORTED;
+ return 1;
+}
+
+/*
+ * This gets called from our children.
+ */
+void
+Var_ExportVars(void)
+{
+ char tmp[BUFSIZ];
+ Hash_Entry *var;
+ Hash_Search state;
+ Var *v;
+ char *val;
+ int n;
+
+ if (VAR_EXPORTED_NONE == var_exportedVars)
+ return;
+
+ if (VAR_EXPORTED_ALL == var_exportedVars) {
+ /*
+ * Ouch! This is crazy...
+ */
+ for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state);
+ var != NULL;
+ var = Hash_EnumNext(&state)) {
+ v = (Var *)Hash_GetValue(var);
+ Var_Export1(v->name, 0);
+ }
+ return;
+ }
+ /*
+ * We have a number of exported vars,
+ */
+ n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
+ if (n < sizeof(tmp)) {
+ char **av;
+ char *as;
+ int ac;
+ int i;
+
+ val = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+ av = brk_string(val, &ac, FALSE, &as);
+ for (i = 0; i < ac; i++) {
+ Var_Export1(av[i], 0);
+ }
+ free(val);
+ free(as);
+ free(av);
+ }
+}
+
+/*
+ * This is called when .export is seen or
+ * .MAKE.EXPORTED is modified.
+ * It is also called when any exported var is modified.
+ */
+void
+Var_Export(char *str, int isExport)
+{
+ char *name;
+ char *val;
+ char **av;
+ char *as;
+ int ac;
+ int i;
+
+ if (isExport && (!str || !str[0])) {
+ var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
+ return;
+ }
+
+ val = Var_Subst(NULL, str, VAR_GLOBAL, 0);
+ av = brk_string(val, &ac, FALSE, &as);
+ for (i = 0; i < ac; i++) {
+ name = av[i];
+ if (!name[1]) {
+ /*
+ * A single char.
+ * If it is one of the vars that should only appear in
+ * local context, skip it, else we can get Var_Subst
+ * into a loop.
+ */
+ switch (name[0]) {
+ case '@':
+ case '%':
+ case '*':
+ case '!':
+ continue;
+ }
+ }
+ if (Var_Export1(name, VAR_EXPORT_FORCE)) {
+ if (VAR_EXPORTED_ALL != var_exportedVars)
+ var_exportedVars = VAR_EXPORTED_YES;
+ if (isExport) {
+ Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
+ }
+ }
+ }
+ free(val);
+ free(as);
+ free(av);
+}
+
/*-
*-----------------------------------------------------------------------
* Var_Set --
@@ -536,7 +754,10 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags)
Buf_AddBytes(v->val, strlen(val), (const Byte *)val);
if (DEBUG(VAR)) {
- printf("%s:%s = %s\n", ctxt->name, name, val);
+ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
+ }
+ if ((v->flags & VAR_EXPORTED)) {
+ Var_Export1(name, VAR_EXPORT_FORCE);
}
}
/*
@@ -558,6 +779,8 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags)
}
if (name != cp)
free(UNCONST(name));
+ if (v != (Var *)NIL)
+ VarFreeEnv(v, TRUE);
}
/*-
@@ -608,7 +831,7 @@ Var_Append(const char *name, const char *val, GNode *ctxt)
Buf_AddBytes(v->val, strlen(val), (const Byte *)val);
if (DEBUG(VAR)) {
- printf("%s:%s = %s\n", ctxt->name, name,
+ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
(char *)Buf_GetAll(v->val, NULL));
}
@@ -654,10 +877,8 @@ Var_Exists(const char *name, GNode *ctxt)
if (v == (Var *)NIL) {
return(FALSE);
- } else if (v->flags & VAR_FROM_ENV) {
- free(v->name);
- Buf_Destroy(v->val, TRUE);
- free(v);
+ } else {
+ (void)VarFreeEnv(v, TRUE);
}
return(TRUE);
}
@@ -687,12 +908,8 @@ Var_Value(const char *name, GNode *ctxt, char **frp)
*frp = NULL;
if (v != (Var *)NIL) {
char *p = ((char *)Buf_GetAll(v->val, NULL));
- if (v->flags & VAR_FROM_ENV) {
- free(v->name);
- Buf_Destroy(v->val, FALSE);
- free(v);
+ if (VarFreeEnv(v, FALSE))
*frp = p;
- }
return p;
} else {
return (NULL);
@@ -1194,14 +1411,14 @@ VarSubstitute(GNode *ctx __unused, Var_Parse_State *vpstate,
*-----------------------------------------------------------------------
*/
static void
-VarREError(int err, regex_t *pat, const char *str)
+VarREError(int errnum, regex_t *pat, const char *str)
{
char *errbuf;
int errlen;
- errlen = regerror(err, pat, 0, 0);
+ errlen = regerror(errnum, pat, 0, 0);
errbuf = emalloc(errlen);
- regerror(err, pat, errbuf, errlen);
+ regerror(errnum, pat, errbuf, errlen);
Error("%s: %s", str, errbuf);
free(errbuf);
}
@@ -1372,7 +1589,7 @@ VarLoopExpand(GNode *ctx __unused, Var_Parse_State *vpstate __unused,
if (word && *word) {
Var_Set(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
- s = Var_Subst(NULL, loop->str, loop->ctxt, loop->err);
+ s = Var_Subst(NULL, loop->str, loop->ctxt, loop->errnum);
if (s != NULL && *s != '\0') {
if (addSpace && *s != '\n')
Buf_AddByte(buf, ' ');
@@ -1424,7 +1641,7 @@ VarSelectWords(GNode *ctx __unused, Var_Parse_State *vpstate,
/* fake what brk_string() would do if there were only one word */
ac = 1;
av = emalloc((ac + 1) * sizeof(char *));
- as = strdup(str);
+ as = estrdup(str);
av[0] = as;
av[1] = NULL;
} else {
@@ -1517,7 +1734,7 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate,
/* fake what brk_string() would do if there were only one word */
ac = 1;
av = emalloc((ac + 1) * sizeof(char *));
- as = strdup(str);
+ as = estrdup(str);
av[0] = as;
av[1] = NULL;
} else {
@@ -1691,7 +1908,7 @@ VarUniq(const char *str)
*/
static char *
VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate __unused,
- int err, const char **tstr, int delim, int *flags,
+ int errnum, const char **tstr, int delim, int *flags,
int *length, VarPattern *pattern)
{
const char *cp;
@@ -1728,17 +1945,17 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate __unused,
if (flags == NULL || (*flags & VAR_NOSUBST) == 0) {
char *cp2;
int len;
- Boolean freeIt;
+ void *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);
+ cp2 = Var_Parse(cp, ctxt, errnum, &len, &freeIt);
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
if (freeIt)
- free(cp2);
+ free(freeIt);
cp += len - 1;
} else {
const char *cp2 = &cp[1];
@@ -1811,12 +2028,19 @@ VarQuote(char *str)
Buffer buf;
/* This should cover most shells :-( */
static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
+ const char *newline;
- buf = Buf_Init(MAKE_BSIZE);
+ newline = Shell_GetNewline();
+
+ buf = Buf_Init(0);
for (; *str; str++) {
- if (strchr(meta, *str) != NULL)
- Buf_AddByte(buf, (Byte)'\\');
- Buf_AddByte(buf, (Byte)*str);
+ if (*str == '\n' && newline != NULL) {
+ Buf_AddBytes(buf, strlen(newline), newline);
+ } else {
+ if (strchr(meta, *str) != NULL)
+ Buf_AddByte(buf, (Byte)'\\');
+ Buf_AddByte(buf, (Byte)*str);
+ }
}
Buf_AddByte(buf, (Byte)'\0');
str = (char *)Buf_GetAll(buf, NULL);
@@ -1848,7 +2072,7 @@ VarChangeCase(char *str, int upper)
int (*modProc)(int);
modProc = (upper ? toupper : tolower);
- buf = Buf_Init(MAKE_BSIZE);
+ buf = Buf_Init(0);
for (; *str ; str++) {
Buf_AddByte(buf, (Byte)modProc(*str));
}
@@ -1858,6 +2082,1110 @@ VarChangeCase(char *str, int upper)
return str;
}
+/*
+ * Now we need to apply any modifiers the user wants applied.
+ * These are:
+ * :M<pattern> words which match the given <pattern>.
+ * <pattern> is of the standard file
+ * wildcarding form.
+ * :N<pattern> words which do not match the given <pattern>.
+ * :S<d><pat1><d><pat2><d>[1gW]
+ * Substitute <pat2> for <pat1> in the value
+ * :C<d><pat1><d><pat2><d>[1gW]
+ * 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
+ * each word
+ * :R Substitute the root of each word
+ * (pathname minus the suffix).
+ * :O ("Order") Alphabeticaly sort words in variable.
+ * :Ox ("intermiX") Randomize words in variable.
+ * :u ("uniq") Remove adjacent duplicate words.
+ * :tu Converts the variable contents to uppercase.
+ * :tl Converts the variable contents to lowercase.
+ * :ts[c] Sets varSpace - the char used to
+ * separate words to 'c'. If 'c' is
+ * omitted then no separation is used.
+ * :tW Treat the variable contents as a single
+ * word, even if it contains spaces.
+ * (Mnemonic: one big 'W'ord.)
+ * :tw Treat the variable contents as multiple
+ * space-separated words.
+ * (Mnemonic: many small 'w'ords.)
+ * :[index] Select a single word from the value.
+ * :[start..end] Select multiple words from the value.
+ * :[*] or :[0] Select the entire value, as a single
+ * word. Equivalent to :tW.
+ * :[@] Select the entire value, as multiple
+ * words. Undoes the effect of :[*].
+ * Equivalent to :tw.
+ * :[#] Returns the number of words in the value.
+ *
+ * :?<true-value>:<false-value>
+ * If the variable evaluates to true, return
+ * true value, else return the second value.
+ * :lhs=rhs Like :S, but the rhs goes to the end of
+ * the invocation.
+ * :sh Treat the current value as a command
+ * to be run, new value is its output.
+ * The following added so we can handle ODE makefiles.
+ * :@<tmpvar>@<newval>@
+ * Assign a temporary local variable <tmpvar>
+ * to the current value of each word in turn
+ * and replace each word with the result of
+ * evaluating <newval>
+ * :D<newval> Use <newval> as value if variable defined
+ * :U<newval> Use <newval> as value if variable undefined
+ * :L Use the name of the variable as the value.
+ * :P Use the path of the node that has the same
+ * name as the variable as the value. This
+ * basically includes an implied :L so that
+ * the common method of refering to the path
+ * of your dependent 'x' in a rule is to use
+ * 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
+ *
+ * ::=<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.
+ */
+
+static char *
+ApplyModifiers(char *nstr, const char *tstr,
+ int startc, int endc,
+ Var *v, GNode *ctxt, Boolean errnum,
+ int *lengthPtr, void **freePtr)
+{
+ const char *start;
+ const char *cp; /* Secondary pointer into str (place marker
+ * for tstr) */
+ char *newStr; /* New value to return */
+ char termc; /* Character which terminated scan */
+ int cnt; /* Used to count brace pairs when variable in
+ * in parens or braces */
+ char delim;
+ int modifier; /* that we are processing */
+ Var_Parse_State parsestate; /* Flags passed to helper functions */
+
+ delim = '\0';
+ parsestate.oneBigWord = FALSE;
+ parsestate.varSpace = ' '; /* word separator */
+
+ start = cp = tstr;
+
+ while (*tstr && *tstr != endc) {
+
+ if (*tstr == '$') {
+ /*
+ * We have some complex modifiers in a variable.
+ */
+ void *freeIt;
+ char *rval;
+ int rlen;
+
+ rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt);
+
+ if (DEBUG(VAR)) {
+ fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
+ rval, rlen, tstr, rlen, tstr + rlen);
+ }
+
+ tstr += rlen;
+
+ if (rval != NULL && *rval) {
+ int used;
+
+ nstr = ApplyModifiers(nstr, rval,
+ 0, 0,
+ v, ctxt, errnum, &used, freePtr);
+ if (nstr == var_Error
+ || (nstr == varNoError && errnum == 0)
+ || strlen(rval) != (size_t) used) {
+ if (freeIt)
+ free(freeIt);
+ goto out; /* error already reported */
+ }
+ }
+ if (freeIt)
+ free(freeIt);
+ if (*tstr == ':')
+ tstr++;
+ else if (!*tstr && endc) {
+ Error("Unclosed variable specification for %s", v->name);
+ goto out;
+ }
+ continue;
+ }
+ if (DEBUG(VAR)) {
+ fprintf(debug_file, "Applying :%c to \"%s\"\n", *tstr, nstr);
+ }
+ newStr = var_Error;
+ switch ((modifier = *tstr)) {
+ case ':':
+ {
+ if (tstr[1] == '=' ||
+ (tstr[2] == '=' &&
+ (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) {
+ /*
+ * "::=", "::!=", "::+=", or "::?="
+ */
+ GNode *v_ctxt; /* context where v belongs */
+ const char *emsg;
+ char *sv_name;
+ VarPattern pattern;
+ int how;
+
+ v_ctxt = ctxt;
+ sv_name = NULL;
+ ++tstr;
+ if (v->flags & VAR_JUNK) {
+ /*
+ * We need to estrdup() it incase
+ * VarGetPattern() recurses.
+ */
+ sv_name = v->name;
+ v->name = estrdup(v->name);
+ } else if (ctxt != VAR_GLOBAL) {
+ Var *gv = VarFind(v->name, ctxt, 0);
+ if (gv == (Var *)NIL)
+ v_ctxt = VAR_GLOBAL;
+ else
+ VarFreeEnv(gv, TRUE);
+ }
+
+ switch ((how = *tstr)) {
+ case '+':
+ case '?':
+ case '!':
+ cp = &tstr[2];
+ break;
+ default:
+ cp = ++tstr;
+ break;
+ }
+ delim = BRCLOSE;
+ pattern.flags = 0;
+
+ pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim, NULL,
+ &pattern.rightLen,
+ NULL);
+ if (v->flags & VAR_JUNK) {
+ /* restore original name */
+ free(v->name);
+ v->name = sv_name;
+ }
+ if (pattern.rhs == NULL)
+ 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, nstr);
+ else
+ Var_Set(v->name, newStr, v_ctxt, 0);
+ if (newStr)
+ free(newStr);
+ break;
+ case '?':
+ if ((v->flags & VAR_JUNK) == 0)
+ break;
+ /* FALLTHROUGH */
+ default:
+ Var_Set(v->name, pattern.rhs, v_ctxt, 0);
+ break;
+ }
+ free(UNCONST(pattern.rhs));
+ newStr = var_Error;
+ break;
+ }
+ goto default_case; /* "::<unrecognised>" */
+ }
+ case '@':
+ {
+ VarLoop_t loop;
+ int flags = VAR_NOSUBST;
+
+ cp = ++tstr;
+ delim = '@';
+ if ((loop.tvar = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim,
+ &flags, &loop.tvarLen,
+ NULL)) == NULL)
+ goto cleanup;
+
+ if ((loop.str = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim,
+ &flags, &loop.strLen,
+ NULL)) == NULL)
+ goto cleanup;
+
+ termc = *cp;
+ delim = '\0';
+
+ loop.errnum = errnum;
+ loop.ctxt = ctxt;
+ newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand,
+ &loop);
+ free(loop.tvar);
+ free(loop.str);
+ break;
+ }
+ case 'D':
+ case 'U':
+ {
+ Buffer buf; /* Buffer for patterns */
+ int wantit; /* want data in buffer */
+
+ /*
+ * Pass through 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).
+ * The result is left in the Buffer buf.
+ */
+ buf = Buf_Init(0);
+ for (cp = tstr + 1;
+ *cp != endc && *cp != ':' && *cp != '\0';
+ cp++) {
+ if ((*cp == '\\') &&
+ ((cp[1] == ':') ||
+ (cp[1] == '$') ||
+ (cp[1] == endc) ||
+ (cp[1] == '\\')))
+ {
+ Buf_AddByte(buf, (Byte)cp[1]);
+ cp++;
+ } else if (*cp == '$') {
+ /*
+ * If unescaped dollar sign, assume it's a
+ * variable substitution and recurse.
+ */
+ char *cp2;
+ int len;
+ void *freeIt;
+
+ cp2 = Var_Parse(cp, ctxt, errnum, &len, &freeIt);
+ Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
+ if (freeIt)
+ free(freeIt);
+ cp += len - 1;
+ } else {
+ Buf_AddByte(buf, (Byte)*cp);
+ }
+ }
+ Buf_AddByte(buf, (Byte)'\0');
+
+ termc = *cp;
+
+ if (*tstr == 'U')
+ wantit = ((v->flags & VAR_JUNK) != 0);
+ else
+ wantit = ((v->flags & VAR_JUNK) == 0);
+ if ((v->flags & VAR_JUNK) != 0)
+ v->flags |= VAR_KEEP;
+ if (wantit) {
+ newStr = (char *)Buf_GetAll(buf, NULL);
+ Buf_Destroy(buf, FALSE);
+ } else {
+ newStr = nstr;
+ Buf_Destroy(buf, TRUE);
+ }
+ break;
+ }
+ case 'L':
+ {
+ if ((v->flags & VAR_JUNK) != 0)
+ v->flags |= VAR_KEEP;
+ newStr = estrdup(v->name);
+ cp = ++tstr;
+ termc = *tstr;
+ break;
+ }
+ case 'P':
+ {
+ GNode *gn;
+
+ if ((v->flags & VAR_JUNK) != 0)
+ v->flags |= VAR_KEEP;
+ gn = Targ_FindNode(v->name, TARG_NOCREATE);
+ if (gn == NILGNODE || gn->type & OP_NOPATH) {
+ newStr = NULL;
+ } else if (gn->path) {
+ newStr = estrdup(gn->path);
+ } else {
+ newStr = Dir_FindFile(v->name, Suff_FindPath(gn));
+ }
+ if (!newStr) {
+ newStr = estrdup(v->name);
+ }
+ cp = ++tstr;
+ termc = *tstr;
+ break;
+ }
+ case '!':
+ {
+ const char *emsg;
+ VarPattern pattern;
+ pattern.flags = 0;
+
+ delim = '!';
+
+ cp = ++tstr;
+ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim,
+ NULL, &pattern.rightLen,
+ NULL)) == NULL)
+ goto cleanup;
+ newStr = Cmd_Exec(pattern.rhs, &emsg);
+ free(UNCONST(pattern.rhs));
+ if (emsg)
+ Error(emsg, nstr);
+ termc = *cp;
+ delim = '\0';
+ if (v->flags & VAR_JUNK) {
+ v->flags |= VAR_KEEP;
+ }
+ break;
+ }
+ case '[':
+ {
+ /*
+ * Look for the closing ']', recursively
+ * expanding any embedded variables.
+ *
+ * estr is a pointer to the expanded result,
+ * which we must free().
+ */
+ char *estr;
+
+ cp = tstr+1; /* point to char after '[' */
+ delim = ']'; /* look for closing ']' */
+ estr = VarGetPattern(ctxt, &parsestate,
+ errnum, &cp, delim,
+ NULL, NULL, NULL);
+ if (estr == NULL)
+ goto cleanup; /* report missing ']' */
+ /* now cp points just after the closing ']' */
+ delim = '\0';
+ if (cp[0] != ':' && cp[0] != endc) {
+ /* Found junk after ']' */
+ free(estr);
+ goto bad_modifier;
+ }
+ if (estr[0] == '\0') {
+ /* Found empty square brackets in ":[]". */
+ free(estr);
+ goto bad_modifier;
+ } else if (estr[0] == '#' && estr[1] == '\0') {
+ /* Found ":[#]" */
+
+ /*
+ * We will need enough space for the decimal
+ * representation of an int. We calculate the
+ * space needed for the octal representation,
+ * and add enough slop to cope with a '-' sign
+ * (which should never be needed) and a '\0'
+ * string terminator.
+ */
+ int newStrSize =
+ (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
+
+ newStr = emalloc(newStrSize);
+ if (parsestate.oneBigWord) {
+ strncpy(newStr, "1", newStrSize);
+ } else {
+ /* XXX: brk_string() is a rather expensive
+ * way of counting words. */
+ char **av;
+ char *as;
+ int ac;
+
+ av = brk_string(nstr, &ac, FALSE, &as);
+ snprintf(newStr, newStrSize, "%d", ac);
+ free(as);
+ free(av);
+ }
+ termc = *cp;
+ free(estr);
+ break;
+ } else if (estr[0] == '*' && estr[1] == '\0') {
+ /* Found ":[*]" */
+ parsestate.oneBigWord = TRUE;
+ newStr = nstr;
+ termc = *cp;
+ free(estr);
+ break;
+ } else if (estr[0] == '@' && estr[1] == '\0') {
+ /* Found ":[@]" */
+ parsestate.oneBigWord = FALSE;
+ newStr = nstr;
+ termc = *cp;
+ free(estr);
+ break;
+ } else {
+ /*
+ * We expect estr to contain a single
+ * integer for :[N], or two integers
+ * separated by ".." for :[start..end].
+ */
+ char *ep;
+
+ VarSelectWords_t seldata = { 0, 0 };
+
+ seldata.start = strtol(estr, &ep, 0);
+ if (ep == estr) {
+ /* Found junk instead of a number */
+ free(estr);
+ goto bad_modifier;
+ } else if (ep[0] == '\0') {
+ /* Found only one integer in :[N] */
+ seldata.end = seldata.start;
+ } else if (ep[0] == '.' && ep[1] == '.' &&
+ ep[2] != '\0') {
+ /* Expecting another integer after ".." */
+ ep += 2;
+ seldata.end = strtol(ep, &ep, 0);
+ if (ep[0] != '\0') {
+ /* Found junk after ".." */
+ free(estr);
+ goto bad_modifier;
+ }
+ } else {
+ /* Found junk instead of ".." */
+ free(estr);
+ goto bad_modifier;
+ }
+ /*
+ * Now seldata is properly filled in,
+ * but we still have to check for 0 as
+ * a special case.
+ */
+ if (seldata.start == 0 && seldata.end == 0) {
+ /* ":[0]" or perhaps ":[0..0]" */
+ parsestate.oneBigWord = TRUE;
+ newStr = nstr;
+ termc = *cp;
+ free(estr);
+ break;
+ } else if (seldata.start == 0 ||
+ seldata.end == 0) {
+ /* ":[0..N]" or ":[N..0]" */
+ free(estr);
+ goto bad_modifier;
+ }
+ /*
+ * Normal case: select the words
+ * described by seldata.
+ */
+ newStr = VarSelectWords(ctxt, &parsestate,
+ nstr, &seldata);
+
+ termc = *cp;
+ free(estr);
+ break;
+ }
+
+ }
+ case 't':
+ {
+ cp = tstr + 1; /* make sure it is set */
+ if (tstr[1] != endc && tstr[1] != ':') {
+ if (tstr[1] == 's') {
+ /*
+ * Use the char (if any) at tstr[2]
+ * as the word separator.
+ */
+ VarPattern pattern;
+
+ if (tstr[2] != endc &&
+ (tstr[3] == endc || tstr[3] == ':')) {
+ /* ":ts<unrecognised><endc>" or
+ * ":ts<unrecognised>:" */
+ parsestate.varSpace = tstr[2];
+ cp = tstr + 3;
+ } else if (tstr[2] == endc || tstr[2] == ':') {
+ /* ":ts<endc>" or ":ts:" */
+ parsestate.varSpace = 0; /* no separator */
+ cp = tstr + 2;
+ } else if (tstr[2] == '\\') {
+ switch (tstr[3]) {
+ case 'n':
+ parsestate.varSpace = '\n';
+ cp = tstr + 4;
+ break;
+ case 't':
+ parsestate.varSpace = '\t';
+ cp = tstr + 4;
+ break;
+ default:
+ if (isdigit((unsigned char)tstr[3])) {
+ char *ep;
+
+ parsestate.varSpace =
+ strtoul(&tstr[3], &ep, 0);
+ if (*ep != ':' && *ep != endc)
+ goto bad_modifier;
+ cp = ep;
+ } else {
+ /*
+ * ":ts<backslash><unrecognised>".
+ */
+ goto bad_modifier;
+ }
+ break;
+ }
+ } else {
+ /*
+ * Found ":ts<unrecognised><unrecognised>".
+ */
+ goto bad_modifier;
+ }
+
+ termc = *cp;
+
+ /*
+ * We cannot be certain that VarModify
+ * will be used - even if there is a
+ * subsequent modifier, so do a no-op
+ * VarSubstitute now to for str to be
+ * re-expanded without the spaces.
+ */
+ pattern.flags = VAR_SUB_ONE;
+ pattern.lhs = pattern.rhs = "\032";
+ pattern.leftLen = pattern.rightLen = 1;
+
+ newStr = VarModify(ctxt, &parsestate, nstr,
+ VarSubstitute,
+ &pattern);
+ } else if (tstr[2] == endc || tstr[2] == ':') {
+ /*
+ * Check for two-character options:
+ * ":tu", ":tl"
+ */
+ if (tstr[1] == 'u' || tstr[1] == 'l') {
+ newStr = VarChangeCase(nstr, (tstr[1] == 'u'));
+ cp = tstr + 2;
+ termc = *cp;
+ } else if (tstr[1] == 'W' || tstr[1] == 'w') {
+ parsestate.oneBigWord = (tstr[1] == 'W');
+ newStr = nstr;
+ cp = tstr + 2;
+ termc = *cp;
+ } else {
+ /* Found ":t<unrecognised>:" or
+ * ":t<unrecognised><endc>". */
+ goto bad_modifier;
+ }
+ } else {
+ /*
+ * Found ":t<unrecognised><unrecognised>".
+ */
+ goto bad_modifier;
+ }
+ } else {
+ /*
+ * Found ":t<endc>" or ":t:".
+ */
+ goto bad_modifier;
+ }
+ break;
+ }
+ case 'N':
+ case 'M':
+ {
+ char *pattern;
+ const char *endpat; /* points just after end of pattern */
+ char *cp2;
+ Boolean copy; /* pattern should be, or has been, copied */
+ int nest;
+
+ copy = FALSE;
+ nest = 1;
+ /*
+ * In the loop below, ignore ':' unless we are at
+ * (or back to) the original brace level.
+ * XXX This will likely not work right if $() and ${}
+ * are intermixed.
+ */
+ for (cp = tstr + 1;
+ *cp != '\0' && !(*cp == ':' && nest == 1);
+ cp++)
+ {
+ if (*cp == '\\' &&
+ (cp[1] == ':' ||
+ cp[1] == endc || cp[1] == startc)) {
+ copy = TRUE;
+ cp++;
+ continue;
+ }
+ if (*cp == startc)
+ ++nest;
+ if (*cp == endc) {
+ --nest;
+ if (nest == 0)
+ break;
+ }
+ }
+ termc = *cp;
+ endpat = cp;
+ if (copy) {
+ /*
+ * Need to compress the \:'s out of the pattern, so
+ * allocate enough room to hold the uncompressed
+ * pattern (note that cp started at tstr+1, so
+ * cp - tstr takes the null byte into account) and
+ * compress the pattern into the space.
+ */
+ pattern = emalloc(cp - tstr);
+ for (cp2 = pattern, cp = tstr + 1;
+ cp < endpat;
+ cp++, cp2++)
+ {
+ if ((*cp == '\\') && (cp+1 < endpat) &&
+ (cp[1] == ':' || cp[1] == endc)) {
+ cp++;
+ }
+ *cp2 = *cp;
+ }
+ *cp2 = '\0';
+ endpat = cp2;
+ } else {
+ /*
+ * Either Var_Subst or VarModify will need a
+ * nul-terminated string soon, so construct one now.
+ */
+ pattern = estrndup(tstr+1, endpat - (tstr + 1));
+ copy = TRUE;
+ }
+ if (strchr(pattern, '$') != NULL) {
+ /*
+ * pattern contains embedded '$', so use Var_Subst to
+ * expand it.
+ */
+ cp2 = pattern;
+ pattern = Var_Subst(NULL, cp2, ctxt, errnum);
+ if (copy)
+ free(cp2);
+ copy = TRUE;
+ }
+ if (*tstr == 'M' || *tstr == 'm') {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarMatch,
+ pattern);
+ } else {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch,
+ pattern);
+ }
+ if (copy) {
+ free(pattern);
+ }
+ break;
+ }
+ case 'S':
+ {
+ VarPattern pattern;
+ Var_Parse_State tmpparsestate;
+
+ pattern.flags = 0;
+ tmpparsestate = parsestate;
+ delim = tstr[1];
+ tstr += 2;
+
+ /*
+ * If pattern begins with '^', it is anchored to the
+ * start of the word -- skip over it and flag pattern.
+ */
+ if (*tstr == '^') {
+ pattern.flags |= VAR_MATCH_START;
+ tstr += 1;
+ }
+
+ cp = tstr;
+ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim,
+ &pattern.flags,
+ &pattern.leftLen,
+ NULL)) == NULL)
+ goto cleanup;
+
+ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim, NULL,
+ &pattern.rightLen,
+ &pattern)) == NULL)
+ goto cleanup;
+
+ /*
+ * Check for global substitution. If 'g' after the final
+ * delimiter, substitution is global and is marked that
+ * way.
+ */
+ for (;; cp++) {
+ switch (*cp) {
+ case 'g':
+ pattern.flags |= VAR_SUB_GLOBAL;
+ continue;
+ case '1':
+ pattern.flags |= VAR_SUB_ONE;
+ continue;
+ case 'W':
+ tmpparsestate.oneBigWord = TRUE;
+ continue;
+ }
+ break;
+ }
+
+ termc = *cp;
+ newStr = VarModify(ctxt, &tmpparsestate, nstr,
+ VarSubstitute,
+ &pattern);
+
+ /*
+ * Free the two strings.
+ */
+ free(UNCONST(pattern.lhs));
+ free(UNCONST(pattern.rhs));
+ delim = '\0';
+ break;
+ }
+ case '?':
+ {
+ VarPattern pattern;
+ Boolean value;
+
+ /* find ':', and then substitute accordingly */
+
+ pattern.flags = 0;
+
+ cp = ++tstr;
+ delim = ':';
+ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim, NULL,
+ &pattern.leftLen,
+ NULL)) == NULL)
+ goto cleanup;
+
+ /* BROPEN or PROPEN */
+ delim = endc;
+ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
+ &cp, delim, NULL,
+ &pattern.rightLen,
+ NULL)) == NULL)
+ goto cleanup;
+
+ termc = *--cp;
+ delim = '\0';
+ if (Cond_EvalExpression(1, v->name, &value, 0)
+ == COND_INVALID) {
+ Error("Bad conditional expression `%s' in %s?%s:%s",
+ v->name, v->name, pattern.lhs, pattern.rhs);
+ goto cleanup;
+ }
+
+ if (value) {
+ newStr = UNCONST(pattern.lhs);
+ free(UNCONST(pattern.rhs));
+ } else {
+ newStr = UNCONST(pattern.rhs);
+ free(UNCONST(pattern.lhs));
+ }
+ if (v->flags & VAR_JUNK) {
+ v->flags |= VAR_KEEP;
+ }
+ break;
+ }
+#ifndef NO_REGEX
+ case 'C':
+ {
+ VarREPattern pattern;
+ char *re;
+ int error;
+ Var_Parse_State tmpparsestate;
+
+ pattern.flags = 0;
+ tmpparsestate = parsestate;
+ delim = tstr[1];
+ tstr += 2;
+
+ cp = tstr;
+
+ if ((re = VarGetPattern(ctxt, &parsestate, errnum, &cp, delim,
+ NULL, NULL, NULL)) == NULL)
+ goto cleanup;
+
+ if ((pattern.replace = VarGetPattern(ctxt, &parsestate,
+ errnum, &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;
+ case 'W':
+ tmpparsestate.oneBigWord = TRUE;
+ continue;
+ }
+ break;
+ }
+
+ termc = *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);
+ goto cleanup;
+ }
+
+ 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(ctxt, &tmpparsestate, nstr,
+ VarRESubstitute,
+ &pattern);
+ regfree(&pattern.re);
+ free(pattern.replace);
+ free(pattern.matches);
+ delim = '\0';
+ break;
+ }
+#endif
+ case 'Q':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarQuote(nstr);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+ case 'T':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarTail,
+ NULL);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+ case 'H':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarHead,
+ NULL);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+ case 'E':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix,
+ NULL);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+ case 'R':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarModify(ctxt, &parsestate, nstr, VarRoot,
+ NULL);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+ case 'O':
+ {
+ char otype;
+
+ cp = tstr + 1; /* skip to the rest in any case */
+ if (tstr[1] == endc || tstr[1] == ':') {
+ otype = 's';
+ termc = *cp;
+ } else if ( (tstr[1] == 'x') &&
+ (tstr[2] == endc || tstr[2] == ':') ) {
+ otype = tstr[1];
+ cp = tstr + 2;
+ termc = *cp;
+ } else {
+ goto bad_modifier;
+ }
+ newStr = VarOrder(nstr, otype);
+ break;
+ }
+ case 'u':
+ if (tstr[1] == endc || tstr[1] == ':') {
+ newStr = VarUniq(nstr);
+ cp = tstr + 1;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+#ifdef SUNSHCMD
+ case 's':
+ if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
+ const char *emsg;
+ newStr = Cmd_Exec(nstr, &emsg);
+ if (emsg)
+ Error(emsg, nstr);
+ cp = tstr + 2;
+ termc = *cp;
+ break;
+ }
+ goto default_case;
+#endif
+ default:
+ default_case:
+ {
+#ifdef SYSVVARSUB
+ /*
+ * This can either be a bogus modifier or a System-V
+ * substitution command.
+ */
+ VarPattern pattern;
+ Boolean eqFound;
+
+ pattern.flags = 0;
+ eqFound = FALSE;
+ /*
+ * First we make a pass through the string trying
+ * to verify it is a SYSV-make-style translation:
+ * it must be: <string1>=<string2>)
+ */
+ cp = tstr;
+ cnt = 1;
+ while (*cp != '\0' && cnt) {
+ if (*cp == '=') {
+ eqFound = TRUE;
+ /* continue looking for endc */
+ }
+ else if (*cp == endc)
+ cnt--;
+ else if (*cp == startc)
+ cnt++;
+ if (cnt)
+ cp++;
+ }
+ if (*cp == endc && eqFound) {
+
+ /*
+ * Now we break this sucker into the lhs and
+ * rhs. We must null terminate them of course.
+ */
+ delim='=';
+ cp = tstr;
+ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate,
+ errnum, &cp, delim, &pattern.flags,
+ &pattern.leftLen, NULL)) == NULL)
+ goto cleanup;
+ delim = endc;
+ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate,
+ errnum, &cp, delim, NULL, &pattern.rightLen,
+ &pattern)) == NULL)
+ goto cleanup;
+
+ /*
+ * SYSV modifications happen through the whole
+ * string. Note the pattern is anchored at the end.
+ */
+ termc = *--cp;
+ delim = '\0';
+ newStr = VarModify(ctxt, &parsestate, nstr,
+ VarSYSVMatch,
+ &pattern);
+ free(UNCONST(pattern.lhs));
+ free(UNCONST(pattern.rhs));
+ } else
+#endif
+ {
+ Error("Unknown modifier '%c'", *tstr);
+ for (cp = tstr+1;
+ *cp != ':' && *cp != endc && *cp != '\0';
+ cp++)
+ continue;
+ termc = *cp;
+ newStr = var_Error;
+ }
+ }
+ }
+ if (DEBUG(VAR)) {
+ fprintf(debug_file, "Result of :%c is \"%s\"\n", modifier, newStr);
+ }
+
+ if (newStr != nstr) {
+ if (*freePtr) {
+ free(nstr);
+ *freePtr = NULL;
+ }
+ nstr = newStr;
+ if (nstr != var_Error && nstr != varNoError) {
+ *freePtr = nstr;
+ }
+ }
+ if (termc == '\0' && endc != '\0') {
+ Error("Unclosed variable specification for %s", v->name);
+ } else if (termc == ':') {
+ cp++;
+ }
+ tstr = cp;
+ }
+ out:
+ *lengthPtr = tstr - start;
+ return (nstr);
+
+ bad_modifier:
+ /* "{(" */
+ Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr,
+ v->name);
+
+ cleanup:
+ *lengthPtr = cp - start;
+ if (delim != '\0')
+ Error("Unclosed substitution for %s (%c missing)",
+ v->name, delim);
+ if (*freePtr) {
+ free(*freePtr);
+ *freePtr = NULL;
+ }
+ return (var_Error);
+}
+
/*-
*-----------------------------------------------------------------------
* Var_Parse --
@@ -1868,49 +3196,45 @@ VarChangeCase(char *str, int upper)
* Input:
* str The string to parse
* ctxt The context for the variable
- * err TRUE if undefined variables are an error
+ * errnum TRUE if undefined variables are an error
* lengthPtr OUT: The length of the specification
- * freePtr OUT: TRUE if caller should free result
+ * freePtr OUT: Non-NULL if caller should free *freePtr
*
* Results:
* The (possibly-modified) value of the variable or var_Error if the
* specification is invalid. The length of the specification is
* placed in *lengthPtr (for invalid specifications, this is just
* 2...?).
- * A Boolean in *freePtr telling whether the returned string should
- * be freed by the caller.
+ * If *freePtr is non-NULL then it's a pointer that the caller
+ * should pass to free() to free memory used by the result.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
+/* coverity[+alloc : arg-*4] */
char *
-Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
- Boolean *freePtr)
+Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
+ void **freePtr)
{
const char *tstr; /* Pointer into str */
Var *v; /* Variable in invocation */
- const char *cp; /* Secondary pointer into str (place marker
- * for tstr) */
Boolean haveModifier;/* TRUE if have modifiers for the variable */
char endc; /* Ending character when variable in parens
* or braces */
char startc=0; /* Starting character when variable in parens
* or braces */
- int cnt; /* Used to count brace pairs when variable in
- * in parens or braces */
int vlen; /* Length of variable name */
- const char *start;
- char delim;
- char *nstr;
+ const char *start; /* Points to original start of str */
+ char *nstr; /* New string, used during expansion */
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
* result is just the invocation, unaltered */
Var_Parse_State parsestate; /* Flags passed to helper functions */
- *freePtr = FALSE;
+ *freePtr = NULL;
dynamic = FALSE;
start = str;
parsestate.oneBigWord = FALSE;
@@ -1955,7 +3279,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
/*
* Error
*/
- return (err ? var_Error : varNoError);
+ return (errnum ? var_Error : varNoError);
} else {
haveModifier = FALSE;
tstr = &str[1];
@@ -1963,13 +3287,13 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
}
} else if (str[1] == '\0') {
*lengthPtr = 1;
- return (err ? var_Error : varNoError);
- } else {
+ return (errnum ? var_Error : varNoError);
+ } else {
Buffer buf; /* Holds the variable name */
startc = str[1];
endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
- buf = Buf_Init(MAKE_BSIZE);
+ buf = Buf_Init(0);
/*
* Skip to the end character or a colon, whichever comes first.
@@ -1983,13 +3307,13 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
*/
if (*tstr == '$') {
int rlen;
- Boolean rfree;
- char *rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);
+ void *freeIt;
+ char *rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt);
if (rval != NULL) {
Buf_AddBytes(buf, strlen(rval), (Byte *)rval);
- if (rfree)
- free(rval);
}
+ if (freeIt)
+ free(freeIt);
tstr += rlen - 1;
}
else
@@ -2006,13 +3330,24 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
* the end of the string, since that's what make does.
*/
*lengthPtr = tstr - str;
+ Buf_Destroy(buf, TRUE);
return (var_Error);
}
- *WR(tstr) = '\0';
Buf_AddByte(buf, (Byte)'\0');
str = Buf_GetAll(buf, NULL);
vlen = strlen(str);
+ /*
+ * At this point, str points into newly allocated memory from
+ * buf, containing only the name of the variable.
+ *
+ * start and tstr point into the const string that was pointed
+ * to by the original value of the str parameter. start points
+ * to the '$' at the beginning of the string, while tstr points
+ * to the char just after the end of the variable name -- this
+ * will be '\0', ':', PRCLOSE, or BRCLOSE.
+ */
+
v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
(vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
@@ -2049,19 +3384,19 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
if (str[1] == 'D') {
val = VarModify(ctxt, &parsestate, val, VarHead,
- (ClientData)0);
+ NULL);
} else {
val = VarModify(ctxt, &parsestate, val, VarTail,
- (ClientData)0);
+ NULL);
}
/*
* Resulting string is dynamically allocated, so
* tell caller to free it.
*/
- *freePtr = TRUE;
+ *freePtr = val;
*lengthPtr = tstr-start+1;
- *WR(tstr) = endc;
Buf_Destroy(buf, TRUE);
+ VarFreeEnv(v, TRUE);
return(val);
}
break;
@@ -2114,17 +3449,14 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
* now.
*/
*lengthPtr = tstr - start + 1;
- *WR(tstr) = endc;
if (dynamic) {
- char *pstr = emalloc(*lengthPtr + 1);
- strncpy(pstr, start, *lengthPtr);
- pstr[*lengthPtr] = '\0';
- *freePtr = TRUE;
+ char *pstr = estrndup(start, *lengthPtr);
+ *freePtr = pstr;
Buf_Destroy(buf, TRUE);
return(pstr);
} else {
Buf_Destroy(buf, TRUE);
- return (err ? var_Error : varNoError);
+ return (errnum ? var_Error : varNoError);
}
} else {
/*
@@ -2141,7 +3473,6 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
Buf_Destroy(buf, TRUE);
}
-
if (v->flags & VAR_IN_USE) {
Fatal("Variable %s is recursive.", v->name);
/*NOTREACHED*/
@@ -2159,1028 +3490,27 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
*/
nstr = (char *)Buf_GetAll(v->val, NULL);
if (strchr(nstr, '$') != NULL) {
- nstr = Var_Subst(NULL, nstr, ctxt, err);
- *freePtr = TRUE;
+ nstr = Var_Subst(NULL, nstr, ctxt, errnum);
+ *freePtr = nstr;
}
v->flags &= ~VAR_IN_USE;
- /*
- * Now we need to apply any modifiers the user wants applied.
- * These are:
- * :M<pattern> words which match the given <pattern>.
- * <pattern> is of the standard file
- * wildcarding form.
- * :N<pattern> words which do not match the given <pattern>.
- * :S<d><pat1><d><pat2><d>[1gW]
- * Substitute <pat2> for <pat1> in the value
- * :C<d><pat1><d><pat2><d>[1gW]
- * 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
- * each word
- * :R Substitute the root of each word
- * (pathname minus the suffix).
- * :O ("Order") Alphabeticaly sort words in variable.
- * :Ox ("intermiX") Randomize words in variable.
- * :u ("uniq") Remove adjacent duplicate words.
- * :tu Converts the variable contents to uppercase.
- * :tl Converts the variable contents to lowercase.
- * :ts[c] Sets varSpace - the char used to
- * separate words to 'c'. If 'c' is
- * omitted then no separation is used.
- * :tW Treat the variable contents as a single
- * word, even if it contains spaces.
- * (Mnemonic: one big 'W'ord.)
- * :tw Treat the variable contents as multiple
- * space-separated words.
- * (Mnemonic: many small 'w'ords.)
- * :[index] Select a single word from the value.
- * :[start..end] Select multiple words from the value.
- * :[*] or :[0] Select the entire value, as a single
- * word. Equivalent to :tW.
- * :[@] Select the entire value, as multiple
- * words. Undoes the effect of :[*].
- * Equivalent to :tw.
- * :[#] Returns the number of words in the value.
- *
- * :?<true-value>:<false-value>
- * If the variable evaluates to true, return
- * true value, else return the second value.
- * :lhs=rhs Like :S, but the rhs goes to the end of
- * the invocation.
- * :sh Treat the current value as a command
- * to be run, new value is its output.
- * The following added so we can handle ODE makefiles.
- * :@<tmpvar>@<newval>@
- * Assign a temporary local variable <tmpvar>
- * to the current value of each word in turn
- * and replace each word with the result of
- * evaluating <newval>
- * :D<newval> Use <newval> as value if variable defined
- * :U<newval> Use <newval> as value if variable undefined
- * :L Use the name of the variable as the value.
- * :P Use the path of the node that has the same
- * name as the variable as the value. This
- * basically includes an implied :L so that
- * the common method of refering to the path
- * of your dependent 'x' in a rule is to use
- * 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
- *
- * ::=<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 ((nstr != NULL) && haveModifier) {
+ int used;
/*
- * Skip initial colon while putting it back.
+ * Skip initial colon.
*/
- *WR(tstr) = ':';
tstr++;
- delim = '\0';
-
- while (*tstr && *tstr != endc) {
- char *newStr; /* New value to return */
- char termc; /* Character which terminated scan */
-
- if (DEBUG(VAR)) {
- printf("Applying :%c to \"%s\"\n", *tstr, nstr);
- }
- newStr = var_Error;
- switch (*tstr) {
- case ':':
- {
- if (tstr[1] == '=' ||
- (tstr[2] == '=' &&
- (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) {
- /*
- * "::=", "::!=", "::+=", or "::?="
- */
- GNode *v_ctxt; /* context where v belongs */
- const char *emsg;
- char *sv_name;
- VarPattern pattern;
- int how;
-
- v_ctxt = ctxt;
- sv_name = NULL;
- ++tstr;
- if (v->flags & VAR_JUNK) {
- /*
- * We need to strdup() it incase
- * VarGetPattern() recurses.
- */
- sv_name = v->name;
- v->name = strdup(v->name);
- } else if (ctxt != VAR_GLOBAL) {
- if (VarFind(v->name, ctxt, 0) == (Var *)NIL)
- v_ctxt = VAR_GLOBAL;
- }
-
- switch ((how = *tstr)) {
- case '+':
- case '?':
- case '!':
- cp = &tstr[2];
- break;
- default:
- cp = ++tstr;
- break;
- }
- delim = BRCLOSE;
- pattern.flags = 0;
-
- pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim, NULL,
- &pattern.rightLen,
- NULL);
- if (v->flags & VAR_JUNK) {
- /* restore original name */
- free(v->name);
- v->name = sv_name;
- }
- if (pattern.rhs == NULL)
- 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, nstr);
- else
- Var_Set(v->name, newStr, v_ctxt, 0);
- if (newStr)
- free(newStr);
- break;
- case '?':
- if ((v->flags & VAR_JUNK) == 0)
- break;
- /* FALLTHROUGH */
- default:
- Var_Set(v->name, pattern.rhs, v_ctxt, 0);
- break;
- }
- free(UNCONST(pattern.rhs));
- newStr = var_Error;
- break;
- }
- goto default_case; /* "::<unrecognised>" */
- }
- case '@':
- {
- VarLoop_t loop;
- int flags = VAR_NOSUBST;
-
- cp = ++tstr;
- delim = '@';
- if ((loop.tvar = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim,
- &flags, &loop.tvarLen,
- NULL)) == NULL)
- goto cleanup;
-
- if ((loop.str = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim,
- &flags, &loop.strLen,
- NULL)) == NULL)
- goto cleanup;
- termc = *cp;
- delim = '\0';
-
- loop.err = err;
- loop.ctxt = ctxt;
- newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand,
- (ClientData)&loop);
- free(loop.tvar);
- free(loop.str);
- break;
- }
- case 'D':
- case 'U':
- {
- Buffer buf; /* Buffer for patterns */
- int wantit; /* want data in buffer */
-
- /*
- * Pass through 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).
- * The result is left in the Buffer buf.
- */
- buf = Buf_Init(0);
- for (cp = tstr + 1;
- *cp != endc && *cp != ':' && *cp != '\0';
- cp++) {
- if ((*cp == '\\') &&
- ((cp[1] == ':') ||
- (cp[1] == '$') ||
- (cp[1] == endc) ||
- (cp[1] == '\\')))
- {
- Buf_AddByte(buf, (Byte)cp[1]);
- cp++;
- } else if (*cp == '$') {
- /*
- * If unescaped dollar sign, 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 {
- Buf_AddByte(buf, (Byte)*cp);
- }
- }
- Buf_AddByte(buf, (Byte)'\0');
-
- termc = *cp;
-
- if (*tstr == 'U')
- wantit = ((v->flags & VAR_JUNK) != 0);
- else
- wantit = ((v->flags & VAR_JUNK) == 0);
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- if (wantit) {
- newStr = (char *)Buf_GetAll(buf, NULL);
- Buf_Destroy(buf, FALSE);
- } else {
- newStr = nstr;
- Buf_Destroy(buf, TRUE);
- }
- break;
- }
- case 'L':
- {
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- newStr = strdup(v->name);
- cp = ++tstr;
- termc = *tstr;
- break;
- }
- case 'P':
- {
- GNode *gn;
-
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- gn = Targ_FindNode(v->name, TARG_NOCREATE);
- if (gn == NILGNODE || gn->path == NULL)
- newStr = strdup(v->name);
- else
- newStr = strdup(gn->path);
- cp = ++tstr;
- termc = *tstr;
- break;
- }
- case '!':
- {
- const char *emsg;
- VarPattern pattern;
- pattern.flags = 0;
-
- delim = '!';
-
- cp = ++tstr;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim,
- NULL, &pattern.rightLen,
- NULL)) == NULL)
- goto cleanup;
- newStr = Cmd_Exec(pattern.rhs, &emsg);
- free(UNCONST(pattern.rhs));
- if (emsg)
- Error(emsg, nstr);
- termc = *cp;
- delim = '\0';
- if (v->flags & VAR_JUNK) {
- v->flags |= VAR_KEEP;
- }
- break;
- }
- case '[':
- {
- /*
- * Look for the closing ']', recursively
- * expanding any embedded variables.
- *
- * estr is a pointer to the expanded result,
- * which we must free().
- */
- char *estr;
-
- cp = tstr+1; /* point to char after '[' */
- delim = ']'; /* look for closing ']' */
- estr = VarGetPattern(ctxt, &parsestate,
- err, &cp, delim,
- NULL, NULL, NULL);
- if (estr == NULL)
- goto cleanup; /* report missing ']' */
- /* now cp points just after the closing ']' */
- delim = '\0';
- if (cp[0] != ':' && cp[0] != endc) {
- /* Found junk after ']' */
- free(estr);
- goto bad_modifier;
- }
- if (estr[0] == '\0') {
- /* Found empty square brackets in ":[]". */
- free(estr);
- goto bad_modifier;
- } else if (estr[0] == '#' && estr[1] == '\0') {
- /* Found ":[#]" */
-
- /*
- * We will need enough space for the decimal
- * representation of an int. We calculate the
- * space needed for the octal representation,
- * and add enough slop to cope with a '-' sign
- * (which should never be needed) and a '\0'
- * string terminator.
- */
- int newStrSize =
- (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
-
- newStr = emalloc(newStrSize);
- if (parsestate.oneBigWord) {
- strncpy(newStr, "1", newStrSize);
- } else {
- /* XXX: brk_string() is a rather expensive
- * way of counting words. */
- char **av;
- char *as;
- int ac;
-
- av = brk_string(nstr, &ac, FALSE, &as);
- snprintf(newStr, newStrSize, "%d", ac);
- free(as);
- free(av);
- }
- termc = *cp;
- free(estr);
- break;
- } else if (estr[0] == '*' && estr[1] == '\0') {
- /* Found ":[*]" */
- parsestate.oneBigWord = TRUE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else if (estr[0] == '@' && estr[1] == '\0') {
- /* Found ":[@]" */
- parsestate.oneBigWord = FALSE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else {
- /*
- * We expect estr to contain a single
- * integer for :[N], or two integers
- * separated by ".." for :[start..end].
- */
- char *ep;
-
- VarSelectWords_t seldata = { 0, 0 };
-
- seldata.start = strtol(estr, &ep, 0);
- if (ep == estr) {
- /* Found junk instead of a number */
- free(estr);
- goto bad_modifier;
- } else if (ep[0] == '\0') {
- /* Found only one integer in :[N] */
- seldata.end = seldata.start;
- } else if (ep[0] == '.' && ep[1] == '.' &&
- ep[2] != '\0') {
- /* Expecting another integer after ".." */
- ep += 2;
- seldata.end = strtol(ep, &ep, 0);
- if (ep[0] != '\0') {
- /* Found junk after ".." */
- free(estr);
- goto bad_modifier;
- }
- } else {
- /* Found junk instead of ".." */
- free(estr);
- goto bad_modifier;
- }
- /*
- * Now seldata is properly filled in,
- * but we still have to check for 0 as
- * a special case.
- */
- if (seldata.start == 0 && seldata.end == 0) {
- /* ":[0]" or perhaps ":[0..0]" */
- parsestate.oneBigWord = TRUE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else if (seldata.start == 0 ||
- seldata.end == 0) {
- /* ":[0..N]" or ":[N..0]" */
- free(estr);
- goto bad_modifier;
- }
- /*
- * Normal case: select the words
- * described by seldata.
- */
- newStr = VarSelectWords(ctxt, &parsestate,
- nstr, &seldata);
-
- termc = *cp;
- free(estr);
- break;
- }
-
- }
- case 't':
- {
- cp = tstr + 1; /* make sure it is set */
- if (tstr[1] != endc && tstr[1] != ':') {
- if (tstr[1] == 's') {
- /*
- * Use the char (if any) at tstr[2]
- * as the word separator.
- */
- VarPattern pattern;
-
- if (tstr[2] != endc &&
- (tstr[3] == endc || tstr[3] == ':')) {
- /* ":ts<unrecognised><endc>" or
- * ":ts<unrecognised>:" */
- parsestate.varSpace = tstr[2];
- cp = tstr + 3;
- } else if (tstr[2] == endc || tstr[2] == ':') {
- /* ":ts<endc>" or ":ts:" */
- parsestate.varSpace = 0; /* no separator */
- cp = tstr + 2;
- } else if (tstr[2] == '\\') {
- switch (tstr[3]) {
- case 'n':
- parsestate.varSpace = '\n';
- cp = tstr + 4;
- break;
- case 't':
- parsestate.varSpace = '\t';
- cp = tstr + 4;
- break;
- default:
- if (isdigit((unsigned char)tstr[3])) {
- char *ep;
-
- parsestate.varSpace =
- strtoul(&tstr[3], &ep, 0);
- if (*ep != ':' && *ep != endc)
- goto bad_modifier;
- cp = ep;
- } else {
- /*
- * ":ts<backslash><unrecognised>".
- */
- goto bad_modifier;
- }
- break;
- }
- } else {
- /*
- * Found ":ts<unrecognised><unrecognised>".
- */
- goto bad_modifier;
- }
-
- termc = *cp;
-
- /*
- * We cannot be certain that VarModify
- * will be used - even if there is a
- * subsequent modifier, so do a no-op
- * VarSubstitute now to for str to be
- * re-expanded without the spaces.
- */
- pattern.flags = VAR_SUB_ONE;
- pattern.lhs = pattern.rhs = "\032";
- pattern.leftLen = pattern.rightLen = 1;
-
- newStr = VarModify(ctxt, &parsestate, nstr,
- VarSubstitute,
- (ClientData)&pattern);
- } else if (tstr[2] == endc || tstr[2] == ':') {
- /*
- * Check for two-character options:
- * ":tu", ":tl"
- */
- if (tstr[1] == 'u' || tstr[1] == 'l') {
- newStr = VarChangeCase(nstr, (tstr[1] == 'u'));
- cp = tstr + 2;
- termc = *cp;
- } else if (tstr[1] == 'W' || tstr[1] == 'w') {
- parsestate.oneBigWord = (tstr[1] == 'W');
- newStr = nstr;
- cp = tstr + 2;
- termc = *cp;
- } else {
- /* Found ":t<unrecognised>:" or
- * ":t<unrecognised><endc>". */
- goto bad_modifier;
- }
- } else {
- /*
- * Found ":t<unrecognised><unrecognised>".
- */
- goto bad_modifier;
- }
- } else {
- /*
- * Found ":t<endc>" or ":t:".
- */
- goto bad_modifier;
- }
- break;
- }
- case 'N':
- case 'M':
- {
- char *pattern;
- char *cp2;
- Boolean copy;
- int nest;
-
- copy = FALSE;
- nest = 1;
- /*
- * In the loop below, ignore ':' unless we are at
- * (or back to) the original brace level.
- * XXX This will likely not work right if $() and ${}
- * are intermixed.
- */
- for (cp = tstr + 1;
- *cp != '\0' && !(*cp == ':' && nest == 1);
- cp++)
- {
- if (*cp == '\\' &&
- (cp[1] == ':' ||
- cp[1] == endc || cp[1] == startc)) {
- copy = TRUE;
- cp++;
- continue;
- }
- if (*cp == startc)
- ++nest;
- if (*cp == endc) {
- --nest;
- if (nest == 0)
- break;
- }
- }
- termc = *cp;
- *WR(cp) = '\0';
- if (copy) {
- /*
- * Need to compress the \:'s out of the pattern, so
- * allocate enough room to hold the uncompressed
- * pattern (note that cp started at tstr+1, so
- * cp - tstr takes the null byte into account) and
- * compress the pattern into the space.
- */
- pattern = emalloc(cp - tstr);
- for (cp2 = pattern, cp = tstr + 1;
- *cp != '\0';
- cp++, cp2++)
- {
- if ((*cp == '\\') &&
- (cp[1] == ':' || cp[1] == endc)) {
- cp++;
- }
- *cp2 = *cp;
- }
- *cp2 = '\0';
- } else {
- pattern = UNCONST(&tstr[1]);
- }
- if ((cp2 = strchr(pattern, '$'))) {
- cp2 = pattern;
- pattern = Var_Subst(NULL, cp2, ctxt, err);
- if (copy)
- free(cp2);
- copy = TRUE;
- }
- if (*tstr == 'M' || *tstr == 'm') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarMatch,
- (ClientData)pattern);
- } else {
- newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch,
- (ClientData)pattern);
- }
- if (copy) {
- free(pattern);
- }
- break;
- }
- case 'S':
- {
- VarPattern pattern;
- Var_Parse_State tmpparsestate;
-
- pattern.flags = 0;
- tmpparsestate = parsestate;
- delim = tstr[1];
- tstr += 2;
-
- /*
- * If pattern begins with '^', it is anchored to the
- * start of the word -- skip over it and flag pattern.
- */
- if (*tstr == '^') {
- pattern.flags |= VAR_MATCH_START;
- tstr += 1;
- }
-
- cp = tstr;
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim,
- &pattern.flags,
- &pattern.leftLen,
- NULL)) == NULL)
- goto cleanup;
-
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim, NULL,
- &pattern.rightLen,
- &pattern)) == NULL)
- goto cleanup;
-
- /*
- * Check for global substitution. If 'g' after the final
- * delimiter, substitution is global and is marked that
- * way.
- */
- for (;; cp++) {
- switch (*cp) {
- case 'g':
- pattern.flags |= VAR_SUB_GLOBAL;
- continue;
- case '1':
- pattern.flags |= VAR_SUB_ONE;
- continue;
- case 'W':
- tmpparsestate.oneBigWord = TRUE;
- continue;
- }
- break;
- }
-
- termc = *cp;
- newStr = VarModify(ctxt, &tmpparsestate, nstr,
- VarSubstitute,
- (ClientData)&pattern);
-
- /*
- * Free the two strings.
- */
- free(UNCONST(pattern.lhs));
- free(UNCONST(pattern.rhs));
- delim = '\0';
- break;
- }
- case '?':
- {
- VarPattern pattern;
- Boolean value;
-
- /* find ':', and then substitute accordingly */
-
- pattern.flags = 0;
-
- cp = ++tstr;
- delim = ':';
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim, NULL,
- &pattern.leftLen,
- NULL)) == NULL)
- goto cleanup;
-
- /* BROPEN or PROPEN */
- delim = endc;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, err,
- &cp, delim, NULL,
- &pattern.rightLen,
- NULL)) == NULL)
- goto cleanup;
-
- termc = *--cp;
- delim = '\0';
- if (Cond_EvalExpression(1, v->name, &value, 0)
- == COND_INVALID) {
- Error("Bad conditional expression `%s' in %s?%s:%s",
- v->name, v->name, pattern.lhs, pattern.rhs);
- goto cleanup;
- }
-
- if (value) {
- newStr = UNCONST(pattern.lhs);
- free(UNCONST(pattern.rhs));
- } else {
- newStr = UNCONST(pattern.rhs);
- free(UNCONST(pattern.lhs));
- }
- if (v->flags & VAR_JUNK) {
- v->flags |= VAR_KEEP;
- }
- break;
- }
-#ifndef NO_REGEX
- case 'C':
- {
- VarREPattern pattern;
- char *re;
- int error;
- Var_Parse_State tmpparsestate;
-
- pattern.flags = 0;
- tmpparsestate = parsestate;
- delim = tstr[1];
- tstr += 2;
-
- cp = tstr;
-
- if ((re = VarGetPattern(ctxt, &parsestate, err, &cp, delim,
- NULL, NULL, NULL)) == NULL)
- goto cleanup;
-
- if ((pattern.replace = VarGetPattern(ctxt, &parsestate,
- 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;
- case 'W':
- tmpparsestate.oneBigWord = TRUE;
- continue;
- }
- break;
- }
-
- termc = *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);
- }
-
- 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(ctxt, &tmpparsestate, nstr,
- VarRESubstitute,
- (ClientData) &pattern);
- regfree(&pattern.re);
- free(pattern.replace);
- free(pattern.matches);
- delim = '\0';
- break;
- }
-#endif
- case 'Q':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarQuote(nstr);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'T':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarTail,
- (ClientData)0);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'H':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarHead,
- (ClientData)0);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'E':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix,
- (ClientData)0);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'R':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarRoot,
- (ClientData)0);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'O':
- {
- char otype;
-
- cp = tstr + 1; /* skip to the rest in any case */
- if (tstr[1] == endc || tstr[1] == ':') {
- otype = 's';
- termc = *cp;
- } else if ( (tstr[1] == 'x') &&
- (tstr[2] == endc || tstr[2] == ':') ) {
- otype = tstr[1];
- cp = tstr + 2;
- termc = *cp;
- } else {
- goto bad_modifier;
- }
- newStr = VarOrder(nstr, otype);
- break;
- }
- case 'u':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarUniq(nstr);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
-#ifdef SUNSHCMD
- case 's':
- if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
- const char *emsg;
- newStr = Cmd_Exec(nstr, &emsg);
- if (emsg)
- Error(emsg, nstr);
- cp = tstr + 2;
- termc = *cp;
- break;
- }
- goto default_case;
-#endif
- default:
- default_case:
- {
-#ifdef SYSVVARSUB
- /*
- * This can either be a bogus modifier or a System-V
- * substitution command.
- */
- VarPattern pattern;
- Boolean eqFound;
-
- pattern.flags = 0;
- eqFound = FALSE;
- /*
- * First we make a pass through the string trying
- * to verify it is a SYSV-make-style translation:
- * it must be: <string1>=<string2>)
- */
- cp = tstr;
- cnt = 1;
- while (*cp != '\0' && cnt) {
- if (*cp == '=') {
- eqFound = TRUE;
- /* continue looking for endc */
- }
- else if (*cp == endc)
- cnt--;
- else if (*cp == startc)
- cnt++;
- if (cnt)
- cp++;
- }
- if (*cp == endc && eqFound) {
-
- /*
- * Now we break this sucker into the lhs and
- * rhs. We must null terminate them of course.
- */
- delim='=';
- cp = tstr;
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate,
- err, &cp, delim, &pattern.flags,
- &pattern.leftLen, NULL)) == NULL)
- goto cleanup;
- delim = endc;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate,
- err, &cp, delim, NULL, &pattern.rightLen,
- &pattern)) == NULL)
- goto cleanup;
-
- /*
- * SYSV modifications happen through the whole
- * string. Note the pattern is anchored at the end.
- */
- termc = *--cp;
- delim = '\0';
- newStr = VarModify(ctxt, &parsestate, nstr,
- VarSYSVMatch,
- (ClientData)&pattern);
- free(UNCONST(pattern.lhs));
- free(UNCONST(pattern.rhs));
- } else
-#endif
- {
- Error("Unknown modifier '%c'", *tstr);
- for (cp = tstr+1;
- *cp != ':' && *cp != endc && *cp != '\0';
- cp++)
- continue;
- termc = *cp;
- newStr = var_Error;
- }
- }
- }
- if (DEBUG(VAR)) {
- printf("Result is \"%s\"\n", newStr);
- }
-
- if (newStr != nstr) {
- if (*freePtr) {
- free(nstr);
- }
- nstr = newStr;
- if (nstr != var_Error && nstr != varNoError) {
- *freePtr = TRUE;
- } else {
- *freePtr = FALSE;
- }
- }
- if (termc == '\0') {
- Error("Unclosed variable specification for %s", v->name);
- } else if (termc == ':') {
- *WR(cp) = termc;
- cp++;
- } else {
- *WR(cp) = termc;
- }
- tstr = cp;
- }
+ nstr = ApplyModifiers(nstr, tstr, startc, endc,
+ v, ctxt, errnum, &used, freePtr);
+ tstr += used;
+ }
+ if (*tstr) {
*lengthPtr = tstr - start + 1;
} else {
- *lengthPtr = tstr - start + 1;
- *WR(tstr) = endc;
+ *lengthPtr = tstr - start;
}
if (v->flags & VAR_FROM_ENV) {
@@ -3193,28 +3523,23 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
* Returning the value unmodified, so tell the caller to free
* the thing.
*/
- *freePtr = TRUE;
+ *freePtr = nstr;
}
- if (nstr != (char *)Buf_GetAll(v->val, NULL))
- Buf_Destroy(v->val, destroy);
- free(v->name);
- free(v);
+ VarFreeEnv(v, destroy);
} else if (v->flags & VAR_JUNK) {
/*
- * Perform any free'ing needed and set *freePtr to FALSE so the caller
+ * Perform any free'ing needed and set *freePtr to NULL so the caller
* doesn't try to free a static pointer.
* If VAR_KEEP is also set then we want to keep str as is.
*/
if (!(v->flags & VAR_KEEP)) {
if (*freePtr) {
free(nstr);
+ *freePtr = NULL;
}
- *freePtr = FALSE;
if (dynamic) {
- nstr = emalloc(*lengthPtr + 1);
- strncpy(nstr, start, *lengthPtr);
- nstr[*lengthPtr] = '\0';
- *freePtr = TRUE;
+ nstr = estrndup(start, *lengthPtr);
+ *freePtr = nstr;
} else {
nstr = var_Error;
}
@@ -3225,20 +3550,6 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
free(v);
}
return (nstr);
-
- bad_modifier:
- /* "{(" */
- Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr,
- v->name);
-
-cleanup:
- *lengthPtr = cp - start + 1;
- if (*freePtr)
- free(nstr);
- if (delim != '\0')
- Error("Unclosed substitution for %s (%c missing)",
- v->name, delim);
- return (var_Error);
}
/*-
@@ -3268,12 +3579,12 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr)
char *val; /* Value to substitute for a variable */
int length; /* Length of the variable invocation */
Boolean trailingBslash; /* variable ends in \ */
- Boolean doFree; /* Set true if val should be freed */
+ void *freeIt = NULL; /* Set if it should be freed */
static Boolean errorReported; /* Set true if an error has already
* been reported to prevent a plethora
* of messages when recursing */
- buf = Buf_Init(MAKE_BSIZE);
+ buf = Buf_Init(0);
errorReported = FALSE;
trailingBslash = FALSE;
@@ -3360,7 +3671,7 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr)
continue;
}
- val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
+ val = Var_Parse(str, ctxt, undefErr, &length, &freeIt);
/*
* When we come down here, val should either point to the
@@ -3407,9 +3718,10 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr)
length = strlen(val);
Buf_AddBytes(buf, length, (Byte *)val);
trailingBslash = length > 0 && val[length - 1] == '\\';
- if (doFree) {
- free(val);
- }
+ }
+ if (freeIt) {
+ free(freeIt);
+ freeIt = NULL;
}
}
}
@@ -3441,7 +3753,7 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, Boolean undefErr)
char *
Var_GetTail(char *file)
{
- return(VarModify(file, VarTail, (ClientData)0));
+ return(VarModify(file, VarTail, NULL));
}
/*-
@@ -3465,7 +3777,7 @@ Var_GetTail(char *file)
char *
Var_GetHead(char *file)
{
- return(VarModify(file, VarHead, (ClientData)0));
+ return(VarModify(file, VarHead, NULL));
}
#endif
@@ -3501,7 +3813,7 @@ static void
VarPrintVar(ClientData vp)
{
Var *v = (Var *)vp;
- printf("%-16s = %s\n", v->name, (char *)Buf_GetAll(v->val, NULL));
+ fprintf(debug_file, "%-16s = %s\n", v->name, (char *)Buf_GetAll(v->val, NULL));
}
/*-