about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2001-11-15 12:10:22 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2001-11-15 12:10:22 +0000
commitb0c56c0561011bdbfd525cda2ce380c1e8ee597e (patch)
tree69be6e31f89526b28edfa5067682463632901a24
parent096e24858f98288a002493a865a7a49ead8d169a (diff)
downloadzsh-b0c56c0561011bdbfd525cda2ce380c1e8ee597e.tar.gz
zsh-b0c56c0561011bdbfd525cda2ce380c1e8ee597e.tar.xz
zsh-b0c56c0561011bdbfd525cda2ce380c1e8ee597e.zip
16241: new rand48(param) math function
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/mod_mathfunc.yo33
-rw-r--r--Src/Modules/mathfunc.c106
-rw-r--r--zshconfig.ac3
4 files changed, 147 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index ea16180e4..141739d1d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2001-11-15  Peter Stephenson  <pws@csr.com>
+
+	* 16241: zshconfig.ac, Src/Modules/mathfunc.c,
+	Doc/Zsh/mod_mathfunc.yo: new rand48(param) math function calls
+	erand48(3), storing seed as hex string in $param.
+
 2001-11-14  Andrej Borsenkow  <bor@zsh.org>
 
 	* 16247: Completion/Mandrake/Command/_urpmi: completion
diff --git a/Doc/Zsh/mod_mathfunc.yo b/Doc/Zsh/mod_mathfunc.yo
index 05ce9fe45..637c22d8f 100644
--- a/Doc/Zsh/mod_mathfunc.yo
+++ b/Doc/Zsh/mod_mathfunc.yo
@@ -52,3 +52,36 @@ a floating point or integer value (by truncation) respectively.
 
 Note that the C tt(pow) function is available in ordinary math evaluation
 as the `tt(**)' operator and is not provided here.
+
+The function tt(rand48) is available if your system's mathematical library
+has the function tt(erand48(3)).  It returns a pseudo-random floating point
+number between 0 and 1.  It takes a single string optional argument.
+
+If the argument is not present, the random number seed is initialised by
+three calls to the tt(rand(3)) function --- this produces the same random
+numbers as the next three values of tt($RANDOM).
+
+If the argument is present, it gives the name of a scalar parameter where
+the current random number seed will be stored.  On the first call, the
+value must contain at least twelve hexadecimal digits (the remainder of the
+string is ignored), or the seed will be initialised in the same manner as
+for a call to tt(rand48) with no argument.  Subsequent calls to
+tt(rand48)LPAR()var(param)RPAR() will then maintain the seed in the
+parameter var(param) as a string of twelve hexadecimal digits, with no base
+signifier.  The random number sequences for different parameters are
+completely independent, and are also independent from that used by calls to
+tt(rand48) with no argument.
+
+For example, consider
+
+example(print $(( rand48(seed) ))
+print $(( rand48() ))
+print $(( rand48(seed) )))
+
+Assuming tt($seed) does not exist, it will be initialised by the first
+call.  In the second call, the default seed is initialised; note, however,
+that because of the properties of tt(rand()) there is a correlation between
+the seeds used for the two initialisations, so for more secure uses, you
+should generate your own 12-byte seed.  The third call returns to the same
+sequence of random numbers used in the first call, unaffected by the
+intervening tt(rand48()).
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index 5ba7b557a..af4366420 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -82,6 +82,12 @@ MF_Y1,
 MF_YN
 };
 
+/* also functions taking a string argument */
+
+enum {
+MS_RAND48
+};
+
 /*
  * also to do, but differently argument or returned: abs (no type
  * conversion), atan2.
@@ -119,6 +125,12 @@ enum {
 
 
 static struct mathfunc mftab[] = {
+  /* Functions taking string arguments */
+#ifdef HAVE_ERAND48
+  /* here to avoid comma hassle */
+  STRMATHFUNC("rand48", math_string, MS_RAND48),
+#endif
+
   NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) |
 	      TFLAG(TF_NOCONV|TF_NOASS)),
   NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)),
@@ -449,6 +461,100 @@ math_func(char *name, int argc, mnumber *argv, int id)
 }
 
 /**/
+static mnumber
+math_string(char *name, char *arg, int id)
+{
+    mnumber ret = zero_mnumber;
+    char *send;
+    /*
+     * Post-process the string argument, which is just passed verbatim.
+     * Not clear if any other functions that use math_string() will
+     * want this, but assume so for now.
+     */
+    while (iblank(*arg))
+	arg++;
+    send = arg + strlen(arg);
+    while (send > arg && iblank(send[-1]))
+	send--;
+    *send = '\0';
+
+    switch (id)
+    {
+#ifdef HAVE_ERAND48
+    case MS_RAND48:
+	{
+	    static unsigned short seedbuf[3];
+	    static int seedbuf_init;
+	    unsigned short tmp_seedbuf[3], *seedbufptr;
+	    int do_init = 1;
+
+	    if (*arg) {
+		/* Seed is contained in parameter named by arg */
+		char *seedstr;
+		seedbufptr = tmp_seedbuf;
+		if ((seedstr = getsparam(arg)) && strlen(seedstr) >= 12) {
+		    int i, j;
+		    do_init = 0;
+		    /*
+		     * Decode three sets of four hex digits corresponding
+		     * to each unsigned short.
+		     */
+		    for (i = 0; i < 3 && !do_init; i++) {
+			unsigned short *seedptr = seedbuf + i;
+			*seedptr = 0;
+			for (j = 0; j < 4; j++) {
+			    if (*seedstr >= '0' && *seedstr <= '9')
+				*seedptr += *seedstr - '0';
+			    else if (tolower(*seedstr) >= 'a' &&
+				     tolower(*seedstr) <= 'f')
+				*seedptr += tolower(*seedstr) - 'a' + 10;
+			    else {
+				do_init = 1;
+				break;
+			    }
+			    seedstr++;
+			    if (j < 3)
+				*seedptr *= 16;
+			}
+		    }
+		}
+		else if (errflag)
+		    break;
+	    }
+	    else
+	    {
+		/* Use default seed: must be initialised. */
+		seedbufptr = seedbuf;
+		if (!seedbuf_init)
+		    seedbuf_init = 1;
+		else
+		    do_init = 1;
+	    }
+	    if (do_init) {
+		seedbufptr[0] = (unsigned short)rand();
+		seedbufptr[1] = (unsigned short)rand();
+		seedbufptr[2] = (unsigned short)rand();
+	    }
+	    ret.type = MN_FLOAT;
+	    ret.u.d = erand48(seedbufptr);
+
+	    if (*arg)
+	    {
+		char outbuf[13];
+		sprintf(outbuf, "%04x%04x%04x", (int)seedbufptr[0],
+			(int)seedbufptr[1], (int)seedbufptr[2]);
+		setsparam(arg, ztrdup(outbuf));
+	    }
+	}
+	break;
+#endif
+    }
+
+    return ret;
+}
+
+
+/**/
 int
 setup_(Module m)
 {
diff --git a/zshconfig.ac b/zshconfig.ac
index c573359d9..4e1a0d882 100644
--- a/zshconfig.ac
+++ b/zshconfig.ac
@@ -938,7 +938,8 @@ AC_CHECK_FUNCS(strftime difftime gettimeofday \
 	       brk sbrk \
 	       pathconf sysconf \
 	       tgetent tigetflag tigetnum tigetstr setupterm \
-	       pcre_compile pcre_study pcre_exec)
+	       pcre_compile pcre_study pcre_exec \
+	       erand48)
 AC_FUNC_STRCOLL
 
 dnl  Check if tgetent accepts NULL (and will allocate its own termcap buffer)