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 ------------------------------------------------------*/
47 /*----- Static variables --------------------------------------------------*/
49 static const codec_class
*cctab
[] = {
60 static const struct { const char *name
; unsigned f
; } flagtab
[] = {
61 { "lowerc", CDCF_LOWERC
},
62 { "igncase", CDCF_IGNCASE
},
63 { "noeqpad", CDCF_NOEQPAD
},
64 { "igneqpad", CDCF_IGNEQPAD
},
65 { "igneqmid", CDCF_IGNEQMID
},
66 { "ignzpad", CDCF_IGNZPAD
},
67 { "ignnewl", CDCF_IGNNEWL
},
68 { "ignspc", CDCF_IGNSPC
},
69 { "igninvch", CDCF_IGNINVCH
},
70 { "ignjunk", CDCF_IGNJUNK
},
74 /*----- Main code ---------------------------------------------------------*/
76 static void usage(FILE *fp
)
79 "Usage: $ [-de] [-f FLAGS] [-i INDENT] [-m MAXLINE] [-o OUTPUT]\n"
80 "\tCODEC [FILE ...]\n");
83 static void version(FILE *fp
)
84 { pquis(fp
, "$, mLib version " VERSION
"\n"); }
86 static void help(FILE *fp
)
94 Encodes and decodes binary files. Options provided:\n\
96 -h, --help Show this help text.\n\
97 -v, --version Show the program's version number.\n\
98 -u, --usage Show a terse usage message.\n\
100 -d, --decode Decode binary FILEs.\n\
101 -e, --encode Encode binary FILEs (default).\n\
102 -f, --flags=FLAGS Set encoding/decoding FLAGS.\n\
103 -i, --indent=INDENT Indent each line with INDENT.\n\
104 -m, --maxline=MAXLINE Limit line length to (about) MAXLINE.\n\
105 -o, --output=OUTPUT Write encoded/decoded data to OUTPUT.\n\
107 #define ENUM(label, tab, end, getname) do { \
108 fputs(label ":", fp); \
109 for (i = 0; tab[i]end; i++) fprintf(fp, " %s", tab[i]getname); \
112 ENUM("Codecs", cctab
, != 0, ->name
);
113 ENUM("Flags", flagtab
, .name
, .name
);
117 static void code(codec
*c
, const char *ifile
, FILE *ifp
, FILE *ofp
)
125 n
= fread(buf
, 1, sizeof(buf
), ifp
);
127 if ((err
= c
->ops
->code(c
, buf
, n
, &d
)) != 0)
128 die(EXIT_FAILURE
, "decoding error: %s", codec_strerror(err
));
129 } while (fwrite(d
.buf
, 1, d
.len
, ofp
) == d
.len
&& n
== sizeof(buf
));
131 die(EXIT_FAILURE
, "error reading `%s': %s", ifile
, strerror(errno
));
134 int main(int argc
, char *argv
[])
136 enum { encode
, decode
};
138 const codec_class
**cc
;
140 const char *indent
= "";
141 const char *imode
, *omode
, *ofile
= 0;
142 unsigned maxline
= 64;
143 unsigned f
= CDCF_IGNSPC
| CDCF_IGNNEWL
;
146 FILE *ifp
, *ofp
= stdout
;
153 #define f_bogus 32768u
158 static const struct option opts
[] = {
159 { "help", 0, 0, 'h' },
160 { "version", 0, 0, 'v' },
161 { "usage", 0, 0, 'u' },
162 { "encode", 0, 0, 'e' },
163 { "decode", 0, 0, 'd' },
164 { "indent", OPTF_ARGREQ
, 0, 'i' },
165 { "maxline", OPTF_ARGREQ
, 0, 'm' },
166 { "output", OPTF_ARGREQ
, 0, 'o' },
167 { "flags", OPTF_ARGREQ
, 0, 'f' },
171 if ((i
= mdwopt(argc
, argv
, "hvu" "edf:i:m:o:", opts
, 0, 0, 0)) < 0)
174 case 'h': help(stdout
); exit(0);
175 case 'v': version(stdout
); exit(0);
176 case 'u': usage(stdout
); exit(0);
178 case 'e': mode
= encode
; break;
179 case 'd': mode
= decode
; break;
180 case 'i': indent
= optarg
; break;
181 case 'o': ofile
= optarg
; break;
185 maxline
= strtoul(optarg
, &q
, 0);
186 if (*q
|| errno
) die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
192 if (*p
== '-') { sense
= 0; p
++; }
193 else if (*p
== '+') { sense
= 1; p
++; }
196 for (i
= 0; flagtab
[i
].name
; i
++) {
197 if (strlen(flagtab
[i
].name
) == n
&&
198 strncmp(flagtab
[i
].name
, p
, n
) == 0)
201 die(EXIT_FAILURE
, "unknown flag `%.*s'", (int)n
, p
);
203 if (sense
) f
|= flagtab
[i
].f
;
204 else f
&= ~flagtab
[i
].f
;
210 default: f
|= f_bogus
; break;
213 argv
+= optind
; argc
-= optind
;
214 if ((f
& f_bogus
) || !argc
) { usage(stderr
); exit(EXIT_FAILURE
); }
216 for (cc
= cctab
;; cc
++) {
217 if (!*cc
) die(EXIT_FAILURE
, "unknown codec `%s'", *argv
);
218 else if (strcmp(*argv
, (*cc
)->name
) == 0) break;
225 for (p
= indent
;; p
++) {
230 case 'a': DPUTC(&d
, '\n'); break;
231 case 'b': DPUTC(&d
, '\b'); break;
232 case 'f': DPUTC(&d
, '\f'); break;
233 case 'n': DPUTC(&d
, '\n'); break;
234 case 'r': DPUTC(&d
, '\r'); break;
235 case 't': DPUTC(&d
, '\t'); break;
236 case 'v': DPUTC(&d
, '\v'); break;
237 case 0: goto done_indent
; break;
238 default: DPUTC(&d
, *p
); break;
250 c
= (*cc
)->encoder(f
, d
.buf
, maxline
);
251 imode
= "rb"; omode
= "w";
254 c
= (*cc
)->decoder(f
);
255 imode
= "r"; omode
= "wb";
261 if (ofile
&& (ofp
= fopen(ofile
, omode
)) == 0) {
262 die(EXIT_FAILURE
, "couldn't open `%s' for writing: %s",
263 ofile
, strerror(errno
));
266 if (mode
== encode
) fwrite(d
.buf
+ 1, 1, d
.len
- 1, ofp
);
268 code(c
, "<stdin>", stdin
, ofp
);
269 else for (i
= 0; i
< argc
; i
++) {
270 if (strcmp(argv
[i
], "-") == 0)
271 code(c
, "<stdin>", stdin
, ofp
);
272 else if ((ifp
= fopen(argv
[i
], imode
)) == 0) {
273 die(EXIT_FAILURE
, "couldn't open `%s' for reading: %s",
274 argv
[i
], strerror(errno
));
276 code(c
, argv
[i
], ifp
, ofp
);
281 if ((err
= c
->ops
->code(c
, 0, 0, &d
)) != 0)
282 die(EXIT_FAILURE
, "decoding error: %s", codec_strerror(err
));
283 if (mode
== encode
) DPUTC(&d
, '\n');
284 fwrite(d
.buf
, 1, d
.len
, ofp
);
285 c
->ops
->destroy(c
); DDESTROY(&d
);
287 if (ferror(ofp
) || fflush(ofp
) || fclose(ofp
)) {
288 die(EXIT_FAILURE
, "error writing to `%s': %s",
289 ofile ? ofile
: "<stdout>", strerror(errno
));
294 /*----- That's all, folks -------------------------------------------------*/