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