summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/bin/make/common/implicit.cc
diff options
context:
space:
mode:
authorIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
committerIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
commite0463df9c3d2ee6155221cc443c571d5da47098a (patch)
tree5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/implicit.cc
downloadsunmake-orig.tar.gz
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/ Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/implicit.cc')
-rw-r--r--usr/src/make_src/Make/bin/make/common/implicit.cc1479
1 files changed, 1479 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/implicit.cc b/usr/src/make_src/Make/bin/make/common/implicit.cc
new file mode 100644
index 0000000..a9b2f1d
--- /dev/null
+++ b/usr/src/make_src/Make/bin/make/common/implicit.cc
@@ -0,0 +1,1479 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)implicit.cc 1.64 06/12/12
+ */
+
+#pragma ident "@(#)implicit.cc 1.64 06/12/12"
+
+/*
+ * implicit.c
+ *
+ * Handle suffix and percent rules
+ */
+
+/*
+ * Included files
+ */
+#include <mk/defs.h>
+#include <mksh/macro.h> /* expand_value() */
+#include <mksh/misc.h> /* retmem() */
+
+/*
+ * Defined macros
+ */
+
+/*
+ * typedefs & structs
+ */
+
+/*
+ * Static variables
+ */
+static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char};
+
+/*
+ * File table of contents
+ */
+extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
+extern Doname find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
+extern Doname find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
+extern void build_suffix_list(register Name target_suffix);
+extern Doname find_percent_rule(register Name target, Property *command, Boolean rechecking);
+static void create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent);
+static Boolean match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf);
+static void construct_string_from_pattern(Percent pat_rule, String percent, String result);
+static Boolean dependency_exists(Name target, Property line);
+extern Property maybe_append_prop(Name, Property_id);
+extern void add_target_to_chain(Name target, Chain * query);
+
+/*
+ * find_suffix_rule(target, target_body, target_suffix, command, rechecking)
+ *
+ * Does the lookup for single and double suffix rules.
+ * It calls build_suffix_list() to build the list of possible suffixes
+ * for the given target.
+ * It then scans the list to find the first possible source file that
+ * exists. This is done by concatenating the body of the target name
+ * (target name less target suffix) and the source suffix and checking
+ * if the resulting file exists.
+ *
+ * Return value:
+ * Indicates if search failed or not
+ *
+ * Parameters:
+ * target The target we need a rule for
+ * target_body The target name without the suffix
+ * target_suffix The suffix of the target
+ * command Pointer to slot to deposit cmd in if found
+ * rechecking true if we are rechecking target which depends
+ * on conditional macro and keep_state is set
+ *
+ * Global variables used:
+ * debug_level Indicates how much tracing to do
+ * recursion_level Used for tracing
+ */
+
+extern int printf (const char *, ...);
+
+static Boolean actual_doname = false;
+
+/* /tolik/
+ * fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
+ * When make attemps to apply % rule it didn't look for a single suffix rule because
+ * if "doname" is called from "find_percent_rule" argument "implicit" is set to true
+ * and find_suffix_rule was not called. I've commented the checking of "implicit"
+ * in "doname" and make got infinite recursion for SVR4 tilde rules.
+ * Usage of "we_are_in_tilde" is intended to avoid this recursion.
+ */
+
+static Boolean we_are_in_tilde = false;
+
+Doname
+find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking)
+{
+ static wchar_t static_string_buf_3M [ 3 * MAXPATHLEN ];
+ Name true_target = target;
+ wchar_t *sourcename = (wchar_t*)static_string_buf_3M;
+ register wchar_t *put_suffix;
+ register Property source_suffix;
+ register Name source;
+ Doname result;
+ register Property line;
+ extern Boolean tilde_rule;
+ Boolean name_found = true;
+ Boolean posix_tilde_attempt = true;
+ int src_len = MAXPATHLEN + strlen(target_body->string_mb);
+
+ /*
+ * To avoid infinite recursion
+ */
+ if(we_are_in_tilde) {
+ we_are_in_tilde = false;
+ return(build_dont_know);
+ }
+
+ /*
+ * If the target is a constructed one for a "::" target,
+ * we need to consider that.
+ */
+ if (target->has_target_prop) {
+ true_target = get_prop(target->prop,
+ target_prop)->body.target.target;
+ }
+ if (debug_level > 1) {
+ (void) printf(NOCATGETS("%*sfind_suffix_rule(%s,%s,%s)\n"),
+ recursion_level,
+ "",
+ true_target->string_mb,
+ target_body->string_mb,
+ target_suffix->string_mb);
+ }
+ if (command != NULL) {
+ if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
+ return build_ok;
+ }
+ }
+ true_target->suffix_scan_done = true;
+ /*
+ * Enter all names from the directory where the target lives as
+ * files that makes sense.
+ * This will make finding the synthesized source possible.
+ */
+ read_directory_of_file(target_body);
+ /* Cache the suffixes for this target suffix if not done. */
+ if (!target_suffix->has_read_suffixes) {
+ build_suffix_list(target_suffix);
+ }
+ /* Preload the sourcename vector with the head of the target name. */
+ if (src_len >= sizeof(static_string_buf_3M)) {
+ sourcename = ALLOC_WC(src_len);
+ }
+ (void) mbstowcs(sourcename,
+ target_body->string_mb,
+ (int) target_body->hash.length);
+ put_suffix = sourcename + target_body->hash.length;
+ /* Scan the suffix list for the target if one exists. */
+ if (target_suffix->has_suffixes) {
+posix_attempts:
+ for (source_suffix = get_prop(target_suffix->prop,
+ suffix_prop);
+ source_suffix != NULL;
+ source_suffix = get_prop(source_suffix->next,
+ suffix_prop)) {
+ /* Build the synthesized source name. */
+ (void) mbstowcs(put_suffix,
+ source_suffix->body.
+ suffix.suffix->string_mb,
+ (int) source_suffix->body.
+ suffix.suffix->hash.length);
+ put_suffix[source_suffix->body.
+ suffix.suffix->hash.length] =
+ (int) nul_char;
+ if (debug_level > 1) {
+ WCSTOMBS(mbs_buffer, sourcename);
+ (void) printf(catgets(catd, 1, 218, "%*sTrying %s\n"),
+ recursion_level,
+ "",
+ mbs_buffer);
+ }
+ source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
+ /*
+ * If the source file is not registered as
+ * a file, this source suffix did not match.
+ */
+ if(vpath_defined && !posix && !svr4) {
+ (void) exists(source);
+ }
+ if (!source->stat.is_file) {
+ if(!(posix|svr4))
+ {
+ if(!name_found) {
+ free_name(source);
+ }
+ continue;
+ }
+
+ /* following code will ensure that the corresponding
+ ** tilde rules are executed when corresponding s. file
+ ** exists in the current directory. Though the current
+ ** target ends with a ~ character, there wont be any
+ ** any file in the current directory with that suffix
+ ** as it's fictitious. Even if it exists, it'll
+ ** execute all the rules for the ~ target.
+ */
+
+ if(source->string_mb[source->hash.length - 1] == '~' &&
+ ( svr4 || posix_tilde_attempt ) )
+ {
+ char *p, *np;
+ char *tmpbuf;
+
+ tmpbuf = getmem(source->hash.length + 8);
+ /* + 8 to add "s." or "SCCS/s." */
+ memset(tmpbuf,0,source->hash.length + 8);
+ source->string_mb[source->hash.length - 1] = '\0';
+ if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length))
+ {
+ while(1) {
+ if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
+ p = np;
+ } else {break;}
+ }
+ /* copy everything including '/' */
+ strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
+ strcat(tmpbuf, NOCATGETS("s."));
+ strcat(tmpbuf, p+1);
+ retmem((wchar_t *) source->string_mb);
+ source->string_mb = tmpbuf;
+
+ } else {
+ strcpy(tmpbuf, NOCATGETS("s."));
+ strcat(tmpbuf, source->string_mb);
+ retmem((wchar_t *) source->string_mb);
+ source->string_mb = tmpbuf;
+
+ }
+ source->hash.length = strlen(source->string_mb);
+ if(exists(source) == file_doesnt_exist)
+ continue;
+ tilde_rule = true;
+ we_are_in_tilde = true;
+ } else {
+ if(!name_found) {
+ free_name(source);
+ }
+ continue;
+ }
+ } else {
+ if(posix && posix_tilde_attempt) {
+ if(exists(source) == file_doesnt_exist) {
+ if(!name_found) {
+ free_name(source);
+ }
+ continue;
+ }
+ }
+ }
+
+ if (command != NULL) {
+ if(!name_found) {
+ store_name(source);
+ }
+ /*
+ * The source file is a file.
+ * Make sure it is up to date.
+ */
+ if (dependency_exists(source,
+ get_prop(target->prop,
+ line_prop))) {
+ result = (Doname) source->state;
+ } else {
+#ifdef NSE
+ nse_check_derived_src(target, source->string,
+ source_suffix->body.suffix.command_template);
+#endif
+#if 0 /* with_squiggle sends false, which is buggy. : djay */
+ result = doname(source,
+ (Boolean) source_suffix->body.
+ suffix.suffix->with_squiggle,
+ true);
+#else
+ result = doname(source,
+ true,
+ true);
+#endif
+ }
+ } else {
+ result = target_can_be_built(source);
+
+ if (result == build_ok) {
+ return result;
+ } else {
+ if(!name_found) {
+ free_name(source);
+ }
+ continue;
+ }
+ }
+
+ switch (result) {
+ case build_dont_know:
+ /*
+ * If we still can't build the source,
+ * this rule is not a match,
+ * try the next one.
+ */
+ if (source->stat.time == file_doesnt_exist) {
+ if(!name_found) {
+ free_name(source);
+ }
+ continue;
+ }
+ case build_running:
+ if(!name_found) {
+ store_name(source);
+ }
+ true_target->suffix_scan_done = false;
+ line = maybe_append_prop(target, line_prop);
+ enter_dependency(line, source, false);
+ line->body.line.target = true_target;
+ return build_running;
+ case build_ok:
+ if(!name_found) {
+ store_name(source);
+ }
+ break;
+ case build_failed:
+ if(!name_found) {
+ store_name(source);
+ }
+ if (sourcename != static_string_buf_3M) {
+ retmem(sourcename);
+ }
+ return build_failed;
+ }
+
+ if (debug_level > 1) {
+ WCSTOMBS(mbs_buffer, sourcename);
+ (void) printf(catgets(catd, 1, 219, "%*sFound %s\n"),
+ recursion_level,
+ "",
+ mbs_buffer);
+ }
+
+ if (source->depends_on_conditional) {
+ target->depends_on_conditional = true;
+ }
+/*
+ * Since it is possible that the same target is built several times during
+ * the make run, we have to patch the target with all information we found
+ * here. Thus, the target will have an explicit rule the next time around.
+ */
+ line = maybe_append_prop(target, line_prop);
+ if (*command == NULL) {
+ *command = line;
+ }
+ if ((source->stat.time > (*command)->body.line.dependency_time) &&
+ (debug_level > 1)) {
+ (void) printf(catgets(catd, 1, 220, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
+ recursion_level,
+ "",
+ source->string_mb,
+ time_to_string(source->
+ stat.time),
+ true_target->string_mb,
+ time_to_string((*command)->
+ body.line.
+ dependency_time));
+ }
+ /*
+ * Determine if this new dependency made the
+ * target out of date.
+ */
+ (*command)->body.line.dependency_time =
+ MAX((*command)->body.line.dependency_time,
+ source->stat.time);
+ Boolean out_of_date;
+ if (target->is_member) {
+ out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
+ (*command)->body.line.dependency_time);
+ } else {
+ out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
+ (*command)->body.line.dependency_time);
+ }
+ if (build_unconditional || out_of_date) {
+ if(!rechecking) {
+ line->body.line.is_out_of_date = true;
+ }
+ if (debug_level > 0) {
+ (void) printf(catgets(catd, 1, 221, "%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
+ recursion_level,
+ "",
+ true_target->string_mb,
+ source_suffix->body.suffix.suffix->string_mb,
+ target_suffix->string_mb,
+ source->string_mb);
+ }
+ }
+ /*
+ * Add the implicit rule as the target's explicit
+ * rule if none actually given, and register
+ * dependency.
+ * The time checking above really should be
+ * conditional on actual use of implicit rule
+ * as well.
+ */
+ line->body.line.sccs_command = false;
+ if (line->body.line.command_template == NULL) {
+ line->body.line.command_template =
+ source_suffix->body.suffix.command_template;
+ }
+ enter_dependency(line, source, false);
+ line->body.line.target = true_target;
+ /*
+ * Also make sure the rule is built with
+ * $* and $< bound properly.
+ */
+ line->body.line.star = target_body;
+ if(svr4|posix) {
+ char * p;
+ char tstr[256];
+ extern Boolean dollarless_flag;
+ extern Name dollarless_value;
+
+ if(tilde_rule) {
+ MBSTOWCS(wcs_buffer, NOCATGETS(source->string_mb));
+ dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
+ }
+ else {
+ dollarless_flag = false;
+ }
+ }
+ line->body.line.less = source;
+ line->body.line.percent = NULL;
+ add_target_to_chain(source, &(line->body.line.query));
+ if (sourcename != static_string_buf_3M) {
+ retmem(sourcename);
+ }
+ return build_ok;
+ }
+ if(posix && posix_tilde_attempt) {
+ posix_tilde_attempt = false;
+ goto posix_attempts;
+ }
+ if ((command != NULL) &&
+ ((*command) != NULL) &&
+ ((*command)->body.line.star == NULL)) {
+ (*command)->body.line.star = target_body;
+ }
+ }
+ if (sourcename != static_string_buf_3M) {
+ retmem(sourcename);
+ }
+ /* Return here in case no rule matched the target */
+ return build_dont_know;
+}
+
+/*
+ * find_ar_suffix_rule(target, true_target, command, rechecking)
+ *
+ * Scans the .SUFFIXES list and tries
+ * to find a suffix on it that matches the tail of the target member name.
+ * If it finds a matching suffix it calls find_suffix_rule() to find
+ * a rule for the target using the suffix ".a".
+ *
+ * Return value:
+ * Indicates if search failed or not
+ *
+ * Parameters:
+ * target The target we need a rule for
+ * true_target The proper name
+ * command Pointer to slot where we stuff cmd, if found
+ * rechecking true if we are rechecking target which depends
+ * on conditional macro and keep_state is set
+ *
+ * Global variables used:
+ * debug_level Indicates how much tracing to do
+ * dot_a The Name ".a", compared against
+ * recursion_level Used for tracing
+ * suffixes List of suffixes used for scan (from .SUFFIXES)
+ */
+Doname
+find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
+{
+ wchar_t *target_end;
+ register Dependency suffix;
+ register int suffix_length;
+ Property line;
+ Name body;
+ static Name dot_a;
+
+ Wstring targ_string(true_target);
+ Wstring suf_string;
+
+ if (dot_a == NULL) {
+ MBSTOWCS(wcs_buffer, NOCATGETS(".a"));
+ dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
+ }
+ target_end = targ_string.get_string() + true_target->hash.length;
+
+ /*
+ * We compare the tail of the target name with the suffixes
+ * from .SUFFIXES.
+ */
+ if (debug_level > 1) {
+ (void) printf(NOCATGETS("%*sfind_ar_suffix_rule(%s)\n"),
+ recursion_level,
+ "",
+ true_target->string_mb);
+ }
+ /*
+ * Scan the .SUFFIXES list to see if the target matches any of
+ * those suffixes.
+ */
+ for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
+ /* Compare one suffix. */
+ suffix_length = suffix->name->hash.length;
+ suf_string.init(suffix->name);
+ if (!IS_WEQUALN(suf_string.get_string(),
+ target_end - suffix_length,
+ suffix_length)) {
+ goto not_this_one;
+ }
+ /*
+ * The target tail matched a suffix from the .SUFFIXES list.
+ * Now check for a rule to match.
+ */
+ target->suffix_scan_done = false;
+ body = GETNAME(targ_string.get_string(),
+ (int)(true_target->hash.length -
+ suffix_length));
+ we_are_in_tilde = false;
+ switch (find_suffix_rule(target,
+ body,
+ dot_a,
+ command,
+ rechecking)) {
+ case build_ok:
+ line = get_prop(target->prop, line_prop);
+ line->body.line.star = body;
+ return build_ok;
+ case build_running:
+ return build_running;
+ }
+ /*
+ * If no rule was found, we try the next suffix to see
+ * if it matches the target tail, and so on.
+ * Go here if the suffix did not match the target tail.
+ */
+ not_this_one:;
+ }
+ return build_dont_know;
+}
+
+/*
+ * find_double_suffix_rule(target, command, rechecking)
+ *
+ * Scans the .SUFFIXES list and tries
+ * to find a suffix on it that matches the tail of the target name.
+ * If it finds a matching suffix it calls find_suffix_rule() to find
+ * a rule for the target.
+ *
+ * Return value:
+ * Indicates if scan failed or not
+ *
+ * Parameters:
+ * target Target we need a rule for
+ * command Pointer to slot where we stuff cmd, if found
+ * rechecking true if we are rechecking target which depends
+ * on conditional macro and keep_state is set
+ *
+ * Global variables used:
+ * debug_level Indicates how much tracing to do
+ * recursion_level Used for tracing
+ * suffixes List of suffixes used for scan (from .SUFFIXES)
+ */
+Doname
+find_double_suffix_rule(register Name target, Property *command, Boolean rechecking)
+{
+ Name true_target = target;
+ Name target_body;
+ register wchar_t *target_end;
+ register Dependency suffix;
+ register int suffix_length;
+ Boolean scanned_once = false;
+ Boolean name_found = true;
+
+ Wstring targ_string;
+ Wstring suf_string;
+
+ /*
+ * If the target is a constructed one for a "::" target,
+ * we need to consider that.
+ */
+ if (target->has_target_prop) {
+ true_target = get_prop(target->prop,
+ target_prop)->body.target.target;
+ }
+ targ_string.init(true_target);
+
+ /*
+ * We compare the tail of the target name with the
+ * suffixes from .SUFFIXES.
+ */
+ target_end = targ_string.get_string() + true_target->hash.length;
+ if (debug_level > 1) {
+ (void) printf(NOCATGETS("%*sfind_double_suffix_rule(%s)\n"),
+ recursion_level,
+ "",
+ true_target->string_mb);
+ }
+ /*
+ * Scan the .SUFFIXES list to see if the target matches
+ * any of those suffixes.
+ */
+ for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
+ target->suffix_scan_done = false;
+ true_target->suffix_scan_done = false;
+ /* Compare one suffix. */
+ suffix_length = suffix->name->hash.length;
+ suf_string.init(suffix->name);
+ /* Check the lengths, or else RTC will report rua. */
+ if (true_target->hash.length < suffix_length) {
+ goto not_this_one;
+ } else if (!IS_WEQUALN(suf_string.get_string(),
+ (target_end - suffix_length),
+ suffix_length)) {
+ goto not_this_one;
+ }
+ /*
+ * The target tail matched a suffix from the .SUFFIXES list.
+ * Now check for a rule to match.
+ */
+ we_are_in_tilde = false;
+ target_body = GETNAME(
+ targ_string.get_string(),
+ (int)(true_target->hash.length - suffix_length)
+ );
+ switch (find_suffix_rule(target,
+ target_body,
+ suffix->name,
+ command,
+ rechecking)) {
+ case build_ok:
+ return build_ok;
+ case build_running:
+ return build_running;
+ }
+ if (true_target->suffix_scan_done == true) {
+ scanned_once = true;
+ }
+ /*
+ * If no rule was found, we try the next suffix to see
+ * if it matches the target tail. And so on.
+ * Go here if the suffix did not match the target tail.
+ */
+ not_this_one:;
+ }
+ if (scanned_once)
+ true_target->suffix_scan_done = true;
+ return build_dont_know;
+}
+
+/*
+ * build_suffix_list(target_suffix)
+ *
+ * Scans the .SUFFIXES list and figures out
+ * which suffixes this target can be derived from.
+ * The target itself is not know here, we just know the suffix of the
+ * target. For each suffix on the list the target can be derived iff
+ * a rule exists for the name "<suffix-on-list><target-suffix>".
+ * A list of all possible building suffixes is built, with the rule for
+ * each, and tacked to the target suffix nameblock.
+ *
+ * Parameters:
+ * target_suffix The suffix we build a match list for
+ *
+ * Global variables used:
+ * debug_level Indicates how much tracing to do
+ * recursion_level Used for tracing
+ * suffixes List of suffixes used for scan (from .SUFFIXES)
+ * working_on_targets Indicates that this is a real target
+ */
+void
+build_suffix_list(register Name target_suffix)
+{
+ register Dependency source_suffix;
+ wchar_t rule_name[MAXPATHLEN];
+ register Property line;
+ register Property suffix;
+ Name rule;
+
+ /* If this is before default.mk has been read we just return to try */
+ /* again later */
+ if ((suffixes == NULL) || !working_on_targets) {
+ return;
+ }
+ if (debug_level > 1) {
+ (void) printf(NOCATGETS("%*sbuild_suffix_list(%s) "),
+ recursion_level,
+ "",
+ target_suffix->string_mb);
+ }
+ /* Mark the target suffix saying we cashed its list */
+ target_suffix->has_read_suffixes = true;
+ /* Scan the .SUFFIXES list */
+ for (source_suffix = suffixes;
+ source_suffix != NULL;
+ source_suffix = source_suffix->next) {
+ /*
+ * Build the name "<suffix-on-list><target-suffix>".
+ * (a popular one would be ".c.o").
+ */
+ (void) mbstowcs(rule_name,
+ source_suffix->name->string_mb,
+ (int) source_suffix->name->hash.length);
+ (void) mbstowcs(rule_name + source_suffix->name->hash.length,
+ target_suffix->string_mb,
+ (int) target_suffix->hash.length);
+ /*
+ * Check if that name has a rule. If not, it cannot match
+ * any implicit rule scan and is ignored.
+ * The GETNAME() call only checks for presence, it will not
+ * enter the name if it is not defined.
+ */
+ if (((rule = getname_fn(rule_name,
+ (int) (source_suffix->name->
+ hash.length +
+ target_suffix->hash.length),
+ true)) != NULL) &&
+ ((line = get_prop(rule->prop, line_prop)) != NULL)) {
+ if (debug_level > 1) {
+ (void) printf("%s ", rule->string_mb);
+ }
+ /*
+ * This makes it possible to quickly determine if
+ * it will pay to look for a suffix property.
+ */
+ target_suffix->has_suffixes = true;
+ /*
+ * Add the suffix property to the target suffix
+ * and save the rule with it.
+ * All information the implicit rule scanner need
+ * is saved in the suffix property.
+ */
+ suffix = append_prop(target_suffix, suffix_prop);
+ suffix->body.suffix.suffix = source_suffix->name;
+ suffix->body.suffix.command_template =
+ line->body.line.command_template;
+ }
+ }
+ if (debug_level > 1) {
+ (void) printf("\n");
+ }
+}
+
+/*
+ * find_percent_rule(target, command, rechecking)
+ *
+ * Tries to find a rule from the list of wildcard matched rules.
+ * It scans the list attempting to match the target.
+ * For each target match it checks if the corresponding source exists.
+ * If it does the match is returned.
+ * The percent_list is built at makefile read time.
+ * Each percent rule get one entry on the list.
+ *
+ * Return value:
+ * Indicates if the scan failed or not
+ *
+ * Parameters:
+ * target The target we need a rule for
+ * command Pointer to slot where we stuff cmd, if found
+ * rechecking true if we are rechecking target which depends
+ * on conditional macro and keep_state is set
+ *
+ * Global variables used:
+ * debug_level Indicates how much tracing to do
+ * percent_list List of all percent rules
+ * recursion_level Used for tracing
+ * empty_name
+ */
+Doname
+find_percent_rule(register Name target, Property *command, Boolean rechecking)
+{
+ register Percent pat_rule, pat_depe;
+ register Name depe_to_check;
+ register Dependency depe;
+ register Property line;
+ String_rec string;
+ wchar_t string_buf[STRING_BUFFER_LENGTH];
+ String_rec percent;
+ wchar_t percent_buf[STRING_BUFFER_LENGTH];
+ Name true_target = target;
+ Name less;
+ Boolean nonpattern_less;
+ Boolean dep_name_found = false;
+ Doname result = build_dont_know;
+ Percent rule_candidate = NULL;
+ Boolean rule_maybe_ok;
+ Boolean is_pattern;
+
+ /* If the target is constructed for a "::" target we consider that */
+ if (target->has_target_prop) {
+ true_target = get_prop(target->prop,
+ target_prop)->body.target.target;
+ }
+ if (target->has_long_member_name) {
+ true_target = get_prop(target->prop,
+ long_member_name_prop)->body.long_member_name.member_name;
+ }
+ if (debug_level > 1) {
+ (void) printf(catgets(catd, 1, 222, "%*sLooking for %% rule for %s\n"),
+ recursion_level,
+ "",
+ true_target->string_mb);
+ }
+ for (pat_rule = percent_list;
+ pat_rule != NULL;
+ pat_rule = pat_rule->next) {
+ /* Avoid infinite recursion when expanding patterns */
+ if (pat_rule->being_expanded == true) {
+ continue;
+ }
+
+ /* Mark this pat_rule as "maybe ok". If no % rule is found
+ make will use this rule. The following algorithm is used:
+ 1) make scans all pattern rules in order to find the rule
+ where ALL dependencies, including nonpattern ones, exist or
+ can be built (GNU behaviour). If such rule is found make
+ will apply it.
+ 2) During this check make also remembers the first pattern rule
+ where all PATTERN dependencies can be build (no matter what
+ happens with nonpattern dependencies).
+ 3) If no rule satisfying 1) is found, make will apply the rule
+ remembered in 2) if there is one.
+ */
+ rule_maybe_ok = true;
+
+ /* used to track first percent dependency */
+ less = NULL;
+ nonpattern_less = true;
+
+ /* check whether pattern matches.
+ if it matches, percent string will contain matched percent part of pattern */
+ if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) {
+ continue;
+ }
+ if (pat_rule->dependencies != NULL) {
+ for (pat_depe = pat_rule->dependencies;
+ pat_depe != NULL;
+ pat_depe = pat_depe->next) {
+ /* checking result for dependency */
+ result = build_dont_know;
+
+ dep_name_found = true;
+ if (pat_depe->name->percent) {
+ is_pattern = true;
+ /* build dependency name */
+ INIT_STRING_FROM_STACK(string, string_buf);
+ construct_string_from_pattern(pat_depe, &percent, &string);
+ depe_to_check = getname_fn(string.buffer.start,
+ FIND_LENGTH,
+ false,
+ &dep_name_found
+ );
+
+ if ((less == NULL) || nonpattern_less) {
+ less = depe_to_check;
+ nonpattern_less = false;
+ }
+ } else {
+ /* nonpattern dependency */
+ is_pattern = false;
+ depe_to_check = pat_depe->name;
+ if(depe_to_check->dollar) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ expand_value(depe_to_check, &string, false);
+ depe_to_check = getname_fn(string.buffer.start,
+ FIND_LENGTH,
+ false,
+ &dep_name_found
+ );
+ }
+ if (less == NULL) {
+ less = depe_to_check;
+ }
+ }
+
+ if (depe_to_check == empty_name) {
+ result = build_ok;
+ } else {
+ if (debug_level > 1) {
+ (void) printf(catgets(catd, 1, 223, "%*sTrying %s\n"),
+ recursion_level,
+ "",
+ depe_to_check->string_mb);
+ }
+
+ pat_rule->being_expanded = true;
+
+ /* suppress message output */
+ int save_debug_level = debug_level;
+ debug_level = 0;
+
+ /* check whether dependency can be built */
+ if (dependency_exists(depe_to_check,
+ get_prop(target->prop,
+ line_prop)))
+ {
+ result = (Doname) depe_to_check->state;
+ } else {
+ if(actual_doname) {
+ result = doname(depe_to_check, true, true);
+ } else {
+ result = target_can_be_built(depe_to_check);
+ }
+ if(!dep_name_found) {
+ if(result != build_ok && result != build_running) {
+ free_name(depe_to_check);
+ } else {
+ store_name(depe_to_check);
+ }
+ }
+ }
+ if(result != build_ok && is_pattern) {
+ rule_maybe_ok = false;
+ }
+
+ /* restore debug_level */
+ debug_level = save_debug_level;
+ }
+
+ if (pat_depe->name->percent) {
+ if (string.free_after_use) {
+ retmem(string.buffer.start);
+ }
+ }
+ /* make can't figure out how to make this dependency */
+ if (result != build_ok && result != build_running) {
+ pat_rule->being_expanded = false;
+ break;
+ }
+ }
+ } else {
+ result = build_ok;
+ }
+
+ /* this pattern rule is the needed one since all dependencies could be built */
+ if (result == build_ok || result == build_running) {
+ break;
+ }
+
+ /* Make does not know how to build some of dependencies from this rule.
+ But if all "pattern" dependencies can be built, we remember this rule
+ as a candidate for the case if no other pattern rule found.
+ */
+ if(rule_maybe_ok && rule_candidate == NULL) {
+ rule_candidate = pat_rule;
+ }
+ }
+
+ /* if no pattern matching rule was found, use the remembered candidate
+ or return build_dont_know if there is no candidate.
+ */
+ if (result != build_ok && result != build_running) {
+ if(rule_candidate) {
+ pat_rule = rule_candidate;
+ } else {
+ return build_dont_know;
+ }
+ }
+
+ /* if we are performing only check whether dependency could be built with existing rules,
+ return success */
+ if (command == NULL) {
+ if(pat_rule != NULL) {
+ pat_rule->being_expanded = false;
+ }
+ return result;
+ }
+
+ if (debug_level > 1) {
+ (void) printf(catgets(catd, 1, 224, "%*sMatched %s:"),
+ recursion_level,
+ "",
+ target->string_mb);
+
+ for (pat_depe = pat_rule->dependencies;
+ pat_depe != NULL;
+ pat_depe = pat_depe->next) {
+ if (pat_depe->name->percent) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ construct_string_from_pattern(pat_depe, &percent, &string);
+ depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
+ } else {
+ depe_to_check = pat_depe->name;
+ if(depe_to_check->dollar) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ expand_value(depe_to_check, &string, false);
+ depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
+ }
+ }
+
+ if (depe_to_check != empty_name) {
+ (void) printf(" %s", depe_to_check->string_mb);
+ }
+ }
+
+ (void) printf(catgets(catd, 1, 225, " from: %s:"),
+ pat_rule->name->string_mb);
+
+ for (pat_depe = pat_rule->dependencies;
+ pat_depe != NULL;
+ pat_depe = pat_depe->next) {
+ (void) printf(" %s", pat_depe->name->string_mb);
+ }
+
+ (void) printf("\n");
+ }
+
+ if (true_target->colons == no_colon) {
+ true_target->colons = one_colon;
+ }
+
+ /* create deppendency list and target group from matched pattern rule */
+ create_target_group_and_dependencies_list(target, pat_rule, &percent);
+
+ /* save command */
+ line = get_prop(target->prop, line_prop);
+ *command = line;
+
+ /* free query chain if one exist */
+ while(line->body.line.query != NULL) {
+ Chain to_free = line->body.line.query;
+ line->body.line.query = line->body.line.query->next;
+ retmem_mb((char *) to_free);
+ }
+
+ if (line->body.line.dependencies != NULL) {
+ /* build all collected dependencies */
+ for (depe = line->body.line.dependencies;
+ depe != NULL;
+ depe = depe->next) {
+ actual_doname = true;
+ result = doname_check(depe->name, true, true, depe->automatic);
+
+ actual_doname = false;
+ if (result == build_failed) {
+ pat_rule->being_expanded = false;
+ return build_failed;
+ }
+ if (result == build_running) {
+ pat_rule->being_expanded = false;
+ return build_running;
+ }
+
+ if ((depe->name->stat.time > line->body.line.dependency_time) &&
+ (debug_level > 1)) {
+ (void) printf(catgets(catd, 1, 226, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
+ recursion_level,
+ "",
+ depe->name->string_mb,
+ time_to_string(depe->name->stat.time),
+ true_target->string_mb,
+ time_to_string(line->body.line.dependency_time));
+ }
+
+ line->body.line.dependency_time =
+ MAX(line->body.line.dependency_time, depe->name->stat.time);
+
+ /* determine whether this dependency made target out of date */
+ Boolean out_of_date;
+ if (target->is_member || depe->name->is_member) {
+ out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
+ } else {
+ out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
+ }
+ if (build_unconditional || out_of_date) {
+ if(!rechecking) {
+ line->body.line.is_out_of_date = true;
+ }
+ add_target_to_chain(depe->name, &(line->body.line.query));
+
+ if (debug_level > 0) {
+ (void) printf(catgets(catd, 1, 227, "%*sBuilding %s using pattern rule %s:"),
+ recursion_level,
+ "",
+ true_target->string_mb,
+ pat_rule->name->string_mb);
+
+ for (pat_depe = pat_rule->dependencies;
+ pat_depe != NULL;
+ pat_depe = pat_depe->next) {
+ (void) printf(" %s", pat_depe->name->string_mb);
+ }
+
+ (void) printf(catgets(catd, 1, 228, " because it is out of date relative to %s\n"),
+ depe->name->string_mb);
+ }
+ }
+ }
+ } else {
+ if ((true_target->stat.time <= file_doesnt_exist) ||
+ (true_target->stat.time < line->body.line.dependency_time)) {
+ if(!rechecking) {
+ line->body.line.is_out_of_date = true;
+ }
+ if (debug_level > 0) {
+ (void) printf(catgets(catd, 1, 229, "%*sBuilding %s using pattern rule %s: "),
+ recursion_level,
+ "",
+ true_target->string_mb,
+ pat_rule->name->string_mb,
+ (target->stat.time > file_doesnt_exist) ?
+ catgets(catd, 1, 230, "because it is out of date") :
+ catgets(catd, 1, 236, "because it does not exist"));
+ }
+ }
+ }
+
+ /* enter explicit rule from percent rule */
+ Name lmn_target = true_target;
+ if (true_target->has_long_member_name) {
+ lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
+ }
+ line->body.line.sccs_command = false;
+ line->body.line.target = true_target;
+ line->body.line.command_template = pat_rule->command_template;
+ line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
+ line->body.line.less = less;
+
+ if (lmn_target->parenleft) {
+ Wstring lmn_string(lmn_target);
+
+ wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char);
+ wchar_t *right = (wchar_t *) wschr(lmn_string.get_string(), (int) parenright_char);
+
+ if ((left == NULL) || (right == NULL)) {
+ line->body.line.percent = NULL;
+ } else {
+ line->body.line.percent = GETNAME(left + 1, right - left - 1);
+ }
+ } else {
+ line->body.line.percent = NULL;
+ }
+ pat_rule->being_expanded = false;
+
+#ifdef TEAMWARE_MAKE_CMN
+ /*
+ * This #ifdef fixes a dmake bug, but introduces bugid 1136156.
+ */
+ return result;
+#else
+ return build_ok;
+#endif
+}
+
+/*
+ * match_found_with_pattern
+ * ( target, pat_rule, percent, percent_buf)
+ *
+ * matches "target->string" with a % pattern.
+ * If pattern contains a MACRO definition, it's expanded first.
+ *
+ * Return value:
+ * true if a match was found
+ *
+ * Parameters:
+ * target The target we're trying to match
+ * pattern
+ * percent record that contains "percent_buf" below
+ * percent_buf This is where the patched % part of pattern is stored
+ *
+ */
+
+static Boolean
+match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) {
+ String_rec string;
+ wchar_t string_buf[STRING_BUFFER_LENGTH];
+
+ /* construct prefix string and check whether prefix matches */
+ Name prefix = pat_rule->patterns[0];
+ int prefix_length;
+
+ Wstring targ_string(target);
+ Wstring pref_string(prefix);
+ Wstring suf_string;
+
+ if (prefix->dollar) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ expand_value(prefix, &string, false);
+ prefix_length = string.text.p - string.buffer.start;
+ if ((string.buffer.start[0] == (int) period_char) &&
+ (string.buffer.start[1] == (int) slash_char)) {
+ string.buffer.start += 2;
+ prefix_length -= 2;
+ }
+ if (!targ_string.equaln(string.buffer.start, prefix_length)) {
+ return false;
+ }
+ } else {
+ prefix_length = prefix->hash.length;
+ if (!targ_string.equaln(&pref_string, prefix_length)) {
+ return false;
+ }
+ }
+
+ /* do the same with pattern suffix */
+ Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1];
+ suf_string.init(suffix);
+
+ int suffix_length;
+ if (suffix->dollar) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ expand_value(suffix, &string, false);
+ suffix_length = string.text.p - string.buffer.start;
+ if(suffix_length > target->hash.length) {
+ return false;
+ }
+ if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) {
+ return false;
+ }
+ } else {
+ suffix_length = (int) suffix->hash.length;
+ if(suffix_length > target->hash.length) {
+ return false;
+ }
+ if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) {
+ return false;
+ }
+ }
+
+ Boolean match_found = false;
+ int percent_length = target->hash.length - prefix_length - suffix_length;
+
+ while (!match_found && (percent_length >= 0)) {
+ /* init result string */
+ INIT_STRING_FROM_STACK(string, string_buf);
+
+ /* init percent string */
+ percent->buffer.start = percent_buf;
+ percent->text.p = percent_buf;
+ percent->text.end = NULL;
+ percent->free_after_use = false;
+ percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH;
+
+ /* construct percent and result strings */
+ targ_string.append_to_str(percent, prefix_length, percent_length);
+ construct_string_from_pattern(pat_rule, percent, &string);
+
+ /* check for match */
+ if (targ_string.equal(string.buffer.start, 0)) {
+ match_found = true;
+ } else {
+ percent_length--;
+ }
+ }
+
+ /* result */
+ return match_found;
+}
+
+
+/*
+ * create_target_group_and_dependencies_list
+ * (target, pat_rule, percent)
+ *
+ * constructs dependency list and a target group from pattern.
+ *
+ * If we have the lines
+ * %/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e
+ * commands
+ *
+ * and we have matched the pattern xx/xx.a with %/%.a, then we
+ * construct a target group that looks like this:
+ * xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies
+ *
+ * and construct dependency list that looks like this:
+ * yyy xx.d bbxx/BBxx.e + already existed dependencies
+ *
+ * Return value:
+ * none
+ *
+ * Parameters:
+ * target The target we are building, in the previous
+ * example, this is xx/xx.a
+ * pat_rule the % pattern that matched "target", here %/%.a
+ * percent string containing matched % part. In the example=xx.
+ *
+ * Global variables used:
+ * empty_name
+ */
+
+static void
+create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) {
+ String_rec string;
+ wchar_t string_buf[STRING_BUFFER_LENGTH];
+ Percent pat_depe;
+ Name depe;
+ Property line = maybe_append_prop(target, line_prop);
+ Chain new_target_group = NULL;
+ Chain *new_target_group_tail = &new_target_group;
+ Chain group_member;
+
+ /* create and append dependencies from rule */
+ for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) {
+ if (pat_depe->name->percent) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ construct_string_from_pattern(pat_depe, percent, &string);
+ depe = GETNAME(string.buffer.start, FIND_LENGTH);
+ if (depe != empty_name) {
+ enter_dependency(line, depe, false);
+ }
+ } else {
+ depe = pat_depe->name;
+ if(depe->dollar) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ expand_value(depe, &string, false);
+ depe = GETNAME(string.buffer.start, FIND_LENGTH);
+ }
+ enter_dependency(line, depe, false);
+ }
+ }
+
+ /* if matched pattern is a group member, create new target group */
+ for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) {
+ Name new_target = group_member->name;
+ if (group_member->name->percent) {
+ INIT_STRING_FROM_STACK(string, string_buf);
+ construct_string_from_pattern(group_member->percent_member, percent, &string);
+ new_target = GETNAME(string.buffer.start, FIND_LENGTH);
+ if (new_target == empty_name) {
+ continue;
+ }
+ }
+
+ /* check for duplicates */
+ Chain tgm;
+ for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) {
+ if (new_target == tgm->name) {
+ break;
+ }
+ }
+ if (tgm != NULL) {
+ continue;
+ }
+
+ /* insert it into the targets list */
+ (*new_target_group_tail) = ALLOC(Chain);
+ (*new_target_group_tail)->name = new_target;
+ (*new_target_group_tail)->next = NULL;
+ new_target_group_tail = &(*new_target_group_tail)->next;
+ }
+
+ /* now we gathered all dependencies and created target group */
+ line->body.line.target_group = new_target_group;
+
+ /* update properties for group members */
+ for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) {
+ if (group_member->name != target) {
+ group_member->name->prop = target->prop;
+ group_member->name->conditional_cnt = target->conditional_cnt;
+ }
+ }
+}
+
+/*
+ * construct_string_from_pattern
+ * (pat_rule, percent, result)
+ *
+ * after pattern matched a target this routine is called to construct targets and dependencies
+ * strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern.
+ *
+ * Return value:
+ * none
+ *
+ * Parameters:
+ * pat_rule matched pattern rule
+ * percent string containing matched % sign part.
+ * result holds the result of string construction.
+ *
+ */
+static void
+construct_string_from_pattern(Percent pat_rule, String percent, String result) {
+ for (int i = 0; i < pat_rule->patterns_total; i++) {
+ if (pat_rule->patterns[i]->dollar) {
+ expand_value(pat_rule->patterns[i],
+ result,
+ false);
+
+ } else {
+ append_string(pat_rule->patterns[i]->string_mb,
+ result,
+ pat_rule->patterns[i]->hash.length);
+ }
+
+ if (i < pat_rule->patterns_total - 1) {
+ append_string(percent->buffer.start,
+ result,
+ percent->text.p - percent->buffer.start);
+ }
+ }
+
+ if ((result->buffer.start[0] == (int) period_char) &&
+ (result->buffer.start[1] == (int) slash_char)) {
+ result->buffer.start += 2;
+ }
+}
+
+/*
+ * dependency_exists(target, line)
+ *
+ * Returns true if the target exists in the
+ * dependency list of the line.
+ *
+ * Return value:
+ * True if target is on dependency list
+ *
+ * Parameters:
+ * target Target we scan for
+ * line We get the dependency list from here
+ *
+ * Global variables used:
+ */
+static Boolean
+dependency_exists(Name target, Property line)
+{
+ Dependency dp;
+
+ if (line == NULL) {
+ return false;
+ }
+ for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
+ if (dp->name == target) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+add_target_to_chain(Name target, Chain * query)
+{
+ if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) {
+ target = get_prop(target->prop, member_prop)->body.member.member;
+ }
+ Chain *query_tail;
+ for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) {
+ if ((*query_tail)->name == target) {
+ return;
+ }
+ }
+ *query_tail = ALLOC(Chain);
+ (*query_tail)->name = target;
+ (*query_tail)->next = NULL;
+}
+