/*
 * Hex dump utility
 */

#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define BLOCK_SIZE 1024

char digits[] = "0123456789abcdef";

void
print_int(int n)
{
    char buf[9];
    int i;

    for (i = 7; i >= 0; --i) {
	buf[i] = digits[(n & 0xf)];
	n >>= 4;
    }
    buf[8] = '\0';
    fputs(buf, stdout);
}

void
print_long(long n)
{
    print_int(n);
}

void
print_short(short n)
{
    char buf[5];
    int i;

    for (i = 3; i >= 0; --i) {
	buf[i] = digits[(n & 0xf)];
	n >>= 4;
    }
    buf[4] = '\0';
    fputs(buf, stdout);
}

void
print_block(long n)
{
    long block = n / BLOCK_SIZE;
    short pos = (short) (n % BLOCK_SIZE);
    print_long(block);
    fputs(".", stdout);
    print_short(pos);
}

void
print_char(char c)
{
    char buf[3];

    buf[2] = 0;
    buf[1] = digits[(c & 0xf)];
    c >>= 4;
    buf[0] = digits[(c & 0xf)];

    fputs(buf, stdout);
}

void
hex_dump(int fd)
{
    unsigned long pos = 0;
    char buf[16];
    int cb;

    while ((cb = read(fd, buf, sizeof(buf))) > 0) {
	int i;

	print_block(pos);
	fputs(": ", stdout);

	i = 0;
	while (i < cb) {
	    print_char(buf[i]);
	    if (i % 2) fputc(' ', stdout);
	    ++i;
	}

	while (i < 16) {
	    fputs("  ", stdout);
	    if (i % 2) fputc(' ', stdout);
	    ++i;
	}

	fputc(' ', stdout);

	i = 0;
	while (i < cb) {
	    fputc(isprint(buf[i]) ? buf[i] : '.', stdout);
	    ++i;
	}

	while (i < 16) {
	    fputc(' ', stdout);
	    ++i;
	}

	fputc('\n', stdout);
	pos += 16;
    }
}


int
main(int argc, char* argv[])
{
    int i;

    for (i = 1; i < argc; ++i) {
	int fd;

	if (strcmp(argv[i], "-") == 0) {
	    fd = STDIN_FILENO;
	} else {
	    if ((fd = open(argv[i], O_RDONLY)) < 0) {
		perror(argv[1]);
		exit(1);
	    }
	}

	hex_dump(fd);
	close(fd);
    }
}

