From 6ff956880b8dde199fe9ac1314e43b66e0046f71 Mon Sep 17 00:00:00 2001 From: June McEnroe Date: Sat, 10 Jun 2017 16:49:51 -0400 Subject: Move actual dotfiles into home directory --- home/.bin/xx.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 home/.bin/xx.c (limited to 'home/.bin/xx.c') diff --git a/home/.bin/xx.c b/home/.bin/xx.c new file mode 100755 index 00000000..269c9d55 --- /dev/null +++ b/home/.bin/xx.c @@ -0,0 +1,116 @@ +#if 0 +exec cc -Wall -Wextra -pedantic $@ -o $(dirname $0)/xx $0 +#endif + +// Hexdump. + +#include +#include +#include +#include +#include +#include +#include +#include + +static bool allZero(const uint8_t *buf, size_t len) { + for (size_t i = 0; i < len; ++i) + if (buf[i]) return false; + return true; +} + +enum { + FLAG_ASCII = 1, + FLAG_OFFSET = 2, + FLAG_SKIP = 4, + FLAG_UNDUMP = 8, +}; + +void dump(size_t cols, size_t group, uint8_t flags, FILE *file) { + uint8_t buf[cols]; + size_t offset = 0, len = 0; + for (;;) { + offset += len; + len = fread(buf, 1, sizeof(buf), file); + if (!len) break; + + if ((flags & FLAG_SKIP) && len == sizeof(buf)) { + static bool skip; + if (allZero(buf, len)) { + if (!skip) printf("*\n"); + skip = true; + continue; + } + skip = false; + } + + if (flags & FLAG_OFFSET) { + printf("%08zx: ", offset); + } + + for (size_t i = 0; i < len; ++i) { + if (group && i && !(i % group)) printf(" "); + printf("%02x ", buf[i]); + } + + if (flags & FLAG_ASCII) { + for (size_t i = len; i < cols; ++i) { + printf((group && !(i % group)) ? " " : " "); + } + printf(" "); + for (size_t i = 0; i < len; ++i) { + printf("%c", isprint(buf[i]) ? buf[i] : '.'); + } + } + + printf("\n"); + if (len < sizeof(buf)) break; + } +} + +void undump(FILE *file) { + uint8_t byte; + int match; + while (1 == (match = fscanf(file, " %hhx", &byte))) { + printf("%c", byte); + } + if (match == 0) errx(EX_DATAERR, "invalid input"); +} + +int main(int argc, char *argv[]) { + size_t cols = 16; + size_t group = 8; + uint8_t flags = FLAG_ASCII | FLAG_OFFSET; + char *path = NULL; + + int opt; + while (0 < (opt = getopt(argc, argv, "ac:fg:hku"))) { + switch (opt) { + case 'a': flags ^= FLAG_ASCII; break; + case 'f': flags ^= FLAG_OFFSET; break; + case 'k': flags ^= FLAG_SKIP; break; + case 'u': flags ^= FLAG_UNDUMP; break; + case 'c': cols = strtoul(optarg, NULL, 10); break; + case 'g': group = strtoul(optarg, NULL, 10); break; + default: + fprintf(stderr, "usage: xx [-afku] [-c cols] [-g group] [file]\n"); + return (opt == 'h') ? EX_OK : EX_USAGE; + } + } + if (!cols) return EX_USAGE; + if (argc > optind) { + path = argv[optind]; + } + + FILE *file = path ? fopen(path, "r") : stdin; + if (!file) err(EX_NOINPUT, "%s", path); + + if (flags & FLAG_UNDUMP) { + undump(file); + } else { + dump(cols, group, flags, file); + } + + if (ferror(file)) err(EX_IOERR, "%s", path); + return EX_OK; +} -- cgit 1.4.1