From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13769 invoked by alias); 7 Nov 2015 17:48:36 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 37074 Received: (qmail 16297 invoked from network); 7 Nov 2015 17:48:34 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.0 X-Originating-IP: [86.6.158.222] X-Spam: 0 X-Authority: v=2.1 cv=UKUgZ3ry c=1 sm=1 tr=0 a=2SBOh4l1h08DI0L+aujZyQ==:117 a=2SBOh4l1h08DI0L+aujZyQ==:17 a=NLZqzBF-AAAA:8 a=kj9zAlcOel0A:10 a=X4SQ7CYGu1zES9FwStwA:9 a=CjuIK1q_8ugA:10 Date: Sat, 7 Nov 2015 17:42:55 +0000 From: Peter Stephenson To: Peter Stephenson Cc: zsh-workers@zsh.org Subject: Re: Inconsistency with SHWORDSPLIT and leading spaces Message-ID: <20151107174255.74054b28@ntlworld.com> In-Reply-To: <20151106170007.5196bd5e@pwslap01u.europe.root.pri> References: <87a8qr75za.fsf@gmail.com> <20151106170007.5196bd5e@pwslap01u.europe.root.pri> X-Mailer: Claws Mail 3.11.1 (GTK+ 2.24.28; x86_64-redhat-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit OK, I know what you're all thinking now. "What about whitespace at the end of an internal parameter argument subject to word-splitting? Doesn't that need handling, too? Isn't this, in fact, the most burning question of our day?" Grmph. This is essentially equivalent. I haven't tested RC_EXPAND_PARAM (see under "soul-destroying") but the following is generic enough it ought to be OK. pws diff --git a/Src/subst.c b/Src/subst.c index 5289121..4d04fa7 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -420,6 +420,22 @@ singsub(char **s) 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 @@ -432,14 +448,13 @@ singsub(char **s) * NULL to use IFS). The return value is true iff the expansion resulted * in an empty list. * - * *ws_at_start is set to 1 if the string had whitespace at thes start - * that should cause word splitting against any preceeding string. + * *ws_at_start 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_at_start) + int *ws_sub) { int l; char **r, **p, *x = *s; @@ -455,7 +470,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, l++; if (!iwsep(STOUC(c))) break; - *ws_at_start = 1; + *ws_sub |= WS_AT_START; } } @@ -487,8 +502,10 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, if (!WC_ZISTYPE(c, ISEP)) break; } - if (!*x) + if (!*x) { + *ws_sub |= WS_AT_END; break; + } insertlinknode(&foo, n, (void *)x), incnode(n); } } @@ -1730,7 +1747,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_at_start = 0; + int ws_sub = 0; *s++ = '\0'; /* @@ -2280,7 +2297,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * necessary, when we handle (P) lower down. */ if (multsub(&val, 0, (aspar ? NULL : &aval), &isarr, NULL, - &ws_at_start) && quoted) { + &ws_sub) && quoted) { /* Empty quoted string --- treat as null string, not elided */ isarr = -1; aval = (char **) hcalloc(sizeof(char *)); @@ -2751,7 +2768,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_at_start); + &isarr, NULL, &ws_sub); copied = 1; spbreak = 0; /* Leave globsubst on if forced */ @@ -2780,14 +2797,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_at_start); + NULL, &isarr, NULL, &ws_sub); } else { if (spbreak) split_flags = PREFORK_SPLIT|PREFORK_SHWORDSPLIT; else split_flags = PREFORK_NOSHWORDSPLIT; multsub(&val, split_flags, &aval, &isarr, NULL, - &ws_at_start); + &ws_sub); spbreak = 0; } if (arrasg) { @@ -3319,7 +3336,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } if (haserr || errflag) return NULL; - ws_at_start = 0; + ws_sub = 0; } /* * This handles taking a length with ${#foo} and variations. @@ -3358,7 +3375,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) sprintf(buf, "%ld", len); val = dupstring(buf); isarr = 0; - ws_at_start = 0; + ws_sub = 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 @@ -3388,7 +3405,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) if (isarr) { val = sepjoin(aval, sep, 1); isarr = 0; - ws_at_start = 0; + ws_sub = 0; } if (!ssub && (spbreak || spsep)) { aval = sepsplit(val, spsep, 0, 1); @@ -3673,10 +3690,14 @@ 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_at_start && aptr > ostr) { + if ((ws_sub & WS_AT_START) && aptr > ostr) { insertlinknode(l, n, dupstrpfx(ostr, aptr - ostr)), incnode(n); ostr = aptr; } + if ((ws_sub & WS_AT_END) && *fstr) { + insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */ + *fstr = '\0'; + } if (isarr) { char *x; char *y; diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 59c14a4..694b613 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -1751,26 +1751,26 @@ } foo=bar foo2="bar bar" - do_test ${:- foo} - do_test ${:- foo bar} - do_test ${:- $foo} - do_test ${:- $foo2} - do_test x${:- foo} - do_test x${:- foo bar} - do_test x${:- $foo} - do_test x${:- $foo2} - do_test x${foo:+ $foo} + do_test ${:- foo } + do_test ${:- foo bar } + do_test ${:- $foo } + do_test ${:- $foo2 } + do_test x${:- foo }y + do_test x${:- foo bar }y + do_test x${:- $foo }y + do_test x${:- $foo2 }y + do_test x${foo:+ $foo }y ) 0:We Love SH_WORD_SPLIT Day celebrated with space at start of internal subst >1: foo >2: foo bar >1: bar >2: bar bar ->2: x foo ->3: x foo bar ->2: x bar ->3: x bar bar ->2: x bar +>3: x foo y +>4: x foo bar y +>3: x bar y +>4: x bar bar y +>3: x bar y (unsetopt shwordsplit # default, for clarity do_test() { @@ -1778,23 +1778,23 @@ } foo=bar foo2="bar bar" - do_test ${:- foo} - do_test ${:- foo bar} - do_test ${:- $foo} - do_test ${:- $foo2} - do_test x${:- foo} - do_test x${:- foo bar} - do_test x${:- $foo} - do_test x${:- $foo2} - do_test x${foo:+ $foo} + do_test ${:- foo } + do_test ${:- foo bar } + do_test ${:- $foo } + do_test ${:- $foo2 } + do_test x${:- foo }y + do_test x${:- foo bar }y + do_test x${:- $foo }y + do_test x${:- $foo2 }y + do_test x${foo:+ $foo }y ) 0:We Love NO_SH_WORD_SPLIT Even More Day celebrated as sanity check ->1: foo ->1: foo bar ->1: bar ->1: bar bar ->1: x foo ->1: x foo bar ->1: x bar ->1: x bar bar ->1: x bar +>1: foo +>1: foo bar +>1: bar +>1: bar bar +>1: x foo y +>1: x foo bar y +>1: x bar y +>1: x bar bar y +>1: x bar y