diff options
author | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
---|---|---|
committer | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
commit | e0463df9c3d2ee6155221cc443c571d5da47098a (patch) | |
tree | 5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/read2.cc | |
download | sunmake-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.cc | 1938 |
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); +} + |