ln = Lst_Find(ctxt->context, VarCmp, name);
ln = Lst_Find(&ctxt->context, VarCmp, name);
static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, void *), void *));static void VarPrintVar __P((void *));static Boolean VarUppercase __P((char *word, Boolean addSpace, Buffer buf, void *dummy));static Boolean VarLowercase __P((char *word, Boolean addSpace, Buffer buf, void *dummy));/*- *----------------------------------------------------------------------- * VarCmp  -- *	See if the given variable matches the named one. Called from *	Lst_Find when searching for a variable of a given name. * * Results: *	0 if they match. non-zero otherwise. * * Side Effects: *	none *----------------------------------------------------------------------- */static intVarCmp(v, name)    void *v;		/* VAR structure to compare */    void *name;		/* name to look for */{    return strcmp((char *)name, ((Var *)v)->name);}/*- *----------------------------------------------------------------------- * VarFind -- *	Find the given variable in the given context and any other contexts *	indicated. * * Results: *	A pointer to the structure describing the desired variable or *	NULL if the variable does not exist. * * Side Effects: *	Caches env variables in the VAR_ENV context. *----------------------------------------------------------------------- */static Var *VarFind (name, ctxt, flags)    char           	*name;	/* name to find */    GNode          	*ctxt;	/* context in which to find it */    int             	flags;	/* FIND_GLOBAL set means to look in the				 * VAR_GLOBAL context as well.				 * FIND_CMD set means to look in the VAR_CMD				 * context also.				 * FIND_ENV set means to look in the				 * environment/VAR_ENV context.  */{    LstNode         	var;    Var		  	*v;	/*	 * If the variable name begins with a '.', it could very well be one of	 * the local ones.  We check the name against all the local variables	 * and substitute the short version in for 'name' if it matches one of	 * them.	 */	if (*name == '.' && isupper((unsigned char) name[1]))		switch (name[1]) {		case 'A':			if (!strcmp(name, ".ALLSRC"))				name = ALLSRC;			if (!strcmp(name, ".ARCHIVE"))				name = ARCHIVE;			break;		case 'I':			if (!strcmp(name, ".IMPSRC"))				name = IMPSRC;			break;		case 'M':			if (!strcmp(name, ".MEMBER"))				name = MEMBER;			break;		case 'O':			if (!strcmp(name, ".OODATE"))				name = OODATE;			break;		case 'P':			if (!strcmp(name, ".PREFIX"))				name = PREFIX;			break;		case 'T':			if (!strcmp(name, ".TARGET"))				name = TARGET;			break;		}    /*     * First look for the variable in the given context. If it's not there,     * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,     * depending on the FIND_* flags in 'flags'     */    var = Lst_Find(ctxt->context, VarCmp, name);    if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD))	var = Lst_Find(VAR_CMD->context, VarCmp, name);    if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) &&	(ctxt != VAR_GLOBAL)) {	var = Lst_Find(VAR_GLOBAL->context, VarCmp, name);    }    if ((var == NULL) && (flags & FIND_ENV)) {    	var = Lst_Find(VAR_ENV->context, VarCmp, name);	if (var == NULL) {	    char *env;	    if ((env = getenv(name)) != NULL)	    	return VarAdd(name, env, VAR_ENV);	}    }    if (var == NULL && checkEnvFirst && (flags & FIND_GLOBAL) &&		   (ctxt != VAR_GLOBAL)) 	    var = Lst_Find(VAR_GLOBAL->context, VarCmp, name);    if (var == NULL)	return NULL;    else 	return (Var *)Lst_Datum(var);}/*- *----------------------------------------------------------------------- * VarAdd  -- *	Add a new variable of name name and value val to the given context * * Results: *	The added variable * * Side Effects: *	The new variable is placed at the front of the given context *	The name and val arguments are duplicated so they may *	safely be freed. *----------------------------------------------------------------------- */static Var *VarAdd(name, val, ctxt)    char           *name;	/* name of variable to add */    char           *val;	/* value to set it to */    GNode          *ctxt;	/* context in which to set it */{    register Var   *v;    int	    	  len;    v = (Var *) emalloc (sizeof (Var));    v->name = estrdup (name);    len = val ? strlen(val) : 0;    Buf_Init(&(v->val), len+1);    Buf_AddChars(&(v->val), len, val);    v->flags = 0;    Lst_AtFront(ctxt->context, v);    Lst_AtEnd(allVars, v);    if (DEBUG(VAR)) {	printf("%s:%s = %s\n", ctxt->name, name, val);    }    return v;}/*- *----------------------------------------------------------------------- * VarDelete  -- *	Delete a variable and all the space associated with it. * * Results: *	None * * Side Effects: *	None *----------------------------------------------------------------------- */static voidVarDelete(vp)    void *vp;{    Var *v = (Var *) vp;    free(v->name);    Buf_Destroy(&(v->val));    free(v);}/*- *----------------------------------------------------------------------- * Var_Delete -- *	Remove a variable from a context. * * Results: *	None. * * Side Effects: *	The Var structure is removed and freed. * *----------------------------------------------------------------------- */voidVar_Delete(name, ctxt)    char    	  *name;    GNode	  *ctxt;{    LstNode 	  ln;    if (DEBUG(VAR)) {	printf("%s:delete %s\n", ctxt->name, name);    }    ln = Lst_Find(ctxt->context, VarCmp, name);    if (ln != NULL) {	register Var 	  *v;	v = (Var *)Lst_Datum(ln);	Lst_Remove(ctxt->context, ln);	ln = Lst_Member(allVars, v);	Lst_Remove(allVars, ln);	VarDelete(v);    }}/*- *----------------------------------------------------------------------- * Var_Set -- *	Set the variable name to the value val in the given context. * * Results: *	None. * * Side Effects: *	If the variable doesn't yet exist, a new record is created for it. *	Else the old value is freed and the new one stuck in its place * * Notes: *	The variable is searched for only in its context before being *	created in that context. I.e. if the context is VAR_GLOBAL, *	only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only *	VAR_CMD->context is searched. This is done to avoid the literally *	thousands of unnecessary strcmp's that used to be done to *	set, say, $(@) or $(<). *----------------------------------------------------------------------- */voidVar_Set (name, val, ctxt)    char           *name;	/* name of variable to set */    char           *val;	/* value to give to the variable */    GNode          *ctxt;	/* context in which to set it */{    register Var   *v;    /*     * We only look for a variable in the given context since anything set     * here will override anything in a lower context, so there's not much     * point in searching them all just to save a bit of memory...     */    v = VarFind (name, ctxt, 0);    if (v == NULL) {	(void)VarAdd(name, val, ctxt);    } else {	Buf_Reset(&(v->val));	Buf_AddString(&(v->val), val);	if (DEBUG(VAR)) {	    printf("%s:%s = %s\n", ctxt->name, name, val);	}    }    /*     * Any variables given on the command line are automatically exported     * to the environment (as per POSIX standard).       * We put them into the env cache directly.     * (Note that additions to VAR_CMD occur very early, so VAR_ENV is     * actually empty at this point).     */    if (ctxt == VAR_CMD) {	setenv(name, val, 1);	(void)VarAdd(name, val, VAR_ENV);    }}/*- *----------------------------------------------------------------------- * Var_Append -- *	The variable of the given name has the given value appended to it in *	the given context. * * Results: *	None * * Side Effects: *	If the variable doesn't exist, it is created. Else the strings *	are concatenated (with a space in between). * * Notes: *	Only if the variable is being sought in the global context is the *	environment searched. *	XXX: Knows its calling circumstances in that if called with ctxt *	an actual target, it will only search that context since only *	a local variable could be being appended to. This is actually *	a big win and must be tolerated. *----------------------------------------------------------------------- */voidVar_Append (name, val, ctxt)    char           *name;	/* Name of variable to modify */    char           *val;	/* String to append to it */    GNode          *ctxt;	/* Context in which this should occur */{    register Var   *v;    v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);    if (v == NULL) {	(void)VarAdd(name, val, ctxt);    } else {	Buf_AddSpace(&(v->val));	Buf_AddString(&(v->val), val);	if (DEBUG(VAR)) {	    printf("%s:%s = %s\n", ctxt->name, name, VarValue(v));	}    }}/*- *----------------------------------------------------------------------- * Var_Exists -- *	See if the given variable exists. * * Results: *	TRUE if it does, FALSE if it doesn't * * Side Effects: *	None. * *----------------------------------------------------------------------- */BooleanVar_Exists(name, ctxt)    char	  *name;    	/* Variable to find */    GNode	  *ctxt;    	/* Context in which to start search */{    Var	    	  *v;    v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);    if (v == NULL)	return FALSE;    else	return TRUE;}/*- *----------------------------------------------------------------------- * Var_Value -- *	Return the value of the named variable in the given context * * Results: *	The value if the variable exists, NULL if it doesn't * * Side Effects: *	None *----------------------------------------------------------------------- */char *Var_Value(name, ctxt)    char           *name;	/* name to find */    GNode          *ctxt;	/* context in which to search for it */{    Var            *v;    v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);    if (v != NULL) 	return VarValue(v);    else	return NULL;}/*- *----------------------------------------------------------------------- * VarUppercase -- *	Place the Upper cased word in the given buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The word is added to the buffer. * *----------------------------------------------------------------------- */static BooleanVarUppercase (word, addSpace, buf, dummy)    char    	  *word;    	/* Word to Upper Case */    Boolean 	  addSpace; 	/* True if need to add a space to the buffer				 * before sticking in the head */    Buffer  	  buf;	    	/* Buffer in which to store it */    void *dummy;{    size_t len = strlen(word);    if (addSpace)	Buf_AddSpace(buf);    while (len--)    	Buf_AddChar(buf, toupper(*word++));    return (TRUE);}/*- *----------------------------------------------------------------------- * VarLowercase -- *	Place the Lower cased word in the given buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The word is added to the buffer. * *----------------------------------------------------------------------- */static BooleanVarLowercase (word, addSpace, buf, dummy)    char    	  *word;    	/* Word to Lower Case */    Boolean 	  addSpace; 	/* True if need to add a space to the buffer				 * before sticking in the head */    Buffer  	  buf;	    	/* Buffer in which to store it */    void *dummy;{    size_t len = strlen(word);    if (addSpace)	Buf_AddSpace(buf);    while (len--)    	Buf_AddChar(buf, tolower(*word++));    return (TRUE);}/*- *----------------------------------------------------------------------- * VarHead -- *	Remove the tail of the given word and place the result in the given *	buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The trimmed word is added to the buffer. * *----------------------------------------------------------------------- */static BooleanVarHead(word, addSpace, buf, dummy)    char    	  *word;    	/* Word to trim */    Boolean 	  addSpace; 	/* True if need to add a space to the buffer				 * before sticking in the head */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *dummy;{    register char *slash;    slash = strrchr(word, '/');    if (slash != NULL) {	if (addSpace)	    Buf_AddSpace(buf);	Buf_AddInterval(buf, word, slash);	return (TRUE);    } else {	/* If no directory part, give . (q.v. the POSIX standard) */	if (addSpace)	    Buf_AddString(buf, " .");	else	    Buf_AddChar(buf, '.');    }    return(dummy ? TRUE : TRUE);}/*- *----------------------------------------------------------------------- * VarTail -- *	Remove the head of the given word and place the result in the given *	buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The trimmed word is added to the buffer. * *----------------------------------------------------------------------- */static BooleanVarTail(word, addSpace, buf, dummy)    char    	  *word;    	/* Word to trim */    Boolean 	  addSpace; 	/* TRUE if need to stick a space in the				 * buffer before adding the tail */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *dummy;{    register char *slash;    if (addSpace) 	Buf_AddSpace(buf);    slash = strrchr(word, '/');    if (slash != NULL)	Buf_AddString(buf, slash+1);    else	Buf_AddString(buf, word);    return (dummy ? TRUE : TRUE);}/*- *----------------------------------------------------------------------- * VarSuffix -- *	Place the suffix of the given word in the given buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The suffix from the word is placed in the buffer. * *----------------------------------------------------------------------- */static BooleanVarSuffix(word, addSpace, buf, dummy)    char    	  *word;    	/* Word to trim */    Boolean 	  addSpace; 	/* TRUE if need to add a space before placing				 * the suffix in the buffer */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *dummy;{    char *dot;    dot = strrchr(word, '.');    if (dot != NULL) {	if (addSpace)	    Buf_AddSpace(buf);	Buf_AddString(buf, dot+1);	addSpace = TRUE;    }    return (dummy ? addSpace : addSpace);}/*- *----------------------------------------------------------------------- * VarRoot -- *	Remove the suffix of the given word and place the result in the *	buffer. * * Results: *	TRUE if characters were added to the buffer (a space needs to be *	added to the buffer before the next word). * * Side Effects: *	The trimmed word is added to the buffer. * *----------------------------------------------------------------------- */static BooleanVarRoot(word, addSpace, buf, dummy)    char    	  *word;    	/* Word to trim */    Boolean 	  addSpace; 	/* TRUE if need to add a space to the buffer				 * before placing the root in it */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *dummy;{    char *dot;    if (addSpace)	Buf_AddSpace(buf);    dot = strrchr(word, '.');    if (dot != NULL)	Buf_AddInterval(buf, word, dot);    else	Buf_AddString(buf, word);    return (dummy ? TRUE : TRUE);}/*- *----------------------------------------------------------------------- * VarMatch -- *	Place the word in the buffer if it matches the given pattern. *	Callback function for VarModify to implement the :M modifier. * * Results: *	TRUE if a space should be placed in the buffer before the next *	word. * * Side Effects: *	The word may be copied to the buffer. * *----------------------------------------------------------------------- */static BooleanVarMatch(word, addSpace, buf, pattern)    char    	  *word;    	/* Word to examine */    Boolean 	  addSpace; 	/* TRUE if need to add a space to the				 * buffer before adding the word, if it				 * matches */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *pattern; 	/* Pattern the word must match */{    if (Str_Match(word, (char *) pattern)) {	if (addSpace)	    Buf_AddSpace(buf);	addSpace = TRUE;	Buf_AddString(buf, word);    }    return(addSpace);}#ifdef SYSVVARSUB/*- *----------------------------------------------------------------------- * VarSYSVMatch -- *	Place the word in the buffer if it matches the given pattern. *	Callback function for VarModify to implement the System V % *	modifiers. * * Results: *	TRUE if a space should be placed in the buffer before the next *	word. * * Side Effects: *	The word may be copied to the buffer. * *----------------------------------------------------------------------- */static BooleanVarSYSVMatch(word, addSpace, buf, patp)    char    	  *word;    	/* Word to examine */    Boolean 	  addSpace; 	/* TRUE if need to add a space to the				 * buffer before adding the word, if it				 * matches */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *patp; 	/* Pattern the word must match */{    int len;    char *ptr;    VarPattern 	  *pat = (VarPattern *) patp;    if (*word) {	    if (addSpace)		Buf_AddSpace(buf);	    addSpace = TRUE;	    if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)		Str_SYSVSubst(buf, pat->rhs, ptr, len);	    else		Buf_AddString(buf, word);    }    return(addSpace);}#endif/*- *----------------------------------------------------------------------- * VarNoMatch -- *	Place the word in the buffer if it doesn't match the given pattern. *	Callback function for VarModify to implement the :N modifier. * * Results: *	TRUE if a space should be placed in the buffer before the next *	word. * * Side Effects: *	The word may be copied to the buffer. * *----------------------------------------------------------------------- */static BooleanVarNoMatch(word, addSpace, buf, pattern)    char    	  *word;    	/* Word to examine */    Boolean 	  addSpace; 	/* TRUE if need to add a space to the				 * buffer before adding the word, if it				 * matches */    Buffer  	  buf;	    	/* Buffer in which to store it */    void 	  *pattern; 	/* Pattern the word must match */{    if (!Str_Match(word, (char *) pattern)) {	if (addSpace)	    Buf_AddSpace(buf);	addSpace = TRUE;	Buf_AddString(buf, word);    }    return(addSpace);}/*- *----------------------------------------------------------------------- * VarSubstitute -- *	Perform a string-substitution on the given word, placing the *	result in the passed buffer. * * Results: *	TRUE if a space is needed before more characters are added. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static BooleanVarSubstitute(word, addSpace, buf, patternp)    char    	  	*word;	    /* Word to modify */    Boolean 	  	addSpace;   /* True if space should be added before				     * other characters */    Buffer  	  	buf;	    /* Buffer for result */    void 		*patternp;  /* Pattern for substitution */{    register size_t  	wordLen;    /* Length of word */    register char 	*cp;	    /* General pointer */    VarPattern	*pattern = (VarPattern *) patternp;    wordLen = strlen(word);    if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=	(VAR_SUB_ONE|VAR_SUB_MATCHED)) {	/*	 * Still substituting -- break it down into simple anchored cases	 * and if none of them fits, perform the general substitution case.	 */	if ((pattern->flags & VAR_MATCH_START) &&	    (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {		/*		 * Anchored at start and beginning of word matches pattern		 */		if ((pattern->flags & VAR_MATCH_END) &&		    (wordLen == pattern->leftLen)) {			/*			 * Also anchored at end and matches to the end (word			 * is same length as pattern) add space and rhs only			 * if rhs is non-null.			 */			if (pattern->rightLen != 0) {			    if (addSpace)				Buf_AddSpace(buf);			    addSpace = TRUE;			    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);			}			pattern->flags |= VAR_SUB_MATCHED;		} else if (pattern->flags & VAR_MATCH_END) {		    /*		     * Doesn't match to end -- copy word wholesale		     */		    goto nosub;		} else {		    /*		     * Matches at start but need to copy in trailing characters		     */		    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){			if (addSpace)			    Buf_AddSpace(buf);			addSpace = TRUE;		    }		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);		    Buf_AddChars(buf, wordLen - pattern->leftLen,				 word + pattern->leftLen);		    pattern->flags |= VAR_SUB_MATCHED;		}	} else if (pattern->flags & VAR_MATCH_START) {	    /*	     * Had to match at start of word and didn't -- copy whole word.	     */	    goto nosub;	} else if (pattern->flags & VAR_MATCH_END) {	    /*	     * Anchored at end, Find only place match could occur (leftLen	     * characters from the end of the word) and see if it does. Note	     * that because the $ will be left at the end of the lhs, we have	     * to use strncmp.	     */	    cp = word + (wordLen - pattern->leftLen);	    if ((cp >= word) &&		(strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {		/*		 * Match found. If we will place characters in the buffer,		 * add a space before hand as indicated by addSpace, then		 * stuff in the initial, unmatched part of the word followed		 * by the right-hand-side.		 */		if (((cp - word) + pattern->rightLen) != 0) {		    if (addSpace)			Buf_AddSpace(buf);		    addSpace = TRUE;		}		Buf_AddInterval(buf, word, cp);		Buf_AddChars(buf, pattern->rightLen, pattern->rhs);		pattern->flags |= VAR_SUB_MATCHED;	    } else {		/*		 * Had to match at end and didn't. Copy entire word.		 */		goto nosub;	    }	} else {	    /*	     * Pattern is unanchored: search for the pattern in the word using	     * String_FindSubstring, copying unmatched portions and the	     * right-hand-side for each match found, handling non-global	     * substitutions correctly, etc. When the loop is done, any	     * remaining part of the word (word and wordLen are adjusted	     * accordingly through the loop) is copied straight into the	     * buffer.	     * addSpace is set FALSE as soon as a space is added to the	     * buffer.	     */	    register Boolean done;	    size_t origSize;	    done = FALSE;	    origSize = Buf_Size(buf);	    while (!done) {		cp = strstr(word, pattern->lhs);		if (cp != (char *)NULL) {		    if (addSpace && (((cp - word) + pattern->rightLen) != 0)){			Buf_AddSpace(buf);			addSpace = FALSE;		    }		    Buf_AddInterval(buf, word, cp);		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);		    wordLen -= (cp - word) + pattern->leftLen;		    word = cp + pattern->leftLen;		    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){			done = TRUE;		    }		    pattern->flags |= VAR_SUB_MATCHED;		} else {		    done = TRUE;		}	    }	    if (wordLen != 0) {		if (addSpace)		    Buf_AddSpace(buf);		Buf_AddChars(buf, wordLen, word);	    }	    /*	     * If added characters to the buffer, need to add a space	     * before we add any more. If we didn't add any, just return	     * the previous value of addSpace.	     */	    return (Buf_Size(buf) != origSize || addSpace);	}	return (addSpace);    } nosub:    if (addSpace)	Buf_AddSpace(buf);    Buf_AddChars(buf, wordLen, word);    return(TRUE);}#ifndef MAKE_BOOTSTRAP/*- *----------------------------------------------------------------------- * VarREError -- *	Print the error caused by a regcomp or regexec call. * * Results: *	None. * * Side Effects: *	An error gets printed. * *----------------------------------------------------------------------- */static voidVarREError(err, pat, str)    int err;    regex_t *pat;    const char *str;{    char *errbuf;    int errlen;    errlen = regerror(err, pat, 0, 0);    errbuf = emalloc(errlen);    regerror(err, pat, errbuf, errlen);    Error("%s: %s", str, errbuf);    free(errbuf);}/*- *----------------------------------------------------------------------- * VarRESubstitute -- *	Perform a regex substitution on the given word, placing the *	result in the passed buffer. * * Results: *	TRUE if a space is needed before more characters are added. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static BooleanVarRESubstitute(word, addSpace, buf, patternp)    char *word;    Boolean addSpace;    Buffer buf;    void *patternp;{    VarREPattern *pat;    int xrv;    char *wp;    char *rp;    int added;#define MAYBE_ADD_SPACE()		\	if (addSpace && !added)		\	    Buf_AddSpace(buf);		\	added = 1    added = 0;    wp = word;    pat = patternp;    if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==	(VAR_SUB_ONE|VAR_SUB_MATCHED))	xrv = REG_NOMATCH;    else {    tryagain:	xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);    }    switch (xrv) {    case 0:	pat->flags |= VAR_SUB_MATCHED;	if (pat->matches[0].rm_so > 0) {	    MAYBE_ADD_SPACE();	    Buf_AddChars(buf, pat->matches[0].rm_so, wp);	}	for (rp = pat->replace; *rp; rp++) {	    if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {		MAYBE_ADD_SPACE();		Buf_AddChar(buf, rp[1]);		rp++;	    }	    else if ((*rp == '&') || ((*rp == '\\') && isdigit(rp[1]))) {		int n;		char *subbuf;		int sublen;		char errstr[3];		if (*rp == '&') {		    n = 0;		    errstr[0] = '&';		    errstr[1] = '\0';		} else {		    n = rp[1] - '0';		    errstr[0] = '\\';		    errstr[1] = rp[1];		    errstr[2] = '\0';		    rp++;		}		if (n > pat->nsub) {		    Error("No subexpression %s", &errstr[0]);		    subbuf = "";		    sublen = 0;		} else if ((pat->matches[n].rm_so == -1) &&			   (pat->matches[n].rm_eo == -1)) {		    Error("No match for subexpression %s", &errstr[0]);		    subbuf = "";		    sublen = 0;	        } else {		    subbuf = wp + pat->matches[n].rm_so;		    sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;		}		if (sublen > 0) {		    MAYBE_ADD_SPACE();		    Buf_AddChars(buf, sublen, subbuf);		}	    } else {		MAYBE_ADD_SPACE();		Buf_AddChar(buf, *rp);	    }	}	wp += pat->matches[0].rm_eo;	if (pat->flags & VAR_SUB_GLOBAL)	    goto tryagain;	if (*wp) {	    MAYBE_ADD_SPACE();	    Buf_AddChars(buf, strlen(wp), wp);	}	break;    default:	VarREError(xrv, &pat->re, "Unexpected regex error");       /* fall through */    case REG_NOMATCH:	if (*wp) {	    MAYBE_ADD_SPACE();	    Buf_AddChars(buf, strlen(wp), wp);	}	break;    }    return(addSpace||added);}#endif/*- *----------------------------------------------------------------------- * VarModify -- *	Modify each of the words of the passed string using the given *	function. Used to implement all modifiers. * * Results: *	A string of all the words modified appropriately. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static char *VarModify (str, modProc, datum)    char    	  *str;	    	    /* String whose words should be trimmed */				    /* Function to use to modify them */    Boolean    	  (*modProc) __P((char *, Boolean, Buffer, void *));    void          *datum;    	    /* Datum to pass it */{    BUFFER  	  buf;	    	    /* Buffer for the new string */    Boolean 	  addSpace; 	    /* TRUE if need to add a space to the				     * buffer before adding the trimmed				     * word */    char **av;			    /* word list */    char *as;			    /* word list memory */    int ac, i;    Buf_Init(&buf, 0);    addSpace = FALSE;    av = brk_string(str, &ac, FALSE, &as);    for (i = 0; i < ac; i++)	addSpace = (*modProc)(av[i], addSpace, &buf, datum);    free(as);    free(av);    return Buf_Retrieve(&buf);}