1 /* $OpenBSD: eval.c,v 1.38 2013/06/19 12:19:02 millert Exp $ */
4 * Expansion - quoting, separation, substitution, globbing
15 * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
16 * second pass: alternation ({,}), filename expansion (*?[]).
19 /* expansion generator state */
20 typedef struct Expand
{
21 /* int type; */ /* see expand() */
22 const char *str
; /* string */
24 const char **strv
;/* string[] */
25 struct shf
*shf
;/* file */
27 struct tbl
*var
; /* variable in ${var..} */
28 short split
; /* split "$@" / call waitlast $() */
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 #define XSUBMID 6 /* middle of expanding ${} */
39 /* States used for field splitting */
40 #define IFS_WORD 0 /* word has chars (or quotes) */
41 #define IFS_WS 1 /* have seen IFS white-space */
42 #define IFS_NWS 2 /* have seen IFS non-white-space */
44 static int varsub(Expand
*, char *, char *, int *, int *);
45 static int comsub(Expand
*, char *);
46 static char *trimsub(char *, char *, int);
47 static void glob(char *, XPtrV
*, int);
48 static void globit(XString
*, char **, char *, XPtrV
*, int);
49 static char *maybe_expand_tilde(char *, XString
*, char **, int);
50 static char *tilde(char *);
51 static char *homedir(char *);
53 static void alt_expand(XPtrV
*, char *, char *, char *, int);
56 /* compile and expand word */
58 substitute(const char *cp
, int f
)
60 struct source
*s
, *sold
;
63 s
= pushs(SWSTR
, ATEMP
);
64 s
->start
= s
->str
= cp
;
66 if (yylex(ONEWORD
) != LWORD
)
67 internal_errorf(1, "substitute");
70 return evalstr(yylval
.cp
, f
);
77 eval(char **ap
, int f
)
84 XPput(w
, NULL
); /* space for shell name */
88 return (char **) XPclose(w
) + 1;
95 evalstr(char *cp
, int f
)
101 cp
= (XPsize(w
) == 0) ? null
: (char*) *XPptrv(w
);
107 * expand string - return only one component
108 * used from iosetup to expand redirection files
111 evalonestr(char *cp
, int f
)
122 cp
= (char*) *XPptrv(w
);
125 cp
= evalstr(cp
, f
&~DOGLOB
);
132 /* for nested substitution: ${var:=$var2} */
133 typedef struct SubType
{
134 short stype
; /* [=+-?%#] action after expanded word */
135 short base
; /* begin position of expanded word */
136 short f
; /* saved value of f (DOPAT, etc) */
137 struct tbl
*var
; /* variable for ${var..} */
138 short quote
; /* saved value of quote (for ${..[%#]..}) */
139 struct SubType
*prev
; /* old type */
140 struct SubType
*next
; /* poped type (to avoid re-allocating) */
144 expand(char *cp
, /* input word */
145 XPtrV
*wp
, /* output words */
146 int f
) /* DO* flags */
149 int type
; /* expansion type */
150 int quote
= 0; /* quoted */
151 XString ds
; /* destination string */
152 char *dp
, *sp
; /* dest., source */
153 int fdo
, word
; /* second pass flags; have word */
154 int doblank
; /* field splitting of parameter/command subst */
156 /* expansion variables */
157 NULL
, { NULL
}, NULL
, 0
159 SubType st_head
, *st
;
160 int newlines
= 0; /* For trailing newlines in COMSUB */
161 int saw_eq
, tilde_ok
;
166 internal_errorf(1, "expand(NULL)");
167 /* for alias, readonly, set, typeset commands */
168 if ((f
& DOVACHECK
) && is_wdvarassign(cp
)) {
169 f
&= ~(DOVACHECK
|DOBLANK
|DOGLOB
|DOTILDE
);
177 if (Flag(FBRACEEXPAND
) && (f
& DOGLOB
))
179 #endif /* BRACE_EXPAND */
181 Xinit(ds
, dp
, 128, ATEMP
); /* init dest. string */
186 tilde_ok
= (f
& (DOTILDE
|DOASNTILDE
)) ? 1 : 0; /* must be 1/0 */
189 word
= (f
&DOBLANK
) ? IFS_WS
: IFS_WORD
;
190 st_head
.next
= (SubType
*) 0;
197 case XBASE
: /* original prefixed string */
207 quote
|= 2; /* temporary quote */
220 if (f
& DONTRUNCOMMAND
) {
222 *dp
++ = '$'; *dp
++ = '(';
223 while (*sp
!= '\0') {
229 type
= comsub(&x
, sp
);
230 if (type
== XCOM
&& (f
&DOBLANK
))
232 sp
= strchr(sp
, 0) + 1;
239 if (f
& DONTRUNCOMMAND
) {
240 *dp
++ = '$'; *dp
++ = '('; *dp
++ = '(';
241 while (*sp
!= '\0') {
245 *dp
++ = ')'; *dp
++ = ')';
250 v
.flag
= DEFINED
|ISSET
|INTEGER
;
251 v
.type
= 10; /* not default */
253 v_evaluate(&v
, substitute(sp
, 0),
254 KSH_UNWIND_ERROR
, true);
255 sp
= strchr(sp
, 0) + 1;
256 for (p
= str_val(&v
); *p
; ) {
262 case OSUBST
: /* ${{#}var{:}[=+-?#%]word} */
264 * OSUBST [{x] plain-variable-part \0
265 * compiled-word-part CSUBST [}x]
266 * This is where all syntax checking gets done...
269 char *varname
= ++sp
; /* skip the { or x (}) */
273 sp
= strchr(sp
, '\0') + 1; /* skip variable */
274 type
= varsub(&x
, varname
, sp
, &stype
, &slen
);
279 sp
= varname
- 2; /* restore sp */
280 end
= (char *) wdscan(sp
, CSUBST
);
281 /* ({) the } or x is already skipped */
284 str
= snptreef(NULL
, 64, "%S", sp
);
286 errorf("%s: bad substitution", str
);
291 if (type
== XBASE
) { /* expand? */
295 newst
= (SubType
*) alloc(
296 sizeof(SubType
), ATEMP
);
297 newst
->next
= (SubType
*) 0;
303 st
->base
= Xsavepos(ds
, dp
);
307 /* skip qualifier(s) */
310 switch (stype
& 0x7f) {
313 /* ! DOBLANK,DOBRACE_,DOTILDE */
314 f
= DOPAT
| (f
&DONTRUNCOMMAND
) |
317 /* Prepend open pattern (so |
318 * in a trim will work as
325 /* Enabling tilde expansion
327 * non-standard ksh, but is
328 * consistent with rules for
329 * other assignments. Not
330 * sure what POSIX thinks of
332 * Not doing tilde expansion
333 * for integer variables is a
334 * non-POSIX thing - makes
335 * sense though, since ~ is
336 * a arithmetic operator.
338 if (!(x
.var
->flag
& INTEGER
))
339 f
|= DOASNTILDE
|DOTILDE
;
341 /* These will be done after the
342 * value has been assigned.
344 f
&= ~(DOBLANK
|DOGLOB
|DOBRACE_
);
352 /* Enable tilde expansion */
358 sp
= (char *) wdscan(sp
, CSUBST
);
361 case CSUBST
: /* only get here if expanding word */
362 sp
++; /* ({) skip the } or x */
363 tilde_ok
= 0; /* in case of ${unset:-} */
369 switch (st
->stype
&0x7f) {
372 /* Append end-pattern */
373 *dp
++ = MAGIC
; *dp
++ = ')'; *dp
= '\0';
374 dp
= Xrestpos(ds
, dp
, st
->base
);
375 /* Must use st->var since calling
376 * global would break things
379 x
.str
= trimsub(str_val(st
->var
),
381 if (x
.str
[0] != '\0' || st
->quote
)
390 /* Restore our position and substitute
391 * the value of st->var (may not be
392 * the assigned value in the presence
393 * of integer/right-adj/etc attributes).
395 dp
= Xrestpos(ds
, dp
, st
->base
);
396 /* Must use st->var since calling
397 * global would cause with things
398 * like x[i+=1] to be evaluated twice.
400 /* Note: not exported by FEXPORT
403 /* XXX POSIX says readonly is only
404 * fatal for special builtins (setstr
405 * does readonly check).
407 len
= strlen(dp
) + 1;
409 debunk((char *) alloc(len
, ATEMP
),
410 dp
, len
), KSH_UNWIND_ERROR
);
411 x
.str
= str_val(st
->var
);
419 char *s
= Xrestpos(ds
, dp
, st
->base
);
421 errorf("%s: %s", st
->var
->name
,
423 "parameter null or not set" :
424 (debunk(s
, s
, strlen(s
) + 1), s
));
431 case OPAT
: /* open pattern: *(foo|bar) */
432 /* Next char is the type of pattern */
437 case SPAT
: /* pattern separator (|) */
442 case CPAT
: /* close pattern */
450 /* Special case for "$@" (and "${foo[@]}") - no
451 * word is generated if $# is 0 (unless there is
452 * other stuff inside the quotes).
457 /* not really correct: x=; "$x$@" should
458 * generate a null argument and
459 * set A; "${@:+}" shouldn't.
461 if (dp
== Xstring(ds
, dp
))
468 if ((c
= *x
.str
++) == 0) {
480 if ((c
= *x
.str
++) == '\0') {
481 /* force null words to be created so
482 * set -- '' 2 ''; foo "$@" will do
485 if (quote
&& x
.split
)
487 if ((x
.str
= *x
.u
.strv
++) == NULL
) {
495 if (quote
&& !x
.split
)
499 if (quote
&& x
.split
) {
500 /* terminate word for "$@" */
508 if (newlines
) { /* Spit out saved nl's */
512 while ((c
= shf_getc(x
.u
.shf
)) == 0 || c
== '\n')
514 newlines
++; /* Save newlines */
515 if (newlines
&& c
!= EOF
) {
516 shf_ungetc(c
, x
.u
.shf
);
525 subst_exstat
= waitlast();
534 /* check for end of word or IFS separation */
535 if (c
== 0 || (!quote
&& (f
& DOBLANK
) && doblank
&&
536 !make_magic
&& ctype(c
, C_IFS
))) {
537 /* How words are broken up:
540 * -----------------------------------
541 * IFS_WORD w/WS w/NWS w
542 * IFS_WS -/WS w/NWS -
543 * IFS_NWS -/NWS w/NWS w
544 * (w means generate a word)
545 * Note that IFS_NWS/0 generates a word (at&t ksh
546 * doesn't do this, but POSIX does).
548 if (word
== IFS_WORD
||
549 (!ctype(c
, C_IFSWS
) && c
&& word
== IFS_NWS
)) {
556 /* also does globbing */
558 p
+ Xlength(ds
, (dp
- 1)),
559 fdo
| (f
& DOMARKDIRS
));
561 #endif /* BRACE_EXPAND */
563 glob(p
, wp
, f
& DOMARKDIRS
);
564 else if ((f
& DOPAT
) || !(fdo
& DOMAGIC_
))
567 XPput(*wp
, debunk(p
, p
, strlen(p
) + 1));
570 tilde_ok
= (f
& (DOTILDE
|DOASNTILDE
)) ? 1 : 0;
572 Xinit(ds
, dp
, 128, ATEMP
);
577 word
= ctype(c
, C_IFSWS
) ? IFS_WS
: IFS_NWS
;
580 if (word
== IFS_NWS
&&
581 Xlength(ds
, dp
) == 0) {
584 if ((p
= strdup("")) == NULL
)
585 internal_errorf(1, "unable "
586 "to allocate memory");
592 /* age tilde_ok info - ~ code tests second bit */
594 /* mark any special second pass chars */
601 /* For character classes - doesn't hurt
602 * to have magic !,-,]'s outside of
605 if (f
& (DOPAT
| DOGLOB
)) {
614 if (f
& (DOPAT
| DOGLOB
)) {
615 fdo
|= DOMAGIC_
| (f
& DOGLOB
);
623 if ((f
& DOBRACE_
) && (c
== OBRACE
||
625 fdo
|= DOBRACE_
|DOMAGIC_
;
629 #endif /* BRACE_EXPAND */
631 /* Note first unquoted = for ~ */
632 if (!(f
& DOTEMP_
) && !saw_eq
) {
638 /* Note unquoted : for ~ */
639 if (!(f
& DOTEMP_
) && (f
& DOASNTILDE
))
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=}~
649 (f
& (DOTILDE
|DOASNTILDE
)) &&
654 p
= maybe_expand_tilde(sp
,
668 quote
&= ~2; /* undo temporary */
672 fdo
|= DOMAGIC_
| (f
& DOGLOB
);
674 } else if (ISMAGIC(c
)) {
678 *dp
++ = c
; /* save output char */
685 * Prepare to generate the string returned by ${} substitution.
688 varsub(Expand
*xp
, char *sp
, char *word
,
689 int *stypep
, /* becomes qualifier type */
690 int *slenp
) /* " " len (=, :=, etc.) valid iff *stypep != 0 */
693 int state
; /* next state: XBASE, XARG, XSUB, XNULLSUB */
694 int stype
; /* substitution type */
699 if (sp
[0] == '\0') /* Bad variable name */
702 xp
->var
= (struct tbl
*) 0;
704 /* ${#var}, string length or array size */
705 if (sp
[0] == '#' && (c
= sp
[1]) != '\0') {
708 /* Can't have any modifiers for ${#...} */
712 /* Check for size of array */
713 if ((p
=strchr(sp
,'[')) && (p
[1]=='*'||p
[1]=='@') && p
[2]==']') {
717 vp
= global(arrayname(sp
));
718 if (vp
->flag
& (ISSET
|ARRAY
))
720 for (; vp
; vp
= vp
->u
.array
)
721 if (vp
->flag
& ISSET
) {
725 c
= n
; /* ksh88/ksh93 go for number, not max index */
726 } else if (c
== '*' || c
== '@')
729 p
= str_val(global(sp
));
733 if (Flag(FNOUNSET
) && c
== 0 && !zero_ok
)
734 errorf("%s: parameter not set", sp
);
735 *stypep
= 0; /* unqualified variable/string substitution */
736 xp
->str
= str_save(ulton((unsigned long)c
, 10), ATEMP
);
740 /* Check for qualifiers in word part */
742 c
= word
[slen
= 0] == CHAR
? word
[1] : 0;
746 c
= word
[slen
+ 0] == CHAR
? word
[slen
+ 1] : 0;
748 if (ctype(c
, C_SUBOP1
)) {
751 } else if (ctype(c
, C_SUBOP2
)) { /* Note: ksh88 allows :%, :%%, etc */
754 if (word
[slen
+ 0] == CHAR
&& c
== word
[slen
+ 1]) {
758 } else if (stype
) /* : is not ok */
760 if (!stype
&& *word
!= CSUBST
)
766 if (c
== '*' || c
== '@') {
767 switch (stype
& 0x7f) {
768 case '=': /* can't assign to a vector */
769 case '%': /* can't trim a vector (yet) */
773 if (e
->loc
->argc
== 0) {
775 xp
->var
= global(sp
);
776 state
= c
== '@' ? XNULLSUB
: XSUB
;
778 xp
->u
.strv
= (const char **) e
->loc
->argv
+ 1;
779 xp
->str
= *xp
->u
.strv
++;
780 xp
->split
= c
== '@'; /* $@ */
784 if ((p
=strchr(sp
,'[')) && (p
[1]=='*'||p
[1]=='@') && p
[2]==']') {
787 switch (stype
& 0x7f) {
788 case '=': /* can't assign to a vector */
789 case '%': /* can't trim a vector (yet) */
795 vp
= global(arrayname(sp
));
796 for (; vp
; vp
= vp
->u
.array
) {
797 if (!(vp
->flag
&ISSET
))
799 XPput(wv
, str_val(vp
));
801 if (XPsize(wv
) == 0) {
803 state
= p
[1] == '@' ? XNULLSUB
: XSUB
;
807 xp
->u
.strv
= (const char **) XPptrv(wv
);
808 xp
->str
= *xp
->u
.strv
++;
809 xp
->split
= p
[1] == '@'; /* ${foo[@]} */
813 /* Can't assign things like $! or $1 */
814 if ((stype
& 0x7f) == '=' &&
815 (ctype(*sp
, C_VAR1
) || digit(*sp
)))
817 xp
->var
= global(sp
);
818 xp
->str
= str_val(xp
->var
);
824 /* test the compiler's code generator */
825 if (ctype(c
, C_SUBOP2
) ||
826 (((stype
&0x80) ? *xp
->str
=='\0' : xp
->str
==null
) ? /* undef? */
827 c
== '=' || c
== '-' || c
== '?' : c
== '+'))
828 state
= XBASE
; /* expand word instead of variable value */
829 if (Flag(FNOUNSET
) && xp
->str
== null
&&
830 (ctype(c
, C_SUBOP2
) || (state
!= XBASE
&& c
!= '+')))
831 errorf("%s: parameter not set", sp
);
836 * Run the command in $(...) and read its output.
839 comsub(Expand
*xp
, char *cp
)
845 s
= pushs(SSTRING
, ATEMP
);
846 s
->start
= s
->str
= cp
;
855 if (t
!= NULL
&& t
->type
== TCOM
&& /* $(<file) */
856 *t
->args
== NULL
&& *t
->vars
== NULL
&& t
->ioact
!= NULL
) {
857 struct ioword
*io
= *t
->ioact
;
860 if ((io
->flag
&IOTYPE
) != IOREAD
)
861 errorf("funny $() command: %s",
862 snptreef((char *) 0, 32, "%R", io
));
863 shf
= shf_open(name
= evalstr(io
->name
, DOTILDE
), O_RDONLY
, 0,
864 SHF_MAPHI
|SHF_CLEXEC
);
866 errorf("%s: cannot open $() input", name
);
867 xp
->split
= 0; /* no waitlast() */
869 int errexit
, ofd1
, pv
[2];
871 shf
= shf_fdopen(pv
[0], SHF_RD
, (struct shf
*) 0);
874 ksh_dup2(pv
[1], 1, false);
878 * Clear FERREXIT temporarily while we execute the command.
879 * We cannot simply pass XERROK since the tree might include
882 errexit
= Flag(FERREXIT
);
884 execute(t
, XFORK
|XXCOM
|XPIPEO
, NULL
);
885 Flag(FERREXIT
) = errexit
;
888 xp
->split
= 1; /* waitlast() */
896 * perform #pattern and %pattern substitution in ${}
900 trimsub(char *str
, char *pat
, int how
)
902 char *end
= strchr(str
, 0);
905 switch (how
&0xff) { /* UCHAR_MAX maybe? */
906 case '#': /* shortest at beginning */
907 for (p
= str
; p
<= end
; p
++) {
909 if (gmatch(str
, pat
, false)) {
916 case '#'|0x80: /* longest match at beginning */
917 for (p
= end
; p
>= str
; p
--) {
919 if (gmatch(str
, pat
, false)) {
926 case '%': /* shortest match at end */
927 for (p
= end
; p
>= str
; p
--) {
928 if (gmatch(p
, pat
, false))
929 return str_nsave(str
, p
- str
, ATEMP
);
932 case '%'|0x80: /* longest match at end */
933 for (p
= str
; p
<= end
; p
++) {
934 if (gmatch(p
, pat
, false))
935 return str_nsave(str
, p
- str
, ATEMP
);
940 return str
; /* no match, return string */
945 * Name derived from V6's /etc/glob, the program that expanded filenames.
948 /* XXX cp not const 'cause slashes are temporarily replaced with nulls... */
950 glob(char *cp
, XPtrV
*wp
, int markdirs
)
952 int oldsize
= XPsize(*wp
);
954 if (glob_str(cp
, wp
, markdirs
) == 0)
955 XPput(*wp
, debunk(cp
, cp
, strlen(cp
) + 1));
957 qsortp(XPptrv(*wp
) + oldsize
, (size_t)(XPsize(*wp
) - oldsize
),
962 #define GF_EXCHECK BIT(0) /* do existence check on file */
963 #define GF_GLOBBED BIT(1) /* some globbing has been done */
964 #define GF_MARKDIR BIT(2) /* add trailing / to directories */
966 /* Apply file globbing to cp and store the matching files in wp. Returns
967 * the number of matches found.
970 glob_str(char *cp
, XPtrV
*wp
, int markdirs
)
972 int oldsize
= XPsize(*wp
);
976 Xinit(xs
, xp
, 256, ATEMP
);
977 globit(&xs
, &xp
, cp
, wp
, markdirs
? GF_MARKDIR
: GF_NONE
);
980 return XPsize(*wp
) - oldsize
;
984 globit(XString
*xs
, /* dest string */
985 char **xpp
, /* ptr to dest end */
986 char *sp
, /* source path */
987 XPtrV
*wp
, /* output list */
988 int check
) /* GF_* flags */
990 char *np
; /* next source component */
995 /* This to allow long expansions to be interrupted */
998 if (sp
== NULL
) { /* end of source path */
999 /* We only need to check if the file exists if a pattern
1000 * is followed by a non-pattern (eg, foo*x/bar; no check
1001 * is needed for foo* since the match must exist) or if
1002 * any patterns were expanded and the markdirs option is set.
1003 * Symlinks make things a bit tricky...
1005 if ((check
& GF_EXCHECK
) ||
1006 ((check
& GF_MARKDIR
) && (check
& GF_GLOBBED
))) {
1007 #define stat_check() (stat_done ? stat_done : \
1008 (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
1010 struct stat lstatb
, statb
;
1011 int stat_done
= 0; /* -1: failed, 1 ok */
1013 if (lstat(Xstring(*xs
, xp
), &lstatb
) < 0)
1015 /* special case for systems which strip trailing
1016 * slashes from regular files (eg, /etc/passwd/).
1017 * SunOS 4.1.3 does this...
1019 if ((check
& GF_EXCHECK
) && xp
> Xstring(*xs
, xp
) &&
1020 xp
[-1] == '/' && !S_ISDIR(lstatb
.st_mode
) &&
1021 (!S_ISLNK(lstatb
.st_mode
) ||
1022 stat_check() < 0 || !S_ISDIR(statb
.st_mode
)))
1024 /* Possibly tack on a trailing / if there isn't already
1025 * one and if the file is a directory or a symlink to a
1028 if (((check
& GF_MARKDIR
) && (check
& GF_GLOBBED
)) &&
1029 xp
> Xstring(*xs
, xp
) && xp
[-1] != '/' &&
1030 (S_ISDIR(lstatb
.st_mode
) ||
1031 (S_ISLNK(lstatb
.st_mode
) && stat_check() > 0 &&
1032 S_ISDIR(statb
.st_mode
)))) {
1037 XPput(*wp
, str_nsave(Xstring(*xs
, xp
), Xlength(*xs
, xp
), ATEMP
));
1041 if (xp
> Xstring(*xs
, xp
))
1043 while (*sp
== '/') {
1047 np
= strchr(sp
, '/');
1050 odirsep
= *np
; /* don't assume '/', can be multiple kinds */
1053 odirsep
= '\0'; /* keep gcc quiet */
1054 se
= sp
+ strlen(sp
);
1058 /* Check if sp needs globbing - done to avoid pattern checks for strings
1059 * containing MAGIC characters, open ['s without the matching close ],
1060 * etc. (otherwise opendir() will be called which may fail because the
1061 * directory isn't readable - if no globbing is needed, only execute
1062 * permission should be required (as per POSIX)).
1064 if (!has_globbing(sp
, se
)) {
1065 XcheckN(*xs
, xp
, se
- sp
+ 1);
1066 debunk(xp
, sp
, Xnleft(*xs
, xp
));
1069 globit(xs
, xpp
, np
, wp
, check
);
1077 /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */
1079 prefix_len
= Xlength(*xs
, xp
);
1080 dirp
= opendir(prefix_len
? Xstring(*xs
, xp
) : ".");
1083 while ((d
= readdir(dirp
)) != NULL
) {
1085 if (name
[0] == '.' &&
1086 (name
[1] == 0 || (name
[1] == '.' && name
[2] == 0)))
1087 continue; /* always ignore . and .. */
1088 if ((*name
== '.' && *sp
!= '.') ||
1089 !gmatch(name
, sp
, true))
1092 len
= strlen(d
->d_name
) + 1;
1093 XcheckN(*xs
, xp
, len
);
1094 memcpy(xp
, name
, len
);
1095 *xpp
= xp
+ len
- 1;
1096 globit(xs
, xpp
, np
, wp
,
1097 (check
& GF_MARKDIR
) | GF_GLOBBED
1098 | (np
? GF_EXCHECK
: GF_NONE
));
1099 xp
= Xstring(*xs
, xp
) + prefix_len
;
1110 /* Check if p contains something that needs globbing; if it does, 0 is
1111 * returned; if not, p is copied into xs/xp after stripping any MAGICs
1113 static int copy_non_glob(XString
*xs
, char **xpp
, char *p
);
1115 copy_non_glob(XString
*xs
, char **xpp
, char *p
)
1118 int len
= strlen(p
);
1120 XcheckN(*xs
, *xpp
, len
);
1126 if (c
== '*' || c
== '?')
1131 if (ISMAGIC(*q
) && q
[1] == NOT
)
1133 if (ISMAGIC(*q
) && q
[1] == ']')
1136 if (ISMAGIC(*q
) && *++q
== ']')
1138 /* pass a literal [ through */
1140 /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */
1150 /* remove MAGIC from string */
1152 debunk(char *dp
, const char *sp
, size_t dlen
)
1156 if ((s
= strchr(sp
, MAGIC
))) {
1159 memcpy(dp
, sp
, s
- sp
);
1160 for (d
= dp
+ (s
- sp
); *s
&& (d
- dp
< dlen
); s
++)
1161 if (!ISMAGIC(*s
) || !(*++s
& 0x80) ||
1162 !strchr("*+?@! ", *s
& 0x7f))
1165 /* extended pattern operators: *+?@! */
1166 if ((*s
& 0x7f) != ' ')
1172 } else if (dp
!= sp
)
1173 strlcpy(dp
, sp
, dlen
);
1177 /* Check if p is an unquoted name, possibly followed by a / or :. If so
1178 * puts the expanded version in *dcp,dp and returns a pointer in p just
1179 * past the name, otherwise returns 0.
1182 maybe_expand_tilde(char *p
, XString
*dsp
, char **dpp
, int isassign
)
1188 Xinit(ts
, tp
, 16, ATEMP
);
1189 /* : only for DOASNTILDE form */
1190 while (p
[0] == CHAR
&& p
[1] != '/' && (!isassign
|| p
[1] != ':'))
1197 r
= (p
[0] == EOS
|| p
[0] == CHAR
|| p
[0] == CSUBST
) ?
1198 tilde(Xstring(ts
, tp
)) : (char *) 0;
1216 * based on a version by Arnold Robbins
1225 dp
= str_val(global("HOME"));
1226 else if (cp
[0] == '+' && cp
[1] == '\0')
1227 dp
= str_val(global("PWD"));
1228 else if (cp
[0] == '-' && cp
[1] == '\0')
1229 dp
= str_val(global("OLDPWD"));
1232 /* If HOME, PWD or OLDPWD are not set, don't expand ~ */
1239 * map userid to user's home directory.
1240 * note that 4.3's getpw adds more than 6K to the shell,
1241 * and the YP version probably adds much more.
1242 * we might consider our own version of getpwnam() to keep the size down.
1250 ap
= ktenter(&homedirs
, name
, hash(name
));
1251 if (!(ap
->flag
& ISSET
)) {
1254 pw
= getpwnam(name
);
1257 ap
->val
.s
= str_save(pw
->pw_dir
, APERM
);
1258 ap
->flag
|= DEFINED
|ISSET
|ALLOC
;
1265 alt_expand(XPtrV
*wp
, char *start
, char *exp_start
, char *end
, int fdo
)
1268 char *brace_start
, *brace_end
, *comma
= NULL
;
1272 /* search for open brace */
1273 for (p
= exp_start
; (p
= strchr(p
, MAGIC
)) && p
[1] != OBRACE
; p
+= 2)
1277 /* find matching close brace, if any */
1281 for (p
+= 2; *p
&& count
; p
++) {
1285 else if (*p
== CBRACE
)
1287 else if (*p
== ',' && count
== 1)
1292 /* no valid expansions... */
1293 if (!p
|| count
!= 0) {
1294 /* Note that given a{{b,c} we do not expand anything (this is
1295 * what at&t ksh does. This may be changed to do the {b,c}
1299 glob(start
, wp
, fdo
& DOMARKDIRS
);
1301 XPput(*wp
, debunk(start
, start
, end
- start
));
1306 alt_expand(wp
, start
, brace_end
, end
, fdo
);
1310 /* expand expression */
1311 field_start
= brace_start
+ 2;
1313 for (p
= brace_start
+ 2; p
!= brace_end
; p
++) {
1317 else if ((*p
== CBRACE
&& --count
== 0) ||
1318 (*p
== ',' && count
== 1)) {
1322 l1
= brace_start
- start
;
1323 l2
= (p
- 1) - field_start
;
1324 l3
= end
- brace_end
;
1325 new = (char *) alloc(l1
+ l2
+ l3
+ 1, ATEMP
);
1326 memcpy(new, start
, l1
);
1327 memcpy(new + l1
, field_start
, l2
);
1328 memcpy(new + l1
+ l2
, brace_end
, l3
);
1329 new[l1
+ l2
+ l3
] = '\0';
1330 alt_expand(wp
, new, new + l1
,
1331 new + l1
+ l2
+ l3
, fdo
);
1332 field_start
= p
+ 1;
1338 #endif /* BRACE_EXPAND */