/* See LICENSE file for copyright and license details. */ #ifdef __linux__ #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE #endif #endif #ifdef _WIN32 #ifndef _CRT_RAND_S #define _CRT_RAND_S #endif #endif #include #include #include #include #include #include #include #ifndef _WIN32 #include #include #endif #include "arg.h" #include "config.h" char *argv0; static unsigned char rbuf[256]; static size_t rpos = sizeof rbuf; static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if (fmt[0] && fmt[strlen(fmt)-1] == ':') { fputc(' ', stderr); perror(NULL); } else { fputc('\n', stderr); } exit(1); } static void usage(void) { fprintf(stderr, "usage: %s [-v] [-n n] [-l l]\n", argv0 ? argv0 : "rg"); exit(1); } static int fillrand(unsigned char *buf, size_t n) { #ifdef _WIN32 size_t i; unsigned int r; int k; for (i = 0; i < n; ) { if (rand_s(&r) != 0) return -1; for (k = 0; k < 4 && i < n; k++) buf[i++] = (unsigned char)(r >> (8 * k)); } return 0; #else size_t off; ssize_t r; off = 0; while (off < n) { r = getrandom(buf + off, n - off, 0); if (r < 0) { if (errno == EINTR) continue; return -1; } if (r == 0) return -1; off += (size_t)r; } return 0; #endif } static unsigned char randbyte(void) { if (rpos >= sizeof rbuf) { if (fillrand(rbuf, sizeof rbuf) < 0) die("rg: rng:"); rpos = 0; } return rbuf[rpos++]; } static uint32_t randu32(void) { return ((uint32_t)randbyte() << 24) | ((uint32_t)randbyte() << 16) | ((uint32_t)randbyte() << 8) | (uint32_t)randbyte(); } static uint32_t randbelow(uint32_t n) { uint32_t x, min; if (n <= 1) return 0; /* reject [0, 2^32 % n) so x % n is unbiased */ min = (uint32_t)(-n) % n; do { x = randu32(); } while (x < min); return x % n; } static int eint(const char *s) { char *end; long v; if (s == NULL || s[0] == '\0') usage(); errno = 0; v = strtol(s, &end, 10); if (errno || end == s || *end != '\0' || v < INT_MIN || v > INT_MAX) die("rg: invalid number '%s'", s); return (int)v; } int main(int argc, char *argv[]) { int i, j, n, l, alen; n = defn; l = defl; ARGBEGIN { case 'n': n = eint(EARGF(usage())); break; case 'l': l = eint(EARGF(usage())); break; case 'v': puts("rg-" VERSION); return 0; default: usage(); } ARGEND if (argc) usage(); if (n < minn || n > maxn) die("rg: n must be %d..%d", minn, maxn); if (l < minl || l > maxl) die("rg: l must be %d..%d", minl, maxl); alen = (int)strlen(alphabet); if (alen < 1) die("rg: empty alphabet"); for (i = 0; i < n; i++) { for (j = 0; j < l; j++) putchar(alphabet[randbelow((uint32_t)alen)]); putchar('\n'); } return 0; }