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: 06/01/2005 17:38:56
--Signature=_Wed__1_Jun_2005_17_38_56_+0300_HXerwiyz59k62nM1
Content-Type: text/plain; charset=US-ASCII
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Tue, 31 May 2005 16:40:53 -0700
"Simon J. Gerraty" <sjg@crufty.net> wrote:
> Looks good.
>=20
> Can you add test cases in say unit-tests/order
> (you'll need to add order to SUBFILES in unit-tests/Makefile)
OK.
After some valuable input from Simon J. Gerraty, Greg Troxel, and Alan
Barret I would like to publish my new patch (see below). Major changes
are:
- Randomization (:Ox) has been completely rewritten and now it
requires much less memory and is O(n).
- Fixed bug when parsing ':O<unknown>' option.
- The ':Or' option was removed as duplicate of ':[-1..1]'; the
alphabetical reverse ordering can be done with ':O:[-1..1]'.
- Generally improve man page (cleanup, add example).
- Created a regression test - unit-tests/modorder (I haven't change
test.exp because my output of make is too differ to it. Is it
normally?)
Any comments, please?
--
Mishka.
Index: main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /usr/home/mishka/NetBSD-CVS/src/usr.bin/make/main.c,v
retrieving revision 1.106
diff -u -r1.106 main.c
--- main.c 16 Feb 2005 15:11:52 -0000 1.106
+++ main.c 1 Jun 2005 14:30:57 -0000
@@ -628,6 +628,14 @@
/* avoid faults on read-only strings */
static char defsyspath[] =3D _PATH_DEFSYSPATH;
char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */
+ struct timeval rightnow; /* to initialize random seed */
+
+ /*
+ * Set the seed to produce a different random sequences
+ * on each program execution.
+ */
+ gettimeofday(&rightnow, NULL);
+ srandom(rightnow.tv_sec + rightnow.tv_usec);
=09
if ((progname =3D strrchr(argv[0], '/')) !=3D NULL)
progname++;
Index: make.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
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 1 Jun 2005 14:30:57 -0000
@@ -663,7 +663,35 @@
but selects all words which do not match
.Ar pattern .
.It Cm \&:O
-Order every word in variable alphabetically.
+Order every word in variable alphabetically. To sort words in
+reverse order use
+.Ql Cm \&:O:[-1..1]
+combination of modifiers.
+.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 \&:=3D
+to prevent such behaviour. For example,
+.Bd -literal -offset indent
+LIST=3D uno due tre quattro
+RANDOM_LIST=3D ${LIST:Ox}
+STATIC_RANDOM_LIST:=3D ${LIST:Ox}
+
+all:
+ @echo "${RANDOM_LIST}"
+ @echo "${RANDOM_LIST}"
+ @echo "${STATIC_RANDOM_LIST}"
+ @echo "${STATIC_RANDOM_LIST}"
+
+.Ed
+may produce the output similar to:
+.Bd -literal -offset indent
+quattro due tre uno
+tre due quattro uno
+due uno quattro tre
+due uno quattro tre
+.Ed
.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
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
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 1 Jun 2005 14:30:58 -0000
@@ -286,7 +286,7 @@
const char *,
Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer, Clien=
tData),
ClientData);
-static char *VarSort(const char *);
+static char *VarOrder(const char *, const char);
static char *VarUniq(const char *);
static int VarWordCompare(const void *, const void *);
static void VarPrintVar(ClientData);
@@ -1542,14 +1542,15 @@
=20
/*-
*-----------------------------------------------------------------------
- * VarSort --
- * Sort the words in the string.
+ * VarOrder --
+ * Order the words in the string.
*
* Input:
- * str String whose words should be sorted
+ * str String whose words should be sorted.
+ * otype How to order: s - sort, x - random.
*
* Results:
- * A string containing the words sorted
+ * A string containing the words ordered.
*
* Side Effects:
* None.
@@ -1557,7 +1558,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 +1570,31 @@
av =3D brk_string(str, &ac, FALSE, &as);
=20
if (ac > 0)
- qsort(av, ac, sizeof(char *), VarWordCompare);
+ switch (otype) {
+ case 's': /* sort alphabetically */
+ qsort(av, ac, sizeof(char *), VarWordCompare);
+ break;
+ case 'x': /* randomize */
+ {
+ int rndidx;
+ char *t;
+
+ /*
+ * We will use [ac..2] range for mod factors. This will produce
+ * random numbers in [(ac-1)..0] interval, and minimal
+ * reasonable value for mod factor is 2 (the mod 1 will produce
+ * 0 with probability 1).
+ */
+ for (i =3D ac-1; i > 0; i--) {
+ rndidx =3D random() % (i + 1);
+ if (i !=3D rndidx) {
+ t =3D av[i];
+ av[i] =3D av[rndidx];
+ av[rndidx] =3D t;
+ }
+ }
+ }
+ } /* end of switch */
=20
for (i =3D 0; i < ac; i++) {
Buf_AddBytes(buf, strlen(av[i]), (Byte *) av[i]);
@@ -2149,7 +2174,8 @@
* 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.
+ * :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 +3033,24 @@
}
/*FALLTHRU*/
case 'O':
+ {
+ char otype;
+
+ cp =3D tstr + 1; /* skip to the rest in any case */
if (tstr[1] =3D=3D endc || tstr[1] =3D=3D ':') {
- newStr =3D VarSort(nstr);
- cp =3D tstr + 1;
+ otype =3D 's';
termc =3D *cp;
- break;
+ } else if ( (tstr[1] =3D=3D 'x') &&
+ (tstr[2] =3D=3D endc || tstr[2] =3D=3D ':') ) {
+ otype =3D tstr[1];
+ cp =3D tstr + 2;
+ termc =3D *cp;
+ } else {
+ goto bad_modifier;
}
- /*FALLTHRU*/
+ newStr =3D VarOrder(nstr, otype);
+ break;
+ } /*FALLTHRU*/
case 'u':
if (tstr[1] =3D=3D endc || tstr[1] =3D=3D ':') {
newStr =3D VarUniq(nstr);
Index: unit-tests/Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /usr/home/mishka/NetBSD-CVS/src/usr.bin/make/unit-tests/Makefile,v
retrieving revision 1.14
diff -u -r1.14 Makefile
--- unit-tests/Makefile 30 Jun 2004 03:26:26 -0000 1.14
+++ unit-tests/Makefile 1 Jun 2005 14:30:58 -0000
@@ -21,6 +21,7 @@
SUBFILES=3D \
cond1 \
modmatch \
+ modorder \
modts \
modword \
posix \
Index: unit-tests/modorder
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: unit-tests/modorder
diff -N unit-tests/modorder
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ unit-tests/modorder 1 Jun 2005 14:30:58 -0000
@@ -0,0 +1,19 @@
+# $NetBSD$
+
+LIST=3D one two three four five six seven eigth nine ten
+LISTX=3D ${LIST:Ox}
+LISTSX:=3D ${LIST:Ox}
+
+all:
+ @echo "LIST =3D ${LIST}"
+ @echo "LIST:O =3D ${LIST:O}"
+ @echo "LIST:Ox =3D ${LIST:Ox}"
+ @echo "LIST:O:Ox =3D ${LIST:O:Ox}"
+ @echo "LISTX 1 =3D ${LISTX}"
+ @echo "LISTX 2 =3D ${LISTX}"
+ @echo "LISTX 3 =3D ${LISTX}"
+ @echo "LISTSX 1 =3D ${LISTSX}"
+ @echo "LISTSX 2 =3D ${LISTSX}"
+ @echo "LISTSX 3 =3D ${LISTSX}"
+ @echo "BADMOD 1 =3D ${LIST:OX}"
+ @echo "BADMOD 2 =3D ${LIST:OxXX}"
--Signature=_Wed__1_Jun_2005_17_38_56_+0300_HXerwiyz59k62nM1
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (NetBSD)
iD8DBQFCnciCHwrNSUJZSkURAiiZAKCqovHk0J8gRCXQ/kPcWcytjgjquwCdHqmM
h1c7zydZ/WrEsEe4PMR2nU4=
=2gVC
-----END PGP SIGNATURE-----
--Signature=_Wed__1_Jun_2005_17_38_56_+0300_HXerwiyz59k62nM1--