shithub: hx

ref: b1c218a33551408c615b22aa42a1327b1d8cc14a
dir: /hx.c/

View raw version
#ifdef __unix__
#ifdef __linux__
#define _GNU_SOURCE
#else
#define _DEFAULT_SOURCE
#endif
#define _FILE_OFFSET_BITS 64
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define OREAD O_RDONLY
#define nil NULL
#define exits(s) do { return (s) != nil; } while (0)
typedef size_t u64int;
#else
#include <u.h>
#include <libc.h>
#endif

enum
{
	Bufsz = 4*1024*1024,
	Linesz = 87,
};

static int section = 0, pipeit = 0;
static unsigned char *buf;
static const char b2h[] = (
	"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
	"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
	"404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
	"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
	"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
	"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
	"c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
	"e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
);

static int
hx(int fd)
{
	u64int addr;
	long sz, i;
	char s[65536], c;
	unsigned char line[16];
	int wroff, off, eof, lineoff, r;

again:
#ifdef __linux__
	readahead(fd, 0, Bufsz);
#endif

	lineoff = 0;
	off = 0;
	eof = 0;
	sz = 0;
	for (addr = 0; eof == 0;) {
		if ((sz = read(fd, buf, Bufsz)) < 1) {
			section = 0;
			break;
		}
		if (pipeit > 0)
			write(pipeit, buf, sz);

		for (i = 0; i < sz; ) {
			if (lineoff == 0) {
				s[off++] = b2h[((addr>>55) & 0x1fe)];
				s[off++] = b2h[((addr>>55) & 0x1fe)+1];
				s[off++] = b2h[((addr>>47) & 0x1fe)];
				s[off++] = b2h[((addr>>47) & 0x1fe)+1];
				s[off++] = b2h[((addr>>39) & 0x1fe)];
				s[off++] = b2h[((addr>>39) & 0x1fe)+1];
				s[off++] = b2h[((addr>>31) & 0x1fe)];
				s[off++] = b2h[((addr>>31) & 0x1fe)+1];
				s[off++] = b2h[((addr>>23) & 0x1fe)];
				s[off++] = b2h[((addr>>23) & 0x1fe)+1];
				s[off++] = b2h[((addr>>15) & 0x1fe)];
				s[off++] = b2h[((addr>>15) & 0x1fe)+1];
				s[off++] = b2h[((addr>>7) & 0x1fe)];
				s[off++] = b2h[((addr>>7) & 0x1fe)+1];
				s[off++] = b2h[((addr<<1) & 0x1fe)];
				s[off++] = b2h[((addr<<1) & 0x1fe)+1];
				s[off++] = ' ';
				s[off++] = ' ';
			}

			for (; i < sz && lineoff < 16; i++, addr++) {
				if (lineoff < 16)
					line[lineoff++] = buf[i];
				s[off++] = b2h[(int)buf[i]*2+0];
				s[off++] = b2h[(int)buf[i]*2+1];
				s[off++] = ' ';
				if (lineoff == 8)
					s[off++] = ' ';
			}

			if (lineoff == 16) {
ascii:
				s[off++] = ' ';
				s[off++] = '|';
				for (lineoff = 0; lineoff < 16; lineoff++) {
					c = line[lineoff];
					if (c < 0x20 || c > 0x7e)
						c = '.';
					s[off++] = c;
				}
				s[off++] = '|';
				s[off++] = '\n';
				lineoff = 0;
			}

			if (off >= (int)sizeof(s)-Linesz) {
writes:
				for (wroff = 0; wroff < off; wroff += r) {
					if ((r = write(pipeit+1, s+wroff, off-wroff)) < 0) {
						sz = -1;
						break;
					}
				}
				off = 0;
			}
		}
		if (section)
			break;
		if (sz == 0)
			continue;

#ifdef __linux__
		readahead(fd, addr, Bufsz);
#endif
		sz = 0;
		goto writes;
	}

	if (sz >= 0) {
		if (eof == 0 && lineoff > 0 && lineoff < 16) {
			eof = 1;
			if (lineoff == 8) {
				off--;
				if (off < 0)
					off = 0;
			}
			for (; lineoff < 16; lineoff++) {
				line[lineoff] = 0;
				s[off++] = ' ';
				s[off++] = ' ';
				s[off++] = ' ';
				if (lineoff == 8)
					s[off++] = ' ';
			}
			i = sz = 0;
			goto ascii;
		}
		for (wroff = 0; wroff < off; wroff += r) {
			if ((r = write(pipeit+1, s+wroff, off-wroff)) < 0) {
				sz = -1;
				break;
			}
		}
	}

	if (section) {
		write(pipeit+1, "\n", 1);
		goto again;
	}

	return sz != 0;
}

#ifdef __unix__
int
#else
void
#endif
main(int argc, char **argv)
{
	int i, fd, res, opts;

	if ((buf = malloc(Bufsz)) == nil) {
		perror("buf");
		exits("buf");
	}

	res = 0;
	opts = 0;
	for (i = 1; i < argc && res == 0; i++) {
		if (argv[i][0] == '-' && argv[i][2] == 0) {
			switch (argv[i][1]) {
			case 's':
				section = 1;
				opts++;
				break;
			case 'p':
				pipeit = 1;
				opts++;
				break;
			default:
				write(2, "unknown option: -", 17);
				write(2, argv[i]+1, 1);
				write(2, "\n", 1);
				exits("usage");
			}
			if (opts == argc-1) {
				fd = 0;
				goto dump;
			}
			continue;
		}
		if ((fd = open(argv[i], OREAD)) < 0) {
			perror(argv[i]);
			res = 1;
		} else {
			if (argc > 2+opts) {
				write(pipeit+1, "hx ", 3);
				write(pipeit+1, argv[i], strlen(argv[i]));
				write(pipeit+1, "\n", 1);
			}
dump:
			if ((res = hx(fd)) != 0)
				perror(argv[1]);
			close(fd);
		}
	}

	memset(buf, 0, Bufsz);
	free(buf);

	exits(res == 0 ? nil : "error");
}