xref: /illumos-gate/usr/src/cmd/make/lib/mksh/macro.cc (revision e7afc443)
110d63b7dSRichard Lowe /*
210d63b7dSRichard Lowe  * CDDL HEADER START
310d63b7dSRichard Lowe  *
410d63b7dSRichard Lowe  * The contents of this file are subject to the terms of the
510d63b7dSRichard Lowe  * Common Development and Distribution License (the "License").
610d63b7dSRichard Lowe  * You may not use this file except in compliance with the License.
710d63b7dSRichard Lowe  *
810d63b7dSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910d63b7dSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
1010d63b7dSRichard Lowe  * See the License for the specific language governing permissions
1110d63b7dSRichard Lowe  * and limitations under the License.
1210d63b7dSRichard Lowe  *
1310d63b7dSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
1410d63b7dSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510d63b7dSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
1610d63b7dSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
1710d63b7dSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
1810d63b7dSRichard Lowe  *
1910d63b7dSRichard Lowe  * CDDL HEADER END
2010d63b7dSRichard Lowe  */
2110d63b7dSRichard Lowe /*
2210d63b7dSRichard Lowe  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2310d63b7dSRichard Lowe  * Use is subject to license terms.
2410d63b7dSRichard Lowe  */
2510d63b7dSRichard Lowe 
2610d63b7dSRichard Lowe 
2710d63b7dSRichard Lowe /*
2810d63b7dSRichard Lowe  *	macro.cc
2910d63b7dSRichard Lowe  *
3010d63b7dSRichard Lowe  *	Handle expansion of make macros
3110d63b7dSRichard Lowe  */
3210d63b7dSRichard Lowe 
3310d63b7dSRichard Lowe /*
3410d63b7dSRichard Lowe  * Included files
3510d63b7dSRichard Lowe  */
3610d63b7dSRichard Lowe #include <mksh/dosys.h>		/* sh_command2string() */
3710d63b7dSRichard Lowe #include <mksh/i18n.h>		/* get_char_semantics_value() */
3810d63b7dSRichard Lowe #include <mksh/macro.h>
3910d63b7dSRichard Lowe #include <mksh/misc.h>		/* retmem() */
4010d63b7dSRichard Lowe #include <mksh/read.h>		/* get_next_block_fn() */
4110d63b7dSRichard Lowe 
4210d63b7dSRichard Lowe #include <libintl.h>
4310d63b7dSRichard Lowe 
4410d63b7dSRichard Lowe /*
4510d63b7dSRichard Lowe  * File table of contents
4610d63b7dSRichard Lowe  */
4710d63b7dSRichard Lowe static void	add_macro_to_global_list(Name macro_to_add);
48*e7afc443SToomas Soome static void	expand_value_with_daemon(Name, Property macro, String destination, Boolean cmd);
4910d63b7dSRichard Lowe 
5010d63b7dSRichard Lowe static void	init_arch_macros(void);
5110d63b7dSRichard Lowe static void	init_mach_macros(void);
5210d63b7dSRichard Lowe static Boolean	init_arch_done = false;
5310d63b7dSRichard Lowe static Boolean	init_mach_done = false;
5410d63b7dSRichard Lowe 
5510d63b7dSRichard Lowe 
5610d63b7dSRichard Lowe long env_alloc_num = 0;
5710d63b7dSRichard Lowe long env_alloc_bytes = 0;
5810d63b7dSRichard Lowe 
5910d63b7dSRichard Lowe /*
6010d63b7dSRichard Lowe  *	getvar(name)
6110d63b7dSRichard Lowe  *
6210d63b7dSRichard Lowe  *	Return expanded value of macro.
6310d63b7dSRichard Lowe  *
6410d63b7dSRichard Lowe  *	Return value:
6510d63b7dSRichard Lowe  *				The expanded value of the macro
6610d63b7dSRichard Lowe  *
6710d63b7dSRichard Lowe  *	Parameters:
6810d63b7dSRichard Lowe  *		name		The name of the macro we want the value for
6910d63b7dSRichard Lowe  *
7010d63b7dSRichard Lowe  *	Global variables used:
7110d63b7dSRichard Lowe  */
7210d63b7dSRichard Lowe Name
getvar(Name name)73*e7afc443SToomas Soome getvar(Name name)
7410d63b7dSRichard Lowe {
7510d63b7dSRichard Lowe 	String_rec		destination;
7610d63b7dSRichard Lowe 	wchar_t			buffer[STRING_BUFFER_LENGTH];
77*e7afc443SToomas Soome 	Name		result;
7810d63b7dSRichard Lowe 
7910d63b7dSRichard Lowe 	if ((name == host_arch) || (name == target_arch)) {
8010d63b7dSRichard Lowe 		if (!init_arch_done) {
8110d63b7dSRichard Lowe 			init_arch_done = true;
8210d63b7dSRichard Lowe 			init_arch_macros();
8310d63b7dSRichard Lowe 		}
8410d63b7dSRichard Lowe 	}
8510d63b7dSRichard Lowe 	if ((name == host_mach) || (name == target_mach)) {
8610d63b7dSRichard Lowe 		if (!init_mach_done) {
8710d63b7dSRichard Lowe 			init_mach_done = true;
8810d63b7dSRichard Lowe 			init_mach_macros();
8910d63b7dSRichard Lowe 		}
9010d63b7dSRichard Lowe 	}
9110d63b7dSRichard Lowe 
9210d63b7dSRichard Lowe 	INIT_STRING_FROM_STACK(destination, buffer);
9310d63b7dSRichard Lowe 	expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
9410d63b7dSRichard Lowe 		     &destination,
9510d63b7dSRichard Lowe 		     false);
9610d63b7dSRichard Lowe 	result = GETNAME(destination.buffer.start, FIND_LENGTH);
9710d63b7dSRichard Lowe 	if (destination.free_after_use) {
9810d63b7dSRichard Lowe 		retmem(destination.buffer.start);
9910d63b7dSRichard Lowe 	}
10010d63b7dSRichard Lowe 	return result;
10110d63b7dSRichard Lowe }
10210d63b7dSRichard Lowe 
10310d63b7dSRichard Lowe /*
10410d63b7dSRichard Lowe  *	expand_value(value, destination, cmd)
10510d63b7dSRichard Lowe  *
10610d63b7dSRichard Lowe  *	Recursively expands all macros in the string value.
10710d63b7dSRichard Lowe  *	destination is where the expanded value should be appended.
10810d63b7dSRichard Lowe  *
10910d63b7dSRichard Lowe  *	Parameters:
11010d63b7dSRichard Lowe  *		value		The value we are expanding
11110d63b7dSRichard Lowe  *		destination	Where to deposit the expansion
11210d63b7dSRichard Lowe  *		cmd		If we are evaluating a command line we
11310d63b7dSRichard Lowe  *				turn \ quoting off
11410d63b7dSRichard Lowe  *
11510d63b7dSRichard Lowe  *	Global variables used:
11610d63b7dSRichard Lowe  */
11710d63b7dSRichard Lowe void
expand_value(Name value,String destination,Boolean cmd)118*e7afc443SToomas Soome expand_value(Name value, String destination, Boolean cmd)
11910d63b7dSRichard Lowe {
12010d63b7dSRichard Lowe 	Source_rec		sourceb;
121*e7afc443SToomas Soome 	Source		source = &sourceb;
122*e7afc443SToomas Soome 	wchar_t	*source_p = NULL;
123*e7afc443SToomas Soome 	wchar_t	*source_end = NULL;
12410d63b7dSRichard Lowe 	wchar_t			*block_start = NULL;
12510d63b7dSRichard Lowe 	int			quote_seen = 0;
12610d63b7dSRichard Lowe 
12710d63b7dSRichard Lowe 	if (value == NULL) {
12810d63b7dSRichard Lowe 		/*
12910d63b7dSRichard Lowe 		 * Make sure to get a string allocated even if it
13010d63b7dSRichard Lowe 		 * will be empty.
13110d63b7dSRichard Lowe 		 */
13210d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "");
13310d63b7dSRichard Lowe 		append_string(wcs_buffer, destination, FIND_LENGTH);
13410d63b7dSRichard Lowe 		destination->text.end = destination->text.p;
13510d63b7dSRichard Lowe 		return;
13610d63b7dSRichard Lowe 	}
13710d63b7dSRichard Lowe 	if (!value->dollar) {
13810d63b7dSRichard Lowe 		/*
13910d63b7dSRichard Lowe 		 * If the value we are expanding does not contain
14010d63b7dSRichard Lowe 		 * any $, we don't have to parse it.
14110d63b7dSRichard Lowe 		 */
14210d63b7dSRichard Lowe 		APPEND_NAME(value,
14310d63b7dSRichard Lowe 			destination,
14410d63b7dSRichard Lowe 			(int) value->hash.length
14510d63b7dSRichard Lowe 		);
14610d63b7dSRichard Lowe 		destination->text.end = destination->text.p;
14710d63b7dSRichard Lowe 		return;
14810d63b7dSRichard Lowe 	}
14910d63b7dSRichard Lowe 
15010d63b7dSRichard Lowe 	if (value->being_expanded) {
15110d63b7dSRichard Lowe 		fatal_reader_mksh(gettext("Loop detected when expanding macro value `%s'"),
15210d63b7dSRichard Lowe 			     value->string_mb);
15310d63b7dSRichard Lowe 	}
15410d63b7dSRichard Lowe 	value->being_expanded = true;
15510d63b7dSRichard Lowe 	/* Setup the structure we read from */
15610d63b7dSRichard Lowe 	Wstring vals(value);
15710d63b7dSRichard Lowe 	sourceb.string.text.p = sourceb.string.buffer.start = wcsdup(vals.get_string());
15810d63b7dSRichard Lowe 	sourceb.string.free_after_use = true;
15910d63b7dSRichard Lowe 	sourceb.string.text.end =
16010d63b7dSRichard Lowe 	  sourceb.string.buffer.end =
16110d63b7dSRichard Lowe 	    sourceb.string.text.p + value->hash.length;
16210d63b7dSRichard Lowe 	sourceb.previous = NULL;
16310d63b7dSRichard Lowe 	sourceb.fd = -1;
16410d63b7dSRichard Lowe 	sourceb.inp_buf =
16510d63b7dSRichard Lowe 	  sourceb.inp_buf_ptr =
16610d63b7dSRichard Lowe 	    sourceb.inp_buf_end = NULL;
16710d63b7dSRichard Lowe 	sourceb.error_converting = false;
16810d63b7dSRichard Lowe 	/* Lift some pointers from the struct to local register variables */
16910d63b7dSRichard Lowe 	CACHE_SOURCE(0);
17010d63b7dSRichard Lowe /* We parse the string in segments */
17110d63b7dSRichard Lowe /* We read chars until we find a $, then we append what we have read so far */
17210d63b7dSRichard Lowe /* (since last $ processing) to the destination. When we find a $ we call */
17310d63b7dSRichard Lowe /* expand_macro() and let it expand that particular $ reference into dest */
17410d63b7dSRichard Lowe 	block_start = source_p;
17510d63b7dSRichard Lowe 	quote_seen = 0;
17610d63b7dSRichard Lowe 	for (; 1; source_p++) {
17710d63b7dSRichard Lowe 		switch (GET_CHAR()) {
17810d63b7dSRichard Lowe 		case backslash_char:
17910d63b7dSRichard Lowe 			/* Quote $ in macro value */
18010d63b7dSRichard Lowe 			if (!cmd) {
18110d63b7dSRichard Lowe 				quote_seen = ~quote_seen;
18210d63b7dSRichard Lowe 			}
18310d63b7dSRichard Lowe 			continue;
18410d63b7dSRichard Lowe 		case dollar_char:
18510d63b7dSRichard Lowe 			/* Save the plain string we found since */
18610d63b7dSRichard Lowe 			/* start of string or previous $ */
18710d63b7dSRichard Lowe 			if (quote_seen) {
18810d63b7dSRichard Lowe 				append_string(block_start,
18910d63b7dSRichard Lowe 					      destination,
19010d63b7dSRichard Lowe 					      source_p - block_start - 1);
19110d63b7dSRichard Lowe 				block_start = source_p;
19210d63b7dSRichard Lowe 				break;
19310d63b7dSRichard Lowe 			}
19410d63b7dSRichard Lowe 			append_string(block_start,
19510d63b7dSRichard Lowe 				      destination,
19610d63b7dSRichard Lowe 				      source_p - block_start);
19710d63b7dSRichard Lowe 			source->string.text.p = ++source_p;
19810d63b7dSRichard Lowe 			UNCACHE_SOURCE();
19910d63b7dSRichard Lowe 			/* Go expand the macro reference */
20010d63b7dSRichard Lowe 			expand_macro(source, destination, sourceb.string.buffer.start, cmd);
20110d63b7dSRichard Lowe 			CACHE_SOURCE(1);
20210d63b7dSRichard Lowe 			block_start = source_p + 1;
20310d63b7dSRichard Lowe 			break;
20410d63b7dSRichard Lowe 		case nul_char:
20510d63b7dSRichard Lowe 			/* The string ran out. Get some more */
20610d63b7dSRichard Lowe 			append_string(block_start,
20710d63b7dSRichard Lowe 				      destination,
20810d63b7dSRichard Lowe 				      source_p - block_start);
20910d63b7dSRichard Lowe 			GET_NEXT_BLOCK_NOCHK(source);
21010d63b7dSRichard Lowe 			if (source == NULL) {
21110d63b7dSRichard Lowe 				destination->text.end = destination->text.p;
21210d63b7dSRichard Lowe 				value->being_expanded = false;
21310d63b7dSRichard Lowe 				return;
21410d63b7dSRichard Lowe 			}
21510d63b7dSRichard Lowe 			if (source->error_converting) {
21610d63b7dSRichard Lowe 				fatal_reader_mksh("Internal error: Invalid byte sequence in expand_value()");
21710d63b7dSRichard Lowe 			}
21810d63b7dSRichard Lowe 			block_start = source_p;
21910d63b7dSRichard Lowe 			source_p--;
22010d63b7dSRichard Lowe 			continue;
22110d63b7dSRichard Lowe 		}
22210d63b7dSRichard Lowe 		quote_seen = 0;
22310d63b7dSRichard Lowe 	}
22410d63b7dSRichard Lowe 	retmem(sourceb.string.buffer.start);
22510d63b7dSRichard Lowe }
22610d63b7dSRichard Lowe 
22710d63b7dSRichard Lowe /*
22810d63b7dSRichard Lowe  *	expand_macro(source, destination, current_string, cmd)
22910d63b7dSRichard Lowe  *
23010d63b7dSRichard Lowe  *	Should be called with source->string.text.p pointing to
23110d63b7dSRichard Lowe  *	the first char after the $ that starts a macro reference.
23210d63b7dSRichard Lowe  *	source->string.text.p is returned pointing to the first char after
23310d63b7dSRichard Lowe  *	the macro name.
23410d63b7dSRichard Lowe  *	It will read the macro name, expanding any macros in it,
23510d63b7dSRichard Lowe  *	and get the value. The value is then expanded.
23610d63b7dSRichard Lowe  *	destination is a String that is filled in with the expanded macro.
23710d63b7dSRichard Lowe  *	It may be passed in referencing a buffer to expand the macro into.
238*e7afc443SToomas Soome  *	Note that most expansions are done on demand, e.g. right
23910d63b7dSRichard Lowe  *	before the command is executed and not while the file is
240*e7afc443SToomas Soome  *	being parsed.
24110d63b7dSRichard Lowe  *
24210d63b7dSRichard Lowe  *	Parameters:
24310d63b7dSRichard Lowe  *		source		The source block that references the string
24410d63b7dSRichard Lowe  *				to expand
24510d63b7dSRichard Lowe  *		destination	Where to put the result
24610d63b7dSRichard Lowe  *		current_string	The string we are expanding, for error msg
24710d63b7dSRichard Lowe  *		cmd		If we are evaluating a command line we
24810d63b7dSRichard Lowe  *				turn \ quoting off
24910d63b7dSRichard Lowe  *
25010d63b7dSRichard Lowe  *	Global variables used:
25110d63b7dSRichard Lowe  *		funny		Vector of semantic tags for characters
25210d63b7dSRichard Lowe  *		is_conditional	Set if a conditional macro is refd
25310d63b7dSRichard Lowe  *		make_word_mentioned Set if the word "MAKE" is mentioned
25410d63b7dSRichard Lowe  *		makefile_type	We deliver extra msg when reading makefiles
25510d63b7dSRichard Lowe  *		query		The Name "?", compared against
25610d63b7dSRichard Lowe  *		query_mentioned	Set if the word "?" is mentioned
25710d63b7dSRichard Lowe  */
25810d63b7dSRichard Lowe void
expand_macro(Source source,String destination,wchar_t * current_string,Boolean cmd)259*e7afc443SToomas Soome expand_macro(Source source, String destination, wchar_t *current_string, Boolean cmd)
26010d63b7dSRichard Lowe {
26110d63b7dSRichard Lowe 	static Name		make = (Name)NULL;
26210d63b7dSRichard Lowe 	static wchar_t		colon_sh[4];
26310d63b7dSRichard Lowe 	static wchar_t		colon_shell[7];
26410d63b7dSRichard Lowe 	String_rec		string;
26510d63b7dSRichard Lowe 	wchar_t			buffer[STRING_BUFFER_LENGTH];
266*e7afc443SToomas Soome 	wchar_t	*source_p = source->string.text.p;
267*e7afc443SToomas Soome 	wchar_t	*source_end = source->string.text.end;
268*e7afc443SToomas Soome 	int		closer = 0;
26910d63b7dSRichard Lowe 	wchar_t			*block_start = (wchar_t *)NULL;
27010d63b7dSRichard Lowe 	int			quote_seen = 0;
271*e7afc443SToomas Soome 	int		closer_level = 1;
27210d63b7dSRichard Lowe 	Name			name = (Name)NULL;
27310d63b7dSRichard Lowe 	wchar_t			*colon = (wchar_t *)NULL;
27410d63b7dSRichard Lowe 	wchar_t			*percent = (wchar_t *)NULL;
27510d63b7dSRichard Lowe 	wchar_t			*eq = (wchar_t *) NULL;
27610d63b7dSRichard Lowe 	Property		macro = NULL;
27710d63b7dSRichard Lowe 	wchar_t			*p = (wchar_t*)NULL;
27810d63b7dSRichard Lowe 	String_rec		extracted;
27910d63b7dSRichard Lowe 	wchar_t			extracted_string[MAXPATHLEN];
28010d63b7dSRichard Lowe 	wchar_t			*left_head = NULL;
28110d63b7dSRichard Lowe 	wchar_t			*left_tail = NULL;
28210d63b7dSRichard Lowe 	wchar_t			*right_tail = NULL;
28310d63b7dSRichard Lowe 	int			left_head_len = 0;
28410d63b7dSRichard Lowe 	int			left_tail_len = 0;
28510d63b7dSRichard Lowe 	int			tmp_len = 0;
28610d63b7dSRichard Lowe 	wchar_t			*right_hand[128];
28710d63b7dSRichard Lowe 	int			i = 0;
28810d63b7dSRichard Lowe 	enum {
28910d63b7dSRichard Lowe 		no_extract,
29010d63b7dSRichard Lowe 		dir_extract,
29110d63b7dSRichard Lowe 		file_extract
29210d63b7dSRichard Lowe 	}                       extraction = no_extract;
29310d63b7dSRichard Lowe 	enum {
29410d63b7dSRichard Lowe 		no_replace,
29510d63b7dSRichard Lowe 		suffix_replace,
29610d63b7dSRichard Lowe 		pattern_replace,
29710d63b7dSRichard Lowe 		sh_replace
29810d63b7dSRichard Lowe 	}			replacement = no_replace;
29910d63b7dSRichard Lowe 
30010d63b7dSRichard Lowe 	if (make == NULL) {
30110d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "MAKE");
30210d63b7dSRichard Lowe 		make = GETNAME(wcs_buffer, FIND_LENGTH);
30310d63b7dSRichard Lowe 
30410d63b7dSRichard Lowe 		MBSTOWCS(colon_sh, ":sh");
30510d63b7dSRichard Lowe 		MBSTOWCS(colon_shell, ":shell");
30610d63b7dSRichard Lowe 	}
30710d63b7dSRichard Lowe 
30810d63b7dSRichard Lowe 	right_hand[0] = NULL;
30910d63b7dSRichard Lowe 
31010d63b7dSRichard Lowe 	/* First copy the (macro-expanded) macro name into string. */
31110d63b7dSRichard Lowe 	INIT_STRING_FROM_STACK(string, buffer);
31210d63b7dSRichard Lowe recheck_first_char:
31310d63b7dSRichard Lowe 	/* Check the first char of the macro name to figure out what to do. */
31410d63b7dSRichard Lowe 	switch (GET_CHAR()) {
31510d63b7dSRichard Lowe 	case nul_char:
31610d63b7dSRichard Lowe 		GET_NEXT_BLOCK_NOCHK(source);
31710d63b7dSRichard Lowe 		if (source == NULL) {
31810d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, current_string);
31910d63b7dSRichard Lowe 			fatal_reader_mksh(gettext("'$' at end of string `%s'"),
32010d63b7dSRichard Lowe 				     mbs_buffer);
32110d63b7dSRichard Lowe 		}
32210d63b7dSRichard Lowe 		if (source->error_converting) {
32310d63b7dSRichard Lowe 			fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
32410d63b7dSRichard Lowe 		}
32510d63b7dSRichard Lowe 		goto recheck_first_char;
32610d63b7dSRichard Lowe 	case parenleft_char:
32710d63b7dSRichard Lowe 		/* Multi char name. */
32810d63b7dSRichard Lowe 		closer = (int) parenright_char;
32910d63b7dSRichard Lowe 		break;
33010d63b7dSRichard Lowe 	case braceleft_char:
33110d63b7dSRichard Lowe 		/* Multi char name. */
33210d63b7dSRichard Lowe 		closer = (int) braceright_char;
33310d63b7dSRichard Lowe 		break;
33410d63b7dSRichard Lowe 	case newline_char:
33510d63b7dSRichard Lowe 		fatal_reader_mksh(gettext("'$' at end of line"));
33610d63b7dSRichard Lowe 	default:
33710d63b7dSRichard Lowe 		/* Single char macro name. Just suck it up */
33810d63b7dSRichard Lowe 		append_char(*source_p, &string);
33910d63b7dSRichard Lowe 		source->string.text.p = source_p + 1;
34010d63b7dSRichard Lowe 		goto get_macro_value;
34110d63b7dSRichard Lowe 	}
34210d63b7dSRichard Lowe 
34310d63b7dSRichard Lowe 	/* Handle multi-char macro names */
34410d63b7dSRichard Lowe 	block_start = ++source_p;
34510d63b7dSRichard Lowe 	quote_seen = 0;
34610d63b7dSRichard Lowe 	for (; 1; source_p++) {
34710d63b7dSRichard Lowe 		switch (GET_CHAR()) {
34810d63b7dSRichard Lowe 		case nul_char:
34910d63b7dSRichard Lowe 			append_string(block_start,
35010d63b7dSRichard Lowe 				      &string,
35110d63b7dSRichard Lowe 				      source_p - block_start);
35210d63b7dSRichard Lowe 			GET_NEXT_BLOCK_NOCHK(source);
35310d63b7dSRichard Lowe 			if (source == NULL) {
35410d63b7dSRichard Lowe 				if (current_string != NULL) {
35510d63b7dSRichard Lowe 					WCSTOMBS(mbs_buffer, current_string);
35610d63b7dSRichard Lowe 					fatal_reader_mksh(gettext("Unmatched `%c' in string `%s'"),
35710d63b7dSRichard Lowe 						     closer ==
35810d63b7dSRichard Lowe 						     (int) braceright_char ?
35910d63b7dSRichard Lowe 						     (int) braceleft_char :
36010d63b7dSRichard Lowe 						     (int) parenleft_char,
36110d63b7dSRichard Lowe 						     mbs_buffer);
36210d63b7dSRichard Lowe 				} else {
36310d63b7dSRichard Lowe 					fatal_reader_mksh(gettext("Premature EOF"));
36410d63b7dSRichard Lowe 				}
36510d63b7dSRichard Lowe 			}
36610d63b7dSRichard Lowe 			if (source->error_converting) {
36710d63b7dSRichard Lowe 				fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
36810d63b7dSRichard Lowe 			}
36910d63b7dSRichard Lowe 			block_start = source_p;
37010d63b7dSRichard Lowe 			source_p--;
37110d63b7dSRichard Lowe 			continue;
37210d63b7dSRichard Lowe 		case newline_char:
37310d63b7dSRichard Lowe 			fatal_reader_mksh(gettext("Unmatched `%c' on line"),
37410d63b7dSRichard Lowe 				     closer == (int) braceright_char ?
37510d63b7dSRichard Lowe 				     (int) braceleft_char :
37610d63b7dSRichard Lowe 				     (int) parenleft_char);
37710d63b7dSRichard Lowe 		case backslash_char:
37810d63b7dSRichard Lowe 			/* Quote dollar in macro value. */
37910d63b7dSRichard Lowe 			if (!cmd) {
38010d63b7dSRichard Lowe 				quote_seen = ~quote_seen;
38110d63b7dSRichard Lowe 			}
38210d63b7dSRichard Lowe 			continue;
38310d63b7dSRichard Lowe 		case dollar_char:
38410d63b7dSRichard Lowe 			/*
38510d63b7dSRichard Lowe 			 * Macro names may reference macros.
38610d63b7dSRichard Lowe 			 * This expands the value of such macros into the
38710d63b7dSRichard Lowe 			 * macro name string.
38810d63b7dSRichard Lowe 			 */
38910d63b7dSRichard Lowe 			if (quote_seen) {
39010d63b7dSRichard Lowe 				append_string(block_start,
39110d63b7dSRichard Lowe 					      &string,
39210d63b7dSRichard Lowe 					      source_p - block_start - 1);
39310d63b7dSRichard Lowe 				block_start = source_p;
39410d63b7dSRichard Lowe 				break;
39510d63b7dSRichard Lowe 			}
39610d63b7dSRichard Lowe 			append_string(block_start,
39710d63b7dSRichard Lowe 				      &string,
39810d63b7dSRichard Lowe 				      source_p - block_start);
39910d63b7dSRichard Lowe 			source->string.text.p = ++source_p;
40010d63b7dSRichard Lowe 			UNCACHE_SOURCE();
40110d63b7dSRichard Lowe 			expand_macro(source, &string, current_string, cmd);
40210d63b7dSRichard Lowe 			CACHE_SOURCE(0);
40310d63b7dSRichard Lowe 			block_start = source_p;
40410d63b7dSRichard Lowe 			source_p--;
40510d63b7dSRichard Lowe 			break;
40610d63b7dSRichard Lowe 		case parenleft_char:
40710d63b7dSRichard Lowe 			/* Allow nested pairs of () in the macro name. */
40810d63b7dSRichard Lowe 			if (closer == (int) parenright_char) {
40910d63b7dSRichard Lowe 				closer_level++;
41010d63b7dSRichard Lowe 			}
41110d63b7dSRichard Lowe 			break;
41210d63b7dSRichard Lowe 		case braceleft_char:
41310d63b7dSRichard Lowe 			/* Allow nested pairs of {} in the macro name. */
41410d63b7dSRichard Lowe 			if (closer == (int) braceright_char) {
41510d63b7dSRichard Lowe 				closer_level++;
41610d63b7dSRichard Lowe 			}
41710d63b7dSRichard Lowe 			break;
41810d63b7dSRichard Lowe 		case parenright_char:
41910d63b7dSRichard Lowe 		case braceright_char:
42010d63b7dSRichard Lowe 			/*
42110d63b7dSRichard Lowe 			 * End of the name. Save the string in the macro
42210d63b7dSRichard Lowe 			 * name string.
42310d63b7dSRichard Lowe 			 */
42410d63b7dSRichard Lowe 			if ((*source_p == closer) && (--closer_level <= 0)) {
42510d63b7dSRichard Lowe 				source->string.text.p = source_p + 1;
42610d63b7dSRichard Lowe 				append_string(block_start,
42710d63b7dSRichard Lowe 					      &string,
42810d63b7dSRichard Lowe 					      source_p - block_start);
42910d63b7dSRichard Lowe 				goto get_macro_value;
43010d63b7dSRichard Lowe 			}
43110d63b7dSRichard Lowe 			break;
43210d63b7dSRichard Lowe 		}
43310d63b7dSRichard Lowe 		quote_seen = 0;
43410d63b7dSRichard Lowe 	}
43510d63b7dSRichard Lowe 	/*
43610d63b7dSRichard Lowe 	 * We got the macro name. We now inspect it to see if it
43710d63b7dSRichard Lowe 	 * specifies any translations of the value.
43810d63b7dSRichard Lowe 	 */
43910d63b7dSRichard Lowe get_macro_value:
44010d63b7dSRichard Lowe 	name = NULL;
44110d63b7dSRichard Lowe 	/* First check if we have a $(@D) type translation. */
44210d63b7dSRichard Lowe 	if ((get_char_semantics_value(string.buffer.start[0]) &
44310d63b7dSRichard Lowe 	     (int) special_macro_sem) &&
44410d63b7dSRichard Lowe 	    (string.text.p - string.buffer.start >= 2) &&
44510d63b7dSRichard Lowe 	    ((string.buffer.start[1] == 'D') ||
44610d63b7dSRichard Lowe 	     (string.buffer.start[1] == 'F'))) {
44710d63b7dSRichard Lowe 		switch (string.buffer.start[1]) {
44810d63b7dSRichard Lowe 		case 'D':
44910d63b7dSRichard Lowe 			extraction = dir_extract;
45010d63b7dSRichard Lowe 			break;
45110d63b7dSRichard Lowe 		case 'F':
45210d63b7dSRichard Lowe 			extraction = file_extract;
45310d63b7dSRichard Lowe 			break;
45410d63b7dSRichard Lowe 		default:
45510d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, string.buffer.start);
45610d63b7dSRichard Lowe 			fatal_reader_mksh(gettext("Illegal macro reference `%s'"),
45710d63b7dSRichard Lowe 				     mbs_buffer);
45810d63b7dSRichard Lowe 		}
45910d63b7dSRichard Lowe 		/* Internalize the macro name using the first char only. */
46010d63b7dSRichard Lowe 		name = GETNAME(string.buffer.start, 1);
46110d63b7dSRichard Lowe 		(void) wcscpy(string.buffer.start, string.buffer.start + 2);
46210d63b7dSRichard Lowe 	}
46310d63b7dSRichard Lowe 	/* Check for other kinds of translations. */
46410d63b7dSRichard Lowe 	if ((colon = (wchar_t *) wcschr(string.buffer.start,
46510d63b7dSRichard Lowe 				       (int) colon_char)) != NULL) {
46610d63b7dSRichard Lowe 		/*
46710d63b7dSRichard Lowe 		 * We have a $(FOO:.c=.o) type translation.
46810d63b7dSRichard Lowe 		 * Get the name of the macro proper.
46910d63b7dSRichard Lowe 		 */
47010d63b7dSRichard Lowe 		if (name == NULL) {
47110d63b7dSRichard Lowe 			name = GETNAME(string.buffer.start,
47210d63b7dSRichard Lowe 				       colon - string.buffer.start);
47310d63b7dSRichard Lowe 		}
47410d63b7dSRichard Lowe 		/* Pickup all the translations. */
47510d63b7dSRichard Lowe 		if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
47610d63b7dSRichard Lowe 			replacement = sh_replace;
47710d63b7dSRichard Lowe 		} else if ((svr4) ||
47810d63b7dSRichard Lowe 		           ((percent = (wchar_t *) wcschr(colon + 1,
47910d63b7dSRichard Lowe 							 (int) percent_char)) == NULL)) {
48010d63b7dSRichard Lowe 			while (colon != NULL) {
48110d63b7dSRichard Lowe 				if ((eq = (wchar_t *) wcschr(colon + 1,
48210d63b7dSRichard Lowe 							    (int) equal_char)) == NULL) {
48310d63b7dSRichard Lowe 					fatal_reader_mksh(gettext("= missing from replacement macro reference"));
48410d63b7dSRichard Lowe 				}
48510d63b7dSRichard Lowe 				left_tail_len = eq - colon - 1;
48610d63b7dSRichard Lowe 				if(left_tail) {
48710d63b7dSRichard Lowe 					retmem(left_tail);
48810d63b7dSRichard Lowe 				}
48910d63b7dSRichard Lowe 				left_tail = ALLOC_WC(left_tail_len + 1);
49010d63b7dSRichard Lowe 				(void) wcsncpy(left_tail,
49110d63b7dSRichard Lowe 					      colon + 1,
49210d63b7dSRichard Lowe 					      eq - colon - 1);
49310d63b7dSRichard Lowe 				left_tail[eq - colon - 1] = (int) nul_char;
49410d63b7dSRichard Lowe 				replacement = suffix_replace;
49510d63b7dSRichard Lowe 				if ((colon = (wchar_t *) wcschr(eq + 1,
49610d63b7dSRichard Lowe 							       (int) colon_char)) != NULL) {
49710d63b7dSRichard Lowe 					tmp_len = colon - eq;
49810d63b7dSRichard Lowe 					if(right_tail) {
49910d63b7dSRichard Lowe 						retmem(right_tail);
50010d63b7dSRichard Lowe 					}
50110d63b7dSRichard Lowe 					right_tail = ALLOC_WC(tmp_len);
50210d63b7dSRichard Lowe 					(void) wcsncpy(right_tail,
50310d63b7dSRichard Lowe 						      eq + 1,
50410d63b7dSRichard Lowe 						      colon - eq - 1);
50510d63b7dSRichard Lowe 					right_tail[colon - eq - 1] =
50610d63b7dSRichard Lowe 					  (int) nul_char;
50710d63b7dSRichard Lowe 				} else {
50810d63b7dSRichard Lowe 					if(right_tail) {
50910d63b7dSRichard Lowe 						retmem(right_tail);
51010d63b7dSRichard Lowe 					}
51110d63b7dSRichard Lowe 					right_tail = ALLOC_WC(wcslen(eq) + 1);
51210d63b7dSRichard Lowe 					(void) wcscpy(right_tail, eq + 1);
51310d63b7dSRichard Lowe 				}
51410d63b7dSRichard Lowe 			}
51510d63b7dSRichard Lowe 		} else {
51610d63b7dSRichard Lowe 			if ((eq = (wchar_t *) wcschr(colon + 1,
51710d63b7dSRichard Lowe 						    (int) equal_char)) == NULL) {
51810d63b7dSRichard Lowe 				fatal_reader_mksh(gettext("= missing from replacement macro reference"));
51910d63b7dSRichard Lowe 			}
52010d63b7dSRichard Lowe 			if ((percent = (wchar_t *) wcschr(colon + 1,
52110d63b7dSRichard Lowe 							 (int) percent_char)) == NULL) {
52210d63b7dSRichard Lowe 				fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
52310d63b7dSRichard Lowe 			}
52410d63b7dSRichard Lowe 			if (eq < percent) {
52510d63b7dSRichard Lowe 				fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
52610d63b7dSRichard Lowe 			}
52710d63b7dSRichard Lowe 
52810d63b7dSRichard Lowe 			if (percent > (colon + 1)) {
52910d63b7dSRichard Lowe 				tmp_len = percent - colon;
53010d63b7dSRichard Lowe 				if(left_head) {
53110d63b7dSRichard Lowe 					retmem(left_head);
53210d63b7dSRichard Lowe 				}
53310d63b7dSRichard Lowe 				left_head = ALLOC_WC(tmp_len);
53410d63b7dSRichard Lowe 				(void) wcsncpy(left_head,
53510d63b7dSRichard Lowe 					      colon + 1,
53610d63b7dSRichard Lowe 					      percent - colon - 1);
53710d63b7dSRichard Lowe 				left_head[percent-colon-1] = (int) nul_char;
53810d63b7dSRichard Lowe 				left_head_len = percent-colon-1;
53910d63b7dSRichard Lowe 			} else {
54010d63b7dSRichard Lowe 				left_head = NULL;
54110d63b7dSRichard Lowe 				left_head_len = 0;
54210d63b7dSRichard Lowe 			}
54310d63b7dSRichard Lowe 
54410d63b7dSRichard Lowe 			if (eq > percent+1) {
54510d63b7dSRichard Lowe 				tmp_len = eq - percent;
54610d63b7dSRichard Lowe 				if(left_tail) {
54710d63b7dSRichard Lowe 					retmem(left_tail);
54810d63b7dSRichard Lowe 				}
54910d63b7dSRichard Lowe 				left_tail = ALLOC_WC(tmp_len);
55010d63b7dSRichard Lowe 				(void) wcsncpy(left_tail,
55110d63b7dSRichard Lowe 					      percent + 1,
55210d63b7dSRichard Lowe 					      eq - percent - 1);
55310d63b7dSRichard Lowe 				left_tail[eq-percent-1] = (int) nul_char;
55410d63b7dSRichard Lowe 				left_tail_len = eq-percent-1;
55510d63b7dSRichard Lowe 			} else {
55610d63b7dSRichard Lowe 				left_tail = NULL;
55710d63b7dSRichard Lowe 				left_tail_len = 0;
55810d63b7dSRichard Lowe 			}
55910d63b7dSRichard Lowe 
56010d63b7dSRichard Lowe 			if ((percent = (wchar_t *) wcschr(++eq,
56110d63b7dSRichard Lowe 							 (int) percent_char)) == NULL) {
56210d63b7dSRichard Lowe 
56310d63b7dSRichard Lowe 				right_hand[0] = ALLOC_WC(wcslen(eq) + 1);
56410d63b7dSRichard Lowe 				right_hand[1] = NULL;
56510d63b7dSRichard Lowe 				(void) wcscpy(right_hand[0], eq);
56610d63b7dSRichard Lowe 			} else {
56710d63b7dSRichard Lowe 				i = 0;
56810d63b7dSRichard Lowe 				do {
56910d63b7dSRichard Lowe 					right_hand[i] = ALLOC_WC(percent-eq+1);
57010d63b7dSRichard Lowe 					(void) wcsncpy(right_hand[i],
57110d63b7dSRichard Lowe 						      eq,
57210d63b7dSRichard Lowe 						      percent - eq);
57310d63b7dSRichard Lowe 					right_hand[i][percent-eq] =
57410d63b7dSRichard Lowe 					  (int) nul_char;
57510d63b7dSRichard Lowe 					if (i++ >= VSIZEOF(right_hand)) {
57610d63b7dSRichard Lowe 						fatal_mksh(gettext("Too many %% in pattern"));
57710d63b7dSRichard Lowe 					}
57810d63b7dSRichard Lowe 					eq = percent + 1;
57910d63b7dSRichard Lowe 					if (eq[0] == (int) nul_char) {
58010d63b7dSRichard Lowe 						MBSTOWCS(wcs_buffer, "");
58110d63b7dSRichard Lowe 						right_hand[i] = (wchar_t *) wcsdup(wcs_buffer);
58210d63b7dSRichard Lowe 						i++;
58310d63b7dSRichard Lowe 						break;
58410d63b7dSRichard Lowe 					}
58510d63b7dSRichard Lowe 				} while ((percent = (wchar_t *) wcschr(eq, (int) percent_char)) != NULL);
58610d63b7dSRichard Lowe 				if (eq[0] != (int) nul_char) {
58710d63b7dSRichard Lowe 					right_hand[i] = ALLOC_WC(wcslen(eq) + 1);
58810d63b7dSRichard Lowe 					(void) wcscpy(right_hand[i], eq);
58910d63b7dSRichard Lowe 					i++;
59010d63b7dSRichard Lowe 				}
59110d63b7dSRichard Lowe 				right_hand[i] = NULL;
59210d63b7dSRichard Lowe 			}
59310d63b7dSRichard Lowe 			replacement = pattern_replace;
59410d63b7dSRichard Lowe 		}
59510d63b7dSRichard Lowe 	}
59610d63b7dSRichard Lowe 	if (name == NULL) {
59710d63b7dSRichard Lowe 		/*
59810d63b7dSRichard Lowe 		 * No translations found.
59910d63b7dSRichard Lowe 		 * Use the whole string as the macro name.
60010d63b7dSRichard Lowe 		 */
60110d63b7dSRichard Lowe 		name = GETNAME(string.buffer.start,
60210d63b7dSRichard Lowe 			       string.text.p - string.buffer.start);
60310d63b7dSRichard Lowe 	}
60410d63b7dSRichard Lowe 	if (string.free_after_use) {
60510d63b7dSRichard Lowe 		retmem(string.buffer.start);
60610d63b7dSRichard Lowe 	}
60710d63b7dSRichard Lowe 	if (name == make) {
60810d63b7dSRichard Lowe 		make_word_mentioned = true;
60910d63b7dSRichard Lowe 	}
61010d63b7dSRichard Lowe 	if (name == query) {
61110d63b7dSRichard Lowe 		query_mentioned = true;
61210d63b7dSRichard Lowe 	}
61310d63b7dSRichard Lowe 	if ((name == host_arch) || (name == target_arch)) {
61410d63b7dSRichard Lowe 		if (!init_arch_done) {
61510d63b7dSRichard Lowe 			init_arch_done = true;
61610d63b7dSRichard Lowe 			init_arch_macros();
61710d63b7dSRichard Lowe 		}
61810d63b7dSRichard Lowe 	}
61910d63b7dSRichard Lowe 	if ((name == host_mach) || (name == target_mach)) {
62010d63b7dSRichard Lowe 		if (!init_mach_done) {
62110d63b7dSRichard Lowe 			init_mach_done = true;
62210d63b7dSRichard Lowe 			init_mach_macros();
62310d63b7dSRichard Lowe 		}
62410d63b7dSRichard Lowe 	}
62510d63b7dSRichard Lowe 	/* Get the macro value. */
62610d63b7dSRichard Lowe 	macro = get_prop(name->prop, macro_prop);
62710d63b7dSRichard Lowe 	if ((macro != NULL) && macro->body.macro.is_conditional) {
62810d63b7dSRichard Lowe 		conditional_macro_used = true;
62910d63b7dSRichard Lowe 		/*
63010d63b7dSRichard Lowe 		 * Add this conditional macro to the beginning of the
63110d63b7dSRichard Lowe 		 * global list.
63210d63b7dSRichard Lowe 		 */
63310d63b7dSRichard Lowe 		add_macro_to_global_list(name);
63410d63b7dSRichard Lowe 		if (makefile_type == reading_makefile) {
63510d63b7dSRichard Lowe 			warning_mksh(gettext("Conditional macro `%s' referenced in file `%ws', line %d"),
63610d63b7dSRichard Lowe 					name->string_mb, file_being_read, line_number);
63710d63b7dSRichard Lowe 		}
63810d63b7dSRichard Lowe 	}
63910d63b7dSRichard Lowe 	/* Macro name read and parsed. Expand the value. */
64010d63b7dSRichard Lowe 	if ((macro == NULL) || (macro->body.macro.value == NULL)) {
64110d63b7dSRichard Lowe 		/* If the value is empty, we just get out of here. */
64210d63b7dSRichard Lowe 		goto exit;
64310d63b7dSRichard Lowe 	}
64410d63b7dSRichard Lowe 	if (replacement == sh_replace) {
64510d63b7dSRichard Lowe 		/* If we should do a :sh transform, we expand the command
64610d63b7dSRichard Lowe 		 * and process it.
64710d63b7dSRichard Lowe 		 */
64810d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(string, buffer);
64910d63b7dSRichard Lowe 		/* Expand the value into a local string buffer and run cmd. */
65010d63b7dSRichard Lowe 		expand_value_with_daemon(name, macro, &string, cmd);
65110d63b7dSRichard Lowe 		sh_command2string(&string, destination);
65210d63b7dSRichard Lowe 	} else if ((replacement != no_replace) || (extraction != no_extract)) {
65310d63b7dSRichard Lowe 		/*
65410d63b7dSRichard Lowe 		 * If there were any transforms specified in the macro
65510d63b7dSRichard Lowe 		 * name, we deal with them here.
65610d63b7dSRichard Lowe 		 */
65710d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(string, buffer);
65810d63b7dSRichard Lowe 		/* Expand the value into a local string buffer. */
65910d63b7dSRichard Lowe 		expand_value_with_daemon(name, macro, &string, cmd);
66010d63b7dSRichard Lowe 		/* Scan the expanded string. */
66110d63b7dSRichard Lowe 		p = string.buffer.start;
66210d63b7dSRichard Lowe 		while (*p != (int) nul_char) {
66310d63b7dSRichard Lowe 			wchar_t		chr;
66410d63b7dSRichard Lowe 
66510d63b7dSRichard Lowe 			/*
66610d63b7dSRichard Lowe 			 * First skip over any white space and append
66710d63b7dSRichard Lowe 			 * that to the destination string.
66810d63b7dSRichard Lowe 			 */
66910d63b7dSRichard Lowe 			block_start = p;
67010d63b7dSRichard Lowe 			while ((*p != (int) nul_char) && iswspace(*p)) {
67110d63b7dSRichard Lowe 				p++;
67210d63b7dSRichard Lowe 			}
67310d63b7dSRichard Lowe 			append_string(block_start,
67410d63b7dSRichard Lowe 				      destination,
67510d63b7dSRichard Lowe 				      p - block_start);
67610d63b7dSRichard Lowe 			/* Then find the end of the next word. */
67710d63b7dSRichard Lowe 			block_start = p;
67810d63b7dSRichard Lowe 			while ((*p != (int) nul_char) && !iswspace(*p)) {
67910d63b7dSRichard Lowe 				p++;
68010d63b7dSRichard Lowe 			}
68110d63b7dSRichard Lowe 			/* If we cant find another word we are done */
68210d63b7dSRichard Lowe 			if (block_start == p) {
68310d63b7dSRichard Lowe 				break;
68410d63b7dSRichard Lowe 			}
68510d63b7dSRichard Lowe 			/* Then apply the transforms to the word */
68610d63b7dSRichard Lowe 			INIT_STRING_FROM_STACK(extracted, extracted_string);
68710d63b7dSRichard Lowe 			switch (extraction) {
68810d63b7dSRichard Lowe 			case dir_extract:
68910d63b7dSRichard Lowe 				/*
69010d63b7dSRichard Lowe 				 * $(@D) type transform. Extract the
69110d63b7dSRichard Lowe 				 * path from the word. Deliver "." if
69210d63b7dSRichard Lowe 				 * none is found.
69310d63b7dSRichard Lowe 				 */
69410d63b7dSRichard Lowe 				if (p != NULL) {
69510d63b7dSRichard Lowe 					chr = *p;
69610d63b7dSRichard Lowe 					*p = (int) nul_char;
69710d63b7dSRichard Lowe 				}
69810d63b7dSRichard Lowe 				eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
69910d63b7dSRichard Lowe 				if (p != NULL) {
70010d63b7dSRichard Lowe 					*p = chr;
70110d63b7dSRichard Lowe 				}
70210d63b7dSRichard Lowe 				if ((eq == NULL) || (eq > p)) {
70310d63b7dSRichard Lowe 					MBSTOWCS(wcs_buffer, ".");
70410d63b7dSRichard Lowe 					append_string(wcs_buffer, &extracted, 1);
70510d63b7dSRichard Lowe 				} else {
70610d63b7dSRichard Lowe 					append_string(block_start,
70710d63b7dSRichard Lowe 						      &extracted,
70810d63b7dSRichard Lowe 						      eq - block_start);
70910d63b7dSRichard Lowe 				}
71010d63b7dSRichard Lowe 				break;
71110d63b7dSRichard Lowe 			case file_extract:
71210d63b7dSRichard Lowe 				/*
71310d63b7dSRichard Lowe 				 * $(@F) type transform. Remove the path
71410d63b7dSRichard Lowe 				 * from the word if any.
71510d63b7dSRichard Lowe 				 */
71610d63b7dSRichard Lowe 				if (p != NULL) {
71710d63b7dSRichard Lowe 					chr = *p;
71810d63b7dSRichard Lowe 					*p = (int) nul_char;
71910d63b7dSRichard Lowe 				}
72010d63b7dSRichard Lowe 				eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
72110d63b7dSRichard Lowe 				if (p != NULL) {
72210d63b7dSRichard Lowe 					*p = chr;
72310d63b7dSRichard Lowe 				}
72410d63b7dSRichard Lowe 				if ((eq == NULL) || (eq > p)) {
72510d63b7dSRichard Lowe 					append_string(block_start,
72610d63b7dSRichard Lowe 						      &extracted,
72710d63b7dSRichard Lowe 						      p - block_start);
72810d63b7dSRichard Lowe 				} else {
72910d63b7dSRichard Lowe 					append_string(eq + 1,
73010d63b7dSRichard Lowe 						      &extracted,
73110d63b7dSRichard Lowe 						      p - eq - 1);
73210d63b7dSRichard Lowe 				}
73310d63b7dSRichard Lowe 				break;
73410d63b7dSRichard Lowe 			case no_extract:
73510d63b7dSRichard Lowe 				append_string(block_start,
73610d63b7dSRichard Lowe 					      &extracted,
73710d63b7dSRichard Lowe 					      p - block_start);
73810d63b7dSRichard Lowe 				break;
73910d63b7dSRichard Lowe 			}
74010d63b7dSRichard Lowe 			switch (replacement) {
74110d63b7dSRichard Lowe 			case suffix_replace:
74210d63b7dSRichard Lowe 				/*
74310d63b7dSRichard Lowe 				 * $(FOO:.o=.c) type transform.
74410d63b7dSRichard Lowe 				 * Maybe replace the tail of the word.
74510d63b7dSRichard Lowe 				 */
74610d63b7dSRichard Lowe 				if (((extracted.text.p -
74710d63b7dSRichard Lowe 				      extracted.buffer.start) >=
74810d63b7dSRichard Lowe 				     left_tail_len) &&
74910d63b7dSRichard Lowe 				    IS_WEQUALN(extracted.text.p - left_tail_len,
75010d63b7dSRichard Lowe 					      left_tail,
75110d63b7dSRichard Lowe 					      left_tail_len)) {
75210d63b7dSRichard Lowe 					append_string(extracted.buffer.start,
75310d63b7dSRichard Lowe 						      destination,
75410d63b7dSRichard Lowe 						      (extracted.text.p -
75510d63b7dSRichard Lowe 						       extracted.buffer.start)
75610d63b7dSRichard Lowe 						      - left_tail_len);
75710d63b7dSRichard Lowe 					append_string(right_tail,
75810d63b7dSRichard Lowe 						      destination,
75910d63b7dSRichard Lowe 						      FIND_LENGTH);
76010d63b7dSRichard Lowe 				} else {
76110d63b7dSRichard Lowe 					append_string(extracted.buffer.start,
76210d63b7dSRichard Lowe 						      destination,
76310d63b7dSRichard Lowe 						      FIND_LENGTH);
76410d63b7dSRichard Lowe 				}
76510d63b7dSRichard Lowe 				break;
76610d63b7dSRichard Lowe 			case pattern_replace:
76710d63b7dSRichard Lowe 				/* $(X:a%b=c%d) type transform. */
76810d63b7dSRichard Lowe 				if (((extracted.text.p -
76910d63b7dSRichard Lowe 				      extracted.buffer.start) >=
77010d63b7dSRichard Lowe 				     left_head_len+left_tail_len) &&
77110d63b7dSRichard Lowe 				    IS_WEQUALN(left_head,
77210d63b7dSRichard Lowe 					      extracted.buffer.start,
77310d63b7dSRichard Lowe 					      left_head_len) &&
77410d63b7dSRichard Lowe 				    IS_WEQUALN(left_tail,
77510d63b7dSRichard Lowe 					      extracted.text.p - left_tail_len,
77610d63b7dSRichard Lowe 					      left_tail_len)) {
77710d63b7dSRichard Lowe 					i = 0;
77810d63b7dSRichard Lowe 					while (right_hand[i] != NULL) {
77910d63b7dSRichard Lowe 						append_string(right_hand[i],
78010d63b7dSRichard Lowe 							      destination,
78110d63b7dSRichard Lowe 							      FIND_LENGTH);
78210d63b7dSRichard Lowe 						i++;
78310d63b7dSRichard Lowe 						if (right_hand[i] != NULL) {
78410d63b7dSRichard Lowe 							append_string(extracted.buffer.
78510d63b7dSRichard Lowe 								      start +
78610d63b7dSRichard Lowe 								      left_head_len,
78710d63b7dSRichard Lowe 								      destination,
78810d63b7dSRichard Lowe 								      (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
78910d63b7dSRichard Lowe 						}
79010d63b7dSRichard Lowe 					}
79110d63b7dSRichard Lowe 				} else {
79210d63b7dSRichard Lowe 					append_string(extracted.buffer.start,
79310d63b7dSRichard Lowe 						      destination,
79410d63b7dSRichard Lowe 						      FIND_LENGTH);
79510d63b7dSRichard Lowe 				}
79610d63b7dSRichard Lowe 				break;
79710d63b7dSRichard Lowe 			case no_replace:
79810d63b7dSRichard Lowe 				append_string(extracted.buffer.start,
79910d63b7dSRichard Lowe 					      destination,
80010d63b7dSRichard Lowe 					      FIND_LENGTH);
80110d63b7dSRichard Lowe 				break;
80210d63b7dSRichard Lowe 			case sh_replace:
80310d63b7dSRichard Lowe 				break;
80410d63b7dSRichard Lowe 			    }
80510d63b7dSRichard Lowe 		}
80610d63b7dSRichard Lowe 		if (string.free_after_use) {
80710d63b7dSRichard Lowe 			retmem(string.buffer.start);
80810d63b7dSRichard Lowe 		}
80910d63b7dSRichard Lowe 	} else {
81010d63b7dSRichard Lowe 		/*
81110d63b7dSRichard Lowe 		 * This is for the case when the macro name did not
81210d63b7dSRichard Lowe 		 * specify transforms.
81310d63b7dSRichard Lowe 		 */
81410d63b7dSRichard Lowe 		if (!strncmp(name->string_mb, "GET", 3)) {
81510d63b7dSRichard Lowe 			dollarget_seen = true;
81610d63b7dSRichard Lowe 		}
81710d63b7dSRichard Lowe 		dollarless_flag = false;
81810d63b7dSRichard Lowe 		if (!strncmp(name->string_mb, "<", 1) &&
81910d63b7dSRichard Lowe 		    dollarget_seen) {
82010d63b7dSRichard Lowe 			dollarless_flag = true;
82110d63b7dSRichard Lowe 			dollarget_seen = false;
82210d63b7dSRichard Lowe 		}
82310d63b7dSRichard Lowe 		expand_value_with_daemon(name, macro, destination, cmd);
82410d63b7dSRichard Lowe 	}
82510d63b7dSRichard Lowe exit:
82610d63b7dSRichard Lowe 	if(left_tail) {
82710d63b7dSRichard Lowe 		retmem(left_tail);
82810d63b7dSRichard Lowe 	}
82910d63b7dSRichard Lowe 	if(right_tail) {
83010d63b7dSRichard Lowe 		retmem(right_tail);
83110d63b7dSRichard Lowe 	}
83210d63b7dSRichard Lowe 	if(left_head) {
83310d63b7dSRichard Lowe 		retmem(left_head);
83410d63b7dSRichard Lowe 	}
83510d63b7dSRichard Lowe 	i = 0;
83610d63b7dSRichard Lowe 	while (right_hand[i] != NULL) {
83710d63b7dSRichard Lowe 		retmem(right_hand[i]);
83810d63b7dSRichard Lowe 		i++;
83910d63b7dSRichard Lowe 	}
84010d63b7dSRichard Lowe 	*destination->text.p = (int) nul_char;
84110d63b7dSRichard Lowe 	destination->text.end = destination->text.p;
84210d63b7dSRichard Lowe }
84310d63b7dSRichard Lowe 
84410d63b7dSRichard Lowe static void
add_macro_to_global_list(Name macro_to_add)84510d63b7dSRichard Lowe add_macro_to_global_list(Name macro_to_add)
84610d63b7dSRichard Lowe {
84710d63b7dSRichard Lowe 	Macro_list	new_macro;
84810d63b7dSRichard Lowe 	Macro_list	macro_on_list;
84910d63b7dSRichard Lowe 	char		*name_on_list = (char*)NULL;
85010d63b7dSRichard Lowe 	char		*name_to_add = macro_to_add->string_mb;
85110d63b7dSRichard Lowe 	char		*value_on_list = (char*)NULL;
85210d63b7dSRichard Lowe 	const char	*value_to_add = (char*)NULL;
85310d63b7dSRichard Lowe 
85410d63b7dSRichard Lowe 	if (macro_to_add->prop->body.macro.value != NULL) {
85510d63b7dSRichard Lowe 		value_to_add = macro_to_add->prop->body.macro.value->string_mb;
85610d63b7dSRichard Lowe 	} else {
85710d63b7dSRichard Lowe 		value_to_add = "";
85810d63b7dSRichard Lowe 	}
85910d63b7dSRichard Lowe 
860*e7afc443SToomas Soome 	/*
86110d63b7dSRichard Lowe 	 * Check if this macro is already on list, if so, do nothing
86210d63b7dSRichard Lowe 	 */
86310d63b7dSRichard Lowe 	for (macro_on_list = cond_macro_list;
86410d63b7dSRichard Lowe 	     macro_on_list != NULL;
86510d63b7dSRichard Lowe 	     macro_on_list = macro_on_list->next) {
86610d63b7dSRichard Lowe 
86710d63b7dSRichard Lowe 		name_on_list = macro_on_list->macro_name;
86810d63b7dSRichard Lowe 		value_on_list = macro_on_list->value;
86910d63b7dSRichard Lowe 
87010d63b7dSRichard Lowe 		if (IS_EQUAL(name_on_list, name_to_add)) {
87110d63b7dSRichard Lowe 			if (IS_EQUAL(value_on_list, value_to_add)) {
87210d63b7dSRichard Lowe 				return;
87310d63b7dSRichard Lowe 			}
87410d63b7dSRichard Lowe 		}
87510d63b7dSRichard Lowe 	}
87610d63b7dSRichard Lowe 	new_macro = (Macro_list) malloc(sizeof(Macro_list_rec));
87710d63b7dSRichard Lowe 	new_macro->macro_name = strdup(name_to_add);
87810d63b7dSRichard Lowe 	new_macro->value = strdup(value_to_add);
87910d63b7dSRichard Lowe 	new_macro->next = cond_macro_list;
88010d63b7dSRichard Lowe 	cond_macro_list = new_macro;
88110d63b7dSRichard Lowe }
88210d63b7dSRichard Lowe 
88310d63b7dSRichard Lowe /*
88410d63b7dSRichard Lowe  *	init_arch_macros(void)
88510d63b7dSRichard Lowe  *
88610d63b7dSRichard Lowe  *	Set the magic macros TARGET_ARCH, HOST_ARCH,
88710d63b7dSRichard Lowe  *
888*e7afc443SToomas Soome  *	Parameters:
88910d63b7dSRichard Lowe  *
89010d63b7dSRichard Lowe  *	Global variables used:
891*e7afc443SToomas Soome  *	                        host_arch   Property for magic macro HOST_ARCH
892*e7afc443SToomas Soome  *	                        target_arch Property for magic macro TARGET_ARCH
89310d63b7dSRichard Lowe  *
89410d63b7dSRichard Lowe  *	Return value:
89510d63b7dSRichard Lowe  *				The function does not return a value, but can
89610d63b7dSRichard Lowe  *				call fatal() in case of error.
89710d63b7dSRichard Lowe  */
89810d63b7dSRichard Lowe static void
init_arch_macros(void)89910d63b7dSRichard Lowe init_arch_macros(void)
90010d63b7dSRichard Lowe {
90110d63b7dSRichard Lowe 	String_rec	result_string;
90210d63b7dSRichard Lowe 	wchar_t		wc_buf[STRING_BUFFER_LENGTH];
90310d63b7dSRichard Lowe 	char		mb_buf[STRING_BUFFER_LENGTH];
90410d63b7dSRichard Lowe 	FILE		*pipe;
90510d63b7dSRichard Lowe 	Name		value;
90610d63b7dSRichard Lowe 	int		set_host, set_target;
90710d63b7dSRichard Lowe 	const char	*mach_command = "/bin/mach";
90810d63b7dSRichard Lowe 
90910d63b7dSRichard Lowe 	set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
91010d63b7dSRichard Lowe 	set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
91110d63b7dSRichard Lowe 
91210d63b7dSRichard Lowe 	if (set_host || set_target) {
91310d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(result_string, wc_buf);
91410d63b7dSRichard Lowe 		append_char((int) hyphen_char, &result_string);
91510d63b7dSRichard Lowe 
91610d63b7dSRichard Lowe 		if ((pipe = popen(mach_command, "r")) == NULL) {
91710d63b7dSRichard Lowe 			fatal_mksh(gettext("Execute of %s failed"), mach_command);
91810d63b7dSRichard Lowe 		}
91910d63b7dSRichard Lowe 		while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
92010d63b7dSRichard Lowe 			MBSTOWCS(wcs_buffer, mb_buf);
92110d63b7dSRichard Lowe 			append_string(wcs_buffer, &result_string, wcslen(wcs_buffer));
92210d63b7dSRichard Lowe 		}
92310d63b7dSRichard Lowe 		if (pclose(pipe) != 0) {
92410d63b7dSRichard Lowe 			fatal_mksh(gettext("Execute of %s failed"), mach_command);
92510d63b7dSRichard Lowe 		}
92610d63b7dSRichard Lowe 
92710d63b7dSRichard Lowe 		value = GETNAME(result_string.buffer.start, wcslen(result_string.buffer.start));
92810d63b7dSRichard Lowe 
92910d63b7dSRichard Lowe 		if (set_host) {
93010d63b7dSRichard Lowe 			(void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
93110d63b7dSRichard Lowe 		}
93210d63b7dSRichard Lowe 		if (set_target) {
93310d63b7dSRichard Lowe 			(void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
93410d63b7dSRichard Lowe 		}
93510d63b7dSRichard Lowe 	}
93610d63b7dSRichard Lowe }
93710d63b7dSRichard Lowe 
93810d63b7dSRichard Lowe /*
93910d63b7dSRichard Lowe  *	init_mach_macros(void)
94010d63b7dSRichard Lowe  *
94110d63b7dSRichard Lowe  *	Set the magic macros TARGET_MACH, HOST_MACH,
94210d63b7dSRichard Lowe  *
943*e7afc443SToomas Soome  *	Parameters:
94410d63b7dSRichard Lowe  *
94510d63b7dSRichard Lowe  *	Global variables used:
946*e7afc443SToomas Soome  *	                        host_mach   Property for magic macro HOST_MACH
947*e7afc443SToomas Soome  *	                        target_mach Property for magic macro TARGET_MACH
94810d63b7dSRichard Lowe  *
94910d63b7dSRichard Lowe  *	Return value:
95010d63b7dSRichard Lowe  *				The function does not return a value, but can
95110d63b7dSRichard Lowe  *				call fatal() in case of error.
95210d63b7dSRichard Lowe  */
95310d63b7dSRichard Lowe static void
init_mach_macros(void)95410d63b7dSRichard Lowe init_mach_macros(void)
95510d63b7dSRichard Lowe {
95610d63b7dSRichard Lowe 	String_rec	result_string;
95710d63b7dSRichard Lowe 	wchar_t		wc_buf[STRING_BUFFER_LENGTH];
95810d63b7dSRichard Lowe 	char		mb_buf[STRING_BUFFER_LENGTH];
95910d63b7dSRichard Lowe 	FILE		*pipe;
96010d63b7dSRichard Lowe 	Name		value;
96110d63b7dSRichard Lowe 	int		set_host, set_target;
96210d63b7dSRichard Lowe 	const char	*arch_command = "/bin/arch";
96310d63b7dSRichard Lowe 
96410d63b7dSRichard Lowe 	set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
96510d63b7dSRichard Lowe 	set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
96610d63b7dSRichard Lowe 
96710d63b7dSRichard Lowe 	if (set_host || set_target) {
96810d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(result_string, wc_buf);
96910d63b7dSRichard Lowe 		append_char((int) hyphen_char, &result_string);
97010d63b7dSRichard Lowe 
97110d63b7dSRichard Lowe 		if ((pipe = popen(arch_command, "r")) == NULL) {
97210d63b7dSRichard Lowe 			fatal_mksh(gettext("Execute of %s failed"), arch_command);
97310d63b7dSRichard Lowe 		}
97410d63b7dSRichard Lowe 		while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
97510d63b7dSRichard Lowe 			MBSTOWCS(wcs_buffer, mb_buf);
97610d63b7dSRichard Lowe 			append_string(wcs_buffer, &result_string, wcslen(wcs_buffer));
97710d63b7dSRichard Lowe 		}
97810d63b7dSRichard Lowe 		if (pclose(pipe) != 0) {
97910d63b7dSRichard Lowe 			fatal_mksh(gettext("Execute of %s failed"), arch_command);
98010d63b7dSRichard Lowe 		}
98110d63b7dSRichard Lowe 
98210d63b7dSRichard Lowe 		value = GETNAME(result_string.buffer.start, wcslen(result_string.buffer.start));
98310d63b7dSRichard Lowe 
98410d63b7dSRichard Lowe 		if (set_host) {
98510d63b7dSRichard Lowe 			(void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
98610d63b7dSRichard Lowe 		}
98710d63b7dSRichard Lowe 		if (set_target) {
98810d63b7dSRichard Lowe 			(void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
98910d63b7dSRichard Lowe 		}
99010d63b7dSRichard Lowe 	}
99110d63b7dSRichard Lowe }
99210d63b7dSRichard Lowe 
99310d63b7dSRichard Lowe /*
99410d63b7dSRichard Lowe  *	expand_value_with_daemon(name, macro, destination, cmd)
99510d63b7dSRichard Lowe  *
99610d63b7dSRichard Lowe  *	Checks for daemons and then maybe calls expand_value().
99710d63b7dSRichard Lowe  *
99810d63b7dSRichard Lowe  *	Parameters:
99910d63b7dSRichard Lowe  *              name            Name of the macro  (Added by the NSE)
100010d63b7dSRichard Lowe  *		macro		The property block with the value to expand
100110d63b7dSRichard Lowe  *		destination	Where the result should be deposited
100210d63b7dSRichard Lowe  *		cmd		If we are evaluating a command line we
100310d63b7dSRichard Lowe  *				turn \ quoting off
100410d63b7dSRichard Lowe  *
100510d63b7dSRichard Lowe  *	Global variables used:
100610d63b7dSRichard Lowe  */
100710d63b7dSRichard Lowe static void
expand_value_with_daemon(Name,Property macro,String destination,Boolean cmd)1008*e7afc443SToomas Soome expand_value_with_daemon(Name, Property macro, String destination, Boolean cmd)
100910d63b7dSRichard Lowe {
1010*e7afc443SToomas Soome 	Chain		chain;
101110d63b7dSRichard Lowe 
101210d63b7dSRichard Lowe 
101310d63b7dSRichard Lowe 	switch (macro->body.macro.daemon) {
101410d63b7dSRichard Lowe 	case no_daemon:
101510d63b7dSRichard Lowe 		if (!svr4 && !posix) {
101610d63b7dSRichard Lowe 			expand_value(macro->body.macro.value, destination, cmd);
101710d63b7dSRichard Lowe 		} else {
101810d63b7dSRichard Lowe 			if (dollarless_flag && tilde_rule) {
101910d63b7dSRichard Lowe 				expand_value(dollarless_value, destination, cmd);
102010d63b7dSRichard Lowe 				dollarless_flag = false;
102110d63b7dSRichard Lowe 				tilde_rule = false;
102210d63b7dSRichard Lowe 			} else {
102310d63b7dSRichard Lowe 				expand_value(macro->body.macro.value, destination, cmd);
102410d63b7dSRichard Lowe 			}
102510d63b7dSRichard Lowe 		}
102610d63b7dSRichard Lowe 		return;
102710d63b7dSRichard Lowe 	case chain_daemon:
102810d63b7dSRichard Lowe 		/* If this is a $? value we call the daemon to translate the */
102910d63b7dSRichard Lowe 		/* list of names to a string */
103010d63b7dSRichard Lowe 		for (chain = (Chain) macro->body.macro.value;
103110d63b7dSRichard Lowe 		     chain != NULL;
103210d63b7dSRichard Lowe 		     chain = chain->next) {
103310d63b7dSRichard Lowe 			APPEND_NAME(chain->name,
103410d63b7dSRichard Lowe 				      destination,
103510d63b7dSRichard Lowe 				      (int) chain->name->hash.length);
103610d63b7dSRichard Lowe 			if (chain->next != NULL) {
103710d63b7dSRichard Lowe 				append_char((int) space_char, destination);
103810d63b7dSRichard Lowe 			}
103910d63b7dSRichard Lowe 		}
104010d63b7dSRichard Lowe 		return;
104110d63b7dSRichard Lowe 	}
104210d63b7dSRichard Lowe }
104310d63b7dSRichard Lowe 
104410d63b7dSRichard Lowe /*
104510d63b7dSRichard Lowe  * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
104610d63b7dSRichard Lowe  */
104710d63b7dSRichard Lowe char	*sunpro_dependencies_buf = NULL;
104810d63b7dSRichard Lowe char	*sunpro_dependencies_oldbuf = NULL;
104910d63b7dSRichard Lowe int	sunpro_dependencies_buf_size = 0;
105010d63b7dSRichard Lowe 
105110d63b7dSRichard Lowe /*
105210d63b7dSRichard Lowe  *	setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
105310d63b7dSRichard Lowe  *
105410d63b7dSRichard Lowe  *	Set a macro value, possibly supplying a daemon to be used
105510d63b7dSRichard Lowe  *	when referencing the value.
105610d63b7dSRichard Lowe  *
105710d63b7dSRichard Lowe  *	Return value:
105810d63b7dSRichard Lowe  *				The property block with the new value
105910d63b7dSRichard Lowe  *
106010d63b7dSRichard Lowe  *	Parameters:
106110d63b7dSRichard Lowe  *		name		Name of the macro to set
106210d63b7dSRichard Lowe  *		value		The value to set
106310d63b7dSRichard Lowe  *		append		Should we reset or append to the current value?
106410d63b7dSRichard Lowe  *		daemon		Special treatment when reading the value
106510d63b7dSRichard Lowe  *		strip_trailing_spaces from the end of value->string
106610d63b7dSRichard Lowe  *		debug_level	Indicates how much tracing we should do
106710d63b7dSRichard Lowe  *
106810d63b7dSRichard Lowe  *	Global variables used:
106910d63b7dSRichard Lowe  *		makefile_type	Used to check if we should enforce read only
107010d63b7dSRichard Lowe  *		path_name	The Name "PATH", compared against
107110d63b7dSRichard Lowe  *		virtual_root	The Name "VIRTUAL_ROOT", compared against
107210d63b7dSRichard Lowe  *		vpath_defined	Set if the macro VPATH is set
107310d63b7dSRichard Lowe  *		vpath_name	The Name "VPATH", compared against
107410d63b7dSRichard Lowe  *		envvar		A list of environment vars with $ in value
107510d63b7dSRichard Lowe  */
107610d63b7dSRichard Lowe Property
setvar_daemon(Name name,Name value,Boolean append,Daemon daemon,Boolean strip_trailing_spaces,short debug_level)1077*e7afc443SToomas Soome setvar_daemon(Name name, Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
107810d63b7dSRichard Lowe {
1079*e7afc443SToomas Soome 	Property	macro = maybe_append_prop(name, macro_prop);
1080*e7afc443SToomas Soome 	Property	macro_apx = get_prop(name->prop, macro_append_prop);
108110d63b7dSRichard Lowe 	int			length = 0;
108210d63b7dSRichard Lowe 	String_rec		destination;
108310d63b7dSRichard Lowe 	wchar_t			buffer[STRING_BUFFER_LENGTH];
1084*e7afc443SToomas Soome 	Chain		chain;
108510d63b7dSRichard Lowe 	Name			val;
108610d63b7dSRichard Lowe 	wchar_t			*val_string = (wchar_t*)NULL;
108710d63b7dSRichard Lowe 	Wstring			wcb;
108810d63b7dSRichard Lowe 
108910d63b7dSRichard Lowe 
109010d63b7dSRichard Lowe 	if ((makefile_type != reading_nothing) &&
109110d63b7dSRichard Lowe 	    macro->body.macro.read_only) {
109210d63b7dSRichard Lowe 		return macro;
109310d63b7dSRichard Lowe 	}
109410d63b7dSRichard Lowe 	/* Strip spaces from the end of the value */
109510d63b7dSRichard Lowe 	if (daemon == no_daemon) {
109610d63b7dSRichard Lowe 		if(value != NULL) {
109710d63b7dSRichard Lowe 			wcb.init(value);
109810d63b7dSRichard Lowe 			length = wcb.length();
109910d63b7dSRichard Lowe 			val_string = wcb.get_string();
110010d63b7dSRichard Lowe 		}
110110d63b7dSRichard Lowe 		if ((length > 0) && iswspace(val_string[length-1])) {
110210d63b7dSRichard Lowe 			INIT_STRING_FROM_STACK(destination, buffer);
110310d63b7dSRichard Lowe 			buffer[0] = 0;
110410d63b7dSRichard Lowe 			append_string(val_string, &destination, length);
110510d63b7dSRichard Lowe 			if (strip_trailing_spaces) {
110610d63b7dSRichard Lowe 				while ((length > 0) &&
110710d63b7dSRichard Lowe 				       iswspace(destination.buffer.start[length-1])) {
110810d63b7dSRichard Lowe 					destination.buffer.start[--length] = 0;
110910d63b7dSRichard Lowe 				}
111010d63b7dSRichard Lowe 			}
111110d63b7dSRichard Lowe 			value = GETNAME(destination.buffer.start, FIND_LENGTH);
111210d63b7dSRichard Lowe 		}
111310d63b7dSRichard Lowe 	}
1114*e7afc443SToomas Soome 
111510d63b7dSRichard Lowe 	if(macro_apx != NULL) {
111610d63b7dSRichard Lowe 		val = macro_apx->body.macro_appendix.value;
111710d63b7dSRichard Lowe 	} else {
111810d63b7dSRichard Lowe 		val = macro->body.macro.value;
111910d63b7dSRichard Lowe 	}
112010d63b7dSRichard Lowe 
112110d63b7dSRichard Lowe 	if (append) {
112210d63b7dSRichard Lowe 		/*
112310d63b7dSRichard Lowe 		 * If we are appending, we just tack the new value after
112410d63b7dSRichard Lowe 		 * the old one with a space in between.
112510d63b7dSRichard Lowe 		 */
112610d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(destination, buffer);
112710d63b7dSRichard Lowe 		buffer[0] = 0;
112810d63b7dSRichard Lowe 		if ((macro != NULL) && (val != NULL)) {
112910d63b7dSRichard Lowe 			APPEND_NAME(val,
113010d63b7dSRichard Lowe 				      &destination,
113110d63b7dSRichard Lowe 				      (int) val->hash.length);
113210d63b7dSRichard Lowe 			if (value != NULL) {
113310d63b7dSRichard Lowe 				wcb.init(value);
113410d63b7dSRichard Lowe 				if(wcb.length() > 0) {
113510d63b7dSRichard Lowe 					MBTOWC(wcs_buffer, " ");
113610d63b7dSRichard Lowe 					append_char(wcs_buffer[0], &destination);
113710d63b7dSRichard Lowe 				}
113810d63b7dSRichard Lowe 			}
113910d63b7dSRichard Lowe 		}
114010d63b7dSRichard Lowe 		if (value != NULL) {
114110d63b7dSRichard Lowe 			APPEND_NAME(value,
114210d63b7dSRichard Lowe 				      &destination,
114310d63b7dSRichard Lowe 				      (int) value->hash.length);
114410d63b7dSRichard Lowe 		}
114510d63b7dSRichard Lowe 		value = GETNAME(destination.buffer.start, FIND_LENGTH);
114610d63b7dSRichard Lowe 		wcb.init(value);
114710d63b7dSRichard Lowe 		if (destination.free_after_use) {
114810d63b7dSRichard Lowe 			retmem(destination.buffer.start);
114910d63b7dSRichard Lowe 		}
115010d63b7dSRichard Lowe 	}
115110d63b7dSRichard Lowe 
115210d63b7dSRichard Lowe 	/* Debugging trace */
115310d63b7dSRichard Lowe 	if (debug_level > 1) {
115410d63b7dSRichard Lowe 		if (value != NULL) {
115510d63b7dSRichard Lowe 			switch (daemon) {
115610d63b7dSRichard Lowe 			case chain_daemon:
115710d63b7dSRichard Lowe 				(void) printf("%s =", name->string_mb);
115810d63b7dSRichard Lowe 				for (chain = (Chain) value;
115910d63b7dSRichard Lowe 				     chain != NULL;
116010d63b7dSRichard Lowe 				     chain = chain->next) {
116110d63b7dSRichard Lowe 					(void) printf(" %s", chain->name->string_mb);
116210d63b7dSRichard Lowe 				}
116310d63b7dSRichard Lowe 				(void) printf("\n");
116410d63b7dSRichard Lowe 				break;
116510d63b7dSRichard Lowe 			case no_daemon:
116610d63b7dSRichard Lowe 				(void) printf("%s= %s\n",
116710d63b7dSRichard Lowe 					      name->string_mb,
116810d63b7dSRichard Lowe 					      value->string_mb);
116910d63b7dSRichard Lowe 				break;
117010d63b7dSRichard Lowe 			}
117110d63b7dSRichard Lowe 		} else {
117210d63b7dSRichard Lowe 			(void) printf("%s =\n", name->string_mb);
117310d63b7dSRichard Lowe 		}
117410d63b7dSRichard Lowe 	}
117510d63b7dSRichard Lowe 	/* Set the new values in the macro property block */
117610d63b7dSRichard Lowe /**/
117710d63b7dSRichard Lowe 	if(macro_apx != NULL) {
117810d63b7dSRichard Lowe 		macro_apx->body.macro_appendix.value = value;
117910d63b7dSRichard Lowe 		INIT_STRING_FROM_STACK(destination, buffer);
118010d63b7dSRichard Lowe 		buffer[0] = 0;
118110d63b7dSRichard Lowe 		if (value != NULL) {
118210d63b7dSRichard Lowe 			APPEND_NAME(value,
118310d63b7dSRichard Lowe 				      &destination,
118410d63b7dSRichard Lowe 				      (int) value->hash.length);
118510d63b7dSRichard Lowe 			if (macro_apx->body.macro_appendix.value_to_append != NULL) {
118610d63b7dSRichard Lowe 				MBTOWC(wcs_buffer, " ");
118710d63b7dSRichard Lowe 				append_char(wcs_buffer[0], &destination);
118810d63b7dSRichard Lowe 			}
118910d63b7dSRichard Lowe 		}
119010d63b7dSRichard Lowe 		if (macro_apx->body.macro_appendix.value_to_append != NULL) {
119110d63b7dSRichard Lowe 			APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
119210d63b7dSRichard Lowe 				      &destination,
119310d63b7dSRichard Lowe 				      (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
119410d63b7dSRichard Lowe 		}
119510d63b7dSRichard Lowe 		value = GETNAME(destination.buffer.start, FIND_LENGTH);
119610d63b7dSRichard Lowe 		if (destination.free_after_use) {
119710d63b7dSRichard Lowe 			retmem(destination.buffer.start);
119810d63b7dSRichard Lowe 		}
119910d63b7dSRichard Lowe 	}
120010d63b7dSRichard Lowe /**/
120110d63b7dSRichard Lowe 	macro->body.macro.value = value;
120210d63b7dSRichard Lowe 	macro->body.macro.daemon = daemon;
120310d63b7dSRichard Lowe 	/*
120410d63b7dSRichard Lowe 	 * If the user changes the VIRTUAL_ROOT, we need to flush
120510d63b7dSRichard Lowe 	 * the vroot package cache.
120610d63b7dSRichard Lowe 	 */
120710d63b7dSRichard Lowe 	if (name == path_name) {
120810d63b7dSRichard Lowe 		flush_path_cache();
120910d63b7dSRichard Lowe 	}
121010d63b7dSRichard Lowe 	if (name == virtual_root) {
121110d63b7dSRichard Lowe 		flush_vroot_cache();
121210d63b7dSRichard Lowe 	}
121310d63b7dSRichard Lowe 	/* If this sets the VPATH we remember that */
121410d63b7dSRichard Lowe 	if ((name == vpath_name) &&
121510d63b7dSRichard Lowe 	    (value != NULL) &&
121610d63b7dSRichard Lowe 	    (value->hash.length > 0)) {
121710d63b7dSRichard Lowe 		vpath_defined = true;
121810d63b7dSRichard Lowe 	}
121910d63b7dSRichard Lowe 	/*
122010d63b7dSRichard Lowe 	 * For environment variables we also set the
122110d63b7dSRichard Lowe 	 * environment value each time.
122210d63b7dSRichard Lowe 	 */
122310d63b7dSRichard Lowe 	if (macro->body.macro.exported) {
122410d63b7dSRichard Lowe 		static char	*env;
122510d63b7dSRichard Lowe 
122610d63b7dSRichard Lowe 		if (!reading_environment && (value != NULL)) {
122710d63b7dSRichard Lowe 			Envvar	p;
122810d63b7dSRichard Lowe 
122910d63b7dSRichard Lowe 			for (p = envvar; p != NULL; p = p->next) {
123010d63b7dSRichard Lowe 				if (p->name == name) {
123110d63b7dSRichard Lowe 					p->value = value;
123210d63b7dSRichard Lowe 					p->already_put = false;
123310d63b7dSRichard Lowe 					goto found_it;
123410d63b7dSRichard Lowe 				}
123510d63b7dSRichard Lowe 			}
123610d63b7dSRichard Lowe 			p = ALLOC(Envvar);
123710d63b7dSRichard Lowe 			p->name = name;
123810d63b7dSRichard Lowe 			p->value = value;
123910d63b7dSRichard Lowe 			p->next = envvar;
124010d63b7dSRichard Lowe 			p->env_string = NULL;
124110d63b7dSRichard Lowe 			p->already_put = false;
124210d63b7dSRichard Lowe 			envvar = p;
124310d63b7dSRichard Lowe found_it:;
124410d63b7dSRichard Lowe 		} if (reading_environment || (value == NULL) || !value->dollar) {
124510d63b7dSRichard Lowe 			length = 2 + strlen(name->string_mb);
124610d63b7dSRichard Lowe 			if (value != NULL) {
124710d63b7dSRichard Lowe 				length += strlen(value->string_mb);
124810d63b7dSRichard Lowe 			}
124910d63b7dSRichard Lowe 			Property env_prop = maybe_append_prop(name, env_mem_prop);
125010d63b7dSRichard Lowe 			/*
125110d63b7dSRichard Lowe 			 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
125210d63b7dSRichard Lowe 			 */
125310d63b7dSRichard Lowe 			if (!strncmp(name->string_mb, "SUNPRO_DEPENDENCIES", 19)) {
125410d63b7dSRichard Lowe 				if (length >= sunpro_dependencies_buf_size) {
125510d63b7dSRichard Lowe 					sunpro_dependencies_buf_size=length*2;
125610d63b7dSRichard Lowe 					if (sunpro_dependencies_buf_size < 4096)
125710d63b7dSRichard Lowe 						sunpro_dependencies_buf_size = 4096; // Default minimum size
125810d63b7dSRichard Lowe 					if (sunpro_dependencies_buf)
125910d63b7dSRichard Lowe 						sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
126010d63b7dSRichard Lowe 					sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
126110d63b7dSRichard Lowe 				}
126210d63b7dSRichard Lowe 				env = sunpro_dependencies_buf;
126310d63b7dSRichard Lowe 			} else {
126410d63b7dSRichard Lowe 				env = getmem(length);
126510d63b7dSRichard Lowe 			}
126610d63b7dSRichard Lowe 			env_alloc_num++;
126710d63b7dSRichard Lowe 			env_alloc_bytes += length;
126810d63b7dSRichard Lowe 			(void) sprintf(env,
126910d63b7dSRichard Lowe 				       "%s=%s",
127010d63b7dSRichard Lowe 				       name->string_mb,
127110d63b7dSRichard Lowe 				       value == NULL ?
127210d63b7dSRichard Lowe 			                 "" : value->string_mb);
127310d63b7dSRichard Lowe 			(void) putenv(env);
127410d63b7dSRichard Lowe 			env_prop->body.env_mem.value = env;
127510d63b7dSRichard Lowe 			if (sunpro_dependencies_oldbuf) {
127610d63b7dSRichard Lowe 				/* Return old buffer */
127710d63b7dSRichard Lowe 				retmem_mb(sunpro_dependencies_oldbuf);
127810d63b7dSRichard Lowe 				sunpro_dependencies_oldbuf = NULL;
127910d63b7dSRichard Lowe 			}
128010d63b7dSRichard Lowe 		}
128110d63b7dSRichard Lowe 	}
128210d63b7dSRichard Lowe 	if (name == target_arch) {
128310d63b7dSRichard Lowe 		Name		ha = getvar(host_arch);
128410d63b7dSRichard Lowe 		Name		ta = getvar(target_arch);
128510d63b7dSRichard Lowe 		Name		vr = getvar(virtual_root);
128610d63b7dSRichard Lowe 		int		length;
128710d63b7dSRichard Lowe 		wchar_t		*new_value;
128810d63b7dSRichard Lowe 		wchar_t		*old_vr;
128910d63b7dSRichard Lowe 		Boolean		new_value_allocated = false;
129010d63b7dSRichard Lowe 
129110d63b7dSRichard Lowe 		Wstring		ha_str(ha);
129210d63b7dSRichard Lowe 		Wstring		ta_str(ta);
129310d63b7dSRichard Lowe 		Wstring		vr_str(vr);
129410d63b7dSRichard Lowe 
129510d63b7dSRichard Lowe 		wchar_t * wcb_ha = ha_str.get_string();
129610d63b7dSRichard Lowe 		wchar_t * wcb_ta = ta_str.get_string();
129710d63b7dSRichard Lowe 		wchar_t * wcb_vr = vr_str.get_string();
129810d63b7dSRichard Lowe 
129910d63b7dSRichard Lowe 		length = 32 +
130010d63b7dSRichard Lowe 		  wcslen(wcb_ha) +
130110d63b7dSRichard Lowe 		    wcslen(wcb_ta) +
130210d63b7dSRichard Lowe 		      wcslen(wcb_vr);
130310d63b7dSRichard Lowe 		old_vr = wcb_vr;
130410d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "/usr/arch/");
130510d63b7dSRichard Lowe 		if (IS_WEQUALN(old_vr,
130610d63b7dSRichard Lowe 			       wcs_buffer,
130710d63b7dSRichard Lowe 			       wcslen(wcs_buffer))) {
130810d63b7dSRichard Lowe 			old_vr = (wchar_t *) wcschr(old_vr, (int) colon_char) + 1;
130910d63b7dSRichard Lowe 		}
131010d63b7dSRichard Lowe 		if ( (ha == ta) || (wcslen(wcb_ta) == 0) ) {
131110d63b7dSRichard Lowe 			new_value = old_vr;
131210d63b7dSRichard Lowe 		} else {
131310d63b7dSRichard Lowe 			new_value = ALLOC_WC(length);
131410d63b7dSRichard Lowe 			new_value_allocated = true;
131510d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, old_vr);
1316*e7afc443SToomas Soome 			(void) swprintf(new_value, length * SIZEOFWCHAR_T,
131710d63b7dSRichard Lowe 				        L"/usr/arch/%s/%s:%s",
131810d63b7dSRichard Lowe 				        ha->string_mb + 1,
131910d63b7dSRichard Lowe 				        ta->string_mb + 1,
132010d63b7dSRichard Lowe 				        mbs_buffer);
132110d63b7dSRichard Lowe 		}
132210d63b7dSRichard Lowe 		if (new_value[0] != 0) {
132310d63b7dSRichard Lowe 			(void) setvar_daemon(virtual_root,
132410d63b7dSRichard Lowe 					     GETNAME(new_value, FIND_LENGTH),
132510d63b7dSRichard Lowe 					     false,
132610d63b7dSRichard Lowe 					     no_daemon,
132710d63b7dSRichard Lowe 					     true,
132810d63b7dSRichard Lowe 					     debug_level);
132910d63b7dSRichard Lowe 		}
133010d63b7dSRichard Lowe 		if (new_value_allocated) {
133110d63b7dSRichard Lowe 			retmem(new_value);
133210d63b7dSRichard Lowe 		}
133310d63b7dSRichard Lowe 	}
133410d63b7dSRichard Lowe 	return macro;
133510d63b7dSRichard Lowe }
1336