chiark / gitweb /
buf.1: Fix stupid speling mitsake.
[misc] / gorp.c
... / ...
CommitLineData
1#include <ctype.h>
2#include <errno.h>
3#include <limits.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include <mLib/alloc.h>
9#include <mLib/base64.h>
10#include <mLib/base32.h>
11#include <mLib/dstr.h>
12#include <mLib/hex.h>
13#include <mLib/mdwopt.h>
14#include <mLib/quis.h>
15#include <mLib/report.h>
16
17#include <catacomb/rand.h>
18#include <catacomb/noise.h>
19
20struct format {
21 const char *name;
22 void (*out)(size_t, unsigned);
23};
24
25#define CHUNK 1024
26
27static void do_format(size_t n, unsigned line, void *ctx,
28 void (*encode)(void *, char *, size_t, dstr *),
29 void (*fix)(char *, size_t))
30{
31 char buf[CHUNK];
32 dstr d = DSTR_INIT;
33
34 while (n) {
35 size_t nn = CHUNK;
36 if (nn > n) nn = n;
37 rand_get(RAND_GLOBAL, buf, nn);
38 encode(ctx, buf, nn, &d);
39 if (fix) fix(d.buf, d.len);
40 DWRITE(&d, stdout);
41 DRESET(&d);
42 n -= nn;
43 }
44 encode(ctx, 0, 0, &d);
45 if (!line) {
46 while (d.len && d.buf[d.len - 1] == '=')
47 d.len--;
48 }
49 if (fix) fix(d.buf, d.len);
50 DPUTC(&d, '\n');
51 DWRITE(&d, stdout);
52}
53
54static void do_base64(void *ctx, char *p, size_t sz, dstr *d)
55 { base64_encode(ctx, p, sz, d); }
56static void do_format_base64(size_t n, unsigned line,
57 void (*fix)(char *, size_t))
58{
59 base64_ctx b;
60
61 base64_init(&b);
62 if (line) { b.indent = "\n"; b.maxline = line; }
63 else { b.indent = ""; b.maxline = 0; }
64 do_format(n, line, &b, do_base64, fix);
65}
66static void format_base64(size_t n, unsigned line)
67 { do_format_base64(n, line, 0); }
68
69static void do_base32(void *ctx, char *p, size_t sz, dstr *d)
70 { base32_encode(ctx, p, sz, d); }
71static void format_base32(size_t n, unsigned line)
72{
73 base32_ctx b;
74
75 base32_init(&b);
76 if (line) { b.indent = "\n"; b.maxline = line; }
77 else { b.indent = ""; b.maxline = 0; }
78 do_format(n, line, &b, do_base32, 0);
79}
80
81static void fix_file64(char *p, size_t n)
82{
83 while (n) {
84 if (*p == '/') *p = '%';
85 p++; n--;
86 }
87}
88static void format_file64(size_t n, unsigned line)
89 { do_format_base64(n, line, fix_file64); }
90
91static void fix_safe64(char *p, size_t n)
92{
93 while (n) {
94 if (*p == '+') *p = '-';
95 else if (*p == '/') *p = '_';
96 p++; n--;
97 }
98}
99static void format_safe64(size_t n, unsigned line)
100 { do_format_base64(n, line, fix_safe64); }
101
102static void do_hex(void *ctx, char *p, size_t sz, dstr *d)
103 { hex_encode(ctx, p, sz, d); }
104static void format_hex(size_t n, unsigned line)
105{
106 hex_ctx b;
107
108 hex_init(&b);
109 if (line) { b.indent = "\n"; b.maxline = line; }
110 else { b.indent = ""; b.maxline = 0; }
111 do_format(n, line, &b, do_hex, 0);
112}
113
114static void format_raw(size_t n, unsigned line)
115{
116 unsigned char buf[CHUNK];
117
118 while (n) {
119 size_t nn = CHUNK;
120 if (nn > n) nn = n;
121 rand_get(RAND_GLOBAL, buf, nn);
122 fwrite(buf, 1, nn, stdout);
123 n -= nn;
124 }
125}
126
127static const struct format fmt[] = {
128 { "base64", format_base64 },
129 { "file64", format_file64 },
130 { "safe64", format_safe64 },
131 { "base32", format_base32 },
132 { "hex", format_hex },
133 { "raw", format_raw },
134 { 0, 0 }
135};
136
137static int uarg(const char *p, const char *what)
138{
139 unsigned long x;
140 char *q;
141 errno = 0;
142 x = strtoul(p, &q, 0);
143 if (*q || errno || x > INT_MAX) die(EXIT_FAILURE, "bad %s", what);
144 return (x);
145}
146
147static void version(FILE *fp)
148{
149 pquis(stderr, "$, version " VERSION "\n");
150}
151
152static void usage(FILE *fp)
153{
154 pquis(stderr, "Usage: $ [-y] [-l LEN] [-f FORMAT] [BITS]\n");
155}
156
157static void help(FILE *fp)
158{
159 version(fp);
160 putc('\n', fp);
161 usage(fp);
162 fputs("\n\
163Generates a random string, and prints it to standard output.\n\
164\n\
165Options:\n\
166\n\
167-h, --help Print this help message.\n\
168-v, --version Print program version number.\n\
169-u, --usage Print short usage summary.\n\
170\n\
171-y, --bytes Output length is bytes, not bits.\n\
172-l, --line=LENGTH For textual output, limit line length to LENGTH.\n\
173-f, --format=FORMAT Select output format:\n\
174 base64, file64, safe64, base32, hex, raw.\n\
175", stdout);
176}
177
178int main(int argc, char *argv[])
179{
180 size_t n;
181 unsigned f = 0;
182 unsigned len = 0;
183 unsigned mul = 8;
184 const struct format *ff = &fmt[0];
185
186#define f_bogus 1u
187
188 ego(argv[0]);
189 for (;;) {
190 static const struct option opt[] = {
191 { "help", 0, 0, 'h' },
192 { "version", 0, 0, 'v' },
193 { "usage", 0, 0, 'u' },
194
195 { "format", OPTF_ARGREQ, 0, 'f' },
196 { "line", OPTF_ARGREQ, 0, 'l' },
197 { "bytes", 0, 0, 'y' },
198 { 0, 0, 0, 0 }
199 };
200 int i;
201
202 i = mdwopt(argc, argv, "hvuf:l:y", opt, 0, 0, 0);
203 if (i < 0)
204 break;
205 switch (i) {
206 case 'h':
207 help(stdout);
208 exit(0);
209 case 'v':
210 version(stdout);
211 exit(0);
212 case 'u':
213 usage(stdout);
214 exit(0);
215 case 'y':
216 mul = 1;
217 break;
218 case 'l':
219 len = uarg(optarg, "line length");
220 break;
221 case 'f':
222 ff = 0;
223 n = strlen(optarg);
224 for (i = 0; fmt[i].name; i++) {
225 if (strncmp(fmt[i].name, optarg, n) != 0)
226 continue;
227 if (!fmt[i].name[n]) {
228 ff = &fmt[i];
229 break;
230 }
231 if (ff)
232 die(EXIT_FAILURE, "ambiguous format name `%s'", optarg);
233 ff = &fmt[i];
234 }
235 if (!ff)
236 die(EXIT_FAILURE, "unknown format name `%s'", optarg);
237 break;
238 default:
239 f |= f_bogus;
240 break;
241 }
242 }
243
244 argc -= optind;
245 argv += optind;
246 if (f & f_bogus && argc > 1) {
247 usage(stderr);
248 exit(EXIT_FAILURE);
249 }
250 n = argc == 1 ? uarg(argv[0], "bit count") : 128;
251 if (!n || n % mul) die(EXIT_FAILURE, "bad bit count");
252 n /= mul;
253 rand_noisesrc(RAND_GLOBAL, &noise_source);
254 rand_seed(RAND_GLOBAL, 160);
255 ff->out(n, len);
256 if (ferror(stdout))
257 die(EXIT_FAILURE, "output error: %s", strerror(errno));
258 return (0);
259}