diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Doc/Zsh/expn.yo | 3 | ||||
-rw-r--r-- | Src/glob.c | 65 |
3 files changed, 66 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog index 8dc686dec..39a4ae592 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2001-07-06 Peter Stephenson <pws@pwstephenson.fsnet.co.uk> + + * 15266: Src/glob.c, Doc/Zsh/expn.yo: ${(S)...%%...} matches + were wrong; try desperately to explain that in ${(SI:...:)...%%...} + and ${(SI:...:)...%...} indices count matches finishing + progressively earlier in the string. + 2001-07-05 Peter Stephenson <pws@csr.com> * 15264: Doc/Zsh/grammar.yo: improve description of use of diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 562e9bef2..d75450f7e 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -793,7 +793,8 @@ flag, or with tt(${)...tt(/)...tt(}) (only the var(expr)th match is substituted) or tt(${)...tt(//)...tt(}) (all matches from the var(expr)th on are substituted). The var(expr)th match is counted such that there is either one or zero matches from each starting -position in the string, although for global substitution matches +position in the string when scanning forwards, or to each finishing +position when scanning backwards, although for global substitution matches overlapping previous replacements are ignored. ) item(tt(M))( diff --git a/Src/glob.c b/Src/glob.c index 5be79329b..12e911d69 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2068,7 +2068,7 @@ set_pat_end(Patprog p, char null_me) static int igetmatch(char **sp, Patprog p, int fl, int n, char *replstr) { - char *s = *sp, *t, sav; + char *s = *sp, *t, sav, *furthestend, *longeststart, *lastend; int i, l = strlen(*sp), ml = ztrlen(*sp), matched = 1; repllist = NULL; @@ -2243,19 +2243,17 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr) *sp = get_match_ret(*sp, l, l, fl, replstr); patoffset = 0; return 1; - } /* fall through */ - case (SUB_END|SUB_LONG|SUB_SUBSTR): - /* Longest/shortest at end, matching substrings. */ + } patoffset--; for (t = s + l - 1; t >= s; t--, patoffset--) { if (t > s && t[-1] == Meta) t--; set_pat_start(p, t-s); if (pattry(p, t) && patinput > t && !--n) { - /* Found the longest match */ - char *mpos = patinput; - if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { - char *ptr; + /* Found a match from this point */ + char *mpos = patinput, *ptr; + if (!(p->flags & PAT_PURES)) { + /* See if there's a shorter to anywhere */ for (ptr = t; ptr < mpos; METAINC(ptr)) { sav = *ptr; set_pat_end(p, sav); @@ -2282,6 +2280,57 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr) } patoffset = 0; break; + + case (SUB_END|SUB_LONG|SUB_SUBSTR): + /* + * Longest at end, matching substrings. Scan up from + * start, remembering the furthest we got. The + * longest string to reach that point wins. + */ + furthestend = longeststart = lastend = NULL; + sav = '\0'; + while (n) { + int l2 = strlen(s); + for (i = 0, t = s; i <= l2; i++, t++, patoffset++) { + set_pat_start(p, t-s); + if (pattry(p, t)) { + if (!furthestend || + patinput - t > furthestend - longeststart) { + furthestend = patinput; + longeststart = t; + } + } + if (*t == Meta) + t++, i++; + } + if (furthestend) { + if (lastend) { + *lastend = sav; + lastend = NULL; + } + if (--n && furthestend > s) { + lastend = (furthestend > s+1 && furthestend[-2] + == Meta) ? furthestend-2 : furthestend-1; + sav = *lastend; + set_pat_end(p, sav); + *lastend = '\0'; + furthestend = NULL; + patoffset = 0; + continue; + } + } + break; + } + if (lastend) + *lastend = sav; + if (!n) { + *sp = get_match_ret(*sp, longeststart-s, furthestend-s, fl, + replstr); + patoffset = 0; + return 1; + } + patoffset = 0; + break; } } |