OSDN Git Service

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