Catcrypt tools: Roll out progress indicator stuff from hashsum.
[u/mdw/catacomb] / catsign.c
index 8171404..3bbd7b2 100644 (file)
--- a/catsign.c
+++ b/catsign.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <ctype.h>
@@ -92,6 +94,7 @@ typedef struct sigmsg {
 #define F_BUFFER 256u
 #define F_UTC 512u
 #define F_NOCHECK 1024u
+#define F_PROGRESS 2048u
 
 /*----- Chunk I/O ---------------------------------------------------------*/
 
@@ -132,6 +135,7 @@ typedef struct msgcanon {
   unsigned f;
   FILE *fp;
   enc *e;
+  fprogress ff;
   size_t (*read)(struct msgcanon *, void *);
   void (*write)(struct msgcanon *, const void *, size_t);
   void (*close)(struct msgcanon *);
@@ -176,6 +180,7 @@ full:
   ungetc(ch, m->fp);
 done:
   m->f = f;
+  if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
   return (n);
 }
 
@@ -197,9 +202,18 @@ static void textwrite(msgcanon *m, const void *bp, size_t n)
 }
 
 static size_t binreadembed(msgcanon *m, void *bp)
-  { return (chunk_read(m->e, bp)); }
+{
+  size_t n = chunk_read(m->e, bp);
+  if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
+  return (n);
+}
+
 static size_t binreaddetach(msgcanon *m, void *bp)
-  { return (fread(bp, 1, MSGBUFSZ - 1, m->fp)); }
+{
+  size_t n = fread(bp, 1, MSGBUFSZ - 1, m->fp);
+  if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
+  return (n);
+}
 
 static void binwriteembed(msgcanon *m, const void *bp, size_t n)
   { chunk_write(m->e, bp, n); }
@@ -208,18 +222,25 @@ static void nullwrite(msgcanon *m, const void *bp, size_t n) { ; }
 
 static void mcsetup_readfile(msgcanon *m, unsigned f, const char *fn)
 {
-  m->f = F_DETACH | (f & F_BINARY);
+  m->f = F_DETACH | (f & (F_BINARY | F_PROGRESS));
   if (!fn || strcmp(fn, "-") == 0) {
     m->fp = stdin;
     m->f |= F_NOCLOSE;
   } else if ((m->fp = fopen(fn, (f & F_BINARY) ? "rb" : "r")) == 0)
     die(EXIT_FAILURE, "couldn't open file `%s': %s", fn, strerror(errno));
+  if (m->f & F_PROGRESS) {
+    if (fprogress_init(&m->ff, fn, m->fp)) {
+      die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+         strerror(errno));
+    }
+  }
   m->read = (f & F_BINARY) ? binreaddetach : textread;
 }
 
 static void mcsetup_writenull(msgcanon *m) { m->write = nullwrite; }
 
-static void mcsetup_read(msgcanon *m, unsigned f, enc **ee, const char *dfn)
+static void mcsetup_read(msgcanon *m, unsigned f, enc **ee,
+                        const char *fn, const char *dfn)
 {
   enc *e = *ee;
 
@@ -232,6 +253,12 @@ static void mcsetup_read(msgcanon *m, unsigned f, enc **ee, const char *dfn)
       *ee = 0;
       m->fp = e->fp;
       m->read = binreadembed;
+      if (m->f & F_PROGRESS) {
+       if (fprogress_init(&m->ff, fn, m->fp)) {
+         die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+             strerror(errno));
+       }
+      }
     } else {
       m->read = binreaddetach;
       if (!dfn || strcmp(dfn, "-") == 0)
@@ -240,6 +267,12 @@ static void mcsetup_read(msgcanon *m, unsigned f, enc **ee, const char *dfn)
        die(EXIT_FAILURE, "can't open `%s': %s", dfn, strerror(errno));
       else
        m->f &= ~F_NOCLOSE;
+      if (m->f & F_PROGRESS) {
+       if (fprogress_init(&m->ff, dfn, m->fp)) {
+         die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+             strerror(errno));
+       }
+      }
     }
   } else {
     m->read = textread;
@@ -249,12 +282,26 @@ static void mcsetup_read(msgcanon *m, unsigned f, enc **ee, const char *dfn)
       m->fp = e->fp;
       e->ops->destroy(e);
       *ee = 0;
-    } else if (!dfn || strcmp(dfn, "-") == 0)
-      m->fp = stdin;
-    else if ((m->fp = fopen(dfn, "r")) == 0)
-      die(EXIT_FAILURE, "can't read file `%s': %s", dfn, strerror(errno));
-    else
-      m->f &= ~F_NOCLOSE;
+      if (m->f & F_PROGRESS) {
+       if (fprogress_init(&m->ff, fn, m->fp)) {
+         die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+             strerror(errno));
+       }
+      }
+    } else {
+      if (!dfn || strcmp(dfn, "-") == 0)
+       m->fp = stdin;
+      else if ((m->fp = fopen(dfn, "r")) == 0)
+       die(EXIT_FAILURE, "can't read file `%s': %s", dfn, strerror(errno));
+      else
+       m->f &= ~F_NOCLOSE;
+      if (m->f & F_PROGRESS) {
+       if (fprogress_init(&m->ff, dfn, m->fp)) {
+         die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+             strerror(errno));
+       }
+      }
+    }
   }
 }
 
@@ -293,6 +340,7 @@ static void mc_endread(msgcanon *m, const encops *eops, enc **ee)
     if (ferror(m->fp) || fclose(m->fp))
       die(EXIT_FAILURE, "error closing message file: %s", strerror(errno));
   }
+  if (m->f & F_PROGRESS) fprogress_done(&m->ff);
 }
 
 static void mc_endwrite(msgcanon *m, const encops *eops, enc **ee)
@@ -453,11 +501,12 @@ static int sign(int argc, char *argv[])
       { "key",         OPTF_ARGREQ,    0,      'k' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { "text",                0,              0,      't' },
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "k:f:o:abdtC", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "k:f:o:abdptC", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'k': kn = optarg; break;
@@ -468,6 +517,7 @@ static int sign(int argc, char *argv[])
       case 'b': f |= F_BINARY; break;
       case 'd': f |= F_DETACH; break;
       case 'C': f |= F_NOCHECK; break;
+      case 'p': f |= F_PROGRESS; break;
       default: f |= F_BOGUS; break;
     }
   }
@@ -574,12 +624,13 @@ static void vrfchoke(const char *m, void *p)
 
 static int verify(int argc, char *argv[])
 {
-  const char *ef = "binary", *of = 0, *dfn = 0, *kn = 0, *err;
+  const char *ef = "binary", *of = 0, *fn, *dfn = 0, *kn = 0, *err;
   vrfctx v = { 0, 0, 1 };
   key_file kf;
   key *k, *kk = 0;
   sigmsg s;
   FILE *fp, *ofp = 0, *rfp = 0;
+  fprogress ff;
   struct tm *tm;
   int i;
   char bb[MSGBUFSZ];
@@ -598,6 +649,7 @@ static int verify(int argc, char *argv[])
       { "key",         OPTF_ARGREQ,    0,      'k' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { "quiet",       0,              0,      'q' },
       { "utc",         0,              0,      'u' },
       { "fresh-time",  0,              0,      't' },
@@ -606,7 +658,7 @@ static int verify(int argc, char *argv[])
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "k:f:o:abqt:uvC", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "k:f:o:abpqt:uvC", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'a': ef = "pem"; break;
@@ -623,6 +675,7 @@ static int verify(int argc, char *argv[])
        break;
       case 'q': if (v.verb > 0) v.verb--; break;
       case 'v': if (v.verb < 10) v.verb++; break;
+      case 'p': v.f |= F_PROGRESS; break;
       default: v.f |= F_BOGUS; break;
     }
   }
@@ -632,16 +685,13 @@ static int verify(int argc, char *argv[])
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
-  if (optind >= argc)
-    fp = stdin;
-  else if (strcmp(argv[optind], "-") == 0) {
+  fn = optind < argc ? argv[optind++] : "-";
+  if (strcmp(fn, "-") == 0)
     fp = stdin;
-    optind++;
-  } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+  else if ((fp = fopen(fn, eo->rmode)) == 0) {
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0))
     die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
@@ -692,7 +742,7 @@ static int verify(int argc, char *argv[])
     sig_readsig(e, &s);
   if (optind < argc)
     dfn = argv[optind++];
-  mcsetup_read(&mc_in, v.f, &e, dfn);
+  mcsetup_read(&mc_in, v.f, &e, fn, dfn);
 
   if (!of && (v.f & F_DETACH)) {
     rfp = ofp = 0;
@@ -756,13 +806,18 @@ static int verify(int argc, char *argv[])
          of, strerror(errno));
     }
     rewind(rfp);
+    if (v.f & F_PROGRESS) fprogress_init(&ff, "copying buffer", rfp);
     if (v.verb && ofp == stdout) printf("DATA\n");
     for (;;) {
       n = fread(bb, 1, sizeof(bb), rfp);
       if (!n) break;
-      if (fwrite(bb, 1, n, ofp) < n)
+      if (v.f & F_PROGRESS) fprogress_update(&ff, n);
+      if (fwrite(bb, 1, n, ofp) < n) {
+       if (v.f & F_PROGRESS) fprogress_done(&ff);
        die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+      }
     }
+    if (v.f & F_PROGRESS) fprogress_done(&ff);
     if (ferror(rfp) || fclose(rfp))
       die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno));
   }
@@ -787,7 +842,7 @@ static int verify(int argc, char *argv[])
 static int format(int argc, char *argv[])
 {
   const char *ief = "binary", *oef = "binary";
-  const char *dfn = 0, *of = 0, *mf = 0;
+  const char *fn, *dfn = 0, *of = 0, *mf = 0;
   sigmsg s;
   FILE *fp, *ofp = 0, *mfp = 0;
   int i;
@@ -811,9 +866,10 @@ static int format(int argc, char *argv[])
       { "format-out",  OPTF_ARGREQ,    0,      'F' },
       { "message",     OPTF_ARGREQ,    0,      'm' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "f:F:m:o:aADE", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "f:F:m:o:apADE", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'a': ief = "pem"; break;
@@ -824,6 +880,7 @@ static int format(int argc, char *argv[])
       case 'E': f &= ~F_DETACH; fm |= F_DETACH; break;
       case 'm': mf = optarg; break;
       case 'o': of = optarg; break;
+      case 'p': f |= F_PROGRESS; break;
       default: f |= F_BOGUS; break;
     }
   }
@@ -836,16 +893,13 @@ static int format(int argc, char *argv[])
   if ((oeo = getenc(oef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", oef);
 
-  if (optind >= argc)
-    fp = stdin;
-  else if (strcmp(argv[optind], "-") == 0) {
+  fn = optind < argc ? argv[optind++] : "-";
+  if (strcmp(fn, "-") == 0)
     fp = stdin;
-    optind++;
-  } else if ((fp = fopen(argv[optind], ieo->rmode)) == 0) {
+  else if ((fp = fopen(fn, ieo->rmode)) == 0) {
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (optind < argc)
     dfn = argv[optind++];
@@ -859,7 +913,7 @@ static int format(int argc, char *argv[])
   if (((s.f ^ v.f) & v.m) != 0)
     moan("boundary string inconsistent with contents (ignoring)");
 
-  mcsetup_read(&mc_in, s.f, &ie, dfn);
+  mcsetup_read(&mc_in, s.f, &ie, fn, dfn);
 
   /* --- Prepare the output stuff --- */
 
@@ -1058,7 +1112,7 @@ static cmd cmdtab[] = {
   CMD_ENCODE,
   CMD_DECODE,
   { "sign", sign,
-    "sign [-adtC] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\
+    "sign [-adptC] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\
 Options:\n\
 \n\
 -a, --armour           Same as `-f pem'.\n\
@@ -1067,11 +1121,12 @@ Options:\n\
 -f, --format=FORMAT    Encode as FORMAT.\n\
 -k, --key=TAG          Use public encryption key named by TAG.\n\
 -o, --output=FILE      Write output to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 -t, --text             Canonify input message as a text file.\n\
 -C, --nocheck          Don't check the private key.\n\
 " },
   { "verify", verify,
-    "verify [-abquvC] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\
+    "verify [-abpquvC] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\
 [FILE [MESSAGE]]", "\
 Options:\n\
 \n\
@@ -1080,6 +1135,7 @@ Options:\n\
 -f, --format=FORMAT    Decode as FORMAT.\n\
 -k, --key=TAG          Require that the message be signed by key TAG.\n\
 -o, --output=FILE      Write message to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 -q, --quiet            Produce fewer messages.\n\
 -t, --freshtime=TIME   Only accept signatures made after this time.\n\
 -u, --utc              Show dates in UTC rather than local time.\n\
@@ -1095,7 +1151,7 @@ Options:\n\
 -u, --utc              Show dates in UTC rather than local time.\n\
 "},
   { "format", format,
-    "format [-auADE] [-f FORMAT] [-F format] [-m FILE] [-o FILE]\n\t\
+    "format [-apuADE] [-f FORMAT] [-F format] [-m FILE] [-o FILE]\n\t\
 [FILE [MESSAGE]]", "\
 Options:\n\
 \n\
@@ -1107,6 +1163,7 @@ Options:\n\
 -F, --format-out=FORMAT        Encode output as FORMAT.\n\
 -m, --message=FILE     Write message to FILE.\n\
 -o, --output=FILE      Write new signature to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 "},
   { 0, 0, 0 }
 }; /* " Emacs seems confused. */