+ } while (!outsz || kb < outsz);
+
+ if (flags & f_progress)
+ fputc('\n', stderr);
+ if (flags & f_timer) {
+ double sec = (double)clk/CLOCKS_PER_SEC;
+ double bps = (outsz << 3)/sec;
+ char *kk;
+
+ for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
+ ;
+ fprintf(stderr, "generated %lu bytes in %g secs (%g %cb/s)\n",
+ (unsigned long)outsz, sec, bps, *kk);
+ }
+ return (0);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+int main(int ac, char *av[])
+{
+ gen *g = &optsg;
+ grand *r;
+
+ /* --- Initialize mLib --- */
+
+ ego(av[0]);
+ sub_init();
+
+ /* --- Set up the main Catacomb generator --- */
+
+ rand_noisesrc(RAND_GLOBAL, &noise_source);
+ rand_seed(RAND_GLOBAL, 160);
+
+ /* --- Initialize the options table --- */
+
+ addopts(sopts, opts);
+ argc = ac;
+ argv = av;
+ outfp = stdout;
+
+ /* --- Read the generator out of the first argument --- */
+
+ if (argc > 1 && *argv[1] != '-') {
+ const char *arg = av[1];
+ size_t sz = strlen(arg);
+ gen *gg;
+
+ g = 0;
+ for (gg = generators; gg->name; gg++) {
+ if (strncmp(arg, gg->name, sz) == 0) {
+ if (gg->name[sz] == 0) {
+ g = gg;
+ break;
+ } else if (g)
+ die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
+ else
+ g = gg;
+ }
+ }
+ if (!g)
+ die(EXIT_FAILURE, "unknown generator name `%s'", arg);
+ argc--;
+ argv++;
+ }
+
+ /* --- 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);