Get it halfway working
This commit is contained in:
parent
5c4be81f25
commit
742647ef80
10
README.adoc
10
README.adoc
|
@ -6,7 +6,7 @@ hex
|
||||||
Plans
|
Plans
|
||||||
-----
|
-----
|
||||||
In the future, it should be able to automatically interpret fields within files
|
In the future, it should be able to automatically interpret fields within files
|
||||||
via a set of Lua scripts.
|
using a set of Lua scripts.
|
||||||
|
|
||||||
Packages
|
Packages
|
||||||
--------
|
--------
|
||||||
|
@ -49,7 +49,7 @@ Create _~/.config/hex/hex.conf_ with contents like the following:
|
||||||
|
|
||||||
....
|
....
|
||||||
colors = {
|
colors = {
|
||||||
header = ""
|
footer = ""
|
||||||
highlight = "bold"
|
highlight = "bold"
|
||||||
bar = "reverse"
|
bar = "reverse"
|
||||||
bar_active = "ul"
|
bar_active = "ul"
|
||||||
|
@ -61,11 +61,9 @@ colors = {
|
||||||
|
|
||||||
Terminal caveats
|
Terminal caveats
|
||||||
----------------
|
----------------
|
||||||
This application aspires to be as close to a GUI as possible. It expects you
|
Terminals are somewhat tricky to get consistent results on, so be aware of the
|
||||||
to use the mouse (though it's not required). Terminals are, however, somewhat
|
following:
|
||||||
tricky to get consistent results on, so be aware of the following:
|
|
||||||
|
|
||||||
- use a UTF-8 locale to get finer resolution progress bars and scrollbars
|
|
||||||
- Xterm needs `XTerm*metaSendsEscape: true` for the default bindings to work
|
- Xterm needs `XTerm*metaSendsEscape: true` for the default bindings to work
|
||||||
- urxvt's 'vtwheel' plugin sabotages scrolling
|
- urxvt's 'vtwheel' plugin sabotages scrolling
|
||||||
|
|
||||||
|
|
291
hex.c
291
hex.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* hex -- a very simple hex viewer
|
* hex -- hex viewer
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
|
* Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -22,19 +22,19 @@
|
||||||
|
|
||||||
// We "need" to have an enum for attributes before including liberty.
|
// We "need" to have an enum for attributes before including liberty.
|
||||||
// Avoiding colours in the defaults here in order to support dumb terminals.
|
// Avoiding colours in the defaults here in order to support dumb terminals.
|
||||||
#define ATTRIBUTE_TABLE(XX) \
|
#define ATTRIBUTE_TABLE(XX) \
|
||||||
XX( HEADER, "header", -1, -1, 0 ) \
|
XX( FOOTER, "footer", -1, -1, 0 ) \
|
||||||
XX( HIGHLIGHT, "highlight", -1, -1, A_BOLD ) \
|
XX( HIGHLIGHT, "highlight", -1, -1, A_BOLD ) \
|
||||||
/* Bar */ \
|
/* Bar */ \
|
||||||
XX( BAR, "bar", -1, -1, A_REVERSE ) \
|
XX( BAR, "bar", -1, -1, A_REVERSE ) \
|
||||||
XX( BAR_ACTIVE, "bar_active", -1, -1, A_UNDERLINE ) \
|
XX( BAR_ACTIVE, "bar_active", -1, -1, A_REVERSE | A_BOLD ) \
|
||||||
/* Listview */ \
|
/* View */ \
|
||||||
XX( EVEN, "even", -1, -1, 0 ) \
|
XX( EVEN, "even", -1, -1, 0 ) \
|
||||||
XX( ODD, "odd", -1, -1, 0 ) \
|
XX( ODD, "odd", -1, -1, 0 ) \
|
||||||
XX( SELECTION, "selection", -1, -1, A_REVERSE ) \
|
XX( SELECTION, "selection", -1, -1, A_REVERSE ) \
|
||||||
/* These are for debugging only */ \
|
/* These are for debugging only */ \
|
||||||
XX( WARNING, "warning", 3, -1, 0 ) \
|
XX( WARNING, "warning", 3, -1, 0 ) \
|
||||||
XX( ERROR, "error", 1, -1, 0 )
|
XX( ERROR, "error", 1, -1, 0 )
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -96,6 +96,12 @@ enum
|
||||||
FOOTER_SIZE = 4, ///< How many rows form the footer
|
FOOTER_SIZE = 4, ///< How many rows form the footer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum endianity
|
||||||
|
{
|
||||||
|
ENDIANITY_LE, ///< Little endian
|
||||||
|
ENDIANITY_BE ///< Big endian
|
||||||
|
};
|
||||||
|
|
||||||
static struct app_context
|
static struct app_context
|
||||||
{
|
{
|
||||||
// Event loop:
|
// Event loop:
|
||||||
|
@ -113,16 +119,16 @@ static struct app_context
|
||||||
char *filename; ///< Target filename
|
char *filename; ///< Target filename
|
||||||
|
|
||||||
uint8_t *data; ///< Target data
|
uint8_t *data; ///< Target data
|
||||||
uint64_t data_len; ///< Length of the data
|
int64_t data_len; ///< Length of the data
|
||||||
uint64_t data_offset; ///< Offset of the data within the file
|
int64_t data_offset; ///< Offset of the data within the file
|
||||||
|
|
||||||
uint64_t view_top; ///< Offset of the top of the screen
|
// View:
|
||||||
uint64_t view_cursor; ///< Offset of the cursor
|
|
||||||
|
|
||||||
// TODO: get rid of this as it can be computed from "data*"
|
int64_t view_top; ///< Offset of the top of the screen
|
||||||
size_t item_count; ///< Total item count
|
int64_t view_cursor; ///< Offset of the cursor
|
||||||
int item_top; ///< Index of the topmost item
|
bool view_skip_nibble; ///< Half-byte offset
|
||||||
int item_selected; ///< Index of the selected item
|
|
||||||
|
enum endianity endianity; ///< Endianity
|
||||||
|
|
||||||
// Emulated widgets:
|
// Emulated widgets:
|
||||||
|
|
||||||
|
@ -345,10 +351,10 @@ app_visible_items (void)
|
||||||
static void
|
static void
|
||||||
app_draw_view (void)
|
app_draw_view (void)
|
||||||
{
|
{
|
||||||
uint64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
|
int64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
|
||||||
for (int y = 0; y < app_visible_items (); y++)
|
for (int y = 0; y < app_visible_items (); y++)
|
||||||
{
|
{
|
||||||
uint64_t row_addr = g_ctx.view_top + y * ROW_SIZE;
|
int64_t row_addr = g_ctx.view_top + y * ROW_SIZE;
|
||||||
if (row_addr > end_addr)
|
if (row_addr > end_addr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -358,7 +364,7 @@ app_draw_view (void)
|
||||||
struct row_buffer buf;
|
struct row_buffer buf;
|
||||||
row_buffer_init (&buf);
|
row_buffer_init (&buf);
|
||||||
|
|
||||||
char *row_addr_str = xstrdup_printf ("%08" PRIX64, row_addr);
|
char *row_addr_str = xstrdup_printf ("%08" PRIx64, row_addr);
|
||||||
row_buffer_append (&buf, row_addr_str, row_attrs);
|
row_buffer_append (&buf, row_addr_str, row_attrs);
|
||||||
free (row_addr_str);
|
free (row_addr_str);
|
||||||
|
|
||||||
|
@ -371,7 +377,7 @@ app_draw_view (void)
|
||||||
if (x % 8 == 0) row_buffer_append (&buf, " ", row_attrs);
|
if (x % 8 == 0) row_buffer_append (&buf, " ", row_attrs);
|
||||||
if (x % 2 == 0) row_buffer_append (&buf, " ", row_attrs);
|
if (x % 2 == 0) row_buffer_append (&buf, " ", row_attrs);
|
||||||
|
|
||||||
uint64_t cell_addr = row_addr + x;
|
int64_t cell_addr = row_addr + x;
|
||||||
if (cell_addr < g_ctx.data_offset
|
if (cell_addr < g_ctx.data_offset
|
||||||
|| cell_addr >= end_addr)
|
|| cell_addr >= end_addr)
|
||||||
{
|
{
|
||||||
|
@ -412,23 +418,39 @@ app_draw_footer (void)
|
||||||
row_buffer_init (&buf);
|
row_buffer_init (&buf);
|
||||||
|
|
||||||
row_buffer_append (&buf, APP_TITLE, a_normal);
|
row_buffer_append (&buf, APP_TITLE, a_normal);
|
||||||
row_buffer_append (&buf, " ", a_normal);
|
|
||||||
// TODO: transcode from locale encoding
|
if (g_ctx.filename)
|
||||||
row_buffer_append (&buf, g_ctx.filename, a_active);
|
{
|
||||||
|
row_buffer_append (&buf, " ", a_normal);
|
||||||
|
char *filename = (char *) u8_strconv_from_locale (g_ctx.filename);
|
||||||
|
row_buffer_append (&buf, filename, a_active);
|
||||||
|
free (filename);
|
||||||
|
}
|
||||||
|
|
||||||
struct str right;
|
struct str right;
|
||||||
str_init (&right);
|
str_init (&right);
|
||||||
str_append_printf (&right, "%08" PRIx64 " ", g_ctx.view_cursor);
|
str_append_printf (&right, "%08" PRIx64 " ", g_ctx.view_cursor);
|
||||||
// TODO: endian switch
|
str_append_printf (&right,
|
||||||
str_append (&right, "?? ");
|
"%s ", g_ctx.endianity == ENDIANITY_LE ? "LE" : "BE");
|
||||||
// TODO: position indication
|
|
||||||
str_append (&right, "???");
|
int64_t top = g_ctx.view_top;
|
||||||
|
int64_t bot = g_ctx.view_top + app_visible_items () * ROW_SIZE;
|
||||||
|
if (top <= g_ctx.data_offset
|
||||||
|
&& bot > g_ctx.data_offset + g_ctx.data_len)
|
||||||
|
str_append (&right, "All");
|
||||||
|
else if (top <= g_ctx.data_offset)
|
||||||
|
str_append (&right, "Top");
|
||||||
|
else if (bot > g_ctx.data_offset + g_ctx.data_len)
|
||||||
|
str_append (&right, "Bot");
|
||||||
|
else
|
||||||
|
// TODO: position indication in percents
|
||||||
|
str_append (&right, "??%");
|
||||||
|
|
||||||
row_buffer_align (&buf, COLS - right.len, a_normal);
|
row_buffer_align (&buf, COLS - right.len, a_normal);
|
||||||
row_buffer_append (&buf, right.str, a_normal);
|
row_buffer_append (&buf, right.str, a_normal);
|
||||||
app_flush_buffer (&buf, COLS, a_normal);
|
app_flush_buffer (&buf, COLS, a_normal);
|
||||||
|
|
||||||
uint64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
|
int64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
|
||||||
if (g_ctx.view_cursor < g_ctx.data_offset
|
if (g_ctx.view_cursor < g_ctx.data_offset
|
||||||
|| g_ctx.view_cursor >= end_addr)
|
|| g_ctx.view_cursor >= end_addr)
|
||||||
return;
|
return;
|
||||||
|
@ -440,37 +462,52 @@ app_draw_footer (void)
|
||||||
int64_t len = end_addr - g_ctx.view_cursor;
|
int64_t len = end_addr - g_ctx.view_cursor;
|
||||||
uint8_t *cursor = g_ctx.data + (g_ctx.view_cursor - g_ctx.data_offset);
|
uint8_t *cursor = g_ctx.data + (g_ctx.view_cursor - g_ctx.data_offset);
|
||||||
|
|
||||||
// TODO: convert endianity, show full numbers
|
uint8_t copy[8] = {};
|
||||||
|
memcpy (copy, cursor, MIN (len, 8));
|
||||||
|
|
||||||
|
if (g_ctx.endianity == ENDIANITY_BE)
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
uint8_t tmp = copy[7 - i];
|
||||||
|
copy[7 - i] = copy[i];
|
||||||
|
copy[i] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: make the headers bold
|
// TODO: make the headers bold
|
||||||
const char *coding = "??";
|
const char *coding = g_ctx.endianity == ENDIANITY_LE ? "le" : "be";
|
||||||
if (len >= 1)
|
if (len >= 1)
|
||||||
{
|
{
|
||||||
str_append_printf (&x, "x8 %02x", cursor[0]);
|
str_append_printf (&x, "x8 %02x", copy[0]);
|
||||||
str_append_printf (&u, "u8 %4u", cursor[0]);
|
str_append_printf (&u, "u8 %4u", copy[0]);
|
||||||
str_append_printf (&s, "s8 %4d", cursor[0]);
|
str_append_printf (&s, "s8 %4d", copy[0]);
|
||||||
}
|
}
|
||||||
if (len >= 2)
|
if (len >= 2)
|
||||||
{
|
{
|
||||||
str_append_printf (&x, " x16%s %04x", coding, cursor[0]);
|
uint16_t val = copy[0] | copy[1] << 8;
|
||||||
str_append_printf (&u, " u16%s %6u", coding, cursor[0]);
|
str_append_printf (&x, " x16%s %04x", coding, val);
|
||||||
str_append_printf (&s, " s16%s %6d", coding, cursor[0]);
|
str_append_printf (&u, " u16%s %6u", coding, val);
|
||||||
|
str_append_printf (&s, " s16%s %6d", coding, val);
|
||||||
}
|
}
|
||||||
if (len >= 4)
|
if (len >= 4)
|
||||||
{
|
{
|
||||||
str_append_printf (&x, " x32%s %08x", coding, cursor[0]);
|
uint32_t val = copy[0] | copy[1] << 8 | copy[2] << 16 | copy[3] << 24;
|
||||||
str_append_printf (&u, " u32%s %11u", coding, cursor[0]);
|
str_append_printf (&x, " x32%s %08x", coding, val);
|
||||||
str_append_printf (&s, " s32%s %11d", coding, cursor[0]);
|
str_append_printf (&u, " u32%s %11u", coding, val);
|
||||||
|
str_append_printf (&s, " s32%s %11d", coding, val);
|
||||||
}
|
}
|
||||||
if (len >= 8)
|
if (len >= 8)
|
||||||
{
|
{
|
||||||
str_append_printf (&x, " x64%s %016x", coding, cursor[0]);
|
uint64_t val = copy[0] | copy[1] << 8 | copy[2] << 16 | copy[3] << 24
|
||||||
str_append_printf (&u, " u64%s %20u", coding, cursor[0]);
|
| (uint64_t) copy[4] << 32 | (uint64_t) copy[5] << 40
|
||||||
str_append_printf (&s, " s64%s %20d", coding, cursor[0]);
|
| (uint64_t) copy[6] << 48 | (uint64_t) copy[7] << 56;
|
||||||
|
str_append_printf (&x, " x64%s %016" PRIx64, coding, val);
|
||||||
|
str_append_printf (&u, " u64%s %20" PRIu64, coding, val);
|
||||||
|
str_append_printf (&s, " s64%s %20" PRId64, coding, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
app_write_line (x.str, APP_ATTR (HEADER));
|
app_write_line (x.str, APP_ATTR (FOOTER));
|
||||||
app_write_line (u.str, APP_ATTR (HEADER));
|
app_write_line (u.str, APP_ATTR (FOOTER));
|
||||||
app_write_line (s.str, APP_ATTR (HEADER));
|
app_write_line (s.str, APP_ATTR (FOOTER));
|
||||||
|
|
||||||
str_free (&x);
|
str_free (&x);
|
||||||
str_free (&u);
|
str_free (&u);
|
||||||
|
@ -490,7 +527,7 @@ app_on_refresh (void *user_data)
|
||||||
int64_t diff = g_ctx.view_cursor - g_ctx.view_top;
|
int64_t diff = g_ctx.view_cursor - g_ctx.view_top;
|
||||||
int y = diff / ROW_SIZE;
|
int y = diff / ROW_SIZE;
|
||||||
int x = diff % ROW_SIZE;
|
int x = diff % ROW_SIZE;
|
||||||
move (y, x + 10 + x/8 + x/2);
|
move (y, 10 + x*2 + g_ctx.view_skip_nibble + x/8 + x/2);
|
||||||
|
|
||||||
refresh ();
|
refresh ();
|
||||||
}
|
}
|
||||||
|
@ -501,21 +538,22 @@ app_on_refresh (void *user_data)
|
||||||
static bool
|
static bool
|
||||||
app_fix_view_range (void)
|
app_fix_view_range (void)
|
||||||
{
|
{
|
||||||
if (g_ctx.item_top < 0)
|
if (g_ctx.view_top < g_ctx.data_offset / ROW_SIZE * ROW_SIZE)
|
||||||
{
|
{
|
||||||
g_ctx.item_top = 0;
|
g_ctx.view_top = g_ctx.data_offset / ROW_SIZE * ROW_SIZE;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the contents are at least as long as the screen, always fill it
|
// If the contents are at least as long as the screen, always fill it
|
||||||
int max_item_top = (int) g_ctx.item_count - app_visible_items ();
|
int64_t max_view_top = (g_ctx.data_offset + g_ctx.data_len - 1)
|
||||||
|
/ ROW_SIZE * ROW_SIZE - app_visible_items () * ROW_SIZE;
|
||||||
// But don't let that suggest a negative offset
|
// But don't let that suggest a negative offset
|
||||||
max_item_top = MAX (max_item_top, 0);
|
max_view_top = MAX (max_view_top, 0);
|
||||||
|
|
||||||
if (g_ctx.item_top > max_item_top)
|
if (g_ctx.view_top > max_view_top)
|
||||||
{
|
{
|
||||||
g_ctx.item_top = max_item_top;
|
g_ctx.view_top = max_view_top;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -526,7 +564,7 @@ app_fix_view_range (void)
|
||||||
static bool
|
static bool
|
||||||
app_scroll (int n)
|
app_scroll (int n)
|
||||||
{
|
{
|
||||||
g_ctx.item_top += n;
|
g_ctx.view_top += n * ROW_SIZE;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
return app_fix_view_range ();
|
return app_fix_view_range ();
|
||||||
}
|
}
|
||||||
|
@ -534,15 +572,12 @@ app_scroll (int n)
|
||||||
static void
|
static void
|
||||||
app_ensure_selection_visible (void)
|
app_ensure_selection_visible (void)
|
||||||
{
|
{
|
||||||
if (g_ctx.item_selected < 0)
|
int too_high = g_ctx.view_top / ROW_SIZE - g_ctx.view_cursor / ROW_SIZE;
|
||||||
return;
|
|
||||||
|
|
||||||
int too_high = g_ctx.item_top - g_ctx.item_selected;
|
|
||||||
if (too_high > 0)
|
if (too_high > 0)
|
||||||
app_scroll (-too_high);
|
app_scroll (-too_high);
|
||||||
|
|
||||||
int too_low = g_ctx.item_selected
|
int too_low = g_ctx.view_cursor / ROW_SIZE
|
||||||
- (g_ctx.item_top + app_visible_items () - 1);
|
- (g_ctx.view_top / ROW_SIZE + app_visible_items () - 1);
|
||||||
if (too_low > 0)
|
if (too_low > 0)
|
||||||
app_scroll (too_low);
|
app_scroll (too_low);
|
||||||
}
|
}
|
||||||
|
@ -550,12 +585,13 @@ app_ensure_selection_visible (void)
|
||||||
static bool
|
static bool
|
||||||
app_move_selection (int diff)
|
app_move_selection (int diff)
|
||||||
{
|
{
|
||||||
int fixed = g_ctx.item_selected += diff;
|
// TODO: disallow partial up/down movement
|
||||||
fixed = MAX (fixed, 0);
|
int64_t fixed = g_ctx.view_cursor += diff * ROW_SIZE;
|
||||||
fixed = MIN (fixed, (int) g_ctx.item_count - 1);
|
fixed = MAX (fixed, g_ctx.data_offset);
|
||||||
|
fixed = MIN (fixed, g_ctx.data_offset + g_ctx.data_len - 1);
|
||||||
|
|
||||||
bool result = g_ctx.item_selected != fixed;
|
bool result = g_ctx.view_cursor != fixed;
|
||||||
g_ctx.item_selected = fixed;
|
g_ctx.view_cursor = fixed;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
|
|
||||||
app_ensure_selection_visible ();
|
app_ensure_selection_visible ();
|
||||||
|
@ -570,8 +606,7 @@ enum action
|
||||||
ACTION_QUIT,
|
ACTION_QUIT,
|
||||||
ACTION_REDRAW,
|
ACTION_REDRAW,
|
||||||
|
|
||||||
ACTION_CHOOSE,
|
ACTION_TOGGLE_ENDIANITY,
|
||||||
ACTION_DELETE,
|
|
||||||
|
|
||||||
ACTION_SCROLL_UP,
|
ACTION_SCROLL_UP,
|
||||||
ACTION_SCROLL_DOWN,
|
ACTION_SCROLL_DOWN,
|
||||||
|
@ -603,31 +638,36 @@ app_process_action (enum action action)
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
case ACTION_TOGGLE_ENDIANITY:
|
||||||
|
g_ctx.endianity = (g_ctx.endianity == ENDIANITY_LE)
|
||||||
|
? ENDIANITY_BE : ENDIANITY_LE;
|
||||||
|
app_invalidate ();
|
||||||
|
break;
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// XXX: these should rather be parametrized
|
// XXX: these should rather be parametrized
|
||||||
case ACTION_SCROLL_UP:
|
case ACTION_SCROLL_UP:
|
||||||
app_scroll (-3);
|
app_scroll (-1);
|
||||||
break;
|
break;
|
||||||
case ACTION_SCROLL_DOWN:
|
case ACTION_SCROLL_DOWN:
|
||||||
app_scroll (3);
|
app_scroll (1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_GOTO_TOP:
|
case ACTION_GOTO_TOP:
|
||||||
if (g_ctx.item_count)
|
g_ctx.view_cursor = g_ctx.data_offset;
|
||||||
{
|
app_ensure_selection_visible ();
|
||||||
g_ctx.item_selected = 0;
|
app_invalidate ();
|
||||||
app_ensure_selection_visible ();
|
|
||||||
app_invalidate ();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ACTION_GOTO_BOTTOM:
|
case ACTION_GOTO_BOTTOM:
|
||||||
if (g_ctx.item_count)
|
if (!g_ctx.data_len)
|
||||||
{
|
break;
|
||||||
g_ctx.item_selected = (int) g_ctx.item_count - 1;
|
|
||||||
app_ensure_selection_visible ();
|
g_ctx.view_cursor = g_ctx.data_offset + g_ctx.data_len - 1;
|
||||||
app_invalidate ();
|
app_ensure_selection_visible ();
|
||||||
}
|
app_invalidate ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_GOTO_PAGE_PREVIOUS:
|
case ACTION_GOTO_PAGE_PREVIOUS:
|
||||||
|
@ -646,10 +686,28 @@ app_process_action (enum action action)
|
||||||
app_move_selection (1);
|
app_move_selection (1);
|
||||||
break;
|
break;
|
||||||
case ACTION_LEFT:
|
case ACTION_LEFT:
|
||||||
// TODO: decrement cursor, check bounds, invalidate
|
if (g_ctx.view_skip_nibble)
|
||||||
|
g_ctx.view_skip_nibble = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: check bounds
|
||||||
|
g_ctx.view_skip_nibble = true;
|
||||||
|
g_ctx.view_cursor--;
|
||||||
|
}
|
||||||
|
app_ensure_selection_visible ();
|
||||||
|
app_invalidate ();
|
||||||
break;
|
break;
|
||||||
case ACTION_RIGHT:
|
case ACTION_RIGHT:
|
||||||
// TODO: increment cursor, check bounds, invalidate
|
if (!g_ctx.view_skip_nibble)
|
||||||
|
g_ctx.view_skip_nibble = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: check bounds
|
||||||
|
g_ctx.view_skip_nibble = false;
|
||||||
|
g_ctx.view_cursor++;
|
||||||
|
}
|
||||||
|
app_ensure_selection_visible ();
|
||||||
|
app_invalidate ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -670,16 +728,24 @@ app_process_left_mouse_click (int line, int column)
|
||||||
{
|
{
|
||||||
if (line == app_visible_items ())
|
if (line == app_visible_items ())
|
||||||
{
|
{
|
||||||
// TODO: LE/BE switch, maybe something else
|
if (column < COLS - 7
|
||||||
|
|| column >= COLS - 5)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO: LE/BE switch
|
||||||
}
|
}
|
||||||
else if (line < app_visible_items ())
|
else if (line < app_visible_items ())
|
||||||
{
|
{
|
||||||
int row_index = line;
|
if (line < 0)
|
||||||
if (row_index < 0
|
|
||||||
|| row_index >= (int) g_ctx.item_count - g_ctx.item_top)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
g_ctx.item_selected = row_index + g_ctx.item_top;
|
// TODO: convert and check "column"
|
||||||
|
int offset = 0;
|
||||||
|
if (column < 10 || column >= 50)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO: check if the result is within bounds and return false if not
|
||||||
|
g_ctx.view_cursor = g_ctx.view_top + line * ROW_SIZE + offset;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -712,27 +778,30 @@ g_default_bindings[] =
|
||||||
{ "Escape", ACTION_QUIT },
|
{ "Escape", ACTION_QUIT },
|
||||||
{ "q", ACTION_QUIT },
|
{ "q", ACTION_QUIT },
|
||||||
{ "C-l", ACTION_REDRAW },
|
{ "C-l", ACTION_REDRAW },
|
||||||
// TODO: Tab switches endianity
|
{ "Tab", ACTION_TOGGLE_ENDIANITY },
|
||||||
|
|
||||||
{ "Home", ACTION_GOTO_TOP },
|
{ "Home", ACTION_GOTO_TOP },
|
||||||
{ "End", ACTION_GOTO_BOTTOM },
|
{ "End", ACTION_GOTO_BOTTOM },
|
||||||
{ "M-<", ACTION_GOTO_TOP },
|
{ "M-<", ACTION_GOTO_TOP },
|
||||||
{ "M->", ACTION_GOTO_BOTTOM },
|
{ "M->", ACTION_GOTO_BOTTOM },
|
||||||
{ "Up", ACTION_UP },
|
|
||||||
{ "Down", ACTION_DOWN },
|
|
||||||
{ "k", ACTION_UP },
|
|
||||||
{ "j", ACTION_DOWN },
|
|
||||||
{ "PageUp", ACTION_GOTO_PAGE_PREVIOUS },
|
{ "PageUp", ACTION_GOTO_PAGE_PREVIOUS },
|
||||||
{ "PageDown", ACTION_GOTO_PAGE_NEXT },
|
{ "PageDown", ACTION_GOTO_PAGE_NEXT },
|
||||||
{ "C-p", ACTION_UP },
|
|
||||||
{ "C-n", ACTION_DOWN },
|
|
||||||
{ "C-b", ACTION_GOTO_PAGE_PREVIOUS },
|
{ "C-b", ACTION_GOTO_PAGE_PREVIOUS },
|
||||||
{ "C-f", ACTION_GOTO_PAGE_NEXT },
|
{ "C-f", ACTION_GOTO_PAGE_NEXT },
|
||||||
// TODO: C-e and C-y scroll up and down
|
|
||||||
|
|
||||||
// Not sure how to set these up, they're pretty arbitrary so far
|
{ "Up", ACTION_UP },
|
||||||
{ "Enter", ACTION_CHOOSE },
|
{ "Down", ACTION_DOWN },
|
||||||
{ "Delete", ACTION_DELETE },
|
{ "Left", ACTION_LEFT },
|
||||||
|
{ "Right", ACTION_RIGHT },
|
||||||
|
{ "k", ACTION_UP },
|
||||||
|
{ "j", ACTION_DOWN },
|
||||||
|
{ "h", ACTION_LEFT },
|
||||||
|
{ "l", ACTION_RIGHT },
|
||||||
|
{ "C-p", ACTION_UP },
|
||||||
|
{ "C-n", ACTION_DOWN },
|
||||||
|
|
||||||
|
{ "C-y", ACTION_SCROLL_UP },
|
||||||
|
{ "C-e", ACTION_SCROLL_DOWN },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -935,15 +1004,15 @@ app_init_poller_events (void)
|
||||||
/// Decode size arguments according to similar rules to those that dd(1) uses;
|
/// Decode size arguments according to similar rules to those that dd(1) uses;
|
||||||
/// we support octal and hexadecimal numbers but they clash with suffixes
|
/// we support octal and hexadecimal numbers but they clash with suffixes
|
||||||
static bool
|
static bool
|
||||||
decode_size (const char *s, uint64_t *out)
|
decode_size (const char *s, int64_t *out)
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
uint64_t n = strtoul (s, &end, 0);
|
int64_t n = strtol (s, &end, 0);
|
||||||
if (errno != 0 || end == s)
|
if (errno != 0 || end == s || n < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint64_t f = 1;
|
int64_t f = 1;
|
||||||
switch (*end)
|
switch (*end)
|
||||||
{
|
{
|
||||||
case 'c': f = 1 << 0; end++; break;
|
case 'c': f = 1 << 0; end++; break;
|
||||||
|
@ -954,7 +1023,7 @@ decode_size (const char *s, uint64_t *out)
|
||||||
case 'M': f = 1 << 20; if (*++end == 'B') { f = 1e6; end++; } break;
|
case 'M': f = 1 << 20; if (*++end == 'B') { f = 1e6; end++; } break;
|
||||||
case 'G': f = 1 << 30; if (*++end == 'B') { f = 1e9; end++; } break;
|
case 'G': f = 1 << 30; if (*++end == 'B') { f = 1e9; end++; } break;
|
||||||
}
|
}
|
||||||
if (*end || n > UINT64_MAX / f)
|
if (*end || n > INT64_MAX / f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*out = n * f;
|
*out = n * f;
|
||||||
|
@ -977,7 +1046,7 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
struct opt_handler oh;
|
struct opt_handler oh;
|
||||||
opt_handler_init (&oh, argc, argv, opts, "[FILE]", "Hex viewer.");
|
opt_handler_init (&oh, argc, argv, opts, "[FILE]", "Hex viewer.");
|
||||||
uint64_t size_limit = 1 << 30;
|
int64_t size_limit = 1 << 30;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = opt_handler_get (&oh)) != -1)
|
while ((c = opt_handler_get (&oh)) != -1)
|
||||||
|
@ -1049,7 +1118,7 @@ main (int argc, char *argv[])
|
||||||
struct str buf;
|
struct str buf;
|
||||||
str_init (&buf);
|
str_init (&buf);
|
||||||
|
|
||||||
while (buf.len < size_limit)
|
while (buf.len < (size_t) size_limit)
|
||||||
{
|
{
|
||||||
str_ensure_space (&buf, 8192);
|
str_ensure_space (&buf, 8192);
|
||||||
ssize_t n_read = read (input_fd, buf.str + buf.len,
|
ssize_t n_read = read (input_fd, buf.str + buf.len,
|
||||||
|
|
Loading…
Reference in New Issue