From: Mikael Magnusson <mikachu@gmail.com>
To: zsh workers <zsh-workers@zsh.org>
Subject: extended braces syntax, {1..32..-03}
Date: Sun, 5 Dec 2010 16:41:20 +0100 [thread overview]
Message-ID: <AANLkTimOhbjnSiCWJ9y8jJ_WCscTF27ROR=Fg2twOMod@mail.gmail.com> (raw)
This patch adds the syntax {start..end..step} to brace expansion. It
also allows negative numbers to be used (this was allowed when
braceccl was set before, which worked inconsistently). It also fixes
up zero-padding with negative numbers. You can specify zeropadding in
the step, as well as a negative step. Using a negative step rather
than reversing the order makes a difference as shown here:
% echo {1..32..4}
1 5 9 13 17 21 25 29
% echo {1..32..-4}
29 25 21 17 13 9 5 1
% echo {32..1..4}
32 28 24 20 16 12 8 4
% echo {32..1..-4}
4 8 12 16 20 24 28 32
The basic syntax is stolen/borrowed from bash, but bash does not allow
negative steps.
Missing still is documentation, but I've had this lying around since
august so I figured I'd post it and see if anyone wants to change
anything first.
Zero-padding works like this:
% echo {01..4}
01 02 03 04
% echo {01..-4}
01 00 -1 -2 -3 -4
% echo {1..-04}
001 000 -01 -02 -03 -04
% echo {1..-4..01}
01 00 -1 -2 -3 -4
% echo {1..-4..-02}
-03 -01 001
Originally i had the same number of zeroes regardless of the minus
sign, but bash does it this way, so I figured I'd be consistent with
that.
The code is admittedly somewhat cryptic in places.
Here's a link to the patch,
http://mika.l3ib.org/patches/zsh-extended-braces.patch
And here's the patch
>From 6fa4a778632320f234f0b9c1f477f5cd3a66a5ff Mon Sep 17 00:00:00 2001
From: Mikael Magnusson <mikachu@gmail.com>
Date: Wed, 7 Jul 2010 00:12:25 +0200
Subject: [PATCH] Add {1..10..2} syntax, allow negative numbers without
braceccl set
---
Src/glob.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/Src/glob.c b/Src/glob.c
index c552e6c..5f68135 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);
--
1.7.3
--
Mikael Magnusson
next reply other threads:[~2010-12-05 16:10 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-05 15:41 Mikael Magnusson [this message]
2010-12-05 17:25 ` Peter Stephenson
2010-12-05 19:17 ` Mikael Magnusson
2010-12-05 19:25 ` Mikael Magnusson
2010-12-05 21:32 ` Mikael Magnusson
2010-12-06 21:02 ` Richard Hartmann
2010-12-06 21:04 ` Mikael Magnusson
2010-12-06 21:18 ` Richard Hartmann
2010-12-07 11:40 ` Peter Stephenson
2010-12-06 20:57 ` Richard Hartmann
2010-12-06 21:00 ` Mikael Magnusson
2010-12-06 21:17 ` Richard Hartmann
2010-12-06 21:49 ` Mikael Magnusson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='AANLkTimOhbjnSiCWJ9y8jJ_WCscTF27ROR=Fg2twOMod@mail.gmail.com' \
--to=mikachu@gmail.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).