/*
 * Copyright (c) 2016-2017 Satlab Aps <satlab@satlab.com>
 * All rights reserved. Do not distribute without permission.
 */

#include <util/hexdump.h>

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>

/* Based on public domain code written by Paul Edwards */
int hexdump_printfunc(const void *data, size_t size, hexdump_printfunc_t func, void *arg)
{
	char c;
	int i, posb = 0, posc = 0, posn = 0;
	char line[80];
	const char *cdata = data;

	for (i = 0; i < size; i++) {
		/* Read data byte */
		c = (char)cdata[i];

		/* Start of line */
		if (!(posn % 16) || !i) {
			memset(line, ' ', sizeof(line));
			sprintf(line, "%06x  ", i);
			posb = 8 + (3 * posn);
			posc = 58 + posn;
		}

		/* Print byte */
		sprintf(line + posb, "%02x ", c);

		/* Print ASCII */
		sprintf(line + posc, "%c", isprint(c) ? c : '.');
		
		/* Set next byte/char position */
		posb += 3;
		posc++;

		/* Clear \0 after last byte */
		*(line + posb) = ' ';

		/* Create group for every 8 bytes */
		if (posn % 8 == 7)
			*(line + posb++) = ' ';

		/* End of line */
		if (posn % 16 == 15 || i + 1 == size) {
			line[sizeof(line) - 1] = '\0';
			func(line, arg);
			posn = 0;
		} else {
			posn++;
		}
	}

	return 0;
}

static void hexdump_printf(const char *str, void *arg)
{
	printf("%s\n", str);
}

int hexdump(const void *data, size_t size)
{
	return hexdump_printfunc(data, size, hexdump_printf, NULL);
}
