catcrypt.c, catsign.c: Shorten chunk sizes.
[u/mdw/catacomb] / hashsum.c
index 85fc6f4..d0ac31e 100644 (file)
--- a/hashsum.c
+++ b/hashsum.c
@@ -7,7 +7,7 @@
  * (c) 2000 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Catacomb.
  *
  * it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * Catacomb is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with Catacomb; if not, write to the Free
  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <assert.h>
 #include "ghash.h"
 #include "cc.h"
 
+#ifndef PATHSEP
+#  if defined(__riscos)
+#    define PATHSEP '.'
+#  elif defined(__unix) || defined(unix)
+#    define PATHSEP '/'
+#  else
+#    define PATHSEP '\\'
+#  endif
+#endif
+
 /*----- Static variables --------------------------------------------------*/
 
 #define f_binary 1u
@@ -64,6 +76,7 @@
 #define f_oddhash 64u
 #define f_escape 128u
 #define f_oddenc 256u
+#define f_progress 512u
 
 /*----- Encoding and decoding ---------------------------------------------*/
 
@@ -94,7 +107,7 @@ static size_t gethex(const char *p, octet *q, size_t sz, char **pp)
   }
   if (pp)
     *pp = (char *)p;
-  return (i); 
+  return (i);
 }
 
 /* --- Base64 encoding --- */
@@ -203,24 +216,109 @@ static const encodeops *getencoding(const char *ename)
  * 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[BUFSIZ];
+  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)
+  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);
@@ -691,10 +789,11 @@ int main(int argc, char *argv[])
       { "check",       0,              0,      'c' },
       { "binary",      0,              0,      'b' },
       { "verbose",     0,              0,      'v' },
+      { "progress",    0,              0,      'p' },
 
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "hVu a:E:l f0 ecbv", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "hVu a:E:l f0 ecbvp", opts, 0, 0, 0);
     if (i < 0)
       break;
 
@@ -738,6 +837,9 @@ int main(int argc, char *argv[])
       case 'v':
        f |= f_verbose;
        break;
+      case 'p':
+       f |= f_progress;
+       break;
       default:
        f |= f_bogus;
        break;
@@ -753,6 +855,11 @@ int main(int argc, char *argv[])
 
   /* --- Generate output --- */
 
+  if (!(f & f_check) && (argc || (f & f_files))) {
+    if (f & f_oddhash) printf("#hash %s\n", gch->name);
+    if (f & f_oddenc) printf("#encoding %s\n", e->name);
+    if (f & f_escape) fputs("#escape\n", stdout);
+  }
   if (!argc)
     rc = hashsum(0, f, gch, e);
   else {
@@ -760,11 +867,6 @@ int main(int argc, char *argv[])
     int rrc;
 
     rc = 0;
-    if (!(f & f_check)) {
-      if (f & f_oddhash) printf("#hash %s\n", gch->name);
-      if (f & f_oddenc) printf("#encoding %s\n", e->name);
-      if (f & f_escape) fputs("#escape\n", stdout);
-    }
     for (i = 0; i < argc; i++) {
       if ((rrc = hashsum(argv[i], f, gch, e)) != 0)
        rc = rrc;