summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/memview.c275
1 files changed, 178 insertions, 97 deletions
diff --git a/src/memview.c b/src/memview.c
index ab85208..5485f25 100644
--- a/src/memview.c
+++ b/src/memview.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
+#include <stdint.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/select.h>
@@ -33,6 +34,7 @@
#define MAGNETA "5"
#define CYAN "6"
#define WHITE "7"
+#define REVERSE "7"
#define ALT_BUF "?1049"
#define CURS "?25"
@@ -58,6 +60,72 @@ struct key {
bool is_csi;
};
+static bool
+get_key(struct key *key)
+{
+ while (1) {
+ unsigned char input;
+ fread(&input, 1, 1, TERM_STREAM);
+
+ switch (input) {
+ case 0x04:
+ return false;
+ case 0x18: // ^X
+ case 0x1a: // ^Z
+ *key = (struct key){0};
+ break;
+ case 0x1b: // ^[
+ *key = (struct key){0};
+ fread(&input, 1, 1, TERM_STREAM);
+ if (input != '[') {
+ key->i = 0;
+ break;
+ }
+ /* fallthrough */
+ case 0x9b: // CSI
+ *key = (struct key){0};
+ key->seq[key->i++] = 0x1b;
+ key->seq[key->i++] = '[';
+ key->is_csi = true;
+ break;
+ default:
+ if (input <= 31) {
+ key->seq[key->i++] = '^';
+ key->seq[key->i++] = input + 0x40;
+ } else if (input == 0x7f) {
+ key->seq[key->i++] = '^';
+ key->seq[key->i++] = '?';
+ } else {
+ key->seq[key->i++] = input;
+ }
+ if (!(key->is_csi && ((input >= '0' && input <= '9') || input == ';')))
+ goto out;
+ break;
+ }
+ }
+out:
+ return true;
+}
+
+struct action {
+ unsigned char seq[sizeof(((struct key*)0)->seq)];
+ void (*fun)(void *arg);
+ intptr_t arg;
+};
+
+static bool
+key_press(const struct key *key, const struct action *actions, const size_t nmemb)
+{
+ for (size_t i = 0; i < nmemb; ++i) {
+ if (memcmp(actions[i].seq, key->seq, key->i))
+ continue;
+
+ actions[i].fun((void*)actions[i].arg);
+ return true;
+ }
+ return false;
+}
+
static struct {
struct named_region {
struct region region;
@@ -84,6 +152,11 @@ static struct {
struct { unsigned int x; unsigned int y; } cur;
} term;
+ struct {
+ char data[255];
+ unsigned char pointer;
+ } input;
+
struct key last_key;
struct mem_io io;
} ctx = { .hexview.octects_per_group = 1 };
@@ -209,6 +282,14 @@ screen_print(const char *str)
}
static void
+screen_putc(const char c)
+{
+ if (ctx.screen.pointer >= ctx.screen.size)
+ return;
+ ctx.screen.buffer[ctx.screen.pointer++] = c;
+}
+
+static void
screen_format(const char *fmt)
{
// optimization for reducing format changes in hexview
@@ -438,8 +519,9 @@ resize(int sig)
}
static void
-next_region(int arg)
+next_region(void *ptr)
{
+ intptr_t arg = (intptr_t)ptr;
size_t region;
if (arg < 0 && ctx.active_region < (size_t)(arg * -1))
region = ctx.num_regions - ((arg * -1) - ctx.active_region);
@@ -460,8 +542,9 @@ enum {
};
static void
-navigate(int arg)
+navigate(void *ptr)
{
+ intptr_t arg = (intptr_t)ptr;
const struct named_region *named = named_region_for_offset(ctx.hexview.offset, false);
switch (arg) {
case MOVE_PAGE_UP: {
@@ -516,42 +599,93 @@ error(const char *fmt, ...)
fread(&input, 1, 1, TERM_STREAM);
}
+static void
+input_move(void *ptr)
+{
+ intptr_t arg = (intptr_t)ptr;
+ switch (arg) {
+ case MOVE_RIGHT:
+ ctx.input.pointer += (ctx.input.pointer < strlen(ctx.input.data));
+ break;
+ case MOVE_LEFT:
+ ctx.input.pointer -= (ctx.input.pointer > 0);
+ break;
+ };
+}
+
+static void
+input_erase(void *ptr)
+{
+ (void)ptr;
+ memmove(ctx.input.data + (ctx.input.pointer > 0 ? ctx.input.pointer - 1 : 0), ctx.input.data + ctx.input.pointer, sizeof(ctx.input.data) - ctx.input.pointer);
+ ctx.input.pointer -= (ctx.input.pointer > 0);
+}
+
static const char*
input(const char *prompt)
{
- static char input[255];
- memset(input, 0, sizeof(input));
- for (unsigned char i = 0;;) {
+ const struct action actions[] = {
+ { .seq = { 0x1b, '[', 'C' }, .fun = input_move, .arg = MOVE_RIGHT },
+ { .seq = { 0x1b, '[', 'D' }, .fun = input_move, .arg = MOVE_LEFT },
+ { .seq = { '^', '?' }, .fun = input_erase },
+ };
+
+ memset(&ctx.input, 0, sizeof(ctx.input));
+ while (true) {
screen_cursor(0, ctx.term.ws.h);
- screen_print(ESCA CLEAR_LINE);
- screen_nprintf(ctx.term.ws.w + sizeof(FMT(FG YELLOW) FMT(PLAIN)) - 1, FMT(FG YELLOW) "%s" FMT(PLAIN) " %s", prompt, input);
+ screen_print(ESCA CLEAR_LINE FMT(FG YELLOW));
+ screen_nprintf(ctx.term.ws.w, "%s: ", prompt);
+ screen_print(FMT(PLAIN));
+
+ const size_t plen = strlen(prompt) + 2;
+ const size_t mlen = ctx.term.ws.w - plen * (ctx.term.ws.w > plen);
+ for (const char *c = ctx.input.data; c < ctx.input.data + mlen && *c; ++c) {
+ if (c == ctx.input.data + ctx.input.pointer)
+ screen_format(FMT(REVERSE));
+
+ screen_putc(*c);
+
+ if (c == ctx.input.data + ctx.input.pointer)
+ screen_format(FMT(PLAIN));
+ }
+
+ if (ctx.input.pointer >= strlen(ctx.input.data))
+ screen_print(FMT(REVERSE) " " FMT(PLAIN));
+
screen_flush();
- fread(input + i, 1, 1, TERM_STREAM);
- switch (input[i]) {
- case 0x7f:
- input[(i > 0 ? i-- : 0)] = 0;
- break;
- case 0x04:
- case 0x1b:
- return NULL;
- case '\n':
- input[i] = 0;
- goto out;
+
+ struct key key = {0};
+ if (!get_key(&key))
+ goto out;
+
+ if (key_press(&key, actions, ARRAY_SIZE(actions)))
+ continue;
+
+ if (key.i == 2 && !memcmp(key.seq, "^J", key.i))
+ goto out;
+ else if (key.i != 1)
+ continue;
+
+ switch (key.seq[0]) {
default:
- i += (i < sizeof(input));
+ if (strlen(ctx.input.data) < sizeof(ctx.input.data) - 1) {
+ memmove(ctx.input.data + ctx.input.pointer + 1, ctx.input.data + ctx.input.pointer, sizeof(ctx.input.data) - 1 - ctx.input.pointer);
+ ctx.input.data[ctx.input.pointer++] = key.seq[0];
+ }
+ break;
}
}
out:
- return input;
+ return ctx.input.data;
}
static void
-goto_offset(int arg)
+goto_offset(void *arg)
{
(void)arg;
const char *v;
- if (!(v = input("offset:")))
+ if (!(v = input("offset")))
return;
char *invalid;
@@ -565,45 +699,13 @@ goto_offset(int arg)
if (v[0] == '+') {
ctx.hexview.offset += ret;
} else if (v[0] == '-') {
- ctx.hexview.offset -= ret;
+ ctx.hexview.offset -= hexdecstrtoull(v + 1, NULL);
} else {
ctx.hexview.offset = ret;
}
}
static void
-key_press(const struct key *key)
-{
- const struct {
- unsigned char seq[sizeof(key->seq)];
- void (*fun)(int);
- int arg;
- } keys[] = {
- { .seq = { 0x1b, '[', '1', ';', '2', 'C' }, .fun = next_region, .arg = 1 },
- { .seq = { 0x1b, '[', '1', ';', '2', 'D' }, .fun = next_region, .arg = -1 },
- { .seq = { 0x1b, '[', '5', '~' }, .fun = navigate, .arg = MOVE_PAGE_UP },
- { .seq = { 0x1b, '[', '6', '~' }, .fun = navigate, .arg = MOVE_PAGE_DOWN },
- { .seq = { 0x1b, '[', 'H' }, .fun = navigate, .arg = MOVE_START },
- { .seq = { 0x1b, '[', 'F' }, .fun = navigate, .arg = MOVE_END },
- { .seq = { 0x1b, '[', 'A' }, .fun = navigate, .arg = MOVE_UP },
- { .seq = { 0x1b, '[', 'B' }, .fun = navigate, .arg = MOVE_DOWN },
- { .seq = { 0x1b, '[', 'C' }, .fun = navigate, .arg = MOVE_RIGHT },
- { .seq = { 0x1b, '[', 'D' }, .fun = navigate, .arg = MOVE_LEFT },
- { .seq = { 'o' }, .fun = goto_offset },
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) {
- if (memcmp(keys[i].seq, key->seq, key->i))
- continue;
-
- keys[i].fun(keys[i].arg);
- break;
- }
-
- ctx.last_key = *key;
-}
-
-static void
quit(void)
{
for (size_t i = 0; i < ctx.num_regions; ++i)
@@ -717,7 +819,20 @@ main(int argc, char *argv[])
signal(SIGWINCH, resize);
resize(0);
- struct key press = {0};
+ const struct action actions[] = {
+ { .seq = { 0x1b, '[', '1', ';', '2', 'C' }, .fun = next_region, .arg = 1 },
+ { .seq = { 0x1b, '[', '1', ';', '2', 'D' }, .fun = next_region, .arg = -1 },
+ { .seq = { 0x1b, '[', '5', '~' }, .fun = navigate, .arg = MOVE_PAGE_UP },
+ { .seq = { 0x1b, '[', '6', '~' }, .fun = navigate, .arg = MOVE_PAGE_DOWN },
+ { .seq = { 0x1b, '[', 'H' }, .fun = navigate, .arg = MOVE_START },
+ { .seq = { 0x1b, '[', 'F' }, .fun = navigate, .arg = MOVE_END },
+ { .seq = { 0x1b, '[', 'A' }, .fun = navigate, .arg = MOVE_UP },
+ { .seq = { 0x1b, '[', 'B' }, .fun = navigate, .arg = MOVE_DOWN },
+ { .seq = { 0x1b, '[', 'C' }, .fun = navigate, .arg = MOVE_RIGHT },
+ { .seq = { 0x1b, '[', 'D' }, .fun = navigate, .arg = MOVE_LEFT },
+ { .seq = { 'o' }, .fun = goto_offset },
+ };
+
while (true) {
fd_set set;
FD_ZERO(&set);
@@ -737,48 +852,14 @@ main(int argc, char *argv[])
continue;
}
- unsigned char input;
- fread(&input, 1, 1, TERM_STREAM);
+ struct key key = {0};
+ if (!get_key(&key))
+ goto quit;
- switch (input) {
- case 0x04:
- goto quit;
- case 0x18: // ^X
- case 0x1a: // ^Z
- press = (struct key){0};
- break;
- case 0x1b: // ^[
- press = (struct key){0};
- fread(&input, 1, 1, TERM_STREAM);
- if (input != '[') {
- press.i = 0;
- break;
- }
- /* fallthrough */
- case 0x9b: // CSI
- press = (struct key){0};
- press.seq[press.i++] = 0x1b;
- press.seq[press.i++] = '[';
- press.is_csi = true;
- break;
- default:
- if (input <= 31) {
- press.seq[press.i++] = '^';
- press.seq[press.i++] = input + 0x40;
- } else if (input == 0x7f) {
- press.seq[press.i++] = '^';
- press.seq[press.i++] = '?';
- } else {
- press.seq[press.i++] = input;
- }
- if (!(press.is_csi && ((input >= '0' && input <= '9') || input == ';'))) {
- key_press(&press);
- press = (struct key){0};
- repaint_dynamic_areas(false);
- screen_flush();
- }
- break;
- }
+ key_press(&key, actions, ARRAY_SIZE(actions));
+ ctx.last_key = key;
+ repaint_dynamic_areas(false);
+ screen_flush();
}
quit: