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