summary refs log tree commit diff
path: root/Src/glob.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/glob.c')
-rw-r--r--Src/glob.c71
1 files changed, 59 insertions, 12 deletions
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);