+
+ 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[])
+{