summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/expn.yo8
-rw-r--r--Src/glob.c45
-rw-r--r--Src/subst.c106
4 files changed, 114 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index 915f54038..4e29c62d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2002-02-22 Oliver Kiddle <opk@zsh.org>
+
+ * 16620, 16697: Src/subst.c, Src/glob.c, Doc/Zsh/expn.yo:
+ add a and n parameter expansion flags for numeric sorting and
+ reverse index ordering of arrays
+
2002-02-21 Clint Adams <clint@zsh.org>
* 16689: Etc/.distfiles, Etc/TODO: list some things to do.
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 3d40da10b..c01e5ce3e 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -620,6 +620,11 @@ arrays; the var(word) part em(must) be converted to an array, for
example by using `tt(${(AA)=)var(name)tt(=)...tt(})' to activate
field splitting, when creating an associative array.
)
+item(tt(a))(
+With tt(o) or tt(O), sort in array index order. Note that `tt(oa)' is
+therefore equivalent to the default but `tt(Oa)' is useful for
+obtaining an array's elements in reverse order.
+)
item(tt(c))(
With tt(${#)var(name)tt(}), count the total number of characters in an array,
as if the elements were concatenated with spaces between them.
@@ -655,6 +660,9 @@ this flag may not be combined with subscript ranges.
item(tt(L))(
Convert all letters in the result to lower case.
)
+item(tt(n))(
+With tt(o) or tt(O), sort numerically.
+)
item(tt(o))(
Sort the resulting words in ascending order.
)
diff --git a/Src/glob.c b/Src/glob.c
index aa82b91c1..75509fee5 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -854,7 +854,10 @@ gmatchcmp(Gmatch a, Gmatch b)
for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
switch (*s & ~GS_DESC) {
case GS_NAME:
- r = notstrcmp(&a->name, &b->name);
+ if (gf_numsort)
+ r = nstrpcmp(&b->name, &a->name);
+ else
+ r = strpcmp(&b->name, &a->name);
break;
case GS_DEPTH:
{
@@ -1611,46 +1614,6 @@ zglob(LinkList list, LinkNode np, int nountok)
restore_globstate(saved);
}
-/* Return the order of two strings, taking into account *
- * possible numeric order if NUMERICGLOBSORT is set. *
- * The comparison here is reversed. */
-
-/**/
-static int
-notstrcmp(char **a, char **b)
-{
- char *c = *b, *d = *a;
- int cmp;
-
-#ifdef HAVE_STRCOLL
- cmp = strcoll(c, d);
-#endif
- for (; *c == *d && *c; c++, d++);
-#ifndef HAVE_STRCOLL
- cmp = (int)STOUC(*c) - (int)STOUC(*d);
-#endif
- if (gf_numsort && (idigit(*c) || idigit(*d))) {
- for (; c > *b && idigit(c[-1]); c--, d--);
- if (idigit(*c) && idigit(*d)) {
- while (*c == '0')
- c++;
- while (*d == '0')
- d++;
- for (; idigit(*c) && *c == *d; c++, d++);
- if (idigit(*c) || idigit(*d)) {
- cmp = (int)STOUC(*c) - (int)STOUC(*d);
- while (idigit(*c) && idigit(*d))
- c++, d++;
- if (idigit(*c) && !idigit(*d))
- return 1;
- if (idigit(*d) && !idigit(*c))
- return -1;
- }
- }
- }
- return cmp;
-}
-
/* Return the trailing character for marking file types */
/**/
diff --git a/Src/subst.c b/Src/subst.c
index 607e9b979..7a0a8b16b 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -540,6 +540,72 @@ invcstrpcmp(const void *a, const void *b)
}
/**/
+int
+nstrpcmp(const void *a, const void *b)
+{
+ char *c = *(char **)a, *d = *(char **)b;
+ int cmp;
+
+#ifdef HAVE_STRCOLL
+ cmp = strcoll(c, d);
+#endif
+ for (; *c == *d && *c; c++, d++);
+#ifndef HAVE_STRCOLL
+ cmp = (int)STOUC(*c) - (int)STOUC(*d);
+#endif
+ if (idigit(*c) || idigit(*d)) {
+ for (; c > *(char **)b && idigit(c[-1]); c--, d--);
+ if (idigit(*c) && idigit(*d)) {
+ while (*c == '0')
+ c++;
+ while (*d == '0')
+ d++;
+ for (; idigit(*c) && *c == *d; c++, d++);
+ if (idigit(*c) || idigit(*d)) {
+ cmp = (int)STOUC(*c) - (int)STOUC(*d);
+ while (idigit(*c) && idigit(*d))
+ c++, d++;
+ if (idigit(*c) && !idigit(*d))
+ return 1;
+ if (idigit(*d) && !idigit(*c))
+ return -1;
+ }
+ }
+ }
+ return cmp;
+}
+
+/**/
+int
+invnstrpcmp(const void *a, const void *b)
+{
+ return -nstrpcmp(a, b);
+}
+
+/**/
+int
+instrpcmp(const void *a, const void *b)
+{
+ VARARR(char, c, strlen(*(char **) a) + 1);
+ VARARR(char, d, strlen(*(char **) b) + 1);
+ char **e = (char **)&c;
+ char **f = (char **)&d;
+ char *s, *t;
+
+ for (s = *(char **) a, t = c; (*t++ = tulower(*s++)););
+ for (s = *(char **) b, t = d; (*t++ = tulower(*s++)););
+
+ return nstrpcmp(&e, &f);
+}
+
+/**/
+int
+invinstrpcmp(const void *a, const void *b)
+{
+ return -instrpcmp(a, b);
+}
+
+/**/
static char *
dopadding(char *str, int prenum, int postnum, char *preone, char *postone, char *premul, char *postmul)
{
@@ -773,7 +839,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
Value v = NULL;
int flags = 0;
int flnum = 0;
- int sortit = 0, casind = 0;
+ int sortit = 0, casind = 0, numord = 0, indord = 0;
int unique = 0;
int casmod = 0;
int quotemod = 0, quotetype = 0, quoteerr = 0;
@@ -881,6 +947,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
case 'i':
casind = 1;
break;
+ case 'n':
+ numord = 1;
+ break;
+ case 'a':
+ indord = 1;
+ break;
case 'V':
visiblemod++;
@@ -1018,7 +1090,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
}
}
if (sortit)
- sortit += (casind << 1);
+ sortit += (casind << 1) + (numord << 2);
if (!premul)
premul = " ";
@@ -1894,16 +1966,30 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
zhuniqarray(aval);
}
if (sortit) {
- static CompareFn sortfn[] = {
- strpcmp, invstrpcmp, cstrpcmp, invcstrpcmp
- };
-
if (!copied)
aval = arrdup(aval);
-
- i = arrlen(aval);
- if (i && (*aval[i-1] || --i))
- qsort(aval, i, sizeof(char *), sortfn[sortit-1]);
+ if (indord) {
+ if (sortit & 2) {
+ char *copy;
+ char **end = aval + arrlen(aval) - 1, **start = aval;
+
+ /* reverse the array */
+ while (start < end) {
+ copy = *end;
+ *end-- = *start;
+ *start++ = copy;
+ }
+ }
+ } else {
+ static CompareFn sortfn[] = {
+ strpcmp, invstrpcmp, cstrpcmp, invcstrpcmp,
+ nstrpcmp, invnstrpcmp, instrpcmp, invinstrpcmp
+ };
+
+ i = arrlen(aval);
+ if (i && (*aval[i-1] || --i))
+ qsort(aval, i, sizeof(char *), sortfn[sortit-1]);
+ }
}
if (plan9) {
LinkNode tn;