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