1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * Included files
28 */
29#include <mk/defs.h>
30#include <mksh/misc.h>		/* get_prop() */
31
32/*
33 * File table of contents
34 */
35void   print_dependencies(register Name target, register Property line);
36static void	print_deps(register Name target, register Property line);
37static void	print_more_deps(Name target, Name name);
38static void	print_filename(Name name);
39static Boolean	should_print_dep(Property line);
40static void	print_forest(Name target);
41static void	print_deplist(Dependency head);
42void		print_value(register Name value, Daemon daemon);
43static void	print_rule(register Name target);
44static	void	print_rec_info(Name target);
45static Boolean	is_out_of_date(Property line);
46extern void depvar_print_results (void);
47
48/*
49 *	print_dependencies(target, line)
50 *
51 *	Print all the dependencies of a target. First print all the Makefiles.
52 *	Then print all the dependencies. Finally, print all the .INIT
53 *	dependencies.
54 *
55 *	Parameters:
56 *		target		The target we print dependencies for
57 *		line		We get the dependency list from here
58 *
59 *	Global variables used:
60 *		done		The Name ".DONE"
61 *		init		The Name ".INIT"
62 *		makefiles_used	List of all makefiles read
63 */
64void
65print_dependencies(register Name target, register Property line)
66{
67	Dependency	dp;
68	static Boolean	makefiles_printed = false;
69
70	if (target_variants) {
71		depvar_print_results();
72	}
73
74	if (!makefiles_printed) {
75		/*
76		 * Search the makefile list for the primary makefile,
77		 * then print it and its inclusions.  After that go back
78		 * and print the default.mk file and its inclusions.
79		 */
80		for (dp = makefiles_used; dp != NULL; dp = dp->next) {
81			if (dp->name == primary_makefile) {
82				break;
83			}
84		}
85		if (dp) {
86			print_deplist(dp);
87			for (dp = makefiles_used; dp != NULL; dp = dp->next) {
88				if (dp->name == primary_makefile) {
89					break;
90				}
91				(void)printf(" %s", dp->name->string_mb);
92			}
93		}
94		(void) printf("\n");
95		makefiles_printed = true;
96	}
97	print_deps(target, line);
98/*
99	print_more_deps(target, init);
100	print_more_deps(target, done);
101 */
102	if (target_variants) {
103		print_forest(target);
104	}
105}
106
107/*
108 *	print_more_deps(target, name)
109 *
110 *	Print some special dependencies.
111 *	These are the dependencies for the .INIT and .DONE targets.
112 *
113 *	Parameters:
114 *		target		Target built during make run
115 *		name		Special target to print dependencies for
116 *
117 *	Global variables used:
118 */
119static void
120print_more_deps(Name target, Name name)
121{
122	Property	line;
123	register Dependency	dependencies;
124
125	line = get_prop(name->prop, line_prop);
126	if (line != NULL && line->body.line.dependencies != NULL) {
127		(void) printf("%s:\t", target->string_mb);
128		print_deplist(line->body.line.dependencies);
129		(void) printf("\n");
130		for (dependencies= line->body.line.dependencies;
131		     dependencies != NULL;
132		     dependencies= dependencies->next) {
133	                 print_deps(dependencies->name,
134				 get_prop(dependencies->name->prop, line_prop));
135		}
136	}
137}
138
139/*
140 *	print_deps(target, line, go_recursive)
141 *
142 *	Print a regular dependency list.  Append to this information which
143 *	indicates whether or not the target is recursive.
144 *
145 *	Parameters:
146 *		target		target to print dependencies for
147 *		line		We get the dependency list from here
148 *		go_recursive	Should we show all dependencies recursively?
149 *
150 *	Global variables used:
151 *		recursive_name	The Name ".RECURSIVE", printed
152 */
153static void
154print_deps(register Name target, register Property line)
155{
156	register Dependency	dep;
157
158	if ((target->dependency_printed) ||
159	    (target == force)) {
160		return;
161	}
162	target->dependency_printed = true;
163
164	/* only print entries that are actually derived and are not leaf
165	 * files and are not the result of sccs get.
166	 */
167	if (should_print_dep(line)) {
168		if ((report_dependencies_level == 2) ||
169		    (report_dependencies_level == 4)) {
170			if (is_out_of_date(line)) {
171			        (void) printf("1 ");
172			} else {
173			        (void) printf("0 ");
174			}
175		}
176		print_filename(target);
177		(void) printf(":\t");
178		print_deplist(line->body.line.dependencies);
179		print_rec_info(target);
180		(void) printf("\n");
181		for (dep = line->body.line.dependencies;
182		     dep != NULL;
183		     dep = dep->next) {
184			print_deps(dep->name,
185			           get_prop(dep->name->prop, line_prop));
186		}
187	}
188}
189
190static Boolean
191is_out_of_date(Property line)
192{
193	Dependency	dep;
194	Property	line2;
195
196	if (line == NULL) {
197		return false;
198	}
199	if (line->body.line.is_out_of_date) {
200		return true;
201	}
202	for (dep = line->body.line.dependencies;
203	     dep != NULL;
204	     dep = dep->next) {
205		line2 = get_prop(dep->name->prop, line_prop);
206		if (is_out_of_date(line2)) {
207			line->body.line.is_out_of_date = true;
208			return true;
209		}
210	}
211	return false;
212}
213
214/*
215 * Given a dependency print it and all its siblings.
216 */
217static void
218print_deplist(Dependency head)
219{
220	Dependency	dp;
221
222	for (dp = head; dp != NULL; dp = dp->next) {
223		if ((report_dependencies_level != 2) ||
224		    ((!dp->automatic) ||
225		     (dp->name->is_double_colon))) {
226			if (dp->name != force) {
227				putwchar(' ');
228				print_filename(dp->name);
229			}
230		}
231	}
232}
233
234/*
235 * Print the name of a file for the -P option.
236 * If the file is a directory put on a trailing slash.
237 */
238static void
239print_filename(Name name)
240{
241	(void) printf("%s", name->string_mb);
242/*
243	if (name->stat.is_dir) {
244		putwchar('/');
245	}
246 */
247}
248
249/*
250 *	should_print_dep(line)
251 *
252 *	Test if we should print the dependencies of this target.
253 *	The line must exist and either have children dependencies
254 *	or have a command that is not an SCCS command.
255 *
256 *	Return value:
257 *				true if the dependencies should be printed
258 *
259 *	Parameters:
260 *		line		We get the dependency list from here
261 *
262 *	Global variables used:
263 */
264static Boolean
265should_print_dep(Property line)
266{
267	if (line == NULL) {
268		return false;
269	}
270	if (line->body.line.dependencies != NULL) {
271		return true;
272	}
273	if (line->body.line.sccs_command) {
274		return false;
275	}
276	return true;
277}
278
279/*
280 * Print out the root nodes of all the dependency trees
281 * in this makefile.
282 */
283static void
284print_forest(Name target)
285{
286	Name_set::iterator np, e;
287	Property	line;
288
289	for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
290			if (np->is_target && !np->has_parent && np != target) {
291				(void) doname_check(np, true, false, false);
292				line = get_prop(np->prop, line_prop);
293				printf("-\n");
294				print_deps(np, line);
295			}
296	}
297}
298
299
300/*
301 *	This is a set  of routines for dumping the internal make state
302 *	Used for the -p option
303 */
304void
305print_value(register Name value, Daemon daemon)
306{
307	Chain			cp;
308
309	if (value == NULL)
310		(void)printf("=\n");
311	else
312		switch (daemon) {
313		    case no_daemon:
314			(void)printf("= %s\n", value->string_mb);
315			break;
316		    case chain_daemon:
317			for (cp= (Chain) value; cp != NULL; cp= cp->next)
318				(void)printf(cp->next == NULL ? "%s" : "%s ",
319					cp->name->string_mb);
320			(void)printf("\n");
321			break;
322		};
323}
324
325static void
326print_rule(register Name target)
327{
328	register Cmd_line	rule;
329	register Property	line;
330
331	if (((line= get_prop(target->prop, line_prop)) == NULL) ||
332	    ((line->body.line.command_template == NULL) &&
333	     (line->body.line.dependencies == NULL)))
334		return;
335	print_dependencies(target, line);
336	for (rule= line->body.line.command_template; rule != NULL; rule= rule->next)
337		(void)printf("\t%s\n", rule->command_line->string_mb);
338}
339
340
341/*
342 *  If target is recursive,  print the following to standard out:
343 *	.RECURSIVE subdir targ Makefile
344 */
345static void
346print_rec_info(Name target)
347{
348	Recursive_make	rp;
349	wchar_t		*colon;
350
351	report_recursive_init();
352
353	rp = find_recursive_target(target);
354
355	if (rp) {
356		/*
357		 * if found,  print starting with the space after the ':'
358		 */
359		colon = (wchar_t *) wcschr(rp->oldline, (int) colon_char);
360		(void) printf("%s", colon + 1);
361	}
362}
363
364