about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-11-18 13:57:18 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-11-18 13:57:18 +0000
commit8f20b2361cc2e3911ba67b92f6aa89e7457d17de (patch)
treeb65be3bf863eb33c6118d0b6326be99832049684
parent23bdfc7fd2a012d5205ed22d18eb39e41c8fbc95 (diff)
downloadzsh-8f20b2361cc2e3911ba67b92f6aa89e7457d17de.tar.gz
zsh-8f20b2361cc2e3911ba67b92f6aa89e7457d17de.tar.xz
zsh-8f20b2361cc2e3911ba67b92f6aa89e7457d17de.zip
28419: Doc/Zsh/expn.yo, Src/subst.c, Test/D04parameter.ztst:
KSH_ARRAY ${*:0:1} gives $0, etc.
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/expn.yo10
-rw-r--r--Src/subst.c36
-rw-r--r--Test/D04parameter.ztst29
4 files changed, 77 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 91b8d964d..947b84777 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2010-11-18  Peter Stephenson  <pws@csr.com>
 
+	* 28419: Doc/Zsh/expn.yo, Src/subst.c, Test/D04parameter.ztst:
+	KSH_ARRAY ${*:0:1} gives $0 etc.
+
 	* 28418: Doc/Zsh/expn.yo, Src/lex.c, Src/params.c, Src/subst.c,
 	Test/D04parameter.ztst: add ${NAME:OFFSET} and
 	${NAME:OFFSET:LENGTH} substitution syntax.
@@ -13825,5 +13828,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5122 $
+* $Revision: 1.5123 $
 *****************************************************
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 6f29a8778..416d46407 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -623,6 +623,16 @@ tt(${)var(name)tt(:-)var(word)tt(}) form of substitution; 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.
+
+For further compatibility with other shells there is a special case
+when the tt(KSH_ARRAYS) option is active, as in emulation of
+Bourne-style shells.  In this case array subscript 0 usually refers to the
+first element of the array.  However, if the substitution refers to the
+positional parameter array, e.g. tt($@) or tt($*), then offset 0
+instead refers to tt($0), offset 1 refers to tt($1), and so on.  In
+other words, the positional parameter array is effectively extended by
+prepending tt($0).  Hence tt(${*:0:1}) substitutes tt($0) and
+tt(${*:1:1}) substitutes tt($1).
 )
 xitem(tt(${)var(name)tt(/)var(pattern)tt(/)var(repl)tt(}))
 item(tt(${)var(name)tt(//)var(pattern)tt(/)var(repl)tt(}))(
diff --git a/Src/subst.c b/Src/subst.c
index c0fb38a48..23c3a7bb5 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1636,6 +1636,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
      * and the argument passing to fetchvalue has another kludge.
      */
     int subexp;
+    /*
+     * If we're referring to the positional parameters, then
+     * e.g ${*:1:1} refers to $1 even if KSH_ARRAYS is in effect.
+     * This is for compatibility.
+     */
+    int horrible_offset_hack = 0;
 
     *s++ = '\0';
     /*
@@ -2281,6 +2287,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		val = getstrvalue(v);
 	    }
 	}
+	/* See if this is a reference to the positional parameters. */
+	if (v && v->pm && v->pm->gsu.a == &vararray_gsu &&
+	    (char ***)v->pm->u.data == &pparams)
+	    horrible_offset_hack = 1;
+	else
+	    horrible_offset_hack = 0;
 	/*
 	 * Finished with the original parameter and its indices;
 	 * carry on looping to see if we need to do more indexing.
@@ -2732,6 +2744,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	    if (check_offset) {
 		zlong offset = mathevali(check_offset);
 		zlong length = (zlong)-1;
+		int offset_hack_argzero = 0;
 		if (errflag)
 		    return NULL;
 		if ((*check_offset2 && *check_offset2 != ':')) {
@@ -2753,8 +2766,21 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 			return NULL;
 		    }
 		}
-		if (!isset(KSHARRAYS) && offset > 0)
-		    offset--;
+		if (!isset(KSHARRAYS) || horrible_offset_hack) {
+		    /*
+		     * As part of the 'orrible hoffset 'ack,
+		     * (what hare you? Han 'orrible hoffset 'ack,
+		     * sergeant major), if we are given a ksh/bash/POSIX
+		     * style array which includes offset 0, we use
+		     * $0.
+		     */
+		    if (isset(KSHARRAYS) && horrible_offset_hack &&
+			offset == 0 && isarr) {
+			offset_hack_argzero = 1;
+		    } else if (offset > 0) {
+			offset--;
+		    }
+		}
 		if (isarr) {
 		    int alen = arrlen(aval), count;
 		    char **srcptr, **dstptr, **newarr;
@@ -2764,6 +2790,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 			if (offset < 0)
 			    offset = 0;
 		    }
+		    if (offset_hack_argzero)
+			alen++;
 		    if (length < 0)
 		      length = alen;
 		    if (offset > alen)
@@ -2774,6 +2802,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		    srcptr = aval + offset;
 		    newarr = dstptr = (char **)
 			zhalloc((length+1)*sizeof(char *));
+		    if (count && offset_hack_argzero) {
+			*dstptr++ = dupstring(argzero);
+			count--;
+		    }
 		    while (count--)
 			*dstptr++ = dupstring(*srcptr++);
 		    *dstptr = (char *)NULL;
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 7c6a465af..46565a121 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1302,3 +1302,32 @@
 >6
 >9
 >1 2 3 4 5 6 7 8 9
+
+   testfn() {
+     emulate -L sh
+     set -A foo 1 2 3
+     set -- 1 2 3
+     str=abc
+     echo ${foo[*]:0:1}
+     echo ${foo[*]:1:1}
+     echo ${foo[*]: -1:1}
+     :
+     echo ${*:0:1}
+     echo ${*:1:1}
+     echo ${*: -1:1}
+     :
+     echo ${str:0:1}
+     echo ${str:1:1}
+     echo ${str: -1:1}
+   }
+   testfn
+0:Bash-style subscripts, Bourne-style indexing
+>1
+>2
+>3
+>testfn
+>1
+>3
+>a
+>b
+>c