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}