From: Mark Wooding Date: Wed, 18 Mar 2015 19:04:47 +0000 (+0000) Subject: progs/rspit.c: Handle large requested output. X-Git-Tag: 2.2.0~7^2~8 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/bafe8a7b569c884c23e1e21219b49cb1a7fb2480 progs/rspit.c: Handle large requested output. We could work with `off_t' throughout, but in fact we might be asked for a /very/ large stream, and it turns out that there's a rather convenient multiprecision integer library just waiting to be used. --- diff --git a/progs/rspit.c b/progs/rspit.c index 2793fb41..1fb33a9d 100644 --- a/progs/rspit.c +++ b/progs/rspit.c @@ -49,6 +49,11 @@ #include #include +#include "mp.h" +#include "mpint.h" +#include "mplimits.h" +#include "mptext.h" + #include "fipstest.h" #include "grand.h" #include "maurer.h" @@ -200,7 +205,7 @@ static const struct { /*----- Miscellaneous static data -----------------------------------------*/ static FILE *outfp; -static size_t outsz = 0; +static mp *outsz = 0; static unsigned maurer_lo = 5, maurer_hi = 8; static int argc; @@ -380,13 +385,13 @@ static int opt(void) break; case 'z': { char *p; - outsz = strtoul(optarg, &p, 0); - if (!outsz) + outsz = mp_readstring(outsz, optarg, &p, 0); + if (!outsz || MP_NEGP(outsz)) die(EXIT_FAILURE, "bad number `%s'", optarg); switch (*p) { - case 'G': case 'g': outsz *= 1024; - case 'M': case 'm': outsz *= 1024; - case 'K': case 'k': outsz *= 1024; + case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10); + case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10); + case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10); case 0: break; default: @@ -1119,14 +1124,15 @@ static int genmaurer(const void *buf, size_t sz, void *p) return (0); } -static int generate(grand *r, size_t outsz, +static int generate(grand *r, mp *outsz, int (*func)(const void *buf, size_t sz, void *p), void *p) { static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 }; unsigned percent = 0; - size_t kb = 0; + mp *kb = MP_ZERO, *t = MP_NEW; + dstr d = DSTR_INIT; time_t last; static char baton[] = "-\\|/"; char *bp; @@ -1151,16 +1157,20 @@ static int generate(grand *r, size_t outsz, signal(SIGPIPE, SIG_IGN); #endif - do { + while (!outsz || MP_CMP(kb, <, outsz)) { octet buf[BUFSIZ]; - size_t sz = sizeof(buf); + size_t sz = sizeof(buf), left; clock_t c_start, c_stop; /* --- Emit a bufferful (or less) of data --- */ if (outsz) { - if (sz > outsz - kb) - sz = outsz - kb; + t = mp_sub(t, outsz, kb); + assert(!MP_NEGP(t)); + if (MP_CMP(t, <=, MP_SIZET_MAX)) { + left = mp_tosizet(t); + if (sz > left) sz = left; + } } c_start = clock(); r->ops->fill(r, buf, sz); @@ -1168,26 +1178,32 @@ static int generate(grand *r, size_t outsz, clk += c_stop - c_start; if (func && (rc = func(buf, sz, p)) != 0) return (rc); - kb += sz; + t = mp_fromsizet(t, sz); + kb = mp_add(kb, kb, t); /* --- Update the display --- */ if (flags & f_progress) { - time_t t = time(0); + time_t now = time(0); unsigned up = 0; if (percent > 100) up = 1; if (!outsz) { - if (difftime(t, last) > 1.0) { + if (difftime(now, last) > 1.0) { up = 1; } if (up) fputs(" ] ", stderr); } else { - unsigned pc = kb * 100.0 / outsz; - if (pc > percent || percent > 100 || difftime(t, last) > 1.0) { + unsigned pc; + t = mp_fromulong(t, 100); + t = mp_mul(t, t, kb); + mp_div(&t, 0, t, outsz); + assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX)); + pc = mp_touint(t); + if (pc > percent || percent > 100 || difftime(now, last) > 1.0) { if (percent > 100) percent = 0; percent &= ~1; @@ -1202,19 +1218,21 @@ static int generate(grand *r, size_t outsz, } if (up) { - size_t q = kb; char *kk = kmg; - while (q > 8192 && kk[1]) { - q >>= 10; + t = mp_add(t, kb, MP_ZERO); + while (mp_bits(t) >= 14) { + t = mp_lsr(t, t, 10); kk++; } - fprintf(stderr, "%4i%c\r[", (int)q, *kk); + DRESET(&d); + mp_writedstr(t, &d, 10); + fprintf(stderr, "%4s%c\r[", d.buf, *kk); if (outsz) { unsigned pc; for (pc = 0; pc < (percent & ~1); pc += 2) putc('.', stderr); } - last = t; + last = now; } if (percent > 100) @@ -1228,26 +1246,44 @@ static int generate(grand *r, size_t outsz, } fflush(stderr); } - - /* --- Terminate the loop --- */ - - } while (!outsz || kb < outsz); + } if (flags & f_progress) fputc('\n', stderr); if (flags & f_timer) { - fprintf(stderr, "generated %lu bytes ", (unsigned long)outsz); + DRESET(&d); + dstr_puts(&d, "generated "); + mp_writedstr(kb, &d, 10); + dstr_puts(&d, " bytes "); if (!clk) - fputs("too quickly to measure\n", stderr); + dstr_puts(&d, "too quickly to measure\n"); else { char *kk; + double out; double sec = (double)clk/CLOCKS_PER_SEC; - double bps = (outsz << 3)/sec; + unsigned long sh; + double bps; + + MP_SHRINK(kb); + switch (MP_LEN(kb)) { + case 0: out = 0; break; + case 1: out = kb->v[0]; break; + default: + sh = mp_bits(kb) - MPW_BITS; + t = mp_lsr(t, kb, sh); + out = ldexp(t->v[0], sh); + break; + } + bps = (8*out)/sec; for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024) ; - fprintf(stderr, "in %g secs (%g %cb/s)\n", sec, bps, *kk); + dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk); + fwrite(d.buf, 1, d.len, stderr); } } + + mp_drop(t); + DDESTROY(&d); return (0); } @@ -1313,9 +1349,12 @@ int main(int ac, char *av[]) if (flags & f_fips) { octet buf[FIPSTEST_BUFSZ]; unsigned rc; + mp *t; octet *p = buf; - generate(r, sizeof(buf), genbuf, &p); + t = mp_fromsizet(MP_NEW, sizeof(buf)); + generate(r, t, genbuf, &p); + mp_drop(t); rc = fipstest(buf); if (rc & FIPSTEST_MONOBIT) moan("failed monobit test"); @@ -1336,6 +1375,7 @@ int main(int ac, char *av[]) size_t bufsz; unsigned i; unsigned rc = 0; + mp *t; genmaurer_ctx g; static struct { double x; const char *sig; } sigtab[] = { @@ -1352,7 +1392,9 @@ int main(int ac, char *av[]) maurer_init(&g.m[i], i + maurer_lo); bufsz = (100 * maurer_hi) << maurer_hi; - generate(r, bufsz, genmaurer, &g); + t = mp_fromsizet(MP_NEW, bufsz); + generate(r, t, genmaurer, &g); + mp_drop(t); for (i = maurer_lo; i <= maurer_hi; i++) { double z = maurer_done(&g.m[i - maurer_lo]);