summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/expn.yo12
-rw-r--r--Src/sort.c25
-rw-r--r--Src/subst.c4
-rw-r--r--Src/zsh.h7
-rw-r--r--Test/D04parameter.ztst7
6 files changed, 49 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index b2d94f38c..5161ef6d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2020-07-03 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * users/24971: Doc/Zsh/expn.yo, Src/sort.c, Src/subst.c,
+ Src/zsh.h, Test/D04parameter.ztst: Add parameter flag (-)
+ to allow signed numeric sorting.
+
2020-06-28 zsugabubus <zsugabubus>
* 46097: Completion/Unix/Command/_rm: Fix "assignment to invalid
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index a637b78a1..79b6037df 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1097,17 +1097,23 @@ are sorted before those with fewer or none. Hence the array `tt(foo1 foo02
foo2 foo3 foo20 foo23)' is sorted into the order shown.
May be combined with `tt(i)' or `tt(O)'.
)
+item(tt(-))(
+As tt(n), but a leading minus sign indicates a negative decimal
+integer. A `tt(-)' not followed by an integer does not trigger
+numeric sorting.
+)
item(tt(o))(
Sort the resulting words in ascending order; if this appears on its
own the sorting is lexical and case-sensitive (unless the locale
renders it case-insensitive). Sorting in ascending order is the
default for other forms of sorting, so this is ignored if combined
-with `tt(a)', `tt(i)' or `tt(n)'.
+with `tt(a)', `tt(i)', `tt(n)' or `tt(DASH())'.
)
item(tt(O))(
Sort the resulting words in descending order; `tt(O)' without `tt(a)',
-`tt(i)' or `tt(n)' sorts in reverse lexical order. May be combined
-with `tt(a)', `tt(i)' or `tt(n)' to reverse the order of sorting.
+`tt(i)', `tt(n)' or `tt(DASH())' sorts in reverse lexical order. May be
+combined with `tt(a)', `tt(i)', `tt(n)' or tt(DASH()) to reverse the
+order of sorting.
)
item(tt(P))(
This forces the value of the parameter var(name) to be interpreted as a
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,
};
/*
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index e51c955ee..ac99ff0e3 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1398,6 +1398,13 @@
>a6 a17 a117 b6 b17 b117
>b117 b17 b6 a117 a17 a6
+ foo=(a-6 a117 a-17 a-34 b6 b-117 b17 b-2)
+ print ${(-)foo}
+ print ${(O-)foo}
+0:Numeric sorting of signed integers
+>a-34 a-17 a-6 a117 b-117 b-2 b6 b17
+>b17 b6 b-2 b-117 a117 a-6 a-17 a-34
+
x=sprodj
x[-10]=scrumf
print $x