1/*-
2 * Copyright (c) 2002 Juli Mallett.
3 * Copyright (c) 1988, 1989, 1990, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 * Copyright (c) 1989 by Berkeley Softworks
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Adam de Boor.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)var.c	8.3 (Berkeley) 3/19/94
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD$");
44
45/**
46 * var.c --
47 *	Variable-handling functions
48 *
49 * Interface:
50 *	Var_Set		Set the value of a variable in the given
51 *			context. The variable is created if it doesn't
52 *			yet exist. The value and variable name need not
53 *			be preserved.
54 *
55 *	Var_Append	Append more characters to an existing variable
56 *			in the given context. The variable needn't
57 *			exist already -- it will be created if it doesn't.
58 *			A space is placed between the old value and the
59 *			new one.
60 *
61 *	Var_Exists	See if a variable exists.
62 *
63 *	Var_Value	Return the value of a variable in a context or
64 *			NULL if the variable is undefined.
65 *
66 *	Var_Subst	Substitute named variable, or all variables if
67 *			NULL in a string using
68 *			the given context as the top-most one. If the
69 *			third argument is non-zero, Parse_Error is
70 *			called if any variables are undefined.
71 *
72 *	Var_Parse	Parse a variable expansion from a string and
73 *			return the result and the number of characters
74 *			consumed.
75 *
76 *	Var_Delete	Delete a variable in a context.
77 *
78 *	Var_Init	Initialize this module.
79 *
80 * Debugging:
81 *	Var_Dump	Print out all variables defined in the given
82 *			context.
83 *
84 * XXX: There's a lot of duplication in these functions.
85 */
86
87#include <ctype.h>
88#include <stdlib.h>
89#include <string.h>
90#include <sys/types.h>
91#include <regex.h>
92
93#include "buf.h"
94#include "config.h"
95#include "globals.h"
96#include "GNode.h"
97#include "job.h"
98#include "lst.h"
99#include "parse.h"
100#include "str.h"
101#include "targ.h"
102#include "util.h"
103#include "var.h"
104
105/**
106 *
107 */
108typedef struct VarParser {
109	const char	*const input;	/* pointer to input string */
110	const char	*ptr;		/* current parser pos in input str */
111	GNode		*ctxt;
112	Boolean		err;
113	Boolean		execute;
114} VarParser;
115
116typedef struct Var {
117	char		*name;	/* the variable's name */
118	struct Buffer	*val;	/* its value */
119	int		flags;	/* miscellaneous status flags */
120
121#define	VAR_IN_USE	1	/* Variable's value currently being used.
122				 * Used to avoid recursion */
123
124#define	VAR_JUNK	4	/* Variable is a junk variable that
125				 * should be destroyed when done with
126				 * it. Used by Var_Parse for undefined,
127				 * modified variables */
128
129#define	VAR_TO_ENV	8	/* Place variable in environment */
130} Var;
131
132typedef struct {
133	struct Buffer	*lhs;	/* String to match */
134	struct Buffer	*rhs;	/* Replacement string (w/ &'s removed) */
135
136	regex_t			re;
137	int			nsub;
138	regmatch_t		*matches;
139
140	int	flags;
141#define	VAR_SUB_GLOBAL	0x01	/* Apply substitution globally */
142#define	VAR_SUB_ONE	0x02	/* Apply substitution to one word */
143#define	VAR_SUB_MATCHED	0x04	/* There was a match */
144#define	VAR_MATCH_START	0x08	/* Match at start of word */
145#define	VAR_MATCH_END	0x10	/* Match at end of word */
146} VarPattern;
147
148typedef Boolean VarModifyProc(const char *, Boolean, struct Buffer *, void *);
149
150static char *VarParse(VarParser *, Boolean *);
151
152/*
153 * This is a harmless return value for Var_Parse that can be used by Var_Subst
154 * to determine if there was an error in parsing -- easier than returning
155 * a flag, as things outside this module don't give a hoot.
156 */
157char	var_Error[] = "";
158
159/*
160 * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
161 * set false. Why not just use a constant? Well, gcc likes to condense
162 * identical string instances...
163 */
164static char	varNoError[] = "";
165
166/*
167 * Internally, variables are contained in four different contexts.
168 *	1) the environment. They may not be changed. If an environment
169 *	   variable is appended-to, the result is placed in the global
170 *	   context.
171 *	2) the global context. Variables set in the Makefile are located in
172 *	   the global context. It is the penultimate context searched when
173 *	   substituting.
174 *	3) the command-line context. All variables set on the command line
175 *	   are placed in this context. They are UNALTERABLE once placed here.
176 *	4) the local context. Each target has associated with it a context
177 *	   list. On this list are located the structures describing such
178 *	   local variables as $(@) and $(*)
179 * The four contexts are searched in the reverse order from which they are
180 * listed.
181 */
182static GNode	*VAR_ENV;	/* variables from the environment */
183GNode		*VAR_GLOBAL;	/* variables from the makefile */
184GNode		*VAR_CMD;	/* variables defined on the command-line */
185
186Boolean		oldVars;	/* variable substitution style */
187Boolean		checkEnvFirst;	/* -e flag */
188
189#define	OPEN_PAREN		'('
190#define	CLOSE_PAREN		')'
191#define	OPEN_BRACE		'{'
192#define	CLOSE_BRACE		'}'
193
194/**
195 * Create a Var object.
196 *
197 * Params:
198 *	name		Name of variable (copied).
199 *	value		Value of variable (copied) or NULL.
200 *	flags		Flags set on variable.
201 *
202 * Returns:
203 *	New variable.
204 */
205static Var *
206VarCreate(const char name[], const char value[], int flags)
207{
208	Var *v;
209
210	v = emalloc(sizeof(Var));
211	v->name = estrdup(name);
212	v->val = Buf_Init(0);
213	v->flags = flags;
214
215	if (value != NULL) {
216		Buf_Append(v->val, value);
217	}
218	return (v);
219}
220
221/**
222 * Destroy a Var object.
223 *
224 * Params:
225 *	v	Object to destroy.
226 *	f	True if internal buffer in Buffer object is to be removed.
227 */
228static void
229VarDestroy(Var *v, Boolean f)
230{
231
232	Buf_Destroy(v->val, f);
233	free(v->name);
234	free(v);
235}
236
237/**
238 * Remove the tail of the given word and place the result in the given
239 * buffer.
240 *
241 * Results:
242 *	TRUE if characters were added to the buffer (a space needs to be
243 *	added to the buffer before the next word).
244 *
245 * Side Effects:
246 *	The trimmed word is added to the buffer.
247 */
248static Boolean
249VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
250{
251	char *slash;
252
253	slash = strrchr(word, '/');
254	if (slash != NULL) {
255		if (addSpace) {
256			Buf_AddByte(buf, (Byte)' ');
257		}
258		Buf_AppendRange(buf, word, slash);
259	} else {
260		/*
261		 * If no directory part, give . (q.v. the POSIX standard)
262		 */
263		if (addSpace) {
264			Buf_Append(buf, " .");
265		} else {
266			Buf_AddByte(buf, (Byte)'.');
267		}
268	}
269	return (TRUE);
270}
271
272/**
273 * Remove the head of the given word and place the result in the given
274 * buffer.
275 *
276 * Results:
277 *	TRUE if characters were added to the buffer (a space needs to be
278 *	added to the buffer before the next word).
279 *
280 * Side Effects:
281 *	The trimmed word is added to the buffer.
282 */
283static Boolean
284VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
285{
286	const char *slash;
287
288	if (addSpace) {
289		Buf_AddByte (buf, (Byte)' ');
290	}
291
292	slash = strrchr(word, '/');
293	if (slash != NULL) {
294		slash++;
295		Buf_Append(buf, slash);
296	} else {
297		Buf_Append(buf, word);
298	}
299	return (TRUE);
300}
301
302/**
303 * Place the suffix of the given word in the given buffer.
304 *
305 * Results:
306 *	TRUE if characters were added to the buffer (a space needs to be
307 *	added to the buffer before the next word).
308 *
309 * Side Effects:
310 *	The suffix from the word is placed in the buffer.
311 */
312static Boolean
313VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
314{
315	const char *dot;
316
317	dot = strrchr(word, '.');
318	if (dot != NULL) {
319		if (addSpace) {
320			Buf_AddByte(buf, (Byte)' ');
321		}
322		dot++;
323		Buf_Append(buf, dot);
324		addSpace = TRUE;
325	}
326	return (addSpace);
327}
328
329/**
330 * Remove the suffix of the given word and place the result in the
331 * buffer.
332 *
333 * Results:
334 *	TRUE if characters were added to the buffer (a space needs to be
335 *	added to the buffer before the next word).
336 *
337 * Side Effects:
338 *	The trimmed word is added to the buffer.
339 */
340static Boolean
341VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
342{
343	char *dot;
344
345	if (addSpace) {
346		Buf_AddByte(buf, (Byte)' ');
347	}
348
349	dot = strrchr(word, '.');
350	if (dot != NULL) {
351		Buf_AppendRange(buf, word, dot);
352	} else {
353		Buf_Append(buf, word);
354	}
355	return (TRUE);
356}
357
358/**
359 * Place the word in the buffer if it matches the given pattern.
360 * Callback function for VarModify to implement the :M modifier.
361 * A space will be added if requested.  A pattern is supplied
362 * which the word must match.
363 *
364 * Results:
365 *	TRUE if a space should be placed in the buffer before the next
366 *	word.
367 *
368 * Side Effects:
369 *	The word may be copied to the buffer.
370 */
371static Boolean
372VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
373{
374
375	if (Str_Match(word, pattern)) {
376		if (addSpace) {
377			Buf_AddByte(buf, (Byte)' ');
378		}
379		addSpace = TRUE;
380		Buf_Append(buf, word);
381	}
382	return (addSpace);
383}
384
385#ifdef SYSVVARSUB
386/**
387 * Place the word in the buffer if it matches the given pattern.
388 * Callback function for VarModify to implement the System V %
389 * modifiers.  A space is added if requested.
390 *
391 * Results:
392 *	TRUE if a space should be placed in the buffer before the next
393 *	word.
394 *
395 * Side Effects:
396 *	The word may be copied to the buffer.
397 */
398static Boolean
399VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp)
400{
401	int		len;
402	const char	*ptr;
403	VarPattern	*pat = (VarPattern *)patp;
404
405	if (addSpace)
406		Buf_AddByte(buf, (Byte)' ');
407
408	addSpace = TRUE;
409
410	if ((ptr = Str_SYSVMatch(word, Buf_Data(pat->lhs), &len)) != NULL)
411		Str_SYSVSubst(buf, Buf_Data(pat->rhs), ptr, len);
412	else
413		Buf_Append(buf, word);
414
415	return (addSpace);
416}
417#endif
418
419/**
420 * Place the word in the buffer if it doesn't match the given pattern.
421 * Callback function for VarModify to implement the :N modifier.  A
422 * space is added if requested.
423 *
424 * Results:
425 *	TRUE if a space should be placed in the buffer before the next
426 *	word.
427 *
428 * Side Effects:
429 *	The word may be copied to the buffer.
430 */
431static Boolean
432VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
433{
434
435	if (!Str_Match(word, pattern)) {
436		if (addSpace) {
437			Buf_AddByte(buf, (Byte)' ');
438		}
439		addSpace = TRUE;
440		Buf_Append(buf, word);
441	}
442	return (addSpace);
443}
444
445/**
446 * Perform a string-substitution on the given word, placing the
447 * result in the passed buffer.  A space is added if requested.
448 *
449 * Results:
450 *	TRUE if a space is needed before more characters are added.
451 */
452static Boolean
453VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
454{
455	size_t		wordLen;	/* Length of word */
456	const char	*cp;		/* General pointer */
457	VarPattern	*pattern = patternp;
458
459	wordLen = strlen(word);
460	if (1) { /* substitute in each word of the variable */
461		/*
462		 * Break substitution down into simple anchored cases
463		 * and if none of them fits, perform the general substitution
464		 * case.
465		 */
466		if ((pattern->flags & VAR_MATCH_START) &&
467		   (strncmp(word, Buf_Data(pattern->lhs),
468		    Buf_Size(pattern->lhs)) == 0)) {
469			/*
470			 * Anchored at start and beginning of word matches
471			 * pattern.
472			 */
473			if ((pattern->flags & VAR_MATCH_END) &&
474			    (wordLen == Buf_Size(pattern->lhs))) {
475				/*
476				 * Also anchored at end and matches to the end
477				 * (word is same length as pattern) add space
478				 * and rhs only if rhs is non-null.
479				 */
480				if (Buf_Size(pattern->rhs) != 0) {
481					if (addSpace) {
482						Buf_AddByte(buf, (Byte)' ');
483					}
484					addSpace = TRUE;
485					Buf_AppendBuf(buf, pattern->rhs);
486				}
487
488			} else if (pattern->flags & VAR_MATCH_END) {
489				/*
490				 * Doesn't match to end -- copy word wholesale
491				 */
492				goto nosub;
493
494			} else {
495				/*
496				 * Matches at start but need to copy in
497				 * trailing characters.
498				 */
499				if ((Buf_Size(pattern->rhs) + wordLen -
500				    Buf_Size(pattern->lhs)) != 0) {
501					if (addSpace) {
502						Buf_AddByte(buf, (Byte)' ');
503					}
504					addSpace = TRUE;
505				}
506				Buf_AppendBuf(buf, pattern->rhs);
507				Buf_AddBytes(buf, wordLen -
508				    Buf_Size(pattern->lhs),
509				    (word + Buf_Size(pattern->lhs)));
510			}
511
512		} else if (pattern->flags & VAR_MATCH_START) {
513			/*
514			 * Had to match at start of word and didn't -- copy
515			 * whole word.
516			 */
517			goto nosub;
518
519		} else if (pattern->flags & VAR_MATCH_END) {
520			/*
521			 * Anchored at end, Find only place match could occur
522			 * (leftLen characters from the end of the word) and
523			 * see if it does. Note that because the $ will be
524			 * left at the end of the lhs, we have to use strncmp.
525			 */
526			cp = word + (wordLen - Buf_Size(pattern->lhs));
527			if ((cp >= word) && (strncmp(cp, Buf_Data(pattern->lhs),
528			    Buf_Size(pattern->lhs)) == 0)) {
529				/*
530				 * Match found. If we will place characters in
531				 * the buffer, add a space before hand as
532				 * indicated by addSpace, then stuff in the
533				 * initial, unmatched part of the word followed
534				 * by the right-hand-side.
535				 */
536				if ((cp - word) + Buf_Size(pattern->rhs) != 0) {
537					if (addSpace) {
538						Buf_AddByte(buf, (Byte)' ');
539					}
540					addSpace = TRUE;
541				}
542				Buf_AppendRange(buf, word, cp);
543				Buf_AppendBuf(buf, pattern->rhs);
544
545			} else {
546				/*
547				 * Had to match at end and didn't. Copy entire
548				 * word.
549				 */
550				goto nosub;
551			}
552		} else {
553			/*
554			 * Pattern is unanchored: search for the pattern in the
555			 * word using strstr(3), copying unmatched portions and
556			 * the right-hand-side for each match found, handling
557			 * non-global substitutions correctly, etc. When the
558			 * loop is done, any remaining part of the word (word
559			 * and wordLen are adjusted accordingly through the
560			 * loop) is copied straight into the buffer.
561			 * addSpace is set FALSE as soon as a space is added
562			 * to the buffer.
563			 */
564			Boolean done;
565			size_t origSize;
566
567			done = FALSE;
568			origSize = Buf_Size(buf);
569			while (!done) {
570				cp = strstr(word, Buf_Data(pattern->lhs));
571				if (cp != NULL) {
572					if (addSpace && (((cp - word) +
573					    Buf_Size(pattern->rhs)) != 0)) {
574						Buf_AddByte(buf, (Byte)' ');
575						addSpace = FALSE;
576					}
577					Buf_AppendRange(buf, word, cp);
578					Buf_AppendBuf(buf, pattern->rhs);
579					wordLen -= (cp - word) +
580					    Buf_Size(pattern->lhs);
581					word = cp + Buf_Size(pattern->lhs);
582					if (wordLen == 0 || (pattern->flags &
583					    VAR_SUB_GLOBAL) == 0) {
584						done = TRUE;
585					}
586				} else {
587					done = TRUE;
588				}
589			}
590			if (wordLen != 0) {
591				if (addSpace) {
592					Buf_AddByte(buf, (Byte)' ');
593				}
594				Buf_AddBytes(buf, wordLen, (const Byte *)word);
595			}
596
597			/*
598			 * If added characters to the buffer, need to add a
599			 * space before we add any more. If we didn't add any,
600			 * just return the previous value of addSpace.
601			 */
602			return ((Buf_Size(buf) != origSize) || addSpace);
603		}
604		/*
605		 * Common code for anchored substitutions:
606		 * addSpace was set TRUE if characters were added to the buffer.
607		 */
608		return (addSpace);
609	}
610  nosub:
611	if (addSpace) {
612		Buf_AddByte(buf, (Byte)' ');
613	}
614	Buf_AddBytes(buf, wordLen, (const Byte *)word);
615	return (TRUE);
616}
617
618/**
619 * Print the error caused by a regcomp or regexec call.
620 *
621 * Side Effects:
622 *	An error gets printed.
623 */
624static void
625VarREError(int err, regex_t *pat, const char *str)
626{
627	char   *errbuf;
628	int     errlen;
629
630	errlen = regerror(err, pat, 0, 0);
631	errbuf = emalloc(errlen);
632	regerror(err, pat, errbuf, errlen);
633	Error("%s: %s", str, errbuf);
634	free(errbuf);
635}
636
637
638/**
639 * Perform a regex substitution on the given word, placing the
640 * result in the passed buffer.  A space is added if requested.
641 *
642 * Results:
643 *	TRUE if a space is needed before more characters are added.
644 */
645static Boolean
646VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
647{
648	VarPattern	*pat;
649	int		xrv;
650	const char	*wp;
651	char		*rp;
652	int		added;
653	int		flags = 0;
654
655#define	MAYBE_ADD_SPACE()			\
656	if (addSpace && !added)			\
657		Buf_AddByte(buf, (Byte)' ');	\
658	added = 1
659
660	added = 0;
661	wp = word;
662	pat = patternp;
663
664	if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
665	    (VAR_SUB_ONE | VAR_SUB_MATCHED)) {
666		xrv = REG_NOMATCH;
667	} else {
668  tryagain:
669		xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
670	}
671
672	switch (xrv) {
673	  case 0:
674		pat->flags |= VAR_SUB_MATCHED;
675		if (pat->matches[0].rm_so > 0) {
676			MAYBE_ADD_SPACE();
677			Buf_AddBytes(buf, pat->matches[0].rm_so,
678			    (const Byte *)wp);
679		}
680
681		for (rp = Buf_Data(pat->rhs); *rp; rp++) {
682			if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
683				MAYBE_ADD_SPACE();
684				Buf_AddByte(buf, (Byte)rp[1]);
685				rp++;
686
687			} else if ((*rp == '&') ||
688			    ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
689				int	n;
690				const char *subbuf;
691				int	sublen;
692				char	errstr[3];
693
694				if (*rp == '&') {
695					n = 0;
696					errstr[0] = '&';
697					errstr[1] = '\0';
698				} else {
699					n = rp[1] - '0';
700					errstr[0] = '\\';
701					errstr[1] = rp[1];
702					errstr[2] = '\0';
703					rp++;
704				}
705
706				if (n > pat->nsub) {
707					Error("No subexpression %s",
708					    &errstr[0]);
709					subbuf = "";
710					sublen = 0;
711
712				} else if ((pat->matches[n].rm_so == -1) &&
713				    (pat->matches[n].rm_eo == -1)) {
714					Error("No match for subexpression %s",
715					    &errstr[0]);
716					subbuf = "";
717					sublen = 0;
718
719				} else {
720					subbuf = wp + pat->matches[n].rm_so;
721					sublen = pat->matches[n].rm_eo -
722					    pat->matches[n].rm_so;
723				}
724
725				if (sublen > 0) {
726					MAYBE_ADD_SPACE();
727					Buf_AddBytes(buf, sublen,
728					    (const Byte *)subbuf);
729				}
730			} else {
731				MAYBE_ADD_SPACE();
732				Buf_AddByte(buf, (Byte)*rp);
733			}
734		}
735		wp += pat->matches[0].rm_eo;
736		if (pat->flags & VAR_SUB_GLOBAL) {
737			flags |= REG_NOTBOL;
738			if (pat->matches[0].rm_so == 0 &&
739			    pat->matches[0].rm_eo == 0) {
740				MAYBE_ADD_SPACE();
741				Buf_AddByte(buf, (Byte)*wp);
742				wp++;
743			}
744			if (*wp)
745				goto tryagain;
746		}
747		if (*wp) {
748			MAYBE_ADD_SPACE();
749			Buf_Append(buf, wp);
750		}
751		break;
752
753	  default:
754		VarREError(xrv, &pat->re, "Unexpected regex error");
755		/* fall through */
756
757	  case REG_NOMATCH:
758		if (*wp) {
759			MAYBE_ADD_SPACE();
760			Buf_Append(buf, wp);
761		}
762		break;
763	}
764	return (addSpace || added);
765}
766
767/**
768 * Find a variable in a variable list.
769 */
770static Var *
771VarLookup(Lst *vlist, const char *name)
772{
773	LstNode	*ln;
774
775	LST_FOREACH(ln, vlist)
776		if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0)
777			return (Lst_Datum(ln));
778	return (NULL);
779}
780
781/**
782 * Expand a variable name's embedded variables in the given context.
783 *
784 * Results:
785 *	The contents of name, possibly expanded.
786 */
787static char *
788VarPossiblyExpand(const char *name, GNode *ctxt)
789{
790	Buffer	*buf;
791
792	if (strchr(name, '$') != NULL) {
793		buf = Var_Subst(name, ctxt, 0);
794		return (Buf_Peel(buf));
795	} else {
796		return estrdup(name);
797	}
798}
799
800/**
801 * If the variable name begins with a '.', it could very well be
802 * one of the local ones.  We check the name against all the local
803 * variables and substitute the short version in for 'name' if it
804 * matches one of them.
805 */
806static const char *
807VarLocal(const char name[])
808{
809	if (name[0] == '.') {
810		switch (name[1]) {
811		case 'A':
812			if (!strcmp(name, ".ALLSRC"))
813				return (ALLSRC);
814			if (!strcmp(name, ".ARCHIVE"))
815				return (ARCHIVE);
816			break;
817		case 'I':
818			if (!strcmp(name, ".IMPSRC"))
819				return (IMPSRC);
820			break;
821		case 'M':
822			if (!strcmp(name, ".MEMBER"))
823				return (MEMBER);
824			break;
825		case 'O':
826			if (!strcmp(name, ".OODATE"))
827				return (OODATE);
828			break;
829		case 'P':
830			if (!strcmp(name, ".PREFIX"))
831				return (PREFIX);
832			break;
833		case 'T':
834			if (!strcmp(name, ".TARGET"))
835				return (TARGET);
836			break;
837		default:
838			break;
839		}
840	}
841	return (name);
842}
843
844/**
845 * Find the given variable in the given context and the environment.
846 *
847 * Results:
848 *	A pointer to the structure describing the desired variable or
849 *	NULL if the variable does not exist.
850 */
851static Var *
852VarFindEnv(const char name[], GNode *ctxt)
853{
854	Var	*var;
855
856	name = VarLocal(name);
857
858	if ((var = VarLookup(&ctxt->context, name)) != NULL)
859		return (var);
860
861	if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
862		return (var);
863
864	return (NULL);
865}
866
867/**
868 * Look for the variable in the given context.
869 */
870static Var *
871VarFindOnly(const char name[], GNode *ctxt)
872{
873	Var	*var;
874
875	name = VarLocal(name);
876
877	if ((var = VarLookup(&ctxt->context, name)) != NULL)
878		return (var);
879
880	return (NULL);
881}
882
883/**
884 * Look for the variable in all contexts.
885 */
886static Var *
887VarFindAny(const char name[], GNode *ctxt)
888{
889	Boolean	localCheckEnvFirst;
890	LstNode	*ln;
891	Var	*var;
892
893	name = VarLocal(name);
894
895	/*
896	 * Note whether this is one of the specific variables we were told
897	 * through the -E flag to use environment-variable-override for.
898	 */
899	localCheckEnvFirst = FALSE;
900	LST_FOREACH(ln, &envFirstVars) {
901		if (strcmp(Lst_Datum(ln), name) == 0) {
902			localCheckEnvFirst = TRUE;
903			break;
904		}
905	}
906
907	/*
908	 * First look for the variable in the given context. If it's not there,
909	 * look for it in VAR_CMD, VAR_GLOBAL and the environment,
910	 * in that order, depending on the FIND_* flags in 'flags'
911	 */
912	if ((var = VarLookup(&ctxt->context, name)) != NULL)
913		return (var);
914
915	/* not there - try command line context */
916	if (ctxt != VAR_CMD) {
917		if ((var = VarLookup(&VAR_CMD->context, name)) != NULL)
918			return (var);
919	}
920
921	/* not there - try global context, but only if not -e/-E */
922	if (ctxt != VAR_GLOBAL && (!checkEnvFirst && !localCheckEnvFirst)) {
923		if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
924			return (var);
925	}
926
927	if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
928		return (var);
929
930	/* deferred check for the environment (in case of -e/-E) */
931	if ((ctxt != VAR_GLOBAL) && (checkEnvFirst || localCheckEnvFirst)) {
932		if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
933			return (var);
934	}
935
936	return (NULL);
937}
938
939/**
940 * Add a new variable of name name and value val to the given context.
941 *
942 * Side Effects:
943 *	The new variable is placed at the front of the given context
944 *	The name and val arguments are duplicated so they may
945 *	safely be freed.
946 */
947static Var *
948VarAdd(const char *name, const char *val, GNode *ctxt)
949{
950	Var *v;
951
952	Lst_AtFront(&ctxt->context, v = VarCreate(name, val, 0));
953	DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, name, val));
954	return (v);
955}
956
957/**
958 * Remove a variable from a context.
959 *
960 * Side Effects:
961 *	The Var structure is removed and freed.
962 */
963void
964Var_Delete(const char *name, GNode *ctxt)
965{
966	LstNode *ln;
967
968	DEBUGF(VAR, ("%s:delete %s\n", ctxt->name, name));
969	LST_FOREACH(ln, &ctxt->context) {
970		if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) {
971			VarDestroy(Lst_Datum(ln), TRUE);
972			Lst_Remove(&ctxt->context, ln);
973			break;
974		}
975	}
976}
977
978/**
979 * Set the variable name to the value val in the given context.
980 *
981 * Side Effects:
982 *	If the variable doesn't yet exist, a new record is created for it.
983 *	Else the old value is freed and the new one stuck in its place
984 *
985 * Notes:
986 *	The variable is searched for only in its context before being
987 *	created in that context. I.e. if the context is VAR_GLOBAL,
988 *	only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
989 *	VAR_CMD->context is searched. This is done to avoid the literally
990 *	thousands of unnecessary strcmp's that used to be done to
991 *	set, say, $(@) or $(<).
992 */
993void
994Var_Set(const char *name, const char *val, GNode *ctxt)
995{
996	Var    *v;
997	char   *n;
998
999	/*
1000	 * We only look for a variable in the given context since anything
1001	 * set here will override anything in a lower context, so there's not
1002	 * much point in searching them all just to save a bit of memory...
1003	 */
1004	n = VarPossiblyExpand(name, ctxt);
1005	v = VarFindOnly(n, ctxt);
1006	if (v == NULL) {
1007		v = VarAdd(n, val, ctxt);
1008	} else {
1009		Buf_Clear(v->val);
1010		Buf_Append(v->val, val);
1011		DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, val));
1012	}
1013
1014	if (ctxt == VAR_CMD || (v->flags & VAR_TO_ENV)) {
1015		/*
1016		 * Any variables given on the command line
1017		 * are automatically exported to the
1018		 * environment (as per POSIX standard)
1019		 */
1020		setenv(n, val, 1);
1021	}
1022
1023	free(n);
1024}
1025
1026/**
1027 * Set the a global name variable to the value.
1028 */
1029void
1030Var_SetGlobal(const char name[], const char value[])
1031{
1032
1033	Var_Set(name, value, VAR_GLOBAL);
1034}
1035
1036
1037/**
1038 * Set the VAR_TO_ENV flag on a variable
1039 */
1040void
1041Var_SetEnv(const char *name, GNode *ctxt)
1042{
1043	Var    *v;
1044
1045	v = VarFindOnly(name, VAR_CMD);
1046	if (v != NULL) {
1047		/*
1048		 * Do not allow .EXPORT: to be set on variables
1049		 * from the comand line or MAKEFLAGS.
1050		 */
1051		Error(
1052		    "Warning: Did not set .EXPORTVAR: on %s because it "
1053		    "is from the comand line or MAKEFLAGS", name);
1054		return;
1055	}
1056
1057	v = VarFindAny(name, ctxt);
1058	if (v == NULL) {
1059		Lst_AtFront(&VAR_ENV->context,
1060		    VarCreate(name, NULL, VAR_TO_ENV));
1061		setenv(name, "", 1);
1062		Error("Warning: .EXPORTVAR: set on undefined variable %s", name);
1063	} else {
1064		if ((v->flags & VAR_TO_ENV) == 0) {
1065			v->flags |= VAR_TO_ENV;
1066			setenv(v->name, Buf_Data(v->val), 1);
1067		}
1068	}
1069}
1070
1071/**
1072 * The variable of the given name has the given value appended to it in
1073 * the given context.
1074 *
1075 * Side Effects:
1076 *	If the variable doesn't exist, it is created. Else the strings
1077 *	are concatenated (with a space in between).
1078 *
1079 * Notes:
1080 *	Only if the variable is being sought in the global context is the
1081 *	environment searched.
1082 *	XXX: Knows its calling circumstances in that if called with ctxt
1083 *	an actual target, it will only search that context since only
1084 *	a local variable could be being appended to. This is actually
1085 *	a big win and must be tolerated.
1086 */
1087void
1088Var_Append(const char *name, const char *val, GNode *ctxt)
1089{
1090	Var	*v;
1091	char	*n;
1092
1093	n = VarPossiblyExpand(name, ctxt);
1094	if (ctxt == VAR_GLOBAL) {
1095		v = VarFindEnv(n, ctxt);
1096	} else {
1097		v = VarFindOnly(n, ctxt);
1098	}
1099	if (v == NULL) {
1100		VarAdd(n, val, ctxt);
1101	} else {
1102		Buf_AddByte(v->val, (Byte)' ');
1103		Buf_Append(v->val, val);
1104		DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val)));
1105	}
1106	free(n);
1107}
1108
1109/**
1110 * See if the given variable exists.
1111 *
1112 * Results:
1113 *	TRUE if it does, FALSE if it doesn't
1114 */
1115Boolean
1116Var_Exists(const char *name, GNode *ctxt)
1117{
1118	Var	*v;
1119	char	*n;
1120
1121	n = VarPossiblyExpand(name, ctxt);
1122	v = VarFindAny(n, ctxt);
1123	if (v == NULL) {
1124		free(n);
1125		return (FALSE);
1126	} else {
1127		free(n);
1128		return (TRUE);
1129	}
1130}
1131
1132/**
1133 * Return the value of the named variable in the given context
1134 *
1135 * Results:
1136 *	The value if the variable exists, NULL if it doesn't.
1137 */
1138const char *
1139Var_Value(const char name[], GNode *ctxt)
1140{
1141	Var	*v;
1142	char	*n;
1143
1144	n = VarPossiblyExpand(name, ctxt);
1145	v = VarFindAny(n, ctxt);
1146	free(n);
1147	if (v == NULL) {
1148		return (NULL);
1149	} else {
1150		return (Buf_Data(v->val));
1151	}
1152}
1153
1154/**
1155 * Modify each of the words of the passed string using the given
1156 * function. Used to implement all modifiers.
1157 *
1158 * Results:
1159 *	A string of all the words modified appropriately.
1160 *
1161 * Side Effects:
1162 *	Uses brk_string() so it invalidates any previous call to
1163 *	brk_string().
1164 */
1165static char *
1166VarModify(const char *str, VarModifyProc *modProc, void *datum)
1167{
1168	ArgArray	aa;
1169	Buffer		*buf;		/* Buffer for the new string */
1170	int		i;
1171	Boolean		addSpace;	/*
1172					 * TRUE if need to add a space to
1173					 * the buffer before adding the
1174					 * trimmed word
1175					 */
1176
1177	brk_string(&aa, str, FALSE);
1178
1179	addSpace = FALSE;
1180	buf = Buf_Init(0);
1181	for (i = 1; i < aa.argc; i++)
1182		addSpace = (*modProc)(aa.argv[i], addSpace, buf, datum);
1183
1184	ArgArray_Done(&aa);
1185	return (Buf_Peel(buf));
1186}
1187
1188/**
1189 * Sort the words in the string.
1190 *
1191 * Input:
1192 *	str		String whose words should be sorted
1193 *	cmp		A comparison function to control the ordering
1194 *
1195 * Results:
1196 *	A string containing the words sorted
1197 */
1198static char *
1199VarSortWords(const char *str, int (*cmp)(const void *, const void *))
1200{
1201	ArgArray	aa;
1202	Buffer		*buf;
1203	int		i;
1204
1205	brk_string(&aa, str, FALSE);
1206	qsort(aa.argv + 1, aa.argc - 1, sizeof(char *), cmp);
1207
1208	buf = Buf_Init(0);
1209	for (i = 1; i < aa.argc; i++) {
1210		Buf_Append(buf, aa.argv[i]);
1211		Buf_AddByte(buf, (Byte)((i < aa.argc - 1) ? ' ' : '\0'));
1212	}
1213
1214	ArgArray_Done(&aa);
1215	return (Buf_Peel(buf));
1216}
1217
1218static int
1219SortIncreasing(const void *l, const void *r)
1220{
1221
1222	return (strcmp(*(const char* const*)l, *(const char* const*)r));
1223}
1224
1225/**
1226 * Remove adjacent duplicate words.
1227 *
1228 * Results:
1229 *	A string containing the resulting words.
1230 */
1231static char *
1232VarUniq(const char *str)
1233{
1234	ArgArray	aa;
1235	Buffer		*buf;		    /* Buffer for new string */
1236	int		i, j;
1237
1238	buf = Buf_Init(0);
1239	brk_string(&aa, str, FALSE);
1240
1241	if (aa.argc > 2) {
1242		for (j = 1, i = 2; i < aa.argc; i++) {
1243			if (strcmp(aa.argv[i], aa.argv[j]) != 0 && (++j != i))
1244				aa.argv[j] = aa.argv[i];
1245		}
1246		aa.argc = j + 1;
1247	}
1248
1249	for (i = 1; i < aa.argc; i++) {
1250		Buf_AddBytes(buf, strlen(aa.argv[i]), (Byte *)aa.argv[i]);
1251		if (i != aa.argc - 1)
1252			Buf_AddByte(buf, ' ');
1253	}
1254	Buf_AddByte(buf, '\0');
1255
1256	ArgArray_Done(&aa);
1257	return (Buf_Peel(buf));
1258}
1259
1260/**
1261 * Pass through the tstr looking for 1) escaped delimiters,
1262 * '$'s and backslashes (place the escaped character in
1263 * uninterpreted) and 2) unescaped $'s that aren't before
1264 * the delimiter (expand the variable substitution).
1265 * Return the expanded string or NULL if the delimiter was missing
1266 * If pattern is specified, handle escaped ampersands, and replace
1267 * unescaped ampersands with the lhs of the pattern.
1268 *
1269 * Results:
1270 *	A string of all the words modified appropriately.
1271 *	If length is specified, return the string length of the buffer
1272 *	If flags is specified and the last character of the pattern is a
1273 *	$ set the VAR_MATCH_END bit of flags.
1274 */
1275static Buffer *
1276VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt)
1277{
1278	Buffer		*buf;
1279
1280	buf = Buf_Init(0);
1281
1282	/*
1283	 * Skim through until the matching delimiter is found; pick up
1284	 * variable substitutions on the way. Also allow backslashes to quote
1285	 * the delimiter, $, and \, but don't touch other backslashes.
1286	 */
1287	while (*vp->ptr != '\0') {
1288		if (*vp->ptr == delim) {
1289			return (buf);
1290
1291		} else if ((vp->ptr[0] == '\\') &&
1292		    ((vp->ptr[1] == delim) ||
1293		     (vp->ptr[1] == '\\') ||
1294		     (vp->ptr[1] == '$') ||
1295		     (vp->ptr[1] == '&' && patt != NULL))) {
1296			vp->ptr++;		/* consume backslash */
1297			Buf_AddByte(buf, (Byte)vp->ptr[0]);
1298			vp->ptr++;
1299
1300		} else if (vp->ptr[0] == '$') {
1301			if (vp->ptr[1] == delim) {
1302				if (flags == NULL) {
1303					Buf_AddByte(buf, (Byte)vp->ptr[0]);
1304					vp->ptr++;
1305				} else {
1306					/*
1307					 * Unescaped $ at end of patt =>
1308					 * anchor patt at end.
1309					 */
1310					*flags |= VAR_MATCH_END;
1311					vp->ptr++;
1312				}
1313			} else {
1314				VarParser	subvp = {
1315					vp->ptr,
1316					vp->ptr,
1317					vp->ctxt,
1318					vp->err,
1319					vp->execute
1320				};
1321				char   *rval;
1322				Boolean rfree;
1323
1324				/*
1325				 * If unescaped dollar sign not
1326				 * before the delimiter, assume it's
1327				 * a variable substitution and
1328				 * recurse.
1329				 */
1330				rval = VarParse(&subvp, &rfree);
1331				Buf_Append(buf, rval);
1332				if (rfree)
1333					free(rval);
1334				vp->ptr = subvp.ptr;
1335			}
1336		} else if (vp->ptr[0] == '&' && patt != NULL) {
1337			Buf_AppendBuf(buf, patt->lhs);
1338			vp->ptr++;
1339		} else {
1340			Buf_AddByte(buf, (Byte)vp->ptr[0]);
1341			vp->ptr++;
1342		}
1343	}
1344
1345	Buf_Destroy(buf, TRUE);
1346	return (NULL);
1347}
1348
1349/**
1350 * Make sure this variable is fully expanded.
1351 */
1352static char *
1353VarExpand(Var *v, VarParser *vp)
1354{
1355	char	*value;
1356	char	*result;
1357
1358	if (v->flags & VAR_IN_USE) {
1359		Fatal("Variable %s is recursive.", v->name);
1360		/* NOTREACHED */
1361	}
1362
1363	v->flags |= VAR_IN_USE;
1364
1365	/*
1366	 * Before doing any modification, we have to make sure the
1367	 * value has been fully expanded. If it looks like recursion
1368	 * might be necessary (there's a dollar sign somewhere in the
1369	 * variable's value) we just call Var_Subst to do any other
1370	 * substitutions that are necessary. Note that the value
1371	 * returned by Var_Subst will have been
1372	 * dynamically-allocated, so it will need freeing when we
1373	 * return.
1374	 */
1375	value = Buf_Data(v->val);
1376	if (strchr(value, '$') == NULL) {
1377		result = strdup(value);
1378	} else {
1379		Buffer	*buf;
1380
1381		buf = Var_Subst(value, vp->ctxt, vp->err);
1382		result = Buf_Peel(buf);
1383	}
1384
1385	v->flags &= ~VAR_IN_USE;
1386
1387	return (result);
1388}
1389
1390/**
1391 * Select only those words in value that match the modifier.
1392 */
1393static char *
1394modifier_M(VarParser *vp, const char value[], char endc)
1395{
1396	char	*patt;
1397	char	*ptr;
1398	char	*newValue;
1399	char	modifier;
1400
1401	modifier = vp->ptr[0];
1402	vp->ptr++;	/* consume 'M' or 'N' */
1403
1404	/*
1405	 * Compress the \:'s out of the pattern, so allocate enough
1406	 * room to hold the uncompressed pattern and compress the
1407	 * pattern into that space.
1408	 */
1409	patt = estrdup(vp->ptr);
1410	ptr = patt;
1411	while (vp->ptr[0] != '\0') {
1412		if (vp->ptr[0] == endc || vp->ptr[0] == ':') {
1413			break;
1414		}
1415		if (vp->ptr[0] == '\\' &&
1416		    (vp->ptr[1] == endc || vp->ptr[1] == ':')) {
1417			vp->ptr++;	/* consume backslash */
1418		}
1419		*ptr = vp->ptr[0];
1420		ptr++;
1421		vp->ptr++;
1422	}
1423	*ptr = '\0';
1424	DEBUGF(VAR, ("Pattern :%s\n", patt));
1425
1426	if (modifier == 'M') {
1427		newValue = VarModify(value, VarMatch, patt);
1428	} else {
1429		newValue = VarModify(value, VarNoMatch, patt);
1430	}
1431	free(patt);
1432
1433	return (newValue);
1434}
1435
1436/**
1437 * Substitute the replacement string for the pattern.  The substitution
1438 * is applied to each word in value.
1439 */
1440static char *
1441modifier_S(VarParser *vp, const char value[], Var *v)
1442{
1443	VarPattern	patt;
1444	char		delim;
1445	char		*newValue;
1446
1447	patt.flags = 0;
1448
1449	vp->ptr++;		/* consume 'S' */
1450
1451	delim = *vp->ptr;	/* used to find end of pattern */
1452	vp->ptr++;		/* consume 1st delim */
1453
1454	/*
1455	 * If pattern begins with '^', it is anchored to the start of the
1456	 * word -- skip over it and flag pattern.
1457	 */
1458	if (*vp->ptr == '^') {
1459		patt.flags |= VAR_MATCH_START;
1460		vp->ptr++;
1461	}
1462
1463	patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL);
1464	if (patt.lhs == NULL) {
1465		/*
1466		 * LHS didn't end with the delim, complain and exit.
1467		 */
1468		Fatal("Unclosed substitution for %s (%c missing)",
1469		    v->name, delim);
1470	}
1471
1472	vp->ptr++;	/* consume 2nd delim */
1473
1474	patt.rhs = VarGetPattern(vp, delim, NULL, &patt);
1475	if (patt.rhs == NULL) {
1476		/*
1477		 * RHS didn't end with the delim, complain and exit.
1478		 */
1479		Fatal("Unclosed substitution for %s (%c missing)",
1480		    v->name, delim);
1481	}
1482
1483	vp->ptr++;	/* consume last delim */
1484
1485	/*
1486	 * Check for global substitution. If 'g' after the final delimiter,
1487	 * substitution is global and is marked that way.
1488	 */
1489	if (vp->ptr[0] == 'g') {
1490		patt.flags |= VAR_SUB_GLOBAL;
1491		vp->ptr++;
1492	}
1493
1494	/*
1495	 * Global substitution of the empty string causes an infinite number
1496	 * of matches, unless anchored by '^' (start of string) or '$' (end
1497	 * of string). Catch the infinite substitution here. Note that flags
1498	 * can only contain the 3 bits we're interested in so we don't have
1499	 * to mask unrelated bits. We can test for equality.
1500	 */
1501	if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL)
1502		Fatal("Global substitution of the empty string");
1503
1504	newValue = VarModify(value, VarSubstitute, &patt);
1505
1506	/*
1507	 * Free the two strings.
1508	 */
1509	free(patt.lhs);
1510	free(patt.rhs);
1511
1512	return (newValue);
1513}
1514
1515static char *
1516modifier_C(VarParser *vp, char value[], Var *v)
1517{
1518	VarPattern	patt;
1519	char		delim;
1520	int		error;
1521	char		*newValue;
1522
1523	patt.flags = 0;
1524
1525	vp->ptr++;		/* consume 'C' */
1526
1527	delim = *vp->ptr;	/* delimiter between sections */
1528
1529	vp->ptr++;		/* consume 1st delim */
1530
1531	patt.lhs = VarGetPattern(vp, delim, NULL, NULL);
1532	if (patt.lhs == NULL) {
1533		Fatal("Unclosed substitution for %s (%c missing)",
1534		     v->name, delim);
1535	}
1536
1537	vp->ptr++;		/* consume 2st delim */
1538
1539	patt.rhs = VarGetPattern(vp, delim, NULL, NULL);
1540	if (patt.rhs == NULL) {
1541		Fatal("Unclosed substitution for %s (%c missing)",
1542		     v->name, delim);
1543	}
1544
1545	vp->ptr++;		/* consume last delim */
1546
1547	switch (*vp->ptr) {
1548	case 'g':
1549		patt.flags |= VAR_SUB_GLOBAL;
1550		vp->ptr++;		/* consume 'g' */
1551		break;
1552	case '1':
1553		patt.flags |= VAR_SUB_ONE;
1554		vp->ptr++;		/* consume '1' */
1555		break;
1556	default:
1557		break;
1558	}
1559
1560	error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED);
1561	if (error) {
1562		VarREError(error, &patt.re, "RE substitution error");
1563		free(patt.rhs);
1564		free(patt.lhs);
1565		return (var_Error);
1566	}
1567
1568	patt.nsub = patt.re.re_nsub + 1;
1569	if (patt.nsub < 1)
1570		patt.nsub = 1;
1571	if (patt.nsub > 10)
1572		patt.nsub = 10;
1573	patt.matches = emalloc(patt.nsub * sizeof(regmatch_t));
1574
1575	newValue = VarModify(value, VarRESubstitute, &patt);
1576
1577	regfree(&patt.re);
1578	free(patt.matches);
1579	free(patt.rhs);
1580	free(patt.lhs);
1581
1582	return (newValue);
1583}
1584
1585static char *
1586sysVvarsub(VarParser *vp, char startc, Var *v, const char value[])
1587{
1588#ifdef SYSVVARSUB
1589	/*
1590	 * This can either be a bogus modifier or a System-V substitution
1591	 * command.
1592	 */
1593	char		endc;
1594	VarPattern	patt;
1595	Boolean		eqFound;
1596	int		cnt;
1597	char		*newStr;
1598	const char	*cp;
1599
1600	endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1601
1602	patt.flags = 0;
1603
1604	/*
1605	 * First we make a pass through the string trying to verify it is a
1606	 * SYSV-make-style translation: it must be: <string1>=<string2>)
1607	 */
1608	eqFound = FALSE;
1609	cp = vp->ptr;
1610	cnt = 1;
1611	while (*cp != '\0' && cnt) {
1612		if (*cp == '=') {
1613			eqFound = TRUE;
1614			/* continue looking for endc */
1615		} else if (*cp == endc)
1616			cnt--;
1617		else if (*cp == startc)
1618			cnt++;
1619		if (cnt)
1620			cp++;
1621	}
1622
1623	if (*cp == endc && eqFound) {
1624		/*
1625		 * Now we break this sucker into the lhs and rhs.
1626		 */
1627		patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL);
1628		if (patt.lhs == NULL) {
1629			Fatal("Unclosed substitution for %s (%c missing)",
1630			      v->name, '=');
1631		}
1632		vp->ptr++;	/* consume '=' */
1633
1634		patt.rhs = VarGetPattern(vp, endc, NULL, &patt);
1635		if (patt.rhs == NULL) {
1636			Fatal("Unclosed substitution for %s (%c missing)",
1637			      v->name, endc);
1638		}
1639
1640		/*
1641		 * SYSV modifications happen through the whole string. Note
1642		 * the pattern is anchored at the end.
1643		 */
1644		newStr = VarModify(value, VarSYSVMatch, &patt);
1645
1646		free(patt.lhs);
1647		free(patt.rhs);
1648	} else
1649#endif
1650	{
1651		Error("Unknown modifier '%c'\n", *vp->ptr);
1652		vp->ptr++;
1653		while (*vp->ptr != '\0') {
1654			if (*vp->ptr == endc && *vp->ptr == ':') {
1655				break;
1656			}
1657			vp->ptr++;
1658		}
1659		newStr = var_Error;
1660	}
1661
1662	return (newStr);
1663}
1664
1665/**
1666 * Quote shell meta-characters in the string
1667 *
1668 * Results:
1669 *	The quoted string
1670 */
1671static char *
1672Var_Quote(const char *str)
1673{
1674	Buffer *buf;
1675	/* This should cover most shells :-( */
1676	static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1677
1678	buf = Buf_Init(MAKE_BSIZE);
1679	for (; *str; str++) {
1680		if (strchr(meta, *str) != NULL)
1681			Buf_AddByte(buf, (Byte)'\\');
1682		Buf_AddByte(buf, (Byte)*str);
1683	}
1684
1685	return (Buf_Peel(buf));
1686}
1687
1688
1689/*
1690 * Now we need to apply any modifiers the user wants applied.
1691 * These are:
1692 *	:M<pattern>
1693 *		words which match the given <pattern>.
1694 *		<pattern> is of the standard file
1695 *		wildcarding form.
1696 *	:N<pattern>
1697 *		words which do not match the given <pattern>
1698 *		<pattern> is of the standard file
1699 *		wildcarding form.
1700 *	:S<d><pat1><d><pat2><d>[g]
1701 *		Substitute <pat2> for <pat1> in the value
1702 *	:C<d><pat1><d><pat2><d>[g]
1703 *		Substitute <pat2> for regex <pat1> in the value
1704 *	:H	Substitute the head of each word
1705 *	:T	Substitute the tail of each word
1706 *	:E	Substitute the extension (minus '.') of
1707 *		each word
1708 *	:R	Substitute the root of each word
1709 *		(pathname minus the suffix).
1710 *	:lhs=rhs
1711 *		Like :S, but the rhs goes to the end of
1712 *		the invocation.
1713 *	:U	Converts variable to upper-case.
1714 *	:L	Converts variable to lower-case.
1715 *	:O	("Order") Alphabeticaly sort words in variable.
1716 *	:u	("uniq") Remove adjacent duplicate words.
1717 */
1718static char *
1719ParseModifier(VarParser *vp, char startc, Var *v, Boolean *freeResult)
1720{
1721	char	*value;
1722	char	endc;
1723
1724	value = VarExpand(v, vp);
1725	*freeResult = TRUE;
1726
1727	endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1728
1729	vp->ptr++;	/* consume first colon */
1730
1731	while (*vp->ptr != '\0') {
1732		char	*newStr;	/* New value to return */
1733
1734		if (*vp->ptr == endc) {
1735			return (value);
1736		}
1737
1738		DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value));
1739		switch (*vp->ptr) {
1740		case 'N':
1741		case 'M':
1742			newStr = modifier_M(vp, value, endc);
1743			break;
1744		case 'S':
1745			newStr = modifier_S(vp, value, v);
1746			break;
1747		case 'C':
1748			newStr = modifier_C(vp, value, v);
1749			break;
1750		case 't':
1751			/* :tl :tu for OSF ODE & NetBSD make compatibility */
1752			switch (vp->ptr[1]) {
1753			case 'l':
1754				vp->ptr++;
1755				goto mod_lower;
1756				break;
1757			case 'u':
1758				vp->ptr++;
1759				goto mod_upper;
1760				break;
1761			}
1762			/* FALLTHROUGH */
1763		default:
1764			if (vp->ptr[1] != endc && vp->ptr[1] != ':') {
1765#ifdef SUNSHCMD
1766				if ((vp->ptr[0] == 's') &&
1767				    (vp->ptr[1] == 'h') &&
1768				    (vp->ptr[2] == endc || vp->ptr[2] == ':')) {
1769					const char	*error = NULL;
1770
1771					if (vp->execute) {
1772						newStr = Buf_Peel(
1773						    Cmd_Exec(value, &error));
1774					} else {
1775						newStr = estrdup("");
1776					}
1777
1778					if (error)
1779						Error(error, value);
1780					vp->ptr += 2;
1781				} else
1782#endif
1783				{
1784					newStr = sysVvarsub(vp, startc, v, value);
1785				}
1786				break;
1787			}
1788
1789			switch (vp->ptr[0]) {
1790			case 'L':
1791			mod_lower:
1792				{
1793				const char	*cp;
1794				Buffer		*buf;
1795				buf = Buf_Init(MAKE_BSIZE);
1796				for (cp = value; *cp; cp++)
1797					Buf_AddByte(buf, (Byte)tolower(*cp));
1798
1799				newStr = Buf_Peel(buf);
1800
1801				vp->ptr++;
1802				break;
1803				}
1804			case 'O':
1805				newStr = VarSortWords(value, SortIncreasing);
1806				vp->ptr++;
1807				break;
1808			case 'Q':
1809				newStr = Var_Quote(value);
1810				vp->ptr++;
1811				break;
1812			case 'T':
1813				newStr = VarModify(value, VarTail, NULL);
1814				vp->ptr++;
1815				break;
1816			case 'U':
1817			mod_upper:
1818				{
1819				const char	*cp;
1820				Buffer		*buf;
1821				buf = Buf_Init(MAKE_BSIZE);
1822				for (cp = value; *cp; cp++)
1823					Buf_AddByte(buf, (Byte)toupper(*cp));
1824
1825				newStr = Buf_Peel(buf);
1826
1827				vp->ptr++;
1828				break;
1829				}
1830			case 'H':
1831				newStr = VarModify(value, VarHead, NULL);
1832				vp->ptr++;
1833				break;
1834			case 'E':
1835				newStr = VarModify(value, VarSuffix, NULL);
1836				vp->ptr++;
1837				break;
1838			case 'R':
1839				newStr = VarModify(value, VarRoot, NULL);
1840				vp->ptr++;
1841				break;
1842			case 'u':
1843				newStr = VarUniq(value);
1844				vp->ptr++;
1845				break;
1846			default:
1847				newStr = sysVvarsub(vp, startc, v, value);
1848				break;
1849			}
1850			break;
1851		}
1852
1853		DEBUGF(VAR, ("Result is \"%s\"\n", newStr));
1854		if (*freeResult) {
1855			free(value);
1856		}
1857
1858		value = newStr;
1859		*freeResult = (value == var_Error) ? FALSE : TRUE;
1860
1861		if (vp->ptr[0] == ':') {
1862			vp->ptr++;	/* consume colon */
1863		}
1864	}
1865
1866	return (value);
1867}
1868
1869static char *
1870ParseRestModifier(VarParser *vp, char startc, Buffer *buf, Boolean *freeResult)
1871{
1872	const char	*vname;
1873	size_t		vlen;
1874	Var		*v;
1875	char		*value;
1876
1877	vname = Buf_GetAll(buf, &vlen);
1878
1879	v = VarFindAny(vname, vp->ctxt);
1880	if (v != NULL) {
1881		value = ParseModifier(vp, startc, v, freeResult);
1882		return (value);
1883	}
1884
1885	if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1886		size_t  consumed;
1887		/*
1888		 * Still need to get to the end of the variable
1889		 * specification, so kludge up a Var structure for the
1890		 * modifications
1891		 */
1892		v = VarCreate(vname, NULL, VAR_JUNK);
1893		value = ParseModifier(vp, startc, v, freeResult);
1894		if (*freeResult) {
1895			free(value);
1896		}
1897		VarDestroy(v, TRUE);
1898
1899		consumed = vp->ptr - vp->input + 1;
1900		/*
1901		 * If substituting a local variable in a non-local context,
1902		 * assume it's for dynamic source stuff. We have to handle
1903		 * this specially and return the longhand for the variable
1904		 * with the dollar sign escaped so it makes it back to the
1905		 * caller. Only four of the local variables are treated
1906		 * specially as they are the only four that will be set when
1907		 * dynamic sources are expanded.
1908		 */
1909		if (vlen == 1 ||
1910		    (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1911			if (strchr("!%*@", vname[0]) != NULL) {
1912				value = emalloc(consumed + 1);
1913				strncpy(value, vp->input, consumed);
1914				value[consumed] = '\0';
1915
1916				*freeResult = TRUE;
1917				return (value);
1918			}
1919		}
1920		if (vlen > 2 &&
1921		    vname[0] == '.' &&
1922		    isupper((unsigned char)vname[1])) {
1923			if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1924			    (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1925			    (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1926			    (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1927				value = emalloc(consumed + 1);
1928				strncpy(value, vp->input, consumed);
1929				value[consumed] = '\0';
1930
1931				*freeResult = TRUE;
1932				return (value);
1933			}
1934		}
1935
1936		*freeResult = FALSE;
1937		return (vp->err ? var_Error : varNoError);
1938	} else {
1939		/*
1940		 * Check for D and F forms of local variables since we're in
1941		 * a local context and the name is the right length.
1942		 */
1943		if (vlen == 2 &&
1944		    (vname[1] == 'F' || vname[1] == 'D') &&
1945		    (strchr("!%*<>@", vname[0]) != NULL)) {
1946			char	name[2];
1947
1948			name[0] = vname[0];
1949			name[1] = '\0';
1950
1951			v = VarFindOnly(name, vp->ctxt);
1952			if (v != NULL) {
1953				value = ParseModifier(vp, startc, v, freeResult);
1954				return (value);
1955			}
1956		}
1957
1958		/*
1959		 * Still need to get to the end of the variable
1960		 * specification, so kludge up a Var structure for the
1961		 * modifications
1962		 */
1963		v = VarCreate(vname, NULL, VAR_JUNK);
1964		value = ParseModifier(vp, startc, v, freeResult);
1965		if (*freeResult) {
1966			free(value);
1967		}
1968		VarDestroy(v, TRUE);
1969
1970		*freeResult = FALSE;
1971		return (vp->err ? var_Error : varNoError);
1972	}
1973}
1974
1975static char *
1976ParseRestEnd(VarParser *vp, Buffer *buf, Boolean *freeResult)
1977{
1978	const char	*vname;
1979	size_t		vlen;
1980	Var		*v;
1981	char		*value;
1982
1983	vname = Buf_GetAll(buf, &vlen);
1984
1985	v = VarFindAny(vname, vp->ctxt);
1986	if (v != NULL) {
1987		value = VarExpand(v, vp);
1988		*freeResult = TRUE;
1989		return (value);
1990	}
1991
1992	if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1993		size_t	consumed = vp->ptr - vp->input + 1;
1994
1995		/*
1996		 * If substituting a local variable in a non-local context,
1997		 * assume it's for dynamic source stuff. We have to handle
1998		 * this specially and return the longhand for the variable
1999		 * with the dollar sign escaped so it makes it back to the
2000		 * caller. Only four of the local variables are treated
2001		 * specially as they are the only four that will be set when
2002		 * dynamic sources are expanded.
2003		 */
2004		if (vlen == 1 ||
2005		    (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
2006			if (strchr("!%*@", vname[0]) != NULL) {
2007				value = emalloc(consumed + 1);
2008				strncpy(value, vp->input, consumed);
2009				value[consumed] = '\0';
2010
2011				*freeResult = TRUE;
2012				return (value);
2013			}
2014		}
2015		if (vlen > 2 &&
2016		    vname[0] == '.' &&
2017		    isupper((unsigned char)vname[1])) {
2018			if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
2019			    (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
2020			    (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
2021			    (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
2022				value = emalloc(consumed + 1);
2023				strncpy(value, vp->input, consumed);
2024				value[consumed] = '\0';
2025
2026				*freeResult = TRUE;
2027				return (value);
2028			}
2029		}
2030	} else {
2031		/*
2032		 * Check for D and F forms of local variables since we're in
2033		 * a local context and the name is the right length.
2034		 */
2035		if (vlen == 2 &&
2036		    (vname[1] == 'F' || vname[1] == 'D') &&
2037		    (strchr("!%*<>@", vname[0]) != NULL)) {
2038			char	name[2];
2039
2040			name[0] = vname[0];
2041			name[1] = '\0';
2042
2043			v = VarFindOnly(name, vp->ctxt);
2044			if (v != NULL) {
2045				char	*val;
2046				/*
2047				 * No need for nested expansion or anything,
2048				 * as we're the only one who sets these
2049				 * things and we sure don't put nested
2050				 * invocations in them...
2051				 */
2052				val = Buf_Data(v->val);
2053
2054				if (vname[1] == 'D') {
2055					val = VarModify(val, VarHead, NULL);
2056				} else {
2057					val = VarModify(val, VarTail, NULL);
2058				}
2059
2060				*freeResult = TRUE;
2061				return (val);
2062			}
2063		}
2064	}
2065
2066	*freeResult = FALSE;
2067	return (vp->err ? var_Error : varNoError);
2068}
2069
2070/**
2071 * Parse a multi letter variable name, and return it's value.
2072 */
2073static char *
2074VarParseLong(VarParser *vp, Boolean *freeResult)
2075{
2076	Buffer		*buf;
2077	char		startc;
2078	char		endc;
2079	char		*value;
2080
2081	buf = Buf_Init(MAKE_BSIZE);
2082
2083	startc = vp->ptr[0];
2084	vp->ptr++;		/* consume opening paren or brace */
2085
2086	endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
2087
2088	/*
2089	 * Process characters until we reach an end character or a colon,
2090	 * replacing embedded variables as we go.
2091	 */
2092	while (*vp->ptr != '\0') {
2093		if (*vp->ptr == endc) {
2094			value = ParseRestEnd(vp, buf, freeResult);
2095			vp->ptr++;	/* consume closing paren or brace */
2096			Buf_Destroy(buf, TRUE);
2097			return (value);
2098
2099		} else if (*vp->ptr == ':') {
2100			value = ParseRestModifier(vp, startc, buf, freeResult);
2101			vp->ptr++;	/* consume closing paren or brace */
2102			Buf_Destroy(buf, TRUE);
2103			return (value);
2104
2105		} else if (*vp->ptr == '$') {
2106			VarParser	subvp = {
2107				vp->ptr,
2108				vp->ptr,
2109				vp->ctxt,
2110				vp->err,
2111				vp->execute
2112			};
2113			char	*rval;
2114			Boolean	rfree;
2115
2116			rval = VarParse(&subvp, &rfree);
2117			if (rval == var_Error) {
2118				Fatal("Error expanding embedded variable.");
2119			}
2120			Buf_Append(buf, rval);
2121			if (rfree)
2122				free(rval);
2123			vp->ptr = subvp.ptr;
2124		} else {
2125			Buf_AddByte(buf, (Byte)*vp->ptr);
2126			vp->ptr++;
2127		}
2128	}
2129
2130	/* If we did not find the end character, return var_Error */
2131	Buf_Destroy(buf, TRUE);
2132	*freeResult = FALSE;
2133	return (var_Error);
2134}
2135
2136/**
2137 * Parse a single letter variable name, and return it's value.
2138 */
2139static char *
2140VarParseShort(VarParser *vp, Boolean *freeResult)
2141{
2142	char	vname[2];
2143	Var	*v;
2144	char	*value;
2145
2146	vname[0] = vp->ptr[0];
2147	vname[1] = '\0';
2148
2149	vp->ptr++;	/* consume single letter */
2150
2151	v = VarFindAny(vname, vp->ctxt);
2152	if (v != NULL) {
2153		value = VarExpand(v, vp);
2154		*freeResult = TRUE;
2155		return (value);
2156	}
2157
2158	/*
2159	 * If substituting a local variable in a non-local context, assume
2160	 * it's for dynamic source stuff. We have to handle this specially
2161	 * and return the longhand for the variable with the dollar sign
2162	 * escaped so it makes it back to the caller. Only four of the local
2163	 * variables are treated specially as they are the only four that
2164	 * will be set when dynamic sources are expanded.
2165	 */
2166	if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
2167
2168		/* XXX: It looks like $% and $! are reversed here */
2169		switch (vname[0]) {
2170		case '@':
2171			*freeResult = TRUE;
2172			return (estrdup("$(.TARGET)"));
2173		case '%':
2174			*freeResult = TRUE;
2175			return (estrdup("$(.ARCHIVE)"));
2176		case '*':
2177			*freeResult = TRUE;
2178			return (estrdup("$(.PREFIX)"));
2179		case '!':
2180			*freeResult = TRUE;
2181			return (estrdup("$(.MEMBER)"));
2182		default:
2183			*freeResult = FALSE;
2184			return (vp->err ? var_Error : varNoError);
2185		}
2186	}
2187
2188	/* Variable name was not found. */
2189	*freeResult = FALSE;
2190	return (vp->err ? var_Error : varNoError);
2191}
2192
2193static char *
2194VarParse(VarParser *vp, Boolean *freeResult)
2195{
2196
2197	vp->ptr++;	/* consume '$' or last letter of conditional */
2198
2199	if (vp->ptr[0] == '\0') {
2200		/* Error, there is only a dollar sign in the input string. */
2201		*freeResult = FALSE;
2202		return (vp->err ? var_Error : varNoError);
2203
2204	} else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) {
2205		/* multi letter variable name */
2206		return (VarParseLong(vp, freeResult));
2207
2208	} else {
2209		/* single letter variable name */
2210		return (VarParseShort(vp, freeResult));
2211	}
2212}
2213
2214/**
2215 * Given the start of a variable invocation, extract the variable
2216 * name and find its value, then modify it according to the
2217 * specification.
2218 *
2219 * Results:
2220 *	The value of the variable or var_Error if the specification
2221 *	is invalid.  The number of characters in the specification
2222 *	is placed in the variable pointed to by consumed.  (for
2223 *	invalid specifications, this is just 2 to skip the '$' and
2224 *	the following letter, or 1 if '$' was the last character
2225 *	in the string).  A Boolean in *freeResult telling whether the
2226 *	returned string should be freed by the caller.
2227 */
2228char *
2229Var_Parse(const char input[], GNode *ctxt, Boolean err,
2230	size_t *consumed, Boolean *freeResult)
2231{
2232	VarParser	vp = {
2233		input,
2234		input,
2235		ctxt,
2236		err,
2237		TRUE
2238	};
2239	char		*value;
2240
2241	value = VarParse(&vp, freeResult);
2242	*consumed += vp.ptr - vp.input;
2243	return (value);
2244}
2245
2246/*
2247 * Given the start of a variable invocation, determine the length
2248 * of the specification.
2249 *
2250 * Results:
2251 *	The number of characters in the specification.  For invalid
2252 *	specifications, this is just 2 to skip the '$' and the
2253 *	following letter, or 1 if '$' was the last character in the
2254 *	string.
2255 */
2256size_t
2257Var_Match(const char input[], GNode *ctxt)
2258{
2259	VarParser	vp = {
2260		input,
2261		input,
2262		ctxt,
2263		FALSE,
2264		FALSE
2265	};
2266	char		*value;
2267	Boolean		freeResult;
2268
2269	value = VarParse(&vp, &freeResult);
2270	if (freeResult) {
2271		free(value);
2272	}
2273	return (vp.ptr - vp.input);
2274}
2275
2276static int
2277match_var(const char str[], const char var[])
2278{
2279	const char	*start = str;
2280	size_t		len;
2281
2282	str++;			/* consume '$' */
2283
2284	if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) {
2285		str++;		/* consume opening paren or brace */
2286
2287		while (str[0] != '\0') {
2288			if (str[0] == '$') {
2289				/*
2290				 * A variable inside the variable. We cannot
2291				 * expand the external variable yet.
2292				 */
2293				return (str - start);
2294			} else if (str[0] == ':' ||
2295				   str[0] == CLOSE_PAREN ||
2296				   str[0] == CLOSE_BRACE) {
2297				len = str - (start + 2);
2298
2299				if (strncmp(var, start + 2, len) == 0 && var[len] == '\0') {
2300					return (0);	/* match */
2301				} else {
2302					/*
2303					 * Not the variable we want to
2304					 * expand.
2305					 */
2306					return (str - start);
2307				}
2308			} else {
2309				++str;
2310			}
2311		}
2312		return (str - start);
2313	} else {
2314		/* Single letter variable name */
2315		if (var[1] == '\0' && var[0] == str[0]) {
2316			return (0);	/* match */
2317		} else {
2318			str++;	/* consume variable name */
2319			return (str - start);
2320		}
2321	}
2322}
2323
2324/**
2325 * Substitute for all variables in the given string in the given
2326 * context If err is TRUE, Parse_Error will be called when an
2327 * undefined variable is encountered.
2328 *
2329 * Results:
2330 *	The resulting string.
2331 *
2332 * Side Effects:
2333 *	None. The old string must be freed by the caller
2334 */
2335Buffer *
2336Var_Subst(const char *str, GNode *ctxt, Boolean err)
2337{
2338	Boolean	errorReported;
2339	Buffer *buf;		/* Buffer for forming things */
2340
2341	/*
2342	 * Set TRUE if an error has already been reported to prevent a
2343	 * plethora of messages when recursing. XXXHB this comment sounds
2344	 * wrong.
2345	 */
2346	errorReported = FALSE;
2347
2348	buf = Buf_Init(0);
2349	while (str[0] != '\0') {
2350		if ((str[0] == '$') && (str[1] == '$')) {
2351			/*
2352			 * A dollar sign may be escaped with another dollar
2353			 * sign.  In such a case, we skip over the escape
2354			 * character and store the dollar sign into the
2355			 * buffer directly.
2356			 */
2357			str++;
2358			Buf_AddByte(buf, (Byte)str[0]);
2359			str++;
2360
2361		} else if (str[0] == '$') {
2362			/* Variable invocation. */
2363			VarParser subvp = {
2364				str,
2365				str,
2366				ctxt,
2367				err,
2368				TRUE
2369			};
2370			char	*rval;
2371			Boolean	rfree;
2372
2373			rval = VarParse(&subvp, &rfree);
2374
2375			/*
2376			 * When we come down here, val should either point to
2377			 * the value of this variable, suitably modified, or
2378			 * be NULL. Length should be the total length of the
2379			 * potential variable invocation (from $ to end
2380			 * character...)
2381			 */
2382			if (rval == var_Error || rval == varNoError) {
2383				/*
2384				 * If performing old-time variable
2385				 * substitution, skip over the variable and
2386				 * continue with the substitution. Otherwise,
2387				 * store the dollar sign and advance str so
2388				 * we continue with the string...
2389				 */
2390				if (oldVars) {
2391					str = subvp.ptr;
2392				} else if (err) {
2393					/*
2394					 * If variable is undefined, complain
2395					 * and skip the variable. The
2396					 * complaint will stop us from doing
2397					 * anything when the file is parsed.
2398					 */
2399					if (!errorReported) {
2400						Parse_Error(PARSE_FATAL,
2401							    "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2402					}
2403					errorReported = TRUE;
2404					str = subvp.ptr;
2405				} else {
2406					Buf_AddByte(buf, (Byte)str[0]);
2407					str++;
2408				}
2409			} else {
2410				/*
2411				 * Copy all the characters from the variable
2412				 * value straight into the new string.
2413				 */
2414				Buf_Append(buf, rval);
2415				if (rfree) {
2416					free(rval);
2417				}
2418				str = subvp.ptr;
2419			}
2420		} else {
2421			Buf_AddByte(buf, (Byte)str[0]);
2422			str++;
2423		}
2424	}
2425
2426	return (buf);
2427}
2428
2429/**
2430 * Substitute for all variables except if it is the same as 'var',
2431 * in the given string in the given context.  If err is TRUE,
2432 * Parse_Error will be called when an undefined variable is
2433 * encountered.
2434 *
2435 * Results:
2436 *	The resulting string.
2437 *
2438 * Side Effects:
2439 *	None. The old string must be freed by the caller
2440 */
2441Buffer *
2442Var_SubstOnly(const char *var, const char *str, Boolean err)
2443{
2444	GNode *ctxt = VAR_GLOBAL;
2445	Boolean	errorReported;
2446	Buffer	*buf;		/* Buffer for forming things */
2447
2448	/*
2449	 * Set TRUE if an error has already been reported to prevent a
2450	 * plethora of messages when recursing. XXXHB this comment sounds
2451	 * wrong.
2452	 */
2453	errorReported = FALSE;
2454
2455	buf = Buf_Init(0);
2456	while (str[0] != '\0') {
2457		if (str[0] == '$') {
2458			int	skip;
2459
2460			skip = match_var(str, var);
2461			if (skip > 0) {
2462				Buf_AddBytes(buf, skip, str);
2463				str += skip;
2464			} else {
2465				/* Variable invocation. */
2466				VarParser	subvp = {
2467					str,
2468					str,
2469					ctxt,
2470					err,
2471					TRUE
2472				};
2473				char	*rval;
2474				Boolean	rfree;
2475
2476				rval = VarParse(&subvp, &rfree);
2477
2478				/*
2479				 * When we get down here, rval should either
2480				 * point to the value of this variable, or be
2481				 * NULL.
2482				 */
2483				if (rval == var_Error || rval == varNoError) {
2484					/*
2485					 * If performing old-time variable
2486					 * substitution, skip over the
2487					 * variable and continue with the
2488					 * substitution. Otherwise, store the
2489					 * dollar sign and advance str so we
2490					 * continue with the string...
2491					 */
2492					if (oldVars) {
2493						str = subvp.ptr;
2494					} else if (err) {
2495						/*
2496						 * If variable is undefined,
2497						 * complain and skip the
2498						 * variable. The complaint
2499						 * will stop us from doing
2500						 * anything when the file is
2501						 * parsed.
2502						 */
2503						if (!errorReported) {
2504							Parse_Error(PARSE_FATAL,
2505								    "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2506						}
2507						errorReported = TRUE;
2508						str = subvp.ptr;
2509					} else {
2510						Buf_AddByte(buf, (Byte)str[0]);
2511						str++;
2512					}
2513				} else {
2514					/*
2515					 * Copy all the characters from the
2516					 * variable value straight into the
2517					 * new string.
2518					 */
2519					Buf_Append(buf, rval);
2520					if (rfree) {
2521						free(rval);
2522					}
2523					str = subvp.ptr;
2524				}
2525			}
2526		} else {
2527			Buf_AddByte(buf, (Byte)str[0]);
2528			str++;
2529		}
2530	}
2531
2532	return (buf);
2533}
2534
2535/**
2536 * Initialize the module
2537 *
2538 * Side Effects:
2539 *	The VAR_CMD and VAR_GLOBAL contexts are created
2540 */
2541void
2542Var_Init(char **env)
2543{
2544	char	**ptr;
2545
2546	VAR_CMD = Targ_NewGN("Command");
2547	VAR_ENV = Targ_NewGN("Environment");
2548	VAR_GLOBAL = Targ_NewGN("Global");
2549
2550	/*
2551	 * Copy user environment variables into ENV context.
2552	 */
2553	for (ptr = env; *ptr != NULL; ++ptr) {
2554		char		*tmp = estrdup(*ptr);
2555		const char	*name = tmp;
2556		char		*sep = strchr(name, '=');
2557		const char	*value = sep + 1;
2558
2559		if (sep != NULL) {
2560			*sep = '\0';
2561			VarAdd(name, value, VAR_ENV);
2562		}
2563		free(tmp);
2564	}
2565}
2566
2567/**
2568 * Print all variables in global and command line contexts.
2569 */
2570void
2571Var_Dump(void)
2572{
2573	const LstNode	*ln;
2574	const Var	*v;
2575
2576	printf("#*** Global Variables:\n");
2577	LST_FOREACH(ln, &VAR_GLOBAL->context) {
2578		v = Lst_Datum(ln);
2579		printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2580	}
2581
2582	printf("#*** Command-line Variables:\n");
2583	LST_FOREACH(ln, &VAR_CMD->context) {
2584		v = Lst_Datum(ln);
2585		printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2586	}
2587}
2588
2589/**
2590 * Print the values of any variables requested by
2591 * the user.
2592 */
2593void
2594Var_Print(Lst *vlist, Boolean expandVars)
2595{
2596	LstNode		*n;
2597	char		*name;
2598
2599	LST_FOREACH(n, vlist) {
2600		name = Lst_Datum(n);
2601		if (expandVars) {
2602			char *value;
2603			char *v;
2604
2605			if (*name == '$') {
2606				v = name;
2607			} else {
2608				v = emalloc(strlen(name) + 1 + 3);
2609				sprintf(v, "${%s}", name);
2610			}
2611			value = Buf_Peel(Var_Subst(v, VAR_GLOBAL, FALSE));
2612			printf("%s\n", value);
2613
2614			if (v != name)
2615				free(v);
2616			free(value);
2617		} else {
2618			const char *value = Var_Value(name, VAR_GLOBAL);
2619			printf("%s\n", value != NULL ? value : "");
2620		}
2621	}
2622}
2623
2624