---
Makefile | 3 +
README | 3 +
base16.1 | 40 ++++++++++++
base16.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++
base32.1 | 40 ++++++++++++
base32.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
base64.1 | 40 ++++++++++++
base64.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 706 insertions(+)
create mode 100644 base16.1
create mode 100644 base16.c
create mode 100644 base32.1
create mode 100644 base32.c
create mode 100644 base64.1
create mode 100644 base64.c
diff --git a/Makefile b/Makefile
index 6b2bfdf..9600639 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -84,6 +84,9 @@ LIBUTILSRC =\
LIB = $(LIBUTF) $(LIBUTIL)
BIN =\
+ base16\
+ base32\
+ base64\
basename\
cal\
cat\
diff --git a/README b/README
index d60d8fc..ebc20a4 100644
--- a/README
+++ b/README
_AT_@ -12,6 +12,9 @@ The following tools are implemented:
UTILITY MISSING
------- -------
+0=* x base16 .
+0=* x base32 .
+0=* x base64 .
0=*|o basename .
0=*|o cal .
0=*|o cat .
diff --git a/base16.1 b/base16.1
new file mode 100644
index 0000000..2debf6a
--- /dev/null
+++ b/base16.1
_AT_@ -0,0 +1,40 @@
+.Dd 2016-03-29
+.Dt BASE16 1
+.Os sbase
+.Sh NAME
+.Nm base16
+.Nd encode data in or decode data from base16
+.Sh SYNOPSIS
+.Nm
+.Op Fl di
+.Op Fl w Ar cols
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+read the
+.Ar file
+in either encode the file in base16 (default)
+or decode it from base16
+.Op Fl d .
+If no
+.Ar file
+is given
+.Nm
+reads from stdin.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl d
+Decode instead of encode.
+.It Fl i
+Ignore garbage if decode. <newline> is always ignored.
+.It Fl w Ar cols
+Wrap the output at
+.Ar cols
+columns (default 76). If
+.Ar cols
+is zero, do not wrap.
+.El
+.Sh STANDARDS
+The output of the
+.Nm
+utility is compliant with the RFC 4648 specification.
diff --git a/base16.c b/base16.c
new file mode 100644
index 0000000..9940a02
--- /dev/null
+++ b/base16.c
_AT_@ -0,0 +1,168 @@
+/* See LICENSE file for copyright and license details. */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+#define ALPHABET "0123456789ABCDEF"
+#define ALTALPHABET "0123456789ABCDEF"
+
+static unsigned char lut[256] =
+ ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET
+ ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET;
+static int iflag = 0;
+static size_t cols;
+static size_t pos = 0;
+static size_t (*output)(const void *restrict, size_t, size_t, FILE *);
+
+static size_t
+wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream)
+{
+ const char *restrict buf = ptr;
+ size_t n = cols - pos;
+
+ if (nitems >= n) {
+ fwrite(buf, 1, n, stream);
+ nitems -= n;
+ buf += n;
+ pos = 0;
+ fputc('\n', stdout);
+ }
+
+ while (nitems >= cols) {
+ fwrite(buf, 1, cols, stream);
+ nitems -= cols;
+ buf += cols;
+ fputc('\n', stdout);
+ }
+
+ if (nitems) {
+ fwrite(buf, 1, nitems, stream);
+ pos = nitems;
+ }
+
+ (void) size;
+ return 0;
+}
+
+static void
+encode(FILE *fp)
+{
+ unsigned char ibuf[BUFSIZ / 2];
+ unsigned char obuf[sizeof(ibuf) * 2];
+ register unsigned char *p, *out;
+ unsigned char *pend;
+ size_t n;
+
+ while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) {
+ out = obuf;
+ for (p = ibuf, pend = p + n; p != pend; p += 1, out += 2) {
+ out[0] = lut[*p >> 4];
+ out[1] = lut[*p];
+ }
+ output(obuf, 1, n << 1, stdout);
+ }
+
+ if (pos)
+ fputc('\n', stdout);
+}
+
+static void
+decode(FILE *fp)
+{
+ unsigned char ibuf[BUFSIZ / 2];
+ unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 2)];
+ unsigned char jbuf[2];
+ unsigned char value;
+ size_t i, j = 0, n, o = 0;
+ register unsigned char *p;
+
+ memset(lut, ~0, sizeof(lut));
+ for (i = 0; i < 16; i++) {
+ lut[(int)(ALPHABET[i])] = i;
+ lut[(int)(ALTALPHABET[i])] = i;
+ }
+
+ while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) {
+ for (p = ibuf; n--; p++) {
+ value = lut[*p];
+ if (value == 0xFF) {
+ if (*p == '\n')
+ continue;
+ else if (iflag)
+ continue;
+ else
+ eprintf("invalid input\n");
+ }
+ jbuf[j++] = value;
+ if (j == 2) {
+ j = 0;
+ obuf[o++] = (jbuf[0] << 4) | jbuf[1];
+ if (o == sizeof(obuf)) {
+ fwrite(obuf, 1, o, stdout);
+ o = 0;
+ }
+ }
+ }
+ }
+ if (j && feof(fp))
+ eprintf("invalid input\n");
+ if (o)
+ fwrite(obuf, 1, o, stdout);
+}
+
+static void
+usage(void)
+{
+ /* Logically, it should be [-d [-i] | -w col], but
+ * for consistency we let it be [-di] [-w col]. */
+
+ eprintf("usage: %s [-di] [-w col] [file]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int dflag = 0;
+ long wflag = -1;
+ FILE *fp = stdin;
+ char *path = "<stdin>";
+
+ ARGBEGIN {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'w':
+ wflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (argc > 1)
+ usage();
+
+ if (argc && strcmp(*argv, "-")) {
+ path = *argv;
+ if (!(fp = fopen(*argv, "r")))
+ eprintf("fopen %s:", *argv);
+ }
+
+ if (wflag == 0) {
+ output = &fwrite;
+ pos = 1;
+ } else {
+ output = &wrapwrite;
+ cols = wflag > 0 ? wflag : 76;
+ }
+
+ (dflag ? decode : encode)(fp);
+ return fshut(fp, path) || fshut(stdout, "<stdout>");
+}
diff --git a/base32.1 b/base32.1
new file mode 100644
index 0000000..51a279a
--- /dev/null
+++ b/base32.1
_AT_@ -0,0 +1,40 @@
+.Dd 2016-03-29
+.Dt BASE32 1
+.Os sbase
+.Sh NAME
+.Nm base32
+.Nd encode data in or decode data from base32
+.Sh SYNOPSIS
+.Nm
+.Op Fl di
+.Op Fl w Ar cols
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+read the
+.Ar file
+in either encode the file in base32 (default)
+or decode it from base32
+.Op Fl d .
+If no
+.Ar file
+is given
+.Nm
+reads from stdin.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl d
+Decode instead of encode.
+.It Fl i
+Ignore garbage if decode. <newline> is always ignored.
+.It Fl w Ar cols
+Wrap the output at
+.Ar cols
+columns (default 76). If
+.Ar cols
+is zero, do not wrap.
+.El
+.Sh STANDARDS
+The output of the
+.Nm
+utility is compliant with the RFC 4648 specification.
diff --git a/base32.c b/base32.c
new file mode 100644
index 0000000..49457e0
--- /dev/null
+++ b/base32.c
_AT_@ -0,0 +1,214 @@
+/* See LICENSE file for copyright and license details. */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
+
+static unsigned char lut[256] = ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET;
+static int iflag = 0;
+static size_t cols;
+static size_t pos = 0;
+static size_t (*output)(const void *restrict, size_t, size_t, FILE *);
+
+static size_t
+wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream)
+{
+ const char *restrict buf = ptr;
+ size_t n = cols - pos;
+
+ if (nitems >= n) {
+ fwrite(buf, 1, n, stream);
+ nitems -= n;
+ buf += n;
+ pos = 0;
+ fputc('\n', stdout);
+ }
+
+ while (nitems >= cols) {
+ fwrite(buf, 1, cols, stream);
+ nitems -= cols;
+ buf += cols;
+ fputc('\n', stdout);
+ }
+
+ if (nitems) {
+ fwrite(buf, 1, nitems, stream);
+ pos = nitems;
+ }
+
+ (void) size;
+ return 0;
+}
+
+static void
+encode(FILE *fp)
+{
+ unsigned char ibuf[(BUFSIZ / 2) - ((BUFSIZ / 2) % 5)];
+ unsigned char obuf[sizeof(ibuf) / 5 * 8];
+ register unsigned char *p, *out;
+ unsigned char *pend;
+ size_t n, o;
+
+ do {
+ for (o = 0; o < sizeof(ibuf); o += n)
+ if (!(n = fread(ibuf + o, 1, sizeof(ibuf) - o, fp)))
+ break;
+ if (!o)
+ goto end;
+ n = o;
+ o %= 5;
+ out = obuf;
+ for (p = ibuf, pend = p + n - o; p != pend; p += 5, out += 8) {
+ out[0] = lut[p[0] >> 3];
+ out[1] = lut[(unsigned char)(p[0] << 2) | (p[1] >> 6)];
+ out[2] = lut[p[1] >> 1];
+ out[3] = lut[(unsigned char)(p[1] << 4) | (p[2] >> 4)];
+ out[4] = lut[(unsigned char)(p[2] << 1) | (p[3] >> 7)];
+ out[5] = lut[p[3] >> 2];
+ out[6] = lut[(unsigned char)(p[3] << 3) | (p[4] >> 5)];
+ out[7] = lut[p[4]];
+ }
+ n = (size_t)(out - obuf);
+ output(obuf, 1, n, stdout);
+ } while (!o);
+
+ /* This part is only reached if padding is required. { */
+
+ memset(obuf, '=', 8);
+ memset(p + o, 0, 8 - o);
+ obuf[0] = lut[p[0] >> 3];
+ obuf[1] = lut[(unsigned char)(p[0] << 2) | (p[1] >> 6)];
+ if (o == 1) goto done;
+ obuf[2] = lut[p[1] >> 1];
+ obuf[3] = lut[(unsigned char)(p[1] << 4) | (p[2] >> 4)];
+ if (o == 2) goto done;
+ obuf[4] = lut[(unsigned char)(p[2] << 1) | (p[3] >> 7)];
+ if (o == 3) goto done;
+ obuf[5] = lut[p[3] >> 2];
+ obuf[6] = lut[(unsigned char)(p[3] << 3)];
+done:
+ output(obuf, 1, 8, stdout);
+
+ /* } */
+
+end:
+ if (pos)
+ fputc('\n', stdout);
+}
+
+static void
+decode(FILE *fp)
+{
+ unsigned char ibuf[BUFSIZ / 2];
+ unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 5)];
+ unsigned char jbuf[8];
+ unsigned char value;
+ size_t i, j = 0, n, o = 0, pads = 0, erasure;
+ register unsigned char *p;
+ static const int pads_to_erasure[] = {0, 1, -1, 2, 3, -1, 4, -1};
+
+ memset(lut, ~0, sizeof(lut));
+ for (i = 0; i < 32; i++)
+ lut[(int)(ALPHABET[i])] = i;
+
+ while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) {
+ for (p = ibuf; n--; p++) {
+ value = lut[*p];
+ if (value == 0xFF) {
+ if (*p == '=') {
+ if (++pads > 6)
+ eprintf("1 invalid input\n");
+ value = 0;
+ } else if (*p == '\n') {
+ continue;
+ } else if (pads) {
+ eprintf("invalid input\n");
+ } else if (iflag) {
+ continue;
+ } else {
+ eprintf("invalid input\n");
+ }
+ }
+ jbuf[j++] = value;
+ if (j == 8) {
+ j = 0;
+ obuf[o++] = (jbuf[0] << 3) | (jbuf[1] >> 2);
+ obuf[o++] = (jbuf[1] << 6) | (jbuf[2] << 1) | (jbuf[3] >> 4);
+ obuf[o++] = (jbuf[3] << 4) | (jbuf[4] >> 1);
+ obuf[o++] = (jbuf[4] << 7) | (jbuf[5] << 2) | (jbuf[6] >> 3);
+ obuf[o++] = (jbuf[6] << 5) | (jbuf[7] >> 0);
+
+ if (o == sizeof(obuf) && !pads) {
+ fwrite(obuf, 1, o, stdout);
+ o = 0;
+ }
+ }
+ }
+ }
+ if (j && feof(fp))
+ eprintf("invalid input\n");
+ if (o) {
+ erasure = pads_to_erasure[pads];
+ if (erasure < 0)
+ eprintf("invalid input\n");
+ fwrite(obuf, 1, o - erasure, stdout);
+ }
+}
+
+static void
+usage(void)
+{
+ /* Logically, it should be [-d [-i] | -w col], but
+ * for compatibility we let it be [-di] [-w col]. */
+
+ eprintf("usage: %s [-di] [-w col] [file]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int dflag = 0;
+ long wflag = -1;
+ FILE *fp = stdin;
+ char *path = "<stdin>";
+
+ ARGBEGIN {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'w':
+ wflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (argc > 1)
+ usage();
+
+ if (argc && strcmp(*argv, "-")) {
+ path = *argv;
+ if (!(fp = fopen(*argv, "r")))
+ eprintf("fopen %s:", *argv);
+ }
+
+ if (wflag == 0) {
+ output = &fwrite;
+ pos = 1;
+ } else {
+ output = &wrapwrite;
+ cols = wflag > 0 ? wflag : 76;
+ }
+
+ (dflag ? decode : encode)(fp);
+ return fshut(fp, path) || fshut(stdout, "<stdout>");
+}
diff --git a/base64.1 b/base64.1
new file mode 100644
index 0000000..d857784
--- /dev/null
+++ b/base64.1
_AT_@ -0,0 +1,40 @@
+.Dd 2016-03-29
+.Dt BASE64 1
+.Os sbase
+.Sh NAME
+.Nm base64
+.Nd encode data in or decode data from base64
+.Sh SYNOPSIS
+.Nm
+.Op Fl di
+.Op Fl w Ar cols
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+read the
+.Ar file
+in either encode the file in base64 (default)
+or decode it from base64
+.Op Fl d .
+If no
+.Ar file
+is given
+.Nm
+reads from stdin.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl d
+Decode instead of encode.
+.It Fl i
+Ignore garbage if decode. <newline> is always ignored.
+.It Fl w Ar cols
+Wrap the output at
+.Ar cols
+columns (default 76). If
+.Ar cols
+is zero, do not wrap.
+.El
+.Sh STANDARDS
+The output of the
+.Nm
+utility is compliant with the RFC 4648 specification.
diff --git a/base64.c b/base64.c
new file mode 100644
index 0000000..4dfc25b
--- /dev/null
+++ b/base64.c
_AT_@ -0,0 +1,198 @@
+/* See LICENSE file for copyright and license details. */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+static unsigned char lut[256] = ALPHABET ALPHABET ALPHABET ALPHABET;
+static int iflag = 0;
+static size_t cols;
+static size_t pos = 0;
+static size_t (*output)(const void *restrict, size_t, size_t, FILE *);
+
+static size_t
+wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream)
+{
+ const char *restrict buf = ptr;
+ size_t n = cols - pos;
+
+ if (nitems >= n) {
+ fwrite(buf, 1, n, stream);
+ nitems -= n;
+ buf += n;
+ pos = 0;
+ fputc('\n', stdout);
+ }
+
+ while (nitems >= cols) {
+ fwrite(buf, 1, cols, stream);
+ nitems -= cols;
+ buf += cols;
+ fputc('\n', stdout);
+ }
+
+ if (nitems) {
+ fwrite(buf, 1, nitems, stream);
+ pos = nitems;
+ }
+
+ (void) size;
+ return 0;
+}
+
+static void
+encode(FILE *fp)
+{
+ unsigned char ibuf[(BUFSIZ / 2) - ((BUFSIZ / 2) % 3)];
+ unsigned char obuf[sizeof(ibuf) / 3 * 4];
+ register unsigned char *p, *out;
+ unsigned char *pend;
+ size_t n, o;
+
+ do {
+ for (o = 0; o < sizeof(ibuf); o += n)
+ if (!(n = fread(ibuf + o, 1, sizeof(ibuf) - o, fp)))
+ break;
+ if (!o)
+ goto end;
+ n = o;
+ o %= 3;
+ out = obuf;
+ for (p = ibuf, pend = p + n - o; p != pend; p += 3, out += 4) {
+ out[0] = lut[p[0] >> 2];
+ out[1] = lut[(unsigned char)(p[0] << 4) | (p[1] >> 4)];
+ out[2] = lut[(unsigned char)(p[1] << 2) | (p[2] >> 6)];
+ out[3] = lut[p[2]];
+ }
+ n = (size_t)(out - obuf);
+ output(obuf, 1, n, stdout);
+ } while (!o);
+
+ /* This part is only reached if padding is required. { */
+
+ obuf[0] = lut[p[0] >> 2];
+ if (o == 1) {
+ obuf[1] = lut[(unsigned char)(p[0] << 4)];
+ obuf[2] = '=';
+ } else {
+ obuf[1] = lut[(unsigned char)(p[0] << 4) | (p[1] >> 4)];
+ obuf[2] = lut[(unsigned char)(p[1] << 2)];
+ }
+ obuf[3] = '=';
+ output(obuf, 1, 4, stdout);
+
+ /* } */
+
+end:
+ if (pos)
+ fputc('\n', stdout);
+}
+
+static void
+decode(FILE *fp)
+{
+ unsigned char ibuf[BUFSIZ / 2];
+ unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 3)];
+ unsigned char jbuf[4];
+ unsigned char value;
+ size_t i, j = 0, n, o = 0, pads = 0;
+ register unsigned char *p;
+
+ memset(lut, ~0, sizeof(lut));
+ for (i = 0; i < 64; i++)
+ lut[(int)(ALPHABET[i])] = i;
+
+ while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) {
+ for (p = ibuf; n--; p++) {
+ value = lut[*p];
+ if (value == 0xFF) {
+ if (*p == '=') {
+ if (++pads > 2)
+ eprintf("invalid input\n");
+ value = 0;
+ } else if (*p == '\n') {
+ continue;
+ } else if (pads) {
+ eprintf("invalid input\n");
+ } else if (iflag) {
+ continue;
+ } else {
+ eprintf("invalid input\n");
+ }
+ }
+ jbuf[j++] = value;
+ if (j == 4) {
+ j = 0;
+ obuf[o++] = (jbuf[0] << 2) | (jbuf[1] >> 4);
+ obuf[o++] = (jbuf[1] << 4) | (jbuf[2] >> 2);
+ obuf[o++] = (jbuf[2] << 6) | (jbuf[3] >> 0);
+ if (o == sizeof(obuf)) {
+ fwrite(obuf, 1, o - pads, stdout);
+ o = 0;
+ }
+ }
+ }
+ }
+ if (j && feof(fp))
+ eprintf("invalid input\n");
+ if (o)
+ fwrite(obuf, 1, o - pads, stdout);
+}
+
+static void
+usage(void)
+{
+ /* Logically, it should be [-d [-i] | -w col], but
+ * for compatibility we let it be [-di] [-w col]. */
+
+ eprintf("usage: %s [-di] [-w col] [file]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int dflag = 0;
+ long wflag = -1;
+ FILE *fp = stdin;
+ char *path = "<stdin>";
+
+ ARGBEGIN {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'w':
+ wflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (argc > 1)
+ usage();
+
+ if (argc && strcmp(*argv, "-")) {
+ path = *argv;
+ if (!(fp = fopen(*argv, "r")))
+ eprintf("fopen %s:", *argv);
+ }
+
+ if (wflag == 0) {
+ output = &fwrite;
+ pos = 1;
+ } else {
+ output = &wrapwrite;
+ cols = wflag > 0 ? wflag : 76;
+ }
+
+ (dflag ? decode : encode)(fp);
+ return fshut(fp, path) || fshut(stdout, "<stdout>");
+}
--
2.7.4
Received on Tue Mar 29 2016 - 18:59:24 CEST
This archive was generated by hypermail 2.3.0 : Tue Mar 29 2016 - 19:00:19 CEST