3 * Common test driver for encoding and decoding
5 * (c) 2009 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
48 /*----- Static variables --------------------------------------------------*/
50 static const codec_class *cctab[] = {
61 static const struct { const char *name; unsigned f; } flagtab[] = {
62 { "lowerc", CDCF_LOWERC },
63 { "igncase", CDCF_IGNCASE },
64 { "noeqpad", CDCF_NOEQPAD },
65 { "igneqpad", CDCF_IGNEQPAD },
66 { "igneqmid", CDCF_IGNEQMID },
67 { "ignzpad", CDCF_IGNZPAD },
68 { "ignnewl", CDCF_IGNNEWL },
69 { "ignspc", CDCF_IGNSPC },
70 { "igninvch", CDCF_IGNINVCH },
71 { "ignjunk", CDCF_IGNJUNK },
75 /*----- Main code ---------------------------------------------------------*/
77 static void usage(FILE *fp)
80 "Usage: $ [-de] [-f FLAGS] [-i INDENT] [-m MAXLINE] [-o OUTPUT]\n"
81 "\tCODEC [FILE ...]\n");
84 static void version(FILE *fp)
85 { pquis(fp, "$, mLib version " VERSION "\n"); }
87 static void help(FILE *fp)
95 Encodes and decodes binary files. Options provided:\n\
97 -h, --help Show this help text.\n\
98 -v, --version Show the program's version number.\n\
99 -u, --usage Show a terse usage message.\n\
101 -d, --decode Decode binary FILEs.\n\
102 -e, --encode Encode binary FILEs (default).\n\
103 -f, --flags=FLAGS Set encoding/decoding FLAGS.\n\
104 -i, --indent=INDENT Indent each line with INDENT.\n\
105 -m, --maxline=MAXLINE Limit line length to (about) MAXLINE.\n\
106 -o, --output=OUTPUT Write encoded/decoded data to OUTPUT.\n\
108 #define ENUM(label, tab, end, getname) do { \
109 fputs(label ":", fp); \
110 for (i = 0; tab[i]end; i++) fprintf(fp, " %s", tab[i]getname); \
113 ENUM("Codecs", cctab, != 0, ->name);
114 ENUM("Flags", flagtab, .name, .name);
118 static void code(codec *c, const char *ifile, FILE *ifp, FILE *ofp)
126 n = fread(buf, 1, sizeof(buf), ifp);
128 if ((err = c->ops->code(c, buf, n, &d)) != 0)
129 die(EXIT_FAILURE, "decoding error: %s", codec_strerror(err));
130 } while (fwrite(d.buf, 1, d.len, ofp) == d.len && n == sizeof(buf));
132 die(EXIT_FAILURE, "error reading `%s': %s", ifile, strerror(errno));
135 int main(int argc, char *argv[])
137 enum { encode, decode };
139 const codec_class **cc;
141 const char *indent = "";
142 const char *imode, *omode, *ofile = 0;
143 unsigned maxline = 64;
144 unsigned f = CDCF_IGNSPC | CDCF_IGNNEWL;
147 FILE *ifp, *ofp = stdout;
154 #define f_bogus 32768u
159 static const struct option opts[] = {
160 { "help", 0, 0, 'h' },
161 { "version", 0, 0, 'v' },
162 { "usage", 0, 0, 'u' },
163 { "encode", 0, 0, 'e' },
164 { "decode", 0, 0, 'd' },
165 { "indent", OPTF_ARGREQ, 0, 'i' },
166 { "maxline", OPTF_ARGREQ, 0, 'm' },
167 { "output", OPTF_ARGREQ, 0, 'o' },
168 { "flags", OPTF_ARGREQ, 0, 'f' },
172 if ((i = mdwopt(argc, argv, "hvu" "edf:i:m:o:", opts, 0, 0, 0)) < 0)
175 case 'h': help(stdout); exit(0);
176 case 'v': version(stdout); exit(0);
177 case 'u': usage(stdout); exit(0);
179 case 'e': mode = encode; break;
180 case 'd': mode = decode; break;
181 case 'i': indent = optarg; break;
182 case 'o': ofile = optarg; break;
186 maxline = strtoul(optarg, &q, 0);
187 if (*q || errno) die(EXIT_FAILURE, "bad integer `%s'", optarg);
193 if (*p == '-') { sense = 0; p++; }
194 else if (*p == '+') { sense = 1; p++; }
197 for (i = 0; flagtab[i].name; i++) {
198 if (strlen(flagtab[i].name) == n &&
199 STRNCMP(flagtab[i].name, ==, p, n))
202 die(EXIT_FAILURE, "unknown flag `%.*s'", (int)n, p);
204 if (sense) f |= flagtab[i].f;
205 else f &= ~flagtab[i].f;
211 default: f |= f_bogus; break;
214 argv += optind; argc -= optind;
215 if ((f & f_bogus) || !argc) { usage(stderr); exit(EXIT_FAILURE); }
217 for (cc = cctab;; cc++) {
218 if (!*cc) die(EXIT_FAILURE, "unknown codec `%s'", *argv);
219 else if (STRCMP(*argv, ==, (*cc)->name)) break;
226 for (p = indent;; p++) {
231 case 'a': DPUTC(&d, '\n'); break;
232 case 'b': DPUTC(&d, '\b'); break;
233 case 'f': DPUTC(&d, '\f'); break;
234 case 'n': DPUTC(&d, '\n'); break;
235 case 'r': DPUTC(&d, '\r'); break;
236 case 't': DPUTC(&d, '\t'); break;
237 case 'v': DPUTC(&d, '\v'); break;
238 case 0: goto done_indent; break;
239 default: DPUTC(&d, *p); break;
251 c = (*cc)->encoder(f, d.buf, maxline);
252 imode = "rb"; omode = "w";
255 c = (*cc)->decoder(f);
256 imode = "r"; omode = "wb";
262 if (ofile && (ofp = fopen(ofile, omode)) == 0) {
263 die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
264 ofile, strerror(errno));
267 if (mode == encode) fwrite(d.buf + 1, 1, d.len - 1, ofp);
269 code(c, "<stdin>", stdin, ofp);
270 else for (i = 0; i < argc; i++) {
271 if (STRCMP(argv[i], ==, "-"))
272 code(c, "<stdin>", stdin, ofp);
273 else if ((ifp = fopen(argv[i], imode)) == 0) {
274 die(EXIT_FAILURE, "couldn't open `%s' for reading: %s",
275 argv[i], strerror(errno));
277 code(c, argv[i], ifp, ofp);
282 if ((err = c->ops->code(c, 0, 0, &d)) != 0)
283 die(EXIT_FAILURE, "decoding error: %s", codec_strerror(err));
284 if (mode == encode) DPUTC(&d, '\n');
285 fwrite(d.buf, 1, d.len, ofp);
286 c->ops->destroy(c); DDESTROY(&d);
288 if (ferror(ofp) || fflush(ofp) || fclose(ofp)) {
289 die(EXIT_FAILURE, "error writing to `%s': %s",
290 ofile ? ofile : "<stdout>", strerror(errno));
295 /*----- That's all, folks -------------------------------------------------*/