2.52 xs_random.h
 1/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
 2
 3#ifndef _XS_RANDOM_H
 4
 5#define _XS_RANDOM_H
 6
 7unsigned int xs_rnd_int32_d(unsigned int *seed);
 8void *xs_rnd_buf(void *buf, int size);
 9
10#ifdef XS_IMPLEMENTATION
11
12#include <stdio.h>
13#include <sys/time.h>
14#include <unistd.h>
15#include <stdlib.h>
16
17unsigned int xs_rnd_int32_d(unsigned int *seed)
18/* returns a deterministic random integer. If seed is NULL, uses a static one */
19{
20    static unsigned int s = 0;
21
22    if (seed == NULL)
23        seed = &s;
24
25    if (*seed == 0) {
26        struct timeval tv;
27
28        gettimeofday(&tv, NULL);
29        *seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
30    }
31
32    /* Linear congruential generator by Numerical Recipes */
33    *seed = (*seed * 1664525) + 1013904223;
34
35    return *seed;
36}
37
38
39void *xs_rnd_buf(void *buf, int size)
40/* fills buf with random data */
41{
42#ifdef __OpenBSD__
43
44    /* available since OpenBSD 2.2 */
45    arc4random_buf(buf, size);
46
47#else
48
49    FILE *f;
50    int done = 0;
51
52    if ((f = fopen("/dev/urandom", "r")) != NULL) {
53        /* fill with great random data from the system */
54        if (fread(buf, size, 1, f) == 1)
55            done = 1;
56
57        fclose(f);
58    }
59
60    if (!done) {
61        /* fill the buffer with poor quality, deterministic data */
62        unsigned int s   = 0;
63        unsigned char *p = (unsigned char *)buf;
64        int n            = size / sizeof(s);
65
66        /* fill with full integers */
67        while (n--) {
68            xs_rnd_int32_d(&s);
69            p = memcpy(p, &s, sizeof(s)) + sizeof(s);
70        }
71
72        if ((n = size % sizeof(s))) {
73            /* fill the remaining */
74            xs_rnd_int32_d(&s);
75            memcpy(p, &s, n);
76        }
77    }
78
79#endif /* __OpenBSD__ */
80
81    return buf;
82}
83
84
85#endif /* XS_IMPLEMENTATION */
86
87#endif /* XS_RANDOM_H */