From d54f58d487bfa5d6646d9a728d503351691081bf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Sep 2017 10:51:12 +0200 Subject: [PATCH] hexedit: implement "[enter] goto offset" key This is a must if you need to edit sector 123456789999 on your /dev/disk. text data bss dec hex filename 922745 481 6832 930058 e310a busybox_old 923023 481 6832 930336 e3220 busybox_unstripped Signed-off-by: Denys Vlasenko --- miscutils/hexedit.c | 79 +++++++++++++++++++++++++++++++-------------- miscutils/less.c | 4 +-- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c index b8627e826..eaf4ba57b 100644 --- a/miscutils/hexedit.c +++ b/miscutils/hexedit.c @@ -17,7 +17,8 @@ #define ESC "\033" #define HOME ESC"[H" -#define CLEAR ESC"[H"ESC"[J" +#define CLEAR ESC"[J" +#define CLEAR_TILL_EOL ESC"[K" #define SET_ALT_SCR ESC"[?1049h" #define POP_ALT_SCR ESC"[?1049l" @@ -30,7 +31,7 @@ struct globals { int fd; unsigned height; unsigned row; - uint8_t *addr; + uint8_t *baseaddr; uint8_t *current_byte; uint8_t *eof_byte; off_t size; @@ -117,14 +118,15 @@ static void redraw(void) { uint8_t *data; off_t offset; - unsigned i; + unsigned i, pos; - data = G.addr; - offset = 0; - i = 0; + printf(HOME CLEAR); + data = G.baseaddr; + offset = G.offset; + pos = i = 0; while (i < G.height) { char buf[LINEBUF_SIZE]; - format_line(buf, data, offset); + pos = format_line(buf, data, offset); printf( "\r\n%s" + (!i)*2, /* print \r\n only on 2nd line and later */ buf @@ -133,6 +135,7 @@ static void redraw(void) offset += 16; i++; } + printf(ESC"[1;%uH", pos + 1); /* position on 1st hex byte in first line */ } static void redraw_cur_line(void) @@ -144,7 +147,7 @@ static void redraw_cur_line(void) column = (0xf & (uintptr_t)G.current_byte); data = G.current_byte - column; - offset = G.offset + (data - G.addr); + offset = G.offset + (data - G.baseaddr); column = column*3 + G.half; column += format_line(buf, data, offset); @@ -158,28 +161,28 @@ static void redraw_cur_line(void) static void remap(unsigned cur_pos) { - if (G.addr) - munmap(G.addr, G_mapsize); + if (G.baseaddr) + munmap(G.baseaddr, G_mapsize); - G.addr = mmap(NULL, + G.baseaddr = mmap(NULL, G_mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, G.fd, G.offset ); - if (G.addr == MAP_FAILED) { + if (G.baseaddr == MAP_FAILED) { restore_term(); bb_perror_msg_and_die("mmap"); } - G.current_byte = G.addr + cur_pos; + G.current_byte = G.baseaddr + cur_pos; - G.eof_byte = G.addr + G_mapsize; + G.eof_byte = G.baseaddr + G_mapsize; if ((G.size - G.offset) < G_mapsize) { /* mapping covers tail of the file */ /* we do have a mapped byte which is past eof */ - G.eof_byte = G.addr + (G.size - G.offset); + G.eof_byte = G.baseaddr + (G.size - G.offset); } } static void move_mapping_further(void) @@ -191,7 +194,7 @@ static void move_mapping_further(void) return; /* can't move mapping even further, it's at the end already */ pagesize = getpagesize(); /* constant on most arches */ - pos = G.current_byte - G.addr; + pos = G.current_byte - G.baseaddr; if (pos >= pagesize) { /* move offset up until current position is in 1st page */ do { @@ -214,7 +217,7 @@ static void move_mapping_lower(void) return; /* we are at 0 already */ pagesize = getpagesize(); /* constant on most arches */ - pos = G.current_byte - G.addr; + pos = G.current_byte - G.baseaddr; /* move offset down until current position is in last page */ pos += pagesize; @@ -252,18 +255,15 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv) G.size = xlseek(G.fd, 0, SEEK_END); /* TERMIOS_RAW_CRNL suppresses \n -> \r\n translation, helps with down-arrow */ + printf(SET_ALT_SCR); set_termios_to_raw(STDIN_FILENO, &G.orig_termios, TERMIOS_RAW_CRNL); bb_signals(BB_FATAL_SIGS, sig_catcher); remap(0); - - printf(SET_ALT_SCR); redraw(); - printf(ESC"[1;10H"); /* position on 1st hex byte in first line */ //TODO: //Home/End: start/end of line; '<'/'>': start/end of file //Backspace: undo - //Enter: goto specified position //Ctrl-L: redraw //Ctrl-Z: suspend //'/', Ctrl-S: search @@ -367,9 +367,9 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv) } if ((0xf & (uintptr_t)G.current_byte) == 0) { /* leftmost pos, wrap to prev line */ - if (G.current_byte == G.addr) { + if (G.current_byte == G.baseaddr) { move_mapping_lower(); - if (G.current_byte == G.addr) + if (G.current_byte == G.baseaddr) break; /* first line, don't do anything */ } G.half = 1; @@ -385,9 +385,9 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv) cnt = G.height; case KEYCODE_UP: k_up: - if ((G.current_byte - G.addr) < 16) { + if ((G.current_byte - G.baseaddr) < 16) { move_mapping_lower(); - if ((G.current_byte - G.addr) < 16) + if ((G.current_byte - G.baseaddr) < 16) break; } G.current_byte -= 16; @@ -403,6 +403,35 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv) if (--cnt) goto k_up; break; + + case '\n': + case '\r': + /* [Enter]: goto specified position */ + { + char buf[sizeof(G.offset)*3 + 4]; + printf(ESC"[999;1H" CLEAR_TILL_EOL); /* go to last line */ + if (read_line_input(NULL, "Go to (dec,0Xhex,0oct): ", buf, sizeof(buf)) >= 0) { + off_t t; + unsigned pgmask; + + t = bb_strtoull(buf, NULL, 0); + if (t >= G.size) + t = G.size - 1; + pgmask = getpagesize() - 1; + cnt = t & pgmask; + t = t & ~(off_t)pgmask; + if (t < 0) + cnt = t = 0; + G.offset = t; + remap(0); + redraw(); + cnt /= 16; + if (cnt) + goto k_down; + break; + } + /* EOF/error on input: fall through to exiting */ + } case CTRL('X'): restore_term(); return EXIT_SUCCESS; diff --git a/miscutils/less.c b/miscutils/less.c index f869a9e82..d524b6c87 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -281,9 +281,9 @@ static void set_tty_cooked(void) /* Move the cursor to a position (x,y), where (0,0) is the top-left corner of the console */ -static void move_cursor(int line, int row) +static void move_cursor(int line, int col) { - printf(ESC"[%u;%uH", line, row); + printf(ESC"[%u;%uH", line, col); } static void clear_line(void)