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