BSD 4.4 Lite Usr.bin Sources

This commit is contained in:
rgrimes 1994-05-27 12:33:43 +00:00
commit 95bef72976
57 changed files with 26173 additions and 0 deletions

14
usr.bin/make/Makefile Normal file
View File

@ -0,0 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= make
CFLAGS+=-I${.CURDIR}
SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \
make.c parse.c str.c suff.c targ.c var.c
SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \
lstDatum.c lstDeQueue.c lstDestroy.c lstDupl.c lstEnQueue.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
.PATH: ${.CURDIR}/lst.lib
.include <bsd.prog.mk>

View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 8/14/93
DIR= psd/12.make
SRCS= tutorial.ms
MACROS= -ms
.include <bsd.doc.mk>

File diff suppressed because it is too large Load Diff

955
usr.bin/make/arch.c Normal file
View File

@ -0,0 +1,955 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
#endif /* not lint */
/*-
* arch.c --
* Functions to manipulate libraries, archives and their members.
*
* Once again, cacheing/hashing comes into play in the manipulation
* of archives. The first time an archive is referenced, all of its members'
* headers are read and hashed and the archive closed again. All hashed
* archives are kept on a list which is searched each time an archive member
* is referenced.
*
* The interface to this module is:
* Arch_ParseArchive Given an archive specification, return a list
* of GNode's, one for each member in the spec.
* FAILURE is returned if the specification is
* invalid for some reason.
*
* Arch_Touch Alter the modification time of the archive
* member described by the given node to be
* the current time.
*
* Arch_TouchLib Update the modification time of the library
* described by the given node. This is special
* because it also updates the modification time
* of the library's table of contents.
*
* Arch_MTime Find the modification time of a member of
* an archive *in the archive*. The time is also
* placed in the member's GNode. Returns the
* modification time.
*
* Arch_MemTime Find the modification time of a member of
* an archive. Called when the member doesn't
* already exist. Looks in the archive for the
* modification time. Returns the modification
* time.
*
* Arch_FindLib Search for a library along a path. The
* library name in the GNode should be in
* -l<name> format.
*
* Arch_LibOODate Special function to decide if a library node
* is out-of-date.
*
* Arch_Init Initialize this module.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <ctype.h>
#include <ar.h>
#include <ranlib.h>
#include <stdio.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
#include "config.h"
static Lst archives; /* Lst of archives we've already examined */
typedef struct Arch {
char *name; /* Name of archive */
Hash_Table members; /* All the members of the archive described
* by <name, struct ar_hdr *> key/value pairs */
} Arch;
static int ArchFindArchive __P((Arch *, char *));
static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean));
static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *));
/*-
*-----------------------------------------------------------------------
* Arch_ParseArchive --
* Parse the archive specification in the given line and find/create
* the nodes for the specified archive members, placing their nodes
* on the given list.
*
* Results:
* SUCCESS if it was a valid specification. The linePtr is updated
* to point to the first non-space after the archive spec. The
* nodes for the members are placed on the given list.
*
* Side Effects:
* Some nodes may be created. The given list is extended.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Arch_ParseArchive (linePtr, nodeLst, ctxt)
char **linePtr; /* Pointer to start of specification */
Lst nodeLst; /* Lst on which to place the nodes */
GNode *ctxt; /* Context in which to expand variables */
{
register char *cp; /* Pointer into line */
GNode *gn; /* New node */
char *libName; /* Library-part of specification */
char *memName; /* Member-part of specification */
char nameBuf[MAKE_BSIZE]; /* temporary place for node name */
char saveChar; /* Ending delimiter of member-name */
Boolean subLibName; /* TRUE if libName should have/had
* variable substitution performed on it */
libName = *linePtr;
subLibName = FALSE;
for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
if (*cp == '$') {
/*
* Variable spec, so call the Var module to parse the puppy
* so we can safely advance beyond it...
*/
int length;
Boolean freeIt;
char *result;
result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
if (result == var_Error) {
return(FAILURE);
} else {
subLibName = TRUE;
}
if (freeIt) {
free(result);
}
cp += length-1;
}
}
*cp++ = '\0';
if (subLibName) {
libName = Var_Subst(NULL, libName, ctxt, TRUE);
}
for (;;) {
/*
* First skip to the start of the member's name, mark that
* place and skip to the end of it (either white-space or
* a close paren).
*/
Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */
while (*cp != '\0' && *cp != ')' && isspace (*cp)) {
cp++;
}
memName = cp;
while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {
if (*cp == '$') {
/*
* Variable spec, so call the Var module to parse the puppy
* so we can safely advance beyond it...
*/
int length;
Boolean freeIt;
char *result;
result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
if (result == var_Error) {
return(FAILURE);
} else {
doSubst = TRUE;
}
if (freeIt) {
free(result);
}
cp += length;
} else {
cp++;
}
}
/*
* If the specification ends without a closing parenthesis,
* chances are there's something wrong (like a missing backslash),
* so it's better to return failure than allow such things to happen
*/
if (*cp == '\0') {
printf("No closing parenthesis in archive specification\n");
return (FAILURE);
}
/*
* If we didn't move anywhere, we must be done
*/
if (cp == memName) {
break;
}
saveChar = *cp;
*cp = '\0';
/*
* XXX: This should be taken care of intelligently by
* SuffExpandChildren, both for the archive and the member portions.
*/
/*
* If member contains variables, try and substitute for them.
* This will slow down archive specs with dynamic sources, of course,
* since we'll be (non-)substituting them three times, but them's
* the breaks -- we need to do this since SuffExpandChildren calls
* us, otherwise we could assume the thing would be taken care of
* later.
*/
if (doSubst) {
char *buf;
char *sacrifice;
char *oldMemName = memName;
memName = Var_Subst(NULL, memName, ctxt, TRUE);
/*
* Now form an archive spec and recurse to deal with nested
* variables and multi-word variable values.... The results
* are just placed at the end of the nodeLst we're returning.
*/
buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);
sprintf(buf, "%s(%s)", libName, memName);
if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
/*
* Must contain dynamic sources, so we can't deal with it now.
* Just create an ARCHV node for the thing and let
* SuffExpandChildren handle it...
*/
gn = Targ_FindNode(buf, TARG_CREATE);
if (gn == NILGNODE) {
free(buf);
return(FAILURE);
} else {
gn->type |= OP_ARCHV;
(void)Lst_AtEnd(nodeLst, (ClientData)gn);
}
} else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
/*
* Error in nested call -- free buffer and return FAILURE
* ourselves.
*/
free(buf);
return(FAILURE);
}
/*
* Free buffer and continue with our work.
*/
free(buf);
} else if (Dir_HasWildcards(memName)) {
Lst members = Lst_Init(FALSE);
char *member;
Dir_Expand(memName, dirSearchPath, members);
while (!Lst_IsEmpty(members)) {
member = (char *)Lst_DeQueue(members);
sprintf(nameBuf, "%s(%s)", libName, member);
free(member);
gn = Targ_FindNode (nameBuf, TARG_CREATE);
if (gn == NILGNODE) {
return (FAILURE);
} else {
/*
* We've found the node, but have to make sure the rest of
* the world knows it's an archive member, without having
* to constantly check for parentheses, so we type the
* thing with the OP_ARCHV bit before we place it on the
* end of the provided list.
*/
gn->type |= OP_ARCHV;
(void) Lst_AtEnd (nodeLst, (ClientData)gn);
}
}
Lst_Destroy(members, NOFREE);
} else {
sprintf(nameBuf, "%s(%s)", libName, memName);
gn = Targ_FindNode (nameBuf, TARG_CREATE);
if (gn == NILGNODE) {
return (FAILURE);
} else {
/*
* We've found the node, but have to make sure the rest of the
* world knows it's an archive member, without having to
* constantly check for parentheses, so we type the thing with
* the OP_ARCHV bit before we place it on the end of the
* provided list.
*/
gn->type |= OP_ARCHV;
(void) Lst_AtEnd (nodeLst, (ClientData)gn);
}
}
if (doSubst) {
free(memName);
}
*cp = saveChar;
}
/*
* If substituted libName, free it now, since we need it no longer.
*/
if (subLibName) {
free(libName);
}
/*
* We promised the pointer would be set up at the next non-space, so
* we must advance cp there before setting *linePtr... (note that on
* entrance to the loop, cp is guaranteed to point at a ')')
*/
do {
cp++;
} while (*cp != '\0' && isspace (*cp));
*linePtr = cp;
return (SUCCESS);
}
/*-
*-----------------------------------------------------------------------
* ArchFindArchive --
* See if the given archive is the one we are looking for. Called
* From ArchStatMember and ArchFindMember via Lst_Find.
*
* Results:
* 0 if it is, non-zero if it isn't.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
static int
ArchFindArchive (ar, archName)
Arch *ar; /* Current list element */
char *archName; /* Name we want */
{
return (strcmp (archName, ar->name));
}
/*-
*-----------------------------------------------------------------------
* ArchStatMember --
* Locate a member of an archive, given the path of the archive and
* the path of the desired member.
*
* Results:
* A pointer to the current struct ar_hdr structure for the member. Note
* That no position is returned, so this is not useful for touching
* archive members. This is mostly because we have no assurances that
* The archive will remain constant after we read all the headers, so
* there's not much point in remembering the position...
*
* Side Effects:
*
*-----------------------------------------------------------------------
*/
static struct ar_hdr *
ArchStatMember (archive, member, hash)
char *archive; /* Path to the archive */
char *member; /* Name of member. If it is a path, only the
* last component is used. */
Boolean hash; /* TRUE if archive should be hashed if not
* already so. */
{
#define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1)
FILE * arch; /* Stream to archive */
int size; /* Size of archive member */
char *cp; /* Useful character pointer */
char magic[SARMAG];
int len;
LstNode ln; /* Lst member containing archive descriptor */
Arch *ar; /* Archive descriptor */
Hash_Entry *he; /* Entry containing member's description */
struct ar_hdr arh; /* archive-member header for reading archive */
char memName[AR_MAX_NAME_LEN+1];
/* Current member name while hashing. The name is
* truncated to AR_MAX_NAME_LEN bytes, but we need
* room for the null byte... */
char copy[AR_MAX_NAME_LEN+1];
/* Holds copy of last path element from member, if
* it has to be truncated, so we don't have to
* figure it out again once the table is hashed. */
/*
* Because of space constraints and similar things, files are archived
* using their final path components, not the entire thing, so we need
* to point 'member' to the final component, if there is one, to make
* the comparisons easier...
*/
cp = strrchr (member, '/');
if (cp != (char *) NULL) {
member = cp + 1;
}
len = strlen (member);
if (len > AR_MAX_NAME_LEN) {
len = AR_MAX_NAME_LEN;
strncpy(copy, member, AR_MAX_NAME_LEN);
copy[AR_MAX_NAME_LEN] = '\0';
member = copy;
}
ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive);
if (ln != NILLNODE) {
ar = (Arch *) Lst_Datum (ln);
he = Hash_FindEntry (&ar->members, member);
if (he != (Hash_Entry *) NULL) {
return ((struct ar_hdr *) Hash_GetValue (he));
} else {
return ((struct ar_hdr *) NULL);
}
}
if (!hash) {
/*
* Caller doesn't want the thing hashed, just use ArchFindMember
* to read the header for the member out and close down the stream
* again. Since the archive is not to be hashed, we assume there's
* no need to allocate extra room for the header we're returning,
* so just declare it static.
*/
static struct ar_hdr sarh;
arch = ArchFindMember(archive, member, &sarh, "r");
if (arch == (FILE *)NULL) {
return ((struct ar_hdr *)NULL);
} else {
fclose(arch);
return (&sarh);
}
}
/*
* We don't have this archive on the list yet, so we want to find out
* everything that's in it and cache it so we can get at it quickly.
*/
arch = fopen (archive, "r");
if (arch == (FILE *) NULL) {
return ((struct ar_hdr *) NULL);
}
/*
* We use the ARMAG string to make sure this is an archive we
* can handle...
*/
if ((fread (magic, SARMAG, 1, arch) != 1) ||
(strncmp (magic, ARMAG, SARMAG) != 0)) {
fclose (arch);
return ((struct ar_hdr *) NULL);
}
ar = (Arch *)emalloc (sizeof (Arch));
ar->name = strdup (archive);
Hash_InitTable (&ar->members, -1);
memName[AR_MAX_NAME_LEN] = '\0';
while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {
if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {
/*
* The header is bogus, so the archive is bad
* and there's no way we can recover...
*/
fclose (arch);
Hash_DeleteTable (&ar->members);
free ((Address)ar);
return ((struct ar_hdr *) NULL);
} else {
(void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name));
for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
continue;
}
cp[1] = '\0';
he = Hash_CreateEntry (&ar->members, strdup (memName),
(Boolean *)NULL);
Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr)));
memcpy ((Address)Hash_GetValue (he), (Address)&arh,
sizeof (struct ar_hdr));
}
/*
* We need to advance the stream's pointer to the start of the
* next header. Files are padded with newlines to an even-byte
* boundary, so we need to extract the size of the file from the
* 'size' field of the header and round it up during the seek.
*/
arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
(void) sscanf (arh.ar_size, "%10d", &size);
fseek (arch, (size + 1) & ~1, 1);
}
fclose (arch);
(void) Lst_AtEnd (archives, (ClientData) ar);
/*
* Now that the archive has been read and cached, we can look into
* the hash table to find the desired member's header.
*/
he = Hash_FindEntry (&ar->members, member);
if (he != (Hash_Entry *) NULL) {
return ((struct ar_hdr *) Hash_GetValue (he));
} else {
return ((struct ar_hdr *) NULL);
}
}
/*-
*-----------------------------------------------------------------------
* ArchFindMember --
* Locate a member of an archive, given the path of the archive and
* the path of the desired member. If the archive is to be modified,
* the mode should be "r+", if not, it should be "r".
*
* Results:
* An FILE *, opened for reading and writing, positioned at the
* start of the member's struct ar_hdr, or NULL if the member was
* nonexistent. The current struct ar_hdr for member.
*
* Side Effects:
* The passed struct ar_hdr structure is filled in.
*
*-----------------------------------------------------------------------
*/
static FILE *
ArchFindMember (archive, member, arhPtr, mode)
char *archive; /* Path to the archive */
char *member; /* Name of member. If it is a path, only the
* last component is used. */
struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */
char *mode; /* The mode for opening the stream */
{
FILE * arch; /* Stream to archive */
int size; /* Size of archive member */
char *cp; /* Useful character pointer */
char magic[SARMAG];
int len;
arch = fopen (archive, mode);
if (arch == (FILE *) NULL) {
return ((FILE *) NULL);
}
/*
* We use the ARMAG string to make sure this is an archive we
* can handle...
*/
if ((fread (magic, SARMAG, 1, arch) != 1) ||
(strncmp (magic, ARMAG, SARMAG) != 0)) {
fclose (arch);
return ((FILE *) NULL);
}
/*
* Because of space constraints and similar things, files are archived
* using their final path components, not the entire thing, so we need
* to point 'member' to the final component, if there is one, to make
* the comparisons easier...
*/
cp = strrchr (member, '/');
if (cp != (char *) NULL) {
member = cp + 1;
}
len = strlen (member);
if (len > sizeof (arhPtr->ar_name)) {
len = sizeof (arhPtr->ar_name);
}
while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) {
if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) {
/*
* The header is bogus, so the archive is bad
* and there's no way we can recover...
*/
fclose (arch);
return ((FILE *) NULL);
} else if (strncmp (member, arhPtr->ar_name, len) == 0) {
/*
* If the member's name doesn't take up the entire 'name' field,
* we have to be careful of matching prefixes. Names are space-
* padded to the right, so if the character in 'name' at the end
* of the matched string is anything but a space, this isn't the
* member we sought.
*/
if (len != sizeof(arhPtr->ar_name) && arhPtr->ar_name[len] != ' '){
continue;
} else {
/*
* To make life easier, we reposition the file at the start
* of the header we just read before we return the stream.
* In a more general situation, it might be better to leave
* the file at the actual member, rather than its header, but
* not here...
*/
fseek (arch, -sizeof(struct ar_hdr), 1);
return (arch);
}
} else {
/*
* This isn't the member we're after, so we need to advance the
* stream's pointer to the start of the next header. Files are
* padded with newlines to an even-byte boundary, so we need to
* extract the size of the file from the 'size' field of the
* header and round it up during the seek.
*/
arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0';
(void)sscanf (arhPtr->ar_size, "%10d", &size);
fseek (arch, (size + 1) & ~1, 1);
}
}
/*
* We've looked everywhere, but the member is not to be found. Close the
* archive and return NULL -- an error.
*/
fclose (arch);
return ((FILE *) NULL);
}
/*-
*-----------------------------------------------------------------------
* Arch_Touch --
* Touch a member of an archive.
*
* Results:
* The 'time' field of the member's header is updated.
*
* Side Effects:
* The modification time of the entire archive is also changed.
* For a library, this could necessitate the re-ranlib'ing of the
* whole thing.
*
*-----------------------------------------------------------------------
*/
void
Arch_Touch (gn)
GNode *gn; /* Node of member to touch */
{
FILE * arch; /* Stream open to archive, positioned properly */
struct ar_hdr arh; /* Current header describing member */
arch = ArchFindMember(Var_Value (ARCHIVE, gn),
Var_Value (TARGET, gn),
&arh, "r+");
sprintf(arh.ar_date, "%-12ld", (long) now);
if (arch != (FILE *) NULL) {
(void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
fclose (arch);
}
}
/*-
*-----------------------------------------------------------------------
* Arch_TouchLib --
* Given a node which represents a library, touch the thing, making
* sure that the table of contents also is touched.
*
* Results:
* None.
*
* Side Effects:
* Both the modification time of the library and of the RANLIBMAG
* member are set to 'now'.
*
*-----------------------------------------------------------------------
*/
void
Arch_TouchLib (gn)
GNode *gn; /* The node of the library to touch */
{
FILE * arch; /* Stream open to archive */
struct ar_hdr arh; /* Header describing table of contents */
struct timeval times[2]; /* Times for utimes() call */
arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+");
sprintf(arh.ar_date, "%-12ld", (long) now);
if (arch != (FILE *) NULL) {
(void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
fclose (arch);
times[0].tv_sec = times[1].tv_sec = now;
times[0].tv_usec = times[1].tv_usec = 0;
utimes(gn->path, times);
}
}
/*-
*-----------------------------------------------------------------------
* Arch_MTime --
* Return the modification time of a member of an archive.
*
* Results:
* The modification time (seconds).
*
* Side Effects:
* The mtime field of the given node is filled in with the value
* returned by the function.
*
*-----------------------------------------------------------------------
*/
int
Arch_MTime (gn)
GNode *gn; /* Node describing archive member */
{
struct ar_hdr *arhPtr; /* Header of desired member */
int modTime; /* Modification time as an integer */
arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn),
Var_Value (TARGET, gn),
TRUE);
if (arhPtr != (struct ar_hdr *) NULL) {
(void)sscanf (arhPtr->ar_date, "%12d", &modTime);
} else {
modTime = 0;
}
gn->mtime = modTime;
return (modTime);
}
/*-
*-----------------------------------------------------------------------
* Arch_MemMTime --
* Given a non-existent archive member's node, get its modification
* time from its archived form, if it exists.
*
* Results:
* The modification time.
*
* Side Effects:
* The mtime field is filled in.
*
*-----------------------------------------------------------------------
*/
int
Arch_MemMTime (gn)
GNode *gn;
{
LstNode ln;
GNode *pgn;
char *nameStart,
*nameEnd;
if (Lst_Open (gn->parents) != SUCCESS) {
gn->mtime = 0;
return (0);
}
while ((ln = Lst_Next (gn->parents)) != NILLNODE) {
pgn = (GNode *) Lst_Datum (ln);
if (pgn->type & OP_ARCHV) {
/*
* If the parent is an archive specification and is being made
* and its member's name matches the name of the node we were
* given, record the modification time of the parent in the
* child. We keep searching its parents in case some other
* parent requires this child to exist...
*/
nameStart = strchr (pgn->name, '(') + 1;
nameEnd = strchr (nameStart, ')');
if (pgn->make &&
strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) {
gn->mtime = Arch_MTime(pgn);
}
} else if (pgn->make) {
/*
* Something which isn't a library depends on the existence of
* this target, so it needs to exist.
*/
gn->mtime = 0;
break;
}
}
Lst_Close (gn->parents);
return (gn->mtime);
}
/*-
*-----------------------------------------------------------------------
* Arch_FindLib --
* Search for a library along the given search path.
*
* Results:
* None.
*
* Side Effects:
* The node's 'path' field is set to the found path (including the
* actual file name, not -l...). If the system can handle the -L
* flag when linking (or we cannot find the library), we assume that
* the user has placed the .LIBRARIES variable in the final linking
* command (or the linker will know where to find it) and set the
* TARGET variable for this node to be the node's name. Otherwise,
* we set the TARGET variable to be the full path of the library,
* as returned by Dir_FindFile.
*
*-----------------------------------------------------------------------
*/
void
Arch_FindLib (gn, path)
GNode *gn; /* Node of library to find */
Lst path; /* Search path */
{
char *libName; /* file name for archive */
libName = (char *)emalloc (strlen (gn->name) + 6 - 2);
sprintf(libName, "lib%s.a", &gn->name[2]);
gn->path = Dir_FindFile (libName, path);
free (libName);
#ifdef LIBRARIES
Var_Set (TARGET, gn->name, gn);
#else
Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn);
#endif LIBRARIES
}
/*-
*-----------------------------------------------------------------------
* Arch_LibOODate --
* Decide if a node with the OP_LIB attribute is out-of-date. Called
* from Make_OODate to make its life easier.
*
* There are several ways for a library to be out-of-date that are
* not available to ordinary files. In addition, there are ways
* that are open to regular files that are not available to
* libraries. A library that is only used as a source is never
* considered out-of-date by itself. This does not preclude the
* library's modification time from making its parent be out-of-date.
* A library will be considered out-of-date for any of these reasons,
* given that it is a target on a dependency line somewhere:
* Its modification time is less than that of one of its
* sources (gn->mtime < gn->cmtime).
* Its modification time is greater than the time at which the
* make began (i.e. it's been modified in the course
* of the make, probably by archiving).
* Its modification time doesn't agree with the modification
* time of its RANLIBMAG member (i.e. its table of contents
* is out-of-date).
*
*
* Results:
* TRUE if the library is out-of-date. FALSE otherwise.
*
* Side Effects:
* The library will be hashed if it hasn't been already.
*
*-----------------------------------------------------------------------
*/
Boolean
Arch_LibOODate (gn)
GNode *gn; /* The library's graph node */
{
Boolean oodate;
if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
oodate = FALSE;
} else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) {
oodate = TRUE;
} else {
struct ar_hdr *arhPtr; /* Header for __.SYMDEF */
int modTimeTOC; /* The table-of-contents's mod time */
arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE);
if (arhPtr != (struct ar_hdr *)NULL) {
(void)sscanf (arhPtr->ar_date, "%12d", &modTimeTOC);
if (DEBUG(ARCH) || DEBUG(MAKE)) {
printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
}
oodate = (gn->mtime > modTimeTOC);
} else {
/*
* A library w/o a table of contents is out-of-date
*/
if (DEBUG(ARCH) || DEBUG(MAKE)) {
printf("No t.o.c....");
}
oodate = TRUE;
}
}
return (oodate);
}
/*-
*-----------------------------------------------------------------------
* Arch_Init --
* Initialize things for this module.
*
* Results:
* None.
*
* Side Effects:
* The 'archives' list is initialized.
*
*-----------------------------------------------------------------------
*/
void
Arch_Init ()
{
archives = Lst_Init (FALSE);
}

436
usr.bin/make/buf.c Normal file
View File

@ -0,0 +1,436 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* buf.c --
* Functions for automatically-expanded buffers.
*/
#include "sprite.h"
#include "make.h"
#include "buf.h"
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
/*
* BufExpand --
* Expand the given buffer to hold the given number of additional
* bytes.
* Makes sure there's room for an extra NULL byte at the end of the
* buffer in case it holds a string.
*/
#define BufExpand(bp,nb) \
if (bp->left < (nb)+1) {\
int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \
Byte *newBuf = (Byte *) realloc((bp)->buffer, newSize); \
\
(bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \
(bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\
(bp)->buffer = newBuf;\
(bp)->size = newSize;\
(bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);\
}
#define BUF_DEF_SIZE 256 /* Default buffer size */
#define BUF_ADD_INC 256 /* Expansion increment when Adding */
#define BUF_UNGET_INC 16 /* Expansion increment when Ungetting */
/*-
*-----------------------------------------------------------------------
* Buf_OvAddByte --
* Add a single byte to the buffer. left is zero or negative.
*
* Results:
* None.
*
* Side Effects:
* The buffer may be expanded.
*
*-----------------------------------------------------------------------
*/
void
Buf_OvAddByte (bp, byte)
register Buffer bp;
int byte;
{
bp->left = 0;
BufExpand (bp, 1);
*bp->inPtr++ = byte;
bp->left--;
/*
* Null-terminate
*/
*bp->inPtr = 0;
}
/*-
*-----------------------------------------------------------------------
* Buf_AddBytes --
* Add a number of bytes to the buffer.
*
* Results:
* None.
*
* Side Effects:
* Guess what?
*
*-----------------------------------------------------------------------
*/
void
Buf_AddBytes (bp, numBytes, bytesPtr)
register Buffer bp;
int numBytes;
Byte *bytesPtr;
{
BufExpand (bp, numBytes);
memcpy (bp->inPtr, bytesPtr, numBytes);
bp->inPtr += numBytes;
bp->left -= numBytes;
/*
* Null-terminate
*/
*bp->inPtr = 0;
}
/*-
*-----------------------------------------------------------------------
* Buf_UngetByte --
* Place the byte back at the beginning of the buffer.
*
* Results:
* SUCCESS if the byte was added ok. FAILURE if not.
*
* Side Effects:
* The byte is stuffed in the buffer and outPtr is decremented.
*
*-----------------------------------------------------------------------
*/
void
Buf_UngetByte (bp, byte)
register Buffer bp;
int byte;
{
if (bp->outPtr != bp->buffer) {
bp->outPtr--;
*bp->outPtr = byte;
} else if (bp->outPtr == bp->inPtr) {
*bp->inPtr = byte;
bp->inPtr++;
bp->left--;
*bp->inPtr = 0;
} else {
/*
* Yech. have to expand the buffer to stuff this thing in.
* We use a different expansion constant because people don't
* usually push back many bytes when they're doing it a byte at
* a time...
*/
int numBytes = bp->inPtr - bp->outPtr;
Byte *newBuf;
newBuf = (Byte *)emalloc(bp->size + BUF_UNGET_INC);
memcpy ((char *)(newBuf+BUF_UNGET_INC), (char *)bp->outPtr, numBytes+1);
bp->outPtr = newBuf + BUF_UNGET_INC;
bp->inPtr = bp->outPtr + numBytes;
free ((char *)bp->buffer);
bp->buffer = newBuf;
bp->size += BUF_UNGET_INC;
bp->left = bp->size - (bp->inPtr - bp->buffer);
bp->outPtr -= 1;
*bp->outPtr = byte;
}
}
/*-
*-----------------------------------------------------------------------
* Buf_UngetBytes --
* Push back a series of bytes at the beginning of the buffer.
*
* Results:
* None.
*
* Side Effects:
* outPtr is decremented and the bytes copied into the buffer.
*
*-----------------------------------------------------------------------
*/
void
Buf_UngetBytes (bp, numBytes, bytesPtr)
register Buffer bp;
int numBytes;
Byte *bytesPtr;
{
if (bp->outPtr - bp->buffer >= numBytes) {
bp->outPtr -= numBytes;
memcpy (bp->outPtr, bytesPtr, numBytes);
} else if (bp->outPtr == bp->inPtr) {
Buf_AddBytes (bp, numBytes, bytesPtr);
} else {
int curNumBytes = bp->inPtr - bp->outPtr;
Byte *newBuf;
int newBytes = max(numBytes,BUF_UNGET_INC);
newBuf = (Byte *)emalloc (bp->size + newBytes);
memcpy((char *)(newBuf+newBytes), (char *)bp->outPtr, curNumBytes+1);
bp->outPtr = newBuf + newBytes;
bp->inPtr = bp->outPtr + curNumBytes;
free ((char *)bp->buffer);
bp->buffer = newBuf;
bp->size += newBytes;
bp->left = bp->size - (bp->inPtr - bp->buffer);
bp->outPtr -= numBytes;
memcpy ((char *)bp->outPtr, (char *)bytesPtr, numBytes);
}
}
/*-
*-----------------------------------------------------------------------
* Buf_GetByte --
* Return the next byte from the buffer. Actually returns an integer.
*
* Results:
* Returns BUF_ERROR if there's no byte in the buffer, or the byte
* itself if there is one.
*
* Side Effects:
* outPtr is incremented and both outPtr and inPtr will be reset if
* the buffer is emptied.
*
*-----------------------------------------------------------------------
*/
int
Buf_GetByte (bp)
register Buffer bp;
{
int res;
if (bp->inPtr == bp->outPtr) {
return (BUF_ERROR);
} else {
res = (int) *bp->outPtr;
bp->outPtr += 1;
if (bp->outPtr == bp->inPtr) {
bp->outPtr = bp->inPtr = bp->buffer;
bp->left = bp->size;
*bp->inPtr = 0;
}
return (res);
}
}
/*-
*-----------------------------------------------------------------------
* Buf_GetBytes --
* Extract a number of bytes from the buffer.
*
* Results:
* The number of bytes gotten.
*
* Side Effects:
* The passed array is overwritten.
*
*-----------------------------------------------------------------------
*/
int
Buf_GetBytes (bp, numBytes, bytesPtr)
register Buffer bp;
int numBytes;
Byte *bytesPtr;
{
if (bp->inPtr - bp->outPtr < numBytes) {
numBytes = bp->inPtr - bp->outPtr;
}
memcpy (bytesPtr, bp->outPtr, numBytes);
bp->outPtr += numBytes;
if (bp->outPtr == bp->inPtr) {
bp->outPtr = bp->inPtr = bp->buffer;
bp->left = bp->size;
*bp->inPtr = 0;
}
return (numBytes);
}
/*-
*-----------------------------------------------------------------------
* Buf_GetAll --
* Get all the available data at once.
*
* Results:
* A pointer to the data and the number of bytes available.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
Byte *
Buf_GetAll (bp, numBytesPtr)
register Buffer bp;
int *numBytesPtr;
{
if (numBytesPtr != (int *)NULL) {
*numBytesPtr = bp->inPtr - bp->outPtr;
}
return (bp->outPtr);
}
/*-
*-----------------------------------------------------------------------
* Buf_Discard --
* Throw away bytes in a buffer.
*
* Results:
* None.
*
* Side Effects:
* The bytes are discarded.
*
*-----------------------------------------------------------------------
*/
void
Buf_Discard (bp, numBytes)
register Buffer bp;
int numBytes;
{
if (bp->inPtr - bp->outPtr <= numBytes) {
bp->inPtr = bp->outPtr = bp->buffer;
bp->left = bp->size;
*bp->inPtr = 0;
} else {
bp->outPtr += numBytes;
}
}
/*-
*-----------------------------------------------------------------------
* Buf_Size --
* Returns the number of bytes in the given buffer. Doesn't include
* the null-terminating byte.
*
* Results:
* The number of bytes.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
int
Buf_Size (buf)
Buffer buf;
{
return (buf->inPtr - buf->outPtr);
}
/*-
*-----------------------------------------------------------------------
* Buf_Init --
* Initialize a buffer. If no initial size is given, a reasonable
* default is used.
*
* Results:
* A buffer to be given to other functions in this library.
*
* Side Effects:
* The buffer is created, the space allocated and pointers
* initialized.
*
*-----------------------------------------------------------------------
*/
Buffer
Buf_Init (size)
int size; /* Initial size for the buffer */
{
Buffer bp; /* New Buffer */
bp = (Buffer)emalloc(sizeof(*bp));
if (size <= 0) {
size = BUF_DEF_SIZE;
}
bp->left = bp->size = size;
bp->buffer = (Byte *)emalloc(size);
bp->inPtr = bp->outPtr = bp->buffer;
*bp->inPtr = 0;
return (bp);
}
/*-
*-----------------------------------------------------------------------
* Buf_Destroy --
* Nuke a buffer and all its resources.
*
* Results:
* None.
*
* Side Effects:
* The buffer is freed.
*
*-----------------------------------------------------------------------
*/
void
Buf_Destroy (buf, freeData)
Buffer buf; /* Buffer to destroy */
Boolean freeData; /* TRUE if the data should be destroyed as well */
{
if (freeData) {
free ((char *)buf->buffer);
}
free ((char *)buf);
}

80
usr.bin/make/buf.h Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)buf.h 8.1 (Berkeley) 6/6/93
*/
/*-
* buf.h --
* Header for users of the buf library.
*/
#ifndef _BUF_H
#define _BUF_H
#include "sprite.h"
typedef unsigned char Byte;
typedef struct Buffer {
int size; /* Current size of the buffer */
int left; /* Space left (== size - (inPtr - buffer)) */
Byte *buffer; /* The buffer itself */
Byte *inPtr; /* Place to write to */
Byte *outPtr; /* Place to read from */
} *Buffer;
/* Buf_AddByte adds a single byte to a buffer. */
#define Buf_AddByte(bp, byte) \
(void) (--(bp)->left <= 0 ? Buf_OvAddByte(bp, byte), 1 : \
(*(bp)->inPtr++ = (byte), *(bp)->inPtr = 0), 1)
#define BUF_ERROR 256
void Buf_AddBytes __P((Buffer, int, Byte *));
void Buf_Destroy __P((Buffer, Boolean));
void Buf_Discard __P((Buffer, int));
Byte *Buf_GetAll __P((Buffer, int *));
int Buf_GetByte __P((Buffer));
int Buf_GetBytes __P((Buffer, int, Byte *));
Buffer Buf_Init __P((int));
void Buf_OvAddByte __P((Buffer, int));
int Buf_Size __P((Buffer));
void Buf_UngetByte __P((Buffer, int));
void Buf_UngetBytes __P((Buffer, int, Byte *));
#endif /* _BUF_H */

641
usr.bin/make/compat.c Normal file
View File

@ -0,0 +1,641 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
#endif /* not lint */
/*-
* compat.c --
* The routines in this file implement the full-compatibility
* mode of PMake. Most of the special functionality of PMake
* is available in this mode. Things not supported:
* - different shells.
* - friendly variable substitution.
*
* Interface:
* Compat_Run Initialize things for this module and recreate
* thems as need creatin'
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
#include "job.h"
extern int errno;
/*
* The following array is used to make a fast determination of which
* characters are interpreted specially by the shell. If a command
* contains any of these characters, it is executed by the shell, not
* directly by us.
*/
static char meta[256];
static GNode *curTarg = NILGNODE;
static GNode *ENDNode;
static void CompatInterrupt __P((int));
static int CompatRunCommand __P((char *, GNode *));
static int CompatMake __P((GNode *, GNode *));
/*-
*-----------------------------------------------------------------------
* CompatInterrupt --
* Interrupt the creation of the current target and remove it if
* it ain't precious.
*
* Results:
* None.
*
* Side Effects:
* The target is removed and the process exits. If .INTERRUPT exists,
* its commands are run first WITH INTERRUPTS IGNORED..
*
*-----------------------------------------------------------------------
*/
static void
CompatInterrupt (signo)
int signo;
{
struct stat sb;
GNode *gn;
if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {
char *file = Var_Value (TARGET, curTarg);
if (!stat(file, &sb) && S_ISREG(sb.st_mode) &&
unlink (file) == SUCCESS) {
printf ("*** %s removed\n", file);
}
/*
* Run .INTERRUPT only if hit with interrupt signal
*/
if (signo == SIGINT) {
gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
if (gn != NILGNODE) {
Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
}
}
}
exit (0);
}
/*-
*-----------------------------------------------------------------------
* CompatRunCommand --
* Execute the next command for a target. If the command returns an
* error, the node's made field is set to ERROR and creation stops.
*
* Results:
* 0 if the command succeeded, 1 if an error occurred.
*
* Side Effects:
* The node's 'made' field may be set to ERROR.
*
*-----------------------------------------------------------------------
*/
static int
CompatRunCommand (cmd, gn)
char *cmd; /* Command to execute */
GNode *gn; /* Node from which the command came */
{
char *cmdStart; /* Start of expanded command */
register char *cp;
Boolean silent, /* Don't print command */
errCheck; /* Check errors */
union wait reason; /* Reason for child's death */
int status; /* Description of child's death */
int cpid; /* Child actually found */
ReturnStatus stat; /* Status of fork */
LstNode cmdNode; /* Node where current command is located */
char **av; /* Argument vector for thing to exec */
int argc; /* Number of arguments in av or 0 if not
* dynamically allocated */
Boolean local; /* TRUE if command should be executed
* locally */
/*
* Avoid clobbered variable warnings by forcing the compiler
* to ``unregister'' variables
*/
#if __GNUC__
(void) &av;
(void) &errCheck;
#endif
silent = gn->type & OP_SILENT;
errCheck = !(gn->type & OP_IGNORE);
cmdNode = Lst_Member (gn->commands, (ClientData)cmd);
cmdStart = Var_Subst (NULL, cmd, gn, FALSE);
/*
* brk_string will return an argv with a NULL in av[1], thus causing
* execvp to choke and die horribly. Besides, how can we execute a null
* command? In any case, we warn the user that the command expanded to
* nothing (is this the right thing to do?).
*/
if (*cmdStart == '\0') {
Error("%s expands to empty string", cmd);
return(0);
} else {
cmd = cmdStart;
}
Lst_Replace (cmdNode, (ClientData)cmdStart);
if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
(void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
return(0);
} else if (strcmp(cmdStart, "...") == 0) {
gn->type |= OP_SAVE_CMDS;
return(0);
}
while ((*cmd == '@') || (*cmd == '-')) {
if (*cmd == '@') {
silent = TRUE;
} else {
errCheck = FALSE;
}
cmd++;
}
while (isspace((unsigned char)*cmd))
cmd++;
/*
* Search for meta characters in the command. If there are no meta
* characters, there's no need to execute a shell to execute the
* command.
*/
for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
continue;
}
/*
* Print the command before echoing if we're not supposed to be quiet for
* this one. We also print the command if -n given.
*/
if (!silent || noExecute) {
printf ("%s\n", cmd);
fflush(stdout);
}
/*
* If we're not supposed to execute any commands, this is as far as
* we go...
*/
if (noExecute) {
return (0);
}
if (*cp != '\0') {
/*
* If *cp isn't the null character, we hit a "meta" character and
* need to pass the command off to the shell. We give the shell the
* -e flag as well as -c if it's supposed to exit when it hits an
* error.
*/
static char *shargv[4] = { "/bin/sh" };
shargv[1] = (errCheck ? "-ec" : "-c");
shargv[2] = cmd;
shargv[3] = (char *)NULL;
av = shargv;
argc = 0;
} else {
/*
* No meta-characters, so no need to exec a shell. Break the command
* into words to form an argument vector we can execute.
* brk_string sticks our name in av[0], so we have to
* skip over it...
*/
av = brk_string(cmd, &argc);
av += 1;
}
local = TRUE;
/*
* Fork and execute the single command. If the fork fails, we abort.
*/
cpid = vfork();
if (cpid < 0) {
Fatal("Could not fork");
}
if (cpid == 0) {
if (local) {
execvp(av[0], av);
(void) write (2, av[0], strlen (av[0]));
(void) write (2, ": not found\n", sizeof(": not found"));
} else {
(void)execv(av[0], av);
}
exit(1);
}
/*
* The child is off and running. Now all we can do is wait...
*/
while (1) {
int id;
if (!local) {
id = 0;
}
while ((stat = wait((int *)&reason)) != cpid) {
if (stat == -1 && errno != EINTR) {
break;
}
}
if (stat > -1) {
if (WIFSTOPPED(reason)) {
status = reason.w_stopval; /* stopped */
} else if (WIFEXITED(reason)) {
status = reason.w_retcode; /* exited */
if (status != 0) {
printf ("*** Error code %d", status);
}
} else {
status = reason.w_termsig; /* signaled */
printf ("*** Signal %d", status);
}
if (!WIFEXITED(reason) || (status != 0)) {
if (errCheck) {
gn->made = ERROR;
if (keepgoing) {
/*
* Abort the current target, but let others
* continue.
*/
printf (" (continuing)\n");
}
} else {
/*
* Continue executing commands for this target.
* If we return 0, this will happen...
*/
printf (" (ignored)\n");
status = 0;
}
}
break;
} else {
Fatal ("error in wait: %d", stat);
/*NOTREACHED*/
}
}
return (status);
}
/*-
*-----------------------------------------------------------------------
* CompatMake --
* Make a target.
*
* Results:
* 0
*
* Side Effects:
* If an error is detected and not being ignored, the process exits.
*
*-----------------------------------------------------------------------
*/
static int
CompatMake (gn, pgn)
GNode *gn; /* The node to make */
GNode *pgn; /* Parent to abort if necessary */
{
if (gn->type & OP_USE) {
Make_HandleUse(gn, pgn);
} else if (gn->made == UNMADE) {
/*
* First mark ourselves to be made, then apply whatever transformations
* the suffix module thinks are necessary. Once that's done, we can
* descend and make all our children. If any of them has an error
* but the -k flag was given, our 'make' field will be set FALSE again.
* This is our signal to not attempt to do anything but abort our
* parent as well.
*/
gn->make = TRUE;
gn->made = BEINGMADE;
Suff_FindDeps (gn);
Lst_ForEach (gn->children, CompatMake, (ClientData)gn);
if (!gn->make) {
gn->made = ABORTED;
pgn->make = FALSE;
return (0);
}
if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn);
}
/*
* All the children were made ok. Now cmtime contains the modification
* time of the newest child, we need to find out if we exist and when
* we were modified last. The criteria for datedness are defined by the
* Make_OODate function.
*/
if (DEBUG(MAKE)) {
printf("Examining %s...", gn->name);
}
if (! Make_OODate(gn)) {
gn->made = UPTODATE;
if (DEBUG(MAKE)) {
printf("up-to-date.\n");
}
return (0);
} else if (DEBUG(MAKE)) {
printf("out-of-date.\n");
}
/*
* If the user is just seeing if something is out-of-date, exit now
* to tell him/her "yes".
*/
if (queryFlag) {
exit (-1);
}
/*
* We need to be re-made. We also have to make sure we've got a $?
* variable. To be nice, we also define the $> variable using
* Make_DoAllVar().
*/
Make_DoAllVar(gn);
/*
* Alter our type to tell if errors should be ignored or things
* should not be printed so CompatRunCommand knows what to do.
*/
if (Targ_Ignore (gn)) {
gn->type |= OP_IGNORE;
}
if (Targ_Silent (gn)) {
gn->type |= OP_SILENT;
}
if (Job_CheckCommands (gn, Fatal)) {
/*
* Our commands are ok, but we still have to worry about the -t
* flag...
*/
if (!touchFlag) {
curTarg = gn;
Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn);
curTarg = NILGNODE;
} else {
Job_Touch (gn, gn->type & OP_SILENT);
}
} else {
gn->made = ERROR;
}
if (gn->made != ERROR) {
/*
* If the node was made successfully, mark it so, update
* its modification time and timestamp all its parents. Note
* that for .ZEROTIME targets, the timestamping isn't done.
* This is to keep its state from affecting that of its parent.
*/
gn->made = MADE;
#ifndef RECHECK
/*
* We can't re-stat the thing, but we can at least take care of
* rules where a target depends on a source that actually creates
* the target, but only if it has changed, e.g.
*
* parse.h : parse.o
*
* parse.o : parse.y
* yacc -d parse.y
* cc -c y.tab.c
* mv y.tab.o parse.o
* cmp -s y.tab.h parse.h || mv y.tab.h parse.h
*
* In this case, if the definitions produced by yacc haven't
* changed from before, parse.h won't have been updated and
* gn->mtime will reflect the current modification time for
* parse.h. This is something of a kludge, I admit, but it's a
* useful one..
*
* XXX: People like to use a rule like
*
* FRC:
*
* To force things that depend on FRC to be made, so we have to
* check for gn->children being empty as well...
*/
if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
gn->mtime = now;
}
#else
/*
* This is what Make does and it's actually a good thing, as it
* allows rules like
*
* cmp -s y.tab.h parse.h || cp y.tab.h parse.h
*
* to function as intended. Unfortunately, thanks to the stateless
* nature of NFS (and the speed of this program), there are times
* when the modification time of a file created on a remote
* machine will not be modified before the stat() implied by
* the Dir_MTime occurs, thus leading us to believe that the file
* is unchanged, wreaking havoc with files that depend on this one.
*
* I have decided it is better to make too much than to make too
* little, so this stuff is commented out unless you're sure it's
* ok.
* -- ardeb 1/12/88
*/
if (noExecute || Dir_MTime(gn) == 0) {
gn->mtime = now;
}
if (gn->cmtime > gn->mtime)
gn->mtime = gn->cmtime;
if (DEBUG(MAKE)) {
printf("update time: %s\n", Targ_FmtTime(gn->mtime));
}
#endif
if (!(gn->type & OP_EXEC)) {
pgn->childMade = TRUE;
Make_TimeStamp(pgn, gn);
}
} else if (keepgoing) {
pgn->make = FALSE;
} else {
printf ("\n\nStop.\n");
exit (1);
}
} else if (gn->made == ERROR) {
/*
* Already had an error when making this beastie. Tell the parent
* to abort.
*/
pgn->make = FALSE;
} else {
if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn);
}
switch(gn->made) {
case BEINGMADE:
Error("Graph cycles through %s\n", gn->name);
gn->made = ERROR;
pgn->make = FALSE;
break;
case MADE:
if ((gn->type & OP_EXEC) == 0) {
pgn->childMade = TRUE;
Make_TimeStamp(pgn, gn);
}
break;
case UPTODATE:
if ((gn->type & OP_EXEC) == 0) {
Make_TimeStamp(pgn, gn);
}
break;
default:
break;
}
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Compat_Run --
* Initialize this mode and start making.
*
* Results:
* None.
*
* Side Effects:
* Guess what?
*
*-----------------------------------------------------------------------
*/
void
Compat_Run(targs)
Lst targs; /* List of target nodes to re-create */
{
char *cp; /* Pointer to string of shell meta-characters */
GNode *gn = NULL;/* Current root target */
int errors; /* Number of targets not remade due to errors */
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
signal(SIGINT, CompatInterrupt);
}
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
signal(SIGTERM, CompatInterrupt);
}
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
signal(SIGHUP, CompatInterrupt);
}
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
signal(SIGQUIT, CompatInterrupt);
}
for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
meta[(unsigned char) *cp] = 1;
}
/*
* The null character serves as a sentinel in the string.
*/
meta[0] = 1;
ENDNode = Targ_FindNode(".END", TARG_CREATE);
/*
* If the user has defined a .BEGIN target, execute the commands attached
* to it.
*/
if (!queryFlag) {
gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
if (gn != NILGNODE) {
Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
}
}
/*
* For each entry in the list of targets to create, call CompatMake on
* it to create the thing. CompatMake will leave the 'made' field of gn
* in one of several states:
* UPTODATE gn was already up-to-date
* MADE gn was recreated successfully
* ERROR An error occurred while gn was being created
* ABORTED gn was not remade because one of its inferiors
* could not be made due to errors.
*/
errors = 0;
while (!Lst_IsEmpty (targs)) {
gn = (GNode *) Lst_DeQueue (targs);
CompatMake (gn, gn);
if (gn->made == UPTODATE) {
printf ("`%s' is up to date.\n", gn->name);
} else if (gn->made == ABORTED) {
printf ("`%s' not remade because of errors.\n", gn->name);
errors += 1;
}
}
/*
* If the user has defined a .END target, run its commands.
*/
if (errors == 0) {
Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn);
}
}

1247
usr.bin/make/cond.c Normal file

File diff suppressed because it is too large Load Diff

92
usr.bin/make/config.h Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)config.h 8.1 (Berkeley) 6/6/93
*/
#define DEFSHELL 1 /* Bourne shell */
/*
* DEFMAXJOBS
* DEFMAXLOCAL
* These control the default concurrency. On no occasion will more
* than DEFMAXJOBS targets be created at once (locally or remotely)
* DEFMAXLOCAL is the highest number of targets which will be
* created on the local machine at once. Note that if you set this
* to 0, nothing will ever happen...
*/
#define DEFMAXJOBS 4
#define DEFMAXLOCAL 1
/*
* INCLUDES
* LIBRARIES
* These control the handling of the .INCLUDES and .LIBS variables.
* If INCLUDES is defined, the .INCLUDES variable will be filled
* from the search paths of those suffixes which are marked by
* .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS
* See suff.c for more details.
*/
#define INCLUDES
#define LIBRARIES
/*
* LIBSUFF
* Is the suffix used to denote libraries and is used by the Suff module
* to find the search path on which to seek any -l<xx> targets.
*
* RECHECK
* If defined, Make_Update will check a target for its current
* modification time after it has been re-made, setting it to the
* starting time of the make only if the target still doesn't exist.
* Unfortunately, under NFS the modification time often doesn't
* get updated in time, so a target will appear to not have been
* re-made, causing later targets to appear up-to-date. On systems
* that don't have this problem, you should defined this. Under
* NFS you probably should not, unless you aren't exporting jobs.
*
* POSIX
* If the POSIX standard for Make is to be followed. There are
* several areas that I dislike, hence this constant.
*/
#define LIBSUFF ".a"
#define RECHECK
#ifndef RANLIBMAG
#define RANLIBMAG "__.SYMDEF"
#endif
/*#define POSIX*/

1238
usr.bin/make/dir.c Normal file

File diff suppressed because it is too large Load Diff

70
usr.bin/make/dir.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)dir.h 8.1 (Berkeley) 6/6/93
*/
/* dir.h --
*/
#ifndef _DIR
#define _DIR
typedef struct Path {
char *name; /* Name of directory */
int refCount; /* Number of paths with this directory */
int hits; /* the number of times a file in this
* directory has been found */
Hash_Table files; /* Hash table of files in directory */
} Path;
void Dir_AddDir __P((Lst, char *));
void Dir_ClearPath __P((Lst));
void Dir_Concat __P((Lst, Lst));
ClientData
Dir_CopyDir __P((Path *));
void Dir_Destroy __P((Path *));
void Dir_Expand __P((char *, Lst, Lst));
char *Dir_FindFile __P((char *, Lst));
Boolean Dir_HasWildcards __P((char *));
void Dir_Init __P((void));
char *Dir_MakeFlags __P((char *, Lst));
int Dir_MTime __P((GNode *));
void Dir_PrintDirectories __P((void));
void Dir_PrintPath __P((Lst));
#endif /* _DIR */

296
usr.bin/make/for.c Normal file
View File

@ -0,0 +1,296 @@
/*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Christos Zoulas.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* for.c --
* Functions to handle loops in a makefile.
*
* Interface:
* For_Eval Evaluate the loop in the passed line.
* For_Run Run accumulated loop
*
*/
#include <ctype.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
#include "buf.h"
/*
* For statements are of the form:
*
* .for <variable> in <varlist>
* ...
* .endfor
*
* The trick is to look for the matching end inside for for loop
* To do that, we count the current nesting level of the for loops.
* and the .endfor statements, accumulating all the statements between
* the initial .for loop and the matching .endfor;
* then we evaluate the for loop for each variable in the varlist.
*/
static int forLevel = 0; /* Nesting level */
static char *forVar; /* Iteration variable */
static Buffer forBuf; /* Commands in loop */
static Lst forLst; /* List of items */
/*
* State of a for loop.
*/
struct For {
Buffer buf; /* Unexpanded buffer */
char* var; /* Index name */
Lst lst; /* List of variables */
};
static int ForExec __P((char *, struct For *));
/*-
*-----------------------------------------------------------------------
* For_Eval --
* Evaluate the for loop in the passed line. The line
* looks like this:
* .for <variable> in <varlist>
*
* Results:
* TRUE: We found a for loop, or we are inside a for loop
* FALSE: We did not find a for loop, or we found the end of the for
* for loop.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
int
For_Eval (line)
char *line; /* Line to parse */
{
char *ptr = line, *sub, *wrd;
int level; /* Level at which to report errors. */
level = PARSE_FATAL;
if (forLevel == 0) {
Buffer buf;
int varlen;
for (ptr++; *ptr && isspace(*ptr); ptr++)
continue;
/*
* If we are not in a for loop quickly determine if the statement is
* a for.
*/
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || !isspace(ptr[3]))
return FALSE;
ptr += 3;
/*
* we found a for loop, and now we are going to parse it.
*/
while (*ptr && isspace(*ptr))
ptr++;
/*
* Grab the variable
*/
buf = Buf_Init(0);
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
continue;
Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd);
forVar = (char *) Buf_GetAll(buf, &varlen);
if (varlen == 0) {
Parse_Error (level, "missing variable in for");
return 0;
}
Buf_Destroy(buf, FALSE);
while (*ptr && isspace(*ptr))
ptr++;
/*
* Grab the `in'
*/
if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace(ptr[2])) {
Parse_Error (level, "missing `in' in for");
printf("%s\n", ptr);
return 0;
}
ptr += 3;
while (*ptr && isspace(*ptr))
ptr++;
/*
* Make a list with the remaining words
*/
forLst = Lst_Init(FALSE);
buf = Buf_Init(0);
sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
#define ADDWORD() \
Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \
Buf_AddByte(buf, (Byte) '\0'), \
Lst_AtEnd(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \
Buf_Destroy(buf, FALSE)
for (ptr = sub; *ptr && isspace(*ptr); ptr++)
continue;
for (wrd = ptr; *ptr; ptr++)
if (isspace(*ptr)) {
ADDWORD();
buf = Buf_Init(0);
while (*ptr && isspace(*ptr))
ptr++;
wrd = ptr--;
}
if (DEBUG(FOR))
(void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub);
if (ptr - wrd > 0)
ADDWORD();
else
Buf_Destroy(buf, TRUE);
free((Address) sub);
forBuf = Buf_Init(0);
forLevel++;
return 1;
}
else if (*ptr == '.') {
for (ptr++; *ptr && isspace(*ptr); ptr++)
continue;
if (strncmp(ptr, "endfor", 6) == 0 && (isspace(ptr[6]) || !ptr[6])) {
if (DEBUG(FOR))
(void) fprintf(stderr, "For: end for %d\n", forLevel);
if (--forLevel < 0) {
Parse_Error (level, "for-less endfor");
return 0;
}
}
else if (strncmp(ptr, "for", 3) == 0 && isspace(ptr[3])) {
forLevel++;
if (DEBUG(FOR))
(void) fprintf(stderr, "For: new loop %d\n", forLevel);
}
}
if (forLevel != 0) {
Buf_AddBytes(forBuf, strlen(line), (Byte *) line);
Buf_AddByte(forBuf, (Byte) '\n');
return 1;
}
else {
return 0;
}
}
/*-
*-----------------------------------------------------------------------
* ForExec --
* Expand the for loop for this index and push it in the Makefile
*
* Results:
* None.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
static int
ForExec(name, arg)
char *name;
struct For *arg;
{
int len;
Var_Set(arg->var, name, VAR_GLOBAL);
if (DEBUG(FOR))
(void) fprintf(stderr, "--- %s = %s\n", arg->var, name);
Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len),
VAR_GLOBAL, FALSE));
Var_Delete(arg->var, VAR_GLOBAL);
return 0;
}
/*-
*-----------------------------------------------------------------------
* For_Run --
* Run the for loop, immitating the actions of an include file
*
* Results:
* None.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
void
For_Run()
{
struct For arg;
if (forVar == NULL || forBuf == NULL || forLst == NULL)
return;
arg.var = forVar;
arg.buf = forBuf;
arg.lst = forLst;
forVar = NULL;
forBuf = NULL;
forLst = NULL;
Lst_ForEach(arg.lst, ForExec, (ClientData) &arg);
free((Address)arg.var);
Lst_Destroy(arg.lst, free);
Buf_Destroy(arg.buf, TRUE);
}

418
usr.bin/make/hash.c Normal file
View File

@ -0,0 +1,418 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/* hash.c --
*
* This module contains routines to manipulate a hash table.
* See hash.h for a definition of the structure of the hash
* table. Hash tables grow automatically as the amount of
* information increases.
*/
#include "sprite.h"
#include "make.h"
#include "hash.h"
/*
* Forward references to local procedures that are used before they're
* defined:
*/
static void RebuildTable __P((Hash_Table *));
/*
* The following defines the ratio of # entries to # buckets
* at which we rebuild the table to make it larger.
*/
#define rebuildLimit 8
/*
*---------------------------------------------------------
*
* Hash_InitTable --
*
* This routine just sets up the hash table.
*
* Results:
* None.
*
* Side Effects:
* Memory is allocated for the initial bucket area.
*
*---------------------------------------------------------
*/
void
Hash_InitTable(t, numBuckets)
register Hash_Table *t; /* Structure to use to hold table. */
int numBuckets; /* How many buckets to create for starters.
* This number is rounded up to a power of
* two. If <= 0, a reasonable default is
* chosen. The table will grow in size later
* as needed. */
{
register int i;
register struct Hash_Entry **hp;
/*
* Round up the size to a power of two.
*/
if (numBuckets <= 0)
i = 16;
else {
for (i = 2; i < numBuckets; i <<= 1)
continue;
}
t->numEntries = 0;
t->size = i;
t->mask = i - 1;
t->bucketPtr = hp = (struct Hash_Entry **)emalloc(sizeof(*hp) * i);
while (--i >= 0)
*hp++ = NULL;
}
/*
*---------------------------------------------------------
*
* Hash_DeleteTable --
*
* This routine removes everything from a hash table
* and frees up the memory space it occupied (except for
* the space in the Hash_Table structure).
*
* Results:
* None.
*
* Side Effects:
* Lots of memory is freed up.
*
*---------------------------------------------------------
*/
void
Hash_DeleteTable(t)
Hash_Table *t;
{
register struct Hash_Entry **hp, *h, *nexth = NULL;
register int i;
for (hp = t->bucketPtr, i = t->size; --i >= 0;) {
for (h = *hp++; h != NULL; h = nexth) {
nexth = h->next;
free((char *)h);
}
}
free((char *)t->bucketPtr);
/*
* Set up the hash table to cause memory faults on any future access
* attempts until re-initialization.
*/
t->bucketPtr = NULL;
}
/*
*---------------------------------------------------------
*
* Hash_FindEntry --
*
* Searches a hash table for an entry corresponding to key.
*
* Results:
* The return value is a pointer to the entry for key,
* if key was present in the table. If key was not
* present, NULL is returned.
*
* Side Effects:
* None.
*
*---------------------------------------------------------
*/
Hash_Entry *
Hash_FindEntry(t, key)
Hash_Table *t; /* Hash table to search. */
char *key; /* A hash key. */
{
register Hash_Entry *e;
register unsigned h;
register char *p;
for (h = 0, p = key; *p;)
h = (h << 5) - h + *p++;
p = key;
for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next)
if (e->namehash == h && strcmp(e->name, p) == 0)
return (e);
return (NULL);
}
/*
*---------------------------------------------------------
*
* Hash_CreateEntry --
*
* Searches a hash table for an entry corresponding to
* key. If no entry is found, then one is created.
*
* Results:
* The return value is a pointer to the entry. If *newPtr
* isn't NULL, then *newPtr is filled in with TRUE if a
* new entry was created, and FALSE if an entry already existed
* with the given key.
*
* Side Effects:
* Memory may be allocated, and the hash buckets may be modified.
*---------------------------------------------------------
*/
Hash_Entry *
Hash_CreateEntry(t, key, newPtr)
register Hash_Table *t; /* Hash table to search. */
char *key; /* A hash key. */
Boolean *newPtr; /* Filled in with TRUE if new entry created,
* FALSE otherwise. */
{
register Hash_Entry *e;
register unsigned h;
register char *p;
int keylen;
struct Hash_Entry **hp;
/*
* Hash the key. As a side effect, save the length (strlen) of the
* key in case we need to create the entry.
*/
for (h = 0, p = key; *p;)
h = (h << 5) - h + *p++;
keylen = p - key;
p = key;
for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) {
if (e->namehash == h && strcmp(e->name, p) == 0) {
if (newPtr != NULL)
*newPtr = FALSE;
return (e);
}
}
/*
* The desired entry isn't there. Before allocating a new entry,
* expand the table if necessary (and this changes the resulting
* bucket chain).
*/
if (t->numEntries >= rebuildLimit * t->size)
RebuildTable(t);
e = (Hash_Entry *) emalloc(sizeof(*e) + keylen);
hp = &t->bucketPtr[h & t->mask];
e->next = *hp;
*hp = e;
e->clientData = NULL;
e->namehash = h;
(void) strcpy(e->name, p);
t->numEntries++;
if (newPtr != NULL)
*newPtr = TRUE;
return (e);
}
/*
*---------------------------------------------------------
*
* Hash_DeleteEntry --
*
* Delete the given hash table entry and free memory associated with
* it.
*
* Results:
* None.
*
* Side Effects:
* Hash chain that entry lives in is modified and memory is freed.
*
*---------------------------------------------------------
*/
void
Hash_DeleteEntry(t, e)
Hash_Table *t;
Hash_Entry *e;
{
register Hash_Entry **hp, *p;
if (e == NULL)
return;
for (hp = &t->bucketPtr[e->namehash & t->mask];
(p = *hp) != NULL; hp = &p->next) {
if (p == e) {
*hp = p->next;
free((char *)p);
t->numEntries--;
return;
}
}
(void) write(2, "bad call to Hash_DeleteEntry\n", 29);
abort();
}
/*
*---------------------------------------------------------
*
* Hash_EnumFirst --
* This procedure sets things up for a complete search
* of all entries recorded in the hash table.
*
* Results:
* The return value is the address of the first entry in
* the hash table, or NULL if the table is empty.
*
* Side Effects:
* The information in searchPtr is initialized so that successive
* calls to Hash_Next will return successive HashEntry's
* from the table.
*
*---------------------------------------------------------
*/
Hash_Entry *
Hash_EnumFirst(t, searchPtr)
Hash_Table *t; /* Table to be searched. */
register Hash_Search *searchPtr;/* Area in which to keep state
* about search.*/
{
searchPtr->tablePtr = t;
searchPtr->nextIndex = 0;
searchPtr->hashEntryPtr = NULL;
return Hash_EnumNext(searchPtr);
}
/*
*---------------------------------------------------------
*
* Hash_EnumNext --
* This procedure returns successive entries in the hash table.
*
* Results:
* The return value is a pointer to the next HashEntry
* in the table, or NULL when the end of the table is
* reached.
*
* Side Effects:
* The information in searchPtr is modified to advance to the
* next entry.
*
*---------------------------------------------------------
*/
Hash_Entry *
Hash_EnumNext(searchPtr)
register Hash_Search *searchPtr; /* Area used to keep state about
search. */
{
register Hash_Entry *e;
Hash_Table *t = searchPtr->tablePtr;
/*
* The hashEntryPtr field points to the most recently returned
* entry, or is nil if we are starting up. If not nil, we have
* to start at the next one in the chain.
*/
e = searchPtr->hashEntryPtr;
if (e != NULL)
e = e->next;
/*
* If the chain ran out, or if we are starting up, we need to
* find the next nonempty chain.
*/
while (e == NULL) {
if (searchPtr->nextIndex >= t->size)
return (NULL);
e = t->bucketPtr[searchPtr->nextIndex++];
}
searchPtr->hashEntryPtr = e;
return (e);
}
/*
*---------------------------------------------------------
*
* RebuildTable --
* This local routine makes a new hash table that
* is larger than the old one.
*
* Results:
* None.
*
* Side Effects:
* The entire hash table is moved, so any bucket numbers
* from the old table are invalid.
*
*---------------------------------------------------------
*/
static void
RebuildTable(t)
register Hash_Table *t;
{
register Hash_Entry *e, *next = NULL, **hp, **xp;
register int i, mask;
register Hash_Entry **oldhp;
int oldsize;
oldhp = t->bucketPtr;
oldsize = i = t->size;
i <<= 1;
t->size = i;
t->mask = mask = i - 1;
t->bucketPtr = hp = (struct Hash_Entry **) emalloc(sizeof(*hp) * i);
while (--i >= 0)
*hp++ = NULL;
for (hp = oldhp, i = oldsize; --i >= 0;) {
for (e = *hp++; e != NULL; e = next) {
next = e->next;
xp = &t->bucketPtr[e->namehash & mask];
e->next = *xp;
*xp = e;
}
}
free((char *)oldhp);
}

116
usr.bin/make/hash.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)hash.h 8.1 (Berkeley) 6/6/93
*/
/* hash.h --
*
* This file contains definitions used by the hash module,
* which maintains hash tables.
*/
#ifndef _HASH
#define _HASH
/*
* The following defines one entry in the hash table.
*/
typedef struct Hash_Entry {
struct Hash_Entry *next; /* Used to link together all the
* entries associated with the same
* bucket. */
ClientData clientData; /* Arbitrary piece of data associated
* with key. */
unsigned namehash; /* hash value of key */
char name[1]; /* key string */
} Hash_Entry;
typedef struct Hash_Table {
struct Hash_Entry **bucketPtr;/* Pointers to Hash_Entry, one
* for each bucket in the table. */
int size; /* Actual size of array. */
int numEntries; /* Number of entries in the table. */
int mask; /* Used to select bits for hashing. */
} Hash_Table;
/*
* The following structure is used by the searching routines
* to record where we are in the search.
*/
typedef struct Hash_Search {
Hash_Table *tablePtr; /* Table being searched. */
int nextIndex; /* Next bucket to check (after current). */
Hash_Entry *hashEntryPtr; /* Next entry to check in current bucket. */
} Hash_Search;
/*
* Macros.
*/
/*
* ClientData Hash_GetValue(h)
* Hash_Entry *h;
*/
#define Hash_GetValue(h) ((h)->clientData)
/*
* Hash_SetValue(h, val);
* Hash_Entry *h;
* char *val;
*/
#define Hash_SetValue(h, val) ((h)->clientData = (ClientData) (val))
/*
* Hash_Size(n) returns the number of words in an object of n bytes
*/
#define Hash_Size(n) (((n) + sizeof (int) - 1) / sizeof (int))
Hash_Entry *Hash_CreateEntry __P((Hash_Table *, char *, Boolean *));
void Hash_DeleteEntry __P((Hash_Table *, Hash_Entry *));
void Hash_DeleteTable __P((Hash_Table *));
Hash_Entry *Hash_EnumFirst __P((Hash_Table *, Hash_Search *));
Hash_Entry *Hash_EnumNext __P((Hash_Search *));
Hash_Entry *Hash_FindEntry __P((Hash_Table *, char *));
void Hash_InitTable __P((Hash_Table *, int));
#endif /* _HASH */

2661
usr.bin/make/job.c Normal file

File diff suppressed because it is too large Load Diff

233
usr.bin/make/job.h Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)job.h 8.1 (Berkeley) 6/6/93
*/
/*-
* 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_
#define TMPPAT "/tmp/makeXXXXX"
/*
* The SEL_ constants determine the maximum amount of time spent in select
* before coming out to see if a child has finished. SEL_SEC is the number of
* seconds and SEL_USEC is the number of micro-seconds
*/
#define SEL_SEC 0
#define SEL_USEC 500000
/*-
* Job Table definitions.
*
* Each job has several things associated with it:
* 1) The process id of the child shell
* 2) The graph node describing the target being made by this job
* 3) A LstNode for the first command to be saved after the job
* completes. This is NILLNODE if there was no "..." in the job's
* 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
* 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,
* 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.
*/
#define JOB_BUFSIZE 1024
typedef struct Job {
int pid; /* The child's process ID */
GNode *node; /* The target the child is making */
LstNode tailCmds; /* The node of the first command to be
* 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 */
short flags; /* Flags to control treatment of job */
#define JOB_IGNERR 0x001 /* Ignore non-zero exits */
#define JOB_SILENT 0x002 /* no output */
#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally
* 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 */
union {
struct {
int op_inPipe; /* Input side of pipe associated
* with job's output channel */
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 */
} Job;
#define outPipe output.o_pipe.op_outPipe
#define inPipe output.o_pipe.op_inPipe
#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
/*-
* Shell Specifications:
* Each shell type has associated with it the following information:
* 1) The string which must match the last character of the shell name
* for the shell to be considered of this type. The longest match
* wins.
* 2) A command to issue to turn off echoing of command lines
* 3) A command to issue to turn echoing back on again
* 4) What the shell prints, and its length, when given the echo-off
* command. This line will not be printed when received from the shell
* 5) A boolean to tell if the shell has the ability to control
* error checking for individual commands.
* 6) The string to turn this checking on.
* 7) The string to turn it off.
* 8) The command-flag to give to cause the shell to start echoing
* commands right away.
* 9) The command-flag to cause the shell to Lib_Exit when an error is
* detected in one of the commands.
*
* Some special stuff goes on if a shell doesn't have error control. In such
* a case, errCheck becomes a printf template for echoing the command,
* should echoing be on and ignErr becomes another printf template for
* executing the command while ignoring the return status. If either of these
* strings is empty when hasErrCtl is FALSE, the command will be executed
* anyway as is and if it causes an error, so be it.
*/
typedef struct Shell {
char *name; /* the name of the shell. For Bourne and C
* shells, this is used only to find the
* shell description when used as the single
* source of a .SHELL target. For user-defined
* shells, this is the full path of the shell.
*/
Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */
char *echoOff; /* command to turn off echo */
char *echoOn; /* command to turn it back on again */
char *noPrint; /* command to skip when printing output from
* shell. This is usually the command which
* was executed to turn off echoing */
int noPLen; /* length of noPrint command */
Boolean hasErrCtl; /* set if can control error checking for
* individual commands */
char *errCheck; /* string to turn error checking on */
char *ignErr; /* string to turn off error checking */
/*
* command-line flags
*/
char *echo; /* echo commands */
char *exit; /* exit on error */
} Shell;
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 */
extern Boolean jobFull; /* Non-zero if no more jobs should/will start*/
void JobFlagForMigration __P((int));
void Job_AbortAll __P((void));
void Job_CatchChildren __P((Boolean));
void Job_CatchOutput __P((void));
Boolean Job_CheckCommands __P((GNode *,
void (*abortProc )(const char *, ...)));
Boolean Job_Empty __P((void));
int Job_End __P((void));
Boolean Job_Full __P((void));
void Job_Init __P((int, int));
void Job_Make __P((GNode *));
ReturnStatus Job_ParseShell __P((char *));
void Job_Touch __P((GNode *, Boolean));
void Job_Wait __P((void));
#endif /* _JOB_H_ */

298
usr.bin/make/list.h Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)list.h 8.1 (Berkeley) 6/6/93
*/
/*
* list.h --
*
* Structures, macros, and routines exported by the List module.
*/
#ifndef _LIST
#define _LIST
#ifndef _SPRITE
#include "sprite.h"
#endif _SPRITE
/*
* This module defines the list abstraction, which enables one to link
* together arbitrary data structures. Lists are doubly-linked and
* circular. A list contains a header followed by its real members, if
* any. (An empty list therefore consists of a single element, the
* header, whose nextPtr and prevPtr fields point to itself). To refer
* to a list as a whole, the user keeps a pointer to the header; that
* header is initialized by a call to List_Init(), which creates an empty
* list given a pointer to a List_Links structure (described below).
*
* The links are contained in a two-element structure called List_Links.
* A list joins List_Links records (that is, each List_Links structure
* points to other List_Links structures), but if the List_Links is the
* first field within a larger structure, then the larger structures are
* effectively linked together as follows:
*
* header
* (List_Links) first elt. second elt.
* ----------------- ----------------- -----------------
* ..-> | nextPtr | ----> | List_Links | ----> | List_Links |----..
* | - - - - - - - | | | | |
* ..-- | prevPtr | <---- | | <---- | |<---..
* ----------------- - --- --- --- - - --- --- --- -
* | rest of | | rest of |
* | structure | | structure |
* | | | |
* | ... | | ... |
* ----------------- -----------------
*
* It is possible to link structures through List_Links fields that are
* not at the beginning of the larger structure, but it is then necessary
* to perform pointer arithmetic to find the beginning of the larger
* structure, given a pointer to some point within it.
*
* A typical structure might be something like:
*
* typedef struct {
* List_Links links;
* char ch;
* integer flags;
* } EditChar;
*
* Before an element is inserted in a list for the first time, it must
* be initialized by calling the macro List_InitElement().
*/
/*
* data structure for lists
*/
typedef struct List_Links {
struct List_Links *prevPtr;
struct List_Links *nextPtr;
} List_Links;
/*
* procedures
*/
void List_Init(); /* initialize a header to a list */
void List_Insert(); /* insert an element into a list */
void List_Remove(); /* remove an element from a list */
void List_Move(); /* move an element elsewhere in a list */
/*
* ----------------------------------------------------------------------------
*
* List_InitElement --
*
* Initialize a list element. Must be called before an element is first
* inserted into a list.
*
* ----------------------------------------------------------------------------
*/
#define List_InitElement(elementPtr) \
(elementPtr)->prevPtr = (List_Links *) NIL; \
(elementPtr)->nextPtr = (List_Links *) NIL;
/*
* Macros for stepping through or selecting parts of lists
*/
/*
* ----------------------------------------------------------------------------
*
* LIST_FORALL --
*
* Macro to loop through a list and perform an operation on each member.
*
* Usage: LIST_FORALL(headerPtr, itemPtr) {
* / *
* * operation on itemPtr, which points to successive members
* * of the list
* *
* * It may be appropriate to first assign
* * foobarPtr = (Foobar *) itemPtr;
* * to refer to the entire Foobar structure.
* * /
* }
*
* Note: itemPtr must be a List_Links pointer variable, and headerPtr
* must evaluate to a pointer to a List_Links structure.
*
* ----------------------------------------------------------------------------
*/
#define LIST_FORALL(headerPtr, itemPtr) \
for (itemPtr = List_First(headerPtr); \
!List_IsAtEnd((headerPtr),itemPtr); \
itemPtr = List_Next(itemPtr))
/*
* ----------------------------------------------------------------------------
*
* List_IsEmpty --
*
* Macro: Boolean value, TRUE if the given list does not contain any
* members.
*
* Usage: if (List_IsEmpty(headerPtr)) ...
*
* ----------------------------------------------------------------------------
*/
#define List_IsEmpty(headerPtr) \
((headerPtr) == (headerPtr)->nextPtr)
/*
* ----------------------------------------------------------------------------
*
* List_IsAtEnd --
*
* Macro: Boolean value, TRUE if itemPtr is after the end of headerPtr
* (i.e., itemPtr is the header of the list).
*
* Usage: if (List_IsAtEnd(headerPtr, itemPtr)) ...
*
* ----------------------------------------------------------------------------
*/
#define List_IsAtEnd(headerPtr, itemPtr) \
((itemPtr) == (headerPtr))
/*
* ----------------------------------------------------------------------------
*
* List_First --
*
* Macro to return the first member in a list, which is the header if
* the list is empty.
*
* Usage: firstPtr = List_First(headerPtr);
*
* ----------------------------------------------------------------------------
*/
#define List_First(headerPtr) ((headerPtr)->nextPtr)
/*
* ----------------------------------------------------------------------------
*
* List_Last --
*
* Macro to return the last member in a list, which is the header if
* the list is empty.
*
* Usage: lastPtr = List_Last(headerPtr);
*
* ----------------------------------------------------------------------------
*/
#define List_Last(headerPtr) ((headerPtr)->prevPtr)
/*
* ----------------------------------------------------------------------------
*
* List_Prev --
*
* Macro to return the member preceding the given member in its list.
* If the given list member is the first element in the list, List_Prev
* returns the list header.
*
* Usage: prevPtr = List_Prev(itemPtr);
*
* ----------------------------------------------------------------------------
*/
#define List_Prev(itemPtr) ((itemPtr)->prevPtr)
/*
* ----------------------------------------------------------------------------
*
* List_Next --
*
* Macro to return the member following the given member in its list.
* If the given list member is the last element in the list, List_Next
* returns the list header.
*
* Usage: nextPtr = List_Next(itemPtr);
*
* ----------------------------------------------------------------------------
*/
#define List_Next(itemPtr) ((itemPtr)->nextPtr)
/*
* ----------------------------------------------------------------------------
* The List_Insert procedure takes two arguments. The first argument
* is a pointer to the structure to be inserted into a list, and
* the second argument is a pointer to the list member after which
* the new element is to be inserted. Macros are used to determine
* which existing member will precede the new one.
*
* The List_Move procedure takes a destination argument with the same
* semantics as List_Insert.
*
* The following macros define where to insert the new element
* in the list:
*
* LIST_AFTER(itemPtr) -- insert after itemPtr
* LIST_BEFORE(itemPtr) -- insert before itemPtr
* LIST_ATFRONT(headerPtr) -- insert at front of list
* LIST_ATREAR(headerPtr) -- insert at end of list
*
* For example,
*
* List_Insert(itemPtr, LIST_AFTER(otherPtr));
*
* will insert itemPtr following otherPtr in the list containing otherPtr.
* ----------------------------------------------------------------------------
*/
#define LIST_AFTER(itemPtr) ((List_Links *) itemPtr)
#define LIST_BEFORE(itemPtr) (((List_Links *) itemPtr)->prevPtr)
#define LIST_ATFRONT(headerPtr) ((List_Links *) headerPtr)
#define LIST_ATREAR(headerPtr) (((List_Links *) headerPtr)->prevPtr)
#endif /* _LIST */

145
usr.bin/make/lst.h Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)lst.h 8.1 (Berkeley) 6/6/93
*/
/*-
* lst.h --
* Header for using the list library
*/
#ifndef _LST_H_
#define _LST_H_
#include <sprite.h>
#if __STDC__
#include <stdlib.h>
#endif
/*
* basic typedef. This is what the Lst_ functions handle
*/
typedef struct Lst *Lst;
typedef struct LstNode *LstNode;
#define NILLST ((Lst) NIL)
#define NILLNODE ((LstNode) NIL)
/*
* NOFREE can be used as the freeProc to Lst_Destroy when the elements are
* not to be freed.
* NOCOPY performs similarly when given as the copyProc to Lst_Duplicate.
*/
#define NOFREE ((void (*)()) 0)
#define NOCOPY ((ClientData (*)()) 0)
#define LST_CONCNEW 0 /* create new LstNode's when using Lst_Concat */
#define LST_CONCLINK 1 /* relink LstNode's when using Lst_Concat */
/*
* Creation/destruction functions
*/
Lst Lst_Init(); /* Create a new list */
Lst Lst_Duplicate(); /* Duplicate an existing list */
void Lst_Destroy(); /* Destroy an old one */
int Lst_Length(); /* Find the length of a list */
Boolean Lst_IsEmpty(); /* True if list is empty */
/*
* Functions to modify a list
*/
ReturnStatus Lst_Insert(); /* Insert an element before another */
ReturnStatus Lst_Append(); /* Insert an element after another */
ReturnStatus Lst_AtFront(); /* Place an element at the front of
* a lst. */
ReturnStatus Lst_AtEnd(); /* Place an element at the end of a
* lst. */
ReturnStatus Lst_Remove(); /* Remove an element */
ReturnStatus Lst_Replace(); /* Replace a node with a new value */
ReturnStatus Lst_Move(); /* Move an element to another place */
ReturnStatus Lst_Concat(); /* Concatenate two lists */
/*
* Node-specific functions
*/
LstNode Lst_First(); /* Return first element in list */
LstNode Lst_Last(); /* Return last element in list */
LstNode Lst_Succ(); /* Return successor to given element */
LstNode Lst_Pred(); /* Return predecessor to given
* element */
ClientData Lst_Datum(); /* Get datum from LstNode */
/*
* Functions for entire lists
*/
LstNode Lst_Find(); /* Find an element in a list */
LstNode Lst_FindFrom(); /* Find an element starting from
* somewhere */
LstNode Lst_Member(); /* See if the given datum is on the
* list. Returns the LstNode containing
* the datum */
int Lst_Index(); /* Returns the index of a datum in the
* list, starting from 0 */
void Lst_ForEach(); /* Apply a function to all elements of
* a lst */
void Lst_ForEachFrom(); /* 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. */
/*
* these functions are for dealing with a list as a table, of sorts.
* An idea of the "current element" is kept and used by all the functions
* between Lst_Open() and Lst_Close().
*/
ReturnStatus Lst_Open(); /* Open the list */
LstNode Lst_Prev(); /* Previous element */
LstNode Lst_Cur(); /* The current element, please */
LstNode Lst_Next(); /* Next element please */
Boolean Lst_IsAtEnd(); /* Done yet? */
void Lst_Close(); /* Finish table access */
/*
* for using the list as a queue
*/
ReturnStatus Lst_EnQueue(); /* Place an element at tail of queue */
ClientData Lst_DeQueue(); /* Remove an element from head of
* queue */
#endif _LST_H_

View File

@ -0,0 +1,113 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstAppend.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstAppend.c --
* Add a new node with a new datum after an existing node
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Append --
* Create a new node and add it to the given list after the given node.
*
* Results:
* SUCCESS if all went well.
*
* Side Effects:
* A new ListNode is created and linked in to the List. The lastPtr
* field of the List will be altered if ln is the last node in the
* list. lastPtr and firstPtr will alter if the list was empty and
* ln was NILLNODE.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Append (l, ln, d)
Lst l; /* affected list */
LstNode ln; /* node after which to append the datum */
ClientData d; /* said datum */
{
register List list;
register ListNode lNode;
register ListNode nLNode;
if (LstValid (l) && (ln == NILLNODE && LstIsEmpty (l))) {
goto ok;
}
if (!LstValid (l) || LstIsEmpty (l) || ! LstNodeValid (ln, l)) {
return (FAILURE);
}
ok:
list = (List)l;
lNode = (ListNode)ln;
PAlloc (nLNode, ListNode);
nLNode->datum = d;
nLNode->useCount = nLNode->flags = 0;
if (lNode == NilListNode) {
if (list->isCirc) {
nLNode->nextPtr = nLNode->prevPtr = nLNode;
} else {
nLNode->nextPtr = nLNode->prevPtr = NilListNode;
}
list->firstPtr = list->lastPtr = nLNode;
} else {
nLNode->prevPtr = lNode;
nLNode->nextPtr = lNode->nextPtr;
lNode->nextPtr = nLNode;
if (nLNode->nextPtr != NilListNode) {
nLNode->nextPtr->prevPtr = nLNode;
}
if (lNode == list->lastPtr) {
list->lastPtr = nLNode;
}
}
return (SUCCESS);
}

View File

@ -0,0 +1,70 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstAtEnd.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstAtEnd.c --
* Add a node at the end of the list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_AtEnd --
* Add a node to the end of the given list
*
* Results:
* SUCCESS if life is good.
*
* Side Effects:
* A new ListNode is created and added to the list.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_AtEnd (l, d)
Lst l; /* List to which to add the datum */
ClientData d; /* Datum to add */
{
register LstNode end;
end = Lst_Last (l);
return (Lst_Append (l, end, d));
}

View File

@ -0,0 +1,71 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstAtFront.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstAtFront.c --
* Add a node at the front of the list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_AtFront --
* Place a piece of data at the front of a list
*
* Results:
* SUCCESS or FAILURE
*
* Side Effects:
* A new ListNode is created and stuck at the front of the list.
* hence, firstPtr (and possible lastPtr) in the list are altered.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_AtFront (l, d)
Lst l;
ClientData d;
{
register LstNode front;
front = Lst_First (l);
return (Lst_Insert (l, front, d));
}

View File

@ -0,0 +1,77 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstClose.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstClose.c --
* Close a list for sequential access.
* The sequential functions access the list in a slightly different way.
* CurPtr points to their idea of the current node in the list and they
* access the list based on it. Because the list is circular, Lst_Next
* and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
* used to determine when to stop.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Close --
* Close a list which was opened for sequential access.
*
* Results:
* None.
*
* Side Effects:
* The list is closed.
*
*-----------------------------------------------------------------------
*/
void
Lst_Close (l)
Lst l; /* The list to close */
{
register List list = (List) l;
if (LstValid(l) == TRUE) {
list->isOpen = FALSE;
list->atEnd = Unknown;
}
}

View File

@ -0,0 +1,174 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstConcat.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* listConcat.c --
* Function to concatentate two lists.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Concat --
* Concatenate two lists. New elements are created to hold the data
* elements, if specified, but the elements themselves are not copied.
* If the elements should be duplicated to avoid confusion with another
* list, the Lst_Duplicate function should be called first.
* If LST_CONCLINK is specified, the second list is destroyed since
* its pointers have been corrupted and the list is no longer useable.
*
* Results:
* SUCCESS if all went well. FAILURE otherwise.
*
* Side Effects:
* New elements are created and appended the the first list.
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Concat (l1, l2, flags)
Lst l1; /* The list to which l2 is to be appended */
Lst l2; /* The list to append to l1 */
int flags; /* LST_CONCNEW if LstNode's should be duplicated
* LST_CONCLINK if should just be relinked */
{
register ListNode ln; /* original LstNode */
register ListNode nln; /* new LstNode */
register ListNode last; /* the last element in the list. Keeps
* bookkeeping until the end */
register List list1 = (List)l1;
register List list2 = (List)l2;
if (!LstValid (l1) || !LstValid (l2)) {
return (FAILURE);
}
if (flags == LST_CONCLINK) {
if (list2->firstPtr != NilListNode) {
/*
* We set the nextPtr of the
* last element of list two to be NIL to make the loop easier and
* so we don't need an extra case should the first list turn
* out to be non-circular -- the final element will already point
* to NIL space and the first element will be untouched if it
* existed before and will also point to NIL space if it didn't.
*/
list2->lastPtr->nextPtr = NilListNode;
/*
* So long as the second list isn't empty, we just link the
* first element of the second list to the last element of the
* first list. If the first list isn't empty, we then link the
* last element of the list to the first element of the second list
* The last element of the second list, if it exists, then becomes
* the last element of the first list.
*/
list2->firstPtr->prevPtr = list1->lastPtr;
if (list1->lastPtr != NilListNode) {
list1->lastPtr->nextPtr = list2->firstPtr;
}
list1->lastPtr = list2->lastPtr;
}
if (list1->isCirc && list1->firstPtr != NilListNode) {
/*
* If the first list is supposed to be circular and it is (now)
* non-empty, we must make sure it's circular by linking the
* first element to the last and vice versa
*/
list1->firstPtr->prevPtr = list1->lastPtr;
list1->lastPtr->nextPtr = list1->firstPtr;
}
free ((Address)l2);
} else if (list2->firstPtr != NilListNode) {
/*
* We set the nextPtr of the last element of list 2 to be nil to make
* the loop less difficult. The loop simply goes through the entire
* second list creating new LstNodes and filling in the nextPtr, and
* prevPtr to fit into l1 and its datum field from the
* datum field of the corresponding element in l2. The 'last' node
* follows the last of the new nodes along until the entire l2 has
* been appended. Only then does the bookkeeping catch up with the
* changes. During the first iteration of the loop, if 'last' is nil,
* the first list must have been empty so the newly-created node is
* made the first node of the list.
*/
list2->lastPtr->nextPtr = NilListNode;
for (last = list1->lastPtr, ln = list2->firstPtr;
ln != NilListNode;
ln = ln->nextPtr)
{
PAlloc (nln, ListNode);
nln->datum = ln->datum;
if (last != NilListNode) {
last->nextPtr = nln;
} else {
list1->firstPtr = nln;
}
nln->prevPtr = last;
nln->flags = nln->useCount = 0;
last = nln;
}
/*
* Finish bookkeeping. The last new element becomes the last element
* of list one.
*/
list1->lastPtr = last;
/*
* The circularity of both list one and list two must be corrected
* for -- list one because of the new nodes added to it; list two
* because of the alteration of list2->lastPtr's nextPtr to ease the
* above for loop.
*/
if (list1->isCirc) {
list1->lastPtr->nextPtr = list1->firstPtr;
list1->firstPtr->prevPtr = list1->lastPtr;
} else {
last->nextPtr = NilListNode;
}
if (list2->isCirc) {
list2->lastPtr->nextPtr = list2->firstPtr;
}
}
return (SUCCESS);
}

View File

@ -0,0 +1,71 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstDatum.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstDatum.c --
* Return the datum associated with a list node.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Datum --
* Return the datum stored in the given node.
*
* Results:
* The datum or (ick!) NIL if the node is invalid.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
ClientData
Lst_Datum (ln)
LstNode ln;
{
if (ln != NILLNODE) {
return (((ListNode)ln)->datum);
} else {
return ((ClientData) NIL);
}
}

View File

@ -0,0 +1,81 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstDeQueue.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstDeQueue.c --
* Remove the node and return its datum from the head of the list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_DeQueue --
* Remove and return the datum at the head of the given list.
*
* Results:
* The datum in the node at the head or (ick) NIL if the list
* is empty.
*
* Side Effects:
* The head node is removed from the list.
*
*-----------------------------------------------------------------------
*/
ClientData
Lst_DeQueue (l)
Lst l;
{
ClientData rd;
register ListNode tln;
tln = (ListNode) Lst_First (l);
if (tln == NilListNode) {
return ((ClientData) NIL);
}
rd = tln->datum;
if (Lst_Remove (l, (LstNode)tln) == FAILURE) {
return ((ClientData) NIL);
} else {
return (rd);
}
}

View File

@ -0,0 +1,98 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstDestroy.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstDestroy.c --
* Nuke a list and all its resources
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Destroy --
* Destroy a list and free all its resources. If the freeProc is
* given, it is called with the datum from each node in turn before
* the node is freed.
*
* Results:
* None.
*
* Side Effects:
* The given list is freed in its entirety.
*
*-----------------------------------------------------------------------
*/
void
Lst_Destroy (l, freeProc)
Lst l;
register void (*freeProc)();
{
register ListNode ln;
register ListNode tln = NilListNode;
register List list = (List)l;
if (l == NILLST || ! l) {
/*
* Note the check for l == (Lst)0 to catch uninitialized static Lst's.
* Gross, but useful.
*/
return;
}
if (freeProc) {
for (ln = list->firstPtr;
ln != NilListNode && tln != list->firstPtr;
ln = tln) {
tln = ln->nextPtr;
(*freeProc) (ln->datum);
free ((Address)ln);
}
} else {
for (ln = list->firstPtr;
ln != NilListNode && tln != list->firstPtr;
ln = tln) {
tln = ln->nextPtr;
free ((Address)ln);
}
}
free ((Address)l);
}

View File

@ -0,0 +1,98 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstDupl.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* listDupl.c --
* Duplicate a list. This includes duplicating the individual
* elements.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Duplicate --
* Duplicate an entire list. If a function to copy a ClientData is
* given, the individual client elements will be duplicated as well.
*
* Results:
* The new Lst structure or NILLST if failure.
*
* Side Effects:
* A new list is created.
*-----------------------------------------------------------------------
*/
Lst
Lst_Duplicate (l, copyProc)
Lst l; /* the list to duplicate */
ClientData (*copyProc)(); /* A function to duplicate each ClientData */
{
register Lst nl;
register ListNode ln;
register List list = (List)l;
if (!LstValid (l)) {
return (NILLST);
}
nl = Lst_Init (list->isCirc);
if (nl == NILLST) {
return (NILLST);
}
ln = list->firstPtr;
while (ln != NilListNode) {
if (copyProc != NOCOPY) {
if (Lst_AtEnd (nl, (*copyProc) (ln->datum)) == FAILURE) {
return (NILLST);
}
} else if (Lst_AtEnd (nl, ln->datum) == FAILURE) {
return (NILLST);
}
if (list->isCirc && ln == list->lastPtr) {
ln = NilListNode;
} else {
ln = ln->nextPtr;
}
}
return (nl);
}

View File

@ -0,0 +1,73 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstEnQueue.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstEnQueue.c--
* Treat the list as a queue and place a datum at its end
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_EnQueue --
* Add the datum to the tail of the given list.
*
* Results:
* SUCCESS or FAILURE as returned by Lst_Append.
*
* Side Effects:
* the lastPtr field is altered all the time and the firstPtr field
* will be altered if the list used to be empty.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_EnQueue (l, d)
Lst l;
ClientData d;
{
if (LstValid (l) == FALSE) {
return (FAILURE);
}
return (Lst_Append (l, Lst_Last(l), d));
}

View File

@ -0,0 +1,70 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstFind.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstFind.c --
* Find a node on a list.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Find --
* Find a node on the given list using the given comparison function
* and the given datum.
*
* Results:
* The found node or NILLNODE if none matches.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_Find (l, d, cProc)
Lst l;
ClientData d;
int (*cProc)();
{
return (Lst_FindFrom (l, Lst_First(l), d, cProc));
}

View File

@ -0,0 +1,94 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstFindFrom.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstFindFrom.c --
* Find a node on a list from a given starting point. Used by Lst_Find.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_FindFrom --
* Search for a node starting and ending with the given one on the
* given list using the passed datum and comparison function to
* determine when it has been found.
*
* Results:
* The found node or NILLNODE
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_FindFrom (l, ln, d, cProc)
Lst l;
register LstNode ln;
register ClientData d;
register int (*cProc)();
{
register ListNode tln;
Boolean found = FALSE;
if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
return (NILLNODE);
}
tln = (ListNode)ln;
do {
if ((*cProc) (tln->datum, d) == 0) {
found = TRUE;
break;
} else {
tln = tln->nextPtr;
}
} while (tln != (ListNode)ln && tln != NilListNode);
if (found) {
return ((LstNode)tln);
} else {
return (NILLNODE);
}
}

View File

@ -0,0 +1,71 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstFirst.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstFirst.c --
* Return the first node of a list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_First --
* Return the first node on the given list.
*
* Results:
* The first node or NILLNODE if the list is empty.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_First (l)
Lst l;
{
if (!LstValid (l) || LstIsEmpty (l)) {
return (NILLNODE);
} else {
return ((LstNode)((List)l)->firstPtr);
}
}

View File

@ -0,0 +1,72 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstForEach.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstForeach.c --
* Perform a given function on all elements of a list.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_ForEach --
* Apply the given function to each element of the given list. The
* function should return 0 if Lst_ForEach should continue and non-
* zero if it should abort.
*
* Results:
* None.
*
* Side Effects:
* Only those created by the passed-in function.
*
*-----------------------------------------------------------------------
*/
/*VARARGS2*/
void
Lst_ForEach (l, proc, d)
Lst l;
register int (*proc)();
register ClientData d;
{
Lst_ForEachFrom(l, Lst_First(l), proc, d);
}

View File

@ -0,0 +1,111 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstForEachFrom.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* lstForEachFrom.c --
* Perform a given function on all elements of a list starting from
* a given point.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_ForEachFrom --
* Apply the given function to each element of the given list. The
* function should return 0 if traversal should continue and non-
* zero if it should abort.
*
* Results:
* None.
*
* Side Effects:
* Only those created by the passed-in function.
*
*-----------------------------------------------------------------------
*/
/*VARARGS2*/
void
Lst_ForEachFrom (l, ln, proc, d)
Lst l;
LstNode ln;
register int (*proc)();
register ClientData d;
{
register ListNode tln = (ListNode)ln;
register List list = (List)l;
register ListNode next;
Boolean done;
int result;
if (!LstValid (list) || LstIsEmpty (list)) {
return;
}
do {
/*
* Take care of having the current element deleted out from under
* us.
*/
next = tln->nextPtr;
(void) tln->useCount++;
result = (*proc) (tln->datum, d);
(void) tln->useCount--;
/*
* We're done with the traversal if
* - nothing's been added after the current node and
* - the next node to examine is the first in the queue or
* doesn't exist.
*/
done = (next == tln->nextPtr &&
(next == NilListNode || next == list->firstPtr));
next = tln->nextPtr;
if (tln->flags & LN_DELETED) {
free((char *)tln);
}
tln = next;
} while (!result && !LstIsEmpty(list) && !done);
}

View File

@ -0,0 +1,76 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstInit.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* init.c --
* Initialize a new linked list.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Init --
* Create and initialize a new list.
*
* Results:
* The created list.
*
* Side Effects:
* A list is created, what else?
*
*-----------------------------------------------------------------------
*/
Lst
Lst_Init(circ)
Boolean circ; /* TRUE if the list should be made circular */
{
register List nList;
PAlloc (nList, List);
nList->firstPtr = NilListNode;
nList->lastPtr = NilListNode;
nList->isOpen = FALSE;
nList->isCirc = circ;
nList->atEnd = Unknown;
return ((Lst)nList);
}

View File

@ -0,0 +1,113 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstInsert.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstInsert.c --
* Insert a new datum before an old one
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Insert --
* Insert a new node with the given piece of data before the given
* node in the given list.
*
* Results:
* SUCCESS or FAILURE.
*
* Side Effects:
* the firstPtr field will be changed if ln is the first node in the
* list.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Insert (l, ln, d)
Lst l; /* list to manipulate */
LstNode ln; /* node before which to insert d */
ClientData d; /* datum to be inserted */
{
register ListNode nLNode; /* new lnode for d */
register ListNode lNode = (ListNode)ln;
register List list = (List)l;
/*
* check validity of arguments
*/
if (LstValid (l) && (LstIsEmpty (l) && ln == NILLNODE))
goto ok;
if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
return (FAILURE);
}
ok:
PAlloc (nLNode, ListNode);
nLNode->datum = d;
nLNode->useCount = nLNode->flags = 0;
if (ln == NILLNODE) {
if (list->isCirc) {
nLNode->prevPtr = nLNode->nextPtr = nLNode;
} else {
nLNode->prevPtr = nLNode->nextPtr = NilListNode;
}
list->firstPtr = list->lastPtr = nLNode;
} else {
nLNode->prevPtr = lNode->prevPtr;
nLNode->nextPtr = lNode;
if (nLNode->prevPtr != NilListNode) {
nLNode->prevPtr->nextPtr = nLNode;
}
lNode->prevPtr = nLNode;
if (lNode == list->firstPtr) {
list->firstPtr = nLNode;
}
}
return (SUCCESS);
}

View File

@ -0,0 +1,110 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)lstInt.h 8.1 (Berkeley) 6/6/93
*/
/*-
* lstInt.h --
* Internals for the list library
*/
#ifndef _LSTINT_H_
#define _LSTINT_H_
#include "lst.h"
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.
* node may not be deleted until count
* goes to 0 */
flags:8; /* Node status flags */
ClientData datum; /* datum associated with this element */
} *ListNode;
/*
* Flags required for synchronization
*/
#define LN_DELETED 0x0001 /* List node should be removed when done */
#define NilListNode ((ListNode)-1)
typedef enum {
Head, Middle, Tail, Unknown
} Where;
typedef struct {
ListNode firstPtr; /* first node in list */
ListNode lastPtr; /* last node in list */
Boolean isCirc; /* true if the list should be considered
* circular */
/*
* fields for sequential access
*/
Where atEnd; /* Where in the list the last access was */
Boolean isOpen; /* true if list has been Lst_Open'ed */
ListNode curPtr; /* current node, if open. NilListNode if
* *just* opened */
ListNode prevPtr; /* Previous node, if open. Used by
* Lst_Remove */
} *List;
#define NilList ((List)-1)
/*
* PAlloc (var, ptype) --
* Allocate a pointer-typedef structure 'ptype' into the variable 'var'
*/
#define PAlloc(var,ptype) var = (ptype) malloc (sizeof (*var))
/*
* LstValid (l) --
* Return TRUE if the list l is valid
*/
#define LstValid(l) (((Lst)l == NILLST) ? FALSE : TRUE)
/*
* LstNodeValid (ln, l) --
* Return TRUE if the LstNode ln is valid with respect to l
*/
#define LstNodeValid(ln, l) ((((LstNode)ln) == NILLNODE) ? FALSE : TRUE)
/*
* LstIsEmpty (l) --
* TRUE if the list l is empty.
*/
#define LstIsEmpty(l) (((List)l)->firstPtr == NilListNode)
#endif _LSTINT_H_

View File

@ -0,0 +1,81 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstIsAtEnd.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstIsAtEnd.c --
* Tell if the current node is at the end of the list.
* The sequential functions access the list in a slightly different way.
* CurPtr points to their idea of the current node in the list and they
* access the list based on it. Because the list is circular, Lst_Next
* and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
* used to determine when to stop.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_IsAtEnd --
* Return true if have reached the end of the given list.
*
* Results:
* TRUE if at the end of the list (this includes the list not being
* open or being invalid) or FALSE if not. We return TRUE if the list
* is invalid or unopend so as to cause the caller to exit its loop
* asap, the assumption being that the loop is of the form
* while (!Lst_IsAtEnd (l)) {
* ...
* }
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
Boolean
Lst_IsAtEnd (l)
Lst l;
{
register List list = (List) l;
return (!LstValid (l) || !list->isOpen ||
(list->atEnd == Head) || (list->atEnd == Tail));
}

View File

@ -0,0 +1,69 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstIsEmpty.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstIsEmpty.c --
* A single function to decide if a list is empty
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_IsEmpty --
* Return TRUE if the given list is empty.
*
* Results:
* TRUE if the list is empty, FALSE otherwise.
*
* Side Effects:
* None.
*
* A list is considered empty if its firstPtr == NilListNode (or if
* the list itself is NILLIST).
*-----------------------------------------------------------------------
*/
Boolean
Lst_IsEmpty (l)
Lst l;
{
return ( ! LstValid (l) || LstIsEmpty(l));
}

View File

@ -0,0 +1,71 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstLast.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstLast.c --
* Return the last element of a list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Last --
* Return the last node on the list l.
*
* Results:
* The requested node or NILLNODE if the list is empty.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_Last (l)
Lst l;
{
if (!LstValid(l) || LstIsEmpty (l)) {
return (NILLNODE);
} else {
return ((LstNode)((List)l)->lastPtr);
}
}

View File

@ -0,0 +1,69 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstMember.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* lstMember.c --
* See if a given datum is on a given list.
*/
#include "lstInt.h"
LstNode
Lst_Member (l, d)
Lst l;
ClientData d;
{
List list = (List) l;
register ListNode lNode;
lNode = list->firstPtr;
if (lNode == NilListNode) {
return NILLNODE;
}
do {
if (lNode->datum == d) {
return (LstNode)lNode;
}
lNode = lNode->nextPtr;
} while (lNode != NilListNode && lNode != list->firstPtr);
return NILLNODE;
}

View File

@ -0,0 +1,114 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstNext.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstNext.c --
* Return the next node for a list.
* The sequential functions access the list in a slightly different way.
* CurPtr points to their idea of the current node in the list and they
* access the list based on it. Because the list is circular, Lst_Next
* and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
* used to determine when to stop.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Next --
* Return the next node for the given list.
*
* Results:
* The next node or NILLNODE if the list has yet to be opened. Also
* if the list is non-circular and the end has been reached, NILLNODE
* is returned.
*
* Side Effects:
* the curPtr field is updated.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_Next (l)
Lst l;
{
register ListNode tln;
register List list = (List)l;
if ((LstValid (l) == FALSE) ||
(list->isOpen == FALSE)) {
return (NILLNODE);
}
list->prevPtr = list->curPtr;
if (list->curPtr == NilListNode) {
if (list->atEnd == Unknown) {
/*
* If we're just starting out, atEnd will be Unknown.
* Then we want to start this thing off in the right
* direction -- at the start with atEnd being Middle.
*/
list->curPtr = tln = list->firstPtr;
list->atEnd = Middle;
} else {
tln = NilListNode;
list->atEnd = Tail;
}
} else {
tln = list->curPtr->nextPtr;
list->curPtr = tln;
if (tln == list->firstPtr || tln == NilListNode) {
/*
* If back at the front, then we've hit the end...
*/
list->atEnd = Tail;
} else {
/*
* Reset to Middle if gone past first.
*/
list->atEnd = Middle;
}
}
return ((LstNode)tln);
}

View File

@ -0,0 +1,81 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstOpen.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstOpen.c --
* Open a list for sequential access. The sequential functions access the
* list in a slightly different way. CurPtr points to their idea of the
* current node in the list and they access the list based on it.
* If the list is circular, Lst_Next and Lst_Prev will go around
* the list forever. Lst_IsAtEnd must be used to determine when to stop.
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Open --
* Open a list for sequential access. A list can still be searched,
* etc., without confusing these functions.
*
* Results:
* SUCCESS or FAILURE.
*
* Side Effects:
* isOpen is set TRUE and curPtr is set to NilListNode so the
* other sequential functions no it was just opened and can choose
* the first element accessed based on this.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Open (l)
register Lst l;
{
if (LstValid (l) == FALSE) {
return (FAILURE);
}
((List) l)->isOpen = TRUE;
((List) l)->atEnd = LstIsEmpty (l) ? Head : Unknown;
((List) l)->curPtr = NilListNode;
return (SUCCESS);
}

View File

@ -0,0 +1,131 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstRemove.c --
* Remove an element from a list
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Remove --
* Remove the given node from the given list.
*
* Results:
* SUCCESS or FAILURE.
*
* Side Effects:
* The list's firstPtr will be set to NilListNode if ln is the last
* node on the list. firsPtr and lastPtr will be altered if ln is
* either the first or last node, respectively, on the list.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Remove (l, ln)
Lst l;
LstNode ln;
{
register List list = (List) l;
register ListNode lNode = (ListNode) ln;
if (!LstValid (l) ||
!LstNodeValid (ln, l)) {
return (FAILURE);
}
/*
* unlink it from the list
*/
if (lNode->nextPtr != NilListNode) {
lNode->nextPtr->prevPtr = lNode->prevPtr;
}
if (lNode->prevPtr != NilListNode) {
lNode->prevPtr->nextPtr = lNode->nextPtr;
}
/*
* if either the firstPtr or lastPtr of the list point to this node,
* adjust them accordingly
*/
if (list->firstPtr == lNode) {
list->firstPtr = lNode->nextPtr;
}
if (list->lastPtr == lNode) {
list->lastPtr = lNode->prevPtr;
}
/*
* Sequential access stuff. If the node we're removing is the current
* node in the list, reset the current node to the previous one. If the
* previous one was non-existent (prevPtr == NilListNode), we set the
* end to be Unknown, since it is.
*/
if (list->isOpen && (list->curPtr == lNode)) {
list->curPtr = list->prevPtr;
if (list->curPtr == NilListNode) {
list->atEnd = Unknown;
}
}
/*
* the only way firstPtr can still point to ln is if ln is the last
* node on the list (the list is circular, so lNode->nextptr == lNode in
* this case). The list is, therefore, empty and is marked as such
*/
if (list->firstPtr == lNode) {
list->firstPtr = NilListNode;
}
/*
* note that the datum is unmolested. The caller must free it as
* necessary and as expected.
*/
if (lNode->useCount == 0) {
free ((Address)ln);
} else {
lNode->flags |= LN_DELETED;
}
return (SUCCESS);
}

View File

@ -0,0 +1,73 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstReplace.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstReplace.c --
* Replace the datum in a node with a new datum
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Replace --
* Replace the datum in the given node with the new datum
*
* Results:
* SUCCESS or FAILURE.
*
* Side Effects:
* The datum field fo the node is altered.
*
*-----------------------------------------------------------------------
*/
ReturnStatus
Lst_Replace (ln, d)
register LstNode ln;
ClientData d;
{
if (ln == NILLNODE) {
return (FAILURE);
} else {
((ListNode) ln)->datum = d;
return (SUCCESS);
}
}

View File

@ -0,0 +1,73 @@
/*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* LstSucc.c --
* return the successor to a given node
*/
#include "lstInt.h"
/*-
*-----------------------------------------------------------------------
* Lst_Succ --
* Return the sucessor to the given node on its list.
*
* Results:
* The successor 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
* successor).
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
LstNode
Lst_Succ (ln)
LstNode ln;
{
if (ln == NILLNODE) {
return (NILLNODE);
} else {
return ((LstNode) ((ListNode) ln)->nextPtr);
}
}

911
usr.bin/make/main.c Normal file
View File

@ -0,0 +1,911 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
#endif /* not lint */
/*-
* main.c --
* The main file for this entire program. Exit routines etc
* reside here.
*
* Utility functions defined in this file:
* Main_ParseArgLine Takes a line of arguments, breaks them and
* treats them as if they were given when first
* invoked. Used by the parse module to implement
* the .MFLAGS target.
*
* Error Print a tagged error message. The global
* MAKE variable must have been defined. This
* takes a format string and two optional
* arguments for it.
*
* Fatal Print an error message and exit. Also takes
* a format string and two arguments.
*
* Punt Aborts all jobs and exits with a message. Also
* takes a format string and two arguments.
*
* Finish Finish things up by printing the number of
* errors which occured, as passed to it, and
* exiting.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "make.h"
#include "hash.h"
#include "dir.h"
#include "job.h"
#include "pathnames.h"
#ifndef DEFMAXLOCAL
#define DEFMAXLOCAL DEFMAXJOBS
#endif DEFMAXLOCAL
#define MAKEFLAGS ".MAKEFLAGS"
Lst create; /* Targets to be made */
time_t now; /* Time at start of make */
GNode *DEFAULT; /* .DEFAULT node */
Boolean allPrecious; /* .PRECIOUS given on line by itself */
static Boolean noBuiltins; /* -r flag */
static Lst makefiles; /* ordered list of makefiles to read */
int maxJobs; /* -J argument */
static int maxLocal; /* -L argument */
Boolean compatMake; /* -B argument */
Boolean debug; /* -d flag */
Boolean noExecute; /* -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 */
static Boolean jobsRunning; /* TRUE if the jobs might be running */
static Boolean ReadMakefile();
static void usage();
static char *curdir; /* startup directory */
static char *objdir; /* where we chdir'ed to */
/*-
* MainParseArgs --
* Parse a given argument vector. Called from main() and from
* Main_ParseArgLine() when the .MAKEFLAGS target is used.
*
* XXX: Deal with command line overriding .MAKEFLAGS in makefile
*
* Results:
* None
*
* Side Effects:
* Various global and local flags will be set depending on the flags
* given
*/
static void
MainParseArgs(argc, argv)
int argc;
char **argv;
{
extern int optind;
extern char *optarg;
char c;
optind = 1; /* since we're called more than once */
#ifdef notyet
# define OPTFLAGS "BD:I:L:PSd:ef:ij:knqrst"
#else
# define OPTFLAGS "D:I:d:ef:ij:knqrst"
#endif
rearg: while ((c = getopt(argc, argv, OPTFLAGS)) != EOF) {
switch(c) {
case 'D':
Var_Set(optarg, "1", VAR_GLOBAL);
Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
break;
case 'I':
Parse_AddIncludeDir(optarg);
Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
break;
#ifdef notyet
case 'B':
compatMake = TRUE;
break;
case 'L':
maxLocal = atoi(optarg);
Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);
Var_Append(MAKEFLAGS, optarg, 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;
#endif
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 'f':
debug |= DEBUG_FOR;
break;
case 'g':
if (modules[1] == '1') {
debug |= DEBUG_GRAPH1;
++modules;
}
else if (modules[1] == '2') {
debug |= DEBUG_GRAPH2;
++modules;
}
break;
case 'j':
debug |= DEBUG_JOB;
break;
case 'm':
debug |= DEBUG_MAKE;
break;
case 's':
debug |= DEBUG_SUFF;
break;
case 't':
debug |= DEBUG_TARG;
break;
case 'v':
debug |= DEBUG_VAR;
break;
default:
(void)fprintf(stderr,
"make: illegal argument to d option -- %c\n",
*modules);
usage();
}
Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
break;
}
case 'e':
checkEnvFirst = TRUE;
Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
break;
case 'f':
(void)Lst_AtEnd(makefiles, (ClientData)optarg);
break;
case 'i':
ignoreErrors = TRUE;
Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
break;
case 'j':
maxJobs = atoi(optarg);
Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
break;
case 'k':
keepgoing = TRUE;
Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
break;
case 'n':
noExecute = TRUE;
Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
break;
case 'q':
queryFlag = TRUE;
/* Kind of nonsensical, wot? */
Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
break;
case 'r':
noBuiltins = TRUE;
Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
break;
case 's':
beSilent = TRUE;
Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
break;
case 't':
touchFlag = TRUE;
Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
break;
default:
case '?':
usage();
}
}
oldVars = TRUE;
/*
* See if the rest of the arguments are variable assignments and
* perform them if so. Else take them to be targets and stuff them
* on the end of the "create" list.
*/
for (argv += optind, argc -= optind; *argv; ++argv, --argc)
if (Parse_IsVar(*argv))
Parse_DoVar(*argv, VAR_CMD);
else {
if (!**argv)
Punt("illegal (null) argument.");
if (**argv == '-') {
if ((*argv)[1])
optind = 0; /* -flag... */
else
optind = 1; /* - */
goto rearg;
}
(void)Lst_AtEnd(create, (ClientData)*argv);
}
}
/*-
* Main_ParseArgLine --
* Used by the parse module when a .MFLAGS or .MAKEFLAGS target
* is encountered and by main() when reading the .MAKEFLAGS envariable.
* Takes a line of arguments and breaks it into its
* component words and passes those words and the number of them to the
* MainParseArgs function.
* The line should have all its leading whitespace removed.
*
* Results:
* None
*
* Side Effects:
* Only those that come from the various arguments.
*/
void
Main_ParseArgLine(line)
char *line; /* Line to fracture */
{
char **argv; /* Manufactured argument vector */
int argc; /* Number of arguments in argv */
if (line == NULL)
return;
for (; *line == ' '; ++line)
continue;
if (!*line)
return;
argv = brk_string(line, &argc);
MainParseArgs(argc, argv);
}
/*-
* main --
* The main function, for obvious reasons. Initializes variables
* and a few modules, then parses the arguments give it in the
* environment and on the command line. Reads the system makefile
* followed by either Makefile, makefile or the file given by the
* -f argument. Sets the .MAKEFLAGS PMake variable based on all the
* flags it has received by then uses either the Make or the Compat
* module to create the initial list of targets.
*
* Results:
* If -q was given, exits -1 if anything was out-of-date. Else it exits
* 0.
*
* Side Effects:
* The program exits when done. Targets are created. etc. etc. etc.
*/
int
main(argc, argv)
int argc;
char **argv;
{
Lst targs; /* target nodes to create -- passed to Make_Init */
Boolean outOfDate = TRUE; /* FALSE if all targets up to date */
struct stat sb, sa;
char *p, *path, *pwd, *getenv(), *getwd();
char mdpath[MAXPATHLEN + 1];
char obpath[MAXPATHLEN + 1];
char cdpath[MAXPATHLEN + 1];
/*
* Find where we are and take care of PWD for the automounter...
* All this code is so that we know where we are when we start up
* on a different machine with pmake.
*/
curdir = cdpath;
if (getwd(curdir) == NULL) {
(void)fprintf(stderr, "make: %s.\n", curdir);
exit(2);
}
if (stat(curdir, &sa) == -1) {
(void)fprintf(stderr, "make: %s: %s.\n",
curdir, strerror(errno));
exit(2);
}
if ((pwd = getenv("PWD")) != NULL) {
if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino &&
sa.st_dev == sb.st_dev)
(void) strcpy(curdir, pwd);
}
/*
* if the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory
* exists, change into it and build there. Once things are
* initted, have to add the original directory to the search path,
* and modify the paths for the Makefiles apropriately. The
* current directory is also placed as a variable for make scripts.
*/
if (!(path = getenv("MAKEOBJDIR"))) {
path = _PATH_OBJDIR;
(void) sprintf(mdpath, "%s.%s", path, MACHINE);
}
else
(void) strncpy(mdpath, path, MAXPATHLEN + 1);
if (stat(mdpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
if (chdir(mdpath)) {
(void)fprintf(stderr, "make warning: %s: %s.\n",
mdpath, strerror(errno));
objdir = curdir;
}
else {
if (mdpath[0] != '/') {
(void) sprintf(obpath, "%s/%s", curdir, mdpath);
objdir = obpath;
}
else
objdir = mdpath;
}
}
else {
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
if (chdir(path)) {
(void)fprintf(stderr, "make warning: %s: %s.\n",
path, strerror(errno));
objdir = curdir;
}
else {
if (path[0] != '/') {
(void) sprintf(obpath, "%s/%s", curdir,
path);
objdir = obpath;
}
else
objdir = obpath;
}
}
else
objdir = curdir;
}
setenv("PWD", objdir, 1);
create = Lst_Init(FALSE);
makefiles = Lst_Init(FALSE);
beSilent = FALSE; /* Print commands as executed */
ignoreErrors = FALSE; /* Pay attention to non-zero returns */
noExecute = FALSE; /* Execute all commands */
keepgoing = FALSE; /* Stop on error */
allPrecious = FALSE; /* Remove targets when interrupted */
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;
maxJobs = DEFMAXJOBS; /* Set default max concurrency */
maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */
#ifdef notyet
compatMake = FALSE; /* No compat mode */
#else
compatMake = TRUE; /* No compat mode */
#endif
/*
* Initialize the parsing, directory and variable modules to prepare
* for the reading of inclusion paths and variable settings on the
* command line
*/
Dir_Init(); /* Initialize directory structures so -I flags
* can be processed correctly */
Parse_Init(); /* Need to initialize the paths of #include
* directories */
Var_Init(); /* As well as the lists of variables for
* parsing arguments */
if (objdir != curdir)
Dir_AddDir(dirSearchPath, curdir);
Var_Set(".CURDIR", curdir, VAR_GLOBAL);
Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
/*
* Initialize various variables.
* MAKE also gets this name, for compatibility
* .MAKEFLAGS gets set to the empty string just in case.
* MFLAGS also gets initialized empty, for compatibility.
*/
Var_Set("MAKE", argv[0], VAR_GLOBAL);
Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
Var_Set("MFLAGS", "", VAR_GLOBAL);
#ifdef MACHINE
Var_Set("MACHINE", MACHINE, VAR_GLOBAL);
#endif
#ifdef MACHINE_ARCH
Var_Set("MACHINE_ARCH", MACHINE_ARCH, VAR_GLOBAL);
#endif
/*
* 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).
*/
#ifdef POSIX
Main_ParseArgLine(getenv("MAKEFLAGS"));
#else
Main_ParseArgLine(getenv("MAKE"));
#endif
MainParseArgs(argc, argv);
/*
* Initialize archive, target and suffix modules in preparation for
* parsing the makefile(s)
*/
Arch_Init();
Targ_Init();
Suff_Init();
DEFAULT = NILGNODE;
(void)time(&now);
/*
* Set up the .TARGETS variable to contain the list of targets to be
* created. If none specified, make the variable empty -- the parser
* will fill the thing in with the default or .MAIN target.
*/
if (!Lst_IsEmpty(create)) {
LstNode ln;
for (ln = Lst_First(create); ln != NILLNODE;
ln = Lst_Succ(ln)) {
char *name = (char *)Lst_Datum(ln);
Var_Append(".TARGETS", name, VAR_GLOBAL);
}
} else
Var_Set(".TARGETS", "", VAR_GLOBAL);
/*
* Read in the built-in rules first, followed by the specified makefile,
* if it was (makefile != (char *) NULL), or the default Makefile and
* makefile, in that order, if it wasn't.
*/
if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK))
Fatal("make: no system rules (%s).", _PATH_DEFSYSMK);
if (!Lst_IsEmpty(makefiles)) {
LstNode ln;
ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);
if (ln != NILLNODE)
Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
} else if (!ReadMakefile("makefile"))
(void)ReadMakefile("Makefile");
(void)ReadMakefile(".depend");
Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL), VAR_GLOBAL);
/* Install all the flags into the MAKE envariable. */
if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL)) != NULL) && *p)
#ifdef POSIX
setenv("MAKEFLAGS", p, 1);
#else
setenv("MAKE", p, 1);
#endif
/*
* For compatibility, look at the directories in the VPATH variable
* and add them to the search path, if the variable is defined. The
* variable's value is in the same format as the PATH envariable, i.e.
* <directory>:<directory>:<directory>...
*/
if (Var_Exists("VPATH", VAR_CMD)) {
char *vpath, *path, *cp, savec;
/*
* GCC stores string constants in read-only memory, but
* Var_Subst will want to write this thing, so store it
* in an array
*/
static char VPATH[] = "${VPATH}";
vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE);
path = vpath;
do {
/* skip to end of directory */
for (cp = path; *cp != ':' && *cp != '\0'; cp++)
continue;
/* Save terminator character so know when to stop */
savec = *cp;
*cp = '\0';
/* Add directory to search path */
Dir_AddDir(dirSearchPath, path);
*cp = savec;
path = cp + 1;
} while (savec == ':');
(void)free((Address)vpath);
}
/*
* Now that all search paths have been read for suffixes et al, it's
* time to add the default search path to their lists...
*/
Suff_DoPaths();
/* print the initial graph, if the user requested it */
if (DEBUG(GRAPH1))
Targ_PrintGraph(1);
/*
* 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);
/*
* this was original amMake -- want to allow parallelism, so put this
* back in, eventually.
*/
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) {
if (maxLocal == -1)
maxLocal = maxJobs;
Job_Init(maxJobs, maxLocal);
jobsRunning = TRUE;
}
/* 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);
/* print the graph now it's been processed if the user requested it */
if (DEBUG(GRAPH2))
Targ_PrintGraph(2);
if (queryFlag && outOfDate)
return(1);
else
return(0);
}
/*-
* ReadMakefile --
* Open and parse the given makefile.
*
* Results:
* TRUE if ok. FALSE if couldn't open file.
*
* Side Effects:
* lots
*/
static Boolean
ReadMakefile(fname)
char *fname; /* makefile to read */
{
extern Lst parseIncPath, sysIncPath;
FILE *stream;
char *name, path[MAXPATHLEN + 1];
if (!strcmp(fname, "-")) {
Parse_File("(stdin)", stdin);
Var_Set("MAKEFILE", "", VAR_GLOBAL);
} else {
if ((stream = fopen(fname, "r")) != NULL)
goto found;
/* if we've chdir'd, rebuild the path name */
if (curdir != objdir && *fname != '/') {
(void)sprintf(path, "%s/%s", curdir, fname);
if ((stream = fopen(path, "r")) != NULL) {
fname = path;
goto found;
}
}
/* look in -I and system include directories. */
name = Dir_FindFile(fname, parseIncPath);
if (!name)
name = Dir_FindFile(fname, sysIncPath);
if (!name || !(stream = fopen(name, "r")))
return(FALSE);
fname = name;
/*
* set the MAKEFILE variable desired by System V fans -- the
* placement of the setting here means it gets set to the last
* makefile specified, as it is set by SysV make.
*/
found: Var_Set("MAKEFILE", fname, VAR_GLOBAL);
Parse_File(fname, stream);
(void)fclose(stream);
}
return(TRUE);
}
/*-
* Error --
* Print an error message given its format.
*
* Results:
* None.
*
* Side Effects:
* The message is printed.
*/
/* VARARGS */
void
#if __STDC__
Error(const char *fmt, ...)
#else
Error(va_alist)
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
char *fmt;
va_start(ap);
fmt = va_arg(ap, char *);
#endif
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
}
/*-
* Fatal --
* Produce a Fatal error message. If jobs are running, waits for them
* to finish.
*
* Results:
* None
*
* Side Effects:
* The program exits
*/
/* VARARGS */
void
#if __STDC__
Fatal(const char *fmt, ...)
#else
Fatal(va_alist)
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
char *fmt;
va_start(ap);
fmt = va_arg(ap, char *);
#endif
if (jobsRunning)
Job_Wait();
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
if (DEBUG(GRAPH2))
Targ_PrintGraph(2);
exit(2); /* Not 1 so -q can distinguish error */
}
/*
* Punt --
* Major exception once jobs are being created. Kills all jobs, prints
* a message and exits.
*
* Results:
* None
*
* Side Effects:
* All children are killed indiscriminately and the program Lib_Exits
*/
/* VARARGS */
void
#if __STDC__
Punt(const char *fmt, ...)
#else
Punt(va_alist)
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
char *fmt;
va_start(ap);
fmt = va_arg(ap, char *);
#endif
(void)fprintf(stderr, "make: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
DieHorribly();
}
/*-
* DieHorribly --
* Exit without giving a message.
*
* Results:
* None
*
* Side Effects:
* A big one...
*/
void
DieHorribly()
{
if (jobsRunning)
Job_AbortAll();
if (DEBUG(GRAPH2))
Targ_PrintGraph(2);
exit(2); /* Not 1, so -q can distinguish error */
}
/*
* Finish --
* Called when aborting due to errors in child shell to signal
* abnormal exit.
*
* Results:
* None
*
* Side Effects:
* The program exits
*/
void
Finish(errors)
int errors; /* number of errors encountered in Make_Make */
{
Fatal("%d error%s", errors, errors == 1 ? "" : "s");
}
/*
* emalloc --
* malloc, but die on error.
*/
char *
emalloc(len)
u_int len;
{
char *p;
if (!(p = malloc(len)))
enomem();
return(p);
}
/*
* enomem --
* die when out of memory.
*/
void
enomem()
{
(void)fprintf(stderr, "make: %s.\n", strerror(errno));
exit(2);
}
/*
* usage --
* exit with usage message
*/
static void
usage()
{
(void)fprintf(stderr,
"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile ]\n\
[-I directory] [-j max_jobs] [variable=value]\n");
exit(2);
}

883
usr.bin/make/make.1 Normal file
View File

@ -0,0 +1,883 @@
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. 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.
.\"
.\" @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
.Dd March 19, 1994
.Dt MAKE 1
.Os
.Sh NAME
.Nm make
.Nd maintain program dependencies
.Sh SYNOPSIS
.Nm make
.Op Fl eiknqrstv
.Op Fl D Ar variable
.Op Fl d Ar flags
.Op Fl f Ar makefile
.Op Fl I Ar directory
.Bk -words
.Op Fl j Ar max_jobs
.Ek
.Op Ar variable=value
.Op Ar target ...
.Sh DESCRIPTION
.Nm Make
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
.Ql Pa makefile
exists, it is read for this list of specifications.
If it does not exist, the file
.Ql Pa Makefile
is read.
If the file
.Ql Pa .depend
exists, it is read (see
.Xr mkdep 1) .
.Pp
This manual page is intended as a reference document only.
For a more thorough description of
.Nm make
and makefiles, please refer to
.%T "Make \- A Tutorial" .
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl D Ar variable
Define Ar variable
to be 1, in the global context.
.It Fl d Ar flags
Turn on debugging, and specify which portions of
.Nm make
are to print debugging information.
.Ar Flags
is one or more of the following:
.Bl -tag -width Ds
.It Ar A
Print all possible debugging information;
equivalent to specifying all of the debugging flags.
.It Ar a
Print debugging information about archive searching and caching.
.It Ar c
Print debugging information about conditional evaluation.
.It Ar d
Print debugging information about directory searching and caching.
.It Ar "g1"
Print the input graph before making anything.
.It Ar "g2"
Print the input graph after making everything, or before exiting
on error.
.It Ar j
Print debugging information about running multiple shells.
.It Ar m
Print debugging information about making targets, including modification
dates.
.It Ar s
Print debugging information about suffix-transformation rules.
.It Ar t
Print debugging information about target list maintenance.
.It Ar v
Print debugging information about variable assignment.
.El
.It Fl e
Specify that environmental variables override macro assignments within
makefiles.
.It Fl f Ar makefile
Specify a makefile to read instead of the default
.Ql Pa makefile
and
.Ql Pa Makefile .
If
.Ar makefile
is
.Ql Fl ,
standard input is read.
Multiple makefile's may be specified, and are read in the order specified.
.It Fl I Ar directory
Specify a directory in which to search for makefiles and included makefiles.
The system makefile directory is automatically included as part of this
list.
.It Fl i
Ignore non-zero exit of shell commands in the makefile.
Equivalent to specifying
.Ql Fl
before each command line in the makefile.
.It Fl j Ar max_jobs
Specify the maximum number of jobs that
.Nm make
may have running at any one time.
.It Fl k
Continue processing after errors are encountered, but only on those targets
that do not depend on the target whose creation caused the error.
.It Fl n
Display the commands that would have been executed, but do not actually
execute them.
.It Fl q
Do not execute any commands, but exit 0 if the specified targets are
up-to-date and 1, otherwise.
.It Fl r
Do not use the built-in rules specified in the system makefile.
.It Fl s
Do not echo any commands as they are executed.
Equivalent to specifying
.Ql Ic @
before each command line in the makefile.
.It Fl t
Rather than re-building a target as specified in the makefile, create it
or update its modification time to make it appear up-to-date.
.It Ar variable=value
Set the value of the variable
.Ar variable
to
.Ar value .
.El
.Pp
There are seven different types of lines in a makefile: file dependency
specifications, shell commands, variable assignments, include statements,
conditional directives, for loops, and comments.
.Pp
In general, lines may be continued from one line to the next by ending
them with a backslash
.Pq Ql \e .
The trailing newline character and initial whitespace on the following
line are compressed into a single space.
.Sh FILE DEPENDENCY SPECIFICATIONS
Dependency lines consist of one or more targets, an operator, and zero
or more sources.
This creates a relationship where the targets ``depend'' on the sources
and are usually created from them.
The exact relationship between the target and the source is determined
by the operator that separates them.
The three operators are as follows:
.Bl -tag -width flag
.It Ic \&:
A target is considered out-of-date if its modification time is less than
those of any of its sources.
Sources for a target accumulate over dependency lines when this operator
is used.
The target is removed if
.Nm make
is interrupted.
.It Ic \&!
Targets are always re-created, but not until all sources have been
examined and re-created as necessary.
Sources for a target accumulate over dependency lines when this operator
is used.
The target is removed if
.Nm make
is interrupted.
.It Ic \&::
If no sources are specified, the target is always re-created.
Otherwise, a target is considered out-of-date if any of its sources has
been modified more recently than the target.
Sources for a target do not accumulate over dependency lines when this
operator is used.
The target will not be removed if
.Nm make
is interrupted.
.El
.Pp
Targets and sources may contain the shell wildcard values
.Ql ? ,
.Ql * ,
.Ql []
and
.Ql {} .
The values
.Ql ? ,
.Ql *
and
.Ql []
may only be used as part of the final
component of the target or source, and must be used to describe existing
files.
The value
.Ql {}
need not necessarily be used to describe existing files.
Expansion is in directory order, not alphabetically as done in the shell.
.Sh SHELL COMMANDS
Each target may have associated with it a series of shell commands, normally
used to create the target.
Each of the commands in this script
.Em must
be preceded by a tab.
While any target may appear on a dependency line, only one of these
dependencies may be followed by a creation script, unless the
.Ql Ic ::
operator is used.
.Pp
If the first or first two characters of the command line are
.Ql Ic @
and/or
.Ql Ic \- ,
the command is treated specially.
A
.Ql Ic @
causes the command not to be echoed before it is executed.
A
.Ql Ic \-
causes any non-zero exit status of the command line to be ignored.
.Sh VARIABLE ASSIGNMENTS
Variables in make are much like variables in the shell, and, by tradition,
consist of all upper-case letters.
The five operators that can be used to assign values to variables are as
follows:
.Bl -tag -width Ds
.It Ic \&=
Assign the value to the variable.
Any previous value is overridden.
.It Ic \&+=
Append the value to the current value of the variable.
.It Ic \&?=
Assign the value to the variable if it is not already defined.
.It Ic \&:=
Assign with expansion, i.e. expand the value before assigning it
to the variable.
Normally, expansion is not done until the variable is referenced.
.It Ic \&!=
Expand the value and pass it to the shell for execution and assign
the result to the variable.
Any newlines in the result are replaced with spaces.
.El
.Pp
Any white-space before the assigned
.Ar value
is removed; if the value is being appended, a single space is inserted
between the previous contents of the variable and the appended value.
.Pp
Variables are expanded by surrounding the variable name with either
curly braces
.Pq Ql {}
or parenthesis
.Pq Ql ()
and preceding it with
a dollar sign
.Pq Ql \&$ .
If the variable name contains only a single letter, the surrounding
braces or parenthesis are not required.
This shorter form is not recommended.
.Pp
Variable substitution occurs at two distinct times, depending on where
the variable is being used.
Variables in dependency lines are expanded as the line is read.
Variables in shell commands are expanded when the shell command is
executed.
.Pp
The four different classes of variables (in order of increasing precedence)
are:
.Bl -tag -width Ds
.It Environment variables
Variables defined as part of
.Nm make Ns 's
environment.
.It Global variables
Variables defined in the makefile or in included makefiles.
.It Command line variables
Variables defined as part of the command line.
.It Local variables
Variables that are defined specific to a certain target.
The seven local variables are as follows:
.Bl -tag -width ".ARCHIVE"
.It Va .ALLSRC
The list of all sources for this target; also known as
.Ql Va \&> .
.It Va .ARCHIVE
The name of the archive file.
.It Va .IMPSRC
The name/path of the source from which the target is to be transformed
(the ``implied'' source); also known as
.Ql Va \&< .
.It Va .MEMBER
The name of the archive member.
.It Va .OODATE
The list of sources for this target that were deemed out-of-date; also
known as
.Ql Va \&? .
.It Va .PREFIX
The file prefix of the file, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
.It Va .TARGET
The name of the target; also known as
.Ql Va @ .
.El
.Pp
The shorter forms
.Ql Va @ ,
.Ql Va ? ,
.Ql Va \&>
and
.Ql Va *
are permitted for backward
compatibility with historical makefiles and are not recommended.
The six variables
.Ql Va "@F" ,
.Ql Va "@D" ,
.Ql Va "<F" ,
.Ql Va "<D" ,
.Ql Va "*F"
and
.Ql Va "*D"
are
permitted for compatibility with
.At V
makefiles and are not recommended.
.Pp
Four of the local variables may be used in sources on dependency lines
because they expand to the proper value for each target on the line.
These variables are
.Ql Va .TARGET ,
.Ql Va .PREFIX ,
.Ql Va .ARCHIVE ,
and
.Ql Va .MEMBER .
.Pp
In addition,
.Nm make
sets or knows about the following variables:
.Bl -tag -width MAKEFLAGS
.It Va \&$
A single dollar sign
.Ql \&$ ,
i.e.
.Ql \&$$
expands to a single dollar
sign.
.It Va .MAKE
The name that
.Nm make
was executed with
.Pq Va argv Op 0
.It Va .CURDIR
A path to the directory where
.Nm make
was executed.
.It Va .OBJDIR
A path to the directory where the targets are built.
.It Ev MAKEFLAGS
The environment variable
.Ql Ev MAKEFLAGS
may contain anything that
may be specified on
.Nm make Ns 's
command line.
Anything specified on
.Nm make Ns 's
command line is appended to the
.Ql Ev MAKEFLAGS
variable which is then
entered into the environment for all programs which
.Nm make
executes.
.El
.Pp
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[:...]]}
.Pp
Each modifier begins with a colon and one of the following
special characters.
The colon may be escaped with a backslash
.Pq Ql \e .
.Bl -tag -width Cm E\&
.It Cm E
Replaces each word in the variable with its suffix.
.It Cm H
Replaces each word in the variable with everything but the last component.
.It Cm M Ns Ar pattern
Select only those words that match the rest of the modifier.
The standard shell wildcard characters
.Pf ( Ql * ,
.Ql ? ,
and
.Ql Op )
may
be used.
The wildcard characters may be escaped with a backslash
.Pq Ql \e .
.It Cm N Ns Ar pattern
This is identical to
.Ql Cm M ,
but selects all words which do not match
the rest of the modifier.
.It Cm R
Replaces each word in the variable with everything but its suffix.
.Sm off
.It Cm S No \&/ Ar old_pattern Xo
.No \&/ Ar new_pattern
.No \&/ Op Cm g
.Xc
.Sm on
Modify the first occurrence of
.Ar old_pattern
in each word to be replaced with
.Ar new_pattern .
If a
.Ql g
is appended to the last slash of the pattern, all occurrences
in each word are replaced.
If
.Ar old_pattern
begins with a carat
.Pq Ql ^ ,
.Ar old_pattern
is anchored at the beginning of each word.
If
.Ar old_pattern
ends with a dollar sign
.Pq Ql \&$ ,
it is anchored at the end of each word.
Inside
.Ar new_string ,
an ampersand
.Pq Ql &
is replaced by
.Ar old_pattern .
Any character may be used as a delimiter for the parts of the modifier
string.
The anchoring, ampersand and delimiter characters may be escaped with a
backslash
.Pq Ql \e .
.Pp
Variable expansion occurs in the normal fashion inside both
.Ar old_string
and
.Ar new_string
with the single exception that a backslash is used to prevent the expansion
of a dollar sign
.Pq Ql \&$
not a preceding dollar sign as is usual.
.It Cm T
Replaces each word in the variable with its last component.
.It Ar old_string=new_string
This is the
.At V
style variable substitution.
It must be the last modifier specified.
If
.Ar old_string
or
.Ar new_string
do not contain the pattern matching character
.Ar %
then it is assumed that they are
anchored at the end of each word, so only suffixes or entire
words may be replaced. Otherwise
.Ar %
is the substring of
.Ar old_string
to be replaced in
.Ar new_string
.El
.Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS
Makefile inclusion, conditional structures and for loops reminiscent
of the C programming language are provided in
.Nm make .
All such structures are identified by a line beginning with a single
dot
.Pq Ql \&.
character.
Files are included with either
.Ql .include <file>
or
.Ql .include \*qfile\*q .
Variables between the angle brackets or double quotes are expanded
to form the file name.
If angle brackets are used, the included makefile is expected to be in
the system makefile directory.
If double quotes are used, the including makefile's directory and any
directories specified using the
.Fl I
option are searched before the system
makefile directory.
.Pp
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 .undef Ar variable
Un-define the specified global variable.
Only global variables may be un-defined.
.It Xo
.Ic \&.if
.Oo \&! Oc Ns Ar expression
.Op Ar operator expression ...
.Xc
Test the value of an expression.
.It Xo
.Ic .ifdef
.Oo \&! Oc Ns Ar variable
.Op Ar operator variable ...
.Xc
Test the value of a variable.
.It Xo
.Ic .ifndef
.Oo \&! Oc Ns Ar variable
.Op Ar operator variable ...
.Xc
Test the value of a variable.
.It Xo
.Ic .ifmake
.Oo \&! Oc Ns Ar target
.Op Ar operator target ...
.Xc
Test the the target being built.
.It Xo
.Ic .ifnmake
.Oo \&! Oc Ar target
.Op Ar operator target ...
.Xc
Test the target being built.
.It Ic .else
Reverse the sense of the last conditional.
.It Xo
.Ic .elif
.Oo \&! Oc Ar expression
.Op Ar operator expression ...
.Xc
A combination of
.Ql Ic .else
followed by
.Ql Ic .if .
.It Xo
.Ic .elifdef
.Oo \&! Oc Ns Ar variable
.Op Ar operator variable ...
.Xc
A combination of
.Ql Ic .else
followed by
.Ql Ic .ifdef .
.It Xo
.Ic .elifndef
.Oo \&! Oc Ns Ar variable
.Op Ar operator variable ...
.Xc
A combination of
.Ql Ic .else
followed by
.Ql Ic .ifndef .
.It Xo
.Ic .elifmake
.Oo \&! Oc Ns Ar target
.Op Ar operator target ...
.Xc
A combination of
.Ql Ic .else
followed by
.Ql Ic .ifmake .
.It Xo
.Ic .elifnmake
.Oo \&! Oc Ns Ar target
.Op Ar operator target ...
.Xc
A combination of
.Ql Ic .else
followed by
.Ql Ic .ifnmake .
.It Ic .endif
End the body of the conditional.
.El
.Pp
The
.Ar operator
may be any one of the following:
.Bl -tag -width "Cm XX"
.It Cm \&|\&|
logical OR
.It Cm \&&&
Logical
.Tn AND ;
of higher precedence than
.Dq .
.El
.Pp
As in C,
.Nm make
will only evaluate a conditional as far as is necessary to determine
its value.
Parentheses may be used to change the order of evaluation.
The boolean operator
.Ql Ic \&!
may be used to logically negate an entire
conditional.
It is of higher precedence than
.Ql Ic \&&& .
.Pp
The value of
.Ar expression
may be any of the following:
.Bl -tag -width Ic defined
.It Ic defined
Takes a variable name as an argument and evaluates to true if the variable
has been defined.
.It Ic make
Takes a target name as an argument and evaluates to true if the target
was specified as part of
.Nm make Ns 's
command line or was declared the default target (either implicitly or
explicitly, see
.Va .MAIN )
before the line containing the conditional.
.It Ic empty
Takes a variable, with possible modifiers, and evaluates to true if
the expansion of the variable would result in an empty string.
.It Ic exists
Takes a file name as an argument and evaluates to true if the file exists.
The file is searched for on the system search path (see
.Va .PATH ) .
.It Ic target
Takes a target name as an argument and evaluates to true if the target
has been defined.
.El
.Pp
.Ar Expression
may also be an arithmetic or string comparison. Variable expansion is
performed on both sides of the comparison, after which the integral
values are compared. A value is interpreted as hexadecimal if it is
preceded by 0x, otherwise it is decimal; octal numbers are not supported.
The standard C relational operators are all supported. If after
variable expansion, either the left or right hand side of a
.Ql Ic ==
or
.Ql Ic "!="
operator is not an integral value, then
string comparison is performed between the expanded
variables.
If no relational operator is given, it is assumed that the expanded
variable is being compared against 0.
.Pp
When
.Nm make
is evaluating one of these conditional expression, and it encounters
a word it doesn't recognize, either the ``make'' or ``defined''
expression is applied to it, depending on the form of the conditional.
If the form is
.Ql Ic .ifdef
or
.Ql Ic .ifndef ,
the ``defined'' expression
is applied.
Similarly, if the form is
.Ql Ic .ifmake
or
.Ql Ic .ifnmake , the ``make''
expression is applied.
.Pp
If the conditional evaluates to true the parsing of the makefile continues
as before.
If it evaluates to false, the following lines are skipped.
In both cases this continues until a
.Ql Ic .else
or
.Ql Ic .endif
is found.
.Pp
For loops are typically used to apply a set of rules to a list of files.
The syntax of a for loop is:
.Bl -tag -width Ds
.It Xo
.Ic \&.for
.Ar variable
.Ic in
.Ar expression
.Xc
.It Xo
<make-rules>
.Xc
.It Xo
.Ic \&.endfor
.Xc
.El
After the for
.Ic expression
is evaluated, it is split into words. The
iteration
.Ic variable
is successively set to each word, and substituted in the
.Ic make-rules
inside the body of the for loop.
.Sh COMMENTS
Comments begin with a hash
.Pq Ql \&#
character, anywhere but in a shell
command line, and continue to the end of the line.
.Sh SPECIAL SOURCES
.Bl -tag -width Ic .IGNORE
.It Ic .IGNORE
Ignore any errors from the commands associated with this target, exactly
as if they all were preceded by a dash
.Pq Ql \- .
.It Ic .MAKE
Execute the commands associated with this target even if the
.Fl n
or
.Fl t
options were specified.
Normally used to mark recursive
.Nm make Ns 's .
.It Ic .NOTMAIN
Normally
.Nm make
selects the first target it encounters as the default target to be built
if no target was specified.
This source prevents this target from being selected.
.It Ic .OPTIONAL
If a target is marked with this attribute and
.Nm make
can't figure out how to create it, it will ignore this fact and assume
the file isn't needed or already exists.
.It Ic .PRECIOUS
When
.Nm make
is interrupted, it removes any partially made targets.
This source prevents the target from being removed.
.It Ic .SILENT
Do not echo any of the commands associated with this target, exactly
as if they all were preceded by an at sign
.Pq Ql @ .
.It Ic .USE
Turn the target into
.Nm make Ns 's .
version of a macro.
When the target is used as a source for another target, the other target
acquires the commands, sources, and attributes (except for
.Ic .USE )
of the
source.
If the target already has commands, the
.Ic .USE
target's commands are appended
to them.
.El
.Sh "SPECIAL TARGETS"
Special targets may not be included with other targets, i.e. they must be
the only target specified.
.Bl -tag -width Ic .BEGIN
.It Ic .BEGIN
Any command lines attached to this target are executed before anything
else is done.
.It Ic .DEFAULT
This is sort of a
.Ic .USE
rule for any target (that was used only as a
source) that
.Nm make
can't figure out any other way to create.
Only the shell script is used.
The
.Ic .IMPSRC
variable of a target that inherits
.Ic .DEFAULT Ns 's
commands is set
to the target's own name.
.It Ic .END
Any command lines attached to this target are executed after everything
else is done.
.It Ic .IGNORE
Mark each of the sources with the
.Ic .IGNORE
attribute.
If no sources are specified, this is the equivalent of specifying the
.Fl i
option.
.It Ic .INTERRUPT
If
.Nm make
is interrupted, the commands for this target will be executed.
.It Ic .MAIN
If no target is specified when
.Nm make
is invoked, this target will be built.
.It Ic .MAKEFLAGS
This target provides a way to specify flags for
.Nm make
when the makefile is used.
The flags are as if typed to the shell, though the
.Fl f
option will have
no effect.
.It Ic .PATH
The sources are directories which are to be searched for files not
found in the current directory.
If no sources are specified, any previously specified directories are
deleted.
.It Ic .PRECIOUS
Apply the
.Ic .PRECIOUS
attribute to any specified sources.
If no sources are specified, the
.Ic .PRECIOUS
attribute is applied to every
target in the file.
.It Ic .SILENT
Apply the
.Ic .SILENT
attribute to any specified sources.
If no sources are specified, the
.Ic .SILENT
attribute is applied to every
command in the file.
.It Ic .SUFFIXES
Each source specifies a suffix to
.Nm make .
If no sources are specified, any previous specified suffices are deleted.
.Sh ENVIRONMENT
.Nm Make
utilizes the following environment variables, if they exist:
.Ev MAKE ,
.Ev MAKEFLAGS
and
.Ev MAKEOBJDIR .
.Sh FILES
.Bl -tag -width /usr/share/mk -compact
.It .depend
list of dependencies
.It Makefile
list of dependencies
.It makefile
list of dependencies
.It sys.mk
system makefile
.It /usr/share/mk
system makefile directory
.El
.Sh SEE ALSO
.Xr mkdep 1
.Sh HISTORY
A
.Nm Make
command appeared in
.At v7 .

859
usr.bin/make/make.c Normal file
View File

@ -0,0 +1,859 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*-
* make.c --
* The functions which perform the examination of targets and
* their suitability for creation
*
* Interface:
* Make_Run Initialize things for the module and recreate
* whatever needs recreating. Returns TRUE if
* work was (or would have been) done and FALSE
* otherwise.
*
* Make_Update Update all parents of a given child. Performs
* various bookkeeping chores like the updating
* of the cmtime field of the parent, filling
* of the IMPSRC context variable, etc. It will
* place the parent on the toBeMade queue if it
* should be.
*
* Make_TimeStamp Function to set the parent's cmtime field
* based on a child's modification time.
*
* Make_DoAllVar Set up the various local variables for a
* target, including the .ALLSRC variable, making
* sure that any variable that needs to exist
* at the very least has the empty value.
*
* Make_OODate Determine if a target is out-of-date.
*
* Make_HandleUse See if a child is a .USE node for a parent
* and perform the .USE actions if so.
*/
#include "make.h"
#include "hash.h"
#include "dir.h"
#include "job.h"
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 __P((GNode *, Lst));
static int MakeAddAllSrc __P((GNode *, GNode *));
static Boolean MakeStartJobs __P((void));
static int MakePrintStatus __P((GNode *, Boolean));
/*-
*-----------------------------------------------------------------------
* Make_TimeStamp --
* Set the cmtime field of a parent node based on the mtime stamp in its
* child. Called from MakeOODate via Lst_ForEach.
*
* Results:
* Always returns 0.
*
* Side Effects:
* The cmtime of the parent node will be changed if the mtime
* field of the child is greater than it.
*-----------------------------------------------------------------------
*/
int
Make_TimeStamp (pgn, cgn)
register GNode *pgn; /* the current parent */
register GNode *cgn; /* the child we've just examined */
{
if (cgn->mtime > pgn->cmtime) {
pgn->cmtime = cgn->mtime;
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Make_OODate --
* See if a given node is out of date with respect to its sources.
* Used by Make_Run when deciding which nodes to place on the
* toBeMade queue initially and by Make_Update to screen out USE and
* EXEC nodes. In the latter case, however, any other sort of node
* must be considered out-of-date since at least one of its children
* will have been recreated.
*
* Results:
* TRUE if the node is out of date. FALSE otherwise.
*
* Side Effects:
* The mtime field of the node and the cmtime field of its parents
* will/may be changed.
*-----------------------------------------------------------------------
*/
Boolean
Make_OODate (gn)
register GNode *gn; /* the node to check */
{
Boolean oodate;
/*
* Certain types of targets needn't even be sought as their datedness
* doesn't depend on their modification time...
*/
if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) {
(void) Dir_MTime (gn);
if (DEBUG(MAKE)) {
if (gn->mtime != 0) {
printf ("modified %s...", Targ_FmtTime(gn->mtime));
} else {
printf ("non-existent...");
}
}
}
/*
* A target is remade in one of the following circumstances:
* its modification time is smaller than that of its youngest child
* and it would actually be run (has commands or type OP_NOP)
* it's the object of a force operator
* it has no children, was on the lhs of an operator and doesn't exist
* already.
*
* Libraries are only considered out-of-date if the archive module says
* they are.
*
* These weird rules are brought to you by Backward-Compatability and
* the strange people who wrote 'Make'.
*/
if (gn->type & OP_USE) {
/*
* If the node is a USE node it is *never* out of date
* no matter *what*.
*/
if (DEBUG(MAKE)) {
printf(".USE node...");
}
oodate = FALSE;
} else if (gn->type & OP_LIB) {
if (DEBUG(MAKE)) {
printf("library...");
}
oodate = Arch_LibOODate (gn);
} else if (gn->type & OP_JOIN) {
/*
* A target with the .JOIN attribute is only considered
* out-of-date if any of its children was out-of-date.
*/
if (DEBUG(MAKE)) {
printf(".JOIN node...");
}
oodate = gn->childMade;
} else if (gn->type & (OP_FORCE|OP_EXEC)) {
/*
* A node which is the object of the force (!) operator or which has
* the .EXEC attribute is always considered out-of-date.
*/
if (DEBUG(MAKE)) {
if (gn->type & OP_FORCE) {
printf("! operator...");
} else {
printf(".EXEC node...");
}
}
oodate = TRUE;
} else if ((gn->mtime < gn->cmtime) ||
((gn->cmtime == 0) &&
((gn->mtime==0) || (gn->type & OP_DOUBLEDEP))))
{
/*
* A node whose modification time is less than that of its
* youngest child or that has no children (cmtime == 0) and
* either doesn't exist (mtime == 0) or was the object of a
* :: operator is out-of-date. Why? Because that's the way Make does
* it.
*/
if (DEBUG(MAKE)) {
if (gn->mtime < gn->cmtime) {
printf("modified before source...");
} else if (gn->mtime == 0) {
printf("non-existent and no sources...");
} else {
printf(":: operator and no sources...");
}
}
oodate = TRUE;
} else {
#if 0
/* WHY? */
if (DEBUG(MAKE)) {
printf("source %smade...", gn->childMade ? "" : "not ");
}
oodate = gn->childMade;
#else
oodate = FALSE;
#endif /* 0 */
}
/*
* If the target isn't out-of-date, the parents need to know its
* modification time. Note that targets that appear to be out-of-date
* but aren't, because they have no commands and aren't of type OP_NOP,
* have their mtime stay below their children's mtime to keep parents from
* thinking they're out-of-date.
*/
if (!oodate) {
Lst_ForEach (gn->parents, Make_TimeStamp, (ClientData)gn);
}
return (oodate);
}
/*-
*-----------------------------------------------------------------------
* MakeAddChild --
* Function used by Make_Run to add a child to the list l.
* It will only add the child if its make field is FALSE.
*
* Results:
* Always returns 0
*
* Side Effects:
* The given list is extended
*-----------------------------------------------------------------------
*/
static int
MakeAddChild (gn, l)
GNode *gn; /* the node to add */
Lst l; /* the list to which to add it */
{
if (!gn->make && !(gn->type & OP_USE)) {
(void)Lst_EnQueue (l, (ClientData)gn);
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Make_HandleUse --
* Function called by Make_Run and SuffApplyTransform on the downward
* pass to handle .USE and transformation nodes. A callback function
* for Lst_ForEach, it implements the .USE and transformation
* functionality by copying the node's commands, type flags
* and children to the parent node. Should be called before the
* children are enqueued to be looked at by MakeAddChild.
*
* A .USE node is much like an explicit transformation rule, except
* its commands are always added to the target node, even if the
* target already has commands.
*
* Results:
* returns 0.
*
* Side Effects:
* Children and commands may be added to the parent and the parent's
* type may be changed.
*
*-----------------------------------------------------------------------
*/
int
Make_HandleUse (cgn, pgn)
register GNode *cgn; /* The .USE node */
register GNode *pgn; /* The target of the .USE node */
{
register GNode *gn; /* A child of the .USE node */
register LstNode ln; /* An element in the children list */
if (cgn->type & (OP_USE|OP_TRANSFORM)) {
if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) {
/*
* .USE or transformation and target has no commands -- append
* the child's commands to the parent.
*/
(void) Lst_Concat (pgn->commands, cgn->commands, LST_CONCNEW);
}
if (Lst_Open (cgn->children) == SUCCESS) {
while ((ln = Lst_Next (cgn->children)) != NILLNODE) {
gn = (GNode *)Lst_Datum (ln);
if (Lst_Member (pgn->children, gn) == NILLNODE) {
(void) Lst_AtEnd (pgn->children, gn);
(void) Lst_AtEnd (gn->parents, pgn);
pgn->unmade += 1;
}
}
Lst_Close (cgn->children);
}
pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);
/*
* This child node is now "made", so we decrement the count of
* unmade children in the parent... We also remove the child
* from the parent's list to accurately reflect the number of decent
* children the parent has. This is used by Make_Run to decide
* whether to queue the parent or examine its children...
*/
if (cgn->type & OP_USE) {
pgn->unmade -= 1;
}
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Make_Update --
* Perform update on the parents of a node. Used by JobFinish once
* a node has been dealt with and by MakeStartJobs if it finds an
* up-to-date node.
*
* Results:
* Always returns 0
*
* Side Effects:
* The unmade field of pgn is decremented and pgn may be placed on
* the toBeMade queue if this field becomes 0.
*
* If the child was made, the parent's childMade field will be set true
* and its cmtime set to now.
*
* If the child wasn't made, the cmtime field of the parent will be
* altered if the child's mtime is big enough.
*
* Finally, if the child is the implied source for the parent, the
* parent's IMPSRC variable is set appropriately.
*
*-----------------------------------------------------------------------
*/
void
Make_Update (cgn)
register GNode *cgn; /* the child node */
{
register GNode *pgn; /* the parent node */
register char *cname; /* the child's name */
register LstNode ln; /* Element in parents and iParents lists */
cname = Var_Value (TARGET, cgn);
/*
* 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
* doesn't exist, make its mtime now.
*/
if (cgn->made != UPTODATE) {
#ifndef RECHECK
/*
* We can't re-stat the thing, but we can at least take care of rules
* where a target depends on a source that actually creates the
* target, but only if it has changed, e.g.
*
* parse.h : parse.o
*
* parse.o : parse.y
* yacc -d parse.y
* cc -c y.tab.c
* mv y.tab.o parse.o
* cmp -s y.tab.h parse.h || mv y.tab.h parse.h
*
* In this case, if the definitions produced by yacc haven't changed
* from before, parse.h won't have been updated and cgn->mtime will
* reflect the current modification time for parse.h. This is
* something of a kludge, I admit, but it's a useful one..
* XXX: People like to use a rule like
*
* FRC:
*
* To force things that depend on FRC to be made, so we have to
* check for gn->children being empty as well...
*/
if (!Lst_IsEmpty(cgn->commands) || Lst_IsEmpty(cgn->children)) {
cgn->mtime = now;
}
#else
/*
* This is what Make does and it's actually a good thing, as it
* allows rules like
*
* cmp -s y.tab.h parse.h || cp y.tab.h parse.h
*
* to function as intended. Unfortunately, thanks to the stateless
* nature of NFS (by which I mean the loose coupling of two clients
* using the same file from a common server), there are times
* when the modification time of a file created on a remote
* machine will not be modified before the local stat() implied by
* the Dir_MTime occurs, thus leading us to believe that the file
* is unchanged, wreaking havoc with files that depend on this one.
*
* I have decided it is better to make too much than to make too
* little, so this stuff is commented out unless you're sure it's ok.
* -- ardeb 1/12/88
*/
/*
* Christos, 4/9/92: If we are saving commands pretend that
* the target is made now. Otherwise archives with ... rules
* don't work!
*/
if (noExecute || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) {
cgn->mtime = now;
}
if (DEBUG(MAKE)) {
printf("update time: %s\n", Targ_FmtTime(cgn->mtime));
}
#endif
}
if (Lst_Open (cgn->parents) == SUCCESS) {
while ((ln = Lst_Next (cgn->parents)) != NILLNODE) {
pgn = (GNode *)Lst_Datum (ln);
if (pgn->make) {
pgn->unmade -= 1;
if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
if (cgn->made == MADE) {
pgn->childMade = TRUE;
if (pgn->cmtime < cgn->mtime) {
pgn->cmtime = cgn->mtime;
}
} else {
(void)Make_TimeStamp (pgn, cgn);
}
}
if (pgn->unmade == 0) {
/*
* Queue the node up -- any unmade predecessors will
* be dealt with in MakeStartJobs.
*/
(void)Lst_EnQueue (toBeMade, (ClientData)pgn);
} else if (pgn->unmade < 0) {
Error ("Graph cycles through %s", pgn->name);
}
}
}
Lst_Close (cgn->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(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) {
GNode *succ = (GNode *)Lst_Datum(ln);
if (succ->make && 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
* of this node.
*/
if (Lst_Open (cgn->iParents) == SUCCESS) {
char *cpref = Var_Value(PREFIX, cgn);
while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) {
pgn = (GNode *)Lst_Datum (ln);
if (pgn->make) {
Var_Set (IMPSRC, cname, pgn);
Var_Set (PREFIX, cpref, pgn);
}
}
Lst_Close (cgn->iParents);
}
}
/*-
*-----------------------------------------------------------------------
* MakeAddAllSrc --
* Add a child's name to the ALLSRC and OODATE variables of the given
* node. Called from Make_DoAllVar via Lst_ForEach. A child is added only
* if it has not been given the .EXEC, .USE or .INVISIBLE attributes.
* .EXEC and .USE children are very rarely going to be files, so...
* A child is added to the OODATE variable if its modification time is
* later than that of its parent, as defined by Make, except if the
* parent is a .JOIN node. In that case, it is only added to the OODATE
* variable if it was actually made (since .JOIN nodes don't have
* modification times, the comparison is rather unfair...)..
*
* Results:
* Always returns 0
*
* Side Effects:
* The ALLSRC variable for the given node is extended.
*-----------------------------------------------------------------------
*/
static int
MakeAddAllSrc (cgn, pgn)
GNode *cgn; /* The child to add */
GNode *pgn; /* The parent to whose ALLSRC variable it should be */
/* added */
{
if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) {
register char *child;
child = Var_Value(TARGET, cgn);
Var_Append (ALLSRC, child, pgn);
if (pgn->type & OP_JOIN) {
if (cgn->made == MADE) {
Var_Append(OODATE, child, pgn);
}
} else if ((pgn->mtime < cgn->mtime) ||
(cgn->mtime >= now && cgn->made == MADE))
{
/*
* It goes in the OODATE variable if the parent is younger than the
* child or if the child has been modified more recently than
* the start of the make. This is to keep pmake from getting
* confused if something else updates the parent after the
* make starts (shouldn't happen, I know, but sometimes it
* does). In such a case, if we've updated the kid, the parent
* is likely to have a modification time later than that of
* the kid and anything that relies on the OODATE variable will
* be hosed.
*
* XXX: This will cause all made children to go in the OODATE
* variable, even if they're not touched, if RECHECK isn't defined,
* since cgn->mtime is set to now in Make_Update. According to
* some people, this is good...
*/
Var_Append(OODATE, child, pgn);
}
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Make_DoAllVar --
* Set up the ALLSRC and OODATE variables. Sad to say, it must be
* done separately, rather than while traversing the graph. This is
* because Make defined OODATE to contain all sources whose modification
* times were later than that of the target, *not* those sources that
* were out-of-date. Since in both compatibility and native modes,
* the modification time of the parent isn't found until the child
* has been dealt with, we have to wait until now to fill in the
* variable. As for ALLSRC, the ordering is important and not
* guaranteed when in native mode, so it must be set here, too.
*
* Results:
* None
*
* Side Effects:
* The ALLSRC and OODATE variables of the given node is filled in.
* If the node is a .JOIN node, its TARGET variable will be set to
* match its ALLSRC variable.
*-----------------------------------------------------------------------
*/
void
Make_DoAllVar (gn)
GNode *gn;
{
Lst_ForEach (gn->children, MakeAddAllSrc, gn);
if (!Var_Exists (OODATE, gn)) {
Var_Set (OODATE, "", gn);
}
if (!Var_Exists (ALLSRC, gn)) {
Var_Set (ALLSRC, "", gn);
}
if (gn->type & OP_JOIN) {
Var_Set (TARGET, Var_Value (ALLSRC, gn), gn);
}
}
/*-
*-----------------------------------------------------------------------
* MakeStartJobs --
* Start as many jobs as possible.
*
* Results:
* If the query flag was given to pmake, no job will be started,
* but as soon as an out-of-date target is found, this function
* returns TRUE. At all other times, this function returns FALSE.
*
* Side Effects:
* Nodes are removed from the toBeMade queue and job table slots
* are filled.
*
*-----------------------------------------------------------------------
*/
static Boolean
MakeStartJobs ()
{
register GNode *gn;
while (!Job_Full() && !Lst_IsEmpty (toBeMade)) {
gn = (GNode *) Lst_DeQueue (toBeMade);
if (DEBUG(MAKE)) {
printf ("Examining %s...", gn->name);
}
/*
* 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->make && pgn->made == UNMADE) {
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;
}
}
numNodes--;
if (Make_OODate (gn)) {
if (DEBUG(MAKE)) {
printf ("out-of-date\n");
}
if (queryFlag) {
return (TRUE);
}
Make_DoAllVar (gn);
Job_Make (gn);
} else {
if (DEBUG(MAKE)) {
printf ("up-to-date\n");
}
gn->made = UPTODATE;
if (gn->type & OP_JOIN) {
/*
* Even for an up-to-date .JOIN node, we need it to have its
* context variables so references to it get the correct
* value for .TARGET when building up the context variables
* of its parent(s)...
*/
Make_DoAllVar (gn);
}
Make_Update (gn);
}
}
return (FALSE);
}
/*-
*-----------------------------------------------------------------------
* MakePrintStatus --
* Print the status of a top-level node, viz. it being up-to-date
* already or not created due to an error in a lower level.
* Callback function for Make_Run via Lst_ForEach.
*
* Results:
* Always returns 0.
*
* Side Effects:
* A message may be printed.
*
*-----------------------------------------------------------------------
*/
static int
MakePrintStatus(gn, cycle)
GNode *gn; /* Node to examine */
Boolean cycle; /* True if gn->unmade being non-zero implies
* a cycle in the graph, not an error in an
* inferior */
{
if (gn->made == UPTODATE) {
printf ("`%s' is up to date.\n", gn->name);
} else if (gn->unmade != 0) {
if (cycle) {
/*
* 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)TRUE);
gn->made = UNMADE;
} else if (gn->made != ENDCYCLE) {
gn->made = CYCLE;
Lst_ForEach(gn->children, MakePrintStatus, (ClientData)TRUE);
}
} else {
printf ("`%s' not remade because of errors.\n", gn->name);
}
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Make_Run --
* Initialize the nodes to remake and the list of nodes which are
* ready to be made by doing a breadth-first traversal of the graph
* starting from the nodes in the given list. Once this traversal
* is finished, all the 'leaves' of the graph are in the toBeMade
* queue.
* Using this queue and the Job module, work back up the graph,
* calling on MakeStartJobs to keep the job table as full as
* possible.
*
* Results:
* TRUE if work was done. FALSE otherwise.
*
* Side Effects:
* The make field of all nodes involved in the creation of the given
* targets is set to 1. The toBeMade list is set to contain all the
* 'leaves' of these subgraphs.
*-----------------------------------------------------------------------
*/
Boolean
Make_Run (targs)
Lst targs; /* the initial list of targets */
{
register GNode *gn; /* a temporary pointer */
register Lst examine; /* List of targets to examine */
int errors; /* Number of errors the Job module reports */
toBeMade = Lst_Init (FALSE);
examine = Lst_Duplicate(targs, NOCOPY);
numNodes = 0;
/*
* Make an initial downward pass over the graph, marking nodes to be made
* as we go down. We call Suff_FindDeps to find where a node is and
* to get some children for it if it has none and also has no commands.
* If the node is a leaf, we stick it on the toBeMade queue to
* be looked at in a minute, otherwise we add its children to our queue
* and go on about our business.
*/
while (!Lst_IsEmpty (examine)) {
gn = (GNode *) Lst_DeQueue (examine);
if (!gn->make) {
gn->make = TRUE;
numNodes++;
/*
* Apply any .USE rules before looking for implicit dependencies
* to make sure everything has commands that should...
*/
Lst_ForEach (gn->children, Make_HandleUse, (ClientData)gn);
Suff_FindDeps (gn);
if (gn->unmade != 0) {
Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine);
} else {
(void)Lst_EnQueue (toBeMade, (ClientData)gn);
}
}
}
Lst_Destroy (examine, NOFREE);
if (queryFlag) {
/*
* We wouldn't do any work unless we could start some jobs in the
* next loop... (we won't actually start any, of course, this is just
* 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();
}
/*
* Main Loop: The idea here is that the ending of jobs will take
* care of the maintenance of data structures and the waiting for output
* will cause us to be idle most of the time while our children run as
* much as possible. Because the job table is kept as full as possible,
* the only time when it will be empty is when all the jobs which need
* running have been run, so that is the end condition of this loop.
* Note that the Job module will exit if there were any errors unless the
* keepgoing flag was given.
*/
while (!Job_Empty ()) {
Job_CatchOutput ();
Job_CatchChildren (!usePipes);
(void)MakeStartJobs();
}
errors = Job_End();
/*
* Print the final status of each target. E.g. if it wasn't made
* because some inferior reported an error.
*/
Lst_ForEach(targs, MakePrintStatus,
(ClientData)((errors == 0) && (numNodes != 0)));
return (TRUE);
}

357
usr.bin/make/make.h Normal file
View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)make.h 8.1 (Berkeley) 6/6/93
*/
/*-
* make.h --
* The global definitions for pmake
*/
#ifndef _MAKE_H_
#define _MAKE_H_
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/cdefs.h>
#if __STDC__
#include <stdlib.h>
#include <unistd.h>
#endif
#include "sprite.h"
#include "lst.h"
#include "config.h"
#include "buf.h"
/*-
* The structure for an individual graph node. Each node has several
* pieces of data associated with it.
* 1) the name of the target it describes
* 2) the location of the target file in the file system.
* 3) the type of operator used to define its sources (qv. parse.c)
* 4) whether it is involved in this invocation of make
* 5) whether the target has been remade
* 6) whether any of its children has been remade
* 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
* 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
* this node.
* 15) 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
* and this target only (qv. var.c [$@ $< $?, etc.])
* 17) a Lst of strings that are commands to be given to a shell
* to create this target.
*/
typedef struct GNode {
char *name; /* The target's name */
char *path; /* The full pathname of the file */
int type; /* Its type (see the OP flags, below) */
Boolean make; /* TRUE if this target needs to be remade */
enum {
UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED,
CYCLE, ENDCYCLE,
} made; /* Set to reflect the state of processing
* on this node:
* UNMADE - Not examined yet
* BEINGMADE - Target is already being made.
* Indicates a cycle in the graph. (compat
* mode only)
* MADE - Was out-of-date and has been made
* UPTODATE - Was already up-to-date
* ERROR - An error occured 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.
*/
Boolean childMade; /* TRUE if one of this target's children was
* made */
int unmade; /* The number of unmade children */
int mtime; /* Its modification time */
int cmtime; /* The modification time of its youngest
* child */
Lst iParents; /* Links to parents for which this is an
* implied source, if any */
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 context; /* The local variables */
Lst commands; /* Creation commands */
struct _Suff *suffix; /* Suffix for the node (determined by
* Suff_FindDeps and opaque to everyone
* but the Suff module) */
} GNode;
/*
* Manifest constants
*/
#define NILGNODE ((GNode *) NIL)
/*
* The OP_ constants are used when parsing a dependency line as a way of
* communicating to other parts of the program the way in which a target
* should be made. These constants are bitwise-OR'ed together and
* placed in the 'type' field of each node. Any node that has
* a 'type' field which satisfies the OP_NOP function was never never on
* the lefthand side of an operator, though it may have been on the
* righthand side...
*/
#define OP_DEPENDS 0x00000001 /* Execution of commands depends on
* kids (:) */
#define OP_FORCE 0x00000002 /* Always execute commands (!) */
#define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids
* per line (::) */
#define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP)
#define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't
* exist and can't be created */
#define OP_USE 0x00000010 /* Use associated commands for parents */
#define OP_EXEC 0x00000020 /* Target is never out of date, but always
* execute commands anyway. Its time
* doesn't matter, so it has none...sort
* of */
#define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */
#define OP_PRECIOUS 0x00000080 /* Don't remove the target when
* interrupted */
#define OP_SILENT 0x00000100 /* Don't echo commands when executed */
#define OP_MAKE 0x00000200 /* Target is a recurrsive make so its
* commands should always be executed when
* it is out of date, regardless of the
* state of the -n or -t flags */
#define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its
* children was out-of-date */
#define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents.
* I.e. it doesn't show up in the parents's
* local variables. */
#define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main
* target' processing in parse.c */
/* 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 */
#define OP_LIB 0x20000000 /* Target is a library */
#define OP_ARCHV 0x10000000 /* Target is an archive construct */
#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should.
* Used when parsing to catch multiple
* commands for a target */
#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */
#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */
/*
* OP_NOP will return TRUE if the node with the given type was not the
* object of a dependency operator
*/
#define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000)
/*
* The TARG_ constants are used when calling the Targ_FindNode and
* Targ_FindList functions in targ.c. They simply tell the functions what to
* do if the desired node(s) is (are) not found. If the TARG_CREATE constant
* is given, a new, empty node will be created for the target, placed in the
* 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 */
/*
* These constants are all used by the Str_Concat function to decide how the
* final string should look. If STR_ADDSPACE is given, a space will be
* placed between the two strings. If STR_ADDSLASH is given, a '/' will
* be used instead of a space. If neither is given, no intervening characters
* will be placed between the two strings in the final output. If the
* STR_DOFREE bit is set, the two input strings will be freed before
* Str_Concat returns.
*/
#define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */
#define STR_DOFREE 0x02 /* free source strings after concatenation */
#define STR_ADDSLASH 0x04 /* add a slash when Str_Concat'ing */
/*
* Error levels for parsing. PARSE_FATAL means the process cannot continue
* once the makefile has been parsed. PARSE_WARNING means it can. Passed
* as the first argument to Parse_Error.
*/
#define PARSE_WARNING 2
#define PARSE_FATAL 1
/*
* Values returned by Cond_Eval.
*/
#define COND_PARSE 0 /* Parse the next lines */
#define COND_SKIP 1 /* Skip the next lines */
#define COND_INVALID 2 /* Not a conditional statement */
/*
* Definitions for the "local" variables. Used only for clarity.
*/
#define TARGET "@" /* Target of dependency */
#define OODATE "?" /* All out-of-date sources */
#define ALLSRC ">" /* All sources */
#define IMPSRC "<" /* Source implied by transformation */
#define PREFIX "*" /* Common prefix */
#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
#define MEMBER "%" /* Member in "archive(member)" syntax */
#define FTARGET "@F" /* file part of TARGET */
#define DTARGET "@D" /* directory part of TARGET */
#define FIMPSRC "<F" /* file part of IMPSRC */
#define DIMPSRC "<D" /* directory part of IMPSRC */
#define FPREFIX "*F" /* file part of PREFIX */
#define DPREFIX "*D" /* directory part of PREFIX */
/*
* Global Variables
*/
extern Lst create; /* The list of target names specified on the
* command line. used to resolve #if
* make(...) statements */
extern Lst dirSearchPath; /* The list of directories to search when
* looking for targets */
extern Boolean compatMake; /* True if we are make compatible */
extern Boolean ignoreErrors; /* True if should ignore all errors */
extern Boolean beSilent; /* True if should print no commands */
extern Boolean noExecute; /* True if should execute nothing */
extern Boolean allPrecious; /* True if every target is precious */
extern Boolean keepgoing; /* True if should continue on unaffected
* portions of the graph when have an error
* 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 checkEnvFirst; /* TRUE if environment should be searched for
* variables before the global context */
extern GNode *DEFAULT; /* .DEFAULT rule */
extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g
* in the Makefile itself */
extern GNode *VAR_CMD; /* Variables defined on the command line */
extern char var_Error[]; /* Value returned by Var_Parse when an error
* is encountered. It actually points to
* an empty string, so naive callers needn't
* worry about it. */
extern time_t now; /* The time at the start of this whole
* process */
extern Boolean oldVars; /* Do old-style variable substitution */
/*
* debug control:
* There is one bit per module. It is up to the module what debug
* information to print.
*/
extern int debug;
#define DEBUG_ARCH 0x0001
#define DEBUG_COND 0x0002
#define DEBUG_DIR 0x0004
#define DEBUG_GRAPH1 0x0008
#define DEBUG_GRAPH2 0x0010
#define DEBUG_JOB 0x0020
#define DEBUG_MAKE 0x0040
#define DEBUG_SUFF 0x0080
#define DEBUG_TARG 0x0100
#define DEBUG_VAR 0x0200
#define DEBUG_FOR 0x0400
#ifdef __STDC__
#define CONCAT(a,b) a##b
#else
#define I(a) a
#define CONCAT(a,b) I(a)b
#endif /* __STDC__ */
#define DEBUG(module) (debug & CONCAT(DEBUG_,module))
/*
* Since there are so many, all functions that return non-integer values are
* extracted by means of a sed script or two and stuck in the file "nonints.h"
*/
#include "nonints.h"
void Make_DoAllVar __P((GNode *));
int Make_HandleUse __P((GNode *, GNode *));
Boolean Make_OODate __P((GNode *));
Boolean Make_Run __P((Lst));
int Make_TimeStamp __P((GNode *, GNode *));
void Make_Update __P((GNode *));
#endif /* _MAKE_H_ */

132
usr.bin/make/nonints.h Normal file
View File

@ -0,0 +1,132 @@
/*-
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)nonints.h 8.3 (Berkeley) 3/19/94
*/
/* arch.c */
ReturnStatus Arch_ParseArchive __P((char **, Lst, GNode *));
void Arch_Touch __P((GNode *));
void Arch_TouchLib __P((GNode *));
int Arch_MTime __P((GNode *));
int Arch_MemMTime __P((GNode *));
void Arch_FindLib __P((GNode *, Lst));
Boolean Arch_LibOODate __P((GNode *));
void Arch_Init __P((void));
/* compat.c */
void Compat_Run __P((Lst));
/* cond.c */
int Cond_Eval __P((char *));
void Cond_End __P((void));
/* for.c */
int For_Eval __P((char *));
void For_Run __P((void));
/* main.c */
void Main_ParseArgLine __P((char *));
int main __P((int, char **));
void Error __P((const char *, ...));
void Fatal __P((const char *, ...));
void Punt __P((const char *, ...));
void DieHorribly __P((void));
void Finish __P((int));
char *emalloc __P((u_int));
void enomem __P((void));
/* parse.c */
void Parse_Error __P((int, const char *, ...));
Boolean Parse_AnyExport __P((void));
Boolean Parse_IsVar __P((char *));
void Parse_DoVar __P((char *, GNode *));
void Parse_AddIncludeDir __P((char *));
void Parse_File __P((char *, FILE *));
void Parse_Init __P((void));
void Parse_FromString __P((char *));
Lst Parse_MainName __P((void));
/* str.c */
char *str_concat __P((char *, char *, int));
char **brk_string __P((char *, int *));
char *Str_FindSubstring __P((char *, char *));
int Str_Match __P((char *, char *));
char *Str_SYSVMatch __P((char *, char *, int *len));
void Str_SYSVSubst __P((Buffer, char *, char *, int));
/* suff.c */
void Suff_ClearSuffixes __P((void));
Boolean Suff_IsTransform __P((char *));
GNode *Suff_AddTransform __P((char *));
int Suff_EndTransform __P((GNode *));
void Suff_AddSuffix __P((char *));
Lst Suff_GetPath __P((char *));
void Suff_DoPaths __P((void));
void Suff_AddInclude __P((char *));
void Suff_AddLib __P((char *));
void Suff_FindDeps __P((GNode *));
void Suff_SetNull __P((char *));
void Suff_Init __P((void));
void Suff_PrintAll __P((void));
/* targ.c */
void Targ_Init __P((void));
GNode *Targ_NewGN __P((char *));
GNode *Targ_FindNode __P((char *, int));
Lst Targ_FindList __P((Lst, int));
Boolean Targ_Ignore __P((GNode *));
Boolean Targ_Silent __P((GNode *));
Boolean Targ_Precious __P((GNode *));
void Targ_SetMain __P((GNode *));
int Targ_PrintCmd __P((char *));
char *Targ_FmtTime __P((time_t));
void Targ_PrintType __P((int));
void Targ_PrintGraph __P((int));
/* var.c */
void Var_Delete __P((char *, GNode *));
void Var_Set __P((char *, char *, GNode *));
void Var_Append __P((char *, char *, GNode *));
Boolean Var_Exists __P((char *, GNode *));
char *Var_Value __P((char *, GNode *));
char *Var_Parse __P((char *, GNode *, Boolean, int *, Boolean *));
char *Var_Subst __P((char *, char *, GNode *, Boolean));
char *Var_GetTail __P((char *));
char *Var_GetHead __P((char *));
void Var_Init __P((void));
void Var_Dump __P((GNode *));

2566
usr.bin/make/parse.c Normal file

File diff suppressed because it is too large Load Diff

39
usr.bin/make/pathnames.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
*/
#define _PATH_OBJDIR "obj"
#define _PATH_DEFSHELLDIR "/bin"
#define _PATH_DEFSYSMK "sys.mk"
#define _PATH_DEFSYSPATH "/usr/share/mk"

114
usr.bin/make/sprite.h Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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.
*
* @(#)sprite.h 8.1 (Berkeley) 6/6/93
*/
/*
* sprite.h --
*
* Common constants and type declarations for Sprite.
*/
#ifndef _SPRITE
#define _SPRITE
/*
* A boolean type is defined as an integer, not an enum. This allows a
* boolean argument to be an expression that isn't strictly 0 or 1 valued.
*/
typedef int Boolean;
#ifndef TRUE
#define TRUE 1
#endif TRUE
#ifndef FALSE
#define FALSE 0
#endif FALSE
/*
* Functions that must return a status can return a ReturnStatus to
* indicate success or type of failure.
*/
typedef int ReturnStatus;
/*
* The following statuses overlap with the first 2 generic statuses
* defined in status.h:
*
* SUCCESS There was no error.
* FAILURE There was a general error.
*/
#define SUCCESS 0x00000000
#define FAILURE 0x00000001
/*
* A nil pointer must be something that will cause an exception if
* referenced. There are two nils: the kernels nil and the nil used
* by user processes.
*/
#define NIL (~0)
#define USER_NIL 0
#ifndef NULL
#define NULL 0
#endif NULL
/*
* An address is just a pointer in C. It is defined as a character pointer
* so that address arithmetic will work properly, a byte at a time.
*/
typedef char *Address;
/*
* ClientData is an uninterpreted word. It is defined as an int so that
* kdbx will not interpret client data as a string. Unlike an "Address",
* client data will generally not be used in arithmetic.
*/
typedef int *ClientData;
#ifdef notdef
#include "status.h"
#endif
#endif _SPRITE

439
usr.bin/make/str.c Normal file
View File

@ -0,0 +1,439 @@
/*-
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)str.c 8.4 (Berkeley) 3/21/94";
#endif /* not lint */
#include "make.h"
/*-
* str_concat --
* concatenate the two strings, inserting a space or slash between them,
* freeing them if requested.
*
* returns --
* the resulting string in allocated space.
*/
char *
str_concat(s1, s2, flags)
char *s1, *s2;
int flags;
{
register int len1, len2;
register char *result;
/* get the length of both strings */
len1 = strlen(s1);
len2 = strlen(s2);
/* allocate length plus separator plus EOS */
result = emalloc((u_int)(len1 + len2 + 2));
/* copy first string into place */
memcpy(result, s1, len1);
/* add separator character */
if (flags & STR_ADDSPACE) {
result[len1] = ' ';
++len1;
} else if (flags & STR_ADDSLASH) {
result[len1] = '/';
++len1;
}
/* copy second string plus EOS into place */
memcpy(result + len1, s2, len2 + 1);
/* free original strings */
if (flags & STR_DOFREE) {
(void)free(s1);
(void)free(s2);
}
return(result);
}
/*-
* brk_string --
* Fracture a string into an array of words (as delineated by tabs or
* spaces) taking quotation marks into account. Leading tabs/spaces
* are ignored.
*
* returns --
* Pointer to the array of pointers to the words. To make life easier,
* the first word is always the value of the .MAKE variable.
*/
char **
brk_string(str, store_argc)
register char *str;
int *store_argc;
{
static int argmax, curlen;
static char **argv, *buf;
register int argc, ch;
register char inquote, *p, *start, *t;
int len;
/* save off pmake variable */
if (!argv) {
argv = (char **)emalloc((argmax = 50) * sizeof(char *));
argv[0] = Var_Value(".MAKE", VAR_GLOBAL);
}
/* skip leading space chars. */
for (; *str == ' ' || *str == '\t'; ++str)
continue;
/* allocate room for a copy of the string */
if ((len = strlen(str) + 1) > curlen)
buf = emalloc(curlen = len);
/*
* copy the string; at the same time, parse backslashes,
* quotes and build the argument list.
*/
argc = 1;
inquote = '\0';
for (p = str, start = t = buf;; ++p) {
switch(ch = *p) {
case '"':
case '\'':
if (inquote)
if (inquote == ch)
inquote = '\0';
else
break;
else
inquote = (char) ch;
continue;
case ' ':
case '\t':
if (inquote)
break;
if (!start)
continue;
/* FALLTHROUGH */
case '\n':
case '\0':
/*
* end of a token -- make sure there's enough argv
* space and save off a pointer.
*/
*t++ = '\0';
if (argc == argmax) {
argmax *= 2; /* ramp up fast */
if (!(argv = (char **)realloc(argv,
argmax * sizeof(char *))))
enomem();
}
argv[argc++] = start;
start = (char *)NULL;
if (ch == '\n' || ch == '\0')
goto done;
continue;
case '\\':
switch (ch = *++p) {
case '\0':
case '\n':
/* hmmm; fix it up as best we can */
ch = '\\';
--p;
break;
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
}
break;
}
if (!start)
start = t;
*t++ = (char) ch;
}
done: argv[argc] = (char *)NULL;
*store_argc = argc;
return(argv);
}
/*
* Str_FindSubstring -- See if a string contains a particular substring.
*
* Results: If string contains substring, the return value is the location of
* the first matching instance of substring in string. If string doesn't
* contain substring, the return value is NULL. Matching is done on an exact
* character-for-character basis with no wildcards or special characters.
*
* Side effects: None.
*/
char *
Str_FindSubstring(string, substring)
register char *string; /* String to search. */
char *substring; /* Substring to find in string */
{
register char *a, *b;
/*
* First scan quickly through the two strings looking for a single-
* character match. When it's found, then compare the rest of the
* substring.
*/
for (b = substring; *string != 0; string += 1) {
if (*string != *b)
continue;
a = string;
for (;;) {
if (*b == 0)
return(string);
if (*a++ != *b++)
break;
}
b = substring;
}
return((char *) NULL);
}
/*
* Str_Match --
*
* See if a particular string matches a particular pattern.
*
* Results: Non-zero is returned if string matches pattern, 0 otherwise. The
* matching operation permits the following special characters in the
* pattern: *?\[] (see the man page for details on what these mean).
*
* Side effects: None.
*/
int
Str_Match(string, pattern)
register char *string; /* String */
register char *pattern; /* Pattern */
{
char c2;
for (;;) {
/*
* See if we're at the end of both the pattern and the
* string. If, we succeeded. If we're at the end of the
* pattern but not at the end of the string, we failed.
*/
if (*pattern == 0)
return(!*string);
if (*string == 0 && *pattern != '*')
return(0);
/*
* Check for a "*" as the next pattern character. It matches
* any substring. We handle this by calling ourselves
* recursively for each postfix of string, until either we
* match or we reach the end of the string.
*/
if (*pattern == '*') {
pattern += 1;
if (*pattern == 0)
return(1);
while (*string != 0) {
if (Str_Match(string, pattern))
return(1);
++string;
}
return(0);
}
/*
* Check for a "?" as the next pattern character. It matches
* any single character.
*/
if (*pattern == '?')
goto thisCharOK;
/*
* Check for a "[" as the next pattern character. It is
* followed by a list of characters that are acceptable, or
* by a range (two characters separated by "-").
*/
if (*pattern == '[') {
++pattern;
for (;;) {
if ((*pattern == ']') || (*pattern == 0))
return(0);
if (*pattern == *string)
break;
if (pattern[1] == '-') {
c2 = pattern[2];
if (c2 == 0)
return(0);
if ((*pattern <= *string) &&
(c2 >= *string))
break;
if ((*pattern >= *string) &&
(c2 <= *string))
break;
pattern += 2;
}
++pattern;
}
while ((*pattern != ']') && (*pattern != 0))
++pattern;
goto thisCharOK;
}
/*
* If the next pattern character is '/', just strip off the
* '/' so we do exact matching on the character that follows.
*/
if (*pattern == '\\') {
++pattern;
if (*pattern == 0)
return(0);
}
/*
* There's no special character. Just make sure that the
* next characters of each string match.
*/
if (*pattern != *string)
return(0);
thisCharOK: ++pattern;
++string;
}
}
/*-
*-----------------------------------------------------------------------
* Str_SYSVMatch --
* Check word against pattern for a match (% is wild),
*
* Results:
* Returns the beginning position of a match or null. The number
* of characters matched is returned in len.
*
* Side Effects:
* None
*
*-----------------------------------------------------------------------
*/
char *
Str_SYSVMatch(word, pattern, len)
char *word; /* Word to examine */
char *pattern; /* Pattern to examine against */
int *len; /* Number of characters to substitute */
{
char *p = pattern;
char *w = word;
char *m;
if (*p == '\0') {
/* Null pattern is the whole string */
*len = strlen(w);
return w;
}
if ((m = strchr(p, '%')) != NULL) {
/* check that the prefix matches */
for (; p != m && *w && *w == *p; w++, p++)
continue;
if (p != m)
return NULL; /* No match */
if (*++p == '\0') {
/* No more pattern, return the rest of the string */
*len = strlen(w);
return w;
}
}
m = w;
/* Find a matching tail */
do
if (strcmp(p, w) == 0) {
*len = w - m;
return m;
}
while (*w++ != '\0');
return NULL;
}
/*-
*-----------------------------------------------------------------------
* Str_SYSVSubst --
* Substitute '%' on the pattern with len characters from src.
* If the pattern does not contain a '%' prepend len characters
* from src.
*
* Results:
* None
*
* Side Effects:
* Places result on buf
*
*-----------------------------------------------------------------------
*/
void
Str_SYSVSubst(buf, pat, src, len)
Buffer buf;
char *pat;
char *src;
int len;
{
char *m;
if ((m = strchr(pat, '%')) != NULL) {
/* Copy the prefix */
Buf_AddBytes(buf, m - pat, (Byte *) pat);
/* skip the % */
pat = m + 1;
}
/* Copy the pattern */
Buf_AddBytes(buf, len, (Byte *) src);
/* append the rest */
Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
}

2218
usr.bin/make/suff.c Normal file

File diff suppressed because it is too large Load Diff

585
usr.bin/make/targ.c Normal file
View File

@ -0,0 +1,585 @@
/*
* Copyright (c) 1988, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1989 by Berkeley Softworks
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 lint
static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
#endif /* not lint */
/*-
* targ.c --
* Functions for maintaining the Lst allTargets. Target nodes are
* kept in two structures: a Lst, maintained by the list library, and a
* hash table, maintained by the hash library.
*
* Interface:
* Targ_Init Initialization procedure.
*
* Targ_NewGN Create a new GNode for the passed target
* (string). The node is *not* placed in the
* hash table, though all its fields are
* initialized.
*
* Targ_FindNode Find the node for a given target, creating
* and storing it if it doesn't exist and the
* flags are right (TARG_CREATE)
*
* Targ_FindList Given a list of names, find nodes for all
* of them. If a name doesn't exist and the
* TARG_NOCREATE flag was given, an error message
* is printed. Else, if a name doesn't exist,
* its node is created.
*
* Targ_Ignore Return TRUE if errors should be ignored when
* creating the given target.
*
* Targ_Silent Return TRUE if we should be silent when
* creating the given target.
*
* Targ_Precious Return TRUE if the target is precious and
* should not be removed if we are interrupted.
*
* Debugging:
* Targ_PrintGraph Print out the entire graphm all variables
* and statistics for the directory cache. Should
* print something for suffixes, too, but...
*/
#include <stdio.h>
#include <time.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
static Lst allTargets; /* the list of all targets found so far */
static Hash_Table targets; /* a hash table of same */
#define HTSIZE 191 /* initial size of hash table */
/*-
*-----------------------------------------------------------------------
* Targ_Init --
* Initialize this module
*
* Results:
* None
*
* Side Effects:
* The allTargets list and the targets hash table are initialized
*-----------------------------------------------------------------------
*/
void
Targ_Init ()
{
allTargets = Lst_Init (FALSE);
Hash_InitTable (&targets, HTSIZE);
}
/*-
*-----------------------------------------------------------------------
* Targ_NewGN --
* Create and initialize a new graph node
*
* Results:
* An initialized graph node with the name field filled with a copy
* of the passed name
*
* Side Effects:
* None.
*-----------------------------------------------------------------------
*/
GNode *
Targ_NewGN (name)
char *name; /* the name to stick in the new node */
{
register GNode *gn;
gn = (GNode *) emalloc (sizeof (GNode));
gn->name = strdup (name);
gn->path = (char *) 0;
if (name[0] == '-' && name[1] == 'l') {
gn->type = OP_LIB;
} else {
gn->type = 0;
}
gn->unmade = 0;
gn->make = FALSE;
gn->made = UNMADE;
gn->childMade = FALSE;
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->context = Lst_Init (FALSE);
gn->commands = Lst_Init (FALSE);
gn->suffix = NULL;
return (gn);
}
/*-
*-----------------------------------------------------------------------
* Targ_FindNode --
* Find a node in the list using the given name for matching
*
* Results:
* The node in the list if it was. If it wasn't, return NILGNODE of
* flags was TARG_NOCREATE or the newly created and initialized node
* if it was TARG_CREATE
*
* Side Effects:
* Sometimes a node is created and added to the list
*-----------------------------------------------------------------------
*/
GNode *
Targ_FindNode (name, flags)
char *name; /* the name to find */
int flags; /* flags governing events when target not
* found */
{
GNode *gn; /* node in that element */
Hash_Entry *he; /* 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);
(void) Lst_AtEnd (allTargets, (ClientData)gn);
}
} else {
he = Hash_FindEntry (&targets, name);
}
if (he == (Hash_Entry *) NULL) {
return (NILGNODE);
} else {
return ((GNode *) Hash_GetValue (he));
}
}
/*-
*-----------------------------------------------------------------------
* Targ_FindList --
* Make a complete list of GNodes from the given list of names
*
* Results:
* A complete list of graph nodes corresponding to all instances of all
* the names in names.
*
* Side Effects:
* If flags is TARG_CREATE, nodes will be created for all names in
* names which do not yet have graph nodes. If flags is TARG_NOCREATE,
* an error message will be printed for each name which can't be found.
* -----------------------------------------------------------------------
*/
Lst
Targ_FindList (names, flags)
Lst names; /* list of names to find */
int flags; /* flags used if no node is found for a given
* name */
{
Lst nodes; /* result list */
register LstNode ln; /* name list element */
register GNode *gn; /* node in tLn */
char *name;
nodes = Lst_Init (FALSE);
if (Lst_Open (names) == FAILURE) {
return (nodes);
}
while ((ln = Lst_Next (names)) != NILLNODE) {
name = (char *)Lst_Datum(ln);
gn = Targ_FindNode (name, flags);
if (gn != NILGNODE) {
/*
* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
* are added to the list in the order in which they were
* encountered in the makefile.
*/
(void) Lst_AtEnd (nodes, (ClientData)gn);
if (gn->type & OP_DOUBLEDEP) {
(void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
}
} else if (flags == TARG_NOCREATE) {
Error ("\"%s\" -- target unknown.", name);
}
}
Lst_Close (names);
return (nodes);
}
/*-
*-----------------------------------------------------------------------
* Targ_Ignore --
* Return true if should ignore errors when creating gn
*
* Results:
* TRUE if should ignore errors
*
* Side Effects:
* None
*-----------------------------------------------------------------------
*/
Boolean
Targ_Ignore (gn)
GNode *gn; /* node to check for */
{
if (ignoreErrors || gn->type & OP_IGNORE) {
return (TRUE);
} else {
return (FALSE);
}
}
/*-
*-----------------------------------------------------------------------
* Targ_Silent --
* Return true if be silent when creating gn
*
* Results:
* TRUE if should be silent
*
* Side Effects:
* None
*-----------------------------------------------------------------------
*/
Boolean
Targ_Silent (gn)
GNode *gn; /* node to check for */
{
if (beSilent || gn->type & OP_SILENT) {
return (TRUE);
} else {
return (FALSE);
}
}
/*-
*-----------------------------------------------------------------------
* Targ_Precious --
* See if the given target is precious
*
* Results:
* TRUE if it is precious. FALSE otherwise
*
* Side Effects:
* None
*-----------------------------------------------------------------------
*/
Boolean
Targ_Precious (gn)
GNode *gn; /* the node to check */
{
if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
return (TRUE);
} else {
return (FALSE);
}
}
/******************* DEBUG INFO PRINTING ****************/
static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
/*-
*-----------------------------------------------------------------------
* Targ_SetMain --
* Set our idea of the main target we'll be creating. Used for
* debugging output.
*
* Results:
* None.
*
* Side Effects:
* "mainTarg" is set to the main target's node.
*-----------------------------------------------------------------------
*/
void
Targ_SetMain (gn)
GNode *gn; /* The main target we'll create */
{
mainTarg = gn;
}
static int
/*ARGSUSED*/
TargPrintName (gn, ppath)
GNode *gn;
int ppath;
{
printf ("%s ", gn->name);
#ifdef notdef
if (ppath) {
if (gn->path) {
printf ("[%s] ", gn->path);
}
if (gn == mainTarg) {
printf ("(MAIN NAME) ");
}
}
#endif /* notdef */
return (0);
}
int
Targ_PrintCmd (cmd)
char *cmd;
{
printf ("\t%s\n", cmd);
return (0);
}
/*-
*-----------------------------------------------------------------------
* Targ_FmtTime --
* Format a modification time in some reasonable way and return it.
*
* Results:
* The time reformatted.
*
* Side Effects:
* The time is placed in a static area, so it is overwritten
* with each call.
*
*-----------------------------------------------------------------------
*/
char *
Targ_FmtTime (time)
time_t time;
{
struct tm *parts;
static char buf[40];
static char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
parts = localtime(&time);
sprintf (buf, "%d:%02d:%02d %s %d, 19%d",
parts->tm_hour, parts->tm_min, parts->tm_sec,
months[parts->tm_mon], parts->tm_mday, parts->tm_year);
return(buf);
}
/*-
*-----------------------------------------------------------------------
* Targ_PrintType --
* Print out a type field giving only those attributes the user can
* set.
*
* Results:
*
* Side Effects:
*
*-----------------------------------------------------------------------
*/
void
Targ_PrintType (type)
register int type;
{
register int tbit;
#ifdef __STDC__
#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
#else
#define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
#endif /* __STDC__ */
type &= ~OP_OPMASK;
while (type) {
tbit = 1 << (ffs(type) - 1);
type &= ~tbit;
switch(tbit) {
PRINTBIT(OPTIONAL);
PRINTBIT(USE);
PRINTBIT(EXEC);
PRINTBIT(IGNORE);
PRINTBIT(PRECIOUS);
PRINTBIT(SILENT);
PRINTBIT(MAKE);
PRINTBIT(JOIN);
PRINTBIT(INVISIBLE);
PRINTBIT(NOTMAIN);
PRINTDBIT(LIB);
/*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
PRINTDBIT(ARCHV);
}
}
}
/*-
*-----------------------------------------------------------------------
* TargPrintNode --
* print the contents of a node
*-----------------------------------------------------------------------
*/
static int
TargPrintNode (gn, pass)
GNode *gn;
int pass;
{
if (!OP_NOP(gn->type)) {
printf("#\n");
if (gn == mainTarg) {
printf("# *** MAIN TARGET ***\n");
}
if (pass == 2) {
if (gn->unmade) {
printf("# %d unmade children\n", gn->unmade);
} else {
printf("# No unmade children\n");
}
if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
if (gn->mtime != 0) {
printf("# 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"))));
} 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"))));
} else {
printf("# unmade\n");
}
}
if (!Lst_IsEmpty (gn->iParents)) {
printf("# implicit parents: ");
Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
fputc ('\n', stdout);
}
}
if (!Lst_IsEmpty (gn->parents)) {
printf("# parents: ");
Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
fputc ('\n', stdout);
}
printf("%-16s", gn->name);
switch (gn->type & OP_OPMASK) {
case OP_DEPENDS:
printf(": "); break;
case OP_FORCE:
printf("! "); break;
case OP_DOUBLEDEP:
printf(":: "); 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");
if (gn->type & OP_DOUBLEDEP) {
Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)pass);
}
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* TargPrintOnlySrc --
* Print only those targets that are just a source.
*
* Results:
* 0.
*
* Side Effects:
* The name of each file is printed preceeded by #\t
*
*-----------------------------------------------------------------------
*/
static int
TargPrintOnlySrc(gn)
GNode *gn;
{
if (OP_NOP(gn->type)) {
printf("#\t%s [%s]\n", gn->name,
gn->path ? gn->path : gn->name);
}
return (0);
}
/*-
*-----------------------------------------------------------------------
* Targ_PrintGraph --
* print the entire graph. heh heh
*
* Results:
* none
*
* Side Effects:
* lots o' output
*-----------------------------------------------------------------------
*/
void
Targ_PrintGraph (pass)
int pass; /* Which pass this is. 1 => no processing
* 2 => processing done */
{
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);
printf("#*** Global Variables:\n");
Var_Dump (VAR_GLOBAL);
printf("#*** Command-line Variables:\n");
Var_Dump (VAR_CMD);
printf("\n");
Dir_PrintDirectories();
printf("\n");
Suff_PrintAll();
}

1986
usr.bin/make/var.c Normal file

File diff suppressed because it is too large Load Diff