OSDN Git Service

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