eval.c revision 1.14 1 /* $NetBSD: eval.c,v 1.14 2011/08/21 21:24:34 dholland Exp $ */
2
3 /*
4 * Expansion - quoting, separation, substitution, globbing
5 */
6 #include <sys/cdefs.h>
7
8 #ifndef lint
9 __RCSID("$NetBSD: eval.c,v 1.14 2011/08/21 21:24:34 dholland Exp $");
10 #endif
11
12 #include <stdint.h>
13 #include <pwd.h>
14
15 #include "sh.h"
16 #include "ksh_dir.h"
17 #include "ksh_stat.h"
18
19 /*
20 * string expansion
21 *
22 * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
23 * second pass: alternation ({,}), filename expansion (*?[]).
24 */
25
26 /* expansion generator state */
27 typedef struct Expand {
28 /* int type; */ /* see expand() */
29 const char *str; /* string */
30 union {
31 const char **strv;/* string[] */
32 struct shf *shf;/* file */
33 } u; /* source */
34 struct tbl *var; /* variable in ${var..} */
35 short split; /* split "$@" / call waitlast $() */
36 } Expand;
37
38 #define XBASE 0 /* scanning original */
39 #define XSUB 1 /* expanding ${} string */
40 #define XARGSEP 2 /* ifs0 between "$*" */
41 #define XARG 3 /* expanding $*, $@ */
42 #define XCOM 4 /* expanding $() */
43 #define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */
44
45 /* States used for field splitting */
46 #define IFS_WORD 0 /* word has chars (or quotes) */
47 #define IFS_WS 1 /* have seen IFS white-space */
48 #define IFS_NWS 2 /* have seen IFS non-white-space */
49
50 static int varsub ARGS((Expand *xp, char *sp, char *word, int *stypep, int *slenp));
51 static int comsub ARGS((Expand *xp, char *cp));
52 static char *trimsub ARGS((char *str, char *pat, int how));
53 static void glob ARGS((char *cp, XPtrV *wp, int markdirs));
54 static void globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp,
55 int check));
56 static char *maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp,
57 int isassign));
58 static char *tilde ARGS((char *acp));
59 static char *homedir ARGS((char *name));
60 #ifdef BRACE_EXPAND
61 static void alt_expand ARGS((XPtrV *wp, char *start, char *exp_start,
62 char *end, int fdo));
63 #endif
64
65 /* compile and expand word */
66 char *
67 substitute(cp, f)
68 const char *cp;
69 int f;
70 {
71 struct source *s, *sold;
72
73 sold = source;
74 s = pushs(SWSTR, ATEMP);
75 s->start = s->str = cp;
76 source = s;
77 if (yylex(ONEWORD) != LWORD)
78 internal_errorf(1, "substitute");
79 source = sold;
80 afree(s, ATEMP);
81 return evalstr(yylval.cp, f);
82 }
83
84 /*
85 * expand arg-list
86 */
87 char **
88 eval(ap, f)
89 register char **ap;
90 int f;
91 {
92 XPtrV w;
93
94 if (*ap == NULL)
95 return ap;
96 XPinit(w, 32);
97 XPput(w, NULL); /* space for shell name */
98 #ifdef SHARPBANG
99 XPput(w, NULL); /* and space for one arg */
100 #endif
101 while (*ap != NULL)
102 expand(*ap++, &w, f);
103 XPput(w, NULL);
104 #ifdef SHARPBANG
105 return (char **) XPclose(w) + 2;
106 #else
107 return (char **) XPclose(w) + 1;
108 #endif
109 }
110
111 /*
112 * expand string
113 */
114 char *
115 evalstr(cp, f)
116 char *cp;
117 int f;
118 {
119 XPtrV w;
120
121 XPinit(w, 1);
122 expand(cp, &w, f);
123 cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w);
124 XPfree(w);
125 return cp;
126 }
127
128 /*
129 * expand string - return only one component
130 * used from iosetup to expand redirection files
131 */
132 char *
133 evalonestr(cp, f)
134 register char *cp;
135 int f;
136 {
137 XPtrV w;
138
139 XPinit(w, 1);
140 expand(cp, &w, f);
141 switch (XPsize(w)) {
142 case 0:
143 cp = null;
144 break;
145 case 1:
146 cp = (char*) *XPptrv(w);
147 break;
148 default:
149 cp = evalstr(cp, f&~DOGLOB);
150 break;
151 }
152 XPfree(w);
153 return cp;
154 }
155
156 /* for nested substitution: ${var:=$var2} */
157 typedef struct SubType {
158 short stype; /* [=+-?%#] action after expanded word */
159 short base; /* begin position of expanded word */
160 short f; /* saved value of f (DOPAT, etc) */
161 struct tbl *var; /* variable for ${var..} */
162 short quote; /* saved value of quote (for ${..[%#]..}) */
163 struct SubType *prev; /* old type */
164 struct SubType *next; /* poped type (to avoid re-allocating) */
165 } SubType;
166
167 void
168 expand(cp, wp, f)
169 char *cp; /* input word */
170 register XPtrV *wp; /* output words */
171 int f; /* DO* flags */
172 {
173 register int UNINITIALIZED(c);
174 register int type; /* expansion type */
175 register int quote = 0; /* quoted */
176 XString ds; /* destination string */
177 register char *dp, *sp; /* dest., source */
178 int fdo, word; /* second pass flags; have word */
179 int doblank; /* field splitting of parameter/command subst */
180 Expand x; /* expansion variables */
181 SubType st_head, *st;
182 int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */
183 int saw_eq, tilde_ok;
184 int make_magic;
185 size_t len;
186
187 x.split = 0; /* XXX gcc */
188 x.str = NULL; /* XXX gcc */
189 x.u.strv = NULL;/* XXX gcc */
190 if (cp == NULL)
191 internal_errorf(1, "expand(NULL)");
192 /* for alias, readonly, set, typeset commands */
193 if ((f & DOVACHECK) && is_wdvarassign(cp)) {
194 f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
195 f |= DOASNTILDE;
196 }
197 if (Flag(FNOGLOB))
198 f &= ~DOGLOB;
199 if (Flag(FMARKDIRS))
200 f |= DOMARKDIRS;
201 #ifdef BRACE_EXPAND
202 if (Flag(FBRACEEXPAND) && (f & DOGLOB))
203 f |= DOBRACE_;
204 #endif /* BRACE_EXPAND */
205
206 Xinit(ds, dp, 128, ATEMP); /* init dest. string */
207 type = XBASE;
208 sp = cp;
209 fdo = 0;
210 saw_eq = 0;
211 tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */
212 doblank = 0;
213 make_magic = 0;
214 word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
215 st_head.next = (SubType *) 0;
216 st = &st_head;
217
218 while (1) {
219 Xcheck(ds, dp);
220
221 switch (type) {
222 case XBASE: /* original prefixed string */
223 c = *sp++;
224 switch (c) {
225 case EOS:
226 c = 0;
227 break;
228 case CHAR:
229 c = *sp++;
230 break;
231 case QCHAR:
232 quote |= 2; /* temporary quote */
233 c = *sp++;
234 break;
235 case OQUOTE:
236 word = IFS_WORD;
237 tilde_ok = 0;
238 quote = 1;
239 continue;
240 case CQUOTE:
241 quote = 0;
242 continue;
243 case COMSUB:
244 tilde_ok = 0;
245 if (f & DONTRUNCOMMAND) {
246 word = IFS_WORD;
247 *dp++ = '$'; *dp++ = '(';
248 while (*sp != '\0') {
249 Xcheck(ds, dp);
250 *dp++ = *sp++;
251 }
252 *dp++ = ')';
253 } else {
254 type = comsub(&x, sp);
255 if (type == XCOM && (f&DOBLANK))
256 doblank++;
257 sp = strchr(sp, 0) + 1;
258 newlines = 0;
259 }
260 continue;
261 case EXPRSUB:
262 word = IFS_WORD;
263 tilde_ok = 0;
264 if (f & DONTRUNCOMMAND) {
265 *dp++ = '$'; *dp++ = '('; *dp++ = '(';
266 while (*sp != '\0') {
267 Xcheck(ds, dp);
268 *dp++ = *sp++;
269 }
270 *dp++ = ')'; *dp++ = ')';
271 } else {
272 struct tbl v;
273 char *p;
274
275 v.flag = DEFINED|ISSET|INTEGER;
276 v.type = 10; /* not default */
277 v.name[0] = '\0';
278 v_evaluate(&v, substitute(sp, 0),
279 KSH_UNWIND_ERROR);
280 sp = strchr(sp, 0) + 1;
281 for (p = str_val(&v); *p; ) {
282 Xcheck(ds, dp);
283 *dp++ = *p++;
284 }
285 }
286 continue;
287 case OSUBST: /* ${{#}var{:}[=+-?#%]word} */
288 /* format is:
289 * OSUBST [{x] plain-variable-part \0
290 * compiled-word-part CSUBST [}x]
291 * This is were all syntax checking gets done...
292 */
293 {
294 char *varname = ++sp; /* skip the { or x (}) */
295 int stype;
296 int slen;
297
298 slen = -1; /* XXX gcc */
299 sp = strchr(sp, '\0') + 1; /* skip variable */
300 type = varsub(&x, varname, sp, &stype, &slen);
301 if (type < 0) {
302 char endc;
303 char *str, *end;
304
305 end = (char *) wdscan(sp, CSUBST);
306 /* ({) the } or x is already skipped */
307 endc = *end;
308 *end = EOS;
309 str = snptreef((char *) 0, 64, "%S",
310 varname - 1);
311 *end = endc;
312 errorf("%s: bad substitution", str);
313 }
314 if (f&DOBLANK)
315 doblank++;
316 tilde_ok = 0;
317 if (type == XBASE) { /* expand? */
318 if (!st->next) {
319 SubType *newst;
320
321 newst = (SubType *) alloc(
322 sizeof(SubType), ATEMP);
323 newst->next = (SubType *) 0;
324 newst->prev = st;
325 st->next = newst;
326 }
327 st = st->next;
328 st->stype = stype;
329 st->base = Xsavepos(ds, dp);
330 st->f = f;
331 st->var = x.var;
332 st->quote = quote;
333 /* skip qualifier(s) */
334 if (stype)
335 sp += slen;
336 switch (stype & 0x7f) {
337 case '#':
338 case '%':
339 /* ! DOBLANK,DOBRACE_,DOTILDE */
340 f = DOPAT | (f&DONTRUNCOMMAND)
341 | DOTEMP_;
342 quote = 0;
343 /* Prepend open pattern (so |
344 * in a trim will work as
345 * expected)
346 */
347 *dp++ = MAGIC;
348 *dp++ = '@' + 0x80;
349 break;
350 case '=':
351 /* Enabling tilde expansion
352 * after :'s here is
353 * non-standard ksh, but is
354 * consistent with rules for
355 * other assignments. Not
356 * sure what POSIX thinks of
357 * this.
358 * Not doing tilde expansion
359 * for integer variables is a
360 * non-POSIX thing - makes
361 * sense though, since ~ is
362 * a arithmetic operator.
363 */
364 if (!(x.var->flag & INTEGER))
365 f |= DOASNTILDE|DOTILDE;
366 f |= DOTEMP_;
367 /* These will be done after the
368 * value has been assigned.
369 */
370 f &= ~(DOBLANK|DOGLOB|DOBRACE_);
371 tilde_ok = 1;
372 break;
373 case '?':
374 f &= ~DOBLANK;
375 f |= DOTEMP_;
376 /* fall through */
377 default:
378 /* Enable tilde expansion */
379 tilde_ok = 1;
380 f |= DOTILDE;
381 }
382 } else
383 /* skip word */
384 sp = (char *) wdscan(sp, CSUBST);
385 continue;
386 }
387 case CSUBST: /* only get here if expanding word */
388 sp++; /* ({) skip the } or x */
389 tilde_ok = 0; /* in case of ${unset:-} */
390 *dp = '\0';
391 quote = st->quote;
392 f = st->f;
393 if (f&DOBLANK)
394 doblank--;
395 switch (st->stype&0x7f) {
396 case '#':
397 case '%':
398 /* Append end-pattern */
399 *dp++ = MAGIC; *dp++ = ')'; *dp = '\0';
400 dp = Xrestpos(ds, dp, st->base);
401 /* Must use st->var since calling
402 * global would break things
403 * like x[i+=1].
404 */
405 x.str = trimsub(str_val(st->var),
406 dp, st->stype);
407 type = XSUB;
408 if (f&DOBLANK)
409 doblank++;
410 st = st->prev;
411 continue;
412 case '=':
413 /* Restore our position and substitute
414 * the value of st->var (may not be
415 * the assigned value in the presence
416 * of integer/right-adj/etc attributes).
417 */
418 dp = Xrestpos(ds, dp, st->base);
419 /* Must use st->var since calling
420 * global would cause with things
421 * like x[i+=1] to be evaluated twice.
422 */
423 /* Note: not exported by FEXPORT
424 * in at&t ksh.
425 */
426 /* XXX POSIX says readonly is only
427 * fatal for special builtins (setstr
428 * does readonly check).
429 */
430 len = strlen(dp) + 1;
431 setstr(st->var,
432 debunk((char *) alloc(len, ATEMP),
433 dp, len),
434 KSH_UNWIND_ERROR);
435 x.str = str_val(st->var);
436 type = XSUB;
437 if (f&DOBLANK)
438 doblank++;
439 st = st->prev;
440 continue;
441 case '?':
442 {
443 char *s = Xrestpos(ds, dp, st->base);
444
445 errorf("%s: %s", st->var->name,
446 dp == s ?
447 "parameter null or not set"
448 : (debunk(s, s, strlen(s) + 1), s));
449 }
450 }
451 st = st->prev;
452 type = XBASE;
453 continue;
454
455 case OPAT: /* open pattern: *(foo|bar) */
456 /* Next char is the type of pattern */
457 make_magic = 1;
458 c = *sp++ + 0x80;
459 break;
460
461 case SPAT: /* pattern separator (|) */
462 make_magic = 1;
463 c = '|';
464 break;
465
466 case CPAT: /* close pattern */
467 make_magic = 1;
468 c = /*(*/ ')';
469 break;
470 }
471 break;
472
473 case XNULLSUB:
474 /* Special case for "$@" (and "${foo[@]}") - no
475 * word is generated if $# is 0 (unless there is
476 * other stuff inside the quotes).
477 */
478 type = XBASE;
479 if (f&DOBLANK) {
480 doblank--;
481 /* not really correct: x=; "$x$@" should
482 * generate a null argument and
483 * set A; "${@:+}" shouldn't.
484 */
485 if (dp == Xstring(ds, dp))
486 word = IFS_WS;
487 }
488 continue;
489
490 case XSUB:
491 if ((c = *x.str++) == 0) {
492 type = XBASE;
493 if (f&DOBLANK)
494 doblank--;
495 continue;
496 }
497 break;
498
499 case XARGSEP:
500 type = XARG;
501 quote = 1;
502 case XARG:
503 if ((c = *x.str++) == '\0') {
504 /* force null words to be created so
505 * set -- '' 2 ''; foo "$@" will do
506 * the right thing
507 */
508 if (quote && x.split)
509 word = IFS_WORD;
510 if ((x.str = *x.u.strv++) == NULL) {
511 type = XBASE;
512 if (f&DOBLANK)
513 doblank--;
514 continue;
515 }
516 c = ifs0;
517 if (c == 0) {
518 if (quote && !x.split)
519 continue;
520 c = ' ';
521 }
522 if (quote && x.split) {
523 /* terminate word for "$@" */
524 type = XARGSEP;
525 quote = 0;
526 }
527 }
528 break;
529
530 case XCOM:
531 if (newlines) { /* Spit out saved nl's */
532 c = '\n';
533 --newlines;
534 } else {
535 while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
536 if (c == '\n')
537 newlines++; /* Save newlines */
538 if (newlines && c != EOF) {
539 shf_ungetc(c, x.u.shf);
540 c = '\n';
541 --newlines;
542 }
543 }
544 if (c == EOF) {
545 newlines = 0;
546 shf_close(x.u.shf);
547 if (x.split)
548 subst_exstat = waitlast();
549 type = XBASE;
550 if (f&DOBLANK)
551 doblank--;
552 continue;
553 }
554 break;
555 }
556
557 /* check for end of word or IFS separation */
558 if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic
559 && ctype(c, C_IFS)))
560 {
561 /* How words are broken up:
562 * | value of c
563 * word | ws nws 0
564 * -----------------------------------
565 * IFS_WORD w/WS w/NWS w
566 * IFS_WS -/WS w/NWS -
567 * IFS_NWS -/NWS w/NWS w
568 * (w means generate a word)
569 * Note that IFS_NWS/0 generates a word (at&t ksh
570 * doesn't do this, but POSIX does).
571 */
572 if (word == IFS_WORD
573 || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS)))
574 {
575 char *p;
576
577 *dp++ = '\0';
578 p = Xclose(ds, dp);
579 #ifdef BRACE_EXPAND
580 if (fdo & DOBRACE_)
581 /* also does globbing */
582 alt_expand(wp, p, p,
583 p + Xlength(ds, (dp - 1)),
584 fdo | (f & DOMARKDIRS));
585 else
586 #endif /* BRACE_EXPAND */
587 if (fdo & DOGLOB)
588 glob(p, wp, f & DOMARKDIRS);
589 else if ((f & DOPAT) || !(fdo & DOMAGIC_))
590 XPput(*wp, p);
591 else
592 XPput(*wp, debunk(p, p, strlen(p) + 1));
593 fdo = 0;
594 saw_eq = 0;
595 tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
596 if (c != 0)
597 Xinit(ds, dp, 128, ATEMP);
598 }
599 if (c == 0)
600 return;
601 if (word != IFS_NWS)
602 word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
603 } else {
604 /* age tilde_ok info - ~ code tests second bit */
605 tilde_ok <<= 1;
606 /* mark any special second pass chars */
607 if (!quote)
608 switch (c) {
609 case '[':
610 case NOT:
611 case '-':
612 case ']':
613 /* For character classes - doesn't hurt
614 * to have magic !,-,]'s outside of
615 * [...] expressions.
616 */
617 if (f & (DOPAT | DOGLOB)) {
618 fdo |= DOMAGIC_;
619 if (c == '[')
620 fdo |= f & DOGLOB;
621 *dp++ = MAGIC;
622 }
623 break;
624 case '*':
625 case '?':
626 if (f & (DOPAT | DOGLOB)) {
627 fdo |= DOMAGIC_ | (f & DOGLOB);
628 *dp++ = MAGIC;
629 }
630 break;
631 #ifdef BRACE_EXPAND
632 case OBRACE:
633 case ',':
634 case CBRACE:
635 if ((f & DOBRACE_) && (c == OBRACE
636 || (fdo & DOBRACE_)))
637 {
638 fdo |= DOBRACE_|DOMAGIC_;
639 *dp++ = MAGIC;
640 }
641 break;
642 #endif /* BRACE_EXPAND */
643 case '=':
644 /* Note first unquoted = for ~ */
645 if (!(f & DOTEMP_) && !saw_eq) {
646 saw_eq = 1;
647 tilde_ok = 1;
648 }
649 break;
650 case PATHSEP: /* : */
651 /* Note unquoted : for ~ */
652 if (!(f & DOTEMP_) && (f & DOASNTILDE))
653 tilde_ok = 1;
654 break;
655 case '~':
656 /* tilde_ok is reset whenever
657 * any of ' " $( $(( ${ } are seen.
658 * Note that tilde_ok must be preserved
659 * through the sequence ${A=a=}~
660 */
661 if (type == XBASE
662 && (f & (DOTILDE|DOASNTILDE))
663 && (tilde_ok & 2))
664 {
665 char *p, *dp_x;
666
667 dp_x = dp;
668 p = maybe_expand_tilde(sp,
669 &ds, &dp_x,
670 f & DOASNTILDE);
671 if (p) {
672 if (dp != dp_x)
673 word = IFS_WORD;
674 dp = dp_x;
675 sp = p;
676 continue;
677 }
678 }
679 break;
680 }
681 else
682 quote &= ~2; /* undo temporary */
683
684 if (make_magic) {
685 make_magic = 0;
686 fdo |= DOMAGIC_ | (f & DOGLOB);
687 *dp++ = MAGIC;
688 } else if (ISMAGIC(c)) {
689 fdo |= DOMAGIC_;
690 *dp++ = MAGIC;
691 }
692 *dp++ = c; /* save output char */
693 word = IFS_WORD;
694 }
695 }
696 }
697
698 /*
699 * Prepare to generate the string returned by ${} substitution.
700 */
701 static int
702 varsub(xp, sp, word, stypep, slenp)
703 Expand *xp;
704 char *sp;
705 char *word;
706 int *stypep; /* becomes qualifier type */
707 int *slenp; /* " " len (=, :=, etc.) valid iff *stypep != 0 */
708 {
709 int c;
710 int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
711 int stype; /* substitution type */
712 int slen;
713 char *p;
714 struct tbl *vp;
715
716 if (sp[0] == '\0') /* Bad variable name */
717 return -1;
718
719 xp->var = NULL;
720
721 /* ${#var}, string length or array size */
722 if (sp[0] == '#' && (c = sp[1]) != '\0') {
723 int zero_ok = 0;
724
725 /* Can't have any modifiers for ${#...} */
726 if (*word != CSUBST)
727 return -1;
728 sp++;
729 /* Check for size of array */
730 if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
731 int n = 0;
732 int max = 0;
733 vp = global(arrayname(sp));
734 if (vp->flag & (ISSET|ARRAY))
735 zero_ok = 1;
736 for (; vp; vp = vp->u.array)
737 if (vp->flag & ISSET) {
738 max = vp->index + 1;
739 n++;
740 }
741 c = n; /* ksh88/ksh93 go for number, not max index */
742 } else if (c == '*' || c == '@')
743 c = e->loc->argc;
744 else {
745 p = str_val(global(sp));
746 zero_ok = p != null;
747 c = strlen(p);
748 }
749 if (Flag(FNOUNSET) && c == 0 && !zero_ok)
750 errorf("%s: parameter not set", sp);
751 *stypep = 0; /* unqualified variable/string substitution */
752 xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
753 return XSUB;
754 }
755
756 /* Check for qualifiers in word part */
757 stype = 0;
758 c = word[slen = 0] == CHAR ? word[1] : 0;
759 if (c == ':') {
760 slen += 2;
761 stype = 0x80;
762 c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
763 }
764 if (ctype(c, C_SUBOP1)) {
765 slen += 2;
766 stype |= c;
767 } else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */
768 slen += 2;
769 stype = c;
770 if (word[slen + 0] == CHAR && c == word[slen + 1]) {
771 stype |= 0x80;
772 slen += 2;
773 }
774 } else if (stype) /* : is not ok */
775 return -1;
776 if (!stype && *word != CSUBST)
777 return -1;
778 *stypep = stype;
779 *slenp = slen;
780
781 c = sp[0];
782 if (c == '*' || c == '@') {
783 switch (stype & 0x7f) {
784 case '=': /* can't assign to a vector */
785 case '%': /* can't trim a vector (yet) */
786 case '#':
787 return -1;
788 }
789 if (e->loc->argc == 0) {
790 xp->u.strv = NULL;
791 xp->str = null;
792 state = c == '@' ? XNULLSUB : XSUB;
793 } else {
794 char **t = &e->loc->argv[1];
795 xp->u.strv = (void *)(uintptr_t)t;
796 xp->str = *xp->u.strv++;
797 xp->split = c == '@'; /* $@ */
798 state = XARG;
799 }
800 } else {
801 if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
802 XPtrV wv;
803
804 switch (stype & 0x7f) {
805 case '=': /* can't assign to a vector */
806 case '%': /* can't trim a vector (yet) */
807 case '#':
808 return -1;
809 }
810 XPinit(wv, 32);
811 vp = global(arrayname(sp));
812 for (; vp; vp = vp->u.array) {
813 if (!(vp->flag&ISSET))
814 continue;
815 XPput(wv, str_val(vp));
816 }
817 if (XPsize(wv) == 0) {
818 xp->str = null;
819 state = p[1] == '@' ? XNULLSUB : XSUB;
820 XPfree(wv);
821 } else {
822 XPput(wv, 0);
823 xp->u.strv = (const char **) XPptrv(wv);
824 xp->str = *xp->u.strv++;
825 xp->split = p[1] == '@'; /* ${foo[@]} */
826 state = XARG;
827 }
828 } else {
829 /* Can't assign things like $! or $1 */
830 if ((stype & 0x7f) == '='
831 && (ctype(*sp, C_VAR1) || digit(*sp)))
832 return -1;
833 xp->var = global(sp);
834 xp->str = str_val(xp->var);
835 state = XSUB;
836 }
837 }
838
839 c = stype&0x7f;
840 /* test the compiler's code generator */
841 if (ctype(c, C_SUBOP2) ||
842 (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
843 c == '=' || c == '-' || c == '?' : c == '+'))
844 state = XBASE; /* expand word instead of variable value */
845 if (Flag(FNOUNSET) && xp->str == null
846 && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
847 errorf("%s: parameter not set", sp);
848 return state;
849 }
850
851 /*
852 * Run the command in $(...) and read its output.
853 */
854 static int
855 comsub(xp, cp)
856 register Expand *xp;
857 char *cp;
858 {
859 Source *s, *sold;
860 register struct op *t;
861 struct shf *shf;
862
863 s = pushs(SSTRING, ATEMP);
864 s->start = s->str = cp;
865 sold = source;
866 t = compile(s);
867 afree(s, ATEMP);
868 source = sold;
869
870 if (t == NULL)
871 return XBASE;
872
873 if (t != NULL && t->type == TCOM && /* $(<file) */
874 *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
875 register struct ioword *io = *t->ioact;
876 char *name;
877
878 if ((io->flag&IOTYPE) != IOREAD)
879 errorf("funny $() command: %s",
880 snptreef((char *) 0, 32, "%R", io));
881 shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
882 SHF_MAPHI|SHF_CLEXEC);
883 if (shf == NULL)
884 errorf("%s: cannot open $() input", name);
885 xp->split = 0; /* no waitlast() */
886 } else {
887 int ofd1, pv[2];
888 openpipe(pv);
889 shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
890 ofd1 = savefd(1, 0); /* fd 1 may be closed... */
891 if (pv[1] != 1) {
892 ksh_dup2(pv[1], 1, FALSE);
893 close(pv[1]);
894 }
895 execute(t, XFORK|XXCOM|XPIPEO);
896 restfd(1, ofd1);
897 startlast();
898 xp->split = 1; /* waitlast() */
899 }
900
901 xp->u.shf = shf;
902 return XCOM;
903 }
904
905 /*
906 * perform #pattern and %pattern substitution in ${}
907 */
908
909 static char *
910 trimsub(str, pat, how)
911 register char *str;
912 char *pat;
913 int how;
914 {
915 register char *end = strchr(str, 0);
916 register char *p, c;
917
918 switch (how&0xff) { /* UCHAR_MAX maybe? */
919 case '#': /* shortest at beginning */
920 for (p = str; p <= end; p++) {
921 c = *p; *p = '\0';
922 if (gmatch(str, pat, FALSE)) {
923 *p = c;
924 return p;
925 }
926 *p = c;
927 }
928 break;
929 case '#'|0x80: /* longest match at beginning */
930 for (p = end; p >= str; p--) {
931 c = *p; *p = '\0';
932 if (gmatch(str, pat, FALSE)) {
933 *p = c;
934 return p;
935 }
936 *p = c;
937 }
938 break;
939 case '%': /* shortest match at end */
940 for (p = end; p >= str; p--) {
941 if (gmatch(p, pat, FALSE))
942 return str_nsave(str, p - str, ATEMP);
943 }
944 break;
945 case '%'|0x80: /* longest match at end */
946 for (p = str; p <= end; p++) {
947 if (gmatch(p, pat, FALSE))
948 return str_nsave(str, p - str, ATEMP);
949 }
950 break;
951 }
952
953 return str; /* no match, return string */
954 }
955
956 /*
957 * glob
958 * Name derived from V6's /etc/glob, the program that expanded filenames.
959 */
960
961 /* XXX cp not const 'cause slashes are temporarily replaced with nulls... */
962 static void
963 glob(cp, wp, markdirs)
964 char *cp;
965 register XPtrV *wp;
966 int markdirs;
967 {
968 int oldsize = XPsize(*wp);
969
970 if (glob_str(cp, wp, markdirs) == 0)
971 XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
972 else
973 qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize),
974 xstrcmp);
975 }
976
977 #define GF_NONE 0
978 #define GF_EXCHECK BIT(0) /* do existence check on file */
979 #define GF_GLOBBED BIT(1) /* some globbing has been done */
980 #define GF_MARKDIR BIT(2) /* add trailing / to directories */
981
982 /* Apply file globbing to cp and store the matching files in wp. Returns
983 * the number of matches found.
984 */
985 int
986 glob_str(cp, wp, markdirs)
987 char *cp;
988 XPtrV *wp;
989 int markdirs;
990 {
991 int oldsize = XPsize(*wp);
992 XString xs;
993 char *xp;
994
995 Xinit(xs, xp, 256, ATEMP);
996 globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
997 Xfree(xs, xp);
998
999 return XPsize(*wp) - oldsize;
1000 }
1001
1002 static void
1003 globit(xs, xpp, sp, wp, check)
1004 XString *xs; /* dest string */
1005 char **xpp; /* ptr to dest end */
1006 char *sp; /* source path */
1007 register XPtrV *wp; /* output list */
1008 int check; /* GF_* flags */
1009 {
1010 register char *np; /* next source component */
1011 char *xp = *xpp;
1012 char *se;
1013 char odirsep;
1014
1015 /* This to allow long expansions to be interrupted */
1016 intrcheck();
1017
1018 if (sp == NULL) { /* end of source path */
1019 /* We only need to check if the file exists if a pattern
1020 * is followed by a non-pattern (eg, foo*x/bar; no check
1021 * is needed for foo* since the match must exist) or if
1022 * any patterns were expanded and the markdirs option is set.
1023 * Symlinks make things a bit tricky...
1024 */
1025 if ((check & GF_EXCHECK)
1026 || ((check & GF_MARKDIR) && (check & GF_GLOBBED)))
1027 {
1028 #define stat_check() (stat_done ? stat_done : \
1029 (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
1030 ? -1 : 1))
1031 struct stat lstatb, statb;
1032 int stat_done = 0; /* -1: failed, 1 ok */
1033
1034 if (lstat(Xstring(*xs, xp), &lstatb) < 0)
1035 return;
1036 /* special case for systems which strip trailing
1037 * slashes from regular files (eg, /etc/passwd/).
1038 * SunOS 4.1.3 does this...
1039 */
1040 if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp)
1041 && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode)
1042 #ifdef S_ISLNK
1043 && (!S_ISLNK(lstatb.st_mode)
1044 || stat_check() < 0
1045 || !S_ISDIR(statb.st_mode))
1046 #endif /* S_ISLNK */
1047 )
1048 return;
1049 /* Possibly tack on a trailing / if there isn't already
1050 * one and if the file is a directory or a symlink to a
1051 * directory
1052 */
1053 if (((check & GF_MARKDIR) && (check & GF_GLOBBED))
1054 && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1])
1055 && (S_ISDIR(lstatb.st_mode)
1056 #ifdef S_ISLNK
1057 || (S_ISLNK(lstatb.st_mode)
1058 && stat_check() > 0
1059 && S_ISDIR(statb.st_mode))
1060 #endif /* S_ISLNK */
1061 ))
1062 {
1063 *xp++ = DIRSEP;
1064 *xp = '\0';
1065 }
1066 }
1067 #ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */
1068 /* Ugly kludge required for command
1069 * completion - see how search_access()
1070 * is implemented for OS/2...
1071 */
1072 # define KLUDGE_VAL 4
1073 #else /* OS2 */
1074 # define KLUDGE_VAL 0
1075 #endif /* OS2 */
1076 XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp)
1077 + KLUDGE_VAL, ATEMP));
1078 return;
1079 }
1080
1081 if (xp > Xstring(*xs, xp))
1082 *xp++ = DIRSEP;
1083 while (ISDIRSEP(*sp)) {
1084 Xcheck(*xs, xp);
1085 *xp++ = *sp++;
1086 }
1087 np = ksh_strchr_dirsep(sp);
1088 if (np != NULL) {
1089 se = np;
1090 odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */
1091 *np++ = '\0';
1092 } else {
1093 odirsep = '\0'; /* keep gcc quiet */
1094 se = sp + strlen(sp);
1095 }
1096
1097
1098 /* Check if sp needs globbing - done to avoid pattern checks for strings
1099 * containing MAGIC characters, open ['s without the matching close ],
1100 * etc. (otherwise opendir() will be called which may fail because the
1101 * directory isn't readable - if no globbing is needed, only execute
1102 * permission should be required (as per POSIX)).
1103 */
1104 if (!has_globbing(sp, se)) {
1105 XcheckN(*xs, xp, se - sp + 1);
1106 debunk(xp, sp, Xnleft(*xs, xp));
1107 xp += strlen(xp);
1108 *xpp = xp;
1109 globit(xs, xpp, np, wp, check);
1110 } else {
1111 DIR *dirp;
1112 struct dirent *d;
1113 char *name;
1114 int len;
1115 int prefix_len;
1116
1117 /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */
1118 *xp = '\0';
1119 prefix_len = Xlength(*xs, xp);
1120 dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : ".");
1121 if (dirp == NULL)
1122 goto Nodir;
1123 while ((d = readdir(dirp)) != NULL) {
1124 name = d->d_name;
1125 if ((*name == '.' && *sp != '.')
1126 || !gmatch(name, sp, TRUE))
1127 continue;
1128
1129 len = NLENGTH(d) + 1;
1130 XcheckN(*xs, xp, len);
1131 memcpy(xp, name, len);
1132 *xpp = xp + len - 1;
1133 globit(xs, xpp, np, wp,
1134 (check & GF_MARKDIR) | GF_GLOBBED
1135 | (np ? GF_EXCHECK : GF_NONE));
1136 xp = Xstring(*xs, xp) + prefix_len;
1137 }
1138 closedir(dirp);
1139 Nodir:;
1140 }
1141
1142 if (np != NULL)
1143 *--np = odirsep;
1144 }
1145
1146 #if 0
1147 /* Check if p contains something that needs globbing; if it does, 0 is
1148 * returned; if not, p is copied into xs/xp after stripping any MAGICs
1149 */
1150 static int copy_non_glob ARGS((XString *xs, char **xpp, char *p));
1151 static int
1152 copy_non_glob(xs, xpp, p)
1153 XString *xs;
1154 char **xpp;
1155 char *p;
1156 {
1157 char *xp;
1158 int len = strlen(p);
1159
1160 XcheckN(*xs, *xpp, len);
1161 xp = *xpp;
1162 for (; *p; p++) {
1163 if (ISMAGIC(*p)) {
1164 int c = *++p;
1165
1166 if (c == '*' || c == '?')
1167 return 0;
1168 if (*p == '[') {
1169 char *q = p + 1;
1170
1171 if (ISMAGIC(*q) && q[1] == NOT)
1172 q += 2;
1173 if (ISMAGIC(*q) && q[1] == ']')
1174 q += 2;
1175 for (; *q; q++)
1176 if (ISMAGIC(*q) && *++q == ']')
1177 return 0;
1178 /* pass a literal [ through */
1179 }
1180 /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */
1181 }
1182 *xp++ = *p;
1183 }
1184 *xp = '\0';
1185 *xpp = xp;
1186 return 1;
1187 }
1188 #endif /* 0 */
1189
1190 /* remove MAGIC from string */
1191 char *
1192 debunk(dp, sp, dlen)
1193 char *dp;
1194 const char *sp;
1195 size_t dlen;
1196 {
1197 char *d, *s;
1198
1199 if ((s = strchr(sp, MAGIC))) {
1200 if (s - sp >= (ptrdiff_t)dlen)
1201 return dp;
1202 memcpy(dp, sp, s - sp);
1203 for (d = dp + (s - sp); *s && (d - dp < (ptrdiff_t)dlen); s++)
1204 if (!ISMAGIC(*s) || !(*++s & 0x80)
1205 || !strchr("*+?@! ", *s & 0x7f))
1206 *d++ = *s;
1207 else {
1208 /* extended pattern operators: *+?@! */
1209 if ((*s & 0x7f) != ' ')
1210 *d++ = *s & 0x7f;
1211 if (d - dp < (ptrdiff_t)dlen)
1212 *d++ = '(';
1213 }
1214 *d = '\0';
1215 } else if (dp != sp)
1216 strlcpy(dp, sp, dlen);
1217 return dp;
1218 }
1219
1220 /* Check if p is an unquoted name, possibly followed by a / or :. If so
1221 * puts the expanded version in *dcp,dp and returns a pointer in p just
1222 * past the name, otherwise returns 0.
1223 */
1224 static char *
1225 maybe_expand_tilde(p, dsp, dpp, isassign)
1226 char *p;
1227 XString *dsp;
1228 char **dpp;
1229 int isassign;
1230 {
1231 XString ts;
1232 char *dp = *dpp;
1233 char *tp, *r;
1234
1235 Xinit(ts, tp, 16, ATEMP);
1236 /* : only for DOASNTILDE form */
1237 while (p[0] == CHAR && !ISDIRSEP(p[1])
1238 && (!isassign || p[1] != PATHSEP))
1239 {
1240 Xcheck(ts, tp);
1241 *tp++ = p[1];
1242 p += 2;
1243 }
1244 *tp = '\0';
1245 r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0;
1246 Xfree(ts, tp);
1247 if (r) {
1248 while (*r) {
1249 Xcheck(*dsp, dp);
1250 if (ISMAGIC(*r))
1251 *dp++ = MAGIC;
1252 *dp++ = *r++;
1253 }
1254 *dpp = dp;
1255 r = p;
1256 }
1257 return r;
1258 }
1259
1260 /*
1261 * tilde expansion
1262 *
1263 * based on a version by Arnold Robbins
1264 */
1265
1266 static char *
1267 tilde(cp)
1268 char *cp;
1269 {
1270 char *dp;
1271
1272 if (cp[0] == '\0')
1273 dp = str_val(global("HOME"));
1274 else if (cp[0] == '+' && cp[1] == '\0')
1275 dp = str_val(global("PWD"));
1276 else if (cp[0] == '-' && cp[1] == '\0')
1277 dp = str_val(global("OLDPWD"));
1278 else
1279 dp = homedir(cp);
1280 /* If HOME, PWD or OLDPWD are not set, don't expand ~ */
1281 if (dp == null)
1282 dp = (char *) 0;
1283 return dp;
1284 }
1285
1286 /*
1287 * map userid to user's home directory.
1288 * note that 4.3's getpw adds more than 6K to the shell,
1289 * and the YP version probably adds much more.
1290 * we might consider our own version of getpwnam() to keep the size down.
1291 */
1292
1293 static char *
1294 homedir(name)
1295 char *name;
1296 {
1297 register struct tbl *ap;
1298
1299 ap = tenter(&homedirs, name, hash(name));
1300 if (!(ap->flag & ISSET)) {
1301 #ifdef OS2
1302 /* No usernames in OS2 - punt */
1303 return NULL;
1304 #else /* OS2 */
1305 struct passwd *pw;
1306 size_t n;
1307
1308 pw = getpwnam(name);
1309 if (pw == NULL)
1310 return NULL;
1311 n = strlen(pw->pw_dir);
1312 if (n > 0 && '/' != pw->pw_dir[n - 1]) {
1313 ap->val.s = str_nsave(pw->pw_dir, n + 1, APERM);
1314 ap->val.s[n] = '/';
1315 ap->val.s[n + 1] = '\0';
1316 } else {
1317 ap->val.s = str_save(pw->pw_dir, APERM);
1318 }
1319 ap->flag |= DEFINED|ISSET|ALLOC;
1320 #endif /* OS2 */
1321 }
1322 return ap->val.s;
1323 }
1324
1325 #ifdef BRACE_EXPAND
1326 static void
1327 alt_expand(wp, start, exp_start, end, fdo)
1328 XPtrV *wp;
1329 char *start, *exp_start;
1330 char *end;
1331 int fdo;
1332 {
1333 int UNINITIALIZED(count);
1334 char *brace_start, *brace_end, *UNINITIALIZED(comma);
1335 char *field_start;
1336 char *p;
1337
1338 /* search for open brace */
1339 for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2)
1340 ;
1341 brace_start = p;
1342
1343 /* find matching close brace, if any */
1344 if (p) {
1345 comma = (char *) 0;
1346 count = 1;
1347 for (p += 2; *p && count; p++) {
1348 if (ISMAGIC(*p)) {
1349 if (*++p == OBRACE)
1350 count++;
1351 else if (*p == CBRACE)
1352 --count;
1353 else if (*p == ',' && count == 1)
1354 comma = p;
1355 }
1356 }
1357 }
1358 /* no valid expansions... */
1359 if (!p || count != 0) {
1360 /* Note that given a{{b,c} we do not expand anything (this is
1361 * what at&t ksh does. This may be changed to do the {b,c}
1362 * expansion. }
1363 */
1364 if (fdo & DOGLOB)
1365 glob(start, wp, fdo & DOMARKDIRS);
1366 else
1367 XPput(*wp, debunk(start, start, end - start));
1368 return;
1369 }
1370 brace_end = p;
1371 if (!comma) {
1372 alt_expand(wp, start, brace_end, end, fdo);
1373 return;
1374 }
1375
1376 /* expand expression */
1377 field_start = brace_start + 2;
1378 count = 1;
1379 for (p = brace_start + 2; p != brace_end; p++) {
1380 if (ISMAGIC(*p)) {
1381 if (*++p == OBRACE)
1382 count++;
1383 else if ((*p == CBRACE && --count == 0)
1384 || (*p == ',' && count == 1))
1385 {
1386 char *new;
1387 int l1, l2, l3;
1388
1389 l1 = brace_start - start;
1390 l2 = (p - 1) - field_start;
1391 l3 = end - brace_end;
1392 new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP);
1393 memcpy(new, start, l1);
1394 memcpy(new + l1, field_start, l2);
1395 memcpy(new + l1 + l2, brace_end, l3);
1396 new[l1 + l2 + l3] = '\0';
1397 alt_expand(wp, new, new + l1,
1398 new + l1 + l2 + l3, fdo);
1399 field_start = p + 1;
1400 }
1401 }
1402 }
1403 return;
1404 }
1405 #endif /* BRACE_EXPAND */
1406