1141104Sharti/*-
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
3762833Swsanchez *
3862833Swsanchez * @(#)targ.c	8.2 (Berkeley) 3/19/94
391590Srgrimes */
401590Srgrimes
4162833Swsanchez#include <sys/cdefs.h>
4294587Sobrien__FBSDID("$FreeBSD$");
431590Srgrimes
44144469Sharti/*
45144469Sharti * Functions for maintaining the Lst allTargets. Target nodes are
461590Srgrimes * kept in two structures: a Lst, maintained by the list library, and a
471590Srgrimes * hash table, maintained by the hash library.
481590Srgrimes *
491590Srgrimes * Interface:
50144469Sharti *	Targ_Init	Initialization procedure.
511590Srgrimes *
52144469Sharti *	Targ_NewGN	Create a new GNode for the passed target (string).
53144469Sharti *			The node is *not* placed in the hash table, though all
54144469Sharti *			its fields are initialized.
551590Srgrimes *
56144469Sharti *	Targ_FindNode	Find the node for a given target, creating and storing
57144469Sharti *			it if it doesn't exist and the flags are right
58144469Sharti *			(TARG_CREATE)
591590Srgrimes *
60144469Sharti *	Targ_FindList	Given a list of names, find nodes for all of them. If a
61144469Sharti *			name doesn't exist and the TARG_NOCREATE flag was given,
62144469Sharti *			an error message is printed. Else, if a name doesn't
63144469Sharti *			exist, its node is created.
641590Srgrimes *
65144469Sharti *	Targ_Ignore	Return TRUE if errors should be ignored when creating
66144469Sharti *			the given target.
671590Srgrimes *
68144469Sharti *	Targ_Silent	Return TRUE if we should be silent when creating the
69144469Sharti *			given target.
701590Srgrimes *
71144469Sharti *	Targ_Precious	Return TRUE if the target is precious and should not
72144469Sharti *			be removed if we are interrupted.
731590Srgrimes *
741590Srgrimes * Debugging:
75144469Sharti *	Targ_PrintGraph	Print out the entire graphm all variables and statistics
76144469Sharti *			for the directory cache. Should print something for
77144469Sharti *			suffixes, too, but...
781590Srgrimes */
791590Srgrimes
80141104Sharti#include <stdio.h>
811590Srgrimes
82141104Sharti#include "dir.h"
83141104Sharti#include "globals.h"
84141104Sharti#include "GNode.h"
85141104Sharti#include "hash.h"
86141104Sharti#include "suff.h"
87141104Sharti#include "targ.h"
88141104Sharti#include "util.h"
89141104Sharti#include "var.h"
90141104Sharti
91138916Sharti/* the list of all targets found so far */
92138916Shartistatic Lst allTargets = Lst_Initializer(allTargets);
93138916Sharti
941590Srgrimesstatic Hash_Table targets;	/* a hash table of same */
951590Srgrimes
96103503Sjmallett#define	HTSIZE	191		/* initial size of hash table */
971590Srgrimes
98144469Sharti/**
99144469Sharti * Targ_Init
1001590Srgrimes *	Initialize this module
1011590Srgrimes *
1021590Srgrimes * Side Effects:
1031590Srgrimes *	The allTargets list and the targets hash table are initialized
1041590Srgrimes */
1051590Srgrimesvoid
106138232ShartiTarg_Init(void)
1071590Srgrimes{
108138232Sharti
109144469Sharti	Hash_InitTable(&targets, HTSIZE);
1101590Srgrimes}
1111590Srgrimes
112144469Sharti/**
113144469Sharti * Targ_NewGN
1141590Srgrimes *	Create and initialize a new graph node
1151590Srgrimes *
1161590Srgrimes * Results:
1171590Srgrimes *	An initialized graph node with the name field filled with a copy
1181590Srgrimes *	of the passed name
1191590Srgrimes *
1201590Srgrimes * Side Effects:
1215814Sjkh *	The gnode is added to the list of all gnodes.
1221590Srgrimes */
1231590SrgrimesGNode *
124141252ShartiTarg_NewGN(const char *name)
1251590Srgrimes{
126144469Sharti	GNode *gn;
1271590Srgrimes
128144469Sharti	gn = emalloc(sizeof(GNode));
129144469Sharti	gn->name = estrdup(name);
130144469Sharti	gn->path = NULL;
131144469Sharti	if (name[0] == '-' && name[1] == 'l') {
132144469Sharti		gn->type = OP_LIB;
133144469Sharti	} else {
134144469Sharti		gn->type = 0;
135144469Sharti	}
136144469Sharti	gn->unmade = 0;
137144469Sharti	gn->make = FALSE;
138144469Sharti	gn->made = UNMADE;
139144469Sharti	gn->childMade = FALSE;
140144469Sharti	gn->order = 0;
141144469Sharti	gn->mtime = gn->cmtime = 0;
142168893Sfjoe	gn->cmtime_gn = NULL;
143144469Sharti	Lst_Init(&gn->iParents);
144144469Sharti	Lst_Init(&gn->cohorts);
145144469Sharti	Lst_Init(&gn->parents);
146144469Sharti	Lst_Init(&gn->children);
147144469Sharti	Lst_Init(&gn->successors);
148144469Sharti	Lst_Init(&gn->preds);
149144469Sharti	Lst_Init(&gn->context);
150144469Sharti	Lst_Init(&gn->commands);
151144469Sharti	gn->suffix = NULL;
1521590Srgrimes
153144469Sharti	return (gn);
1541590Srgrimes}
1551590Srgrimes
156144469Sharti/**
157144469Sharti * Targ_FindNode
1581590Srgrimes *	Find a node in the list using the given name for matching
1591590Srgrimes *
1601590Srgrimes * Results:
16169527Swill *	The node in the list if it was. If it wasn't, return NULL of
1621590Srgrimes *	flags was TARG_NOCREATE or the newly created and initialized node
1631590Srgrimes *	if it was TARG_CREATE
1641590Srgrimes *
1651590Srgrimes * Side Effects:
1661590Srgrimes *	Sometimes a node is created and added to the list
1671590Srgrimes */
1681590SrgrimesGNode *
169141252ShartiTarg_FindNode(const char *name, int flags)
1701590Srgrimes{
171144469Sharti	GNode		*gn;	/* node in that element */
172144469Sharti	Hash_Entry	*he;	/* New or used hash entry for node */
173144469Sharti	Boolean		isNew;	/* Set TRUE if Hash_CreateEntry had to create */
174144469Sharti		      		/* an entry for the node */
1751590Srgrimes
176144469Sharti	if (flags & TARG_CREATE) {
177144469Sharti		he = Hash_CreateEntry(&targets, name, &isNew);
178144469Sharti		if (isNew) {
179144469Sharti			gn = Targ_NewGN(name);
180144469Sharti			Hash_SetValue(he, gn);
181144469Sharti			Lst_AtEnd(&allTargets, gn);
182144469Sharti		}
183144469Sharti	} else {
184144469Sharti		he = Hash_FindEntry(&targets, name);
1851590Srgrimes	}
1861590Srgrimes
187144469Sharti	if (he == NULL) {
188144469Sharti		return (NULL);
189144469Sharti	} else {
190144469Sharti		return (Hash_GetValue(he));
191144469Sharti	}
1921590Srgrimes}
1931590Srgrimes
194144469Sharti/**
195144469Sharti * Targ_FindList
1968874Srgrimes *	Make a complete list of GNodes from the given list of names
1971590Srgrimes *
1981590Srgrimes * Results:
1991590Srgrimes *	A complete list of graph nodes corresponding to all instances of all
2008874Srgrimes *	the names in names.
2011590Srgrimes *
2021590Srgrimes * Side Effects:
2031590Srgrimes *	If flags is TARG_CREATE, nodes will be created for all names in
2041590Srgrimes *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
2051590Srgrimes *	an error message will be printed for each name which can't be found.
2061590Srgrimes */
207138916Shartivoid
208138916ShartiTarg_FindList(Lst *nodes, Lst *names, int flags)
2091590Srgrimes{
210144469Sharti	LstNode	*ln;	/* name list element */
211144469Sharti	GNode	*gn;	/* node in tLn */
212144469Sharti	char	*name;
2131590Srgrimes
214144469Sharti	for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
215144469Sharti		name = Lst_Datum(ln);
216144469Sharti		gn = Targ_FindNode(name, flags);
217144469Sharti		if (gn != NULL) {
218144469Sharti			/*
219144469Sharti			 * Note: Lst_AtEnd must come before the Lst_Concat so
220144469Sharti			 * the nodes are added to the list in the order in which
221144469Sharti			 * they were encountered in the makefile.
222144469Sharti			 */
223144469Sharti			Lst_AtEnd(nodes, gn);
224144469Sharti			if (gn->type & OP_DOUBLEDEP) {
225144469Sharti				Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
226144469Sharti			}
227144469Sharti
228144469Sharti		} else if (flags == TARG_NOCREATE) {
229144469Sharti			Error("\"%s\" -- target unknown.", name);
230144469Sharti		}
2311590Srgrimes	}
2321590Srgrimes}
2331590Srgrimes
234144469Sharti/**
235144469Sharti * Targ_Ignore
2361590Srgrimes *	Return true if should ignore errors when creating gn
2371590Srgrimes *
2381590Srgrimes * Results:
2391590Srgrimes *	TRUE if should ignore errors
2401590Srgrimes */
2411590SrgrimesBoolean
242138232ShartiTarg_Ignore(GNode *gn)
2431590Srgrimes{
244138232Sharti
245144469Sharti	if (ignoreErrors || (gn->type & OP_IGNORE)) {
246144469Sharti		return (TRUE);
247144469Sharti	} else {
248144469Sharti		return (FALSE);
249144469Sharti	}
2501590Srgrimes}
2511590Srgrimes
252144469Sharti/**
253144469Sharti * Targ_Silent
2541590Srgrimes *	Return true if be silent when creating gn
2551590Srgrimes *
2561590Srgrimes * Results:
2571590Srgrimes *	TRUE if should be silent
2581590Srgrimes */
2591590SrgrimesBoolean
260138232ShartiTarg_Silent(GNode *gn)
2611590Srgrimes{
262138232Sharti
263144469Sharti	if (beSilent || (gn->type & OP_SILENT)) {
264144469Sharti		return (TRUE);
265144469Sharti	} else {
266144469Sharti		return (FALSE);
267144469Sharti	}
2681590Srgrimes}
2691590Srgrimes
270144469Sharti/**
271144469Sharti * Targ_Precious
2721590Srgrimes *	See if the given target is precious
2731590Srgrimes *
2741590Srgrimes * Results:
2751590Srgrimes *	TRUE if it is precious. FALSE otherwise
2761590Srgrimes */
2771590SrgrimesBoolean
278138232ShartiTarg_Precious(GNode *gn)
2791590Srgrimes{
280138232Sharti
281144469Sharti	if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
282144469Sharti		return (TRUE);
283144469Sharti	} else {
284144469Sharti		return (FALSE);
285144469Sharti	}
2861590Srgrimes}
2871590Srgrimes
288144469Shartistatic GNode	*mainTarg;	/* the main target, as set by Targ_SetMain */
2891590Srgrimes
290144469Sharti/**
291144469Sharti * Targ_SetMain
2921590Srgrimes *	Set our idea of the main target we'll be creating. Used for
2931590Srgrimes *	debugging output.
2941590Srgrimes *
2951590Srgrimes * Side Effects:
2961590Srgrimes *	"mainTarg" is set to the main target's node.
2971590Srgrimes */
2981590Srgrimesvoid
299138232ShartiTarg_SetMain(GNode *gn)
3001590Srgrimes{
301138232Sharti
302144469Sharti	mainTarg = gn;
3031590Srgrimes}
3041590Srgrimes
305144469Sharti/**
306144469Sharti * Targ_FmtTime
3071590Srgrimes *	Format a modification time in some reasonable way and return it.
3081590Srgrimes *
3091590Srgrimes * Results:
3101590Srgrimes *	The time reformatted.
3111590Srgrimes *
3121590Srgrimes * Side Effects:
3131590Srgrimes *	The time is placed in a static area, so it is overwritten
3141590Srgrimes *	with each call.
3151590Srgrimes */
3161590Srgrimeschar *
317138232ShartiTarg_FmtTime(time_t modtime)
3181590Srgrimes{
319144469Sharti	struct tm	*parts;
320144469Sharti	static char	buf[128];
3211590Srgrimes
322144469Sharti	parts = localtime(&modtime);
3231590Srgrimes
324144469Sharti	strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts);
325144469Sharti	buf[sizeof(buf) - 1] = '\0';
326144469Sharti	return (buf);
3271590Srgrimes}
3288874Srgrimes
329144469Sharti/**
330144469Sharti * Targ_PrintType
3311590Srgrimes *	Print out a type field giving only those attributes the user can
3321590Srgrimes *	set.
3331590Srgrimes */
3341590Srgrimesvoid
335138232ShartiTarg_PrintType(int type)
3361590Srgrimes{
337146184Sharti	static const struct flag2str type2str[] = {
338146184Sharti		{ OP_OPTIONAL,	".OPTIONAL" },
339146184Sharti		{ OP_USE,	".USE" },
340146184Sharti		{ OP_EXEC,	".EXEC" },
341146184Sharti		{ OP_IGNORE,	".IGNORE" },
342146184Sharti		{ OP_PRECIOUS,	".PRECIOUS" },
343146184Sharti		{ OP_SILENT,	".SILENT" },
344146184Sharti		{ OP_MAKE,	".MAKE" },
345146184Sharti		{ OP_JOIN,	".JOIN" },
346146184Sharti		{ OP_INVISIBLE,	".INVISIBLE" },
347146184Sharti		{ OP_NOTMAIN,	".NOTMAIN" },
348146184Sharti		{ OP_PHONY,	".PHONY" },
349146184Sharti		{ OP_LIB,	".LIB" },
350146184Sharti		{ OP_MEMBER,	".MEMBER" },
351146184Sharti		{ OP_ARCHV,	".ARCHV" },
352146184Sharti		{ 0,		NULL }
353146184Sharti	};
3548874Srgrimes
355144469Sharti	type &= ~OP_OPMASK;
356146184Sharti	if (!DEBUG(TARG))
357146184Sharti		type &= ~(OP_ARCHV | OP_LIB | OP_MEMBER);
358146184Sharti	print_flags(stdout, type2str, type, 0);
3591590Srgrimes}
3601590Srgrimes
361144469Sharti/**
362144469Sharti * TargPrintNode
3631590Srgrimes *	print the contents of a node
3641590Srgrimes */
3651590Srgrimesstatic int
366143650ShartiTargPrintNode(const GNode *gn, int pass)
3671590Srgrimes{
368144469Sharti	const LstNode	*tln;
369138232Sharti
370144469Sharti	if (!OP_NOP(gn->type)) {
371144469Sharti		printf("#\n");
372144469Sharti		if (gn == mainTarg) {
373144469Sharti			printf("# *** MAIN TARGET ***\n");
3741590Srgrimes		}
375144469Sharti		if (pass == 2) {
376144469Sharti			if (gn->unmade) {
377144469Sharti				printf("# %d unmade children\n", gn->unmade);
378144469Sharti			} else {
379144469Sharti				printf("# No unmade children\n");
380144469Sharti			}
381144469Sharti			if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
382144469Sharti				if (gn->mtime != 0) {
383144469Sharti					printf("# last modified %s: %s\n",
384144469Sharti					    Targ_FmtTime(gn->mtime),
385144469Sharti					    gn->made == UNMADE ? "unmade" :
386144469Sharti					    gn->made == MADE ? "made" :
387144469Sharti					    gn->made == UPTODATE ? "up-to-date":
388144469Sharti					    "error when made");
389144469Sharti				} else if (gn->made != UNMADE) {
390144469Sharti					printf("# non-existent (maybe): %s\n",
391144469Sharti					    gn->made == MADE ? "made" :
392144469Sharti					    gn->made == UPTODATE ? "up-to-date":
393144469Sharti					    gn->made == ERROR?"error when made":
394144469Sharti				 	    "aborted");
395144469Sharti				} else {
396144469Sharti					printf("# unmade\n");
397144469Sharti				}
398144469Sharti			}
399144469Sharti			if (!Lst_IsEmpty(&gn->iParents)) {
400144469Sharti				printf("# implicit parents: ");
401144469Sharti				LST_FOREACH(tln, &gn->iParents)
402144469Sharti					printf("%s ", ((const GNode *)
403144469Sharti					    Lst_Datum(tln))->name);
404144469Sharti				printf("\n");
405144469Sharti			}
406144469Sharti		}
407144469Sharti		if (!Lst_IsEmpty(&gn->parents)) {
408144469Sharti			printf("# parents: ");
409144469Sharti			LST_FOREACH(tln, &gn->parents)
410144469Sharti				printf("%s ", ((const GNode *)
411144469Sharti				    Lst_Datum(tln))->name);
412144469Sharti			printf("\n");
413144469Sharti		}
414144469Sharti
415144469Sharti		printf("%-16s", gn->name);
416144469Sharti		switch (gn->type & OP_OPMASK) {
417144469Sharti		  case OP_DEPENDS:
418144469Sharti			printf(": ");
419144469Sharti			break;
420144469Sharti		  case OP_FORCE:
421144469Sharti			printf("! ");
422144469Sharti			break;
423144469Sharti		  case OP_DOUBLEDEP:
424144469Sharti			printf(":: ");
425144469Sharti			break;
426144469Sharti		  default:
427144469Sharti			break;
428144469Sharti		}
429144469Sharti		Targ_PrintType(gn->type);
430144469Sharti		LST_FOREACH(tln, &gn->children)
431143650Sharti			printf("%s ", ((const GNode *)Lst_Datum(tln))->name);
432143650Sharti		printf("\n");
433144469Sharti		LST_FOREACH(tln, &gn->commands)
434144469Sharti			printf("\t%s\n", (const char *)Lst_Datum(tln));
435144469Sharti		printf("\n\n");
436144469Sharti		if (gn->type & OP_DOUBLEDEP) {
437144469Sharti			LST_FOREACH(tln, &gn->cohorts)
438144469Sharti				TargPrintNode((const GNode *)Lst_Datum(tln),
439144469Sharti				    pass);
440144469Sharti		}
4411590Srgrimes	}
442144469Sharti	return (0);
4431590Srgrimes}
4441590Srgrimes
445144469Sharti/**
446144469Sharti * Targ_PrintGraph
447104696Sjmallett *	Print the entire graph.
4481590Srgrimes */
4491590Srgrimesvoid
450138232ShartiTarg_PrintGraph(int pass)
4511590Srgrimes{
452144469Sharti	const GNode	*gn;
453144469Sharti	const LstNode	*tln;
454138264Sharti
455144469Sharti	printf("#*** Input graph:\n");
456144469Sharti	LST_FOREACH(tln, &allTargets)
457144469Sharti		TargPrintNode((const GNode *)Lst_Datum(tln), pass);
458144469Sharti	printf("\n\n");
459143650Sharti
460144469Sharti	printf("#\n#   Files that are only sources:\n");
461144469Sharti	LST_FOREACH(tln, &allTargets) {
462144469Sharti		gn = Lst_Datum(tln);
463144469Sharti		if (OP_NOP(gn->type))
464144469Sharti			printf("#\t%s [%s]\n", gn->name,
465144469Sharti			    gn->path ? gn->path : gn->name);
466144469Sharti	}
467146039Sharti	Var_Dump();
468144469Sharti	printf("\n");
469144469Sharti	Dir_PrintDirectories();
470144469Sharti	printf("\n");
471144469Sharti	Suff_PrintAll();
4721590Srgrimes}
473