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