1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-02 22:11:54 +02:00

29224: Support negative LEN in ${VAR:OFFSET:LEN} like bash.

This commit is contained in:
Mikael Magnusson 2011-05-19 16:24:38 +00:00
parent 6a29bc80d0
commit 0198b8423d
5 changed files with 61 additions and 14 deletions

View file

@ -1,3 +1,7 @@
2011-05-19 Mikael Magnusson <mikachu@gmail.com>
* 29224: Support negative LEN in ${VAR:OFFSET:LEN} like bash.
2011-05-19 Mikael Magnusson <mikachu@gmail.com>
* 29261: Add g:: parameter expansion flag. Add note that s::
@ -14757,5 +14761,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.5313 $
* $Revision: 1.5314 $
*****************************************************

View file

@ -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

3
NEWS
View file

@ -19,6 +19,9 @@ the command line is edited.
In POSIX emulation ("emulate sh") the shell is more accurate about
when it should or should not exit on errors.
The ${NAME:OFFSET:LENGTH} syntax now supports negative LENGTH, which
counts back from the end of the string.
Changes between versions 4.3.10 and 4.3.11
------------------------------------------

View file

@ -2839,7 +2839,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;
@ -2854,14 +2855,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) {
@ -2889,8 +2887,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)
@ -2909,6 +2915,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; ) {
@ -2918,12 +2925,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--;

View file

@ -1366,6 +1366,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
@ -1377,6 +1378,7 @@
>7
>9
>123456789
>67
foo=(1 2 3 4 5 6 7 8 9)
print ${foo:3}
@ -1389,6 +1391,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
@ -1400,6 +1403,7 @@
>7
>9
>1 2 3 4 5 6 7 8 9
>6 7
testfn() {
emulate -L sh
@ -1438,3 +1442,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