summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/lib/mksh/src/macro.cc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/make_src/Make/lib/mksh/src/macro.cc')
-rw-r--r--usr/src/make_src/Make/lib/mksh/src/macro.cc1414
1 files changed, 1414 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/lib/mksh/src/macro.cc b/usr/src/make_src/Make/lib/mksh/src/macro.cc
new file mode 100644
index 0000000..43d7603
--- /dev/null
+++ b/usr/src/make_src/Make/lib/mksh/src/macro.cc
@@ -0,0 +1,1414 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)macro.cc 1.22 06/12/12
+ */
+
+#pragma ident "@(#)macro.cc 1.22 06/12/12"
+
+/*
+ * macro.cc
+ *
+ * Handle expansion of make macros
+ */
+
+/*
+ * Included files
+ */
+#include <mksh/dosys.h> /* sh_command2string() */
+#include <mksh/i18n.h> /* get_char_semantics_value() */
+#include <mksh/macro.h>
+#include <mksh/misc.h> /* retmem() */
+#include <mksh/read.h> /* get_next_block_fn() */
+#include <mksdmsi18n/mksdmsi18n.h> /* libmksdmsi18n_init() */
+
+/*
+ * File table of contents
+ */
+static void add_macro_to_global_list(Name macro_to_add);
+#ifdef NSE
+static void expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd);
+#else
+static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
+#endif
+
+static void init_arch_macros(void);
+static void init_mach_macros(void);
+static Boolean init_arch_done = false;
+static Boolean init_mach_done = false;
+
+
+long env_alloc_num = 0;
+long env_alloc_bytes = 0;
+
+/*
+ * getvar(name)
+ *
+ * Return expanded value of macro.
+ *
+ * Return value:
+ * The expanded value of the macro
+ *
+ * Parameters:
+ * name The name of the macro we want the value for
+ *
+ * Global variables used:
+ */
+Name
+getvar(register Name name)
+{
+ String_rec destination;
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ register Name result;
+
+ if ((name == host_arch) || (name == target_arch)) {
+ if (!init_arch_done) {
+ init_arch_done = true;
+ init_arch_macros();
+ }
+ }
+ if ((name == host_mach) || (name == target_mach)) {
+ if (!init_mach_done) {
+ init_mach_done = true;
+ init_mach_macros();
+ }
+ }
+
+ INIT_STRING_FROM_STACK(destination, buffer);
+ expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
+ &destination,
+ false);
+ result = GETNAME(destination.buffer.start, FIND_LENGTH);
+ if (destination.free_after_use) {
+ retmem(destination.buffer.start);
+ }
+ return result;
+}
+
+/*
+ * expand_value(value, destination, cmd)
+ *
+ * Recursively expands all macros in the string value.
+ * destination is where the expanded value should be appended.
+ *
+ * Parameters:
+ * value The value we are expanding
+ * destination Where to deposit the expansion
+ * cmd If we are evaluating a command line we
+ * turn \ quoting off
+ *
+ * Global variables used:
+ */
+void
+expand_value(Name value, register String destination, Boolean cmd)
+{
+ Source_rec sourceb;
+ register Source source = &sourceb;
+ register wchar_t *source_p = NULL;
+ register wchar_t *source_end = NULL;
+ wchar_t *block_start = NULL;
+ int quote_seen = 0;
+
+ if (value == NULL) {
+ /*
+ * Make sure to get a string allocated even if it
+ * will be empty.
+ */
+ MBSTOWCS(wcs_buffer, "");
+ append_string(wcs_buffer, destination, FIND_LENGTH);
+ destination->text.end = destination->text.p;
+ return;
+ }
+ if (!value->dollar) {
+ /*
+ * If the value we are expanding does not contain
+ * any $, we don't have to parse it.
+ */
+ APPEND_NAME(value,
+ destination,
+ (int) value->hash.length
+ );
+ destination->text.end = destination->text.p;
+ return;
+ }
+
+ if (value->being_expanded) {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 113, "Loop detected when expanding macro value `%s'"),
+ value->string_mb);
+ }
+ value->being_expanded = true;
+ /* Setup the structure we read from */
+ Wstring vals(value);
+ sourceb.string.text.p = sourceb.string.buffer.start = wsdup(vals.get_string());
+ sourceb.string.free_after_use = true;
+ sourceb.string.text.end =
+ sourceb.string.buffer.end =
+ sourceb.string.text.p + value->hash.length;
+ sourceb.previous = NULL;
+ sourceb.fd = -1;
+ sourceb.inp_buf =
+ sourceb.inp_buf_ptr =
+ sourceb.inp_buf_end = NULL;
+ sourceb.error_converting = false;
+ /* Lift some pointers from the struct to local register variables */
+ CACHE_SOURCE(0);
+/* We parse the string in segments */
+/* We read chars until we find a $, then we append what we have read so far */
+/* (since last $ processing) to the destination. When we find a $ we call */
+/* expand_macro() and let it expand that particular $ reference into dest */
+ block_start = source_p;
+ quote_seen = 0;
+ for (; 1; source_p++) {
+ switch (GET_CHAR()) {
+ case backslash_char:
+ /* Quote $ in macro value */
+ if (!cmd) {
+ quote_seen = ~quote_seen;
+ }
+ continue;
+ case dollar_char:
+ /* Save the plain string we found since */
+ /* start of string or previous $ */
+ if (quote_seen) {
+ append_string(block_start,
+ destination,
+ source_p - block_start - 1);
+ block_start = source_p;
+ break;
+ }
+ append_string(block_start,
+ destination,
+ source_p - block_start);
+ source->string.text.p = ++source_p;
+ UNCACHE_SOURCE();
+ /* Go expand the macro reference */
+ expand_macro(source, destination, sourceb.string.buffer.start, cmd);
+ CACHE_SOURCE(1);
+ block_start = source_p + 1;
+ break;
+ case nul_char:
+ /* The string ran out. Get some more */
+ append_string(block_start,
+ destination,
+ source_p - block_start);
+ GET_NEXT_BLOCK_NOCHK(source);
+ if (source == NULL) {
+ destination->text.end = destination->text.p;
+ value->being_expanded = false;
+ return;
+ }
+ if (source->error_converting) {
+ fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_value()"));
+ }
+ block_start = source_p;
+ source_p--;
+ continue;
+ }
+ quote_seen = 0;
+ }
+ retmem(sourceb.string.buffer.start);
+}
+
+/*
+ * expand_macro(source, destination, current_string, cmd)
+ *
+ * Should be called with source->string.text.p pointing to
+ * the first char after the $ that starts a macro reference.
+ * source->string.text.p is returned pointing to the first char after
+ * the macro name.
+ * It will read the macro name, expanding any macros in it,
+ * and get the value. The value is then expanded.
+ * destination is a String that is filled in with the expanded macro.
+ * It may be passed in referencing a buffer to expand the macro into.
+ * Note that most expansions are done on demand, e.g. right
+ * before the command is executed and not while the file is
+ * being parsed.
+ *
+ * Parameters:
+ * source The source block that references the string
+ * to expand
+ * destination Where to put the result
+ * current_string The string we are expanding, for error msg
+ * cmd If we are evaluating a command line we
+ * turn \ quoting off
+ *
+ * Global variables used:
+ * funny Vector of semantic tags for characters
+ * is_conditional Set if a conditional macro is refd
+ * make_word_mentioned Set if the word "MAKE" is mentioned
+ * makefile_type We deliver extra msg when reading makefiles
+ * query The Name "?", compared against
+ * query_mentioned Set if the word "?" is mentioned
+ */
+void
+expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
+{
+ static Name make = (Name)NULL;
+ static wchar_t colon_sh[4];
+ static wchar_t colon_shell[7];
+ String_rec string;
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ register wchar_t *source_p = source->string.text.p;
+ register wchar_t *source_end = source->string.text.end;
+ register int closer = 0;
+ wchar_t *block_start = (wchar_t *)NULL;
+ int quote_seen = 0;
+ register int closer_level = 1;
+ Name name = (Name)NULL;
+ wchar_t *colon = (wchar_t *)NULL;
+ wchar_t *percent = (wchar_t *)NULL;
+ wchar_t *eq = (wchar_t *) NULL;
+ Property macro = NULL;
+ wchar_t *p = (wchar_t*)NULL;
+ String_rec extracted;
+ wchar_t extracted_string[MAXPATHLEN];
+ wchar_t *left_head = NULL;
+ wchar_t *left_tail = NULL;
+ wchar_t *right_tail = NULL;
+ int left_head_len = 0;
+ int left_tail_len = 0;
+ int tmp_len = 0;
+ wchar_t *right_hand[128];
+ int i = 0;
+ enum {
+ no_extract,
+ dir_extract,
+ file_extract
+ } extraction = no_extract;
+ enum {
+ no_replace,
+ suffix_replace,
+ pattern_replace,
+ sh_replace
+ } replacement = no_replace;
+
+ if (make == NULL) {
+ MBSTOWCS(wcs_buffer, NOCATGETS("MAKE"));
+ make = GETNAME(wcs_buffer, FIND_LENGTH);
+
+ MBSTOWCS(colon_sh, NOCATGETS(":sh"));
+ MBSTOWCS(colon_shell, NOCATGETS(":shell"));
+ }
+
+ right_hand[0] = NULL;
+
+ /* First copy the (macro-expanded) macro name into string. */
+ INIT_STRING_FROM_STACK(string, buffer);
+recheck_first_char:
+ /* Check the first char of the macro name to figure out what to do. */
+ switch (GET_CHAR()) {
+ case nul_char:
+ GET_NEXT_BLOCK_NOCHK(source);
+ if (source == NULL) {
+ WCSTOMBS(mbs_buffer, current_string);
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 114, "'$' at end of string `%s'"),
+ mbs_buffer);
+ }
+ if (source->error_converting) {
+ fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()"));
+ }
+ goto recheck_first_char;
+ case parenleft_char:
+ /* Multi char name. */
+ closer = (int) parenright_char;
+ break;
+ case braceleft_char:
+ /* Multi char name. */
+ closer = (int) braceright_char;
+ break;
+ case newline_char:
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 115, "'$' at end of line"));
+ default:
+ /* Single char macro name. Just suck it up */
+ append_char(*source_p, &string);
+ source->string.text.p = source_p + 1;
+ goto get_macro_value;
+ }
+
+ /* Handle multi-char macro names */
+ block_start = ++source_p;
+ quote_seen = 0;
+ for (; 1; source_p++) {
+ switch (GET_CHAR()) {
+ case nul_char:
+ append_string(block_start,
+ &string,
+ source_p - block_start);
+ GET_NEXT_BLOCK_NOCHK(source);
+ if (source == NULL) {
+ if (current_string != NULL) {
+ WCSTOMBS(mbs_buffer, current_string);
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 116, "Unmatched `%c' in string `%s'"),
+ closer ==
+ (int) braceright_char ?
+ (int) braceleft_char :
+ (int) parenleft_char,
+ mbs_buffer);
+ } else {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 117, "Premature EOF"));
+ }
+ }
+ if (source->error_converting) {
+ fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()"));
+ }
+ block_start = source_p;
+ source_p--;
+ continue;
+ case newline_char:
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 118, "Unmatched `%c' on line"),
+ closer == (int) braceright_char ?
+ (int) braceleft_char :
+ (int) parenleft_char);
+ case backslash_char:
+ /* Quote dollar in macro value. */
+ if (!cmd) {
+ quote_seen = ~quote_seen;
+ }
+ continue;
+ case dollar_char:
+ /*
+ * Macro names may reference macros.
+ * This expands the value of such macros into the
+ * macro name string.
+ */
+ if (quote_seen) {
+ append_string(block_start,
+ &string,
+ source_p - block_start - 1);
+ block_start = source_p;
+ break;
+ }
+ append_string(block_start,
+ &string,
+ source_p - block_start);
+ source->string.text.p = ++source_p;
+ UNCACHE_SOURCE();
+ expand_macro(source, &string, current_string, cmd);
+ CACHE_SOURCE(0);
+ block_start = source_p;
+ source_p--;
+ break;
+ case parenleft_char:
+ /* Allow nested pairs of () in the macro name. */
+ if (closer == (int) parenright_char) {
+ closer_level++;
+ }
+ break;
+ case braceleft_char:
+ /* Allow nested pairs of {} in the macro name. */
+ if (closer == (int) braceright_char) {
+ closer_level++;
+ }
+ break;
+ case parenright_char:
+ case braceright_char:
+ /*
+ * End of the name. Save the string in the macro
+ * name string.
+ */
+ if ((*source_p == closer) && (--closer_level <= 0)) {
+ source->string.text.p = source_p + 1;
+ append_string(block_start,
+ &string,
+ source_p - block_start);
+ goto get_macro_value;
+ }
+ break;
+ }
+ quote_seen = 0;
+ }
+ /*
+ * We got the macro name. We now inspect it to see if it
+ * specifies any translations of the value.
+ */
+get_macro_value:
+ name = NULL;
+ /* First check if we have a $(@D) type translation. */
+ if ((get_char_semantics_value(string.buffer.start[0]) &
+ (int) special_macro_sem) &&
+ (string.text.p - string.buffer.start >= 2) &&
+ ((string.buffer.start[1] == 'D') ||
+ (string.buffer.start[1] == 'F'))) {
+ switch (string.buffer.start[1]) {
+ case 'D':
+ extraction = dir_extract;
+ break;
+ case 'F':
+ extraction = file_extract;
+ break;
+ default:
+ WCSTOMBS(mbs_buffer, string.buffer.start);
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 119, "Illegal macro reference `%s'"),
+ mbs_buffer);
+ }
+ /* Internalize the macro name using the first char only. */
+ name = GETNAME(string.buffer.start, 1);
+ (void) wscpy(string.buffer.start, string.buffer.start + 2);
+ }
+ /* Check for other kinds of translations. */
+ if ((colon = (wchar_t *) wschr(string.buffer.start,
+ (int) colon_char)) != NULL) {
+ /*
+ * We have a $(FOO:.c=.o) type translation.
+ * Get the name of the macro proper.
+ */
+ if (name == NULL) {
+ name = GETNAME(string.buffer.start,
+ colon - string.buffer.start);
+ }
+ /* Pickup all the translations. */
+ if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
+ replacement = sh_replace;
+ } else if ((svr4) ||
+ ((percent = (wchar_t *) wschr(colon + 1,
+ (int) percent_char)) == NULL)) {
+ while (colon != NULL) {
+ if ((eq = (wchar_t *) wschr(colon + 1,
+ (int) equal_char)) == NULL) {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 120, "= missing from replacement macro reference"));
+ }
+ left_tail_len = eq - colon - 1;
+ if(left_tail) {
+ retmem(left_tail);
+ }
+ left_tail = ALLOC_WC(left_tail_len + 1);
+ (void) wsncpy(left_tail,
+ colon + 1,
+ eq - colon - 1);
+ left_tail[eq - colon - 1] = (int) nul_char;
+ replacement = suffix_replace;
+ if ((colon = (wchar_t *) wschr(eq + 1,
+ (int) colon_char)) != NULL) {
+ tmp_len = colon - eq;
+ if(right_tail) {
+ retmem(right_tail);
+ }
+ right_tail = ALLOC_WC(tmp_len);
+ (void) wsncpy(right_tail,
+ eq + 1,
+ colon - eq - 1);
+ right_tail[colon - eq - 1] =
+ (int) nul_char;
+ } else {
+ if(right_tail) {
+ retmem(right_tail);
+ }
+ right_tail = ALLOC_WC(wslen(eq) + 1);
+ (void) wscpy(right_tail, eq + 1);
+ }
+ }
+ } else {
+ if ((eq = (wchar_t *) wschr(colon + 1,
+ (int) equal_char)) == NULL) {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 121, "= missing from replacement macro reference"));
+ }
+ if ((percent = (wchar_t *) wschr(colon + 1,
+ (int) percent_char)) == NULL) {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 122, "%% missing from replacement macro reference"));
+ }
+ if (eq < percent) {
+ fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 123, "%% missing from replacement macro reference"));
+ }
+
+ if (percent > (colon + 1)) {
+ tmp_len = percent - colon;
+ if(left_head) {
+ retmem(left_head);
+ }
+ left_head = ALLOC_WC(tmp_len);
+ (void) wsncpy(left_head,
+ colon + 1,
+ percent - colon - 1);
+ left_head[percent-colon-1] = (int) nul_char;
+ left_head_len = percent-colon-1;
+ } else {
+ left_head = NULL;
+ left_head_len = 0;
+ }
+
+ if (eq > percent+1) {
+ tmp_len = eq - percent;
+ if(left_tail) {
+ retmem(left_tail);
+ }
+ left_tail = ALLOC_WC(tmp_len);
+ (void) wsncpy(left_tail,
+ percent + 1,
+ eq - percent - 1);
+ left_tail[eq-percent-1] = (int) nul_char;
+ left_tail_len = eq-percent-1;
+ } else {
+ left_tail = NULL;
+ left_tail_len = 0;
+ }
+
+ if ((percent = (wchar_t *) wschr(++eq,
+ (int) percent_char)) == NULL) {
+
+ right_hand[0] = ALLOC_WC(wslen(eq) + 1);
+ right_hand[1] = NULL;
+ (void) wscpy(right_hand[0], eq);
+ } else {
+ i = 0;
+ do {
+ right_hand[i] = ALLOC_WC(percent-eq+1);
+ (void) wsncpy(right_hand[i],
+ eq,
+ percent - eq);
+ right_hand[i][percent-eq] =
+ (int) nul_char;
+ if (i++ >= VSIZEOF(right_hand)) {
+ fatal_mksh(catgets(libmksdmsi18n_catd, 1, 124, "Too many %% in pattern"));
+ }
+ eq = percent + 1;
+ if (eq[0] == (int) nul_char) {
+ MBSTOWCS(wcs_buffer, "");
+ right_hand[i] = (wchar_t *) wsdup(wcs_buffer);
+ i++;
+ break;
+ }
+ } while ((percent = (wchar_t *) wschr(eq, (int) percent_char)) != NULL);
+ if (eq[0] != (int) nul_char) {
+ right_hand[i] = ALLOC_WC(wslen(eq) + 1);
+ (void) wscpy(right_hand[i], eq);
+ i++;
+ }
+ right_hand[i] = NULL;
+ }
+ replacement = pattern_replace;
+ }
+ }
+ if (name == NULL) {
+ /*
+ * No translations found.
+ * Use the whole string as the macro name.
+ */
+ name = GETNAME(string.buffer.start,
+ string.text.p - string.buffer.start);
+ }
+ if (string.free_after_use) {
+ retmem(string.buffer.start);
+ }
+ if (name == make) {
+ make_word_mentioned = true;
+ }
+ if (name == query) {
+ query_mentioned = true;
+ }
+ if ((name == host_arch) || (name == target_arch)) {
+ if (!init_arch_done) {
+ init_arch_done = true;
+ init_arch_macros();
+ }
+ }
+ if ((name == host_mach) || (name == target_mach)) {
+ if (!init_mach_done) {
+ init_mach_done = true;
+ init_mach_macros();
+ }
+ }
+ /* Get the macro value. */
+ macro = get_prop(name->prop, macro_prop);
+#ifdef NSE
+ if (nse_watch_vars && nse && macro != NULL) {
+ if (macro->body.macro.imported) {
+ nse_shell_var_used= name;
+ }
+ if (macro->body.macro.value != NULL){
+ if (nse_backquotes(macro->body.macro.value->string)) {
+ nse_backquote_seen= name;
+ }
+ }
+ }
+#endif
+ if ((macro != NULL) && macro->body.macro.is_conditional) {
+ conditional_macro_used = true;
+ /*
+ * Add this conditional macro to the beginning of the
+ * global list.
+ */
+ add_macro_to_global_list(name);
+ if (makefile_type == reading_makefile) {
+ warning_mksh(catgets(libmksdmsi18n_catd, 1, 164, "Conditional macro `%s' referenced in file `%ws', line %d"),
+ name->string_mb, file_being_read, line_number);
+ }
+ }
+ /* Macro name read and parsed. Expand the value. */
+ if ((macro == NULL) || (macro->body.macro.value == NULL)) {
+ /* If the value is empty, we just get out of here. */
+ goto exit;
+ }
+ if (replacement == sh_replace) {
+ /* If we should do a :sh transform, we expand the command
+ * and process it.
+ */
+ INIT_STRING_FROM_STACK(string, buffer);
+ /* Expand the value into a local string buffer and run cmd. */
+ expand_value_with_daemon(name, macro, &string, cmd);
+ sh_command2string(&string, destination);
+ } else if ((replacement != no_replace) || (extraction != no_extract)) {
+ /*
+ * If there were any transforms specified in the macro
+ * name, we deal with them here.
+ */
+ INIT_STRING_FROM_STACK(string, buffer);
+ /* Expand the value into a local string buffer. */
+ expand_value_with_daemon(name, macro, &string, cmd);
+ /* Scan the expanded string. */
+ p = string.buffer.start;
+ while (*p != (int) nul_char) {
+ wchar_t chr;
+
+ /*
+ * First skip over any white space and append
+ * that to the destination string.
+ */
+ block_start = p;
+ while ((*p != (int) nul_char) && iswspace(*p)) {
+ p++;
+ }
+ append_string(block_start,
+ destination,
+ p - block_start);
+ /* Then find the end of the next word. */
+ block_start = p;
+ while ((*p != (int) nul_char) && !iswspace(*p)) {
+ p++;
+ }
+ /* If we cant find another word we are done */
+ if (block_start == p) {
+ break;
+ }
+ /* Then apply the transforms to the word */
+ INIT_STRING_FROM_STACK(extracted, extracted_string);
+ switch (extraction) {
+ case dir_extract:
+ /*
+ * $(@D) type transform. Extract the
+ * path from the word. Deliver "." if
+ * none is found.
+ */
+ if (p != NULL) {
+ chr = *p;
+ *p = (int) nul_char;
+ }
+ eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
+ if (p != NULL) {
+ *p = chr;
+ }
+ if ((eq == NULL) || (eq > p)) {
+ MBSTOWCS(wcs_buffer, ".");
+ append_string(wcs_buffer, &extracted, 1);
+ } else {
+ append_string(block_start,
+ &extracted,
+ eq - block_start);
+ }
+ break;
+ case file_extract:
+ /*
+ * $(@F) type transform. Remove the path
+ * from the word if any.
+ */
+ if (p != NULL) {
+ chr = *p;
+ *p = (int) nul_char;
+ }
+ eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
+ if (p != NULL) {
+ *p = chr;
+ }
+ if ((eq == NULL) || (eq > p)) {
+ append_string(block_start,
+ &extracted,
+ p - block_start);
+ } else {
+ append_string(eq + 1,
+ &extracted,
+ p - eq - 1);
+ }
+ break;
+ case no_extract:
+ append_string(block_start,
+ &extracted,
+ p - block_start);
+ break;
+ }
+ switch (replacement) {
+ case suffix_replace:
+ /*
+ * $(FOO:.o=.c) type transform.
+ * Maybe replace the tail of the word.
+ */
+ if (((extracted.text.p -
+ extracted.buffer.start) >=
+ left_tail_len) &&
+ IS_WEQUALN(extracted.text.p - left_tail_len,
+ left_tail,
+ left_tail_len)) {
+ append_string(extracted.buffer.start,
+ destination,
+ (extracted.text.p -
+ extracted.buffer.start)
+ - left_tail_len);
+ append_string(right_tail,
+ destination,
+ FIND_LENGTH);
+ } else {
+ append_string(extracted.buffer.start,
+ destination,
+ FIND_LENGTH);
+ }
+ break;
+ case pattern_replace:
+ /* $(X:a%b=c%d) type transform. */
+ if (((extracted.text.p -
+ extracted.buffer.start) >=
+ left_head_len+left_tail_len) &&
+ IS_WEQUALN(left_head,
+ extracted.buffer.start,
+ left_head_len) &&
+ IS_WEQUALN(left_tail,
+ extracted.text.p - left_tail_len,
+ left_tail_len)) {
+ i = 0;
+ while (right_hand[i] != NULL) {
+ append_string(right_hand[i],
+ destination,
+ FIND_LENGTH);
+ i++;
+ if (right_hand[i] != NULL) {
+ append_string(extracted.buffer.
+ start +
+ left_head_len,
+ destination,
+ (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
+ }
+ }
+ } else {
+ append_string(extracted.buffer.start,
+ destination,
+ FIND_LENGTH);
+ }
+ break;
+ case no_replace:
+ append_string(extracted.buffer.start,
+ destination,
+ FIND_LENGTH);
+ break;
+ case sh_replace:
+ break;
+ }
+ }
+ if (string.free_after_use) {
+ retmem(string.buffer.start);
+ }
+ } else {
+ /*
+ * This is for the case when the macro name did not
+ * specify transforms.
+ */
+ if (!strncmp(name->string_mb, NOCATGETS("GET"), 3)) {
+ dollarget_seen = true;
+ }
+ dollarless_flag = false;
+ if (!strncmp(name->string_mb, "<", 1) &&
+ dollarget_seen) {
+ dollarless_flag = true;
+ dollarget_seen = false;
+ }
+ expand_value_with_daemon(name, macro, destination, cmd);
+ }
+exit:
+ if(left_tail) {
+ retmem(left_tail);
+ }
+ if(right_tail) {
+ retmem(right_tail);
+ }
+ if(left_head) {
+ retmem(left_head);
+ }
+ i = 0;
+ while (right_hand[i] != NULL) {
+ retmem(right_hand[i]);
+ i++;
+ }
+ *destination->text.p = (int) nul_char;
+ destination->text.end = destination->text.p;
+}
+
+static void
+add_macro_to_global_list(Name macro_to_add)
+{
+ Macro_list new_macro;
+ Macro_list macro_on_list;
+ char *name_on_list = (char*)NULL;
+ char *name_to_add = macro_to_add->string_mb;
+ char *value_on_list = (char*)NULL;
+ char *value_to_add = (char*)NULL;
+
+ if (macro_to_add->prop->body.macro.value != NULL) {
+ value_to_add = macro_to_add->prop->body.macro.value->string_mb;
+ } else {
+ value_to_add = "";
+ }
+
+ /*
+ * Check if this macro is already on list, if so, do nothing
+ */
+ for (macro_on_list = cond_macro_list;
+ macro_on_list != NULL;
+ macro_on_list = macro_on_list->next) {
+
+ name_on_list = macro_on_list->macro_name;
+ value_on_list = macro_on_list->value;
+
+ if (IS_EQUAL(name_on_list, name_to_add)) {
+ if (IS_EQUAL(value_on_list, value_to_add)) {
+ return;
+ }
+ }
+ }
+ new_macro = (Macro_list) malloc(sizeof(Macro_list_rec));
+ new_macro->macro_name = strdup(name_to_add);
+ new_macro->value = strdup(value_to_add);
+ new_macro->next = cond_macro_list;
+ cond_macro_list = new_macro;
+}
+
+/*
+ * init_arch_macros(void)
+ *
+ * Set the magic macros TARGET_ARCH, HOST_ARCH,
+ *
+ * Parameters:
+ *
+ * Global variables used:
+ * host_arch Property for magic macro HOST_ARCH
+ * target_arch Property for magic macro TARGET_ARCH
+ *
+ * Return value:
+ * The function does not return a value, but can
+ * call fatal() in case of error.
+ */
+static void
+init_arch_macros(void)
+{
+ String_rec result_string;
+ wchar_t wc_buf[STRING_BUFFER_LENGTH];
+ char mb_buf[STRING_BUFFER_LENGTH];
+ FILE *pipe;
+ Name value;
+ int set_host, set_target;
+#ifdef NSE
+ Property macro;
+#endif
+#if defined(linux)
+ const char *mach_command = NOCATGETS("/bin/uname -p");
+#else
+ const char *mach_command = NOCATGETS("/bin/mach");
+#endif
+
+ set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
+ set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
+
+ if (set_host || set_target) {
+ INIT_STRING_FROM_STACK(result_string, wc_buf);
+ append_char((int) hyphen_char, &result_string);
+
+ if ((pipe = popen(mach_command, "r")) == NULL) {
+ fatal_mksh(catgets(libmksdmsi18n_catd, 1, 185, "Execute of %s failed"), mach_command);
+ }
+ while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
+ MBSTOWCS(wcs_buffer, mb_buf);
+ append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
+ }
+ if (pclose(pipe) != 0) {
+ fatal_mksh(catgets(libmksdmsi18n_catd, 1, 186, "Execute of %s failed"), mach_command);
+ }
+
+ value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
+
+#ifdef NSE
+ macro = setvar_daemon(host_arch, value, false, no_daemon, true, 0);
+ macro->body.macro.imported= true;
+ macro = setvar_daemon(target_arch, value, false, no_daemon, true, 0);
+ macro->body.macro.imported= true;
+#else
+ if (set_host) {
+ (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
+ }
+ if (set_target) {
+ (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
+ }
+#endif
+ }
+}
+
+/*
+ * init_mach_macros(void)
+ *
+ * Set the magic macros TARGET_MACH, HOST_MACH,
+ *
+ * Parameters:
+ *
+ * Global variables used:
+ * host_mach Property for magic macro HOST_MACH
+ * target_mach Property for magic macro TARGET_MACH
+ *
+ * Return value:
+ * The function does not return a value, but can
+ * call fatal() in case of error.
+ */
+static void
+init_mach_macros(void)
+{
+ String_rec result_string;
+ wchar_t wc_buf[STRING_BUFFER_LENGTH];
+ char mb_buf[STRING_BUFFER_LENGTH];
+ FILE *pipe;
+ Name value;
+ int set_host, set_target;
+ const char *arch_command = NOCATGETS("/bin/arch");
+
+ set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
+ set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
+
+ if (set_host || set_target) {
+ INIT_STRING_FROM_STACK(result_string, wc_buf);
+ append_char((int) hyphen_char, &result_string);
+
+ if ((pipe = popen(arch_command, "r")) == NULL) {
+ fatal_mksh(catgets(libmksdmsi18n_catd, 1, 183, "Execute of %s failed"), arch_command);
+ }
+ while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
+ MBSTOWCS(wcs_buffer, mb_buf);
+ append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
+ }
+ if (pclose(pipe) != 0) {
+ fatal_mksh(catgets(libmksdmsi18n_catd, 1, 184, "Execute of %s failed"), arch_command);
+ }
+
+ value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
+
+ if (set_host) {
+ (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
+ }
+ if (set_target) {
+ (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
+ }
+ }
+}
+
+/*
+ * expand_value_with_daemon(name, macro, destination, cmd)
+ *
+ * Checks for daemons and then maybe calls expand_value().
+ *
+ * Parameters:
+ * name Name of the macro (Added by the NSE)
+ * macro The property block with the value to expand
+ * destination Where the result should be deposited
+ * cmd If we are evaluating a command line we
+ * turn \ quoting off
+ *
+ * Global variables used:
+ */
+static void
+#ifdef NSE
+expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd)
+#else
+expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
+#endif
+{
+ register Chain chain;
+
+#ifdef NSE
+ if (reading_dependencies) {
+ /*
+ * Processing the dependencies themselves
+ */
+ depvar_dep_macro_used(name);
+ } else {
+ /*
+ * Processing the rules for the targets
+ * the nse_watch_vars flags chokes off most
+ * checks. it is true only when processing
+ * the output from a recursive make run
+ * which is all we are interested in here.
+ */
+ if (nse_watch_vars) {
+ depvar_rule_macro_used(name);
+ }
+ }
+#endif
+
+ switch (macro->body.macro.daemon) {
+ case no_daemon:
+ if (!svr4 && !posix) {
+ expand_value(macro->body.macro.value, destination, cmd);
+ } else {
+ if (dollarless_flag && tilde_rule) {
+ expand_value(dollarless_value, destination, cmd);
+ dollarless_flag = false;
+ tilde_rule = false;
+ } else {
+ expand_value(macro->body.macro.value, destination, cmd);
+ }
+ }
+ return;
+ case chain_daemon:
+ /* If this is a $? value we call the daemon to translate the */
+ /* list of names to a string */
+ for (chain = (Chain) macro->body.macro.value;
+ chain != NULL;
+ chain = chain->next) {
+ APPEND_NAME(chain->name,
+ destination,
+ (int) chain->name->hash.length);
+ if (chain->next != NULL) {
+ append_char((int) space_char, destination);
+ }
+ }
+ return;
+ }
+}
+
+/*
+ * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
+ */
+char *sunpro_dependencies_buf = NULL;
+char *sunpro_dependencies_oldbuf = NULL;
+int sunpro_dependencies_buf_size = 0;
+
+/*
+ * setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
+ *
+ * Set a macro value, possibly supplying a daemon to be used
+ * when referencing the value.
+ *
+ * Return value:
+ * The property block with the new value
+ *
+ * Parameters:
+ * name Name of the macro to set
+ * value The value to set
+ * append Should we reset or append to the current value?
+ * daemon Special treatment when reading the value
+ * strip_trailing_spaces from the end of value->string
+ * debug_level Indicates how much tracing we should do
+ *
+ * Global variables used:
+ * makefile_type Used to check if we should enforce read only
+ * path_name The Name "PATH", compared against
+ * virtual_root The Name "VIRTUAL_ROOT", compared against
+ * vpath_defined Set if the macro VPATH is set
+ * vpath_name The Name "VPATH", compared against
+ * envvar A list of environment vars with $ in value
+ */
+Property
+setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
+{
+ register Property macro = maybe_append_prop(name, macro_prop);
+ register Property macro_apx = get_prop(name->prop, macro_append_prop);
+ int length = 0;
+ String_rec destination;
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ register Chain chain;
+ Name val;
+ wchar_t *val_string = (wchar_t*)NULL;
+ Wstring wcb;
+
+#ifdef NSE
+ macro->body.macro.imported = false;
+#endif
+
+ if ((makefile_type != reading_nothing) &&
+ macro->body.macro.read_only) {
+ return macro;
+ }
+ /* Strip spaces from the end of the value */
+ if (daemon == no_daemon) {
+ if(value != NULL) {
+ wcb.init(value);
+ length = wcb.length();
+ val_string = wcb.get_string();
+ }
+ if ((length > 0) && iswspace(val_string[length-1])) {
+ INIT_STRING_FROM_STACK(destination, buffer);
+ buffer[0] = 0;
+ append_string(val_string, &destination, length);
+ if (strip_trailing_spaces) {
+ while ((length > 0) &&
+ iswspace(destination.buffer.start[length-1])) {
+ destination.buffer.start[--length] = 0;
+ }
+ }
+ value = GETNAME(destination.buffer.start, FIND_LENGTH);
+ }
+ }
+
+ if(macro_apx != NULL) {
+ val = macro_apx->body.macro_appendix.value;
+ } else {
+ val = macro->body.macro.value;
+ }
+
+ if (append) {
+ /*
+ * If we are appending, we just tack the new value after
+ * the old one with a space in between.
+ */
+ INIT_STRING_FROM_STACK(destination, buffer);
+ buffer[0] = 0;
+ if ((macro != NULL) && (val != NULL)) {
+ APPEND_NAME(val,
+ &destination,
+ (int) val->hash.length);
+ if (value != NULL) {
+ wcb.init(value);
+ if(wcb.length() > 0) {
+ MBTOWC(wcs_buffer, " ");
+ append_char(wcs_buffer[0], &destination);
+ }
+ }
+ }
+ if (value != NULL) {
+ APPEND_NAME(value,
+ &destination,
+ (int) value->hash.length);
+ }
+ value = GETNAME(destination.buffer.start, FIND_LENGTH);
+ wcb.init(value);
+ if (destination.free_after_use) {
+ retmem(destination.buffer.start);
+ }
+ }
+
+ /* Debugging trace */
+ if (debug_level > 1) {
+ if (value != NULL) {
+ switch (daemon) {
+ case chain_daemon:
+ (void) printf("%s =", name->string_mb);
+ for (chain = (Chain) value;
+ chain != NULL;
+ chain = chain->next) {
+ (void) printf(" %s", chain->name->string_mb);
+ }
+ (void) printf("\n");
+ break;
+ case no_daemon:
+ (void) printf("%s= %s\n",
+ name->string_mb,
+ value->string_mb);
+ break;
+ }
+ } else {
+ (void) printf("%s =\n", name->string_mb);
+ }
+ }
+ /* Set the new values in the macro property block */
+/**/
+ if(macro_apx != NULL) {
+ macro_apx->body.macro_appendix.value = value;
+ INIT_STRING_FROM_STACK(destination, buffer);
+ buffer[0] = 0;
+ if (value != NULL) {
+ APPEND_NAME(value,
+ &destination,
+ (int) value->hash.length);
+ if (macro_apx->body.macro_appendix.value_to_append != NULL) {
+ MBTOWC(wcs_buffer, " ");
+ append_char(wcs_buffer[0], &destination);
+ }
+ }
+ if (macro_apx->body.macro_appendix.value_to_append != NULL) {
+ APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
+ &destination,
+ (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
+ }
+ value = GETNAME(destination.buffer.start, FIND_LENGTH);
+ if (destination.free_after_use) {
+ retmem(destination.buffer.start);
+ }
+ }
+/**/
+ macro->body.macro.value = value;
+ macro->body.macro.daemon = daemon;
+ /*
+ * If the user changes the VIRTUAL_ROOT, we need to flush
+ * the vroot package cache.
+ */
+ if (name == path_name) {
+ flush_path_cache();
+ }
+ if (name == virtual_root) {
+ flush_vroot_cache();
+ }
+ /* If this sets the VPATH we remember that */
+ if ((name == vpath_name) &&
+ (value != NULL) &&
+ (value->hash.length > 0)) {
+ vpath_defined = true;
+ }
+ /*
+ * For environment variables we also set the
+ * environment value each time.
+ */
+ if (macro->body.macro.exported) {
+ static char *env;
+
+#ifdef DISTRIBUTED
+ if (!reading_environment && (value != NULL)) {
+#else
+ if (!reading_environment && (value != NULL) && value->dollar) {
+#endif
+ Envvar p;
+
+ for (p = envvar; p != NULL; p = p->next) {
+ if (p->name == name) {
+ p->value = value;
+ p->already_put = false;
+ goto found_it;
+ }
+ }
+ p = ALLOC(Envvar);
+ p->name = name;
+ p->value = value;
+ p->next = envvar;
+ p->env_string = NULL;
+ p->already_put = false;
+ envvar = p;
+found_it:;
+#ifdef DISTRIBUTED
+ }
+ if (reading_environment || (value == NULL) || !value->dollar) {
+#else
+ } else {
+#endif
+ length = 2 + strlen(name->string_mb);
+ if (value != NULL) {
+ length += strlen(value->string_mb);
+ }
+ Property env_prop = maybe_append_prop(name, env_mem_prop);
+ /*
+ * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
+ */
+ if (!strncmp(name->string_mb, NOCATGETS("SUNPRO_DEPENDENCIES"), 19)) {
+ if (length >= sunpro_dependencies_buf_size) {
+ sunpro_dependencies_buf_size=length*2;
+ if (sunpro_dependencies_buf_size < 4096)
+ sunpro_dependencies_buf_size = 4096; // Default minimum size
+ if (sunpro_dependencies_buf)
+ sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
+ sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
+ }
+ env = sunpro_dependencies_buf;
+ } else {
+ env = getmem(length);
+ }
+ env_alloc_num++;
+ env_alloc_bytes += length;
+ (void) sprintf(env,
+ "%s=%s",
+ name->string_mb,
+ value == NULL ?
+ "" : value->string_mb);
+ (void) putenv(env);
+ env_prop->body.env_mem.value = env;
+ if (sunpro_dependencies_oldbuf) {
+ /* Return old buffer */
+ retmem_mb(sunpro_dependencies_oldbuf);
+ sunpro_dependencies_oldbuf = NULL;
+ }
+ }
+ }
+ if (name == target_arch) {
+ Name ha = getvar(host_arch);
+ Name ta = getvar(target_arch);
+ Name vr = getvar(virtual_root);
+ int length;
+ wchar_t *new_value;
+ wchar_t *old_vr;
+ Boolean new_value_allocated = false;
+
+ Wstring ha_str(ha);
+ Wstring ta_str(ta);
+ Wstring vr_str(vr);
+
+ wchar_t * wcb_ha = ha_str.get_string();
+ wchar_t * wcb_ta = ta_str.get_string();
+ wchar_t * wcb_vr = vr_str.get_string();
+
+ length = 32 +
+ wslen(wcb_ha) +
+ wslen(wcb_ta) +
+ wslen(wcb_vr);
+ old_vr = wcb_vr;
+ MBSTOWCS(wcs_buffer, NOCATGETS("/usr/arch/"));
+ if (IS_WEQUALN(old_vr,
+ wcs_buffer,
+ wslen(wcs_buffer))) {
+ old_vr = (wchar_t *) wschr(old_vr, (int) colon_char) + 1;
+ }
+ if ( (ha == ta) || (wslen(wcb_ta) == 0) ) {
+ new_value = old_vr;
+ } else {
+ new_value = ALLOC_WC(length);
+ new_value_allocated = true;
+ WCSTOMBS(mbs_buffer, old_vr);
+#if !defined(linux)
+ (void) wsprintf(new_value,
+ NOCATGETS("/usr/arch/%s/%s:%s"),
+ ha->string_mb + 1,
+ ta->string_mb + 1,
+ mbs_buffer);
+#else
+ char * mbs_new_value = (char *)getmem(length);
+ (void) sprintf(mbs_new_value,
+ NOCATGETS("/usr/arch/%s/%s:%s"),
+ ha->string_mb + 1,
+ ta->string_mb + 1,
+ mbs_buffer);
+ MBSTOWCS(new_value, mbs_new_value);
+ retmem_mb(mbs_new_value);
+#endif
+ }
+ if (new_value[0] != 0) {
+ (void) setvar_daemon(virtual_root,
+ GETNAME(new_value, FIND_LENGTH),
+ false,
+ no_daemon,
+ true,
+ debug_level);
+ }
+ if (new_value_allocated) {
+ retmem(new_value);
+ }
+ }
+ return macro;
+}