1737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes/*	$OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
6fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes *	mirabilos <m@mirbsd.org>
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.219 2018/01/14 01:29:47 tg Exp $");
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * string expansion
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * second pass: alternation ({,}), filename expansion (*?[]).
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* expansion generator state */
36811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glasertypedef struct {
37811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* not including an "int type;" member, see expand() */
38811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* string */
39811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	const char *str;
40811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* source */
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	union {
42811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* string[] */
43811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		const char **strv;
44811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* file */
45811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		struct shf *shf;
46811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	} u;
47811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* variable in ${var...} */
48811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	struct tbl *var;
49811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* split "$@" / call waitlast in $() */
50811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	bool split;
515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} Expand;
525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	XBASE		0	/* scanning original */
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	XSUB		1	/* expanding ${} string */
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	XARGSEP		2	/* ifs0 between "$*" */
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	XARG		3	/* expanding $*, $@ */
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	XCOM		4	/* expanding $() */
585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define XNULLSUB	5	/* "$@" when $# is 0 (don't generate word) */
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define XSUBMID		6	/* middle of expanding ${} */
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* States used for field splitting */
6250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes#define IFS_WORD	0	/* word has chars (or quotes except "$@") */
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define IFS_WS		1	/* have seen IFS white-space */
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define IFS_NWS		2	/* have seen IFS non-white-space */
65966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes#define IFS_IWS		3	/* beginning of word, ignore IFS WS */
6650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes#define IFS_QUOTE	4	/* beg.w/quote, become IFS_WORD unless "$@" */
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes#define STYPE_CHAR	0xFF
6923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes#define STYPE_DBL	0x100
7023925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes#define STYPE_AT	0x200
7123925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes#define STYPE_SINGLE	0x2FF
7223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes#define STYPE_MASK	0x300
7323925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int varsub(Expand *, const char *, const char *, int *, int *);
75c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int comsub(Expand *, const char *, int);
76811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic char *valsub(struct op *, Area *);
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *trimsub(char *, char *, int);
78c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void glob(char *, XPtrV *, bool);
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void globit(XString *, char **, char *, XPtrV *, int);
8050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughesstatic const char *maybe_expand_tilde(const char *, XString *, char **, bool);
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_NOPWNAM
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *homedir(char *);
835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void alt_expand(XPtrV *, char *, char *, char *, int);
85737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesstatic int utflen(const char *) MKSH_A_PURE;
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void utfincptr(const char *, mksh_ari_t *);
875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* UTFMODE functions */
8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruutflen(const char *s)
915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t n;
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (UTFMODE) {
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		n = 0;
965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*s) {
975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s += utf_ptradj(s);
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++n;
995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		n = strlen(s);
10203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
10303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (n > 2147483647)
10403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		n = 2147483647;
10503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return ((int)n);
1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruutfincptr(const char *s, mksh_ari_t *lp)
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *cp = s;
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((*lp)--)
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cp += utf_ptradj(cp);
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*lp = cp - s;
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* compile and expand word */
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
1205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusubstitute(const char *cp, int f)
1215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct source *s, *sold;
1235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sold = source;
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	s = pushs(SWSTR, ATEMP);
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	s->start = s->str = cp;
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = s;
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (yylex(ONEWORD) != LWORD)
12977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		internal_errorf(Tbadsubst);
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = sold;
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(s, ATEMP);
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (evalstr(yylval.cp, f));
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * expand arg-list
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar **
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querueval(const char **ap, int f)
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV w;
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (*ap == NULL) {
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		union mksh_ccphack vap;
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vap.ro = ap;
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (vap.rw);
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(w, 32);
15003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* space for shell name */
15103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	XPput(w, NULL);
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (*ap != NULL)
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		expand(*ap++, &w, f);
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(w, NULL);
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((char **)XPclose(w) + 1);
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * expand string
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruevalstr(const char *cp, int f)
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV w;
1655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *dp = null;
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(w, 1);
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	expand(cp, &w, f);
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (XPsize(w))
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		dp = *XPptrv(w);
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPfree(w);
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (dp);
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * expand string - return only one component
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * used from iosetup to expand redirection files
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruevalonestr(const char *cp, int f)
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV w;
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *rv;
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(w, 1);
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	expand(cp, &w, f);
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (XPsize(w)) {
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 0:
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = null;
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 1:
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = (char *) *XPptrv(w);
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
19577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		rv = evalstr(cp, f & ~DOGLOB);
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPfree(w);
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* for nested substitution: ${var:=$var2} */
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querutypedef struct SubType {
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *var;	/* variable for ${var..} */
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct SubType *prev;	/* old type */
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct SubType *next;	/* poped type (to avoid re-allocating) */
207966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes	size_t	base;		/* start position of expanded word */
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short	stype;		/* [=+-?%#] action after expanded word */
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short	f;		/* saved value of f (DOPAT, etc) */
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint8_t	quotep;		/* saved value of quote (for ${..[%#]..}) */
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint8_t	quotew;		/* saved value of quote (for ${..[+-=]..}) */
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} SubType;
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
215811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserexpand(
216811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    /* input word */
217811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    const char *ccp,
218811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    /* output words */
219811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    XPtrV *wp,
220811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    /* DO* flags */
221811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser    int f)
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c = 0;
224811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* expansion type */
225811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	int type;
226811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* quoted */
227811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	int quote = 0;
228811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* destination string and live pointer */
229811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	XString ds;
230811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	char *dp;
231811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* source */
232811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	const char *sp;
233811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* second pass flags */
234811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	int fdo;
235811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* have word */
236811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	int word;
237811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* field splitting of parameter/command substitution */
238811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	int doblank;
239811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* expansion variables */
24003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Expand x = {
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		NULL, { NULL }, NULL, 0
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	};
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	SubType st_head, *st;
244811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* record number of trailing newlines in COMSUB */
24503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int newlines = 0;
246c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool saw_eq, make_magic;
24750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	unsigned int tilde_ok;
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t len;
249811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	char *cp;
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
251811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (ccp == NULL)
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		internal_errorf("expand(NULL)");
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* for alias, readonly, set, typeset commands */
254811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
25556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE);
25650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		f |= DOASNTILDE | DOSCALAR;
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FNOGLOB))
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		f &= ~DOGLOB;
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FMARKDIRS))
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		f |= DOMARKDIRS;
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FBRACEEXPAND) && (f & DOGLOB))
26303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		f |= DOBRACE;
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* init destination string */
26603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Xinit(ds, dp, 128, ATEMP);
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	type = XBASE;
268811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	sp = ccp;
2695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	fdo = 0;
270c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	saw_eq = false;
27103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* must be 1/0 */
27256b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes	tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	doblank = 0;
274c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	make_magic = false;
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* clang doesn't know OSUBST comes before CSUBST */
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	memset(&st_head, 0, sizeof(st_head));
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	st = &st_head;
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
28003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Xcheck(ds, dp);
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (type) {
28403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case XBASE:
28503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* original prefixed string */
28623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			c = ord(*sp++);
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (c) {
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case EOS:
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = 0;
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case CHAR:
29223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				c = ord(*sp++);
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case QCHAR:
29503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* temporary quote */
29603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				quote |= 2;
29723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				c = ord(*sp++);
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case OQUOTE:
30096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (word != IFS_WORD)
30150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					word = IFS_QUOTE;
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tilde_ok = 0;
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quote = 1;
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case CQUOTE:
30696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (word == IFS_QUOTE)
30796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					word = IFS_WORD;
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quote = st->quotew;
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
310a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes			case COMASUB:
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case COMSUB:
312a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes			case FUNASUB:
313c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case FUNSUB:
314811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			case VALSUB:
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tilde_ok = 0;
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (f & DONTRUNCOMMAND) {
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					word = IFS_WORD;
318c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					*dp++ = '$';
319a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					switch (c) {
320a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					case COMASUB:
321a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					case COMSUB:
322a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						*dp++ = '(';
323dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						c = ORD(')');
324a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						break;
325a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					case FUNASUB:
326a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					case FUNSUB:
327a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					case VALSUB:
328a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						*dp++ = '{';
329a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						*dp++ = c == VALSUB ? '|' : ' ';
330dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						c = ORD('}');
331a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						break;
332a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					}
3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					while (*sp != '\0') {
3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						Xcheck(ds, dp);
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*dp++ = *sp++;
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
337dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					if ((unsigned int)c == ORD('}'))
338c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						*dp++ = ';';
339a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					*dp++ = c;
3405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else {
341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					type = comsub(&x, sp, c);
342811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					if (type != XBASE && (f & DOBLANK))
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						doblank++;
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					sp = strnul(sp) + 1;
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					newlines = 0;
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
3485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case EXPRSUB:
3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tilde_ok = 0;
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (f & DONTRUNCOMMAND) {
351737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					word = IFS_WORD;
3525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*dp++ = '$'; *dp++ = '('; *dp++ = '(';
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					while (*sp != '\0') {
3545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						Xcheck(ds, dp);
3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*dp++ = *sp++;
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*dp++ = ')'; *dp++ = ')';
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else {
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					struct tbl v;
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					v.flag = DEFINED|ISSET|INTEGER;
36203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* not default */
36303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					v.type = 10;
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					v.name[0] = '\0';
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					v_evaluate(&v, substitute(sp, 0),
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    KSH_UNWIND_ERROR, true);
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					sp = strnul(sp) + 1;
368737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					x.str = str_val(&v);
369737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					type = XSUB;
370737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (f & DOBLANK)
371737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes						doblank++;
3725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
37403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case OSUBST: {
37503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* ${{#}var{:}[=+-?#%]word} */
37603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*-
37703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * format is:
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	OSUBST [{x] plain-variable-part \0
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	    compiled-word-part CSUBST [}x]
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * This is where all syntax checking gets done...
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
38203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* skip the { or x (}) */
38303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				const char *varname = ++sp;
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				int stype;
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				int slen = 0;
3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
38703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* skip variable */
38803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				sp = cstrchr(sp, '\0') + 1;
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				type = varsub(&x, varname, sp, &stype, &slen);
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (type < 0) {
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					char *beg, *end, *str;
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unwind_substsyn:
39303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* restore sp */
39403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					sp = varname - 2;
39577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					beg = wdcopy(sp, ATEMP);
39677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					end = (wdscan(cstrchr(sp, '\0') + 1,
39777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					    CSUBST) - sp) + beg;
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* ({) the } or x is already skipped */
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (end < wdscan(beg, EOS))
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*end = EOS;
40177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					str = snptreef(NULL, 64, Tf_S, beg);
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					afree(beg, ATEMP);
40377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					errorf(Tf_sD_s, str, Tbadsubst);
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (f & DOBLANK)
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					doblank++;
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tilde_ok = 0;
40850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				if (word == IFS_QUOTE && type != XNULLSUB)
40950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					word = IFS_WORD;
41003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (type == XBASE) {
41103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* expand? */
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (!st->next) {
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						SubType *newst;
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						newst = alloc(sizeof(SubType), ATEMP);
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						newst->next = NULL;
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						newst->prev = st;
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						st->next = newst;
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st = st->next;
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st->stype = stype;
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st->base = Xsavepos(ds, dp);
4235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st->f = f;
42477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					if (x.var == vtemp) {
42577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						st->var = tempvar(vtemp->name);
426c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						st->var->flag &= ~INTEGER;
427c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						/* can't fail here */
428c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						setstr(st->var,
429c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						    str_val(x.var),
430c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						    KSH_RETURN_ERROR | 0x4);
431c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					} else
432c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						st->var = x.var;
433c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st->quotew = st->quotep = quote;
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* skip qualifier(s) */
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (stype)
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						sp += slen;
43823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes					switch (stype & STYPE_SINGLE) {
439dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('#') | STYPE_AT:
44003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						x.str = shf_smprintf("%08X",
441737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes						    (unsigned int)hash(str_val(st->var)));
442c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						break;
443dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('Q') | STYPE_AT: {
444c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						struct shf shf;
445c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
446c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
447c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						print_value_quoted(&shf, str_val(st->var));
448c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						x.str = shf_sclose(&shf);
44903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						break;
45056b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					    }
451dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('0'): {
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						char *beg, *mid, *end, *stg;
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						mksh_ari_t from = 0, num = -1, flen, finc = 0;
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						beg = wdcopy(sp, ATEMP);
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						mid = beg + (wdscan(sp, ADELIM) - sp);
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						stg = beg + (wdscan(sp, CSUBST) - sp);
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						mid[-2] = EOS;
459dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if (ord(mid[-1]) == ORD(/*{*/ '}')) {
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							sp += mid - beg - 1;
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							end = NULL;
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						} else {
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							end = mid +
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							    (wdscan(mid, ADELIM) - mid);
465dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes							if (ord(end[-1]) != ORD(/*{*/ '}'))
466fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes								/* more than max delimiters */
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								goto unwind_substsyn;
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							end[-2] = EOS;
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							sp += end - beg - 1;
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						}
47103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						evaluate(substitute(stg = wdstrip(beg, 0), 0),
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						    &from, KSH_UNWIND_ERROR, true);
4735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(stg, ATEMP);
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (end) {
47503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra							evaluate(substitute(stg = wdstrip(mid, 0), 0),
4765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							    &num, KSH_UNWIND_ERROR, true);
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							afree(stg, ATEMP);
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						}
4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(beg, ATEMP);
4805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						beg = str_val(st->var);
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						flen = utflen(beg);
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (from < 0) {
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							if (-from < flen)
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								finc = flen + from;
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						} else
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							finc = from < flen ? from : flen;
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (UTFMODE)
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							utfincptr(beg, &finc);
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						beg += finc;
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						flen = utflen(beg);
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (num < 0 || num > flen)
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							num = flen;
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (UTFMODE)
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							utfincptr(beg, &num);
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						strndupx(x.str, beg, num, ATEMP);
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						goto do_CSUBST;
49756b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					    }
498dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('/') | STYPE_AT:
499dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('/'): {
5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						char *s, *p, *d, *sbeg, *end;
50177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						char *pat = NULL, *rrep = null;
502fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						char fpat = 0, *tpat1, *tpat2;
50377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						char *ws, *wpat, *wrep;
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
50577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						s = ws = wdcopy(sp, ATEMP);
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						p = s + (wdscan(sp, ADELIM) - sp);
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						d = s + (wdscan(sp, CSUBST) - sp);
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						p[-2] = EOS;
509dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if (ord(p[-1]) == ORD(/*{*/ '}'))
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							d = NULL;
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						else
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							d[-2] = EOS;
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						sp += (d ? d : p) - s - 1;
51423925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						if (!(stype & STYPE_MASK) &&
515fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						    s[0] == CHAR &&
51623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						    ctype(s[1], C_SUB2))
517fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							fpat = s[1];
51877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						wpat = s + (fpat ? 2 : 0);
51977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						wrep = d ? p : NULL;
52023925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						if (!(stype & STYPE_AT)) {
52177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							rrep = wrep ? evalstr(wrep,
52277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							    DOTILDE | DOSCALAR) :
52377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							    null;
52477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						}
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
52677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						/* prepare string on which to work */
52777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						strdupx(s, str_val(st->var), ATEMP);
52877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						sbeg = s;
52977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes again_search:
53077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						pat = evalstr(wpat,
53177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						    DOTILDE | DOSCALAR | DOPAT);
53203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/* check for special cases */
533fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						if (!*pat && !fpat) {
534fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							/*
535fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							 * empty unanchored
536fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							 * pattern => reject
537fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							 */
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							goto no_repl;
53903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						}
54023925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						if ((stype & STYPE_MASK) &&
541fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						    gmatchx(null, pat, false)) {
54203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra							/*
54396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes							 * pattern matches empty
54496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes							 * string => don't loop
54503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra							 */
54623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes							stype &= ~STYPE_MASK;
54703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						}
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* first see if we have any match at all */
550dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if (ord(fpat) == ORD('#')) {
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							/* anchor at the beginning */
552fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							tpat1 = shf_smprintf("%s%c*", pat, MAGIC);
5535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							tpat2 = tpat1;
554dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						} else if (ord(fpat) == ORD('%')) {
5555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							/* anchor at the end */
556fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							tpat1 = shf_smprintf("%c*%s", MAGIC, pat);
557fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							tpat2 = pat;
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						} else {
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							/* float */
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC);
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							tpat2 = tpat1 + 2;
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						}
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru again_repl:
56403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/*
56503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 * this would not be necessary if gmatchx would return
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * the start and end values of a match found, like re*
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 */
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (!gmatchx(sbeg, tpat1, false))
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							goto end_repl;
5705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						end = strnul(s);
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* now anchor the beginning of the match */
572dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if (ord(fpat) != ORD('#'))
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							while (sbeg <= end) {
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								if (gmatchx(sbeg, tpat2, false))
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru									break;
5765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								else
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru									sbeg++;
5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							}
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* now anchor the end of the match */
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						p = end;
581dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if (ord(fpat) != ORD('%'))
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							while (p >= sbeg) {
5835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								bool gotmatch;
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
585dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes								c = ord(*p);
58603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra								*p = '\0';
587fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes								gotmatch = tobool(gmatchx(sbeg, pat, false));
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								*p = c;
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								if (gotmatch)
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru									break;
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								p--;
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							}
59377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						strndupx(end, sbeg, p - sbeg, ATEMP);
59477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						record_match(end);
59577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						afree(end, ATEMP);
59623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						if (stype & STYPE_AT) {
59777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							if (rrep != null)
59877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes								afree(rrep, ATEMP);
59977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							rrep = wrep ? evalstr(wrep,
60077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							    DOTILDE | DOSCALAR) :
60177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							    null;
60277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						}
6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						strndupx(end, s, sbeg - s, ATEMP);
60477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						d = shf_smprintf(Tf_sss, end, rrep, p);
6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(end, ATEMP);
6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						sbeg = d + (sbeg - s) + strlen(rrep);
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(s, ATEMP);
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						s = d;
60923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						if (stype & STYPE_AT) {
61077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							afree(tpat1, ATEMP);
61177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							afree(pat, ATEMP);
61277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes							goto again_search;
61323925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						} else if (stype & STYPE_DBL)
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							goto again_repl;
6155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru end_repl:
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(tpat1, ATEMP);
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						x.str = s;
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru no_repl:
6195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						afree(pat, ATEMP);
6205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (rrep != null)
6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							afree(rrep, ATEMP);
62277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes						afree(ws, ATEMP);
6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						goto do_CSUBST;
62456b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					    }
625dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('#'):
626dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('%'):
627fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						/* ! DOBLANK,DOBRACE */
628c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						f = (f & DONTRUNCOMMAND) |
629fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						    DOPAT | DOTILDE |
630fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						    DOTEMP | DOSCALAR;
631fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						tilde_ok = 1;
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						st->quotew = quote = 0;
63303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/*
63403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 * Prepend open pattern (so |
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * in a trim will work as
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * expected)
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 */
63803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						if (!Flag(FSH)) {
63903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra							*dp++ = MAGIC;
640dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes							*dp++ = ORD(0x80 | '@');
64103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						}
6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						break;
643dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('='):
64403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/*
645a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * Tilde expansion for string
646a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * variables in POSIX mode is
647a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * governed by Austinbug 351.
648a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * In non-POSIX mode historic
649a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * ksh behaviour (enable it!)
650a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						 * us followed.
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * Not doing tilde expansion
6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * for integer variables is a
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * non-POSIX thing - makes
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * sense though, since ~ is
6555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * a arithmetic operator.
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 */
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (!(x.var->flag & INTEGER))
65856b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes							f |= DOASNTILDE | DOTILDE;
659a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						f |= DOTEMP | DOSCALAR;
66003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/*
66103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 * These will be done after the
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * value has been assigned.
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 */
66403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						f &= ~(DOBLANK|DOGLOB|DOBRACE);
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						tilde_ok = 1;
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						break;
667dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					case ORD('?'):
668fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes						if (*sp == CSUBST)
669fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							errorf("%s: parameter null or not set",
670fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes							    st->var->name);
6715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						f &= ~DOBLANK;
67203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						f |= DOTEMP;
6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* FALLTHROUGH */
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					default:
67550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						/* '-' '+' '?' */
67650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						if (quote)
67750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes							word = IFS_WORD;
67850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						else if (dp == Xstring(ds, dp))
67950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes							word = IFS_IWS;
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* Enable tilde expansion */
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						tilde_ok = 1;
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						f |= DOTILDE;
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
6845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* skip word */
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					sp += wdscan(sp, CSUBST) - sp;
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
68856b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			    }
68903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case CSUBST:
69003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* only get here if expanding word */
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru do_CSUBST:
69203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* ({) skip the } or x */
69303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				sp++;
69403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* in case of ${unset:-} */
69503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tilde_ok = 0;
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*dp = '\0';
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quote = st->quotep;
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				f = st->f;
699737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes				if (f & DOBLANK)
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					doblank--;
70123925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				switch (st->stype & STYPE_SINGLE) {
702dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('#'):
703dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('%'):
70403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					if (!Flag(FSH)) {
70503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/* Append end-pattern */
70603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						*dp++ = MAGIC;
70703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						*dp++ = ')';
70803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					}
70903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					*dp = '\0';
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					dp = Xrestpos(ds, dp, st->base);
71103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
71203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * Must use st->var since calling
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * global would break things
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * like x[i+=1].
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					x.str = trimsub(str_val(st->var),
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						dp, st->stype);
718737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (x.str[0] != '\0') {
71950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						word = IFS_IWS;
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						type = XSUB;
72150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					} else if (quote) {
72250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						word = IFS_WORD;
72350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						type = XSUB;
72450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					} else {
72550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						if (dp == Xstring(ds, dp))
72650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes							word = IFS_IWS;
72750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						type = XNULLSUB;
72850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					}
729737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (f & DOBLANK)
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						doblank++;
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st = st->prev;
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					continue;
733dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('='):
73403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
73503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * Restore our position and substitute
7365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * the value of st->var (may not be
7375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * the assigned value in the presence
7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * of integer/right-adj/etc attributes).
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
7405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					dp = Xrestpos(ds, dp, st->base);
74103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
74203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * Must use st->var since calling
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * global would cause with things
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * like x[i+=1] to be evaluated twice.
7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
74603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
74703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * Note: not exported by FEXPORT
7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * in AT&T ksh.
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
75003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
75103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * XXX POSIX says readonly is only
7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * fatal for special builtins (setstr
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * does readonly check).
7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					len = strlen(dp) + 1;
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					setstr(st->var,
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    debunk(alloc(len, ATEMP),
7585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    dp, len), KSH_UNWIND_ERROR);
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					x.str = str_val(st->var);
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					type = XSUB;
761737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (f & DOBLANK)
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						doblank++;
7635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st = st->prev;
76450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
7655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					continue;
766dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('?'):
767fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					dp = Xrestpos(ds, dp, st->base);
7685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
76977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					errorf(Tf_sD_s, st->var->name,
770fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					    debunk(dp, dp, strlen(dp) + 1));
771fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					break;
772dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('0'):
773dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('/') | STYPE_AT:
774dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('/'):
775dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('#') | STYPE_AT:
776dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('Q') | STYPE_AT:
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					dp = Xrestpos(ds, dp, st->base);
7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					type = XSUB;
77950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
780737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (f & DOBLANK)
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						doblank++;
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					st = st->prev;
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					continue;
78450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				/* default: '-' '+' */
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				st = st->prev;
7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				type = XBASE;
7885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
7895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
79003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case OPAT:
79103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* open pattern: *(foo|bar) */
7925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* Next char is the type of pattern */
793c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				make_magic = true;
794dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				c = ord(*sp++) | 0x80U;
7955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
79703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case SPAT:
79803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* pattern separator (|) */
799c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				make_magic = true;
800dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				c = ORD('|');
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
8025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
80303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case CPAT:
80403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* close pattern */
805c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				make_magic = true;
806dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				c = ORD(/*(*/ ')');
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XNULLSUB:
81203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
81303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * Special case for "$@" (and "${foo[@]}") - no
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * word is generated if $# is 0 (unless there is
8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * other stuff inside the quotes).
8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type = XBASE;
818737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			if (f & DOBLANK) {
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				doblank--;
82050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				if (dp == Xstring(ds, dp) && word != IFS_WORD)
82150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					word = IFS_IWS;
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XSUB:
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XSUBMID:
827dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if ((c = ord(*x.str++)) == 0) {
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				type = XBASE;
829737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes				if (f & DOBLANK)
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					doblank--;
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XARGSEP:
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type = XARG;
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quote = 1;
838c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XARG:
840dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if ((c = ord(*x.str++)) == '\0') {
84103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
84203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * force null words to be created so
84356b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				 * set -- "" 2 ""; echo "$@" will do
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * the right thing
8455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
8465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (quote && x.split)
8475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					word = IFS_WORD;
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((x.str = *x.u.strv++) == NULL) {
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					type = XBASE;
850737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes					if (f & DOBLANK)
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						doblank--;
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					continue;
8535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
85423925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				c = ord(ifs0);
85550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				if ((f & DOHEREDOC)) {
85650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					/* pseudo-field-split reliably */
85750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					if (c == 0)
858dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						c = ORD(' ');
85950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					break;
86050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				}
86150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				if ((f & DOSCALAR)) {
86250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					/* do not field-split */
86356b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					if (x.split) {
864dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						c = ORD(' ');
86556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes						break;
86656b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					}
86750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					if (c == 0)
86856b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes						continue;
86956b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				}
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (c == 0) {
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (quote && !x.split)
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						continue;
87356b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					if (!quote && word == IFS_WS)
87456b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes						continue;
875811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					/* this is so we don't terminate */
876dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					c = ORD(' ');
877811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					/* now force-emit a word */
878811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					goto emit_word;
8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (quote && x.split) {
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* terminate word for "$@" */
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					type = XARGSEP;
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					quote = 0;
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case XCOM:
889811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (x.u.shf == NULL) {
890811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				/* $(<...) failed */
891811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				subst_exstat = 1;
892811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				/* fake EOF */
89350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				c = -1;
894811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			} else if (newlines) {
895811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				/* spit out saved NLs */
896dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				c = ORD('\n');
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--newlines;
8985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else {
899a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes				while ((c = shf_getc(x.u.shf)) == 0 ||
900dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				    cinttype(c, C_NL)) {
901a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes#ifdef MKSH_WITH_TEXTMODE
902dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					if (c == ORD('\r')) {
903a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						c = shf_getc(x.u.shf);
904a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						switch (c) {
905dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						case ORD('\n'):
906a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes							break;
907a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						default:
908a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes							shf_ungetc(c, x.u.shf);
909a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes							/* FALLTHROUGH */
910a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						case -1:
911dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes							c = ORD('\r');
912a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes							break;
913a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes						}
914a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes					}
915a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes#endif
916dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					if (c == ORD('\n'))
917811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						/* save newlines */
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						newlines++;
919a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes				}
92050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				if (newlines && c != -1) {
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					shf_ungetc(c, x.u.shf);
922dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					c = ORD('\n');
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					--newlines;
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
92650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (c == -1) {
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				newlines = 0;
928811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				if (x.u.shf)
929811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					shf_close(x.u.shf);
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (x.split)
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					subst_exstat = waitlast();
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				type = XBASE;
933737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes				if (f & DOBLANK)
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					doblank--;
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* check for end of word or IFS separation */
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == 0 || (!quote && (f & DOBLANK) && doblank &&
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    !make_magic && ctype(c, C_IFS))) {
94303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*-
94403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * How words are broken up:
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *			|	value of c
9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	word		|	ws	nws	0
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	-----------------------------------
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	IFS_WORD		w/WS	w/NWS	w
94956b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			 *	IFS_WS			-/WS	-/NWS	-
95056b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			 *	IFS_NWS			-/NWS	w/NWS	-
951f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes			 *	IFS_IWS			-/WS	w/NWS	-
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * (w means generate a word)
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
95450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
955f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes			    (word == IFS_IWS || word == IFS_NWS) &&
956f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes			    !ctype(c, C_IFSWS))) {
957811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser emit_word:
958fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				if (f & DOHERESTR)
959fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					*dp++ = '\n';
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*dp++ = '\0';
961811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				cp = Xclose(ds, dp);
96203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (fdo & DOBRACE)
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* also does globbing */
964811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					alt_expand(wp, cp, cp,
965811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					    cp + Xlength(ds, (dp - 1)),
9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    fdo | (f & DOMARKDIRS));
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if (fdo & DOGLOB)
968811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					glob(cp, wp, tobool(f & DOMARKDIRS));
96903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				else if ((f & DOPAT) || !(fdo & DOMAGIC))
970811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					XPput(*wp, cp);
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else
972811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					XPput(*wp, debunk(cp, cp,
973811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					    strlen(cp) + 1));
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				fdo = 0;
975c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				saw_eq = false;
97656b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				/* must be 1/0 */
97756b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
978c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (c == 0)
979c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					return;
980c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				Xinit(ds, dp, 128, ATEMP);
981c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			} else if (c == 0) {
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return;
983c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			} else if (type == XSUB && ctype(c, C_IFS) &&
984c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
985811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				*(cp = alloc(1, ATEMP)) = '\0';
986811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				XPput(*wp, cp);
987c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				type = XSUBMID;
988c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (word != IFS_NWS)
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (type == XSUB) {
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (word == IFS_NWS &&
9945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    Xlength(ds, dp) == 0) {
995811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					*(cp = alloc(1, ATEMP)) = '\0';
996811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser					XPput(*wp, cp);
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				type = XSUBMID;
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* age tilde_ok info - ~ code tests second bit */
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tilde_ok <<= 1;
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* mark any special second pass chars */
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!quote)
100523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				switch (ord(c)) {
1006dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('['):
1007dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('!'):
1008dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('-'):
1009dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD(']'):
101003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
101103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * For character classes - doesn't hurt
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * to have magic !,-,]s outside of
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * [...] expressions.
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (f & (DOPAT | DOGLOB)) {
101603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						fdo |= DOMAGIC;
1017dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes						if ((unsigned int)c == ORD('['))
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							fdo |= f & DOGLOB;
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*dp++ = MAGIC;
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
1022dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('*'):
1023dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('?'):
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (f & (DOPAT | DOGLOB)) {
102503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						fdo |= DOMAGIC | (f & DOGLOB);
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*dp++ = MAGIC;
10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
1029dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('{'):
1030dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('}'):
1031dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD(','):
103223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes					if ((f & DOBRACE) &&
1033dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes					    (ord(c) == ORD('{' /*}*/) ||
103403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    (fdo & DOBRACE))) {
103503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						fdo |= DOBRACE|DOMAGIC;
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*dp++ = MAGIC;
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
1039dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('='):
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* Note first unquoted = for ~ */
1041fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					if (!(f & DOTEMP) && (!Flag(FPOSIX) ||
1042fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes					    (f & DOASNTILDE)) && !saw_eq) {
1043c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						saw_eq = true;
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						tilde_ok = 1;
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
1047dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD(':'):
104803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* : */
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* Note unquoted : for ~ */
105003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					if (!(f & DOTEMP) && (f & DOASNTILDE))
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						tilde_ok = 1;
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
1053dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				case ORD('~'):
105403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
105503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * tilde_ok is reset whenever
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * any of ' " $( $(( ${ } are seen.
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * Note that tilde_ok must be preserved
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * through the sequence ${A=a=}~
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (type == XBASE &&
106156b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					    (f & (DOTILDE | DOASNTILDE)) &&
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    (tilde_ok & 2)) {
1063811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						const char *tcp;
1064811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						char *tdp = dp;
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1066811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						tcp = maybe_expand_tilde(sp,
1067811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						    &ds, &tdp,
106850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes						    tobool(f & DOASNTILDE));
1069811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser						if (tcp) {
1070811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser							if (dp != tdp)
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru								word = IFS_WORD;
1072811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser							dp = tdp;
1073811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser							sp = tcp;
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							continue;
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						}
10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
10785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
10795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
108003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* undo temporary */
108103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				quote &= ~2;
10825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (make_magic) {
1084c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				make_magic = false;
108503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				fdo |= DOMAGIC | (f & DOGLOB);
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*dp++ = MAGIC;
10875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (ISMAGIC(c)) {
108803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				fdo |= DOMAGIC;
10895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*dp++ = MAGIC;
10905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* save output char */
109203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp++ = c;
10935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			word = IFS_WORD;
10945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1098fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughesstatic bool
1099fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hugheshasnonempty(const char **strv)
1100fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes{
1101fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	size_t i = 0;
1102fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes
1103fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	while (strv[i])
1104fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		if (*strv[i++])
1105fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			return (true);
1106fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	return (false);
1107fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes}
1108fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes
11095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Prepare to generate the string returned by ${} substitution.
11115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
11135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvarsub(Expand *xp, const char *sp, const char *word,
11145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    int *stypep,	/* becomes qualifier type */
11155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    int *slenp)		/* " " len (=, :=, etc.) valid iff *stypep != 0 */
11165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int state;	/* next state: XBASE, XARG, XSUB, XNULLSUB */
11195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int stype;	/* substitution type */
112077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	int slen = 0;
11215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
11225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp;
11235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool zero_ok = false;
11245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
112523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	if ((stype = ord(sp[0])) == '\0')
112603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Bad variable name */
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
11285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	xp->var = NULL;
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*-
11325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * ${#var}, string length (-U: characters, +U: octets) or array size
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * ${%var}, string width (-U: screen columns, +U: octets)
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
113523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	c = ord(sp[1]);
1136dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	if ((unsigned int)stype == ORD('%') && c == '\0')
11375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
113823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	if (ctype(stype, C_SUB2) && c != '\0') {
11395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Can't have any modifiers for ${#...} or ${%...} */
11405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*word != CSUBST)
11415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sp++;
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Check for size of array */
1144dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ORD('*') ||
1145dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		    ord(p[1]) == ORD('@')) && ord(p[2]) == ORD(']')) {
11465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			int n = 0;
11475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1148dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if ((unsigned int)stype != ORD('#'))
11495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (-1);
11505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp = global(arrayname(sp));
11515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (vp->flag & (ISSET|ARRAY))
11525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				zero_ok = true;
11535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (; vp; vp = vp->u.array)
11545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (vp->flag & ISSET)
11555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					n++;
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = n;
1157dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		} else if ((unsigned int)c == ORD('*') ||
1158dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		    (unsigned int)c == ORD('@')) {
1159dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if ((unsigned int)stype != ORD('#'))
11605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (-1);
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = e->loc->argc;
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = str_val(global(sp));
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			zero_ok = p != null;
1165dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if ((unsigned int)stype == ORD('#'))
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = utflen(p);
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* partial utf_mbswidth reimplementation */
11695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				const char *s = p;
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unsigned int wc;
11715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				size_t len;
11725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				int cw;
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = 0;
11755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while (*s) {
11765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (!UTFMODE || (len = utf_mbtowc(&wc,
11775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    s)) == (size_t)-1)
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* not UTFMODE or not UTF-8 */
117923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes						wc = rtt2asc(*s++);
11805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					else
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* UTFMODE and UTF-8 */
11825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						s += len;
11835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* wc == char or wchar at s++ */
11845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if ((cw = utf_wcwidth(wc)) == -1) {
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/* 646, 8859-1, 10646 C0/C1 */
11865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						c = -1;
11875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						break;
11885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
11895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					c += cw;
11905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
11915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FNOUNSET) && c == 0 && !zero_ok)
119477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			errorf(Tf_parm, sp);
119503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* unqualified variable/string substitution */
119603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*stypep = 0;
119777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		xp->str = shf_smprintf(Tf_d, c);
119877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		return (XSUB);
119977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	}
1200dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	if ((unsigned int)stype == ORD('!') && c != '\0' && *word == CSUBST) {
120177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		sp++;
1202dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ORD('*') ||
1203dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		    ord(p[1]) == ORD('@')) && ord(p[2]) == ORD(']')) {
1204dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			c = ORD('!');
120577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			stype = 0;
120677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			goto arraynames;
120777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		}
120877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		xp->var = global(sp);
120977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		xp->str = p ? shf_smprintf("%s[%lu]",
121077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		    xp->var->name, arrayindex(xp->var)) : xp->var->name;
121177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		*stypep = 0;
12125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (XSUB);
12135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Check for qualifiers in word part */
12165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	stype = 0;
121723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	c = word[slen + 0] == CHAR ? ord(word[slen + 1]) : 0;
1218dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	if ((unsigned int)c == ORD(':')) {
12195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		slen += 2;
122023925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		stype = STYPE_DBL;
122123925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		c = word[slen + 0] == CHAR ? ord(word[slen + 1]) : 0;
12225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1223dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	if (!stype && (unsigned int)c == ORD('/')) {
12245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		slen += 2;
12255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		stype = c;
122623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		if (word[slen] == ADELIM &&
122723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		    ord(word[slen + 1]) == (unsigned int)c) {
12285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			slen += 2;
122923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			stype |= STYPE_DBL;
12305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1231dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	} else if (stype == STYPE_DBL && ((unsigned int)c == ORD(' ') ||
1232dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (unsigned int)c == ORD('0'))) {
1233dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		stype |= ORD('0');
123423925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	} else if (ctype(c, C_SUB1)) {
12355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		slen += 2;
12365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		stype |= c;
123723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	} else if (ctype(c, C_SUB2)) {
123803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Note: ksh88 allows :%, :%%, etc */
12395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		slen += 2;
12405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		stype = c;
124123925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		if (word[slen + 0] == CHAR &&
124223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		    ord(word[slen + 1]) == (unsigned int)c) {
124323925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			stype |= STYPE_DBL;
12445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			slen += 2;
12455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1246dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	} else if ((unsigned int)c == ORD('@')) {
124703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* @x where x is command char */
124823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		switch (c = ord(word[slen + 2]) == CHAR ?
124923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		    ord(word[slen + 3]) : 0) {
1250dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('#'):
1251dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('/'):
1252dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('Q'):
1253a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes			break;
1254a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		default:
1255a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes			return (-1);
125603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
125723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		stype |= STYPE_AT | c;
1258a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		slen += 4;
125903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else if (stype)
126003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* : is not ok */
12615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
12625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!stype && *word != CSUBST)
12635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
12645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
126523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	c = ord(sp[0]);
1266dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	if ((unsigned int)c == ORD('*') || (unsigned int)c == ORD('@')) {
126723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		switch (stype & STYPE_SINGLE) {
1268811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* can't assign to a vector */
1269dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('='):
1270811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* can't trim a vector (yet) */
1271dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('%'):
1272dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('#'):
1273dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('?'):
1274dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('0'):
1275dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('/') | STYPE_AT:
1276dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('/'):
1277dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('#') | STYPE_AT:
1278dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('Q') | STYPE_AT:
12795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
12805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
12815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (e->loc->argc == 0) {
12825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp->str = null;
12835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp->var = global(sp);
1284dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			state = (unsigned int)c == ORD('@') ? XNULLSUB : XSUB;
12855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
12865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp->u.strv = (const char **)e->loc->argv + 1;
12875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp->str = *xp->u.strv++;
1288c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* $@ */
1289dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			xp->split = tobool((unsigned int)c == ORD('@'));
12905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			state = XARG;
12915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
129203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* POSIX 2009? */
129303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		zero_ok = true;
1294dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	} else if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ORD('*') ||
1295dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    ord(p[1]) == ORD('@')) && ord(p[2]) == ORD(']')) {
129677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		XPtrV wv;
129777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes
129823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		switch (stype & STYPE_SINGLE) {
129977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		/* can't assign to a vector */
1300dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('='):
130177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		/* can't trim a vector (yet) */
1302dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('%'):
1303dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('#'):
1304dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('?'):
1305dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('0'):
1306dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('/') | STYPE_AT:
1307dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('/'):
1308dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('#') | STYPE_AT:
1309dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		case ORD('Q') | STYPE_AT:
131077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			return (-1);
131177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		}
131277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		c = 0;
131377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes arraynames:
131477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		XPinit(wv, 32);
131577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		vp = global(arrayname(sp));
131677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		for (; vp; vp = vp->u.array) {
131777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			if (!(vp->flag&ISSET))
131877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				continue;
1319dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			XPput(wv, (unsigned int)c == ORD('!') ?
1320dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			    shf_smprintf(Tf_lu, arrayindex(vp)) :
132177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			    str_val(vp));
132277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		}
132377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		if (XPsize(wv) == 0) {
132477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			xp->str = null;
1325dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			state = ord(p[1]) == ORD('@') ? XNULLSUB : XSUB;
132677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			XPfree(wv);
13275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
132877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			XPput(wv, 0);
132977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			xp->u.strv = (const char **)XPptrv(wv);
133077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			xp->str = *xp->u.strv++;
133177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			/* ${foo[@]} */
1332dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			xp->split = tobool(ord(p[1]) == ORD('@'));
133377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			state = XARG;
13345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
133577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	} else {
133677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		xp->var = global(sp);
133777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		xp->str = str_val(xp->var);
133877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		/* can't assign things like $! or $1 */
1339dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		if ((unsigned int)(stype & STYPE_SINGLE) == ORD('=') &&
1340dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes		    !*xp->str && ctype(*sp, C_VAR1 | C_DIGIT))
134177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			return (-1);
134277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		state = XSUB;
13435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
134523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	c = stype & STYPE_CHAR;
13465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* test the compiler's code generator */
134723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	if ((!(stype & STYPE_AT) && (ctype(c, C_SUB2) ||
134823925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	    (((stype & STYPE_DBL) ? *xp->str == '\0' : xp->str == null) &&
1349fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	    (state != XARG || (ifs0 || xp->split ?
1350fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	    (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
1351dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    ctype(c, C_EQUAL | C_MINUS | C_QUEST) : (unsigned int)c == ORD('+')))) ||
1352dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (unsigned int)stype == (ORD('0') | STYPE_DBL) ||
1353dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (unsigned int)stype == (ORD('#') | STYPE_AT) ||
1354dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (unsigned int)stype == (ORD('Q') | STYPE_AT) ||
1355dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (unsigned int)(stype & STYPE_CHAR) == ORD('/'))
135603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* expand word instead of variable value */
135703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		state = XBASE;
13585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
1359dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	    (ctype(c, C_SUB2) || (state != XBASE && (unsigned int)c != ORD('+'))))
136077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		errorf(Tf_parm, sp);
136177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	*stypep = stype;
136277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	*slenp = slen;
13635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (state);
13645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
13675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Run the command in $(...) and read its output.
13685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
13695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
1370a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughescomsub(Expand *xp, const char *cp, int fn)
13715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Source *s, *sold;
13735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
13745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct shf *shf;
1375a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	bool doalias = false;
137603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	uint8_t old_utfmode = UTFMODE;
13775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1378a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	switch (fn) {
1379a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	case COMASUB:
1380a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		fn = COMSUB;
1381a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		if (0)
1382a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes			/* FALLTHROUGH */
1383a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	case FUNASUB:
1384a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		  fn = FUNSUB;
1385a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes		doalias = true;
1386a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	}
1387a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes
13885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	s = pushs(SSTRING, ATEMP);
13895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	s->start = s->str = cp;
13905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sold = source;
1391a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	t = compile(s, true, doalias);
13925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(s, ATEMP);
13935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = sold;
13945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1395c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	UTFMODE = old_utfmode;
1396c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
13975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t == NULL)
13985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (XBASE);
13995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1400c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* no waitlast() unless specifically enabled later */
1401c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	xp->split = false;
1402c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1403c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (t->type == TCOM &&
14045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
140503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* $(<file) */
14065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct ioword *io = *t->ioact;
14075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *name;
14085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
140977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		switch (io->ioflag & IOTYPE) {
141077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		case IOREAD:
141177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			shf = shf_open(name = evalstr(io->ioname, DOTILDE),
141277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
141377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			if (shf == NULL)
141477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				warningf(!Flag(FTALKING), Tf_sD_s_sD_s,
141577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				    name, Tcant_open, "$(<...) input",
141677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				    cstrerror(errno));
141777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			break;
141877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		case IOHERE:
141977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			if (!herein(io, &name)) {
142077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				xp->str = name;
142177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				/* as $(…) requires, trim trailing newlines */
142223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				name = strnul(name);
142377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				while (name > xp->str && name[-1] == '\n')
142477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes					--name;
142577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				*name = '\0';
142677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				return (XSUB);
142777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			}
142877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			shf = NULL;
142977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			break;
143077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		default:
143177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			errorf(Tf_sD_s, T_funny_command,
143277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			    snptreef(NULL, 32, Tft_R, io));
143377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		}
1434c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else if (fn == FUNSUB) {
1435c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		int ofd1;
1436c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		struct temp *tf = NULL;
1437c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1438811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/*
1439811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		 * create a temporary file, open for reading and writing,
1440811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		 * with an shf open for reading (buffered) but yet unused
1441811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		 */
1442c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		maketemp(ATEMP, TT_FUNSUB, &tf);
1443c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!tf->shf) {
144477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			errorf(Tf_temp,
144577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes			    Tcreate, tf->tffn, cstrerror(errno));
1446c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
1447811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* extract shf from temporary file, unlink and free it */
1448811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		shf = tf->shf;
1449811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		unlink(tf->tffn);
1450811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		afree(tf, ATEMP);
1451811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* save stdout and let it point to the tempfile */
1452c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ofd1 = savefd(1);
1453811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		ksh_dup2(shf_fileno(shf), 1, false);
1454c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/*
1455c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * run tree, with output thrown into the tempfile,
1456c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * in a new function block
1457c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 */
1458811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		valsub(t, NULL);
1459c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subst_exstat = exstat & 0xFF;
1460811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* rewind the tempfile and restore regular stdout */
1461811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
1462c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		restfd(1, ofd1);
1463811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	} else if (fn == VALSUB) {
1464811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		xp->str = valsub(t, ATEMP);
1465811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		subst_exstat = exstat & 0xFF;
1466811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		return (XSUB);
14675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
14685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int ofd1, pv[2];
1469c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
14705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		openpipe(pv);
14715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf = shf_fdopen(pv[0], SHF_RD, NULL);
14725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ofd1 = savefd(1);
14735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (pv[1] != 1) {
14745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(pv[1], 1, false);
14755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			close(pv[1]);
14765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1477c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		execute(t, XXCOM | XPIPEO | XFORK, NULL);
14785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		restfd(1, ofd1);
14795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		startlast();
148003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* waitlast() */
1481c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		xp->split = true;
14825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	xp->u.shf = shf;
14855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (XCOM);
14865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
14895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * perform #pattern and %pattern substitution in ${}
14905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
14915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
14925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querutrimsub(char *str, char *pat, int how)
14935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *end = strnul(str);
14955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *p, c;
14965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
149723925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	switch (how & (STYPE_CHAR | STYPE_DBL)) {
1498dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	case ORD('#'):
149903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* shortest match at beginning */
15005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (p = str; p <= end; p += utf_ptradj(p)) {
15015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = *p; *p = '\0';
15025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (gmatchx(str, pat, false)) {
150377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				record_match(str);
15045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*p = c;
15055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (p);
15065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
15075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*p = c;
15085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1510dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	case ORD('#') | STYPE_DBL:
151103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* longest match at beginning */
15125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (p = end; p >= str; p--) {
15135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = *p; *p = '\0';
15145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (gmatchx(str, pat, false)) {
151577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				record_match(str);
15165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*p = c;
15175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (p);
15185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
15195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*p = c;
15205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1522dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	case ORD('%'):
152303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* shortest match at end */
15245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p = end;
15255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (p >= str) {
15265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (gmatchx(p, pat, false))
15275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto trimsub_match;
15285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (UTFMODE) {
15295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				char *op = p;
153023925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes				while ((p-- > str) && ((rtt2asc(*p) & 0xC0) == 0x80))
15315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					;
15325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((p < str) || (p + utf_ptradj(p) != op))
15335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					p = op - 1;
15345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
15355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--p;
15365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1538dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	case ORD('%') | STYPE_DBL:
153903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* longest match at end */
15405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (p = str; p <= end; p++)
15415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (gmatchx(p, pat, false)) {
15425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru trimsub_match:
154377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes				record_match(p);
15445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				strndupx(end, str, p - str, ATEMP);
15455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (end);
15465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
15475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
15485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
155003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* no match, return string */
155103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (str);
15525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
15555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * glob
15565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Name derived from V6's /etc/glob, the program that expanded filenames.
15575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
15585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* XXX cp not const 'cause slashes are temporarily replaced with NULs... */
15605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
1561c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserglob(char *cp, XPtrV *wp, bool markdirs)
15625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int oldsize = XPsize(*wp);
15645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (glob_str(cp, wp, markdirs) == 0)
15665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
15675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
15685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize,
156923925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		    sizeof(void *), ascpstrcmp);
15705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define GF_NONE		0
15735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define GF_EXCHECK	BIT(0)		/* do existence check on file */
15745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define GF_GLOBBED	BIT(1)		/* some globbing has been done */
15755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define GF_MARKDIR	BIT(2)		/* add trailing / to directories */
15765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
157703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
157803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Apply file globbing to cp and store the matching files in wp. Returns
15795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the number of matches found.
15805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
15815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
1582c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserglob_str(char *cp, XPtrV *wp, bool markdirs)
15835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int oldsize = XPsize(*wp);
15855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XString xs;
15865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp;
15875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xinit(xs, xp, 256, ATEMP);
15895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
15905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xfree(xs, xp);
15915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (XPsize(*wp) - oldsize);
15935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
15965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruglobit(XString *xs,	/* dest string */
15975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    char **xpp,		/* ptr to dest end */
15985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    char *sp,		/* source path */
15995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    XPtrV *wp,		/* output list */
16005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    int check)		/* GF_* flags */
16015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *np;		/* next source component */
16035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp = *xpp;
16045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *se;
16055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char odirsep;
16065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* This to allow long expansions to be interrupted */
16085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	intrcheck();
16095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
161003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (sp == NULL) {
161103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* end of source path */
161203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
161303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * We only need to check if the file exists if a pattern
16145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * is followed by a non-pattern (eg, foo*x/bar; no check
16155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * is needed for foo* since the match must exist) or if
16165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * any patterns were expanded and the markdirs option is set.
16175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * Symlinks make things a bit tricky...
16185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
16195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((check & GF_EXCHECK) ||
16205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
1621811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser#define stat_check()	(stat_done ? stat_done : (stat_done = \
1622811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			    stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
16235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct stat lstatb, statb;
1624811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			/* -1: failed, 1 ok, 0 not yet done */
1625811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			int stat_done = 0;
16265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1627c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
16285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return;
162903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
163003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * special case for systems which strip trailing
16315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * slashes from regular files (eg, /etc/passwd/).
16325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * SunOS 4.1.3 does this...
16335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
16345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) &&
1635966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes			    mksh_cdirsep(xp[-1]) && !S_ISDIR(lstatb.st_mode) &&
16365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (!S_ISLNK(lstatb.st_mode) ||
16375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    stat_check() < 0 || !S_ISDIR(statb.st_mode)))
16385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return;
163903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
164003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * Possibly tack on a trailing / if there isn't already
16415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * one and if the file is a directory or a symlink to a
16425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * directory
16435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
16445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) &&
1645966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes			    xp > Xstring(*xs, xp) && !mksh_cdirsep(xp[-1]) &&
16465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (S_ISDIR(lstatb.st_mode) ||
16475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (S_ISLNK(lstatb.st_mode) && stat_check() > 0 &&
16485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    S_ISDIR(statb.st_mode)))) {
16495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*xp++ = '/';
16505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*xp = '\0';
16515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
16525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
16535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strndupx(np, Xstring(*xs, xp), Xlength(*xs, xp), ATEMP);
16545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(*wp, np);
16555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
16565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (xp > Xstring(*xs, xp))
16595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*xp++ = '/';
1660966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes	while (mksh_cdirsep(*sp)) {
16615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Xcheck(*xs, xp);
16625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*xp++ = *sp++;
16635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1664966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes	np = mksh_sdirsep(sp);
16655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (np != NULL) {
16665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		se = np;
166703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* don't assume '/', can be multiple kinds */
166803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		odirsep = *np;
16695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*np++ = '\0';
16705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
16715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		odirsep = '\0'; /* keep gcc quiet */
167223925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		se = strnul(sp);
16735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
167603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
167703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Check if sp needs globbing - done to avoid pattern checks for strings
16785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * containing MAGIC characters, open [s without the matching close ],
16795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * etc. (otherwise opendir() will be called which may fail because the
16805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * directory isn't readable - if no globbing is needed, only execute
16815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * permission should be required (as per POSIX)).
16825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
168323925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes	if (!has_globbing(sp)) {
16845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XcheckN(*xs, xp, se - sp + 1);
16855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		debunk(xp, sp, Xnleft(*xs, xp));
168623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes		xp = strnul(xp);
16875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*xpp = xp;
16885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		globit(xs, xpp, np, wp, check);
16895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
16905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		DIR *dirp;
16915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct dirent *d;
16925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *name;
169303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		size_t len, prefix_len;
16945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* xp = *xpp;	copy_non_glob() may have re-alloc'd xs */
16965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*xp = '\0';
16975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		prefix_len = Xlength(*xs, xp);
169877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		dirp = opendir(prefix_len ? Xstring(*xs, xp) : Tdot);
16995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (dirp == NULL)
17005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Nodir;
17015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((d = readdir(dirp)) != NULL) {
17025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			name = d->d_name;
17035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (name[0] == '.' &&
17045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
170503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* always ignore . and .. */
170603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				continue;
17075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((*name == '.' && *sp != '.') ||
17085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    !gmatchx(name, sp, true))
17095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
17105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			len = strlen(d->d_name) + 1;
17125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XcheckN(*xs, xp, len);
17135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(xp, name, len);
17145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*xpp = xp + len - 1;
171523925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			globit(xs, xpp, np, wp, (check & GF_MARKDIR) |
171623925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			    GF_GLOBBED | (np ? GF_EXCHECK : GF_NONE));
17175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp = Xstring(*xs, xp) + prefix_len;
17185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
17195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		closedir(dirp);
17205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Nodir:
17215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		;
17225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
17235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (np != NULL)
17255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*--np = odirsep;
17265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* remove MAGIC from string */
17295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
17305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudebunk(char *dp, const char *sp, size_t dlen)
17315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
17325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *d;
17335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s;
17345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((s = cstrchr(sp, MAGIC))) {
17365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (s - sp >= (ssize_t)dlen)
17375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (dp);
17385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memmove(dp, sp, s - sp);
17395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++)
17405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!ISMAGIC(*s) || !(*++s & 0x80) ||
174123925bb36e72ff98ab562ea647e93db914e833d3Elliott Hughes			    !ctype(*s & 0x7F, C_PATMO | C_SPC))
17425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*d++ = *s;
17435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
17445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* extended pattern operators: *+?@! */
17455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((*s & 0x7f) != ' ')
17465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*d++ = *s & 0x7f;
17475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (d - dp < (ssize_t)dlen)
17485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*d++ = '(';
17495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
17505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*d = '\0';
17515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (dp != sp)
17525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strlcpy(dp, sp, dlen);
17535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (dp);
17545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
175603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
175703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Check if p is an unquoted name, possibly followed by a / or :. If so
17585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * puts the expanded version in *dcp,dp and returns a pointer in p just
17595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * past the name, otherwise returns 0.
17605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
17615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
176250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughesmaybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
17635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
17645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XString ts;
17655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *dp = *dpp;
17665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *tp;
17675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *r;
17685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xinit(ts, tp, 16, ATEMP);
17705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* : only for DOASNTILDE form */
1771a3c3f96fb829bbed2d01b359890bf8b729fa5c54Elliott Hughes	while (p[0] == CHAR && /* not cdirsep */ p[1] != '/' &&
1772966dd55b233982d9657c50b971cfa754d0315c19Elliott Hughes	    (!isassign || p[1] != ':')) {
17735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Xcheck(ts, tp);
17745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*tp++ = p[1];
17755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p += 2;
17765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
17775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*tp = '\0';
17785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ?
177950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	    do_tilde(Xstring(ts, tp)) : NULL;
17805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xfree(ts, tp);
17815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (r) {
17825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*r) {
17835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			Xcheck(*dsp, dp);
17845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ISMAGIC(*r))
17855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*dp++ = MAGIC;
17865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*dp++ = *r++;
17875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
17885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*dpp = dp;
17895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		r = p;
17905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
17915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (r);
17925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
17955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * tilde expansion
17965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
17975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * based on a version by Arnold Robbins
17985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1799c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserchar *
180050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughesdo_tilde(char *cp)
18015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *dp = null;
180377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes#ifndef MKSH_NOPWNAM
180477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	bool do_simplify = true;
180577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes#endif
18065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (cp[0] == '\0')
18085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		dp = str_val(global("HOME"));
18095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (cp[0] == '+' && cp[1] == '\0')
181077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		dp = str_val(global(TPWD));
181196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes	else if (ksh_isdash(cp))
181277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		dp = str_val(global(TOLDPWD));
18135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_NOPWNAM
181477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	else {
18155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		dp = homedir(cp);
181677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		do_simplify = false;
181777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	}
18185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
181977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes
182077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	/* if parameters aren't set, don't expand ~ */
182177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	if (dp == NULL || dp == null)
182277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		return (NULL);
182377740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes
182477740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	/* simplify parameters as if cwd upon entry */
182577740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes#ifndef MKSH_NOPWNAM
182677740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	if (do_simplify)
182777740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes#endif
182877740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	  {
182977740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		strdupx(dp, dp, ATEMP);
183077740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes		simplify_path(dp);
183177740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	}
183277740fcd3dfcd2a78a8ad0ea0f0314dd6b23ecb6Elliott Hughes	return (dp);
18335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_NOPWNAM
18365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
18375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * map userid to user's home directory.
18385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * note that 4.3's getpw adds more than 6K to the shell,
18395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * and the YP version probably adds much more.
18405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * we might consider our own version of getpwnam() to keep the size down.
18415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
18425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
18435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhomedir(char *name)
18445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *ap;
18465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ap = ktenter(&homedirs, name, hash(name));
18485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(ap->flag & ISSET)) {
18495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct passwd *pw;
18505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		pw = getpwnam(name);
18525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (pw == NULL)
18535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
18545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(ap->val.s, pw->pw_dir, APERM);
18555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ap->flag |= DEFINED|ISSET|ALLOC;
18565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ap->val.s);
18585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
18605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
18625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querualt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
18635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
186450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	unsigned int count = 0;
18655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *brace_start, *brace_end, *comma = NULL;
18665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *field_start;
186750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	char *p = exp_start;
18685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* search for open brace */
1870dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes	while ((p = strchr(p, MAGIC)) && ord(p[1]) != ORD('{' /*}*/))
187150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		p += 2;
18725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	brace_start = p;
18735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* find matching close brace, if any */
18755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p) {
18765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		comma = NULL;
18775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		count = 1;
187850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		p += 2;
187950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		while (*p && count) {
188050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (ISMAGIC(*p++)) {
1881dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				if (ord(*p) == ORD('{' /*}*/))
188250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					++count;
1883dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes				else if (ord(*p) == ORD(/*{*/ '}'))
18845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					--count;
18855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if (*p == ',' && count == 1)
18865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					comma = p;
188750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				++p;
18885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
18895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
18905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* no valid expansions... */
18925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!p || count != 0) {
189303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
189403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Note that given a{{b,c} we do not expand anything (this is
18955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * what AT&T ksh does. This may be changed to do the {b,c}
18965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * expansion. }
18975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
18985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (fdo & DOGLOB)
1899c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			glob(start, wp, tobool(fdo & DOMARKDIRS));
19005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
19015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XPput(*wp, debunk(start, start, end - start));
19025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
19035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
19045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	brace_end = p;
19055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!comma) {
19065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		alt_expand(wp, start, brace_end, end, fdo);
19075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
19085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
19095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* expand expression */
19115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	field_start = brace_start + 2;
19125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	count = 1;
19135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = brace_start + 2; p != brace_end; p++) {
19145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ISMAGIC(*p)) {
1915dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			if (ord(*++p) == ORD('{' /*}*/))
191650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				++count;
1917dd4abe0a6aa4badb34480972d393466bf0e4c66bElliott Hughes			else if ((ord(*p) == ORD(/*{*/ '}') && --count == 0) ||
19185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (*p == ',' && count == 1)) {
19195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				char *news;
19205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				int l1, l2, l3;
19215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
192203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
192303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * addition safe since these operate on
192403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * one string (separate substrings)
192503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 */
19265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				l1 = brace_start - start;
19275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				l2 = (p - 1) - field_start;
19285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				l3 = end - brace_end;
19295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				news = alloc(l1 + l2 + l3 + 1, ATEMP);
19305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memcpy(news, start, l1);
19315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memcpy(news + l1, field_start, l2);
19325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memcpy(news + l1 + l2, brace_end, l3);
19335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				news[l1 + l2 + l3] = '\0';
19345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				alt_expand(wp, news, news + l1,
19355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    news + l1 + l2 + l3, fdo);
19365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				field_start = p + 1;
19375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
19385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
19395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
19405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return;
19415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1942c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1943c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* helper function due to setjmp/longjmp woes */
1944811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic char *
1945811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaservalsub(struct op *t, Area *ap)
1946c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1947811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	char * volatile cp = NULL;
1948811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	struct tbl * volatile vp = NULL;
1949811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
1950811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	newenv(E_FUNC);
1951c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	newblock();
1952811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (ap)
1953811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		vp = local("REPLY", false);
1954c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!kshsetjmp(e->jbuf))
1955c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		execute(t, XXCOM | XERROK, NULL);
1956811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (vp)
1957811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		strdupx(cp, str_val(vp), ap);
1958811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	quitenv(NULL);
1959811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
1960811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	return (cp);
1961c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1962