From b175946ba4426c4bb529f9b98f75105e21208c83 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 20 Jun 2008 20:20:54 +0000 Subject: [PATCH] vi: fix the bug where vi never grows the edit buffer. vi: do G trick on it function old new delta place_cursor 264 276 +12 next_tabstop 22 34 +12 mycmp 44 52 +8 status_line 34 40 +6 yank_delete 89 92 +3 what_reg 34 37 +3 suspend_sig 63 66 +3 find_range 493 496 +3 redraw 104 106 +2 cont_sig 63 65 +2 Indicate_Error 59 61 +2 status_line_bold 71 72 +1 file_insert 327 328 +1 vi_setops 1 - -1 ... cmdcnt 4 - -4 chars_to_parse 4 - -4 ccol 4 - -4 dot_scroll 88 79 -9 stupid_insert 28 18 -10 winch_sig 102 91 -11 char_insert 353 336 -17 readit 354 336 -18 get_one_char 128 110 -18 init_text_buffer 171 152 -19 text_hole_delete 132 112 -20 edit_file 940 918 -22 get_input_line 198 168 -30 show_status_line 449 408 -41 colon 3112 3067 -45 vi_main 312 250 -62 refresh 1077 974 -103 do_cmd 4818 4483 -335 ------------------------------------------------------------------------------ (add/remove: 0/38 grow/shrink: 13/20 up/down: 58/-889) Total: -831 bytes text data bss dec hex filename 809566 612 7044 817222 c7846 busybox_old 808794 611 6924 816329 c74c9 busybox_unstripped text data bss dec hex filename 18888 1 122 19011 4a43 busybox.t8/editors/vi.o 18116 0 0 18116 46c4 busybox.t9/editors/vi.o --- editors/vi.c | 273 +++++++++++++++++++++++++++++---------------------- 1 file changed, 153 insertions(+), 120 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 1770d98c5..17ce88b93 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -112,11 +112,19 @@ enum { S_END_ALNUM = 5, // used in skip_thing() for moving "dot" }; + /* vi.c expects chars to be unsigned. */ /* busybox build system provides that, but it's better */ /* to audit and fix the source */ -static smallint vi_setops; +struct globals { + /* many references - keep near the top of globals */ + char *text, *end; // pointers to the user data in memory + char *dot; // where all the action takes place + int text_size; // size of the allocated buffer + + /* the rest */ + smallint vi_setops; #define VI_AUTOINDENT 1 #define VI_SHOWMATCH 2 #define VI_IGNORECASE 4 @@ -127,83 +135,76 @@ static smallint vi_setops; /* indicate error with beep or flash */ #define err_method (vi_setops & VI_ERR_METHOD) - -static smallint editing; // >0 while we are editing a file - // [code audit says "can be 0 or 1 only"] -static smallint cmd_mode; // 0=command 1=insert 2=replace -static smallint file_modified; // buffer contents changed -static smallint last_file_modified = -1; -static int fn_start; // index of first cmd line file name -static int save_argc; // how many file names on cmd line -static int cmdcnt; // repetition count -static unsigned rows, columns; // the terminal screen is this size -static int crow, ccol; // cursor is on Crow x Ccol -static int offset; // chars scrolled off the screen to the left -static char *status_buffer; // mesages to the user -#define STATUS_BUFFER_LEN 200 -static int have_status_msg; // is default edit status needed? - // [don't make smallint!] -static int last_status_cksum; // hash of current status line -static char *current_filename; // current file name -//static char *text, *end; // pointers to the user data in memory -static char *screen; // pointer to the virtual screen buffer -static int screensize; // and its size -static char *screenbegin; // index into text[], of top line on the screen -//static char *dot; // where all the action takes place -static int tabstop; -static char erase_char; // the users erase character -static char last_input_char; // last char read from user -static char last_forward_char; // last char searched for with 'f' - #if ENABLE_FEATURE_VI_READONLY -//static smallint vi_readonly, readonly; -static smallint readonly_mode = 0; + smallint readonly_mode; #define SET_READONLY_FILE(flags) ((flags) |= 0x01) #define SET_READONLY_MODE(flags) ((flags) |= 0x02) #define UNSET_READONLY_FILE(flags) ((flags) &= 0xfe) #else -#define readonly_mode 0 -#define SET_READONLY_FILE(flags) -#define SET_READONLY_MODE(flags) -#define UNSET_READONLY_FILE(flags) +#define SET_READONLY_FILE(flags) ((void)0) +#define SET_READONLY_MODE(flags) ((void)0) +#define UNSET_READONLY_FILE(flags) ((void)0) #endif + smallint editing; // >0 while we are editing a file + // [code audit says "can be 0 or 1 only"] + smallint cmd_mode; // 0=command 1=insert 2=replace + int file_modified; // buffer contents changed (counter, not flag!) + int last_file_modified; // = -1; + int fn_start; // index of first cmd line file name + int save_argc; // how many file names on cmd line + int cmdcnt; // repetition count + unsigned rows, columns; // the terminal screen is this size + int crow, ccol; // cursor is on Crow x Ccol + int offset; // chars scrolled off the screen to the left + int have_status_msg; // is default edit status needed? + // [don't make smallint!] + int last_status_cksum; // hash of current status line + char *current_filename; + char *screenbegin; // index into text[], of top line on the screen + char *screen; // pointer to the virtual screen buffer + int screensize; // and its size + int tabstop; + char erase_char; // the users erase character + char last_input_char; // last char read from user + char last_forward_char; // last char searched for with 'f' + #if ENABLE_FEATURE_VI_DOT_CMD -static smallint adding2q; // are we currently adding user input to q -static char *last_modifying_cmd; // [MAX_INPUT_LEN] last modifying cmd for "." -static smallint lmc_len; // length of last_modifying_cmd -static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" + smallint adding2q; // are we currently adding user input to q + int lmc_len; // length of last_modifying_cmd + char *ioq, *ioq_start; // pointer to string for get_one_char to "read" #endif #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR -static int last_row; // where the cursor was last moved to + int last_row; // where the cursor was last moved to #endif #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME -static int my_pid; + int my_pid; #endif #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK -static char *modifying_cmds; // cmds that modify text[] + char *modifying_cmds; // cmds that modify text[] #endif #if ENABLE_FEATURE_VI_SEARCH -static char *last_search_pattern; // last pattern from a '/' or '?' search + char *last_search_pattern; // last pattern from a '/' or '?' search #endif + int chars_to_parse; + /* former statics */ +#if ENABLE_FEATURE_VI_YANKMARK + char *edit_file__cur_line; +#endif + int refresh__old_offset; + int format_edit_status__tot; -/* Moving biggest data to malloced space... */ -struct globals { - /* many references - keep near the top of globals */ - char *text, *end; // pointers to the user data in memory - char *dot; // where all the action takes place - int text_size; // size of the allocated buffer + /* a few references only */ #if ENABLE_FEATURE_VI_YANKMARK int YDreg, Ureg; // default delete register and orig line for "U" char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' char *context_start, *context_end; #endif - /* a few references only */ #if ENABLE_FEATURE_VI_USE_SIGNALS - sigjmp_buf restart; // catch_sig() + sigjmp_buf restart; // catch_sig() #endif - struct termios term_orig, term_vi; // remember what the cooked mode was + struct termios term_orig, term_vi; // remember what the cooked mode was #if ENABLE_FEATURE_VI_COLON char *initial_cmds[3]; // currently 2 entries, NULL terminated #endif @@ -214,6 +215,12 @@ struct globals { #else char readbuffer[32]; #endif +#define STATUS_BUFFER_LEN 200 + char status_buffer[STATUS_BUFFER_LEN]; // messages to the user +#if ENABLE_FEATURE_VI_DOT_CMD + char last_modifying_cmd[MAX_INPUT_LEN]; // last modifying cmd for "." +#endif + char get_input_line__buf[MAX_INPUT_LEN]; /* former static */ char scr_out_buf[MAX_SCR_COLS + MAX_TABSTOP * 2]; }; @@ -223,6 +230,50 @@ struct globals { #define end (G.end ) #define dot (G.dot ) #define reg (G.reg ) + +#define vi_setops (G.vi_setops ) +#define editing (G.editing ) +#define cmd_mode (G.cmd_mode ) +#define file_modified (G.file_modified ) +#define last_file_modified (G.last_file_modified ) +#define fn_start (G.fn_start ) +#define save_argc (G.save_argc ) +#define cmdcnt (G.cmdcnt ) +#define rows (G.rows ) +#define columns (G.columns ) +#define crow (G.crow ) +#define ccol (G.ccol ) +#define offset (G.offset ) +#define status_buffer (G.status_buffer ) +#define have_status_msg (G.have_status_msg ) +#define last_status_cksum (G.last_status_cksum ) +#define current_filename (G.current_filename ) +#define screen (G.screen ) +#define screensize (G.screensize ) +#define screenbegin (G.screenbegin ) +#define tabstop (G.tabstop ) +#define erase_char (G.erase_char ) +#define last_input_char (G.last_input_char ) +#define last_forward_char (G.last_forward_char ) +#if ENABLE_FEATURE_VI_READONLY +#define readonly_mode (G.readonly_mode ) +#else +#define readonly_mode 0 readonly_mode ) +#endif +#define adding2q (G.adding2q ) +#define lmc_len (G.lmc_len ) +#define ioq (G.ioq ) +#define ioq_start (G.ioq_start ) +#define last_row (G.last_row ) +#define my_pid (G.my_pid ) +#define modifying_cmds (G.modifying_cmds ) +#define last_search_pattern (G.last_search_pattern) +#define chars_to_parse (G.chars_to_parse ) + +#define edit_file__cur_line (G.edit_file__cur_line) +#define refresh__old_offset (G.refresh__old_offset) +#define format_edit_status__tot (G.format_edit_status__tot) + #define YDreg (G.YDreg ) #define Ureg (G.Ureg ) #define mark (G.mark ) @@ -234,10 +285,15 @@ struct globals { #define initial_cmds (G.initial_cmds ) #define readbuffer (G.readbuffer ) #define scr_out_buf (G.scr_out_buf ) +#define last_modifying_cmd (G.last_modifying_cmd ) +#define get_input_line__buf (G.get_input_line__buf) + #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + last_file_modified = -1; \ } while (0) + static int init_text_buffer(char *); // init from file or create new static void edit_file(char *); // edit one file static void do_cmd(char); // execute a command @@ -355,22 +411,15 @@ int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vi_main(int argc, char **argv) { int c; - RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); + + INIT_G(); #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME my_pid = getpid(); #endif - - INIT_G(); - #if ENABLE_FEATURE_VI_CRASHME srand((long) my_pid); #endif - - status_buffer = STATUS_BUFFER; - last_status_cksum = 0; - text = NULL; - #ifdef NO_SUCH_APPLET_YET /* If we aren't "vi", we are "view" */ if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) { @@ -379,9 +428,6 @@ int vi_main(int argc, char **argv) #endif vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; -#if ENABLE_FEATURE_VI_YANKMARK - memset(reg, 0, sizeof(reg)); // init the yank regs -#endif #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] #endif @@ -417,7 +463,6 @@ int vi_main(int argc, char **argv) case 'H': show_help(); /* fall through */ - default: bb_show_usage(); return 1; @@ -451,9 +496,7 @@ static int init_text_buffer(char *fn) /* allocate/reallocate text buffer */ free(text); - text_size = size * 2; - if (text_size < 10240) - text_size = 10240; // have a minimum size for new files + text_size = size + 10240; screenbegin = dot = end = text = xzalloc(text_size); if (fn != current_filename) { @@ -479,15 +522,14 @@ static int init_text_buffer(char *fn) static void edit_file(char *fn) { +#if ENABLE_FEATURE_VI_YANKMARK +#define cur_line edit_file__cur_line +#endif char c; int size; - #if ENABLE_FEATURE_VI_USE_SIGNALS int sig; #endif -#if ENABLE_FEATURE_VI_YANKMARK - static char *cur_line; -#endif editing = 1; // 0 = exit, 1 = one file, 2 = multiple files rawmode(); @@ -606,6 +648,7 @@ static void edit_file(char *fn) place_cursor(rows, 0, FALSE); // go to bottom of screen clear_to_eol(); // Erase to end of line cookmode(); +#undef cur_line } //----- The Colon commands ------------------------------------- @@ -1611,7 +1654,7 @@ static char *char_insert(char * p, char c) // insert the char c at 'p' c = get_one_char(); *p = c; p++; - file_modified++; // has the file been modified + file_modified++; } else if (c == 27) { // Is this an ESC? cmd_mode = 0; cmdcnt = 0; @@ -1654,12 +1697,9 @@ static char *char_insert(char * p, char c) // insert the char c at 'p' static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p' { p = text_hole_make(p, 1); - if (p != 0) { - *p = c; - file_modified++; // has the file been modified - p++; - } - return p; + *p = c; + //file_modified++; - done by text_hole_make() + return p + 1; } static int find_range(char ** start, char ** stop, char c) @@ -1842,24 +1882,21 @@ static void showmatching(char *p) // open a hole in text[] static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte hole { - char *src, *dest; - int cnt; - if (size <= 0) - goto thm0; - src = p; - dest = p + size; - cnt = end - src; // the rest of buffer - if ( ((end + size) >= (text + text_size)) // TODO: realloc here - || memmove(dest, src, cnt) != dest) { - status_line_bold("can't create room for new characters"); - p = NULL; - goto thm0; + return p; + end += size; // adjust the new END + if (end >= (text + text_size)) { + char *new_text; + text_size += end - (text + text_size) + 10240; + new_text = xrealloc(text, text_size); + screenbegin = new_text + (screenbegin - text); + dot = new_text + (dot - text); + end = new_text + (end - text); + p = new_text + (p - text); + text = new_text; } memset(p, ' ', size); // clear new hole - end += size; // adjust the new END - file_modified++; // has the file been modified - thm0: + file_modified++; return p; } @@ -1885,16 +1922,14 @@ static char *text_hole_delete(char * p, char * q) // delete "p" through "q", inc goto thd0; if (src >= end) goto thd_atend; // just delete the end of the buffer - if (memmove(dest, src, cnt) != dest) { - status_line_bold("can't delete the character"); - } + memmove(dest, src, cnt); thd_atend: end = end - hole_size; // adjust the new END if (dest >= end) dest = end - 1; // make sure dest in below end-1 if (end <= text) dest = end = text; // keep pointers valid - file_modified++; // has the file been modified + file_modified++; thd0: return dest; } @@ -1973,8 +2008,6 @@ static void show_help(void) static void start_new_cmd_q(char c) { // get buffer for new cmd - if (!last_modifying_cmd) - last_modifying_cmd = xzalloc(MAX_INPUT_LEN); // if there is a current cmd count put it in the buffer first if (cmdcnt > 0) lmc_len = sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); @@ -2164,8 +2197,6 @@ static int mysleep(int hund) // sleep for 'h' 1/100 seconds return safe_poll(pfd, 1, hund*10) > 0; } -static int chars_to_parse; - //----- IO Routines -------------------------------------------- static char readit(void) // read (maybe cursor) key from stdin { @@ -2300,13 +2331,11 @@ static char get_one_char(void) } else { // adding STDIN chars to q c = readit(); // get the users input - if (last_modifying_cmd != NULL) { - if (lmc_len >= MAX_INPUT_LEN - 1) { - status_line_bold("last_modifying_cmd overrun"); - } else { - // add new char to q - last_modifying_cmd[lmc_len++] = c; - } + if (lmc_len >= MAX_INPUT_LEN - 1) { + status_line_bold("last_modifying_cmd overrun"); + } else { + // add new char to q + last_modifying_cmd[lmc_len++] = c; } } #else @@ -2318,13 +2347,12 @@ static char get_one_char(void) // Get input line (uses "status line" area) static char *get_input_line(const char *prompt) { - static char *buf; // [MAX_INPUT_LEN] + // char [MAX_INPUT_LEN] +#define buf get_input_line__buf char c; int i; - if (!buf) buf = xmalloc(MAX_INPUT_LEN); - strcpy(buf, prompt); last_status_cksum = 0; // force status update place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen @@ -2350,6 +2378,7 @@ static char *get_input_line(const char *prompt) } refresh(FALSE); return buf; +#undef buf } static int file_size(const char *fn) // what is the byte size of "fn" @@ -2451,7 +2480,7 @@ static int file_write(char * fn, char * first, char * last) ftruncate(fd, charcnt); if (charcnt == cnt) { // good write - //file_modified = FALSE; // the file has not been modified + //file_modified = FALSE; } else { charcnt = 0; } @@ -2701,8 +2730,10 @@ static void not_implemented(const char *s) // show file status on status line static int format_edit_status(void) { - static int tot; static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; + +#define tot format_edit_status__tot + int cur, percent, ret, trunc_at; // file_modified is now a counter rather than a flag. this @@ -2753,13 +2784,14 @@ static int format_edit_status(void) return ret; /* it all fit */ return trunc_at; /* had to truncate */ +#undef tot } //----- Force refresh of all Lines ----------------------------- static void redraw(int full_screen) { place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display + clear_to_eos(); // tell terminal to erase display screen_erase(); // erase the internal screen buffer last_status_cksum = 0; // force status update refresh(full_screen); // this will redraw the entire display @@ -2831,7 +2863,7 @@ static char* format_line(char *src /*, int li*/) // static void refresh(int full_screen) { - static int old_offset; +#define old_offset refresh__old_offset int li, changed; char *tp, *sp; // pointer into text[] and screen[] @@ -2919,6 +2951,7 @@ static void refresh(int full_screen) place_cursor(crow, ccol, TRUE); old_offset = offset; +#undef old_offset } //--------------------------------------------------------------------- @@ -3276,7 +3309,7 @@ static void do_cmd(char c) case '.': // .- repeat the last modifying command // Stuff the last_modifying_cmd back into stdin // and let it be re-executed. - if (last_modifying_cmd != NULL && lmc_len > 0) { + if (lmc_len > 0) { last_modifying_cmd[lmc_len] = 0; ioq = ioq_start = xstrdup(last_modifying_cmd); } @@ -3750,7 +3783,7 @@ static void do_cmd(char c) c1 = get_one_char(); // get the replacement char if (*dot != '\n') { *dot = c1; - file_modified++; // has the file been modified + file_modified++; } end_cmd_q(); // stop adding to q break; @@ -3795,10 +3828,10 @@ static void do_cmd(char c) } // repeat cnt if (islower(*dot)) { *dot = toupper(*dot); - file_modified++; // has the file been modified + file_modified++; } else if (isupper(*dot)) { *dot = tolower(*dot); - file_modified++; // has the file been modified + file_modified++; } dot_right(); end_cmd_q(); // stop adding to q