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