summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)