about summary refs log tree commit diff
path: root/Src/glob.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2014-01-09 10:05:13 +0000
committerPeter Stephenson <pws@zsh.org>2014-01-09 10:05:13 +0000
commitd26461a3c61b311bdbd58334ee5f8a5113dcdbf2 (patch)
tree0bd7ce04f457b52718e94d22310ee7340bdbdd9e /Src/glob.c
parenta34754e962d323ac828a60a233587204c35b7690 (diff)
downloadzsh-d26461a3c61b311bdbd58334ee5f8a5113dcdbf2.tar.gz
zsh-d26461a3c61b311bdbd58334ee5f8a5113dcdbf2.tar.xz
zsh-d26461a3c61b311bdbd58334ee5f8a5113dcdbf2.zip
users/18298 (tidied up): add {<char>..<char>} expansion
Diffstat (limited to 'Src/glob.c')
-rw-r--r--Src/glob.c101
1 files changed, 98 insertions, 3 deletions
diff --git a/Src/glob.c b/Src/glob.c
index e0d0cf68e..9a34a7f30 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1895,6 +1895,8 @@ hasbraces(char *str)
 	switch (*str++) {
 	case Inbrace:
 	    if (!lbr) {
+		if (bracechardots(str-1, NULL, NULL))
+		    return 1;
 		lbr = str - 1;
 		if (*str == '-')
 		    str++;
@@ -2027,6 +2029,52 @@ xpandredir(struct redir *fn, LinkList redirtab)
     return ret;
 }
 
+/*
+ * Check for a brace expansion of the form {<char>..<char>}.
+ * On input str must be positioned at an Inbrace, but the sequence
+ * of characters beyond that has not necessarily been checked.
+ * Return 1 if found else 0.
+ *
+ * The other parameters are optionaland if the function returns 1 are
+ * used to return:
+ * - *c1p: the first character in the expansion.
+ * - *c2p: the final character in the expansion.
+ */
+
+/**/
+static int
+bracechardots(char *str, convchar_t *c1p, convchar_t *c2p)
+{
+    convchar_t cstart, cend;
+    char *pnext = str + 1, *pconv, convstr[2];
+    if (itok(*pnext)) {
+	convstr[0] = ztokens[*pnext - Pound];
+	convstr[1] = '\0';
+	pconv = convstr;
+    } else
+	pconv = pnext;
+    MB_METACHARINIT();
+    pnext += MB_METACHARLENCONV(pconv, &cstart);
+    if (cstart == WEOF || pnext[0] != '.' || pnext[1] != '.')
+	return 0;
+    pnext += 2;
+    if (itok(*pnext)) {
+	convstr[0] = ztokens[*pnext - Pound];
+	convstr[1] = '\0';
+	pconv = convstr;
+    } else
+	pconv = pnext;
+    MB_METACHARINIT();
+    pnext += MB_METACHARLENCONV(pconv, &cend);
+    if (cend == WEOF || *pnext != Outbrace)
+	return 0;
+    if (c1p)
+	*c1p = cstart;
+    if (c2p)
+	*c2p = cend;
+    return 1;
+}
+
 /* brace expansion */
 
 /**/
@@ -2060,10 +2108,57 @@ xpandbraces(LinkList list, LinkNode *np)
 	char *dots, *p, *dots2 = NULL;
 	LinkNode olast = last;
 	/* Get the first number of the range */
-	zlong rstart = zstrtol(str+1,&dots,10), rend = 0;
+	zlong rstart, rend;
 	int err = 0, rev = 0, rincr = 1;
-	int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2, wid3 = 0;
-	int strp = str - str3;
+	int wid1, wid2, wid3, strp;
+	convchar_t cstart, cend;
+
+	if (bracechardots(str, &cstart, &cend)) {
+	    int lenalloc;
+	    /*
+	     * This is a character range.
+	     */
+	    if (cend < cstart) {
+		convchar_t ctmp = cend;
+		cend = cstart;
+		cstart = ctmp;
+		rev = 1;
+	    }
+	    uremnode(list, node);
+	    strp = str - str3;
+	    lenalloc = strp + strlen(str2+1) + 1;
+	    for (; cend >= cstart; cend--) {
+#ifdef MULTIBYTE_SUPPORT
+		char *ncptr;
+		int nclen;
+		mb_metacharinit();
+		ncptr = wcs_nicechar(cend, NULL, NULL);
+		nclen = strlen(ncptr);
+		p = zhalloc(lenalloc + nclen);
+		memcpy(p, str3, strp);
+		memcpy(p + strp, ncptr, nclen);
+		strcpy(p + strp + nclen, str2 + 1);
+#else
+		p = zhalloc(lenalloc + 1);
+		memcpy(p, str3, strp);
+		sprintf(p + strp, "%c", cend);
+		strcat(p + strp, str2 + 1);
+#endif
+		insertlinknode(list, last, p);
+		if (rev)	/* decreasing:  add in reverse order. */
+		    last = nextnode(last);
+	    }
+	    *np = nextnode(olast);
+	    return;
+	}
+
+	/* Get the first number of the range */
+	rstart = zstrtol(str+1,&dots,10);
+	rend = 0;
+	wid1 = (dots - str) - 1;
+	wid2 = (str2 - dots) - 2;
+	wid3 = 0;
+	strp = str - str3;
 
 	if (dots == str + 1 || *dots != '.' || dots[1] != '.')
 	    err++;