8163451249
Yeah, kinda embarassing. Forgot about that.
164 lines
3.3 KiB
C
164 lines
3.3 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "util.h"
|
|
|
|
static size_t bytes_per_line = 16;
|
|
static off_t maxbytes = -1;
|
|
static off_t skip = 0;
|
|
static unsigned char radix = 'o';
|
|
static unsigned char type = 'o';
|
|
|
|
static void
|
|
printaddress(FILE *f, off_t addr)
|
|
{
|
|
char fmt[] = "%07j# ";
|
|
|
|
if (radix == 'n') {
|
|
fputc(' ', f);
|
|
} else {
|
|
fmt[4] = radix;
|
|
fprintf(f, fmt, (intmax_t)addr);
|
|
}
|
|
}
|
|
|
|
static void
|
|
printchar(FILE *f, unsigned char c)
|
|
{
|
|
const char *namedict[] = {
|
|
"nul", "soh", "stx", "etx", "eot", "enq", "ack",
|
|
"bel", "bs", "ht", "nl", "vt", "ff", "cr",
|
|
"so", "si", "dle", "dc1", "dc2", "dc3", "dc4",
|
|
"nak", "syn", "etb", "can", "em", "sub", "esc",
|
|
"fs", "gs", "rs", "us", "sp",
|
|
};
|
|
const char *escdict[] = {
|
|
['\0'] = "\\0", ['\a'] = "\\a",
|
|
['\b'] = "\\b", ['\t'] = "\\t",
|
|
['\n'] = "\\n", ['\v'] = "\\v",
|
|
['\f'] = "\\f", ['\r'] = "\\r",
|
|
};
|
|
const char *fmtdict[] = {
|
|
['d'] = "%4hhd ", ['o'] = "%03hho ",
|
|
['u'] = "%3hhu ", ['x'] = "%02hhx ",
|
|
};
|
|
|
|
switch (type) {
|
|
case 'a':
|
|
c &= ~128; /* clear high bit as required by standard */
|
|
if (c < LEN(namedict) || c == 127) {
|
|
fprintf(f, "%3s ", (c == 127) ? "del" : namedict[c]);
|
|
} else {
|
|
fprintf(f, "%3c ", c);
|
|
}
|
|
break;
|
|
case 'c':
|
|
if (strchr("\a\b\t\n\b\f\r\0", c)) {
|
|
fprintf(f, "%3s ", escdict[c]);
|
|
} else {
|
|
fprintf(f, "%3c ", c);
|
|
}
|
|
break;
|
|
default:
|
|
fprintf(f, fmtdict[type], c);
|
|
}
|
|
}
|
|
|
|
static void
|
|
od(FILE *in, char *in_name, FILE *out, char *out_name)
|
|
{
|
|
off_t addr;
|
|
size_t i, chunklen;
|
|
unsigned char buf[BUFSIZ];
|
|
|
|
for (addr = 0; (chunklen = fread(buf, 1, BUFSIZ, in)); ) {
|
|
for (i = 0; i < chunklen && (maxbytes == -1 ||
|
|
(addr - skip) < maxbytes); ++i, ++addr) {
|
|
if (addr - skip < 0)
|
|
continue;
|
|
if (((addr - skip) % bytes_per_line) == 0) {
|
|
if (addr - skip)
|
|
fputc('\n', out);
|
|
printaddress(out, addr);
|
|
}
|
|
printchar(out, buf[i]);
|
|
}
|
|
if (feof(in) || ferror(in) || ferror(out))
|
|
break;
|
|
}
|
|
if (addr)
|
|
fputc('\n', out);
|
|
if (radix != 'n') {
|
|
printaddress(out, addr);
|
|
fputc('\n', out);
|
|
}
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
eprintf("usage: %s [-A d|o|x|n] [-t a|c|d|o|u|x] [-v] [file ...]\n", argv0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
FILE *fp;
|
|
int ret = 0;
|
|
char *s;
|
|
|
|
ARGBEGIN {
|
|
case 'A':
|
|
s = EARGF(usage());
|
|
if (strlen(s) != 1 || !strchr("doxn", s[0]))
|
|
usage();
|
|
radix = s[0];
|
|
break;
|
|
case 'j':
|
|
if ((skip = parseoffset(EARGF(usage()))) < 0)
|
|
return 1;
|
|
break;
|
|
case 'N':
|
|
if ((maxbytes = parseoffset(EARGF(usage()))) < 0)
|
|
return 1;
|
|
break;
|
|
case 't':
|
|
s = EARGF(usage());
|
|
if (strlen(s) != 1 || !strchr("acdoux", s[0]))
|
|
usage();
|
|
type = s[0];
|
|
break;
|
|
case 'v':
|
|
/* Always set. Use "uniq -f 1 -c" to handle duplicate lines. */
|
|
break;
|
|
default:
|
|
usage();
|
|
} ARGEND;
|
|
|
|
if (!argc) {
|
|
od(stdin, "<stdin>", stdout, "<stdout>");
|
|
} else {
|
|
for (; *argv; argc--, argv++) {
|
|
if (!strcmp(*argv, "-")) {
|
|
*argv = "<stdin>";
|
|
fp = stdin;
|
|
} else if (!(fp = fopen(*argv, "r"))) {
|
|
weprintf("fopen %s:", *argv);
|
|
ret = 1;
|
|
continue;
|
|
}
|
|
od(fp, *argv, stdout, "<stdout>");
|
|
if (fp != stdin && fshut(fp, *argv))
|
|
ret = 1;
|
|
}
|
|
}
|
|
|
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") |
|
|
fshut(stderr, "<stderr>");
|
|
|
|
return ret;
|
|
}
|