summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-10-23 20:17:08 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2018-10-23 20:17:08 +0300
commitcdfe4162d626b701a1b366ef3db7b4a9d5bd8864 (patch)
tree9d43acf15a3863d95e5cbb7009214302b49c366a /src
parentafa1926e8049a8b66fa9532329856cc04979576e (diff)
memview: Reuse input handling for input function
Also better inputline in general. We are basically reimplementing getline here. There's lots of repeated patterns here we could split into nicer utiliteis, but lets clean later. I want a useful tool as first prioritory.
Diffstat (limited to 'src')
-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: