110d63b7Richard Lowe/*
210d63b7Richard Lowe * CDDL HEADER START
310d63b7Richard Lowe *
410d63b7Richard Lowe * The contents of this file are subject to the terms of the
510d63b7Richard Lowe * Common Development and Distribution License (the "License").
610d63b7Richard Lowe * You may not use this file except in compliance with the License.
710d63b7Richard Lowe *
810d63b7Richard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910d63b7Richard Lowe * or http://www.opensolaris.org/os/licensing.
1010d63b7Richard Lowe * See the License for the specific language governing permissions
1110d63b7Richard Lowe * and limitations under the License.
1210d63b7Richard Lowe *
1310d63b7Richard Lowe * When distributing Covered Code, include this CDDL HEADER in each
1410d63b7Richard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510d63b7Richard Lowe * If applicable, add the following below this CDDL HEADER, with the
1610d63b7Richard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
1710d63b7Richard Lowe * information: Portions Copyright [yyyy] [name of copyright owner]
1810d63b7Richard Lowe *
1910d63b7Richard Lowe * CDDL HEADER END
2010d63b7Richard Lowe */
2110d63b7Richard Lowe/*
2210d63b7Richard Lowe * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2310d63b7Richard Lowe * Use is subject to license terms.
2410d63b7Richard Lowe */
2510d63b7Richard Lowe
2610d63b7Richard Lowe
2710d63b7Richard Lowe/*
2810d63b7Richard Lowe *	macro.cc
2910d63b7Richard Lowe *
3010d63b7Richard Lowe *	Handle expansion of make macros
3110d63b7Richard Lowe */
3210d63b7Richard Lowe
3310d63b7Richard Lowe/*
3410d63b7Richard Lowe * Included files
3510d63b7Richard Lowe */
3610d63b7Richard Lowe#include <mksh/dosys.h>		/* sh_command2string() */
3710d63b7Richard Lowe#include <mksh/i18n.h>		/* get_char_semantics_value() */
3810d63b7Richard Lowe#include <mksh/macro.h>
3910d63b7Richard Lowe#include <mksh/misc.h>		/* retmem() */
4010d63b7Richard Lowe#include <mksh/read.h>		/* get_next_block_fn() */
4110d63b7Richard Lowe
4210d63b7Richard Lowe#include <libintl.h>
4310d63b7Richard Lowe
4410d63b7Richard Lowe/*
4510d63b7Richard Lowe * File table of contents
4610d63b7Richard Lowe */
4710d63b7Richard Lowestatic void	add_macro_to_global_list(Name macro_to_add);
4810d63b7Richard Lowestatic void	expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
4910d63b7Richard Lowe
5010d63b7Richard Lowestatic void	init_arch_macros(void);
5110d63b7Richard Lowestatic void	init_mach_macros(void);
5210d63b7Richard Lowestatic Boolean	init_arch_done = false;
5310d63b7Richard Lowestatic Boolean	init_mach_done = false;
5410d63b7Richard Lowe
5510d63b7Richard Lowe
5610d63b7Richard Lowelong env_alloc_num = 0;
5710d63b7Richard Lowelong env_alloc_bytes = 0;
5810d63b7Richard Lowe
5910d63b7Richard Lowe/*
6010d63b7Richard Lowe *	getvar(name)
6110d63b7Richard Lowe *
6210d63b7Richard Lowe *	Return expanded value of macro.
6310d63b7Richard Lowe *
6410d63b7Richard Lowe *	Return value:
6510d63b7Richard Lowe *				The expanded value of the macro
6610d63b7Richard Lowe *
6710d63b7Richard Lowe *	Parameters:
6810d63b7Richard Lowe *		name		The name of the macro we want the value for
6910d63b7Richard Lowe *
7010d63b7Richard Lowe *	Global variables used:
7110d63b7Richard Lowe */
7210d63b7Richard LoweName
7310d63b7Richard Lowegetvar(register Name name)
7410d63b7Richard Lowe{
7510d63b7Richard Lowe	String_rec		destination;
7610d63b7Richard Lowe	wchar_t			buffer[STRING_BUFFER_LENGTH];
7710d63b7Richard Lowe	register Name		result;
7810d63b7Richard Lowe
7910d63b7Richard Lowe	if ((name == host_arch) || (name == target_arch)) {
8010d63b7Richard Lowe		if (!init_arch_done) {
8110d63b7Richard Lowe			init_arch_done = true;
8210d63b7Richard Lowe			init_arch_macros();
8310d63b7Richard Lowe		}
8410d63b7Richard Lowe	}
8510d63b7Richard Lowe	if ((name == host_mach) || (name == target_mach)) {
8610d63b7Richard Lowe		if (!init_mach_done) {
8710d63b7Richard Lowe			init_mach_done = true;
8810d63b7Richard Lowe			init_mach_macros();
8910d63b7Richard Lowe		}
9010d63b7Richard Lowe	}
9110d63b7Richard Lowe
9210d63b7Richard Lowe	INIT_STRING_FROM_STACK(destination, buffer);
9310d63b7Richard Lowe	expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
9410d63b7Richard Lowe		     &destination,
9510d63b7Richard Lowe		     false);
9610d63b7Richard Lowe	result = GETNAME(destination.buffer.start, FIND_LENGTH);
9710d63b7Richard Lowe	if (destination.free_after_use) {
9810d63b7Richard Lowe		retmem(destination.buffer.start);
9910d63b7Richard Lowe	}
10010d63b7Richard Lowe	return result;
10110d63b7Richard Lowe}
10210d63b7Richard Lowe
10310d63b7Richard Lowe/*
10410d63b7Richard Lowe *	expand_value(value, destination, cmd)
10510d63b7Richard Lowe *
10610d63b7Richard Lowe *	Recursively expands all macros in the string value.
10710d63b7Richard Lowe *	destination is where the expanded value should be appended.
10810d63b7Richard Lowe *
10910d63b7Richard Lowe *	Parameters:
11010d63b7Richard Lowe *		value		The value we are expanding
11110d63b7Richard Lowe *		destination	Where to deposit the expansion
11210d63b7Richard Lowe *		cmd		If we are evaluating a command line we
11310d63b7Richard Lowe *				turn \ quoting off
11410d63b7Richard Lowe *
11510d63b7Richard Lowe *	Global variables used:
11610d63b7Richard Lowe */
11710d63b7Richard Lowevoid
11810d63b7Richard Loweexpand_value(Name value, register String destination, Boolean cmd)
11910d63b7Richard Lowe{
12010d63b7Richard Lowe	Source_rec		sourceb;
12110d63b7Richard Lowe	register Source		source = &sourceb;
12210d63b7Richard Lowe	register wchar_t	*source_p = NULL;
12310d63b7Richard Lowe	register wchar_t	*source_end = NULL;
12410d63b7Richard Lowe	wchar_t			*block_start = NULL;
12510d63b7Richard Lowe	int			quote_seen = 0;
12610d63b7Richard Lowe
12710d63b7Richard Lowe	if (value == NULL) {
12810d63b7Richard Lowe		/*
12910d63b7Richard Lowe		 * Make sure to get a string allocated even if it
13010d63b7Richard Lowe		 * will be empty.
13110d63b7Richard Lowe		 */
13210d63b7Richard Lowe		MBSTOWCS(wcs_buffer, "");
13310d63b7Richard Lowe		append_string(wcs_buffer, destination, FIND_LENGTH);
13410d63b7Richard Lowe		destination->text.end = destination->text.p;
13510d63b7Richard Lowe		return;
13610d63b7Richard Lowe	}
13710d63b7Richard Lowe	if (!value->dollar) {
13810d63b7Richard Lowe		/*
13910d63b7Richard Lowe		 * If the value we are expanding does not contain
14010d63b7Richard Lowe		 * any $, we don't have to parse it.
14110d63b7Richard Lowe		 */
14210d63b7Richard Lowe		APPEND_NAME(value,
14310d63b7Richard Lowe			destination,
14410d63b7Richard Lowe			(int) value->hash.length
14510d63b7Richard Lowe		);
14610d63b7Richard Lowe		destination->text.end = destination->text.p;
14710d63b7Richard Lowe		return;
14810d63b7Richard Lowe	}
14910d63b7Richard Lowe
15010d63b7Richard Lowe	if (value->being_expanded) {
15110d63b7Richard Lowe		fatal_reader_mksh(gettext("Loop detected when expanding macro value `%s'"),
15210d63b7Richard Lowe			     value->string_mb);
15310d63b7Richard Lowe	}
15410d63b7Richard Lowe	value->being_expanded = true;
15510d63b7Richard Lowe	/* Setup the structure we read from */
15610d63b7Richard Lowe	Wstring vals(value);
15710d63b7Richard Lowe	sourceb.string.text.p = sourceb.string.buffer.start = wcsdup(vals.get_string());
15810d63b7Richard Lowe	sourceb.string.free_after_use = true;
15910d63b7Richard Lowe	sourceb.string.text.end =
16010d63b7Richard Lowe	  sourceb.string.buffer.end =
16110d63b7Richard Lowe	    sourceb.string.text.p + value->hash.length;
16210d63b7Richard Lowe	sourceb.previous = NULL;
16310d63b7Richard Lowe	sourceb.fd = -1;
16410d63b7Richard Lowe	sourceb.inp_buf =
16510d63b7Richard Lowe	  sourceb.inp_buf_ptr =
16610d63b7Richard Lowe	    sourceb.inp_buf_end = NULL;
16710d63b7Richard Lowe	sourceb.error_converting = false;
16810d63b7Richard Lowe	/* Lift some pointers from the struct to local register variables */
16910d63b7Richard Lowe	CACHE_SOURCE(0);
17010d63b7Richard Lowe/* We parse the string in segments */
17110d63b7Richard Lowe/* We read chars until we find a $, then we append what we have read so far */
17210d63b7Richard Lowe/* (since last $ processing) to the destination. When we find a $ we call */
17310d63b7Richard Lowe/* expand_macro() and let it expand that particular $ reference into dest */
17410d63b7Richard Lowe	block_start = source_p;
17510d63b7Richard Lowe	quote_seen = 0;
17610d63b7Richard Lowe	for (; 1; source_p++) {
17710d63b7Richard Lowe		switch (GET_CHAR()) {
17810d63b7Richard Lowe		case backslash_char:
17910d63b7Richard Lowe			/* Quote $ in macro value */
18010d63b7Richard Lowe			if (!cmd) {
18110d63b7Richard Lowe				quote_seen = ~quote_seen;
18210d63b7Richard Lowe			}
18310d63b7Richard Lowe			continue;
18410d63b7Richard Lowe		case dollar_char:
18510d63b7Richard Lowe			/* Save the plain string we found since */
18610d63b7Richard Lowe			/* start of string or previous $ */
18710d63b7Richard Lowe			if (quote_seen) {
18810d63b7Richard Lowe				append_string(block_start,
18910d63b7Richard Lowe					      destination,
19010d63b7Richard Lowe					      source_p - block_start - 1);
19110d63b7Richard Lowe				block_start = source_p;
19210d63b7Richard Lowe				break;
19310d63b7Richard Lowe			}
19410d63b7Richard Lowe			append_string(block_start,
19510d63b7Richard Lowe				      destination,
19610d63b7Richard Lowe				      source_p - block_start);
19710d63b7Richard Lowe			source->string.text.p = ++source_p;
19810d63b7Richard Lowe			UNCACHE_SOURCE();
19910d63b7Richard Lowe			/* Go expand the macro reference */
20010d63b7Richard Lowe			expand_macro(source, destination, sourceb.string.buffer.start, cmd);
20110d63b7Richard Lowe			CACHE_SOURCE(1);
20210d63b7Richard Lowe			block_start = source_p + 1;
20310d63b7Richard Lowe			break;
20410d63b7Richard Lowe		case nul_char:
20510d63b7Richard Lowe			/* The string ran out. Get some more */
20610d63b7Richard Lowe			append_string(block_start,
20710d63b7Richard Lowe				      destination,
20810d63b7Richard Lowe				      source_p - block_start);
20910d63b7Richard Lowe			GET_NEXT_BLOCK_NOCHK(source);
21010d63b7Richard Lowe			if (source == NULL) {
21110d63b7Richard Lowe				destination->text.end = destination->text.p;
21210d63b7Richard Lowe				value->being_expanded = false;
21310d63b7Richard Lowe				return;
21410d63b7Richard Lowe			}
21510d63b7Richard Lowe			if (source->error_converting) {
21610d63b7Richard Lowe				fatal_reader_mksh("Internal error: Invalid byte sequence in expand_value()");
21710d63b7Richard Lowe			}
21810d63b7Richard Lowe			block_start = source_p;
21910d63b7Richard Lowe			source_p--;
22010d63b7Richard Lowe			continue;
22110d63b7Richard Lowe		}
22210d63b7Richard Lowe		quote_seen = 0;
22310d63b7Richard Lowe	}
22410d63b7Richard Lowe	retmem(sourceb.string.buffer.start);
22510d63b7Richard Lowe}
22610d63b7Richard Lowe
22710d63b7Richard Lowe/*
22810d63b7Richard Lowe *	expand_macro(source, destination, current_string, cmd)
22910d63b7Richard Lowe *
23010d63b7Richard Lowe *	Should be called with source->string.text.p pointing to
23110d63b7Richard Lowe *	the first char after the $ that starts a macro reference.
23210d63b7Richard Lowe *	source->string.text.p is returned pointing to the first char after
23310d63b7Richard Lowe *	the macro name.
23410d63b7Richard Lowe *	It will read the macro name, expanding any macros in it,
23510d63b7Richard Lowe *	and get the value. The value is then expanded.
23610d63b7Richard Lowe *	destination is a String that is filled in with the expanded macro.
23710d63b7Richard Lowe *	It may be passed in referencing a buffer to expand the macro into.
23810d63b7Richard Lowe * 	Note that most expansions are done on demand, e.g. right
23910d63b7Richard Lowe *	before the command is executed and not while the file is
24010d63b7Richard Lowe * 	being parsed.
24110d63b7Richard Lowe *
24210d63b7Richard Lowe *	Parameters:
24310d63b7Richard Lowe *		source		The source block that references the string
24410d63b7Richard Lowe *				to expand
24510d63b7Richard Lowe *		destination	Where to put the result
24610d63b7Richard Lowe *		current_string	The string we are expanding, for error msg
24710d63b7Richard Lowe *		cmd		If we are evaluating a command line we
24810d63b7Richard Lowe *				turn \ quoting off
24910d63b7Richard Lowe *
25010d63b7Richard Lowe *	Global variables used:
25110d63b7Richard Lowe *		funny		Vector of semantic tags for characters
25210d63b7Richard Lowe *		is_conditional	Set if a conditional macro is refd
25310d63b7Richard Lowe *		make_word_mentioned Set if the word "MAKE" is mentioned
25410d63b7Richard Lowe *		makefile_type	We deliver extra msg when reading makefiles
25510d63b7Richard Lowe *		query		The Name "?", compared against
25610d63b7Richard Lowe *		query_mentioned	Set if the word "?" is mentioned
25710d63b7Richard Lowe */
25810d63b7Richard Lowevoid
25910d63b7Richard Loweexpand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
26010d63b7Richard Lowe{
26110d63b7Richard Lowe	static Name		make = (Name)NULL;
26210d63b7Richard Lowe	static wchar_t		colon_sh[4];
26310d63b7Richard Lowe	static wchar_t		colon_shell[7];
26410d63b7Richard Lowe	String_rec		string;
26510d63b7Richard Lowe	wchar_t			buffer[STRING_BUFFER_LENGTH];
26610d63b7Richard Lowe	register wchar_t	*source_p = source->string.text.p;
26710d63b7Richard Lowe	register wchar_t	*source_end = source->string.text.end;
26810d63b7Richard Lowe	register int		closer = 0;
26910d63b7Richard Lowe	wchar_t			*block_start = (wchar_t *)NULL;
27010d63b7Richard Lowe	int			quote_seen = 0;
27110d63b7Richard Lowe	register int		closer_level = 1;
27210d63b7Richard Lowe	Name			name = (Name)NULL;
27310d63b7Richard Lowe	wchar_t			*colon = (wchar_t *)NULL;
27410d63b7Richard Lowe	wchar_t			*percent = (wchar_t *)NULL;
27510d63b7Richard Lowe	wchar_t			*eq = (wchar_t *) NULL;
27610d63b7Richard Lowe	Property		macro = NULL;
27710d63b7Richard Lowe	wchar_t			*p = (wchar_t*)NULL;
27810d63b7Richard Lowe	String_rec		extracted;
27910d63b7Richard Lowe	wchar_t			extracted_string[MAXPATHLEN];
28010d63b7Richard Lowe	wchar_t			*left_head = NULL;
28110d63b7Richard Lowe	wchar_t			*left_tail = NULL;
28210d63b7Richard Lowe	wchar_t			*right_tail = NULL;
28310d63b7Richard Lowe	int			left_head_len = 0;
28410d63b7Richard Lowe	int			left_tail_len = 0;
28510d63b7Richard Lowe	int			tmp_len = 0;
28610d63b7Richard Lowe	wchar_t			*right_hand[128];
28710d63b7Richard Lowe	int			i = 0;
28810d63b7Richard Lowe	enum {
28910d63b7Richard Lowe		no_extract,
29010d63b7Richard Lowe		dir_extract,
29110d63b7Richard Lowe		file_extract
29210d63b7Richard Lowe	}                       extraction = no_extract;
29310d63b7Richard Lowe	enum {
29410d63b7Richard Lowe		no_replace,
29510d63b7Richard Lowe		suffix_replace,
29610d63b7Richard Lowe		pattern_replace,
29710d63b7Richard Lowe		sh_replace
29810d63b7Richard Lowe	}			replacement = no_replace;
29910d63b7Richard Lowe
30010d63b7Richard Lowe	if (make == NULL) {
30110d63b7Richard Lowe		MBSTOWCS(wcs_buffer, "MAKE");
30210d63b7Richard Lowe		make = GETNAME(wcs_buffer, FIND_LENGTH);
30310d63b7Richard Lowe
30410d63b7Richard Lowe		MBSTOWCS(colon_sh, ":sh");
30510d63b7Richard Lowe		MBSTOWCS(colon_shell, ":shell");
30610d63b7Richard Lowe	}
30710d63b7Richard Lowe
30810d63b7Richard Lowe	right_hand[0] = NULL;
30910d63b7Richard Lowe
31010d63b7Richard Lowe	/* First copy the (macro-expanded) macro name into string. */
31110d63b7Richard Lowe	INIT_STRING_FROM_STACK(string, buffer);
31210d63b7Richard Lowerecheck_first_char:
31310d63b7Richard Lowe	/* Check the first char of the macro name to figure out what to do. */
31410d63b7Richard Lowe	switch (GET_CHAR()) {
31510d63b7Richard Lowe	case nul_char:
31610d63b7Richard Lowe		GET_NEXT_BLOCK_NOCHK(source);
31710d63b7Richard Lowe		if (source == NULL) {
31810d63b7Richard Lowe			WCSTOMBS(mbs_buffer, current_string);
31910d63b7Richard Lowe			fatal_reader_mksh(gettext("'$' at end of string `%s'"),
32010d63b7Richard Lowe				     mbs_buffer);
32110d63b7Richard Lowe		}
32210d63b7Richard Lowe		if (source->error_converting) {
32310d63b7Richard Lowe			fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
32410d63b7Richard Lowe		}
32510d63b7Richard Lowe		goto recheck_first_char;
32610d63b7Richard Lowe	case parenleft_char:
32710d63b7Richard Lowe		/* Multi char name. */
32810d63b7Richard Lowe		closer = (int) parenright_char;
32910d63b7Richard Lowe		break;
33010d63b7Richard Lowe	case braceleft_char:
33110d63b7Richard Lowe		/* Multi char name. */
33210d63b7Richard Lowe		closer = (int) braceright_char;
33310d63b7Richard Lowe		break;
33410d63b7Richard Lowe	case newline_char:
33510d63b7Richard Lowe		fatal_reader_mksh(gettext("'$' at end of line"));
33610d63b7Richard Lowe	default:
33710d63b7Richard Lowe		/* Single char macro name. Just suck it up */
33810d63b7Richard Lowe		append_char(*source_p, &string);
33910d63b7Richard Lowe		source->string.text.p = source_p + 1;
34010d63b7Richard Lowe		goto get_macro_value;
34110d63b7Richard Lowe	}
34210d63b7Richard Lowe
34310d63b7Richard Lowe	/* Handle multi-char macro names */
34410d63b7Richard Lowe	block_start = ++source_p;
34510d63b7Richard Lowe	quote_seen = 0;
34610d63b7Richard Lowe	for (; 1; source_p++) {
34710d63b7Richard Lowe		switch (GET_CHAR()) {
34810d63b7Richard Lowe		case nul_char:
34910d63b7Richard Lowe			append_string(block_start,
35010d63b7Richard Lowe				      &string,
35110d63b7Richard Lowe				      source_p - block_start);
35210d63b7Richard Lowe			GET_NEXT_BLOCK_NOCHK(source);
35310d63b7Richard Lowe			if (source == NULL) {
35410d63b7Richard Lowe				if (current_string != NULL) {
35510d63b7Richard Lowe					WCSTOMBS(mbs_buffer, current_string);
35610d63b7Richard Lowe					fatal_reader_mksh(gettext("Unmatched `%c' in string `%s'"),
35710d63b7Richard Lowe						     closer ==
35810d63b7Richard Lowe						     (int) braceright_char ?
35910d63b7Richard Lowe						     (int) braceleft_char :
36010d63b7Richard Lowe						     (int) parenleft_char,
36110d63b7Richard Lowe						     mbs_buffer);
36210d63b7Richard Lowe				} else {
36310d63b7Richard Lowe					fatal_reader_mksh(gettext("Premature EOF"));
36410d63b7Richard Lowe				}
36510d63b7Richard Lowe			}
36610d63b7Richard Lowe			if (source->error_converting) {
36710d63b7Richard Lowe				fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
36810d63b7Richard Lowe			}
36910d63b7Richard Lowe			block_start = source_p;
37010d63b7Richard Lowe			source_p--;
37110d63b7Richard Lowe			continue;
37210d63b7Richard Lowe		case newline_char:
37310d63b7Richard Lowe			fatal_reader_mksh(gettext("Unmatched `%c' on line"),
37410d63b7Richard Lowe				     closer == (int) braceright_char ?
37510d63b7Richard Lowe				     (int) braceleft_char :
37610d63b7Richard Lowe				     (int) parenleft_char);
37710d63b7Richard Lowe		case backslash_char:
37810d63b7Richard Lowe			/* Quote dollar in macro value. */
37910d63b7Richard Lowe			if (!cmd) {
38010d63b7Richard Lowe				quote_seen = ~quote_seen;
38110d63b7Richard Lowe			}
38210d63b7Richard Lowe			continue;
38310d63b7Richard Lowe		case dollar_char:
38410d63b7Richard Lowe			/*
38510d63b7Richard Lowe			 * Macro names may reference macros.
38610d63b7Richard Lowe			 * This expands the value of such macros into the
38710d63b7Richard Lowe			 * macro name string.
38810d63b7Richard Lowe			 */
38910d63b7Richard Lowe			if (quote_seen) {
39010d63b7Richard Lowe				append_string(block_start,
39110d63b7Richard Lowe					      &string,
39210d63b7Richard Lowe					      source_p - block_start - 1);
39310d63b7Richard Lowe				block_start = source_p;
39410d63b7Richard Lowe				break;
39510d63b7Richard Lowe			}
39610d63b7Richard Lowe			append_string(block_start,
39710d63b7Richard Lowe				      &string,
39810d63b7Richard Lowe				      source_p - block_start);
39910d63b7Richard Lowe			source->string.text.p = ++source_p;
40010d63b7Richard Lowe			UNCACHE_SOURCE();
40110d63b7Richard Lowe			expand_macro(source, &string, current_string, cmd);
40210d63b7Richard Lowe			CACHE_SOURCE(0);
40310d63b7Richard Lowe			block_start = source_p;
40410d63b7Richard Lowe			source_p--;
40510d63b7Richard Lowe			break;
40610d63b7Richard Lowe		case parenleft_char:
40710d63b7Richard Lowe			/* Allow nested pairs of () in the macro name. */
40810d63b7Richard Lowe			if (closer == (int) parenright_char) {
40910d63b7Richard Lowe				closer_level++;
41010d63b7Richard Lowe			}
41110d63b7Richard Lowe			break;
41210d63b7Richard Lowe		case braceleft_char:
41310d63b7Richard Lowe			/* Allow nested pairs of {} in the macro name. */
41410d63b7Richard Lowe			if (closer == (int) braceright_char) {
41510d63b7Richard Lowe				closer_level++;
41610d63b7Richard Lowe			}
41710d63b7Richard Lowe			break;
41810d63b7Richard Lowe		case parenright_char:
41910d63b7Richard Lowe		case braceright_char:
42010d63b7Richard Lowe			/*
42110d63b7Richard Lowe			 * End of the name. Save the string in the macro
42210d63b7Richard Lowe			 * name string.
42310d63b7Richard Lowe			 */
42410d63b7Richard Lowe			if ((*source_p == closer) && (--closer_level <= 0)) {
42510d63b7Richard Lowe				source->string.text.p = source_p + 1;
42610d63b7Richard Lowe				append_string(block_start,
42710d63b7Richard Lowe					      &string,
42810d63b7Richard Lowe					      source_p - block_start);
42910d63b7Richard Lowe				goto get_macro_value;
43010d63b7Richard Lowe			}
43110d63b7Richard Lowe			break;
43210d63b7Richard Lowe		}
43310d63b7Richard Lowe		quote_seen = 0;
43410d63b7Richard Lowe	}
43510d63b7Richard Lowe	/*
43610d63b7Richard Lowe	 * We got the macro name. We now inspect it to see if it
43710d63b7Richard Lowe	 * specifies any translations of the value.
43810d63b7Richard Lowe	 */
43910d63b7Richard Loweget_macro_value:
44010d63b7Richard Lowe	name = NULL;
44110d63b7Richard Lowe	/* First check if we have a $(@D) type translation. */
44210d63b7Richard Lowe	if ((get_char_semantics_value(string.buffer.start[0]) &
44310d63b7Richard Lowe	     (int) special_macro_sem) &&
44410d63b7Richard Lowe	    (string.text.p - string.buffer.start >= 2) &&
44510d63b7Richard Lowe	    ((string.buffer.start[1] == 'D') ||
44610d63b7Richard Lowe	     (string.buffer.start[1] == 'F'))) {
44710d63b7Richard Lowe		switch (string.buffer.start[1]) {
44810d63b7Richard Lowe		case 'D':
44910d63b7Richard Lowe			extraction = dir_extract;
45010d63b7Richard Lowe			break;
45110d63b7Richard Lowe		case 'F':
45210d63b7Richard Lowe			extraction = file_extract;
45310d63b7Richard Lowe			break;
45410d63b7Richard Lowe		default:
45510d63b7Richard Lowe			WCSTOMBS(mbs_buffer, string.buffer.start);
45610d63b7Richard Lowe			fatal_reader_mksh(gettext("Illegal macro reference `%s'"),
45710d63b7Richard Lowe				     mbs_buffer);
45810d63b7Richard Lowe		}
45910d63b7Richard Lowe		/* Internalize the macro name using the first char only. */
46010d63b7Richard Lowe		name = GETNAME(string.buffer.start, 1);
46110d63b7Richard Lowe		(void) wcscpy(string.buffer.start, string.buffer.start + 2);
46210d63b7Richard Lowe	}
46310d63b7Richard Lowe	/* Check for other kinds of translations. */
46410d63b7Richard Lowe	if ((colon = (wchar_t *) wcschr(string.buffer.start,
46510d63b7Richard Lowe				       (int) colon_char)) != NULL) {
46610d63b7Richard Lowe		/*
46710d63b7Richard Lowe		 * We have a $(FOO:.c=.o) type translation.
46810d63b7Richard Lowe		 * Get the name of the macro proper.
46910d63b7Richard Lowe		 */
47010d63b7Richard Lowe		if (name == NULL) {
47110d63b7Richard Lowe			name = GETNAME(string.buffer.start,
47210d63b7Richard Lowe				       colon - string.buffer.start);
47310d63b7Richard Lowe		}
47410d63b7Richard Lowe		/* Pickup all the translations. */
47510d63b7Richard Lowe		if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
47610d63b7Richard Lowe			replacement = sh_replace;
47710d63b7Richard Lowe		} else if ((svr4) ||
47810d63b7Richard Lowe		           ((percent = (wchar_t *) wcschr(colon + 1,
47910d63b7Richard Lowe							 (int) percent_char)) == NULL)) {
48010d63b7Richard Lowe			while (colon != NULL) {
48110d63b7Richard Lowe				if ((eq = (wchar_t *) wcschr(colon + 1,
48210d63b7Richard Lowe							    (int) equal_char)) == NULL) {
48310d63b7Richard Lowe					fatal_reader_mksh(gettext("= missing from replacement macro reference"));
48410d63b7Richard Lowe				}
48510d63b7Richard Lowe				left_tail_len = eq - colon - 1;
48610d63b7Richard Lowe				if(left_tail) {
48710d63b7Richard Lowe					retmem(left_tail);
48810d63b7Richard Lowe				}
48910d63b7Richard Lowe				left_tail = ALLOC_WC(left_tail_len + 1);
49010d63b7Richard Lowe				(void) wcsncpy(left_tail,
49110d63b7Richard Lowe					      colon + 1,
49210d63b7Richard Lowe					      eq - colon - 1);
49310d63b7Richard Lowe				left_tail[eq - colon - 1] = (int) nul_char;
49410d63b7Richard Lowe				replacement = suffix_replace;
49510d63b7Richard Lowe				if ((colon = (wchar_t *) wcschr(eq + 1,
49610d63b7Richard Lowe							       (int) colon_char)) != NULL) {
49710d63b7Richard Lowe					tmp_len = colon - eq;
49810d63b7Richard Lowe					if(right_tail) {
49910d63b7Richard Lowe						retmem(right_tail);
50010d63b7Richard Lowe					}
50110d63b7Richard Lowe					right_tail = ALLOC_WC(tmp_len);
50210d63b7Richard Lowe					(void) wcsncpy(right_tail,
50310d63b7Richard Lowe						      eq + 1,
50410d63b7Richard Lowe						      colon - eq - 1);
50510d63b7Richard Lowe					right_tail[colon - eq - 1] =
50610d63b7Richard Lowe					  (int) nul_char;
50710d63b7Richard Lowe				} else {
50810d63b7Richard Lowe					if(right_tail) {
50910d63b7Richard Lowe						retmem(right_tail);
51010d63b7Richard Lowe					}
51110d63b7Richard Lowe					right_tail = ALLOC_WC(wcslen(eq) + 1);
51210d63b7Richard Lowe					(void) wcscpy(right_tail, eq + 1);
51310d63b7Richard Lowe				}
51410d63b7Richard Lowe			}
51510d63b7Richard Lowe		} else {
51610d63b7Richard Lowe			if ((eq = (wchar_t *) wcschr(colon + 1,
51710d63b7Richard Lowe						    (int) equal_char)) == NULL) {
51810d63b7Richard Lowe				fatal_reader_mksh(gettext("= missing from replacement macro reference"));
51910d63b7Richard Lowe			}
52010d63b7Richard Lowe			if ((percent = (wchar_t *) wcschr(colon + 1,
52110d63b7Richard Lowe							 (int) percent_char)) == NULL) {
52210d63b7Richard Lowe				fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
52310d63b7Richard Lowe			}
52410d63b7Richard Lowe			if (eq < percent) {
52510d63b7Richard Lowe				fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
52610d63b7Richard Lowe			}
52710d63b7Richard Lowe
52810d63b7Richard Lowe			if (percent > (colon + 1)) {
52910d63b7Richard Lowe				tmp_len = percent - colon;
53010d63b7Richard Lowe				if(left_head) {
53110d63b7Richard Lowe					retmem(left_head);
53210d63b7Richard Lowe				}
53310d63b7Richard Lowe				left_head = ALLOC_WC(tmp_len);
53410d63b7Richard Lowe				(void) wcsncpy(left_head,
53510d63b7Richard Lowe					      colon + 1,
53610d63b7Richard Lowe					      percent - colon - 1);
53710d63b7Richard Lowe				left_head[percent-colon-1] = (int) nul_char;
53810d63b7Richard Lowe				left_head_len = percent-colon-1;
53910d63b7Richard Lowe			} else {
54010d63b7Richard Lowe				left_head = NULL;
54110d63b7Richard Lowe				left_head_len = 0;
54210d63b7Richard Lowe			}
54310d63b7Richard Lowe
54410d63b7Richard Lowe			if (eq > percent+1) {
54510d63b7Richard Lowe				tmp_len = eq - percent;
54610d63b7Richard Lowe				if(left_tail) {
54710d63b7Richard Lowe					retmem(left_tail);
54810d63b7Richard Lowe				}
54910d63b7Richard Lowe				left_tail = ALLOC_WC(tmp_len);
55010d63b7Richard Lowe				(void) wcsncpy(left_tail,
55110d63b7Richard Lowe					      percent + 1,
55210d63b7Richard Lowe					      eq - percent - 1);
55310d63b7Richard Lowe				left_tail[eq-percent-1] = (int) nul_char;
55410d63b7Richard Lowe				left_tail_len = eq-percent-1;
55510d63b7Richard Lowe			} else {
55610d63b7Richard Lowe				left_tail = NULL;
55710d63b7Richard Lowe				left_tail_len = 0;
55810d63b7Richard Lowe			}
55910d63b7Richard Lowe
56010d63b7Richard Lowe			if ((percent = (wchar_t *) wcschr(++eq,
56110d63b7Richard Lowe							 (int) percent_char)) == NULL) {
56210d63b7Richard Lowe
56310d63b7Richard Lowe				right_hand[0] = ALLOC_WC(wcslen(eq) + 1);
56410d63b7Richard Lowe				right_hand[1] = NULL;
56510d63b7Richard Lowe				(void) wcscpy(right_hand[0], eq);
56610d63b7Richard Lowe			} else {
56710d63b7Richard Lowe				i = 0;
56810d63b7Richard Lowe				do {
56910d63b7Richard Lowe					right_hand[i] = ALLOC_WC(percent-eq+1);
57010d63b7Richard Lowe					(void) wcsncpy(right_hand[i],
57110d63b7Richard Lowe						      eq,
57210d63b7Richard Lowe						      percent - eq);
57310d63b7Richard Lowe					right_hand[i][percent-eq] =
57410d63b7Richard Lowe					  (int) nul_char;
57510d63b7Richard Lowe					if (i++ >= VSIZEOF(right_hand)) {
57610d63b7Richard Lowe						fatal_mksh(gettext("Too many %% in pattern"));
57710d63b7Richard Lowe					}
57810d63b7Richard Lowe					eq = percent + 1;
57910d63b7Richard Lowe					if (eq[0] == (int) nul_char) {
58010d63b7Richard Lowe						MBSTOWCS(wcs_buffer, "");
58110d63b7Richard Lowe						right_hand[i] = (wchar_t *) wcsdup(wcs_buffer);
58210d63b7Richard Lowe						i++;
58310d63b7Richard Lowe						break;
58410d63b7Richard Lowe					}
58510d63b7Richard Lowe				} while ((percent = (wchar_t *) wcschr(eq, (int) percent_char)) != NULL);
58610d63b7Richard Lowe				if (eq[0] != (int) nul_char) {
58710d63b7Richard Lowe					right_hand[i] = ALLOC_WC(wcslen(eq) + 1);
58810d63b7Richard Lowe					(void) wcscpy(right_hand[i], eq);
58910d63b7Richard Lowe					i++;
59010d63b7Richard Lowe				}
59110d63b7Richard Lowe				right_hand[i] = NULL;
59210d63b7Richard Lowe			}
59310d63b7Richard Lowe			replacement = pattern_replace;
59410d63b7Richard Lowe		}
59510d63b7Richard Lowe	}
59610d63b7Richard Lowe	if (name == NULL) {
59710d63b7Richard Lowe		/*
59810d63b7Richard Lowe		 * No translations found.
59910d63b7Richard Lowe		 * Use the whole string as the macro name.
60010d63b7Richard Lowe		 */
60110d63b7Richard Lowe		name = GETNAME(string.buffer.start,
60210d63b7Richard Lowe			       string.text.p - string.buffer.start);
60310d63b7Richard Lowe	}
60410d63b7Richard Lowe	if (string.free_after_use) {
60510d63b7Richard Lowe		retmem(string.buffer.start);
60610d63b7Richard Lowe	}
60710d63b7Richard Lowe	if (name == make) {
60810d63b7Richard Lowe		make_word_mentioned = true;
60910d63b7Richard Lowe	}
61010d63b7Richard Lowe	if (name == query) {
61110d63b7Richard Lowe		query_mentioned = true;
61210d63b7Richard Lowe	}
61310d63b7Richard Lowe	if ((name == host_arch) || (name == target_arch)) {
61410d63b7Richard Lowe		if (!init_arch_done) {
61510d63b7Richard Lowe			init_arch_done = true;
61610d63b7Richard Lowe			init_arch_macros();
61710d63b7Richard Lowe		}
61810d63b7Richard Lowe	}
61910d63b7Richard Lowe	if ((name == host_mach) || (name == target_mach)) {
62010d63b7Richard Lowe		if (!init_mach_done) {
62110d63b7Richard Lowe			init_mach_done = true;
62210d63b7Richard Lowe			init_mach_macros();
62310d63b7Richard Lowe		}
62410d63b7Richard Lowe	}
62510d63b7Richard Lowe	/* Get the macro value. */
62610d63b7Richard Lowe	macro = get_prop(name->prop, macro_prop);
62710d63b7Richard Lowe	if ((macro != NULL) && macro->body.macro.is_conditional) {
62810d63b7Richard Lowe		conditional_macro_used = true;
62910d63b7Richard Lowe		/*
63010d63b7Richard Lowe		 * Add this conditional macro to the beginning of the
63110d63b7Richard Lowe		 * global list.
63210d63b7Richard Lowe		 */
63310d63b7Richard Lowe		add_macro_to_global_list(name);
63410d63b7Richard Lowe		if (makefile_type == reading_makefile) {
63510d63b7Richard Lowe			warning_mksh(gettext("Conditional macro `%s' referenced in file `%ws', line %d"),
63610d63b7Richard Lowe					name->string_mb, file_being_read, line_number);
63710d63b7Richard Lowe		}
63810d63b7Richard Lowe	}
63910d63b7Richard Lowe	/* Macro name read and parsed. Expand the value. */
64010d63b7Richard Lowe	if ((macro == NULL) || (macro->body.macro.value == NULL)) {
64110d63b7Richard Lowe		/* If the value is empty, we just get out of here. */
64210d63b7Richard Lowe		goto exit;
64310d63b7Richard Lowe	}
64410d63b7Richard Lowe	if (replacement == sh_replace) {
64510d63b7Richard Lowe		/* If we should do a :sh transform, we expand the command
64610d63b7Richard Lowe		 * and process it.
64710d63b7Richard Lowe		 */
64810d63b7Richard Lowe		INIT_STRING_FROM_STACK(string, buffer);
64910d63b7Richard Lowe		/* Expand the value into a local string buffer and run cmd. */
65010d63b7Richard Lowe		expand_value_with_daemon(name, macro, &string, cmd);
65110d63b7Richard Lowe		sh_command2string(&string, destination);
65210d63b7Richard Lowe	} else if ((replacement != no_replace) || (extraction != no_extract)) {
65310d63b7Richard Lowe		/*
65410d63b7Richard Lowe		 * If there were any transforms specified in the macro
65510d63b7Richard Lowe		 * name, we deal with them here.
65610d63b7Richard Lowe		 */
65710d63b7Richard Lowe		INIT_STRING_FROM_STACK(string, buffer);
65810d63b7Richard Lowe		/* Expand the value into a local string buffer. */
65910d63b7Richard Lowe		expand_value_with_daemon(name, macro, &string, cmd);
66010d63b7Richard Lowe		/* Scan the expanded string. */
66110d63b7Richard Lowe		p = string.buffer.start;
66210d63b7Richard Lowe		while (*p != (int) nul_char) {
66310d63b7Richard Lowe			wchar_t		chr;
66410d63b7Richard Lowe
66510d63b7Richard Lowe			/*
66610d63b7Richard Lowe			 * First skip over any white space and append
66710d63b7Richard Lowe			 * that to the destination string.
66810d63b7Richard Lowe			 */
66910d63b7Richard Lowe			block_start = p;
67010d63b7Richard Lowe			while ((*p != (int) nul_char) && iswspace(*p)) {
67110d63b7Richard Lowe				p++;
67210d63b7Richard Lowe			}
67310d63b7Richard Lowe			append_string(block_start,
67410d63b7Richard Lowe				      destination,
67510d63b7Richard Lowe				      p - block_start);
67610d63b7Richard Lowe			/* Then find the end of the next word. */
67710d63b7Richard Lowe			block_start = p;
67810d63b7Richard Lowe			while ((*p != (int) nul_char) && !iswspace(*p)) {
67910d63b7Richard Lowe				p++;
68010d63b7Richard Lowe			}
68110d63b7Richard Lowe			/* If we cant find another word we are done */
68210d63b7Richard Lowe			if (block_start == p) {
68310d63b7Richard Lowe				break;
68410d63b7Richard Lowe			}
68510d63b7Richard Lowe			/* Then apply the transforms to the word */
68610d63b7Richard Lowe			INIT_STRING_FROM_STACK(extracted, extracted_string);
68710d63b7Richard Lowe			switch (extraction) {
68810d63b7Richard Lowe			case dir_extract:
68910d63b7Richard Lowe				/*
69010d63b7Richard Lowe				 * $(@D) type transform. Extract the
69110d63b7Richard Lowe				 * path from the word. Deliver "." if
69210d63b7Richard Lowe				 * none is found.
69310d63b7Richard Lowe				 */
69410d63b7Richard Lowe				if (p != NULL) {
69510d63b7Richard Lowe					chr = *p;
69610d63b7Richard Lowe					*p = (int) nul_char;
69710d63b7Richard Lowe				}
69810d63b7Richard Lowe				eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
69910d63b7Richard Lowe				if (p != NULL) {
70010d63b7Richard Lowe					*p = chr;
70110d63b7Richard Lowe				}
70210d63b7Richard Lowe				if ((eq == NULL) || (eq > p)) {
70310d63b7Richard Lowe					MBSTOWCS(wcs_buffer, ".");
70410d63b7Richard Lowe					append_string(wcs_buffer, &extracted, 1);
70510d63b7Richard Lowe				} else {
70610d63b7Richard Lowe					append_string(block_start,
70710d63b7Richard Lowe						      &extracted,
70810d63b7Richard Lowe						      eq - block_start);
70910d63b7Richard Lowe				}
71010d63b7Richard Lowe				break;
71110d63b7Richard Lowe			case file_extract:
71210d63b7Richard Lowe				/*
71310d63b7Richard Lowe				 * $(@F) type transform. Remove the path
71410d63b7Richard Lowe				 * from the word if any.
71510d63b7Richard Lowe				 */
71610d63b7Richard Lowe				if (p != NULL) {
71710d63b7Richard Lowe					chr = *p;
71810d63b7Richard Lowe					*p = (int) nul_char;
71910d63b7Richard Lowe				}
72010d63b7Richard Lowe				eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
72110d63b7Richard Lowe				if (p != NULL) {
72210d63b7Richard Lowe					*p = chr;
72310d63b7Richard Lowe				}
72410d63b7Richard Lowe				if ((eq == NULL) || (eq > p)) {
72510d63b7Richard Lowe					append_string(block_start,
72610d63b7Richard Lowe						      &extracted,
72710d63b7Richard Lowe						      p - block_start);
72810d63b7Richard Lowe				} else {
72910d63b7Richard Lowe					append_string(eq + 1,
73010d63b7Richard Lowe						      &extracted,
73110d63b7Richard Lowe						      p - eq - 1);
73210d63b7Richard Lowe				}
73310d63b7Richard Lowe				break;
73410d63b7Richard Lowe			case no_extract:
73510d63b7Richard Lowe				append_string(block_start,
73610d63b7Richard Lowe					      &extracted,
73710d63b7Richard Lowe					      p - block_start);
73810d63b7Richard Lowe				break;
73910d63b7Richard Lowe			}
74010d63b7Richard Lowe			switch (replacement) {
74110d63b7Richard Lowe			case suffix_replace:
74210d63b7Richard Lowe				/*
74310d63b7Richard Lowe				 * $(FOO:.o=.c) type transform.
74410d63b7Richard Lowe				 * Maybe replace the tail of the word.
74510d63b7Richard Lowe				 */
74610d63b7Richard Lowe				if (((extracted.text.p -
74710d63b7Richard Lowe				      extracted.buffer.start) >=
74810d63b7Richard Lowe				     left_tail_len) &&
74910d63b7Richard Lowe				    IS_WEQUALN(extracted.text.p - left_tail_len,
75010d63b7Richard Lowe					      left_tail,
75110d63b7Richard Lowe					      left_tail_len)) {
75210d63b7Richard Lowe					append_string(extracted.buffer.start,
75310d63b7Richard Lowe						      destination,
75410d63b7Richard Lowe						      (extracted.text.p -
75510d63b7Richard Lowe						       extracted.buffer.start)
75610d63b7Richard Lowe						      - left_tail_len);
75710d63b7Richard Lowe					append_string(right_tail,
75810d63b7Richard Lowe						      destination,
75910d63b7Richard Lowe						      FIND_LENGTH);
76010d63b7Richard Lowe				} else {
76110d63b7Richard Lowe					append_string(extracted.buffer.start,
76210d63b7Richard Lowe						      destination,
76310d63b7Richard Lowe						      FIND_LENGTH);
76410d63b7Richard Lowe				}
76510d63b7Richard Lowe				break;
76610d63b7Richard Lowe			case pattern_replace:
76710d63b7Richard Lowe				/* $(X:a%b=c%d) type transform. */
76810d63b7Richard Lowe				if (((extracted.text.p -
76910d63b7Richard Lowe				      extracted.buffer.start) >=
77010d63b7Richard Lowe				     left_head_len+left_tail_len) &&
77110d63b7Richard Lowe				    IS_WEQUALN(left_head,
77210d63b7Richard Lowe					      extracted.buffer.start,
77310d63b7Richard Lowe					      left_head_len) &&
77410d63b7Richard Lowe				    IS_WEQUALN(left_tail,
77510d63b7Richard Lowe					      extracted.text.p - left_tail_len,
77610d63b7Richard Lowe					      left_tail_len)) {
77710d63b7Richard Lowe					i = 0;
77810d63b7Richard Lowe					while (right_hand[i] != NULL) {
77910d63b7Richard Lowe						append_string(right_hand[i],
78010d63b7Richard Lowe							      destination,
78110d63b7Richard Lowe							      FIND_LENGTH);
78210d63b7Richard Lowe						i++;
78310d63b7Richard Lowe						if (right_hand[i] != NULL) {
78410d63b7Richard Lowe							append_string(extracted.buffer.
78510d63b7Richard Lowe								      start +
78610d63b7Richard Lowe								      left_head_len,
78710d63b7Richard Lowe								      destination,
78810d63b7Richard Lowe								      (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
78910d63b7Richard Lowe						}
79010d63b7Richard Lowe					}
79110d63b7Richard Lowe				} else {
79210d63b7Richard Lowe					append_string(extracted.buffer.start,
79310d63b7Richard Lowe						      destination,
79410d63b7Richard Lowe						      FIND_LENGTH);
79510d63b7Richard Lowe				}
79610d63b7Richard Lowe				break;
79710d63b7Richard Lowe			case no_replace:
79810d63b7Richard Lowe				append_string(extracted.buffer.start,
79910d63b7Richard Lowe					      destination,
80010d63b7Richard Lowe					      FIND_LENGTH);
80110d63b7Richard Lowe				break;
80210d63b7Richard Lowe			case sh_replace:
80310d63b7Richard Lowe				break;
80410d63b7Richard Lowe			    }
80510d63b7Richard Lowe		}
80610d63b7Richard Lowe		if (string.free_after_use) {
80710d63b7Richard Lowe			retmem(string.buffer.start);
80810d63b7Richard Lowe		}
80910d63b7Richard Lowe	} else {
81010d63b7Richard Lowe		/*
81110d63b7Richard Lowe		 * This is for the case when the macro name did not
81210d63b7Richard Lowe		 * specify transforms.
81310d63b7Richard Lowe		 */
81410d63b7Richard Lowe		if (!strncmp(name->string_mb, "GET", 3)) {
81510d63b7Richard Lowe			dollarget_seen = true;
81610d63b7Richard Lowe		}