From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29101 invoked by alias); 11 May 2011 15:39:53 -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: 29224 Received: (qmail 4287 invoked from network); 11 May 2011 15:39:50 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW, T_TO_NO_BRKTS_FREEMAIL autolearn=ham version=3.3.1 Received-SPF: pass (ns1.primenet.com.au: SPF record at _spf.google.com designates 209.85.214.43 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:subject:date:message-id:x-mailer :in-reply-to:references; bh=agJ7PVDblAFgofejCz2tbtLnFlGZ8lkpfUIxzfowKOo=; b=o5YZ97/Q9jW/L5dkFcToq0iLPFy2cQJWpPxKZeLgH9iPb2IZs3BcWzbOVwBcMj7Gw0 ou/q9JXU8va7dtyX/77Dhewe4/LfynN1J+XsYnHjDb3TyEA73eYJ2YTxve+6q72clfmx EyBXuJxfqNOD1YNF0erea22BeUvteVIfw5b80= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:subject:date:message-id:x-mailer:in-reply-to:references; b=kRKpUXIGkDypeKUbKYZc2lHJvNvMEB8hNOMB/2Sr5uAEK9eNuwwuVXQiQLSS8k/aVp tn1Y6heDBALNALnnvST77BOclyZ+qeHpC4LDBBKqQguqh22EDPDafOtKKx0sceNK/ZXg PhouCUSkSIyMxhy+mxPOwkk3aEMSucB6g9UL8= From: Mikael Magnusson To: zsh-workers@zsh.org Subject: PATCH: support negative LEN in ${VAR:OFFSET:LEN} Date: Wed, 11 May 2011 17:39:33 +0200 Message-Id: <1305128373-26513-1-git-send-email-mikachu@gmail.com> X-Mailer: git-send-email 1.7.4-rc1 In-Reply-To: <110316092120.ZM19292@torch.brasslantern.com> References: <110316092120.ZM19292@torch.brasslantern.com> Updated with your docs and error messages. % echo ${path:10:-5} zsh: substring expression: 8 < 10 % echo ${PATH:150:-150} zsh: substring expression: 85 < 150 --- Doc/Zsh/expn.yo | 12 ++++++++---- Src/subst.c | 40 +++++++++++++++++++++++++++++++--------- Test/D04parameter.ztst | 14 ++++++++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 3a1c372..5d69dbd 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -588,7 +588,7 @@ remove the non-matched elements). xitem(tt(${)var(name)tt(:)var(offset)tt(})) item(tt(${)var(name)tt(:)var(offset)tt(:)var(length)tt(}))( This syntax gives effects similar to parameter subscripting -in the form tt($)var(name)tt({)var(start)tt(,)var(end)tt(}), but is +in the form tt($)var(name)tt([)var(start)tt(,)var(end)tt(]), but is compatible with other shells; note that both var(offset) and var(length) are interpreted differently from the components of a subscript. @@ -608,8 +608,12 @@ the option tt(KSH_ARRAYS). A negative offset counts backwards from the end of the scalar or array, so that -1 corresponds to the last character or element, and so on. -var(length) is always treated directly as a length and hence may not be -negative. The option tt(MULTIBYTE) is obeyed, i.e. the offset and length +When positive, var(length) counts from the var(offset) position +toward the end of the scalar or array. When negative, var(length) +counts back from the end. If this results in a position smaller +than var(offset), a diagnostic is printed and nothing is substituted. + +The option tt(MULTIBYTE) is obeyed, i.e. the offset and length count multibyte characters where appropriate. var(offset) and var(length) undergo the same set of shell substitutions @@ -635,7 +639,7 @@ tt(${)var(name)tt(:-)var(word)tt(}) form of substitution. Instead, a space may be inserted before the tt(-). Furthermore, neither var(offset) nor var(length) may begin with an alphabetic character or tt(&) as these are used to indicate history-style modifiers. To substitute a value from a -variable, the recommended approach is to proceed it with a tt($) as this +variable, the recommended approach is to precede it with a tt($) as this signifies the intention (parameter substitution can easily be rendered unreadable); however, as arithmetic substitution is performed, the expression tt(${var: offs}) does work, retrieving the offset from diff --git a/Src/subst.c b/Src/subst.c index 723bb25..ce4dbe6 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2834,7 +2834,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) char *check_offset = check_colon_subscript(s, &check_offset2); if (check_offset) { zlong offset = mathevali(check_offset); - zlong length = (zlong)-1; + zlong length; + int length_set = 0; int offset_hack_argzero = 0; if (errflag) return NULL; @@ -2849,14 +2850,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) zerr("invalid length: %s", check_offset); return NULL; } - if (check_offset) { + if (check_offset) { length = mathevali(check_offset); + length_set = 1; if (errflag) return NULL; - if (length < (zlong)0) { - zerr("invalid length: %s", check_offset); - return NULL; - } } } if (horrible_offset_hack) { @@ -2884,8 +2882,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } if (offset_hack_argzero) alen++; - if (length < 0) - length = alen; + if (length_set) { + if (length < 0) + length += alen - offset; + if (length < 0) { + zerr("substring expression: %d < %d", + length + offset, offset); + return NULL; + } + } else + length = alen; if (offset > alen) offset = alen; if (offset + length > alen) @@ -2904,6 +2910,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) aval = newarr; } else { char *sptr, *eptr; + int given_offset; if (offset < 0) { MB_METACHARINIT(); for (sptr = val; *sptr; ) { @@ -2913,12 +2920,27 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (offset < 0) offset = 0; } + given_offset = offset; MB_METACHARINIT(); + if (length_set && length < 0) + length -= offset; for (sptr = val; *sptr && offset; ) { sptr += MB_METACHARLEN(sptr); offset--; } - if (length >= 0) { + if (length_set) { + if (length < 0) { + MB_METACHARINIT(); + for (eptr = val; *eptr; ) { + eptr += MB_METACHARLEN(eptr); + length++; + } + if (length < 0) { + zerr("substring expression: %d < %d", + length + given_offset, given_offset); + return NULL; + } + } for (eptr = sptr; *eptr && length; ) { eptr += MB_METACHARLEN(eptr); length--; diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 3646245..b91caaa 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -1346,6 +1346,7 @@ print ${foo:$(echo 3 + 3):`echo 4 - 3`} print ${foo: -1} print ${foo: -10} + print ${foo:5:-2} 0:Bash-style offsets, scalar >456789 >56789 @@ -1357,6 +1358,7 @@ >7 >9 >123456789 +>67 foo=(1 2 3 4 5 6 7 8 9) print ${foo:3} @@ -1369,6 +1371,7 @@ print ${foo:$(echo 3 + 3):`echo 4 - 3`} print ${foo: -1} print ${foo: -10} + print ${foo:5:-2} 0:Bash-style offsets, array >4 5 6 7 8 9 >5 6 7 8 9 @@ -1380,6 +1383,7 @@ >7 >9 >1 2 3 4 5 6 7 8 9 +>6 7 testfn() { emulate -L sh @@ -1418,3 +1422,13 @@ print ${str:0:} 1:Regression test for missing length after offset ?(eval):2: unrecognized modifier + + foo="123456789" + print ${foo:5:-6} +1:Regression test for total length < 0 in string +?(eval):2: substring expression: 3 < 5 + + foo=(1 2 3 4 5 6 7 8 9) + print ${foo:5:-6} +1:Regression test for total length < 0 in array +?(eval):2: substring expression: 3 < 5 -- 1.7.4-rc1