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