Add :On for numeric sort

Reviewed by: christos rillig
This commit is contained in:
sjg 2021-07-30 19:55:22 +00:00
parent 4b00815e3d
commit 4696d0f378
5 changed files with 103 additions and 7 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: make.1,v 1.296 2021/02/04 21:42:46 rillig Exp $
.\" $NetBSD: make.1,v 1.297 2021/07/30 19:55:22 sjg Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
.Dd December 22, 2020
.Dd July 30, 2020
.Dt MAKE 1
.Os
.Sh NAME
@ -1232,8 +1232,18 @@ but selects all words which do not match
.Ar pattern .
.It Cm \&:O
Orders every word in variable alphabetically.
.It Cm \&:On
Orders every word in variable numerically.
A number followed by one of
.Ql K ,
.Ql M
or
.Ql G
is multiplied by the appropriate factor.
.It Cm \&:Or
Orders every word in variable in reverse alphabetical order.
.It Cm \&:Orn
Orders every word in variable in reverse numerical order.
.It Cm \&:Ox
Shuffles the words in variable.
The results will be different each time you are referring to the

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.280 2021/06/29 00:35:23 sjg Exp $
# $NetBSD: Makefile,v 1.281 2021/07/30 19:55:22 sjg Exp $
#
# Unit tests for make(1)
#
@ -355,6 +355,7 @@ TESTS+= varmod-match
TESTS+= varmod-match-escape
TESTS+= varmod-no-match
TESTS+= varmod-order
TESTS+= varmod-order-numeric
TESTS+= varmod-order-reverse
TESTS+= varmod-order-shuffle
TESTS+= varmod-path

View File

@ -0,0 +1 @@
exit status 0

View File

@ -0,0 +1,18 @@
# $NetBSD: varmod-order-numeric.mk,v 1.1 2021/07/30 19:55:22 sjg Exp $
#
# Tests for the :On variable modifier, which returns the words, sorted in
# ascending numeric order.
NUMBERS= 3 5 7 1 42 -42 1M 1k
.if ${NUMBERS:On} != "-42 1 3 5 7 42 1k 1M"
. error ${NUMBERS:On}
.endif
.if ${NUMBERS:Orn} != "1M 1k 42 7 5 3 1 -42"
. error ${NUMBERS:Orn}
.endif
all:
@:;

View File

@ -1,4 +1,4 @@
/* $NetBSD: var.c,v 1.938 2021/06/21 18:25:20 rillig Exp $ */
/* $NetBSD: var.c,v 1.939 2021/07/30 19:55:22 sjg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -140,7 +140,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: var.c,v 1.938 2021/06/21 18:25:20 rillig Exp $");
MAKE_RCSID("$NetBSD: var.c,v 1.939 2021/07/30 19:55:22 sjg Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@ -3272,6 +3272,56 @@ bad_modifier:
return AMR_BAD;
}
#ifndef NUM_TYPE
# define NUM_TYPE long long
#endif
static NUM_TYPE
num_val(const char *s)
{
NUM_TYPE val;
char *ep;
val = strtoll(s, &ep, 0);
if (ep != s) {
switch (*ep) {
case 'K':
case 'k':
val <<= 10;
break;
case 'M':
case 'm':
val <<= 20;
break;
case 'G':
case 'g':
val <<= 30;
break;
}
}
return val;
}
static int
num_cmp_asc(const void *sa, const void *sb)
{
NUM_TYPE a, b;
a = num_val(*(const char *const *)sa);
b = num_val(*(const char *const *)sb);
return (a > b) ? 1 : (b > a) ? -1 : 0;
}
static int
num_cmp_desc(const void *sa, const void *sb)
{
NUM_TYPE a, b;
a = num_val(*(const char *const *)sa);
b = num_val(*(const char *const *)sb);
return (a > b) ? -1 : (b > a) ? 1 : 0;
}
static int
str_cmp_asc(const void *a, const void *b)
{
@ -3297,22 +3347,35 @@ ShuffleStrings(char **strs, size_t n)
}
}
/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */
/* :O (order ascending) or :Or (order descending) or :Ox (shuffle) or
* :On (numeric ascending) or :Onr or :Orn (numeric descending)
*/
static ApplyModifierResult
ApplyModifier_Order(const char **pp, ModChain *ch)
{
const char *mod = (*pp)++; /* skip past the 'O' in any case */
Words words;
enum SortMode {
ASC, DESC, SHUFFLE
ASC, DESC, NUM_ASC, NUM_DESC, SHUFFLE
} mode;
if (IsDelimiter(mod[1], ch)) {
mode = ASC;
} else if (mod[1] == 'n') {
mode = NUM_ASC;
(*pp)++;
if (!IsDelimiter(mod[2], ch)) {
(*pp)++;
if (mod[2] == 'r')
mode = NUM_DESC;
}
} else if ((mod[1] == 'r' || mod[1] == 'x') &&
IsDelimiter(mod[2], ch)) {
(*pp)++;
mode = mod[1] == 'r' ? DESC : SHUFFLE;
} else if (mod[1] == 'r' && mod[2] == 'n') {
(*pp) += 2;
mode = NUM_DESC;
} else
return AMR_BAD;
@ -3322,6 +3385,9 @@ ApplyModifier_Order(const char **pp, ModChain *ch)
words = Str_Words(ch->expr->value.str, false);
if (mode == SHUFFLE)
ShuffleStrings(words.words, words.len);
else if (mode == NUM_ASC || mode == NUM_DESC)
qsort(words.words, words.len, sizeof words.words[0],
mode == NUM_ASC ? num_cmp_asc : num_cmp_desc);
else
qsort(words.words, words.len, sizeof words.words[0],
mode == ASC ? str_cmp_asc : str_cmp_desc);