Home | History | Annotate | Download | only in src
      1 /*	$OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
      5  *		 2011, 2012, 2013, 2014, 2015, 2016
      6  *	mirabilos <m (at) mirbsd.org>
      7  *
      8  * Provided that these terms and disclaimer and all copyright notices
      9  * are retained or reproduced in an accompanying document, permission
     10  * is granted to deal in this work without restriction, including un-
     11  * limited rights to use, publicly perform, distribute, sell, modify,
     12  * merge, give away, or sublicence.
     13  *
     14  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
     15  * the utmost extent permitted by applicable law, neither express nor
     16  * implied; without malicious intent or gross negligence. In no event
     17  * may a licensor, author or contributor be held liable for indirect,
     18  * direct, other damage, loss, or other issues arising in any way out
     19  * of dealing in the work, even if advised of the possibility of such
     20  * damage or existence of a defect, except proven that it results out
     21  * of said person's immediate fault when using the work as intended.
     22  */
     23 
     24 #include "sh.h"
     25 
     26 __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.194 2016/11/11 23:31:34 tg Exp $");
     27 
     28 /*
     29  * string expansion
     30  *
     31  * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
     32  * second pass: alternation ({,}), filename expansion (*?[]).
     33  */
     34 
     35 /* expansion generator state */
     36 typedef struct {
     37 	/* not including an "int type;" member, see expand() */
     38 	/* string */
     39 	const char *str;
     40 	/* source */
     41 	union {
     42 		/* string[] */
     43 		const char **strv;
     44 		/* file */
     45 		struct shf *shf;
     46 	} u;
     47 	/* variable in ${var...} */
     48 	struct tbl *var;
     49 	/* split "$@" / call waitlast in $() */
     50 	bool split;
     51 } Expand;
     52 
     53 #define	XBASE		0	/* scanning original */
     54 #define	XSUB		1	/* expanding ${} string */
     55 #define	XARGSEP		2	/* ifs0 between "$*" */
     56 #define	XARG		3	/* expanding $*, $@ */
     57 #define	XCOM		4	/* expanding $() */
     58 #define XNULLSUB	5	/* "$@" when $# is 0 (don't generate word) */
     59 #define XSUBMID		6	/* middle of expanding ${} */
     60 
     61 /* States used for field splitting */
     62 #define IFS_WORD	0	/* word has chars (or quotes except "$@") */
     63 #define IFS_WS		1	/* have seen IFS white-space */
     64 #define IFS_NWS		2	/* have seen IFS non-white-space */
     65 #define IFS_IWS		3	/* beginning of word, ignore IFS WS */
     66 #define IFS_QUOTE	4	/* beg.w/quote, become IFS_WORD unless "$@" */
     67 
     68 static int varsub(Expand *, const char *, const char *, int *, int *);
     69 static int comsub(Expand *, const char *, int);
     70 static char *valsub(struct op *, Area *);
     71 static char *trimsub(char *, char *, int);
     72 static void glob(char *, XPtrV *, bool);
     73 static void globit(XString *, char **, char *, XPtrV *, int);
     74 static const char *maybe_expand_tilde(const char *, XString *, char **, bool);
     75 #ifndef MKSH_NOPWNAM
     76 static char *homedir(char *);
     77 #endif
     78 static void alt_expand(XPtrV *, char *, char *, char *, int);
     79 static int utflen(const char *) MKSH_A_PURE;
     80 static void utfincptr(const char *, mksh_ari_t *);
     81 
     82 /* UTFMODE functions */
     83 static int
     84 utflen(const char *s)
     85 {
     86 	size_t n;
     87 
     88 	if (UTFMODE) {
     89 		n = 0;
     90 		while (*s) {
     91 			s += utf_ptradj(s);
     92 			++n;
     93 		}
     94 	} else
     95 		n = strlen(s);
     96 
     97 	if (n > 2147483647)
     98 		n = 2147483647;
     99 	return ((int)n);
    100 }
    101 
    102 static void
    103 utfincptr(const char *s, mksh_ari_t *lp)
    104 {
    105 	const char *cp = s;
    106 
    107 	while ((*lp)--)
    108 		cp += utf_ptradj(cp);
    109 	*lp = cp - s;
    110 }
    111 
    112 /* compile and expand word */
    113 char *
    114 substitute(const char *cp, int f)
    115 {
    116 	struct source *s, *sold;
    117 
    118 	sold = source;
    119 	s = pushs(SWSTR, ATEMP);
    120 	s->start = s->str = cp;
    121 	source = s;
    122 	if (yylex(ONEWORD) != LWORD)
    123 		internal_errorf(Tbadsubst);
    124 	source = sold;
    125 	afree(s, ATEMP);
    126 	return (evalstr(yylval.cp, f));
    127 }
    128 
    129 /*
    130  * expand arg-list
    131  */
    132 char **
    133 eval(const char **ap, int f)
    134 {
    135 	XPtrV w;
    136 
    137 	if (*ap == NULL) {
    138 		union mksh_ccphack vap;
    139 
    140 		vap.ro = ap;
    141 		return (vap.rw);
    142 	}
    143 	XPinit(w, 32);
    144 	/* space for shell name */
    145 	XPput(w, NULL);
    146 	while (*ap != NULL)
    147 		expand(*ap++, &w, f);
    148 	XPput(w, NULL);
    149 	return ((char **)XPclose(w) + 1);
    150 }
    151 
    152 /*
    153  * expand string
    154  */
    155 char *
    156 evalstr(const char *cp, int f)
    157 {
    158 	XPtrV w;
    159 	char *dp = null;
    160 
    161 	XPinit(w, 1);
    162 	expand(cp, &w, f);
    163 	if (XPsize(w))
    164 		dp = *XPptrv(w);
    165 	XPfree(w);
    166 	return (dp);
    167 }
    168 
    169 /*
    170  * expand string - return only one component
    171  * used from iosetup to expand redirection files
    172  */
    173 char *
    174 evalonestr(const char *cp, int f)
    175 {
    176 	XPtrV w;
    177 	char *rv;
    178 
    179 	XPinit(w, 1);
    180 	expand(cp, &w, f);
    181 	switch (XPsize(w)) {
    182 	case 0:
    183 		rv = null;
    184 		break;
    185 	case 1:
    186 		rv = (char *) *XPptrv(w);
    187 		break;
    188 	default:
    189 		rv = evalstr(cp, f & ~DOGLOB);
    190 		break;
    191 	}
    192 	XPfree(w);
    193 	return (rv);
    194 }
    195 
    196 /* for nested substitution: ${var:=$var2} */
    197 typedef struct SubType {
    198 	struct tbl *var;	/* variable for ${var..} */
    199 	struct SubType *prev;	/* old type */
    200 	struct SubType *next;	/* poped type (to avoid re-allocating) */
    201 	size_t	base;		/* start position of expanded word */
    202 	short	stype;		/* [=+-?%#] action after expanded word */
    203 	short	f;		/* saved value of f (DOPAT, etc) */
    204 	uint8_t	quotep;		/* saved value of quote (for ${..[%#]..}) */
    205 	uint8_t	quotew;		/* saved value of quote (for ${..[+-=]..}) */
    206 } SubType;
    207 
    208 void
    209 expand(
    210     /* input word */
    211     const char *ccp,
    212     /* output words */
    213     XPtrV *wp,
    214     /* DO* flags */
    215     int f)
    216 {
    217 	int c = 0;
    218 	/* expansion type */
    219 	int type;
    220 	/* quoted */
    221 	int quote = 0;
    222 	/* destination string and live pointer */
    223 	XString ds;
    224 	char *dp;
    225 	/* source */
    226 	const char *sp;
    227 	/* second pass flags */
    228 	int fdo;
    229 	/* have word */
    230 	int word;
    231 	/* field splitting of parameter/command substitution */
    232 	int doblank;
    233 	/* expansion variables */
    234 	Expand x = {
    235 		NULL, { NULL }, NULL, 0
    236 	};
    237 	SubType st_head, *st;
    238 	/* record number of trailing newlines in COMSUB */
    239 	int newlines = 0;
    240 	bool saw_eq, make_magic;
    241 	unsigned int tilde_ok;
    242 	size_t len;
    243 	char *cp;
    244 
    245 	if (ccp == NULL)
    246 		internal_errorf("expand(NULL)");
    247 	/* for alias, readonly, set, typeset commands */
    248 	if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
    249 		f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE);
    250 		f |= DOASNTILDE | DOSCALAR;
    251 	}
    252 	if (Flag(FNOGLOB))
    253 		f &= ~DOGLOB;
    254 	if (Flag(FMARKDIRS))
    255 		f |= DOMARKDIRS;
    256 	if (Flag(FBRACEEXPAND) && (f & DOGLOB))
    257 		f |= DOBRACE;
    258 
    259 	/* init destination string */
    260 	Xinit(ds, dp, 128, ATEMP);
    261 	type = XBASE;
    262 	sp = ccp;
    263 	fdo = 0;
    264 	saw_eq = false;
    265 	/* must be 1/0 */
    266 	tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
    267 	doblank = 0;
    268 	make_magic = false;
    269 	word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
    270 	/* clang doesn't know OSUBST comes before CSUBST */
    271 	memset(&st_head, 0, sizeof(st_head));
    272 	st = &st_head;
    273 
    274 	while (/* CONSTCOND */ 1) {
    275 		Xcheck(ds, dp);
    276 
    277 		switch (type) {
    278 		case XBASE:
    279 			/* original prefixed string */
    280 			c = *sp++;
    281 			switch (c) {
    282 			case EOS:
    283 				c = 0;
    284 				break;
    285 			case CHAR:
    286 				c = *sp++;
    287 				break;
    288 			case QCHAR:
    289 				/* temporary quote */
    290 				quote |= 2;
    291 				c = *sp++;
    292 				break;
    293 			case OQUOTE:
    294 				if (word != IFS_WORD)
    295 					word = IFS_QUOTE;
    296 				tilde_ok = 0;
    297 				quote = 1;
    298 				continue;
    299 			case CQUOTE:
    300 				if (word == IFS_QUOTE)
    301 					word = IFS_WORD;
    302 				quote = st->quotew;
    303 				continue;
    304 			case COMSUB:
    305 			case FUNSUB:
    306 			case VALSUB:
    307 				tilde_ok = 0;
    308 				if (f & DONTRUNCOMMAND) {
    309 					word = IFS_WORD;
    310 					*dp++ = '$';
    311 					*dp++ = c == COMSUB ? '(' : '{';
    312 					if (c != COMSUB)
    313 						*dp++ = c == FUNSUB ? ' ' : '|';
    314 					while (*sp != '\0') {
    315 						Xcheck(ds, dp);
    316 						*dp++ = *sp++;
    317 					}
    318 					if (c != COMSUB) {
    319 						*dp++ = ';';
    320 						*dp++ = '}';
    321 					} else
    322 						*dp++ = ')';
    323 				} else {
    324 					type = comsub(&x, sp, c);
    325 					if (type != XBASE && (f & DOBLANK))
    326 						doblank++;
    327 					sp = strnul(sp) + 1;
    328 					newlines = 0;
    329 				}
    330 				continue;
    331 			case EXPRSUB:
    332 				tilde_ok = 0;
    333 				if (f & DONTRUNCOMMAND) {
    334 					word = IFS_WORD;
    335 					*dp++ = '$'; *dp++ = '('; *dp++ = '(';
    336 					while (*sp != '\0') {
    337 						Xcheck(ds, dp);
    338 						*dp++ = *sp++;
    339 					}
    340 					*dp++ = ')'; *dp++ = ')';
    341 				} else {
    342 					struct tbl v;
    343 
    344 					v.flag = DEFINED|ISSET|INTEGER;
    345 					/* not default */
    346 					v.type = 10;
    347 					v.name[0] = '\0';
    348 					v_evaluate(&v, substitute(sp, 0),
    349 					    KSH_UNWIND_ERROR, true);
    350 					sp = strnul(sp) + 1;
    351 					x.str = str_val(&v);
    352 					type = XSUB;
    353 					if (f & DOBLANK)
    354 						doblank++;
    355 				}
    356 				continue;
    357 			case OSUBST: {
    358 				/* ${{#}var{:}[=+-?#%]word} */
    359 			/*-
    360 			 * format is:
    361 			 *	OSUBST [{x] plain-variable-part \0
    362 			 *	    compiled-word-part CSUBST [}x]
    363 			 * This is where all syntax checking gets done...
    364 			 */
    365 				/* skip the { or x (}) */
    366 				const char *varname = ++sp;
    367 				int stype;
    368 				int slen = 0;
    369 
    370 				/* skip variable */
    371 				sp = cstrchr(sp, '\0') + 1;
    372 				type = varsub(&x, varname, sp, &stype, &slen);
    373 				if (type < 0) {
    374 					char *beg, *end, *str;
    375  unwind_substsyn:
    376 					/* restore sp */
    377 					sp = varname - 2;
    378 					beg = wdcopy(sp, ATEMP);
    379 					end = (wdscan(cstrchr(sp, '\0') + 1,
    380 					    CSUBST) - sp) + beg;
    381 					/* ({) the } or x is already skipped */
    382 					if (end < wdscan(beg, EOS))
    383 						*end = EOS;
    384 					str = snptreef(NULL, 64, Tf_S, beg);
    385 					afree(beg, ATEMP);
    386 					errorf(Tf_sD_s, str, Tbadsubst);
    387 				}
    388 				if (f & DOBLANK)
    389 					doblank++;
    390 				tilde_ok = 0;
    391 				if (word == IFS_QUOTE && type != XNULLSUB)
    392 					word = IFS_WORD;
    393 				if (type == XBASE) {
    394 					/* expand? */
    395 					if (!st->next) {
    396 						SubType *newst;
    397 
    398 						newst = alloc(sizeof(SubType), ATEMP);
    399 						newst->next = NULL;
    400 						newst->prev = st;
    401 						st->next = newst;
    402 					}
    403 					st = st->next;
    404 					st->stype = stype;
    405 					st->base = Xsavepos(ds, dp);
    406 					st->f = f;
    407 					if (x.var == vtemp) {
    408 						st->var = tempvar(vtemp->name);
    409 						st->var->flag &= ~INTEGER;
    410 						/* can't fail here */
    411 						setstr(st->var,
    412 						    str_val(x.var),
    413 						    KSH_RETURN_ERROR | 0x4);
    414 					} else
    415 						st->var = x.var;
    416 
    417 					st->quotew = st->quotep = quote;
    418 					/* skip qualifier(s) */
    419 					if (stype)
    420 						sp += slen;
    421 					switch (stype & 0x17F) {
    422 					case 0x100 | '#':
    423 						x.str = shf_smprintf("%08X",
    424 						    (unsigned int)hash(str_val(st->var)));
    425 						break;
    426 					case 0x100 | 'Q': {
    427 						struct shf shf;
    428 
    429 						shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
    430 						print_value_quoted(&shf, str_val(st->var));
    431 						x.str = shf_sclose(&shf);
    432 						break;
    433 					    }
    434 					case '0': {
    435 						char *beg, *mid, *end, *stg;
    436 						mksh_ari_t from = 0, num = -1, flen, finc = 0;
    437 
    438 						beg = wdcopy(sp, ATEMP);
    439 						mid = beg + (wdscan(sp, ADELIM) - sp);
    440 						stg = beg + (wdscan(sp, CSUBST) - sp);
    441 						mid[-2] = EOS;
    442 						if (mid[-1] == /*{*/'}') {
    443 							sp += mid - beg - 1;
    444 							end = NULL;
    445 						} else {
    446 							end = mid +
    447 							    (wdscan(mid, ADELIM) - mid);
    448 							if (end[-1] != /*{*/ '}')
    449 								/* more than max delimiters */
    450 								goto unwind_substsyn;
    451 							end[-2] = EOS;
    452 							sp += end - beg - 1;
    453 						}
    454 						evaluate(substitute(stg = wdstrip(beg, 0), 0),
    455 						    &from, KSH_UNWIND_ERROR, true);
    456 						afree(stg, ATEMP);
    457 						if (end) {
    458 							evaluate(substitute(stg = wdstrip(mid, 0), 0),
    459 							    &num, KSH_UNWIND_ERROR, true);
    460 							afree(stg, ATEMP);
    461 						}
    462 						afree(beg, ATEMP);
    463 						beg = str_val(st->var);
    464 						flen = utflen(beg);
    465 						if (from < 0) {
    466 							if (-from < flen)
    467 								finc = flen + from;
    468 						} else
    469 							finc = from < flen ? from : flen;
    470 						if (UTFMODE)
    471 							utfincptr(beg, &finc);
    472 						beg += finc;
    473 						flen = utflen(beg);
    474 						if (num < 0 || num > flen)
    475 							num = flen;
    476 						if (UTFMODE)
    477 							utfincptr(beg, &num);
    478 						strndupx(x.str, beg, num, ATEMP);
    479 						goto do_CSUBST;
    480 					    }
    481 					case 0x100 | '/':
    482 					case '/': {
    483 						char *s, *p, *d, *sbeg, *end;
    484 						char *pat = NULL, *rrep = null;
    485 						char fpat = 0, *tpat1, *tpat2;
    486 						char *ws, *wpat, *wrep;
    487 
    488 						s = ws = wdcopy(sp, ATEMP);
    489 						p = s + (wdscan(sp, ADELIM) - sp);
    490 						d = s + (wdscan(sp, CSUBST) - sp);
    491 						p[-2] = EOS;
    492 						if (p[-1] == /*{*/'}')
    493 							d = NULL;
    494 						else
    495 							d[-2] = EOS;
    496 						sp += (d ? d : p) - s - 1;
    497 						if (!(stype & 0x180) &&
    498 						    s[0] == CHAR &&
    499 						    (s[1] == '#' || s[1] == '%'))
    500 							fpat = s[1];
    501 						wpat = s + (fpat ? 2 : 0);
    502 						wrep = d ? p : NULL;
    503 						if (!(stype & 0x100)) {
    504 							rrep = wrep ? evalstr(wrep,
    505 							    DOTILDE | DOSCALAR) :
    506 							    null;
    507 						}
    508 
    509 						/* prepare string on which to work */
    510 						strdupx(s, str_val(st->var), ATEMP);
    511 						sbeg = s;
    512  again_search:
    513 						pat = evalstr(wpat,
    514 						    DOTILDE | DOSCALAR | DOPAT);
    515 						/* check for special cases */
    516 						if (!*pat && !fpat) {
    517 							/*
    518 							 * empty unanchored
    519 							 * pattern => reject
    520 							 */
    521 							goto no_repl;
    522 						}
    523 						if ((stype & 0x180) &&
    524 						    gmatchx(null, pat, false)) {
    525 							/*
    526 							 * pattern matches empty
    527 							 * string => don't loop
    528 							 */
    529 							stype &= ~0x180;
    530 						}
    531 
    532 						/* first see if we have any match at all */
    533 						if (fpat == '#') {
    534 							/* anchor at the beginning */
    535 							tpat1 = shf_smprintf("%s%c*", pat, MAGIC);
    536 							tpat2 = tpat1;
    537 						} else if (fpat == '%') {
    538 							/* anchor at the end */
    539 							tpat1 = shf_smprintf("%c*%s", MAGIC, pat);
    540 							tpat2 = pat;
    541 						} else {
    542 							/* float */
    543 							tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC);
    544 							tpat2 = tpat1 + 2;
    545 						}
    546  again_repl:
    547 						/*
    548 						 * this would not be necessary if gmatchx would return
    549 						 * the start and end values of a match found, like re*
    550 						 */
    551 						if (!gmatchx(sbeg, tpat1, false))
    552 							goto end_repl;
    553 						end = strnul(s);
    554 						/* now anchor the beginning of the match */
    555 						if (fpat != '#')
    556 							while (sbeg <= end) {
    557 								if (gmatchx(sbeg, tpat2, false))
    558 									break;
    559 								else
    560 									sbeg++;
    561 							}
    562 						/* now anchor the end of the match */
    563 						p = end;
    564 						if (fpat != '%')
    565 							while (p >= sbeg) {
    566 								bool gotmatch;
    567 
    568 								c = *p;
    569 								*p = '\0';
    570 								gotmatch = tobool(gmatchx(sbeg, pat, false));
    571 								*p = c;
    572 								if (gotmatch)
    573 									break;
    574 								p--;
    575 							}
    576 						strndupx(end, sbeg, p - sbeg, ATEMP);
    577 						record_match(end);
    578 						afree(end, ATEMP);
    579 						if (stype & 0x100) {
    580 							if (rrep != null)
    581 								afree(rrep, ATEMP);
    582 							rrep = wrep ? evalstr(wrep,
    583 							    DOTILDE | DOSCALAR) :
    584 							    null;
    585 						}
    586 						strndupx(end, s, sbeg - s, ATEMP);
    587 						d = shf_smprintf(Tf_sss, end, rrep, p);
    588 						afree(end, ATEMP);
    589 						sbeg = d + (sbeg - s) + strlen(rrep);
    590 						afree(s, ATEMP);
    591 						s = d;
    592 						if (stype & 0x100) {
    593 							afree(tpat1, ATEMP);
    594 							afree(pat, ATEMP);
    595 							goto again_search;
    596 						} else if (stype & 0x80)
    597 							goto again_repl;
    598  end_repl:
    599 						afree(tpat1, ATEMP);
    600 						x.str = s;
    601  no_repl:
    602 						afree(pat, ATEMP);
    603 						if (rrep != null)
    604 							afree(rrep, ATEMP);
    605 						afree(ws, ATEMP);
    606 						goto do_CSUBST;
    607 					    }
    608 					case '#':
    609 					case '%':
    610 						/* ! DOBLANK,DOBRACE */
    611 						f = (f & DONTRUNCOMMAND) |
    612 						    DOPAT | DOTILDE |
    613 						    DOTEMP | DOSCALAR;
    614 						tilde_ok = 1;
    615 						st->quotew = quote = 0;
    616 						/*
    617 						 * Prepend open pattern (so |
    618 						 * in a trim will work as
    619 						 * expected)
    620 						 */
    621 						if (!Flag(FSH)) {
    622 							*dp++ = MAGIC;
    623 							*dp++ = 0x80 | '@';
    624 						}
    625 						break;
    626 					case '=':
    627 						/*
    628 						 * Enabling tilde expansion
    629 						 * after :s here is
    630 						 * non-standard ksh, but is
    631 						 * consistent with rules for
    632 						 * other assignments. Not
    633 						 * sure what POSIX thinks of
    634 						 * this.
    635 						 * Not doing tilde expansion
    636 						 * for integer variables is a
    637 						 * non-POSIX thing - makes
    638 						 * sense though, since ~ is
    639 						 * a arithmetic operator.
    640 						 */
    641 						if (!(x.var->flag & INTEGER))
    642 							f |= DOASNTILDE | DOTILDE;
    643 						f |= DOTEMP;
    644 						/*
    645 						 * These will be done after the
    646 						 * value has been assigned.
    647 						 */
    648 						f &= ~(DOBLANK|DOGLOB|DOBRACE);
    649 						tilde_ok = 1;
    650 						break;
    651 					case '?':
    652 						if (*sp == CSUBST)
    653 							errorf("%s: parameter null or not set",
    654 							    st->var->name);
    655 						f &= ~DOBLANK;
    656 						f |= DOTEMP;
    657 						/* FALLTHROUGH */
    658 					default:
    659 						/* '-' '+' '?' */
    660 						if (quote)
    661 							word = IFS_WORD;
    662 						else if (dp == Xstring(ds, dp))
    663 							word = IFS_IWS;
    664 						/* Enable tilde expansion */
    665 						tilde_ok = 1;
    666 						f |= DOTILDE;
    667 					}
    668 				} else
    669 					/* skip word */
    670 					sp += wdscan(sp, CSUBST) - sp;
    671 				continue;
    672 			    }
    673 			case CSUBST:
    674 				/* only get here if expanding word */
    675  do_CSUBST:
    676 				/* ({) skip the } or x */
    677 				sp++;
    678 				/* in case of ${unset:-} */
    679 				tilde_ok = 0;
    680 				*dp = '\0';
    681 				quote = st->quotep;
    682 				f = st->f;
    683 				if (f & DOBLANK)
    684 					doblank--;
    685 				switch (st->stype & 0x17F) {
    686 				case '#':
    687 				case '%':
    688 					if (!Flag(FSH)) {
    689 						/* Append end-pattern */
    690 						*dp++ = MAGIC;
    691 						*dp++ = ')';
    692 					}
    693 					*dp = '\0';
    694 					dp = Xrestpos(ds, dp, st->base);
    695 					/*
    696 					 * Must use st->var since calling
    697 					 * global would break things
    698 					 * like x[i+=1].
    699 					 */
    700 					x.str = trimsub(str_val(st->var),
    701 						dp, st->stype);
    702 					if (x.str[0] != '\0') {
    703 						word = IFS_IWS;
    704 						type = XSUB;
    705 					} else if (quote) {
    706 						word = IFS_WORD;
    707 						type = XSUB;
    708 					} else {
    709 						if (dp == Xstring(ds, dp))
    710 							word = IFS_IWS;
    711 						type = XNULLSUB;
    712 					}
    713 					if (f & DOBLANK)
    714 						doblank++;
    715 					st = st->prev;
    716 					continue;
    717 				case '=':
    718 					/*
    719 					 * Restore our position and substitute
    720 					 * the value of st->var (may not be
    721 					 * the assigned value in the presence
    722 					 * of integer/right-adj/etc attributes).
    723 					 */
    724 					dp = Xrestpos(ds, dp, st->base);
    725 					/*
    726 					 * Must use st->var since calling
    727 					 * global would cause with things
    728 					 * like x[i+=1] to be evaluated twice.
    729 					 */
    730 					/*
    731 					 * Note: not exported by FEXPORT
    732 					 * in AT&T ksh.
    733 					 */
    734 					/*
    735 					 * XXX POSIX says readonly is only
    736 					 * fatal for special builtins (setstr
    737 					 * does readonly check).
    738 					 */
    739 					len = strlen(dp) + 1;
    740 					setstr(st->var,
    741 					    debunk(alloc(len, ATEMP),
    742 					    dp, len), KSH_UNWIND_ERROR);
    743 					x.str = str_val(st->var);
    744 					type = XSUB;
    745 					if (f & DOBLANK)
    746 						doblank++;
    747 					st = st->prev;
    748 					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
    749 					continue;
    750 				case '?':
    751 					dp = Xrestpos(ds, dp, st->base);
    752 
    753 					errorf(Tf_sD_s, st->var->name,
    754 					    debunk(dp, dp, strlen(dp) + 1));
    755 					break;
    756 				case '0':
    757 				case 0x100 | '/':
    758 				case '/':
    759 				case 0x100 | '#':
    760 				case 0x100 | 'Q':
    761 					dp = Xrestpos(ds, dp, st->base);
    762 					type = XSUB;
    763 					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
    764 					if (f & DOBLANK)
    765 						doblank++;
    766 					st = st->prev;
    767 					continue;
    768 				/* default: '-' '+' */
    769 				}
    770 				st = st->prev;
    771 				type = XBASE;
    772 				continue;
    773 
    774 			case OPAT:
    775 				/* open pattern: *(foo|bar) */
    776 				/* Next char is the type of pattern */
    777 				make_magic = true;
    778 				c = *sp++ | 0x80;
    779 				break;
    780 
    781 			case SPAT:
    782 				/* pattern separator (|) */
    783 				make_magic = true;
    784 				c = '|';
    785 				break;
    786 
    787 			case CPAT:
    788 				/* close pattern */
    789 				make_magic = true;
    790 				c = /*(*/ ')';
    791 				break;
    792 			}
    793 			break;
    794 
    795 		case XNULLSUB:
    796 			/*
    797 			 * Special case for "$@" (and "${foo[@]}") - no
    798 			 * word is generated if $# is 0 (unless there is
    799 			 * other stuff inside the quotes).
    800 			 */
    801 			type = XBASE;
    802 			if (f & DOBLANK) {
    803 				doblank--;
    804 				if (dp == Xstring(ds, dp) && word != IFS_WORD)
    805 					word = IFS_IWS;
    806 			}
    807 			continue;
    808 
    809 		case XSUB:
    810 		case XSUBMID:
    811 			if ((c = *x.str++) == 0) {
    812 				type = XBASE;
    813 				if (f & DOBLANK)
    814 					doblank--;
    815 				continue;
    816 			}
    817 			break;
    818 
    819 		case XARGSEP:
    820 			type = XARG;
    821 			quote = 1;
    822 			/* FALLTHROUGH */
    823 		case XARG:
    824 			if ((c = *x.str++) == '\0') {
    825 				/*
    826 				 * force null words to be created so
    827 				 * set -- "" 2 ""; echo "$@" will do
    828 				 * the right thing
    829 				 */
    830 				if (quote && x.split)
    831 					word = IFS_WORD;
    832 				if ((x.str = *x.u.strv++) == NULL) {
    833 					type = XBASE;
    834 					if (f & DOBLANK)
    835 						doblank--;
    836 					continue;
    837 				}
    838 				c = ifs0;
    839 				if ((f & DOHEREDOC)) {
    840 					/* pseudo-field-split reliably */
    841 					if (c == 0)
    842 						c = ' ';
    843 					break;
    844 				}
    845 				if ((f & DOSCALAR)) {
    846 					/* do not field-split */
    847 					if (x.split) {
    848 						c = ' ';
    849 						break;
    850 					}
    851 					if (c == 0)
    852 						continue;
    853 				}
    854 				if (c == 0) {
    855 					if (quote && !x.split)
    856 						continue;
    857 					if (!quote && word == IFS_WS)
    858 						continue;
    859 					/* this is so we don't terminate */
    860 					c = ' ';
    861 					/* now force-emit a word */
    862 					goto emit_word;
    863 				}
    864 				if (quote && x.split) {
    865 					/* terminate word for "$@" */
    866 					type = XARGSEP;
    867 					quote = 0;
    868 				}
    869 			}
    870 			break;
    871 
    872 		case XCOM:
    873 			if (x.u.shf == NULL) {
    874 				/* $(<...) failed */
    875 				subst_exstat = 1;
    876 				/* fake EOF */
    877 				c = -1;
    878 			} else if (newlines) {
    879 				/* spit out saved NLs */
    880 				c = '\n';
    881 				--newlines;
    882 			} else {
    883 				while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
    884 					if (c == '\n')
    885 						/* save newlines */
    886 						newlines++;
    887 				if (newlines && c != -1) {
    888 					shf_ungetc(c, x.u.shf);
    889 					c = '\n';
    890 					--newlines;
    891 				}
    892 			}
    893 			if (c == -1) {
    894 				newlines = 0;
    895 				if (x.u.shf)
    896 					shf_close(x.u.shf);
    897 				if (x.split)
    898 					subst_exstat = waitlast();
    899 				type = XBASE;
    900 				if (f & DOBLANK)
    901 					doblank--;
    902 				continue;
    903 			}
    904 			break;
    905 		}
    906 
    907 		/* check for end of word or IFS separation */
    908 		if (c == 0 || (!quote && (f & DOBLANK) && doblank &&
    909 		    !make_magic && ctype(c, C_IFS))) {
    910 			/*-
    911 			 * How words are broken up:
    912 			 *			|	value of c
    913 			 *	word		|	ws	nws	0
    914 			 *	-----------------------------------
    915 			 *	IFS_WORD		w/WS	w/NWS	w
    916 			 *	IFS_WS			-/WS	-/NWS	-
    917 			 *	IFS_NWS			-/NWS	w/NWS	-
    918 			 *	IFS_IWS			-/WS	w/NWS	-
    919 			 * (w means generate a word)
    920 			 */
    921 			if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
    922 			    (word == IFS_IWS || word == IFS_NWS) &&
    923 			    !ctype(c, C_IFSWS))) {
    924  emit_word:
    925 				if (f & DOHERESTR)
    926 					*dp++ = '\n';
    927 				*dp++ = '\0';
    928 				cp = Xclose(ds, dp);
    929 				if (fdo & DOBRACE)
    930 					/* also does globbing */
    931 					alt_expand(wp, cp, cp,
    932 					    cp + Xlength(ds, (dp - 1)),
    933 					    fdo | (f & DOMARKDIRS));
    934 				else if (fdo & DOGLOB)
    935 					glob(cp, wp, tobool(f & DOMARKDIRS));
    936 				else if ((f & DOPAT) || !(fdo & DOMAGIC))
    937 					XPput(*wp, cp);
    938 				else
    939 					XPput(*wp, debunk(cp, cp,
    940 					    strlen(cp) + 1));
    941 				fdo = 0;
    942 				saw_eq = false;
    943 				/* must be 1/0 */
    944 				tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
    945 				if (c == 0)
    946 					return;
    947 				Xinit(ds, dp, 128, ATEMP);
    948 			} else if (c == 0) {
    949 				return;
    950 			} else if (type == XSUB && ctype(c, C_IFS) &&
    951 			    !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
    952 				*(cp = alloc(1, ATEMP)) = '\0';
    953 				XPput(*wp, cp);
    954 				type = XSUBMID;
    955 			}
    956 			if (word != IFS_NWS)
    957 				word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
    958 		} else {
    959 			if (type == XSUB) {
    960 				if (word == IFS_NWS &&
    961 				    Xlength(ds, dp) == 0) {
    962 					*(cp = alloc(1, ATEMP)) = '\0';
    963 					XPput(*wp, cp);
    964 				}
    965 				type = XSUBMID;
    966 			}
    967 
    968 			/* age tilde_ok info - ~ code tests second bit */
    969 			tilde_ok <<= 1;
    970 			/* mark any special second pass chars */
    971 			if (!quote)
    972 				switch (c) {
    973 				case '[':
    974 				case '!':
    975 				case '-':
    976 				case ']':
    977 					/*
    978 					 * For character classes - doesn't hurt
    979 					 * to have magic !,-,]s outside of
    980 					 * [...] expressions.
    981 					 */
    982 					if (f & (DOPAT | DOGLOB)) {
    983 						fdo |= DOMAGIC;
    984 						if (c == '[')
    985 							fdo |= f & DOGLOB;
    986 						*dp++ = MAGIC;
    987 					}
    988 					break;
    989 				case '*':
    990 				case '?':
    991 					if (f & (DOPAT | DOGLOB)) {
    992 						fdo |= DOMAGIC | (f & DOGLOB);
    993 						*dp++ = MAGIC;
    994 					}
    995 					break;
    996 				case '{':
    997 				case '}':
    998 				case ',':
    999 					if ((f & DOBRACE) && (c == '{' /*}*/ ||
   1000 					    (fdo & DOBRACE))) {
   1001 						fdo |= DOBRACE|DOMAGIC;
   1002 						*dp++ = MAGIC;
   1003 					}
   1004 					break;
   1005 				case '=':
   1006 					/* Note first unquoted = for ~ */
   1007 					if (!(f & DOTEMP) && (!Flag(FPOSIX) ||
   1008 					    (f & DOASNTILDE)) && !saw_eq) {
   1009 						saw_eq = true;
   1010 						tilde_ok = 1;
   1011 					}
   1012 					break;
   1013 				case ':':
   1014 					/* : */
   1015 					/* Note unquoted : for ~ */
   1016 					if (!(f & DOTEMP) && (f & DOASNTILDE))
   1017 						tilde_ok = 1;
   1018 					break;
   1019 				case '~':
   1020 					/*
   1021 					 * tilde_ok is reset whenever
   1022 					 * any of ' " $( $(( ${ } are seen.
   1023 					 * Note that tilde_ok must be preserved
   1024 					 * through the sequence ${A=a=}~
   1025 					 */
   1026 					if (type == XBASE &&
   1027 					    (f & (DOTILDE | DOASNTILDE)) &&
   1028 					    (tilde_ok & 2)) {
   1029 						const char *tcp;
   1030 						char *tdp = dp;
   1031 
   1032 						tcp = maybe_expand_tilde(sp,
   1033 						    &ds, &tdp,
   1034 						    tobool(f & DOASNTILDE));
   1035 						if (tcp) {
   1036 							if (dp != tdp)
   1037 								word = IFS_WORD;
   1038 							dp = tdp;
   1039 							sp = tcp;
   1040 							continue;
   1041 						}
   1042 					}
   1043 					break;
   1044 				}
   1045 			else
   1046 				/* undo temporary */
   1047 				quote &= ~2;
   1048 
   1049 			if (make_magic) {
   1050 				make_magic = false;
   1051 				fdo |= DOMAGIC | (f & DOGLOB);
   1052 				*dp++ = MAGIC;
   1053 			} else if (ISMAGIC(c)) {
   1054 				fdo |= DOMAGIC;
   1055 				*dp++ = MAGIC;
   1056 			}
   1057 			/* save output char */
   1058 			*dp++ = c;
   1059 			word = IFS_WORD;
   1060 		}
   1061 	}
   1062 }
   1063 
   1064 static bool
   1065 hasnonempty(const char **strv)
   1066 {
   1067 	size_t i = 0;
   1068 
   1069 	while (strv[i])
   1070 		if (*strv[i++])
   1071 			return (true);
   1072 	return (false);
   1073 }
   1074 
   1075 /*
   1076  * Prepare to generate the string returned by ${} substitution.
   1077  */
   1078 static int
   1079 varsub(Expand *xp, const char *sp, const char *word,
   1080     int *stypep,	/* becomes qualifier type */
   1081     int *slenp)		/* " " len (=, :=, etc.) valid iff *stypep != 0 */
   1082 {
   1083 	int c;
   1084 	int state;	/* next state: XBASE, XARG, XSUB, XNULLSUB */
   1085 	int stype;	/* substitution type */
   1086 	int slen = 0;
   1087 	const char *p;
   1088 	struct tbl *vp;
   1089 	bool zero_ok = false;
   1090 
   1091 	if ((stype = sp[0]) == '\0')
   1092 		/* Bad variable name */
   1093 		return (-1);
   1094 
   1095 	xp->var = NULL;
   1096 
   1097 	/*-
   1098 	 * ${#var}, string length (-U: characters, +U: octets) or array size
   1099 	 * ${%var}, string width (-U: screen columns, +U: octets)
   1100 	 */
   1101 	c = sp[1];
   1102 	if (stype == '%' && c == '\0')
   1103 		return (-1);
   1104 	if ((stype == '#' || stype == '%') && c != '\0') {
   1105 		/* Can't have any modifiers for ${#...} or ${%...} */
   1106 		if (*word != CSUBST)
   1107 			return (-1);
   1108 		sp++;
   1109 		/* Check for size of array */
   1110 		if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
   1111 		    p[2] == ']') {
   1112 			int n = 0;
   1113 
   1114 			if (stype != '#')
   1115 				return (-1);
   1116 			vp = global(arrayname(sp));
   1117 			if (vp->flag & (ISSET|ARRAY))
   1118 				zero_ok = true;
   1119 			for (; vp; vp = vp->u.array)
   1120 				if (vp->flag & ISSET)
   1121 					n++;
   1122 			c = n;
   1123 		} else if (c == '*' || c == '@') {
   1124 			if (stype != '#')
   1125 				return (-1);
   1126 			c = e->loc->argc;
   1127 		} else {
   1128 			p = str_val(global(sp));
   1129 			zero_ok = p != null;
   1130 			if (stype == '#')
   1131 				c = utflen(p);
   1132 			else {
   1133 				/* partial utf_mbswidth reimplementation */
   1134 				const char *s = p;
   1135 				unsigned int wc;
   1136 				size_t len;
   1137 				int cw;
   1138 
   1139 				c = 0;
   1140 				while (*s) {
   1141 					if (!UTFMODE || (len = utf_mbtowc(&wc,
   1142 					    s)) == (size_t)-1)
   1143 						/* not UTFMODE or not UTF-8 */
   1144 						wc = (unsigned char)(*s++);
   1145 					else
   1146 						/* UTFMODE and UTF-8 */
   1147 						s += len;
   1148 					/* wc == char or wchar at s++ */
   1149 					if ((cw = utf_wcwidth(wc)) == -1) {
   1150 						/* 646, 8859-1, 10646 C0/C1 */
   1151 						c = -1;
   1152 						break;
   1153 					}
   1154 					c += cw;
   1155 				}
   1156 			}
   1157 		}
   1158 		if (Flag(FNOUNSET) && c == 0 && !zero_ok)
   1159 			errorf(Tf_parm, sp);
   1160 		/* unqualified variable/string substitution */
   1161 		*stypep = 0;
   1162 		xp->str = shf_smprintf(Tf_d, c);
   1163 		return (XSUB);
   1164 	}
   1165 	if (stype == '!' && c != '\0' && *word == CSUBST) {
   1166 		sp++;
   1167 		if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
   1168 		    p[2] == ']') {
   1169 			c = '!';
   1170 			stype = 0;
   1171 			goto arraynames;
   1172 		}
   1173 		xp->var = global(sp);
   1174 		xp->str = p ? shf_smprintf("%s[%lu]",
   1175 		    xp->var->name, arrayindex(xp->var)) : xp->var->name;
   1176 		*stypep = 0;
   1177 		return (XSUB);
   1178 	}
   1179 
   1180 	/* Check for qualifiers in word part */
   1181 	stype = 0;
   1182 	c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
   1183 	if (c == ':') {
   1184 		slen += 2;
   1185 		stype = 0x80;
   1186 		c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
   1187 	}
   1188 	if (!stype && c == '/') {
   1189 		slen += 2;
   1190 		stype = c;
   1191 		if (word[slen] == ADELIM && word[slen + 1] == c) {
   1192 			slen += 2;
   1193 			stype |= 0x80;
   1194 		}
   1195 	} else if (stype == 0x80 && (c == ' ' || c == '0')) {
   1196 		stype |= '0';
   1197 	} else if (ctype(c, C_SUBOP1)) {
   1198 		slen += 2;
   1199 		stype |= c;
   1200 	} else if (ctype(c, C_SUBOP2)) {
   1201 		/* Note: ksh88 allows :%, :%%, etc */
   1202 		slen += 2;
   1203 		stype = c;
   1204 		if (word[slen + 0] == CHAR && c == word[slen + 1]) {
   1205 			stype |= 0x80;
   1206 			slen += 2;
   1207 		}
   1208 	} else if (c == '@') {
   1209 		/* @x where x is command char */
   1210 		slen += 2;
   1211 		stype |= 0x100;
   1212 		if (word[slen] == CHAR) {
   1213 			stype |= word[slen + 1];
   1214 			slen += 2;
   1215 		}
   1216 	} else if (stype)
   1217 		/* : is not ok */
   1218 		return (-1);
   1219 	if (!stype && *word != CSUBST)
   1220 		return (-1);
   1221 
   1222 	c = sp[0];
   1223 	if (c == '*' || c == '@') {
   1224 		switch (stype & 0x17F) {
   1225 		/* can't assign to a vector */
   1226 		case '=':
   1227 		/* can't trim a vector (yet) */
   1228 		case '%':
   1229 		case '#':
   1230 		case '?':
   1231 		case '0':
   1232 		case 0x100 | '/':
   1233 		case '/':
   1234 		case 0x100 | '#':
   1235 		case 0x100 | 'Q':
   1236 			return (-1);
   1237 		}
   1238 		if (e->loc->argc == 0) {
   1239 			xp->str = null;
   1240 			xp->var = global(sp);
   1241 			state = c == '@' ? XNULLSUB : XSUB;
   1242 		} else {
   1243 			xp->u.strv = (const char **)e->loc->argv + 1;
   1244 			xp->str = *xp->u.strv++;
   1245 			/* $@ */
   1246 			xp->split = tobool(c == '@');
   1247 			state = XARG;
   1248 		}
   1249 		/* POSIX 2009? */
   1250 		zero_ok = true;
   1251 	} else if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
   1252 	    p[2] == ']') {
   1253 		XPtrV wv;
   1254 
   1255 		switch (stype & 0x17F) {
   1256 		/* can't assign to a vector */
   1257 		case '=':
   1258 		/* can't trim a vector (yet) */
   1259 		case '%':
   1260 		case '#':
   1261 		case '?':
   1262 		case '0':
   1263 		case 0x100 | '/':
   1264 		case '/':
   1265 		case 0x100 | '#':
   1266 		case 0x100 | 'Q':
   1267 			return (-1);
   1268 		}
   1269 		c = 0;
   1270  arraynames:
   1271 		XPinit(wv, 32);
   1272 		vp = global(arrayname(sp));
   1273 		for (; vp; vp = vp->u.array) {
   1274 			if (!(vp->flag&ISSET))
   1275 				continue;
   1276 			XPput(wv, c == '!' ? shf_smprintf(Tf_lu,
   1277 			    arrayindex(vp)) :
   1278 			    str_val(vp));
   1279 		}
   1280 		if (XPsize(wv) == 0) {
   1281 			xp->str = null;
   1282 			state = p[1] == '@' ? XNULLSUB : XSUB;
   1283 			XPfree(wv);
   1284 		} else {
   1285 			XPput(wv, 0);
   1286 			xp->u.strv = (const char **)XPptrv(wv);
   1287 			xp->str = *xp->u.strv++;
   1288 			/* ${foo[@]} */
   1289 			xp->split = tobool(p[1] == '@');
   1290 			state = XARG;
   1291 		}
   1292 	} else {
   1293 		xp->var = global(sp);
   1294 		xp->str = str_val(xp->var);
   1295 		/* can't assign things like $! or $1 */
   1296 		if ((stype & 0x17F) == '=' && !*xp->str &&
   1297 		    ctype(*sp, C_VAR1 | C_DIGIT))
   1298 			return (-1);
   1299 		state = XSUB;
   1300 	}
   1301 
   1302 	c = stype & 0x7F;
   1303 	/* test the compiler's code generator */
   1304 	if (((stype < 0x100) && (ctype(c, C_SUBOP2) ||
   1305 	    (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
   1306 	    (state != XARG || (ifs0 || xp->split ?
   1307 	    (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
   1308 	    c == '=' || c == '-' || c == '?' : c == '+'))) ||
   1309 	    stype == (0x80 | '0') || stype == (0x100 | '#') ||
   1310 	    stype == (0x100 | 'Q') || (stype & 0x7F) == '/')
   1311 		/* expand word instead of variable value */
   1312 		state = XBASE;
   1313 	if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
   1314 	    (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
   1315 		errorf(Tf_parm, sp);
   1316 	*stypep = stype;
   1317 	*slenp = slen;
   1318 	return (state);
   1319 }
   1320 
   1321 /*
   1322  * Run the command in $(...) and read its output.
   1323  */
   1324 static int
   1325 comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
   1326 {
   1327 	Source *s, *sold;
   1328 	struct op *t;
   1329 	struct shf *shf;
   1330 	uint8_t old_utfmode = UTFMODE;
   1331 
   1332 	s = pushs(SSTRING, ATEMP);
   1333 	s->start = s->str = cp;
   1334 	sold = source;
   1335 	t = compile(s, true);
   1336 	afree(s, ATEMP);
   1337 	source = sold;
   1338 
   1339 	UTFMODE = old_utfmode;
   1340 
   1341 	if (t == NULL)
   1342 		return (XBASE);
   1343 
   1344 	/* no waitlast() unless specifically enabled later */
   1345 	xp->split = false;
   1346 
   1347 	if (t->type == TCOM &&
   1348 	    *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
   1349 		/* $(<file) */
   1350 		struct ioword *io = *t->ioact;
   1351 		char *name;
   1352 
   1353 		switch (io->ioflag & IOTYPE) {
   1354 		case IOREAD:
   1355 			shf = shf_open(name = evalstr(io->ioname, DOTILDE),
   1356 				O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
   1357 			if (shf == NULL)
   1358 				warningf(!Flag(FTALKING), Tf_sD_s_sD_s,
   1359 				    name, Tcant_open, "$(<...) input",
   1360 				    cstrerror(errno));
   1361 			break;
   1362 		case IOHERE:
   1363 			if (!herein(io, &name)) {
   1364 				xp->str = name;
   1365 				/* as $() requires, trim trailing newlines */
   1366 				name += strlen(name);
   1367 				while (name > xp->str && name[-1] == '\n')
   1368 					--name;
   1369 				*name = '\0';
   1370 				return (XSUB);
   1371 			}
   1372 			shf = NULL;
   1373 			break;
   1374 		default:
   1375 			errorf(Tf_sD_s, T_funny_command,
   1376 			    snptreef(NULL, 32, Tft_R, io));
   1377 		}
   1378 	} else if (fn == FUNSUB) {
   1379 		int ofd1;
   1380 		struct temp *tf = NULL;
   1381 
   1382 		/*
   1383 		 * create a temporary file, open for reading and writing,
   1384 		 * with an shf open for reading (buffered) but yet unused
   1385 		 */
   1386 		maketemp(ATEMP, TT_FUNSUB, &tf);
   1387 		if (!tf->shf) {
   1388 			errorf(Tf_temp,
   1389 			    Tcreate, tf->tffn, cstrerror(errno));
   1390 		}
   1391 		/* extract shf from temporary file, unlink and free it */
   1392 		shf = tf->shf;
   1393 		unlink(tf->tffn);
   1394 		afree(tf, ATEMP);
   1395 		/* save stdout and let it point to the tempfile */
   1396 		ofd1 = savefd(1);
   1397 		ksh_dup2(shf_fileno(shf), 1, false);
   1398 		/*
   1399 		 * run tree, with output thrown into the tempfile,
   1400 		 * in a new function block
   1401 		 */
   1402 		valsub(t, NULL);
   1403 		subst_exstat = exstat & 0xFF;
   1404 		/* rewind the tempfile and restore regular stdout */
   1405 		lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
   1406 		restfd(1, ofd1);
   1407 	} else if (fn == VALSUB) {
   1408 		xp->str = valsub(t, ATEMP);
   1409 		subst_exstat = exstat & 0xFF;
   1410 		return (XSUB);
   1411 	} else {
   1412 		int ofd1, pv[2];
   1413 
   1414 		openpipe(pv);
   1415 		shf = shf_fdopen(pv[0], SHF_RD, NULL);
   1416 		ofd1 = savefd(1);
   1417 		if (pv[1] != 1) {
   1418 			ksh_dup2(pv[1], 1, false);
   1419 			close(pv[1]);
   1420 		}
   1421 		execute(t, XXCOM | XPIPEO | XFORK, NULL);
   1422 		restfd(1, ofd1);
   1423 		startlast();
   1424 		/* waitlast() */
   1425 		xp->split = true;
   1426 	}
   1427 
   1428 	xp->u.shf = shf;
   1429 	return (XCOM);
   1430 }
   1431 
   1432 /*
   1433  * perform #pattern and %pattern substitution in ${}
   1434  */
   1435 static char *
   1436 trimsub(char *str, char *pat, int how)
   1437 {
   1438 	char *end = strnul(str);
   1439 	char *p, c;
   1440 
   1441 	switch (how & 0xFF) {
   1442 	case '#':
   1443 		/* shortest match at beginning */
   1444 		for (p = str; p <= end; p += utf_ptradj(p)) {
   1445 			c = *p; *p = '\0';
   1446 			if (gmatchx(str, pat, false)) {
   1447 				record_match(str);
   1448 				*p = c;
   1449 				return (p);
   1450 			}
   1451 			*p = c;
   1452 		}
   1453 		break;
   1454 	case '#'|0x80:
   1455 		/* longest match at beginning */
   1456 		for (p = end; p >= str; p--) {
   1457 			c = *p; *p = '\0';
   1458 			if (gmatchx(str, pat, false)) {
   1459 				record_match(str);
   1460 				*p = c;
   1461 				return (p);
   1462 			}
   1463 			*p = c;
   1464 		}
   1465 		break;
   1466 	case '%':
   1467 		/* shortest match at end */
   1468 		p = end;
   1469 		while (p >= str) {
   1470 			if (gmatchx(p, pat, false))
   1471 				goto trimsub_match;
   1472 			if (UTFMODE) {
   1473 				char *op = p;
   1474 				while ((p-- > str) && ((*p & 0xC0) == 0x80))
   1475 					;
   1476 				if ((p < str) || (p + utf_ptradj(p) != op))
   1477 					p = op - 1;
   1478 			} else
   1479 				--p;
   1480 		}
   1481 		break;
   1482 	case '%'|0x80:
   1483 		/* longest match at end */
   1484 		for (p = str; p <= end; p++)
   1485 			if (gmatchx(p, pat, false)) {
   1486  trimsub_match:
   1487 				record_match(p);
   1488 				strndupx(end, str, p - str, ATEMP);
   1489 				return (end);
   1490 			}
   1491 		break;
   1492 	}
   1493 
   1494 	/* no match, return string */
   1495 	return (str);
   1496 }
   1497 
   1498 /*
   1499  * glob
   1500  * Name derived from V6's /etc/glob, the program that expanded filenames.
   1501  */
   1502 
   1503 /* XXX cp not const 'cause slashes are temporarily replaced with NULs... */
   1504 static void
   1505 glob(char *cp, XPtrV *wp, bool markdirs)
   1506 {
   1507 	int oldsize = XPsize(*wp);
   1508 
   1509 	if (glob_str(cp, wp, markdirs) == 0)
   1510 		XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
   1511 	else
   1512 		qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize,
   1513 		    sizeof(void *), xstrcmp);
   1514 }
   1515 
   1516 #define GF_NONE		0
   1517 #define GF_EXCHECK	BIT(0)		/* do existence check on file */
   1518 #define GF_GLOBBED	BIT(1)		/* some globbing has been done */
   1519 #define GF_MARKDIR	BIT(2)		/* add trailing / to directories */
   1520 
   1521 /*
   1522  * Apply file globbing to cp and store the matching files in wp. Returns
   1523  * the number of matches found.
   1524  */
   1525 int
   1526 glob_str(char *cp, XPtrV *wp, bool markdirs)
   1527 {
   1528 	int oldsize = XPsize(*wp);
   1529 	XString xs;
   1530 	char *xp;
   1531 
   1532 	Xinit(xs, xp, 256, ATEMP);
   1533 	globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
   1534 	Xfree(xs, xp);
   1535 
   1536 	return (XPsize(*wp) - oldsize);
   1537 }
   1538 
   1539 static void
   1540 globit(XString *xs,	/* dest string */
   1541     char **xpp,		/* ptr to dest end */
   1542     char *sp,		/* source path */
   1543     XPtrV *wp,		/* output list */
   1544     int check)		/* GF_* flags */
   1545 {
   1546 	char *np;		/* next source component */
   1547 	char *xp = *xpp;
   1548 	char *se;
   1549 	char odirsep;
   1550 
   1551 	/* This to allow long expansions to be interrupted */
   1552 	intrcheck();
   1553 
   1554 	if (sp == NULL) {
   1555 		/* end of source path */
   1556 		/*
   1557 		 * We only need to check if the file exists if a pattern
   1558 		 * is followed by a non-pattern (eg, foo*x/bar; no check
   1559 		 * is needed for foo* since the match must exist) or if
   1560 		 * any patterns were expanded and the markdirs option is set.
   1561 		 * Symlinks make things a bit tricky...
   1562 		 */
   1563 		if ((check & GF_EXCHECK) ||
   1564 		    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
   1565 #define stat_check()	(stat_done ? stat_done : (stat_done = \
   1566 			    stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
   1567 			struct stat lstatb, statb;
   1568 			/* -1: failed, 1 ok, 0 not yet done */
   1569 			int stat_done = 0;
   1570 
   1571 			if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
   1572 				return;
   1573 			/*
   1574 			 * special case for systems which strip trailing
   1575 			 * slashes from regular files (eg, /etc/passwd/).
   1576 			 * SunOS 4.1.3 does this...
   1577 			 */
   1578 			if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) &&
   1579 			    mksh_cdirsep(xp[-1]) && !S_ISDIR(lstatb.st_mode) &&
   1580 			    (!S_ISLNK(lstatb.st_mode) ||
   1581 			    stat_check() < 0 || !S_ISDIR(statb.st_mode)))
   1582 				return;
   1583 			/*
   1584 			 * Possibly tack on a trailing / if there isn't already
   1585 			 * one and if the file is a directory or a symlink to a
   1586 			 * directory
   1587 			 */
   1588 			if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) &&
   1589 			    xp > Xstring(*xs, xp) && !mksh_cdirsep(xp[-1]) &&
   1590 			    (S_ISDIR(lstatb.st_mode) ||
   1591 			    (S_ISLNK(lstatb.st_mode) && stat_check() > 0 &&
   1592 			    S_ISDIR(statb.st_mode)))) {
   1593 				*xp++ = '/';
   1594 				*xp = '\0';
   1595 			}
   1596 		}
   1597 		strndupx(np, Xstring(*xs, xp), Xlength(*xs, xp), ATEMP);
   1598 		XPput(*wp, np);
   1599 		return;
   1600 	}
   1601 
   1602 	if (xp > Xstring(*xs, xp))
   1603 		*xp++ = '/';
   1604 	while (mksh_cdirsep(*sp)) {
   1605 		Xcheck(*xs, xp);
   1606 		*xp++ = *sp++;
   1607 	}
   1608 	np = mksh_sdirsep(sp);
   1609 	if (np != NULL) {
   1610 		se = np;
   1611 		/* don't assume '/', can be multiple kinds */
   1612 		odirsep = *np;
   1613 		*np++ = '\0';
   1614 	} else {
   1615 		odirsep = '\0'; /* keep gcc quiet */
   1616 		se = sp + strlen(sp);
   1617 	}
   1618 
   1619 
   1620 	/*
   1621 	 * Check if sp needs globbing - done to avoid pattern checks for strings
   1622 	 * containing MAGIC characters, open [s without the matching close ],
   1623 	 * etc. (otherwise opendir() will be called which may fail because the
   1624 	 * directory isn't readable - if no globbing is needed, only execute
   1625 	 * permission should be required (as per POSIX)).
   1626 	 */
   1627 	if (!has_globbing(sp, se)) {
   1628 		XcheckN(*xs, xp, se - sp + 1);
   1629 		debunk(xp, sp, Xnleft(*xs, xp));
   1630 		xp += strlen(xp);
   1631 		*xpp = xp;
   1632 		globit(xs, xpp, np, wp, check);
   1633 	} else {
   1634 		DIR *dirp;
   1635 		struct dirent *d;
   1636 		char *name;
   1637 		size_t len, prefix_len;
   1638 
   1639 		/* xp = *xpp;	copy_non_glob() may have re-alloc'd xs */
   1640 		*xp = '\0';
   1641 		prefix_len = Xlength(*xs, xp);
   1642 		dirp = opendir(prefix_len ? Xstring(*xs, xp) : Tdot);
   1643 		if (dirp == NULL)
   1644 			goto Nodir;
   1645 		while ((d = readdir(dirp)) != NULL) {
   1646 			name = d->d_name;
   1647 			if (name[0] == '.' &&
   1648 			    (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
   1649 				/* always ignore . and .. */
   1650 				continue;
   1651 			if ((*name == '.' && *sp != '.') ||
   1652 			    !gmatchx(name, sp, true))
   1653 				continue;
   1654 
   1655 			len = strlen(d->d_name) + 1;
   1656 			XcheckN(*xs, xp, len);
   1657 			memcpy(xp, name, len);
   1658 			*xpp = xp + len - 1;
   1659 			globit(xs, xpp, np, wp,
   1660 				(check & GF_MARKDIR) | GF_GLOBBED
   1661 				| (np ? GF_EXCHECK : GF_NONE));
   1662 			xp = Xstring(*xs, xp) + prefix_len;
   1663 		}
   1664 		closedir(dirp);
   1665  Nodir:
   1666 		;
   1667 	}
   1668 
   1669 	if (np != NULL)
   1670 		*--np = odirsep;
   1671 }
   1672 
   1673 /* remove MAGIC from string */
   1674 char *
   1675 debunk(char *dp, const char *sp, size_t dlen)
   1676 {
   1677 	char *d;
   1678 	const char *s;
   1679 
   1680 	if ((s = cstrchr(sp, MAGIC))) {
   1681 		if (s - sp >= (ssize_t)dlen)
   1682 			return (dp);
   1683 		memmove(dp, sp, s - sp);
   1684 		for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++)
   1685 			if (!ISMAGIC(*s) || !(*++s & 0x80) ||
   1686 			    !vstrchr("*+?@! ", *s & 0x7f))
   1687 				*d++ = *s;
   1688 			else {
   1689 				/* extended pattern operators: *+?@! */
   1690 				if ((*s & 0x7f) != ' ')
   1691 					*d++ = *s & 0x7f;
   1692 				if (d - dp < (ssize_t)dlen)
   1693 					*d++ = '(';
   1694 			}
   1695 		*d = '\0';
   1696 	} else if (dp != sp)
   1697 		strlcpy(dp, sp, dlen);
   1698 	return (dp);
   1699 }
   1700 
   1701 /*
   1702  * Check if p is an unquoted name, possibly followed by a / or :. If so
   1703  * puts the expanded version in *dcp,dp and returns a pointer in p just
   1704  * past the name, otherwise returns 0.
   1705  */
   1706 static const char *
   1707 maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
   1708 {
   1709 	XString ts;
   1710 	char *dp = *dpp;
   1711 	char *tp;
   1712 	const char *r;
   1713 
   1714 	Xinit(ts, tp, 16, ATEMP);
   1715 	/* : only for DOASNTILDE form */
   1716 	while (p[0] == CHAR && !mksh_cdirsep(p[1]) &&
   1717 	    (!isassign || p[1] != ':')) {
   1718 		Xcheck(ts, tp);
   1719 		*tp++ = p[1];
   1720 		p += 2;
   1721 	}
   1722 	*tp = '\0';
   1723 	r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ?
   1724 	    do_tilde(Xstring(ts, tp)) : NULL;
   1725 	Xfree(ts, tp);
   1726 	if (r) {
   1727 		while (*r) {
   1728 			Xcheck(*dsp, dp);
   1729 			if (ISMAGIC(*r))
   1730 				*dp++ = MAGIC;
   1731 			*dp++ = *r++;
   1732 		}
   1733 		*dpp = dp;
   1734 		r = p;
   1735 	}
   1736 	return (r);
   1737 }
   1738 
   1739 /*
   1740  * tilde expansion
   1741  *
   1742  * based on a version by Arnold Robbins
   1743  */
   1744 char *
   1745 do_tilde(char *cp)
   1746 {
   1747 	char *dp = null;
   1748 #ifndef MKSH_NOPWNAM
   1749 	bool do_simplify = true;
   1750 #endif
   1751 
   1752 	if (cp[0] == '\0')
   1753 		dp = str_val(global("HOME"));
   1754 	else if (cp[0] == '+' && cp[1] == '\0')
   1755 		dp = str_val(global(TPWD));
   1756 	else if (ksh_isdash(cp))
   1757 		dp = str_val(global(TOLDPWD));
   1758 #ifndef MKSH_NOPWNAM
   1759 	else {
   1760 		dp = homedir(cp);
   1761 		do_simplify = false;
   1762 	}
   1763 #endif
   1764 
   1765 	/* if parameters aren't set, don't expand ~ */
   1766 	if (dp == NULL || dp == null)
   1767 		return (NULL);
   1768 
   1769 	/* simplify parameters as if cwd upon entry */
   1770 #ifndef MKSH_NOPWNAM
   1771 	if (do_simplify)
   1772 #endif
   1773 	  {
   1774 		strdupx(dp, dp, ATEMP);
   1775 		simplify_path(dp);
   1776 	}
   1777 	return (dp);
   1778 }
   1779 
   1780 #ifndef MKSH_NOPWNAM
   1781 /*
   1782  * map userid to user's home directory.
   1783  * note that 4.3's getpw adds more than 6K to the shell,
   1784  * and the YP version probably adds much more.
   1785  * we might consider our own version of getpwnam() to keep the size down.
   1786  */
   1787 static char *
   1788 homedir(char *name)
   1789 {
   1790 	struct tbl *ap;
   1791 
   1792 	ap = ktenter(&homedirs, name, hash(name));
   1793 	if (!(ap->flag & ISSET)) {
   1794 		struct passwd *pw;
   1795 
   1796 		pw = getpwnam(name);
   1797 		if (pw == NULL)
   1798 			return (NULL);
   1799 		strdupx(ap->val.s, pw->pw_dir, APERM);
   1800 		ap->flag |= DEFINED|ISSET|ALLOC;
   1801 	}
   1802 	return (ap->val.s);
   1803 }
   1804 #endif
   1805 
   1806 static void
   1807 alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
   1808 {
   1809 	unsigned int count = 0;
   1810 	char *brace_start, *brace_end, *comma = NULL;
   1811 	char *field_start;
   1812 	char *p = exp_start;
   1813 
   1814 	/* search for open brace */
   1815 	while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/)
   1816 		p += 2;
   1817 	brace_start = p;
   1818 
   1819 	/* find matching close brace, if any */
   1820 	if (p) {
   1821 		comma = NULL;
   1822 		count = 1;
   1823 		p += 2;
   1824 		while (*p && count) {
   1825 			if (ISMAGIC(*p++)) {
   1826 				if (*p == '{' /*}*/)
   1827 					++count;
   1828 				else if (*p == /*{*/ '}')
   1829 					--count;
   1830 				else if (*p == ',' && count == 1)
   1831 					comma = p;
   1832 				++p;
   1833 			}
   1834 		}
   1835 	}
   1836 	/* no valid expansions... */
   1837 	if (!p || count != 0) {
   1838 		/*
   1839 		 * Note that given a{{b,c} we do not expand anything (this is
   1840 		 * what AT&T ksh does. This may be changed to do the {b,c}
   1841 		 * expansion. }
   1842 		 */
   1843 		if (fdo & DOGLOB)
   1844 			glob(start, wp, tobool(fdo & DOMARKDIRS));
   1845 		else
   1846 			XPput(*wp, debunk(start, start, end - start));
   1847 		return;
   1848 	}
   1849 	brace_end = p;
   1850 	if (!comma) {
   1851 		alt_expand(wp, start, brace_end, end, fdo);
   1852 		return;
   1853 	}
   1854 
   1855 	/* expand expression */
   1856 	field_start = brace_start + 2;
   1857 	count = 1;
   1858 	for (p = brace_start + 2; p != brace_end; p++) {
   1859 		if (ISMAGIC(*p)) {
   1860 			if (*++p == '{' /*}*/)
   1861 				++count;
   1862 			else if ((*p == /*{*/ '}' && --count == 0) ||
   1863 			    (*p == ',' && count == 1)) {
   1864 				char *news;
   1865 				int l1, l2, l3;
   1866 
   1867 				/*
   1868 				 * addition safe since these operate on
   1869 				 * one string (separate substrings)
   1870 				 */
   1871 				l1 = brace_start - start;
   1872 				l2 = (p - 1) - field_start;
   1873 				l3 = end - brace_end;
   1874 				news = alloc(l1 + l2 + l3 + 1, ATEMP);
   1875 				memcpy(news, start, l1);
   1876 				memcpy(news + l1, field_start, l2);
   1877 				memcpy(news + l1 + l2, brace_end, l3);
   1878 				news[l1 + l2 + l3] = '\0';
   1879 				alt_expand(wp, news, news + l1,
   1880 				    news + l1 + l2 + l3, fdo);
   1881 				field_start = p + 1;
   1882 			}
   1883 		}
   1884 	}
   1885 	return;
   1886 }
   1887 
   1888 /* helper function due to setjmp/longjmp woes */
   1889 static char *
   1890 valsub(struct op *t, Area *ap)
   1891 {
   1892 	char * volatile cp = NULL;
   1893 	struct tbl * volatile vp = NULL;
   1894 
   1895 	newenv(E_FUNC);
   1896 	newblock();
   1897 	if (ap)
   1898 		vp = local("REPLY", false);
   1899 	if (!kshsetjmp(e->jbuf))
   1900 		execute(t, XXCOM | XERROK, NULL);
   1901 	if (vp)
   1902 		strdupx(cp, str_val(vp), ap);
   1903 	quitenv(NULL);
   1904 
   1905 	return (cp);
   1906 }
   1907