aboutsummaryrefslogtreecommitdiff
path: root/miscutils/hexedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils/hexedit.c')
-rw-r--r--miscutils/hexedit.c79
1 files changed, 52 insertions, 27 deletions
diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c
index e8bc73b7e..b8627e826 100644
--- a/miscutils/hexedit.c
+++ b/miscutils/hexedit.c
@@ -15,19 +15,28 @@
#include "libbb.h"
-#define ESC "\033"
-#define HOME ESC"[H"
-#define CLEAR ESC"[H"ESC"[J"
+#define ESC "\033"
+#define HOME ESC"[H"
+#define CLEAR ESC"[H"ESC"[J"
+#define SET_ALT_SCR ESC"[?1049h"
+#define POP_ALT_SCR ESC"[?1049l"
+
+#undef CTRL
+#define CTRL(c) ((c) & (uint8_t)~0x60)
struct globals {
smallint half;
+ smallint in_read_key;
int fd;
unsigned height;
+ unsigned row;
uint8_t *addr;
uint8_t *current_byte;
uint8_t *eof_byte;
off_t size;
off_t offset;
+ /* needs to be zero-inited, thus keeping it in G: */
+ char read_key_buffer[KEYCODE_BUFFER_SIZE];
struct termios orig_termios;
};
#define G (*ptr_to_globals)
@@ -41,6 +50,24 @@ struct globals {
/* "12ef5670 (xx )*16 _1_3_5_7_9abcdef\n"NUL */
#define LINEBUF_SIZE (8 + 1 + 3*16 + 16 + 1 + 1 /*paranoia:*/ + 13)
+static void restore_term(void)
+{
+ tcsetattr_stdin_TCSANOW(&G.orig_termios);
+ printf(POP_ALT_SCR);
+ fflush_all();
+}
+
+static void sig_catcher(int sig)
+{
+ if (!G.in_read_key) {
+ /* now it's not safe to do I/O, just inform the main loop */
+ bb_got_signal = sig;
+ return;
+ }
+ restore_term();
+ kill_myself_with_sig(sig);
+}
+
static int format_line(char *hex, uint8_t *data, off_t offset)
{
int ofs_pos;
@@ -141,9 +168,10 @@ static void remap(unsigned cur_pos)
G.fd,
G.offset
);
- if (G.addr == MAP_FAILED)
-//TODO: restore termios?
+ if (G.addr == MAP_FAILED) {
+ restore_term();
bb_perror_msg_and_die("mmap");
+ }
G.current_byte = G.addr + cur_pos;
@@ -201,12 +229,6 @@ static void move_mapping_lower(void)
remap(pos);
}
-static void sig_catcher(int sig)
-{
- tcsetattr_stdin_TCSANOW(&G.orig_termios);
- kill_myself_with_sig(sig);
-}
-
//usage:#define hexedit_trivial_usage
//usage: "FILE"
//usage:#define hexedit_full_usage "\n\n"
@@ -214,8 +236,6 @@ static void sig_catcher(int sig)
int hexedit_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int hexedit_main(int argc UNUSED_PARAM, char **argv)
{
- unsigned row = 0;
-
INIT_G();
get_terminal_width_height(-1, NULL, &G.height);
@@ -237,7 +257,7 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
remap(0);
- printf(CLEAR);
+ printf(SET_ALT_SCR);
redraw();
printf(ESC"[1;10H"); /* position on 1st hex byte in first line */
@@ -245,21 +265,22 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
//Backspace: undo
//Enter: goto specified position
//Ctrl-L: redraw
- //Ctrl-X: save and exit (maybe also Q?)
//Ctrl-Z: suspend
//'/', Ctrl-S: search
-//TODO: go to end-of-screen on exit (for this, sighandler should interrupt read_key())
//TODO: detect window resize
-//TODO: read-only mode if open(O_RDWR) fails? hide cursor in this case?
for (;;) {
- char read_key_buffer[KEYCODE_BUFFER_SIZE];
unsigned cnt;
- int32_t key;
+ int32_t key = key; // for compiler
uint8_t byte;
fflush_all();
- key = read_key(STDIN_FILENO, read_key_buffer, -1);
+ G.in_read_key = 1;
+ if (!bb_got_signal)
+ key = read_key(STDIN_FILENO, G.read_key_buffer, -1);
+ G.in_read_key = 0;
+ if (bb_got_signal)
+ key = CTRL('X');
cnt = 1;
switch (key) {
@@ -329,9 +350,9 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
}
down:
putchar('\n'); /* down one line, possibly scroll screen */
- row++;
- if (row >= G.height) {
- row--;
+ G.row++;
+ if (G.row >= G.height) {
+ G.row--;
redraw_cur_line();
}
if (--cnt)
@@ -371,8 +392,8 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
}
G.current_byte -= 16;
up:
- if (row != 0) {
- row--;
+ if (G.row != 0) {
+ G.row--;
printf(ESC"[A"); /* up (won't scroll) */
} else {
//printf(ESC"[T"); /* scroll up */ - not implemented on Linux VT!
@@ -382,8 +403,12 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
if (--cnt)
goto k_up;
break;
- }
- }
+ case CTRL('X'):
+ restore_term();
+ return EXIT_SUCCESS;
+ } /* switch */
+ } /* for (;;) */
+ /* not reached */
return EXIT_SUCCESS;
}