GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/make/varmodifiers.c Lines: 287 450 63.8 %
Date: 2016-12-06 Branches: 161 404 39.9 %

Line Branch Exec Source
1
/*	$OpenBSD: varmodifiers.c,v 1.43 2015/11/15 06:19:22 daniel 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
#include <regex.h>
71
#include <stddef.h>
72
#include <stdio.h>
73
#include <stdlib.h>
74
#include <string.h>
75
#include "config.h"
76
#include "defines.h"
77
#include "buf.h"
78
#include "var.h"
79
#include "varmodifiers.h"
80
#include "varname.h"
81
#include "targ.h"
82
#include "error.h"
83
#include "str.h"
84
#include "cmd_exec.h"
85
#include "memory.h"
86
#include "gnode.h"
87
88
89
/* Var*Pattern flags */
90
#define VAR_SUB_GLOBAL	0x01	/* Apply substitution globally */
91
#define VAR_SUB_ONE	0x02	/* Apply substitution to one word */
92
#define VAR_SUB_MATCHED 0x04	/* There was a match */
93
#define VAR_MATCH_START 0x08	/* Match at start of word */
94
#define VAR_MATCH_END	0x10	/* Match at end of word */
95
96
/* Modifiers flags */
97
#define VAR_EQUAL	0x20
98
#define VAR_MAY_EQUAL	0x40
99
#define VAR_ADD_EQUAL	0x80
100
#define VAR_BANG_EQUAL	0x100
101
102
typedef struct {
103
	char	  *lbuffer; /* left string to free */
104
	char	  *lhs;     /* String to match */
105
	size_t	  leftLen;  /* Length of string */
106
	char	  *rhs;     /* Replacement string (w/ &'s removed) */
107
	size_t	  rightLen; /* Length of replacement */
108
	int 	  flags;
109
} VarPattern;
110
111
struct LoopStuff {
112
	struct LoopVar	*var;
113
	char	*expand;
114
	bool	err;
115
};
116
117
static bool VarHead(struct Name *, bool, Buffer, void *);
118
static bool VarTail(struct Name *, bool, Buffer, void *);
119
static bool VarSuffix(struct Name *, bool, Buffer, void *);
120
static bool VarRoot(struct Name *, bool, Buffer, void *);
121
static bool VarMatch(struct Name *, bool, Buffer, void *);
122
static bool VarSYSVMatch(struct Name *, bool, Buffer, void *);
123
static bool VarNoMatch(struct Name *, bool, Buffer, void *);
124
static bool VarUniq(struct Name *, bool, Buffer, void *);
125
static bool VarLoop(struct Name *, bool, Buffer, void *);
126
127
128
static void VarREError(int, regex_t *, const char *);
129
static bool VarRESubstitute(struct Name *, bool, Buffer, void *);
130
static char *do_regex(const char *, const struct Name *, void *);
131
132
typedef struct {
133
	regex_t	  re;
134
	int 	  nsub;
135
	regmatch_t	 *matches;
136
	char	 *replace;
137
	int 	  flags;
138
} VarREPattern;
139
140
static bool VarSubstitute(struct Name *, bool, Buffer, void *);
141
static char *VarGetPattern(SymTable *, int, const char **, int, int,
142
    size_t *, VarPattern *);
143
static char *VarQuote(const char *, const struct Name *, void *);
144
static char *VarModify(char *, bool (*)(struct Name *, bool, Buffer, void *), void *);
145
146
static void *check_empty(const char **, SymTable *, bool, int);
147
static void *check_quote(const char **, SymTable *, bool, int);
148
static char *do_upper(const char *, const struct Name *, void *);
149
static char *do_lower(const char *, const struct Name *, void *);
150
static void *check_shcmd(const char **, SymTable *, bool, int);
151
static char *do_shcmd(const char *, const struct Name *, void *);
152
static char *do_sort(const char *, const struct Name *, void *);
153
static char *finish_loop(const char *, const struct Name *, void *);
154
static int NameCompare(const void *, const void *);
155
static char *do_label(const char *, const struct Name *, void *);
156
static char *do_path(const char *, const struct Name *, void *);
157
static char *do_def(const char *, const struct Name *, void *);
158
static char *do_undef(const char *, const struct Name *, void *);
159
static char *do_assign(const char *, const struct Name *, void *);
160
static char *do_exec(const char *, const struct Name *, void *);
161
162
static void *assign_get_value(const char **, SymTable *, bool, int);
163
static void *get_cmd(const char **, SymTable *, bool, int);
164
static void *get_value(const char **, SymTable *, bool, int);
165
static void *get_stringarg(const char **, SymTable *, bool, int);
166
static void free_stringarg(void *);
167
static void *get_patternarg(const char **, SymTable *, bool, int);
168
static void *get_spatternarg(const char **, SymTable *, bool, int);
169
static void *common_get_patternarg(const char **, SymTable *, bool, int, bool);
170
static void free_patternarg(void *);
171
static void free_looparg(void *);
172
static void *get_sysvpattern(const char **, SymTable *, bool, int);
173
static void *get_loop(const char **, SymTable *, bool, int);
174
static char *LoopGrab(const char **);
175
176
static struct Name dummy;
177
static struct Name *dummy_arg = &dummy;
178
179
static struct modifier {
180
	    bool atstart;
181
	    void * (*getarg)(const char **, SymTable *, bool, int);
182
	    char * (*apply)(const char *, const struct Name *, void *);
183
	    bool (*word_apply)(struct Name *, bool, Buffer, void *);
184
	    void   (*freearg)(void *);
185
} *choose_mod[256],
186
	match_mod = {false, get_stringarg, NULL, VarMatch, free_stringarg},
187
	nomatch_mod = {false, get_stringarg, NULL, VarNoMatch, free_stringarg},
188
	subst_mod = {false, get_spatternarg, NULL, VarSubstitute, free_patternarg},
189
	resubst_mod = {false, get_patternarg, do_regex, NULL, free_patternarg},
190
	quote_mod = {false, check_quote, VarQuote, NULL , free},
191
	tail_mod = {false, check_empty, NULL, VarTail, NULL},
192
	head_mod = {false, check_empty, NULL, VarHead, NULL},
193
	suffix_mod = {false, check_empty, NULL, VarSuffix, NULL},
194
	root_mod = {false, check_empty, NULL, VarRoot, NULL},
195
	upper_mod = {false, check_empty, do_upper, NULL, NULL},
196
	lower_mod = {false, check_empty, do_lower, NULL, NULL},
197
	shcmd_mod = {false, check_shcmd, do_shcmd, NULL, NULL},
198
	sysv_mod = {false, get_sysvpattern, NULL, VarSYSVMatch, free_patternarg},
199
	uniq_mod = {false, check_empty, NULL, VarUniq, NULL},
200
	sort_mod = {false, check_empty, do_sort, NULL, NULL},
201
	loop_mod = {false, get_loop, finish_loop, VarLoop, free_looparg},
202
	undef_mod = {true, get_value, do_undef, NULL, NULL},
203
	def_mod = {true, get_value, do_def, NULL, NULL},
204
	label_mod = {true, check_empty, do_label, NULL, NULL},
205
	path_mod = {true, check_empty, do_path, NULL, NULL},
206
	assign_mod = {true, assign_get_value, do_assign, NULL, free_patternarg},
207
	exec_mod = {true, get_cmd, do_exec, NULL, free_patternarg}
208
;
209
210
void
211
VarModifiers_Init()
212
729
{
213
729
	choose_mod['M'] = &match_mod;
214
729
	choose_mod['N'] = &nomatch_mod;
215
729
	choose_mod['S'] = &subst_mod;
216
729
	choose_mod['C'] = &resubst_mod;
217
729
	choose_mod['Q'] = &quote_mod;
218
729
	choose_mod['T'] = &tail_mod;
219
729
	choose_mod['H'] = &head_mod;
220
729
	choose_mod['E'] = &suffix_mod;
221
729
	choose_mod['R'] = &root_mod;
222
	if (FEATURES(FEATURE_UPPERLOWER)) {
223
729
		choose_mod['U'] = &upper_mod;
224
729
		choose_mod['L'] = &lower_mod;
225
	}
226
	if (FEATURES(FEATURE_SUNSHCMD))
227
729
		choose_mod['s'] = &shcmd_mod;
228
	if (FEATURES(FEATURE_UNIQ))
229
		choose_mod['u'] = &uniq_mod;
230
	if (FEATURES(FEATURE_SORT))
231
		choose_mod['O'] = &sort_mod;
232
	if (FEATURES(FEATURE_ODE)) {
233
		choose_mod['@'] = &loop_mod;
234
		choose_mod['D'] = &def_mod;
235
		choose_mod['U'] = &undef_mod;
236
		choose_mod['L'] = &label_mod;
237
		choose_mod['P'] = &path_mod;
238
	}
239
	if (FEATURES(FEATURE_ASSIGN))
240
		choose_mod[':'] = &assign_mod;
241
	if (FEATURES(FEATURE_EXECMOD))
242
		choose_mod['!'] = &exec_mod;
243
729
}
244
245
/* All modifiers handle addSpace (need to add a space before placing the
246
 * next word into the buffer) and propagate it when necessary.
247
 */
248
249
/*-
250
 *-----------------------------------------------------------------------
251
 * VarHead --
252
 *	Remove the tail of the given word and add the result to the given
253
 *	buffer.
254
 *-----------------------------------------------------------------------
255
 */
256
static bool
257
VarHead(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
258
{
259
	const char	*slash;
260
261
	slash = Str_rchri(word->s, word->e, '/');
262
	if (slash != NULL) {
263
		if (addSpace)
264
			Buf_AddSpace(buf);
265
		Buf_Addi(buf, word->s, slash);
266
	} else {
267
		/* If no directory part, give . (q.v. the POSIX standard).  */
268
		if (addSpace)
269
			Buf_AddString(buf, " .");
270
		else
271
			Buf_AddChar(buf, '.');
272
	}
273
	return true;
274
}
275
276
/*-
277
 *-----------------------------------------------------------------------
278
 * VarTail --
279
 *	Remove the head of the given word add the result to the given
280
 *	buffer.
281
 *-----------------------------------------------------------------------
282
 */
283
static bool
284
VarTail(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
285
324
{
286
	const char	*slash;
287
288
324
	if (addSpace)
289
		Buf_AddSpace(buf);
290
324
	slash = Str_rchri(word->s, word->e, '/');
291
324
	if (slash != NULL)
292
3
		Buf_Addi(buf, slash+1, word->e);
293
	else
294
321
		Buf_Addi(buf, word->s, word->e);
295
324
	return true;
296
}
297
298
/*-
299
 *-----------------------------------------------------------------------
300
 * VarSuffix --
301
 *	Add the suffix of the given word to the given buffer.
302
 *-----------------------------------------------------------------------
303
 */
304
static bool
305
VarSuffix(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
306
324
{
307
	const char	*dot;
308
309
324
	dot = Str_rchri(word->s, word->e, '.');
310
324
	if (dot != NULL) {
311
324
		if (addSpace)
312
			Buf_AddSpace(buf);
313
324
		Buf_Addi(buf, dot+1, word->e);
314
324
		addSpace = true;
315
	}
316
324
	return addSpace;
317
}
318
319
/*-
320
 *-----------------------------------------------------------------------
321
 * VarRoot --
322
 *	Remove the suffix of the given word and add the result to the
323
 *	buffer.
324
 *-----------------------------------------------------------------------
325
 */
326
static bool
327
VarRoot(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
328
4568
{
329
	const char	*dot;
330
331
4568
	if (addSpace)
332
3413
		Buf_AddSpace(buf);
333
4568
	dot = Str_rchri(word->s, word->e, '.');
334
4568
	if (dot != NULL)
335
4568
		Buf_Addi(buf, word->s, dot);
336
	else
337
		Buf_Addi(buf, word->s, word->e);
338
4568
	return true;
339
}
340
341
/*-
342
 *-----------------------------------------------------------------------
343
 * VarMatch --
344
 *	Add the word to the buffer if it matches the given pattern.
345
 *-----------------------------------------------------------------------
346
 */
347
static bool
348
VarMatch(struct Name *word, bool addSpace, Buffer buf,
349
    void *pattern) /* Pattern the word must match */
350
24473
{
351
24473
	const char *pat = pattern;
352
353
24473
	if (Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
354
1772
		if (addSpace)
355
			Buf_AddSpace(buf);
356
1772
		Buf_Addi(buf, word->s, word->e);
357
1772
		return true;
358
	} else
359
22701
		return addSpace;
360
}
361
362
/*-
363
 *-----------------------------------------------------------------------
364
 * VarNoMatch --
365
 *	Add the word to the buffer if it doesn't match the given pattern.
366
 *-----------------------------------------------------------------------
367
 */
368
static bool
369
VarNoMatch(struct Name *word, bool addSpace, Buffer buf,
370
    void *pattern) /* Pattern the word must not match */
371
11892
{
372
11892
	const char *pat = pattern;
373
374
11892
	if (!Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
375
11892
		if (addSpace)
376
8712
			Buf_AddSpace(buf);
377
11892
		Buf_Addi(buf, word->s, word->e);
378
11892
		return true;
379
	} else
380
		return addSpace;
381
}
382
383
static bool
384
VarUniq(struct Name *word, bool addSpace, Buffer buf, void *lastp)
385
{
386
	struct Name *last = lastp;
387
388
	/* does not match */
389
	if (last->s == NULL || last->e - last->s != word->e - word->s ||
390
	    strncmp(word->s, last->s, word->e - word->s) != 0) {
391
		if (addSpace)
392
			Buf_AddSpace(buf);
393
		Buf_Addi(buf, word->s, word->e);
394
		addSpace = true;
395
	}
396
	last->s = word->s;
397
	last->e = word->e;
398
	return addSpace;
399
}
400
401
static bool
402
VarLoop(struct Name *word, bool addSpace, Buffer buf, void *vp)
403
{
404
	struct LoopStuff *v = vp;
405
406
	if (addSpace)
407
		Buf_AddSpace(buf);
408
	Var_SubstVar(buf, v->expand, v->var, word->s);
409
	return true;
410
}
411
412
static char *
413
finish_loop(const char *s, const struct Name *n UNUSED , void *p)
414
{
415
	struct LoopStuff *l = p;
416
417
	return Var_Subst(s, NULL,  l->err);
418
}
419
420
static int
421
NameCompare(const void *ap, const void *bp)
422
{
423
	const struct Name *a, *b;
424
	size_t n, m;
425
	int c;
426
427
	a = ap;
428
	b = bp;
429
	n = a->e - a->s;
430
	m = b->e - b->s;
431
	if (n < m) {
432
		c = strncmp(a->s, b->s, n);
433
		if (c != 0)
434
			return c;
435
		else
436
			return -1;
437
    	} else if (m < n) {
438
		c = strncmp(a->s, b->s, m);
439
		if (c != 0)
440
			return c;
441
		else
442
			return 1;
443
    	} else
444
		return strncmp(a->s, b->s, n);
445
}
446
447
static char *
448
do_sort(const char *s, const struct Name *dummy UNUSED, void *arg UNUSED)
449
{
450
	struct Name *t;
451
	unsigned long n, i, j;
452
	const char *start, *end;
453
454
	n = 1024;	/* start at 1024 words */
455
	t = ereallocarray(NULL, n, sizeof(struct Name));
456
	start = s;
457
	end = start;
458
459
	for (i = 0;; i++) {
460
		if (i == n) {
461
			n *= 2;
462
			t = ereallocarray(t, n, sizeof(struct Name));
463
		}
464
		start = iterate_words(&end);
465
		if (start == NULL)
466
			break;
467
		t[i].s = start;
468
		t[i].e = end;
469
	}
470
	if (i > 0) {
471
		BUFFER buf;
472
473
		Buf_Init(&buf, end - s);
474
		qsort(t, i, sizeof(struct Name), NameCompare);
475
		Buf_Addi(&buf, t[0].s, t[0].e);
476
		for (j = 1; j < i; j++) {
477
			Buf_AddSpace(&buf);
478
			Buf_Addi(&buf, t[j].s, t[j].e);
479
		}
480
		free(t);
481
		return Buf_Retrieve(&buf);
482
	} else {
483
		free(t);
484
		return "";
485
	}
486
}
487
488
static char *
489
do_label(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
490
{
491
	return Str_dupi(n->s, n->e);
492
}
493
494
static char *
495
do_path(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
496
{
497
	GNode *gn;
498
499
	gn = Targ_FindNodei(n->s, n->e, TARG_NOCREATE);
500
	if (gn == NULL)
501
		return Str_dupi(n->s, n->e);
502
	else
503
		return strdup(gn->path);
504
}
505
506
static char *
507
do_def(const char *s, const struct Name *n UNUSED, void *arg)
508
{
509
	VarPattern *v = arg;
510
	if (s == NULL) {
511
		free_patternarg(v);
512
		return NULL;
513
	} else
514
		return v->lbuffer;
515
}
516
517
static char *
518
do_undef(const char *s, const struct Name *n UNUSED, void *arg)
519
{
520
	VarPattern *v = arg;
521
	if (s != NULL) {
522
		free_patternarg(v);
523
		return NULL;
524
	} else
525
		return v->lbuffer;
526
}
527
528
static char *
529
do_assign(const char *s, const struct Name *n, void *arg)
530
{
531
	VarPattern *v = arg;
532
	char *msg;
533
	char *result;
534
535
	switch (v->flags) {
536
	case VAR_EQUAL:
537
		Var_Seti(n->s, n->e, v->lbuffer);
538
		break;
539
	case VAR_MAY_EQUAL:
540
		if (s == NULL)
541
			Var_Seti(n->s, n->e, v->lbuffer);
542
		break;
543
	case VAR_ADD_EQUAL:
544
		if (s == NULL)
545
			Var_Seti(n->s, n->e, v->lbuffer);
546
		else
547
			Var_Appendi(n->s, n->e, v->lbuffer);
548
		break;
549
	case VAR_BANG_EQUAL:
550
		result = Cmd_Exec(v->lbuffer, &msg);
551
		if (result != NULL) {
552
			Var_Seti(n->s, n->e, result);
553
			free(result);
554
		} else
555
			Error(msg, v->lbuffer);
556
		break;
557
558
	}
559
	return NULL;
560
}
561
562
static char *
563
do_exec(const char *s UNUSED, const struct Name *n UNUSED, void *arg)
564
{
565
	VarPattern *v = arg;
566
	char *msg;
567
	char *result;
568
569
	result = Cmd_Exec(v->lbuffer, &msg);
570
	if (result == NULL)
571
		Error(msg, v->lbuffer);
572
	return result;
573
}
574
575
/*-
576
 *-----------------------------------------------------------------------
577
 * VarSYSVMatch --
578
 *	Add the word to the buffer if it matches the given pattern.
579
 *	Used to implement the System V % modifiers.
580
 *-----------------------------------------------------------------------
581
 */
582
static bool
583
VarSYSVMatch(struct Name *word, bool addSpace, Buffer buf, void *patp)
584
447
{
585
	size_t	len;
586
	const char	*ptr;
587
447
	VarPattern	*pat = patp;
588
589
447
	if (*word->s != '\0') {
590
447
		if (addSpace)
591
395
			Buf_AddSpace(buf);
592
447
		if ((ptr = Str_SYSVMatch(word->s, pat->lhs, &len)) != NULL)
593
447
			Str_SYSVSubst(buf, pat->rhs, ptr, len);
594
		else
595
			Buf_Addi(buf, word->s, word->e);
596
447
		return true;
597
	} else
598
		return addSpace;
599
}
600
601
void *
602
get_sysvpattern(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
603
943
{
604
	VarPattern		*pattern;
605
	const char		*cp, *cp2;
606
	BUFFER buf;
607
943
	int cnt = 0;
608
943
	char startc = endc == ')' ? '(' : '{';
609
2829
	for (cp = *p;; cp++) {
610
2829
		if (*cp == '=' && cnt == 0)
611
943
			break;
612
1886
		if (*cp == '\0')
613
			return NULL;
614
1886
		if (*cp == startc)
615
			cnt++;
616
1886
		else if (*cp == endc) {
617
			cnt--;
618
			if (cnt < 0)
619
				return NULL;
620
		}
621
1886
	}
622
943
	Buf_Init(&buf, 0);
623
2858
	for (cp2 = cp+1;; cp2++) {
624


2858
		if (((*cp2 == ':' && cp2[1] != endc) || *cp2 == endc) &&
625
		    cnt == 0)
626
943
			break;
627
1915
		if (*cp2 == '\0') {
628
			Buf_Destroy(&buf);
629
			return NULL;
630
		}
631
1915
		if (*cp2 == startc)
632
			cnt++;
633
1915
		else if (*cp2 == endc) {
634
			cnt--;
635
			if (cnt < 0) {
636
				Buf_Destroy(&buf);
637
				return NULL;
638
			}
639
1915
		} else if (*cp2 == '$') {
640
			if (cp2[1] == '$')
641
				cp2++;
642
			else {
643
				size_t len;
644
				(void)Var_ParseBuffer(&buf, cp2, ctxt, err,
645
				    &len);
646
				cp2 += len - 1;
647
				continue;
648
			}
649
		}
650
1915
		Buf_AddChar(&buf, *cp2);
651
1915
	}
652
653
943
	pattern = emalloc(sizeof(VarPattern));
654
943
	pattern->lbuffer = pattern->lhs = Str_dupi(*p, cp);
655
943
	pattern->leftLen = cp - *p;
656
943
	pattern->rhs = Buf_Retrieve(&buf);
657
943
	pattern->rightLen = Buf_Size(&buf);
658
943
	pattern->flags = 0;
659
943
	*p = cp2;
660
943
	return pattern;
661
}
662
663
664
/*-
665
 *-----------------------------------------------------------------------
666
 * VarSubstitute --
667
 *	Perform a string-substitution on the given word, Adding the
668
 *	result to the given buffer.
669
 *-----------------------------------------------------------------------
670
 */
671
static bool
672
VarSubstitute(struct Name *word, bool addSpace, Buffer buf,
673
    void *patternp) /* Pattern for substitution */
674
8250
{
675
    size_t	wordLen;    /* Length of word */
676
    const char	*cp;	    /* General pointer */
677
8250
    VarPattern	*pattern = patternp;
678
679
8250
    wordLen = word->e - word->s;
680
8250
    if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
681
	(VAR_SUB_ONE|VAR_SUB_MATCHED)) {
682
	/* Still substituting -- break it down into simple anchored cases
683
	 * and if none of them fits, perform the general substitution case.  */
684

8250
	if ((pattern->flags & VAR_MATCH_START) &&
685
	    (strncmp(word->s, pattern->lhs, pattern->leftLen) == 0)) {
686
		/* Anchored at start and beginning of word matches pattern.  */
687

208
		if ((pattern->flags & VAR_MATCH_END) &&
688
		    (wordLen == pattern->leftLen)) {
689
			/* Also anchored at end and matches to the end (word
690
			 * is same length as pattern) add space and rhs only
691
			 * if rhs is non-null.	*/
692
			if (pattern->rightLen != 0) {
693
			    if (addSpace)
694
				Buf_AddSpace(buf);
695
			    addSpace = true;
696
			    Buf_AddChars(buf, pattern->rightLen,
697
					 pattern->rhs);
698
			}
699
			pattern->flags |= VAR_SUB_MATCHED;
700
208
		} else if (pattern->flags & VAR_MATCH_END) {
701
		    /* Doesn't match to end -- copy word wholesale.  */
702
		    goto nosub;
703
		} else {
704
		    /* Matches at start but need to copy in
705
		     * trailing characters.  */
706
208
		    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
707
208
			if (addSpace)
708
24
			    Buf_AddSpace(buf);
709
208
			addSpace = true;
710
		    }
711
208
		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
712
208
		    Buf_AddChars(buf, wordLen - pattern->leftLen,
713
				 word->s + pattern->leftLen);
714
208
		    pattern->flags |= VAR_SUB_MATCHED;
715
		}
716
8042
	} else if (pattern->flags & VAR_MATCH_START) {
717
	    /* Had to match at start of word and didn't -- copy whole word.  */
718
3181
	    goto nosub;
719
4861
	} else if (pattern->flags & VAR_MATCH_END) {
720
	    /* Anchored at end, Find only place match could occur (leftLen
721
	     * characters from the end of the word) and see if it does. Note
722
	     * that because the $ will be left at the end of the lhs, we have
723
	     * to use strncmp.	*/
724
4599
	    cp = word->s + (wordLen - pattern->leftLen);
725

4599
	    if (cp >= word->s &&
726
		strncmp(cp, pattern->lhs, pattern->leftLen) == 0) {
727
		/* Match found. If we will place characters in the buffer,
728
		 * add a space before hand as indicated by addSpace, then
729
		 * stuff in the initial, unmatched part of the word followed
730
		 * by the right-hand-side.  */
731
4599
		if (((cp - word->s) + pattern->rightLen) != 0) {
732
4599
		    if (addSpace)
733
3437
			Buf_AddSpace(buf);
734
4599
		    addSpace = true;
735
		}
736
4599
		Buf_Addi(buf, word->s, cp);
737
4599
		Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
738
4599
		pattern->flags |= VAR_SUB_MATCHED;
739
	    } else {
740
		/* Had to match at end and didn't. Copy entire word.  */
741
		goto nosub;
742
	    }
743
	} else {
744
	    /* Pattern is unanchored: search for the pattern in the word using
745
	     * strstr, copying unmatched portions and the
746
	     * right-hand-side for each match found, handling non-global
747
	     * substitutions correctly, etc. When the loop is done, any
748
	     * remaining part of the word (word and wordLen are adjusted
749
	     * accordingly through the loop) is copied straight into the
750
	     * buffer.
751
	     * addSpace is set to false as soon as a space is added to the
752
	     * buffer.	*/
753
	    bool done;
754
	    size_t origSize;
755
756
262
	    done = false;
757
262
	    origSize = Buf_Size(buf);
758
786
	    while (!done) {
759
262
		cp = strstr(word->s, pattern->lhs);
760
262
		if (cp != NULL) {
761

262
		    if (addSpace && (cp - word->s) + pattern->rightLen != 0){
762
			Buf_AddSpace(buf);
763
			addSpace = false;
764
		    }
765
262
		    Buf_Addi(buf, word->s, cp);
766
262
		    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
767
262
		    wordLen -= (cp - word->s) + pattern->leftLen;
768
262
		    word->s = cp + pattern->leftLen;
769

262
		    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0)
770
262
			done = true;
771
262
		    pattern->flags |= VAR_SUB_MATCHED;
772
		} else
773
		    done = true;
774
	    }
775
262
	    if (wordLen != 0) {
776
262
		if (addSpace)
777
		    Buf_AddSpace(buf);
778
262
		Buf_AddChars(buf, wordLen, word->s);
779
	    }
780
	    /* If added characters to the buffer, need to add a space
781
	     * before we add any more. If we didn't add any, just return
782
	     * the previous value of addSpace.	*/
783

262
	    return Buf_Size(buf) != origSize || addSpace;
784
	}
785
4807
	return addSpace;
786
    }
787
3181
 nosub:
788
3181
    if (addSpace)
789
	Buf_AddSpace(buf);
790
3181
    Buf_AddChars(buf, wordLen, word->s);
791
3181
    return true;
792
}
793
794
/*-
795
 *-----------------------------------------------------------------------
796
 * VarREError --
797
 *	Print the error caused by a regcomp or regexec call.
798
 *-----------------------------------------------------------------------
799
 */
800
static void
801
VarREError(int err, regex_t *pat, const char *str)
802
{
803
	char	*errbuf;
804
	int 	errlen;
805
806
	errlen = regerror(err, pat, 0, 0);
807
	errbuf = emalloc(errlen);
808
	regerror(err, pat, errbuf, errlen);
809
	Error("%s: %s", str, errbuf);
810
	free(errbuf);
811
}
812
813
/*-
814
 *-----------------------------------------------------------------------
815
 * VarRESubstitute --
816
 *	Perform a regex substitution on the given word, placing the
817
 *	result in the passed buffer.
818
 *-----------------------------------------------------------------------
819
 */
820
static bool
821
VarRESubstitute(struct Name *word, bool addSpace, Buffer buf, void *patternp)
822
5404
{
823
	VarREPattern	*pat;
824
	int 		xrv;
825
	const char		*wp;
826
	char		*rp;
827
	int 		added;
828
829
#define MAYBE_ADD_SPACE()		\
830
	if (addSpace && !added) 	\
831
		Buf_AddSpace(buf);	\
832
	added = 1
833
834
5404
	added = 0;
835
5404
	wp = word->s;
836
5404
	pat = patternp;
837
838
5404
	if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
839
	    (VAR_SUB_ONE|VAR_SUB_MATCHED))
840
		xrv = REG_NOMATCH;
841
	else {
842
5404
	tryagain:
843
5404
		xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);
844
	}
845
846
5404
	switch (xrv) {
847
	case 0:
848
5404
		pat->flags |= VAR_SUB_MATCHED;
849
5404
		if (pat->matches[0].rm_so > 0) {
850

2702
			MAYBE_ADD_SPACE();
851
2702
			Buf_AddChars(buf, pat->matches[0].rm_so, wp);
852
		}
853
854
5404
		for (rp = pat->replace; *rp; rp++) {
855
			if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
856
				MAYBE_ADD_SPACE();
857
				Buf_AddChar(buf,rp[1]);
858
				rp++;
859
			}
860
			else if (*rp == '&' ||
861
			    (*rp == '\\' && ISDIGIT(rp[1]))) {
862
				int n;
863
				const char *subbuf;
864
				int sublen;
865
				char errstr[3];
866
867
				if (*rp == '&') {
868
					n = 0;
869
					errstr[0] = '&';
870
					errstr[1] = '\0';
871
				} else {
872
					n = rp[1] - '0';
873
					errstr[0] = '\\';
874
					errstr[1] = rp[1];
875
					errstr[2] = '\0';
876
					rp++;
877
				}
878
879
				if (n > pat->nsub) {
880
					Error("No subexpression %s",
881
					    &errstr[0]);
882
					subbuf = "";
883
					sublen = 0;
884
				} else if (pat->matches[n].rm_so == -1 &&
885
				    pat->matches[n].rm_eo == -1) {
886
					Error("No match for subexpression %s",
887
					    &errstr[0]);
888
					subbuf = "";
889
					sublen = 0;
890
				} else {
891
					subbuf = wp + pat->matches[n].rm_so;
892
					sublen = pat->matches[n].rm_eo -
893
					    pat->matches[n].rm_so;
894
				}
895
896
				if (sublen > 0) {
897
					MAYBE_ADD_SPACE();
898
					Buf_AddChars(buf, sublen, subbuf);
899
				}
900
			} else {
901
				MAYBE_ADD_SPACE();
902
				Buf_AddChar(buf, *rp);
903
			}
904
		}
905
5404
		wp += pat->matches[0].rm_eo;
906
5404
		if (pat->flags & VAR_SUB_GLOBAL) {
907
			/* like most modern tools, empty string matches
908
			 * should advance one char at a time...
909
			 */
910
			if (pat->matches[0].rm_eo == 0)  {
911
				if (*wp) {
912
					MAYBE_ADD_SPACE();
913
					Buf_AddChar(buf, *wp++);
914
				} else
915
					break;
916
			}
917
			goto tryagain;
918
		}
919
5404
		if (*wp) {
920

2702
			MAYBE_ADD_SPACE();
921
2702
			Buf_AddString(buf, wp);
922
		}
923
		break;
924
	default:
925
		VarREError(xrv, &pat->re, "Unexpected regex error");
926
	       /* FALLTHROUGH */
927
	case REG_NOMATCH:
928
		if (*wp) {
929
			MAYBE_ADD_SPACE();
930
			Buf_AddString(buf, wp);
931
		}
932
		break;
933
	}
934

5404
	return addSpace||added;
935
}
936
937
/*-
938
 *-----------------------------------------------------------------------
939
 * VarModify --
940
 *	Modify each of the words of the passed string using the given
941
 *	function. Used to implement all modifiers.
942
 *
943
 * Results:
944
 *	A string of all the words modified appropriately.
945
 *-----------------------------------------------------------------------
946
 */
947
static char *
948
VarModify(char *str, 		/* String whose words should be trimmed */
949
				/* Function to use to modify them */
950
    bool (*modProc)(struct Name *, bool, Buffer, void *),
951
    void *datum)		/* Datum to pass it */
952
24611
{
953
	BUFFER	  buf;		/* Buffer for the new string */
954
	bool	  addSpace;	/* true if need to add a space to the
955
				     * buffer before adding the trimmed
956
				     * word */
957
	struct Name	  word;
958
959
24611
	Buf_Init(&buf, 0);
960
24611
	addSpace = false;
961
962
24611
	word.e = str;
963
964
104904
	while ((word.s = iterate_words(&word.e)) != NULL) {
965
		char termc;
966
967
55682
		termc = *word.e;
968
55682
		*((char *)(word.e)) = '\0';
969
55682
		addSpace = (*modProc)(&word, addSpace, &buf, datum);
970
55682
		*((char *)(word.e)) = termc;
971
	}
972
24611
	return Buf_Retrieve(&buf);
973
}
974
975
/*-
976
 *-----------------------------------------------------------------------
977
 * VarGetPattern --
978
 *	Pass through the tstr looking for 1) escaped delimiters,
979
 *	'$'s and backslashes (place the escaped character in
980
 *	uninterpreted) and 2) unescaped $'s that aren't before
981
 *	the delimiter (expand the variable substitution).
982
 *	Return the expanded string or NULL if the delimiter was missing
983
 *	If pattern is specified, handle escaped ampersands, and replace
984
 *	unescaped ampersands with the lhs of the pattern.
985
 *
986
 * Results:
987
 *	A string of all the words modified appropriately.
988
 *	If length is specified, return the string length of the buffer
989
 *-----------------------------------------------------------------------
990
 */
991
static char *
992
VarGetPattern(SymTable *ctxt, int err, const char **tstr, int delim1,
993
    int delim2, size_t *length, VarPattern *pattern)
994
20386
{
995
	const char	*cp;
996
	char	*result;
997
	BUFFER	buf;
998
	size_t	junk;
999
1000
20386
	Buf_Init(&buf, 0);
1001
20386
	if (length == NULL)
1002
		length = &junk;
1003
1004
#define IS_A_MATCH(cp, delim1, delim2) \
1005
	(cp[0] == '\\' && (cp[1] == delim1 || cp[1] == delim2 || \
1006
	 cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&')))
1007
1008
	/*
1009
	 * Skim through until the matching delimiter is found;
1010
	 * pick up variable substitutions on the way. Also allow
1011
	 * backslashes to quote the delimiter, $, and \, but don't
1012
	 * touch other backslashes.
1013
	 */
1014

91477
	for (cp = *tstr; *cp != '\0' && *cp != delim1 && *cp != delim2; cp++) {
1015



71615
		if (IS_A_MATCH(cp, delim1, delim2)) {
1016
524
			Buf_AddChar(&buf, cp[1]);
1017
524
			cp++;
1018
70567
		} else if (*cp == '$') {
1019
			/* Allowed at end of pattern */
1020

2586
			if (cp[1] == delim1 || cp[1] == delim2)
1021
1162
				Buf_AddChar(&buf, *cp);
1022
			else {
1023
				size_t len;
1024
1025
				/* If unescaped dollar sign not before the
1026
				 * delimiter, assume it's a variable
1027
				 * substitution and recurse.  */
1028
262
				(void)Var_ParseBuffer(&buf, cp, ctxt, err,
1029
				    &len);
1030
262
				cp += len - 1;
1031
			}
1032

69143
		} else if (pattern && *cp == '&')
1033
			Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
1034
		else
1035
69143
			Buf_AddChar(&buf, *cp);
1036
	}
1037
1038
20386
	*length = Buf_Size(&buf);
1039
20386
	result = Buf_Retrieve(&buf);
1040
1041

20386
	if (*cp != delim1 && *cp != delim2) {
1042
		*tstr = cp;
1043
		*length = 0;
1044
		free(result);
1045
		return NULL;
1046
	}
1047
	else {
1048
20386
		*tstr = ++cp;
1049
20386
		return result;
1050
	}
1051
}
1052
1053
/*-
1054
 *-----------------------------------------------------------------------
1055
 * VarQuote --
1056
 *	Quote shell meta-characters in the string
1057
 *
1058
 * Results:
1059
 *	The quoted string
1060
 *-----------------------------------------------------------------------
1061
 */
1062
static char *
1063
VarQuote(const char *str, const struct Name *n UNUSED, void *islistp)
1064
{
1065
	int *p = islistp;
1066
	int islist = *p;
1067
1068
	BUFFER	  buf;
1069
	/* This should cover most shells :-( */
1070
	static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1071
	char *rep = meta;
1072
	if (islist)
1073
		rep += 3;
1074
1075
	Buf_Init(&buf, MAKE_BSIZE);
1076
	for (; *str; str++) {
1077
		if (strchr(rep, *str) != NULL)
1078
			Buf_AddChar(&buf, '\\');
1079
		Buf_AddChar(&buf, *str);
1080
	}
1081
	return Buf_Retrieve(&buf);
1082
}
1083
1084
static void *
1085
check_empty(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1086
2466
{
1087
2466
	dummy_arg->s = NULL;
1088

2466
	if ((*p)[1] == endc || (*p)[1] == ':') {
1089
2466
		(*p)++;
1090
2466
		return dummy_arg;
1091
	} else
1092
		return NULL;
1093
}
1094
1095
static void *
1096
check_quote(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1097
{
1098
	int *qargs = emalloc(sizeof(int));
1099
	*qargs = 0;
1100
	if ((*p)[1] == 'L') {
1101
		*qargs = 1;
1102
		(*p)++;
1103
	}
1104
	if ((*p)[1] == endc || (*p)[1] == ':') {
1105
		(*p)++;
1106
		return qargs;
1107
	} else  {
1108
		free(qargs);
1109
		return NULL;
1110
	}
1111
}
1112
1113
static void *
1114
check_shcmd(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1115
{
1116
	if ((*p)[1] == 'h' && ((*p)[2] == endc || (*p)[2] == ':')) {
1117
		(*p)+=2;
1118
		return dummy_arg;
1119
	} else
1120
		return NULL;
1121
}
1122
1123
1124
static char *
1125
do_shcmd(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1126
{
1127
	char *err;
1128
	char *t;
1129
1130
	t = Cmd_Exec(s, &err);
1131
	if (err)
1132
		Error(err, s);
1133
	return t;
1134
}
1135
1136
static void *
1137
get_stringarg(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1138
11672
{
1139
	const char *cp;
1140
	char *s;
1141
1142

68151
	for (cp = *p + 1; *cp != ':' && *cp != endc; cp++) {
1143
56479
		if (*cp == '\\') {
1144
			if (cp[1] == ':' || cp[1] == endc || cp[1] == '\\')
1145
				cp++;
1146
56479
		} else if (*cp == '\0')
1147
			return NULL;
1148
	}
1149
11672
	s = escape_dupi(*p+1, cp, ":)}");
1150
11672
	*p = cp;
1151
11672
	return s;
1152
}
1153
1154
static void
1155
free_stringarg(void *arg)
1156
11672
{
1157
11672
	free(arg);
1158
11672
}
1159
1160
static char *
1161
do_upper(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1162
{
1163
	size_t len, i;
1164
	char *t;
1165
1166
	len = strlen(s);
1167
	t = emalloc(len+1);
1168
	for (i = 0; i < len; i++)
1169
		t[i] = TOUPPER(s[i]);
1170
	t[len] = '\0';
1171
	return t;
1172
}
1173
1174
static char *
1175
do_lower(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1176
663
{
1177
	size_t	len, i;
1178
	char	*t;
1179
1180
663
	len = strlen(s);
1181
663
	t = emalloc(len+1);
1182
2105
	for (i = 0; i < len; i++)
1183
1442
		t[i] = TOLOWER(s[i]);
1184
663
	t[len] = '\0';
1185
663
	return t;
1186
}
1187
1188
static void *
1189
get_patternarg(const char **p, SymTable *ctxt, bool err, int endc)
1190
5404
{
1191
5404
	return common_get_patternarg(p, ctxt, err, endc, false);
1192
}
1193
1194
/* Extract anchors */
1195
static void *
1196
get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
1197
4789
{
1198
	VarPattern *pattern;
1199
1200
4789
	pattern = common_get_patternarg(p, ctxt, err, endc, true);
1201

4789
	if (pattern != NULL && pattern->leftLen > 0) {
1202
4789
		if (pattern->lhs[pattern->leftLen-1] == '$') {
1203
1162
			    pattern->leftLen--;
1204
1162
			    pattern->flags |= VAR_MATCH_END;
1205
		}
1206
4789
		if (pattern->lhs[0] == '^') {
1207
3365
			    pattern->lhs++;
1208
3365
			    pattern->leftLen--;
1209
3365
			    pattern->flags |= VAR_MATCH_START;
1210
		}
1211
	}
1212
4789
	return pattern;
1213
}
1214
1215
static void
1216
free_looparg(void *arg)
1217
{
1218
	struct LoopStuff *l = arg;
1219
1220
	Var_DeleteLoopVar(l->var);
1221
	free(l->expand);
1222
}
1223
1224
static char *
1225
LoopGrab(const char **s)
1226
{
1227
	const char *p, *start;
1228
1229
	start = *s;
1230
	for (p = start; *p != '@'; p++) {
1231
		if (*p == '\\')
1232
			p++;
1233
		if (*p == 0)
1234
			return NULL;
1235
	}
1236
	*s = p+1;
1237
	return escape_dupi(start, p, "@\\");
1238
}
1239
1240
static void *
1241
get_loop(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
1242
{
1243
	static struct LoopStuff loop;
1244
	const char *s;
1245
	const char *var;
1246
1247
	s = *p +1;
1248
1249
	loop.var = NULL;
1250
	loop.expand = NULL;
1251
	loop.err = err;
1252
	var = LoopGrab(&s);
1253
	if (var != NULL) {
1254
		loop.expand = LoopGrab(&s);
1255
		if (*s == endc || *s == ':') {
1256
			*p = s;
1257
			loop.var = Var_NewLoopVar(var, NULL);
1258
			return &loop;
1259
		}
1260
	}
1261
	free_looparg(&loop);
1262
	return NULL;
1263
}
1264
1265
static void *
1266
common_get_patternarg(const char **p, SymTable *ctxt, bool err, int endc,
1267
    bool dosubst)
1268
10193
{
1269
	VarPattern *pattern;
1270
	char delim;
1271
	const char *s;
1272
1273
10193
	pattern = emalloc(sizeof(VarPattern));
1274
10193
	pattern->flags = 0;
1275
10193
	s = *p;
1276
1277
10193
	delim = s[1];
1278
10193
	if (delim == '\0')
1279
		return NULL;
1280
10193
	s += 2;
1281
1282
10193
	pattern->rhs = NULL;
1283
10193
	pattern->lhs = VarGetPattern(ctxt, err, &s, delim, delim,
1284
	    &pattern->leftLen, NULL);
1285
10193
	pattern->lbuffer = pattern->lhs;
1286
10193
	if (pattern->lhs != NULL) {
1287
10193
		pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
1288
		    &pattern->rightLen, dosubst ? pattern: NULL);
1289
10193
		if (pattern->rhs != NULL) {
1290
			/* Check for global substitution. If 'g' after the
1291
			 * final delimiter, substitution is global and is
1292
			 * marked that way.  */
1293
			for (;; s++) {
1294
10193
				switch (*s) {
1295
				case 'g':
1296
					pattern->flags |= VAR_SUB_GLOBAL;
1297
					continue;
1298
				case '1':
1299
					pattern->flags |= VAR_SUB_ONE;
1300
					continue;
1301
				}
1302
				break;
1303
			}
1304

10193
			if (*s == endc || *s == ':') {
1305
10193
				*p = s;
1306
10193
				return pattern;
1307
			}
1308
		}
1309
	}
1310
	free_patternarg(pattern);
1311
	return NULL;
1312
}
1313
1314
static void *
1315
assign_get_value(const char **p, SymTable *ctxt, bool err, int endc)
1316
{
1317
	const char *s;
1318
	int flags;
1319
	VarPattern *arg;
1320
1321
	s = *p + 1;
1322
	if (s[0] == '=')
1323
		flags = VAR_EQUAL;
1324
	else if (s[0] == '?' && s[1] == '=')
1325
		flags = VAR_MAY_EQUAL;
1326
	else if (s[0] == '+' && s[1] == '=')
1327
		flags = VAR_ADD_EQUAL;
1328
	else if (s[0] == '!' && s[1] == '=')
1329
		flags = VAR_BANG_EQUAL;
1330
	else
1331
		return NULL;
1332
1333
	arg = get_value(&s, ctxt, err, endc);
1334
	if (arg != NULL) {
1335
		*p = s;
1336
		arg->flags = flags;
1337
	}
1338
	return arg;
1339
}
1340
1341
static void *
1342
get_value(const char **p, SymTable *ctxt, bool err, int endc)
1343
{
1344
	VarPattern *pattern;
1345
	const char *s;
1346
1347
	pattern = emalloc(sizeof(VarPattern));
1348
	s = *p + 1;
1349
	pattern->rhs = NULL;
1350
	pattern->lbuffer = VarGetPattern(ctxt, err, &s, ':', endc,
1351
	    &pattern->leftLen, NULL);
1352
	if (s[-1] == endc || s[-1] == ':') {
1353
		*p = s-1;
1354
		return pattern;
1355
	}
1356
	free_patternarg(pattern);
1357
	return NULL;
1358
}
1359
1360
static void *
1361
get_cmd(const char **p, SymTable *ctxt, bool err, int endc UNUSED)
1362
{
1363
	VarPattern *pattern;
1364
	const char *s;
1365
1366
	pattern = emalloc(sizeof(VarPattern));
1367
	s = *p + 1;
1368
	pattern->rhs = NULL;
1369
	pattern->lbuffer = VarGetPattern(ctxt, err, &s, '!', '!',
1370
	    &pattern->leftLen, NULL);
1371
	if (s[-1] == '!') {
1372
		*p = s-1;
1373
		return pattern;
1374
	}
1375
	free_patternarg(pattern);
1376
	return NULL;
1377
}
1378
1379
static void
1380
free_patternarg(void *p)
1381
11136
{
1382
11136
	VarPattern *vp = p;
1383
1384
11136
	free(vp->lbuffer);
1385
11136
	free(vp->rhs);
1386
11136
	free(vp);
1387
11136
}
1388
1389
static char *
1390
do_regex(const char *s, const struct Name *n UNUSED, void *arg)
1391
5404
{
1392
	VarREPattern p2;
1393
5404
	VarPattern *p = arg;
1394
	int error;
1395
	char *result;
1396
1397
5404
	error = regcomp(&p2.re, p->lhs, REG_EXTENDED);
1398
5404
	if (error) {
1399
		VarREError(error, &p2.re, "RE substitution error");
1400
		return var_Error;
1401
	}
1402
5404
	p2.nsub = p2.re.re_nsub + 1;
1403
5404
	p2.replace = p->rhs;
1404
5404
	p2.flags = p->flags;
1405
5404
	if (p2.nsub < 1)
1406
		p2.nsub = 1;
1407
5404
	if (p2.nsub > 10)
1408
		p2.nsub = 10;
1409
5404
	p2.matches = ereallocarray(NULL, p2.nsub, sizeof(regmatch_t));
1410
5404
	result = VarModify((char *)s, VarRESubstitute, &p2);
1411
5404
	regfree(&p2.re);
1412
5404
	free(p2.matches);
1413
5404
	return result;
1414
}
1415
1416
char *
1417
VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
1418
    bool err, bool *freePtr, const char **pscan, int paren)
1419
20475
{
1420
	const char *tstr;
1421
	bool atstart;    /* Some ODE modifiers only make sense at start */
1422
20475
	char endc = paren == '(' ? ')' : '}';
1423
20475
	const char *start = *pscan;
1424
1425
20475
	tstr = start;
1426
	/*
1427
	 * Now we need to apply any modifiers the user wants applied.
1428
	 * These are:
1429
	 *		  :M<pattern>	words which match the given <pattern>.
1430
	 *				<pattern> is of the standard file
1431
	 *				wildcarding form.
1432
	 *		  :S<d><pat1><d><pat2><d>[g]
1433
	 *				Substitute <pat2> for <pat1> in the
1434
	 *				value
1435
	 *		  :C<d><pat1><d><pat2><d>[g]
1436
	 *				Substitute <pat2> for regex <pat1> in
1437
	 *				the value
1438
	 *		  :H		Substitute the head of each word
1439
	 *		  :T		Substitute the tail of each word
1440
	 *		  :E		Substitute the extension (minus '.') of
1441
	 *				each word
1442
	 *		  :R		Substitute the root of each word
1443
	 *				(pathname minus the suffix).
1444
	 *		  :lhs=rhs	Like :S, but the rhs goes to the end of
1445
	 *				the invocation.
1446
	 */
1447
1448
20475
	atstart = true;
1449

66224
	while (*tstr != endc && *tstr != '\0') {
1450
		struct modifier *mod;
1451
		void *arg;
1452
		char *newStr;
1453
1454
25274
		tstr++;
1455
25274
		if (DEBUG(VAR))
1456
			printf("Applying :%c to \"%s\"\n", *tstr, str);
1457
1458
25274
		mod = choose_mod[(unsigned char)*tstr];
1459
25274
		arg = NULL;
1460
1461

25274
		if (mod != NULL && (!mod->atstart || atstart))
1462
24331
			arg = mod->getarg(&tstr, ctxt, err, endc);
1463
25274
		if (FEATURES(FEATURE_SYSVVARSUB) && arg == NULL) {
1464
943
			mod = &sysv_mod;
1465
943
			arg = mod->getarg(&tstr, ctxt, err, endc);
1466
		}
1467
25274
		atstart = false;
1468
25274
		if (arg != NULL) {
1469

25274
			if (str != NULL || (mod->atstart && name != NULL)) {
1470
25274
				if (mod->word_apply != NULL) {
1471
19207
					newStr = VarModify(str,
1472
					    mod->word_apply, arg);
1473
19207
					if (mod->apply != NULL) {
1474
						char *newStr2;
1475
1476
						newStr2 = mod->apply(newStr,
1477
						    name, arg);
1478
						free(newStr);
1479
						newStr = newStr2;
1480
					}
1481
				} else
1482
6067
					newStr = mod->apply(str, name, arg);
1483
25274
				if (*freePtr)
1484
7585
					free(str);
1485
25274
				str = newStr;
1486
25274
				if (str != var_Error)
1487
25274
					*freePtr = true;
1488
				else
1489
					*freePtr = false;
1490
			}
1491
25274
			if (mod->freearg != NULL)
1492
22808
				mod->freearg(arg);
1493
		} else {
1494
			Error("Bad modifier: %s", tstr);
1495
			/* Try skipping to end of var... */
1496
			for (tstr++; *tstr != endc && *tstr != '\0';)
1497
				tstr++;
1498
			if (str != NULL && *freePtr)
1499
				free(str);
1500
			str = var_Error;
1501
			*freePtr = false;
1502
			break;
1503
		}
1504
25274
		if (DEBUG(VAR))
1505
			printf("Result is \"%s\"\n", str);
1506
	}
1507
20475
	if (*tstr == '\0')
1508
		Parse_Error(PARSE_FATAL, "Unclosed variable specification");
1509
	else
1510
20475
		tstr++;
1511
1512
20475
	*pscan = tstr;
1513
20475
	return str;
1514
}
1515
1516
char *
1517
Var_GetHead(char *s)
1518
{
1519
	return VarModify(s, VarHead, NULL);
1520
}
1521
1522
char *
1523
Var_GetTail(char *s)
1524
{
1525
	return VarModify(s, VarTail, NULL);
1526
}