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