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.180 2016/01/19 23:12:12 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	/* begin 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("bad substitution");
    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;		/* begin 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 					end = (beg = wdcopy(sp, ATEMP)) +
    379 					    (wdscan(sp, CSUBST) - sp);
    380 					/* ({) the } or x is already skipped */
    381 					if (end < wdscan(beg, EOS))
    382 						*end = EOS;
    383 					str = snptreef(NULL, 64, "%S", beg);
    384 					afree(beg, ATEMP);
    385 					errorf("%s: %s", str, "bad substitution");
    386 				}
    387 				if (f & DOBLANK)
    388 					doblank++;
    389 				tilde_ok = 0;
    390 				if (word == IFS_QUOTE && type != XNULLSUB)
    391 					word = IFS_WORD;
    392 				if (type == XBASE) {
    393 					/* expand? */
    394 					if (!st->next) {
    395 						SubType *newst;
    396 
    397 						newst = alloc(sizeof(SubType), ATEMP);
    398 						newst->next = NULL;
    399 						newst->prev = st;
    400 						st->next = newst;
    401 					}
    402 					st = st->next;
    403 					st->stype = stype;
    404 					st->base = Xsavepos(ds, dp);
    405 					st->f = f;
    406 					if (x.var == &vtemp) {
    407 						st->var = tempvar();
    408 						st->var->flag &= ~INTEGER;
    409 						/* can't fail here */
    410 						setstr(st->var,
    411 						    str_val(x.var),
    412 						    KSH_RETURN_ERROR | 0x4);
    413 					} else
    414 						st->var = x.var;
    415 
    416 					st->quotew = st->quotep = quote;
    417 					/* skip qualifier(s) */
    418 					if (stype)
    419 						sp += slen;
    420 					switch (stype & 0x17F) {
    421 					case 0x100 | '#':
    422 						x.str = shf_smprintf("%08X",
    423 						    (unsigned int)hash(str_val(st->var)));
    424 						break;
    425 					case 0x100 | 'Q': {
    426 						struct shf shf;
    427 
    428 						shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
    429 						print_value_quoted(&shf, str_val(st->var));
    430 						x.str = shf_sclose(&shf);
    431 						break;
    432 					    }
    433 					case '0': {
    434 						char *beg, *mid, *end, *stg;
    435 						mksh_ari_t from = 0, num = -1, flen, finc = 0;
    436 
    437 						beg = wdcopy(sp, ATEMP);
    438 						mid = beg + (wdscan(sp, ADELIM) - sp);
    439 						stg = beg + (wdscan(sp, CSUBST) - sp);
    440 						mid[-2] = EOS;
    441 						if (mid[-1] == /*{*/'}') {
    442 							sp += mid - beg - 1;
    443 							end = NULL;
    444 						} else {
    445 							end = mid +
    446 							    (wdscan(mid, ADELIM) - mid);
    447 							if (end[-1] != /*{*/ '}')
    448 								/* more than max delimiters */
    449 								goto unwind_substsyn;
    450 							end[-2] = EOS;
    451 							sp += end - beg - 1;
    452 						}
    453 						evaluate(substitute(stg = wdstrip(beg, 0), 0),
    454 						    &from, KSH_UNWIND_ERROR, true);
    455 						afree(stg, ATEMP);
    456 						if (end) {
    457 							evaluate(substitute(stg = wdstrip(mid, 0), 0),
    458 							    &num, KSH_UNWIND_ERROR, true);
    459 							afree(stg, ATEMP);
    460 						}
    461 						afree(beg, ATEMP);
    462 						beg = str_val(st->var);
    463 						flen = utflen(beg);
    464 						if (from < 0) {
    465 							if (-from < flen)
    466 								finc = flen + from;
    467 						} else
    468 							finc = from < flen ? from : flen;
    469 						if (UTFMODE)
    470 							utfincptr(beg, &finc);
    471 						beg += finc;
    472 						flen = utflen(beg);
    473 						if (num < 0 || num > flen)
    474 							num = flen;
    475 						if (UTFMODE)
    476 							utfincptr(beg, &num);
    477 						strndupx(x.str, beg, num, ATEMP);
    478 						goto do_CSUBST;
    479 					    }
    480 					case '/': {
    481 						char *s, *p, *d, *sbeg, *end;
    482 						char *pat, *rrep;
    483 						char fpat = 0, *tpat1, *tpat2;
    484 
    485 						s = wdcopy(sp, ATEMP);
    486 						p = s + (wdscan(sp, ADELIM) - sp);
    487 						d = s + (wdscan(sp, CSUBST) - sp);
    488 						p[-2] = EOS;
    489 						if (p[-1] == /*{*/'}')
    490 							d = NULL;
    491 						else
    492 							d[-2] = EOS;
    493 						sp += (d ? d : p) - s - 1;
    494 						if (!(stype & 0x80) &&
    495 						    s[0] == CHAR &&
    496 						    (s[1] == '#' || s[1] == '%'))
    497 							fpat = s[1];
    498 						pat = evalstr(s + (fpat ? 2 : 0),
    499 						    DOTILDE | DOSCALAR | DOPAT);
    500 						rrep = d ? evalstr(p,
    501 						    DOTILDE | DOSCALAR) : null;
    502 						afree(s, ATEMP);
    503 
    504 						/* check for special cases */
    505 						if (!*pat && !fpat) {
    506 							/*
    507 							 * empty unanchored
    508 							 * pattern => reject
    509 							 */
    510 							goto no_repl;
    511 						}
    512 						if ((stype & 0x80) &&
    513 						    gmatchx(null, pat, false)) {
    514 							/*
    515 							 * pattern matches empty
    516 							 * string => don't loop
    517 							 */
    518 							stype &= ~0x80;
    519 						}
    520 
    521 						/* prepare string on which to work */
    522 						strdupx(s, str_val(st->var), ATEMP);
    523 						sbeg = s;
    524 
    525 						/* first see if we have any match at all */
    526 						if (fpat == '#') {
    527 							/* anchor at the beginning */
    528 							tpat1 = shf_smprintf("%s%c*", pat, MAGIC);
    529 							tpat2 = tpat1;
    530 						} else if (fpat == '%') {
    531 							/* anchor at the end */
    532 							tpat1 = shf_smprintf("%c*%s", MAGIC, pat);
    533 							tpat2 = pat;
    534 						} else {
    535 							/* float */
    536 							tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC);
    537 							tpat2 = tpat1 + 2;
    538 						}
    539  again_repl:
    540 						/*
    541 						 * this would not be necessary if gmatchx would return
    542 						 * the start and end values of a match found, like re*
    543 						 */
    544 						if (!gmatchx(sbeg, tpat1, false))
    545 							goto end_repl;
    546 						end = strnul(s);
    547 						/* now anchor the beginning of the match */
    548 						if (fpat != '#')
    549 							while (sbeg <= end) {
    550 								if (gmatchx(sbeg, tpat2, false))
    551 									break;
    552 								else
    553 									sbeg++;
    554 							}
    555 						/* now anchor the end of the match */
    556 						p = end;
    557 						if (fpat != '%')
    558 							while (p >= sbeg) {
    559 								bool gotmatch;
    560 
    561 								c = *p;
    562 								*p = '\0';
    563 								gotmatch = tobool(gmatchx(sbeg, pat, false));
    564 								*p = c;
    565 								if (gotmatch)
    566 									break;
    567 								p--;
    568 							}
    569 						strndupx(end, s, sbeg - s, ATEMP);
    570 						d = shf_smprintf("%s%s%s", end, rrep, p);
    571 						afree(end, ATEMP);
    572 						sbeg = d + (sbeg - s) + strlen(rrep);
    573 						afree(s, ATEMP);
    574 						s = d;
    575 						if (stype & 0x80)
    576 							goto again_repl;
    577  end_repl:
    578 						afree(tpat1, ATEMP);
    579 						x.str = s;
    580  no_repl:
    581 						afree(pat, ATEMP);
    582 						if (rrep != null)
    583 							afree(rrep, ATEMP);
    584 						goto do_CSUBST;
    585 					    }
    586 					case '#':
    587 					case '%':
    588 						/* ! DOBLANK,DOBRACE */
    589 						f = (f & DONTRUNCOMMAND) |
    590 						    DOPAT | DOTILDE |
    591 						    DOTEMP | DOSCALAR;
    592 						tilde_ok = 1;
    593 						st->quotew = quote = 0;
    594 						/*
    595 						 * Prepend open pattern (so |
    596 						 * in a trim will work as
    597 						 * expected)
    598 						 */
    599 						if (!Flag(FSH)) {
    600 							*dp++ = MAGIC;
    601 							*dp++ = 0x80 | '@';
    602 						}
    603 						break;
    604 					case '=':
    605 						/*
    606 						 * Enabling tilde expansion
    607 						 * after :s here is
    608 						 * non-standard ksh, but is
    609 						 * consistent with rules for
    610 						 * other assignments. Not
    611 						 * sure what POSIX thinks of
    612 						 * this.
    613 						 * Not doing tilde expansion
    614 						 * for integer variables is a
    615 						 * non-POSIX thing - makes
    616 						 * sense though, since ~ is
    617 						 * a arithmetic operator.
    618 						 */
    619 						if (!(x.var->flag & INTEGER))
    620 							f |= DOASNTILDE | DOTILDE;
    621 						f |= DOTEMP;
    622 						/*
    623 						 * These will be done after the
    624 						 * value has been assigned.
    625 						 */
    626 						f &= ~(DOBLANK|DOGLOB|DOBRACE);
    627 						tilde_ok = 1;
    628 						break;
    629 					case '?':
    630 						if (*sp == CSUBST)
    631 							errorf("%s: parameter null or not set",
    632 							    st->var->name);
    633 						f &= ~DOBLANK;
    634 						f |= DOTEMP;
    635 						/* FALLTHROUGH */
    636 					default:
    637 						/* '-' '+' '?' */
    638 						if (quote)
    639 							word = IFS_WORD;
    640 						else if (dp == Xstring(ds, dp))
    641 							word = IFS_IWS;
    642 						/* Enable tilde expansion */
    643 						tilde_ok = 1;
    644 						f |= DOTILDE;
    645 					}
    646 				} else
    647 					/* skip word */
    648 					sp += wdscan(sp, CSUBST) - sp;
    649 				continue;
    650 			    }
    651 			case CSUBST:
    652 				/* only get here if expanding word */
    653  do_CSUBST:
    654 				/* ({) skip the } or x */
    655 				sp++;
    656 				/* in case of ${unset:-} */
    657 				tilde_ok = 0;
    658 				*dp = '\0';
    659 				quote = st->quotep;
    660 				f = st->f;
    661 				if (f & DOBLANK)
    662 					doblank--;
    663 				switch (st->stype & 0x17F) {
    664 				case '#':
    665 				case '%':
    666 					if (!Flag(FSH)) {
    667 						/* Append end-pattern */
    668 						*dp++ = MAGIC;
    669 						*dp++ = ')';
    670 					}
    671 					*dp = '\0';
    672 					dp = Xrestpos(ds, dp, st->base);
    673 					/*
    674 					 * Must use st->var since calling
    675 					 * global would break things
    676 					 * like x[i+=1].
    677 					 */
    678 					x.str = trimsub(str_val(st->var),
    679 						dp, st->stype);
    680 					if (x.str[0] != '\0') {
    681 						word = IFS_IWS;
    682 						type = XSUB;
    683 					} else if (quote) {
    684 						word = IFS_WORD;
    685 						type = XSUB;
    686 					} else {
    687 						if (dp == Xstring(ds, dp))
    688 							word = IFS_IWS;
    689 						type = XNULLSUB;
    690 					}
    691 					if (f & DOBLANK)
    692 						doblank++;
    693 					st = st->prev;
    694 					continue;
    695 				case '=':
    696 					/*
    697 					 * Restore our position and substitute
    698 					 * the value of st->var (may not be
    699 					 * the assigned value in the presence
    700 					 * of integer/right-adj/etc attributes).
    701 					 */
    702 					dp = Xrestpos(ds, dp, st->base);
    703 					/*
    704 					 * Must use st->var since calling
    705 					 * global would cause with things
    706 					 * like x[i+=1] to be evaluated twice.
    707 					 */
    708 					/*
    709 					 * Note: not exported by FEXPORT
    710 					 * in AT&T ksh.
    711 					 */
    712 					/*
    713 					 * XXX POSIX says readonly is only
    714 					 * fatal for special builtins (setstr
    715 					 * does readonly check).
    716 					 */
    717 					len = strlen(dp) + 1;
    718 					setstr(st->var,
    719 					    debunk(alloc(len, ATEMP),
    720 					    dp, len), KSH_UNWIND_ERROR);
    721 					x.str = str_val(st->var);
    722 					type = XSUB;
    723 					if (f & DOBLANK)
    724 						doblank++;
    725 					st = st->prev;
    726 					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
    727 					continue;
    728 				case '?':
    729 					dp = Xrestpos(ds, dp, st->base);
    730 
    731 					errorf("%s: %s", st->var->name,
    732 					    debunk(dp, dp, strlen(dp) + 1));
    733 					break;
    734 				case '0':
    735 				case '/':
    736 				case 0x100 | '#':
    737 				case 0x100 | 'Q':
    738 					dp = Xrestpos(ds, dp, st->base);
    739 					type = XSUB;
    740 					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
    741 					if (f & DOBLANK)
    742 						doblank++;
    743 					st = st->prev;
    744 					continue;
    745 				/* default: '-' '+' */
    746 				}
    747 				st = st->prev;
    748 				type = XBASE;
    749 				continue;
    750 
    751 			case OPAT:
    752 				/* open pattern: *(foo|bar) */
    753 				/* Next char is the type of pattern */
    754 				make_magic = true;
    755 				c = *sp++ | 0x80;
    756 				break;
    757 
    758 			case SPAT:
    759 				/* pattern separator (|) */
    760 				make_magic = true;
    761 				c = '|';
    762 				break;
    763 
    764 			case CPAT:
    765 				/* close pattern */
    766 				make_magic = true;
    767 				c = /*(*/ ')';
    768 				break;
    769 			}
    770 			break;
    771 
    772 		case XNULLSUB:
    773 			/*
    774 			 * Special case for "$@" (and "${foo[@]}") - no
    775 			 * word is generated if $# is 0 (unless there is
    776 			 * other stuff inside the quotes).
    777 			 */
    778 			type = XBASE;
    779 			if (f & DOBLANK) {
    780 				doblank--;
    781 				if (dp == Xstring(ds, dp) && word != IFS_WORD)
    782 					word = IFS_IWS;
    783 			}
    784 			continue;
    785 
    786 		case XSUB:
    787 		case XSUBMID:
    788 			if ((c = *x.str++) == 0) {
    789 				type = XBASE;
    790 				if (f & DOBLANK)
    791 					doblank--;
    792 				continue;
    793 			}
    794 			break;
    795 
    796 		case XARGSEP:
    797 			type = XARG;
    798 			quote = 1;
    799 			/* FALLTHROUGH */
    800 		case XARG:
    801 			if ((c = *x.str++) == '\0') {
    802 				/*
    803 				 * force null words to be created so
    804 				 * set -- "" 2 ""; echo "$@" will do
    805 				 * the right thing
    806 				 */
    807 				if (quote && x.split)
    808 					word = IFS_WORD;
    809 				if ((x.str = *x.u.strv++) == NULL) {
    810 					type = XBASE;
    811 					if (f & DOBLANK)
    812 						doblank--;
    813 					continue;
    814 				}
    815 				c = ifs0;
    816 				if ((f & DOHEREDOC)) {
    817 					/* pseudo-field-split reliably */
    818 					if (c == 0)
    819 						c = ' ';
    820 					break;
    821 				}
    822 				if ((f & DOSCALAR)) {
    823 					/* do not field-split */
    824 					if (x.split) {
    825 						c = ' ';
    826 						break;
    827 					}
    828 					if (c == 0)
    829 						continue;
    830 				}
    831 				if (c == 0) {
    832 					if (quote && !x.split)
    833 						continue;
    834 					if (!quote && word == IFS_WS)
    835 						continue;
    836 					/* this is so we don't terminate */
    837 					c = ' ';
    838 					/* now force-emit a word */
    839 					goto emit_word;
    840 				}
    841 				if (quote && x.split) {
    842 					/* terminate word for "$@" */
    843 					type = XARGSEP;
    844 					quote = 0;
    845 				}
    846 			}
    847 			break;
    848 
    849 		case XCOM:
    850 			if (x.u.shf == NULL) {
    851 				/* $(<...) failed */
    852 				subst_exstat = 1;
    853 				/* fake EOF */
    854 				c = -1;
    855 			} else if (newlines) {
    856 				/* spit out saved NLs */
    857 				c = '\n';
    858 				--newlines;
    859 			} else {
    860 				while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
    861 					if (c == '\n')
    862 						/* save newlines */
    863 						newlines++;
    864 				if (newlines && c != -1) {
    865 					shf_ungetc(c, x.u.shf);
    866 					c = '\n';
    867 					--newlines;
    868 				}
    869 			}
    870 			if (c == -1) {
    871 				newlines = 0;
    872 				if (x.u.shf)
    873 					shf_close(x.u.shf);
    874 				if (x.split)
    875 					subst_exstat = waitlast();
    876 				type = XBASE;
    877 				if (f & DOBLANK)
    878 					doblank--;
    879 				continue;
    880 			}
    881 			break;
    882 		}
    883 
    884 		/* check for end of word or IFS separation */
    885 		if (c == 0 || (!quote && (f & DOBLANK) && doblank &&
    886 		    !make_magic && ctype(c, C_IFS))) {
    887 			/*-
    888 			 * How words are broken up:
    889 			 *			|	value of c
    890 			 *	word		|	ws	nws	0
    891 			 *	-----------------------------------
    892 			 *	IFS_WORD		w/WS	w/NWS	w
    893 			 *	IFS_WS			-/WS	-/NWS	-
    894 			 *	IFS_NWS			-/NWS	w/NWS	-
    895 			 *	IFS_IWS			-/WS	w/NWS	-
    896 			 * (w means generate a word)
    897 			 */
    898 			if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
    899 			    (word == IFS_IWS || word == IFS_NWS) &&
    900 			    !ctype(c, C_IFSWS))) {
    901  emit_word:
    902 				if (f & DOHERESTR)
    903 					*dp++ = '\n';
    904 				*dp++ = '\0';
    905 				cp = Xclose(ds, dp);
    906 				if (fdo & DOBRACE)
    907 					/* also does globbing */
    908 					alt_expand(wp, cp, cp,
    909 					    cp + Xlength(ds, (dp - 1)),
    910 					    fdo | (f & DOMARKDIRS));
    911 				else if (fdo & DOGLOB)
    912 					glob(cp, wp, tobool(f & DOMARKDIRS));
    913 				else if ((f & DOPAT) || !(fdo & DOMAGIC))
    914 					XPput(*wp, cp);
    915 				else
    916 					XPput(*wp, debunk(cp, cp,
    917 					    strlen(cp) + 1));
    918 				fdo = 0;
    919 				saw_eq = false;
    920 				/* must be 1/0 */
    921 				tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
    922 				if (c == 0)
    923 					return;
    924 				Xinit(ds, dp, 128, ATEMP);
    925 			} else if (c == 0) {
    926 				return;
    927 			} else if (type == XSUB && ctype(c, C_IFS) &&
    928 			    !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
    929 				*(cp = alloc(1, ATEMP)) = '\0';
    930 				XPput(*wp, cp);
    931 				type = XSUBMID;
    932 			}
    933 			if (word != IFS_NWS)
    934 				word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
    935 		} else {
    936 			if (type == XSUB) {
    937 				if (word == IFS_NWS &&
    938 				    Xlength(ds, dp) == 0) {
    939 					*(cp = alloc(1, ATEMP)) = '\0';
    940 					XPput(*wp, cp);
    941 				}
    942 				type = XSUBMID;
    943 			}
    944 
    945 			/* age tilde_ok info - ~ code tests second bit */
    946 			tilde_ok <<= 1;
    947 			/* mark any special second pass chars */
    948 			if (!quote)
    949 				switch (c) {
    950 				case '[':
    951 				case '!':
    952 				case '-':
    953 				case ']':
    954 					/*
    955 					 * For character classes - doesn't hurt
    956 					 * to have magic !,-,]s outside of
    957 					 * [...] expressions.
    958 					 */
    959 					if (f & (DOPAT | DOGLOB)) {
    960 						fdo |= DOMAGIC;
    961 						if (c == '[')
    962 							fdo |= f & DOGLOB;
    963 						*dp++ = MAGIC;
    964 					}
    965 					break;
    966 				case '*':
    967 				case '?':
    968 					if (f & (DOPAT | DOGLOB)) {
    969 						fdo |= DOMAGIC | (f & DOGLOB);
    970 						*dp++ = MAGIC;
    971 					}
    972 					break;
    973 				case '{':
    974 				case '}':
    975 				case ',':
    976 					if ((f & DOBRACE) && (c == '{' /*}*/ ||
    977 					    (fdo & DOBRACE))) {
    978 						fdo |= DOBRACE|DOMAGIC;
    979 						*dp++ = MAGIC;
    980 					}
    981 					break;
    982 				case '=':
    983 					/* Note first unquoted = for ~ */
    984 					if (!(f & DOTEMP) && (!Flag(FPOSIX) ||
    985 					    (f & DOASNTILDE)) && !saw_eq) {
    986 						saw_eq = true;
    987 						tilde_ok = 1;
    988 					}
    989 					break;
    990 				case ':':
    991 					/* : */
    992 					/* Note unquoted : for ~ */
    993 					if (!(f & DOTEMP) && (f & DOASNTILDE))
    994 						tilde_ok = 1;
    995 					break;
    996 				case '~':
    997 					/*
    998 					 * tilde_ok is reset whenever
    999 					 * any of ' " $( $(( ${ } are seen.
   1000 					 * Note that tilde_ok must be preserved
   1001 					 * through the sequence ${A=a=}~
   1002 					 */
   1003 					if (type == XBASE &&
   1004 					    (f & (DOTILDE | DOASNTILDE)) &&
   1005 					    (tilde_ok & 2)) {
   1006 						const char *tcp;
   1007 						char *tdp = dp;
   1008 
   1009 						tcp = maybe_expand_tilde(sp,
   1010 						    &ds, &tdp,
   1011 						    tobool(f & DOASNTILDE));
   1012 						if (tcp) {
   1013 							if (dp != tdp)
   1014 								word = IFS_WORD;
   1015 							dp = tdp;
   1016 							sp = tcp;
   1017 							continue;
   1018 						}
   1019 					}
   1020 					break;
   1021 				}
   1022 			else
   1023 				/* undo temporary */
   1024 				quote &= ~2;
   1025 
   1026 			if (make_magic) {
   1027 				make_magic = false;
   1028 				fdo |= DOMAGIC | (f & DOGLOB);
   1029 				*dp++ = MAGIC;
   1030 			} else if (ISMAGIC(c)) {
   1031 				fdo |= DOMAGIC;
   1032 				*dp++ = MAGIC;
   1033 			}
   1034 			/* save output char */
   1035 			*dp++ = c;
   1036 			word = IFS_WORD;
   1037 		}
   1038 	}
   1039 }
   1040 
   1041 static bool
   1042 hasnonempty(const char **strv)
   1043 {
   1044 	size_t i = 0;
   1045 
   1046 	while (strv[i])
   1047 		if (*strv[i++])
   1048 			return (true);
   1049 	return (false);
   1050 }
   1051 
   1052 /*
   1053  * Prepare to generate the string returned by ${} substitution.
   1054  */
   1055 static int
   1056 varsub(Expand *xp, const char *sp, const char *word,
   1057     int *stypep,	/* becomes qualifier type */
   1058     int *slenp)		/* " " len (=, :=, etc.) valid iff *stypep != 0 */
   1059 {
   1060 	int c;
   1061 	int state;	/* next state: XBASE, XARG, XSUB, XNULLSUB */
   1062 	int stype;	/* substitution type */
   1063 	int slen;
   1064 	const char *p;
   1065 	struct tbl *vp;
   1066 	bool zero_ok = false;
   1067 
   1068 	if ((stype = sp[0]) == '\0')
   1069 		/* Bad variable name */
   1070 		return (-1);
   1071 
   1072 	xp->var = NULL;
   1073 
   1074 	/*-
   1075 	 * ${#var}, string length (-U: characters, +U: octets) or array size
   1076 	 * ${%var}, string width (-U: screen columns, +U: octets)
   1077 	 */
   1078 	c = sp[1];
   1079 	if (stype == '%' && c == '\0')
   1080 		return (-1);
   1081 	if ((stype == '#' || stype == '%') && c != '\0') {
   1082 		/* Can't have any modifiers for ${#...} or ${%...} */
   1083 		if (*word != CSUBST)
   1084 			return (-1);
   1085 		sp++;
   1086 		/* Check for size of array */
   1087 		if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
   1088 		    p[2] == ']') {
   1089 			int n = 0;
   1090 
   1091 			if (stype != '#')
   1092 				return (-1);
   1093 			vp = global(arrayname(sp));
   1094 			if (vp->flag & (ISSET|ARRAY))
   1095 				zero_ok = true;
   1096 			for (; vp; vp = vp->u.array)
   1097 				if (vp->flag & ISSET)
   1098 					n++;
   1099 			c = n;
   1100 		} else if (c == '*' || c == '@') {
   1101 			if (stype != '#')
   1102 				return (-1);
   1103 			c = e->loc->argc;
   1104 		} else {
   1105 			p = str_val(global(sp));
   1106 			zero_ok = p != null;
   1107 			if (stype == '#')
   1108 				c = utflen(p);
   1109 			else {
   1110 				/* partial utf_mbswidth reimplementation */
   1111 				const char *s = p;
   1112 				unsigned int wc;
   1113 				size_t len;
   1114 				int cw;
   1115 
   1116 				c = 0;
   1117 				while (*s) {
   1118 					if (!UTFMODE || (len = utf_mbtowc(&wc,
   1119 					    s)) == (size_t)-1)
   1120 						/* not UTFMODE or not UTF-8 */
   1121 						wc = (unsigned char)(*s++);
   1122 					else
   1123 						/* UTFMODE and UTF-8 */
   1124 						s += len;
   1125 					/* wc == char or wchar at s++ */
   1126 					if ((cw = utf_wcwidth(wc)) == -1) {
   1127 						/* 646, 8859-1, 10646 C0/C1 */
   1128 						c = -1;
   1129 						break;
   1130 					}
   1131 					c += cw;
   1132 				}
   1133 			}
   1134 		}
   1135 		if (Flag(FNOUNSET) && c == 0 && !zero_ok)
   1136 			errorf("%s: %s", sp, "parameter not set");
   1137 		/* unqualified variable/string substitution */
   1138 		*stypep = 0;
   1139 		xp->str = shf_smprintf("%d", c);
   1140 		return (XSUB);
   1141 	}
   1142 
   1143 	/* Check for qualifiers in word part */
   1144 	stype = 0;
   1145 	c = word[slen = 0] == CHAR ? word[1] : 0;
   1146 	if (c == ':') {
   1147 		slen += 2;
   1148 		stype = 0x80;
   1149 		c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
   1150 	}
   1151 	if (!stype && c == '/') {
   1152 		slen += 2;
   1153 		stype = c;
   1154 		if (word[slen] == ADELIM) {
   1155 			slen += 2;
   1156 			stype |= 0x80;
   1157 		}
   1158 	} else if (stype == 0x80 && (c == ' ' || c == '0')) {
   1159 		stype |= '0';
   1160 	} else if (ctype(c, C_SUBOP1)) {
   1161 		slen += 2;
   1162 		stype |= c;
   1163 	} else if (ctype(c, C_SUBOP2)) {
   1164 		/* Note: ksh88 allows :%, :%%, etc */
   1165 		slen += 2;
   1166 		stype = c;
   1167 		if (word[slen + 0] == CHAR && c == word[slen + 1]) {
   1168 			stype |= 0x80;
   1169 			slen += 2;
   1170 		}
   1171 	} else if (c == '@') {
   1172 		/* @x where x is command char */
   1173 		slen += 2;
   1174 		stype |= 0x100;
   1175 		if (word[slen] == CHAR) {
   1176 			stype |= word[slen + 1];
   1177 			slen += 2;
   1178 		}
   1179 	} else if (stype)
   1180 		/* : is not ok */
   1181 		return (-1);
   1182 	if (!stype && *word != CSUBST)
   1183 		return (-1);
   1184 	*stypep = stype;
   1185 	*slenp = slen;
   1186 
   1187 	c = sp[0];
   1188 	if (c == '*' || c == '@') {
   1189 		switch (stype & 0x17F) {
   1190 		/* can't assign to a vector */
   1191 		case '=':
   1192 		/* can't trim a vector (yet) */
   1193 		case '%':
   1194 		case '#':
   1195 		case '0':
   1196 		case '/':
   1197 		case 0x100 | '#':
   1198 		case 0x100 | 'Q':
   1199 			return (-1);
   1200 		}
   1201 		if (e->loc->argc == 0) {
   1202 			xp->str = null;
   1203 			xp->var = global(sp);
   1204 			state = c == '@' ? XNULLSUB : XSUB;
   1205 		} else {
   1206 			xp->u.strv = (const char **)e->loc->argv + 1;
   1207 			xp->str = *xp->u.strv++;
   1208 			/* $@ */
   1209 			xp->split = tobool(c == '@');
   1210 			state = XARG;
   1211 		}
   1212 		/* POSIX 2009? */
   1213 		zero_ok = true;
   1214 	} else {
   1215 		if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
   1216 		    p[2] == ']') {
   1217 			XPtrV wv;
   1218 
   1219 			switch (stype & 0x17F) {
   1220 			/* can't assign to a vector */
   1221 			case '=':
   1222 			/* can't trim a vector (yet) */
   1223 			case '%':
   1224 			case '#':
   1225 			case '?':
   1226 			case '0':
   1227 			case '/':
   1228 			case 0x100 | '#':
   1229 			case 0x100 | 'Q':
   1230 				return (-1);
   1231 			}
   1232 			XPinit(wv, 32);
   1233 			if ((c = sp[0]) == '!')
   1234 				++sp;
   1235 			vp = global(arrayname(sp));
   1236 			for (; vp; vp = vp->u.array) {
   1237 				if (!(vp->flag&ISSET))
   1238 					continue;
   1239 				XPput(wv, c == '!' ? shf_smprintf("%lu",
   1240 				    arrayindex(vp)) :
   1241 				    str_val(vp));
   1242 			}
   1243 			if (XPsize(wv) == 0) {
   1244 				xp->str = null;
   1245 				state = p[1] == '@' ? XNULLSUB : XSUB;
   1246 				XPfree(wv);
   1247 			} else {
   1248 				XPput(wv, 0);
   1249 				xp->u.strv = (const char **)XPptrv(wv);
   1250 				xp->str = *xp->u.strv++;
   1251 				/* ${foo[@]} */
   1252 				xp->split = tobool(p[1] == '@');
   1253 				state = XARG;
   1254 			}
   1255 		} else {
   1256 			/* Can't assign things like $! or $1 */
   1257 			if ((stype & 0x17F) == '=' &&
   1258 			    ctype(*sp, C_VAR1 | C_DIGIT))
   1259 				return (-1);
   1260 			if (*sp == '!' && sp[1]) {
   1261 				++sp;
   1262 				xp->var = global(sp);
   1263 				if (vstrchr(sp, '['))
   1264 					xp->str = shf_smprintf("%s[%lu]",
   1265 					    xp->var->name,
   1266 					    arrayindex(xp->var));
   1267 				else
   1268 					xp->str = xp->var->name;
   1269 			} else {
   1270 				xp->var = global(sp);
   1271 				xp->str = str_val(xp->var);
   1272 			}
   1273 			state = XSUB;
   1274 		}
   1275 	}
   1276 
   1277 	c = stype & 0x7F;
   1278 	/* test the compiler's code generator */
   1279 	if (((stype < 0x100) && (ctype(c, C_SUBOP2) || c == '/' ||
   1280 	    (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
   1281 	    (state != XARG || (ifs0 || xp->split ?
   1282 	    (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
   1283 	    c == '=' || c == '-' || c == '?' : c == '+'))) ||
   1284 	    stype == (0x80 | '0') || stype == (0x100 | '#') ||
   1285 	    stype == (0x100 | 'Q'))
   1286 		/* expand word instead of variable value */
   1287 		state = XBASE;
   1288 	if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
   1289 	    (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
   1290 		errorf("%s: %s", sp, "parameter not set");
   1291 	return (state);
   1292 }
   1293 
   1294 /*
   1295  * Run the command in $(...) and read its output.
   1296  */
   1297 static int
   1298 comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
   1299 {
   1300 	Source *s, *sold;
   1301 	struct op *t;
   1302 	struct shf *shf;
   1303 	uint8_t old_utfmode = UTFMODE;
   1304 
   1305 	s = pushs(SSTRING, ATEMP);
   1306 	s->start = s->str = cp;
   1307 	sold = source;
   1308 	t = compile(s, true);
   1309 	afree(s, ATEMP);
   1310 	source = sold;
   1311 
   1312 	UTFMODE = old_utfmode;
   1313 
   1314 	if (t == NULL)
   1315 		return (XBASE);
   1316 
   1317 	/* no waitlast() unless specifically enabled later */
   1318 	xp->split = false;
   1319 
   1320 	if (t->type == TCOM &&
   1321 	    *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
   1322 		/* $(<file) */
   1323 		struct ioword *io = *t->ioact;
   1324 		char *name;
   1325 
   1326 		if ((io->ioflag & IOTYPE) != IOREAD)
   1327 			errorf("%s: %s", T_funny_command,
   1328 			    snptreef(NULL, 32, "%R", io));
   1329 		shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY,
   1330 			0, SHF_MAPHI | SHF_CLEXEC);
   1331 		if (shf == NULL)
   1332 			warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
   1333 			    "can't open", "$(<...) input", cstrerror(errno));
   1334 	} else if (fn == FUNSUB) {
   1335 		int ofd1;
   1336 		struct temp *tf = NULL;
   1337 
   1338 		/*
   1339 		 * create a temporary file, open for reading and writing,
   1340 		 * with an shf open for reading (buffered) but yet unused
   1341 		 */
   1342 		maketemp(ATEMP, TT_FUNSUB, &tf);
   1343 		if (!tf->shf) {
   1344 			errorf("can't %s temporary file %s: %s",
   1345 			    "create", tf->tffn, cstrerror(errno));
   1346 		}
   1347 		/* extract shf from temporary file, unlink and free it */
   1348 		shf = tf->shf;
   1349 		unlink(tf->tffn);
   1350 		afree(tf, ATEMP);
   1351 		/* save stdout and let it point to the tempfile */
   1352 		ofd1 = savefd(1);
   1353 		ksh_dup2(shf_fileno(shf), 1, false);
   1354 		/*
   1355 		 * run tree, with output thrown into the tempfile,
   1356 		 * in a new function block
   1357 		 */
   1358 		valsub(t, NULL);
   1359 		subst_exstat = exstat & 0xFF;
   1360 		/* rewind the tempfile and restore regular stdout */
   1361 		lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
   1362 		restfd(1, ofd1);
   1363 	} else if (fn == VALSUB) {
   1364 		xp->str = valsub(t, ATEMP);
   1365 		subst_exstat = exstat & 0xFF;
   1366 		return (XSUB);
   1367 	} else {
   1368 		int ofd1, pv[2];
   1369 
   1370 		openpipe(pv);
   1371 		shf = shf_fdopen(pv[0], SHF_RD, NULL);
   1372 		ofd1 = savefd(1);
   1373 		if (pv[1] != 1) {
   1374 			ksh_dup2(pv[1], 1, false);
   1375 			close(pv[1]);
   1376 		}
   1377 		execute(t, XXCOM | XPIPEO | XFORK, NULL);
   1378 		restfd(1, ofd1);
   1379 		startlast();
   1380 		/* waitlast() */
   1381 		xp->split = true;
   1382 	}
   1383 
   1384 	xp->u.shf = shf;
   1385 	return (XCOM);
   1386 }
   1387 
   1388 /*
   1389  * perform #pattern and %pattern substitution in ${}
   1390  */
   1391 static char *
   1392 trimsub(char *str, char *pat, int how)
   1393 {
   1394 	char *end = strnul(str);
   1395 	char *p, c;
   1396 
   1397 	switch (how & 0xFF) {
   1398 	case '#':
   1399 		/* shortest match at beginning */
   1400 		for (p = str; p <= end; p += utf_ptradj(p)) {
   1401 			c = *p; *p = '\0';
   1402 			if (gmatchx(str, pat, false)) {
   1403 				*p = c;
   1404 				return (p);
   1405 			}
   1406 			*p = c;
   1407 		}
   1408 		break;
   1409 	case '#'|0x80:
   1410 		/* longest match at beginning */
   1411 		for (p = end; p >= str; p--) {
   1412 			c = *p; *p = '\0';
   1413 			if (gmatchx(str, pat, false)) {
   1414 				*p = c;
   1415 				return (p);
   1416 			}
   1417 			*p = c;
   1418 		}
   1419 		break;
   1420 	case '%':
   1421 		/* shortest match at end */
   1422 		p = end;
   1423 		while (p >= str) {
   1424 			if (gmatchx(p, pat, false))
   1425 				goto trimsub_match;
   1426 			if (UTFMODE) {
   1427 				char *op = p;
   1428 				while ((p-- > str) && ((*p & 0xC0) == 0x80))
   1429 					;
   1430 				if ((p < str) || (p + utf_ptradj(p) != op))
   1431 					p = op - 1;
   1432 			} else
   1433 				--p;
   1434 		}
   1435 		break;
   1436 	case '%'|0x80:
   1437 		/* longest match at end */
   1438 		for (p = str; p <= end; p++)
   1439 			if (gmatchx(p, pat, false)) {
   1440  trimsub_match:
   1441 				strndupx(end, str, p - str, ATEMP);
   1442 				return (end);
   1443 			}
   1444 		break;
   1445 	}
   1446 
   1447 	/* no match, return string */
   1448 	return (str);
   1449 }
   1450 
   1451 /*
   1452  * glob
   1453  * Name derived from V6's /etc/glob, the program that expanded filenames.
   1454  */
   1455 
   1456 /* XXX cp not const 'cause slashes are temporarily replaced with NULs... */
   1457 static void
   1458 glob(char *cp, XPtrV *wp, bool markdirs)
   1459 {
   1460 	int oldsize = XPsize(*wp);
   1461 
   1462 	if (glob_str(cp, wp, markdirs) == 0)
   1463 		XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
   1464 	else
   1465 		qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize,
   1466 		    sizeof(void *), xstrcmp);
   1467 }
   1468 
   1469 #define GF_NONE		0
   1470 #define GF_EXCHECK	BIT(0)		/* do existence check on file */
   1471 #define GF_GLOBBED	BIT(1)		/* some globbing has been done */
   1472 #define GF_MARKDIR	BIT(2)		/* add trailing / to directories */
   1473 
   1474 /*
   1475  * Apply file globbing to cp and store the matching files in wp. Returns
   1476  * the number of matches found.
   1477  */
   1478 int
   1479 glob_str(char *cp, XPtrV *wp, bool markdirs)
   1480 {
   1481 	int oldsize = XPsize(*wp);
   1482 	XString xs;
   1483 	char *xp;
   1484 
   1485 	Xinit(xs, xp, 256, ATEMP);
   1486 	globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
   1487 	Xfree(xs, xp);
   1488 
   1489 	return (XPsize(*wp) - oldsize);
   1490 }
   1491 
   1492 static void
   1493 globit(XString *xs,	/* dest string */
   1494     char **xpp,		/* ptr to dest end */
   1495     char *sp,		/* source path */
   1496     XPtrV *wp,		/* output list */
   1497     int check)		/* GF_* flags */
   1498 {
   1499 	char *np;		/* next source component */
   1500 	char *xp = *xpp;
   1501 	char *se;
   1502 	char odirsep;
   1503 
   1504 	/* This to allow long expansions to be interrupted */
   1505 	intrcheck();
   1506 
   1507 	if (sp == NULL) {
   1508 		/* end of source path */
   1509 		/*
   1510 		 * We only need to check if the file exists if a pattern
   1511 		 * is followed by a non-pattern (eg, foo*x/bar; no check
   1512 		 * is needed for foo* since the match must exist) or if
   1513 		 * any patterns were expanded and the markdirs option is set.
   1514 		 * Symlinks make things a bit tricky...
   1515 		 */
   1516 		if ((check & GF_EXCHECK) ||
   1517 		    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
   1518 #define stat_check()	(stat_done ? stat_done : (stat_done = \
   1519 			    stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
   1520 			struct stat lstatb, statb;
   1521 			/* -1: failed, 1 ok, 0 not yet done */
   1522 			int stat_done = 0;
   1523 
   1524 			if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
   1525 				return;
   1526 			/*
   1527 			 * special case for systems which strip trailing
   1528 			 * slashes from regular files (eg, /etc/passwd/).
   1529 			 * SunOS 4.1.3 does this...
   1530 			 */
   1531 			if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) &&
   1532 			    xp[-1] == '/' && !S_ISDIR(lstatb.st_mode) &&
   1533 			    (!S_ISLNK(lstatb.st_mode) ||
   1534 			    stat_check() < 0 || !S_ISDIR(statb.st_mode)))
   1535 				return;
   1536 			/*
   1537 			 * Possibly tack on a trailing / if there isn't already
   1538 			 * one and if the file is a directory or a symlink to a
   1539 			 * directory
   1540 			 */
   1541 			if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) &&
   1542 			    xp > Xstring(*xs, xp) && xp[-1] != '/' &&
   1543 			    (S_ISDIR(lstatb.st_mode) ||
   1544 			    (S_ISLNK(lstatb.st_mode) && stat_check() > 0 &&
   1545 			    S_ISDIR(statb.st_mode)))) {
   1546 				*xp++ = '/';
   1547 				*xp = '\0';
   1548 			}
   1549 		}
   1550 		strndupx(np, Xstring(*xs, xp), Xlength(*xs, xp), ATEMP);
   1551 		XPput(*wp, np);
   1552 		return;
   1553 	}
   1554 
   1555 	if (xp > Xstring(*xs, xp))
   1556 		*xp++ = '/';
   1557 	while (*sp == '/') {
   1558 		Xcheck(*xs, xp);
   1559 		*xp++ = *sp++;
   1560 	}
   1561 	np = strchr(sp, '/');
   1562 	if (np != NULL) {
   1563 		se = np;
   1564 		/* don't assume '/', can be multiple kinds */
   1565 		odirsep = *np;
   1566 		*np++ = '\0';
   1567 	} else {
   1568 		odirsep = '\0'; /* keep gcc quiet */
   1569 		se = sp + strlen(sp);
   1570 	}
   1571 
   1572 
   1573 	/*
   1574 	 * Check if sp needs globbing - done to avoid pattern checks for strings
   1575 	 * containing MAGIC characters, open [s without the matching close ],
   1576 	 * etc. (otherwise opendir() will be called which may fail because the
   1577 	 * directory isn't readable - if no globbing is needed, only execute
   1578 	 * permission should be required (as per POSIX)).
   1579 	 */
   1580 	if (!has_globbing(sp, se)) {
   1581 		XcheckN(*xs, xp, se - sp + 1);
   1582 		debunk(xp, sp, Xnleft(*xs, xp));
   1583 		xp += strlen(xp);
   1584 		*xpp = xp;
   1585 		globit(xs, xpp, np, wp, check);
   1586 	} else {
   1587 		DIR *dirp;
   1588 		struct dirent *d;
   1589 		char *name;
   1590 		size_t len, prefix_len;
   1591 
   1592 		/* xp = *xpp;	copy_non_glob() may have re-alloc'd xs */
   1593 		*xp = '\0';
   1594 		prefix_len = Xlength(*xs, xp);
   1595 		dirp = opendir(prefix_len ? Xstring(*xs, xp) : ".");
   1596 		if (dirp == NULL)
   1597 			goto Nodir;
   1598 		while ((d = readdir(dirp)) != NULL) {
   1599 			name = d->d_name;
   1600 			if (name[0] == '.' &&
   1601 			    (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
   1602 				/* always ignore . and .. */
   1603 				continue;
   1604 			if ((*name == '.' && *sp != '.') ||
   1605 			    !gmatchx(name, sp, true))
   1606 				continue;
   1607 
   1608 			len = strlen(d->d_name) + 1;
   1609 			XcheckN(*xs, xp, len);
   1610 			memcpy(xp, name, len);
   1611 			*xpp = xp + len - 1;
   1612 			globit(xs, xpp, np, wp,
   1613 				(check & GF_MARKDIR) | GF_GLOBBED
   1614 				| (np ? GF_EXCHECK : GF_NONE));
   1615 			xp = Xstring(*xs, xp) + prefix_len;
   1616 		}
   1617 		closedir(dirp);
   1618  Nodir:
   1619 		;
   1620 	}
   1621 
   1622 	if (np != NULL)
   1623 		*--np = odirsep;
   1624 }
   1625 
   1626 /* remove MAGIC from string */
   1627 char *
   1628 debunk(char *dp, const char *sp, size_t dlen)
   1629 {
   1630 	char *d;
   1631 	const char *s;
   1632 
   1633 	if ((s = cstrchr(sp, MAGIC))) {
   1634 		if (s - sp >= (ssize_t)dlen)
   1635 			return (dp);
   1636 		memmove(dp, sp, s - sp);
   1637 		for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++)
   1638 			if (!ISMAGIC(*s) || !(*++s & 0x80) ||
   1639 			    !vstrchr("*+?@! ", *s & 0x7f))
   1640 				*d++ = *s;
   1641 			else {
   1642 				/* extended pattern operators: *+?@! */
   1643 				if ((*s & 0x7f) != ' ')
   1644 					*d++ = *s & 0x7f;
   1645 				if (d - dp < (ssize_t)dlen)
   1646 					*d++ = '(';
   1647 			}
   1648 		*d = '\0';
   1649 	} else if (dp != sp)
   1650 		strlcpy(dp, sp, dlen);
   1651 	return (dp);
   1652 }
   1653 
   1654 /*
   1655  * Check if p is an unquoted name, possibly followed by a / or :. If so
   1656  * puts the expanded version in *dcp,dp and returns a pointer in p just
   1657  * past the name, otherwise returns 0.
   1658  */
   1659 static const char *
   1660 maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
   1661 {
   1662 	XString ts;
   1663 	char *dp = *dpp;
   1664 	char *tp;
   1665 	const char *r;
   1666 
   1667 	Xinit(ts, tp, 16, ATEMP);
   1668 	/* : only for DOASNTILDE form */
   1669 	while (p[0] == CHAR && p[1] != '/' && (!isassign || p[1] != ':'))
   1670 	{
   1671 		Xcheck(ts, tp);
   1672 		*tp++ = p[1];
   1673 		p += 2;
   1674 	}
   1675 	*tp = '\0';
   1676 	r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ?
   1677 	    do_tilde(Xstring(ts, tp)) : NULL;
   1678 	Xfree(ts, tp);
   1679 	if (r) {
   1680 		while (*r) {
   1681 			Xcheck(*dsp, dp);
   1682 			if (ISMAGIC(*r))
   1683 				*dp++ = MAGIC;
   1684 			*dp++ = *r++;
   1685 		}
   1686 		*dpp = dp;
   1687 		r = p;
   1688 	}
   1689 	return (r);
   1690 }
   1691 
   1692 /*
   1693  * tilde expansion
   1694  *
   1695  * based on a version by Arnold Robbins
   1696  */
   1697 
   1698 char *
   1699 do_tilde(char *cp)
   1700 {
   1701 	char *dp = null;
   1702 
   1703 	if (cp[0] == '\0')
   1704 		dp = str_val(global("HOME"));
   1705 	else if (cp[0] == '+' && cp[1] == '\0')
   1706 		dp = str_val(global("PWD"));
   1707 	else if (ksh_isdash(cp))
   1708 		dp = str_val(global("OLDPWD"));
   1709 #ifndef MKSH_NOPWNAM
   1710 	else
   1711 		dp = homedir(cp);
   1712 #endif
   1713 	/* If HOME, PWD or OLDPWD are not set, don't expand ~ */
   1714 	return (dp == null ? NULL : dp);
   1715 }
   1716 
   1717 #ifndef MKSH_NOPWNAM
   1718 /*
   1719  * map userid to user's home directory.
   1720  * note that 4.3's getpw adds more than 6K to the shell,
   1721  * and the YP version probably adds much more.
   1722  * we might consider our own version of getpwnam() to keep the size down.
   1723  */
   1724 static char *
   1725 homedir(char *name)
   1726 {
   1727 	struct tbl *ap;
   1728 
   1729 	ap = ktenter(&homedirs, name, hash(name));
   1730 	if (!(ap->flag & ISSET)) {
   1731 		struct passwd *pw;
   1732 
   1733 		pw = getpwnam(name);
   1734 		if (pw == NULL)
   1735 			return (NULL);
   1736 		strdupx(ap->val.s, pw->pw_dir, APERM);
   1737 		ap->flag |= DEFINED|ISSET|ALLOC;
   1738 	}
   1739 	return (ap->val.s);
   1740 }
   1741 #endif
   1742 
   1743 static void
   1744 alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
   1745 {
   1746 	unsigned int count = 0;
   1747 	char *brace_start, *brace_end, *comma = NULL;
   1748 	char *field_start;
   1749 	char *p = exp_start;
   1750 
   1751 	/* search for open brace */
   1752 	while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/)
   1753 		p += 2;
   1754 	brace_start = p;
   1755 
   1756 	/* find matching close brace, if any */
   1757 	if (p) {
   1758 		comma = NULL;
   1759 		count = 1;
   1760 		p += 2;
   1761 		while (*p && count) {
   1762 			if (ISMAGIC(*p++)) {
   1763 				if (*p == '{' /*}*/)
   1764 					++count;
   1765 				else if (*p == /*{*/ '}')
   1766 					--count;
   1767 				else if (*p == ',' && count == 1)
   1768 					comma = p;
   1769 				++p;
   1770 			}
   1771 		}
   1772 	}
   1773 	/* no valid expansions... */
   1774 	if (!p || count != 0) {
   1775 		/*
   1776 		 * Note that given a{{b,c} we do not expand anything (this is
   1777 		 * what AT&T ksh does. This may be changed to do the {b,c}
   1778 		 * expansion. }
   1779 		 */
   1780 		if (fdo & DOGLOB)
   1781 			glob(start, wp, tobool(fdo & DOMARKDIRS));
   1782 		else
   1783 			XPput(*wp, debunk(start, start, end - start));
   1784 		return;
   1785 	}
   1786 	brace_end = p;
   1787 	if (!comma) {
   1788 		alt_expand(wp, start, brace_end, end, fdo);
   1789 		return;
   1790 	}
   1791 
   1792 	/* expand expression */
   1793 	field_start = brace_start + 2;
   1794 	count = 1;
   1795 	for (p = brace_start + 2; p != brace_end; p++) {
   1796 		if (ISMAGIC(*p)) {
   1797 			if (*++p == '{' /*}*/)
   1798 				++count;
   1799 			else if ((*p == /*{*/ '}' && --count == 0) ||
   1800 			    (*p == ',' && count == 1)) {
   1801 				char *news;
   1802 				int l1, l2, l3;
   1803 
   1804 				/*
   1805 				 * addition safe since these operate on
   1806 				 * one string (separate substrings)
   1807 				 */
   1808 				l1 = brace_start - start;
   1809 				l2 = (p - 1) - field_start;
   1810 				l3 = end - brace_end;
   1811 				news = alloc(l1 + l2 + l3 + 1, ATEMP);
   1812 				memcpy(news, start, l1);
   1813 				memcpy(news + l1, field_start, l2);
   1814 				memcpy(news + l1 + l2, brace_end, l3);
   1815 				news[l1 + l2 + l3] = '\0';
   1816 				alt_expand(wp, news, news + l1,
   1817 				    news + l1 + l2 + l3, fdo);
   1818 				field_start = p + 1;
   1819 			}
   1820 		}
   1821 	}
   1822 	return;
   1823 }
   1824 
   1825 /* helper function due to setjmp/longjmp woes */
   1826 static char *
   1827 valsub(struct op *t, Area *ap)
   1828 {
   1829 	char * volatile cp = NULL;
   1830 	struct tbl * volatile vp = NULL;
   1831 
   1832 	newenv(E_FUNC);
   1833 	newblock();
   1834 	if (ap)
   1835 		vp = local("REPLY", false);
   1836 	if (!kshsetjmp(e->jbuf))
   1837 		execute(t, XXCOM | XERROK, NULL);
   1838 	if (vp)
   1839 		strdupx(cp, str_val(vp), ap);
   1840 	quitenv(NULL);
   1841 
   1842 	return (cp);
   1843 }
   1844