summaryrefslogtreecommitdiff
path: root/cli.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli.c')
-rw-r--r--cli.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/cli.c b/cli.c
new file mode 100644
index 0000000..f365991
--- /dev/null
+++ b/cli.c
@@ -0,0 +1,294 @@
+/*
+ * basE91 command line front-end
+ *
+ * Copyright (c) 2000-2006 Joachim Henke
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Joachim Henke nor the names of his contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+#include <getopt.h>
+#include "base91.h"
+
+#define FLG_D 1
+#define FLG_V 2
+#define FLG_VV 4
+
+static char status[32];
+static const char *progname;
+static char *ibuf, *obuf;
+static size_t ibuf_size, llen;
+static struct basE91 b91;
+
+static void stream_b91enc_p(void)
+{
+ size_t itotal = 0;
+ size_t ototal = 0;
+ size_t s;
+
+ while ((s = fread(ibuf, 1, ibuf_size, stdin)) > 0) {
+ itotal += s;
+ s = basE91_encode(&b91, ibuf, s, obuf);
+ ototal += s;
+ fwrite(obuf, 1, s, stdout);
+ }
+ s = basE91_encode_end(&b91, obuf); /* empty bit queue */
+ ototal += s;
+ fwrite(obuf, 1, s, stdout);
+
+ sprintf(status, "\t%.2f%%\n", itotal ? (float) ototal / itotal * 100.0 : 1.0);
+}
+
+static void stream_b91enc_w(void)
+{
+ size_t l = llen;
+ size_t ltotal = 0;
+ size_t i, s;
+ char x;
+
+ while ((s = fread(ibuf, 1, ibuf_size, stdin)) > 0) {
+ s = basE91_encode(&b91, ibuf, s, obuf);
+ for (i = 0; l <= s; l += llen) {
+ x = obuf[l];
+ obuf[l] = '\0';
+ puts(obuf + i);
+ ++ltotal;
+ obuf[l] = x;
+ i = l;
+ }
+ fwrite(obuf + i, 1, s - i, stdout);
+ l -= s;
+ }
+ s = basE91_encode_end(&b91, obuf);
+ if (s || l < llen) {
+ obuf[s] = '\0';
+ if (s > l) {
+ x = obuf[1];
+ obuf[1] = '\0';
+ puts(obuf);
+ ++ltotal;
+ obuf[0] = x;
+ }
+ puts(obuf);
+ ++ltotal;
+ }
+
+ sprintf(status, "\t%lu lines\n", (unsigned long) ltotal);
+}
+
+static void stream_b91dec(void)
+{
+ size_t s;
+
+ while ((s = fread(ibuf, 1, ibuf_size, stdin)) > 0) {
+ s = basE91_decode(&b91, ibuf, s, obuf);
+ fwrite(obuf, 1, s, stdout);
+ }
+ s = basE91_decode_end(&b91, obuf); /* empty bit queue */
+ fwrite(obuf, 1, s, stdout);
+
+ sprintf(status, "done\n");
+}
+
+static int init_flags(const char *p)
+{
+ size_t l = strlen(p);
+
+ if (l > 5) {
+ progname = p + l - 6;
+ if (!strcmp(progname, "b91enc"))
+ return 0;
+ if (!strcmp(progname, "b91dec"))
+ return FLG_D;
+ }
+ llen = 76;
+ progname = "base91";
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ size_t buf_size = 65536; /* buffer memory defaults to 64 KiB */
+ int flags = init_flags(*argv);
+ char *ifile = "from standard input";
+ char *ofile = NULL;
+ int opt;
+ struct option longopts[8] = {
+ {"decode", no_argument, NULL, 'd'},
+ {"output", required_argument, NULL, 'o'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"wrap", required_argument, NULL, 'w'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while ((opt = getopt_long(argc, argv, "dem:o:vw:hV", longopts, NULL)) != -1)
+ switch (opt) {
+ case 'd':
+ flags |= FLG_D;
+ break;
+ case 'e':
+ flags &= ~FLG_D;
+ break;
+ case 'm':
+ {
+ char *t;
+ long l = strtol(optarg, &t, 0);
+
+ if (t == optarg || strlen(t) > 1 || l < 0) {
+ fprintf(stderr, "invalid SIZE argument: `%s'\n", optarg);
+ return EXIT_FAILURE;
+ }
+ buf_size = l;
+ switch (*t | 32) {
+ case ' ':
+ case 'b':
+ break;
+ case 'k':
+ buf_size <<= 10;
+ break;
+ case 'm':
+ buf_size <<= 20;
+ break;
+ default:
+ fprintf(stderr, "invalid SIZE suffix: `%s'\n", t);
+ return EXIT_FAILURE;
+ }
+ }
+ break;
+ case 'o':
+ if (strcmp(optarg, "-"))
+ ofile = optarg;
+ break;
+ case 'v':
+ flags |= (flags & FLG_V) ? FLG_VV : FLG_V;
+ break;
+ case 'w':
+ {
+ char *t;
+ long l = strtol(optarg, &t, 0);
+
+ if (*t || l < 0) {
+ fprintf(stderr, "invalid number of columns: `%s'\n", optarg);
+ return EXIT_FAILURE;
+ }
+ llen = l;
+ }
+ break;
+ case 'h':
+ printf("Usage: %s [OPTION]... [FILE]\n"
+ "basE91 encode or decode FILE, or standard input, to standard output.\n", progname);
+ puts("\n -d, --decode\t\tdecode data\n"
+ " -m SIZE\t\tuse SIZE bytes of memory for buffers (suffixes b, K, M)\n"
+ " -o, --output=FILE\twrite to FILE instead of standard output\n"
+ " -v, --verbose\t\tverbose mode\n"
+ " -w, --wrap=COLS\twrap encoded lines after COLS characters (default 76)\n"
+ " --help\t\tdisplay this help and exit\n"
+ " --version\t\toutput version information and exit\n\n"
+ "With no FILE, or when FILE is -, read standard input.");
+ return EXIT_SUCCESS;
+ case 'V':
+ printf("%s 0.6.0\nCopyright (c) 2000-2006 Joachim Henke\n", progname);
+ return EXIT_SUCCESS;
+ default:
+ fprintf(stderr, "Try `%s --help' for more information.\n", *argv);
+ return EXIT_FAILURE;
+ }
+
+ if (flags & FLG_D) {
+ ibuf_size = (buf_size - 1) << 3;
+ if (ibuf_size < 15) {
+ fputs("SIZE must be >= 3 for decoding\n", stderr);
+ return EXIT_FAILURE;
+ }
+ ibuf_size /= 15;
+ } else {
+ ibuf_size = (buf_size - 2) << 4;
+ if (ibuf_size < 29) {
+ fputs("SIZE must be >= 4 for encoding\n", stderr);
+ return EXIT_FAILURE;
+ }
+ ibuf_size /= 29;
+ }
+
+ if (optind < argc && strcmp(argv[optind], "-")) {
+ ifile = argv[optind];
+ if (freopen(ifile, "r", stdin) != stdin) {
+ perror(ifile);
+ return EXIT_FAILURE;
+ }
+ }
+ if (ofile)
+ if (freopen(ofile, "w", stdout) != stdout) {
+ perror(ofile);
+ return EXIT_FAILURE;
+ }
+
+ if (flags & FLG_VV)
+ fprintf(stderr, "using %lu bytes for buffers; input buffer: %lu bytes\n", (unsigned long) buf_size, (unsigned long) ibuf_size);
+ obuf = malloc(buf_size);
+ if (!obuf) {
+ fputs("failed to allocate buffer memory\n", stderr);
+ return EXIT_FAILURE;
+ }
+
+ basE91_init(&b91);
+#ifdef _WIN32
+ _setmode(_fileno(stdin), _O_BINARY);
+#endif
+
+ if (flags & FLG_D) {
+#ifdef _WIN32
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ ibuf = obuf + 1; /* create overlapping buffers to use memory efficiently */
+ if (flags & FLG_V)
+ fprintf(stderr, "decoding %s ...", ifile);
+ stream_b91dec();
+ } else {
+ ibuf = obuf + buf_size - ibuf_size; /* partial overlap */
+ if (flags & FLG_V)
+ fprintf(stderr, "encoding %s ...", ifile);
+ if (llen)
+ stream_b91enc_w();
+ else
+ stream_b91enc_p();
+ }
+ free(obuf);
+
+ if (flags & FLG_V)
+ fputs(status, stderr);
+
+ return EXIT_SUCCESS;
+}