1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*
28  * @(#)nse_printdep.cc 1.18 06/12/12
29  */
30 
31 #pragma	ident	"@(#)nse_printdep.cc	1.18	06/12/12"
32 
33 /*
34  * Copyright 2017-2019 J. Schilling
35  *
36  * @(#)nse_printdep.cc	1.7 19/10/19 2017-2019 J. Schilling
37  */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static	UConst char sccsid[] =
41 	"@(#)nse_printdep.cc	1.7 19/10/19 2017-2019 J. Schilling";
42 #endif
43 
44 /*
45  * Included files
46  */
47 #include <mk/defs.h>
48 #include <mksh/misc.h>		/* get_prop() */
49 
50 /*
51  * File table of contents
52  */
53 void   print_dependencies(register Name target, register Property line);
54 static void	print_deps(register Name target, register Property line);
55 static void	print_more_deps(Name target, Name name);
56 static void	print_filename(Name name);
57 static Boolean	should_print_dep(Property line);
58 static void	print_forest(Name target);
59 static void	print_deplist(Dependency head);
60 void		print_value(register Name value, Daemon daemon);
61 static void	print_rule(register Name target);
62 static	void	print_rec_info(Name target);
63 static Boolean	is_out_of_date(Property line);
64 extern void depvar_print_results (void);
65 
66 /*
67  *	print_dependencies(target, line)
68  *
69  *	Print all the dependencies of a target. First print all the Makefiles.
70  *	Then print all the dependencies. Finally, print all the .INIT
71  *	dependencies.
72  *
73  *	Parameters:
74  *		target		The target we print dependencies for
75  *		line		We get the dependency list from here
76  *
77  *	Global variables used:
78  *		done		The Name ".DONE"
79  *		init		The Name ".INIT"
80  *		makefiles_used	List of all makefiles read
81  */
82 void
print_dependencies(register Name target,register Property line)83 print_dependencies(register Name target, register Property line)
84 {
85 	Dependency	dp;
86 	static Boolean	makefiles_printed = false;
87 
88 #ifdef SUNOS4_AND_AFTER
89 	if (target_variants) {
90 #else
91 	if (is_true(flag.target_variants)) {
92 #endif
93 		depvar_print_results();
94 	}
95 
96 	if (!makefiles_printed) {
97 		/*
98 		 * Search the makefile list for the primary makefile,
99 		 * then print it and its inclusions.  After that go back
100 		 * and print the default.mk file and its inclusions.
101 		 */
102 		for (dp = makefiles_used; dp != NULL; dp = dp->next) {
103 			if (dp->name == primary_makefile) {
104 				break;
105 			}
106 		}
107 		if (dp) {
108 			print_deplist(dp);
109 			for (dp = makefiles_used; dp != NULL; dp = dp->next) {
110 				if (dp->name == primary_makefile) {
111 					break;
112 				}
113 				(void)printf(" %s", dp->name->string_mb);
114 			}
115 		}
116 		(void) printf("\n");
117 		makefiles_printed = true;
118 	}
119 	print_deps(target, line);
120 #ifdef SUNOS4_AND_AFTER
121 /*
122 	print_more_deps(target, init);
123 	print_more_deps(target, done);
124  */
125 	if (target_variants) {
126 #else
127 	print_more_deps(target, cached_names.init);
128 	print_more_deps(target, cached_names.done);
129 	if (is_true(flag.target_variants)) {
130 #endif
131 		print_forest(target);
132 	}
133 }
134 
135 /*
136  *	print_more_deps(target, name)
137  *
138  *	Print some special dependencies.
139  *	These are the dependencies for the .INIT and .DONE targets.
140  *
141  *	Parameters:
142  *		target		Target built during make run
143  *		name		Special target to print dependencies for
144  *
145  *	Global variables used:
146  */
147 static void
148 print_more_deps(Name target, Name name)
149 {
150 	Property	line;
151 	register Dependency	dependencies;
152 
153 	line = get_prop(name->prop, line_prop);
154 	if (line != NULL && line->body.line.dependencies != NULL) {
155 		(void) printf("%s:\t", target->string_mb);
156 		print_deplist(line->body.line.dependencies);
157 		(void) printf("\n");
158 		for (dependencies= line->body.line.dependencies;
159 		     dependencies != NULL;
160 		     dependencies= dependencies->next) {
161 	                 print_deps(dependencies->name,
162 				 get_prop(dependencies->name->prop, line_prop));
163 		}
164 	}
165 }
166 
167 /*
168  *	print_deps(target, line, go_recursive)
169  *
170  *	Print a regular dependency list.  Append to this information which
171  *	indicates whether or not the target is recursive.
172  *
173  *	Parameters:
174  *		target		target to print dependencies for
175  *		line		We get the dependency list from here
176  *		go_recursive	Should we show all dependencies recursively?
177  *
178  *	Global variables used:
179  *		recursive_name	The Name ".RECURSIVE", printed
180  */
181 static void
182 print_deps(register Name target, register Property line)
183 {
184 	register Dependency	dep;
185 
186 #ifdef SUNOS4_AND_AFTER
187 	if ((target->dependency_printed) ||
188 	    (target == force)) {
189 #else
190 	if (is_true(target->dependency_printed)) {
191 #endif
192 		return;
193 	}
194 	target->dependency_printed = true;
195 
196 	/* only print entries that are actually derived and are not leaf
197 	 * files and are not the result of sccs get.
198 	 */
199 	if (should_print_dep(line)) {
200 #ifdef NSE
201 		nse_check_no_deps_no_rule(target, line, line);
202 #endif
203 		if ((report_dependencies_level == 2) ||
204 		    (report_dependencies_level == 4)) {
205 			if (is_out_of_date(line)) {
206 			        (void) printf("1 ");
207 			} else {
208 			        (void) printf("0 ");
209 			}
210 		}
211 		print_filename(target);
212 	    	(void) printf(":\t");
213 	    	print_deplist(line->body.line.dependencies);
214 		print_rec_info(target);
215 	   	(void) printf("\n");
216 	 	for (dep = line->body.line.dependencies;
217 		     dep != NULL;
218 		     dep = dep->next) {
219 			print_deps(dep->name,
220 			           get_prop(dep->name->prop, line_prop));
221 		}
222 	}
223 }
224 
225 static Boolean
226 is_out_of_date(Property line)
227 {
228 	Dependency	dep;
229 	Property	line2;
230 
231 	if (line == NULL) {
232 		return false;
233 	}
234 	if (line->body.line.is_out_of_date) {
235 		return true;
236 	}
237 	for (dep = line->body.line.dependencies;
238 	     dep != NULL;
239 	     dep = dep->next) {
240 		line2 = get_prop(dep->name->prop, line_prop);
241 		if (is_out_of_date(line2)) {
242 			line->body.line.is_out_of_date = true;
243 			return true;
244 		}
245 	}
246 	return false;
247 }
248 
249 /*
250  * Given a dependency print it and all its siblings.
251  */
252 static void
253 print_deplist(Dependency head)
254 {
255 	Dependency	dp;
256 
257 	for (dp = head; dp != NULL; dp = dp->next) {
258 		if ((report_dependencies_level != 2) ||
259 		    ((!dp->automatic) ||
260 		     (dp->name->is_double_colon))) {
261 			if (dp->name != force) {
262 				putchar(' ');
263 				print_filename(dp->name);
264 			}
265 		}
266 	}
267 }
268 
269 /*
270  * Print the name of a file for the -P option.
271  * If the file is a directory put on a trailing slash.
272  */
273 static void
274 print_filename(Name name)
275 {
276 	(void) printf("%s", name->string_mb);
277 /*
278 	if (name->stat.is_dir) {
279 		putchar('/');
280 	}
281  */
282 }
283 
284 /*
285  *	should_print_dep(line)
286  *
287  *	Test if we should print the dependencies of this target.
288  *	The line must exist and either have children dependencies
289  *	or have a command that is not an SCCS command.
290  *
291  *	Return value:
292  *				true if the dependencies should be printed
293  *
294  *	Parameters:
295  *		line		We get the dependency list from here
296  *
297  *	Global variables used:
298  */
299 static Boolean
300 should_print_dep(Property line)
301 {
302 	if (line == NULL) {
303 		return false;
304 	}
305 	if (line->body.line.dependencies != NULL) {
306 		return true;
307 	}
308 #ifdef SUNOS4_AND_AFTER
309 	if (line->body.line.sccs_command) {
310 #else
311 	if (is_true(line->body.line.sccs_command)) {
312 #endif
313 		return false;
314 	}
315 	return true;
316 }
317 
318 /*
319  * Print out the root nodes of all the dependency trees
320  * in this makefile.
321  */
322 static void
323 print_forest(Name target)
324 {
325 	Name_set::iterator np, e;
326 	Property	line;
327 
328  	for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
329 #ifdef SUNOS4_AND_AFTER
330 			if (np->is_target && !np->has_parent && np != target) {
331 #else
332 			if (is_true(np->is_target) &&
333 			    is_false(np->has_parent) &&
334 			    np != target) {
335 #endif
336 				(void) doname_check(np, true, false, false);
337 				line = get_prop(np->prop, line_prop);
338 				printf("-\n");
339 				print_deps(np, line);
340 			}
341 	}
342 }
343 
344 #ifndef SUNOS4_AND_AFTER
345 printdesc()
346 {
347 	Name_set::iterator	p, e;
348 	register Property	prop;
349 	register Dependency	dep;
350 	register Cmd_line	rule;
351 	Percent			percent, percent_depe;
352 
353 	/* Default target */
354 	if (default_target_to_build != NULL) {
355 		print_rule(default_target_to_build);
356 		default_target_to_build->dependency_printed= true;
357 	};
358 	(void)printf("\n");
359 
360 	/* .AR_REPLACE */
361 	if (ar_replace_rule != NULL) {
362 		(void)printf("%s:\n", cached_names.ar_replace->string_mb);
363 		for (rule= ar_replace_rule; rule != NULL; rule= rule->next)
364 			(void)printf("\t%s\n", rule->command_line->string_mb);
365 	};
366 
367 	/* .DEFAULT */
368 	if (default_rule != NULL) {
369 		(void)printf("%s:\n", cached_names.default_rule->string_mb);
370 		for (rule= default_rule; rule != NULL; rule= rule->next)
371 			(void)printf("\t%s\n", rule->command_line->string_mb);
372 	};
373 
374 	/* .IGNORE */
375 	if (is_true(flag.ignore_errors))
376 		(void)printf("%s:\n", cached_names.ignore->string_mb);
377 
378 	/* .KEEP_STATE: */
379 	if (is_true(flag.keep_state))
380 		(void)printf("%s:\n\n", cached_names.dot_keep_state->string_mb);
381 
382 	/* .PHONY */
383 	(void)printf("%s: ", cached_names.phony->string_mb);
384  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
385 			if (is_true(p->stat.is_phony))
386 				(void)printf("%s ", p->string_mb);
387 	(void)printf("\n");
388 
389 	/* .PRECIOUS */
390 	(void)printf("%s: ", cached_names.precious->string_mb);
391  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
392 			if (is_true(p->stat.is_precious | all_precious))
393 				(void)printf("%s ", p->string_mb);
394 	(void)printf("\n");
395 
396 	/* .SCCS_GET */
397 	if (sccs_get_rule != NULL) {
398 		(void)printf("%s:\n", cached_names.sccs_get->string_mb);
399 		for (rule= sccs_get_rule; rule != NULL; rule= rule->next)
400 			(void)printf("\t%s\n", rule->command_line->string_mb);
401 	};
402 
403 	/* .SILENT */
404 	if (is_true(flag.silent))
405 		(void)printf("%s:\n", cached_names.silent->string_mb);
406 
407 	/* .SUFFIXES: */
408 	(void)printf("%s: ", cached_names.suffixes->string_mb);
409 	for (dep= suffixes; dep != NULL; dep= dep->next) {
410 		(void)printf("%s ", dep->name->string_mb);
411 		build_suffix_list(dep->name);
412 	};
413 	(void)printf("\n\n");
414 
415 	/* % rules */
416 	for (percent= percent_list; percent != NULL; percent= percent->next) {
417 		(void) printf("%s:", percent->name->string_mb);
418 
419 		for (percent_depe= percent->dependencies; percent_depe != NULL; percent_depe = percent_depe->next)
420 			(void) printf(" %s", percent_depe->name->string_mb);
421 
422 		(void) printf("\n");
423 
424 		for (rule= percent->command_template; rule != NULL; rule= rule->next)
425 			(void)printf("\t%s\n", rule->command_line->string_mb);
426 	};
427 
428 	/* Suffix rules */
429  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
430 			if (is_false(p->dependency_printed) && (p->string[0] == PERIOD)) {
431 				print_rule(p);
432 				p->dependency_printed= true;
433 			};
434 
435 	/* Macro assignments */
436  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
437 			if (((prop= get_prop(p->prop, macro_prop)) != NULL) &&
438 			    (prop->body.macro.value != NULL)) {
439 				(void)printf("%s", p->string_mb);
440 				print_value(prop->body.macro.value,
441 					    prop->body.macro.daemon);
442 			};
443 	(void)printf("\n");
444 
445 	/* Delays */
446  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
447 			for (prop= get_prop(p->prop, conditional_prop);
448 			     prop != NULL;
449 			     prop= get_prop(prop->next, conditional_prop)) {
450 				(void)printf("%s := %s",
451 					     p->string_mb,
452 					     prop->body.conditional.name->string_mb);
453 				print_value(prop->body.conditional.value, no_daemon);
454 			};
455 	(void)printf("\n");
456 
457 	/* All other dependencies */
458  	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++)
459 			if (is_false(p->dependency_printed) && (p->colons != no_colon))
460 				print_rule(p);
461 	(void)printf("\n");
462 	exit(0);
463 }
464 #endif
465 
466 /*
467  *	This is a set  of routines for dumping the internal make state
468  *	Used for the -p option
469  */
470 void
471 print_value(register Name value, Daemon daemon)
472 
473 #ifdef SUNOS4_AND_AFTER
474 
475 #else
476 
477 #endif
478 {
479 	Chain			cp;
480 
481 	if (value == NULL)
482 		(void)printf("=\n");
483 	else
484 		switch (daemon) {
485 		    case no_daemon:
486 			(void)printf("= %s\n", value->string_mb);
487 			break;
488 		    case chain_daemon:
489 			for (cp= (Chain) value; cp != NULL; cp= cp->next)
490 				(void)printf(cp->next == NULL ? "%s" : "%s ",
491 					cp->name->string_mb);
492 			(void)printf("\n");
493 			break;
494 		};
495 }
496 
497 static void
498 print_rule(register Name target)
499 {
500 	register Cmd_line	rule;
501 	register Property	line;
502 
503 	if (((line= get_prop(target->prop, line_prop)) == NULL) ||
504 	    ((line->body.line.command_template == NULL) &&
505 	     (line->body.line.dependencies == NULL)))
506 		return;
507 	print_dependencies(target, line);
508 	for (rule= line->body.line.command_template; rule != NULL; rule= rule->next)
509 		(void)printf("\t%s\n", rule->command_line->string_mb);
510 }
511 
512 
513 /*
514  *  If target is recursive,  print the following to standard out:
515  *	.RECURSIVE subdir targ Makefile
516  */
517 static void
518 print_rec_info(Name target)
519 {
520 	Recursive_make	rp;
521 	wchar_t		*colon;
522 
523 	report_recursive_init();
524 
525 	rp = find_recursive_target(target);
526 
527 	if (rp) {
528 		/*
529 		 * if found,  print starting with the space after the ':'
530 		 */
531 		colon = (wchar_t *) wcschr(rp->oldline, (int) colon_char);
532 		(void) printf("%ls", colon + 1);
533 	}
534 }
535 
536