about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <p.w.stephenson@ntlworld.com>2020-07-03 21:05:46 +0100
committerPeter Stephenson <p.w.stephenson@ntlworld.com>2020-07-03 21:05:46 +0100
commit4e0058afc5ea040a788d70edbfa43593295816d1 (patch)
tree2ddff880e422a30b17333a329df25d24a902e975 /Src
parent19390a1ba8dc983b0a1379058e90cd51ce156815 (diff)
downloadzsh-4e0058afc5ea040a788d70edbfa43593295816d1.tar.gz
zsh-4e0058afc5ea040a788d70edbfa43593295816d1.tar.xz
zsh-4e0058afc5ea040a788d70edbfa43593295816d1.zip
users/24971: ${(-)var} sorts on signed integers
Diffstat (limited to 'Src')
-rw-r--r--Src/sort.c25
-rw-r--r--Src/subst.c4
-rw-r--r--Src/zsh.h7
3 files changed, 27 insertions, 9 deletions
diff --git a/Src/sort.c b/Src/sort.c
index 8faf9349c..26949ad9c 100644
--- a/Src/sort.c
+++ b/Src/sort.c
@@ -135,12 +135,23 @@ eltpcmp(const void *a, const void *b)
 #endif
 
     if (sortnumeric) {
+	int mul = 0;
 	for (; *as == *bs && *as; as++, bs++);
 #ifndef HAVE_STRCOLL
 	cmp = (int)STOUC(*as) - (int)STOUC(*bs);
 #endif
-	if (idigit(*as) || idigit(*bs)) {
+	if (sortnumeric < 0) {
+	    if (*as == '-' && idigit(as[1]) && idigit(*bs)) {
+		cmp = -1;
+		mul = 1;
+	    } else if (*bs == '-' && idigit(bs[1]) && idigit(*as)) {
+		cmp = 1;
+		mul = 1;
+	    }
+	}
+	if (!mul && (idigit(*as) || idigit(*bs))) {
 	    for (; as > ao && idigit(as[-1]); as--, bs--);
+	    mul = (sortnumeric < 0 && as > ao && as[-1] == '-') ? -1 : 1;
 	    if (idigit(*as) && idigit(*bs)) {
 		while (*as == '0')
 		    as++;
@@ -148,13 +159,13 @@ eltpcmp(const void *a, const void *b)
 		    bs++;
 		for (; idigit(*as) && *as == *bs; as++, bs++);
 		if (idigit(*as) || idigit(*bs)) {
-		    cmp = (int)STOUC(*as) - (int)STOUC(*bs);
+		    cmp = mul * ((int)STOUC(*as) - (int)STOUC(*bs));
 		    while (idigit(*as) && idigit(*bs))
 			as++, bs++;
 		    if (idigit(*as) && !idigit(*bs))
-			return sortdir;
+			return mul * sortdir;
 		    if (idigit(*bs) && !idigit(*as))
-			return -sortdir;
+			return -mul * sortdir;
 		}
 	    }
 	}
@@ -195,7 +206,8 @@ zstrcmp(const char *as, const char *bs, int sortflags)
 
     sortdir = 1;
     sortnobslash = (sortflags & SORTIT_IGNORING_BACKSLASHES) ? 1 : 0;
-    sortnumeric = (sortflags & SORTIT_NUMERICALLY) ? 1 : 0;
+    sortnumeric = (sortflags & SORTIT_NUMERICALLY_SIGNED) ? -1 :
+	(sortflags & SORTIT_NUMERICALLY) ? 1 : 0;
 
     ret = eltpcmp(&aeptr, &beptr);
 
@@ -389,7 +401,8 @@ strmetasort(char **array, int sortwhat, int *unmetalenp)
     oldsortnumeric = sortnumeric;
 
     sortdir = (sortwhat & SORTIT_BACKWARDS) ? -1 : 1;
-    sortnumeric = (sortwhat & SORTIT_NUMERICALLY) ? 1 : 0;
+    sortnumeric = (sortwhat & SORTIT_NUMERICALLY_SIGNED) ? -1 :
+	(sortwhat & SORTIT_NUMERICALLY) ? 1 : 0;
 
     qsort(sortptrarr, nsort, sizeof(SortElt), eltpcmp);
 
diff --git a/Src/subst.c b/Src/subst.c
index ed3f4a82b..b98ddaf02 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1979,6 +1979,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 		case 'n':
 		    sortit |= SORTIT_NUMERICALLY;
 		    break;
+		case '-':
+		case Dash:
+		    sortit |= SORTIT_NUMERICALLY_SIGNED;
+		    break;
 		case 'a':
 		    sortit |= SORTIT_SOMEHOW;
 		    indord = 1;
diff --git a/Src/zsh.h b/Src/zsh.h
index ed123f2b9..c48be4ffd 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2997,17 +2997,18 @@ enum {
     SORTIT_ANYOLDHOW = 0,	/* Defaults */
     SORTIT_IGNORING_CASE = 1,
     SORTIT_NUMERICALLY = 2,
-    SORTIT_BACKWARDS = 4,
+    SORTIT_NUMERICALLY_SIGNED = 4,
+    SORTIT_BACKWARDS = 8,
     /*
      * Ignore backslashes that quote another character---which may
      * be another backslash; the second backslash is active.
      */
-    SORTIT_IGNORING_BACKSLASHES = 8,
+    SORTIT_IGNORING_BACKSLASHES = 16,
     /*
      * Ignored by strmetasort(); used by paramsubst() to indicate
      * there is some sorting to do.
      */
-    SORTIT_SOMEHOW = 16,
+    SORTIT_SOMEHOW = 32,
 };
 
 /*