1319884Ssjg/*	$NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $	*/
2236769Sobrien
3236769Sobrien/*
4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993
5236769Sobrien *	The Regents of the University of California.  All rights reserved.
6236769Sobrien *
7236769Sobrien * This code is derived from software contributed to Berkeley by
8236769Sobrien * Adam de Boor.
9236769Sobrien *
10236769Sobrien * Redistribution and use in source and binary forms, with or without
11236769Sobrien * modification, are permitted provided that the following conditions
12236769Sobrien * are met:
13236769Sobrien * 1. Redistributions of source code must retain the above copyright
14236769Sobrien *    notice, this list of conditions and the following disclaimer.
15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright
16236769Sobrien *    notice, this list of conditions and the following disclaimer in the
17236769Sobrien *    documentation and/or other materials provided with the distribution.
18236769Sobrien * 3. Neither the name of the University nor the names of its contributors
19236769Sobrien *    may be used to endorse or promote products derived from this software
20236769Sobrien *    without specific prior written permission.
21236769Sobrien *
22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25236769Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32236769Sobrien * SUCH DAMAGE.
33236769Sobrien */
34236769Sobrien
35236769Sobrien/*
36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks
37236769Sobrien * All rights reserved.
38236769Sobrien *
39236769Sobrien * This code is derived from software contributed to Berkeley by
40236769Sobrien * Adam de Boor.
41236769Sobrien *
42236769Sobrien * Redistribution and use in source and binary forms, with or without
43236769Sobrien * modification, are permitted provided that the following conditions
44236769Sobrien * are met:
45236769Sobrien * 1. Redistributions of source code must retain the above copyright
46236769Sobrien *    notice, this list of conditions and the following disclaimer.
47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright
48236769Sobrien *    notice, this list of conditions and the following disclaimer in the
49236769Sobrien *    documentation and/or other materials provided with the distribution.
50236769Sobrien * 3. All advertising materials mentioning features or use of this software
51236769Sobrien *    must display the following acknowledgement:
52236769Sobrien *	This product includes software developed by the University of
53236769Sobrien *	California, Berkeley and its contributors.
54236769Sobrien * 4. Neither the name of the University nor the names of its contributors
55236769Sobrien *    may be used to endorse or promote products derived from this software
56236769Sobrien *    without specific prior written permission.
57236769Sobrien *
58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61236769Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68236769Sobrien * SUCH DAMAGE.
69236769Sobrien */
70236769Sobrien
71236769Sobrien#ifndef MAKE_NATIVE
72319884Ssjgstatic char rcsid[] = "$NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $";
73236769Sobrien#else
74236769Sobrien#include <sys/cdefs.h>
75236769Sobrien#ifndef lint
76236769Sobrien#if 0
77236769Sobrienstatic char sccsid[] = "@(#)targ.c	8.2 (Berkeley) 3/19/94";
78236769Sobrien#else
79319884Ssjg__RCSID("$NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $");
80236769Sobrien#endif
81236769Sobrien#endif /* not lint */
82236769Sobrien#endif
83236769Sobrien
84236769Sobrien/*-
85236769Sobrien * targ.c --
86236769Sobrien *	Functions for maintaining the Lst allTargets. Target nodes are
87236769Sobrien * kept in two structures: a Lst, maintained by the list library, and a
88236769Sobrien * hash table, maintained by the hash library.
89236769Sobrien *
90236769Sobrien * Interface:
91236769Sobrien *	Targ_Init 	    	Initialization procedure.
92236769Sobrien *
93236769Sobrien *	Targ_End 	    	Cleanup the module
94236769Sobrien *
95236769Sobrien *	Targ_List 	    	Return the list of all targets so far.
96236769Sobrien *
97236769Sobrien *	Targ_NewGN	    	Create a new GNode for the passed target
98236769Sobrien *	    	  	    	(string). The node is *not* placed in the
99236769Sobrien *	    	  	    	hash table, though all its fields are
100236769Sobrien *	    	  	    	initialized.
101236769Sobrien *
102236769Sobrien *	Targ_FindNode	    	Find the node for a given target, creating
103236769Sobrien *	    	  	    	and storing it if it doesn't exist and the
104236769Sobrien *	    	  	    	flags are right (TARG_CREATE)
105236769Sobrien *
106236769Sobrien *	Targ_FindList	    	Given a list of names, find nodes for all
107236769Sobrien *	    	  	    	of them. If a name doesn't exist and the
108236769Sobrien *	    	  	    	TARG_NOCREATE flag was given, an error message
109236769Sobrien *	    	  	    	is printed. Else, if a name doesn't exist,
110236769Sobrien *	    	  	    	its node is created.
111236769Sobrien *
112236769Sobrien *	Targ_Ignore	    	Return TRUE if errors should be ignored when
113236769Sobrien *	    	  	    	creating the given target.
114236769Sobrien *
115236769Sobrien *	Targ_Silent	    	Return TRUE if we should be silent when
116236769Sobrien *	    	  	    	creating the given target.
117236769Sobrien *
118236769Sobrien *	Targ_Precious	    	Return TRUE if the target is precious and
119236769Sobrien *	    	  	    	should not be removed if we are interrupted.
120236769Sobrien *
121236769Sobrien *	Targ_Propagate		Propagate information between related
122236769Sobrien *				nodes.	Should be called after the
123236769Sobrien *				makefiles are parsed but before any
124236769Sobrien *				action is taken.
125236769Sobrien *
126236769Sobrien * Debugging:
127236769Sobrien *	Targ_PrintGraph	    	Print out the entire graphm all variables
128236769Sobrien *	    	  	    	and statistics for the directory cache. Should
129236769Sobrien *	    	  	    	print something for suffixes, too, but...
130236769Sobrien */
131236769Sobrien
132236769Sobrien#include	  <stdio.h>
133236769Sobrien#include	  <time.h>
134236769Sobrien
135236769Sobrien#include	  "make.h"
136236769Sobrien#include	  "hash.h"
137236769Sobrien#include	  "dir.h"
138236769Sobrien
139236769Sobrienstatic Lst        allTargets;	/* the list of all targets found so far */
140236769Sobrien#ifdef CLEANUP
141236769Sobrienstatic Lst	  allGNs;	/* List of all the GNodes */
142236769Sobrien#endif
143236769Sobrienstatic Hash_Table targets;	/* a hash table of same */
144236769Sobrien
145236769Sobrien#define HTSIZE	191		/* initial size of hash table */
146236769Sobrien
147236769Sobrienstatic int TargPrintOnlySrc(void *, void *);
148236769Sobrienstatic int TargPrintName(void *, void *);
149236769Sobrien#ifdef CLEANUP
150236769Sobrienstatic void TargFreeGN(void *);
151236769Sobrien#endif
152236769Sobrienstatic int TargPropagateCohort(void *, void *);
153236769Sobrienstatic int TargPropagateNode(void *, void *);
154236769Sobrien
155236769Sobrien/*-
156236769Sobrien *-----------------------------------------------------------------------
157236769Sobrien * Targ_Init --
158236769Sobrien *	Initialize this module
159236769Sobrien *
160236769Sobrien * Results:
161236769Sobrien *	None
162236769Sobrien *
163236769Sobrien * Side Effects:
164236769Sobrien *	The allTargets list and the targets hash table are initialized
165236769Sobrien *-----------------------------------------------------------------------
166236769Sobrien */
167236769Sobrienvoid
168236769SobrienTarg_Init(void)
169236769Sobrien{
170236769Sobrien    allTargets = Lst_Init(FALSE);
171236769Sobrien    Hash_InitTable(&targets, HTSIZE);
172236769Sobrien}
173236769Sobrien
174236769Sobrien/*-
175236769Sobrien *-----------------------------------------------------------------------
176236769Sobrien * Targ_End --
177236769Sobrien *	Finalize this module
178236769Sobrien *
179236769Sobrien * Results:
180236769Sobrien *	None
181236769Sobrien *
182236769Sobrien * Side Effects:
183236769Sobrien *	All lists and gnodes are cleared
184236769Sobrien *-----------------------------------------------------------------------
185236769Sobrien */
186236769Sobrienvoid
187236769SobrienTarg_End(void)
188236769Sobrien{
189236769Sobrien#ifdef CLEANUP
190236769Sobrien    Lst_Destroy(allTargets, NULL);
191236769Sobrien    if (allGNs)
192236769Sobrien	Lst_Destroy(allGNs, TargFreeGN);
193236769Sobrien    Hash_DeleteTable(&targets);
194236769Sobrien#endif
195236769Sobrien}
196236769Sobrien
197236769Sobrien/*-
198236769Sobrien *-----------------------------------------------------------------------
199236769Sobrien * Targ_List --
200236769Sobrien *	Return the list of all targets
201236769Sobrien *
202236769Sobrien * Results:
203236769Sobrien *	The list of all targets.
204236769Sobrien *
205236769Sobrien * Side Effects:
206236769Sobrien *	None
207236769Sobrien *-----------------------------------------------------------------------
208236769Sobrien */
209236769SobrienLst
210236769SobrienTarg_List(void)
211236769Sobrien{
212236769Sobrien    return allTargets;
213236769Sobrien}
214236769Sobrien
215236769Sobrien/*-
216236769Sobrien *-----------------------------------------------------------------------
217236769Sobrien * Targ_NewGN  --
218236769Sobrien *	Create and initialize a new graph node
219236769Sobrien *
220236769Sobrien * Input:
221236769Sobrien *	name		the name to stick in the new node
222236769Sobrien *
223236769Sobrien * Results:
224236769Sobrien *	An initialized graph node with the name field filled with a copy
225236769Sobrien *	of the passed name
226236769Sobrien *
227236769Sobrien * Side Effects:
228236769Sobrien *	The gnode is added to the list of all gnodes.
229236769Sobrien *-----------------------------------------------------------------------
230236769Sobrien */
231236769SobrienGNode *
232236769SobrienTarg_NewGN(const char *name)
233236769Sobrien{
234236769Sobrien    GNode *gn;
235236769Sobrien
236236769Sobrien    gn = bmake_malloc(sizeof(GNode));
237236769Sobrien    gn->name = bmake_strdup(name);
238236769Sobrien    gn->uname = NULL;
239236769Sobrien    gn->path = NULL;
240236769Sobrien    if (name[0] == '-' && name[1] == 'l') {
241236769Sobrien	gn->type = OP_LIB;
242236769Sobrien    } else {
243236769Sobrien	gn->type = 0;
244236769Sobrien    }
245236769Sobrien    gn->unmade =    	0;
246236769Sobrien    gn->unmade_cohorts = 0;
247236769Sobrien    gn->cohort_num[0] = 0;
248236769Sobrien    gn->centurion =    	NULL;
249236769Sobrien    gn->made = 	    	UNMADE;
250236769Sobrien    gn->flags = 	0;
251236769Sobrien    gn->checked =	0;
252236769Sobrien    gn->mtime =		0;
253236769Sobrien    gn->cmgn =		NULL;
254236769Sobrien    gn->iParents =  	Lst_Init(FALSE);
255236769Sobrien    gn->cohorts =   	Lst_Init(FALSE);
256236769Sobrien    gn->parents =   	Lst_Init(FALSE);
257236769Sobrien    gn->children =  	Lst_Init(FALSE);
258236769Sobrien    gn->order_pred =  	Lst_Init(FALSE);
259236769Sobrien    gn->order_succ =  	Lst_Init(FALSE);
260236769Sobrien    Hash_InitTable(&gn->context, 0);
261236769Sobrien    gn->commands =  	Lst_Init(FALSE);
262236769Sobrien    gn->suffix =	NULL;
263236769Sobrien    gn->lineno =	0;
264236769Sobrien    gn->fname = 	NULL;
265236769Sobrien
266236769Sobrien#ifdef CLEANUP
267236769Sobrien    if (allGNs == NULL)
268236769Sobrien	allGNs = Lst_Init(FALSE);
269236769Sobrien    Lst_AtEnd(allGNs, gn);
270236769Sobrien#endif
271236769Sobrien
272236769Sobrien    return (gn);
273236769Sobrien}
274236769Sobrien
275236769Sobrien#ifdef CLEANUP
276236769Sobrien/*-
277236769Sobrien *-----------------------------------------------------------------------
278236769Sobrien * TargFreeGN  --
279236769Sobrien *	Destroy a GNode
280236769Sobrien *
281236769Sobrien * Results:
282236769Sobrien *	None.
283236769Sobrien *
284236769Sobrien * Side Effects:
285236769Sobrien *	None.
286236769Sobrien *-----------------------------------------------------------------------
287236769Sobrien */
288236769Sobrienstatic void
289236769SobrienTargFreeGN(void *gnp)
290236769Sobrien{
291236769Sobrien    GNode *gn = (GNode *)gnp;
292236769Sobrien
293236769Sobrien
294236769Sobrien    free(gn->name);
295296637Ssjg    free(gn->uname);
296296637Ssjg    free(gn->path);
297236769Sobrien    /* gn->fname points to name allocated when file was opened, don't free */
298236769Sobrien
299236769Sobrien    Lst_Destroy(gn->iParents, NULL);
300236769Sobrien    Lst_Destroy(gn->cohorts, NULL);
301236769Sobrien    Lst_Destroy(gn->parents, NULL);
302236769Sobrien    Lst_Destroy(gn->children, NULL);
303236769Sobrien    Lst_Destroy(gn->order_succ, NULL);
304236769Sobrien    Lst_Destroy(gn->order_pred, NULL);
305236769Sobrien    Hash_DeleteTable(&gn->context);
306236769Sobrien    Lst_Destroy(gn->commands, NULL);
307236769Sobrien    free(gn);
308236769Sobrien}
309236769Sobrien#endif
310236769Sobrien
311236769Sobrien
312236769Sobrien/*-
313236769Sobrien *-----------------------------------------------------------------------
314236769Sobrien * Targ_FindNode  --
315236769Sobrien *	Find a node in the list using the given name for matching
316236769Sobrien *
317236769Sobrien * Input:
318236769Sobrien *	name		the name to find
319236769Sobrien *	flags		flags governing events when target not
320236769Sobrien *			found
321236769Sobrien *
322236769Sobrien * Results:
323236769Sobrien *	The node in the list if it was. If it wasn't, return NULL of
324236769Sobrien *	flags was TARG_NOCREATE or the newly created and initialized node
325236769Sobrien *	if it was TARG_CREATE
326236769Sobrien *
327236769Sobrien * Side Effects:
328236769Sobrien *	Sometimes a node is created and added to the list
329236769Sobrien *-----------------------------------------------------------------------
330236769Sobrien */
331236769SobrienGNode *
332236769SobrienTarg_FindNode(const char *name, int flags)
333236769Sobrien{
334236769Sobrien    GNode         *gn;	      /* node in that element */
335236769Sobrien    Hash_Entry	  *he = NULL; /* New or used hash entry for node */
336236769Sobrien    Boolean	  isNew;      /* Set TRUE if Hash_CreateEntry had to create */
337236769Sobrien			      /* an entry for the node */
338236769Sobrien
339236769Sobrien    if (!(flags & (TARG_CREATE | TARG_NOHASH))) {
340236769Sobrien	he = Hash_FindEntry(&targets, name);
341236769Sobrien	if (he == NULL)
342236769Sobrien	    return NULL;
343236769Sobrien	return (GNode *)Hash_GetValue(he);
344236769Sobrien    }
345236769Sobrien
346236769Sobrien    if (!(flags & TARG_NOHASH)) {
347236769Sobrien	he = Hash_CreateEntry(&targets, name, &isNew);
348236769Sobrien	if (!isNew)
349236769Sobrien	    return (GNode *)Hash_GetValue(he);
350236769Sobrien    }
351236769Sobrien
352236769Sobrien    gn = Targ_NewGN(name);
353236769Sobrien    if (!(flags & TARG_NOHASH))
354236769Sobrien	Hash_SetValue(he, gn);
355236769Sobrien    Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
356236769Sobrien    (void)Lst_AtEnd(allTargets, gn);
357236769Sobrien    if (doing_depend)
358236769Sobrien	gn->flags |= FROM_DEPEND;
359236769Sobrien    return gn;
360236769Sobrien}
361236769Sobrien
362236769Sobrien/*-
363236769Sobrien *-----------------------------------------------------------------------
364236769Sobrien * Targ_FindList --
365236769Sobrien *	Make a complete list of GNodes from the given list of names
366236769Sobrien *
367236769Sobrien * Input:
368236769Sobrien *	name		list of names to find
369236769Sobrien *	flags		flags used if no node is found for a given name
370236769Sobrien *
371236769Sobrien * Results:
372236769Sobrien *	A complete list of graph nodes corresponding to all instances of all
373236769Sobrien *	the names in names.
374236769Sobrien *
375236769Sobrien * Side Effects:
376236769Sobrien *	If flags is TARG_CREATE, nodes will be created for all names in
377236769Sobrien *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
378236769Sobrien *	an error message will be printed for each name which can't be found.
379236769Sobrien * -----------------------------------------------------------------------
380236769Sobrien */
381236769SobrienLst
382236769SobrienTarg_FindList(Lst names, int flags)
383236769Sobrien{
384236769Sobrien    Lst            nodes;	/* result list */
385236769Sobrien    LstNode	   ln;		/* name list element */
386236769Sobrien    GNode	   *gn;		/* node in tLn */
387236769Sobrien    char    	   *name;
388236769Sobrien
389236769Sobrien    nodes = Lst_Init(FALSE);
390236769Sobrien
391236769Sobrien    if (Lst_Open(names) == FAILURE) {
392236769Sobrien	return (nodes);
393236769Sobrien    }
394236769Sobrien    while ((ln = Lst_Next(names)) != NULL) {
395236769Sobrien	name = (char *)Lst_Datum(ln);
396236769Sobrien	gn = Targ_FindNode(name, flags);
397236769Sobrien	if (gn != NULL) {
398236769Sobrien	    /*
399236769Sobrien	     * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
400236769Sobrien	     * are added to the list in the order in which they were
401236769Sobrien	     * encountered in the makefile.
402236769Sobrien	     */
403236769Sobrien	    (void)Lst_AtEnd(nodes, gn);
404236769Sobrien	} else if (flags == TARG_NOCREATE) {
405236769Sobrien	    Error("\"%s\" -- target unknown.", name);
406236769Sobrien	}
407236769Sobrien    }
408236769Sobrien    Lst_Close(names);
409236769Sobrien    return (nodes);
410236769Sobrien}
411236769Sobrien
412236769Sobrien/*-
413236769Sobrien *-----------------------------------------------------------------------
414236769Sobrien * Targ_Ignore  --
415236769Sobrien *	Return true if should ignore errors when creating gn
416236769Sobrien *
417236769Sobrien * Input:
418236769Sobrien *	gn		node to check for
419236769Sobrien *
420236769Sobrien * Results:
421236769Sobrien *	TRUE if should ignore errors
422236769Sobrien *
423236769Sobrien * Side Effects:
424236769Sobrien *	None
425236769Sobrien *-----------------------------------------------------------------------
426236769Sobrien */
427236769SobrienBoolean
428236769SobrienTarg_Ignore(GNode *gn)
429236769Sobrien{
430236769Sobrien    if (ignoreErrors || gn->type & OP_IGNORE) {
431236769Sobrien	return (TRUE);
432236769Sobrien    } else {
433236769Sobrien	return (FALSE);
434236769Sobrien    }
435236769Sobrien}
436236769Sobrien
437236769Sobrien/*-
438236769Sobrien *-----------------------------------------------------------------------
439236769Sobrien * Targ_Silent  --
440236769Sobrien *	Return true if be silent when creating gn
441236769Sobrien *
442236769Sobrien * Input:
443236769Sobrien *	gn		node to check for
444236769Sobrien *
445236769Sobrien * Results:
446236769Sobrien *	TRUE if should be silent
447236769Sobrien *
448236769Sobrien * Side Effects:
449236769Sobrien *	None
450236769Sobrien *-----------------------------------------------------------------------
451236769Sobrien */
452236769SobrienBoolean
453236769SobrienTarg_Silent(GNode *gn)
454236769Sobrien{
455236769Sobrien    if (beSilent || gn->type & OP_SILENT) {
456236769Sobrien	return (TRUE);
457236769Sobrien    } else {
458236769Sobrien	return (FALSE);
459236769Sobrien    }
460236769Sobrien}
461236769Sobrien
462236769Sobrien/*-
463236769Sobrien *-----------------------------------------------------------------------
464236769Sobrien * Targ_Precious --
465236769Sobrien *	See if the given target is precious
466236769Sobrien *
467236769Sobrien * Input:
468236769Sobrien *	gn		the node to check
469236769Sobrien *
470236769Sobrien * Results:
471236769Sobrien *	TRUE if it is precious. FALSE otherwise
472236769Sobrien *
473236769Sobrien * Side Effects:
474236769Sobrien *	None
475236769Sobrien *-----------------------------------------------------------------------
476236769Sobrien */
477236769SobrienBoolean
478236769SobrienTarg_Precious(GNode *gn)
479236769Sobrien{
480236769Sobrien    if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
481236769Sobrien	return (TRUE);
482236769Sobrien    } else {
483236769Sobrien	return (FALSE);
484236769Sobrien    }
485236769Sobrien}
486236769Sobrien
487236769Sobrien/******************* DEBUG INFO PRINTING ****************/
488236769Sobrien
489236769Sobrienstatic GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
490236769Sobrien/*-
491236769Sobrien *-----------------------------------------------------------------------
492236769Sobrien * Targ_SetMain --
493236769Sobrien *	Set our idea of the main target we'll be creating. Used for
494236769Sobrien *	debugging output.
495236769Sobrien *
496236769Sobrien * Input:
497236769Sobrien *	gn		The main target we'll create
498236769Sobrien *
499236769Sobrien * Results:
500236769Sobrien *	None.
501236769Sobrien *
502236769Sobrien * Side Effects:
503236769Sobrien *	"mainTarg" is set to the main target's node.
504236769Sobrien *-----------------------------------------------------------------------
505236769Sobrien */
506236769Sobrienvoid
507236769SobrienTarg_SetMain(GNode *gn)
508236769Sobrien{
509236769Sobrien    mainTarg = gn;
510236769Sobrien}
511236769Sobrien
512236769Sobrienstatic int
513237578SobrienTargPrintName(void *gnp, void *pflags MAKE_ATTR_UNUSED)
514236769Sobrien{
515236769Sobrien    GNode *gn = (GNode *)gnp;
516236769Sobrien
517236769Sobrien    fprintf(debug_file, "%s%s ", gn->name, gn->cohort_num);
518236769Sobrien
519236769Sobrien    return 0;
520236769Sobrien}
521236769Sobrien
522236769Sobrien
523236769Sobrienint
524319884SsjgTarg_PrintCmd(void *cmd, void *dummy MAKE_ATTR_UNUSED)
525236769Sobrien{
526236769Sobrien    fprintf(debug_file, "\t%s\n", (char *)cmd);
527319884Ssjg    return 0;
528236769Sobrien}
529236769Sobrien
530236769Sobrien/*-
531236769Sobrien *-----------------------------------------------------------------------
532236769Sobrien * Targ_FmtTime --
533236769Sobrien *	Format a modification time in some reasonable way and return it.
534236769Sobrien *
535236769Sobrien * Results:
536236769Sobrien *	The time reformatted.
537236769Sobrien *
538236769Sobrien * Side Effects:
539236769Sobrien *	The time is placed in a static area, so it is overwritten
540236769Sobrien *	with each call.
541236769Sobrien *
542236769Sobrien *-----------------------------------------------------------------------
543236769Sobrien */
544236769Sobrienchar *
545236769SobrienTarg_FmtTime(time_t tm)
546236769Sobrien{
547236769Sobrien    struct tm	  	*parts;
548236769Sobrien    static char	  	buf[128];
549236769Sobrien
550236769Sobrien    parts = localtime(&tm);
551236769Sobrien    (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
552236769Sobrien    return(buf);
553236769Sobrien}
554236769Sobrien
555236769Sobrien/*-
556236769Sobrien *-----------------------------------------------------------------------
557236769Sobrien * Targ_PrintType --
558236769Sobrien *	Print out a type field giving only those attributes the user can
559236769Sobrien *	set.
560236769Sobrien *
561236769Sobrien * Results:
562236769Sobrien *
563236769Sobrien * Side Effects:
564236769Sobrien *
565236769Sobrien *-----------------------------------------------------------------------
566236769Sobrien */
567236769Sobrienvoid
568236769SobrienTarg_PrintType(int type)
569236769Sobrien{
570236769Sobrien    int    tbit;
571236769Sobrien
572236769Sobrien#define PRINTBIT(attr)	case CONCAT(OP_,attr): fprintf(debug_file, "." #attr " "); break
573236769Sobrien#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))fprintf(debug_file, "." #attr " "); break
574236769Sobrien
575236769Sobrien    type &= ~OP_OPMASK;
576236769Sobrien
577236769Sobrien    while (type) {
578236769Sobrien	tbit = 1 << (ffs(type) - 1);
579236769Sobrien	type &= ~tbit;
580236769Sobrien
581236769Sobrien	switch(tbit) {
582236769Sobrien	    PRINTBIT(OPTIONAL);
583236769Sobrien	    PRINTBIT(USE);
584236769Sobrien	    PRINTBIT(EXEC);
585236769Sobrien	    PRINTBIT(IGNORE);
586236769Sobrien	    PRINTBIT(PRECIOUS);
587236769Sobrien	    PRINTBIT(SILENT);
588236769Sobrien	    PRINTBIT(MAKE);
589236769Sobrien	    PRINTBIT(JOIN);
590236769Sobrien	    PRINTBIT(INVISIBLE);
591236769Sobrien	    PRINTBIT(NOTMAIN);
592236769Sobrien	    PRINTDBIT(LIB);
593236769Sobrien	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
594236769Sobrien	    case OP_MEMBER: if (DEBUG(TARG))fprintf(debug_file, ".MEMBER "); break;
595236769Sobrien	    PRINTDBIT(ARCHV);
596236769Sobrien	    PRINTDBIT(MADE);
597236769Sobrien	    PRINTDBIT(PHONY);
598236769Sobrien	}
599236769Sobrien    }
600236769Sobrien}
601236769Sobrien
602236769Sobrienstatic const char *
603236769Sobrienmade_name(enum enum_made made)
604236769Sobrien{
605236769Sobrien    switch (made) {
606236769Sobrien    case UNMADE:     return "unmade";
607236769Sobrien    case DEFERRED:   return "deferred";
608236769Sobrien    case REQUESTED:  return "requested";
609236769Sobrien    case BEINGMADE:  return "being made";
610236769Sobrien    case MADE:       return "made";
611236769Sobrien    case UPTODATE:   return "up-to-date";
612236769Sobrien    case ERROR:      return "error when made";
613236769Sobrien    case ABORTED:    return "aborted";
614236769Sobrien    default:         return "unknown enum_made value";
615236769Sobrien    }
616236769Sobrien}
617236769Sobrien
618236769Sobrien/*-
619236769Sobrien *-----------------------------------------------------------------------
620236769Sobrien * TargPrintNode --
621236769Sobrien *	print the contents of a node
622236769Sobrien *-----------------------------------------------------------------------
623236769Sobrien */
624236769Sobrienint
625236769SobrienTarg_PrintNode(void *gnp, void *passp)
626236769Sobrien{
627236769Sobrien    GNode         *gn = (GNode *)gnp;
628236769Sobrien    int	    	  pass = passp ? *(int *)passp : 0;
629236769Sobrien
630236769Sobrien    fprintf(debug_file, "# %s%s, flags %x, type %x, made %d\n",
631236769Sobrien	    gn->name, gn->cohort_num, gn->flags, gn->type, gn->made);
632236769Sobrien    if (gn->flags == 0)
633236769Sobrien	return 0;
634236769Sobrien
635236769Sobrien    if (!OP_NOP(gn->type)) {
636236769Sobrien	fprintf(debug_file, "#\n");
637236769Sobrien	if (gn == mainTarg) {
638236769Sobrien	    fprintf(debug_file, "# *** MAIN TARGET ***\n");
639236769Sobrien	}
640236769Sobrien	if (pass >= 2) {
641236769Sobrien	    if (gn->unmade) {
642236769Sobrien		fprintf(debug_file, "# %d unmade children\n", gn->unmade);
643236769Sobrien	    } else {
644236769Sobrien		fprintf(debug_file, "# No unmade children\n");
645236769Sobrien	    }
646236769Sobrien	    if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
647236769Sobrien		if (gn->mtime != 0) {
648236769Sobrien		    fprintf(debug_file, "# last modified %s: %s\n",
649236769Sobrien			      Targ_FmtTime(gn->mtime),
650236769Sobrien			      made_name(gn->made));
651236769Sobrien		} else if (gn->made != UNMADE) {
652236769Sobrien		    fprintf(debug_file, "# non-existent (maybe): %s\n",
653236769Sobrien			      made_name(gn->made));
654236769Sobrien		} else {
655236769Sobrien		    fprintf(debug_file, "# unmade\n");
656236769Sobrien		}
657236769Sobrien	    }
658236769Sobrien	    if (!Lst_IsEmpty (gn->iParents)) {
659236769Sobrien		fprintf(debug_file, "# implicit parents: ");
660236769Sobrien		Lst_ForEach(gn->iParents, TargPrintName, NULL);
661236769Sobrien		fprintf(debug_file, "\n");
662236769Sobrien	    }
663236769Sobrien	} else {
664236769Sobrien	    if (gn->unmade)
665236769Sobrien		fprintf(debug_file, "# %d unmade children\n", gn->unmade);
666236769Sobrien	}
667236769Sobrien	if (!Lst_IsEmpty (gn->parents)) {
668236769Sobrien	    fprintf(debug_file, "# parents: ");
669236769Sobrien	    Lst_ForEach(gn->parents, TargPrintName, NULL);
670236769Sobrien	    fprintf(debug_file, "\n");
671236769Sobrien	}
672236769Sobrien	if (!Lst_IsEmpty (gn->order_pred)) {
673236769Sobrien	    fprintf(debug_file, "# order_pred: ");
674236769Sobrien	    Lst_ForEach(gn->order_pred, TargPrintName, NULL);
675236769Sobrien	    fprintf(debug_file, "\n");
676236769Sobrien	}
677236769Sobrien	if (!Lst_IsEmpty (gn->order_succ)) {
678236769Sobrien	    fprintf(debug_file, "# order_succ: ");
679236769Sobrien	    Lst_ForEach(gn->order_succ, TargPrintName, NULL);
680236769Sobrien	    fprintf(debug_file, "\n");
681236769Sobrien	}
682236769Sobrien
683236769Sobrien	fprintf(debug_file, "%-16s", gn->name);
684236769Sobrien	switch (gn->type & OP_OPMASK) {
685236769Sobrien	    case OP_DEPENDS:
686236769Sobrien		fprintf(debug_file, ": "); break;
687236769Sobrien	    case OP_FORCE:
688236769Sobrien		fprintf(debug_file, "! "); break;
689236769Sobrien	    case OP_DOUBLEDEP:
690236769Sobrien		fprintf(debug_file, ":: "); break;
691236769Sobrien	}
692236769Sobrien	Targ_PrintType(gn->type);
693236769Sobrien	Lst_ForEach(gn->children, TargPrintName, NULL);
694236769Sobrien	fprintf(debug_file, "\n");
695236769Sobrien	Lst_ForEach(gn->commands, Targ_PrintCmd, NULL);
696236769Sobrien	fprintf(debug_file, "\n\n");
697236769Sobrien	if (gn->type & OP_DOUBLEDEP) {
698236769Sobrien	    Lst_ForEach(gn->cohorts, Targ_PrintNode, &pass);
699236769Sobrien	}
700236769Sobrien    }
701236769Sobrien    return (0);
702236769Sobrien}
703236769Sobrien
704236769Sobrien/*-
705236769Sobrien *-----------------------------------------------------------------------
706236769Sobrien * TargPrintOnlySrc --
707236769Sobrien *	Print only those targets that are just a source.
708236769Sobrien *
709236769Sobrien * Results:
710236769Sobrien *	0.
711236769Sobrien *
712236769Sobrien * Side Effects:
713236769Sobrien *	The name of each file is printed preceded by #\t
714236769Sobrien *
715236769Sobrien *-----------------------------------------------------------------------
716236769Sobrien */
717236769Sobrienstatic int
718237578SobrienTargPrintOnlySrc(void *gnp, void *dummy MAKE_ATTR_UNUSED)
719236769Sobrien{
720236769Sobrien    GNode   	  *gn = (GNode *)gnp;
721236769Sobrien    if (!OP_NOP(gn->type))
722236769Sobrien	return 0;
723236769Sobrien
724236769Sobrien    fprintf(debug_file, "#\t%s [%s] ",
725236769Sobrien	    gn->name, gn->path ? gn->path : gn->name);
726236769Sobrien    Targ_PrintType(gn->type);
727236769Sobrien    fprintf(debug_file, "\n");
728236769Sobrien
729236769Sobrien    return 0;
730236769Sobrien}
731236769Sobrien
732236769Sobrien/*-
733236769Sobrien *-----------------------------------------------------------------------
734236769Sobrien * Targ_PrintGraph --
735236769Sobrien *	print the entire graph. heh heh
736236769Sobrien *
737236769Sobrien * Input:
738236769Sobrien *	pass		Which pass this is. 1 => no processing
739236769Sobrien *			2 => processing done
740236769Sobrien *
741236769Sobrien * Results:
742236769Sobrien *	none
743236769Sobrien *
744236769Sobrien * Side Effects:
745236769Sobrien *	lots o' output
746236769Sobrien *-----------------------------------------------------------------------
747236769Sobrien */
748236769Sobrienvoid
749236769SobrienTarg_PrintGraph(int pass)
750236769Sobrien{
751236769Sobrien    fprintf(debug_file, "#*** Input graph:\n");
752236769Sobrien    Lst_ForEach(allTargets, Targ_PrintNode, &pass);
753236769Sobrien    fprintf(debug_file, "\n\n");
754236769Sobrien    fprintf(debug_file, "#\n#   Files that are only sources:\n");
755236769Sobrien    Lst_ForEach(allTargets, TargPrintOnlySrc, NULL);
756236769Sobrien    fprintf(debug_file, "#*** Global Variables:\n");
757236769Sobrien    Var_Dump(VAR_GLOBAL);
758236769Sobrien    fprintf(debug_file, "#*** Command-line Variables:\n");
759236769Sobrien    Var_Dump(VAR_CMD);
760236769Sobrien    fprintf(debug_file, "\n");
761236769Sobrien    Dir_PrintDirectories();
762236769Sobrien    fprintf(debug_file, "\n");
763236769Sobrien    Suff_PrintAll();
764236769Sobrien}
765236769Sobrien
766236769Sobrien/*-
767236769Sobrien *-----------------------------------------------------------------------
768236769Sobrien * TargPropagateNode --
769236769Sobrien *	Propagate information from a single node to related nodes if
770236769Sobrien *	appropriate.
771236769Sobrien *
772236769Sobrien * Input:
773236769Sobrien *	gnp		The node that we are processing.
774236769Sobrien *
775236769Sobrien * Results:
776236769Sobrien *	Always returns 0, for the benefit of Lst_ForEach().
777236769Sobrien *
778236769Sobrien * Side Effects:
779236769Sobrien *	Information is propagated from this node to cohort or child
780236769Sobrien *	nodes.
781236769Sobrien *
782236769Sobrien *	If the node was defined with "::", then TargPropagateCohort()
783236769Sobrien *	will be called for each cohort node.
784236769Sobrien *
785236769Sobrien *	If the node has recursive predecessors, then
786236769Sobrien *	TargPropagateRecpred() will be called for each recursive
787236769Sobrien *	predecessor.
788236769Sobrien *-----------------------------------------------------------------------
789236769Sobrien */
790236769Sobrienstatic int
791237578SobrienTargPropagateNode(void *gnp, void *junk MAKE_ATTR_UNUSED)
792236769Sobrien{
793236769Sobrien    GNode	  *gn = (GNode *)gnp;
794236769Sobrien
795236769Sobrien    if (gn->type & OP_DOUBLEDEP)
796236769Sobrien	Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
797236769Sobrien    return (0);
798236769Sobrien}
799236769Sobrien
800236769Sobrien/*-
801236769Sobrien *-----------------------------------------------------------------------
802236769Sobrien * TargPropagateCohort --
803236769Sobrien *	Propagate some bits in the type mask from a node to
804236769Sobrien *	a related cohort node.
805236769Sobrien *
806236769Sobrien * Input:
807236769Sobrien *	cnp		The node that we are processing.
808236769Sobrien *	gnp		Another node that has cnp as a cohort.
809236769Sobrien *
810236769Sobrien * Results:
811236769Sobrien *	Always returns 0, for the benefit of Lst_ForEach().
812236769Sobrien *
813236769Sobrien * Side Effects:
814236769Sobrien *	cnp's type bitmask is modified to incorporate some of the
815236769Sobrien *	bits from gnp's type bitmask.  (XXX need a better explanation.)
816236769Sobrien *-----------------------------------------------------------------------
817236769Sobrien */
818236769Sobrienstatic int
819236769SobrienTargPropagateCohort(void *cgnp, void *pgnp)
820236769Sobrien{
821236769Sobrien    GNode	  *cgn = (GNode *)cgnp;
822236769Sobrien    GNode	  *pgn = (GNode *)pgnp;
823236769Sobrien
824236769Sobrien    cgn->type |= pgn->type & ~OP_OPMASK;
825236769Sobrien    return (0);
826236769Sobrien}
827236769Sobrien
828236769Sobrien/*-
829236769Sobrien *-----------------------------------------------------------------------
830236769Sobrien * Targ_Propagate --
831236769Sobrien *	Propagate information between related nodes.  Should be called
832236769Sobrien *	after the makefiles are parsed but before any action is taken.
833236769Sobrien *
834236769Sobrien * Results:
835236769Sobrien *	none
836236769Sobrien *
837236769Sobrien * Side Effects:
838236769Sobrien *	Information is propagated between related nodes throughout the
839236769Sobrien *	graph.
840236769Sobrien *-----------------------------------------------------------------------
841236769Sobrien */
842236769Sobrienvoid
843236769SobrienTarg_Propagate(void)
844236769Sobrien{
845236769Sobrien    Lst_ForEach(allTargets, TargPropagateNode, NULL);
846236769Sobrien}
847