Catcrypt tools: Roll out progress indicator stuff from hashsum.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 22 Jan 2012 13:12:14 +0000 (13:12 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 22 Jan 2012 13:12:14 +0000 (13:12 +0000)
Factor out the progress indication from hashsum, and introduce it into
the other tools.

18 files changed:
Makefile.m4
catcrypt.1
catcrypt.c
catsign.1
catsign.c
cc-enc.c
cc-kem.c
cc-list.c
cc-progress.c [new file with mode: 0644]
cc-sig.c
cc-subcmd.c
cc.h
cookie.c
dsig.1
dsig.c
hashsum.c
keyutil.c
perftest.c

index 6312e98..1ef5632 100644 (file)
@@ -287,7 +287,7 @@ noinst_PROGRAMS = \
 LDADD = libcatcrypt.a libcatacomb.la
 
 define(`LIBCAT_SRC', `cc.h getdate.h dnl
 LDADD = libcatcrypt.a libcatacomb.la
 
 define(`LIBCAT_SRC', `cc.h getdate.h dnl
-       cc-sig.c cc-subcmd.c cc-enc.c cc-kem.c cc-list.c')
+       cc-sig.c cc-subcmd.c cc-enc.c cc-kem.c cc-list.c cc-progress.c')
 libcatcrypt_a_SOURCES = LIBCAT_SRC getdate.y
 
 patsubst(MP_BASE MP_SOURCES, `\.c\>', `.lo') dsig.o keyutil.o rspit.o \
 libcatcrypt_a_SOURCES = LIBCAT_SRC getdate.y
 
 patsubst(MP_BASE MP_SOURCES, `\.c\>', `.lo') dsig.o keyutil.o rspit.o \
index 72bfe12..6bace86 100644 (file)
@@ -44,7 +44,7 @@ is one of:
 .RI [ item ...]
 .br
 .B encrypt
 .RI [ item ...]
 .br
 .B encrypt
-.RB [ \-aC ]
+.RB [ \-apC ]
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
@@ -54,7 +54,7 @@ is one of:
 .RI [ file ]
 .br
 .B decrypt
 .RI [ file ]
 .br
 .B decrypt
-.RB [ \-aqvC ]
+.RB [ \-apqvC ]
 .RB [ \-f
 .IR format ]
 .RB [ \-o
 .RB [ \-f
 .IR format ]
 .RB [ \-o
@@ -62,6 +62,7 @@ is one of:
 .RI [ file ]
 .br
 .B encode
 .RI [ file ]
 .br
 .B encode
+.RB [ \-p ]
 .RB [ \-f
 .IR format ]
 .RB [ \-b
 .RB [ \-f
 .IR format ]
 .RB [ \-b
@@ -71,6 +72,7 @@ is one of:
 .RI [ file ]
 .br
 .B decode
 .RI [ file ]
 .br
 .B decode
+.RB [ \-p ]
 .RB [ \-f
 .IR format ]
 .RB [ \-b
 .RB [ \-f
 .IR format ]
 .RB [ \-b
@@ -486,6 +488,9 @@ Use the key-encapsulation key named
 in the current keyring; the default key is
 .BR ccrypt .
 .TP
 in the current keyring; the default key is
 .BR ccrypt .
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-s, \-\-sign-key " tag
 Use the signature key named
 .I tag
 .BI "\-s, \-\-sign-key " tag
 Use the signature key named
 .I tag
@@ -523,6 +528,9 @@ on if output is to stdout, but is always available as an option.
 Read input encoded according to
 .IR format .
 .TP
 Read input encoded according to
 .IR format .
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .B "\-v, \-\-verbose"
 Produce more verbose messages.  See below for the messages produced
 during decryption.  The default verbosity level is 1.  (Currently this
 .B "\-v, \-\-verbose"
 Produce more verbose messages.  See below for the messages produced
 during decryption.  The default verbosity level is 1.  (Currently this
@@ -593,6 +601,9 @@ The input is read from the
 given on the command line, or from standard input if none is specified.
 Options provided are:
 .TP
 given on the command line, or from standard input if none is specified.
 Options provided are:
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-f, \-\-format " format
 Produce output in
 .IR format .
 .BI "\-f, \-\-format " format
 Produce output in
 .IR format .
@@ -647,6 +658,9 @@ lines.  Without this option,
 will start reading at the first plausible boundary string, and continue
 processing until it reaches the matching end boundary.
 .TP
 will start reading at the first plausible boundary string, and continue
 processing until it reaches the matching end boundary.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-o, \-\-output " file
 Write output to
 .I file
 .BI "\-o, \-\-output " file
 Write output to
 .I file
index d10739d..08fb7e0 100644 (file)
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include "config.h"
 
 #include <errno.h>
@@ -126,10 +128,11 @@ err:
 
 static int encrypt(int argc, char *argv[])
 {
 
 static int encrypt(int argc, char *argv[])
 {
-  const char *of = 0, *kn = "ccrypt", *skn = 0;
+  const char *fn, *of = 0, *kn = "ccrypt", *skn = 0;
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
+  fprogress ff;
   const char *err;
   int i;
   int en;
   const char *err;
   int i;
   int en;
@@ -153,6 +156,7 @@ static int encrypt(int argc, char *argv[])
 
 #define f_bogus 1u
 #define f_nocheck 2u
 
 #define f_bogus 1u
 #define f_nocheck 2u
+#define f_progress 4u
 
   for (;;) {
     static const struct option opt[] = {
 
   for (;;) {
     static const struct option opt[] = {
@@ -162,10 +166,11 @@ static int encrypt(int argc, char *argv[])
       { "armor",       0,              0,      'a' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
       { "armor",       0,              0,      'a' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "k:s:af:o:C", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "k:s:af:o:pC", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'k': kn = optarg; break;
     if (i < 0) break;
     switch (i) {
       case 'k': kn = optarg; break;
@@ -173,6 +178,7 @@ static int encrypt(int argc, char *argv[])
       case 'a': ef = "pem"; break;
       case 'f': ef = optarg; break;
       case 'o': of = optarg; break;
       case 'a': ef = "pem"; break;
       case 'f': ef = optarg; break;
       case 'o': of = optarg; break;
+      case 'p': f |= f_progress; break;
       case 'C': f |= f_nocheck; break;
       default: f |= f_bogus; break;
     }
       case 'C': f |= f_nocheck; break;
       default: f |= f_bogus; break;
     }
@@ -190,16 +196,13 @@ static int encrypt(int argc, char *argv[])
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
   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;
     fp = stdin;
-    optind++;
-  } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+  else if ((fp = fopen(fn, "rb")) == 0) {
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
@@ -258,6 +261,13 @@ static int encrypt(int argc, char *argv[])
 
   /* --- Now do the main crypto --- */
 
 
   /* --- Now do the main crypto --- */
 
+  if (f & f_progress) {
+    if (fprogress_init(&ff, fn, fp)) {
+      die(EXIT_FAILURE, "failed to initialize progress display: %s",
+         strerror(errno));
+    }
+  }
+
   assert(GC_CLASS(c)->blksz <= sizeof(bb));
   dstr_ensure(&d, sizeof(bb) + GM_CLASS(m)->hashsz);
   seq = 0;
   assert(GC_CLASS(c)->blksz <= sizeof(bb));
   dstr_ensure(&d, sizeof(bb) + GM_CLASS(m)->hashsz);
   seq = 0;
@@ -272,6 +282,7 @@ static int encrypt(int argc, char *argv[])
     }
     n = fread(bb, 1, chsz, fp);
     if (!n) break;
     }
     n = fread(bb, 1, chsz, fp);
     if (!n) break;
+    if (f & f_progress) fprogress_update(&ff, n);
     buf_init(&b, d.buf, d.sz);
     tag = buf_get(&b, GM_CLASS(m)->hashsz);
     ct = buf_get(&b, n);
     buf_init(&b, d.buf, d.sz);
     tag = buf_get(&b, GM_CLASS(m)->hashsz);
     ct = buf_get(&b, n);
@@ -294,6 +305,7 @@ static int encrypt(int argc, char *argv[])
 
   /* --- All done --- */
 
 
   /* --- All done --- */
 
+  if (f & f_progress) fprogress_done(&ff);
   e->ops->encdone(e);
   GM_DESTROY(m);
   GC_DESTROY(c);
   e->ops->encdone(e);
   GM_DESTROY(m);
   GC_DESTROY(c);
@@ -309,16 +321,18 @@ static int encrypt(int argc, char *argv[])
 
 #undef f_bogus
 #undef f_nocheck
 
 #undef f_bogus
 #undef f_nocheck
+#undef f_progress
 }
 
 /*---- Decryption ---------------------------------------------------------*/
 
 static int decrypt(int argc, char *argv[])
 {
 }
 
 /*---- Decryption ---------------------------------------------------------*/
 
 static int decrypt(int argc, char *argv[])
 {
-  const char *of = 0;
+  const char *fn, *of = 0;
   FILE *ofp = 0, *rfp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   FILE *ofp = 0, *rfp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
+  fprogress ff;
   int i;
   size_t n;
   dstr d = DSTR_INIT;
   int i;
   size_t n;
   dstr d = DSTR_INIT;
@@ -344,6 +358,7 @@ static int decrypt(int argc, char *argv[])
 #define f_bogus 1u
 #define f_buffer 2u
 #define f_nocheck 4u
 #define f_bogus 1u
 #define f_buffer 2u
 #define f_nocheck 4u
+#define f_progress 8u
 
   for (;;) {
     static const struct option opt[] = {
 
   for (;;) {
     static const struct option opt[] = {
@@ -355,9 +370,10 @@ static int decrypt(int argc, char *argv[])
       { "nocheck",     0,              0,      'C' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
       { "nocheck",     0,              0,      'C' },
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { 0,             0,              0,      0 }
     };
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "abf:o:qvC", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "abf:o:pqvC", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'a': ef = "pem"; break;
     if (i < 0) break;
     switch (i) {
       case 'a': ef = "pem"; break;
@@ -367,6 +383,7 @@ static int decrypt(int argc, char *argv[])
       case 'C': f |= f_nocheck; break;
       case 'f': ef = optarg; break;
       case 'o': of = optarg; break;
       case 'C': f |= f_nocheck; break;
       case 'f': ef = optarg; break;
       case 'o': of = optarg; break;
+      case 'p': f |= f_progress; break;
       default: f |= f_bogus; break;
     }
   }
       default: f |= f_bogus; break;
     }
   }
@@ -376,44 +393,55 @@ static int decrypt(int argc, char *argv[])
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
   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;
     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",
     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);
 
   e = initdec(eo, fp, checkbdry, "CATCRYPT ENCRYPTED MESSAGE");
 
 
   if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0))
     die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
 
   e = initdec(eo, fp, checkbdry, "CATCRYPT ENCRYPTED MESSAGE");
 
+  if (f & f_progress) {
+    if (fprogress_init(&ff, fn, fp)) {
+      die(EXIT_FAILURE, "failed to initialize progress display: %s",
+         strerror(errno));
+    }
+  }
+
   /* --- Read the header chunk --- */
 
   chunk_read(e, &d, &b);
   /* --- Read the header chunk --- */
 
   chunk_read(e, &d, &b);
+  if (f & f_progress)
+    fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
   if (buf_getu32(&b, &id)) {
   if (buf_getu32(&b, &id)) {
+    if (f & f_progress) fprogress_done(&ff);
     if (verb) printf("FAIL malformed header: missing keyid\n");
     exit(EXIT_FAILURE);
   }
   if ((k = key_byid(&kf, id)) == 0) {
     if (verb) printf("FAIL malformed header: missing keyid\n");
     exit(EXIT_FAILURE);
   }
   if ((k = key_byid(&kf, id)) == 0) {
+    if (f & f_progress) fprogress_done(&ff);
     if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
     exit(EXIT_FAILURE);
   }
   if (BLEFT(&b)) {
     if (buf_getu32(&b, &id)) {
     if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
     exit(EXIT_FAILURE);
   }
   if (BLEFT(&b)) {
     if (buf_getu32(&b, &id)) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb) printf("FAIL malformed header: missing signature keyid\n");
       exit(EXIT_FAILURE);
     }
     if ((sk = key_byid(&kf, id)) == 0) {
       if (verb) printf("FAIL malformed header: missing signature keyid\n");
       exit(EXIT_FAILURE);
     }
     if ((sk = key_byid(&kf, id)) == 0) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
       exit(EXIT_FAILURE);
     }
   }
   if (BLEFT(&b)) {
       if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
       exit(EXIT_FAILURE);
     }
   }
   if (BLEFT(&b)) {
+    if (f & f_progress) fprogress_done(&ff);
     if (verb) printf("FAIL malformed header: junk at end\n");
     exit(EXIT_FAILURE);
   }
     if (verb) printf("FAIL malformed header: junk at end\n");
     exit(EXIT_FAILURE);
   }
@@ -434,7 +462,10 @@ static int decrypt(int argc, char *argv[])
   /* --- Read the KEM chunk --- */
 
   chunk_read(e, &d, &b);
   /* --- Read the KEM chunk --- */
 
   chunk_read(e, &d, &b);
+  if (f & f_progress)
+    fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
   if (setupkem(km, &d, &cx, &c, &m)) {
   if (setupkem(km, &d, &cx, &c, &m)) {
+    if (f & f_progress) fprogress_done(&ff);
     if (verb) printf("FAIL failed to decapsulate key\n");
     exit(EXIT_FAILURE);
   }
     if (verb) printf("FAIL failed to decapsulate key\n");
     exit(EXIT_FAILURE);
   }
@@ -448,18 +479,24 @@ static int decrypt(int argc, char *argv[])
     GC_ENCRYPT(cx, 0, d.buf, 1024);
     GH_HASH(s->h, d.buf, 1024);
     chunk_read(e, &d, &b);
     GC_ENCRYPT(cx, 0, d.buf, 1024);
     GH_HASH(s->h, d.buf, 1024);
     chunk_read(e, &d, &b);
+    if (f & f_progress)
+      fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
     if (s->ops->doit(s, &d)) {
     if (s->ops->doit(s, &d)) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb) printf("FAIL signature verification failed\n");
       exit(EXIT_FAILURE);
     }
     if (verb) {
       dstr_reset(&d);
       key_fulltag(sk, &d);
       if (verb) printf("FAIL signature verification failed\n");
       exit(EXIT_FAILURE);
     }
     if (verb) {
       dstr_reset(&d);
       key_fulltag(sk, &d);
+      if (f & f_progress) fprogress_clear(&ff);
       printf("INFO good-signature %s\n", d.buf);
     }
     freesig(s);
       printf("INFO good-signature %s\n", d.buf);
     }
     freesig(s);
-  } else if (verb)
+  } else if (verb) {
+    if (f & f_progress) fprogress_clear(&ff);
     printf("INFO no-signature\n");
     printf("INFO no-signature\n");
+  }
 
   /* --- Now decrypt the main body --- */
 
 
   /* --- Now decrypt the main body --- */
 
@@ -469,12 +506,15 @@ static int decrypt(int argc, char *argv[])
   }
   if (!(f & f_buffer)) {
     if ((ofp = fopen(of, "wb")) == 0) {
   }
   if (!(f & f_buffer)) {
     if ((ofp = fopen(of, "wb")) == 0) {
+      if (f & f_progress) fprogress_done(&ff);
       die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
          ofp, strerror(errno));
     }
     rfp = ofp;
       die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
          ofp, strerror(errno));
     }
     rfp = ofp;
-  } else if ((rfp = tmpfile()) == 0)
+  } else if ((rfp = tmpfile()) == 0) {
+    if (f & f_progress) fprogress_done(&ff);
     die(EXIT_FAILURE, "couldn't create temporary file: %s", strerror(errno));
     die(EXIT_FAILURE, "couldn't create temporary file: %s", strerror(errno));
+  }
 
   seq = 0;
   dstr_ensure(&d, GC_CLASS(c)->blksz);
 
   seq = 0;
   dstr_ensure(&d, GC_CLASS(c)->blksz);
@@ -488,12 +528,16 @@ static int decrypt(int argc, char *argv[])
     GH_HASHU32(h, seq);
     seq++;
     chunk_read(e, &d, &b);
     GH_HASHU32(h, seq);
     seq++;
     chunk_read(e, &d, &b);
+    if (f & f_progress)
+      fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
     if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0) {
     if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb) printf("FAIL bad ciphertext chunk: no tag\n");
       exit(EXIT_FAILURE);
     }
     GH_HASH(h, BCUR(&b), BLEFT(&b));
     if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0) {
       if (verb) printf("FAIL bad ciphertext chunk: no tag\n");
       exit(EXIT_FAILURE);
     }
     GH_HASH(h, BCUR(&b), BLEFT(&b));
     if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb)
        printf("FAIL bad ciphertext chunk: authentication failure\n");
       exit(EXIT_FAILURE);
       if (verb)
        printf("FAIL bad ciphertext chunk: authentication failure\n");
       exit(EXIT_FAILURE);
@@ -503,11 +547,13 @@ static int decrypt(int argc, char *argv[])
       break;
     GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
     if (fwrite(BCUR(&b), 1, BLEFT(&b), rfp) != BLEFT(&b)) {
       break;
     GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
     if (fwrite(BCUR(&b), 1, BLEFT(&b), rfp) != BLEFT(&b)) {
+      if (f & f_progress) fprogress_done(&ff);
       if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
       exit(EXIT_FAILURE);
     }
   }
 
       if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
       exit(EXIT_FAILURE);
     }
   }
 
+  if (f & f_progress) fprogress_done(&ff);
   if (fflush(rfp) || ferror(rfp)) {
     if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
     exit(EXIT_FAILURE);
   if (fflush(rfp) || ferror(rfp)) {
     if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
     exit(EXIT_FAILURE);
@@ -518,15 +564,20 @@ static int decrypt(int argc, char *argv[])
          of, strerror(errno));
     }
     rewind(rfp);
          of, strerror(errno));
     }
     rewind(rfp);
+    if (f & f_progress) fprogress_init(&ff, "copying buffer", rfp);
     dstr_reset(&d);
     dstr_ensure(&d, 65536);
     if (verb && ofp == stdout) printf("DATA\n");
     for (;;) {
       n = fread(d.buf, 1, d.sz, rfp);
       if (!n) break;
     dstr_reset(&d);
     dstr_ensure(&d, 65536);
     if (verb && ofp == stdout) printf("DATA\n");
     for (;;) {
       n = fread(d.buf, 1, d.sz, rfp);
       if (!n) break;
-      if (fwrite(d.buf, 1, n, ofp) < n)
+      if (f & f_progress) fprogress_update(&ff, n);
+      if (fwrite(d.buf, 1, n, ofp) < n) {
+       if (f & f_progress) fprogress_done(&ff);
        die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
        die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+      }
     }
     }
+    if (f & f_progress) fprogress_done(&ff);
     if (ferror(rfp) || fclose(rfp))
       die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno));
   }
     if (ferror(rfp) || fclose(rfp))
       die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno));
   }
@@ -549,6 +600,7 @@ static int decrypt(int argc, char *argv[])
 #undef f_bogus
 #undef f_buffer
 #undef f_nocheck
 #undef f_bogus
 #undef f_buffer
 #undef f_nocheck
+#undef f_progress
 }
 
 /*----- Main code ---------------------------------------------------------*/
 }
 
 /*----- Main code ---------------------------------------------------------*/
@@ -584,7 +636,7 @@ static cmd cmdtab[] = {
   CMD_ENCODE,
   CMD_DECODE,
   { "encrypt", encrypt,
   CMD_ENCODE,
   CMD_DECODE,
   { "encrypt", encrypt,
-    "encrypt [-aC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\
+    "encrypt [-apC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\
 [-o OUTPUT] [FILE]", "\
 Options:\n\
 \n\
 [-o OUTPUT] [FILE]", "\
 Options:\n\
 \n\
@@ -593,20 +645,22 @@ Options:\n\
 -k, --key=TAG          Use public encryption key named by TAG.\n\
 -s, --sign-key=TAG     Use private signature key named by TAG.\n\
 -o, --output=FILE      Write output to FILE.\n\
 -k, --key=TAG          Use public encryption key named by TAG.\n\
 -s, --sign-key=TAG     Use private signature key named by TAG.\n\
 -o, --output=FILE      Write output to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 -C, --nocheck          Don't check the public key.\n\
 " },
   { "decrypt", decrypt,
 -C, --nocheck          Don't check the public key.\n\
 " },
   { "decrypt", decrypt,
-    "decrypt [-abqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\
+    "decrypt [-abpqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\
 Options:\n\
 \n\
 -a, --armour           Same as `-f pem'.\n\
 -b, --buffer           Buffer output until we're sure we have it all.\n\
 -f, --format=FORMAT    Decode as FORMAT.\n\
 -o, --output=FILE      Write output to FILE.\n\
 Options:\n\
 \n\
 -a, --armour           Same as `-f pem'.\n\
 -b, --buffer           Buffer output until we're sure we have it all.\n\
 -f, --format=FORMAT    Decode as FORMAT.\n\
 -o, --output=FILE      Write output to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 -q, --quiet            Produce fewer messages.\n\
 -v, --verbose          Produce more verbose messages.\n\
 -C, --nocheck          Don't check the private key.\n\
 -q, --quiet            Produce fewer messages.\n\
 -v, --verbose          Produce more verbose messages.\n\
 -C, --nocheck          Don't check the private key.\n\
-" }, /* ' emacs is confused */
+" },
   { 0, 0, 0 }
 };
 
   { 0, 0, 0 }
 };
 
index 93fe70d..190c631 100644 (file)
--- a/catsign.1
+++ b/catsign.1
@@ -44,7 +44,7 @@ is one of:
 .RI [ item ...]
 .br
 .B sign
 .RI [ item ...]
 .br
 .B sign
-.RB [ \-adtC ]
+.RB [ \-adptC ]
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
@@ -54,7 +54,7 @@ is one of:
 .RI [ file ]
 .br
 .B verify
 .RI [ file ]
 .br
 .B verify
-.RB [ \-aquvC ]
+.RB [ \-apquvC ]
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
 .RB [ \-k
 .IR tag ]
 .RB [ \-f
@@ -75,7 +75,7 @@ is one of:
 .RI [ file ]
 .br
 .B format
 .RI [ file ]
 .br
 .B format
-.RB [ \-auABDET ]
+.RB [ \-apuABDET ]
 .RB [ \-f
 .IR format ]
 .RB [ \-F
 .RB [ \-f
 .IR format ]
 .RB [ \-F
@@ -90,6 +90,7 @@ is one of:
 .RI [ message ]]
 .br
 .B encode
 .RI [ message ]]
 .br
 .B encode
+.RB [ \-p ]
 .RB [ \-f
 .IR format ]
 .RB [ \-b
 .RB [ \-f
 .IR format ]
 .RB [ \-b
@@ -99,6 +100,7 @@ is one of:
 .RI [ file ]
 .br
 .B decode
 .RI [ file ]
 .br
 .B decode
+.RB [ \-p ]
 .RB [ \-f
 .IR format ]
 .RB [ \-b
 .RB [ \-f
 .IR format ]
 .RB [ \-b
@@ -416,6 +418,9 @@ Write output to
 .I file
 rather than to standard output.
 .TP
 .I file
 rather than to standard output.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .B "\-t, \-\-text"
 Read and sign the input as text.  This is the default.
 .TP
 .B "\-t, \-\-text"
 Read and sign the input as text.  This is the default.
 .TP
@@ -459,6 +464,9 @@ Produce more verbose messages.  See below for the messages produced
 during decryption.  The default verbosity level is 1.  (Currently this
 is the most verbose setting.  This might not be the case always.)
 .TP
 during decryption.  The default verbosity level is 1.  (Currently this
 is the most verbose setting.  This might not be the case always.)
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .B "\-q, \-\-quiet"
 Produce fewer messages.
 .TP
 .B "\-q, \-\-quiet"
 Produce fewer messages.
 .TP
@@ -564,6 +572,9 @@ is also accepted.
 Read input encoded according to
 .IR format .
 .TP
 Read input encoded according to
 .IR format .
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .B "\-u, \-\-utc"
 Show the datestamp in the signature in UTC rather than (your) local
 time.  The synonym
 .B "\-u, \-\-utc"
 Show the datestamp in the signature in UTC rather than (your) local
 time.  The synonym
@@ -641,6 +652,9 @@ The variant spelling
 .B "\-\-armor"
 is also accepted.
 .TP
 .B "\-\-armor"
 is also accepted.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-A, \-\-armour-out"
 Produce ASCII-armoured output.  This is equivalent to specifying
 .BR "\-F pem" .
 .BI "\-A, \-\-armour-out"
 Produce ASCII-armoured output.  This is equivalent to specifying
 .BR "\-F pem" .
@@ -712,6 +726,9 @@ at the bottom.  The default
 is
 .BR MESSAGE .
 .TP
 is
 .BR MESSAGE .
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-o, \-\-output " file
 Write output to
 .I file
 .BI "\-o, \-\-output " file
 Write output to
 .I file
@@ -747,6 +764,9 @@ lines.  Without this option,
 will start reading at the first plausible boundary string, and continue
 processing until it reaches the matching end boundary.
 .TP
 will start reading at the first plausible boundary string, and continue
 processing until it reaches the matching end boundary.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-o, \-\-output " file
 Write output to
 .I file
 .BI "\-o, \-\-output " file
 Write output to
 .I file
index 8171404..3bbd7b2 100644 (file)
--- a/catsign.c
+++ b/catsign.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <ctype.h>
 #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_BUFFER 256u
 #define F_UTC 512u
 #define F_NOCHECK 1024u
+#define F_PROGRESS 2048u
 
 /*----- Chunk I/O ---------------------------------------------------------*/
 
 
 /*----- Chunk I/O ---------------------------------------------------------*/
 
@@ -132,6 +135,7 @@ typedef struct msgcanon {
   unsigned f;
   FILE *fp;
   enc *e;
   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 *);
   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;
   ungetc(ch, m->fp);
 done:
   m->f = f;
+  if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
   return (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)
 }
 
 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)
 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); }
 
 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)
 {
 
 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 (!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; }
 
   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;
 
 {
   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;
       *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)
     } 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;
        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;
     }
   } 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;
       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 (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)
 }
 
 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' },
       { "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 }
     };
       { "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;
     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 '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;
     }
   }
       default: f |= F_BOGUS; break;
     }
   }
@@ -574,12 +624,13 @@ static void vrfchoke(const char *m, void *p)
 
 static int verify(int argc, char *argv[])
 {
 
 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;
   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];
   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' },
       { "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' },
       { "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 }
     };
       { "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;
     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;
        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;
     }
   }
       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 ((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;
     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",
     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);
 
   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++];
     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;
 
   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);
          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 (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));
        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));
   }
     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";
 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;
   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' },
       { "format-out",  OPTF_ARGREQ,    0,      'F' },
       { "message",     OPTF_ARGREQ,    0,      'm' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { 0,             0,              0,      0 }
     };
       { 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;
     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 '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;
     }
   }
       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 ((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;
     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",
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (optind < argc)
     dfn = argv[optind++];
 
   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)");
 
   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 --- */
 
 
   /* --- Prepare the output stuff --- */
 
@@ -1058,7 +1112,7 @@ static cmd cmdtab[] = {
   CMD_ENCODE,
   CMD_DECODE,
   { "sign", sign,
   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\
 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\
 -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,
 -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\
 [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\
 -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\
 -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,
 -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\
 [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\
 -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. */
 "},
   { 0, 0, 0 }
 }; /* " Emacs seems confused. */
index c7354e6..2b8b0fd 100644 (file)
--- a/cc-enc.c
+++ b/cc-enc.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <errno.h>
 #include <stdio.h>
 
 #include <errno.h>
 #include <stdio.h>
 
@@ -268,12 +270,12 @@ static void pem_destroy(enc *e)
 /* --- Encoder table --- */
 
 const encops enctab[] = {
 /* --- Encoder table --- */
 
 const encops enctab[] = {
-  { "binary", "rb", "wb",
+  { "binary", "rb", "wb", 1, 1,
     bin_encinit, bin_decinit,
     bin_read, bin_write,
     bin_done, bin_done,
     bin_destroy },
     bin_encinit, bin_decinit,
     bin_read, bin_write,
     bin_done, bin_done,
     bin_destroy },
-  { "pem", "r", "w",
+  { "pem", "r", "w", 3, 4,
     pem_encinit, pem_decinit,
     pem_read, pem_write,
     pem_encdone, pem_decdone,
     pem_encinit, pem_decinit,
     pem_read, pem_write,
     pem_encdone, pem_decdone,
@@ -358,11 +360,12 @@ void freeenc(enc *e) { e->ops->destroy(e); }
 
 int cmd_encode(int argc, char *argv[])
 {
 
 int cmd_encode(int argc, char *argv[])
 {
-  const char *of = 0;
+  const char *fn, *of = 0;
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   const char *bd = "MESSAGE";
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   const char *bd = "MESSAGE";
+  fprogress ff;
   int i;
   size_t n;
   char buf[4096];
   int i;
   size_t n;
   char buf[4096];
@@ -371,20 +374,23 @@ int cmd_encode(int argc, char *argv[])
   enc *e;
 
 #define f_bogus 1u
   enc *e;
 
 #define f_bogus 1u
+#define f_progress 2u
 
   for (;;) {
     static const struct option opt[] = {
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "boundary",    OPTF_ARGREQ,    0,      'b' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
 
   for (;;) {
     static const struct option opt[] = {
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "boundary",    OPTF_ARGREQ,    0,      'b' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { 0,             0,              0,      0 }
     };
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'f': ef = optarg; break;
       case 'b': bd = optarg; break;
       case 'o': of = optarg; break;
     if (i < 0) break;
     switch (i) {
       case 'f': ef = optarg; break;
       case 'b': bd = optarg; break;
       case 'o': of = optarg; break;
+      case 'p': f |= f_progress; break;
       default: f |= f_bogus; break;
     }
   }
       default: f |= f_bogus; break;
     }
   }
@@ -394,16 +400,13 @@ int cmd_encode(int argc, char *argv[])
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
   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;
     fp = stdin;
-    optind++;
-  } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+  else if ((fp = fopen(fn, "rb")) == 0) {
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
@@ -414,25 +417,38 @@ int cmd_encode(int argc, char *argv[])
 
   e = initenc(eo, ofp, bd);
 
 
   e = initenc(eo, ofp, bd);
 
+  if (f & f_progress) {
+    if (fprogress_init(&ff, fn, fp)) {
+      die(EXIT_FAILURE, "failed to initialize progress display: %s",
+         strerror(errno));
+    }
+  }
+
   do {
     n = fread(buf, 1, sizeof(buf), fp);
   do {
     n = fread(buf, 1, sizeof(buf), fp);
-    if (e->ops->write(e, buf, n))
+    if (f & f_progress) fprogress_update(&ff, n);
+    if (e->ops->write(e, buf, n)) {
+      if (f & f_progress) fprogress_done(&ff);
       die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
       die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+    }
   } while (n == sizeof(buf));
   } while (n == sizeof(buf));
+  if (f & f_progress) fprogress_done(&ff);
   e->ops->encdone(e);
   freeenc(e);
   return (0);
 
 #undef f_bogus
   e->ops->encdone(e);
   freeenc(e);
   return (0);
 
 #undef f_bogus
+#undef f_progress
 }
 
 int cmd_decode(int argc, char *argv[])
 {
 }
 
 int cmd_decode(int argc, char *argv[])
 {
-  const char *of = 0;
+  const char *fn, *of = 0;
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   const char *bd = 0;
   FILE *ofp = 0;
   FILE *fp = 0;
   const char *ef = "binary";
   const char *bd = 0;
+  fprogress ff;
   int i;
   char buf[4096];
   unsigned f = 0;
   int i;
   char buf[4096];
   unsigned f = 0;
@@ -440,20 +456,23 @@ int cmd_decode(int argc, char *argv[])
   enc *e;
 
 #define f_bogus 1u
   enc *e;
 
 #define f_bogus 1u
+#define f_progress 2u
 
   for (;;) {
     static const struct option opt[] = {
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "boundary",    OPTF_ARGREQ,    0,      'b' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
 
   for (;;) {
     static const struct option opt[] = {
       { "format",      OPTF_ARGREQ,    0,      'f' },
       { "boundary",    OPTF_ARGREQ,    0,      'b' },
       { "output",      OPTF_ARGREQ,    0,      'o' },
+      { "progress",    0,              0,      'p' },
       { 0,             0,              0,      0 }
     };
       { 0,             0,              0,      0 }
     };
-    i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+    i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'f': ef = optarg; break;
       case 'b': bd = optarg; break;
       case 'o': of = optarg; break;
     if (i < 0) break;
     switch (i) {
       case 'f': ef = optarg; break;
       case 'b': bd = optarg; break;
       case 'o': of = optarg; break;
+      case 'p': f |= f_progress; break;
       default: f |= f_bogus; break;
     }
   }
       default: f |= f_bogus; break;
     }
   }
@@ -463,16 +482,13 @@ int cmd_decode(int argc, char *argv[])
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
   if ((eo = getenc(ef)) == 0)
     die(EXIT_FAILURE, "encoding `%s' not found", ef);
 
-  if (optind == argc)
+  fn = optind < argc ? argv[optind++] : "-";
+  if (strcmp(fn, "-") == 0)
     fp = stdin;
     fp = stdin;
-  else if (strcmp(argv[optind], "-") == 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",
     die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       argv[optind], strerror(errno));
-  } else
-    optind++;
+       fn, strerror(errno));
+  }
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
 
   if (!of || strcmp(of, "-") == 0)
     ofp = stdout;
@@ -483,17 +499,32 @@ int cmd_decode(int argc, char *argv[])
 
   e = initdec(eo, fp, checkbdry, (/*unconst*/ void *)bd);
 
 
   e = initdec(eo, fp, checkbdry, (/*unconst*/ void *)bd);
 
+  if (f & f_progress) {
+    if (fprogress_init(&ff, fn, fp)) {
+      die(EXIT_FAILURE, "failed to initialize progress display: %s",
+         strerror(errno));
+    }
+  }
+
   do {
   do {
-    if ((i = e->ops->read(e, buf, sizeof(buf))) < 0)
+    if ((i = e->ops->read(e, buf, sizeof(buf))) < 0) {
+      if (f & f_progress) fprogress_done(&ff);
       die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
       die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
-    if (fwrite(buf, 1, i, ofp) < i)
+    }
+    if (f & f_progress)
+      fprogress_update(&ff, i*e->ops->ncook/e->ops->nraw);
+    if (fwrite(buf, 1, i, ofp) < i) {
+      if (f & f_progress) fprogress_done(&ff);
       die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
       die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+    }
   } while (i == sizeof(buf));
   e->ops->decdone(e);
   } while (i == sizeof(buf));
   e->ops->decdone(e);
+  if (f & f_progress) fprogress_done(&ff);
   freeenc(e);
   return (0);
 
 #undef f_bogus
   freeenc(e);
   return (0);
 
 #undef f_bogus
+#undef f_progress
 }
 
 /*----- That's all, folks -------------------------------------------------*/
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index 28fcd4b..63199fc 100644 (file)
--- a/cc-kem.c
+++ b/cc-kem.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <stdlib.h>
 
 #include <mLib/alloc.h>
 #include <stdlib.h>
 
 #include <mLib/alloc.h>
index 9c06cd0..b182ba4 100644 (file)
--- a/cc-list.c
+++ b/cc-list.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <mLib/report.h>
 
 #include "cc.h"
 #include <mLib/report.h>
 
 #include "cc.h"
diff --git a/cc-progress.c b/cc-progress.c
new file mode 100644 (file)
index 0000000..903e80e
--- /dev/null
@@ -0,0 +1,244 @@
+/* -*-c-*-
+ *
+ * Progress indicators for command-line tools
+ *
+ * (c) 2011 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * 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,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#define _FILE_OFFSET_BITS 64
+
+#include "config.h"
+
+#include "cc.h"
+
+#ifndef PATHSEP
+#  if defined(__riscos)
+#    define PATHSEP '.'
+#  elif defined(__unix) || defined(unix)
+#    define PATHSEP '/'
+#  else
+#    define PATHSEP '\\'
+#  endif
+#endif
+
+/*----- Static data -------------------------------------------------------*/
+
+static const char baton[] = "-\\|/";
+
+/*----- Human-friendly unit printing --------------------------------------*/
+
+struct unit {
+  const char *name;
+  int m;
+};
+
+/* --- @prhuman_time@ --- *
+ *
+ * Arguments:  @FILE *fp@ = stream to print on
+ *             @unsigned long n@ = time in seconds to print
+ *
+ * Returns:    ---
+ *
+ * Use:                Prints a time in some reasonable format.  The time takes up
+ *             PRHUMAN_TIMEWD character spaces.
+ */
+
+#define PRHUMAN_TIMEWD 7
+
+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);
+}
+
+/* --- @prhuman_data@ --- *
+ *
+ * Arguments:  @FILE *fp@ = file to print on
+ *             @off_t n@ = size to be printed
+ *
+ * Returns:    ---
+ *
+ * Use:                Prints a data size in some reasonable format.  The data size
+ *             takes up PRHUMAN_DATAWD character spaces.
+ */
+
+#define PRHUMAN_DATAWD 7
+
+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);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+#define BARWD 16
+
+/* --- @fprogress_init@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context to be initialized
+ *             @const char *name@ = file name string to show
+ *             @FILE *fp@ = file we're reading from
+ *
+ * Returns:    Zero on success, nonzero if the file's state is now broken.
+ *
+ * Use:                Initializes a progress context.  Nothing is actually
+ *             displayed yet.
+ */
+
+int fprogress_init(fprogress *f, const char *name, FILE *fp)
+{
+  const char *p;
+  off_t o, sz = -1;
+  size_t n;
+
+  /* --- Set up the offset --- */
+
+  if ((o = ftello(fp)) >= 0 &&
+      fseeko(fp, 0, SEEK_END) >= 0 &&
+      (sz = ftello(fp),
+       fseeko(fp, o, SEEK_SET) < 0))
+    return (-1);
+  if (o != -1 && sz != -1) sz -= o;
+  f->o = f->olast = 0; f->sz = sz;
+
+  /* --- Set up the file name --- */
+
+  n = strlen(name);
+  if (n < sizeof(f->name))
+    strcpy(f->name, name);
+  else if ((p = strchr(name + n - sizeof(f->name) + 4, PATHSEP)) != 0)
+    sprintf(f->name, "...%s", p);
+  else {
+    p = strrchr(name, PATHSEP);
+    if (!p) sprintf(f->name, "%.*s...", (int)sizeof(f->name) - 4, name);
+    else sprintf(f->name, "...%.*s...", (int)sizeof(f->name) - 7, p);
+  }
+
+  /* --- Set up some other stuff --- */
+
+  f->start = f->last = time(0);
+  f->bp = baton;
+
+  /* --- Done --- */
+
+  return (0);
+}
+
+/* --- @fprogress_clear@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *
+ * Returns:    ---
+ *
+ * Use:                Clears the progress display from the screen.
+ */
+
+void fprogress_clear(fprogress *f)
+{
+  fprintf(stderr, "\r%*s\r",
+         sizeof(f->name) + 2*PRHUMAN_DATAWD + PRHUMAN_TIMEWD + BARWD + 16,
+         "");
+}
+
+/* --- @fprogress_update@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *             @size_t n@ = how much progress has been made
+ *
+ * Returns:    ---
+ *
+ * Use:                Maybe updates the display to show that some progress has been
+ *             made.
+ */
+
+void fprogress_update(fprogress *f, size_t sz)
+{
+  time_t now = time(0);
+  int i, n;
+
+  /* --- See if there's anything to do --- */
+
+  f->o += sz;
+  if (difftime(now, f->last) < 1) return;
+  f->last = now;
+
+  /* --- See if we're going to lose the ETA and percentage indicators --- */
+
+  if (f->olast < f->sz && f->o > f->sz) fprogress_clear(f);
+  f->olast = f->o;
+
+  /* --- Do the initial display --- */
+
+  fprintf(stderr, "\r%-*s%c ",
+         (int)sizeof(f->name), f->name,
+         *f->bp++);
+  if (!*f->bp) f->bp = baton;
+  prhuman_data(stderr, f->o);
+
+  /* --- More complicated display if we have a set size --- */
+
+  if (f->sz > f->o) {
+    fputc('/', stderr);
+    prhuman_data(stderr, f->sz);
+    fputs(" [", stderr);
+    n = (f->o*BARWD + f->sz/2)/f->sz;
+    for (i = 0; i < n; i++) fputc('.', stderr);
+    fprintf(stderr, "%*s] %3d%% ETA ", BARWD - n, "",
+           (int)((f->o*100 + 50)/f->sz));
+    prhuman_time(stderr, difftime(now, f->start)*(f->sz - f->o)/f->o);
+  }
+}
+
+/* --- @fprogress_done@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *
+ * Returns:    ---
+ *
+ * Use:                Clear up the progress context and removes any display.
+ */
+
+void fprogress_done(fprogress *f) { fprogress_clear(f); }
+
+/*----- That's all, folks -------------------------------------------------*/
index eecda46..54b58f3 100644 (file)
--- a/cc-sig.c
+++ b/cc-sig.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <stdlib.h>
 
 #include <mLib/report.h>
 #include <stdlib.h>
 
 #include <mLib/report.h>
index b77a9c9..c8f8b51 100644 (file)
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include <mLib/quis.h>
 #include <mLib/report.h>
 
 #include <mLib/quis.h>
 #include <mLib/report.h>
 
diff --git a/cc.h b/cc.h
index 45e7eff..6f92978 100644 (file)
--- a/cc.h
+++ b/cc.h
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#if _FILE_OFFSET_BITS != 64
+#  error "Must set _FILE_OFFSET_BITS to 64."
+#endif
+
 #include <stdio.h>
 #include <string.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 
 #include <mLib/dstr.h>
 
 
 #include <mLib/dstr.h>
 
 
 /*----- Data structures ---------------------------------------------------*/
 
 
 /*----- Data structures ---------------------------------------------------*/
 
+/* --- Progress indicators --- */
+
+typedef struct fprogress {
+  const char *bp;
+  off_t o, sz, olast;
+  time_t start, last;
+  char name[24];
+} fprogress;
+
 /* --- Key encapsulation --- */
 
 typedef struct kem {
 /* --- Key encapsulation --- */
 
 typedef struct kem {
@@ -114,6 +128,7 @@ typedef struct enc {
 typedef struct encops {
   const char *name;
   const char *rmode, *wmode;
 typedef struct encops {
   const char *name;
   const char *rmode, *wmode;
+  int nraw, ncook;
   enc *(*initenc)(FILE */*fp*/, const char */*msg*/);
   enc *(*initdec)(FILE */*fp*/,
                  int (*/*func*/)(const char *, void *), void */*p*/);
   enc *(*initenc)(FILE */*fp*/, const char */*msg*/);
   enc *(*initdec)(FILE */*fp*/,
                  int (*/*func*/)(const char *, void *), void */*p*/);
@@ -258,24 +273,26 @@ extern void freeenc(enc */*e*/);
 
 #define CMD_ENCODE {                                                   \
   "encode", cmd_encode,                                                        \
 
 #define CMD_ENCODE {                                                   \
   "encode", cmd_encode,                                                        \
-    "encode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",                        \
+    "encode [-p] [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",           \
     "\
 Options:\n\
 \n\
 -f, --format=FORMAT    Encode to FORMAT.\n\
 -b, --boundary=LABEL   PEM boundary is LABEL.\n\
 -o, --output=FILE      Write output to FILE.\n\
     "\
 Options:\n\
 \n\
 -f, --format=FORMAT    Encode to FORMAT.\n\
 -b, --boundary=LABEL   PEM boundary is LABEL.\n\
 -o, --output=FILE      Write output to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 " }
 
 #define CMD_DECODE {                                                   \
   "decode", cmd_decode,                                                        \
 " }
 
 #define CMD_DECODE {                                                   \
   "decode", cmd_decode,                                                        \
-    "decode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",                        \
+    "decode [-p] [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",           \
     "\
 Options:\n\
 \n\
 -f, --format=FORMAT    Decode from FORMAT.\n\
 -b, --boundary=LABEL   PEM boundary is LABEL.\n\
 -o, --output=FILE      Write output to FILE.\n\
     "\
 Options:\n\
 \n\
 -f, --format=FORMAT    Decode from FORMAT.\n\
 -b, --boundary=LABEL   PEM boundary is LABEL.\n\
 -o, --output=FILE      Write output to FILE.\n\
+-p, --progress         Show progress on large files.\n\
 " }
 
 extern int cmd_encode(int /*argc*/, char */*argv*/[]);
 " }
 
 extern int cmd_encode(int /*argc*/, char */*argv*/[]);
@@ -387,6 +404,58 @@ const cmd *findcmd(const cmd */*cmds*/, const char */*name*/);
 extern void sc_help(const cmd */*cmds*/, FILE */*fp*/,
                    char *const */*argv*/);
 
 extern void sc_help(const cmd */*cmds*/, FILE */*fp*/,
                    char *const */*argv*/);
 
+/*----- Progress indicators -----------------------------------------------*/
+
+/* --- @fprogress_init@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context to be initialized
+ *             @const char *name@ = file name string to show
+ *             @FILE *fp@ = file we're reading from
+ *
+ * Returns:    Zero on success, nonzero if the file's state is now broken.
+ *
+ * Use:                Initializes a progress context.  Nothing is actually
+ *             displayed yet.
+ */
+
+extern int fprogress_init(fprogress */*f*/,
+                         const char */*name*/, FILE */*fp*/);
+
+/* --- @fprogress_update@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *             @size_t n@ = how much progress has been made
+ *
+ * Returns:    ---
+ *
+ * Use:                Maybe updates the display to show that some progress has been
+ *             made.
+ */
+
+extern void fprogress_update(fprogress */*f*/, size_t /*n*/);
+
+/* --- @fprogress_clear@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *
+ * Returns:    ---
+ *
+ * Use:                Clears the progress display from the screen.
+ */
+
+extern void fprogress_clear(fprogress */*f*/);
+
+/* --- @fprogress_done@ --- *
+ *
+ * Arguments:  @fprogress *f@ = progress context
+ *
+ * Returns:    ---
+ *
+ * Use:                Clear up the progress context and removes any display.
+ */
+
+extern void fprogress_done(fprogress */*f*/);
+
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus
index 3414695..8fa07da 100644 (file)
--- a/cookie.c
+++ b/cookie.c
@@ -28,6 +28,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include "config.h"
 
 #include <errno.h>
diff --git a/dsig.1 b/dsig.1
index edd1036..58cea8f 100644 (file)
--- a/dsig.1
+++ b/dsig.1
@@ -44,7 +44,7 @@ is one of:
 .RI [ item ...]
 .br
 .B sign
 .RI [ item ...]
 .br
 .B sign
-.RB [ \-0bqvC ]
+.RB [ \-0bpqvC ]
 .RB [ \-c
 .IR comment ]
 .RB [ \-k
 .RB [ \-c
 .IR comment ]
 .RB [ \-k
@@ -59,7 +59,7 @@ is one of:
 .IR output ]
 .br
 .B verify
 .IR output ]
 .br
 .B verify
-.RB [ \-qvC ]
+.RB [ \-pqvC ]
 .RI [ file ]
 .SH DESCRIPTION
 The
 .RI [ file ]
 .SH DESCRIPTION
 The
@@ -301,6 +301,9 @@ Writes
 as a comment in the output file.  The comment's integrity is protected
 by the signature.
 .TP
 as a comment in the output file.  The comment's integrity is protected
 by the signature.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .BI "\-f, \-\-file " name
 Read filenames from
 .I name
 .BI "\-f, \-\-file " name
 Read filenames from
 .I name
@@ -366,6 +369,9 @@ Produce more informational output.  The default verbosity level is 1.
 .B "\-q, \-\-quiet"
 Produce less information output.
 .TP
 .B "\-q, \-\-quiet"
 Produce less information output.
 .TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
 .B "\-C, \-\-nocheck"
 Don't check the public key for validity.  This makes verification go
 much faster, but at the risk of using a duff key, and potentially
 .B "\-C, \-\-nocheck"
 Don't check the public key for validity.  This makes verification go
 much faster, but at the risk of using a duff key, and potentially
diff --git a/dsig.c b/dsig.c
index c379e94..d09b675 100644 (file)
--- a/dsig.c
+++ b/dsig.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <ctype.h>
 #include "config.h"
 
 #include <ctype.h>
@@ -595,6 +597,7 @@ static const char *keyring = "keyring";
 /* --- @fhash@ --- *
  *
  * Arguments:  @const gchash *c@ = pointer to hash class
 /* --- @fhash@ --- *
  *
  * Arguments:  @const gchash *c@ = pointer to hash class
+ *             @unsigned f@ = flags
  *             @const char *file@ = file to hash
  *             @void *b@ = pointer to output buffer
  *
  *             @const char *file@ = file to hash
  *             @void *b@ = pointer to output buffer
  *
@@ -603,9 +606,12 @@ static const char *keyring = "keyring";
  * Use:                Hashes a file.
  */
 
  * Use:                Hashes a file.
  */
 
-static int fhash(const gchash *c, const char *file, void *b)
+#define FHF_PROGRESS 256u
+
+static int fhash(const gchash *c, unsigned f, const char *file, void *b)
 {
   FILE *fp = fopen(file, "rb");
 {
   FILE *fp = fopen(file, "rb");
+  fprogress ff;
   ghash *h = GH_INIT(c);
   char buf[4096];
   size_t sz;
   ghash *h = GH_INIT(c);
   char buf[4096];
   size_t sz;
@@ -613,10 +619,16 @@ static int fhash(const gchash *c, const char *file, void *b)
 
   if (!fp)
     return (-1);
 
   if (!fp)
     return (-1);
-  while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0)
+  if (f & FHF_PROGRESS) {
+    if (fprogress_init(&ff, file, fp)) return (-1);
+  }
+  while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0) {
     GH_HASH(h, buf, sz);
     GH_HASH(h, buf, sz);
+    if (f & FHF_PROGRESS) fprogress_update(&ff, sz);
+  }
   if (ferror(fp))
     rc = -1;
   if (ferror(fp))
     rc = -1;
+  if (f & FHF_PROGRESS) fprogress_done(&ff);
   GH_DONE(h, b);
   GH_DESTROY(h);
   fclose(fp);
   GH_DONE(h, b);
   GH_DESTROY(h);
   fclose(fp);
@@ -677,6 +689,7 @@ static int sign(int argc, char *argv[])
       { "null",                0,              0,      '0' },
       { "binary",      0,              0,      'b' },
       { "verbose",     0,              0,      'v' },
       { "null",                0,              0,      '0' },
       { "binary",      0,              0,      'b' },
       { "verbose",     0,              0,      'v' },
+      { "progress",    0,              0,      'p' },
       { "quiet",       0,              0,      'q' },
       { "comment",     OPTF_ARGREQ,    0,      'c' },
       { "file",                OPTF_ARGREQ,    0,      'f' },
       { "quiet",       0,              0,      'q' },
       { "comment",     OPTF_ARGREQ,    0,      'c' },
       { "file",                OPTF_ARGREQ,    0,      'f' },
@@ -686,7 +699,7 @@ static int sign(int argc, char *argv[])
       { "nocheck",     OPTF_ARGREQ,    0,      'C' },
       { 0,             0,              0,      0 }
     };
       { "nocheck",     OPTF_ARGREQ,    0,      'C' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+0vqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+0vpqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
     if (i < 0)
       break;
     switch (i) {
@@ -699,6 +712,9 @@ static int sign(int argc, char *argv[])
       case 'v':
        verb++;
        break;
       case 'v':
        verb++;
        break;
+      case 'p':
+       f |= FHF_PROGRESS;
+       break;
       case 'q':
        if (verb > 0)
          verb--;
       case 'q':
        if (verb > 0)
          verb--;
@@ -811,7 +827,7 @@ static int sign(int argc, char *argv[])
       break;
     b.tag = T_FILE;
     DENSURE(&b.b, GH_CLASS(s->h)->hashsz);
       break;
     b.tag = T_FILE;
     DENSURE(&b.b, GH_CLASS(s->h)->hashsz);
-    if (fhash(GH_CLASS(s->h), b.d.buf, b.b.buf)) {
+    if (fhash(GH_CLASS(s->h), f, b.d.buf, b.b.buf)) {
       moan("Error reading `%s': %s", b.d.buf, strerror(errno));
       f |= f_bogus;
     } else {
       moan("Error reading `%s': %s", b.d.buf, strerror(errno));
       f |= f_bogus;
     } else {
@@ -897,17 +913,21 @@ static int verify(int argc, char *argv[])
   for (;;) {
     static struct option opts[] = {
       { "verbose",     0,              0,      'v' },
   for (;;) {
     static struct option opts[] = {
       { "verbose",     0,              0,      'v' },
+      { "progress",    0,              0,      'p' },
       { "quiet",       0,              0,      'q' },
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
       { "quiet",       0,              0,      'q' },
       { "nocheck",     0,              0,      'C' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+vqC", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+vpqC", opts, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
       case 'v':
        verb++;
        break;
     if (i < 0)
       break;
     switch (i) {
       case 'v':
        verb++;
        break;
+      case 'p':
+       f |= FHF_PROGRESS;
+       break;
       case 'q':
        if (verb)
          verb--;
       case 'q':
        if (verb)
          verb--;
@@ -1025,7 +1045,7 @@ static int verify(int argc, char *argv[])
       case T_FILE:
        DRESET(&d);
        DENSURE(&d, GH_CLASS(s->h)->hashsz);
       case T_FILE:
        DRESET(&d);
        DENSURE(&d, GH_CLASS(s->h)->hashsz);
-       if (fhash(GH_CLASS(s->h), b.d.buf, d.buf)) {
+       if (fhash(GH_CLASS(s->h), f, b.d.buf, d.buf)) {
          if (verb > 1) {
            printf("BAD error reading file `%s': %s\n",
                    b.d.buf, strerror(errno));
          if (verb > 1) {
            printf("BAD error reading file `%s': %s\n",
                    b.d.buf, strerror(errno));
@@ -1109,7 +1129,7 @@ static cmd cmdtab[] = {
   { "help", cmd_help, "help [COMMAND...]" },
   { "show", cmd_show, "show [ITEM...]" },
   { "sign", sign,
   { "help", cmd_help, "help [COMMAND...]" },
   { "show", cmd_show, "show [ITEM...]" },
   { "sign", sign,
-    "sign [-0bqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\
+    "sign [-0bpqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\
 [-f FILE] [-o OUTPUT]",
     "\
 Options:\n\
 [-f FILE] [-o OUTPUT]",
     "\
 Options:\n\
@@ -1118,6 +1138,7 @@ Options:\n\
 -b, --binary           Produce a binary output file.\n\
 -q, --quiet            Produce fewer messages while working.\n\
 -v, --verbose          Produce more messages while working.\n\
 -b, --binary           Produce a binary output file.\n\
 -q, --quiet            Produce fewer messages while working.\n\
 -v, --verbose          Produce more messages while working.\n\
+-p, --progress         Show progress on large files.\n\
 -C, --nocheck          Don't check the private key.\n\
 -c, --comment=COMMENT  Include COMMENT in the output file.\n\
 -f, --file=FILE                Read filenames to hash from FILE.\n\
 -C, --nocheck          Don't check the private key.\n\
 -c, --comment=COMMENT  Include COMMENT in the output file.\n\
 -f, --file=FILE                Read filenames to hash from FILE.\n\
@@ -1126,11 +1147,12 @@ Options:\n\
 -e, --expire=TIME      The signature should expire after TIME.\n\
 " },
   { "verify", verify,
 -e, --expire=TIME      The signature should expire after TIME.\n\
 " },
   { "verify", verify,
-    "verify [-qvC] [FILE]", "\
+    "verify [-pqvC] [FILE]", "\
 Options:\n\
 \n\
 -q, --quiet            Produce fewer messages while working.\n\
 -v, --verbose          Produce more messages while working.\n\
 Options:\n\
 \n\
 -q, --quiet            Produce fewer messages while working.\n\
 -v, --verbose          Produce more messages while working.\n\
+-p, --progress         Show progress on large files.\n\
 -C, --nocheck          Don't check the public key.\n\
 " },
   { 0, 0, 0 }
 -C, --nocheck          Don't check the public key.\n\
 " },
   { 0, 0, 0 }
index d0ac31e..554b079 100644 (file)
--- a/hashsum.c
+++ b/hashsum.c
 #include "ghash.h"
 #include "cc.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
 /*----- Static variables --------------------------------------------------*/
 
 #define f_binary 1u
@@ -216,41 +206,6 @@ static const encodeops *getencoding(const char *ename)
  * Use:                Hashes a file.
  */
 
  * 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;
 static int fhash(const char *file, unsigned f, const gchash *gch, void *buf)
 {
   FILE *fp;
@@ -258,13 +213,7 @@ static int fhash(const char *file, unsigned f, const gchash *gch, void *buf)
   size_t sz;
   ghash *h;
   int e;
   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;
+  fprogress ff;
 
   if (!file || strcmp(file, "-") == 0)
     fp = stdin;
 
   if (!file || strcmp(file, "-") == 0)
     fp = stdin;
@@ -272,53 +221,17 @@ static int fhash(const char *file, unsigned f, const gchash *gch, void *buf)
     return (-1);
 
   if (f & f_progress) {
     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);
+    if (fprogress_init(&ff, file, fp)) return (-1);
   }
 
   h = GH_INIT(gch);
   while ((sz = fread(fbuf, 1, sizeof(fbuf), fp)) > 0) {
     GH_HASH(h, fbuf, sz);
   }
 
   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);
-      }
-    }
+    if (f & f_progress) fprogress_update(&ff, sz);
   }
   GH_DONE(h, buf);
   GH_DESTROY(h);
   }
   GH_DONE(h, buf);
   GH_DESTROY(h);
-  if (f & f_progress) fprintf(stderr, "\r%78s\r", "");
+  if (f & f_progress) fprogress_done(&ff);
   e = ferror(fp);
   if (file)
     fclose(fp);
   e = ferror(fp);
   if (file)
     fclose(fp);
index 74f6409..cca075f 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <ctype.h>
 #include "config.h"
 
 #include <ctype.h>
index 3a0df7e..3c26937 100644 (file)
@@ -29,6 +29,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include "config.h"
 
 #include <errno.h>