+ /* --- Get a generic random number generator --- */
+
+ r = g->seed(g->i);
+ if (!r || optind != ac - 1) {
+ usage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* --- Do the FIPS test --- */
+
+ if (flags & f_fips) {
+ octet buf[FIPSTEST_BUFSZ];
+ unsigned rc;
+ octet *p = buf;
+
+ generate(r, sizeof(buf), genbuf, &p);
+ rc = fipstest(buf);
+ if (rc & FIPSTEST_MONOBIT)
+ moan("failed monobit test");
+ if (rc & FIPSTEST_POKER)
+ moan("failed poker test");
+ if (rc & FIPSTEST_RUNS)
+ moan("failed runs test");
+ if (rc & FIPSTEST_LONGRUNS)
+ moan("failed long runs test");
+ if (!rc && (flags & f_progress))
+ fputs("test passed\n", stderr);
+ return (rc ? EXIT_FAILURE : 0);
+ }
+
+ /* --- Do Maurer's test --- */
+
+ if (flags & f_maurer) {
+ size_t bufsz;
+ unsigned i;
+ unsigned rc = 0;
+ genmaurer_ctx g;
+
+ static struct { double x; const char *sig; } sigtab[] = {
+ { 3.2905, "1e-3" },
+ { 3.0902, "2e-3" },
+ { 2.8070, "5e-3" },
+ { 2.5758, "1e-2" },
+ { 0 , 0 }
+ };
+
+ g.n = maurer_hi - maurer_lo + 1;
+ g.m = xmalloc(g.n * sizeof(maurer_ctx));
+ for (i = 0; i < g.n; i++)
+ maurer_init(&g.m[i], i + maurer_lo);
+ bufsz = (100 * maurer_hi) << maurer_hi;
+
+ generate(r, bufsz, genmaurer, &g);
+
+ for (i = maurer_lo; i <= maurer_hi; i++) {
+ double z = maurer_done(&g.m[i - maurer_lo]);
+ double zz = fabs(z);
+ unsigned j;
+
+ for (j = 0; sigtab[j].sig; j++) {
+ if (zz > sigtab[j].x) {
+ rc = EXIT_FAILURE;
+ moan("failed, bits = %u, sig = %s, Z_u = %g",
+ i, sigtab[j].sig, z);
+ break;
+ }
+ }
+ if (flags & f_progress)
+ fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
+ }
+
+ xfree(g.m);
+ return (rc);
+ }
+
+ /* --- Discard --- */
+
+ if (flags & f_discard) {
+ generate(r, outsz, 0, 0);
+ return (0);
+ }
+
+ /* --- Write to a file --- */
+
+#ifndef PORTABLE
+ if (!(flags & f_file) && isatty(STDOUT_FILENO))
+ die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
+#endif
+
+ generate(r, outsz, genfile, outfp);
+