diff options
Diffstat (limited to 'xs_random.h')
-rw-r--r-- | xs_random.h | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/xs_random.h b/xs_random.h new file mode 100644 index 0000000..3566827 --- /dev/null +++ b/xs_random.h @@ -0,0 +1,87 @@ +/* copyright (c) 2022 - 2023 grunfink / MIT license */ + +#ifndef _XS_RANDOM_H + +#define _XS_RANDOM_H + +unsigned int xs_rnd_int32_d(unsigned int *seed); +void *xs_rnd_buf(void *buf, int size); + +#ifdef XS_IMPLEMENTATION + +#include <stdio.h> +#include <sys/time.h> +#include <unistd.h> +#include <stdlib.h> + +unsigned int xs_rnd_int32_d(unsigned int *seed) +/* returns a deterministic random integer. If seed is NULL, uses a static one */ +{ + static unsigned int s = 0; + + if (seed == NULL) + seed = &s; + + if (*seed == 0) { + struct timeval tv; + + gettimeofday(&tv, NULL); + *seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); + } + + /* Linear congruential generator by Numerical Recipes */ + *seed = (*seed * 1664525) + 1013904223; + + return *seed; +} + + +void *xs_rnd_buf(void *buf, int size) +/* fills buf with random data */ +{ +#ifdef __OpenBSD__ + + /* available since OpenBSD 2.2 */ + arc4random_buf(buf, size); + +#else + + FILE *f; + int done = 0; + + if ((f = fopen("/dev/urandom", "r")) != NULL) { + /* fill with great random data from the system */ + if (fread(buf, size, 1, f) == 1) + done = 1; + + fclose(f); + } + + if (!done) { + /* fill the buffer with poor quality, deterministic data */ + unsigned int s = 0; + unsigned char *p = (unsigned char *)buf; + int n = size / sizeof(s); + + /* fill with full integers */ + while (n--) { + xs_rnd_int32_d(&s); + p = memcpy(p, &s, sizeof(s)) + sizeof(s); + } + + if ((n = size % sizeof(s))) { + /* fill the remaining */ + xs_rnd_int32_d(&s); + memcpy(p, &s, n); + } + } + +#endif /* __OpenBSD__ */ + + return buf; +} + + +#endif /* XS_IMPLEMENTATION */ + +#endif /* XS_RANDOM_H */ |