summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/bin/make/common/read2.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/read2.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/read2.cc')
-rw-r--r--usr/src/make_src/Make/bin/make/common/read2.cc1938
1 files changed, 1938 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/read2.cc b/usr/src/make_src/Make/bin/make/common/read2.cc
new file mode 100644
index 0000000..e1a9e1f
--- /dev/null
+++ b/usr/src/make_src/Make/bin/make/common/read2.cc
@@ -0,0 +1,1938 @@
+/*
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)read2.cc 1.53 06/12/12
+ */
+
+#pragma ident "@(#)read2.cc 1.53 06/12/12"
+
+/*
+ * read.c
+ *
+ * This file contains the makefile reader.
+ */
+
+/*
+ * Included files
+ */
+#include <mk/defs.h>
+#include <mksh/dosys.h> /* sh_command2string() */
+#include <mksh/macro.h> /* expand_value() */
+#include <mksh/misc.h> /* retmem() */
+#include <stdarg.h> /* va_list, va_start(), va_end() */
+
+/*
+ * Defined macros
+ */
+
+/*
+ * typedefs & structs
+ */
+
+/*
+ * Static variables
+ */
+static Boolean built_last_make_run_seen;
+
+/*
+ * File table of contents
+ */
+static Name_vector enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names);
+extern Name normalize_name(register wchar_t *name_string, register int length);
+static void read_suffixes_list(register Name_vector depes);
+static void make_relative(wchar_t *to, wchar_t *result);
+static void print_rule(register Cmd_line command);
+static void sh_transform(Name *name, Name *value);
+
+
+/*
+ * enter_name(string, tail_present, string_start, string_end,
+ * current_names, extra_names, target_group_seen)
+ *
+ * Take one string and enter it as a name. The string is passed in
+ * two parts. A make string and possibly a C string to append to it.
+ * The result is stuffed in the vector current_names.
+ * extra_names points to a vector that is used if current_names overflows.
+ * This is allocad in the calling routine.
+ * Here we handle the "lib.a[members]" notation.
+ *
+ * Return value:
+ * The name vector that was used
+ *
+ * Parameters:
+ * tail_present Indicates if both C and make string was passed
+ * string_start C string
+ * string_end Pointer to char after last in C string
+ * string make style string with head of name
+ * current_names Vector to deposit the name in
+ * extra_names Where to get next name vector if we run out
+ * target_group_seen Pointer to boolean that is set if "+" is seen
+ *
+ * Global variables used:
+ * makefile_type When we read a report file we normalize paths
+ * plus Points to the Name "+"
+ */
+
+Name_vector
+enter_name(String string, Boolean tail_present, register wchar_t *string_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names, Boolean *target_group_seen)
+{
+ Name name;
+ register wchar_t *cp;
+ wchar_t ch;
+
+ /* If we were passed a separate tail of the name we append it to the */
+ /* make string with the rest of it */
+ if (tail_present) {
+ append_string(string_start, string, string_end - string_start);
+ string_start = string->buffer.start;
+ string_end = string->text.p;
+ }
+ ch = *string_end;
+ *string_end = (int) nul_char;
+ /*
+ * Check if there are any ( or [ that are not prefixed with $.
+ * If there are, we have to deal with the lib.a(members) format.
+ */
+ for (cp = (wchar_t *) wschr(string_start, (int) parenleft_char);
+ cp != NULL;
+ cp = (wchar_t *) wschr(cp + 1, (int) parenleft_char)) {
+ if (*(cp - 1) != (int) dollar_char) {
+ *string_end = ch;
+ return enter_member_name(string_start,
+ cp,
+ string_end,
+ current_names,
+ extra_names);
+ }
+ }
+ *string_end = ch;
+
+ if (makefile_type == reading_cpp_file) {
+ /* Remove extra ../ constructs if we are reading from a report file */
+ name = normalize_name(string_start, string_end - string_start);
+ } else {
+ /*
+ * /tolik, fix bug 1197477/
+ * Normalize every target name before entering.
+ * ..//obj/a.o and ../obj//a.o are not two different targets.
+ * There is only one target ../obj/a.o
+ */
+ /*name = GETNAME(string_start, string_end - string_start);*/
+ name = normalize_name(string_start, string_end - string_start);
+ }
+
+ /* Internalize the name. Detect the name "+" (target group here) */
+if(current_names->used != 0 && current_names->names[current_names->used-1] == plus) {
+ if(name == plus) {
+ return current_names;
+ }
+}
+ /* If the current_names vector is full we patch in the one from */
+ /* extra_names */
+ if (current_names->used == VSIZEOF(current_names->names)) {
+ if (current_names->next != NULL) {
+ current_names = current_names->next;
+ } else {
+ current_names->next = *extra_names;
+ *extra_names = NULL;
+ current_names = current_names->next;
+ current_names->used = 0;
+ current_names->next = NULL;
+ }
+ }
+ current_names->target_group[current_names->used] = NULL;
+ current_names->names[current_names->used++] = name;
+ if (name == plus) {
+ *target_group_seen = true;
+ }
+ if (tail_present && string->free_after_use) {
+ retmem(string->buffer.start);
+ }
+ return current_names;
+}
+
+/*
+ * enter_member_name(lib_start, member_start, string_end,
+ * current_names, extra_names)
+ *
+ * A string has been found to contain member names.
+ * (The "lib.a[members]" and "lib.a(members)" notation)
+ * Handle it pretty much as enter_name() does for simple names.
+ *
+ * Return value:
+ * The name vector that was used
+ *
+ * Parameters:
+ * lib_start Points to the of start of "lib.a(member.o)"
+ * member_start Points to "member.o" from above string.
+ * string_end Points to char after last of above string.
+ * current_names Vector to deposit the name in
+ * extra_names Where to get next name vector if we run out
+ *
+ * Global variables used:
+ */
+static Name_vector
+enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names)
+{
+ register Boolean entry = false;
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ Name lib;
+ Name member;
+ Name name;
+ Property prop;
+ wchar_t *memberp;
+ wchar_t *q;
+ register int paren_count;
+ register Boolean has_dollar;
+ register wchar_t *cq;
+ Name long_member_name = NULL;
+
+ /* Internalize the name of the library */
+ lib = GETNAME(lib_start, member_start - lib_start);
+ lib->is_member = true;
+ member_start++;
+ if (*member_start == (int) parenleft_char) {
+ /* This is really the "lib.a((entries))" format */
+ entry = true;
+ member_start++;
+ }
+ /* Move the library name to the buffer where we intend to build the */
+ /* "lib.a(member)" for each member */
+ (void) wsncpy(buffer, lib_start, member_start - lib_start);
+ memberp = buffer + (member_start-lib_start);
+ while (1) {
+ long_member_name = NULL;
+ /* Skip leading spaces */
+ for (;
+ (member_start < string_end) && iswspace(*member_start);
+ member_start++);
+ /* Find the end of the member name. Allow nested (). Detect $*/
+ for (cq = memberp, has_dollar = false, paren_count = 0;
+ (member_start < string_end) &&
+ ((*member_start != (int) parenright_char) ||
+ (paren_count > 0)) &&
+ !iswspace(*member_start);
+ *cq++ = *member_start++) {
+ switch (*member_start) {
+ case parenleft_char:
+ paren_count++;
+ break;
+ case parenright_char:
+ paren_count--;
+ break;
+ case dollar_char:
+ has_dollar = true;
+ }
+ }
+ /* Internalize the member name */
+ member = GETNAME(memberp, cq - memberp);
+ *cq = 0;
+ if ((q = (wchar_t *) wsrchr(memberp, (int) slash_char)) == NULL) {
+ q = memberp;
+ }
+ if ((cq - q > (int) ar_member_name_len) &&
+ !has_dollar) {
+ *cq++ = (int) parenright_char;
+ if (entry) {
+ *cq++ = (int) parenright_char;
+ }
+ long_member_name = GETNAME(buffer, cq - buffer);
+ cq = q + (int) ar_member_name_len;
+ }
+ *cq++ = (int) parenright_char;
+ if (entry) {
+ *cq++ = (int) parenright_char;
+ }
+ /* Internalize the "lib.a(member)" notation for this member */
+ name = GETNAME(buffer, cq - buffer);
+ name->is_member = lib->is_member;
+ if (long_member_name != NULL) {
+ prop = append_prop(name, long_member_name_prop);
+ name->has_long_member_name = true;
+ prop->body.long_member_name.member_name =
+ long_member_name;
+ }
+ /* And add the member prop */
+ prop = append_prop(name, member_prop);
+ prop->body.member.library = lib;
+ if (entry) {
+ /* "lib.a((entry))" notation */
+ prop->body.member.entry = member;
+ prop->body.member.member = NULL;
+ } else {
+ /* "lib.a(member)" Notation */
+ prop->body.member.entry = NULL;
+ prop->body.member.member = member;
+ }
+ /* Handle overflow of current_names */
+ if (current_names->used == VSIZEOF(current_names->names)) {
+ if (current_names->next != NULL) {
+ current_names = current_names->next;
+ } else {
+ if (*extra_names == NULL) {
+ current_names =
+ current_names->next =
+ ALLOC(Name_vector);
+ } else {
+ current_names =
+ current_names->next =
+ *extra_names;
+ *extra_names = NULL;
+ }
+ current_names->used = 0;
+ current_names->next = NULL;
+ }
+ }
+ current_names->target_group[current_names->used] = NULL;
+ current_names->names[current_names->used++] = name;
+ while (iswspace(*member_start)) {
+ member_start++;
+ }
+ /* Check if there are more members */
+ if ((*member_start == (int) parenright_char) ||
+ (member_start >= string_end)) {
+ return current_names;
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * normalize_name(name_string, length)
+ *
+ * Take a namestring and remove redundant ../, // and ./ constructs
+ *
+ * Return value:
+ * The normalized name
+ *
+ * Parameters:
+ * name_string Path string to normalize
+ * length Length of that string
+ *
+ * Global variables used:
+ * dot The Name ".", compared against
+ * dotdot The Name "..", compared against
+ */
+Name
+normalize_name(register wchar_t *name_string, register int length)
+{
+ static Name dotdot;
+ register wchar_t *string = ALLOC_WC(length + 1);
+ register wchar_t *string2;
+ register wchar_t *cdp;
+ wchar_t *current_component;
+ Name name;
+ register int count;
+
+ if (dotdot == NULL) {
+ MBSTOWCS(wcs_buffer, "..");
+ dotdot = GETNAME(wcs_buffer, FIND_LENGTH);
+ }
+
+ /*
+ * Copy string removing ./ and //.
+ * First strip leading ./
+ */
+ while ((length > 1) &&
+ (name_string[0] == (int) period_char) &&
+ (name_string[1] == (int) slash_char)) {
+ name_string += 2;
+ length -= 2;
+ while ((length > 0) && (name_string[0] == (int) slash_char)) {
+ name_string++;
+ length--;
+ }
+ }
+ /* Then copy the rest of the string removing /./ & // */
+ cdp = string;
+ while (length > 0) {
+ if (((length > 2) &&
+ (name_string[0] == (int) slash_char) &&
+ (name_string[1] == (int) period_char) &&
+ (name_string[2] == (int) slash_char)) ||
+ ((length == 2) &&
+ (name_string[0] == (int) slash_char) &&
+ (name_string[1] == (int) period_char))) {
+ name_string += 2;
+ length -= 2;
+ continue;
+ }
+ if ((length > 1) &&
+ (name_string[0] == (int) slash_char) &&
+ (name_string[1] == (int) slash_char)) {
+ name_string++;
+ length--;
+ continue;
+ }
+ *cdp++ = *name_string++;
+ length--;
+ }
+ *cdp = (int) nul_char;
+ /*
+ * Now scan for <name>/../ and remove such combinations iff <name>
+ * is not another ..
+ * Each time something is removed, the whole process is restarted.
+ */
+removed_one:
+ name_string = string;
+ string2 = name_string; /*save for free*/
+ current_component =
+ cdp =
+ string =
+ ALLOC_WC((length = wslen(name_string)) + 1);
+ while (length > 0) {
+ if (((length > 3) &&
+ (name_string[0] == (int) slash_char) &&
+ (name_string[1] == (int) period_char) &&
+ (name_string[2] == (int) period_char) &&
+ (name_string[3] == (int) slash_char)) ||
+ ((length == 3) &&
+ (name_string[0] == (int) slash_char) &&
+ (name_string[1] == (int) period_char) &&
+ (name_string[2] == (int) period_char))) {
+ /* Positioned on the / that starts a /.. sequence */
+ if (((count = cdp - current_component) != 0) &&
+ (exists(name = GETNAME(string, cdp - string)) > file_doesnt_exist) &&
+ (!name->stat.is_sym_link)) {
+ name = GETNAME(current_component, count);
+ if(name != dotdot) {
+ cdp = current_component;
+ name_string += 3;
+ length -= 3;
+ if (length > 0) {
+ name_string++; /* skip slash */
+ length--;
+ while (length > 0) {
+ *cdp++ = *name_string++;
+ length--;
+ }
+ }
+ *cdp = (int) nul_char;
+ retmem(string2);
+ goto removed_one;
+ }
+ }
+ }
+ if ((*cdp++ = *name_string++) == (int) slash_char) {
+ current_component = cdp;
+ }
+ length--;
+ }
+ *cdp = (int) nul_char;
+ if (string[0] == (int) nul_char) {
+ name = dot;
+ } else {
+ name = GETNAME(string, FIND_LENGTH);
+ }
+ retmem(string);
+ retmem(string2);
+ return name;
+}
+
+/*
+ * find_target_groups(target_list)
+ *
+ * If a "+" was seen when the target list was scanned we need to extract
+ * the groups. Each target in the name vector that is a member of a
+ * group gets a pointer to a chain of all the members stuffed in its
+ * target_group vector slot
+ *
+ * Parameters:
+ * target_list The list of targets that contains "+"
+ *
+ * Global variables used:
+ * plus The Name "+", compared against
+ */
+Chain
+find_target_groups(register Name_vector target_list, register int i, Boolean reset)
+{
+ static Chain target_group = NULL;
+ static Chain tail_target_group = NULL;
+ static Name *next;
+ static Boolean clear_target_group = false;
+
+ if (reset) {
+ target_group = NULL;
+ tail_target_group = NULL;
+ clear_target_group = false;
+ }
+
+ /* Scan the list of targets */
+ /* If the previous target terminated a group */
+ /* we flush the pointer to that member chain */
+ if (clear_target_group) {
+ clear_target_group = false;
+ target_group = NULL;
+ }
+ /* Pick up a pointer to the cell with */
+ /* the next target */
+ if (i + 1 != target_list->used) {
+ next = &target_list->names[i + 1];
+ } else {
+ next = (target_list->next != NULL) ?
+ &target_list->next->names[0] : NULL;
+ }
+ /* We have four states here :
+ * 0: No target group started and next element is not "+"
+ * This is not interesting.
+ * 1: A target group is being built and the next element
+ * is not "+". This terminates the group.
+ * 2: No target group started and the next member is "+"
+ * This is the first target in a group.
+ * 3: A target group started and the next member is a "+"
+ * The group continues.
+ */
+ switch ((target_group ? 1 : 0) +
+ (next && (*next == plus) ?
+ 2 : 0)) {
+ case 0: /* Not target_group */
+ break;
+ case 1: /* Last group member */
+ /* We need to keep this pointer so */
+ /* we can stuff it for last member */
+ clear_target_group = true;
+ /* fall into */
+ case 3: /* Middle group member */
+ /* Add this target to the */
+ /* current chain */
+ tail_target_group->next = ALLOC(Chain);
+ tail_target_group = tail_target_group->next;
+ tail_target_group->next = NULL;
+ tail_target_group->name = target_list->names[i];
+ break;
+ case 2: /* First group member */
+ /* Start a new chain */
+ target_group = tail_target_group = ALLOC(Chain);
+ target_group->next = NULL;
+ target_group->name = target_list->names[i];
+ break;
+ }
+ /* Stuff the current chain, if any, in the */
+ /* targets group slot */
+ target_list->target_group[i] = target_group;
+ if ((next != NULL) &&
+ (*next == plus)) {
+ *next = NULL;
+ }
+ return (tail_target_group);
+}
+
+/*
+ * enter_dependencies(target, target_group, depes, command, separator)
+ *
+ * Take one target and a list of dependencies and process the whole thing.
+ * The target might be special in some sense in which case that is handled
+ *
+ * Parameters:
+ * target The target we want to enter
+ * target_group Non-NULL if target is part of a group this time
+ * depes A list of dependencies for the target
+ * command The command the target should be entered with
+ * separator Indicates if this is a ":" or a "::" rule
+ *
+ * Static variables used:
+ * built_last_make_run_seen If the previous target was
+ * .BUILT_LAST_MAKE_RUN we say to rewrite
+ * the state file later on
+ *
+ * Global variables used:
+ * command_changed Set to indicate if .make.state needs rewriting
+ * default_target_to_build Set to the target if reading makefile
+ * and this is the first regular target
+ * force The Name " FORCE", used with "::" targets
+ * makefile_type We do different things for makefile vs. report
+ * not_auto The Name ".NOT_AUTO", compared against
+ * recursive_name The Name ".RECURSIVE", compared against
+ * temp_file_number Used to figure out when to clear stale
+ * automatic dependencies
+ * trace_reader Indicates that we should echo stuff we read
+ */
+void
+enter_dependencies(register Name target, Chain target_group, register Name_vector depes, register Cmd_line command, register Separator separator)
+{
+ register int i;
+ register Property line;
+ Name name;
+ Name directory;
+ wchar_t *namep;
+ char *mb_namep;
+ Dependency dp;
+ Dependency *dpp;
+ Property line2;
+ wchar_t relative[MAXPATHLEN];
+ register int recursive_state;
+ Boolean register_as_auto;
+ Boolean not_auto_found;
+ char *slash;
+ Wstring depstr;
+
+ /* Check if this is a .RECURSIVE line */
+ if ((depes->used >= 3) &&
+ (depes->names[0] == recursive_name)) {
+#ifdef NSE
+ nse_did_recursion= true;
+#endif
+ target->has_recursive_dependency = true;
+ depes->names[0] = NULL;
+ recursive_state = 0;
+ dp = NULL;
+ dpp = &dp;
+ /* Read the dependencies. They are "<directory> <target-made>*/
+ /* <makefile>*" */
+ for (; depes != NULL; depes = depes->next) {
+ for (i = 0; i < depes->used; i++) {
+ if (depes->names[i] != NULL) {
+ switch (recursive_state++) {
+ case 0: /* Directory */
+ {
+ depstr.init(depes->names[i]);
+ make_relative(depstr.get_string(),
+ relative);
+ directory =
+ GETNAME(relative,
+ FIND_LENGTH);
+ }
+ break;
+ case 1: /* Target */
+ name = depes->names[i];
+ break;
+ default: /* Makefiles */
+ *dpp = ALLOC(Dependency);
+ (*dpp)->next = NULL;
+ (*dpp)->name = depes->names[i];
+ (*dpp)->automatic = false;
+ (*dpp)->stale = false;
+ (*dpp)->built = false;
+ dpp = &((*dpp)->next);
+ break;
+ }
+ }
+ }
+ }
+ /* Check if this recursion already has been reported else */
+ /* enter the recursive prop for the target */
+ /* The has_built flag is used to tell if this .RECURSIVE */
+ /* was discovered from this run (read from a tmp file) */
+ /* or was from discovered from the original .make.state */
+ /* file */
+ for (line = get_prop(target->prop, recursive_prop);
+ line != NULL;
+ line = get_prop(line->next, recursive_prop)) {
+ if ((line->body.recursive.directory == directory) &&
+ (line->body.recursive.target == name)) {
+ line->body.recursive.makefiles = dp;
+ line->body.recursive.has_built =
+ (Boolean)
+ (makefile_type == reading_cpp_file);
+ return;
+ }
+ }
+ line2 = append_prop(target, recursive_prop);
+ line2->body.recursive.directory = directory;
+ line2->body.recursive.target = name;
+ line2->body.recursive.makefiles = dp;
+ line2->body.recursive.has_built =
+ (Boolean) (makefile_type == reading_cpp_file);
+ line2->body.recursive.in_depinfo = false;
+ return;
+ }
+ /* If this is the first target that doesnt start with a "." in the */
+ /* makefile we remember that */
+ Wstring tstr(target);
+ wchar_t * wcb = tstr.get_string();
+ if ((makefile_type == reading_makefile) &&
+ (default_target_to_build == NULL) &&
+ ((wcb[0] != (int) period_char) ||
+ wschr(wcb, (int) slash_char))) {
+
+/* BID 1181577: $(EMPTY_MACRO) + $(EMPTY_MACRO):
+** The target with empty name cannot be default_target_to_build
+*/
+ if (target->hash.length != 0)
+ default_target_to_build = target;
+ }
+ /* Check if the line is ":" or "::" */
+ if (makefile_type == reading_makefile) {
+ if (target->colons == no_colon) {
+ target->colons = separator;
+ } else {
+ if (target->colons != separator) {
+ fatal_reader(catgets(catd, 1, 92, ":/:: conflict for target `%s'"),
+ target->string_mb);
+ }
+ }
+ if (target->colons == two_colon) {
+ if (depes->used == 0) {
+ /* If this is a "::" type line with no */
+ /* dependencies we add one "FRC" type */
+ /* dependency for free */
+ depes->used = 1; /* Force :: targets with no
+ * depes to always run */
+ depes->names[0] = force;
+ }
+ /* Do not delete "::" type targets when interrupted */
+ target->stat.is_precious = true;
+ /*
+ * Build a synthetic target "<number>%target"
+ * for "target".
+ */
+ mb_namep = getmem((int) (strlen(target->string_mb) + 10));
+ namep = ALLOC_WC((int) (target->hash.length + 10));
+ slash = strrchr(target->string_mb, (int) slash_char);
+ if (slash == NULL) {
+ (void) sprintf(mb_namep,
+ "%d@%s",
+ target->colon_splits++,
+ target->string_mb);
+ } else {
+ *slash = 0;
+ (void) sprintf(mb_namep,
+ "%s/%d@%s",
+ target->string_mb,
+ target->colon_splits++,
+ slash + 1);
+ *slash = (int) slash_char;
+ }
+ MBSTOWCS(namep, mb_namep);
+ retmem_mb(mb_namep);
+ name = GETNAME(namep, FIND_LENGTH);
+ retmem(namep);
+ if (trace_reader) {
+ (void) printf("%s:\t", target->string_mb);
+ }
+ /* Make "target" depend on "<number>%target */
+ line2 = maybe_append_prop(target, line_prop);
+ enter_dependency(line2, name, true);
+ line2->body.line.target = target;
+ /* Put a prop on "<number>%target that makes */
+ /* appear as "target" */
+ /* when it is processed */
+ maybe_append_prop(name, target_prop)->
+ body.target.target = target;
+ target->is_double_colon_parent = true;
+ name->is_double_colon = true;
+ name->has_target_prop = true;
+ if (trace_reader) {
+ (void) printf("\n");
+ }
+ (target = name)->stat.is_file = true;
+ }
+ }
+ /* This really is a regular dependency line. Just enter it */
+ line = maybe_append_prop(target, line_prop);
+ line->body.line.target = target;
+ /* Depending on what kind of makefile we are reading we have to */
+ /* treat things differently */
+ switch (makefile_type) {
+ case reading_makefile:
+ /* Reading regular makefile. Just notice whether this */
+ /* redefines the rule for the target */
+ if (command != NULL) {
+ if (line->body.line.command_template != NULL) {
+ line->body.line.command_template_redefined =
+ true;
+ if ((wcb[0] == (int) period_char) &&
+ !wschr(wcb, (int) slash_char)) {
+ line->body.line.command_template =
+ command;
+ }
+ } else {
+ line->body.line.command_template = command;
+ }
+ } else {
+ if ((wcb[0] == (int) period_char) &&
+ !wschr(wcb, (int) slash_char)) {
+ line->body.line.command_template = command;
+ }
+ }
+ break;
+ case rereading_statefile:
+ /* Rereading the statefile. We only enter thing that changed */
+ /* since the previous time we read it */
+ if (!built_last_make_run_seen) {
+ for (Cmd_line next, cmd = command; cmd != NULL; cmd = next) {
+ next = cmd->next;
+ free(cmd);
+ }
+ return;
+ }
+ built_last_make_run_seen = false;
+ command_changed = true;
+ target->ran_command = true;
+ case reading_statefile:
+ /* Reading the statefile for the first time. Enter the rules */
+ /* as "Commands used" not "templates to use" */
+ if (command != NULL) {
+ for (Cmd_line next, cmd = line->body.line.command_used;
+ cmd != NULL; cmd = next) {
+ next = cmd->next;
+ free(cmd);
+ }
+ line->body.line.command_used = command;
+ }
+ case reading_cpp_file:
+ /* Reading report file from programs that reports */
+ /* dependencies. If this is the first time the target is */
+ /* read from this reportfile we clear all old */
+ /* automatic depes */
+ if (target->temp_file_number == temp_file_number) {
+ break;
+ }
+ target->temp_file_number = temp_file_number;
+ command_changed = true;
+ if (line != NULL) {
+ for (dp = line->body.line.dependencies;
+ dp != NULL;
+ dp = dp->next) {
+ if (dp->automatic) {
+ dp->stale = true;
+ }
+ }
+ }
+ break;
+ default:
+ fatal_reader(catgets(catd, 1, 93, "Internal error. Unknown makefile type %d"),
+ makefile_type);
+ }
+ /* A target may only be involved in one target group */
+ if (line->body.line.target_group != NULL) {
+ if (target_group != NULL) {
+ fatal_reader(catgets(catd, 1, 94, "Too many target groups for target `%s'"),
+ target->string_mb);
+ }
+ } else {
+ line->body.line.target_group = target_group;
+ }
+
+ if (trace_reader) {
+ (void) printf("%s:\t", target->string_mb);
+ }
+ /* Enter the dependencies */
+ register_as_auto = BOOLEAN(makefile_type != reading_makefile);
+ not_auto_found = false;
+ for (;
+ (depes != NULL) && !not_auto_found;
+ depes = depes->next) {
+ for (i = 0; i < depes->used; i++) {
+ /* the dependency .NOT_AUTO signals beginning of
+ * explicit dependancies which were put at end of
+ * list in .make.state file - we stop entering
+ * dependencies at this point
+ */
+ if (depes->names[i] == not_auto) {
+ not_auto_found = true;
+ break;
+ }
+ enter_dependency(line,
+ depes->names[i],
+ register_as_auto);
+ }
+ }
+ if (trace_reader) {
+ (void) printf("\n");
+ print_rule(command);
+ }
+}
+
+/*
+ * enter_dependency(line, depe, automatic)
+ *
+ * Enter one dependency. Do not enter duplicates.
+ *
+ * Parameters:
+ * line The line block that the dependeny is
+ * entered for
+ * depe The dependency to enter
+ * automatic Used to set the field "automatic"
+ *
+ * Global variables used:
+ * makefile_type We do different things for makefile vs. report
+ * trace_reader Indicates that we should echo stuff we read
+ * wait_name The Name ".WAIT", compared against
+ */
+void
+enter_dependency(Property line, register Name depe, Boolean automatic)
+{
+ register Dependency dp;
+ register Dependency *insert;
+
+ if (trace_reader) {
+ (void) printf("%s ", depe->string_mb);
+ }
+ /* Find the end of the list and check for duplicates */
+ for (insert = &line->body.line.dependencies, dp = *insert;
+ dp != NULL;
+ insert = &dp->next, dp = *insert) {
+ if ((dp->name == depe) && (depe != wait_name)) {
+ if (dp->automatic) {
+ dp->automatic = automatic;
+ if (automatic) {
+ dp->built = false;
+ depe->stat.is_file = true;
+#ifdef NSE
+ depe->has_parent= true;
+ depe->is_target= true;
+#endif
+ }
+ }
+ dp->stale = false;
+ return;
+ }
+ }
+ /* Insert the new dependency since we couldnt find it */
+ dp = *insert = ALLOC(Dependency);
+ dp->name = depe;
+ dp->next = NULL;
+ dp->automatic = automatic;
+ dp->stale = false;
+ dp->built = false;
+ depe->stat.is_file = true;
+#ifdef NSE
+ depe->has_parent= true;
+ depe->is_target= true;
+#endif
+
+ if ((makefile_type == reading_makefile) &&
+ (line != NULL) &&
+ (line->body.line.target != NULL)) {
+ line->body.line.target->has_regular_dependency = true;
+#ifdef NSE
+ line->body.line.target->is_target= true;
+#endif
+ }
+}
+
+/*
+ * enter_percent(target, depes, command)
+ *
+ * Enter "x%y : a%b" type lines
+ * % patterns are stored in four parts head and tail for target and source
+ *
+ * Parameters:
+ * target Left hand side of pattern
+ * depes The dependency list with the rh pattern
+ * command The command for the pattern
+ *
+ * Global variables used:
+ * empty_name The Name "", compared against
+ * percent_list The list of all percent rules, added to
+ * trace_reader Indicates that we should echo stuff we read
+ */
+Percent
+enter_percent(register Name target, Chain target_group, register Name_vector depes, Cmd_line command)
+{
+ register Percent result = ALLOC(Percent);
+ register Percent depe;
+ register Percent *depe_tail = &result->dependencies;
+ register Percent *insert;
+ register wchar_t *cp, *cp1;
+ Name_vector nvp;
+ int i;
+ int pattern;
+
+ result->next = NULL;
+ result->patterns = NULL;
+ result->patterns_total = 0;
+ result->command_template = command;
+ result->being_expanded = false;
+ result->name = target;
+ result->dependencies = NULL;
+ result->target_group = target_group;
+
+ /* get patterns count */
+ Wstring wcb(target);
+ cp = wcb.get_string();
+ while (true) {
+ cp = (wchar_t *) wschr(cp, (int) percent_char);
+ if (cp != NULL) {
+ result->patterns_total++;
+ cp++;
+ } else {
+ break;
+ }
+ }
+ result->patterns_total++;
+
+ /* allocate storage for patterns */
+ result->patterns = (Name *) getmem(sizeof(Name) * result->patterns_total);
+
+ /* then create patterns */
+ cp = wcb.get_string();
+ pattern = 0;
+ while (true) {
+ cp1 = (wchar_t *) wschr(cp, (int) percent_char);
+ if (cp1 != NULL) {
+ result->patterns[pattern] = GETNAME(cp, cp1 - cp);
+ cp = cp1 + 1;
+ pattern++;
+ } else {
+ result->patterns[pattern] = GETNAME(cp, (int) target->hash.length - (cp - wcb.get_string()));
+ break;
+ }
+ }
+
+ Wstring wcb1;
+
+ /* build dependencies list */
+ for (nvp = depes; nvp != NULL; nvp = nvp->next) {
+ for (i = 0; i < nvp->used; i++) {
+ depe = ALLOC(Percent);
+ depe->next = NULL;
+ depe->patterns = NULL;
+ depe->patterns_total = 0;
+ depe->name = nvp->names[i];
+ depe->dependencies = NULL;
+ depe->command_template = NULL;
+ depe->being_expanded = false;
+ depe->target_group = NULL;
+
+ *depe_tail = depe;
+ depe_tail = &depe->next;
+
+ if (depe->name->percent) {
+ /* get patterns count */
+ wcb1.init(depe->name);
+ cp = wcb1.get_string();
+ while (true) {
+ cp = (wchar_t *) wschr(cp, (int) percent_char);
+ if (cp != NULL) {
+ depe->patterns_total++;
+ cp++;
+ } else {
+ break;
+ }
+ }
+ depe->patterns_total++;
+
+ /* allocate storage for patterns */
+ depe->patterns = (Name *) getmem(sizeof(Name) * depe->patterns_total);
+
+ /* then create patterns */
+ cp = wcb1.get_string();
+ pattern = 0;
+ while (true) {
+ cp1 = (wchar_t *) wschr(cp, (int) percent_char);
+ if (cp1 != NULL) {
+ depe->patterns[pattern] = GETNAME(cp, cp1 - cp);
+ cp = cp1 + 1;
+ pattern++;
+ } else {
+ depe->patterns[pattern] = GETNAME(cp, (int) depe->name->hash.length - (cp - wcb1.get_string()));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Find the end of the percent list and append the new pattern */
+ for (insert = &percent_list; (*insert) != NULL; insert = &(*insert)->next);
+ *insert = result;
+
+ if (trace_reader) {
+ (void) printf("%s:", result->name->string_mb);
+
+ for (depe = result->dependencies; depe != NULL; depe = depe->next) {
+ (void) printf(" %s", depe->name->string_mb);
+ }
+
+ (void) printf("\n");
+
+ print_rule(command);
+ }
+
+ return result;
+}
+
+/*
+ * enter_dyntarget(target)
+ *
+ * Enter "$$(MACRO) : b" type lines
+ *
+ * Parameters:
+ * target Left hand side of pattern
+ *
+ * Global variables used:
+ * dyntarget_list The list of all percent rules, added to
+ * trace_reader Indicates that we should echo stuff we read
+ */
+Dyntarget
+enter_dyntarget(register Name target)
+{
+ register Dyntarget result = ALLOC(Dyntarget);
+ Dyntarget p;
+ Dyntarget *insert;
+ int i;
+
+ result->next = NULL;
+ result->name = target;
+
+
+ /* Find the end of the dyntarget list and append the new pattern */
+ for (insert = &dyntarget_list, p = *insert;
+ p != NULL;
+ insert = &p->next, p = *insert);
+ *insert = result;
+
+ if (trace_reader) {
+ (void) printf(NOCATGETS("Dynamic target %s:\n"), result->name->string_mb);
+ }
+ return( result);
+}
+
+
+/*
+ * special_reader(target, depes, command)
+ *
+ * Read the pseudo targets make knows about
+ * This handles the special targets that should not be entered as regular
+ * target/dependency sets.
+ *
+ * Parameters:
+ * target The special target
+ * depes The list of dependencies it was entered with
+ * command The command it was entered with
+ *
+ * Static variables used:
+ * built_last_make_run_seen Set to indicate .BUILT_LAST... seen
+ *
+ * Global variables used:
+ * all_parallel Set to indicate that everything runs parallel
+ * svr4 Set when ".SVR4" target is read
+ * svr4_name The Name ".SVR4"
+ * posix Set when ".POSIX" target is read
+ * posix_name The Name ".POSIX"
+ * current_make_version The Name "<current version number>"
+ * default_rule Set when ".DEFAULT" target is read
+ * default_rule_name The Name ".DEFAULT", used for tracing
+ * dot_keep_state The Name ".KEEP_STATE", used for tracing
+ * ignore_errors Set if ".IGNORE" target is read
+ * ignore_name The Name ".IGNORE", used for tracing
+ * keep_state Set if ".KEEP_STATE" target is read
+ * no_parallel_name The Name ".NO_PARALLEL", used for tracing
+ * only_parallel Set to indicate only some targets runs parallel
+ * parallel_name The Name ".PARALLEL", used for tracing
+ * precious The Name ".PRECIOUS", used for tracing
+ * sccs_get_name The Name ".SCCS_GET", used for tracing
+ * sccs_get_posix_name The Name ".SCCS_GET_POSIX", used for tracing
+ * get_name The Name ".GET", used for tracing
+ * sccs_get_rule Set when ".SCCS_GET" target is read
+ * silent Set when ".SILENT" target is read
+ * silent_name The Name ".SILENT", used for tracing
+ * trace_reader Indicates that we should echo stuff we read
+ */
+void
+special_reader(Name target, register Name_vector depes, Cmd_line command)
+{
+ register int n;
+
+ switch (target->special_reader) {
+
+ case svr4_special:
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 98, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ svr4 = true;
+ posix = false;
+ keep_state = false;
+ all_parallel = false;
+ only_parallel = false;
+ if (trace_reader) {
+ (void) printf("%s:\n", svr4_name->string_mb);
+ }
+ break;
+
+ case posix_special:
+ if(svr4)
+ break;
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 99, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ posix = true;
+ /* with posix on, use the posix get rule */
+ sccs_get_rule = sccs_get_posix_rule;
+ /* turn keep state off being SunPro make specific */
+ keep_state = false;
+ #if defined(SUN5_0)
+ /* Use /usr/xpg4/bin/sh on Solaris */
+ MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
+ (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
+ #endif
+ if (trace_reader) {
+ (void) printf("%s:\n", posix_name->string_mb);
+ }
+ break;
+
+ case built_last_make_run_special:
+ built_last_make_run_seen = true;
+ break;
+
+ case default_special:
+ if (depes->used != 0) {
+ warning(catgets(catd, 1, 100, "Illegal dependency list for target `%s'"),
+ target->string_mb);
+ }
+ default_rule = command;
+ if (trace_reader) {
+ (void) printf("%s:\n",
+ default_rule_name->string_mb);
+ print_rule(command);
+ }
+ break;
+
+#ifdef NSE
+ case derived_src_special:
+ for (; depes != NULL; depes= depes->next)
+ for (n= 0; n < depes->used; n++) {
+ if (trace_reader)
+ (void)printf("%s:\t%s\n",
+ precious->string_mb,
+ depes->names[n]->string_mb);
+ depes->names[n]->stat.is_derived_src= true;
+ };
+ break;
+#endif
+
+ case ignore_special:
+ if ((depes->used != 0) &&(!posix)){
+ fatal_reader(catgets(catd, 1, 101, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ if (depes->used == 0)
+ {
+ ignore_errors_all = true;
+ }
+ if(svr4) {
+ ignore_errors_all = true;
+ break;
+ }
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ depes->names[n]->ignore_error_mode = true;
+ }
+ }
+ if (trace_reader) {
+ (void) printf("%s:\n", ignore_name->string_mb);
+ }
+ break;
+
+ case keep_state_special:
+ if(svr4)
+ break;
+ /* ignore keep state, being SunPro make specific */
+ if(posix)
+ break;
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 102, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ keep_state = true;
+ if (trace_reader) {
+ (void) printf("%s:\n",
+ dot_keep_state->string_mb);
+ }
+ break;
+
+ case keep_state_file_special:
+ if(svr4)
+ break;
+ if(posix)
+ break;
+ /* it's not necessary to specify KEEP_STATE, if this
+ ** is given, so set the keep_state.
+ */
+ keep_state = true;
+ if (depes->used != 0) {
+ if((!make_state) ||(!strcmp(make_state->string_mb,NOCATGETS(".make.state")))) {
+ make_state = depes->names[0];
+ }
+ }
+ break;
+ case make_version_special:
+ if(svr4)
+ break;
+ if (depes->used != 1) {
+ fatal_reader(catgets(catd, 1, 103, "Illegal dependency list for target `%s'"),
+ target->string_mb);
+ }
+ if (depes->names[0] != current_make_version) {
+ /*
+ * Special case the fact that version 1.0 and 1.1
+ * are identical.
+ */
+ if (!IS_EQUAL(depes->names[0]->string_mb,
+ NOCATGETS("VERSION-1.1")) ||
+ !IS_EQUAL(current_make_version->string_mb,
+ NOCATGETS("VERSION-1.0"))) {
+ /*
+ * Version mismatches should cause the
+ * .make.state file to be skipped.
+ * This is currently not true - it is read
+ * anyway.
+ */
+ warning(catgets(catd, 1, 104, "Version mismatch between current version `%s' and `%s'"),
+ current_make_version->string_mb,
+ depes->names[0]->string_mb);
+ }
+ }
+ break;
+
+ case no_parallel_special:
+ if(svr4)
+ break;
+ /* Set the no_parallel bit for all the targets on */
+ /* the dependency list */
+ if (depes->used == 0) {
+ /* only those explicitly made parallel */
+ only_parallel = true;
+ all_parallel = false;
+ }
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ if (trace_reader) {
+ (void) printf("%s:\t%s\n",
+ no_parallel_name->string_mb,
+ depes->names[n]->string_mb);
+ }
+ depes->names[n]->no_parallel = true;
+ depes->names[n]->parallel = false;
+ }
+ }
+ break;
+
+ case parallel_special:
+ if(svr4)
+ break;
+ if (depes->used == 0) {
+ /* everything runs in parallel */
+ all_parallel = true;
+ only_parallel = false;
+ }
+ /* Set the parallel bit for all the targets on */
+ /* the dependency list */
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ if (trace_reader) {
+ (void) printf("%s:\t%s\n",
+ parallel_name->string_mb,
+ depes->names[n]->string_mb);
+ }
+ depes->names[n]->parallel = true;
+ depes->names[n]->no_parallel = false;
+ }
+ }
+ break;
+
+ case localhost_special:
+ if(svr4)
+ break;
+ /* Set the no_parallel bit for all the targets on */
+ /* the dependency list */
+ if (depes->used == 0) {
+ /* only those explicitly made parallel */
+ only_parallel = true;
+ all_parallel = false;
+ }
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ if (trace_reader) {
+ (void) printf("%s:\t%s\n",
+ localhost_name->string_mb,
+ depes->names[n]->string_mb);
+ }
+ depes->names[n]->no_parallel = true;
+ depes->names[n]->parallel = false;
+ depes->names[n]->localhost = true;
+ }
+ }
+ break;
+
+ case precious_special:
+ if (depes->used == 0) {
+ /* everything is precious */
+ all_precious = true;
+ } else {
+ all_precious = false;
+ }
+ if(svr4) {
+ all_precious = true;
+ break;
+ }
+ /* Set the precious bit for all the targets on */
+ /* the dependency list */
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ if (trace_reader) {
+ (void) printf("%s:\t%s\n",
+ precious->string_mb,
+ depes->names[n]->string_mb);
+ }
+ depes->names[n]->stat.is_precious = true;
+ }
+ }
+ break;
+
+ case sccs_get_special:
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 105, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ sccs_get_rule = command;
+ sccs_get_org_rule = command;
+ if (trace_reader) {
+ (void) printf("%s:\n", sccs_get_name->string_mb);
+ print_rule(command);
+ }
+ break;
+
+ case sccs_get_posix_special:
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 106, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ sccs_get_posix_rule = command;
+ if (trace_reader) {
+ (void) printf("%s:\n", sccs_get_posix_name->string_mb);
+ print_rule(command);
+ }
+ break;
+
+ case get_posix_special:
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 107, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ get_posix_rule = command;
+ if (trace_reader) {
+ (void) printf("%s:\n", get_posix_name->string_mb);
+ print_rule(command);
+ }
+ break;
+
+ case get_special:
+ if(!svr4) {
+ break;
+ }
+ if (depes->used != 0) {
+ fatal_reader(catgets(catd, 1, 108, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ get_rule = command;
+ sccs_get_rule = command;
+ if (trace_reader) {
+ (void) printf("%s:\n", get_name->string_mb);
+ print_rule(command);
+ }
+ break;
+
+ case silent_special:
+ if ((depes->used != 0) && (!posix)){
+ fatal_reader(catgets(catd, 1, 109, "Illegal dependencies for target `%s'"),
+ target->string_mb);
+ }
+ if (depes->used == 0)
+ {
+ silent_all = true;
+ }
+ if(svr4) {
+ silent_all = true;
+ break;
+ }
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ depes->names[n]->silent_mode = true;
+ }
+ }
+ if (trace_reader) {
+ (void) printf("%s:\n", silent_name->string_mb);
+ }
+ break;
+
+ case suffixes_special:
+ read_suffixes_list(depes);
+ break;
+
+ default:
+
+ fatal_reader(catgets(catd, 1, 110, "Internal error: Unknown special reader"));
+ }
+}
+
+/*
+ * read_suffixes_list(depes)
+ *
+ * Read the special list .SUFFIXES. If it is empty the old list is
+ * cleared. Else the new one is appended. Suffixes with ~ are extracted
+ * and marked.
+ *
+ * Parameters:
+ * depes The list of suffixes
+ *
+ * Global variables used:
+ * hashtab The central hashtable for Names.
+ * suffixes The list of suffixes, set or appended to
+ * suffixes_name The Name ".SUFFIXES", used for tracing
+ * trace_reader Indicates that we should echo stuff we read
+ */
+static void
+read_suffixes_list(register Name_vector depes)
+{
+ register int n;
+ register Dependency dp;
+ register Dependency *insert_dep;
+ register Name np;
+ Name np2;
+ register Boolean first = true;
+
+ if (depes->used == 0) {
+ /* .SUFFIXES with no dependency list clears the */
+ /* suffixes list */
+ for (Name_set::iterator np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
+ np->with_squiggle =
+ np->without_squiggle =
+ false;
+ }
+ suffixes = NULL;
+ if (trace_reader) {
+ (void) printf("%s:\n", suffixes_name->string_mb);
+ }
+ return;
+ }
+ Wstring str;
+ /* Otherwise we append to the list */
+ for (; depes != NULL; depes = depes->next) {
+ for (n = 0; n < depes->used; n++) {
+ np = depes->names[n];
+ /* Find the end of the list and check if the */
+ /* suffix already has been entered */
+ for (insert_dep = &suffixes, dp = *insert_dep;
+ dp != NULL;
+ insert_dep = &dp->next, dp = *insert_dep) {
+ if (dp->name == np) {
+ goto duplicate_suffix;
+ }
+ }
+ if (trace_reader) {
+ if (first) {
+ (void) printf("%s:\t",
+ suffixes_name->string_mb);
+ first = false;
+ }
+ (void) printf("%s ", depes->names[n]->string_mb);
+ }
+ if(!(posix|svr4)) {
+ /* If the suffix is suffixed with "~" we */
+ /* strip that and mark the suffix nameblock */
+ str.init(np);
+ wchar_t * wcb = str.get_string();
+ if (wcb[np->hash.length - 1] ==
+ (int) tilde_char) {
+ np2 = GETNAME(wcb,
+ (int)(np->hash.length - 1));
+ np2->with_squiggle = true;
+ if (np2->without_squiggle) {
+ continue;
+ }
+ np = np2;
+ }
+ }
+ np->without_squiggle = true;
+ /* Add the suffix to the list */
+ dp = *insert_dep = ALLOC(Dependency);
+ insert_dep = &dp->next;
+ dp->next = NULL;
+ dp->name = np;
+ dp->built = false;
+ duplicate_suffix:;
+ }
+ }
+ if (trace_reader) {
+ (void) printf("\n");
+ }
+}
+
+/*
+ * make_relative(to, result)
+ *
+ * Given a file name compose a relative path name from it to the
+ * current directory.
+ *
+ * Parameters:
+ * to The path we want to make relative
+ * result Where to put the resulting relative path
+ *
+ * Global variables used:
+ */
+static void
+make_relative(wchar_t *to, wchar_t *result)
+{
+ wchar_t *from;
+ wchar_t *allocated;
+ wchar_t *cp;
+ wchar_t *tocomp;
+ int ncomps;
+ int i;
+ int len;
+
+ /* Check if the path is already relative. */
+ if (to[0] != (int) slash_char) {
+ (void) wscpy(result, to);
+ return;
+ }
+
+ MBSTOWCS(wcs_buffer, get_current_path());
+ from = allocated = (wchar_t *) wsdup(wcs_buffer);
+
+ /*
+ * Find the number of components in the from name.
+ * ncomp = number of slashes + 1.
+ */
+ ncomps = 1;
+ for (cp = from; *cp != (int) nul_char; cp++) {
+ if (*cp == (int) slash_char) {
+ ncomps++;
+ }
+ }
+
+ /*
+ * See how many components match to determine how many "..",
+ * if any, will be needed.
+ */
+ result[0] = (int) nul_char;
+ tocomp = to;
+ while ((*from != (int) nul_char) && (*from == *to)) {
+ if (*from == (int) slash_char) {
+ ncomps--;
+ tocomp = &to[1];
+ }
+ from++;
+ to++;
+ }
+
+ /*
+ * Now for some special cases. Check for exact matches and
+ * for either name terminating exactly.
+ */
+ if (*from == (int) nul_char) {
+ if (*to == (int) nul_char) {
+ MBSTOWCS(wcs_buffer, ".");
+ (void) wscpy(result, wcs_buffer);
+ retmem(allocated);
+ return;
+ }
+ if (*to == (int) slash_char) {
+ ncomps--;
+ tocomp = &to[1];
+ }
+ } else if ((*from == (int) slash_char) && (*to == (int) nul_char)) {
+ ncomps--;
+ tocomp = to;
+ }
+ /* Add on the ".."s. */
+ for (i = 0; i < ncomps; i++) {
+ MBSTOWCS(wcs_buffer, "../");
+ (void) wscat(result, wcs_buffer);
+ }
+
+ /* Add on the remainder of the to name, if any. */
+ if (*tocomp == (int) nul_char) {
+ len = wslen(result);
+ result[len - 1] = (int) nul_char;
+ } else {
+ (void) wscat(result, tocomp);
+ }
+ retmem(allocated);
+ return;
+}
+
+/*
+ * print_rule(command)
+ *
+ * Used when tracing the reading of rules
+ *
+ * Parameters:
+ * command Command to print
+ *
+ * Global variables used:
+ */
+static void
+print_rule(register Cmd_line command)
+{
+ for (; command != NULL; command = command->next) {
+ (void) printf("\t%s\n", command->command_line->string_mb);
+ }
+}
+
+/*
+ * enter_conditional(target, name, value, append)
+ *
+ * Enter "target := MACRO= value" constructs
+ *
+ * Parameters:
+ * target The target the macro is for
+ * name The name of the macro
+ * value The value for the macro
+ * append Indicates if the assignment is appending or not
+ *
+ * Global variables used:
+ * conditionals A special Name that stores all conditionals
+ * where the target is a % pattern
+ * trace_reader Indicates that we should echo stuff we read
+ */
+void
+enter_conditional(register Name target, Name name, Name value, register Boolean append)
+{
+ register Property conditional;
+ static int sequence;
+ Name orig_target = target;
+
+ if (name == target_arch) {
+ enter_conditional(target, virtual_root, virtual_root, false);
+ }
+
+ if (target->percent) {
+ target = conditionals;
+ }
+
+ if (name->colon) {
+ sh_transform(&name, &value);
+ }
+
+ /* Count how many conditionals we must activate before building the */
+ /* target */
+ if (target->percent) {
+ target = conditionals;
+ }
+
+ target->conditional_cnt++;
+ maybe_append_prop(name, macro_prop)->body.macro.is_conditional = true;
+ /* Add the property for the target */
+ conditional = append_prop(target, conditional_prop);
+ conditional->body.conditional.target = orig_target;
+ conditional->body.conditional.name = name;
+ conditional->body.conditional.value = value;
+ conditional->body.conditional.sequence = sequence++;
+ conditional->body.conditional.append = append;
+ if (trace_reader) {
+ if (value == NULL) {
+ (void) printf("%s := %s %c=\n",
+ target->string_mb,
+ name->string_mb,
+ append ?
+ (int) plus_char : (int) space_char);
+ } else {
+ (void) printf("%s := %s %c= %s\n",
+ target->string_mb,
+ name->string_mb,
+ append ?
+ (int) plus_char : (int) space_char,
+ value->string_mb);
+ }
+ }
+}
+
+/*
+ * enter_equal(name, value, append)
+ *
+ * Enter "MACRO= value" constructs
+ *
+ * Parameters:
+ * name The name of the macro
+ * value The value for the macro
+ * append Indicates if the assignment is appending or not
+ *
+ * Global variables used:
+ * trace_reader Indicates that we should echo stuff we read
+ */
+void
+enter_equal(Name name, Name value, register Boolean append)
+{
+ wchar_t *string;
+ Name temp;
+
+ if (name->colon) {
+ sh_transform(&name, &value);
+ }
+ (void) SETVAR(name, value, append);
+
+ /* if we're setting FC, we want to set F77 to the same value. */
+ Wstring nms(name);
+ wchar_t * wcb = nms.get_string();
+ string = wcb;
+ if (string[0]=='F' &&
+ string[1]=='C' &&
+ string[2]=='\0') {
+ MBSTOWCS(wcs_buffer, NOCATGETS("F77"));
+ temp = GETNAME(wcs_buffer, FIND_LENGTH);
+ (void) SETVAR(temp, value, append);
+/*
+ fprintf(stderr, catgets(catd, 1, 111, "warning: FC is obsolete, use F77 instead\n"));
+ */
+ }
+
+ if (trace_reader) {
+ if (value == NULL) {
+ (void) printf("%s %c=\n",
+ name->string_mb,
+ append ?
+ (int) plus_char : (int) space_char);
+ } else {
+ (void) printf("%s %c= %s\n",
+ name->string_mb,
+ append ?
+ (int) plus_char : (int) space_char,
+ value->string_mb);
+ }
+ }
+}
+
+/*
+ * sh_transform(name, value)
+ *
+ * Parameters:
+ * name The name of the macro we might transform
+ * value The value to transform
+ *
+ */
+static void
+sh_transform(Name *name, Name *value)
+{
+ /* Check if we need :sh transform */
+ wchar_t *colon;
+ String_rec command;
+ String_rec destination;
+ wchar_t buffer[1000];
+ wchar_t buffer1[1000];
+
+ static wchar_t colon_sh[4];
+ static wchar_t colon_shell[7];
+
+ if (colon_sh[0] == (int) nul_char) {
+ MBSTOWCS(colon_sh, NOCATGETS(":sh"));
+ MBSTOWCS(colon_shell, NOCATGETS(":shell"));
+ }
+ Wstring nms((*name));
+ wchar_t * wcb = nms.get_string();
+
+ colon = (wchar_t *) wsrchr(wcb, (int) colon_char);
+ if ((colon != NULL) && (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell))) {
+ INIT_STRING_FROM_STACK(destination, buffer);
+
+ if(*value == NULL) {
+ buffer[0] = 0;
+ } else {
+ Wstring wcb1((*value));
+ if (IS_WEQUAL(colon, colon_shell)) {
+ INIT_STRING_FROM_STACK(command, buffer1);
+ expand_value(*value, &command, false);
+ } else {
+ command.text.p = wcb1.get_string() + (*value)->hash.length;
+ command.text.end = command.text.p;
+ command.buffer.start = wcb1.get_string();
+ command.buffer.end = command.text.p;
+ }
+ sh_command2string(&command, &destination);
+ }
+
+ (*value) = GETNAME(destination.buffer.start, FIND_LENGTH);
+ *colon = (int) nul_char;
+ (*name) = GETNAME(wcb, FIND_LENGTH);
+ *colon = (int) colon_char;
+ }
+}
+
+/*
+ * fatal_reader(format, args...)
+ *
+ * Parameters:
+ * format printf style format string
+ * args arguments to match the format
+ *
+ * Global variables used:
+ * file_being_read Name of the makefile being read
+ * line_number Line that is being read
+ * report_pwd Indicates whether current path should be shown
+ * temp_file_name When reading tempfile we report that name
+ */
+/*VARARGS*/
+void
+fatal_reader(char * pattern, ...)
+{
+ va_list args;
+ char message[1000];
+
+ va_start(args, pattern);
+ if (file_being_read != NULL) {
+ WCSTOMBS(mbs_buffer, file_being_read);
+ if (line_number != 0) {
+ (void) sprintf(message,
+ catgets(catd, 1, 112, "%s, line %d: %s"),
+ mbs_buffer,
+ line_number,
+ pattern);
+ } else {
+ (void) sprintf(message,
+ "%s: %s",
+ mbs_buffer,
+ pattern);
+ }
+ pattern = message;
+ }
+
+ (void) fflush(stdout);
+#ifdef DISTRIBUTED
+ (void) fprintf(stderr, catgets(catd, 1, 113, "dmake: Fatal error in reader: "));
+#else
+ (void) fprintf(stderr, catgets(catd, 1, 238, "make: Fatal error in reader: "));
+#endif
+ (void) vfprintf(stderr, pattern, args);
+ (void) fprintf(stderr, "\n");
+ va_end(args);
+
+ if (temp_file_name != NULL) {
+ (void) fprintf(stderr,
+#ifdef DISTRIBUTED
+ catgets(catd, 1, 114, "dmake: Temp-file %s not removed\n"),
+#else
+ catgets(catd, 1, 239, "make: Temp-file %s not removed\n"),
+#endif
+ temp_file_name->string_mb);
+ temp_file_name = NULL;
+ }
+
+ if (report_pwd) {
+ (void) fprintf(stderr,
+ catgets(catd, 1, 115, "Current working directory %s\n"),
+ get_current_path());
+ }
+ (void) fflush(stderr);
+#if defined(SUN5_0) || defined(HP_UX)
+ exit_status = 1;
+#endif
+ exit(1);
+}
+