xref: /titanic_50/usr/src/cmd/make/bin/implicit.cc (revision 10d63b7db37a83b39c7f511cf9426c9d03ea0760)
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 2004 Sun Microsystems, Inc. All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *	implicit.c
28  *
29  *	Handle suffix and percent rules
30  */
31 
32 /*
33  * Included files
34  */
35 #include <mk/defs.h>
36 #include <mksh/macro.h>		/* expand_value() */
37 #include <mksh/misc.h>		/* retmem() */
38 #include <libintl.h>
39 
40 /*
41  * Defined macros
42  */
43 
44 /*
45  * typedefs & structs
46  */
47 
48 /*
49  * Static variables
50  */
51 static	wchar_t		WIDE_NULL[1] = {(wchar_t) nul_char};
52 
53 /*
54  * File table of contents
55  */
56 extern	Doname		find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
57 extern	Doname		find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
58 extern	Doname		find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
59 extern	void		build_suffix_list(register Name target_suffix);
60 extern	Doname		find_percent_rule(register Name target, Property *command, Boolean rechecking);
61 static	void 		create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent);
62 static	Boolean		match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf);
63 static	void		construct_string_from_pattern(Percent pat_rule, String percent, String result);
64 static	Boolean		dependency_exists(Name target, Property line);
65 extern	Property	maybe_append_prop(Name, Property_id);
66 extern	void		add_target_to_chain(Name target, Chain * query);
67 
68 /*
69  *	find_suffix_rule(target, target_body, target_suffix, command, rechecking)
70  *
71  *	Does the lookup for single and double suffix rules.
72  *	It calls build_suffix_list() to build the list of possible suffixes
73  *	for the given target.
74  *	It then scans the list to find the first possible source file that
75  *	exists. This is done by concatenating the body of the target name
76  *	(target name less target suffix) and the source suffix and checking
77  *	if the resulting file exists.
78  *
79  *	Return value:
80  *				Indicates if search failed or not
81  *
82  *	Parameters:
83  *		target		The target we need a rule for
84  *		target_body	The target name without the suffix
85  *		target_suffix	The suffix of the target
86  *		command		Pointer to slot to deposit cmd in if found
87  *		rechecking	true if we are rechecking target which depends
88  *				on conditional macro and keep_state is set
89  *
90  *	Global variables used:
91  *		debug_level	Indicates how much tracing to do
92  *		recursion_level	Used for tracing
93  */
94 
95 static Boolean actual_doname = false;
96 
97 /* /tolik/
98  * fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
99  * When make attemps to apply % rule it didn't look for a single suffix rule because
100  * if "doname" is called from "find_percent_rule" argument "implicit" is set to true
101  * and find_suffix_rule was not called. I've commented the checking of "implicit"
102  * in "doname" and make got infinite recursion for SVR4 tilde rules.
103  * Usage of "we_are_in_tilde" is intended to avoid this recursion.
104  */
105 
106 static Boolean we_are_in_tilde = false;
107 
108 Doname
find_suffix_rule(Name target,Name target_body,Name target_suffix,Property * command,Boolean rechecking)109 find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking)
110 {
111 	static wchar_t		static_string_buf_3M [ 3 * MAXPATHLEN ];
112 	Name			true_target = target;
113 	wchar_t			*sourcename = (wchar_t*)static_string_buf_3M;
114 	register wchar_t	*put_suffix;
115 	register Property	source_suffix;
116 	register Name		source;
117 	Doname			result;
118 	register Property	line;
119 	extern Boolean 		tilde_rule;
120 	Boolean 		name_found = true;
121 	Boolean 		posix_tilde_attempt = true;
122 	int			src_len = MAXPATHLEN + strlen(target_body->string_mb);
123 
124 	/*
125 	 * To avoid infinite recursion
126 	 */
127 	if(we_are_in_tilde) {
128 		we_are_in_tilde = false;
129 		return(build_dont_know);
130 	}
131 
132 	/*
133 	 * If the target is a constructed one for a "::" target,
134 	 * we need to consider that.
135 	 */
136 	if (target->has_target_prop) {
137 		true_target = get_prop(target->prop,
138 				       target_prop)->body.target.target;
139 	}
140 	if (debug_level > 1) {
141 		(void) printf("%*sfind_suffix_rule(%s,%s,%s)\n",
142 			      recursion_level,
143 			      "",
144 			      true_target->string_mb,
145 			      target_body->string_mb,
146 			      target_suffix->string_mb);
147 	}
148 	if (command != NULL) {
149 		if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
150 			return build_ok;
151 		}
152 	}
153 	true_target->suffix_scan_done = true;
154 	/*
155 	 * Enter all names from the directory where the target lives as
156 	 * files that makes sense.
157 	 * This will make finding the synthesized source possible.
158 	 */
159 	read_directory_of_file(target_body);
160 	/* Cache the suffixes for this target suffix if not done. */
161 	if (!target_suffix->has_read_suffixes) {
162 		build_suffix_list(target_suffix);
163 	}
164 	/* Preload the sourcename vector with the head of the target name. */
165 	if (src_len >= sizeof(static_string_buf_3M)) {
166 		sourcename = ALLOC_WC(src_len);
167 	}
168 	(void) mbstowcs(sourcename,
169 		      target_body->string_mb,
170 		      (int) target_body->hash.length);
171 	put_suffix = sourcename + target_body->hash.length;
172 	/* Scan the suffix list for the target if one exists. */
173 	if (target_suffix->has_suffixes) {
174 posix_attempts:
175 		for (source_suffix = get_prop(target_suffix->prop,
176 					      suffix_prop);
177 		     source_suffix != NULL;
178 		     source_suffix = get_prop(source_suffix->next,
179 					      suffix_prop)) {
180 			/* Build the synthesized source name. */
181 			(void) mbstowcs(put_suffix,
182 				      source_suffix->body.
183 				      suffix.suffix->string_mb,
184 				      (int) source_suffix->body.
185 				      suffix.suffix->hash.length);
186 			put_suffix[source_suffix->body.
187 				   suffix.suffix->hash.length] =
188 			  (int) nul_char;
189 			if (debug_level > 1) {
190 				WCSTOMBS(mbs_buffer, sourcename);
191 				(void) printf(gettext("%*sTrying %s\n"),
192 					      recursion_level,
193 					      "",
194 					      mbs_buffer);
195 			}
196 			source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
197 			/*
198 			 * If the source file is not registered as
199 			 * a file, this source suffix did not match.
200 			 */
201 			if(vpath_defined && !posix && !svr4) {
202 				(void) exists(source);
203 			}
204 			if (!source->stat.is_file) {
205 			   if(!(posix|svr4))
206 			   {
207 				if(!name_found) {
208 					free_name(source);
209 				}
210 				continue;
211 			   }
212 
213 			   /* following code will ensure that the corresponding
214 			   ** tilde rules are executed when corresponding s. file
215 			   ** exists in the current directory. Though the current
216 			   ** target ends with a ~ character, there wont be any
217 			   ** any file in the current directory with that suffix
218 			   ** as it's fictitious. Even if it exists, it'll
219 			   ** execute all the rules for the ~ target.
220 			   */
221 
222 			   if(source->string_mb[source->hash.length - 1] == '~' &&
223 			      ( svr4 || posix_tilde_attempt ) )
224 			   {
225 				char *p, *np;
226 				char *tmpbuf;
227 
228 				tmpbuf = getmem(source->hash.length + 8);
229 				/* + 8 to add "s." or "SCCS/s." */
230 			        memset(tmpbuf,0,source->hash.length + 8);
231 			        source->string_mb[source->hash.length - 1] = '\0';
232 			        if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length))
233 				{
234 			          while(1) {
235 				    if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
236 			              p = np;
237 			            } else {break;}
238 			          }
239 				  /* copy everything including '/' */
240 				  strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
241 				  strcat(tmpbuf, "s.");
242 				  strcat(tmpbuf, p+1);
243 				  retmem((wchar_t *) source->string_mb);
244 				  source->string_mb = tmpbuf;
245 
246 			        } else {
247 				  strcpy(tmpbuf, "s.");
248 				  strcat(tmpbuf, source->string_mb);
249 				  retmem((wchar_t *) source->string_mb);
250 				  source->string_mb = tmpbuf;
251 
252 			        }
253 				source->hash.length = strlen(source->string_mb);
254 				if(exists(source) == file_doesnt_exist)
255 				  continue;
256 				tilde_rule = true;
257 				we_are_in_tilde = true;
258 			   } else {
259 				if(!name_found) {
260 					free_name(source);
261 				}
262 				continue;
263 			   }
264 			} else {
265 			   if(posix && posix_tilde_attempt) {
266 				if(exists(source) == file_doesnt_exist) {
267 					if(!name_found) {
268 						free_name(source);
269 					}
270 					continue;
271 				}
272 			   }
273 			}
274 
275 			if (command != NULL) {
276 				if(!name_found) {
277 					store_name(source);
278 				}
279 				/*
280 				 * The source file is a file.
281 				 * Make sure it is up to date.
282 				 */
283 				if (dependency_exists(source,
284 						      get_prop(target->prop,
285 							       line_prop))) {
286 					result = (Doname) source->state;
287 				} else {
288 #if 0  /* with_squiggle sends false, which is buggy. : djay */
289 					result = doname(source,
290 							(Boolean) source_suffix->body.
291 							suffix.suffix->with_squiggle,
292 							true);
293 #else
294 					result = doname(source,
295 							true,
296 							true);
297 #endif
298 				}
299 			} else {
300 				result = target_can_be_built(source);
301 
302 				if (result == build_ok) {
303 					return result;
304 				} else {
305 					if(!name_found) {
306 						free_name(source);
307 					}
308 					continue;
309 				}
310 			}
311 
312 			switch (result) {
313 			case build_dont_know:
314 				/*
315 				 * If we still can't build the source,
316 				 * this rule is not a match,
317 				 * try the next one.
318 				 */
319 				if (source->stat.time == file_doesnt_exist) {
320 					if(!name_found) {
321 						free_name(source);
322 					}
323 					continue;
324 				}
325 			case build_running:
326 				if(!name_found) {
327 					store_name(source);
328 				}
329 				true_target->suffix_scan_done = false;
330 				line = maybe_append_prop(target, line_prop);
331 				enter_dependency(line, source, false);
332 				line->body.line.target = true_target;
333 				return build_running;
334 			case build_ok:
335 				if(!name_found) {
336 					store_name(source);
337 				}
338 				break;
339 			case build_failed:
340 				if(!name_found) {
341 					store_name(source);
342 				}
343 				if (sourcename != static_string_buf_3M) {
344 					retmem(sourcename);
345 				}
346 				return build_failed;
347 			}
348 
349 			if (debug_level > 1) {
350 				WCSTOMBS(mbs_buffer, sourcename);
351 				(void) printf(gettext("%*sFound %s\n"),
352 					      recursion_level,
353 					      "",
354 					      mbs_buffer);
355 			}
356 
357 			if (source->depends_on_conditional) {
358 				target->depends_on_conditional = true;
359 			}
360 /*
361  * Since it is possible that the same target is built several times during
362  * the make run, we have to patch the target with all information we found
363  * here. Thus, the target will have an explicit rule the next time around.
364  */
365 			line = maybe_append_prop(target, line_prop);
366 			if (*command == NULL) {
367 				*command = line;
368 			}
369 			if ((source->stat.time > (*command)->body.line.dependency_time) &&
370 			    (debug_level > 1)) {
371 				(void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
372 					      recursion_level,
373 					      "",
374 					      source->string_mb,
375 					      time_to_string(source->
376 							     stat.time),
377 					      true_target->string_mb,
378 					      time_to_string((*command)->
379 							     body.line.
380 							     dependency_time));
381 			}
382 			/*
383 			 * Determine if this new dependency made the
384 			 * target out of date.
385 			 */
386 			(*command)->body.line.dependency_time =
387 			  MAX((*command)->body.line.dependency_time,
388 			      source->stat.time);
389 			Boolean out_of_date;
390 			if (target->is_member) {
391 				out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
392 									(*command)->body.line.dependency_time);
393 			} else {
394 				out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
395 								    (*command)->body.line.dependency_time);
396 			}
397 			if (build_unconditional || out_of_date) {
398 				if(!rechecking) {
399 					line->body.line.is_out_of_date = true;
400 				}
401 				if (debug_level > 0) {
402 					(void) printf(gettext("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
403 						      recursion_level,
404 						      "",
405 						      true_target->string_mb,
406 						      source_suffix->body.suffix.suffix->string_mb,
407 						      target_suffix->string_mb,
408 						      source->string_mb);
409 				}
410 			}
411 			/*
412 			 * Add the implicit rule as the target's explicit
413 			 * rule if none actually given, and register
414 			 * dependency.
415 			 * The time checking above really should be
416 			 * conditional on actual use of implicit rule
417 			 * as well.
418 			 */
419 			line->body.line.sccs_command = false;
420 			if (line->body.line.command_template == NULL) {
421 				line->body.line.command_template =
422 				  source_suffix->body.suffix.command_template;
423 			}
424 			enter_dependency(line, source, false);
425 			line->body.line.target = true_target;
426 			/*
427 			 * Also make sure the rule is built with
428 			 * $* and $< bound properly.
429 			 */
430 			line->body.line.star = target_body;
431 			if(svr4|posix) {
432 			  char * p;
433 			  char tstr[256];
434 			  extern Boolean dollarless_flag;
435 			  extern Name dollarless_value;
436 
437 			  if(tilde_rule) {
438 			      MBSTOWCS(wcs_buffer, source->string_mb);
439 			      dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
440 			  }
441 			  else {
442 				   dollarless_flag = false;
443 			  }
444 			}
445 			line->body.line.less = source;
446 			line->body.line.percent = NULL;
447 			add_target_to_chain(source, &(line->body.line.query));
448 			if (sourcename != static_string_buf_3M) {
449 				retmem(sourcename);
450 			}
451 			return build_ok;
452 		}
453 		if(posix && posix_tilde_attempt) {
454 			posix_tilde_attempt = false;
455 			goto posix_attempts;
456 		}
457 		if ((command != NULL) &&
458 		    ((*command) != NULL) &&
459 		    ((*command)->body.line.star == NULL)) {
460 			(*command)->body.line.star = target_body;
461 		}
462 	}
463 	if (sourcename != static_string_buf_3M) {
464 		retmem(sourcename);
465 	}
466 	/* Return here in case no rule matched the target */
467 	return build_dont_know;
468 }
469 
470 /*
471  *	find_ar_suffix_rule(target, true_target, command, rechecking)
472  *
473  *	Scans the .SUFFIXES list and tries
474  *	to find a suffix on it that matches the tail of the target member name.
475  *	If it finds a matching suffix it calls find_suffix_rule() to find
476  *	a rule for the target using the suffix ".a".
477  *
478  *	Return value:
479  *				Indicates if search failed or not
480  *
481  *	Parameters:
482  *		target		The target we need a rule for
483  *		true_target	The proper name
484  *		command		Pointer to slot where we stuff cmd, if found
485  *		rechecking	true if we are rechecking target which depends
486  *				on conditional macro and keep_state is set
487  *
488  *	Global variables used:
489  *		debug_level	Indicates how much tracing to do
490  *		dot_a		The Name ".a", compared against
491  *		recursion_level	Used for tracing
492  *		suffixes	List of suffixes used for scan (from .SUFFIXES)
493  */
494 Doname
find_ar_suffix_rule(register Name target,Name true_target,Property * command,Boolean rechecking)495 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
496 {
497 	wchar_t			*target_end;
498 	register Dependency	suffix;
499 	register int		suffix_length;
500 	Property		line;
501 	Name			body;
502 	static Name		dot_a;
503 
504 	Wstring			targ_string(true_target);
505 	Wstring			suf_string;
506 
507 	if (dot_a == NULL) {
508 		MBSTOWCS(wcs_buffer, ".a");
509 		dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
510 	}
511 	target_end = targ_string.get_string() + true_target->hash.length;
512 
513 	/*
514 	 * We compare the tail of the target name with the suffixes
515 	 * from .SUFFIXES.
516 	 */
517 	if (debug_level > 1) {
518 		(void) printf("%*sfind_ar_suffix_rule(%s)\n",
519 			      recursion_level,
520 			      "",
521 			      true_target->string_mb);
522 	}
523 	/*
524 	 * Scan the .SUFFIXES list to see if the target matches any of
525 	 * those suffixes.
526 	 */
527 	for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
528 		/* Compare one suffix. */
529 		suffix_length = suffix->name->hash.length;
530 		suf_string.init(suffix->name);
531 		if (!IS_WEQUALN(suf_string.get_string(),
532 			        target_end - suffix_length,
533 			        suffix_length)) {
534 			goto not_this_one;
535 		}
536 		/*
537 		 * The target tail matched a suffix from the .SUFFIXES list.
538 		 * Now check for a rule to match.
539 		 */
540 		target->suffix_scan_done = false;
541 		body = GETNAME(targ_string.get_string(),
542   			       (int)(true_target->hash.length -
543 				     suffix_length));
544 		we_are_in_tilde = false;
545 		switch (find_suffix_rule(target,
546 					 body,
547 					 dot_a,
548 					 command,
549 					 rechecking)) {
550 		case build_ok:
551 			line = get_prop(target->prop, line_prop);
552 			line->body.line.star = body;
553 			return build_ok;
554 		case build_running:
555 			return build_running;
556 		}
557 		/*
558 		 * If no rule was found, we try the next suffix to see
559 		 * if it matches the target tail, and so on.
560 		 * Go here if the suffix did not match the target tail.
561 		 */
562 	not_this_one:;
563 	}
564 	return build_dont_know;
565 }
566 
567 /*
568  *	find_double_suffix_rule(target, command, rechecking)
569  *
570  *	Scans the .SUFFIXES list and tries
571  *	to find a suffix on it that matches the tail of the target name.
572  *	If it finds a matching suffix it calls find_suffix_rule() to find
573  *	a rule for the target.
574  *
575  *	Return value:
576  *				Indicates if scan failed or not
577  *
578  *	Parameters:
579  *		target		Target we need a rule for
580  *		command		Pointer to slot where we stuff cmd, if found
581  *		rechecking	true if we are rechecking target which depends
582  *				on conditional macro and keep_state is set
583  *
584  *	Global variables used:
585  *		debug_level	Indicates how much tracing to do
586  *		recursion_level	Used for tracing
587  *		suffixes	List of suffixes used for scan (from .SUFFIXES)
588  */
589 Doname
find_double_suffix_rule(register Name target,Property * command,Boolean rechecking)590 find_double_suffix_rule(register Name target, Property *command, Boolean rechecking)
591 {
592 	Name			true_target = target;
593 	Name			target_body;
594 	register wchar_t	*target_end;
595 	register Dependency	suffix;
596 	register int		suffix_length;
597 	Boolean			scanned_once = false;
598 	Boolean			name_found = true;
599 
600 	Wstring			targ_string;
601 	Wstring			suf_string;
602 
603 	/*
604 	 * If the target is a constructed one for a "::" target,
605 	 * we need to consider that.
606 	 */
607 	if (target->has_target_prop) {
608 		true_target = get_prop(target->prop,
609 				       target_prop)->body.target.target;
610 	}
611 	targ_string.init(true_target);
612 
613 	/*
614 	 * We compare the tail of the target name with the
615 	 * suffixes from .SUFFIXES.
616 	 */
617 	target_end = targ_string.get_string() + true_target->hash.length;
618 	if (debug_level > 1) {
619 		(void) printf("%*sfind_double_suffix_rule(%s)\n",
620 			      recursion_level,
621 			      "",
622 			      true_target->string_mb);
623 	}
624 	/*
625 	 * Scan the .SUFFIXES list to see if the target matches
626 	 * any of those suffixes.
627 	 */
628 	for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
629 		target->suffix_scan_done = false;
630 		true_target->suffix_scan_done = false;
631 		/* Compare one suffix. */
632 		suffix_length = suffix->name->hash.length;
633 		suf_string.init(suffix->name);
634 		/* Check the lengths, or else RTC will report rua. */
635 		if (true_target->hash.length < suffix_length) {
636 			goto not_this_one;
637 		} else if (!IS_WEQUALN(suf_string.get_string(),
638 			        (target_end - suffix_length),
639 			        suffix_length)) {
640 			goto not_this_one;
641 		}
642 		/*
643 		 * The target tail matched a suffix from the .SUFFIXES list.
644 		 * Now check for a rule to match.
645 		 */
646 		we_are_in_tilde = false;
647 		target_body = GETNAME(
648 			targ_string.get_string(),
649 			(int)(true_target->hash.length - suffix_length)
650 		);
651 		switch (find_suffix_rule(target,
652 					 target_body,
653 					 suffix->name,
654 					 command,
655 					 rechecking)) {
656 		case build_ok:
657 			return build_ok;
658 		case build_running:
659 			return build_running;
660 		}
661 		if (true_target->suffix_scan_done == true) {
662 			scanned_once = true;
663 		}
664 		/*
665 		 * If no rule was found, we try the next suffix to see
666 		 * if it matches the target tail. And so on.
667 		 * Go here if the suffix did not match the target tail.
668 		 */
669 	not_this_one:;
670 	}
671 	if (scanned_once)
672 		true_target->suffix_scan_done = true;
673 	return build_dont_know;
674 }
675 
676 /*
677  *	build_suffix_list(target_suffix)
678  *
679  *	Scans the .SUFFIXES list and figures out
680  *	which suffixes this target can be derived from.
681  *	The target itself is not know here, we just know the suffix of the
682  *	target. For each suffix on the list the target can be derived iff
683  *	a rule exists for the name "<suffix-on-list><target-suffix>".
684  *	A list of all possible building suffixes is built, with the rule for
685  *	each, and tacked to the target suffix nameblock.
686  *
687  *	Parameters:
688  *		target_suffix	The suffix we build a match list for
689  *
690  *	Global variables used:
691  *		debug_level	Indicates how much tracing to do
692  *		recursion_level	Used for tracing
693  *		suffixes	List of suffixes used for scan (from .SUFFIXES)
694  *		working_on_targets Indicates that this is a real target
695  */
696 void
build_suffix_list(register Name target_suffix)697 build_suffix_list(register Name target_suffix)
698 {
699 	register Dependency	source_suffix;
700 	wchar_t			rule_name[MAXPATHLEN];
701 	register Property	line;
702 	register Property	suffix;
703 	Name			rule;
704 
705 	/* If this is before default.mk has been read we just return to try */
706 	/* again later */
707 	if ((suffixes == NULL) || !working_on_targets) {
708 		return;
709 	}
710 	if (debug_level > 1) {
711 		(void) printf("%*sbuild_suffix_list(%s) ",
712 			      recursion_level,
713 			      "",
714 			      target_suffix->string_mb);
715 	}
716 	/* Mark the target suffix saying we cashed its list */
717 	target_suffix->has_read_suffixes = true;
718 	/* Scan the .SUFFIXES list */
719 	for (source_suffix = suffixes;
720 	     source_suffix != NULL;
721 	     source_suffix = source_suffix->next) {
722 		/*
723 		 * Build the name "<suffix-on-list><target-suffix>".
724 		 * (a popular one would be ".c.o").
725 		 */
726 		(void) mbstowcs(rule_name,
727 			      source_suffix->name->string_mb,
728 			      (int) source_suffix->name->hash.length);
729 		(void) mbstowcs(rule_name + source_suffix->name->hash.length,
730 			      target_suffix->string_mb,
731 			      (int) target_suffix->hash.length);
732 		/*
733 		 * Check if that name has a rule. If not, it cannot match
734 		 * any implicit rule scan and is ignored.
735 		 * The GETNAME() call only checks for presence, it will not
736 		 * enter the name if it is not defined.
737 		 */
738 		if (((rule = getname_fn(rule_name,
739 					(int) (source_suffix->name->
740 					       hash.length +
741 					       target_suffix->hash.length),
742 					true)) != NULL) &&
743 		    ((line = get_prop(rule->prop, line_prop)) != NULL)) {
744 			if (debug_level > 1) {
745 				(void) printf("%s ", rule->string_mb);
746 			}
747 			/*
748 			 * This makes it possible to quickly determine if
749 			 * it will pay to look for a suffix property.
750 			 */
751 			target_suffix->has_suffixes = true;
752 			/*
753 			 * Add the suffix property to the target suffix
754 			 * and save the rule with it.
755 			 * All information the implicit rule scanner need
756 			 * is saved in the suffix property.
757 			 */
758 			suffix = append_prop(target_suffix, suffix_prop);
759 			suffix->body.suffix.suffix = source_suffix->name;
760 			suffix->body.suffix.command_template =
761 			  line->body.line.command_template;
762 		}
763 	}
764 	if (debug_level > 1) {
765 		(void) printf("\n");
766 	}
767 }
768 
769 /*
770  *	find_percent_rule(target, command, rechecking)
771  *
772  *	Tries to find a rule from the list of wildcard matched rules.
773  *	It scans the list attempting to match the target.
774  *	For each target match it checks if the corresponding source exists.
775  *	If it does the match is returned.
776  *	The percent_list is built at makefile read time.
777  *	Each percent rule get one entry on the list.
778  *
779  *	Return value:
780  *				Indicates if the scan failed or not
781  *
782  *	Parameters:
783  *		target		The target we need a rule for
784  *		command		Pointer to slot where we stuff cmd, if found
785  *		rechecking	true if we are rechecking target which depends
786  *				on conditional macro and keep_state is set
787  *
788  *	Global variables used:
789  *		debug_level	Indicates how much tracing to do
790  *		percent_list	List of all percent rules
791  *		recursion_level	Used for tracing
792  *		empty_name
793  */
794 Doname
find_percent_rule(register Name target,Property * command,Boolean rechecking)795 find_percent_rule(register Name target, Property *command, Boolean rechecking)
796 {
797 	register Percent	pat_rule, pat_depe;
798 	register Name		depe_to_check;
799 	register Dependency	depe;
800 	register Property	line;
801 	String_rec		string;
802 	wchar_t			string_buf[STRING_BUFFER_LENGTH];
803 	String_rec		percent;
804 	wchar_t			percent_buf[STRING_BUFFER_LENGTH];
805 	Name			true_target = target;
806 	Name			less;
807 	Boolean			nonpattern_less;
808 	Boolean			dep_name_found = false;
809 	Doname			result = build_dont_know;
810 	Percent			rule_candidate = NULL;
811 	Boolean			rule_maybe_ok;
812 	Boolean			is_pattern;
813 
814 	/* If the target is constructed for a "::" target we consider that */
815 	if (target->has_target_prop) {
816 		true_target = get_prop(target->prop,
817 				       target_prop)->body.target.target;
818 	}
819 	if (target->has_long_member_name) {
820 		true_target = get_prop(target->prop,
821 				       long_member_name_prop)->body.long_member_name.member_name;
822 	}
823 	if (debug_level > 1) {
824 		(void) printf(gettext("%*sLooking for %% rule for %s\n"),
825 			      recursion_level,
826 			      "",
827 			      true_target->string_mb);
828 	}
829 	for (pat_rule = percent_list;
830 	     pat_rule != NULL;
831 	     pat_rule = pat_rule->next) {
832 		/* Avoid infinite recursion when expanding patterns */
833 		if (pat_rule->being_expanded == true) {
834 			continue;
835 		}
836 
837 		/* Mark this pat_rule as "maybe ok". If no % rule is found
838 		   make will use this rule. The following algorithm is used:
839 		   1) make scans all pattern rules in order to find the rule
840 		      where ALL dependencies, including nonpattern ones, exist or
841 		      can be built (GNU behaviour). If such rule is found make
842 		      will apply it.
843 		   2) During this check make also remembers the first pattern rule
844 		      where all PATTERN dependencies can be build (no matter what
845 		      happens with nonpattern dependencies).
846 		   3) If no rule satisfying 1) is found, make will apply the rule
847 		      remembered in 2) if there is one.
848 		*/
849 		rule_maybe_ok = true;
850 
851 		/* used to track first percent dependency */
852 		less = NULL;
853 		nonpattern_less = true;
854 
855 		/* check whether pattern matches.
856 		   if it matches, percent string will contain matched percent part of pattern */
857 		if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) {
858 			continue;
859 		}
860 		if (pat_rule->dependencies != NULL) {
861 			for (pat_depe = pat_rule->dependencies;
862 			     pat_depe != NULL;
863 			     pat_depe = pat_depe->next) {
864 				/* checking result for dependency */
865 				result = build_dont_know;
866 
867 				dep_name_found = true;
868 				if (pat_depe->name->percent) {
869 					is_pattern = true;
870 					/* build dependency name */
871 					INIT_STRING_FROM_STACK(string, string_buf);
872 					construct_string_from_pattern(pat_depe, &percent, &string);
873 					depe_to_check = getname_fn(string.buffer.start,
874 						FIND_LENGTH,
875 						false,
876 						&dep_name_found
877 					);
878 
879 					if ((less == NULL) || nonpattern_less) {
880 						less = depe_to_check;
881 						nonpattern_less = false;
882 					}
883 				} else {
884 					/* nonpattern dependency */
885 					is_pattern = false;
886 					depe_to_check = pat_depe->name;
887 					if(depe_to_check->dollar) {
888 						INIT_STRING_FROM_STACK(string, string_buf);
889 						expand_value(depe_to_check, &string, false);
890 						depe_to_check = getname_fn(string.buffer.start,
891 							FIND_LENGTH,
892 							false,
893 							&dep_name_found
894 						);
895 					}
896 					if (less == NULL) {
897 						less = depe_to_check;
898 					}
899 				}
900 
901 				if (depe_to_check == empty_name) {
902 						result = build_ok;
903 				} else {
904 					if (debug_level > 1) {
905 						(void) printf(gettext("%*sTrying %s\n"),
906 							      recursion_level,
907 							      "",
908 							      depe_to_check->string_mb);
909 					}
910 
911 					pat_rule->being_expanded = true;
912 
913 					/* suppress message output */
914 					int save_debug_level = debug_level;
915 					debug_level = 0;
916 
917 					/* check whether dependency can be built */
918 					if (dependency_exists(depe_to_check,
919 					      get_prop(target->prop,
920 						       line_prop)))
921 					{
922 						result = (Doname) depe_to_check->state;
923 					} else {
924 						if(actual_doname) {
925 							result = doname(depe_to_check, true, true);
926 						} else {
927 							result = target_can_be_built(depe_to_check);
928 						}
929 						if(!dep_name_found) {
930 							if(result != build_ok && result != build_running) {
931 								free_name(depe_to_check);
932 							} else {
933 								store_name(depe_to_check);
934 							}
935 						}
936 					}
937 					if(result != build_ok && is_pattern) {
938 						rule_maybe_ok = false;
939 					}
940 
941 					/* restore debug_level */
942 					debug_level = save_debug_level;
943 				}
944 
945 				if (pat_depe->name->percent) {
946 					if (string.free_after_use) {
947 						retmem(string.buffer.start);
948 					}
949 				}
950 				/* make can't figure out how to make this dependency */
951 				if (result != build_ok && result != build_running) {
952 					pat_rule->being_expanded = false;
953 					break;
954 				}
955 			}
956 		} else {
957 			result = build_ok;
958 		}
959 
960 		/* this pattern rule is the needed one since all dependencies could be built */
961 		if (result == build_ok || result == build_running) {
962 			break;
963 		}
964 
965 		/* Make does not know how to build some of dependencies from this rule.
966 		   But if all "pattern" dependencies can be built, we remember this rule
967 		   as a candidate for the case if no other pattern rule found.
968 		*/
969 		if(rule_maybe_ok && rule_candidate == NULL) {
970 			rule_candidate = pat_rule;
971 		}
972 	}
973 
974 	/* if no pattern matching rule was found, use the remembered candidate
975 	   or return build_dont_know if there is no candidate.
976 	*/
977 	if (result != build_ok && result != build_running) {
978 		if(rule_candidate) {
979 			pat_rule = rule_candidate;
980 		} else {
981 			return build_dont_know;
982 		}
983 	}
984 
985 	/* if we are performing only check whether dependency could be built with existing rules,
986 	   return success */
987 	if (command == NULL) {
988 		if(pat_rule != NULL) {
989 			pat_rule->being_expanded = false;
990 		}
991 		return result;
992 	}
993 
994 	if (debug_level > 1) {
995 		(void) printf(gettext("%*sMatched %s:"),
996 				      recursion_level,
997 				      "",
998 				      target->string_mb);
999 
1000 		for (pat_depe = pat_rule->dependencies;
1001 		     pat_depe != NULL;
1002 		     pat_depe = pat_depe->next) {
1003 			if (pat_depe->name->percent) {
1004 				INIT_STRING_FROM_STACK(string, string_buf);
1005 				construct_string_from_pattern(pat_depe, &percent, &string);
1006 				depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1007 			} else {
1008 				depe_to_check = pat_depe->name;
1009 				if(depe_to_check->dollar) {
1010 					INIT_STRING_FROM_STACK(string, string_buf);
1011 					expand_value(depe_to_check, &string, false);
1012 					depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1013 				}
1014 			}
1015 
1016 			if (depe_to_check != empty_name) {
1017 				(void) printf(" %s", depe_to_check->string_mb);
1018 			}
1019 		}
1020 
1021 		(void) printf(gettext(" from: %s:"),
1022 			      pat_rule->name->string_mb);
1023 
1024 		for (pat_depe = pat_rule->dependencies;
1025 		     pat_depe != NULL;
1026 		     pat_depe = pat_depe->next) {
1027 			(void) printf(" %s", pat_depe->name->string_mb);
1028 		}
1029 
1030 		(void) printf("\n");
1031 	}
1032 
1033 	if (true_target->colons == no_colon) {
1034 		true_target->colons = one_colon;
1035 	}
1036 
1037 	/* create deppendency list and target group from matched pattern rule */
1038 	create_target_group_and_dependencies_list(target, pat_rule, &percent);
1039 
1040 	/* save command */
1041 	line = get_prop(target->prop, line_prop);
1042 	*command = line;
1043 
1044 	/* free query chain if one exist */
1045 	while(line->body.line.query != NULL) {
1046 		Chain to_free = line->body.line.query;
1047 		line->body.line.query = line->body.line.query->next;
1048 		retmem_mb((char *) to_free);
1049 	}
1050 
1051 	if (line->body.line.dependencies != NULL) {
1052 		/* build all collected dependencies */
1053 		for (depe = line->body.line.dependencies;
1054 		     depe != NULL;
1055 		     depe = depe->next) {
1056 			actual_doname = true;
1057 			result = doname_check(depe->name, true, true, depe->automatic);
1058 
1059 			actual_doname = false;
1060 			if (result == build_failed) {
1061 				pat_rule->being_expanded = false;
1062 				return build_failed;
1063 			}
1064 			if (result == build_running) {
1065 				pat_rule->being_expanded = false;
1066 				return build_running;
1067 			}
1068 
1069 			if ((depe->name->stat.time > line->body.line.dependency_time) &&
1070 			    (debug_level > 1)) {
1071 				(void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1072 					      recursion_level,
1073 					      "",
1074 					      depe->name->string_mb,
1075 					      time_to_string(depe->name->stat.time),
1076 					      true_target->string_mb,
1077 					      time_to_string(line->body.line.dependency_time));
1078 			}
1079 
1080 			line->body.line.dependency_time =
1081 			  MAX(line->body.line.dependency_time, depe->name->stat.time);
1082 
1083 			/* determine whether this dependency made target out of date */
1084 			Boolean out_of_date;
1085 			if (target->is_member || depe->name->is_member) {
1086 				out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1087 			} else {
1088 				out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1089 			}
1090 			if (build_unconditional || out_of_date) {
1091 				if(!rechecking) {
1092 					line->body.line.is_out_of_date = true;
1093 				}
1094 				add_target_to_chain(depe->name, &(line->body.line.query));
1095 
1096 				if (debug_level > 0) {
1097 					(void) printf(gettext("%*sBuilding %s using pattern rule %s:"),
1098 						      recursion_level,
1099 						      "",
1100 						      true_target->string_mb,
1101 						      pat_rule->name->string_mb);
1102 
1103 					for (pat_depe = pat_rule->dependencies;
1104 					     pat_depe != NULL;
1105 					     pat_depe = pat_depe->next) {
1106 						(void) printf(" %s", pat_depe->name->string_mb);
1107 					}
1108 
1109 					(void) printf(gettext(" because it is out of date relative to %s\n"),
1110 						      depe->name->string_mb);
1111 				}
1112 			}
1113 		}
1114 	} else {
1115 		if ((true_target->stat.time <= file_doesnt_exist) ||
1116 		    (true_target->stat.time < line->body.line.dependency_time)) {
1117 			if(!rechecking) {
1118 				line->body.line.is_out_of_date = true;
1119 			}
1120 			if (debug_level > 0) {
1121 				(void) printf(gettext("%*sBuilding %s using pattern rule %s: "),
1122 					      recursion_level,
1123 					      "",
1124 					      true_target->string_mb,
1125 					      pat_rule->name->string_mb,
1126 					      (target->stat.time > file_doesnt_exist) ?
1127 					      gettext("because it is out of date") :
1128 					      gettext("because it does not exist"));
1129 			}
1130 		}
1131 	}
1132 
1133 	/* enter explicit rule from percent rule */
1134 	Name lmn_target = true_target;
1135 	if (true_target->has_long_member_name) {
1136 		lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1137 	}
1138 	line->body.line.sccs_command = false;
1139 	line->body.line.target = true_target;
1140 	line->body.line.command_template = pat_rule->command_template;
1141 	line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1142 	line->body.line.less = less;
1143 
1144 	if (lmn_target->parenleft) {
1145 		Wstring lmn_string(lmn_target);
1146 
1147 		wchar_t *left = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenleft_char);
1148 		wchar_t *right = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenright_char);
1149 
1150 		if ((left == NULL) || (right == NULL)) {
1151 			line->body.line.percent = NULL;
1152 		} else {
1153 			line->body.line.percent = GETNAME(left + 1, right - left - 1);
1154 		}
1155 	} else {
1156 		line->body.line.percent = NULL;
1157 	}
1158 	pat_rule->being_expanded = false;
1159 
1160 	return result;
1161 }
1162 
1163 /*
1164  *	match_found_with_pattern
1165  *           ( target, pat_rule, percent, percent_buf)
1166  *
1167  *	matches "target->string" with a % pattern.
1168  *	If pattern contains a MACRO definition, it's expanded first.
1169  *
1170  *	Return value:
1171  *				true if a match was found
1172  *
1173  *	Parameters:
1174  *		target		The target we're trying to match
1175  *     		pattern
1176  *		percent		record that contains "percent_buf" below
1177  *		percent_buf	This is where the patched % part of pattern is stored
1178  *
1179  */
1180 
1181 static Boolean
match_found_with_pattern(Name target,Percent pat_rule,String percent,wchar_t * percent_buf)1182 match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) {
1183 	String_rec		string;
1184 	wchar_t			string_buf[STRING_BUFFER_LENGTH];
1185 
1186 	/* construct prefix string and check whether prefix matches */
1187 	Name prefix = pat_rule->patterns[0];
1188 	int prefix_length;
1189 
1190 	Wstring targ_string(target);
1191 	Wstring pref_string(prefix);
1192 	Wstring suf_string;
1193 
1194 	if (prefix->dollar) {
1195 		INIT_STRING_FROM_STACK(string, string_buf);
1196 		expand_value(prefix, &string, false);
1197 		prefix_length = string.text.p - string.buffer.start;
1198 		if ((string.buffer.start[0] == (int) period_char) &&
1199 		    (string.buffer.start[1] == (int) slash_char)) {
1200 			string.buffer.start += 2;
1201 			prefix_length -= 2;
1202 		}
1203 		if (!targ_string.equaln(string.buffer.start, prefix_length)) {
1204 			return false;
1205 		}
1206 	} else {
1207 		prefix_length = prefix->hash.length;
1208 		if (!targ_string.equaln(&pref_string, prefix_length)) {
1209 			return false;
1210 		}
1211 	}
1212 
1213 	/* do the same with pattern suffix */
1214 	Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1];
1215 	suf_string.init(suffix);
1216 
1217 	int suffix_length;
1218 	if (suffix->dollar) {
1219 		INIT_STRING_FROM_STACK(string, string_buf);
1220 		expand_value(suffix, &string, false);
1221 		suffix_length = string.text.p - string.buffer.start;
1222 		if(suffix_length > target->hash.length) {
1223 			return false;
1224 		}
1225 		if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) {
1226 			return false;
1227 		}
1228 	} else {
1229 		suffix_length = (int) suffix->hash.length;
1230 		if(suffix_length > target->hash.length) {
1231 			return false;
1232 		}
1233 		if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) {
1234 			return false;
1235 		}
1236 	}
1237 
1238 	Boolean match_found = false;
1239 	int percent_length = target->hash.length - prefix_length - suffix_length;
1240 
1241 	while (!match_found && (percent_length >= 0)) {
1242 		/* init result string */
1243 		INIT_STRING_FROM_STACK(string, string_buf);
1244 
1245 		/* init percent string */
1246 		percent->buffer.start = percent_buf;
1247 		percent->text.p = percent_buf;
1248 		percent->text.end = NULL;
1249 		percent->free_after_use = false;
1250 		percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH;
1251 
1252 		/* construct percent and result strings */
1253 		targ_string.append_to_str(percent, prefix_length, percent_length);
1254 		construct_string_from_pattern(pat_rule, percent, &string);
1255 
1256 		/* check for match */
1257 		if (targ_string.equal(string.buffer.start, 0)) {
1258 			match_found = true;
1259 		} else {
1260 			percent_length--;
1261 		}
1262 	}
1263 
1264 	/* result */
1265 	return match_found;
1266 }
1267 
1268 
1269 /*
1270  *	create_target_group_and_dependencies_list
1271  *           (target, pat_rule, percent)
1272  *
1273  *	constructs dependency list and a target group from pattern.
1274  *
1275  *	If we have the lines
1276  *		%/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e
1277  *			commands
1278  *
1279  * 	and we have matched the pattern xx/xx.a with %/%.a, then we
1280  *	construct a target group that looks like this:
1281  *		xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies
1282  *
1283  *	and construct dependency list that looks like this:
1284  *	yyy xx.d bbxx/BBxx.e + already existed dependencies
1285  *
1286  *	Return value:
1287  *				none
1288  *
1289  *	Parameters:
1290  *		target		The target we are building, in the previous
1291  *				example, this is xx/xx.a
1292  *     		pat_rule        the % pattern that matched "target", here %/%.a
1293  *		percent		string containing matched % part. In the example=xx.
1294  *
1295  *	Global variables used:
1296  *		empty_name
1297  */
1298 
1299 static void
create_target_group_and_dependencies_list(Name target,Percent pat_rule,String percent)1300 create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) {
1301 	String_rec	string;
1302 	wchar_t		string_buf[STRING_BUFFER_LENGTH];
1303 	Percent		pat_depe;
1304 	Name		depe;
1305 	Property	line = maybe_append_prop(target, line_prop);
1306 	Chain		new_target_group = NULL;
1307 	Chain		*new_target_group_tail = &new_target_group;
1308 	Chain		group_member;
1309 
1310 	/* create and append dependencies from rule */
1311 	for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) {
1312 		if (pat_depe->name->percent) {
1313 			INIT_STRING_FROM_STACK(string, string_buf);
1314 			construct_string_from_pattern(pat_depe, percent, &string);
1315 			depe = GETNAME(string.buffer.start, FIND_LENGTH);
1316 			if (depe != empty_name) {
1317 				enter_dependency(line, depe, false);
1318 			}
1319 		} else {
1320 			depe = pat_depe->name;
1321 			if(depe->dollar) {
1322 				INIT_STRING_FROM_STACK(string, string_buf);
1323 				expand_value(depe, &string, false);
1324 				depe = GETNAME(string.buffer.start, FIND_LENGTH);
1325 			}
1326 			enter_dependency(line, depe, false);
1327 		}
1328 	}
1329 
1330 	/* if matched pattern is a group member, create new target group */
1331 	for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) {
1332 		Name new_target = group_member->name;
1333 		if (group_member->name->percent) {
1334 			INIT_STRING_FROM_STACK(string, string_buf);
1335 			construct_string_from_pattern(group_member->percent_member, percent, &string);
1336 			new_target = GETNAME(string.buffer.start, FIND_LENGTH);
1337 			if (new_target == empty_name) {
1338 				continue;
1339 			}
1340 		}
1341 
1342 		/* check for duplicates */
1343 		Chain	tgm;
1344 		for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) {
1345 			if (new_target == tgm->name) {
1346 				break;
1347 			}
1348 		}
1349 		if (tgm != NULL) {
1350 			continue;
1351 		}
1352 
1353 		/* insert it into the targets list */
1354 		(*new_target_group_tail) = ALLOC(Chain);
1355 		(*new_target_group_tail)->name = new_target;
1356 		(*new_target_group_tail)->next = NULL;
1357 		new_target_group_tail = &(*new_target_group_tail)->next;
1358 	}
1359 
1360 	/* now we gathered all dependencies and created target group */
1361 	line->body.line.target_group = new_target_group;
1362 
1363 	/* update properties for group members */
1364 	for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) {
1365 		if (group_member->name != target) {
1366 			group_member->name->prop = target->prop;
1367 			group_member->name->conditional_cnt = target->conditional_cnt;
1368 		}
1369 	}
1370 }
1371 
1372 /*
1373  *	construct_string_from_pattern
1374  *		(pat_rule, percent, result)
1375  *
1376  *	after pattern matched a target this routine is called to construct targets and dependencies
1377  *	strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern.
1378  *
1379  *	Return value:
1380  *				none
1381  *
1382  *	Parameters:
1383  *     		pat_rule 	matched pattern rule
1384  *		percent		string containing matched % sign part.
1385  *		result		holds the result of string construction.
1386  *
1387  */
1388 static void
construct_string_from_pattern(Percent pat_rule,String percent,String result)1389 construct_string_from_pattern(Percent pat_rule, String percent, String result) {
1390 	for (int i = 0; i < pat_rule->patterns_total; i++) {
1391 		if (pat_rule->patterns[i]->dollar) {
1392 			expand_value(pat_rule->patterns[i],
1393 				     result,
1394 				     false);
1395 
1396 		} else {
1397 			append_string(pat_rule->patterns[i]->string_mb,
1398 				      result,
1399 				      pat_rule->patterns[i]->hash.length);
1400 		}
1401 
1402 		if (i < pat_rule->patterns_total - 1) {
1403 			append_string(percent->buffer.start,
1404 				      result,
1405 				      percent->text.p - percent->buffer.start);
1406 		}
1407 	}
1408 
1409 	if ((result->buffer.start[0] == (int) period_char) &&
1410 	    (result->buffer.start[1] == (int) slash_char)) {
1411 		result->buffer.start += 2;
1412 	}
1413 }
1414 
1415 /*
1416  *	dependency_exists(target, line)
1417  *
1418  *	Returns true if the target exists in the
1419  *	dependency list of the line.
1420  *
1421  *	Return value:
1422  *				True if target is on dependency list
1423  *
1424  *	Parameters:
1425  *		target		Target we scan for
1426  *		line		We get the dependency list from here
1427  *
1428  *	Global variables used:
1429  */
1430 static Boolean
dependency_exists(Name target,Property line)1431 dependency_exists(Name target, Property line)
1432 {
1433 	Dependency	dp;
1434 
1435 	if (line == NULL) {
1436 		return false;
1437 	}
1438 	for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1439 		if (dp->name == target) {
1440 			return true;
1441 		}
1442 	}
1443 	return false;
1444 }
1445 
1446 void
add_target_to_chain(Name target,Chain * query)1447 add_target_to_chain(Name target, Chain * query)
1448 {
1449 	if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) {
1450 		target = get_prop(target->prop, member_prop)->body.member.member;
1451 	}
1452 	Chain	*query_tail;
1453 	for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) {
1454 		if ((*query_tail)->name == target) {
1455 			return;
1456 		}
1457 	}
1458 	*query_tail = ALLOC(Chain);
1459 	(*query_tail)->name = target;
1460 	(*query_tail)->next = NULL;
1461 }
1462 
1463