chiark / gitweb /
Make gorp better. Deb fixes.
authormdw <mdw>
Sat, 29 Nov 2003 23:45:44 +0000 (23:45 +0000)
committermdw <mdw>
Sat, 29 Nov 2003 23:45:44 +0000 (23:45 +0000)
debian/changelog
debian/control
debian/rules
gorp.1
gorp.c

index 040a1cbde86e1539e03335785a06946157a0a52b..6b41c19a013f53d9a470f72b1977753cd83b9e49 100644 (file)
@@ -1,5 +1,13 @@
+nsict-utils (1.1.0) experimental; urgency=low
+
+  * Make gorp a much more useful program.
+  
+  * Get the right version number.  Oops!
+
+ -- Mark Wooding <mdw@nsict.org>  Tue, 18 Nov 2003 18:47:21 +0000
+
 nsict-utils (1.0) experimental; urgency=low
   
   * Debianization!
   
- -- Mark Wooding <mdw@nsict.org>  Wed, 12 Nov 2003 20:17:35 +0000
+ -- Mark Wooding <mdw@nsict.org>  Tue, 18 Nov 2003 13:48:03 +0000
index cf1f43b56f0132a237efd78ff94df27dc170a72f..c1d2749dbbd14ea255de9d3ca2bc338339e11abc 100644 (file)
@@ -2,6 +2,8 @@ Source: nsict-utils
 Section: utils
 Priority: extra
 Maintainer: Mark Wooding <mdw@nsict.org>
+Build-Depends: freecdb, bash-builtins, debhelper (>= 4.0.2),
+ catacomb-dev (>= 2.0.0), mlib-dev (>= 2.0.0), libspamc-dev
 Standards-Version: 3.1.1
 
 Package: nsict-utils
index 2360dcccfc41588503b50cb0fa4ebc606c17d88f..d987ec68900762dd9a456d1f69f8989005905700 100755 (executable)
@@ -25,6 +25,7 @@ binary-indep:
        dh_compress -i
        dh_installdocs -i
        dh_gencontrol -i
+       dh_perl -i
        dh_fixperms -i
        dh_installdeb -i
        dh_md5sums -i
diff --git a/gorp.1 b/gorp.1
index f00ce13cbcc884bc3ae8e076f48cea8286960aa8..6f9000d922a01213ac30b495181fa714c2a701c2 100644 (file)
--- a/gorp.1
+++ b/gorp.1
@@ -4,12 +4,58 @@
 gorp \- write a short random string
 .SH SYNOPSIS
 .B gorp
+.RB [ \-y ]
+.RB [ \-l
+.IR length ]
+.RB [ \-f
+.IR format ]
 .RI [ bits ]
 .SH DESCRIPTION
 Generates
 .I bits
 random bits (must be a multiple of 8, default is 128) and writes the
-resulting string to standard output in base64 format.
+resulting string to standard output.
+.PP
+The following options are recognized.
+.TP
+.B "\-h, \-\-help"
+Prints a help message to standard output and exits successfully.
+.TP
+.B "\-v, \-\-version"
+Prints the program's version number to standard output and exits
+successfully.
+.TP
+.B "\-u, \-\-usage"
+Prints a really short usage summary to standard output and exits
+successfully.
+.TP
+.BI "\-f, \-\-format=" format
+Prints the random string using the chosen output
+.IR format ,
+which may be
+.B base64
+(standard Base64 encoding, as described in RFC2045; this is the default), 
+.B file64
+(Base64 encoding, with
+.RB ` % '
+instead of
+.RB ` / ',
+so the output is suitable for use as a filename),
+.B hex
+(plain hexadecimal encoding), or
+.B raw
+(raw binary output, not printable).
+.TP
+.B "\-l, \-\-line=" length
+Breaks textual output into lines of at most
+.I length
+characters, and does all encoding in a strictly conforming way.  By
+default, the textual output is not line-broken, and strange terminator
+characters are not printed.
+.TP
+.B "\-y, \-\-bytes"
+The output length is bits, not bytes.  This doesn't affect the default
+value of 128.
 .SH BUGS
 None known.
 .SH AUTHOR
diff --git a/gorp.c b/gorp.c
index 933460c03c5af31131ec122c1f4ad2210d5f1a1a..398e852b3b2dbc260e827da26c93575e2792227e 100644 (file)
--- a/gorp.c
+++ b/gorp.c
@@ -1,3 +1,6 @@
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <mLib/alloc.h>
 #include <mLib/base64.h>
 #include <mLib/dstr.h>
+#include <mLib/hex.h>
+#include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
 
 #include <catacomb/rand.h>
 #include <catacomb/noise.h>
 
-int main(int argc, char *argv[])
+struct format {
+  const char *name;
+  void (*out)(size_t, unsigned);
+};
+
+#define CHUNK 1024
+
+static void format_base64(size_t n, unsigned line)
 {
+  unsigned char buf[CHUNK];
   dstr d = DSTR_INIT;
   base64_ctx b;
-  char *p;
+
+  base64_init(&b);
+  if (line) {
+    b.indent = "\n";
+    b.maxline = line;
+  } else {
+    b.indent = "";
+    b.maxline = 0;
+  }
+
+  while (n) {
+    size_t nn = CHUNK;
+    if (nn > n) nn = n;
+    rand_get(RAND_GLOBAL, buf, nn);
+    base64_encode(&b, buf, nn, &d);
+    DWRITE(&d, stdout);
+    DRESET(&d);
+    n -= nn;
+  }
+  base64_encode(&b, 0, 0, &d);
+  if (!line) {
+    while (d.len && d.buf[d.len - 1] == '=')
+      d.len--;
+  }
+  DPUTC(&d, '\n');
+  DWRITE(&d, stdout);
+}
+
+static void file_fix(char *p, size_t n)
+{
+  while (n) {
+    if (*p == '/') *p = '%';
+    p++; n--;
+  }
+}
+
+static void format_file64(size_t n, unsigned line)
+{
+  unsigned char buf[CHUNK];
+  dstr d = DSTR_INIT;
+  base64_ctx b;
+
+  base64_init(&b);
+  b.indent = "";
+  b.maxline = 0;
+
+  while (n) {
+    size_t nn = CHUNK;
+    if (nn > n) nn = n;
+    rand_get(RAND_GLOBAL, buf, nn);
+    base64_encode(&b, buf, nn, &d);
+    file_fix(d.buf, d.len);
+    DWRITE(&d, stdout);
+    DRESET(&d);
+    n -= nn;
+  }
+  base64_encode(&b, 0, 0, &d);
+  file_fix(d.buf, d.len);
+  while (d.len && d.buf[d.len - 1] == '=')
+    d.len--;
+  DPUTC(&d, '\n');
+  DWRITE(&d, stdout);
+}
+
+static void format_hex(size_t n, unsigned line)
+{
+  unsigned char buf[CHUNK];
+  dstr d = DSTR_INIT;
+  hex_ctx h;
+
+  hex_init(&h);
+  if (line) {
+    h.indent = "\n";
+    h.maxline = line;
+  } else {
+    h.indent = "";
+    h.maxline = 0;
+  }
+
+  while (n) {
+    size_t nn = CHUNK;
+    if (nn > n) nn = n;
+    rand_get(RAND_GLOBAL, buf, nn);
+    hex_encode(&h, buf, nn, &d);
+    DWRITE(&d, stdout);
+    DRESET(&d);
+    n -= nn;
+  }
+  hex_encode(&h, 0, 0, &d);
+  DPUTC(&d, '\n');
+  DWRITE(&d, stdout);
+}
+
+static void format_raw(size_t n, unsigned line)
+{
+  unsigned char buf[CHUNK];
+
+  while (n) {
+    size_t nn = CHUNK;
+    if (nn > n) nn = n;
+    rand_get(RAND_GLOBAL, buf, nn);
+    fwrite(buf, 1, nn, stdout);
+    n -= nn;
+  }
+}
+
+static const struct format fmt[] = {
+  { "base64",  format_base64 },
+  { "file64",  format_file64 },
+  { "hex",     format_hex },
+  { "raw",     format_raw },
+  { 0,         0 }
+};
+
+static int uarg(const char *p, const char *what)
+{
+  unsigned long x;
+  char *q;
+  errno = 0;
+  x = strtoul(p, &q, 0);
+  if (*q || errno || x > INT_MAX) die(EXIT_FAILURE, "bad %s", what);
+  return (x);
+}
+
+static void version(FILE *fp)
+{
+  pquis(stderr, "$, version " VERSION "\n");
+}
+
+static void usage(FILE *fp)
+{
+  pquis(stderr, "Usage: $ [-y] [-l LEN] [-f FORMAT] [BITS]\n");
+}
+
+static void help(FILE *fp)
+{
+  version(fp);
+  putc('\n', fp);
+  usage(fp);
+  fputs("\n\
+Generates a random string, and prints it to standard output.\n\
+\n\
+Options:\n\
+\n\
+-h, --help             Print this help message.\n\
+-v, --version          Print program version number.\n\
+-u, --usage            Print short usage summary.\n\
+\n\
+-y, --bytes            Output length is bytes, not bits.\n\
+-l, --line=LENGTH      For textual output, limit line length to LENGTH.\n\
+-f, --format=FORMAT    Select output format: base64, file64, hex, raw.\n\
+", stdout);
+}
+
+int main(int argc, char *argv[])
+{
   size_t n;
+  unsigned f = 0;
+  unsigned len = 0;
+  unsigned mul = 8;
+  const struct format *ff = &fmt[0];
+
+#define f_bogus 1u
 
   ego(argv[0]);
-  if (argc > 2) {
-    pquis(stderr, "Usage: $ [BITS]\n");
+  for (;;) {
+    static const struct option opt[] = {
+      { "help",                0,              0,      'h' },
+      { "version",     0,              0,      'v' },
+      { "usage",       0,              0,      'u' },
+
+      { "format",      OPTF_ARGREQ,    0,      'f' },
+      { "line",                OPTF_ARGREQ,    0,      'l' },
+      { "bytes",       0,              0,      'y' },
+      { 0,             0,              0,      0 }
+    };
+    int i;
+
+    i = mdwopt(argc, argv, "hvuf:l:y", opt, 0, 0, 0);
+    if (i < 0)
+      break;
+    switch (i) {
+      case 'h':
+       help(stdout);
+       exit(0);
+      case 'v':
+       version(stdout);
+       exit(0);
+      case 'u':
+       usage(stdout);
+       exit(0);
+      case 'y':
+       mul = 1;
+       break;
+      case 'l':
+       len = uarg(optarg, "line length");
+       break;
+      case 'f':
+       ff = 0;
+       n = strlen(optarg);
+       for (i = 0; fmt[i].name; i++) {
+         if (strncmp(fmt[i].name, optarg, n) != 0)
+           continue;
+         if (!fmt[i].name[n]) {
+           ff = &fmt[i];
+           break;
+         }
+         if (ff)
+           die(EXIT_FAILURE, "ambiguous format name `%s'", optarg);
+         ff = &fmt[i];
+       }
+       if (!ff)
+         die(EXIT_FAILURE, "unknown format name `%s'", optarg);
+       break;
+      default:
+       f |= f_bogus;
+       break;
+    }
+  }
+
+  argc -= optind;
+  argv += optind;
+  if (f & f_bogus && argc > 1) {
+    usage(stderr);
     exit(EXIT_FAILURE);
   }
-  n = argc == 2 ? atoi(argv[1]) : 128;
-  if (!n || n % 8) die(EXIT_FAILURE, "bad bit count");
-  n >>= 3;
-  p = xmalloc(n);
+  n = argc == 1 ? uarg(argv[0], "bit count") : 128;
+  if (!n || n % mul) die(EXIT_FAILURE, "bad bit count");
+  n /= mul;
   rand_noisesrc(RAND_GLOBAL, &noise_source);
   rand_seed(RAND_GLOBAL, 160);
-  rand_get(RAND_GLOBAL, p, n);
-  base64_init(&b);
-  b.maxline = 0;
-  b.indent = "";
-  base64_encode(&b, p, n, &d);
-  base64_encode(&b, 0, 0, &d);
-  printf("%s\n", d.buf);
+  ff->out(n, len);
+  if (ferror(stdout))
+    die(EXIT_FAILURE, "output error: %s", strerror(errno));
   return (0);
 }