diff options
Diffstat (limited to 'usr.bin/make/targ.c')
-rw-r--r-- | usr.bin/make/targ.c | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c new file mode 100644 index 0000000..7e1475a --- /dev/null +++ b/usr.bin/make/targ.c @@ -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(); +} |