/*
* 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
* 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
*
* Handle expansion of make macros
*/
/*
* Included files
*/
#include <libintl.h>
/*
* File table of contents
*/
static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
static void init_arch_macros(void);
static void init_mach_macros(void);
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:
*/
{
if (!init_arch_done) {
init_arch_done = true;
}
}
if (!init_mach_done) {
init_mach_done = true;
}
}
false);
if (destination.free_after_use) {
}
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
{
int quote_seen = 0;
/*
* Make sure to get a string allocated even if it
* will be empty.
*/
return;
}
/*
* If the value we are expanding does not contain
* any $, we don't have to parse it.
*/
);
return;
}
if (value->being_expanded) {
}
value->being_expanded = true;
/* Setup the structure we read from */
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 */
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) {
break;
}
source_p - block_start);
/* Go expand the macro reference */
CACHE_SOURCE(1);
break;
case nul_char:
/* The string ran out. Get some more */
source_p - block_start);
value->being_expanded = false;
return;
}
if (source->error_converting) {
fatal_reader_mksh("Internal error: Invalid byte sequence in expand_value()");
}
source_p--;
continue;
}
quote_seen = 0;
}
}
/*
* 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)
{
register int closer = 0;
int quote_seen = 0;
wchar_t *p = (wchar_t*)NULL;
int left_head_len = 0;
int left_tail_len = 0;
int tmp_len = 0;
int i = 0;
enum {
enum {
}
right_hand[0] = NULL;
/* First copy the (macro-expanded) macro name into string. */
/* Check the first char of the macro name to figure out what to do. */
switch (GET_CHAR()) {
case nul_char:
}
if (source->error_converting) {
fatal_reader_mksh("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:
default:
/* Single char macro name. Just suck it up */
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:
&string,
source_p - block_start);
if (current_string != NULL) {
closer ==
(int) braceright_char ?
(int) braceleft_char :
(int) parenleft_char,
} else {
}
}
if (source->error_converting) {
fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
}
source_p--;
continue;
case newline_char:
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) {
&string,
break;
}
&string,
source_p - block_start);
CACHE_SOURCE(0);
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.
*/
&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.
*/
/* First check if we have a $(@D) type translation. */
(int) special_macro_sem) &&
case 'D':
break;
case 'F':
break;
default:
}
/* Internalize the macro name using the first char only. */
}
/* Check for other kinds of translations. */
(int) colon_char)) != NULL) {
/*
* We have a $(FOO:.c=.o) type translation.
* Get the name of the macro proper.
*/
}
/* Pickup all the translations. */
} else if ((svr4) ||
(int) percent_char)) == NULL)) {
(int) equal_char)) == NULL) {
}
if(left_tail) {
}
colon + 1,
(int) colon_char)) != NULL) {
if(right_tail) {
}
(void) wcsncpy(right_tail,
eq + 1,
(int) nul_char;
} else {
if(right_tail) {
}
}
}
} else {
(int) equal_char)) == NULL) {
}
(int) percent_char)) == NULL) {
}
}
if(left_head) {
}
colon + 1,
} else {
left_head_len = 0;
}
if(left_tail) {
}
percent + 1,
} else {
left_tail_len = 0;
}
(int) percent_char)) == NULL) {
} else {
i = 0;
do {
(void) wcsncpy(right_hand[i],
eq,
(int) nul_char;
if (i++ >= VSIZEOF(right_hand)) {
}
i++;
break;
}
i++;
}
right_hand[i] = NULL;
}
}
}
/*
* No translations found.
* Use the whole string as the macro name.
*/
}
if (string.free_after_use) {
}
make_word_mentioned = true;
}
query_mentioned = true;
}
if (!init_arch_done) {
init_arch_done = true;
}
}
if (!init_mach_done) {
init_mach_done = true;
}
}
/* Get the macro value. */
conditional_macro_used = true;
/*
* Add this conditional macro to the beginning of the
* global list.
*/
if (makefile_type == reading_makefile) {
}
}
/* Macro name read and parsed. Expand the value. */
/* 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.
*/
/* Expand the value into a local string buffer and run cmd. */
/*
* If there were any transforms specified in the macro
* name, we deal with them here.
*/
/* Expand the value into a local string buffer. */
/* Scan the expanded string. */
while (*p != (int) nul_char) {
wchar_t chr;
/*
* First skip over any white space and append
* that to the destination string.
*/
block_start = p;
p++;
}
p - block_start);
/* Then find the end of the next word. */
block_start = p;
p++;
}
/* If we cant find another word we are done */
if (block_start == p) {
break;
}
/* Then apply the transforms to the word */
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;
}
if (p != NULL) {
*p = chr;
}
} else {
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;
}
if (p != NULL) {
*p = chr;
}
p - block_start);
} else {
p - eq - 1);
}
break;
case no_extract:
p - block_start);
break;
}
switch (replacement) {
case suffix_replace:
/*
* $(FOO:.o=.c) type transform.
* Maybe replace the tail of the word.
*/
left_tail_len) &&
left_tail_len)) {
- left_tail_len);
} else {
}
break;
case pattern_replace:
/* $(X:a%b=c%d) type transform. */
left_head_len) &&
left_tail_len)) {
i = 0;
while (right_hand[i] != NULL) {
i++;
if (right_hand[i] != NULL) {
start +
}
}
} else {
}
break;
case no_replace:
break;
case sh_replace:
break;
}
}
if (string.free_after_use) {
}
} else {
/*
* This is for the case when the macro name did not
* specify transforms.
*/
dollarget_seen = true;
}
dollarless_flag = false;
dollarless_flag = true;
dollarget_seen = false;
}
}
exit:
if(left_tail) {
}
if(right_tail) {
}
if(left_head) {
}
i = 0;
while (right_hand[i] != NULL) {
retmem(right_hand[i]);
i++;
}
}
static void
{
} 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;
return;
}
}
}
}
/*
* 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)
{
if (set_host || set_target) {
}
}
}
if (set_host) {
}
if (set_target) {
}
}
}
/*
* 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)
{
if (set_host || set_target) {
}
}
}
if (set_host) {
}
if (set_target) {
}
}
}
/*
* 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
{
case no_daemon:
} else {
if (dollarless_flag && tilde_rule) {
dollarless_flag = false;
tilde_rule = false;
} else {
}
}
return;
case chain_daemon:
/* If this is a $? value we call the daemon to translate the */
/* list of names to a string */
}
}
return;
}
}
/*
* We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
*/
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
*/
setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
{
int length = 0;
if ((makefile_type != reading_nothing) &&
return macro;
}
/* Strip spaces from the end of the value */
}
buffer[0] = 0;
if (strip_trailing_spaces) {
while ((length > 0) &&
}
}
}
}
} else {
}
if (append) {
/*
* If we are appending, we just tack the new value after
* the old one with a space in between.
*/
buffer[0] = 0;
}
}
}
}
if (destination.free_after_use) {
}
}
/* Debugging trace */
if (debug_level > 1) {
switch (daemon) {
case chain_daemon:
}
(void) printf("\n");
break;
case no_daemon:
(void) printf("%s= %s\n",
break;
}
} else {
}
}
/* Set the new values in the macro property block */
/**/
buffer[0] = 0;
}
}
}
if (destination.free_after_use) {
}
}
/**/
/*
* If the user changes the VIRTUAL_ROOT, we need to flush
* the vroot package cache.
*/
}
if (name == virtual_root) {
}
/* If this sets the VPATH we remember that */
if ((name == vpath_name) &&
vpath_defined = true;
}
/*
* For environment variables we also set the
* environment value each time.
*/
static char *env;
Envvar p;
p->already_put = false;
goto found_it;
}
}
p->env_string = NULL;
p->already_put = false;
envvar = p;
found_it:;
}
/*
* We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
*/
if (length >= sunpro_dependencies_buf_size) {
if (sunpro_dependencies_buf_size < 4096)
}
} else {
}
"%s=%s",
if (sunpro_dependencies_oldbuf) {
/* Return old buffer */
}
}
}
if (name == target_arch) {
int length;
wchar_t *new_value;
wchar_t *old_vr;
length = 32 +
if (IS_WEQUALN(old_vr,
wcslen(wcs_buffer))) {
}
} else {
new_value_allocated = true;
}
if (new_value[0] != 0) {
(void) setvar_daemon(virtual_root,
false,
true,
}
if (new_value_allocated) {
}
}
return macro;
}