xref: /openbsd-src/usr.bin/make/varmodifiers.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: varmodifiers.c,v 1.30 2011/08/16 14:18: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 = (struct Name *)emalloc(sizeof(struct Name) * n);
464 	start = s;
465 	end = start;
466 
467 	for (i = 0;; i++) {
468 		if (i == n) {
469 			n *= 2;
470 			t = (struct Name *)erealloc(t, sizeof(struct Name) * n);
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 			goto tryagain;
917 		if (*wp) {
918 			MAYBE_ADD_SPACE();
919 			Buf_AddString(buf, wp);
920 		}
921 		break;
922 	default:
923 		VarREError(xrv, &pat->re, "Unexpected regex error");
924 	       /* FALLTHROUGH */
925 	case REG_NOMATCH:
926 		if (*wp) {
927 			MAYBE_ADD_SPACE();
928 			Buf_AddString(buf, wp);
929 		}
930 		break;
931 	}
932 	return addSpace||added;
933 }
934 #endif
935 
936 /*-
937  *-----------------------------------------------------------------------
938  * VarModify --
939  *	Modify each of the words of the passed string using the given
940  *	function. Used to implement all modifiers.
941  *
942  * Results:
943  *	A string of all the words modified appropriately.
944  *-----------------------------------------------------------------------
945  */
946 static char *
947 VarModify(char *str, 		/* String whose words should be trimmed */
948 				/* Function to use to modify them */
949     bool (*modProc)(struct Name *, bool, Buffer, void *),
950     void *datum)		/* Datum to pass it */
951 {
952 	BUFFER	  buf;		/* Buffer for the new string */
953 	bool	  addSpace;	/* true if need to add a space to the
954 				     * buffer before adding the trimmed
955 				     * word */
956 	struct Name	  word;
957 
958 	Buf_Init(&buf, 0);
959 	addSpace = false;
960 
961 	word.e = str;
962 
963 	while ((word.s = iterate_words(&word.e)) != NULL) {
964 		char termc;
965 
966 		termc = *word.e;
967 		*((char *)(word.e)) = '\0';
968 		addSpace = (*modProc)(&word, addSpace, &buf, datum);
969 		*((char *)(word.e)) = termc;
970 	}
971 	return Buf_Retrieve(&buf);
972 }
973 
974 /*-
975  *-----------------------------------------------------------------------
976  * VarGetPattern --
977  *	Pass through the tstr looking for 1) escaped delimiters,
978  *	'$'s and backslashes (place the escaped character in
979  *	uninterpreted) and 2) unescaped $'s that aren't before
980  *	the delimiter (expand the variable substitution).
981  *	Return the expanded string or NULL if the delimiter was missing
982  *	If pattern is specified, handle escaped ampersands, and replace
983  *	unescaped ampersands with the lhs of the pattern.
984  *
985  * Results:
986  *	A string of all the words modified appropriately.
987  *	If length is specified, return the string length of the buffer
988  *-----------------------------------------------------------------------
989  */
990 static char *
991 VarGetPattern(SymTable *ctxt, int err, const char **tstr, int delim1,
992     int delim2, size_t *length, VarPattern *pattern)
993 {
994 	const char	*cp;
995 	char	*result;
996 	BUFFER	buf;
997 	size_t	junk;
998 
999 	Buf_Init(&buf, 0);
1000 	if (length == NULL)
1001 		length = &junk;
1002 
1003 #define IS_A_MATCH(cp, delim1, delim2) \
1004 	(cp[0] == '\\' && (cp[1] == delim1 || cp[1] == delim2 || \
1005 	 cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&')))
1006 
1007 	/*
1008 	 * Skim through until the matching delimiter is found;
1009 	 * pick up variable substitutions on the way. Also allow
1010 	 * backslashes to quote the delimiter, $, and \, but don't
1011 	 * touch other backslashes.
1012 	 */
1013 	for (cp = *tstr; *cp != '\0' && *cp != delim1 && *cp != delim2; cp++) {
1014 		if (IS_A_MATCH(cp, delim1, delim2)) {
1015 			Buf_AddChar(&buf, cp[1]);
1016 			cp++;
1017 		} else if (*cp == '$') {
1018 			/* Allowed at end of pattern */
1019 			if (cp[1] == delim1 || cp[1] == delim2)
1020 				Buf_AddChar(&buf, *cp);
1021 			else {
1022 				size_t len;
1023 
1024 				/* If unescaped dollar sign not before the
1025 				 * delimiter, assume it's a variable
1026 				 * substitution and recurse.  */
1027 				(void)Var_ParseBuffer(&buf, cp, ctxt, err,
1028 				    &len);
1029 				cp += len - 1;
1030 			}
1031 		} else if (pattern && *cp == '&')
1032 			Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
1033 		else
1034 			Buf_AddChar(&buf, *cp);
1035 	}
1036 
1037 	*length = Buf_Size(&buf);
1038 	result = Buf_Retrieve(&buf);
1039 
1040 	if (*cp != delim1 && *cp != delim2) {
1041 		*tstr = cp;
1042 		*length = 0;
1043 		free(result);
1044 		return NULL;
1045 	}
1046 	else {
1047 		*tstr = ++cp;
1048 		return result;
1049 	}
1050 }
1051 
1052 /*-
1053  *-----------------------------------------------------------------------
1054  * VarQuote --
1055  *	Quote shell meta-characters in the string
1056  *
1057  * Results:
1058  *	The quoted string
1059  *-----------------------------------------------------------------------
1060  */
1061 static char *
1062 VarQuote(const char *str, const struct Name *n UNUSED, void *islistp)
1063 {
1064 	int islist = *((int *)islistp);
1065 
1066 	BUFFER	  buf;
1067 	/* This should cover most shells :-( */
1068 	static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1069 	char *rep = meta;
1070 	if (islist)
1071 		rep += 3;
1072 
1073 	Buf_Init(&buf, MAKE_BSIZE);
1074 	for (; *str; str++) {
1075 		if (strchr(rep, *str) != NULL)
1076 			Buf_AddChar(&buf, '\\');
1077 		Buf_AddChar(&buf, *str);
1078 	}
1079 	return Buf_Retrieve(&buf);
1080 }
1081 
1082 static void *
1083 check_empty(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1084 {
1085 	dummy_arg->s = NULL;
1086 	if ((*p)[1] == endc || (*p)[1] == ':') {
1087 		(*p)++;
1088 		return dummy_arg;
1089 	} else
1090 		return NULL;
1091 }
1092 
1093 static void *
1094 check_quote(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1095 {
1096 	int *qargs = emalloc(sizeof(int));
1097 	*qargs = 0;
1098 	if ((*p)[1] == 'L') {
1099 		*qargs = 1;
1100 		(*p)++;
1101 	}
1102 	if ((*p)[1] == endc || (*p)[1] == ':') {
1103 		(*p)++;
1104 		return qargs;
1105 	} else
1106 		return NULL;
1107 }
1108 
1109 static void *
1110 check_shcmd(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1111 {
1112 	if ((*p)[1] == 'h' && ((*p)[2] == endc || (*p)[2] == ':')) {
1113 		(*p)+=2;
1114 		return dummy_arg;
1115 	} else
1116 		return NULL;
1117 }
1118 
1119 
1120 static char *
1121 do_shcmd(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1122 {
1123 	char *err;
1124 	char *t;
1125 
1126 	t = Cmd_Exec(s, &err);
1127 	if (err)
1128 		Error(err, s);
1129 	return t;
1130 }
1131 
1132 static void *
1133 get_stringarg(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1134 {
1135 	const char *cp;
1136 	char *s;
1137 
1138 	for (cp = *p + 1; *cp != ':' && *cp != endc; cp++) {
1139 		if (*cp == '\\') {
1140 			if (cp[1] == ':' || cp[1] == endc || cp[1] == '\\')
1141 				cp++;
1142 		} else if (*cp == '\0')
1143 			return NULL;
1144 	}
1145 	s = escape_dupi(*p+1, cp, ":)}");
1146 	*p = cp;
1147 	return s;
1148 }
1149 
1150 static void
1151 free_stringarg(void *arg)
1152 {
1153 	free(arg);
1154 }
1155 
1156 static char *
1157 do_upper(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1158 {
1159 	size_t len, i;
1160 	char *t;
1161 
1162 	len = strlen(s);
1163 	t = emalloc(len+1);
1164 	for (i = 0; i < len; i++)
1165 		t[i] = toupper(s[i]);
1166 	t[len] = '\0';
1167 	return t;
1168 }
1169 
1170 static char *
1171 do_lower(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1172 {
1173 	size_t	len, i;
1174 	char	*t;
1175 
1176 	len = strlen(s);
1177 	t = emalloc(len+1);
1178 	for (i = 0; i < len; i++)
1179 		t[i] = tolower(s[i]);
1180 	t[len] = '\0';
1181 	return t;
1182 }
1183 
1184 static void *
1185 get_patternarg(const char **p, SymTable *ctxt, bool err, int endc)
1186 {
1187 	return common_get_patternarg(p, ctxt, err, endc, false);
1188 }
1189 
1190 /* Extract anchors */
1191 static void *
1192 get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
1193 {
1194 	VarPattern *pattern;
1195 
1196 	pattern = common_get_patternarg(p, ctxt, err, endc, true);
1197 	if (pattern != NULL && pattern->leftLen > 0) {
1198 		if (pattern->lhs[pattern->leftLen-1] == '$') {
1199 			    pattern->leftLen--;
1200 			    pattern->flags |= VAR_MATCH_END;
1201 		}
1202 		if (pattern->lhs[0] == '^') {
1203 			    pattern->lhs++;
1204 			    pattern->leftLen--;
1205 			    pattern->flags |= VAR_MATCH_START;
1206 		}
1207 	}
1208 	return pattern;
1209 }
1210 
1211 static void
1212 free_looparg(void *arg)
1213 {
1214 	struct LoopStuff *l = (struct LoopStuff *)arg;
1215 
1216 	Var_DeleteLoopVar(l->var);
1217 	free(l->expand);
1218 }
1219 
1220 static char *
1221 LoopGrab(const char **s)
1222 {
1223 	const char *p, *start;
1224 
1225 	start = *s;
1226 	for (p = start; *p != '@'; p++) {
1227 		if (*p == '\\')
1228 			p++;
1229 		if (*p == 0)
1230 			return NULL;
1231 	}
1232 	*s = p+1;
1233 	return escape_dupi(start, p, "@\\");
1234 }
1235 
1236 static void *
1237 get_loop(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
1238 {
1239 	static struct LoopStuff loop;
1240 	const char *s;
1241 	const char *var;
1242 
1243 	s = *p +1;
1244 
1245 	loop.var = NULL;
1246 	loop.expand = NULL;
1247 	loop.err = err;
1248 	var = LoopGrab(&s);
1249 	if (var != NULL) {
1250 		loop.expand = LoopGrab(&s);
1251 		if (*s == endc || *s == ':') {
1252 			*p = s;
1253 			loop.var = Var_NewLoopVar(var, NULL);
1254 			return &loop;
1255 		}
1256 	}
1257 	free_looparg(&loop);
1258 	return NULL;
1259 }
1260 
1261 static void *
1262 common_get_patternarg(const char **p, SymTable *ctxt, bool err, int endc,
1263     bool dosubst)
1264 {
1265 	VarPattern *pattern;
1266 	char delim;
1267 	const char *s;
1268 
1269 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1270 	pattern->flags = 0;
1271 	s = *p;
1272 
1273 	delim = s[1];
1274 	if (delim == '\0')
1275 		return NULL;
1276 	s += 2;
1277 
1278 	pattern->rhs = NULL;
1279 	pattern->lhs = VarGetPattern(ctxt, err, &s, delim, delim,
1280 	    &pattern->leftLen, NULL);
1281 	pattern->lbuffer = pattern->lhs;
1282 	if (pattern->lhs != NULL) {
1283 		pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
1284 		    &pattern->rightLen, dosubst ? pattern: NULL);
1285 		if (pattern->rhs != NULL) {
1286 			/* Check for global substitution. If 'g' after the
1287 			 * final delimiter, substitution is global and is
1288 			 * marked that way.  */
1289 			for (;; s++) {
1290 				switch (*s) {
1291 				case 'g':
1292 					pattern->flags |= VAR_SUB_GLOBAL;
1293 					continue;
1294 				case '1':
1295 					pattern->flags |= VAR_SUB_ONE;
1296 					continue;
1297 				}
1298 				break;
1299 			}
1300 			if (*s == endc || *s == ':') {
1301 				*p = s;
1302 				return pattern;
1303 			}
1304 		}
1305 	}
1306 	free_patternarg(pattern);
1307 	return NULL;
1308 }
1309 
1310 static void *
1311 assign_get_value(const char **p, SymTable *ctxt, bool err, int endc)
1312 {
1313 	const char *s;
1314 	int flags;
1315 	VarPattern *arg;
1316 
1317 	s = *p + 1;
1318 	if (s[0] == '=')
1319 		flags = VAR_EQUAL;
1320 	else if (s[0] == '?' && s[1] == '=')
1321 		flags = VAR_MAY_EQUAL;
1322 	else if (s[0] == '+' && s[1] == '=')
1323 		flags = VAR_ADD_EQUAL;
1324 	else if (s[0] == '!' && s[1] == '=')
1325 		flags = VAR_BANG_EQUAL;
1326 	else
1327 		return NULL;
1328 
1329 	arg = get_value(&s, ctxt, err, endc);
1330 	if (arg != NULL) {
1331 		*p = s;
1332 		arg->flags = flags;
1333 	}
1334 	return arg;
1335 }
1336 
1337 static void *
1338 get_value(const char **p, SymTable *ctxt, bool err, int endc)
1339 {
1340 	VarPattern *pattern;
1341 	const char *s;
1342 
1343 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1344 	s = *p + 1;
1345 	pattern->rhs = NULL;
1346 	pattern->lbuffer = VarGetPattern(ctxt, err, &s, ':', endc,
1347 	    &pattern->leftLen, NULL);
1348 	if (s[-1] == endc || s[-1] == ':') {
1349 		*p = s-1;
1350 		return pattern;
1351 	}
1352 	free_patternarg(pattern);
1353 	return NULL;
1354 }
1355 
1356 static void *
1357 get_cmd(const char **p, SymTable *ctxt, bool err, int endc UNUSED)
1358 {
1359 	VarPattern *pattern;
1360 	const char *s;
1361 
1362 	pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1363 	s = *p + 1;
1364 	pattern->rhs = NULL;
1365 	pattern->lbuffer = VarGetPattern(ctxt, err, &s, '!', '!',
1366 	    &pattern->leftLen, NULL);
1367 	if (s[-1] == '!') {
1368 		*p = s-1;
1369 		return pattern;
1370 	}
1371 	free_patternarg(pattern);
1372 	return NULL;
1373 }
1374 
1375 static void
1376 free_patternarg(void *p)
1377 {
1378 	VarPattern *vp = (VarPattern *)p;
1379 
1380 	free(vp->lbuffer);
1381 	free(vp->rhs);
1382 	free(vp);
1383 }
1384 
1385 #ifndef MAKE_BOOTSTRAP
1386 static char *
1387 do_regex(const char *s, const struct Name *n UNUSED, void *arg)
1388 {
1389 	VarREPattern p2;
1390 	VarPattern *p = (VarPattern *)arg;
1391 	int error;
1392 	char *result;
1393 
1394 	error = regcomp(&p2.re, p->lhs, REG_EXTENDED);
1395 	if (error) {
1396 		VarREError(error, &p2.re, "RE substitution error");
1397 		return var_Error;
1398 	}
1399 	p2.nsub = p2.re.re_nsub + 1;
1400 	p2.replace = p->rhs;
1401 	p2.flags = p->flags;
1402 	if (p2.nsub < 1)
1403 		p2.nsub = 1;
1404 	if (p2.nsub > 10)
1405 		p2.nsub = 10;
1406 	p2.matches = emalloc(p2.nsub * sizeof(regmatch_t));
1407 	result = VarModify((char *)s, VarRESubstitute, &p2);
1408 	regfree(&p2.re);
1409 	free(p2.matches);
1410 	return result;
1411 }
1412 #endif
1413 
1414 char *
1415 VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
1416     bool err, bool *freePtr, const char **pscan, int paren)
1417 {
1418 	const char *tstr;
1419 	bool atstart;    /* Some ODE modifiers only make sense at start */
1420 	char endc = paren == '(' ? ')' : '}';
1421 	const char *start = *pscan;
1422 
1423 	tstr = start;
1424 	/*
1425 	 * Now we need to apply any modifiers the user wants applied.
1426 	 * These are:
1427 	 *		  :M<pattern>	words which match the given <pattern>.
1428 	 *				<pattern> is of the standard file
1429 	 *				wildcarding form.
1430 	 *		  :S<d><pat1><d><pat2><d>[g]
1431 	 *				Substitute <pat2> for <pat1> in the
1432 	 *				value
1433 	 *		  :C<d><pat1><d><pat2><d>[g]
1434 	 *				Substitute <pat2> for regex <pat1> in
1435 	 *				the value
1436 	 *		  :H		Substitute the head of each word
1437 	 *		  :T		Substitute the tail of each word
1438 	 *		  :E		Substitute the extension (minus '.') of
1439 	 *				each word
1440 	 *		  :R		Substitute the root of each word
1441 	 *				(pathname minus the suffix).
1442 	 *		  :lhs=rhs	Like :S, but the rhs goes to the end of
1443 	 *				the invocation.
1444 	 */
1445 
1446 	atstart = true;
1447 	while (*tstr != endc && *tstr != '\0') {
1448 		struct modifier *mod;
1449 		void *arg;
1450 		char *newStr;
1451 
1452 		tstr++;
1453 		if (DEBUG(VAR))
1454 			printf("Applying :%c to \"%s\"\n", *tstr, str);
1455 
1456 		mod = choose_mod[*tstr];
1457 		arg = NULL;
1458 
1459 		if (mod != NULL && (!mod->atstart || atstart))
1460 			arg = mod->getarg(&tstr, ctxt, err, endc);
1461 		if (FEATURES(FEATURE_SYSVVARSUB) && arg == NULL) {
1462 			mod = &sysv_mod;
1463 			arg = mod->getarg(&tstr, ctxt, err, endc);
1464 		}
1465 		atstart = false;
1466 		if (arg != NULL) {
1467 			if (str != NULL || (mod->atstart && name != NULL)) {
1468 				if (mod->word_apply != NULL) {
1469 					newStr = VarModify(str,
1470 					    mod->word_apply, arg);
1471 					if (mod->apply != NULL) {
1472 						char *newStr2;
1473 
1474 						newStr2 = mod->apply(newStr,
1475 						    name, arg);
1476 						free(newStr);
1477 						newStr = newStr2;
1478 					}
1479 				} else
1480 					newStr = mod->apply(str, name, arg);
1481 				if (*freePtr)
1482 					free(str);
1483 				str = newStr;
1484 				if (str != var_Error)
1485 					*freePtr = true;
1486 				else
1487 					*freePtr = false;
1488 			}
1489 			if (mod->freearg != NULL)
1490 				mod->freearg(arg);
1491 		} else {
1492 			Error("Bad modifier: %s\n", tstr);
1493 			/* Try skipping to end of var... */
1494 			for (tstr++; *tstr != endc && *tstr != '\0';)
1495 				tstr++;
1496 			if (str != NULL && *freePtr)
1497 				free(str);
1498 			str = var_Error;
1499 			*freePtr = false;
1500 			break;
1501 		}
1502 		if (DEBUG(VAR))
1503 			printf("Result is \"%s\"\n", str);
1504 	}
1505 	if (*tstr == '\0')
1506 		Error("Unclosed variable specification");
1507 	else
1508 		tstr++;
1509 
1510 	*pscan = tstr;
1511 	return str;
1512 }
1513 
1514 char *
1515 Var_GetHead(char *s)
1516 {
1517 	return VarModify(s, VarHead, NULL);
1518 }
1519 
1520 char *
1521 Var_GetTail(char *s)
1522 {
1523 	return VarModify(s, VarTail, NULL);
1524 }
1525