diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index cbdae4d58..b3396721f 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1422,7 +1422,7 @@ error, and the flag itself has no effect. enditem() The following flags are meaningful with the tt(${)...tt(#)...tt(}) or -tt(${)...tt(%)...tt(}) forms. The tt(S) and tt(I) flags may also be +tt(${)...tt(%)...tt(}) forms. The tt(S), tt(I), and tt(*) flags may also be used with the tt(${)...tt(/)...tt(}) forms. startitem() @@ -1488,6 +1488,10 @@ will remove the same matches as for `tt(#)', but in reverse order, and the form using `tt(%%)' will remove the same matches as for `tt(##)' in reverse order. ) +item(tt(*))( +Enable tt(EXTENDED_GLOB) for substitution via tt(${)...tt(/)...tt(}) or +tt(${)...tt(//)...tt(}). +) item(tt(B))( Include the index of the beginning of the match in the result. ) diff --git a/Src/subst.c b/Src/subst.c index b98ddaf02..2af61653a 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1708,7 +1708,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, /* * This expressive name refers to the set of flags which * is applied to matching for #, %, / and their doubled variants: - * (M), (R), (B), (E), (N), (S). + * (M), (R), (B), (E), (N), (S), (*). */ int flags = 0; /* Value from (I) flag, used for ditto. */ @@ -1930,6 +1930,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, case '@': nojoin = 2; /* nojoin = 2 means force */ break; + case '*': + case Star: + flags |= SUB_EGLOB; + break; case 'M': flags |= SUB_MATCH; break; @@ -2810,7 +2814,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, c == '#' || c == Pound || c == '?' || c == Quest || c == '/')) { - + int eglob = isset(EXTENDEDGLOB); /* * Default index is 1 if no (I) or (I) gave zero. But * why don't we set the default explicitly at the start @@ -2832,9 +2836,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, char *ptr; /* * previous flags are irrelevant, except for (S) which - * indicates shortest substring; else look for longest. + * indicates shortest substring; else look for longest, + # and (*) which temporarily enables extended globbing. */ - flags = (flags & SUB_SUBSTR) ? 0 : SUB_LONG; + flags = ((flags & SUB_SUBSTR) ? 0 : SUB_LONG)|(flags & SUB_EGLOB); if ((c = *s) == '/') { /* doubled, so replace all occurrences */ flags |= SUB_GLOBAL; @@ -3136,7 +3141,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, for (ap = aval; *ap; ap++) { untokenize(*ap); } + if (flags & SUB_EGLOB) + opts[EXTENDEDGLOB] = 1; getmatcharr(&aval, s, flags, flnum, replstr); + opts[EXTENDEDGLOB] = eglob; } else { if (vunset) { if (vunset > 0 && unset(UNSET)) { @@ -3151,7 +3159,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, copied = 1; untokenize(val); } + if (flags & SUB_EGLOB) + opts[EXTENDEDGLOB] = 1; getmatch(&val, s, flags, flnum, replstr); + opts[EXTENDEDGLOB] = eglob; } break; } diff --git a/Src/zsh.h b/Src/zsh.h index 94f5099c6..6cf1b4186 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1991,6 +1991,7 @@ struct tieddata { #define SUB_START 0x1000 /* force match at start with SUB_END * and no SUB_SUBSTR */ #define SUB_LIST 0x2000 /* no substitution, return list of matches */ +#define SUB_EGLOB 0x4000 /* use extended globbing in patterns */ /* * Structure recording multiple matches inside a test string. diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index f250244e7..176846d46 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -792,6 +792,11 @@ *>*/glob.tmp/(flip|flop) *>*/glob.tmp/(flip|flop)/trailing/components + unsetopt extendedglob + print -r -- ${(*)=${(@s.+.):-A+B}/(#b)(?)/-${(L)match[1]} ${match[1]}} +0:the '*' qualfier enables extended_glob for pattern matching +>-a A -b B + %clean # Fix unreadable-directory permissions so ztst can clean up properly