-/*----- Support functions -------------------------------------------------*/
-
-/* --- @fhash@ --- *
- *
- * Arguments: @const char *file@ = file name to be hashed (null for stdin)
- * @unsigned f@ = flags to set
- * @const gchash *gch@ = pointer to hash function to use
- * @void *buf@ = pointer to hash output buffer
- *
- * Returns: Zero if it worked, nonzero on error.
- *
- * Use: Hashes a file.
- */
-
-struct unit {
- const char *name;
- int m;
-};
-
-static void prhuman_time(FILE *fp, unsigned long n)
-{
- const static struct unit utime[] = {
- { "s", 60 }, { "m", 60 }, { "h", 24 }, { "d", 0 }
- };
-
- unsigned long m = 0;
- const struct unit *u = utime;
-
- while (u[1].m && n > u[0].m*u[1].m) { n /= u->m; u++; }
- m = n / u[1].m; n %= u[0].m;
- if (m) fprintf(fp, "%3lu%s%02lu%s", m, u[1].name, n, u[0].name);
- else fprintf(fp, " %2lu%s", n, u[0].name);
-}
-
-static void prhuman_data(FILE *fp, off_t n)
-{
- const static struct unit udata[] = {
- { " ", 1024 }, { "k", 1024 }, { "M", 1024 }, { "G", 1024 },
- { "T", 1024 }, { "P", 1024 }, { "E", 1024 }, { "Z", 1024 },
- { "Y", 0 }
- };
-
- double x = n;
- const struct unit *u = udata;
-
- while (u->m && x >= u->m) { x /= u->m; u++; }
- fprintf(fp, "%6.1f%s", x, u->name);
-}
-
-static int fhash(const char *file, unsigned f, const gchash *gch, void *buf)
-{
- FILE *fp;
- char fbuf[1024 * 128];
- size_t sz;
- ghash *h;
- int e;
- off_t fsz = -1, fo;
- const char *p;
- dstr d = DSTR_INIT;
- static char baton[] = "-\\|/";
- char *bp = baton;
- time_t now, last, start;
- int i, pc;
-
- if (!file || strcmp(file, "-") == 0)
- fp = stdin;
- else if ((fp = fopen(file, f & f_binary ? "rb" : "r")) == 0)
- return (-1);
-
- if (f & f_progress) {
- if ((fo = ftello(fp)) >= 0 &&
- fseeko(fp, 0, SEEK_END) >= 0 &&
- (fsz = ftello(fp),
- fseeko(fp, fo, SEEK_SET) < 0))
- return (-1);
- if (fo != -1 && fsz != -1) fsz -= fo;
- fo = 0;
- sz = strlen(file);
- if (sz < 24)
- dstr_puts(&d, file);
- else if ((p = strchr(file + sz - 20, PATHSEP)) != 0) {
- dstr_puts(&d, "..."); dstr_puts(&d, p);
- } else {
- p = strrchr(file, PATHSEP);
- if (!p) dstr_putf(&d, "%.20s...", file);
- else dstr_putf(&d, "...%.17s...", p);
- }
- start = last = time(0);
- }
-
- h = GH_INIT(gch);
- while ((sz = fread(fbuf, 1, sizeof(fbuf), fp)) > 0) {
- GH_HASH(h, fbuf, sz);
- if (f & f_progress) {
- fo += sz;
- now = time(0);
- if (difftime(now, last) < 1) continue;
- last = now;
- fprintf(stderr, "\r%-24s", d.buf);
- fprintf(stderr, "%c ", *bp++); if (!*bp) bp = baton;
- prhuman_data(stderr, fo);
- if (fsz >= fo) {
- fputc('/', stderr);
- prhuman_data(stderr, fsz);
- fputs(" [", stderr);
- pc = (fo*16 + fsz/2)/fsz;
- for (i = 0; i < pc; i++) fputc('.', stderr);
- for (; i < 16; i++) fputc(' ', stderr);
- fprintf(stderr, "] %3d%%", (int)((fo*100 + 50)/fsz));
- fprintf(stderr, " ETA ");
- prhuman_time(stderr, difftime(now, start)*(fsz - fo)/fo);
- }
- }
- }
- GH_DONE(h, buf);
- GH_DESTROY(h);
- if (f & f_progress) fprintf(stderr, "\r%78s\r", "");
- e = ferror(fp);
- if (file)
- fclose(fp);
- return (e ? -1 : 0);
-}
-
-/* --- @gethash@ --- *
- *
- * Arguments: @const char *name@ = pointer to name string
- *
- * Returns: Pointer to appropriate hash class.
- *
- * Use: Chooses a hash function by name.
- */
-
-static const gchash *gethash(const char *name)
-{
- const gchash *const *g, *gg = 0;
- size_t sz = strlen(name);
- for (g = ghashtab; *g; g++) {
- if (strncmp(name, (*g)->name, sz) == 0) {
- if ((*g)->name[sz] == 0) {
- gg = *g;
- break;
- } else if (gg)
- return (0);
- else
- gg = *g;
- }
- }
- return (gg);
-}
-
-/* --- @getstring@ --- *
- *
- * Arguments: @FILE *fp@ = stream from which to read
- * @const char *p@ = string to read from instead
- * @dstr *d@ = destination string
- * @unsigned raw@ = raw or cooked read
- *
- * Returns: Zero if OK, nonzero on end-of-file.
- *
- * Use: Reads a filename (or something similar) from a stream.
- */
-
-static int getstring(FILE *fp, const char *p, dstr *d, unsigned raw)