about summary refs log tree commit diff
path: root/Src/Modules/mathfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/mathfunc.c')
-rw-r--r--Src/Modules/mathfunc.c106
1 files changed, 106 insertions, 0 deletions
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)
 {