hexdiff

Highlighted diff for binary files
git clone https://git.sinitax.com/sinitax/hexdiff
Log | Files | Refs | LICENSE | sfeed.txt

hexdiff.c (2760B)


      1#include <err.h>
      2#include <stdio.h>
      3#include <string.h>
      4#include <stdint.h>
      5#include <stdbool.h>
      6#include <stdlib.h>
      7
      8struct file {
      9	const char *fname;
     10	FILE *file;
     11	uint8_t buf[16];
     12	size_t buflen;
     13};
     14
     15static const int equal_gradient[256] = {
     16	[0] = 241,
     17	[1 ... 31] = 242,
     18	[32 ... 63] = 244,
     19	[64 ... 95] = 246,
     20	[96 ... 127] = 247,
     21	[128 ... 159] = 248,
     22	[160 ... 191] = 250,
     23	[192 ... 223] = 252,
     24	[224 ... 254] = 254,
     25	[255] = 255,
     26};
     27
     28static const int diff_gradient[256] = {
     29	[0] = 52,
     30	[1 ... 95] = 88,
     31	[96 ... 159] = 124,
     32	[160 ... 223] = 160,
     33	[224 ... 255] = 196,
     34};
     35
     36static bool has_color = false;
     37
     38static bool use_color = true;
     39static bool show_all = true;
     40static bool only_diff = false;
     41
     42static inline void
     43color_byte(struct file *cur, struct file *other, size_t i)
     44{
     45	if (i >= other->buflen || cur->buf[i] != other->buf[i])
     46		printf("\x1b[38:5:%um", diff_gradient[cur->buf[i]]);
     47	else
     48		printf("\x1b[38:5:%um", equal_gradient[cur->buf[i]]);
     49	has_color = true;
     50}
     51
     52static inline void
     53color_clear(void)
     54{
     55	printf("\x1b[0m");
     56}
     57
     58int
     59main(int argc, const char **argv)
     60{
     61	struct file f1, f2;
     62	const char **arg;
     63	size_t pos, i;
     64
     65	memset(&f1, 0, sizeof(f1));
     66	memset(&f2, 0, sizeof(f2));
     67
     68	for (arg = &argv[1]; *arg; arg++) {
     69		if (!strcmp(*arg, "-c") || !strcmp(*arg, "-C")) {
     70			use_color = (arg[0][1] == 'c');
     71		} else if (!strcmp(*arg, "-d") || !strcmp(*arg, "-D")) {
     72			only_diff = (arg[0][1] == 'd');
     73		} else if (!strcmp(*arg, "-a") || !strcmp(*arg, "-A")) {
     74			show_all = (arg[0][1] == 'a');
     75		} else if (!f1.fname) {
     76			f1.fname = *arg;
     77		} else if (!f2.fname) {
     78			f2.fname = *arg;
     79		} else {
     80			break;
     81		}
     82	}
     83
     84	if (!f1.fname || !f2.fname || *arg) {
     85		fprintf(stderr, "Usage: hexdiff [-cC] [-aA] [-bB] FILE FILE\n");
     86		return 1;
     87	}
     88
     89	f1.file = fopen(f1.fname, "r");
     90	if (!f1.file) err(1, "fopen %s", f1.fname);
     91
     92	f2.file = fopen(f2.fname, "r");
     93	if (!f2.file) err(1, "fopen %s", f2.fname);
     94
     95	pos = 0;
     96	while (show_all ? !feof(f1.file) || !feof(f2.file)
     97			: !feof(f1.file) && !feof(f2.file)) {
     98		f1.buflen = fread(f1.buf, 1, 16, f1.file);
     99		f2.buflen = fread(f2.buf, 1, 16, f2.file);
    100		if (only_diff && f1.buflen == f2.buflen
    101				&& !memcmp(f1.buf, f2.buf, f1.buflen))
    102			continue;
    103		if (!f1.buflen && !f2.buflen) break;
    104
    105		printf("%06lx: ", pos);
    106		for (i = 0; i < 16; i++) {
    107			if (i < f1.buflen) {
    108				if (use_color) color_byte(&f1, &f2, i);
    109				printf("%02x ", f1.buf[i]);
    110				if (has_color) color_clear();
    111			} else {
    112				printf("   ");
    113			}
    114		}
    115		printf("| ");
    116		for (i = 0; i < 16; i++) {
    117			if (i < f2.buflen) {
    118				if (use_color) color_byte(&f2, &f1, i);
    119				printf("%02x ", f2.buf[i]);
    120				if (has_color) color_clear();
    121			} else {
    122				printf("   ");
    123			}
    124		}
    125		printf("\n");
    126
    127		pos += 16;
    128	}
    129
    130	fclose(f1.file);
    131	fclose(f2.file);
    132}