summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-12-05 21:07:48 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-12-05 21:07:48 +0000
commit25b12c5d1139de9b7527a1fa2b722fe19c46f462 (patch)
tree2dd4bfe5de2cd459ddc694a8fd748e4a885e30cc
parent71d8d60e7d62a8b683d44ff5416ec79b12a5e256 (diff)
downloadzsh-25b12c5d1139de9b7527a1fa2b722fe19c46f462.tar.gz
zsh-25b12c5d1139de9b7527a1fa2b722fe19c46f462.zip
28474, 28478: extended {START..END..STEP} syntax
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/expn.yo13
-rw-r--r--Src/glob.c71
-rw-r--r--Test/D09brace.ztst47
4 files changed, 122 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 0d001fa9a..212ac68f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2010-12-05 Peter Stephenson <p.w.stephenson@ntlworld.com>
+ * Mikael: 28474, 28478: Doc/Zsh/expn.yo, Src/glob.c,
+ Test/D09brace.ztst: extended {START..END..STEP} syntax.
+
* 28476: Test/.distfiles, Test/D09brace.ztst: new set of tests
for brace expansion.
@@ -13893,5 +13896,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5138 $
+* $Revision: 1.5139 $
*****************************************************
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 0c26a7ca5..bae3736a9 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1419,9 +1419,20 @@ where var(n1) and var(n2) are integers,
is expanded to every number between
var(n1) and var(n2) inclusive. If either number begins with a
zero, all the resulting numbers will be padded with leading zeroes to
-that minimum width. If the numbers are in decreasing order the
+that minimum width, but for negative numbers the tt(-) character is also
+included in the width. If the numbers are in decreasing order the
resulting sequence will also be in decreasing order.
+An expression of the form `tt({)var(n1)tt(..)var(n2)tt(..)var(n3)tt(})',
+where var(n1), var(n2), and var(n3) are integers,
+is expanded as above, but only every var(n3)th number starting from var(n1)
+is output. If var(n3) is negative the numbers are output in reverse order,
+this is slightly different from simply swapping var(n1) and var(n2) in the case
+that the step var(n3) doesn't evenly divide the range. Zero padding can be
+specified in any of the three numbers, specifying it in the third can be useful
+to pad for example `tt({-99..100..01})' which is not possible to specify by putting a
+0 on either of the first two numbers (i.e. pad to two characters).
+
If a brace expression matches none of the above forms, it is left
unchanged, unless the option tt(BRACE_CCL) (an abbreviation for `brace
character class') is set.
diff --git a/Src/glob.c b/Src/glob.c
index c552e6cf1..5f6813589 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1924,14 +1924,29 @@ hasbraces(char *str)
case Inbrace:
if (!lbr) {
lbr = str - 1;
+ if (*str == '-')
+ str++;
while (idigit(*str))
str++;
if (*str == '.' && str[1] == '.') {
- str++;
- while (idigit(*++str));
+ str++; str++;
+ if (*str == '-')
+ str++;
+ while (idigit(*str))
+ str++;
if (*str == Outbrace &&
(idigit(lbr[1]) || idigit(str[-1])))
return 1;
+ else if (*str == '.' && str[1] == '.') {
+ str++; str++;
+ if (*str == '-')
+ str++;
+ while (idigit(*str))
+ str++;
+ if (*str == Outbrace &&
+ (idigit(lbr[1]) || idigit(str[-1])))
+ return 1;
+ }
}
} else {
char *s = --str;
@@ -2061,18 +2076,20 @@ xpandbraces(LinkList list, LinkNode *np)
} else if (bc == 1) {
if (*str2 == Comma)
++comma; /* we have {foo,bar} */
- else if (*str2 == '.' && str2[1] == '.')
+ else if (*str2 == '.' && str2[1] == '.') {
dotdot++; /* we have {num1..num2} */
+ ++str2;
+ }
}
DPUTS(bc, "BUG: unmatched brace in xpandbraces()");
if (!comma && dotdot) {
/* Expand range like 0..10 numerically: comma or recursive
brace expansion take precedence. */
- char *dots, *p;
+ char *dots, *p, *dots2 = NULL;
LinkNode olast = last;
/* Get the first number of the range */
- int rstart = zstrtol(str+1,&dots,10), rend = 0, err = 0, rev = 0;
- int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2;
+ int rstart = zstrtol(str+1,&dots,10), rend = 0, err = 0, rev = 0, rincr = 1;
+ int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2, wid3 = 0;
int strp = str - str3;
if (dots == str + 1 || *dots != '.' || dots[1] != '.')
@@ -2080,23 +2097,53 @@ xpandbraces(LinkList list, LinkNode *np)
else {
/* Get the last number of the range */
rend = zstrtol(dots+2,&p,10);
- if (p == dots+2 || p != str2)
+ if (p == dots+2)
err++;
+ /* check for {num1..num2..incr} */
+ if (p != str2) {
+ wid2 = (p - dots) - 2;
+ dots2 = p;
+ if (dotdot == 2 && *p == '.' && p[1] == '.') {
+ rincr = zstrtol(p+2, &p, 10);
+ wid3 = p - dots2 - 2;
+ if (p != str2 || !rincr)
+ err++;
+ } else
+ err++;
+ }
}
if (!err) {
/* If either no. begins with a zero, pad the output with *
- * zeroes. Otherwise, choose a min width to suppress them. */
- int minw = (str[1] == '0') ? wid1 : (dots[2] == '0' ) ? wid2 :
- (wid2 > wid1) ? wid1 : wid2;
+ * zeroes. Otherwise, set min width to 0 to suppress them.
+ * str+1 is the first number in the range, dots+2 the last,
+ * and dots2+2 is the increment if that's given. */
+ /* TODO: sorry about this */
+ int minw = (str[1] == '0' || (str[1] == '-' && str[2] == '0'))
+ ? wid1
+ : (dots[2] == '0' || (dots[2] == '-' && dots[3] == '0'))
+ ? wid2
+ : (dots2 && (dots2[2] == '0' ||
+ (dots2[2] == '-' && dots2[3] == '0')))
+ ? wid3
+ : 0;
+ if (rincr < 0) {
+ /* Handle negative increment */
+ rincr = -rincr;
+ rev = !rev;
+ }
if (rstart > rend) {
/* Handle decreasing ranges correctly. */
int rt = rend;
rend = rstart;
rstart = rt;
- rev = 1;
+ rev = !rev;
+ } else if (rincr > 1) {
+ /* when incr > 1, range is aligned to the highest number of str1,
+ * compensate for this so that it is aligned to the first number */
+ rend -= (rend - rstart) % rincr;
}
uremnode(list, node);
- for (; rend >= rstart; rend--) {
+ for (; rend >= rstart; rend -= rincr) {
/* Node added in at end, so do highest first */
p = dupstring(str3);
sprintf(p + strp, "%0*d", minw, rend);
diff --git a/Test/D09brace.ztst b/Test/D09brace.ztst
index ff2eb522c..d0ec93cd3 100644
--- a/Test/D09brace.ztst
+++ b/Test/D09brace.ztst
@@ -50,3 +50,50 @@
print X{4..1}Y
0:Numeric range expansion, decreasing
>X4Y X3Y X2Y X1Y
+
+ print X{1..4}{1..4}Y
+0:Numeric range expansion, combined braces
+>X11Y X12Y X13Y X14Y X21Y X22Y X23Y X24Y X31Y X32Y X33Y X34Y X41Y X42Y X43Y X44Y
+
+ print X{-4..4}Y
+0:Numeric range expansion, negative numbers (1)
+>X-4Y X-3Y X-2Y X-1Y X0Y X1Y X2Y X3Y X4Y
+
+ print X{4..-4}Y
+0:Numeric range expansion, negative numbers (2)
+>X4Y X3Y X2Y X1Y X0Y X-1Y X-2Y X-3Y X-4Y
+
+ print X{004..-4..2}Y
+0:Numeric range expansion, stepping and padding (1)
+>X004Y X002Y X000Y X-02Y X-04Y
+
+ print X{4..-4..02}Y
+0:Numeric range expansion, stepping and padding (1)
+>X04Y X02Y X00Y X-2Y X-4Y
+
+ print X{1..32..3}Y
+0:Numeric range expansion, step alignment (1)
+>X1Y X4Y X7Y X10Y X13Y X16Y X19Y X22Y X25Y X28Y X31Y
+
+ print X{1..32..-3}Y
+0:Numeric range expansion, step alignment (2)
+>X31Y X28Y X25Y X22Y X19Y X16Y X13Y X10Y X7Y X4Y X1Y
+
+ print X{32..1..3}Y
+0:Numeric range expansion, step alignment (3)
+>X32Y X29Y X26Y X23Y X20Y X17Y X14Y X11Y X8Y X5Y X2Y
+
+ print X{32..1..-3}Y
+0:Numeric range expansion, step alignment (4)
+>X2Y X5Y X8Y X11Y X14Y X17Y X20Y X23Y X26Y X29Y X32Y
+
+ setopt brace_ccl
+ print X{za-q521}Y
+ unsetopt brace_ccl
+0:BRACE_CCL on
+>X1Y X2Y X5Y XaY XbY XcY XdY XeY XfY XgY XhY XiY XjY XkY XlY XmY XnY XoY XpY XqY XzY
+
+ print X{za-q521}Y
+0:BRACE_CCL off
+>X{za-q521}Y
+