Vladimir N. Oleynik writes:
[oweals/busybox.git] / editors / vi.c
index 1275d133b0a74df6abfa7ed92c62060629e2678a..57b011444bc4d3b512fafd6c4b81b91731537336 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 static const char vi_Version[] =
-       "$Id: vi.c,v 1.24 2002/10/26 10:19:19 andersen Exp $";
+       "$Id: vi.c,v 1.32 2004/02/04 11:19:44 andersen Exp $";
 
 /*
  * To compile for standalone use:
@@ -87,6 +87,12 @@ static const char vi_Version[] =
 #include "busybox.h"
 #endif                                                 /* STANDALONE */
 
+#ifdef CONFIG_LOCALE_SUPPORT
+#define Isprint(c) isprint((c))
+#else
+#define Isprint(c) ( (c) >= ' ' && (c) != 127 && (c) != ((unsigned char)'\233') )
+#endif
+
 #ifndef TRUE
 #define TRUE                   ((int)1)
 #define FALSE                  ((int)0)
@@ -116,6 +122,22 @@ static const char vi_Version[] =
 #define VI_K_FUN11             147     // Function Key F11
 #define VI_K_FUN12             148     // Function Key F12
 
+/* vt102 typical ESC sequence */
+/* terminal standout start/normal ESC sequence */
+static const char SOs[] = "\033[7m";
+static const char SOn[] = "\033[0m";
+/* terminal bell sequence */
+static const char bell[] = "\007";
+/* Clear-end-of-line and Clear-end-of-screen ESC sequence */
+static const char Ceol[] = "\033[0K";
+static const char Ceos [] = "\033[0J";
+/* Cursor motion arbitrary destination ESC sequence */
+static const char CMrc[] = "\033[%d;%dH";
+/* Cursor motion up and down ESC sequence */
+static const char CMup[] = "\033[A";
+static const char CMdown[] = "\n";
+
+
 static const int YANKONLY = FALSE;
 static const int YANKDEL = TRUE;
 static const int FORWARD = 1;  // code depends on "1"  for array index
@@ -131,27 +153,29 @@ static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot"
 
 typedef unsigned char Byte;
 
+static int vi_setops;
+#define VI_AUTOINDENT 1
+#define VI_SHOWMATCH  2
+#define VI_IGNORECASE 4
+#define VI_ERR_METHOD 8
+#define autoindent (vi_setops & VI_AUTOINDENT)
+#define showmatch  (vi_setops & VI_SHOWMATCH )
+#define ignorecase (vi_setops & VI_IGNORECASE)
+/* indicate error with beep or flash */
+#define err_method (vi_setops & VI_ERR_METHOD)
+
 
 static int editing;            // >0 while we are editing a file
 static int cmd_mode;           // 0=command  1=insert
 static int file_modified;      // buffer contents changed
-static int err_method;         // indicate error with beep or flash
 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 fd_set rfds;            // use select() for small sleeps
 static struct timeval tv;      // use select() for small sleeps
-static char erase_char;                // the users erase character
 static int rows, columns;      // the terminal screen is this size
 static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
-static char *SOs, *SOn;                // terminal standout start/normal ESC sequence
-static char *bell;             // terminal bell sequence
-static char *Ceol, *Ceos;      // Clear-end-of-line and Clear-end-of-screen ESC sequence
-static char *CMrc;             // Cursor motion arbitrary destination ESC sequence
-static char *CMup, *CMdown;    // Cursor motion up and down ESC sequence
 static Byte *status_buffer;    // mesages to the user
-static Byte last_input_char;   // last char read from user
-static Byte last_forward_char; // last char searched for with 'f'
 static Byte *cfn;              // previous, current, and next file name
 static Byte *text, *end, *textend;     // pointers to the user data in memory
 static Byte *screen;           // pointer to the virtual screen buffer
@@ -160,6 +184,9 @@ static Byte *screenbegin;   // index into text[], of top line on the screen
 static Byte *dot;              // where all the action takes place
 static int tabstop;
 static struct termios term_orig, term_vi;      // remember what the cooked mode was
+static Byte erase_char;         // the users erase character
+static Byte last_input_char;    // last char read from user
+static Byte last_forward_char;  // last char searched for with 'f'
 
 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
 static int last_row;           // where the cursor was last moved to
@@ -167,9 +194,9 @@ static int last_row;                // where the cursor was last moved to
 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
 static jmp_buf restart;                // catch_sig()
 #endif                                                 /* CONFIG_FEATURE_VI_USE_SIGNALS */
-#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
-static struct winsize winsize; // remember the window size
-#endif                                                 /* CONFIG_FEATURE_VI_WIN_RESIZE */
+#if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME)
+static int my_pid;
+#endif
 #ifdef CONFIG_FEATURE_VI_DOT_CMD
 static int adding2q;           // are we currently adding user input to q
 static Byte *last_modifying_cmd;       // last modifying cmd for "."
@@ -181,11 +208,6 @@ static Byte *modifying_cmds;       // cmds that modify text[]
 #ifdef CONFIG_FEATURE_VI_READONLY
 static int vi_readonly, readonly;
 #endif                                                 /* CONFIG_FEATURE_VI_READONLY */
-#ifdef CONFIG_FEATURE_VI_SETOPTS
-static int autoindent;
-static int showmatch;
-static int ignorecase;
-#endif                                                 /* CONFIG_FEATURE_VI_SETOPTS */
 #ifdef CONFIG_FEATURE_VI_YANKMARK
 static Byte *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
 static int YDreg, Ureg;                // default delete register and orig line for "U"
@@ -202,7 +224,6 @@ static void do_cmd(Byte);   // execute a command
 static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot
 static Byte *begin_line(Byte *);       // return pointer to cur line B-o-l
 static Byte *end_line(Byte *); // return pointer to cur line E-o-l
-extern inline Byte *dollar_line(Byte *);       // return pointer to just before NL
 static Byte *prev_line(Byte *);        // return pointer to prev line B-o-l
 static Byte *next_line(Byte *);        // return pointer to next line B-o-l
 static Byte *end_screen(void); // get pointer to last char on screen
@@ -232,13 +253,12 @@ static Byte *text_hole_delete(Byte *, Byte *);    // at "p", delete a 'size' byte h
 static Byte *text_hole_make(Byte *, int);      // at "p", make a 'size' byte hole
 static Byte *yank_delete(Byte *, Byte *, int, int);    // yank text[] into register then delete
 static void show_help(void);   // display some help info
-extern inline void print_literal(Byte *, Byte *);      // copy s to buf, convert unprintable
 static void rawmode(void);     // set "raw" mode on tty
 static void cookmode(void);    // return to "cooked" mode on tty
 static int mysleep(int);       // sleep for 'h' 1/100 seconds
 static Byte readit(void);      // read (maybe cursor) key from stdin
 static Byte get_one_char(void);        // read 1 char from stdin
-static int file_size(Byte *);  // what is the byte size of "fn"
+static int file_size(const Byte *);   // what is the byte size of "fn"
 static int file_insert(Byte *, Byte *, int);
 static int file_write(Byte *, Byte *, Byte *);
 static void place_cursor(int, int, int);
@@ -248,17 +268,18 @@ static void clear_to_eos(void);
 static void standout_start(void);      // send "start reverse video" sequence
 static void standout_end(void);        // send "end reverse video" sequence
 static void flash(int);                // flash the terminal screen
-static void beep(void);                // beep the terminal
-static void indicate_error(char);      // use flash or beep to indicate error
 static void show_status_line(void);    // put a message on the bottom line
-static void psb(char *, ...);  // Print Status Buf
-static void psbs(char *, ...); // Print Status Buf in standout mode
+static void psb(const char *, ...);     // Print Status Buf
+static void psbs(const char *, ...);    // Print Status Buf in standout mode
 static void ni(Byte *);                // display messages
 static void edit_status(void); // show file status on status line
 static void redraw(int);       // force a full screen refresh
 static void format_line(Byte*, Byte*, int);
 static void refresh(int);      // update the terminal from screen[]
 
+static void Indicate_Error(void);       // use flash or beep to indicate error
+#define indicate_error(c) Indicate_Error()
+
 #ifdef CONFIG_FEATURE_VI_SEARCH
 static Byte *char_search(Byte *, Byte *, int, int);    // search for pattern starting at p
 static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
@@ -269,12 +290,10 @@ static Byte *get_one_address(Byte *, int *);      // get colon addr, if present
 static Byte *get_address(Byte *, int *, int *);        // get two colon addrs, if present
 static void colon(Byte *);     // execute the "colon" mode cmds
 #endif                                                 /* CONFIG_FEATURE_VI_COLON */
-static Byte *get_input_line(Byte *);   // get input line- use "status line"
 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
 static void winch_sig(int);    // catch window size changes
 static void suspend_sig(int);  // catch ctrl-Z
-static void alarm_sig(int);    // catch alarm time-outs
-static void catch_sig(int);    // catch ctrl-C
+static void catch_sig(int);     // catch ctrl-C and alarm time-outs
 static void core_sig(int);     // catch a core dump signal
 #endif                                                 /* CONFIG_FEATURE_VI_USE_SIGNALS */
 #ifdef CONFIG_FEATURE_VI_DOT_CMD
@@ -296,7 +315,6 @@ static Byte *string_insert(Byte *, Byte *); // insert the string at 'p'
 static Byte *text_yank(Byte *, Byte *, int);   // save copy of "p" into a register
 static Byte what_reg(void);            // what is letter of current YDreg
 static void check_context(Byte);       // remember context for '' command
-extern inline Byte *swap_context(Byte *);      // goto new context for '' command
 #endif                                                 /* CONFIG_FEATURE_VI_YANKMARK */
 #ifdef CONFIG_FEATURE_VI_CRASHME
 static void crash_dummy();
@@ -305,26 +323,28 @@ static int crashme = 0;
 #endif                                                 /* CONFIG_FEATURE_VI_CRASHME */
 
 
+static void write1(const char *out)
+{
+       fputs(out, stdout);
+}
+
 extern int vi_main(int argc, char **argv)
 {
        int c;
+       RESERVE_CONFIG_BUFFER(STATUS_BUFFER, 200);
 
 #ifdef CONFIG_FEATURE_VI_YANKMARK
        int i;
 #endif                                                 /* CONFIG_FEATURE_VI_YANKMARK */
-
-       CMrc= "\033[%d;%dH";    // Terminal Crusor motion ESC sequence
-       CMup= "\033[A";         // move cursor up one line, same col
-       CMdown="\n";            // move cursor down one line, same col
-       Ceol= "\033[0K";        // Clear from cursor to end of line
-       Ceos= "\033[0J";        // Clear from cursor to end of screen
-       SOs = "\033[7m";        // Terminal standout mode on
-       SOn = "\033[0m";        // Terminal standout mode off
-       bell= "\007";           // Terminal bell sequence
+#if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME)
+       my_pid = getpid();
+#endif
 #ifdef CONFIG_FEATURE_VI_CRASHME
-       (void) srand((long) getpid());
+       (void) srand((long) my_pid);
 #endif                                                 /* CONFIG_FEATURE_VI_CRASHME */
-       status_buffer = (Byte *) xmalloc(200);  // hold messages to user
+
+       status_buffer = STATUS_BUFFER;
+
 #ifdef CONFIG_FEATURE_VI_READONLY
        vi_readonly = readonly = FALSE;
        if (strncmp(argv[0], "view", 4) == 0) {
@@ -332,11 +352,7 @@ extern int vi_main(int argc, char **argv)
                vi_readonly = TRUE;
        }
 #endif                                                 /* CONFIG_FEATURE_VI_READONLY */
-#ifdef CONFIG_FEATURE_VI_SETOPTS
-       autoindent = 1;
-       ignorecase = 1;
-       showmatch = 1;
-#endif                                                 /* CONFIG_FEATURE_VI_SETOPTS */
+       vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD;
 #ifdef CONFIG_FEATURE_VI_YANKMARK
        for (i = 0; i < 28; i++) {
                reg[i] = 0;
@@ -383,9 +399,8 @@ extern int vi_main(int argc, char **argv)
        } else {
                for (; optind < argc; optind++) {
                        editing = 1;    // 0=exit, 1=one file, 2+ =many files
-                       if (cfn != 0)
-                               free(cfn);
-                       cfn = (Byte *) xstrdup(argv[optind]);
+                       free(cfn);
+                       cfn = (Byte *) bb_xstrdup(argv[optind]);
                        edit_file(cfn);
                }
        }
@@ -394,13 +409,20 @@ extern int vi_main(int argc, char **argv)
        return (0);
 }
 
+#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
+//----- See what the window size currently is --------------------
+static inline void window_size_get(int fd)
+{
+       get_terminal_width_height(fd, &columns, &rows);
+}
+#endif                                                 /* CONFIG_FEATURE_VI_WIN_RESIZE */
+
 static void edit_file(Byte * fn)
 {
-       char c;
+       Byte c;
        int cnt, size, ch;
 
 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
-       char *msg;
        int sig;
 #endif                                                 /* CONFIG_FEATURE_VI_USE_SIGNALS */
 #ifdef CONFIG_FEATURE_VI_YANKMARK
@@ -436,33 +458,20 @@ static void edit_file(Byte * fn)
        mark[26] = mark[27] = text;     // init "previous context"
 #endif                                                 /* CONFIG_FEATURE_VI_YANKMARK */
 
-       err_method = 1;         // flash
        last_forward_char = last_input_char = '\0';
        crow = 0;
        ccol = 0;
        edit_status();
 
 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
-       signal(SIGHUP, catch_sig);
-       signal(SIGINT, catch_sig);
-       signal(SIGALRM, alarm_sig);
-       signal(SIGTERM, catch_sig);
-       signal(SIGQUIT, core_sig);
-       signal(SIGILL, core_sig);
-       signal(SIGTRAP, core_sig);
-       signal(SIGIOT, core_sig);
-       signal(SIGABRT, core_sig);
-       signal(SIGFPE, core_sig);
-       signal(SIGBUS, core_sig);
-       signal(SIGSEGV, core_sig);
-#ifdef SIGSYS
-       signal(SIGSYS, core_sig);
-#endif 
+       catch_sig(0);
+       core_sig(0);
        signal(SIGWINCH, winch_sig);
        signal(SIGTSTP, suspend_sig);
        sig = setjmp(restart);
        if (sig != 0) {
-               msg = "";
+               const char *msg = "";
+
                if (sig == SIGWINCH)
                        msg = "(window resize)";
                if (sig == SIGHUP)
@@ -490,15 +499,14 @@ static void edit_file(Byte * fn)
        offset = 0;                     // no horizontal offset
        c = '\0';
 #ifdef CONFIG_FEATURE_VI_DOT_CMD
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
-       if (ioq_start != NULL)
-               free(ioq_start);
+       free(last_modifying_cmd);
+       free(ioq_start);
        ioq = ioq_start = last_modifying_cmd = 0;
        adding2q = 0;
 #endif                                                 /* CONFIG_FEATURE_VI_DOT_CMD */
        redraw(FALSE);                  // dont force every col re-draw
        show_status_line();
+       fflush(stdout);
 
        //------This is the main Vi cmd handling loop -----------------------
        while (editing > 0) {
@@ -552,212 +560,6 @@ static void edit_file(Byte * fn)
        cookmode();
 }
 
-static Byte readbuffer[BUFSIZ];
-
-#ifdef CONFIG_FEATURE_VI_CRASHME
-static int totalcmds = 0;
-static int Mp = 85;            // Movement command Probability
-static int Np = 90;            // Non-movement command Probability
-static int Dp = 96;            // Delete command Probability
-static int Ip = 97;            // Insert command Probability
-static int Yp = 98;            // Yank command Probability
-static int Pp = 99;            // Put command Probability
-static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
-char chars[20] = "\t012345 abcdABCD-=.$";
-char *words[20] = { "this", "is", "a", "test",
-       "broadcast", "the", "emergency", "of",
-       "system", "quick", "brown", "fox",
-       "jumped", "over", "lazy", "dogs",
-       "back", "January", "Febuary", "March"
-};
-char *lines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-char *multilines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-
-// create a random command to execute
-static void crash_dummy()
-{
-       static int sleeptime;   // how long to pause between commands
-       char c, cm, *cmd, *cmd1;
-       int i, cnt, thing, rbi, startrbi, percent;
-
-       // "dot" movement commands
-       cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
-
-       // is there already a command running?
-       if (strlen((char *) readbuffer) > 0)
-               goto cd1;
-  cd0:
-       startrbi = rbi = 0;
-       sleeptime = 0;          // how long to pause between commands
-       memset(readbuffer, '\0', BUFSIZ - 1);   // clear the read buffer
-       // generate a command by percentages
-       percent = (int) lrand48() % 100;        // get a number from 0-99
-       if (percent < Mp) {     //  Movement commands
-               // available commands
-               cmd = cmd1;
-               M++;
-       } else if (percent < Np) {      //  non-movement commands
-               cmd = "mz<>\'\"";       // available commands
-               N++;
-       } else if (percent < Dp) {      //  Delete commands
-               cmd = "dx";             // available commands
-               D++;
-       } else if (percent < Ip) {      //  Inset commands
-               cmd = "iIaAsrJ";        // available commands
-               I++;
-       } else if (percent < Yp) {      //  Yank commands
-               cmd = "yY";             // available commands
-               Y++;
-       } else if (percent < Pp) {      //  Put commands
-               cmd = "pP";             // available commands
-               P++;
-       } else {
-               // We do not know how to handle this command, try again
-               U++;
-               goto cd0;
-       }
-       // randomly pick one of the available cmds from "cmd[]"
-       i = (int) lrand48() % strlen(cmd);
-       cm = cmd[i];
-       if (strchr(":\024", cm))
-               goto cd0;               // dont allow colon or ctrl-T commands
-       readbuffer[rbi++] = cm; // put cmd into input buffer
-
-       // now we have the command-
-       // there are 1, 2, and multi char commands
-       // find out which and generate the rest of command as necessary
-       if (strchr("dmryz<>\'\"", cm)) {        // 2-char commands
-               cmd1 = " \n\r0$^-+wWeEbBhjklHL";
-               if (cm == 'm' || cm == '\'' || cm == '\"') {    // pick a reg[]
-                       cmd1 = "abcdefghijklmnopqrstuvwxyz";
-               }
-               thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-               c = cmd1[thing];
-               readbuffer[rbi++] = c;  // add movement to input buffer
-       }
-       if (strchr("iIaAsc", cm)) {     // multi-char commands
-               if (cm == 'c') {
-                       // change some thing
-                       thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-                       c = cmd1[thing];
-                       readbuffer[rbi++] = c;  // add movement to input buffer
-               }
-               thing = (int) lrand48() % 4;    // what thing to insert
-               cnt = (int) lrand48() % 10;     // how many to insert
-               for (i = 0; i < cnt; i++) {
-                       if (thing == 0) {       // insert chars
-                               readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
-                       } else if (thing == 1) {        // insert words
-                               strcat((char *) readbuffer, words[(int) lrand48() % 20]);
-                               strcat((char *) readbuffer, " ");
-                               sleeptime = 0;  // how fast to type
-                       } else if (thing == 2) {        // insert lines
-                               strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       } else {        // insert multi-lines
-                               strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       }
-               }
-               strcat((char *) readbuffer, "\033");
-       }
-  cd1:
-       totalcmds++;
-       if (sleeptime > 0)
-               (void) mysleep(sleeptime);      // sleep 1/100 sec
-}
-
-// test to see if there are any errors
-static void crash_test()
-{
-       static time_t oldtim;
-       time_t tim;
-       char d[2], buf[BUFSIZ], msg[BUFSIZ];
-
-       msg[0] = '\0';
-       if (end < text) {
-               strcat((char *) msg, "end<text ");
-       }
-       if (end > textend) {
-               strcat((char *) msg, "end>textend ");
-       }
-       if (dot < text) {
-               strcat((char *) msg, "dot<text ");
-       }
-       if (dot > end) {
-               strcat((char *) msg, "dot>end ");
-       }
-       if (screenbegin < text) {
-               strcat((char *) msg, "screenbegin<text ");
-       }
-       if (screenbegin > end - 1) {
-               strcat((char *) msg, "screenbegin>end-1 ");
-       }
-
-       if (strlen(msg) > 0) {
-               alarm(0);
-               sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
-                       totalcmds, last_input_char, msg, SOs, SOn);
-               write(1, buf, strlen(buf));
-               while (read(0, d, 1) > 0) {
-                       if (d[0] == '\n' || d[0] == '\r')
-                               break;
-               }
-               alarm(3);
-       }
-       tim = (time_t) time((time_t *) 0);
-       if (tim >= (oldtim + 3)) {
-               sprintf((char *) status_buffer,
-                               "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
-                               totalcmds, M, N, I, D, Y, P, U, end - text + 1);
-               oldtim = tim;
-       }
-       return;
-}
-#endif                                                 /* CONFIG_FEATURE_VI_CRASHME */
-
 //----- The Colon commands -------------------------------------
 #ifdef CONFIG_FEATURE_VI_COLON
 static Byte *get_one_address(Byte * p, int *addr)      // get colon addr, if present
@@ -800,7 +602,7 @@ static Byte *get_one_address(Byte * p, int *addr)   // get colon addr, if present
                        *q++ = *p;
                        *q = '\0';
                }
-               pat = (Byte *) xstrdup((char *) buf);   // save copy of pattern
+               pat = (Byte *) bb_xstrdup((char *) buf);        // save copy of pattern
                if (*p == '/')
                        p++;
                q = char_search(dot, pat, FORWARD, FULL);
@@ -851,6 +653,23 @@ ga0:
        return (p);
 }
 
+#ifdef CONFIG_FEATURE_VI_SETOPTS
+static void setops(const Byte *args, const char *opname, int flg_no,
+                       const char *short_opname, int opt)
+{
+       const char *a = (char *) args + flg_no;
+       int l = strlen(opname) - 1; /* opname have + ' ' */
+
+       if (strncasecmp(a, opname, l) == 0 ||
+                       strncasecmp(a, short_opname, 2) == 0) {
+               if(flg_no)
+                       vi_setops &= ~opt;
+                else
+                       vi_setops |= opt;
+       }
+}
+#endif
+
 static void colon(Byte * buf)
 {
        Byte c, *orig_buf, *buf1, *q, *r;
@@ -997,9 +816,8 @@ static void colon(Byte * buf)
 
                // There is a read-able regular file
                // make this the current file
-               q = (Byte *) xstrdup((char *) fn);      // save the cfn
-               if (cfn != 0)
-                       free(cfn);              // free the old name
+               q = (Byte *) bb_xstrdup((char *) fn);   // save the cfn
+               free(cfn);              // free the old name
                cfn = q;                        // remember new cfn
 
          vc5:
@@ -1048,9 +866,8 @@ static void colon(Byte * buf)
                }
                if (strlen((char *) args) > 0) {
                        // user wants a new filename
-                       if (cfn != NULL)
-                               free(cfn);
-                       cfn = (Byte *) xstrdup((char *) args);
+                       free(cfn);
+                       cfn = (Byte *) bb_xstrdup((char *) args);
                } else {
                        // user wants file status info
                        edit_status();
@@ -1070,19 +887,27 @@ static void colon(Byte * buf)
                }
                place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
                clear_to_eol(); // clear the line
-               write(1, "\r\n", 2);
+               puts("\r");
                for (; q <= r; q++) {
+                       int c_is_no_print;
+
                        c = *q;
-                       if (c > '~')
+                       c_is_no_print = c > 127 && !Isprint(c);
+                       if (c_is_no_print) {
+                               c = '.';
                                standout_start();
+                               }
                        if (c == '\n') {
-                               write(1, "$\r", 2);
-                       } else if (*q < ' ') {
-                               write(1, "^", 1);
+                               write1("$\r");
+                       } else if (c < ' ' || c == 127) {
+                               putchar('^');
+                               if(c == 127)
+                                       c = '?';
+                                else
                                c += '@';
                        }
-                       write(1, &c, 1);
-                       if (c > '~')
+                       putchar(c);
+                       if (c_is_no_print)
                                standout_end();
                }
 #ifdef CONFIG_FEATURE_VI_SET
@@ -1190,23 +1015,11 @@ static void colon(Byte * buf)
                if (strncasecmp((char *) args, "no", 2) == 0)
                        i = 2;          // ":set noautoindent"
 #ifdef CONFIG_FEATURE_VI_SETOPTS
-               if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ai", 2) == 0) {
-                       autoindent = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
-                       strncasecmp((char *) args + i, "fl", 2) == 0) {
-                       err_method = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ic", 2) == 0) {
-                       ignorecase = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "showmatch", 9) == 0 ||
-                       strncasecmp((char *) args + i, "sm", 2) == 0) {
-                       showmatch = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "tabstop", 7) == 0) {
+               setops(args, "autoindent ", i, "ai", VI_AUTOINDENT);
+               setops(args, "flash ", i, "fl", VI_ERR_METHOD);
+               setops(args, "ignorecase ", i, "ic", VI_IGNORECASE);
+               setops(args, "showmatch ", i, "ic", VI_SHOWMATCH);
+               if (strncasecmp((char *) args + i, "tabstop=%d ", 7) == 0) {
                        sscanf(strchr((char *) args + i, '='), "=%d", &ch);
                        if (ch > 0 && ch < columns - 1)
                                tabstop = ch;
@@ -1323,9 +1136,7 @@ static void colon(Byte * buf)
 #ifdef CONFIG_FEATURE_VI_SEARCH
 colon_s_fail:
        psb(":s expression missing delimiters");
-       return;
 #endif
-
 }
 
 static void Hit_Return(void)
@@ -1333,7 +1144,7 @@ static void Hit_Return(void)
        char c;
 
        standout_start();       // start reverse video
-       write(1, "[Hit return to continue]", 24);
+       write1("[Hit return to continue]");
        standout_end();         // end reverse video
        while ((c = get_one_char()) != '\n' && c != '\r')       /*do nothing */
                ;
@@ -1397,7 +1208,7 @@ static void sync_cursor(Byte * d, int *row, int *col)
                if (*tp == '\t') {
                        //         7       - (co %    8  )
                        co += ((tabstop - 1) - (co % tabstop));
-               } else if (*tp < ' ') {
+               } else if (*tp < ' ' || *tp == 127) {
                        co++;           // display as ^X, use 2 columns
                }
        } while (tp++ < d && ++co);
@@ -1447,7 +1258,7 @@ static Byte *end_line(Byte * p) // return pointer to NL of cur line line
        return (p);
 }
 
-extern inline Byte *dollar_line(Byte * p) // return pointer to just before NL line
+static inline Byte *dollar_line(Byte * p) // return pointer to just before NL line
 {
        while (p < end - 1 && *p != '\n')
                p++;                    // go to cur line E-o-l
@@ -1552,7 +1363,7 @@ static Byte *move_to_col(Byte * p, int l)
                if (*p == '\t') {
                        //         7       - (co %    8  )
                        co += ((tabstop - 1) - (co % tabstop));
-               } else if (*p < ' ') {
+               } else if (*p < ' ' || *p == 127) {
                        co++;           // display as ^X, use 2 columns
                }
        } while (++co <= l && p++ < end);
@@ -1635,8 +1446,7 @@ static Byte *new_screen(int ro, int co)
 {
        int li;
 
-       if (screen != 0)
-               free(screen);
+       free(screen);
        screensize = ro * co + 8;
        screen = (Byte *) xmalloc(screensize);
        // initialize the new screen. assume this will be a empty file.
@@ -1652,10 +1462,7 @@ static Byte *new_text(int size)
 {
        if (size < 10240)
                size = 10240;   // have a minimum size for new files
-       if (text != 0) {
-               //text -= 4;
-               free(text);
-       }
+       free(text);
        text = (Byte *) xmalloc(size + 8);
        memset(text, '\0', size);       // clear new text[]
        //text += 4;            // leave some room for "oops"
@@ -1796,7 +1603,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
                        p = text_hole_delete(p, p);     // shrink buffer 1 char
 #ifdef CONFIG_FEATURE_VI_DOT_CMD
                        // also rmove char from last_modifying_cmd
-                       if (strlen((char *) last_modifying_cmd) > 0) {
+                       if (last_modifying_cmd != 0 && strlen((char *) last_modifying_cmd) > 0) {
                                Byte *q;
 
                                q = last_modifying_cmd;
@@ -1862,8 +1669,13 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
                q = dot;
        } else if (strchr("wW", c)) {
                do_cmd(c);              // execute movement cmd
-               if (dot > text)
-                       dot--;          // move back off of next word
+               // if we are at the next word's first char
+               // step back one char
+               // but check the possibilities when it is true
+               if (dot > text && ((isspace(dot[0]) && !isspace(dot[0]))
+                               || (ispunct(dot[-1]) && !ispunct(dot[0]))
+                               || (isalnum(dot[-1]) && !isalnum(dot[0]))))
+                       dot--;          // move back off of next word
                if (dot > text && *dot == '\n')
                        dot--;          // stay off NL
                q = dot;
@@ -2139,7 +1951,7 @@ static void show_help(void)
        );
 }
 
-extern inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
+static inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
 {
        Byte c, b[2];
 
@@ -2148,19 +1960,25 @@ extern inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert
        if (strlen((char *) s) <= 0)
                s = (Byte *) "(NULL)";
        for (; *s > '\0'; s++) {
+               int c_is_no_print;
+
                c = *s;
-               if (*s > '~') {
-                       strcat((char *) buf, SOs);
-                       c = *s - 128;
+               c_is_no_print = c > 127 && !Isprint(c);
+               if (c_is_no_print) {
+                       strcat((char *) buf, SOn);
+                       c = '.';
                }
-               if (*s < ' ') {
+               if (c < ' ' || c == 127) {
                        strcat((char *) buf, "^");
+                       if(c == 127)
+                               c = '?';
+                        else
                        c += '@';
                }
                b[0] = c;
                strcat((char *) buf, (char *) b);
-               if (*s > '~')
-                       strcat((char *) buf, SOn);
+               if (c_is_no_print)
+                       strcat((char *) buf, SOs);
                if (*s == '\n') {
                        strcat((char *) buf, "$");
                }
@@ -2171,8 +1989,7 @@ extern inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert
 static void start_new_cmd_q(Byte c)
 {
        // release old cmd
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
+       free(last_modifying_cmd);
        // get buffer for new cmd
        last_modifying_cmd = (Byte *) xmalloc(BUFSIZ);
        memset(last_modifying_cmd, '\0', BUFSIZ);       // clear new cmd queue
@@ -2227,9 +2044,7 @@ static Byte *text_yank(Byte * p, Byte * q, int dest)      // copy text into a registe
        }
        cnt = q - p + 1;
        t = reg[dest];
-       if (t != 0) {           // if already a yank register
-               free(t);                //   free it
-       }
+       free(t);                //  if already a yank register, free it
        t = (Byte *) xmalloc(cnt + 1);  // get a new register
        memset(t, '\0', cnt + 1);       // clear new text[]
        strncpy((char *) t, (char *) p, cnt);   // copy text[] into bufer
@@ -2271,7 +2086,7 @@ static void check_context(Byte cmd)
        return;
 }
 
-extern inline Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
+static inline Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
 {
        Byte *tmp;
 
@@ -2303,42 +2118,18 @@ static void rawmode(void)
        term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG ON- allow intr's
        term_vi.c_iflag &= (~IXON & ~ICRNL);
        term_vi.c_oflag &= (~ONLCR);
-#ifndef linux
        term_vi.c_cc[VMIN] = 1;
        term_vi.c_cc[VTIME] = 0;
-#endif
        erase_char = term_vi.c_cc[VERASE];
        tcsetattr(0, TCSANOW, &term_vi);
 }
 
 static void cookmode(void)
 {
+       fflush(stdout);
        tcsetattr(0, TCSANOW, &term_orig);
 }
 
-#ifdef CONFIG_FEATURE_VI_WIN_RESIZE
-//----- See what the window size currently is --------------------
-static void window_size_get(int sig)
-{
-       int i;
-
-       i = ioctl(0, TIOCGWINSZ, &winsize);
-       if (i != 0) {
-               // force 24x80
-               winsize.ws_row = 24;
-               winsize.ws_col = 80;
-       }
-       if (winsize.ws_row <= 1) {
-               winsize.ws_row = 24;
-       }
-       if (winsize.ws_col <= 1) {
-               winsize.ws_col = 80;
-       }
-       rows = (int) winsize.ws_row;
-       columns = (int) winsize.ws_col;
-}
-#endif                                                 /* CONFIG_FEATURE_VI_WIN_RESIZE */
-
 //----- Come here when we get a window resize signal ---------
 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
 static void winch_sig(int sig)
@@ -2360,7 +2151,7 @@ static void cont_sig(int sig)
 
        signal(SIGTSTP, suspend_sig);
        signal(SIGCONT, SIG_DFL);
-       kill(getpid(), SIGCONT);
+       kill(my_pid, SIGCONT);
 }
 
 //----- Come here when we get a Suspend signal -------------------
@@ -2372,7 +2163,7 @@ static void suspend_sig(int sig)
 
        signal(SIGCONT, cont_sig);
        signal(SIGTSTP, SIG_DFL);
-       kill(getpid(), SIGTSTP);
+       kill(my_pid, SIGTSTP);
 }
 
 //----- Come here when we get a signal ---------------------------
@@ -2381,12 +2172,8 @@ static void catch_sig(int sig)
        signal(SIGHUP, catch_sig);
        signal(SIGINT, catch_sig);
        signal(SIGTERM, catch_sig);
-       longjmp(restart, sig);
-}
-
-static void alarm_sig(int sig)
-{
        signal(SIGALRM, catch_sig);
+       if(sig)
        longjmp(restart, sig);
 }
 
@@ -2405,15 +2192,18 @@ static void core_sig(int sig)
        signal(SIGSYS, core_sig);
 #endif
 
+       if(sig) {       // signaled
        dot = bound_dot(dot);   // make sure "dot" is valid
 
        longjmp(restart, sig);
+       }
 }
 #endif                                                 /* CONFIG_FEATURE_VI_USE_SIGNALS */
 
 static int mysleep(int hund)   // sleep for 'h' 1/100 seconds
 {
        // Don't hang- Wait 5/100 seconds-  1 Sec= 1000000
+       fflush(stdout);
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
        tv.tv_sec = 0;
@@ -2422,60 +2212,66 @@ static int mysleep(int hund)    // sleep for 'h' 1/100 seconds
        return (FD_ISSET(0, &rfds));
 }
 
+static Byte readbuffer[BUFSIZ];
+static int readed_for_parse;
+
 //----- IO Routines --------------------------------------------
 static Byte readit(void)       // read (maybe cursor) key from stdin
 {
        Byte c;
-       int i, bufsiz, cnt, cmdindex;
+       int n;
        struct esc_cmds {
-               Byte *seq;
+               const char *seq;
                Byte val;
        };
 
-       static struct esc_cmds esccmds[] = {
-               {(Byte *) "\eOA", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\eOB", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\eOC", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\eOD", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\eOH", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\eOF", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[A", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\e[B", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\e[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\e[D", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\e[H", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\e[F", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
-               {(Byte *) "\e[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
-               {(Byte *) "\e[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
-               {(Byte *) "\eOP", (Byte) VI_K_FUN1},     // Function Key F1
-               {(Byte *) "\eOQ", (Byte) VI_K_FUN2},     // Function Key F2
-               {(Byte *) "\eOR", (Byte) VI_K_FUN3},     // Function Key F3
-               {(Byte *) "\eOS", (Byte) VI_K_FUN4},     // Function Key F4
-               {(Byte *) "\e[15~", (Byte) VI_K_FUN5},   // Function Key F5
-               {(Byte *) "\e[17~", (Byte) VI_K_FUN6},   // Function Key F6
-               {(Byte *) "\e[18~", (Byte) VI_K_FUN7},   // Function Key F7
-               {(Byte *) "\e[19~", (Byte) VI_K_FUN8},   // Function Key F8
-               {(Byte *) "\e[20~", (Byte) VI_K_FUN9},   // Function Key F9
-               {(Byte *) "\e[21~", (Byte) VI_K_FUN10},  // Function Key F10
-               {(Byte *) "\e[23~", (Byte) VI_K_FUN11},  // Function Key F11
-               {(Byte *) "\e[24~", (Byte) VI_K_FUN12},  // Function Key F12
-               {(Byte *) "\e[11~", (Byte) VI_K_FUN1},   // Function Key F1
-               {(Byte *) "\e[12~", (Byte) VI_K_FUN2},   // Function Key F2
-               {(Byte *) "\e[13~", (Byte) VI_K_FUN3},   // Function Key F3
-               {(Byte *) "\e[14~", (Byte) VI_K_FUN4},   // Function Key F4
+       static const struct esc_cmds esccmds[] = {
+               {"OA", (Byte) VI_K_UP},       // cursor key Up
+               {"OB", (Byte) VI_K_DOWN},     // cursor key Down
+               {"OC", (Byte) VI_K_RIGHT},    // Cursor Key Right
+               {"OD", (Byte) VI_K_LEFT},     // cursor key Left
+               {"OH", (Byte) VI_K_HOME},     // Cursor Key Home
+               {"OF", (Byte) VI_K_END},      // Cursor Key End
+               {"[A", (Byte) VI_K_UP},       // cursor key Up
+               {"[B", (Byte) VI_K_DOWN},     // cursor key Down
+               {"[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
+               {"[D", (Byte) VI_K_LEFT},     // cursor key Left
+               {"[H", (Byte) VI_K_HOME},     // Cursor Key Home
+               {"[F", (Byte) VI_K_END},      // Cursor Key End
+               {"[1~", (Byte) VI_K_HOME},     // Cursor Key Home
+               {"[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
+               {"[4~", (Byte) VI_K_END},      // Cursor Key End
+               {"[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
+               {"[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
+               {"OP", (Byte) VI_K_FUN1},     // Function Key F1
+               {"OQ", (Byte) VI_K_FUN2},     // Function Key F2
+               {"OR", (Byte) VI_K_FUN3},     // Function Key F3
+               {"OS", (Byte) VI_K_FUN4},     // Function Key F4
+               {"[15~", (Byte) VI_K_FUN5},   // Function Key F5
+               {"[17~", (Byte) VI_K_FUN6},   // Function Key F6
+               {"[18~", (Byte) VI_K_FUN7},   // Function Key F7
+               {"[19~", (Byte) VI_K_FUN8},   // Function Key F8
+               {"[20~", (Byte) VI_K_FUN9},   // Function Key F9
+               {"[21~", (Byte) VI_K_FUN10},  // Function Key F10
+               {"[23~", (Byte) VI_K_FUN11},  // Function Key F11
+               {"[24~", (Byte) VI_K_FUN12},  // Function Key F12
+               {"[11~", (Byte) VI_K_FUN1},   // Function Key F1
+               {"[12~", (Byte) VI_K_FUN2},   // Function Key F2
+               {"[13~", (Byte) VI_K_FUN3},   // Function Key F3
+               {"[14~", (Byte) VI_K_FUN4},   // Function Key F4
        };
 
 #define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
 
        (void) alarm(0);        // turn alarm OFF while we wait for input
+       fflush(stdout);
+       n = readed_for_parse;
        // get input from User- are there already input chars in Q?
-       bufsiz = strlen((char *) readbuffer);
-       if (bufsiz <= 0) {
+       if (n <= 0) {
          ri0:
                // the Q is empty, wait for a typed char
-               bufsiz = read(0, readbuffer, BUFSIZ - 1);
-               if (bufsiz < 0) {
+               n = read(0, readbuffer, BUFSIZ - 1);
+               if (n < 0) {
                        if (errno == EINTR)
                                goto ri0;       // interrupted sys call
                        if (errno == EBADF)
@@ -2487,14 +2283,10 @@ static Byte readit(void)        // read (maybe cursor) key from stdin
                        if (errno == EIO)
                                editing = 0;
                        errno = 0;
-                       bufsiz = 0;
                }
-               readbuffer[bufsiz] = '\0';
-       }
-       // return char if it is not part of ESC sequence
-       if (readbuffer[0] != 27)
-               goto ri1;
-
+               if(n <= 0)
+                       return 0;       // error
+               if (readbuffer[0] == 27) {
        // This is an ESC char. Is this Esc sequence?
        // Could be bare Esc key. See if there are any
        // more chars to read after the ESC. This would
@@ -2505,34 +2297,44 @@ static Byte readit(void)        // read (maybe cursor) key from stdin
        tv.tv_usec = 50000;     // Wait 5/100 seconds- 1 Sec=1000000
 
        // keep reading while there are input chars and room in buffer
-       while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
+                       while (select(1, &rfds, NULL, NULL, &tv) > 0 && n <= (BUFSIZ - 5)) {
                // read the rest of the ESC string
-               i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz);
-               if (i > 0) {
-                       bufsiz += i;
-                       readbuffer[bufsiz] = '\0';      // Terminate the string
+                               int r = read(0, (void *) (readbuffer + n), BUFSIZ - n);
+                               if (r > 0) {
+                                       n += r;
+                               }
+                       }
                }
+               readed_for_parse = n;
        }
+       c = readbuffer[0];
+       if(c == 27 && n > 1) {
        // Maybe cursor or function key?
-       for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) {
-               cnt = strlen((char *) esccmds[cmdindex].seq);
-               i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt);
-               if (i == 0) {
+               const struct esc_cmds *eindex;
+
+               for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) {
+                       int cnt = strlen(eindex->seq);
+
+                       if(n <= cnt)
+                               continue;
+                       if(strncmp(eindex->seq, (char *) readbuffer + 1, cnt))
+                               continue;
                        // is a Cursor key- put derived value back into Q
-                       readbuffer[0] = esccmds[cmdindex].val;
-                       // squeeze out the ESC sequence
-                       for (i = 1; i < cnt; i++) {
-                               memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2);
-                               readbuffer[BUFSIZ - 1] = '\0';
-                       }
+                       c = eindex->val;
+                       // for squeeze out the ESC sequence
+                       n = cnt + 1;
                        break;
                }
+               if(eindex == &esccmds[ESCCMDS_COUNT]) {
+                       /* defined ESC sequence not found, set only one ESC */
+                       n = 1;
        }
-  ri1:
-       c = readbuffer[0];
-       // remove one char from Q
-       memmove(readbuffer, readbuffer + 1, BUFSIZ - 1);
-       readbuffer[BUFSIZ - 1] = '\0';
+       } else {
+               n = 1;
+       }
+       // remove key sequence from Q
+       readed_for_parse -= n;
+       memmove(readbuffer, readbuffer + n, BUFSIZ - n);
        (void) alarm(3);        // we are done waiting for input, turn alarm ON
        return (c);
 }
@@ -2573,7 +2375,6 @@ static Byte get_one_char()
                                // add new char to q
                                last_modifying_cmd[len] = c;
                        }
-
                }
        }
 #else                                                  /* CONFIG_FEATURE_VI_DOT_CMD */
@@ -2593,7 +2394,7 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
        *status_buffer = '\0';  // clear the status buffer
        place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
        clear_to_eol();         // clear the line
-       write(1, prompt, strlen((char *) prompt));      // write out the :, /, or ? prompt
+       write1(prompt);      // write out the :, /, or ? prompt
 
        for (i = strlen((char *) buf); i < BUFSIZ;) {
                c = get_one_char();     // read user input
@@ -2603,25 +2404,24 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
                        i--;            // backup to prev char
                        buf[i] = '\0';  // erase the char
                        buf[i + 1] = '\0';      // null terminate buffer
-                       write(1, "\b \b", 3);     // erase char on screen
+                       write1("\b \b");     // erase char on screen
                        if (i <= 0) {   // user backs up before b-o-l, exit
                                break;
                        }
                } else {
                        buf[i] = c;     // save char in buffer
                        buf[i + 1] = '\0';      // make sure buffer is null terminated
-                       write(1, buf + i, 1);   // echo the char back to user
+                       putchar(c);   // echo the char back to user
                        i++;
                }
        }
        refresh(FALSE);
-       if (obufp != NULL)
-               free(obufp);
-       obufp = (Byte *) xstrdup((char *) buf);
+       free(obufp);
+       obufp = (Byte *) bb_xstrdup((char *) buf);
        return (obufp);
 }
 
-static int file_size(Byte * fn) // what is the byte size of "fn"
+static int file_size(const Byte * fn) // what is the byte size of "fn"
 {
        struct stat st_buf;
        int cnt, sr;
@@ -2742,7 +2542,6 @@ static void place_cursor(int row, int col, int opti)
 {
        char cm1[BUFSIZ];
        char *cm;
-       int l;
 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
        char cm2[BUFSIZ];
        Byte *screenp;
@@ -2797,32 +2596,31 @@ static void place_cursor(int row, int col, int opti)
        } */
 #endif                                                 /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
   pc0:
-       l= strlen(cm);
-       if (l) write(1, cm, l);                 // move the cursor
+       write1(cm);                 // move the cursor
 }
 
 //----- Erase from cursor to end of line -----------------------
 static void clear_to_eol()
 {
-       write(1, Ceol, strlen(Ceol));   // Erase from cursor to end of line
+       write1(Ceol);   // Erase from cursor to end of line
 }
 
 //----- Erase from cursor to end of screen -----------------------
 static void clear_to_eos()
 {
-       write(1, Ceos, strlen(Ceos));   // Erase from cursor to end of screen
+       write1(Ceos);   // Erase from cursor to end of screen
 }
 
 //----- Start standout mode ------------------------------------
 static void standout_start() // send "start reverse video" sequence
 {
-       write(1, SOs, strlen(SOs));     // Start reverse video mode
+       write1(SOs);     // Start reverse video mode
 }
 
 //----- End standout mode --------------------------------------
 static void standout_end() // send "end reverse video" sequence
 {
-       write(1, SOn, strlen(SOn));     // End reverse video mode
+       write1(SOn);     // End reverse video mode
 }
 
 //----- Flash the screen  --------------------------------------
@@ -2835,19 +2633,14 @@ static void flash(int h)
        redraw(TRUE);
 }
 
-static void beep()
-{
-       write(1, bell, strlen(bell));   // send out a bell character
-}
-
-static void indicate_error(char c)
+static void Indicate_Error(void)
 {
 #ifdef CONFIG_FEATURE_VI_CRASHME
        if (crashme > 0)
                return;                 // generate a random command
 #endif                                                 /* CONFIG_FEATURE_VI_CRASHME */
-       if (err_method == 0) {
-               beep();
+       if (!err_method) {
+               write1(bell);   // send out a bell character
        } else {
                flash(10);
        }
@@ -2872,7 +2665,7 @@ static void show_status_line(void)
        if (cnt > 0 && last_cksum != cksum) {
                last_cksum= cksum;              // remember if we have seen this line
                place_cursor(rows - 1, 0, FALSE);       // put cursor on status line
-               write(1, status_buffer, cnt);
+               write1(status_buffer);
                clear_to_eol();
                place_cursor(crow, ccol, FALSE);        // put cursor back in correct place
        }
@@ -2880,7 +2673,7 @@ static void show_status_line(void)
 
 //----- format the status buffer, the bottom line of screen ------
 // print status buffer, with STANDOUT mode
-static void psbs(char *format, ...)
+static void psbs(const char *format, ...)
 {
        va_list args;
 
@@ -2895,7 +2688,7 @@ static void psbs(char *format, ...)
 }
 
 // print status buffer
-static void psb(char *format, ...)
+static void psb(const char *format, ...)
 {
        va_list args;
 
@@ -2967,7 +2760,10 @@ static void format_line(Byte *dest, Byte *src, int li)
                }
                if (c == '\n')
                        break;
-               if (c < ' ' || c > '~') {
+               if (c > 127 && !Isprint(c)) {
+                       c = '.';
+               }
+               if (c < ' ' || c == 127) {
                        if (c == '\t') {
                                c = ' ';
                                //       co %    8     !=     7
@@ -2976,8 +2772,10 @@ static void format_line(Byte *dest, Byte *src, int li)
                                }
                        } else {
                                dest[co++] = '^';
-                               c |= '@';       // make it visible
-                               c &= 0x7f;      // get rid of hi bit
+                               if(c == 127)
+                                       c = '?';
+                                else
+                                       c += '@';       // make it visible
                        }
                }
                // the co++ is done here so that the column will
@@ -3080,7 +2878,15 @@ static void refresh(int full_screen)
                        }
 
                        // write line out to terminal
-                       write(1, sp+cs, ce-cs+1);
+                       {
+                               int nic = ce-cs+1;
+                               char *out = sp+cs;
+
+                               while(nic-- > 0) {
+                                       putchar(*out);
+                                       out++;
+                               }
+                       }
 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
                        last_row = li;
 #endif                                                 /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
@@ -3144,12 +2950,14 @@ static void do_cmd(Byte c)
        }
 
        if (cmd_mode == 2) {
+               //  flip-flop Insert/Replace mode
+               if (c == VI_K_INSERT) goto dc_i;
                // we are 'R'eplacing the current *dot with new char
                if (*dot == '\n') {
                        // don't Replace past E-o-l
                        cmd_mode = 1;   // convert to insert
                } else {
-                       if (1 <= c && c <= 127) {       // only ASCII chars
+                       if (1 <= c || Isprint(c)) {
                                if (c != 27)
                                        dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
                                dot = char_insert(dot, c);      // insert new char
@@ -3161,8 +2969,8 @@ static void do_cmd(Byte c)
                //  hitting "Insert" twice means "R" replace mode
                if (c == VI_K_INSERT) goto dc5;
                // insert the char c at "dot"
-               if (1 <= c && c <= 127) {
-                       dot = char_insert(dot, c);      // only ASCII chars
+               if (1 <= c || Isprint(c)) {
+                       dot = char_insert(dot, c);
                }
                goto dc1;
        }
@@ -3215,7 +3023,7 @@ key_cmd_mode:
        default:                        // unrecognised command
                buf[0] = c;
                buf[1] = '\0';
-               if (c <= ' ') {
+               if (c < ' ') {
                        buf[0] = '^';
                        buf[1] = c + '@';
                        buf[2] = '\0';
@@ -3392,7 +3200,7 @@ key_cmd_mode:
                if (cmdcnt-- > 1) {
                        do_cmd(c);
                }                               // repeat cnt
-               dot = end_line(dot + 1);
+               dot = end_line(dot);
                break;
        case '%':                       // %- find matching char of pair () [] {}
                for (q = dot; q < end && *q != '\n'; q++) {
@@ -3440,7 +3248,7 @@ key_cmd_mode:
                // Stuff the last_modifying_cmd back into stdin
                // and let it be re-executed.
                if (last_modifying_cmd != 0) {
-                       ioq = ioq_start = (Byte *) xstrdup((char *) last_modifying_cmd);
+                       ioq = ioq_start = (Byte *) bb_xstrdup((char *) last_modifying_cmd);
                }
                break;
 #endif                                                 /* CONFIG_FEATURE_VI_DOT_CMD */
@@ -3454,10 +3262,8 @@ key_cmd_mode:
                        goto dc3;       // if no pat re-use old pat
                if (strlen((char *) q) > 1) {   // new pat- save it and find
                        // there is a new pat
-                       if (last_search_pattern != 0) {
-                               free(last_search_pattern);
-                       }
-                       last_search_pattern = (Byte *) xstrdup((char *) q);
+                       free(last_search_pattern);
+                       last_search_pattern = (Byte *) bb_xstrdup((char *) q);
                        goto dc3;       // now find the pattern
                }
                // user changed mind and erased the "/"-  do nothing
@@ -3968,3 +3774,208 @@ key_cmd_mode:
        if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
                dot--;
 }
+
+#ifdef CONFIG_FEATURE_VI_CRASHME
+static int totalcmds = 0;
+static int Mp = 85;             // Movement command Probability
+static int Np = 90;             // Non-movement command Probability
+static int Dp = 96;             // Delete command Probability
+static int Ip = 97;             // Insert command Probability
+static int Yp = 98;             // Yank command Probability
+static int Pp = 99;             // Put command Probability
+static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
+char chars[20] = "\t012345 abcdABCD-=.$";
+char *words[20] = { "this", "is", "a", "test",
+       "broadcast", "the", "emergency", "of",
+       "system", "quick", "brown", "fox",
+       "jumped", "over", "lazy", "dogs",
+       "back", "January", "Febuary", "March"
+};
+char *lines[20] = {
+       "You should have received a copy of the GNU General Public License\n",
+       "char c, cm, *cmd, *cmd1;\n",
+       "generate a command by percentages\n",
+       "Numbers may be typed as a prefix to some commands.\n",
+       "Quit, discarding changes!\n",
+       "Forced write, if permission originally not valid.\n",
+       "In general, any ex or ed command (such as substitute or delete).\n",
+       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+       "Please get w/ me and I will go over it with you.\n",
+       "The following is a list of scheduled, committed changes.\n",
+       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+       "Any question about transactions please contact Sterling Huxley.\n",
+       "I will try to get back to you by Friday, December 31.\n",
+       "This Change will be implemented on Friday.\n",
+       "Let me know if you have problems accessing this;\n",
+       "Sterling Huxley recently added you to the access list.\n",
+       "Would you like to go to lunch?\n",
+       "The last command will be automatically run.\n",
+       "This is too much english for a computer geek.\n",
+};
+char *multilines[20] = {
+       "You should have received a copy of the GNU General Public License\n",
+       "char c, cm, *cmd, *cmd1;\n",
+       "generate a command by percentages\n",
+       "Numbers may be typed as a prefix to some commands.\n",
+       "Quit, discarding changes!\n",
+       "Forced write, if permission originally not valid.\n",
+       "In general, any ex or ed command (such as substitute or delete).\n",
+       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+       "Please get w/ me and I will go over it with you.\n",
+       "The following is a list of scheduled, committed changes.\n",
+       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+       "Any question about transactions please contact Sterling Huxley.\n",
+       "I will try to get back to you by Friday, December 31.\n",
+       "This Change will be implemented on Friday.\n",
+       "Let me know if you have problems accessing this;\n",
+       "Sterling Huxley recently added you to the access list.\n",
+       "Would you like to go to lunch?\n",
+       "The last command will be automatically run.\n",
+       "This is too much english for a computer geek.\n",
+};
+
+// create a random command to execute
+static void crash_dummy()
+{
+       static int sleeptime;   // how long to pause between commands
+       char c, cm, *cmd, *cmd1;
+       int i, cnt, thing, rbi, startrbi, percent;
+
+       // "dot" movement commands
+       cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
+
+       // is there already a command running?
+       if (readed_for_parse > 0)
+               goto cd1;
+  cd0:
+       startrbi = rbi = 0;
+       sleeptime = 0;          // how long to pause between commands
+       memset(readbuffer, '\0', BUFSIZ);   // clear the read buffer
+       // generate a command by percentages
+       percent = (int) lrand48() % 100;        // get a number from 0-99
+       if (percent < Mp) {     //  Movement commands
+               // available commands
+               cmd = cmd1;
+               M++;
+       } else if (percent < Np) {      //  non-movement commands
+               cmd = "mz<>\'\"";       // available commands
+               N++;
+       } else if (percent < Dp) {      //  Delete commands
+               cmd = "dx";             // available commands
+               D++;
+       } else if (percent < Ip) {      //  Inset commands
+               cmd = "iIaAsrJ";        // available commands
+               I++;
+       } else if (percent < Yp) {      //  Yank commands
+               cmd = "yY";             // available commands
+               Y++;
+       } else if (percent < Pp) {      //  Put commands
+               cmd = "pP";             // available commands
+               P++;
+       } else {
+               // We do not know how to handle this command, try again
+               U++;
+               goto cd0;
+       }
+       // randomly pick one of the available cmds from "cmd[]"
+       i = (int) lrand48() % strlen(cmd);
+       cm = cmd[i];
+       if (strchr(":\024", cm))
+               goto cd0;               // dont allow colon or ctrl-T commands
+       readbuffer[rbi++] = cm; // put cmd into input buffer
+
+       // now we have the command-
+       // there are 1, 2, and multi char commands
+       // find out which and generate the rest of command as necessary
+       if (strchr("dmryz<>\'\"", cm)) {        // 2-char commands
+               cmd1 = " \n\r0$^-+wWeEbBhjklHL";
+               if (cm == 'm' || cm == '\'' || cm == '\"') {    // pick a reg[]
+                       cmd1 = "abcdefghijklmnopqrstuvwxyz";
+               }
+               thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+               c = cmd1[thing];
+               readbuffer[rbi++] = c;  // add movement to input buffer
+       }
+       if (strchr("iIaAsc", cm)) {     // multi-char commands
+               if (cm == 'c') {
+                       // change some thing
+                       thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+                       c = cmd1[thing];
+                       readbuffer[rbi++] = c;  // add movement to input buffer
+               }
+               thing = (int) lrand48() % 4;    // what thing to insert
+               cnt = (int) lrand48() % 10;     // how many to insert
+               for (i = 0; i < cnt; i++) {
+                       if (thing == 0) {       // insert chars
+                               readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
+                       } else if (thing == 1) {        // insert words
+                               strcat((char *) readbuffer, words[(int) lrand48() % 20]);
+                               strcat((char *) readbuffer, " ");
+                               sleeptime = 0;  // how fast to type
+                       } else if (thing == 2) {        // insert lines
+                               strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
+                               sleeptime = 0;  // how fast to type
+                       } else {        // insert multi-lines
+                               strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
+                               sleeptime = 0;  // how fast to type
+                       }
+               }
+               strcat((char *) readbuffer, "\033");
+       }
+       readed_for_parse = strlen(readbuffer);
+  cd1:
+       totalcmds++;
+       if (sleeptime > 0)
+               (void) mysleep(sleeptime);      // sleep 1/100 sec
+}
+
+// test to see if there are any errors
+static void crash_test()
+{
+       static time_t oldtim;
+       time_t tim;
+       char d[2], msg[BUFSIZ];
+
+       msg[0] = '\0';
+       if (end < text) {
+               strcat((char *) msg, "end<text ");
+       }
+       if (end > textend) {
+               strcat((char *) msg, "end>textend ");
+       }
+       if (dot < text) {
+               strcat((char *) msg, "dot<text ");
+       }
+       if (dot > end) {
+               strcat((char *) msg, "dot>end ");
+       }
+       if (screenbegin < text) {
+               strcat((char *) msg, "screenbegin<text ");
+       }
+       if (screenbegin > end - 1) {
+               strcat((char *) msg, "screenbegin>end-1 ");
+       }
+
+       if (strlen(msg) > 0) {
+               alarm(0);
+               printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
+                       totalcmds, last_input_char, msg, SOs, SOn);
+               fflush(stdout);
+               while (read(0, d, 1) > 0) {
+                       if (d[0] == '\n' || d[0] == '\r')
+                               break;
+               }
+               alarm(3);
+       }
+       tim = (time_t) time((time_t *) 0);
+       if (tim >= (oldtim + 3)) {
+               sprintf((char *) status_buffer,
+                               "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
+                               totalcmds, M, N, I, D, Y, P, U, end - text + 1);
+               oldtim = tim;
+       }
+       return;
+}
+#endif                                                  /* CONFIG_FEATURE_VI_CRASHME */