xref: /openbsd/usr.bin/make/varmodifiers.c (revision a6445c1d)
1 /*	$OpenBSD: varmodifiers.c,v 1.39 2014/09/21 13:43:25 espie Exp $	*/
2 /*	$NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1999-2010 Marc Espie.
6  *
7  * Extensive code changes for the OpenBSD project.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
22  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*
31  * Copyright (c) 1988, 1989, 1990, 1993
32  *	The Regents of the University of California.  All rights reserved.
33  * Copyright (c) 1989 by Berkeley Softworks
34  * All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * Adam de Boor.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  */
63 
64 /* VarModifiers_Apply is mostly a constituent function of Var_Parse, it
65  * is also called directly by Var_SubstVar.  */
66 
67 
68 #include <ctype.h>
69 #include <sys/types.h>
70 #ifndef MAKE_BOOTSTRAP
71 #include <regex.h>
72 #endif
73 #include <stddef.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include "config.h"
78 #include "defines.h"
79 #include "buf.h"
80 #include "var.h"
81 #include "varmodifiers.h"
82 #include "varname.h"
83 #include "targ.h"
84 #include "error.h"
85 #include "str.h"
86 #include "cmd_exec.h"
87 #include "memory.h"
88 #include "gnode.h"
89 
90 
91 /* Var*Pattern flags */
92 #define VAR_SUB_GLOBAL	0x01	/* Apply substitution globally */
93 #define VAR_SUB_ONE	0x02	/* Apply substitution to one word */
94 #define VAR_SUB_MATCHED 0x04	/* There was a match */
95 #define VAR_MATCH_START 0x08	/* Match at start of word */
96 #define VAR_MATCH_END	0x10	/* Match at end of word */
97 
98 /* Modifiers flags */
99 #define VAR_EQUAL	0x20
100 #define VAR_MAY_EQUAL	0x40
101 #define VAR_ADD_EQUAL	0x80
102 #define VAR_BANG_EQUAL	0x100
103 
104 typedef struct {
105 	char	  *lbuffer; /* left string to free */
106 	char	  *lhs;     /* String to match */
107 	size_t	  leftLen;  /* Length of string */
108 	char	  *rhs;     /* Replacement string (w/ &'s removed) */
109 	size_t	  rightLen; /* Length of replacement */
110 	int 	  flags;
111 } VarPattern;
112 
113 struct LoopStuff {
114 	struct LoopVar	*var;
115 	char	*expand;
116 	bool	err;
117 };
118 
119 static bool VarHead(struct Name *, bool, Buffer, void *);
120 static bool VarTail(struct Name *, bool, Buffer, void *);
121 static bool VarSuffix(struct Name *, bool, Buffer, void *);
122 static bool VarRoot(struct Name *, bool, Buffer, void *);
123 static bool VarMatch(struct Name *, bool, Buffer, void *);
124 static bool VarSYSVMatch(struct Name *, bool, Buffer, void *);
125 static bool VarNoMatch(struct Name *, bool, Buffer, void *);
126 static bool VarUniq(struct Name *, bool, Buffer, void *);
127 static bool VarLoop(struct Name *, bool, Buffer, void *);
128 
129 
130 #ifndef MAKE_BOOTSTRAP
131 static void VarREError(int, regex_t *, const char *);
132 static bool VarRESubstitute(struct Name *, bool, Buffer, void *);
133 static char *do_regex(const char *, const struct Name *, void *);
134 
135 typedef struct {
136 	regex_t	  re;
137 	int 	  nsub;
138 	regmatch_t	 *matches;
139 	char	 *replace;
140 	int 	  flags;
141 } VarREPattern;
142 #endif
143 
144 static bool VarSubstitute(struct Name *, bool, Buffer, void *);
145 static char *VarGetPattern(SymTable *, int, const char **, int, int,
146     size_t *, VarPattern *);
147 static char *VarQuote(const char *, const struct Name *, void *);
148 static char *VarModify(char *, bool (*)(struct Name *, bool, Buffer, void *), void *);
149 
150 static void *check_empty(const char **, SymTable *, bool, int);
151 static void *check_quote(const char **, SymTable *, bool, int);
152 static char *do_upper(const char *, const struct Name *, void *);
153 static char *do_lower(const char *, const struct Name *, void *);
154 static void *check_shcmd(const char **, SymTable *, bool, int);
155 static char *do_shcmd(const char *, const struct Name *, void *);
156 static char *do_sort(const char *, const struct Name *, void *);
157 static char *finish_loop(const char *, const struct Name *, void *);
158 static int NameCompare(const void *, const void *);
159 static char *do_label(const char *, const struct Name *, void *);
160 static char *do_path(const char *, const struct Name *, void *);
161 static char *do_def(const char *, const struct Name *, void *);
162 static char *do_undef(const char *, const struct Name *, void *);
163 static char *do_assign(const char *, const struct Name *, void *);
164 static char *do_exec(const char *, const struct Name *, void *);
165 
166 static void *assign_get_value(const char **, SymTable *, bool, int);
167 static void *get_cmd(const char **, SymTable *, bool, int);
168 static void *get_value(const char **, SymTable *, bool, int);
169 static void *get_stringarg(const char **, SymTable *, bool, int);
170 static void free_stringarg(void *);
171 static void *get_patternarg(const char **, SymTable *, bool, int);
172 static void *get_spatternarg(const char **, SymTable *, bool, int);
173 static void *common_get_patternarg(const char **, SymTable *, bool, int, bool);
174 static void free_patternarg(void *);
175 static void free_looparg(void *);
176 static void *get_sysvpattern(const char **, SymTable *, bool, int);
177 static void *get_loop(const char **, SymTable *, bool, int);
178 static char *LoopGrab(const char **);
179 
180 static struct Name dummy;
181 static struct Name *dummy_arg = &dummy;
182 
183 static struct modifier {
184 	    bool atstart;
185 	    void * (*getarg)(const char **, SymTable *, bool, int);
186 	    char * (*apply)(const char *, const struct Name *, void *);
187 	    bool (*word_apply)(struct Name *, bool, Buffer, void *);
188 	    void   (*freearg)(void *);
189 } *choose_mod[256],
190 	match_mod = {false, get_stringarg, NULL, VarMatch, free_stringarg},
191 	nomatch_mod = {false, get_stringarg, NULL, VarNoMatch, free_stringarg},
192 	subst_mod = {false, get_spatternarg, NULL, VarSubstitute, free_patternarg},
193 #ifndef MAKE_BOOTSTRAP
194 	resubst_mod = {false, get_patternarg, do_regex, NULL, free_patternarg},
195 #endif
196 	quote_mod = {false, check_quote, VarQuote, NULL , free},
197 	tail_mod = {false, check_empty, NULL, VarTail, NULL},
198 	head_mod = {false, check_empty, NULL, VarHead, NULL},
199 	suffix_mod = {false, check_empty, NULL, VarSuffix, NULL},
200 	root_mod = {false, check_empty, NULL, VarRoot, NULL},
201 	upper_mod = {false, check_empty, do_upper, NULL, NULL},
202 	lower_mod = {false, check_empty, do_lower, NULL, NULL},
203 	shcmd_mod = {false, check_shcmd, do_shcmd, NULL, NULL},
204 	sysv_mod = {false, get_sysvpattern, NULL, VarSYSVMatch, free_patternarg},
205 	uniq_mod = {false, check_empty, NULL, VarUniq, NULL},
206 	sort_mod = {false, check_empty, do_sort, NULL, NULL},
207 	loop_mod = {false, get_loop, finish_loop, VarLoop, free_looparg},
208 	undef_mod = {true, get_value, do_undef, NULL, NULL},
209 	def_mod = {true, get_value, do_def, NULL, NULL},
210 	label_mod = {true, check_empty, do_label, NULL, NULL},
211 	path_mod = {true, check_empty, do_path, NULL, NULL},
212 	assign_mod = {true, assign_get_value, do_assign, NULL, free_patternarg},
213 	exec_mod = {true, get_cmd, do_exec, NULL, free_patternarg}
214 ;
215 
216 void
217 VarModifiers_Init()
218 {
219 	choose_mod['M'] = &match_mod;
220 	choose_mod['N'] = &nomatch_mod;
221 	choose_mod['S'] = &subst_mod;
222 #ifndef MAKE_BOOTSTRAP
223 	choose_mod['C'] = &resubst_mod;
224 #endif
225 	choose_mod['Q'] = &quote_mod;
226 	choose_mod['T'] = &tail_mod;
227 	choose_mod['H'] = &head_mod;
228 	choose_mod['E'] = &suffix_mod;
229 	choose_mod['R'] = &root_mod;
230 	if (FEATURES(FEATURE_UPPERLOWER)) {
231 		choose_mod['U'] = &upper_mod;
232 		choose_mod['L'] = &lower_mod;
233 	}
234 	if (FEATURES(FEATURE_SUNSHCMD))
235 		choose_mod['s'] = &shcmd_mod;
236 	if (FEATURES(FEATURE_UNIQ))
237 		choose_mod['u'] = &uniq_mod;
238 	if (FEATURES(FEATURE_SORT))
239 		choose_mod['O'] = &sort_mod;
240 	if (FEATURES(FEATURE_ODE)) {
241 		choose_mod['@'] = &loop_mod;
242 		choose_mod['D'] = &def_mod;
243 		choose_mod['U'] = &undef_mod;
244 		choose_mod['L'] = &label_mod;
245 		choose_mod['P'] = &path_mod;
246 	}
247 	if (FEATURES(FEATURE_ASSIGN))
248 		choose_mod[':'] = &assign_mod;
249 	if (FEATURES(FEATURE_EXECMOD))
250 		choose_mod['!'] = &exec_mod;
251 }
252 
253 /* All modifiers handle addSpace (need to add a space before placing the
254  * next word into the buffer) and propagate it when necessary.
255  */
256 
257 /*-
258  *-----------------------------------------------------------------------
259  * VarHead --
260  *	Remove the tail of the given word and add the result to the given
261  *	buffer.
262  *-----------------------------------------------------------------------
263  */
264 static bool
265 VarHead(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
266 {
267 	const char	*slash;
268 
269 	slash = Str_rchri(word->s, word->e, '/');
270 	if (slash != NULL) {
271 		if (addSpace)
272 			Buf_AddSpace(buf);
273 		Buf_Addi(buf, word->s, slash);
274 	} else {
275 		/* If no directory part, give . (q.v. the POSIX standard).  */
276 		if (addSpace)
277 			Buf_AddString(buf, " .");
278 		else
279 			Buf_AddChar(buf, '.');
280 	}
281 	return true;
282 }
283 
284 /*-
285  *-----------------------------------------------------------------------
286  * VarTail --
287  *	Remove the head of the given word add the result to the given
288  *	buffer.
289  *-----------------------------------------------------------------------
290  */
291 static bool
292 VarTail(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
293 {
294 	const char	*slash;
295 
296 	if (addSpace)
297 		Buf_AddSpace(buf);
298 	slash = Str_rchri(word->s, word->e, '/');
299 	if (slash != NULL)
300 		Buf_Addi(buf, slash+1, word->e);
301 	else
302 		Buf_Addi(buf, word->s, word->e);
303 	return true;
304 }
305 
306 /*-
307  *-----------------------------------------------------------------------
308  * VarSuffix --
309  *	Add the suffix of the given word to the given buffer.
310  *-----------------------------------------------------------------------
311  */
312 static bool
313 VarSuffix(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
314 {
315 	const char	*dot;
316 
317 	dot = Str_rchri(word->s, word->e, '.');
318 	if (dot != NULL) {
319 		if (addSpace)
320 			Buf_AddSpace(buf);
321 		Buf_Addi(buf, dot+1, word->e);
322 		addSpace = true;
323 	}
324 	return addSpace;
325 }
326 
327 /*-
328  *-----------------------------------------------------------------------
329  * VarRoot --
330  *	Remove the suffix of the given word and add the result to the
331  *	buffer.
332  *-----------------------------------------------------------------------
333  */
334 static bool
335 VarRoot(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
336 {
337 	const char	*dot;
338 
339 	if (addSpace)
340 		Buf_AddSpace(buf);
341 	dot = Str_rchri(word->s, word->e, '.');
342 	if (dot != NULL)
343 		Buf_Addi(buf, word->s, dot);
344 	else
345 		Buf_Addi(buf, word->s, word->e);
346 	return true;
347 }
348 
349 /*-
350  *-----------------------------------------------------------------------
351  * VarMatch --
352  *	Add the word to the buffer if it matches the given pattern.
353  *-----------------------------------------------------------------------
354  */
355 static bool
356 VarMatch(struct Name *word, bool addSpace, Buffer buf,
357     void *pattern) /* Pattern the word must match */
358 {
359 	const char *pat = (const char *)pattern;
360 
361 	if (Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
362 		if (addSpace)
363 			Buf_AddSpace(buf);
364 		Buf_Addi(buf, word->s, word->e);
365 		return true;
366 	} else
367 		return addSpace;
368 }
369 
370 /*-
371  *-----------------------------------------------------------------------
372  * VarNoMatch --
373  *	Add the word to the buffer if it doesn't match the given pattern.
374  *-----------------------------------------------------------------------
375  */
376 static bool
377 VarNoMatch(struct Name *word, bool addSpace, Buffer buf,
378     void *pattern) /* Pattern the word must not match */
379 {
380 	const char *pat = (const char *)pattern;
381 
382 	if (!Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
383 		if (addSpace)
384 			Buf_AddSpace(buf);
385 		Buf_Addi(buf, word->s, word->e);
386 		return true;
387 	} else
388 		return addSpace;
389 }
390 
391 static bool
392 VarUniq(struct Name *word, bool addSpace, Buffer buf, void *lastp)
393 {
394 	struct Name *last = (struct Name *)lastp;
395 
396 	/* does not match */
397 	if (last->s == NULL || last->e - last->s != word->e - word->s ||
398 	    strncmp(word->s, last->s, word->e - word->s) != 0) {
399 		if (addSpace)
400 			Buf_AddSpace(buf);
401 		Buf_Addi(buf, word->s, word->e);
402 		addSpace = true;
403 	}
404 	last->s = word->s;
405 	last->e = word->e;
406 	return addSpace;
407 }
408 
409 static bool
410 VarLoop(struct Name *word, bool addSpace, Buffer buf, void *vp)
411 {
412 	struct LoopStuff *v = (struct LoopStuff *)vp;
413 
414 	if (addSpace)
415 		Buf_AddSpace(buf);
416 	Var_SubstVar(buf, v->expand, v->var, word->s);
417 	return true;
418 }
419 
420 static char *
421 finish_loop(const char *s, const struct Name *n UNUSED , void *p)
422 {
423 	struct LoopStuff *l = (struct LoopStuff *)p;
424 
425 	return Var_Subst(s, NULL,  l->err);
426 }
427 
428 static int
429 NameCompare(const void *ap, const void *bp)
430 {
431 	struct Name *a, *b;
432 	size_t n, m;
433 	int c;
434 
435 	a = (struct Name *)ap;
436 	b = (struct Name *)bp;
437 	n = a->e - a->s;
438 	m = b->e - b->s;
439 	if (n < m) {
440 		c = strncmp(a->s, b->s, n);
441 		if (c != 0)
442 		    return c;
443 		else
444 		    return -1;
445     	} else if (m < n) {
446 		c = strncmp(a->s, b->s, m);
447 		if (c != 0)
448 		    return c;
449 		else
450 		    return 1;
451     	} else
452 	    return strncmp(a->s, b->s, n);
453 }
454 
455 static char *
456 do_sort(const char *s, const struct Name *dummy UNUSED, void *arg UNUSED)
457 {
458 	struct Name *t;
459 	unsigned long n, i, j;
460 	const char *start, *end;
461 
462 	n = 1024;	/* start at 1024 words */
463 	t = ereallocarray(NULL, n, sizeof(struct Name));
464 	start = s;
465 	end = start;
466 
467 	for (i = 0;; i++) {
468 		if (i == n) {
469 			n *= 2;
470 			t = ereallocarray(t, n, sizeof(struct Name));
471 		}
472 		start = iterate_words(&end);
473 		if (start == NULL)
474 			break;
475 		t[i].s = start;
476 		t[i].e = end;
477 	}
478 	if (i > 0) {
479 		BUFFER buf;
480 
481 		Buf_Init(&buf, end - s);
482 		qsort(t, i, sizeof(struct Name), NameCompare);
483 		Buf_Addi(&buf, t[0].s, t[0].e);
484 		for (j = 1; j < i; j++) {
485 			Buf_AddSpace(&buf);
486 			Buf_Addi(&buf, t[j].s, t[j].e);
487 		}
488 		free(t);
489 		return Buf_Retrieve(&buf);
490 	} else {
491 		free(t);
492 		return "";
493 	}
494 }
495 
496 static char *
497 do_label(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
498 {
499 	return Str_dupi(n->s, n->e);
500 }
501 
502 static char *
503 do_path(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
504 {
505 	GNode *gn;
506 
507 	gn = Targ_FindNodei(n->s, n->e, TARG_NOCREATE);
508 	if (gn == NULL)
509 		return Str_dupi(n->s, n->e);
510 	else
511 		return strdup(gn->path);
512 }
513 
514 static char *
515 do_def(const char *s, const struct Name *n UNUSED, void *arg)
516 {
517 	VarPattern *v = (VarPattern *)arg;
518 	if (s == NULL) {
519 		free_patternarg(v);
520 		return NULL;
521 	} else
522 		return v->lbuffer;
523 }
524 
525 static char *
526 do_undef(const char *s, const struct Name *n UNUSED, void *arg)
527 {
528 	VarPattern *v = (VarPattern *)arg;
529 	if (s != NULL) {
530 		free_patternarg(v);
531 		return NULL;
532 	} else
533 		return v->lbuffer;
534 }
535 
536 static char *
537 do_assign(const char *s, const struct Name *n, void *arg)
538 {
539 	VarPattern *v = (VarPattern *)arg;
540 	char *msg;
541 	char *result;
542 
543 	switch (v->flags) {
544 	case VAR_EQUAL:
545 		Var_Seti(n->s, n->e, v->lbuffer);
546 		break;
547 	case VAR_MAY_EQUAL:
548 		if (s == NULL)
549 			Var_Seti(n->s, n->e, v->lbuffer);
550 		break;
551 	case VAR_ADD_EQUAL:
552 		if (s == NULL)
553 			Var_Seti(n->s, n->e, v->lbuffer);
554 		else
555 			Var_Appendi(n->s, n->e, v->lbuffer);
556 		break;
557 	case VAR_BANG_EQUAL:
558 		result = Cmd_Exec(v->lbuffer, &msg);
559 		if (result != NULL) {
560 			Var_Seti(n->s, n->e, result);
561 			free(result);
562 		} else
563 			Error(msg, v->lbuffer);
564 		break;
565 
566 	}
567 	return NULL;
568 }
569 
570 static char *
571 do_exec(const char *s UNUSED, const struct Name *n UNUSED, void *arg)
572 {
573 	VarPattern *v = (VarPattern *)arg;
574 	char *msg;
575 	char *result;
576 
577 	result = Cmd_Exec(v->lbuffer, &msg);
578 	if (result == NULL)
579 		Error(msg, v->lbuffer);
580 	return result;
581 }
582 
583 /*-
584  *-----------------------------------------------------------------------
585  * VarSYSVMatch --
586  *	Add the word to the buffer if it matches the given pattern.
587  *	Used to implement the System V % modifiers.
588  *-----------------------------------------------------------------------
589  */
590 static bool
591 VarSYSVMatch(struct Name *word, bool addSpace, Buffer buf, void *patp)
592 {
593 	size_t	len;
594 	const char	*ptr;
595 	VarPattern	*pat = (VarPattern *)patp;
596 
597 	if (*word->s != '\0') {
598 		if (addSpace)
599 			Buf_AddSpace(buf);
600 		if ((ptr = Str_SYSVMatch(word->s, pat->lhs, &len)) != NULL)
601 			Str_SYSVSubst(buf, pat->rhs, ptr, len);
602 		else
603 			Buf_Addi(buf, word->s, word->e);
604 		return true;
605 	} else
606 		return addSpace;
607 }
608 
609 void *
610 get_sysvpattern(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
611 {
612 	VarPattern		*pattern;
613 	const char		*cp, *cp2;
614 	BUFFER buf;
615 	int cnt = 0;
616 	char startc = endc == ')' ? '(' : '{';
617 	for (cp = *p;; cp++) {
618 		if (*cp == '=' && cnt == 0)
619 			break;
620 		if (*cp == '\0')
621 			return NULL;
622 		if (*cp == startc)
623 			cnt++;
624 		else if (*cp == endc) {
625 			cnt--;
626 			if (cnt < 0)
627 				return NULL;
628 		}
629 	}
630 	Buf_Init(&buf, 0);
631 	for (cp2 = cp+1;; cp2++) {
632 		if (((*cp2 == ':' && cp2[1] != endc) || *cp2 == endc) &&
633 		    cnt == 0)
634 			break;
635 		if (*cp2 == '\0') {
636 			Buf_Destroy(&buf);
637 			return NULL;
638 		}
639 		if (*cp2 == startc)
640 			cnt++;
641 		else if (*cp2 == endc) {
642 			cnt--;
643 			if (cnt < 0) {
644 				Buf_Destroy(&buf);
645 				return NULL;
646 			}
647 		} else if (*cp2 == '$') {
648 			if (cp2[1] == '$')
649 				cp2++;
650 			else {
651 				size_t len;
652 				(void)Var_ParseBuffer(&buf, cp2, ctxt, err,
653 				    &len);
654 				cp2 += len - 1;
655 				continue;
656 			}
657 		}
658 		Buf_AddChar(&buf, *cp2);
659 	}
660 
661 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
662 	pattern->lbuffer = pattern->lhs = Str_dupi(*p, cp);
663 	pattern->leftLen = cp - *p;
664 	pattern->rhs = Buf_Retrieve(&buf);
665 	pattern->rightLen = Buf_Size(&buf);
666 	pattern->flags = 0;
667 	*p = cp2;
668 	return pattern;
669 }
670 
671 
672 /*-
673  *-----------------------------------------------------------------------
674  * VarSubstitute --
675  *	Perform a string-substitution on the given word, Adding the
676  *	result to the given buffer.
677  *-----------------------------------------------------------------------
678  */
679 static bool
680 VarSubstitute(struct Name *word, bool addSpace, Buffer buf,
681     void *patternp) /* Pattern for substitution */
682 {
683     size_t	wordLen;    /* Length of word */
684     const char	*cp;	    /* General pointer */
685     VarPattern	*pattern = (VarPattern *)patternp;
686 
687     wordLen = word->e - word->s;
688     if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
689 	(VAR_SUB_ONE|VAR_SUB_MATCHED)) {
690 	/* Still substituting -- break it down into simple anchored cases
691 	 * and if none of them fits, perform the general substitution case.  */
692 	if ((pattern->flags & VAR_MATCH_START) &&
693 	    (strncmp(word->s, pattern->lhs, pattern->leftLen) == 0)) {
694 		/* Anchored at start and beginning of word matches pattern.  */
695 		if ((pattern->flags & VAR_MATCH_END) &&
696 		    (wordLen == pattern->leftLen)) {
697 			/* Also anchored at end and matches to the end (word
698 			 * is same length as pattern) add space and rhs only
699 			 * if rhs is non-null.	*/
700 			if (pattern->rightLen != 0) {
701 			    if (addSpace)
702 				Buf_AddSpace(buf);
703 			    addSpace = true;
704 			    Buf_AddChars(buf, pattern->rightLen,
705 					 pattern->rhs);
706 			}
707 			pattern->flags |= VAR_SUB_MATCHED;
708 		} else if (pattern->flags & VAR_MATCH_END) {
709 		    /* Doesn't match to end -- copy word wholesale.  */
710 		    goto nosub;
711 		} else {
712 		    /* Matches at start but need to copy in
713 		     * trailing characters.  */
714 		    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
715 			if (addSpace)
716 			    Buf_AddSpace(buf);
717 			addSpace = true;
718 		    }
719 		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
720 		    Buf_AddChars(buf, wordLen - pattern->leftLen,
721 				 word->s + pattern->leftLen);
722 		    pattern->flags |= VAR_SUB_MATCHED;
723 		}
724 	} else if (pattern->flags & VAR_MATCH_START) {
725 	    /* Had to match at start of word and didn't -- copy whole word.  */
726 	    goto nosub;
727 	} else if (pattern->flags & VAR_MATCH_END) {
728 	    /* Anchored at end, Find only place match could occur (leftLen
729 	     * characters from the end of the word) and see if it does. Note
730 	     * that because the $ will be left at the end of the lhs, we have
731 	     * to use strncmp.	*/
732 	    cp = word->s + (wordLen - pattern->leftLen);
733 	    if (cp >= word->s &&
734 		strncmp(cp, pattern->lhs, pattern->leftLen) == 0) {
735 		/* Match found. If we will place characters in the buffer,
736 		 * add a space before hand as indicated by addSpace, then
737 		 * stuff in the initial, unmatched part of the word followed
738 		 * by the right-hand-side.  */
739 		if (((cp - word->s) + pattern->rightLen) != 0) {
740 		    if (addSpace)
741 			Buf_AddSpace(buf);
742 		    addSpace = true;
743 		}
744 		Buf_Addi(buf, word->s, cp);
745 		Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
746 		pattern->flags |= VAR_SUB_MATCHED;
747 	    } else {
748 		/* Had to match at end and didn't. Copy entire word.  */
749 		goto nosub;
750 	    }
751 	} else {
752 	    /* Pattern is unanchored: search for the pattern in the word using
753 	     * strstr, copying unmatched portions and the
754 	     * right-hand-side for each match found, handling non-global
755 	     * substitutions correctly, etc. When the loop is done, any
756 	     * remaining part of the word (word and wordLen are adjusted
757 	     * accordingly through the loop) is copied straight into the
758 	     * buffer.
759 	     * addSpace is set to false as soon as a space is added to the
760 	     * buffer.	*/
761 	    bool done;
762 	    size_t origSize;
763 
764 	    done = false;
765 	    origSize = Buf_Size(buf);
766 	    while (!done) {
767 		cp = strstr(word->s, pattern->lhs);
768 		if (cp != NULL) {
769 		    if (addSpace && (cp - word->s) + pattern->rightLen != 0){
770 			Buf_AddSpace(buf);
771 			addSpace = false;
772 		    }
773 		    Buf_Addi(buf, word->s, cp);
774 		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
775 		    wordLen -= (cp - word->s) + pattern->leftLen;
776 		    word->s = cp + pattern->leftLen;
777 		    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0)
778 			done = true;
779 		    pattern->flags |= VAR_SUB_MATCHED;
780 		} else
781 		    done = true;
782 	    }
783 	    if (wordLen != 0) {
784 		if (addSpace)
785 		    Buf_AddSpace(buf);
786 		Buf_AddChars(buf, wordLen, word->s);
787 	    }
788 	    /* If added characters to the buffer, need to add a space
789 	     * before we add any more. If we didn't add any, just return
790 	     * the previous value of addSpace.	*/
791 	    return Buf_Size(buf) != origSize || addSpace;
792 	}
793 	return addSpace;
794     }
795  nosub:
796     if (addSpace)
797 	Buf_AddSpace(buf);
798     Buf_AddChars(buf, wordLen, word->s);
799     return true;
800 }
801 
802 #ifndef MAKE_BOOTSTRAP
803 /*-
804  *-----------------------------------------------------------------------
805  * VarREError --
806  *	Print the error caused by a regcomp or regexec call.
807  *-----------------------------------------------------------------------
808  */
809 static void
810 VarREError(int err, regex_t *pat, const char *str)
811 {
812 	char	*errbuf;
813 	int 	errlen;
814 
815 	errlen = regerror(err, pat, 0, 0);
816 	errbuf = emalloc(errlen);
817 	regerror(err, pat, errbuf, errlen);
818 	Error("%s: %s", str, errbuf);
819 	free(errbuf);
820 }
821 
822 /*-
823  *-----------------------------------------------------------------------
824  * VarRESubstitute --
825  *	Perform a regex substitution on the given word, placing the
826  *	result in the passed buffer.
827  *-----------------------------------------------------------------------
828  */
829 static bool
830 VarRESubstitute(struct Name *word, bool addSpace, Buffer buf, void *patternp)
831 {
832 	VarREPattern	*pat;
833 	int 		xrv;
834 	const char		*wp;
835 	char		*rp;
836 	int 		added;
837 
838 #define MAYBE_ADD_SPACE()		\
839 	if (addSpace && !added) 	\
840 		Buf_AddSpace(buf);	\
841 	added = 1
842 
843 	added = 0;
844 	wp = word->s;
845 	pat = patternp;
846 
847 	if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
848 	    (VAR_SUB_ONE|VAR_SUB_MATCHED))
849 		xrv = REG_NOMATCH;
850 	else {
851 	tryagain:
852 		xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);
853 	}
854 
855 	switch (xrv) {
856 	case 0:
857 		pat->flags |= VAR_SUB_MATCHED;
858 		if (pat->matches[0].rm_so > 0) {
859 			MAYBE_ADD_SPACE();
860 			Buf_AddChars(buf, pat->matches[0].rm_so, wp);
861 		}
862 
863 		for (rp = pat->replace; *rp; rp++) {
864 			if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
865 				MAYBE_ADD_SPACE();
866 				Buf_AddChar(buf,rp[1]);
867 				rp++;
868 			}
869 			else if (*rp == '&' ||
870 			    (*rp == '\\' && ISDIGIT(rp[1]))) {
871 				int n;
872 				const char *subbuf;
873 				int sublen;
874 				char errstr[3];
875 
876 				if (*rp == '&') {
877 					n = 0;
878 					errstr[0] = '&';
879 					errstr[1] = '\0';
880 				} else {
881 					n = rp[1] - '0';
882 					errstr[0] = '\\';
883 					errstr[1] = rp[1];
884 					errstr[2] = '\0';
885 					rp++;
886 				}
887 
888 				if (n > pat->nsub) {
889 					Error("No subexpression %s",
890 					    &errstr[0]);
891 					subbuf = "";
892 					sublen = 0;
893 				} else if (pat->matches[n].rm_so == -1 &&
894 				    pat->matches[n].rm_eo == -1) {
895 					Error("No match for subexpression %s",
896 					    &errstr[0]);
897 					subbuf = "";
898 					sublen = 0;
899 				} else {
900 					subbuf = wp + pat->matches[n].rm_so;
901 					sublen = pat->matches[n].rm_eo -
902 					    pat->matches[n].rm_so;
903 				}
904 
905 				if (sublen > 0) {
906 					MAYBE_ADD_SPACE();
907 					Buf_AddChars(buf, sublen, subbuf);
908 				}
909 			} else {
910 				MAYBE_ADD_SPACE();
911 				Buf_AddChar(buf, *rp);
912 			}
913 		}
914 		wp += pat->matches[0].rm_eo;
915 		if (pat->flags & VAR_SUB_GLOBAL) {
916 			/* like most modern tools, empty string matches
917 			 * should advance one char at a time...
918 			 */
919 			if (pat->matches[0].rm_eo == 0)  {
920 				if (*wp) {
921 					MAYBE_ADD_SPACE();
922 					Buf_AddChar(buf, *wp++);
923 				} else
924 					break;
925 			}
926 			goto tryagain;
927 		}
928 		if (*wp) {
929 			MAYBE_ADD_SPACE();
930 			Buf_AddString(buf, wp);
931 		}
932 		break;
933 	default:
934 		VarREError(xrv, &pat->re, "Unexpected regex error");
935 	       /* FALLTHROUGH */
936 	case REG_NOMATCH:
937 		if (*wp) {
938 			MAYBE_ADD_SPACE();
939 			Buf_AddString(buf, wp);
940 		}
941 		break;
942 	}
943 	return addSpace||added;
944 }
945 #endif
946 
947 /*-
948  *-----------------------------------------------------------------------
949  * VarModify --
950  *	Modify each of the words of the passed string using the given
951  *	function. Used to implement all modifiers.
952  *
953  * Results:
954  *	A string of all the words modified appropriately.
955  *-----------------------------------------------------------------------
956  */
957 static char *
958 VarModify(char *str, 		/* String whose words should be trimmed */
959 				/* Function to use to modify them */
960     bool (*modProc)(struct Name *, bool, Buffer, void *),
961     void *datum)		/* Datum to pass it */
962 {
963 	BUFFER	  buf;		/* Buffer for the new string */
964 	bool	  addSpace;	/* true if need to add a space to the
965 				     * buffer before adding the trimmed
966 				     * word */
967 	struct Name	  word;
968 
969 	Buf_Init(&buf, 0);
970 	addSpace = false;
971 
972 	word.e = str;
973 
974 	while ((word.s = iterate_words(&word.e)) != NULL) {
975 		char termc;
976 
977 		termc = *word.e;
978 		*((char *)(word.e)) = '\0';
979 		addSpace = (*modProc)(&word, addSpace, &buf, datum);
980 		*((char *)(word.e)) = termc;
981 	}
982 	return Buf_Retrieve(&buf);
983 }
984 
985 /*-
986  *-----------------------------------------------------------------------
987  * VarGetPattern --
988  *	Pass through the tstr looking for 1) escaped delimiters,
989  *	'$'s and backslashes (place the escaped character in
990  *	uninterpreted) and 2) unescaped $'s that aren't before
991  *	the delimiter (expand the variable substitution).
992  *	Return the expanded string or NULL if the delimiter was missing
993  *	If pattern is specified, handle escaped ampersands, and replace
994  *	unescaped ampersands with the lhs of the pattern.
995  *
996  * Results:
997  *	A string of all the words modified appropriately.
998  *	If length is specified, return the string length of the buffer
999  *-----------------------------------------------------------------------
1000  */
1001 static char *
1002 VarGetPattern(SymTable *ctxt, int err, const char **tstr, int delim1,
1003     int delim2, size_t *length, VarPattern *pattern)
1004 {
1005 	const char	*cp;
1006 	char	*result;
1007 	BUFFER	buf;
1008 	size_t	junk;
1009 
1010 	Buf_Init(&buf, 0);
1011 	if (length == NULL)
1012 		length = &junk;
1013 
1014 #define IS_A_MATCH(cp, delim1, delim2) \
1015 	(cp[0] == '\\' && (cp[1] == delim1 || cp[1] == delim2 || \
1016 	 cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&')))
1017 
1018 	/*
1019 	 * Skim through until the matching delimiter is found;
1020 	 * pick up variable substitutions on the way. Also allow
1021 	 * backslashes to quote the delimiter, $, and \, but don't
1022 	 * touch other backslashes.
1023 	 */
1024 	for (cp = *tstr; *cp != '\0' && *cp != delim1 && *cp != delim2; cp++) {
1025 		if (IS_A_MATCH(cp, delim1, delim2)) {
1026 			Buf_AddChar(&buf, cp[1]);
1027 			cp++;
1028 		} else if (*cp == '$') {
1029 			/* Allowed at end of pattern */
1030 			if (cp[1] == delim1 || cp[1] == delim2)
1031 				Buf_AddChar(&buf, *cp);
1032 			else {
1033 				size_t len;
1034 
1035 				/* If unescaped dollar sign not before the
1036 				 * delimiter, assume it's a variable
1037 				 * substitution and recurse.  */
1038 				(void)Var_ParseBuffer(&buf, cp, ctxt, err,
1039 				    &len);
1040 				cp += len - 1;
1041 			}
1042 		} else if (pattern && *cp == '&')
1043 			Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
1044 		else
1045 			Buf_AddChar(&buf, *cp);
1046 	}
1047 
1048 	*length = Buf_Size(&buf);
1049 	result = Buf_Retrieve(&buf);
1050 
1051 	if (*cp != delim1 && *cp != delim2) {
1052 		*tstr = cp;
1053 		*length = 0;
1054 		free(result);
1055 		return NULL;
1056 	}
1057 	else {
1058 		*tstr = ++cp;
1059 		return result;
1060 	}
1061 }
1062 
1063 /*-
1064  *-----------------------------------------------------------------------
1065  * VarQuote --
1066  *	Quote shell meta-characters in the string
1067  *
1068  * Results:
1069  *	The quoted string
1070  *-----------------------------------------------------------------------
1071  */
1072 static char *
1073 VarQuote(const char *str, const struct Name *n UNUSED, void *islistp)
1074 {
1075 	int islist = *((int *)islistp);
1076 
1077 	BUFFER	  buf;
1078 	/* This should cover most shells :-( */
1079 	static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1080 	char *rep = meta;
1081 	if (islist)
1082 		rep += 3;
1083 
1084 	Buf_Init(&buf, MAKE_BSIZE);
1085 	for (; *str; str++) {
1086 		if (strchr(rep, *str) != NULL)
1087 			Buf_AddChar(&buf, '\\');
1088 		Buf_AddChar(&buf, *str);
1089 	}
1090 	return Buf_Retrieve(&buf);
1091 }
1092 
1093 static void *
1094 check_empty(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1095 {
1096 	dummy_arg->s = NULL;
1097 	if ((*p)[1] == endc || (*p)[1] == ':') {
1098 		(*p)++;
1099 		return dummy_arg;
1100 	} else
1101 		return NULL;
1102 }
1103 
1104 static void *
1105 check_quote(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1106 {
1107 	int *qargs = emalloc(sizeof(int));
1108 	*qargs = 0;
1109 	if ((*p)[1] == 'L') {
1110 		*qargs = 1;
1111 		(*p)++;
1112 	}
1113 	if ((*p)[1] == endc || (*p)[1] == ':') {
1114 		(*p)++;
1115 		return qargs;
1116 	} else  {
1117 		free(qargs);
1118 		return NULL;
1119 	}
1120 }
1121 
1122 static void *
1123 check_shcmd(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1124 {
1125 	if ((*p)[1] == 'h' && ((*p)[2] == endc || (*p)[2] == ':')) {
1126 		(*p)+=2;
1127 		return dummy_arg;
1128 	} else
1129 		return NULL;
1130 }
1131 
1132 
1133 static char *
1134 do_shcmd(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1135 {
1136 	char *err;
1137 	char *t;
1138 
1139 	t = Cmd_Exec(s, &err);
1140 	if (err)
1141 		Error(err, s);
1142 	return t;
1143 }
1144 
1145 static void *
1146 get_stringarg(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1147 {
1148 	const char *cp;
1149 	char *s;
1150 
1151 	for (cp = *p + 1; *cp != ':' && *cp != endc; cp++) {
1152 		if (*cp == '\\') {
1153 			if (cp[1] == ':' || cp[1] == endc || cp[1] == '\\')
1154 				cp++;
1155 		} else if (*cp == '\0')
1156 			return NULL;
1157 	}
1158 	s = escape_dupi(*p+1, cp, ":)}");
1159 	*p = cp;
1160 	return s;
1161 }
1162 
1163 static void
1164 free_stringarg(void *arg)
1165 {
1166 	free(arg);
1167 }
1168 
1169 static char *
1170 do_upper(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1171 {
1172 	size_t len, i;
1173 	char *t;
1174 
1175 	len = strlen(s);
1176 	t = emalloc(len+1);
1177 	for (i = 0; i < len; i++)
1178 		t[i] = TOUPPER(s[i]);
1179 	t[len] = '\0';
1180 	return t;
1181 }
1182 
1183 static char *
1184 do_lower(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1185 {
1186 	size_t	len, i;
1187 	char	*t;
1188 
1189 	len = strlen(s);
1190 	t = emalloc(len+1);
1191 	for (i = 0; i < len; i++)
1192 		t[i] = TOLOWER(s[i]);
1193 	t[len] = '\0';
1194 	return t;
1195 }
1196 
1197 static void *
1198 get_patternarg(const char **p, SymTable *ctxt, bool err, int endc)
1199 {
1200 	return common_get_patternarg(p, ctxt, err, endc, false);
1201 }
1202 
1203 /* Extract anchors */
1204 static void *
1205 get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
1206 {
1207 	VarPattern *pattern;
1208 
1209 	pattern = common_get_patternarg(p, ctxt, err, endc, true);
1210 	if (pattern != NULL && pattern->leftLen > 0) {
1211 		if (pattern->lhs[pattern->leftLen-1] == '$') {
1212 			    pattern->leftLen--;
1213 			    pattern->flags |= VAR_MATCH_END;
1214 		}
1215 		if (pattern->lhs[0] == '^') {
1216 			    pattern->lhs++;
1217 			    pattern->leftLen--;
1218 			    pattern->flags |= VAR_MATCH_START;
1219 		}
1220 	}
1221 	return pattern;
1222 }
1223 
1224 static void
1225 free_looparg(void *arg)
1226 {
1227 	struct LoopStuff *l = (struct LoopStuff *)arg;
1228 
1229 	Var_DeleteLoopVar(l->var);
1230 	free(l->expand);
1231 }
1232 
1233 static char *
1234 LoopGrab(const char **s)
1235 {
1236 	const char *p, *start;
1237 
1238 	start = *s;
1239 	for (p = start; *p != '@'; p++) {
1240 		if (*p == '\\')
1241 			p++;
1242 		if (*p == 0)
1243 			return NULL;
1244 	}
1245 	*s = p+1;
1246 	return escape_dupi(start, p, "@\\");
1247 }
1248 
1249 static void *
1250 get_loop(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
1251 {
1252 	static struct LoopStuff loop;
1253 	const char *s;
1254 	const char *var;
1255 
1256 	s = *p +1;
1257 
1258 	loop.var = NULL;
1259 	loop.expand = NULL;
1260 	loop.err = err;
1261 	var = LoopGrab(&s);
1262 	if (var != NULL) {
1263 		loop.expand = LoopGrab(&s);
1264 		if (*s == endc || *s == ':') {
1265 			*p = s;
1266 			loop.var = Var_NewLoopVar(var, NULL);
1267 			return &loop;
1268 		}
1269 	}
1270 	free_looparg(&loop);
1271 	return NULL;
1272 }
1273 
1274 static void *
1275 common_get_patternarg(const char **p, SymTable *ctxt, bool err, int endc,
1276     bool dosubst)
1277 {
1278 	VarPattern *pattern;
1279 	char delim;
1280 	const char *s;
1281 
1282 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1283 	pattern->flags = 0;
1284 	s = *p;
1285 
1286 	delim = s[1];
1287 	if (delim == '\0')
1288 		return NULL;
1289 	s += 2;
1290 
1291 	pattern->rhs = NULL;
1292 	pattern->lhs = VarGetPattern(ctxt, err, &s, delim, delim,
1293 	    &pattern->leftLen, NULL);
1294 	pattern->lbuffer = pattern->lhs;
1295 	if (pattern->lhs != NULL) {
1296 		pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
1297 		    &pattern->rightLen, dosubst ? pattern: NULL);
1298 		if (pattern->rhs != NULL) {
1299 			/* Check for global substitution. If 'g' after the
1300 			 * final delimiter, substitution is global and is
1301 			 * marked that way.  */
1302 			for (;; s++) {
1303 				switch (*s) {
1304 				case 'g':
1305 					pattern->flags |= VAR_SUB_GLOBAL;
1306 					continue;
1307 				case '1':
1308 					pattern->flags |= VAR_SUB_ONE;
1309 					continue;
1310 				}
1311 				break;
1312 			}
1313 			if (*s == endc || *s == ':') {
1314 				*p = s;
1315 				return pattern;
1316 			}
1317 		}
1318 	}
1319 	free_patternarg(pattern);
1320 	return NULL;
1321 }
1322 
1323 static void *
1324 assign_get_value(const char **p, SymTable *ctxt, bool err, int endc)
1325 {
1326 	const char *s;
1327 	int flags;
1328 	VarPattern *arg;
1329 
1330 	s = *p + 1;
1331 	if (s[0] == '=')
1332 		flags = VAR_EQUAL;
1333 	else if (s[0] == '?' && s[1] == '=')
1334 		flags = VAR_MAY_EQUAL;
1335 	else if (s[0] == '+' && s[1] == '=')
1336 		flags = VAR_ADD_EQUAL;
1337 	else if (s[0] == '!' && s[1] == '=')
1338 		flags = VAR_BANG_EQUAL;
1339 	else
1340 		return NULL;
1341 
1342 	arg = get_value(&s, ctxt, err, endc);
1343 	if (arg != NULL) {
1344 		*p = s;
1345 		arg->flags = flags;
1346 	}
1347 	return arg;
1348 }
1349 
1350 static void *
1351 get_value(const char **p, SymTable *ctxt, bool err, int endc)
1352 {
1353 	VarPattern *pattern;
1354 	const char *s;
1355 
1356 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1357 	s = *p + 1;
1358 	pattern->rhs = NULL;
1359 	pattern->lbuffer = VarGetPattern(ctxt, err, &s, ':', endc,
1360 	    &pattern->leftLen, NULL);
1361 	if (s[-1] == endc || s[-1] == ':') {
1362 		*p = s-1;
1363 		return pattern;
1364 	}
1365 	free_patternarg(pattern);
1366 	return NULL;
1367 }
1368 
1369 static void *
1370 get_cmd(const char **p, SymTable *ctxt, bool err, int endc UNUSED)
1371 {
1372 	VarPattern *pattern;
1373 	const char *s;
1374 
1375 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1376 	s = *p + 1;
1377 	pattern->rhs = NULL;
1378 	pattern->lbuffer = VarGetPattern(ctxt, err, &s, '!', '!',
1379 	    &pattern->leftLen, NULL);
1380 	if (s[-1] == '!') {
1381 		*p = s-1;
1382 		return pattern;
1383 	}
1384 	free_patternarg(pattern);
1385 	return NULL;
1386 }
1387 
1388 static void
1389 free_patternarg(void *p)
1390 {
1391 	VarPattern *vp = (VarPattern *)p;
1392 
1393 	free(vp->lbuffer);
1394 	free(vp->rhs);
1395 	free(vp);
1396 }
1397 
1398 #ifndef MAKE_BOOTSTRAP
1399 static char *
1400 do_regex(const char *s, const struct Name *n UNUSED, void *arg)
1401 {
1402 	VarREPattern p2;
1403 	VarPattern *p = (VarPattern *)arg;
1404 	int error;
1405 	char *result;
1406 
1407 	error = regcomp(&p2.re, p->lhs, REG_EXTENDED);
1408 	if (error) {
1409 		VarREError(error, &p2.re, "RE substitution error");
1410 		return var_Error;
1411 	}
1412 	p2.nsub = p2.re.re_nsub + 1;
1413 	p2.replace = p->rhs;
1414 	p2.flags = p->flags;
1415 	if (p2.nsub < 1)
1416 		p2.nsub = 1;
1417 	if (p2.nsub > 10)
1418 		p2.nsub = 10;
1419 	p2.matches = ereallocarray(NULL, p2.nsub, sizeof(regmatch_t));
1420 	result = VarModify((char *)s, VarRESubstitute, &p2);
1421 	regfree(&p2.re);
1422 	free(p2.matches);
1423 	return result;
1424 }
1425 #endif
1426 
1427 char *
1428 VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
1429     bool err, bool *freePtr, const char **pscan, int paren)
1430 {
1431 	const char *tstr;
1432 	bool atstart;    /* Some ODE modifiers only make sense at start */
1433 	char endc = paren == '(' ? ')' : '}';
1434 	const char *start = *pscan;
1435 
1436 	tstr = start;
1437 	/*
1438 	 * Now we need to apply any modifiers the user wants applied.
1439 	 * These are:
1440 	 *		  :M<pattern>	words which match the given <pattern>.
1441 	 *				<pattern> is of the standard file
1442 	 *				wildcarding form.
1443 	 *		  :S<d><pat1><d><pat2><d>[g]
1444 	 *				Substitute <pat2> for <pat1> in the
1445 	 *				value
1446 	 *		  :C<d><pat1><d><pat2><d>[g]
1447 	 *				Substitute <pat2> for regex <pat1> in
1448 	 *				the value
1449 	 *		  :H		Substitute the head of each word
1450 	 *		  :T		Substitute the tail of each word
1451 	 *		  :E		Substitute the extension (minus '.') of
1452 	 *				each word
1453 	 *		  :R		Substitute the root of each word
1454 	 *				(pathname minus the suffix).
1455 	 *		  :lhs=rhs	Like :S, but the rhs goes to the end of
1456 	 *				the invocation.
1457 	 */
1458 
1459 	atstart = true;
1460 	while (*tstr != endc && *tstr != '\0') {
1461 		struct modifier *mod;
1462 		void *arg;
1463 		char *newStr;
1464 
1465 		tstr++;
1466 		if (DEBUG(VAR))
1467 			printf("Applying :%c to \"%s\"\n", *tstr, str);
1468 
1469 		mod = choose_mod[(unsigned char)*tstr];
1470 		arg = NULL;
1471 
1472 		if (mod != NULL && (!mod->atstart || atstart))
1473 			arg = mod->getarg(&tstr, ctxt, err, endc);
1474 		if (FEATURES(FEATURE_SYSVVARSUB) && arg == NULL) {
1475 			mod = &sysv_mod;
1476 			arg = mod->getarg(&tstr, ctxt, err, endc);
1477 		}
1478 		atstart = false;
1479 		if (arg != NULL) {
1480 			if (str != NULL || (mod->atstart && name != NULL)) {
1481 				if (mod->word_apply != NULL) {
1482 					newStr = VarModify(str,
1483 					    mod->word_apply, arg);
1484 					if (mod->apply != NULL) {
1485 						char *newStr2;
1486 
1487 						newStr2 = mod->apply(newStr,
1488 						    name, arg);
1489 						free(newStr);
1490 						newStr = newStr2;
1491 					}
1492 				} else
1493 					newStr = mod->apply(str, name, arg);
1494 				if (*freePtr)
1495 					free(str);
1496 				str = newStr;
1497 				if (str != var_Error)
1498 					*freePtr = true;
1499 				else
1500 					*freePtr = false;
1501 			}
1502 			if (mod->freearg != NULL)
1503 				mod->freearg(arg);
1504 		} else {
1505 			Error("Bad modifier: %s", tstr);
1506 			/* Try skipping to end of var... */
1507 			for (tstr++; *tstr != endc && *tstr != '\0';)
1508 				tstr++;
1509 			if (str != NULL && *freePtr)
1510 				free(str);
1511 			str = var_Error;
1512 			*freePtr = false;
1513 			break;
1514 		}
1515 		if (DEBUG(VAR))
1516 			printf("Result is \"%s\"\n", str);
1517 	}
1518 	if (*tstr == '\0')
1519 		Parse_Error(PARSE_FATAL, "Unclosed variable specification");
1520 	else
1521 		tstr++;
1522 
1523 	*pscan = tstr;
1524 	return str;
1525 }
1526 
1527 char *
1528 Var_GetHead(char *s)
1529 {
1530 	return VarModify(s, VarHead, NULL);
1531 }
1532 
1533 char *
1534 Var_GetTail(char *s)
1535 {
1536 	return VarModify(s, VarTail, NULL);
1537 }
1538