xref: /freebsd/bin/sh/expand.c (revision 3157ba21)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)expand.c	8.5 (Berkeley) 5/15/95";
38 #endif
39 #endif /* not lint */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42 
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <dirent.h>
48 #include <unistd.h>
49 #include <pwd.h>
50 #include <stdlib.h>
51 #include <limits.h>
52 #include <stdio.h>
53 #include <string.h>
54 
55 /*
56  * Routines to expand arguments to commands.  We have to deal with
57  * backquotes, shell variables, and file metacharacters.
58  */
59 
60 #include "shell.h"
61 #include "main.h"
62 #include "nodes.h"
63 #include "eval.h"
64 #include "expand.h"
65 #include "syntax.h"
66 #include "parser.h"
67 #include "jobs.h"
68 #include "options.h"
69 #include "var.h"
70 #include "input.h"
71 #include "output.h"
72 #include "memalloc.h"
73 #include "error.h"
74 #include "mystring.h"
75 #include "arith.h"
76 #include "show.h"
77 
78 /*
79  * Structure specifying which parts of the string should be searched
80  * for IFS characters.
81  */
82 
83 struct ifsregion {
84 	struct ifsregion *next;	/* next region in list */
85 	int begoff;		/* offset of start of region */
86 	int endoff;		/* offset of end of region */
87 	int inquotes;		/* search for nul bytes only */
88 };
89 
90 
91 STATIC char *expdest;			/* output of current string */
92 STATIC struct nodelist *argbackq;	/* list of back quote expressions */
93 STATIC struct ifsregion ifsfirst;	/* first struct in list of ifs regions */
94 STATIC struct ifsregion *ifslastp;	/* last struct in list */
95 STATIC struct arglist exparg;		/* holds expanded arg list */
96 
97 STATIC void argstr(char *, int);
98 STATIC char *exptilde(char *, int);
99 STATIC void expbackq(union node *, int, int);
100 STATIC int subevalvar(char *, char *, int, int, int, int);
101 STATIC char *evalvar(char *, int);
102 STATIC int varisset(char *, int);
103 STATIC void varvalue(char *, int, int, int);
104 STATIC void recordregion(int, int, int);
105 STATIC void removerecordregions(int);
106 STATIC void ifsbreakup(char *, struct arglist *);
107 STATIC void expandmeta(struct strlist *, int);
108 STATIC void expmeta(char *, char *);
109 STATIC void addfname(char *);
110 STATIC struct strlist *expsort(struct strlist *);
111 STATIC struct strlist *msort(struct strlist *, int);
112 STATIC int pmatch(const char *, const char *, int);
113 STATIC char *cvtnum(int, char *);
114 STATIC int collate_range_cmp(int, int);
115 
116 STATIC int
117 collate_range_cmp(int c1, int c2)
118 {
119 	static char s1[2], s2[2];
120 
121 	s1[0] = c1;
122 	s2[0] = c2;
123 	return (strcoll(s1, s2));
124 }
125 
126 /*
127  * Expand shell variables and backquotes inside a here document.
128  *	union node *arg		the document
129  *	int fd;			where to write the expanded version
130  */
131 
132 void
133 expandhere(union node *arg, int fd)
134 {
135 	herefd = fd;
136 	expandarg(arg, (struct arglist *)NULL, 0);
137 	xwrite(fd, stackblock(), expdest - stackblock());
138 }
139 
140 
141 /*
142  * Perform variable substitution and command substitution on an argument,
143  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
144  * perform splitting and file name expansion.  When arglist is NULL, perform
145  * here document expansion.
146  */
147 
148 void
149 expandarg(union node *arg, struct arglist *arglist, int flag)
150 {
151 	struct strlist *sp;
152 	char *p;
153 
154 	argbackq = arg->narg.backquote;
155 	STARTSTACKSTR(expdest);
156 	ifsfirst.next = NULL;
157 	ifslastp = NULL;
158 	argstr(arg->narg.text, flag);
159 	if (arglist == NULL) {
160 		return;			/* here document expanded */
161 	}
162 	STPUTC('\0', expdest);
163 	p = grabstackstr(expdest);
164 	exparg.lastp = &exparg.list;
165 	/*
166 	 * TODO - EXP_REDIR
167 	 */
168 	if (flag & EXP_FULL) {
169 		ifsbreakup(p, &exparg);
170 		*exparg.lastp = NULL;
171 		exparg.lastp = &exparg.list;
172 		expandmeta(exparg.list, flag);
173 	} else {
174 		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
175 			rmescapes(p);
176 		sp = (struct strlist *)stalloc(sizeof (struct strlist));
177 		sp->text = p;
178 		*exparg.lastp = sp;
179 		exparg.lastp = &sp->next;
180 	}
181 	while (ifsfirst.next != NULL) {
182 		struct ifsregion *ifsp;
183 		INTOFF;
184 		ifsp = ifsfirst.next->next;
185 		ckfree(ifsfirst.next);
186 		ifsfirst.next = ifsp;
187 		INTON;
188 	}
189 	*exparg.lastp = NULL;
190 	if (exparg.list) {
191 		*arglist->lastp = exparg.list;
192 		arglist->lastp = exparg.lastp;
193 	}
194 }
195 
196 
197 
198 /*
199  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
200  * characters to allow for further processing.  Otherwise treat
201  * $@ like $* since no splitting will be performed.
202  */
203 
204 STATIC void
205 argstr(char *p, int flag)
206 {
207 	char c;
208 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);	/* do CTLESC */
209 	int firsteq = 1;
210 
211 	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
212 		p = exptilde(p, flag);
213 	for (;;) {
214 		switch (c = *p++) {
215 		case '\0':
216 		case CTLENDVAR: /* ??? */
217 			goto breakloop;
218 		case CTLQUOTEMARK:
219 			/* "$@" syntax adherence hack */
220 			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
221 				break;
222 			if ((flag & EXP_FULL) != 0)
223 				STPUTC(c, expdest);
224 			break;
225 		case CTLESC:
226 			if (quotes)
227 				STPUTC(c, expdest);
228 			c = *p++;
229 			STPUTC(c, expdest);
230 			break;
231 		case CTLVAR:
232 			p = evalvar(p, flag);
233 			break;
234 		case CTLBACKQ:
235 		case CTLBACKQ|CTLQUOTE:
236 			expbackq(argbackq->n, c & CTLQUOTE, flag);
237 			argbackq = argbackq->next;
238 			break;
239 		case CTLENDARI:
240 			expari(flag);
241 			break;
242 		case ':':
243 		case '=':
244 			/*
245 			 * sort of a hack - expand tildes in variable
246 			 * assignments (after the first '=' and after ':'s).
247 			 */
248 			STPUTC(c, expdest);
249 			if (flag & EXP_VARTILDE && *p == '~') {
250 				if (c == '=') {
251 					if (firsteq)
252 						firsteq = 0;
253 					else
254 						break;
255 				}
256 				p = exptilde(p, flag);
257 			}
258 			break;
259 		default:
260 			STPUTC(c, expdest);
261 		}
262 	}
263 breakloop:;
264 }
265 
266 STATIC char *
267 exptilde(char *p, int flag)
268 {
269 	char c, *startp = p;
270 	struct passwd *pw;
271 	char *home;
272 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
273 
274 	while ((c = *p) != '\0') {
275 		switch(c) {
276 		case CTLESC: /* This means CTL* are always considered quoted. */
277 		case CTLVAR:
278 		case CTLBACKQ:
279 		case CTLBACKQ | CTLQUOTE:
280 		case CTLARI:
281 		case CTLENDARI:
282 		case CTLQUOTEMARK:
283 			return (startp);
284 		case ':':
285 			if (flag & EXP_VARTILDE)
286 				goto done;
287 			break;
288 		case '/':
289 		case CTLENDVAR:
290 			goto done;
291 		}
292 		p++;
293 	}
294 done:
295 	*p = '\0';
296 	if (*(startp+1) == '\0') {
297 		if ((home = lookupvar("HOME")) == NULL)
298 			goto lose;
299 	} else {
300 		if ((pw = getpwnam(startp+1)) == NULL)
301 			goto lose;
302 		home = pw->pw_dir;
303 	}
304 	if (*home == '\0')
305 		goto lose;
306 	*p = c;
307 	while ((c = *home++) != '\0') {
308 		if (quotes && SQSYNTAX[(int)c] == CCTL)
309 			STPUTC(CTLESC, expdest);
310 		STPUTC(c, expdest);
311 	}
312 	return (p);
313 lose:
314 	*p = c;
315 	return (startp);
316 }
317 
318 
319 STATIC void
320 removerecordregions(int endoff)
321 {
322 	if (ifslastp == NULL)
323 		return;
324 
325 	if (ifsfirst.endoff > endoff) {
326 		while (ifsfirst.next != NULL) {
327 			struct ifsregion *ifsp;
328 			INTOFF;
329 			ifsp = ifsfirst.next->next;
330 			ckfree(ifsfirst.next);
331 			ifsfirst.next = ifsp;
332 			INTON;
333 		}
334 		if (ifsfirst.begoff > endoff)
335 			ifslastp = NULL;
336 		else {
337 			ifslastp = &ifsfirst;
338 			ifsfirst.endoff = endoff;
339 		}
340 		return;
341 	}
342 
343 	ifslastp = &ifsfirst;
344 	while (ifslastp->next && ifslastp->next->begoff < endoff)
345 		ifslastp=ifslastp->next;
346 	while (ifslastp->next != NULL) {
347 		struct ifsregion *ifsp;
348 		INTOFF;
349 		ifsp = ifslastp->next->next;
350 		ckfree(ifslastp->next);
351 		ifslastp->next = ifsp;
352 		INTON;
353 	}
354 	if (ifslastp->endoff > endoff)
355 		ifslastp->endoff = endoff;
356 }
357 
358 /*
359  * Expand arithmetic expression.  Backup to start of expression,
360  * evaluate, place result in (backed up) result, adjust string position.
361  */
362 void
363 expari(int flag)
364 {
365 	char *p, *q, *start;
366 	arith_t result;
367 	int begoff;
368 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
369 	int quoted;
370 
371 
372 	/*
373 	 * This routine is slightly over-complicated for
374 	 * efficiency.  First we make sure there is
375 	 * enough space for the result, which may be bigger
376 	 * than the expression if we add exponentiation.  Next we
377 	 * scan backwards looking for the start of arithmetic.  If the
378 	 * next previous character is a CTLESC character, then we
379 	 * have to rescan starting from the beginning since CTLESC
380 	 * characters have to be processed left to right.
381 	 */
382 	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
383 	USTPUTC('\0', expdest);
384 	start = stackblock();
385 	p = expdest - 2;
386 	while (p >= start && *p != CTLARI)
387 		--p;
388 	if (p < start || *p != CTLARI)
389 		error("missing CTLARI (shouldn't happen)");
390 	if (p > start && *(p - 1) == CTLESC)
391 		for (p = start; *p != CTLARI; p++)
392 			if (*p == CTLESC)
393 				p++;
394 
395 	if (p[1] == '"')
396 		quoted=1;
397 	else
398 		quoted=0;
399 	begoff = p - start;
400 	removerecordregions(begoff);
401 	if (quotes)
402 		rmescapes(p+2);
403 	q = grabstackstr(expdest);
404 	result = arith(p+2);
405 	ungrabstackstr(q, expdest);
406 	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
407 	while (*p++)
408 		;
409 	if (quoted == 0)
410 		recordregion(begoff, p - 1 - start, 0);
411 	result = expdest - p + 1;
412 	STADJUST(-result, expdest);
413 }
414 
415 
416 /*
417  * Expand stuff in backwards quotes.
418  */
419 
420 STATIC void
421 expbackq(union node *cmd, int quoted, int flag)
422 {
423 	struct backcmd in;
424 	int i;
425 	char buf[128];
426 	char *p;
427 	char *dest = expdest;
428 	struct ifsregion saveifs, *savelastp;
429 	struct nodelist *saveargbackq;
430 	char lastc;
431 	int startloc = dest - stackblock();
432 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
433 	int saveherefd;
434 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
435 	int nnl;
436 
437 	INTOFF;
438 	saveifs = ifsfirst;
439 	savelastp = ifslastp;
440 	saveargbackq = argbackq;
441 	saveherefd = herefd;
442 	herefd = -1;
443 	p = grabstackstr(dest);
444 	evalbackcmd(cmd, &in);
445 	ungrabstackstr(p, dest);
446 	ifsfirst = saveifs;
447 	ifslastp = savelastp;
448 	argbackq = saveargbackq;
449 	herefd = saveherefd;
450 
451 	p = in.buf;
452 	lastc = '\0';
453 	nnl = 0;
454 	/* Don't copy trailing newlines */
455 	for (;;) {
456 		if (--in.nleft < 0) {
457 			if (in.fd < 0)
458 				break;
459 			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
460 			TRACE(("expbackq: read returns %d\n", i));
461 			if (i <= 0)
462 				break;
463 			p = buf;
464 			in.nleft = i - 1;
465 		}
466 		lastc = *p++;
467 		if (lastc != '\0') {
468 			if (quotes && syntax[(int)lastc] == CCTL)
469 				STPUTC(CTLESC, dest);
470 			if (lastc == '\n') {
471 				nnl++;
472 			} else {
473 				while (nnl > 0) {
474 					nnl--;
475 					STPUTC('\n', dest);
476 				}
477 				STPUTC(lastc, dest);
478 			}
479 		}
480 	}
481 
482 	if (in.fd >= 0)
483 		close(in.fd);
484 	if (in.buf)
485 		ckfree(in.buf);
486 	if (in.jp)
487 		exitstatus = waitforjob(in.jp, (int *)NULL);
488 	if (quoted == 0)
489 		recordregion(startloc, dest - stackblock(), 0);
490 	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
491 		(dest - stackblock()) - startloc,
492 		(dest - stackblock()) - startloc,
493 		stackblock() + startloc));
494 	expdest = dest;
495 	INTON;
496 }
497 
498 
499 
500 STATIC int
501 subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
502   int varflags)
503 {
504 	char *startp;
505 	char *loc = NULL;
506 	char *q;
507 	int c = 0;
508 	int saveherefd = herefd;
509 	struct nodelist *saveargbackq = argbackq;
510 	int amount;
511 
512 	herefd = -1;
513 	argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
514 	    subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
515 	    EXP_CASE : 0) | EXP_TILDE);
516 	STACKSTRNUL(expdest);
517 	herefd = saveherefd;
518 	argbackq = saveargbackq;
519 	startp = stackblock() + startloc;
520 	if (str == NULL)
521 	    str = stackblock() + strloc;
522 
523 	switch (subtype) {
524 	case VSASSIGN:
525 		setvar(str, startp, 0);
526 		amount = startp - expdest;
527 		STADJUST(amount, expdest);
528 		varflags &= ~VSNUL;
529 		if (c != 0)
530 			*loc = c;
531 		return 1;
532 
533 	case VSQUESTION:
534 		if (*p != CTLENDVAR) {
535 			outfmt(out2, "%s\n", startp);
536 			error((char *)NULL);
537 		}
538 		error("%.*s: parameter %snot set", (int)(p - str - 1),
539 		      str, (varflags & VSNUL) ? "null or "
540 					      : nullstr);
541 		return 0;
542 
543 	case VSTRIMLEFT:
544 		for (loc = startp; loc < str; loc++) {
545 			c = *loc;
546 			*loc = '\0';
547 			if (patmatch(str, startp, varflags & VSQUOTE)) {
548 				*loc = c;
549 				goto recordleft;
550 			}
551 			*loc = c;
552 			if ((varflags & VSQUOTE) && *loc == CTLESC)
553 				loc++;
554 		}
555 		return 0;
556 
557 	case VSTRIMLEFTMAX:
558 		for (loc = str - 1; loc >= startp;) {
559 			c = *loc;
560 			*loc = '\0';
561 			if (patmatch(str, startp, varflags & VSQUOTE)) {
562 				*loc = c;
563 				goto recordleft;
564 			}
565 			*loc = c;
566 			loc--;
567 			if ((varflags & VSQUOTE) && loc > startp &&
568 			    *(loc - 1) == CTLESC) {
569 				for (q = startp; q < loc; q++)
570 					if (*q == CTLESC)
571 						q++;
572 				if (q > loc)
573 					loc--;
574 			}
575 		}
576 		return 0;
577 
578 	case VSTRIMRIGHT:
579 		for (loc = str - 1; loc >= startp;) {
580 			if (patmatch(str, loc, varflags & VSQUOTE)) {
581 				amount = loc - expdest;
582 				STADJUST(amount, expdest);
583 				return 1;
584 			}
585 			loc--;
586 			if ((varflags & VSQUOTE) && loc > startp &&
587 			    *(loc - 1) == CTLESC) {
588 				for (q = startp; q < loc; q++)
589 					if (*q == CTLESC)
590 						q++;
591 				if (q > loc)
592 					loc--;
593 			}
594 		}
595 		return 0;
596 
597 	case VSTRIMRIGHTMAX:
598 		for (loc = startp; loc < str - 1; loc++) {
599 			if (patmatch(str, loc, varflags & VSQUOTE)) {
600 				amount = loc - expdest;
601 				STADJUST(amount, expdest);
602 				return 1;
603 			}
604 			if ((varflags & VSQUOTE) && *loc == CTLESC)
605 				loc++;
606 		}
607 		return 0;
608 
609 
610 	default:
611 		abort();
612 	}
613 
614 recordleft:
615 	amount = ((str - 1) - (loc - startp)) - expdest;
616 	STADJUST(amount, expdest);
617 	while (loc != str - 1)
618 		*startp++ = *loc++;
619 	return 1;
620 }
621 
622 
623 /*
624  * Expand a variable, and return a pointer to the next character in the
625  * input string.
626  */
627 
628 STATIC char *
629 evalvar(char *p, int flag)
630 {
631 	int subtype;
632 	int varflags;
633 	char *var;
634 	char *val;
635 	int patloc;
636 	int c;
637 	int set;
638 	int special;
639 	int startloc;
640 	int varlen;
641 	int easy;
642 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
643 
644 	varflags = (unsigned char)*p++;
645 	subtype = varflags & VSTYPE;
646 	var = p;
647 	special = 0;
648 	if (! is_name(*p))
649 		special = 1;
650 	p = strchr(p, '=') + 1;
651 again: /* jump here after setting a variable with ${var=text} */
652 	if (varflags & VSLINENO) {
653 		set = 1;
654 		special = 0;
655 		val = var;
656 		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
657 				   terminated string */
658 	} else if (special) {
659 		set = varisset(var, varflags & VSNUL);
660 		val = NULL;
661 	} else {
662 		val = bltinlookup(var, 1);
663 		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
664 			val = NULL;
665 			set = 0;
666 		} else
667 			set = 1;
668 	}
669 	varlen = 0;
670 	startloc = expdest - stackblock();
671 	if (!set && uflag && *var != '@' && *var != '*') {
672 		switch (subtype) {
673 		case VSNORMAL:
674 		case VSTRIMLEFT:
675 		case VSTRIMLEFTMAX:
676 		case VSTRIMRIGHT:
677 		case VSTRIMRIGHTMAX:
678 		case VSLENGTH:
679 			error("%.*s: parameter not set", (int)(p - var - 1),
680 			    var);
681 		}
682 	}
683 	if (set && subtype != VSPLUS) {
684 		/* insert the value of the variable */
685 		if (special) {
686 			varvalue(var, varflags & VSQUOTE, subtype, flag);
687 			if (subtype == VSLENGTH) {
688 				varlen = expdest - stackblock() - startloc;
689 				STADJUST(-varlen, expdest);
690 			}
691 		} else {
692 			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
693 								  : BASESYNTAX;
694 
695 			if (subtype == VSLENGTH) {
696 				for (;*val; val++)
697 					varlen++;
698 			}
699 			else {
700 				while (*val) {
701 					if (quotes &&
702 					    syntax[(int)*val] == CCTL)
703 						STPUTC(CTLESC, expdest);
704 					STPUTC(*val++, expdest);
705 				}
706 
707 			}
708 		}
709 	}
710 
711 	if (subtype == VSPLUS)
712 		set = ! set;
713 
714 	easy = ((varflags & VSQUOTE) == 0 ||
715 		(*var == '@' && shellparam.nparam != 1));
716 
717 
718 	switch (subtype) {
719 	case VSLENGTH:
720 		expdest = cvtnum(varlen, expdest);
721 		goto record;
722 
723 	case VSNORMAL:
724 		if (!easy)
725 			break;
726 record:
727 		recordregion(startloc, expdest - stackblock(),
728 			     varflags & VSQUOTE);
729 		break;
730 
731 	case VSPLUS:
732 	case VSMINUS:
733 		if (!set) {
734 			argstr(p, flag);
735 			break;
736 		}
737 		if (easy)
738 			goto record;
739 		break;
740 
741 	case VSTRIMLEFT:
742 	case VSTRIMLEFTMAX:
743 	case VSTRIMRIGHT:
744 	case VSTRIMRIGHTMAX:
745 		if (!set)
746 			break;
747 		/*
748 		 * Terminate the string and start recording the pattern
749 		 * right after it
750 		 */
751 		STPUTC('\0', expdest);
752 		patloc = expdest - stackblock();
753 		if (subevalvar(p, NULL, patloc, subtype,
754 			       startloc, varflags) == 0) {
755 			int amount = (expdest - stackblock() - patloc) + 1;
756 			STADJUST(-amount, expdest);
757 		}
758 		/* Remove any recorded regions beyond start of variable */
759 		removerecordregions(startloc);
760 		goto record;
761 
762 	case VSASSIGN:
763 	case VSQUESTION:
764 		if (!set) {
765 			if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
766 				varflags &= ~VSNUL;
767 				/*
768 				 * Remove any recorded regions beyond
769 				 * start of variable
770 				 */
771 				removerecordregions(startloc);
772 				goto again;
773 			}
774 			break;
775 		}
776 		if (easy)
777 			goto record;
778 		break;
779 
780 	case VSERROR:
781 		c = p - var - 1;
782 		error("${%.*s%s}: Bad substitution", c, var,
783 		    (c > 0 && *p != CTLENDVAR) ? "..." : "");
784 
785 	default:
786 		abort();
787 	}
788 	p[-1] = '=';	/* recover overwritten '=' */
789 
790 	if (subtype != VSNORMAL) {	/* skip to end of alternative */
791 		int nesting = 1;
792 		for (;;) {
793 			if ((c = *p++) == CTLESC)
794 				p++;
795 			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
796 				if (set)
797 					argbackq = argbackq->next;
798 			} else if (c == CTLVAR) {
799 				if ((*p++ & VSTYPE) != VSNORMAL)
800 					nesting++;
801 			} else if (c == CTLENDVAR) {
802 				if (--nesting == 0)
803 					break;
804 			}
805 		}
806 	}
807 	return p;
808 }
809 
810 
811 
812 /*
813  * Test whether a specialized variable is set.
814  */
815 
816 STATIC int
817 varisset(char *name, int nulok)
818 {
819 
820 	if (*name == '!')
821 		return backgndpid != -1;
822 	else if (*name == '@' || *name == '*') {
823 		if (*shellparam.p == NULL)
824 			return 0;
825 
826 		if (nulok) {
827 			char **av;
828 
829 			for (av = shellparam.p; *av; av++)
830 				if (**av != '\0')
831 					return 1;
832 			return 0;
833 		}
834 	} else if (is_digit(*name)) {
835 		char *ap;
836 		int num = atoi(name);
837 
838 		if (num > shellparam.nparam)
839 			return 0;
840 
841 		if (num == 0)
842 			ap = arg0;
843 		else
844 			ap = shellparam.p[num - 1];
845 
846 		if (nulok && (ap == NULL || *ap == '\0'))
847 			return 0;
848 	}
849 	return 1;
850 }
851 
852 
853 
854 /*
855  * Add the value of a specialized variable to the stack string.
856  */
857 
858 STATIC void
859 varvalue(char *name, int quoted, int subtype, int flag)
860 {
861 	int num;
862 	char *p;
863 	int i;
864 	char sep;
865 	char **ap;
866 	char const *syntax;
867 
868 #define STRTODEST(p) \
869 	do {\
870 	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
871 		syntax = quoted? DQSYNTAX : BASESYNTAX; \
872 		while (*p) { \
873 			if (syntax[(int)*p] == CCTL) \
874 				STPUTC(CTLESC, expdest); \
875 			STPUTC(*p++, expdest); \
876 		} \
877 	} else \
878 		while (*p) \
879 			STPUTC(*p++, expdest); \
880 	} while (0)
881 
882 
883 	switch (*name) {
884 	case '$':
885 		num = rootpid;
886 		goto numvar;
887 	case '?':
888 		num = oexitstatus;
889 		goto numvar;
890 	case '#':
891 		num = shellparam.nparam;
892 		goto numvar;
893 	case '!':
894 		num = backgndpid;
895 numvar:
896 		expdest = cvtnum(num, expdest);
897 		break;
898 	case '-':
899 		for (i = 0 ; i < NOPTS ; i++) {
900 			if (optlist[i].val)
901 				STPUTC(optlist[i].letter, expdest);
902 		}
903 		break;
904 	case '@':
905 		if (flag & EXP_FULL && quoted) {
906 			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
907 				STRTODEST(p);
908 				if (*ap)
909 					STPUTC('\0', expdest);
910 			}
911 			break;
912 		}
913 		/* FALLTHROUGH */
914 	case '*':
915 		if (ifsset())
916 			sep = ifsval()[0];
917 		else
918 			sep = ' ';
919 		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
920 			STRTODEST(p);
921 			if (*ap && sep)
922 				STPUTC(sep, expdest);
923 		}
924 		break;
925 	case '0':
926 		p = arg0;
927 		STRTODEST(p);
928 		break;
929 	default:
930 		if (is_digit(*name)) {
931 			num = atoi(name);
932 			if (num > 0 && num <= shellparam.nparam) {
933 				p = shellparam.p[num - 1];
934 				STRTODEST(p);
935 			}
936 		}
937 		break;
938 	}
939 }
940 
941 
942 
943 /*
944  * Record the the fact that we have to scan this region of the
945  * string for IFS characters.
946  */
947 
948 STATIC void
949 recordregion(int start, int end, int inquotes)
950 {
951 	struct ifsregion *ifsp;
952 
953 	if (ifslastp == NULL) {
954 		ifsp = &ifsfirst;
955 	} else {
956 		if (ifslastp->endoff == start
957 		    && ifslastp->inquotes == inquotes) {
958 			/* extend previous area */
959 			ifslastp->endoff = end;
960 			return;
961 		}
962 		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
963 		ifslastp->next = ifsp;
964 	}
965 	ifslastp = ifsp;
966 	ifslastp->next = NULL;
967 	ifslastp->begoff = start;
968 	ifslastp->endoff = end;
969 	ifslastp->inquotes = inquotes;
970 }
971 
972 
973 
974 /*
975  * Break the argument string into pieces based upon IFS and add the
976  * strings to the argument list.  The regions of the string to be
977  * searched for IFS characters have been stored by recordregion.
978  */
979 STATIC void
980 ifsbreakup(char *string, struct arglist *arglist)
981 {
982 	struct ifsregion *ifsp;
983 	struct strlist *sp;
984 	char *start;
985 	char *p;
986 	char *q;
987 	const char *ifs;
988 	const char *ifsspc;
989 	int had_param_ch = 0;
990 
991 	start = string;
992 
993 	if (ifslastp == NULL) {
994 		/* Return entire argument, IFS doesn't apply to any of it */
995 		sp = (struct strlist *)stalloc(sizeof *sp);
996 		sp->text = start;
997 		*arglist->lastp = sp;
998 		arglist->lastp = &sp->next;
999 		return;
1000 	}
1001 
1002 	ifs = ifsset() ? ifsval() : " \t\n";
1003 
1004 	for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1005 		p = string + ifsp->begoff;
1006 		while (p < string + ifsp->endoff) {
1007 			q = p;
1008 			if (*p == CTLESC)
1009 				p++;
1010 			if (ifsp->inquotes) {
1011 				/* Only NULs (should be from "$@") end args */
1012 				had_param_ch = 1;
1013 				if (*p != 0) {
1014 					p++;
1015 					continue;
1016 				}
1017 				ifsspc = NULL;
1018 			} else {
1019 				if (!strchr(ifs, *p)) {
1020 					had_param_ch = 1;
1021 					p++;
1022 					continue;
1023 				}
1024 				ifsspc = strchr(" \t\n", *p);
1025 
1026 				/* Ignore IFS whitespace at start */
1027 				if (q == start && ifsspc != NULL) {
1028 					p++;
1029 					start = p;
1030 					continue;
1031 				}
1032 				had_param_ch = 0;
1033 			}
1034 
1035 			/* Save this argument... */
1036 			*q = '\0';
1037 			sp = (struct strlist *)stalloc(sizeof *sp);
1038 			sp->text = start;
1039 			*arglist->lastp = sp;
1040 			arglist->lastp = &sp->next;
1041 			p++;
1042 
1043 			if (ifsspc != NULL) {
1044 				/* Ignore further trailing IFS whitespace */
1045 				for (; p < string + ifsp->endoff; p++) {
1046 					q = p;
1047 					if (*p == CTLESC)
1048 						p++;
1049 					if (strchr(ifs, *p) == NULL) {
1050 						p = q;
1051 						break;
1052 					}
1053 					if (strchr(" \t\n", *p) == NULL) {
1054 						p++;
1055 						break;
1056 					}
1057 				}
1058 			}
1059 			start = p;
1060 		}
1061 	}
1062 
1063 	/*
1064 	 * Save anything left as an argument.
1065 	 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1066 	 * generating 2 arguments, the second of which is empty.
1067 	 * Some recent clarification of the Posix spec say that it
1068 	 * should only generate one....
1069 	 */
1070 	if (had_param_ch || *start != 0) {
1071 		sp = (struct strlist *)stalloc(sizeof *sp);
1072 		sp->text = start;
1073 		*arglist->lastp = sp;
1074 		arglist->lastp = &sp->next;
1075 	}
1076 }
1077 
1078 
1079 
1080 /*
1081  * Expand shell metacharacters.  At this point, the only control characters
1082  * should be escapes.  The results are stored in the list exparg.
1083  */
1084 
1085 STATIC char *expdir;
1086 
1087 
1088 STATIC void
1089 expandmeta(struct strlist *str, int flag __unused)
1090 {
1091 	char *p;
1092 	struct strlist **savelastp;
1093 	struct strlist *sp;
1094 	char c;
1095 	/* TODO - EXP_REDIR */
1096 
1097 	while (str) {
1098 		if (fflag)
1099 			goto nometa;
1100 		p = str->text;
1101 		for (;;) {			/* fast check for meta chars */
1102 			if ((c = *p++) == '\0')
1103 				goto nometa;
1104 			if (c == '*' || c == '?' || c == '[' || c == '!')
1105 				break;
1106 		}
1107 		savelastp = exparg.lastp;
1108 		INTOFF;
1109 		if (expdir == NULL) {
1110 			int i = strlen(str->text);
1111 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
1112 		}
1113 
1114 		expmeta(expdir, str->text);
1115 		ckfree(expdir);
1116 		expdir = NULL;
1117 		INTON;
1118 		if (exparg.lastp == savelastp) {
1119 			/*
1120 			 * no matches
1121 			 */
1122 nometa:
1123 			*exparg.lastp = str;
1124 			rmescapes(str->text);
1125 			exparg.lastp = &str->next;
1126 		} else {
1127 			*exparg.lastp = NULL;
1128 			*savelastp = sp = expsort(*savelastp);
1129 			while (sp->next != NULL)
1130 				sp = sp->next;
1131 			exparg.lastp = &sp->next;
1132 		}
1133 		str = str->next;
1134 	}
1135 }
1136 
1137 
1138 /*
1139  * Do metacharacter (i.e. *, ?, [...]) expansion.
1140  */
1141 
1142 STATIC void
1143 expmeta(char *enddir, char *name)
1144 {
1145 	char *p;
1146 	char *q;
1147 	char *start;
1148 	char *endname;
1149 	int metaflag;
1150 	struct stat statb;
1151 	DIR *dirp;
1152 	struct dirent *dp;
1153 	int atend;
1154 	int matchdot;
1155 	int esc;
1156 
1157 	metaflag = 0;
1158 	start = name;
1159 	for (p = name; esc = 0, *p; p += esc + 1) {
1160 		if (*p == '*' || *p == '?')
1161 			metaflag = 1;
1162 		else if (*p == '[') {
1163 			q = p + 1;
1164 			if (*q == '!' || *q == '^')
1165 				q++;
1166 			for (;;) {
1167 				while (*q == CTLQUOTEMARK)
1168 					q++;
1169 				if (*q == CTLESC)
1170 					q++;
1171 				if (*q == '/' || *q == '\0')
1172 					break;
1173 				if (*++q == ']') {
1174 					metaflag = 1;
1175 					break;
1176 				}
1177 			}
1178 		} else if (*p == '!' && p[1] == '!'	&& (p == name || p[-1] == '/')) {
1179 			metaflag = 1;
1180 		} else if (*p == '\0')
1181 			break;
1182 		else if (*p == CTLQUOTEMARK)
1183 			continue;
1184 		else {
1185 			if (*p == CTLESC)
1186 				esc++;
1187 			if (p[esc] == '/') {
1188 				if (metaflag)
1189 					break;
1190 				start = p + esc + 1;
1191 			}
1192 		}
1193 	}
1194 	if (metaflag == 0) {	/* we've reached the end of the file name */
1195 		if (enddir != expdir)
1196 			metaflag++;
1197 		for (p = name ; ; p++) {
1198 			if (*p == CTLQUOTEMARK)
1199 				continue;
1200 			if (*p == CTLESC)
1201 				p++;
1202 			*enddir++ = *p;
1203 			if (*p == '\0')
1204 				break;
1205 		}
1206 		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1207 			addfname(expdir);
1208 		return;
1209 	}
1210 	endname = p;
1211 	if (start != name) {
1212 		p = name;
1213 		while (p < start) {
1214 			while (*p == CTLQUOTEMARK)
1215 				p++;
1216 			if (*p == CTLESC)
1217 				p++;
1218 			*enddir++ = *p++;
1219 		}
1220 	}
1221 	if (enddir == expdir) {
1222 		p = ".";
1223 	} else if (enddir == expdir + 1 && *expdir == '/') {
1224 		p = "/";
1225 	} else {
1226 		p = expdir;
1227 		enddir[-1] = '\0';
1228 	}
1229 	if ((dirp = opendir(p)) == NULL)
1230 		return;
1231 	if (enddir != expdir)
1232 		enddir[-1] = '/';
1233 	if (*endname == 0) {
1234 		atend = 1;
1235 	} else {
1236 		atend = 0;
1237 		*endname = '\0';
1238 		endname += esc + 1;
1239 	}
1240 	matchdot = 0;
1241 	p = start;
1242 	while (*p == CTLQUOTEMARK)
1243 		p++;
1244 	if (*p == CTLESC)
1245 		p++;
1246 	if (*p == '.')
1247 		matchdot++;
1248 	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1249 		if (dp->d_name[0] == '.' && ! matchdot)
1250 			continue;
1251 		if (patmatch(start, dp->d_name, 0)) {
1252 			if (atend) {
1253 				scopy(dp->d_name, enddir);
1254 				addfname(expdir);
1255 			} else {
1256 				for (p = enddir, q = dp->d_name;
1257 				     (*p++ = *q++) != '\0';)
1258 					continue;
1259 				p[-1] = '/';
1260 				expmeta(p, endname);
1261 			}
1262 		}
1263 	}
1264 	closedir(dirp);
1265 	if (! atend)
1266 		endname[-esc - 1] = esc ? CTLESC : '/';
1267 }
1268 
1269 
1270 /*
1271  * Add a file name to the list.
1272  */
1273 
1274 STATIC void
1275 addfname(char *name)
1276 {
1277 	char *p;
1278 	struct strlist *sp;
1279 
1280 	p = stalloc(strlen(name) + 1);
1281 	scopy(name, p);
1282 	sp = (struct strlist *)stalloc(sizeof *sp);
1283 	sp->text = p;
1284 	*exparg.lastp = sp;
1285 	exparg.lastp = &sp->next;
1286 }
1287 
1288 
1289 /*
1290  * Sort the results of file name expansion.  It calculates the number of
1291  * strings to sort and then calls msort (short for merge sort) to do the
1292  * work.
1293  */
1294 
1295 STATIC struct strlist *
1296 expsort(struct strlist *str)
1297 {
1298 	int len;
1299 	struct strlist *sp;
1300 
1301 	len = 0;
1302 	for (sp = str ; sp ; sp = sp->next)
1303 		len++;
1304 	return msort(str, len);
1305 }
1306 
1307 
1308 STATIC struct strlist *
1309 msort(struct strlist *list, int len)
1310 {
1311 	struct strlist *p, *q = NULL;
1312 	struct strlist **lpp;
1313 	int half;
1314 	int n;
1315 
1316 	if (len <= 1)
1317 		return list;
1318 	half = len >> 1;
1319 	p = list;
1320 	for (n = half ; --n >= 0 ; ) {
1321 		q = p;
1322 		p = p->next;
1323 	}
1324 	q->next = NULL;			/* terminate first half of list */
1325 	q = msort(list, half);		/* sort first half of list */
1326 	p = msort(p, len - half);		/* sort second half */
1327 	lpp = &list;
1328 	for (;;) {
1329 		if (strcmp(p->text, q->text) < 0) {
1330 			*lpp = p;
1331 			lpp = &p->next;
1332 			if ((p = *lpp) == NULL) {
1333 				*lpp = q;
1334 				break;
1335 			}
1336 		} else {
1337 			*lpp = q;
1338 			lpp = &q->next;
1339 			if ((q = *lpp) == NULL) {
1340 				*lpp = p;
1341 				break;
1342 			}
1343 		}
1344 	}
1345 	return list;
1346 }
1347 
1348 
1349 
1350 /*
1351  * Returns true if the pattern matches the string.
1352  */
1353 
1354 int
1355 patmatch(const char *pattern, const char *string, int squoted)
1356 {
1357 #ifdef notdef
1358 	if (pattern[0] == '!' && pattern[1] == '!')
1359 		return 1 - pmatch(pattern + 2, string);
1360 	else
1361 #endif
1362 		return pmatch(pattern, string, squoted);
1363 }
1364 
1365 
1366 STATIC int
1367 pmatch(const char *pattern, const char *string, int squoted)
1368 {
1369 	const char *p, *q;
1370 	char c;
1371 
1372 	p = pattern;
1373 	q = string;
1374 	for (;;) {
1375 		switch (c = *p++) {
1376 		case '\0':
1377 			goto breakloop;
1378 		case CTLESC:
1379 			if (squoted && *q == CTLESC)
1380 				q++;
1381 			if (*q++ != *p++)
1382 				return 0;
1383 			break;
1384 		case CTLQUOTEMARK:
1385 			continue;
1386 		case '?':
1387 			if (squoted && *q == CTLESC)
1388 				q++;
1389 			if (*q++ == '\0')
1390 				return 0;
1391 			break;
1392 		case '*':
1393 			c = *p;
1394 			while (c == CTLQUOTEMARK || c == '*')
1395 				c = *++p;
1396 			if (c != CTLESC &&  c != CTLQUOTEMARK &&
1397 			    c != '?' && c != '*' && c != '[') {
1398 				while (*q != c) {
1399 					if (squoted && *q == CTLESC &&
1400 					    q[1] == c)
1401 						break;
1402 					if (*q == '\0')
1403 						return 0;
1404 					if (squoted && *q == CTLESC)
1405 						q++;
1406 					q++;
1407 				}
1408 			}
1409 			do {
1410 				if (pmatch(p, q, squoted))
1411 					return 1;
1412 				if (squoted && *q == CTLESC)
1413 					q++;
1414 			} while (*q++ != '\0');
1415 			return 0;
1416 		case '[': {
1417 			const char *endp;
1418 			int invert, found;
1419 			char chr;
1420 
1421 			endp = p;
1422 			if (*endp == '!' || *endp == '^')
1423 				endp++;
1424 			for (;;) {
1425 				while (*endp == CTLQUOTEMARK)
1426 					endp++;
1427 				if (*endp == '\0')
1428 					goto dft;		/* no matching ] */
1429 				if (*endp == CTLESC)
1430 					endp++;
1431 				if (*++endp == ']')
1432 					break;
1433 			}
1434 			invert = 0;
1435 			if (*p == '!' || *p == '^') {
1436 				invert++;
1437 				p++;
1438 			}
1439 			found = 0;
1440 			chr = *q++;
1441 			if (squoted && chr == CTLESC)
1442 				chr = *q++;
1443 			if (chr == '\0')
1444 				return 0;
1445 			c = *p++;
1446 			do {
1447 				if (c == CTLQUOTEMARK)
1448 					continue;
1449 				if (c == CTLESC)
1450 					c = *p++;
1451 				if (*p == '-' && p[1] != ']') {
1452 					p++;
1453 					while (*p == CTLQUOTEMARK)
1454 						p++;
1455 					if (*p == CTLESC)
1456 						p++;
1457 					if (   collate_range_cmp(chr, c) >= 0
1458 					    && collate_range_cmp(chr, *p) <= 0
1459 					   )
1460 						found = 1;
1461 					p++;
1462 				} else {
1463 					if (chr == c)
1464 						found = 1;
1465 				}
1466 			} while ((c = *p++) != ']');
1467 			if (found == invert)
1468 				return 0;
1469 			break;
1470 		}
1471 dft:	        default:
1472 			if (squoted && *q == CTLESC)
1473 				q++;
1474 			if (*q++ != c)
1475 				return 0;
1476 			break;
1477 		}
1478 	}
1479 breakloop:
1480 	if (*q != '\0')
1481 		return 0;
1482 	return 1;
1483 }
1484 
1485 
1486 
1487 /*
1488  * Remove any CTLESC characters from a string.
1489  */
1490 
1491 void
1492 rmescapes(char *str)
1493 {
1494 	char *p, *q;
1495 
1496 	p = str;
1497 	while (*p != CTLESC && *p != CTLQUOTEMARK) {
1498 		if (*p++ == '\0')
1499 			return;
1500 	}
1501 	q = p;
1502 	while (*p) {
1503 		if (*p == CTLQUOTEMARK) {
1504 			p++;
1505 			continue;
1506 		}
1507 		if (*p == CTLESC)
1508 			p++;
1509 		*q++ = *p++;
1510 	}
1511 	*q = '\0';
1512 }
1513 
1514 
1515 
1516 /*
1517  * See if a pattern matches in a case statement.
1518  */
1519 
1520 int
1521 casematch(union node *pattern, const char *val)
1522 {
1523 	struct stackmark smark;
1524 	int result;
1525 	char *p;
1526 
1527 	setstackmark(&smark);
1528 	argbackq = pattern->narg.backquote;
1529 	STARTSTACKSTR(expdest);
1530 	ifslastp = NULL;
1531 	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1532 	STPUTC('\0', expdest);
1533 	p = grabstackstr(expdest);
1534 	result = patmatch(p, val, 0);
1535 	popstackmark(&smark);
1536 	return result;
1537 }
1538 
1539 /*
1540  * Our own itoa().
1541  */
1542 
1543 STATIC char *
1544 cvtnum(int num, char *buf)
1545 {
1546 	char temp[32];
1547 	int neg = num < 0;
1548 	char *p = temp + 31;
1549 
1550 	temp[31] = '\0';
1551 
1552 	do {
1553 		*--p = num % 10 + '0';
1554 	} while ((num /= 10) != 0);
1555 
1556 	if (neg)
1557 		*--p = '-';
1558 
1559 	while (*p)
1560 		STPUTC(*p++, buf);
1561 	return buf;
1562 }
1563 
1564 /*
1565  * Do most of the work for wordexp(3).
1566  */
1567 
1568 int
1569 wordexpcmd(int argc, char **argv)
1570 {
1571 	size_t len;
1572 	int i;
1573 
1574 	out1fmt("%08x", argc - 1);
1575 	for (i = 1, len = 0; i < argc; i++)
1576 		len += strlen(argv[i]);
1577 	out1fmt("%08x", (int)len);
1578 	for (i = 1; i < argc; i++) {
1579 		out1str(argv[i]);
1580 		out1c('\0');
1581 	}
1582         return (0);
1583 }
1584