1237578Sobrien/*	$NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg 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
72237578Sobrienstatic char rcsid[] = "$NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg 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
79237578Sobrien__RCSID("$NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg 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);
295236769Sobrien    if (gn->uname)
296236769Sobrien	free(gn->uname);
297236769Sobrien    if (gn->path)
298236769Sobrien	free(gn->path);
299236769Sobrien    /* gn->fname points to name allocated when file was opened, don't free */
300236769Sobrien
301236769Sobrien    Lst_Destroy(gn->iParents, NULL);
302236769Sobrien    Lst_Destroy(gn->cohorts, NULL);
303236769Sobrien    Lst_Destroy(gn->parents, NULL);
304236769Sobrien    Lst_Destroy(gn->children, NULL);
305236769Sobrien    Lst_Destroy(gn->order_succ, NULL);
306236769Sobrien    Lst_Destroy(gn->order_pred, NULL);
307236769Sobrien    Hash_DeleteTable(&gn->context);
308236769Sobrien    Lst_Destroy(gn->commands, NULL);
309236769Sobrien    free(gn);
310236769Sobrien}
311236769Sobrien#endif
312236769Sobrien
313236769Sobrien
314236769Sobrien/*-
315236769Sobrien *-----------------------------------------------------------------------
316236769Sobrien * Targ_FindNode  --
317236769Sobrien *	Find a node in the list using the given name for matching
318236769Sobrien *
319236769Sobrien * Input:
320236769Sobrien *	name		the name to find
321236769Sobrien *	flags		flags governing events when target not
322236769Sobrien *			found
323236769Sobrien *
324236769Sobrien * Results:
325236769Sobrien *	The node in the list if it was. If it wasn't, return NULL of
326236769Sobrien *	flags was TARG_NOCREATE or the newly created and initialized node
327236769Sobrien *	if it was TARG_CREATE
328236769Sobrien *
329236769Sobrien * Side Effects:
330236769Sobrien *	Sometimes a node is created and added to the list
331236769Sobrien *-----------------------------------------------------------------------
332236769Sobrien */
333236769SobrienGNode *
334236769SobrienTarg_FindNode(const char *name, int flags)
335236769Sobrien{
336236769Sobrien    GNode         *gn;	      /* node in that element */
337236769Sobrien    Hash_Entry	  *he = NULL; /* New or used hash entry for node */
338236769Sobrien    Boolean	  isNew;      /* Set TRUE if Hash_CreateEntry had to create */
339236769Sobrien			      /* an entry for the node */
340236769Sobrien
341236769Sobrien    if (!(flags & (TARG_CREATE | TARG_NOHASH))) {
342236769Sobrien	he = Hash_FindEntry(&targets, name);
343236769Sobrien	if (he == NULL)
344236769Sobrien	    return NULL;
345236769Sobrien	return (GNode *)Hash_GetValue(he);
346236769Sobrien    }
347236769Sobrien
348236769Sobrien    if (!(flags & TARG_NOHASH)) {
349236769Sobrien	he = Hash_CreateEntry(&targets, name, &isNew);
350236769Sobrien	if (!isNew)
351236769Sobrien	    return (GNode *)Hash_GetValue(he);
352236769Sobrien    }
353236769Sobrien
354236769Sobrien    gn = Targ_NewGN(name);
355236769Sobrien    if (!(flags & TARG_NOHASH))
356236769Sobrien	Hash_SetValue(he, gn);
357236769Sobrien    Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
358236769Sobrien    (void)Lst_AtEnd(allTargets, gn);
359236769Sobrien    if (doing_depend)
360236769Sobrien	gn->flags |= FROM_DEPEND;
361236769Sobrien    return gn;
362236769Sobrien}
363236769Sobrien
364236769Sobrien/*-
365236769Sobrien *-----------------------------------------------------------------------
366236769Sobrien * Targ_FindList --
367236769Sobrien *	Make a complete list of GNodes from the given list of names
368236769Sobrien *
369236769Sobrien * Input:
370236769Sobrien *	name		list of names to find
371236769Sobrien *	flags		flags used if no node is found for a given name
372236769Sobrien *
373236769Sobrien * Results:
374236769Sobrien *	A complete list of graph nodes corresponding to all instances of all
375236769Sobrien *	the names in names.
376236769Sobrien *
377236769Sobrien * Side Effects:
378236769Sobrien *	If flags is TARG_CREATE, nodes will be created for all names in
379236769Sobrien *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
380236769Sobrien *	an error message will be printed for each name which can't be found.
381236769Sobrien * -----------------------------------------------------------------------
382236769Sobrien */
383236769SobrienLst
384236769SobrienTarg_FindList(Lst names, int flags)
385236769Sobrien{
386236769Sobrien    Lst            nodes;	/* result list */
387236769Sobrien    LstNode	   ln;		/* name list element */
388236769Sobrien    GNode	   *gn;		/* node in tLn */
389236769Sobrien    char    	   *name;
390236769Sobrien
391236769Sobrien    nodes = Lst_Init(FALSE);
392236769Sobrien
393236769Sobrien    if (Lst_Open(names) == FAILURE) {
394236769Sobrien	return (nodes);
395236769Sobrien    }
396236769Sobrien    while ((ln = Lst_Next(names)) != NULL) {
397236769Sobrien	name = (char *)Lst_Datum(ln);
398236769Sobrien	gn = Targ_FindNode(name, flags);
399236769Sobrien	if (gn != NULL) {
400236769Sobrien	    /*
401236769Sobrien	     * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
402236769Sobrien	     * are added to the list in the order in which they were
403236769Sobrien	     * encountered in the makefile.
404236769Sobrien	     */
405236769Sobrien	    (void)Lst_AtEnd(nodes, gn);
406236769Sobrien	} else if (flags == TARG_NOCREATE) {
407236769Sobrien	    Error("\"%s\" -- target unknown.", name);
408236769Sobrien	}
409236769Sobrien    }
410236769Sobrien    Lst_Close(names);
411236769Sobrien    return (nodes);
412236769Sobrien}
413236769Sobrien
414236769Sobrien/*-
415236769Sobrien *-----------------------------------------------------------------------
416236769Sobrien * Targ_Ignore  --
417236769Sobrien *	Return true if should ignore errors when creating gn
418236769Sobrien *
419236769Sobrien * Input:
420236769Sobrien *	gn		node to check for
421236769Sobrien *
422236769Sobrien * Results:
423236769Sobrien *	TRUE if should ignore errors
424236769Sobrien *
425236769Sobrien * Side Effects:
426236769Sobrien *	None
427236769Sobrien *-----------------------------------------------------------------------
428236769Sobrien */
429236769SobrienBoolean
430236769SobrienTarg_Ignore(GNode *gn)
431236769Sobrien{
432236769Sobrien    if (ignoreErrors || gn->type & OP_IGNORE) {
433236769Sobrien	return (TRUE);
434236769Sobrien    } else {
435236769Sobrien	return (FALSE);
436236769Sobrien    }
437236769Sobrien}
438236769Sobrien
439236769Sobrien/*-
440236769Sobrien *-----------------------------------------------------------------------
441236769Sobrien * Targ_Silent  --
442236769Sobrien *	Return true if be silent when creating gn
443236769Sobrien *
444236769Sobrien * Input:
445236769Sobrien *	gn		node to check for
446236769Sobrien *
447236769Sobrien * Results:
448236769Sobrien *	TRUE if should be silent
449236769Sobrien *
450236769Sobrien * Side Effects:
451236769Sobrien *	None
452236769Sobrien *-----------------------------------------------------------------------
453236769Sobrien */
454236769SobrienBoolean
455236769SobrienTarg_Silent(GNode *gn)
456236769Sobrien{
457236769Sobrien    if (beSilent || gn->type & OP_SILENT) {
458236769Sobrien	return (TRUE);
459236769Sobrien    } else {
460236769Sobrien	return (FALSE);
461236769Sobrien    }
462236769Sobrien}
463236769Sobrien
464236769Sobrien/*-
465236769Sobrien *-----------------------------------------------------------------------
466236769Sobrien * Targ_Precious --
467236769Sobrien *	See if the given target is precious
468236769Sobrien *
469236769Sobrien * Input:
470236769Sobrien *	gn		the node to check
471236769Sobrien *
472236769Sobrien * Results:
473236769Sobrien *	TRUE if it is precious. FALSE otherwise
474236769Sobrien *
475236769Sobrien * Side Effects:
476236769Sobrien *	None
477236769Sobrien *-----------------------------------------------------------------------
478236769Sobrien */
479236769SobrienBoolean
480236769SobrienTarg_Precious(GNode *gn)
481236769Sobrien{
482236769Sobrien    if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
483236769Sobrien	return (TRUE);
484236769Sobrien    } else {
485236769Sobrien	return (FALSE);
486236769Sobrien    }
487236769Sobrien}
488236769Sobrien
489236769Sobrien/******************* DEBUG INFO PRINTING ****************/
490236769Sobrien
491236769Sobrienstatic GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
492236769Sobrien/*-
493236769Sobrien *-----------------------------------------------------------------------
494236769Sobrien * Targ_SetMain --
495236769Sobrien *	Set our idea of the main target we'll be creating. Used for
496236769Sobrien *	debugging output.
497236769Sobrien *
498236769Sobrien * Input:
499236769Sobrien *	gn		The main target we'll create
500236769Sobrien *
501236769Sobrien * Results:
502236769Sobrien *	None.
503236769Sobrien *
504236769Sobrien * Side Effects:
505236769Sobrien *	"mainTarg" is set to the main target's node.
506236769Sobrien *-----------------------------------------------------------------------
507236769Sobrien */
508236769Sobrienvoid
509236769SobrienTarg_SetMain(GNode *gn)
510236769Sobrien{
511236769Sobrien    mainTarg = gn;
512236769Sobrien}
513236769Sobrien
514236769Sobrienstatic int
515237578SobrienTargPrintName(void *gnp, void *pflags MAKE_ATTR_UNUSED)
516236769Sobrien{
517236769Sobrien    GNode *gn = (GNode *)gnp;
518236769Sobrien
519236769Sobrien    fprintf(debug_file, "%s%s ", gn->name, gn->cohort_num);
520236769Sobrien
521236769Sobrien    return 0;
522236769Sobrien}
523236769Sobrien
524236769Sobrien
525236769Sobrienint
526236769SobrienTarg_PrintCmd(void *cmd, void *dummy)
527236769Sobrien{
528236769Sobrien    fprintf(debug_file, "\t%s\n", (char *)cmd);
529236769Sobrien    return (dummy ? 0 : 0);
530236769Sobrien}
531236769Sobrien
532236769Sobrien/*-
533236769Sobrien *-----------------------------------------------------------------------
534236769Sobrien * Targ_FmtTime --
535236769Sobrien *	Format a modification time in some reasonable way and return it.
536236769Sobrien *
537236769Sobrien * Results:
538236769Sobrien *	The time reformatted.
539236769Sobrien *
540236769Sobrien * Side Effects:
541236769Sobrien *	The time is placed in a static area, so it is overwritten
542236769Sobrien *	with each call.
543236769Sobrien *
544236769Sobrien *-----------------------------------------------------------------------
545236769Sobrien */
546236769Sobrienchar *
547236769SobrienTarg_FmtTime(time_t tm)
548236769Sobrien{
549236769Sobrien    struct tm	  	*parts;
550236769Sobrien    static char	  	buf[128];
551236769Sobrien
552236769Sobrien    parts = localtime(&tm);
553236769Sobrien    (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
554236769Sobrien    return(buf);
555236769Sobrien}
556236769Sobrien
557236769Sobrien/*-
558236769Sobrien *-----------------------------------------------------------------------
559236769Sobrien * Targ_PrintType --
560236769Sobrien *	Print out a type field giving only those attributes the user can
561236769Sobrien *	set.
562236769Sobrien *
563236769Sobrien * Results:
564236769Sobrien *
565236769Sobrien * Side Effects:
566236769Sobrien *
567236769Sobrien *-----------------------------------------------------------------------
568236769Sobrien */
569236769Sobrienvoid
570236769SobrienTarg_PrintType(int type)
571236769Sobrien{
572236769Sobrien    int    tbit;
573236769Sobrien
574236769Sobrien#define PRINTBIT(attr)	case CONCAT(OP_,attr): fprintf(debug_file, "." #attr " "); break
575236769Sobrien#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))fprintf(debug_file, "." #attr " "); break
576236769Sobrien
577236769Sobrien    type &= ~OP_OPMASK;
578236769Sobrien
579236769Sobrien    while (type) {
580236769Sobrien	tbit = 1 << (ffs(type) - 1);
581236769Sobrien	type &= ~tbit;
582236769Sobrien
583236769Sobrien	switch(tbit) {
584236769Sobrien	    PRINTBIT(OPTIONAL);
585236769Sobrien	    PRINTBIT(USE);
586236769Sobrien	    PRINTBIT(EXEC);
587236769Sobrien	    PRINTBIT(IGNORE);
588236769Sobrien	    PRINTBIT(PRECIOUS);
589236769Sobrien	    PRINTBIT(SILENT);
590236769Sobrien	    PRINTBIT(MAKE);
591236769Sobrien	    PRINTBIT(JOIN);
592236769Sobrien	    PRINTBIT(INVISIBLE);
593236769Sobrien	    PRINTBIT(NOTMAIN);
594236769Sobrien	    PRINTDBIT(LIB);
595236769Sobrien	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
596236769Sobrien	    case OP_MEMBER: if (DEBUG(TARG))fprintf(debug_file, ".MEMBER "); break;
597236769Sobrien	    PRINTDBIT(ARCHV);
598236769Sobrien	    PRINTDBIT(MADE);
599236769Sobrien	    PRINTDBIT(PHONY);
600236769Sobrien	}
601236769Sobrien    }
602236769Sobrien}
603236769Sobrien
604236769Sobrienstatic const char *
605236769Sobrienmade_name(enum enum_made made)
606236769Sobrien{
607236769Sobrien    switch (made) {
608236769Sobrien    case UNMADE:     return "unmade";
609236769Sobrien    case DEFERRED:   return "deferred";
610236769Sobrien    case REQUESTED:  return "requested";
611236769Sobrien    case BEINGMADE:  return "being made";
612236769Sobrien    case MADE:       return "made";
613236769Sobrien    case UPTODATE:   return "up-to-date";
614236769Sobrien    case ERROR:      return "error when made";
615236769Sobrien    case ABORTED:    return "aborted";
616236769Sobrien    default:         return "unknown enum_made value";
617236769Sobrien    }
618236769Sobrien}
619236769Sobrien
620236769Sobrien/*-
621236769Sobrien *-----------------------------------------------------------------------
622236769Sobrien * TargPrintNode --
623236769Sobrien *	print the contents of a node
624236769Sobrien *-----------------------------------------------------------------------
625236769Sobrien */
626236769Sobrienint
627236769SobrienTarg_PrintNode(void *gnp, void *passp)
628236769Sobrien{
629236769Sobrien    GNode         *gn = (GNode *)gnp;
630236769Sobrien    int	    	  pass = passp ? *(int *)passp : 0;
631236769Sobrien
632236769Sobrien    fprintf(debug_file, "# %s%s, flags %x, type %x, made %d\n",
633236769Sobrien	    gn->name, gn->cohort_num, gn->flags, gn->type, gn->made);
634236769Sobrien    if (gn->flags == 0)
635236769Sobrien	return 0;
636236769Sobrien
637236769Sobrien    if (!OP_NOP(gn->type)) {
638236769Sobrien	fprintf(debug_file, "#\n");
639236769Sobrien	if (gn == mainTarg) {
640236769Sobrien	    fprintf(debug_file, "# *** MAIN TARGET ***\n");
641236769Sobrien	}
642236769Sobrien	if (pass >= 2) {
643236769Sobrien	    if (gn->unmade) {
644236769Sobrien		fprintf(debug_file, "# %d unmade children\n", gn->unmade);
645236769Sobrien	    } else {
646236769Sobrien		fprintf(debug_file, "# No unmade children\n");
647236769Sobrien	    }
648236769Sobrien	    if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
649236769Sobrien		if (gn->mtime != 0) {
650236769Sobrien		    fprintf(debug_file, "# last modified %s: %s\n",
651236769Sobrien			      Targ_FmtTime(gn->mtime),
652236769Sobrien			      made_name(gn->made));
653236769Sobrien		} else if (gn->made != UNMADE) {
654236769Sobrien		    fprintf(debug_file, "# non-existent (maybe): %s\n",
655236769Sobrien			      made_name(gn->made));
656236769Sobrien		} else {
657236769Sobrien		    fprintf(debug_file, "# unmade\n");
658236769Sobrien		}
659236769Sobrien	    }
660236769Sobrien	    if (!Lst_IsEmpty (gn->iParents)) {
661236769Sobrien		fprintf(debug_file, "# implicit parents: ");
662236769Sobrien		Lst_ForEach(gn->iParents, TargPrintName, NULL);
663236769Sobrien		fprintf(debug_file, "\n");
664236769Sobrien	    }
665236769Sobrien	} else {
666236769Sobrien	    if (gn->unmade)
667236769Sobrien		fprintf(debug_file, "# %d unmade children\n", gn->unmade);
668236769Sobrien	}
669236769Sobrien	if (!Lst_IsEmpty (gn->parents)) {
670236769Sobrien	    fprintf(debug_file, "# parents: ");
671236769Sobrien	    Lst_ForEach(gn->parents, TargPrintName, NULL);
672236769Sobrien	    fprintf(debug_file, "\n");
673236769Sobrien	}
674236769Sobrien	if (!Lst_IsEmpty (gn->order_pred)) {
675236769Sobrien	    fprintf(debug_file, "# order_pred: ");
676236769Sobrien	    Lst_ForEach(gn->order_pred, TargPrintName, NULL);
677236769Sobrien	    fprintf(debug_file, "\n");
678236769Sobrien	}
679236769Sobrien	if (!Lst_IsEmpty (gn->order_succ)) {
680236769Sobrien	    fprintf(debug_file, "# order_succ: ");
681236769Sobrien	    Lst_ForEach(gn->order_succ, TargPrintName, NULL);
682236769Sobrien	    fprintf(debug_file, "\n");
683236769Sobrien	}
684236769Sobrien
685236769Sobrien	fprintf(debug_file, "%-16s", gn->name);
686236769Sobrien	switch (gn->type & OP_OPMASK) {
687236769Sobrien	    case OP_DEPENDS:
688236769Sobrien		fprintf(debug_file, ": "); break;
689236769Sobrien	    case OP_FORCE:
690236769Sobrien		fprintf(debug_file, "! "); break;
691236769Sobrien	    case OP_DOUBLEDEP:
692236769Sobrien		fprintf(debug_file, ":: "); break;
693236769Sobrien	}
694236769Sobrien	Targ_PrintType(gn->type);
695236769Sobrien	Lst_ForEach(gn->children, TargPrintName, NULL);
696236769Sobrien	fprintf(debug_file, "\n");
697236769Sobrien	Lst_ForEach(gn->commands, Targ_PrintCmd, NULL);
698236769Sobrien	fprintf(debug_file, "\n\n");
699236769Sobrien	if (gn->type & OP_DOUBLEDEP) {
700236769Sobrien	    Lst_ForEach(gn->cohorts, Targ_PrintNode, &pass);
701236769Sobrien	}
702236769Sobrien    }
703236769Sobrien    return (0);
704236769Sobrien}
705236769Sobrien
706236769Sobrien/*-
707236769Sobrien *-----------------------------------------------------------------------
708236769Sobrien * TargPrintOnlySrc --
709236769Sobrien *	Print only those targets that are just a source.
710236769Sobrien *
711236769Sobrien * Results:
712236769Sobrien *	0.
713236769Sobrien *
714236769Sobrien * Side Effects:
715236769Sobrien *	The name of each file is printed preceded by #\t
716236769Sobrien *
717236769Sobrien *-----------------------------------------------------------------------
718236769Sobrien */
719236769Sobrienstatic int
720237578SobrienTargPrintOnlySrc(void *gnp, void *dummy MAKE_ATTR_UNUSED)
721236769Sobrien{
722236769Sobrien    GNode   	  *gn = (GNode *)gnp;
723236769Sobrien    if (!OP_NOP(gn->type))
724236769Sobrien	return 0;
725236769Sobrien
726236769Sobrien    fprintf(debug_file, "#\t%s [%s] ",
727236769Sobrien	    gn->name, gn->path ? gn->path : gn->name);
728236769Sobrien    Targ_PrintType(gn->type);
729236769Sobrien    fprintf(debug_file, "\n");
730236769Sobrien
731236769Sobrien    return 0;
732236769Sobrien}
733236769Sobrien
734236769Sobrien/*-
735236769Sobrien *-----------------------------------------------------------------------
736236769Sobrien * Targ_PrintGraph --
737236769Sobrien *	print the entire graph. heh heh
738236769Sobrien *
739236769Sobrien * Input:
740236769Sobrien *	pass		Which pass this is. 1 => no processing
741236769Sobrien *			2 => processing done
742236769Sobrien *
743236769Sobrien * Results:
744236769Sobrien *	none
745236769Sobrien *
746236769Sobrien * Side Effects:
747236769Sobrien *	lots o' output
748236769Sobrien *-----------------------------------------------------------------------
749236769Sobrien */
750236769Sobrienvoid
751236769SobrienTarg_PrintGraph(int pass)
752236769Sobrien{
753236769Sobrien    fprintf(debug_file, "#*** Input graph:\n");
754236769Sobrien    Lst_ForEach(allTargets, Targ_PrintNode, &pass);
755236769Sobrien    fprintf(debug_file, "\n\n");
756236769Sobrien    fprintf(debug_file, "#\n#   Files that are only sources:\n");
757236769Sobrien    Lst_ForEach(allTargets, TargPrintOnlySrc, NULL);
758236769Sobrien    fprintf(debug_file, "#*** Global Variables:\n");
759236769Sobrien    Var_Dump(VAR_GLOBAL);
760236769Sobrien    fprintf(debug_file, "#*** Command-line Variables:\n");
761236769Sobrien    Var_Dump(VAR_CMD);
762236769Sobrien    fprintf(debug_file, "\n");
763236769Sobrien    Dir_PrintDirectories();
764236769Sobrien    fprintf(debug_file, "\n");
765236769Sobrien    Suff_PrintAll();
766236769Sobrien}
767236769Sobrien
768236769Sobrien/*-
769236769Sobrien *-----------------------------------------------------------------------
770236769Sobrien * TargPropagateNode --
771236769Sobrien *	Propagate information from a single node to related nodes if
772236769Sobrien *	appropriate.
773236769Sobrien *
774236769Sobrien * Input:
775236769Sobrien *	gnp		The node that we are processing.
776236769Sobrien *
777236769Sobrien * Results:
778236769Sobrien *	Always returns 0, for the benefit of Lst_ForEach().
779236769Sobrien *
780236769Sobrien * Side Effects:
781236769Sobrien *	Information is propagated from this node to cohort or child
782236769Sobrien *	nodes.
783236769Sobrien *
784236769Sobrien *	If the node was defined with "::", then TargPropagateCohort()
785236769Sobrien *	will be called for each cohort node.
786236769Sobrien *
787236769Sobrien *	If the node has recursive predecessors, then
788236769Sobrien *	TargPropagateRecpred() will be called for each recursive
789236769Sobrien *	predecessor.
790236769Sobrien *-----------------------------------------------------------------------
791236769Sobrien */
792236769Sobrienstatic int
793237578SobrienTargPropagateNode(void *gnp, void *junk MAKE_ATTR_UNUSED)
794236769Sobrien{
795236769Sobrien    GNode	  *gn = (GNode *)gnp;
796236769Sobrien
797236769Sobrien    if (gn->type & OP_DOUBLEDEP)
798236769Sobrien	Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
799236769Sobrien    return (0);
800236769Sobrien}
801236769Sobrien
802236769Sobrien/*-
803236769Sobrien *-----------------------------------------------------------------------
804236769Sobrien * TargPropagateCohort --
805236769Sobrien *	Propagate some bits in the type mask from a node to
806236769Sobrien *	a related cohort node.
807236769Sobrien *
808236769Sobrien * Input:
809236769Sobrien *	cnp		The node that we are processing.
810236769Sobrien *	gnp		Another node that has cnp as a cohort.
811236769Sobrien *
812236769Sobrien * Results:
813236769Sobrien *	Always returns 0, for the benefit of Lst_ForEach().
814236769Sobrien *
815236769Sobrien * Side Effects:
816236769Sobrien *	cnp's type bitmask is modified to incorporate some of the
817236769Sobrien *	bits from gnp's type bitmask.  (XXX need a better explanation.)
818236769Sobrien *-----------------------------------------------------------------------
819236769Sobrien */
820236769Sobrienstatic int
821236769SobrienTargPropagateCohort(void *cgnp, void *pgnp)
822236769Sobrien{
823236769Sobrien    GNode	  *cgn = (GNode *)cgnp;
824236769Sobrien    GNode	  *pgn = (GNode *)pgnp;
825236769Sobrien
826236769Sobrien    cgn->type |= pgn->type & ~OP_OPMASK;
827236769Sobrien    return (0);
828236769Sobrien}
829236769Sobrien
830236769Sobrien/*-
831236769Sobrien *-----------------------------------------------------------------------
832236769Sobrien * Targ_Propagate --
833236769Sobrien *	Propagate information between related nodes.  Should be called
834236769Sobrien *	after the makefiles are parsed but before any action is taken.
835236769Sobrien *
836236769Sobrien * Results:
837236769Sobrien *	none
838236769Sobrien *
839236769Sobrien * Side Effects:
840236769Sobrien *	Information is propagated between related nodes throughout the
841236769Sobrien *	graph.
842236769Sobrien *-----------------------------------------------------------------------
843236769Sobrien */
844236769Sobrienvoid
845236769SobrienTarg_Propagate(void)
846236769Sobrien{
847236769Sobrien    Lst_ForEach(allTargets, TargPropagateNode, NULL);
848236769Sobrien}
849