commit 926e1c04eee17d60a49e5903d3273232fbd30fb0 from: Alexander Arkhipov date: Fri Dec 30 16:53:53 2022 UTC improve the algorithm commit - 88da105c5d8bf235538925538a0a36723b9daf48 commit + 926e1c04eee17d60a49e5903d3273232fbd30fb0 blob - aeeb3c2404fa31ee8abb2aefae8f1b5cb84ba3d6 blob + 78ac0b578eecc06acd9c2976066f2824afcba822 --- gpass.c +++ gpass.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,15 +11,15 @@ #include -#define MAXWORDS 128 -#define RANDLINE randombytes_uniform(nlines)+1 +#define MAXWORDS 32768 #ifndef PREFIX # define PREFIX "/usr/local" #endif FILE *dicfp; +uint32_t nwords = 0; +int offs[MAXWORDS]; int plen = 70; -uint32_t nlines = 0; void errx(int eval, const char *fmt, ...) @@ -61,37 +62,32 @@ usage(void) void gen(void) { - char c; - int left = plen; - uint32_t cur = 1, sought = RANDLINE; + int c; + int left; + uint32_t n; - rewind(dicfp); - - for (;;) { - while (getc(dicfp) != '\n') - ; - if (++cur != sought) - continue; - while ((c = getc(dicfp)) != '\n') + for (left = plen; left; left--) { + n = randombytes_uniform(nwords) + 1; + if (fseek(dicfp, offs[n], SEEK_SET) == -1) + err(1, "fseek"); + while ((c = getc(dicfp)) != EOF && !isspace(c)) putchar(c); - if (!--left) - break; - putchar(' '); - if ((sought = RANDLINE) <= cur) { - rewind(dicfp); - cur = 0; - } + if (left > 1) + putchar(' '); } - putchar('\n'); } int main(int argc, char *argv[]) { - int c, npass = 1; - char *dicname = NULL; + int c, isword, npass, temp; + char *dicname; + isword = 0; + npass = 1; + dicname = NULL; + #ifdef __OpenBSD__ if (pledge("stdio unveil rpath", NULL) == -1) /* first call */ err(1, "pledge"); @@ -125,14 +121,22 @@ main(int argc, char *argv[]) if (pledge("stdio rpath", NULL) == -1) /* revoke unveil */ err(1, "pledge"); #endif + if (!(dicfp = fopen(dicname, "r"))) err(1, "could not open %s", dicname); - while ((c = getc(dicfp)) != EOF && nlines < UINT32_MAX) - nlines += (c == '\n'); - if (nlines < 2) - errx(1, "%s has less that 2 lines", dicname); - int log2nlines = log2(nlines); - plen = plen / log2nlines + !!(plen % log2nlines); + offs[0] = ftell(dicfp); + while ((c = getc(dicfp)) != EOF && nwords < MAXWORDS) + if (isspace(c)) { + nwords += isword ? 1 : 0; + isword = 0; + offs[nwords] = ftell(dicfp); + } else + isword = 1; + if (nwords < 2) + errx(1, "%s has less that 2 words", dicname); + + temp = log2(nwords); + plen = plen / temp + !!(plen % temp); plen += !plen; for (int i = 0; i < npass; i++)