aboutsummaryrefslogtreecommitdiff
path: root/hexdump_pretty.c
diff options
context:
space:
mode:
Diffstat (limited to 'hexdump_pretty.c')
-rw-r--r--hexdump_pretty.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/hexdump_pretty.c b/hexdump_pretty.c
new file mode 100644
index 0000000..d082c0b
--- /dev/null
+++ b/hexdump_pretty.c
@@ -0,0 +1,125 @@
+#include "hexdump_pretty.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LINELEN 0x8
+
+static struct segment line_segments[LINELEN];
+static size_t file_idx = 0;
+static size_t line_idx = 0;
+static size_t current_segment = 0;
+
+
+enum color next_color(void) {
+ static uint8_t cc = 0;
+ cc += 1;
+ cc %= 6;
+ return cc + 1;
+}
+
+void color_put(enum color c) {
+ printf("\x1b[0;3%im", c);
+}
+
+void color_reset(void) {
+ printf("\x1b[m");
+}
+
+void cleanup_line(void) {
+ for (int i = 0; i < current_segment; i++) {
+ free(line_segments[i].data);
+ }
+}
+
+void put_byte(uint8_t byte) {
+ static bool flip = 0;
+ printf("%02x", byte);
+ flip = !flip;
+ if (! flip) {
+ printf(" ");
+ }
+}
+
+void flush_line() {
+ printf("%06lx: ", file_idx);
+ file_idx += LINELEN;
+ for (int i = 0; i < current_segment; i++) {
+ color_put(line_segments[i].c);
+ for (int b = 0; b < line_segments[i].len; b++) {
+ put_byte(line_segments[i].data[b]);
+ }
+ color_reset();
+ }
+ for (int i = 0; i < current_segment; i++) {
+ color_put(line_segments[i].c);
+ for (int b = 0; b < line_segments[i].len; b++) {
+ uint8_t ch = line_segments[i].data[b];
+ if (isprint(ch)) {
+ printf("%c", ch);
+ } else {
+ printf(".");
+ }
+ }
+ color_reset();
+ }
+ printf("\n");
+}
+
+void add_segment(struct segment segment) {
+ line_segments[current_segment++] = segment;
+ line_idx += segment.len;
+ if (line_idx == LINELEN) {
+ flush_line();
+ cleanup_line();
+ current_segment = 0;
+ line_idx = 0;
+ }
+}
+
+/*
+ * Buf MUST be a malloc:ed buffer, which is invalidated on this call.
+ */
+void write_chunk(uint8_t *buf, size_t len) {
+ if (line_idx + len >= LINELEN) {
+ enum color c = next_color();
+ size_t len1 = LINELEN - line_idx,
+ len2 = len - len1;
+ uint8_t *buf1 = malloc(len1),
+ *buf2 = malloc(len2);
+ memcpy(buf1, buf, len1);
+ memcpy(buf2, buf + len1, len2);
+ free(buf);
+ struct segment
+ seg1 = {
+ .c = c,
+ .len = len1,
+ .data = buf1,
+ },
+ seg2 = {
+ .c = c,
+ .len = len2,
+ .data = buf2,
+ };
+ add_segment(seg1);
+ add_segment(seg2);
+ } else {
+ struct segment seg = {
+ .c = next_color(),
+ .len = len,
+ .data = buf,
+ };
+ add_segment(seg);
+ }
+}
+
+void write_chunk_s(uint8_t *buf, size_t len) {
+ assert (len >= 0);
+ uint8_t *true_buf = malloc(len);
+ memcpy(true_buf, buf, len);
+ write_chunk(true_buf, len);
+}