#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>


#define	BUFFER	4096


static int do_open(const char *name)
{
	int fd;

	fd = open(name, O_RDONLY);
	if (fd >= 0)
		return fd;

	perror(name);
	exit(1);
}


static void usage(const char *name)
{
	fprintf(stderr,
"usage: %s [-w|-l] [-B] file1 file2\n"
"  -w  compare words (16 bits; default is bytes)\n"
"  -l  compare long words (32 bits; default is bytes)\n"
"  -B  use big-endian (default: little-endian)\n"
    , name);
	exit(1);
}


int main(int argc, char *const *argv)
{
	int little = 1;
	int bytes = 1;
	int c;
	int fd1, fd2;
	const char *name1, *name2;
	uint8_t buf1[BUFFER], buf2[BUFFER];
	ssize_t got1, got2, len;
	uint32_t a, b;
	int i, j;
	static unsigned bin[32][2];

	while ((c = getopt(argc, argv, "Blw")) != EOF) {
		switch (c) {
		case 'B':
			little = 0;
			break;
		case 'l':
			bytes = 4;
			break;
		case 'w':
			bytes = 2;
			break;
		default:
			usage(*argv);
		}
	}
	if (argc-optind != 2)
		usage(*argv);

	name1 = argv[optind];
	name2 = argv[optind+1];

	fd1 = do_open(name1);
	fd2 = do_open(name2);

	while (1) {
		memset(buf1, 0, BUFFER);
		memset(buf2, 0, BUFFER);
		got1 = read(fd1, buf1, BUFFER);
		if (got1 < 0) {
			perror(name1);
			return 1;
		}
		got2 = read(fd2, buf2, BUFFER);
		if (got2 < 0) {
			perror(name2);
			return 1;
		}
		if (got1 != got2)
			fprintf(stderr, "%s < %s\n",
			    got1 < got2 ? name1 : name2,
			    got1 < got2 ? name2 : name1);
		len = got1 < got2 ? got1 : got2;
		if (!len)
			break;
		for (i = 0; i < len; i += bytes) {
			a = b = 0;
			switch (bytes) {
			case 4:
				a |= buf1[i+2] << 16;
				b |= buf2[i+2] << 16;
				a |= buf1[i+3] << 24;
				b |= buf2[i+3] << 24;
				/* fall through */
			case 2:
				a |= buf1[i+1] << 8;
				b |= buf2[i+1] << 8;
				/* fall through */
			case 1:
				a |= buf1[i];
				b |= buf2[i];
				break;
			default:
				abort();
			}
			for (j = 0; j != 32; j++)
				if ((a ^ b) & (1 << j))
					bin[j][(b >> j) & 1]++;
		}
	}

	for (j = 0; j != 8*bytes; j++) {
		if (little)
			i = j;
		else
			i = 8*(bytes-1-(j >> 3))+(j & 7);
		if (bin[i][0] || bin[i][1])
			printf("%2d: %u %u\n", j, bin[i][0], bin[i][1]);
	}
	return 0;
}
