From e1c0a947cc845c71dd844db44016d07922cfcefa Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 11 Sep 2015 21:40:45 +0100 Subject: Read full multibyte string early for self-insert --- Src/Zle/zle_hist.c | 4 ++-- Src/Zle/zle_keymap.c | 37 +++++++++++++++++++++++++++++-------- Src/Zle/zle_main.c | 10 ++++++++-- Src/Zle/zle_misc.c | 6 ++---- Src/Zle/zle_vi.c | 2 +- 5 files changed, 42 insertions(+), 17 deletions(-) (limited to 'Src/Zle') diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index c61b4ef0e..0cff0391a 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -1643,7 +1643,7 @@ doisearch(char **args, int dir, int pattern) } else if (cmd == Th(z_selfinsert)) { #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) - if (getrestchar(lastchar) == WEOF) { + if (getrestchar(lastchar, NULL, NULL) == WEOF) { handlefeep(zlenoargs); continue; } @@ -1877,7 +1877,7 @@ getvisrchstr(void) } else { #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) - if (getrestchar(lastchar) == WEOF) { + if (getrestchar(lastchar, NULL, NULL) == WEOF) { handlefeep(zlenoargs); continue; } diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 5b4189faa..069580f8a 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1501,6 +1501,20 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) * they wait till a key is pressed for the movement anyway */ timeout = !(!virangeflag && !region_active && f && f->widget && f->widget->flags & ZLE_VIOPER); +#ifdef MULTIBYTE_SUPPORT + if ((f == Th(z_selfinsert) || f == Th(z_selfinsertunmeta)) && + !lastchar_wide_valid) { + int len; + VARARR(char, mbc, MB_CUR_MAX); + ZLE_INT_T inchar = getrestchar(lastchar, mbc, &len); + if (inchar != WEOF && len) { + char *ptr = mbc; + while (len--) + addkeybuf(STOUC(*ptr++)); + lastlen = keybuflen; + } + } +#endif } if (!ispfx) break; @@ -1521,6 +1535,20 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) return keybuf; } +/**/ +static void +addkeybuf(int c) +{ + if(keybuflen + 3 > keybufsz) + keybuf = realloc(keybuf, keybufsz *= 2); + if(imeta(c)) { + keybuf[keybuflen++] = Meta; + keybuf[keybuflen++] = c ^ 32; + } else + keybuf[keybuflen++] = c; + keybuf[keybuflen] = 0; +} + /* * Add a (possibly metafied) byte to the key input so far. * This handles individual bytes of a multibyte string separately; @@ -1542,14 +1570,7 @@ getkeybuf(int w) if(c < 0) return EOF; - if(keybuflen + 3 > keybufsz) - keybuf = realloc(keybuf, keybufsz *= 2); - if(imeta(c)) { - keybuf[keybuflen++] = Meta; - keybuf[keybuflen++] = c ^ 32; - } else - keybuf[keybuflen++] = c; - keybuf[keybuflen] = 0; + addkeybuf(c); return c; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index ec3d2c354..992f152df 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -933,7 +933,7 @@ getfullchar(int do_keytmout) int inchar = getbyte((long)do_keytmout, NULL); #ifdef MULTIBYTE_SUPPORT - return getrestchar(inchar); + return getrestchar(inchar, NULL, NULL); #else return inchar; #endif @@ -951,7 +951,7 @@ getfullchar(int do_keytmout) /**/ mod_export ZLE_INT_T -getrestchar(int inchar) +getrestchar(int inchar, char *outstr, int *outcount) { char c = inchar; wchar_t outchar; @@ -965,6 +965,8 @@ getrestchar(int inchar) */ lastchar_wide_valid = 1; + if (outcount) + *outcount = 0; if (inchar == EOF) { /* End of input, so reset the shift state. */ memset(&mbs, 0, sizeof mbs); @@ -1013,6 +1015,10 @@ getrestchar(int inchar) return lastchar_wide = WEOF; } c = inchar; + if (outstr) { + *outstr++ = c; + (*outcount)++; + } } return lastchar_wide = (ZLE_INT_T)outchar; } diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 2d1862813..12143e05f 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -115,9 +115,7 @@ selfinsert(UNUSED(char **args)) ZLE_CHAR_T tmp; #ifdef MULTIBYTE_SUPPORT - if (!lastchar_wide_valid) - if (getrestchar(lastchar) == WEOF) - return 1; + DPUTS(!lastchar_wide_valid, "keybuf did not read full wide character"); #endif tmp = LASTFULLCHAR; doinsert(&tmp, 1); @@ -1431,7 +1429,7 @@ executenamedcommand(char *prmt) else { #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) - getrestchar(lastchar); + getrestchar(lastchar, NULL, NULL); if (lastchar_wide == WEOF) feep = 1; else diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 42dc46e7e..86840bdd6 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -151,7 +151,7 @@ vigetkey(void) #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) { - getrestchar(lastchar); + getrestchar(lastchar, NULL, NULL); } #endif return LASTFULLCHAR; -- cgit v1.2.3 From d37b59fe0969a619f049dee081b15af696070009 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 11 Sep 2015 21:47:53 +0000 Subject: 36443: Revert "35834: strip a final newline from pasted text: inserting is hard to tell apart from accepting it" This reverts commit f17eb26a34af69a2238a3d8b46079445e09c096e. Conflicts: ChangeLog Src/Zle/zle_misc.c --- ChangeLog | 5 +++++ Src/Zle/zle_misc.c | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 914ee4e47..a484ad7fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-09-11 Daniel Shahaf + + * 36443: Revert 35834. + 2015-09-11 Peter Stephenson * 36496 (plus tweak for key buffer length): Src/Zle/zle_hist.c, @@ -438,6 +442,7 @@ * 35834 (tweaked): Src/Zle/zle_misc.c: strip a final newline from pasted text: inserting is hard to tell apart from accepting it + [reverted in 36443] 2015-08-12 Mikael Magnusson diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 12143e05f..297dc4ca8 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -785,12 +785,6 @@ bracketedpaste(char **args) zmult = 1; if (region_active) killregion(zlenoargs); - /* Chop a final newline if its insertion would be hard to - * distinguish by the user from the line being accepted. */ - else if (n > 1 && zlecontext != ZLCON_VARED && - (zlecs + (insmode ? 0 : n - 1)) >= zlell && - wpaste[n-1] == ZWC('\n')) - n--; yankcs = yankb = zlecs; doinsert(wpaste, n); yanke = zlecs; -- cgit v1.2.3 From c76f4f96a65c7bfbba2183c422a1fb567069981f Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 7 Sep 2015 15:50:26 +0000 Subject: 36443: Set zle_highlight=(paste:standout) by default. --- ChangeLog | 3 +++ Doc/Zsh/zle.yo | 2 +- Src/Zle/zle_refresh.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index a484ad7fc..aedeaed4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-09-11 Daniel Shahaf + * 36443: Doc/Zsh/zle.yo Src/Zle/zle_refresh.c: Set + zle_highlight=(paste:standout) by default. + * 36443: Revert 35834. 2015-09-11 Peter Stephenson diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 2c539c460..71a7af0d7 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2679,7 +2679,7 @@ If tt(zle_highlight) is not set or no value applies to a particular context, the defaults applied are equivalent to example(zle_highlight=LPAR()region:standout special:standout -suffix:bold isearch:underline+RPAR()) +suffix:bold isearch:underline paste:standout+RPAR()) i.e. both the region and special characters are shown in standout mode. diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 0c28c0a2d..6facff429 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -372,7 +372,8 @@ zle_set_highlight(void) region_highlights[1].atr = TXTUNDERLINE; if (!suffix_atr_on_set) region_highlights[2].atr = TXTBOLDFACE; - /* paste defaults to 0 */ + if (!paste_atr_on_set) + region_highlights[3].atr = TXTSTANDOUT; allocate_colour_buffer(); } -- cgit v1.2.3 From 8e77fcb050ed09042cc2464f804ac023c0f88b42 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 12 Sep 2015 16:13:01 -0700 Subject: 36522: unmetafy the argument of "zle -U" --- ChangeLog | 2 ++ Src/Zle/zle_thingy.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 3aa4f208a..1ce47d7f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-09-12 Barton E. Schaefer + * 36522: Src/Zle/zle_thingy.c: unmetafy the argument of "zle -U" + * 36509: Src/Modules/curses.c: allocate hash table nodes with zshcalloc() to avoid garbage flag values diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 7fd3a5941..da3a6d458 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -466,7 +466,7 @@ bin_zle_mesg(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) static int bin_zle_unget(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) { - char *b = *args, *p = b + strlen(b); + char *b = unmeta(*args), *p = b + strlen(b); if (!zleactive) { zwarnnam(name, "can only be called from widget function"); -- cgit v1.2.3 From 8a818381cfa843f6bdc25e3517500da31d63c282 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 12 Sep 2015 20:49:13 -0700 Subject: 36525: revert only the selfinsert() bit of 36496 selfinsert() may be called with incomplete wide character processing from places other than getkeymapcmd() --- ChangeLog | 4 ++++ Src/Zle/zle_misc.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index db594cc5d..79fb2c779 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ 2015-09-12 Barton E. Schaefer + * 36525: Src/Zle/zle_misc.c: revert only the selfinsert() bit of + 36496 because selfinsert() may be called with incomplete wide + character processing from places other than getkeymapcmd() + * unposted: Functions/Zle/bracketed-paste-magic: revert 36483 as multibyte is now handled by "zle .read-command"; adapt to new default behavior of zle_highlight for paste diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 297dc4ca8..0483f758d 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -115,7 +115,10 @@ selfinsert(UNUSED(char **args)) ZLE_CHAR_T tmp; #ifdef MULTIBYTE_SUPPORT - DPUTS(!lastchar_wide_valid, "keybuf did not read full wide character"); + /* may be redundant with getkeymapcmd(), but other widgets call here too */ + if (!lastchar_wide_valid) + if (getrestchar(lastchar, NULL, NULL) == WEOF) + return 1; #endif tmp = LASTFULLCHAR; doinsert(&tmp, 1); -- cgit v1.2.3 From 729f6ddfff8a229c404f0ec2b9d83c89395e541d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 21 Sep 2015 20:33:58 +0100 Subject: 36580: don't copy empty buffer in compmatch. Also check if length is non-zero when buffer is empty. --- ChangeLog | 5 +++++ Src/Zle/compmatch.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 1dd57123c..4a8c0531a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-09-21 Peter Stephenson + + * 36580: Src/Zle/compmatch.c: don't copy empty buffer and check + size is consistent. + 2015-09-21 Frank Terbeck * 36575: Completion/Unix/Command/_tmux: _tmux: ‘lock-server’ diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index 05ae43ae6..b5728a5fe 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -338,8 +338,15 @@ add_match_str(Cmatcher m, char *l, char *w, int wl, int sfx) char *buf; buf = (char *) zalloc(blen); - memcpy(buf, matchbuf, matchbuflen); - zfree(matchbuf, matchbuflen); + if (matchbuf) { + memcpy(buf, matchbuf, matchbuflen); + zfree(matchbuf, matchbuflen); + } +#ifdef DEBUG + else { + DPUTS(matchbuflen, "matchbuflen with no matchbuf"); + } +#endif matchbuf = buf; matchbuflen = blen; } -- cgit v1.2.3 From acf5bd766a7b5d656cdf1c636c8508492c1aadf4 Mon Sep 17 00:00:00 2001 From: Han Pingtian Date: Tue, 22 Sep 2015 05:55:23 +0800 Subject: 36586: fix completion match right anchor --- ChangeLog | 8 +++++++- Doc/Zsh/compwid.yo | 2 +- Src/Zle/compmatch.c | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 897aa1ad6..e5ea4fd30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ 2015-09-22 Peter Stephenson - * 36538: Han Pingtian: Doc/Zsh/compwid.yo: tweak code for match + * 36586: Han Pingtian: Src/Zle/compmatch.c: tweak to completion + matching with right anchor. + + * 36545: Han Pingtian: Doc/Zsh/compwid.yo: tweak doc for match + anchors e and E. + + * 36538: Han Pingtian: Doc/Zsh/compwid.yo: tweak doc for match anchors to get correct difference between b and B. 2015-09-22 Jun-ichi Takimoto diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 303c19db5..c01763316 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -911,7 +911,7 @@ item(tt(E:)var(lpat)tt(=)var(tpat))( As tt(l), tt(L), tt(b) and tt(B), with the difference that the command line and trial completion patterns are anchored on the right side. Here an empty var(ranchor) and the tt(e) and tt(E) forms force the -match to the end of the trial completion or command line string. +match to the end of the command line or trial completion string. ) enditem() diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index b5728a5fe..948144006 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -820,10 +820,12 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp, continue; else if (mp->right) t = pattern_match(mp->right, - tl + mp->llen - mp->ralen, + //tl + mp->llen - mp->ralen, + tl + mp->llen, NULL, NULL) && pattern_match(mp->right, - tw + mp->wlen - mp->ralen, + //tw + mp->wlen - mp->ralen, + tw + mp->wlen, NULL, NULL) && (!mp->lalen || pattern_match(mp->left, tw + mp->wlen - -- cgit v1.2.3 From 1b5987cdb11253e2f399bfff72016af22bad9240 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 23 Sep 2015 21:40:34 +0000 Subject: unposted: Followup to 36586: Change C99 comment syntax to the C89 syntax. --- ChangeLog | 5 +++++ Src/Zle/compmatch.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index f948328a7..b92432044 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-09-23 Daniel Shahaf + + * unposted: Src/Zle/compmatch.c: Followup to 36586: Change C99 + comment syntax to the C89 syntax. + 2015-09-23 Mikael Magnusson * Eric Cook: 36571: Completion/Linux/Command/_losetup, diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index 948144006..0e41ac3a5 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -820,11 +820,11 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp, continue; else if (mp->right) t = pattern_match(mp->right, - //tl + mp->llen - mp->ralen, + /* tl + mp->llen - mp->ralen, */ tl + mp->llen, NULL, NULL) && pattern_match(mp->right, - //tw + mp->wlen - mp->ralen, + /* tw + mp->wlen - mp->ralen, */ tw + mp->wlen, NULL, NULL) && (!mp->lalen || -- cgit v1.2.3 From 8165b488cb223ac58629d99f8df1bda930dd29c0 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 25 Sep 2015 23:38:39 +0000 Subject: unposted: zle: Document the C helper function processcmd(). Also, tweak the docstring of zlelineasstring(). --- ChangeLog | 5 +++++ Src/Zle/zle_tricky.c | 3 +++ Src/Zle/zle_utils.c | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 71788378d..fbd7c3a00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-09-25 Daniel Shahaf + + * unposted: Src/Zle/zle_tricky.c Src/Zle/zle_utils.c: zle: + Document the C helper function processcmd(). + 2015-09-25 Christoph Mathys * 36626: Completion/Unix/Command/_hg: _hg: completion for diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index b1a6f9e7e..e26f66379 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2952,6 +2952,9 @@ getcurcmd(void) return s; } +/* Run '$WIDGET $commandword' and then restore the command-line using push-line. + */ + /**/ int processcmd(UNUSED(char **args)) diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 9751f7a1f..714d911a6 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -166,13 +166,13 @@ zlecharasstring(ZLE_CHAR_T inchar, char *buf) } /* - * Input a line in internal zle format, possibly using wide characters, + * Input: a line in internal zle format, possibly using wide characters, * possibly not, together with its length and the cursor position. * The length must be accurate and includes all characters (no NULL * termination is expected). The input cursor position is only * significant if outcs is non-NULL. * - * Output an ordinary NULL-terminated string, using multibyte characters + * Output: an ordinary NULL-terminated string, using multibyte characters * instead of wide characters where appropriate and with the contents * metafied. * -- cgit v1.2.3 From 50721a1986a3637e923ccc4531135b8aa39c8e70 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 26 Sep 2015 13:46:20 -0700 Subject: 36641: fix multibyte handling in incremental search during menu selection --- ChangeLog | 5 +++++ Src/Zle/complist.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index f700ec067..964e340f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-09-26 Barton E. Schaefer + + * 36641: Src/Modules/complist.c: fix multibyte handling in + incremental search during menu selection + 2015-09-26 Daniel Shahaf * unposted (see 36633): Completion/Unix/Command/_hg: _hg: diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 01bcb7cf8..433701514 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -3300,7 +3300,7 @@ domenuselect(Hookdef dummy, Chdata dat) int len; memset(&mbs, 0, sizeof(mbs)); - len = wcrtomb(s, lastchar_wide, &mbs); + len = wcrtomb(toins, lastchar_wide, &mbs); if (len < 0) len = 0; insert[len] = '\0'; -- cgit v1.2.3 From f9d7651c2554bb5db0373f63185ff358f795ab3c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 28 Sep 2015 20:31:51 +0100 Subject: 36682: expand pattern interface to optimise unmetafication --- ChangeLog | 6 + Src/Zle/complist.c | 5 +- Src/Zle/zle_hist.c | 4 +- Src/glob.c | 56 +++++---- Src/pattern.c | 337 +++++++++++++++++++++++++++++++++++++---------------- Src/zsh.h | 10 ++ 6 files changed, 288 insertions(+), 130 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 546620d6b..38e0e4627 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-09-28 Peter Stephenson + + * 36682: Src/glob.c, Src/pattern.c, Src/zsh.h, + Src/Zle/complist,c, Src/Zle/zle_hist.c: expand pattern interface + to allow unmetafying trial string once for reuse. + 2015-09-28 Daniel Shahaf * unposted: Test/D04parameter.ztst: Test for 36669 diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 433701514..986ad31ea 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -868,7 +868,7 @@ putmatchcol(char *group, char *n) nrefs = MAX_POS - 1; if ((!pc->prog || !group || pattry(pc->prog, group)) && - pattryrefs(pc->pat, n, -1, -1, 0, &nrefs, begpos, endpos)) { + pattryrefs(pc->pat, n, -1, -1, NULL, 0, &nrefs, begpos, endpos)) { if (pc->cols[1]) { patcols = pc->cols; @@ -900,7 +900,8 @@ putfilecol(char *group, char *filename, mode_t m, int special) nrefs = MAX_POS - 1; if ((!pc->prog || !group || pattry(pc->prog, group)) && - pattryrefs(pc->pat, filename, -1, -1, 0, &nrefs, begpos, endpos)) { + pattryrefs(pc->pat, filename, -1, -1, NULL, + 0, &nrefs, begpos, endpos)) { if (pc->cols[1]) { patcols = pc->cols; diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 0cff0391a..95d96c95c 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -1306,8 +1306,8 @@ doisearch(char **args, int dir, int pattern) * this mode. */ if (!skip_pos && - pattryrefs(patprog, zt, -1, -1, 0, NULL, NULL, - &end_pos)) + pattryrefs(patprog, zt, -1, -1, NULL, 0, + NULL, NULL, &end_pos)) t = zt; } else { if (!matchlist && !skip_pos) { diff --git a/Src/glob.c b/Src/glob.c index fa3ce25f4..8bf73520f 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2780,7 +2780,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, p->flags &= ~(PAT_NOTSTART|PAT_NOTEND); if (fl & SUB_ALL) { - int i = matched && pattry(p, s); + int i = matched && pattrylen(p, s, -1, -1, NULL, 0); *sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, NULL); if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i))) return 0; @@ -2809,7 +2809,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * Largest/smallest possible match at head of string. * First get the longest match... */ - if (pattry(p, s)) { + if (pattrylen(p, s, -1, -1, NULL, 0)) { /* patmatchlen returns metafied length, as we need */ int mlen = patmatchlen(); if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { @@ -2820,7 +2820,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, mb_charinit(); for (t = s, umlen = 0; t < s + mlen; ) { set_pat_end(p, *t); - if (pattrylen(p, s, t - s, umlen, 0)) { + if (pattrylen(p, s, t - s, umlen, NULL, 0)) { mlen = patmatchlen(); break; } @@ -2847,7 +2847,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, tmatch = NULL; for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) tmatch = t; if (fl & SUB_START) break; @@ -2857,7 +2857,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, *sp = get_match_ret(*sp, tmatch - s, l, fl, replstr, NULL); return 1; } - if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) { + if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, NULL, ioff)) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } @@ -2870,7 +2870,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL); return 1; } @@ -2878,7 +2878,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, break; umlen -= iincchar(&t); } - if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) { + if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, NULL, ioff)) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } @@ -2887,7 +2887,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, case SUB_SUBSTR: /* Smallest at start, but matching substrings. */ set_pat_start(p, l); - if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) { + if (!(fl & SUB_GLOBAL) && pattrylen(p, s + l, -1, -1, NULL, 0) && + !--n) { *sp = get_match_ret(*sp, 0, 0, fl, replstr, NULL); return 1; } /* fall through */ @@ -2908,7 +2909,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, for (; t < s + l; ioff++) { /* Find the longest match from this position. */ set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { char *mpos = t + patmatchlen(); if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { char *ptr; @@ -2922,7 +2923,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, */ for (ptr = t, umlen2 = 0; ptr < mpos;) { set_pat_end(p, *ptr); - if (pattrylen(p, t, ptr - t, umlen2, ioff)) { + if (pattrylen(p, t, ptr - t, umlen2, + NULL, ioff)) { mpos = t + patmatchlen(); break; } @@ -2970,7 +2972,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, */ set_pat_start(p, l); if ((fl & (SUB_LONG|SUB_GLOBAL)) == SUB_LONG && - pattry(p, s + l) && !--n) { + pattrylen(p, s + l, -1, -1, NULL, 0) && !--n) { *sp = get_match_ret(*sp, 0, 0, fl, replstr, repllist); return 1; } @@ -2981,7 +2983,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, /* Longest/shortest at end, matching substrings. */ if (!(fl & SUB_LONG)) { set_pat_start(p, l); - if (pattrylen(p, s + l, 0, 0, umltot) && !--n) { + if (pattrylen(p, s + l, 0, 0, NULL, umltot) && !--n) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } @@ -3001,7 +3003,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { nmatches++; tmatch = t; } @@ -3017,7 +3019,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff) && + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff) && !n--) { tmatch = t; break; @@ -3030,7 +3032,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { for (t = tmatch, umlen = 0; t < mpos; ) { set_pat_end(p, *t); - if (pattrylen(p, tmatch, t - tmatch, umlen, ioff)) { + if (pattrylen(p, tmatch, t - tmatch, umlen, + NULL, ioff)) { mpos = tmatch + patmatchlen(); break; } @@ -3042,7 +3045,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, return 1; } set_pat_start(p, l); - if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, umltot) && !--n) { + if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, NULL, umltot) && + !--n) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } @@ -3167,7 +3171,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, */ for (t = s, umlen = 0; t < s + mlen; METAINC(t), umlen++) { set_pat_end(p, *t); - if (pattrylen(p, s, t - s, umlen, 0)) { + if (pattrylen(p, s, t - s, umlen, NULL, 0)) { mlen = patmatchlen(); break; } @@ -3187,7 +3191,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, if (t > s && t[-1] == Meta) t--; set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { *sp = get_match_ret(*sp, t - s, l, fl, replstr, NULL); return 1; } @@ -3203,7 +3207,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, for (ioff = 0, t = s, umlen = uml; t < s + l; ioff++, METAINC(t), umlen--) { set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL); return 1; } @@ -3235,7 +3239,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, for (; t < s + l; METAINC(t), ioff++, umlen--) { /* Find the longest match from this position. */ set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff)) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff)) { char *mpos = t + patmatchlen(); if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { char *ptr; @@ -3243,7 +3247,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, for (ptr = t, umlen2 = 0; ptr < mpos; METAINC(ptr), umlen2++) { set_pat_end(p, *ptr); - if (pattrylen(p, t, ptr - t, umlen2, ioff)) { + if (pattrylen(p, t, ptr - t, umlen2, + NULL, ioff)) { mpos = t + patmatchlen(); break; } @@ -3300,7 +3305,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, /* Longest/shortest at end, matching substrings. */ if (!(fl & SUB_LONG)) { set_pat_start(p, l); - if (pattrylen(p, s + l, 0, 0, uml) && !--n) { + if (pattrylen(p, s + l, 0, 0, NULL, uml) && !--n) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } @@ -3310,7 +3315,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, if (t > s && t[-1] == Meta) t--; set_pat_start(p, t-s); - if (pattrylen(p, t, s + l - t, umlen, ioff) && !--n) { + if (pattrylen(p, t, s + l - t, umlen, NULL, ioff) && !--n) { /* Found the longest match */ char *mpos = t + patmatchlen(); if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) { @@ -3319,7 +3324,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, for (ptr = t, umlen2 = 0; ptr < mpos; METAINC(ptr), umlen2++) { set_pat_end(p, *ptr); - if (pattrylen(p, t, ptr - t, umlen2, ioff)) { + if (pattrylen(p, t, ptr - t, umlen2, NULL, ioff)) { mpos = t + patmatchlen(); break; } @@ -3331,7 +3336,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, } } set_pat_start(p, l); - if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, uml) && !--n) { + if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, NULL, uml) && + !--n) { *sp = get_match_ret(*sp, l, l, fl, replstr, NULL); return 1; } diff --git a/Src/pattern.c b/Src/pattern.c index af56bd9cc..03ba37d92 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -2022,6 +2022,131 @@ pattrystart(void) errsfound = 0; } +/* + * Allocate memeory for pattern match. Note this is specific to use + * of pattern *and* trial string. + * + * Unmetafy a trial string for use in pattern matching, if needed. + * + * If it is needed, returns a zalloc()'d string; if not needed, returns + * NULL. + * + * prog is the pattern to be executed. + * string is the metafied trial string. + * stringlen is it's length; it will be calculated if it's negative + * (this is a simple strlen()). + * unmetalen is the unmetafied length of the string, may be -1. + * force is 1 if we always unmetafy: this is useful if we are going + * to try again with different versions of the string. If this is + * called from pattryrefs() we don't force unmetafication as it won't + * be optimal. + * In patstralloc (supplied by caller, must last until last pattry is done) + * unmetalen is the unmetafied length of the string; it will be + * calculated if the input value is negative. + * unmetalenp is the umetafied length of a path segment preceeding + * the trial string needed for file mananagement; it is calculated as + * needed so does not need to be initialised. + * alloced is the memory allocated --- same as return value from + * function. + */ +/**/ +mod_export +char *patallocstr(Patprog prog, char *string, int stringlen, int unmetalen, + int force, Patstralloc patstralloc) +{ + int needfullpath; + + /* + * For a top-level ~-exclusion, we will need the full + * path to exclude, so copy the path so far and append the + * current test string. + */ + needfullpath = (prog->flags & PAT_HAS_EXCLUDP) && pathpos; + + /* Get the length of the full string when unmetafied. */ + if (unmetalen < 0) + patstralloc->unmetalen = ztrsub(string + stringlen, string); + else + patstralloc->unmetalen = unmetalen; + if (needfullpath) { + patstralloc->unmetalenp = ztrsub(pathbuf + pathpos, pathbuf); + if (!patstralloc->unmetalenp) + needfullpath = 0; + } else + patstralloc->unmetalenp = 0; + /* Initialise cache area */ + patstralloc->progstrunmeta = NULL; + patstralloc->progstrunmetalen = 0; + + DPUTS(needfullpath && (prog->flags & (PAT_PURES|PAT_ANY)), + "rum sort of file exclusion"); + /* + * Partly for efficiency, and partly for the convenience of + * globbing, we don't unmetafy pure string patterns, and + * there's no reason to if the pattern is just a *. + */ + if (force || + (!(prog->flags & (PAT_PURES|PAT_ANY)) + && (needfullpath || patstralloc->unmetalen != stringlen))) { + /* + * We need to copy if we need to prepend the path so far + * (in which case we copy both chunks), or if we have + * Meta characters. + */ + char *dst, *ptr; + int i, icopy, ncopy; + + dst = patstralloc->alloced = + zalloc(patstralloc->unmetalen + patstralloc->unmetalenp); + + if (needfullpath) { + /* loop twice, copy path buffer first time */ + ptr = pathbuf; + ncopy = patstralloc->unmetalenp; + } else { + /* just loop once, copy string with unmetafication */ + ptr = string; + ncopy = patstralloc->unmetalen; + } + for (icopy = 0; icopy < 2; icopy++) { + for (i = 0; i < ncopy; i++) { + if (*ptr == Meta) { + ptr++; + *dst++ = *ptr++ ^ 32; + } else { + *dst++ = *ptr++; + } + } + if (!needfullpath) + break; + /* next time append test string to path so far */ + ptr = string; + ncopy = patstralloc->unmetalen; + } + } + else + { + patstralloc->alloced = NULL; + } + + return patstralloc->alloced; +} + + +/* + * Free memory allocated by patallocstr(). + */ + +/**/ +mod_export +void patfreestr(Patstralloc patstralloc) +{ + if (patstralloc->alloced) + zfree(patstralloc->alloced, + patstralloc->unmetalen + patstralloc->unmetalenp); +} + + /* * Test prog against null-terminated, metafied string. */ @@ -2030,7 +2155,7 @@ pattrystart(void) mod_export int pattry(Patprog prog, char *string) { - return pattryrefs(prog, string, -1, -1, 0, NULL, NULL, NULL); + return pattryrefs(prog, string, -1, -1, NULL, 0, NULL, NULL, NULL); } /* @@ -2041,9 +2166,11 @@ pattry(Patprog prog, char *string) /**/ mod_export int -pattrylen(Patprog prog, char *string, int len, int unmetalen, int offset) +pattrylen(Patprog prog, char *string, int len, int unmetalen, + Patstralloc patstralloc, int offset) { - return pattryrefs(prog, string, len, unmetalen, offset, NULL, NULL, NULL); + return pattryrefs(prog, string, len, unmetalen, patstralloc, offset, + NULL, NULL, NULL); } /* @@ -2055,14 +2182,32 @@ pattrylen(Patprog prog, char *string, int len, int unmetalen, int offset) * there may be a severe penalty for this if a lot of matching is done * on one string. * - * offset is the position in the original string (not seen by + * If patstralloc is not NULL it is used to optimise unmetafication + * of a trial string that may be passed (or any substring may be passed) to + * pattryrefs multiple times or the same pattern (N.B. so patstralloc + * depends on both prog *and* the trial string). This should only be + * done if there is no path prefix (pathpos == 0) as otherwise the path + * buffer and unmetafied string may not match. To do this, + * patallocstr() is callled (use force = 1 to ensure it is alway + * unmetafied); paststralloc points to existing storage. When all + * pattern matching is done, patfreestr() is called. + * patstralloc->alloced and patstralloc->unmetalen contain the + * unmetafied string and its length. In that case, the rules for the + * earlier arguments change: + * - string is an unmetafied string + * - stringlen is its unmetafied (i.e. actual) length + * - unmetalenin is not used. + * string and stringlen may refer to arbitrary substrings of + * patstralloc->alloced without any internal modification to patstralloc. + * + * patoffset is the position in the original string (not seen by * the pattern module) at which we are trying to match. * This is added in to the positions recorded in patbeginp and patendp * when we are looking for substrings. Currently this only happens * in the parameter substitution code. * - * Note this is a character offset, i.e. a metafied character - * counts as 1. + * Note this is a character offset, i.e. a single possibly metafied and + * possibly multibyte character counts as 1. * * The last three arguments are used to report the positions for the * backreferences. On entry, *nump should contain the maximum number @@ -2075,14 +2220,15 @@ pattrylen(Patprog prog, char *string, int len, int unmetalen, int offset) /**/ mod_export int -pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, - int patoffset, +pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin, + Patstralloc patstralloc, int patoffset, int *nump, int *begp, int *endp) { - int i, maxnpos = 0, ret, needfullpath, unmetalenp; + int i, maxnpos = 0, ret; int origlen; - char **sp, **ep, *tryalloced, *ptr; + char **sp, **ep, *ptr; char *progstr = (char *)prog + prog->startoff; + struct patstralloc patstralloc_struct; if (nump) { maxnpos = *nump; @@ -2091,86 +2237,38 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, /* inherited from domatch, but why, exactly? */ if (*string == Nularg) { string++; - unmetalen--; + if (unmetalenin > 0) + unmetalenin--; + if (stringlen > 0) + stringlen--; } if (stringlen < 0) stringlen = strlen(string); origlen = stringlen; - patflags = prog->flags; - /* - * For a top-level ~-exclusion, we will need the full - * path to exclude, so copy the path so far and append the - * current test string. - */ - needfullpath = (patflags & PAT_HAS_EXCLUDP) && pathpos; - - /* Get the length of the full string when unmetafied. */ - if (unmetalen < 0) - unmetalen = ztrsub(string + stringlen, string); - if (needfullpath) - unmetalenp = ztrsub(pathbuf + pathpos, pathbuf); - else - unmetalenp = 0; - - DPUTS(needfullpath && (patflags & (PAT_PURES|PAT_ANY)), - "rum sort of file exclusion"); - /* - * Partly for efficiency, and partly for the convenience of - * globbing, we don't unmetafy pure string patterns, and - * there's no reason to if the pattern is just a *. - */ - if (!(patflags & (PAT_PURES|PAT_ANY)) - && (needfullpath || unmetalen != stringlen)) { - /* - * We need to copy if we need to prepend the path so far - * (in which case we copy both chunks), or if we have - * Meta characters. - */ - char *dst; - int icopy, ncopy; - - dst = tryalloced = zalloc(unmetalen + unmetalenp); - - if (needfullpath) { - /* loop twice, copy path buffer first time */ - ptr = pathbuf; - ncopy = unmetalenp; - } else { - /* just loop once, copy string with unmetafication */ - ptr = string; - ncopy = unmetalen; - } - for (icopy = 0; icopy < 2; icopy++) { - for (i = 0; i < ncopy; i++) { - if (*ptr == Meta) { - ptr++; - *dst++ = *ptr++ ^ 32; - } else { - *dst++ = *ptr++; - } - } - if (!needfullpath) - break; - /* next time append test string to path so far */ - ptr = string; - ncopy = unmetalen; - } - - if (needfullpath) { - patinstart = tryalloced + unmetalenp; - patinpath = tryalloced; - } else { - patinstart = tryalloced; - patinpath = NULL; - } - stringlen = unmetalen; - } else { + if (patstralloc) { + DPUTS(!patstralloc->alloced, + "External unmetafy didn't actually unmetafy."); + DPUTS(patstralloc->unmetalenp, + "Ooh-err: pathpos with external unmetafy. I have bad vibes."); + patinpath = NULL; patinstart = string; - tryalloced = patinpath = NULL; + /* stringlen is unmetafied length; unmetalenin is ignored */ + } else { + patstralloc = &patstralloc_struct; + if (patallocstr(prog, string, stringlen, unmetalenin, 0, patstralloc)) { + patinstart = patstralloc->alloced + patstralloc->unmetalenp; + stringlen = patstralloc->unmetalen; + } else + patinstart = string; + if (patstralloc->unmetalenp) + patinpath = patstralloc->alloced; + else + patinpath = NULL; } + patflags = prog->flags; patinend = patinstart + stringlen; /* * From now on we do not require NULL termination of @@ -2183,7 +2281,30 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, * Either we are testing against a pure string, * or we can match anything at all. */ - int ret; + int ret, pstrlen; + char *pstr; + if (patstralloc->alloced) + { + /* + * Unmetafied; we need pattern sring that's also unmetafied. + * We'll cache it in the patstralloc structure. + * Note it's on the heap. + */ + if (!patstralloc->progstrunmeta) + { + patstralloc->progstrunmeta = dupstring(progstr); + unmetafy(patstralloc->progstrunmeta, + &patstralloc->progstrunmetalen); + } + pstr = patstralloc->progstrunmeta; + pstrlen = patstralloc->progstrunmetalen; + } + else + { + /* Metafied. */ + pstr = progstr; + pstrlen = (int)prog->patmlen; + } if (prog->flags & PAT_ANY) { /* * Optimisation for a single "*": always matches @@ -2195,11 +2316,11 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, * Testing a pure string. See if initial * components match. */ - int lendiff = stringlen - prog->patmlen; + int lendiff = stringlen - pstrlen; if (lendiff < 0) { /* No, the pattern string is too long. */ ret = 0; - } else if (!memcmp(progstr, patinstart, prog->patmlen)) { + } else if (!memcmp(pstr, patinstart, pstrlen)) { /* * Initial component matches. Matches either * if lengths are the same or we are not anchored @@ -2221,7 +2342,9 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, } else { /* * Remember the length in case used for ${..#..} etc. - * In this case, we didn't unmetafy the string. + * In this case, we didn't unmetafy the pattern string + * In the orignal structure, but it might be unmetafied + * for use with an unmetafied test string. */ patinlen = (int)prog->patmlen; /* if matching files, must update globbing flags */ @@ -2229,16 +2352,26 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, if ((patglobflags & GF_MATCHREF) && !(patflags & PAT_FILE)) { - char *str = ztrduppfx(patinstart, patinlen); + char *str; int mlen; - /* - * Count the characters. We're not using CHARSUB() - * because the string is still metafied. - */ - MB_METACHARINIT(); - mlen = MB_METASTRLEN2END(patinstart, 0, - patinstart + patinlen); + if (patstralloc->alloced) { + /* + * Unmetafied: pstrlen contains unmetafied + * length in bytes. + */ + str = metafy(patinstart, pstrlen, META_ALLOC); + mlen = CHARSUB(patinstart, patinstart + pstrlen); + } else { + str = ztrduppfx(patinstart, patinlen); + /* + * Count the characters. We're not using CHARSUB() + * because the string is still metafied. + */ + MB_METACHARINIT(); + mlen = MB_METASTRLEN2END(patinstart, 0, + patinstart + patinlen); + } setsparam("MATCH", str); setiparam("MBEGIN", @@ -2250,9 +2383,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, } } - if (tryalloced) - zfree(tryalloced, unmetalen + unmetalenp); - + if (patstralloc == &patstralloc_struct) + patfreestr(patstralloc); return ret; } else { int q = queue_signal_level(); @@ -2289,8 +2421,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, } } if (!ret) { - if (tryalloced) - zfree(tryalloced, unmetalen + unmetalenp); + if (patstralloc == &patstralloc_struct) + patfreestr(patstralloc); return 0; } @@ -2322,8 +2454,11 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, /* * Optimization: if we didn't find any Meta characters * to begin with, we don't need to look for them now. + * Only do this if we did the unmetfication internally, + * since otherwise it's too hard to work out. */ - if (unmetalen != origlen) { + if (patstralloc == &patstralloc_struct && + patstralloc->unmetalen != origlen) { for (ptr = patinstart; ptr < patinput; ptr++) if (imeta(*ptr)) patinlen++; @@ -2444,8 +2579,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, restore_queue_signals(q); - if (tryalloced) - zfree(tryalloced, unmetalen + unmetalenp); + if (patstralloc == &patstralloc_struct) + patfreestr(patstralloc); return ret; } diff --git a/Src/zsh.h b/Src/zsh.h index dd0596116..32f2e0cb2 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -491,6 +491,7 @@ typedef struct options *Options; typedef struct optname *Optname; typedef struct param *Param; typedef struct paramdef *Paramdef; +typedef struct patstralloc *Patstralloc; typedef struct patprog *Patprog; typedef struct prepromptfn *Prepromptfn; typedef struct process *Process; @@ -1470,6 +1471,15 @@ struct patprog { char patstartch; }; +struct patstralloc { + int unmetalen; /* Unmetafied length of trial string */ + int unmetalenp; /* Unmetafied length of path prefix. + If 0, no path prefix. */ + char *alloced; /* Allocated string, may be NULL */ + char *progstrunmeta; /* Unmetafied pure string in pattern, cached */ + int progstrunmetalen; /* Length of the foregoing */ +}; + /* Flags used in pattern matchers (Patprog) and passed down to patcompile */ #define PAT_FILE 0x0001 /* Pattern is a file name */ -- cgit v1.2.3 From a855d7bd246ef44d5393c3088aae8214d41d2b85 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 29 Sep 2015 06:11:24 +0200 Subject: 36709: zle -f from inside widget to set flags and make yank start/end zle params writable --- ChangeLog | 7 +++++++ Doc/Zsh/zle.yo | 29 ++++++++++++++++++++++++----- Src/Zle/zle_main.c | 5 +++-- Src/Zle/zle_params.c | 24 +++++++++++++++++++----- Src/Zle/zle_thingy.c | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 12 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 20860a1f6..eaa565870 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2015-10-01 Mikael Magnusson + + * 36709: Doc/Zsh/zle.yo, Functions/Zle/bracketed-paste-url-magic, + Src/Zle/zle_main.c, Src/Zle/zle_params.c, Src/Zle/zle_thingy.c: + zle -f from inside widget to set flags and make yank start/end + zle params writable. + 2015-09-30 Daniel Shahaf * 36725: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 7d95eb377..05bb14829 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -404,6 +404,7 @@ xitem(tt(zle) tt(-l) [ tt(-L) | tt(-a) ] [ var(string) ... ]) xitem(tt(zle) tt(-D) var(widget) ...) xitem(tt(zle) tt(-A) var(old-widget) var(new-widget)) xitem(tt(zle) tt(-N) var(widget) [ var(function) ]) +xitem(tt(zle) tt(-f) var(flag) [ var(flag)... ]) xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function)) xitem(tt(zle) tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ]) xitem(tt(zle) tt(-M) var(string)) @@ -464,6 +465,21 @@ ifzman(the section `Widgets' below)\ ifnzman(noderef(Zle Widgets))\ . ) +item(tt(-f) var(flag) [ var(flag)... ])( +Set various flags on the running widget. Possible values for var(flag) are: + +tt(yank) for indicating that the widget has yanked text into the buffer. +If the widget is wrapping an existing internal widget, no further +action is necessary, but if it has inserted the text manually, then it +should also take care to set tt(YANK_START) and tt(YANK_END) correctly. +tt(yankbefore) does the same but is used when the yanked text appears +after the cursor. + +tt(kill) for indicating that text has been killed into the cutbuffer. +When repeatedly invoking a kill widget, text is appended to the cutbuffer +instead of replacing it, but when wrapping such widgets, it is necessary +to call `tt(zle -f kill)' to retain this effect. +) cindex(completion widgets, creating) item(tt(-C) var(widget) var(completion-widget) var(function))( Create a user-defined completion widget named var(widget). The @@ -1011,11 +1027,14 @@ vindex(YANK_END) xitem(tt(YANK_ACTIVE) (integer)) xitem(tt(YANK_START) (integer)) item(tt(YANK_END) (integer))( -These three parameters indicate whether text has just been yanked (pasted) -into the buffer. tt(YANK_START) and tt(YANK_END) are in the same units as -tt(CURSOR), and are only valid when tt(YANK_ACTIVE) is non-zero. - -All three are read-only. +tt(YANK_ACTIVE) indicates whether text has just been yanked (pasted) +into the buffer. tt(YANK_START) and tt(YANK_END) give the location of +the pasted text and are in the same units as tt(CURSOR). They are only +valid for reading when tt(YANK_ACTIVE) is non-zero. They can also be +assigned by widgets that insert text in a yank-like fashion, for example +wrappers of tt(bracketed-paste). See also tt(zle -f). + +tt(YANK_ACTIVE) is read-only. ) vindex(ZLE_STATE) item(tt(ZLE_STATE) (scalar))( diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 992f152df..593d636cc 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1402,7 +1402,8 @@ execzlefunc(Thingy func, char **args, int set_bindk) opts[XTRACE] = oxt; sfcontext = osc; endparamscope(); - lastcmd = 0; + lastcmd = w->flags; + w->flags = 0; r = 1; redup(osi, 0); } @@ -1981,7 +1982,7 @@ zle_main_entry(int cmd, va_list ap) static struct builtin bintab[] = { BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL), BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcef:hi:M:m:p:r:t:", NULL), - BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNrRTUw", NULL), + BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDfFgGIKlLmMNrRTUw", NULL), }; /* The order of the entries in this table has to match the *HOOK diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 000bc388c..b5bb288f1 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -98,9 +98,9 @@ static const struct gsu_integer undo_change_no_gsu = static const struct gsu_integer undo_limit_no_gsu = { get_undo_limit_change, set_undo_limit_change, zleunsetfn }; static const struct gsu_integer yankstart_gsu = -{ get_yankstart, NULL, zleunsetfn }; +{ get_yankstart, set_yankstart, zleunsetfn }; static const struct gsu_integer yankend_gsu = -{ get_yankend, NULL, zleunsetfn }; +{ get_yankend, set_yankend, zleunsetfn }; static const struct gsu_integer yankactive_gsu = { get_yankactive, NULL, zleunsetfn }; @@ -149,8 +149,8 @@ static struct zleparam { { "WIDGET", PM_SCALAR | PM_READONLY, GSU(widget_gsu), NULL }, { "WIDGETFUNC", PM_SCALAR | PM_READONLY, GSU(widgetfunc_gsu), NULL }, { "WIDGETSTYLE", PM_SCALAR | PM_READONLY, GSU(widgetstyle_gsu), NULL }, - { "YANK_START", PM_INTEGER | PM_READONLY, GSU(yankstart_gsu), NULL }, - { "YANK_END", PM_INTEGER | PM_READONLY, GSU(yankend_gsu), NULL }, + { "YANK_START", PM_INTEGER, GSU(yankstart_gsu), NULL }, + { "YANK_END", PM_INTEGER, GSU(yankend_gsu), NULL }, { "YANK_ACTIVE", PM_INTEGER | PM_READONLY, GSU(yankactive_gsu), NULL }, { "ZLE_STATE", PM_SCALAR | PM_READONLY, GSU(zle_state_gsu), NULL }, { NULL, 0, NULL, NULL } @@ -503,7 +503,21 @@ get_yankend(UNUSED(Param pm)) static zlong get_yankactive(UNUSED(Param pm)) { - return lastcmd & ZLE_YANK; + return !!(lastcmd & ZLE_YANK) + !!(lastcmd & ZLE_YANKAFTER); +} + +/**/ +static void +set_yankstart(UNUSED(Param pm), zlong i) +{ + yankb = i; +} + +/**/ +static void +set_yankend(UNUSED(Param pm), zlong i) +{ + yanke = i; } /**/ diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index da3a6d458..3963d7eaf 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -352,6 +352,7 @@ bin_zle(char *name, char **args, Options ops, UNUSED(int func)) { 'U', bin_zle_unget, 1, 1 }, { 'K', bin_zle_keymap, 1, 1 }, { 'I', bin_zle_invalidate, 0, 0 }, + { 'f', bin_zle_flags, 1, -1 }, { 'F', bin_zle_fd, 0, 2 }, { 'T', bin_zle_transform, 0, 2}, { 0, bin_zle_call, 0, -1 }, @@ -623,6 +624,44 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) return 0; } +/**/ +static int +bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) +{ + char **flag; + + if (!zle_usable()) { + zwarnnam(name, "can only set flags from a widget"); + return 1; + } + + if (bindk) { + Widget w = bindk->widget; + if (w) { + for (flag = args; *flag; flag++) { + if (!strcmp(*flag, "yank")) { + w->flags |= ZLE_YANKAFTER; + } else if (!strcmp(*flag, "yankbefore")) + w->flags |= ZLE_YANKBEFORE; + else if (!strcmp(*flag, "kill")) + w->flags |= ZLE_KILL; + /* + * These won't do anything yet, because of how execzlefunc + * handles user widgets + } else if (!strcmp(*flag, "menucmp")) + w->flags |= ZLE_MENUCMP; + else if (!strcmp(*flag, "linemove")) + w->flags |= ZLE_LINEMOVE; + else if (!strcmp(*flag, "keepsuffix")) + w->flags |= ZLE_KEEPSUFFIX; + */ + else + zwarnnam(name, "invalid flag `%s' given to zle -f", *flag); + } + } + } +} + /**/ static int zle_usable() -- cgit v1.2.3 From fa72e547120581cdbff1b1695a47c2c19fed3487 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Thu, 1 Oct 2015 20:24:09 +0200 Subject: unposted: zle_thingy: return a value in bin_zle_flags --- Src/Zle/zle_thingy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/Zle') diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 3963d7eaf..ba89e00a8 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -628,6 +628,7 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) static int bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) { + int ret = 0; char **flag; if (!zle_usable()) { @@ -655,11 +656,14 @@ bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) else if (!strcmp(*flag, "keepsuffix")) w->flags |= ZLE_KEEPSUFFIX; */ - else + else { zwarnnam(name, "invalid flag `%s' given to zle -f", *flag); + ret = 1; + } } } } + return ret; } /**/ -- cgit v1.2.3 From 0626be9e3c02ca9171cd4e0975c208e0c3d6ec2b Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Fri, 2 Oct 2015 20:41:49 +0200 Subject: unposted: define zle_usable before using it (reported in 36741) --- Src/Zle/zle_thingy.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'Src/Zle') diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index ba89e00a8..c6ef8e6a0 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -624,6 +624,23 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) return 0; } +/**/ +static int +zle_usable() +{ + return zleactive && !incompctlfunc && !incompfunc +#if 0 + /* + * PWS experiment: commenting this out allows zle widgets + * in signals, hooks etc. I'm not sure if this has a down side; + * it ought to be that zleactive is good enough to test whether + * widgets are callable. + */ + && sfcontext == SFC_WIDGET +#endif + ; +} + /**/ static int bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) @@ -666,23 +683,6 @@ bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) return ret; } -/**/ -static int -zle_usable() -{ - return zleactive && !incompctlfunc && !incompfunc -#if 0 - /* - * PWS experiment: commenting this out allows zle widgets - * in signals, hooks etc. I'm not sure if this has a down side; - * it ought to be that zleactive is good enough to test whether - * widgets are callable. - */ - && sfcontext == SFC_WIDGET -#endif - ; -} - /**/ static int bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) -- cgit v1.2.3 From a40417929cb6f94ccd8fb5af78aa47ff69a785c0 Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Sun, 25 Oct 2015 23:42:03 +0900 Subject: 36911: '-optarg' should not match optspec '-opt=' Remove the requirement that -xy= should come before -x= in the list of optspecs passed to _arguments. --- ChangeLog | 5 +++++ Src/Zle/computil.c | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index e6edaa8c0..8bf01dc3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-25 Jun-ichi Takimoto + + * 36911: Src/Zle/computil.c: '-optarg' should not match + optspec '-opt=' + 2015-10-24 Barton E. Schaefer * 36943 (with updated comment): Src/mem.c: restore scan for diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index e5db0867b..db8db88a6 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -1693,10 +1693,13 @@ ca_get_opt(Cadef d, char *line, int full, char **end) for (p = d->opts; p; p = p->next) if (p->active && ((!p->args || p->type == CAO_NEXT) ? !strcmp(p->name, line) : strpfx(p->name, line))) { + int l = strlen(p->name); + if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) && + line[l] && line[l] != '=') + continue; + if (end) { /* Return a pointer to the end of the option. */ - int l = strlen(p->name); - if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) && line[l] == '=') l++; -- cgit v1.2.3 From 11ca38c6d99192856d33254c504114d4ba8cd258 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 26 Oct 2015 10:00:54 +0000 Subject: users/20825: fix crash when complex completion hooks. get_undo_current_change() needs protecting against execution in completion environment. --- ChangeLog | 6 ++++++ Src/Zle/zle_utils.c | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index e26e62e5f..b2291f5b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-10-26 Peter Stephenson + + * users/20825: Src/Zle/zle_utils.c: get_undo_current_change() + needs same protection as mkundoent() for execution within + completion. + 2015-10-25 Daniel Shahaf * 36962: Completion/Unix/Command/_git: _git: Fix completion of diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 714d911a6..ffff8fd1c 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1739,9 +1739,26 @@ zlecallhook(char *name, char *arg) zlong get_undo_current_change(UNUSED(Param pm)) { + int remetafy; + + /* + * Yuk: we call this from within the completion system, + * so we need to convert back to the form which can be + * copied into undo entries. + */ + if (zlemetaline != NULL) { + unmetafy_line(); + remetafy = 1; + } else + remetafy = 0; + /* add entry for any pending changes */ mkundoent(); setlastline(); + + if (remetafy) + metafy_line(); + return undo_changeno; } -- cgit v1.2.3 From d45a68c5463224f43721371fb7bd4cbc24e62874 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 27 Oct 2015 09:28:36 +0000 Subject: 36974: fix some functions with empty argument lists --- ChangeLog | 6 ++++++ Src/Modules/zftp.c | 8 ++++---- Src/Zle/complist.c | 6 +++--- Src/Zle/computil.c | 4 ++-- Src/Zle/zle_thingy.c | 2 +- Src/parse.c | 2 +- 6 files changed, 17 insertions(+), 11 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index bdd27871d..846b57ef7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-10-27 Peter Stephenson + + * 36974: Src/Modules/zftp.c, Src/Zle/complist.c, + Src/Zle/computil.c, Src/Zle/zle_thingy.c, Src/parse.c: fix empty + argument lists. + 2015-10-26 Barton E. Schaefer * 36906: Kamil Dudka : Src/mem.c: diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index bd51512f9..b4081df5f 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -409,7 +409,7 @@ zfalarm(int tmout) /**/ static void -zfpipe() +zfpipe(void) { /* Just ignore SIGPIPE and rely on getting EPIPE from the write. */ signal(SIGPIPE, SIG_IGN); @@ -450,7 +450,7 @@ zfunalarm(void) /**/ static void -zfunpipe() +zfunpipe(void) { if (sigtrapped[SIGPIPE]) { if (siglists[SIGPIPE] || (sigtrapped[SIGPIPE] & ZSIG_FUNC)) @@ -1298,7 +1298,7 @@ zfstarttrans(char *nam, int recv, off_t sz) /**/ static void -zfendtrans() +zfendtrans(void) { zfunsetparam("ZFTP_SIZE"); zfunsetparam("ZFTP_FILE"); @@ -2834,7 +2834,7 @@ newsession(char *nm) /* Save the existing session: this just means saving the parameters. */ static void -savesession() +savesession(void) { char **ps, **pd, *val; diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 986ad31ea..29aaee82a 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -499,7 +499,7 @@ filecol(char *col) */ static void -getcols() +getcols(void) { char *s; int i, l; @@ -602,7 +602,7 @@ zcoff(void) static void -initiscol() +initiscol(void) { int i; @@ -1909,7 +1909,7 @@ singlecalc(int *cp, int l, int *lcp) } static void -singledraw() +singledraw(void) { Cmgroup g; int mc1, mc2, ml1, ml2, md1, md2, mcc1, mcc2, lc1, lc2, t1, t2; diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index db8db88a6..60fb096be 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -185,7 +185,7 @@ cd_group(int maxg) * descriptions. */ static void -cd_calc() +cd_calc(void) { Cdset set; Cdstr str; @@ -236,7 +236,7 @@ cd_sort(const void *a, const void *b) } static int -cd_prep() +cd_prep(void) { Cdrun run, *runp; Cdset set; diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index c6ef8e6a0..271fd8efc 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -626,7 +626,7 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) /**/ static int -zle_usable() +zle_usable(void) { return zleactive && !incompctlfunc && !incompfunc #if 0 diff --git a/Src/parse.c b/Src/parse.c index a26df6f0a..83ba396b0 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -530,7 +530,7 @@ empty_eprog(Eprog p) } static void -clear_hdocs() +clear_hdocs(void) { struct heredocs *p, *n; -- cgit v1.2.3 From f1312d1e2272ba97b08396328c2bf25f433f1c8c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 11 Nov 2015 16:09:28 +0000 Subject: 37091: clear lastline and lastlinesz when freeing --- Src/Zle/zle_utils.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Src/Zle') diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index ffff8fd1c..6e9a98bde 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1436,6 +1436,8 @@ freeundo(void) freechanges(changes); freechanges(nextchanges); zfree(lastline, lastlinesz); + lastline = NULL; + lastlinesz = 0; } /**/ -- cgit v1.2.3 From 830d54e629e8e12eb5a219a65a013876662e7b3e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 11 Nov 2015 18:04:20 +0000 Subject: 37092: make nested ${(P)name} properly refer to parameter on return --- ChangeLog | 5 +++ Doc/Zsh/expn.yo | 11 ++++- Src/Zle/compctl.c | 4 +- Src/Zle/zle_tricky.c | 2 +- Src/cond.c | 2 +- Src/exec.c | 16 ++++---- Src/glob.c | 2 +- Src/subst.c | 114 +++++++++++++++++++++++++++++++-------------------- Src/zsh.h | 51 +++++++++++++++++------ 9 files changed, 138 insertions(+), 69 deletions(-) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 5f6c59c0a..e9bef7d68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2015-11-11 Peter Stephenson + * 37092: Doc/Zsh/expn.yo, Src/Zle/compctl.c, + Src/Zle/zle_tricky.c, Src/cond.c, Src/exec.c, Src/glob.c, + Src/subst.c, Src/zsh.h: make a ${(P)name} subexpression properly + refer to a parameter name. + * 37091: Src/Zle/zle_utils.c: clear lastline and lastlinesz when freeing. diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 20e0c8d35..4c373d1f2 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1033,7 +1033,16 @@ var(name) used in this fashion. If used with a nested parameter or command substitution, the result of that will be taken as a parameter name in the same way. For example, if you have `tt(foo=bar)' and `tt(bar=baz)', the strings tt(${(P)foo}), -tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to `tt(baz)'. +tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to +`tt(baz)'. + +Likewise, if the reference is itself nested, the expression with the +flag is treated as if it were directly replaced by the parameter name. +It is an error if this nested substitution produces an array with more +than one word. For example, if `tt(name=assoc)' where the parameter +tt(assoc) is an associative array, then +`tt(${${(P)name}[elt]})' refers to the element of the associative +subscripted `tt(elt)'. ) item(tt(q))( Quote characters that are special to the shell in the resulting words with diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index bac533e7e..8381867d0 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2116,7 +2116,7 @@ getreal(char *str) noerrs = 1; addlinknode(l, dupstring(str)); - prefork(l, 0); + prefork(l, 0, NULL); noerrs = ne; if (!errflag && nonempty(l) && ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) @@ -3728,7 +3728,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) errflag &= ~ERRFLAG_ERROR; zcontext_restore(); /* Fine, now do full expansion. */ - prefork(foo, 0); + prefork(foo, 0, NULL); if (!errflag) { globlist(foo, 0); if (!errflag) diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index e26f66379..4e6854928 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2223,7 +2223,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) else if (*ts == '\'') *ts = Snull; addlinknode(vl, ss); - prefork(vl, 0); + prefork(vl, 0, NULL); if (errflag) goto end; if (lst == COMP_LIST_EXPAND || lst == COMP_EXPAND) { diff --git a/Src/cond.c b/Src/cond.c index df9065660..c5ab65eea 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -43,7 +43,7 @@ static void cond_subst(char **strp, int glob_ok) checkglobqual(*strp, strlen(*strp), 1, NULL)) { LinkList args = newlinklist(); addlinknode(args, *strp); - prefork(args, 0); + prefork(args, 0, NULL); while (!errflag && args && nonempty(args) && has_token((char *)peekfirst(args))) zglob(args, firstnode(args), 0); diff --git a/Src/exec.c b/Src/exec.c index f0d1d2f70..c0ee527b7 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2290,7 +2290,7 @@ addvars(Estate state, Wordcode pc, int addflags) if (vl && htok) { prefork(vl, (isstr ? (PREFORK_SINGLE|PREFORK_ASSIGN) : - PREFORK_ASSIGN)); + PREFORK_ASSIGN), NULL); if (errflag) { state->pc = opc; return; @@ -2416,7 +2416,7 @@ void execsubst(LinkList strs) { if (strs) { - prefork(strs, esprefork); + prefork(strs, esprefork, NULL); if (esglob && !errflag) { LinkList ostrs = strs; globlist(strs, 0); @@ -2721,7 +2721,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* Do prefork substitutions */ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0; if (args && htok) - prefork(args, esprefork); + prefork(args, esprefork, NULL); if (type == WC_SIMPLE || type == WC_TYPESET) { int unglobbed = 0; @@ -3558,7 +3558,7 @@ execcmd(Estate state, int input, int output, int how, int last1) */ /* Unused dummy value for name */ (void)ecgetstr(state, EC_DUPTOK, &htok); - prefork(&svl, PREFORK_TYPESET); + prefork(&svl, PREFORK_TYPESET, NULL); if (errflag) { state->pc = opc; break; @@ -3584,7 +3584,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } continue; } - prefork(&svl, PREFORK_SINGLE); + prefork(&svl, PREFORK_SINGLE, NULL); name = empty(&svl) ? "" : (char *)getdata(firstnode(&svl)); } @@ -3600,7 +3600,9 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (htok) { init_list1(svl, val); - prefork(&svl, PREFORK_SINGLE|PREFORK_ASSIGN); + prefork(&svl, + PREFORK_SINGLE|PREFORK_ASSIGN, + NULL); if (errflag) { state->pc = opc; break; @@ -3622,7 +3624,7 @@ execcmd(Estate state, int input, int output, int how, int last1) EC_DUPTOK, &htok); if (asg->value.array) { - prefork(asg->value.array, PREFORK_ASSIGN); + prefork(asg->value.array, PREFORK_ASSIGN, NULL); if (errflag) { state->pc = opc; break; diff --git a/Src/glob.c b/Src/glob.c index 51ffeb5d5..94b3f620d 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2093,7 +2093,7 @@ xpandredir(struct redir *fn, LinkList redirtab) /* Stick the name in a list... */ init_list1(fake, fn->name); /* ...which undergoes all the usual shell expansions */ - prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE); + prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE, NULL); /* Globbing is only done for multios. */ if (!errflag && isset(MULTIOS)) globlist(&fake, 0); diff --git a/Src/subst.c b/Src/subst.c index febdc9bea..f3a4ad44d 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -44,15 +44,23 @@ char nulstring[] = {Nularg, '\0'}; * - Brace expansion * - Tilde and equals substitution * - * PREFORK_* flags are defined in zsh.h + * "flag"s contains PREFORK_* flags, defined in zsh.h. + * + * "ret_flags" is used to return values from nested parameter + * substitions. It may be NULL in which case PREFORK_SUBEXP + * must not appear in flags; any return value from below + * will be discarded. */ /**/ mod_export void -prefork(LinkList list, int flags) +prefork(LinkList list, int flags, int *ret_flags) { LinkNode node, stop = 0; int keep = 0, asssub = (flags & PREFORK_TYPESET) && isset(KSHTYPESET); + int ret_flags_local = 0; + if (!ret_flags) + ret_flags = &ret_flags_local; /* will be discarded */ queue_signals(); for (node = firstnode(list); node; incnode(node)) { @@ -75,10 +83,8 @@ prefork(LinkList list, int flags) setdata(node, cptr); } if (!(node = stringsubst(list, node, - flags & (PREFORK_SINGLE|PREFORK_SPLIT| - PREFORK_SHWORDSPLIT| - PREFORK_NOSHWORDSPLIT), - asssub))) { + flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN), + ret_flags, asssub))) { unqueue_signals(); return; } @@ -149,7 +155,8 @@ stringsubstquote(char *strstart, char **pstrdpos) /**/ static LinkNode -stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub) +stringsubst(LinkList list, LinkNode node, int pf_flags, int *ret_flags, + int asssub) { int qt; char *str3 = (char *)getdata(node); @@ -235,7 +242,8 @@ stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub) pf_flags |= PREFORK_SHWORDSPLIT; node = paramsubst( list, node, &str, qt, - pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT)); + pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT| + PREFORK_SUBEXP), ret_flags); if (errflag || !node) return NULL; str3 = (char *)getdata(node); @@ -413,29 +421,13 @@ singsub(char **s) init_list1(foo, *s); - prefork(&foo, PREFORK_SINGLE); + prefork(&foo, PREFORK_SINGLE, NULL); if (errflag) return; *s = (char *) ugetnode(&foo); DPUTS(nonempty(&foo), "BUG: singsub() produced more than one word!"); } -/* - * Bit flags passed back from multsub() to paramsubst(). - */ -enum { - /* - * Set if the string had whitespace at the start - * that should cause word splitting against any preceeding string. - */ - WS_AT_START = 1, - /* - * Set if the string had whitespace at the end - * that should cause word splitting against any following string. - */ - WS_AT_END = 2 -}; - /* Perform substitution on a single word, *s. Unlike with singsub(), the * result can be more than one word. If split is non-zero, the string is * first word-split using IFS, but only for non-quoted "whitespace" (as @@ -448,13 +440,13 @@ enum { * NULL to use IFS). The return value is true iff the expansion resulted * in an empty list. * - * *ws_at_start is set to bits in the enum above as neeed. + * *ms_flags is set to bits in the enum above as neeed. */ /**/ static int multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, - int *ws_sub) + int *ms_flags) { int l; char **r, **p, *x = *s; @@ -470,7 +462,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, l++; if (!iwsep(STOUC(c))) break; - *ws_sub |= WS_AT_START; + *ms_flags |= MULTSUB_WS_AT_START; } } @@ -503,7 +495,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, break; } if (!*x) { - *ws_sub |= WS_AT_END; + *ms_flags |= MULTSUB_WS_AT_END; break; } insertlinknode(&foo, n, (void *)x), incnode(n); @@ -532,7 +524,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, } } - prefork(&foo, pf_flags); + prefork(&foo, pf_flags, ms_flags); if (errflag) { if (isarr) *isarr = 0; @@ -1517,7 +1509,8 @@ check_colon_subscript(char *str, char **endp) /**/ static LinkNode -paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) +paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, + int *ret_flags) { char *aptr = *str, c, cc; char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n); @@ -1747,7 +1740,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * whitespace. However, if there's no "x" the whitespace is * simply removed. */ - int ws_sub = 0; + int ms_flags = 0; *s++ = '\0'; /* @@ -2296,8 +2289,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * remove the aspar test and extract a value from an array, if * necessary, when we handle (P) lower down. */ - if (multsub(&val, 0, (aspar ? NULL : &aval), &isarr, NULL, - &ws_sub) && quoted) { + if (multsub(&val, PREFORK_SUBEXP, (aspar ? NULL : &aval), &isarr, NULL, + &ms_flags) && quoted) { /* Empty quoted string --- treat as null string, not elided */ isarr = -1; aval = (char **) hcalloc(sizeof(char *)); @@ -2311,6 +2304,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) */ while (inull(*s)) s++; + if (ms_flags & MULTSUB_PARAM_NAME) { + /* + * Downbelow has told us this is a parameter name, e.g. + * ${${(P)name}...}. We're going to behave as if + * we have exactly that name followed by the rest of + * the parameter for subscripting etc. + * + * See below for where we set the flag in the nested + * substitution. + */ + if (isarr) { + if (aval[1]) { + zerr("parameter name reference used with array"); + return NULL; + } + val = aval[0]; + isarr = 0; + } + s = dyncat(val, s); + /* Now behave po-faced as if it was always like that... */ + subexp = aspar = 0; + } v = (Value) NULL; } else if (aspar) { /* @@ -2328,13 +2343,24 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } else vunset = 1; } + if (aspar && (pf_flags & PREFORK_SUBEXP)) { + /* + * This is the inner handling for the case referred to above + * where we have something like ${${(P)name}...}. + * + * Treat this as as a normal value here; all transformations on + * result are in outer instance. + */ + aspar = 0; + *ret_flags |= MULTSUB_PARAM_NAME; + } /* * We need to retrieve a value either if we haven't already * got it from a subexpression, or if the processing so * far has just yielded us a parameter name to be processed * with (P). */ - if (!subexp || aspar) { + else if (!subexp || aspar) { char *ov = val; /* @@ -2768,7 +2794,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) split_flags = PREFORK_NOSHWORDSPLIT; } multsub(&val, split_flags, (aspar ? NULL : &aval), - &isarr, NULL, &ws_sub); + &isarr, NULL, &ms_flags); copied = 1; spbreak = 0; /* Leave globsubst on if forced */ @@ -2797,14 +2823,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * behavior on caller choice of PREFORK_SHWORDSPLIT. */ multsub(&val, spbreak ? PREFORK_SINGLE : PREFORK_NOSHWORDSPLIT, - NULL, &isarr, NULL, &ws_sub); + NULL, &isarr, NULL, &ms_flags); } else { if (spbreak) split_flags = PREFORK_SPLIT|PREFORK_SHWORDSPLIT; else split_flags = PREFORK_NOSHWORDSPLIT; multsub(&val, split_flags, &aval, &isarr, NULL, - &ws_sub); + &ms_flags); spbreak = 0; } if (arrasg) { @@ -3336,7 +3362,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } if (haserr || errflag) return NULL; - ws_sub = 0; + ms_flags = 0; } /* * This handles taking a length with ${#foo} and variations. @@ -3375,7 +3401,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) sprintf(buf, "%ld", len); val = dupstring(buf); isarr = 0; - ws_sub = 0; + ms_flags = 0; } /* At this point we make sure that our arrayness has affected the * arrayness of the linked list. Then, we can turn our value into @@ -3405,7 +3431,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) if (isarr) { val = sepjoin(aval, sep, 1); isarr = 0; - ws_sub = 0; + ms_flags = 0; } if (!ssub && (spbreak || spsep)) { aval = sepsplit(val, spsep, 0, 1); @@ -3690,12 +3716,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * If a multsub result had whitespace at the start and we're * splitting and there's a previous string, now's the time to do so. */ - if ((ws_sub & WS_AT_START) && aptr > ostr) { + if ((ms_flags & MULTSUB_WS_AT_START) && aptr > ostr) { insertlinknode(l, n, dupstrpfx(ostr, aptr - ostr)), incnode(n); ostr = aptr; } /* Likewise at the end */ - if ((ws_sub & WS_AT_END) && *fstr) { + if ((ms_flags & MULTSUB_WS_AT_END) && *fstr) { insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */ *fstr = '\0'; } @@ -3777,7 +3803,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) *--fstr = Marker; init_list1(tl, fstr); - if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, 0)) + if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, ret_flags, 0)) return NULL; *str = aptr; tn = firstnode(&tl); diff --git a/Src/zsh.h b/Src/zsh.h index a6f039741..d3bfcefcc 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1866,18 +1866,45 @@ enum { }; /* Flags as the second argument to prefork */ -/* argument handled like typeset foo=bar */ -#define PREFORK_TYPESET 0x01 -/* argument handled like the RHS of foo=bar */ -#define PREFORK_ASSIGN 0x02 -/* single word substitution */ -#define PREFORK_SINGLE 0x04 -/* explicitly split nested substitution */ -#define PREFORK_SPLIT 0x08 -/* SHWORDSPLIT in parameter expn */ -#define PREFORK_SHWORDSPLIT 0x10 -/* SHWORDSPLIT forced off in nested subst */ -#define PREFORK_NOSHWORDSPLIT 0x20 +enum { + /* argument handled like typeset foo=bar */ + PREFORK_TYPESET = 0x01, + /* argument handled like the RHS of foo=bar */ + PREFORK_ASSIGN = 0x02, + /* single word substitution */ + PREFORK_SINGLE = 0x04, + /* explicitly split nested substitution */ + PREFORK_SPLIT = 0x08, + /* SHWORDSPLIT in parameter expn */ + PREFORK_SHWORDSPLIT = 0x10, + /* SHWORDSPLIT forced off in nested subst */ + PREFORK_NOSHWORDSPLIT = 0x20, + /* Prefork is part of a parameter subexpression */ + PREFORK_SUBEXP = 0x40 +}; + +/* + * Bit flags passed back from multsub() to paramsubst(). + * Some flags go from a nested parmsubst() through the enclosing + * stringsubst() and prefork(). + */ +enum { + /* + * Set if the string had whitespace at the start + * that should cause word splitting against any preceeding string. + */ + MULTSUB_WS_AT_START = 1, + /* + * Set if the string had whitespace at the end + * that should cause word splitting against any following string. + */ + MULTSUB_WS_AT_END = 2, + /* + * Set by nested paramsubst() to indicate the return + * value is a parameter name, rather than a value. + */ + MULTSUB_PARAM_NAME = 4 +}; /* * Structure for adding parameters in a module. -- cgit v1.2.3 From 9ab9da49f7f5d7e8a32c14bde1c7b2c7f264d6fa Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 13 Nov 2015 20:18:22 +0000 Subject: unposted: Make $EDITOR's jump-to-matching-brace happy. --- ChangeLog | 3 +++ Src/Zle/zle_tricky.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'Src/Zle') diff --git a/ChangeLog b/ChangeLog index 9fd23ada9..52c770b00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-11-13 Daniel Shahaf + * unposted: Src/Zle/zle_tricky.c: Make $EDITOR's + jump-to-matching-brace happy. + * 37031: Completion/Unix/Command/_git: _git-merge: Exclude ancestors of HEAD from recent commit completion diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 4e6854928..cc4b7d673 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -1878,6 +1878,7 @@ get_comp_string(void) if (!isset(IGNOREBRACES)) { /* Try and deal with foo{xxx etc. */ + /*}*/ char *curs = s + (isset(COMPLETEINWORD) ? offs : (int)strlen(s)); char *predup = dupstring(s), *dp = predup; char *bbeg = NULL, *bend = NULL, *dbeg = NULL; @@ -1889,6 +1890,7 @@ get_comp_string(void) * we try to get braces after a parameter expansion right, * but this may fail sometimes. sorry. */ + /*}*/ if (*p == String || *p == Qstring) { if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) { char *tp = p + 1; -- cgit v1.2.3