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