From: mdw Date: Sat, 29 Nov 2003 23:45:44 +0000 (+0000) Subject: Make gorp better. Deb fixes. X-Git-Tag: 1.1.1~2 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/misc/commitdiff_plain/22fb157c9459f0d07eb46d09370c27d3e57a437c Make gorp better. Deb fixes. --- diff --git a/debian/changelog b/debian/changelog index 040a1cb..6b41c19 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Tue, 18 Nov 2003 18:47:21 +0000 + nsict-utils (1.0) experimental; urgency=low * Debianization! - -- Mark Wooding Wed, 12 Nov 2003 20:17:35 +0000 + -- Mark Wooding Tue, 18 Nov 2003 13:48:03 +0000 diff --git a/debian/control b/debian/control index cf1f43b..c1d2749 100644 --- a/debian/control +++ b/debian/control @@ -2,6 +2,8 @@ Source: nsict-utils Section: utils Priority: extra Maintainer: Mark Wooding +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 diff --git a/debian/rules b/debian/rules index 2360dcc..d987ec6 100755 --- a/debian/rules +++ b/debian/rules @@ -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 f00ce13..6f9000d 100644 --- 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 933460c..398e852 100644 --- a/gorp.c +++ b/gorp.c @@ -1,3 +1,6 @@ +#include +#include +#include #include #include #include @@ -5,36 +8,259 @@ #include #include #include +#include +#include #include #include #include #include -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); }