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