summaryrefslogtreecommitdiff
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)
{