Subject: Re: make(1) variables: sort and disorder [patch]
To: Simon J. Gerraty <sjg@crufty.net>
From: Mike M. Volokhov <mishka@apk.od.ua>
List: tech-userlevel
Date: 05/31/2005 18:14:11
On Mon, 30 May 2005 12:39:05 -0700 (PDT)
sjg@crufty.net (Simon J. Gerraty) wrote:
> >To change this behaviour, I've modified make(1) program to provide a
> >new variable modifier (:X) which is designed to disorder all words in
> >variable, opposite to :O. For example:
>
> This is a very interesting idea - the patch is a bit hard to read due to
> the transport encoding. One suggestion up front though.
>
> Rathere than add a new option :X, turn allow :O to take an optional 2nd
> flag - eg.
> :O ordered
> :Or reversed
> :Ox random
>
> or something like that.
Done. Please take a look to the patch (below) and thanks for the advice.
--
Mishka.
Index: make.1
===================================================================
RCS file: /usr/home/mishka/NetBSD-CVS/src/usr.bin/make/make.1,v
retrieving revision 1.107
diff -u -r1.107 make.1
--- make.1 8 May 2005 00:38:47 -0000 1.107
+++ make.1 31 May 2005 15:10:59 -0000
@@ -664,6 +664,17 @@
.Ar pattern .
.It Cm \&:O
Order every word in variable alphabetically.
+.It Cm \&:Or
+Reverse words in variable from head to tail.
+.It Cm \&:Ox
+Randomize words in variable. The results will be different each
+time you are referring to the modified variable; use the assignment
+with expansion
+.Pq Ql Cm \&:=
+to prevent such behaviour. If randomization will be done on unsorted
+source sequence, it may produce an alphabetically ordered result;
+to avoid this explicitly sort the source, and then randomize it as
+.Ql Cm \&:O:Ox .
.It Cm \&:Q
Quotes every shell meta-character in the variable, so that it can be passed
safely through recursive invocations of
Index: var.c
===================================================================
RCS file: /usr/home/mishka/NetBSD-CVS/src/usr.bin/make/var.c,v
retrieving revision 1.92
diff -u -r1.92 var.c
--- var.c 16 Feb 2005 15:11:53 -0000 1.92
+++ var.c 31 May 2005 15:10:59 -0000
@@ -130,6 +130,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
+#include <sys/time.h>
#include "make.h"
#include "buf.h"
@@ -286,8 +287,9 @@
const char *,
Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer, ClientData),
ClientData);
-static char *VarSort(const char *);
+static char *VarOrder(const char *, const char);
static char *VarUniq(const char *);
+static int VarNumbCompare(const void *, const void *);
static int VarWordCompare(const void *, const void *);
static void VarPrintVar(ClientData);
@@ -1540,13 +1542,24 @@
return r;
}
+static int
+VarNumbCompare(const void *a, const void *b)
+{
+ if (*(int *)a > *(int *)b)
+ return 1;
+ else if (*(int *)a < *(int *)b)
+ return -1;
+ return 0;
+}
+
/*-
*-----------------------------------------------------------------------
- * VarSort --
- * Sort the words in the string.
+ * VarOrder --
+ * Order the words in the string.
*
* Input:
* str String whose words should be sorted
+ * otype How to order: (s)ort, (r)everse, intermi(x)
*
* Results:
* A string containing the words sorted
@@ -1557,7 +1570,7 @@
*-----------------------------------------------------------------------
*/
static char *
-VarSort(const char *str)
+VarOrder(const char *str, const char otype)
{
Buffer buf; /* Buffer for the new string */
char **av; /* word list [first word does not count] */
@@ -1569,7 +1582,48 @@
av = brk_string(str, &ac, FALSE, &as);
if (ac > 0)
- qsort(av, ac, sizeof(char *), VarWordCompare);
+ switch (otype) {
+ case 's': /* sort alphabetically */
+ qsort(av, ac, sizeof(char *), VarWordCompare);
+ break;
+ case 'r': /* reverse */
+ {
+ char *t;
+ int ac1, ac2;
+
+ ac1 = ac - 1;
+ ac2 = ac / 2 - 1;
+ for (i = 0; i <= ac2; i++) {
+ t = av[i];
+ av[i] = av[ac1-i];
+ av[ac1-i] = t;
+ }
+ break;
+ }
+ case 'x': /* randomize */
+ {
+ struct ai {
+ int rnd; /* this must be placed first; see VarNumbCompare */
+ char *avi;
+ } *ai = NULL;
+ struct timeval rightnow;
+
+ /* intermixed variable should return different values each time */
+ gettimeofday(&rightnow, NULL);
+ srandom(rightnow.tv_sec + rightnow.tv_usec);
+
+ ai = emalloc(ac * sizeof(struct ai));
+ for (i = 0; i < ac; i++) {
+ ai[i].rnd = random();
+ ai[i].avi = av[i];
+ }
+ /* sorting ai by the first field will disorder the second */
+ qsort(ai, ac, sizeof(struct ai), VarNumbCompare);
+ for (i = 0; i < ac; i++)
+ av[i] = ai[i].avi;
+ free(ai);
+ }
+ } /* end of switch */
for (i = 0; i < ac; i++) {
Buf_AddBytes(buf, strlen(av[i]), (Byte *) av[i]);
@@ -2149,7 +2203,9 @@
* each word
* :R Substitute the root of each word
* (pathname minus the suffix).
- * :O ("Order") Sort words in variable.
+ * :O ("Order") Alphabeticaly sort words in variable.
+ * :Or ("Reverse") Reverse words backwards.
+ * :Ox ("intermiX") Randomize words in variable.
* :u ("uniq") Remove adjacent duplicate words.
* :tu Converts the variable contents to uppercase.
* :tl Converts the variable contents to lowercase.
@@ -3007,13 +3063,23 @@
}
/*FALLTHRU*/
case 'O':
+ {
+ char otype;
+
if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarSort(nstr);
+ otype = 's';
cp = tstr + 1;
- termc = *cp;
- break;
+ } else if ( (tstr[1] == 'r' || tstr[1] == 'x') &&
+ (tstr[2] == endc || tstr[2] == ':') ) {
+ otype = tstr[1];
+ cp = tstr + 2;
+ } else {
+ goto bad_modifier;
}
- /*FALLTHRU*/
+ termc = *cp;
+ newStr = VarOrder(nstr, otype);
+ break;
+ } /*FALLTHRU*/
case 'u':
if (tstr[1] == endc || tstr[1] == ':') {
newStr = VarUniq(nstr);