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