saw commit of vapier@busybox.net (thanks!),
[oweals/busybox.git] / shell / cmdedit.c
index f999b88e9c0e4f0dd50092967a030fac116efba5..32001324fa5667639d76239810cdce3d5fe00e2c 100644 (file)
  *      Erik Andersen    <andersen@codepoet.org> (Majorly adjusted for busybox)
  *
  * This code is 'as is' with no warranty.
  *      Erik Andersen    <andersen@codepoet.org> (Majorly adjusted for busybox)
  *
  * This code is 'as is' with no warranty.
- *
- *
  */
 
 /*
  */
 
 /*
-   Usage and Known bugs:
+   Usage and known bugs:
    Terminal key codes are not extensive, and more will probably
    need to be added. This version was created on Debian GNU/Linux 2.x.
    Delete, Backspace, Home, End, and the arrow keys were tested
    Terminal key codes are not extensive, and more will probably
    need to be added. This version was created on Debian GNU/Linux 2.x.
    Delete, Backspace, Home, End, and the arrow keys were tested
    - not true viewing if length prompt less terminal width
  */
 
    - not true viewing if length prompt less terminal width
  */
 
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <limits.h>
-
 #include "busybox.h"
 #include "busybox.h"
+#include <sys/ioctl.h>
 
 
-#include "../shell/cmdedit.h"
+#include "cmdedit.h"
 
 
 
 
-#ifdef CONFIG_LOCALE_SUPPORT
-#define Isprint(c) isprint((c))
+#if ENABLE_LOCALE_SUPPORT
+#define Isprint(c) isprint(c)
 #else
 #else
-#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
+#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
 #endif
 
 #endif
 
-#ifdef TEST
 
 
-/* pretect redefined for test */
-#undef CONFIG_FEATURE_COMMAND_EDITING
-#undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
-#undef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
-#undef CONFIG_FEATURE_CLEAN_UP
+/* FIXME: obsolete CONFIG item? */
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
 
 
-#define CONFIG_FEATURE_COMMAND_EDITING
-#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
-#define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
-#define CONFIG_FEATURE_CLEAN_UP
 
 
-#endif  /* TEST */
+#ifdef TEST
 
 
-#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-#include <dirent.h>
-#include <sys/stat.h>
-#endif
+#define ENABLE_FEATURE_COMMAND_EDITING 0
+#define ENABLE_FEATURE_COMMAND_TAB_COMPLETION 0
+#define ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 0
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
+#define ENABLE_FEATURE_CLEAN_UP 0
 
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
+#endif  /* TEST */
 
 
-#if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
-#define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
-#endif
 
 
-#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
-#include "pwd_.h"
-#endif  /* advanced FEATURES */
+#if ENABLE_FEATURE_COMMAND_EDITING
 
 
+#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
+(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT)
 
 /* Maximum length of the linked list for the command line history */
 
 /* Maximum length of the linked list for the command line history */
-#ifndef CONFIG_FEATURE_COMMAND_HISTORY
+#if !ENABLE_FEATURE_COMMAND_HISTORY
 #define MAX_HISTORY   15
 #else
 #define MAX_HISTORY   15
 #else
-#define MAX_HISTORY   CONFIG_FEATURE_COMMAND_HISTORY
+#define MAX_HISTORY   (CONFIG_FEATURE_COMMAND_HISTORY + 0)
 #endif
 
 #endif
 
-#if MAX_HISTORY < 1
-#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off.
-#else
+#if MAX_HISTORY > 0
 static char *history[MAX_HISTORY+1]; /* history + current */
 /* saved history lines */
 static int n_history;
 static char *history[MAX_HISTORY+1]; /* history + current */
 /* saved history lines */
 static int n_history;
@@ -102,8 +76,7 @@ static int n_history;
 static int cur_history;
 #endif
 
 static int cur_history;
 #endif
 
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
+#define setTermSettings(fd,argp) tcsetattr(fd, TCSANOW, argp)
 #define getTermSettings(fd,argp) tcgetattr(fd, argp);
 
 /* Current termio and the previous termio before starting sh */
 #define getTermSettings(fd,argp) tcgetattr(fd, argp);
 
 /* Current termio and the previous termio before starting sh */
@@ -127,37 +100,33 @@ static int cmdedit_x;           /* real x terminal position */
 static int cmdedit_y;           /* pseudoreal y terminal position */
 static int cmdedit_prmt_len;    /* lenght prompt without colores string */
 
 static int cmdedit_y;           /* pseudoreal y terminal position */
 static int cmdedit_prmt_len;    /* lenght prompt without colores string */
 
-static int cursor;              /* required global for signal handler */
-static int len;                 /* --- "" - - "" - -"- --""-- --""--- */
-static char *command_ps;        /* --- "" - - "" - -"- --""-- --""--- */
-static
-#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
-       const
-#endif
-char *cmdedit_prompt;           /* --- "" - - "" - -"- --""-- --""--- */
+static int cursor;              /* required globals for signal handler */
+static int len;                 /* --- "" - - "" -- -"- --""-- --""--- */
+static char *command_ps;        /* --- "" - - "" -- -"- --""-- --""--- */
+static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; /* -- */
 
 
-#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
 static char *user_buf = "";
 static char *home_pwd_buf = "";
 static int my_euid;
 #endif
 
 static char *user_buf = "";
 static char *home_pwd_buf = "";
 static int my_euid;
 #endif
 
-#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
+#if ENABLE_FEATURE_SH_FANCY_PROMPT
 static char *hostname_buf;
 static int num_ok_lines = 1;
 #endif
 
 
 static char *hostname_buf;
 static int num_ok_lines = 1;
 #endif
 
 
-#ifdef  CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
 
 
-#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
+#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
 static int my_euid;
 #endif
 
 static int my_uid;
 static int my_gid;
 
 static int my_euid;
 #endif
 
 static int my_uid;
 static int my_gid;
 
-#endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
+#endif  /* FEATURE_COMMAND_TAB_COMPLETION */
 
 static void cmdedit_setwidth(int w, int redraw_flg);
 
 
 static void cmdedit_setwidth(int w, int redraw_flg);
 
@@ -165,13 +134,13 @@ static void win_changed(int nsig)
 {
        static sighandler_t previous_SIGWINCH_handler;  /* for reset */
 
 {
        static sighandler_t previous_SIGWINCH_handler;  /* for reset */
 
-       /*   emulate      || signal call */
+       /* emulate || signal call */
        if (nsig == -SIGWINCH || nsig == SIGWINCH) {
                int width = 0;
                get_terminal_width_height(0, &width, NULL);
                cmdedit_setwidth(width, nsig == SIGWINCH);
        }
        if (nsig == -SIGWINCH || nsig == SIGWINCH) {
                int width = 0;
                get_terminal_width_height(0, &width, NULL);
                cmdedit_setwidth(width, nsig == SIGWINCH);
        }
-       /* Unix not all standart in recall signal */
+       /* Unix not all standard in recall signal */
 
        if (nsig == -SIGWINCH)          /* save previous handler   */
                previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
 
        if (nsig == -SIGWINCH)          /* save previous handler   */
                previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
@@ -184,12 +153,12 @@ static void win_changed(int nsig)
 
 static void cmdedit_reset_term(void)
 {
 
 static void cmdedit_reset_term(void)
 {
-       if ((handlers_sets & SET_RESET_TERM) != 0) {
+       if (handlers_sets & SET_RESET_TERM) {
 /* sparc and other have broken termios support: use old termio handling. */
                setTermSettings(STDIN_FILENO, (void *) &initial_settings);
                handlers_sets &= ~SET_RESET_TERM;
        }
 /* sparc and other have broken termios support: use old termio handling. */
                setTermSettings(STDIN_FILENO, (void *) &initial_settings);
                handlers_sets &= ~SET_RESET_TERM;
        }
-       if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
+       if (handlers_sets & SET_WCHG_HANDLERS) {
                /* reset SIGWINCH handler to previous (default) */
                win_changed(0);
                handlers_sets &= ~SET_WCHG_HANDLERS;
                /* reset SIGWINCH handler to previous (default) */
                win_changed(0);
                handlers_sets &= ~SET_WCHG_HANDLERS;
@@ -201,12 +170,11 @@ static void cmdedit_reset_term(void)
 /* special for recount position for scroll and remove terminal margin effect */
 static void cmdedit_set_out_char(int next_char)
 {
 /* special for recount position for scroll and remove terminal margin effect */
 static void cmdedit_set_out_char(int next_char)
 {
-
-       int c = (int)((unsigned char) command_ps[cursor]);
+       int c = (unsigned char)command_ps[cursor];
 
        if (c == 0)
                c = ' ';        /* destroy end char? */
 
        if (c == 0)
                c = ' ';        /* destroy end char? */
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
        if (!Isprint(c)) {      /* Inverse put non-printable characters */
                if (c >= 128)
                        c -= 128;
        if (!Isprint(c)) {      /* Inverse put non-printable characters */
                if (c >= 128)
                        c -= 128;
@@ -217,7 +185,10 @@ static void cmdedit_set_out_char(int next_char)
                printf("\033[7m%c\033[0m", c);
        } else
 #endif
                printf("\033[7m%c\033[0m", c);
        } else
 #endif
-               putchar(c);
+       {
+               if (initial_settings.c_lflag & ECHO)
+                       putchar(c);
+       }
        if (++cmdedit_x >= cmdedit_termw) {
                /* terminal is scrolled down */
                cmdedit_y++;
        if (++cmdedit_x >= cmdedit_termw) {
                /* terminal is scrolled down */
                cmdedit_y++;
@@ -248,13 +219,13 @@ static void goto_new_line(void)
 }
 
 
 }
 
 
-static inline void out1str(const char *s)
+static void out1str(const char *s)
 {
 {
-       if ( s )
+       if (s)
                fputs(s, stdout);
 }
 
                fputs(s, stdout);
 }
 
-static inline void beep(void)
+static void beep(void)
 {
        putchar('\007');
 }
 {
        putchar('\007');
 }
@@ -272,7 +243,6 @@ static void input_backward(int num)
                if (num < 4)
                        while (num-- > 0)
                                putchar('\b');
                if (num < 4)
                        while (num-- > 0)
                                putchar('\b');
-
                else
                        printf("\033[%dD", num);
        } else {
                else
                        printf("\033[%dD", num);
        } else {
@@ -285,7 +255,7 @@ static void input_backward(int num)
                count_y = 1 + num / cmdedit_termw;
                printf("\033[%dA", count_y);
                cmdedit_y -= count_y;
                count_y = 1 + num / cmdedit_termw;
                printf("\033[%dA", count_y);
                cmdedit_y -= count_y;
-               /*  require  forward  after  uping   */
+               /* require forward after uping */
                cmdedit_x = cmdedit_termw * count_y - num;
                printf("\033[%dC", cmdedit_x);  /* set term cursor   */
        }
                cmdedit_x = cmdedit_termw * count_y - num;
                printf("\033[%dC", cmdedit_x);  /* set term cursor   */
        }
@@ -299,7 +269,7 @@ static void put_prompt(void)
        cmdedit_y = 0;                  /* new quasireal y */
 }
 
        cmdedit_y = 0;                  /* new quasireal y */
 }
 
-#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
+#if !ENABLE_FEATURE_SH_FANCY_PROMPT
 static void parse_prompt(const char *prmt_ptr)
 {
        cmdedit_prompt = prmt_ptr;
 static void parse_prompt(const char *prmt_ptr)
 {
        cmdedit_prompt = prmt_ptr;
@@ -311,20 +281,20 @@ static void parse_prompt(const char *prmt_ptr)
 {
        int prmt_len = 0;
        size_t cur_prmt_len = 0;
 {
        int prmt_len = 0;
        size_t cur_prmt_len = 0;
-       char  flg_not_length = '[';
-       char *prmt_mem_ptr = xcalloc(1, 1);
+       char flg_not_length = '[';
+       char *prmt_mem_ptr = xzalloc(1);
        char *pwd_buf = xgetcwd(0);
        char *pwd_buf = xgetcwd(0);
-       char  buf2[PATH_MAX + 1];
-       char  buf[2];
-       char  c;
+       char buf2[PATH_MAX + 1];
+       char buf[2];
+       char c;
        char *pbuf;
 
        if (!pwd_buf) {
        char *pbuf;
 
        if (!pwd_buf) {
-               pwd_buf=(char *)bb_msg_unknown;
+               pwd_buf = (char *)bb_msg_unknown;
        }
 
        while (*prmt_ptr) {
        }
 
        while (*prmt_ptr) {
-               pbuf    = buf;
+               pbuf = buf;
                pbuf[1] = 0;
                c = *prmt_ptr++;
                if (c == '\\') {
                pbuf[1] = 0;
                c = *prmt_ptr++;
                if (c == '\\') {
@@ -332,88 +302,88 @@ static void parse_prompt(const char *prmt_ptr)
                        int l;
 
                        c = bb_process_escape_sequence(&prmt_ptr);
                        int l;
 
                        c = bb_process_escape_sequence(&prmt_ptr);
-                       if(prmt_ptr==cp) {
-                         if (*cp == 0)
-                               break;
-                         c = *prmt_ptr++;
-                         switch (c) {
-#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'u':
-                               pbuf = user_buf;
-                               break;
+                       if (prmt_ptr == cp) {
+                               if (*cp == 0)
+                                       break;
+                               c = *prmt_ptr++;
+                               switch (c) {
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+                               case 'u':
+                                       pbuf = user_buf;
+                                       break;
 #endif
 #endif
-                         case 'h':
-                               pbuf = hostname_buf;
-                               if (pbuf == 0) {
-                                       pbuf = xcalloc(256, 1);
-                                       if (gethostname(pbuf, 255) < 0) {
-                                               strcpy(pbuf, "?");
-                                       } else {
-                                               char *s = strchr(pbuf, '.');
-
-                                               if (s)
-                                                       *s = 0;
+                               case 'h':
+                                       pbuf = hostname_buf;
+                                       if (pbuf == 0) {
+                                               pbuf = xzalloc(256);
+                                               if (gethostname(pbuf, 255) < 0) {
+                                                       strcpy(pbuf, "?");
+                                               } else {
+                                                       char *s = strchr(pbuf, '.');
+                                                       if (s)
+                                                               *s = 0;
+                                               }
+                                               hostname_buf = pbuf;
                                        }
                                        }
-                                       hostname_buf = pbuf;
-                               }
-                               break;
-                         case '$':
-                               c = my_euid == 0 ? '#' : '$';
-                               break;
-#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'w':
-                               pbuf = pwd_buf;
-                               l = strlen(home_pwd_buf);
-                               if (home_pwd_buf[0] != 0 &&
-                                   strncmp(home_pwd_buf, pbuf, l) == 0 &&
-                                   (pbuf[l]=='/' || pbuf[l]=='\0') &&
-                                   strlen(pwd_buf+l)<PATH_MAX) {
-                                       pbuf = buf2;
-                                       *pbuf = '~';
-                                       strcpy(pbuf+1, pwd_buf+l);
+                                       break;
+                               case '$':
+                                       c = (my_euid == 0 ? '#' : '$');
+                                       break;
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+                               case 'w':
+                                       pbuf = pwd_buf;
+                                       l = strlen(home_pwd_buf);
+                                       if (home_pwd_buf[0] != 0
+                                        && strncmp(home_pwd_buf, pbuf, l) == 0
+                                        && (pbuf[l]=='/' || pbuf[l]=='\0')
+                                        && strlen(pwd_buf+l)<PATH_MAX
+                                       ) {
+                                               pbuf = buf2;
+                                               *pbuf = '~';
+                                               strcpy(pbuf+1, pwd_buf+l);
                                        }
                                        }
-                               break;
+                                       break;
 #endif
 #endif
-                         case 'W':
-                               pbuf = pwd_buf;
-                               cp = strrchr(pbuf,'/');
-                               if ( (cp != NULL) && (cp != pbuf) )
-                                       pbuf += (cp-pbuf)+1;
-                               break;
-                         case '!':
-                               snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
-                               break;
-                         case 'e': case 'E':     /* \e \E = \033 */
-                               c = '\033';
-                               break;
-                         case 'x': case 'X':
-                               for (l = 0; l < 3;) {
-                                       int h;
-                                       buf2[l++] = *prmt_ptr;
+                               case 'W':
+                                       pbuf = pwd_buf;
+                                       cp = strrchr(pbuf,'/');
+                                       if (cp != NULL && cp != pbuf)
+                                               pbuf += (cp-pbuf) + 1;
+                                       break;
+                               case '!':
+                                       snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
+                                       break;
+                               case 'e': case 'E':     /* \e \E = \033 */
+                                       c = '\033';
+                                       break;
+                               case 'x': case 'X':
+                                       for (l = 0; l < 3;) {
+                                               int h;
+                                               buf2[l++] = *prmt_ptr;
+                                               buf2[l] = 0;
+                                               h = strtol(buf2, &pbuf, 16);
+                                               if (h > UCHAR_MAX || (pbuf - buf2) < l) {
+                                                       l--;
+                                                       break;
+                                               }
+                                               prmt_ptr++;
+                                       }
                                        buf2[l] = 0;
                                        buf2[l] = 0;
-                                       h = strtol(buf2, &pbuf, 16);
-                                       if (h > UCHAR_MAX || (pbuf - buf2) < l) {
-                                               l--;
-                                               break;
+                                       c = (char)strtol(buf2, 0, 16);
+                                       if (c == 0)
+                                               c = '?';
+                                       pbuf = buf;
+                                       break;
+                               case '[': case ']':
+                                       if (c == flg_not_length) {
+                                               flg_not_length = flg_not_length == '[' ? ']' : '[';
+                                               continue;
                                        }
                                        }
-                                       prmt_ptr++;
-                               }
-                               buf2[l] = 0;
-                               c = (char)strtol(buf2, 0, 16);
-                               if(c==0)
-                                       c = '?';
-                               pbuf = buf;
-                               break;
-                         case '[': case ']':
-                               if (c == flg_not_length) {
-                                       flg_not_length = flg_not_length == '[' ? ']' : '[';
-                                       continue;
+                                       break;
                                }
                                }
-                               break;
-                         }
                        }
                }
                        }
                }
-               if(pbuf == buf)
+               if (pbuf == buf)
                        *pbuf = c;
                cur_prmt_len = strlen(pbuf);
                prmt_len += cur_prmt_len;
                        *pbuf = c;
                cur_prmt_len = strlen(pbuf);
                prmt_len += cur_prmt_len;
@@ -421,7 +391,7 @@ static void parse_prompt(const char *prmt_ptr)
                        cmdedit_prmt_len += cur_prmt_len;
                prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
        }
                        cmdedit_prmt_len += cur_prmt_len;
                prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
        }
-       if(pwd_buf!=(char *)bb_msg_unknown)
+       if (pwd_buf!=(char *)bb_msg_unknown)
                free(pwd_buf);
        cmdedit_prompt = prmt_mem_ptr;
        put_prompt();
                free(pwd_buf);
        cmdedit_prompt = prmt_mem_ptr;
        put_prompt();
@@ -441,10 +411,11 @@ static void redraw(int y, int back_cursor)
        input_backward(back_cursor);
 }
 
        input_backward(back_cursor);
 }
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
-static char delbuf[BUFSIZ];  /* a place to store deleted characters */
-static char *delp = delbuf;
-static int newdelflag;      /* whether delbuf should be reused yet */
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
+#define DELBUFSIZ 128
+static char *delbuf;  /* a (malloced) place to store deleted characters */
+static char *delp;
+static char newdelflag;      /* whether delbuf should be reused yet */
 #endif
 
 /* Delete the char in front of the cursor, optionally saving it
 #endif
 
 /* Delete the char in front of the cursor, optionally saving it
@@ -456,13 +427,16 @@ static void input_delete(int save)
        if (j == len)
                return;
 
        if (j == len)
                return;
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
        if (save) {
                if (newdelflag) {
        if (save) {
                if (newdelflag) {
+                       if (!delbuf)
+                               delbuf = malloc(DELBUFSIZ);
+                       /* safe if malloc fails */
                        delp = delbuf;
                        newdelflag = 0;
                }
                        delp = delbuf;
                        newdelflag = 0;
                }
-               if (delp - delbuf < BUFSIZ)
+               if (delbuf && (delp - delbuf < DELBUFSIZ))
                        *delp++ = command_ps[j];
        }
 #endif
                        *delp++ = command_ps[j];
        }
 #endif
@@ -474,7 +448,7 @@ static void input_delete(int save)
        input_backward(cursor - j);     /* back to old pos cursor */
 }
 
        input_backward(cursor - j);     /* back to old pos cursor */
 }
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
 static void put(void)
 {
        int ocursor, j = delp - delbuf;
 static void put(void)
 {
        int ocursor, j = delp - delbuf;
@@ -486,7 +460,7 @@ static void put(void)
        strncpy(command_ps + cursor, delbuf, j);
        len += j;
        input_end();                    /* rewrite new line */
        strncpy(command_ps + cursor, delbuf, j);
        len += j;
        input_end();                    /* rewrite new line */
-       input_backward(cursor-ocursor-j+1); /* at end of new text */
+       input_backward(cursor - ocursor - j + 1); /* at end of new text */
 }
 #endif
 
 }
 #endif
 
@@ -530,65 +504,67 @@ static void cmdedit_setwidth(int w, int redraw_flg)
 static void cmdedit_init(void)
 {
        cmdedit_prmt_len = 0;
 static void cmdedit_init(void)
 {
        cmdedit_prmt_len = 0;
-       if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
+       if (!(handlers_sets & SET_WCHG_HANDLERS)) {
                /* emulate usage handler to set handler and call yours work */
                win_changed(-SIGWINCH);
                handlers_sets |= SET_WCHG_HANDLERS;
        }
 
                /* emulate usage handler to set handler and call yours work */
                win_changed(-SIGWINCH);
                handlers_sets |= SET_WCHG_HANDLERS;
        }
 
-       if ((handlers_sets & SET_ATEXIT) == 0) {
-#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
+       if (!(handlers_sets & SET_ATEXIT)) {
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
                struct passwd *entry;
 
                my_euid = geteuid();
                entry = getpwuid(my_euid);
                if (entry) {
                struct passwd *entry;
 
                my_euid = geteuid();
                entry = getpwuid(my_euid);
                if (entry) {
-                       user_buf = bb_xstrdup(entry->pw_name);
-                       home_pwd_buf = bb_xstrdup(entry->pw_dir);
+                       user_buf = xstrdup(entry->pw_name);
+                       home_pwd_buf = xstrdup(entry->pw_dir);
                }
 #endif
 
                }
 #endif
 
-#ifdef  CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
 
 
-#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
+#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
                my_euid = geteuid();
 #endif
                my_uid = getuid();
                my_gid = getgid();
                my_euid = geteuid();
 #endif
                my_uid = getuid();
                my_gid = getgid();
-#endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
+#endif  /* FEATURE_COMMAND_TAB_COMPLETION */
                handlers_sets |= SET_ATEXIT;
                atexit(cmdedit_reset_term);     /* be sure to do this only once */
        }
 }
 
                handlers_sets |= SET_ATEXIT;
                atexit(cmdedit_reset_term);     /* be sure to do this only once */
        }
 }
 
-#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
 
 static char **matches;
 static int num_matches;
 
 static char **matches;
 static int num_matches;
-static char *add_char_to_match;
 
 
-static void add_match(char *matched, int add_char)
+static void add_match(char *matched)
 {
        int nm = num_matches;
        int nm1 = nm + 1;
 
        matches = xrealloc(matches, nm1 * sizeof(char *));
 {
        int nm = num_matches;
        int nm1 = nm + 1;
 
        matches = xrealloc(matches, nm1 * sizeof(char *));
-       add_char_to_match = xrealloc(add_char_to_match, nm1);
        matches[nm] = matched;
        matches[nm] = matched;
-       add_char_to_match[nm] = (char)add_char;
        num_matches++;
 }
 
        num_matches++;
 }
 
+/*
 static int is_execute(const struct stat *st)
 {
 static int is_execute(const struct stat *st)
 {
-       if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
-               (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
-               (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
-               (st->st_mode & S_IXOTH)) return TRUE;
+       if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+        || (my_uid == st->st_uid && (st->st_mode & S_IXUSR))
+        || (my_gid == st->st_gid && (st->st_mode & S_IXGRP))
+        || (st->st_mode & S_IXOTH)
+       ) {
+               return TRUE;
+       }
        return FALSE;
 }
        return FALSE;
 }
+*/
 
 
-#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
+#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
 
 static void username_tab_completion(char *ud, char *with_shash_flg)
 {
 
 static void username_tab_completion(char *ud, char *with_shash_flg)
 {
@@ -631,14 +607,14 @@ static void username_tab_completion(char *ud, char *with_shash_flg)
                while ((entry = getpwent()) != NULL) {
                        /* Null usernames should result in all users as possible completions. */
                        if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
                while ((entry = getpwent()) != NULL) {
                        /* Null usernames should result in all users as possible completions. */
                        if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
-                               add_match(bb_xasprintf("~%s", entry->pw_name), '/');
+                               add_match(xasprintf("~%s/", entry->pw_name));
                        }
                }
 
                endpwent();
        }
 }
                        }
                }
 
                endpwent();
        }
 }
-#endif  /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */
+#endif  /* FEATURE_COMMAND_USERNAME_COMPLETION */
 
 enum {
        FIND_EXE_ONLY = 0,
 
 enum {
        FIND_EXE_ONLY = 0,
@@ -646,7 +622,7 @@ enum {
        FIND_FILE_ONLY = 2,
 };
 
        FIND_FILE_ONLY = 2,
 };
 
-#ifdef CONFIG_ASH
+#if ENABLE_ASH
 const char *cmdedit_path_lookup;
 #else
 #define cmdedit_path_lookup getenv("PATH")
 const char *cmdedit_path_lookup;
 #else
 #define cmdedit_path_lookup getenv("PATH")
@@ -656,49 +632,47 @@ static int path_parse(char ***p, int flags)
 {
        int npth;
        const char *tmp;
 {
        int npth;
        const char *tmp;
-       const char *pth;
+       const char *pth = cmdedit_path_lookup;
 
        /* if not setenv PATH variable, to search cur dir "." */
 
        /* if not setenv PATH variable, to search cur dir "." */
-       if (flags != FIND_EXE_ONLY || (pth = cmdedit_path_lookup) == 0 ||
-               /* PATH=<empty> or PATH=:<empty> */
-               *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
+       if (flags != FIND_EXE_ONLY)
+               return 1;
+       /* PATH=<empty> or PATH=:<empty> */
+       if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
                return 1;
                return 1;
-       }
 
        tmp = pth;
        npth = 0;
 
 
        tmp = pth;
        npth = 0;
 
-       for (;;) {
+       while (1) {
                npth++;                 /* count words is + 1 count ':' */
                tmp = strchr(tmp, ':');
                npth++;                 /* count words is + 1 count ':' */
                tmp = strchr(tmp, ':');
-               if (tmp) {
-                       if (*++tmp == 0)
-                               break;  /* :<empty> */
-               } else
+               if (!tmp)
                        break;
                        break;
+               if (*++tmp == 0)
+                       break;  /* :<empty> */
        }
 
        *p = xmalloc(npth * sizeof(char *));
 
        tmp = pth;
        }
 
        *p = xmalloc(npth * sizeof(char *));
 
        tmp = pth;
-       (*p)[0] = bb_xstrdup(tmp);
+       (*p)[0] = xstrdup(tmp);
        npth = 1;                       /* count words is + 1 count ':' */
 
        npth = 1;                       /* count words is + 1 count ':' */
 
-       for (;;) {
+       while (1) {
                tmp = strchr(tmp, ':');
                tmp = strchr(tmp, ':');
-               if (tmp) {
-                       (*p)[0][(tmp - pth)] = 0;       /* ':' -> '\0' */
-                       if (*++tmp == 0)
-                               break;                  /* :<empty> */
-               } else
+               if (!tmp)
                        break;
                        break;
+               (*p)[0][(tmp - pth)] = 0;       /* ':' -> '\0' */
+               if (*++tmp == 0)
+                       break;                  /* :<empty> */
                (*p)[npth++] = &(*p)[0][(tmp - pth)];   /* p[next]=p[0][&'\0'+1] */
        }
 
        return npth;
 }
 
                (*p)[npth++] = &(*p)[0][(tmp - pth)];   /* p[next]=p[0][&'\0'+1] */
        }
 
        return npth;
 }
 
-static char *add_quote_for_spec_chars(char *found, int add)
+static char *add_quote_for_spec_chars(char *found)
 {
        int l = 0;
        char *s = xmalloc((strlen(found) + 1) * 2);
 {
        int l = 0;
        char *s = xmalloc((strlen(found) + 1) * 2);
@@ -708,8 +682,6 @@ static char *add_quote_for_spec_chars(char *found, int add)
                        s[l++] = '\\';
                s[l++] = *found++;
        }
                        s[l++] = '\\';
                s[l++] = *found++;
        }
-       if(add)
-           s[l++] = (char)add;
        s[l] = 0;
        return s;
 }
        s[l] = 0;
        return s;
 }
@@ -739,7 +711,7 @@ static void exe_n_cwd_tab_completion(char *command, int type)
                strcpy(dirbuf, command);
                /* set dir only */
                dirbuf[(pfind - command) + 1] = 0;
                strcpy(dirbuf, command);
                /* set dir only */
                dirbuf[(pfind - command) + 1] = 0;
-#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
+#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
                if (dirbuf[0] == '~')   /* ~/... or ~user/... */
                        username_tab_completion(dirbuf, dirbuf);
 #endif
                if (dirbuf[0] == '~')   /* ~/... or ~user/... */
                        username_tab_completion(dirbuf, dirbuf);
 #endif
@@ -757,45 +729,45 @@ static void exe_n_cwd_tab_completion(char *command, int type)
                        continue;
 
                while ((next = readdir(dir)) != NULL) {
                        continue;
 
                while ((next = readdir(dir)) != NULL) {
+                       int len1;
                        char *str_found = next->d_name;
                        char *str_found = next->d_name;
-                       int add_chr = 0;
 
 
-                       /* matched ? */
+                       /* matched? */
                        if (strncmp(str_found, pfind, strlen(pfind)))
                                continue;
                        /* not see .name without .match */
                        if (*str_found == '.' && *pfind == 0) {
                        if (strncmp(str_found, pfind, strlen(pfind)))
                                continue;
                        /* not see .name without .match */
                        if (*str_found == '.' && *pfind == 0) {
-                               if (*paths[i] == '/' && paths[i][1] == 0
-                                       && str_found[1] == 0) str_found = "";   /* only "/" */
-                               else
+                               if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
                                        continue;
                                        continue;
+                               str_found = ""; /* only "/" */
                        }
                        found = concat_path_file(paths[i], str_found);
                        /* hmm, remover in progress? */
                        if (stat(found, &st) < 0)
                                goto cont;
                        }
                        found = concat_path_file(paths[i], str_found);
                        /* hmm, remover in progress? */
                        if (stat(found, &st) < 0)
                                goto cont;
-                       /* find with dirs ? */
+                       /* find with dirs? */
                        if (paths[i] != dirbuf)
                                strcpy(found, next->d_name);    /* only name */
                        if (paths[i] != dirbuf)
                                strcpy(found, next->d_name);    /* only name */
+
+                       len1 = strlen(found);
+                       found = xrealloc(found, len1 + 2);
+                       found[len1] = '\0';
+                       found[len1+1] = '\0';
+
                        if (S_ISDIR(st.st_mode)) {
                                /* name is directory      */
                        if (S_ISDIR(st.st_mode)) {
                                /* name is directory      */
-                               char *e = found + strlen(found) - 1;
-
-                               add_chr = '/';
-                               if(*e == '/')
-                                       *e = '\0';
+                               if (found[len1-1] != '/') {
+                                       found[len1] = '/';
+                               }
                        } else {
                                /* not put found file if search only dirs for cd */
                                if (type == FIND_DIR_ONLY)
                                        goto cont;
                        } else {
                                /* not put found file if search only dirs for cd */
                                if (type == FIND_DIR_ONLY)
                                        goto cont;
-                               if (type == FIND_FILE_ONLY ||
-                                       (type == FIND_EXE_ONLY && is_execute(&st)))
-                                       add_chr = ' ';
                        }
                        /* Add it to the list */
                        }
                        /* Add it to the list */
-                       add_match(found, add_chr);
+                       add_match(found);
                        continue;
                        continue;
-cont:
+ cont:
                        free(found);
                }
                closedir(dir);
                        free(found);
                }
                closedir(dir);
@@ -807,7 +779,7 @@ cont:
 }
 
 
 }
 
 
-#define QUOT    (UCHAR_MAX+1)
+#define QUOT (UCHAR_MAX+1)
 
 #define collapse_pos(is, in) { \
        memmove(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
 
 #define collapse_pos(is, in) { \
        memmove(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
@@ -823,7 +795,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
 
        /* set to integer dimension characters and own positions */
        for (i = 0;; i++) {
 
        /* set to integer dimension characters and own positions */
        for (i = 0;; i++) {
-               int_buf[i] = (int) ((unsigned char) matchBuf[i]);
+               int_buf[i] = (unsigned char)matchBuf[i];
                if (int_buf[i] == 0) {
                        pos_buf[i] = -1;        /* indicator end line */
                        break;
                if (int_buf[i] == 0) {
                        pos_buf[i] = -1;        /* indicator end line */
                        break;
@@ -837,12 +809,12 @@ static int find_match(char *matchBuf, int *len_with_quotes)
                        collapse_pos(j, j + 1);
                        int_buf[j] |= QUOT;
                        i++;
                        collapse_pos(j, j + 1);
                        int_buf[j] |= QUOT;
                        i++;
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
                        if (matchBuf[i] == '\t')        /* algorithm equivalent */
                                int_buf[j] = ' ' | QUOT;
 #endif
                }
                        if (matchBuf[i] == '\t')        /* algorithm equivalent */
                                int_buf[j] = ' ' | QUOT;
 #endif
                }
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
                else if (matchBuf[i] == '\t')
                        int_buf[j] = ' ';
 #endif
                else if (matchBuf[i] == '\t')
                        int_buf[j] = ' ';
 #endif
@@ -864,7 +836,7 @@ static int find_match(char *matchBuf, int *len_with_quotes)
                        int_buf[i] |= QUOT;
        }
 
                        int_buf[i] |= QUOT;
        }
 
-       /* skip commands with arguments if line have commands delimiters */
+       /* skip commands with arguments if line has commands delimiters */
        /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
        for (i = 0; int_buf[i]; i++) {
                c = int_buf[i];
        /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
        for (i = 0; int_buf[i]; i++) {
                c = int_buf[i];
@@ -935,16 +907,17 @@ static int find_match(char *matchBuf, int *len_with_quotes)
        for (i = 0; int_buf[i]; i++)
                if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
                        if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
        for (i = 0; int_buf[i]; i++)
                if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
                        if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
-                               && matchBuf[pos_buf[0]]=='c'
-                               && matchBuf[pos_buf[1]]=='d' )
+                        && matchBuf[pos_buf[0]]=='c'
+                        && matchBuf[pos_buf[1]]=='d'
+                       ) {
                                command_mode = FIND_DIR_ONLY;
                                command_mode = FIND_DIR_ONLY;
-                       else {
+                       else {
                                command_mode = FIND_FILE_ONLY;
                                break;
                        }
                }
                                command_mode = FIND_FILE_ONLY;
                                break;
                        }
                }
-       /* "strlen" */
-       for (i = 0; int_buf[i]; i++);
+       for (i = 0; int_buf[i]; i++)
+               /* "strlen" */;
        /* find last word */
        for (--i; i >= 0; i--) {
                c = int_buf[i];
        /* find last word */
        for (--i; i >= 0; i--) {
                c = int_buf[i];
@@ -954,11 +927,12 @@ static int find_match(char *matchBuf, int *len_with_quotes)
                }
        }
        /* skip first not quoted '\'' or '"' */
                }
        }
        /* skip first not quoted '\'' or '"' */
-       for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
+       for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
+               /*skip*/;
        /* collapse quote or unquote // or /~ */
        /* collapse quote or unquote // or /~ */
-       while ((int_buf[i] & ~QUOT) == '/' &&
-                       ((int_buf[i + 1] & ~QUOT) == '/'
-                        || (int_buf[i + 1] & ~QUOT) == '~')) {
+       while ((int_buf[i] & ~QUOT) == '/'
+        && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
+       ) {
                i++;
        }
 
                i++;
        }
 
@@ -985,14 +959,11 @@ static void showfiles(void)
        int column_width = 0;
        int nfiles = num_matches;
        int nrows = nfiles;
        int column_width = 0;
        int nfiles = num_matches;
        int nrows = nfiles;
-       char str_add_chr[2];
        int l;
 
        /* find the longest file name-  use that as the column width */
        for (row = 0; row < nrows; row++) {
                l = strlen(matches[row]);
        int l;
 
        /* find the longest file name-  use that as the column width */
        for (row = 0; row < nrows; row++) {
                l = strlen(matches[row]);
-               if(add_char_to_match[row])
-                   l++;
                if (column_width < l)
                        column_width = l;
        }
                if (column_width < l)
                        column_width = l;
        }
@@ -1001,32 +972,27 @@ static void showfiles(void)
 
        if (ncols > 1) {
                nrows /= ncols;
 
        if (ncols > 1) {
                nrows /= ncols;
-               if(nfiles % ncols)
+               if (nfiles % ncols)
                        nrows++;        /* round up fractionals */
        } else {
                ncols = 1;
        }
                        nrows++;        /* round up fractionals */
        } else {
                ncols = 1;
        }
-       str_add_chr[1] = 0;
        for (row = 0; row < nrows; row++) {
                int n = row;
                int nc;
        for (row = 0; row < nrows; row++) {
                int n = row;
                int nc;
-               int acol;
-
-               for(nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
-                       str_add_chr[0] = add_char_to_match[n];
-                       acol = str_add_chr[0] ? column_width - 1 : column_width;
-                       printf("%s%s", matches[n], str_add_chr);
-                       l = strlen(matches[n]);
-                       while(l < acol) {
-                           putchar(' ');
-                           l++;
-                       }
+
+               for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
+                       printf("%s%-*s", matches[n],
+                               (int)(column_width - strlen(matches[n])), "");
                }
                }
-               str_add_chr[0] = add_char_to_match[n];
-               printf("%s%s\n", matches[n], str_add_chr);
+               printf("%s\n", matches[n]);
        }
 }
 
        }
 }
 
+static int match_compare(const void *a, const void *b)
+{
+       return strcmp(*(char**)a, *(char**)b);
+}
 
 static void input_tab(int *lastWasTab)
 {
 
 static void input_tab(int *lastWasTab)
 {
@@ -1037,13 +1003,10 @@ static void input_tab(int *lastWasTab)
                                free(matches[--num_matches]);
                        free(matches);
                        matches = (char **) NULL;
                                free(matches[--num_matches]);
                        free(matches);
                        matches = (char **) NULL;
-                       free(add_char_to_match);
-                       add_char_to_match = NULL;
                }
                return;
        }
                }
                return;
        }
-       if (! *lastWasTab) {
-
+       if (!*lastWasTab) {
                char *tmp, *tmp1;
                int len_found;
                char matchBuf[BUFSIZ];
                char *tmp, *tmp1;
                int len_found;
                char matchBuf[BUFSIZ];
@@ -1062,7 +1025,7 @@ static void input_tab(int *lastWasTab)
                /* Free up any memory already allocated */
                input_tab(0);
 
                /* Free up any memory already allocated */
                input_tab(0);
 
-#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
+#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
                /* If the word starts with `~' and there is no slash in the word,
                 * then try completing this word as a username. */
 
                /* If the word starts with `~' and there is no slash in the word,
                 * then try completing this word as a username. */
 
@@ -1073,45 +1036,30 @@ static void input_tab(int *lastWasTab)
                /* Try to match any executable in our path and everything
                 * in the current working directory that matches.  */
                        exe_n_cwd_tab_completion(matchBuf, find_type);
                /* Try to match any executable in our path and everything
                 * in the current working directory that matches.  */
                        exe_n_cwd_tab_completion(matchBuf, find_type);
-               /* Remove duplicate found and sort */
-               if(matches) {
-                       int i, j, n, srt;
-                       /* bubble */
-                       n = num_matches;
-                       for(i=0; i<(n-1); i++)
-                           for(j=i+1; j<n; j++)
-                               if(matches[i]!=NULL && matches[j]!=NULL) {
-                                   srt = strcmp(matches[i], matches[j]);
-                                   if(srt == 0) {
-                                       free(matches[j]);
-                                       matches[j]=0;
-                                   } else if(srt > 0) {
-                                       tmp1 = matches[i];
-                                       matches[i] = matches[j];
-                                       matches[j] = tmp1;
-                                       srt = add_char_to_match[i];
-                                       add_char_to_match[i] = add_char_to_match[j];
-                                       add_char_to_match[j] = srt;
-                                   }
+               /* Sort, then remove any duplicates found */
+               if (matches) {
+                       int i, n = 0;
+                       qsort(matches, num_matches, sizeof(char*), match_compare);
+                       for (i = 0; i < num_matches - 1; ++i) {
+                               if (matches[i] && matches[i+1]) {
+                                       if (strcmp(matches[i], matches[i+1]) == 0) {
+                                               free(matches[i]);
+                                               matches[i] = 0;
+                                       } else {
+                                               matches[n++] = matches[i];
+                                       }
                                }
                                }
-                       j = n;
-                       n = 0;
-                       for(i=0; i<j; i++)
-                           if(matches[i]) {
-                               matches[n]=matches[i];
-                               add_char_to_match[n]=add_char_to_match[i];
-                               n++;
-                           }
+                       }
+                       matches[n++] = matches[num_matches-1];
                        num_matches = n;
                }
                /* Did we find exactly one match? */
                if (!matches || num_matches > 1) {
                        num_matches = n;
                }
                /* Did we find exactly one match? */
                if (!matches || num_matches > 1) {
-
                        beep();
                        if (!matches)
                                return;         /* not found */
                        /* find minimal match */
                        beep();
                        if (!matches)
                                return;         /* not found */
                        /* find minimal match */
-                       tmp1 = bb_xstrdup(matches[0]);
+                       tmp1 = xstrdup(matches[0]);
                        for (tmp = tmp1; *tmp; tmp++)
                                for (len_found = 1; len_found < num_matches; len_found++)
                                        if (matches[len_found][(tmp - tmp1)] != *tmp) {
                        for (tmp = tmp1; *tmp; tmp++)
                                for (len_found = 1; len_found < num_matches; len_found++)
                                        if (matches[len_found][(tmp - tmp1)] != *tmp) {
@@ -1122,12 +1070,18 @@ static void input_tab(int *lastWasTab)
                                free(tmp1);
                                return;
                        }
                                free(tmp1);
                                return;
                        }
-                       tmp = add_quote_for_spec_chars(tmp1, 0);
+                       tmp = add_quote_for_spec_chars(tmp1);
                        free(tmp1);
                } else {                        /* one match */
                        free(tmp1);
                } else {                        /* one match */
-                       tmp = add_quote_for_spec_chars(matches[0], add_char_to_match[0]);
+                       tmp = add_quote_for_spec_chars(matches[0]);
                        /* for next completion current found */
                        *lastWasTab = FALSE;
                        /* for next completion current found */
                        *lastWasTab = FALSE;
+
+                       len_found = strlen(tmp);
+                       if (tmp[len_found-1] != '/') {
+                               tmp[len_found] = ' ';
+                               tmp[len_found+1] = '\0';
+                       }
                }
                len_found = strlen(tmp);
                /* have space to placed match? */
                }
                len_found = strlen(tmp);
                /* have space to placed match? */
@@ -1165,14 +1119,14 @@ static void input_tab(int *lastWasTab)
                }
        }
 }
                }
        }
 }
-#endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
+#endif  /* FEATURE_COMMAND_TAB_COMPLETION */
 
 
-#if MAX_HISTORY >= 1
+#if MAX_HISTORY > 0
 static void get_previous_history(void)
 {
 static void get_previous_history(void)
 {
-       if(command_ps[0] != 0 || history[cur_history] == 0) {
+       if (command_ps[0] != 0 || history[cur_history] == 0) {
                free(history[cur_history]);
                free(history[cur_history]);
-               history[cur_history] = bb_xstrdup(command_ps);
+               history[cur_history] = xstrdup(command_ps);
        }
        cur_history--;
 }
        }
        cur_history--;
 }
@@ -1183,59 +1137,60 @@ static int get_next_history(void)
 
        if (ch < n_history) {
                get_previous_history(); /* save the current history line */
 
        if (ch < n_history) {
                get_previous_history(); /* save the current history line */
-               return (cur_history = ch+1);
+               cur_history = ch + 1;
+               return cur_history;
        } else {
                beep();
                return 0;
        }
 }
 
        } else {
                beep();
                return 0;
        }
 }
 
-#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
-extern void load_history ( const char *fromfile )
+#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
+void load_history(const char *fromfile)
 {
        FILE *fp;
        int hi;
 
        /* cleanup old */
 
 {
        FILE *fp;
        int hi;
 
        /* cleanup old */
 
-       for(hi = n_history; hi > 0; ) {
+       for (hi = n_history; hi > 0;) {
                hi--;
                hi--;
-               free ( history [hi] );
+               free(history[hi]);
        }
 
        }
 
-       if (( fp = fopen ( fromfile, "r" ))) {
-
-               for ( hi = 0; hi < MAX_HISTORY; ) {
-                       char * hl = bb_get_chomped_line_from_file(fp);
+       fp = fopen(fromfile, "r");
+       if (fp) {
+               for (hi = 0; hi < MAX_HISTORY;) {
+                       char * hl = xmalloc_getline(fp);
                        int l;
 
                        int l;
 
-                       if(!hl)
+                       if (!hl)
                                break;
                        l = strlen(hl);
                                break;
                        l = strlen(hl);
-                       if(l >= BUFSIZ)
+                       if (l >= BUFSIZ)
                                hl[BUFSIZ-1] = 0;
                                hl[BUFSIZ-1] = 0;
-                       if(l == 0 || hl[0] == ' ') {
+                       if (l == 0 || hl[0] == ' ') {
                                free(hl);
                                continue;
                        }
                                free(hl);
                                continue;
                        }
-                       history [hi++] = hl;
+                       history[hi++] = hl;
                }
                }
-               fclose ( fp );
+               fclose(fp);
        }
        cur_history = n_history = hi;
 }
 
        }
        cur_history = n_history = hi;
 }
 
-extern void save_history ( const char *tofile )
+void save_history (const char *tofile)
 {
 {
-       FILE *fp = fopen ( tofile, "w" );
+       FILE *fp = fopen(tofile, "w");
 
 
-       if ( fp ) {
+       if (fp) {
                int i;
 
                int i;
 
-               for ( i = 0; i < n_history; i++ ) {
-                       fprintf(fp, "%s\n", history [i]);
+               for (i = 0; i < n_history; i++) {
+                       fprintf(fp, "%s\n", history[i]);
                }
                }
-               fclose ( fp );
+               fclose(fp);
        }
 }
 #endif
        }
 }
 #endif
@@ -1266,7 +1221,7 @@ enum {
  *
  */
 
  *
  */
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
 static int vi_mode;
 
 void setvimode ( int viflag )
 static int vi_mode;
 
 void setvimode ( int viflag )
@@ -1287,13 +1242,11 @@ static void
 vi_word_motion(char *command, int eat)
 {
        if (isalnum(command[cursor]) || command[cursor] == '_') {
 vi_word_motion(char *command, int eat)
 {
        if (isalnum(command[cursor]) || command[cursor] == '_') {
-               while (cursor < len &&
-                   (isalnum(command[cursor+1]) ||
-                               command[cursor+1] == '_'))
+               while (cursor < len
+                && (isalnum(command[cursor+1]) || command[cursor+1] == '_'))
                        input_forward();
        } else if (ispunct(command[cursor])) {
                        input_forward();
        } else if (ispunct(command[cursor])) {
-               while (cursor < len &&
-                   (ispunct(command[cursor+1])))
+               while (cursor < len && ispunct(command[cursor+1]))
                        input_forward();
        }
 
                        input_forward();
        }
 
@@ -1326,13 +1279,13 @@ vi_end_motion(char *command)
        if (cursor >= len-1)
                return;
        if (isalnum(command[cursor]) || command[cursor] == '_') {
        if (cursor >= len-1)
                return;
        if (isalnum(command[cursor]) || command[cursor] == '_') {
-               while (cursor < len-1 &&
-                   (isalnum(command[cursor+1]) ||
-                               command[cursor+1] == '_'))
+               while (cursor < len-1
+                && (isalnum(command[cursor+1]) || command[cursor+1] == '_')
+               ) {
                        input_forward();
                        input_forward();
+               }
        } else if (ispunct(command[cursor])) {
        } else if (ispunct(command[cursor])) {
-               while (cursor < len-1 &&
-                   (ispunct(command[cursor+1])))
+               while (cursor < len-1 && ispunct(command[cursor+1]))
                        input_forward();
        }
 }
                        input_forward();
        }
 }
@@ -1357,36 +1310,31 @@ vi_back_motion(char *command)
        if (cursor <= 0)
                return;
        if (isalnum(command[cursor]) || command[cursor] == '_') {
        if (cursor <= 0)
                return;
        if (isalnum(command[cursor]) || command[cursor] == '_') {
-               while (cursor > 0 &&
-                   (isalnum(command[cursor-1]) ||
-                               command[cursor-1] == '_'))
+               while (cursor > 0
+                && (isalnum(command[cursor-1]) || command[cursor-1] == '_')
+               ) {
                        input_backward(1);
                        input_backward(1);
+               }
        } else if (ispunct(command[cursor])) {
        } else if (ispunct(command[cursor])) {
-               while (cursor > 0 &&
-                   (ispunct(command[cursor-1])))
+               while (cursor > 0 && ispunct(command[cursor-1]))
                        input_backward(1);
        }
 }
 #endif
 
 /*
                        input_backward(1);
        }
 }
 #endif
 
 /*
- * the normal emacs mode and vi's insert mode are the same.
- * commands entered when in vi command mode ("escape mode") get
- * an extra bit added to distinguish them.  this lets them share
- * much of the code in the big switch and while loop.  i
- * experimented with an ugly macro to make the case labels for
- * these cases go away entirely when vi mode isn't configured, in
- * hopes of letting the jump tables get smaller:
- *  #define vcase(caselabel) caselabel
- * and then
- *      case CNTRL('A'):
- *      case vcase(VICMD('0'):)
- * but it didn't seem to make any difference in code size,
- * and the macro-ized code was too ugly.
+ * the emacs and vi modes share much of the code in the big
+ * command loop.  commands entered when in vi's command mode (aka
+ * "escape mode") get an extra bit added to distinguish them --
+ * this keeps them from being self-inserted.  this clutters the
+ * big switch a bit, but keeps all the code in one place.
  */
 
  */
 
-#define VI_cmdbit 0x100
-#define VICMD(somecmd) ((somecmd)|VI_cmdbit)
+#define vbit 0x100
+
+/* leave out the "vi-mode"-only case labels if vi editing isn't
+ * configured. */
+#define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel)
 
 /* convert uppercase ascii to equivalent control char, for readability */
 #define CNTRL(uc_char) ((uc_char) - 0x40)
 
 /* convert uppercase ascii to equivalent control char, for readability */
 #define CNTRL(uc_char) ((uc_char) - 0x40)
@@ -1394,12 +1342,12 @@ vi_back_motion(char *command)
 
 int cmdedit_read_input(char *prompt, char command[BUFSIZ])
 {
 
 int cmdedit_read_input(char *prompt, char command[BUFSIZ])
 {
-
        int break_out = 0;
        int lastWasTab = FALSE;
        unsigned char c;
        int break_out = 0;
        int lastWasTab = FALSE;
        unsigned char c;
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
-       unsigned int ic, prevc;
+       unsigned int ic;
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
+       unsigned int prevc;
        int vi_cmdmode = 0;
 #endif
        /* prepare before init handlers */
        int vi_cmdmode = 0;
 #endif
        /* prepare before init handlers */
@@ -1416,9 +1364,9 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
        new_settings.c_cc[VMIN] = 1;
        new_settings.c_cc[VTIME] = 0;
        /* Turn off CTRL-C, so we can trap it */
        new_settings.c_cc[VMIN] = 1;
        new_settings.c_cc[VTIME] = 0;
        /* Turn off CTRL-C, so we can trap it */
-#       ifndef _POSIX_VDISABLE
-#               define _POSIX_VDISABLE '\0'
-#       endif
+#      ifndef _POSIX_VDISABLE
+#              define _POSIX_VDISABLE '\0'
+#      endif
        new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
        command[0] = 0;
 
        new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
        command[0] = 0;
 
@@ -1431,48 +1379,45 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
        parse_prompt(prompt);
 
        while (1) {
        parse_prompt(prompt);
 
        while (1) {
-
                fflush(stdout);                 /* buffered out to fast */
 
                if (safe_read(0, &c, 1) < 1)
                        /* if we can't read input then exit */
                        goto prepare_to_die;
 
                fflush(stdout);                 /* buffered out to fast */
 
                if (safe_read(0, &c, 1) < 1)
                        /* if we can't read input then exit */
                        goto prepare_to_die;
 
-#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI
-               newdelflag = 1;
                ic = c;
                ic = c;
+
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
+               newdelflag = 1;
                if (vi_cmdmode)
                if (vi_cmdmode)
-                       ic |= VI_cmdbit;
-               switch (ic)
-#else
-               switch (c)
+                       ic |= vbit;
 #endif
 #endif
-               {
+               switch (ic) {
                case '\n':
                case '\r':
                case '\n':
                case '\r':
-               case VICMD('\n'):
-               case VICMD('\r'):
+               vi_case( case '\n'|vbit: )
+               vi_case( case '\r'|vbit: )
                        /* Enter */
                        goto_new_line();
                        break_out = 1;
                        break;
                case CNTRL('A'):
                        /* Enter */
                        goto_new_line();
                        break_out = 1;
                        break;
                case CNTRL('A'):
-               case VICMD('0'):
+               vi_case( case '0'|vbit: )
                        /* Control-a -- Beginning of line */
                        input_backward(cursor);
                        break;
                case CNTRL('B'):
                        /* Control-a -- Beginning of line */
                        input_backward(cursor);
                        break;
                case CNTRL('B'):
-               case VICMD('h'):
-               case VICMD('\b'):
-               case VICMD(DEL):
+               vi_case( case 'h'|vbit: )
+               vi_case( case '\b'|vbit: )
+               vi_case( case DEL|vbit: )
                        /* Control-b -- Move back one character */
                        input_backward(1);
                        break;
                case CNTRL('C'):
                        /* Control-b -- Move back one character */
                        input_backward(1);
                        break;
                case CNTRL('C'):
-               case VICMD(CNTRL('C')):
+               vi_case( case CNTRL('C')|vbit: )
                        /* Control-c -- stop gathering input */
                        goto_new_line();
                        /* Control-c -- stop gathering input */
                        goto_new_line();
-#ifndef CONFIG_ASH
+#if !ENABLE_ASH
                        command[0] = 0;
                        len = 0;
                        lastWasTab = FALSE;
                        command[0] = 0;
                        len = 0;
                        lastWasTab = FALSE;
@@ -1486,9 +1431,9 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
                        /* Control-d -- Delete one character, or exit
                         * if the len=0 and no chars to delete */
                        if (len == 0) {
                        /* Control-d -- Delete one character, or exit
                         * if the len=0 and no chars to delete */
                        if (len == 0) {
-                                       errno = 0;
-prepare_to_die:
-#if !defined(CONFIG_ASH)
+                               errno = 0;
+ prepare_to_die:
+#if !ENABLE_ASH
                                printf("exit");
                                goto_new_line();
                                /* cmdedit_reset_term() called in atexit */
                                printf("exit");
                                goto_new_line();
                                /* cmdedit_reset_term() called in atexit */
@@ -1503,13 +1448,13 @@ prepare_to_die:
                        }
                        break;
                case CNTRL('E'):
                        }
                        break;
                case CNTRL('E'):
-               case VICMD('$'):
+               vi_case( case '$'|vbit: )
                        /* Control-e -- End of line */
                        input_end();
                        break;
                case CNTRL('F'):
                        /* Control-e -- End of line */
                        input_end();
                        break;
                case CNTRL('F'):
-               case VICMD('l'):
-               case VICMD(' '):
+               vi_case( case 'l'|vbit: )
+               vi_case( case ' '|vbit: )
                        /* Control-f -- Move forward one character */
                        input_forward();
                        break;
                        /* Control-f -- Move forward one character */
                        input_forward();
                        break;
@@ -1519,33 +1464,33 @@ prepare_to_die:
                        input_backspace();
                        break;
                case '\t':
                        input_backspace();
                        break;
                case '\t':
-#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
                        input_tab(&lastWasTab);
 #endif
                        break;
                case CNTRL('K'):
                        /* Control-k -- clear to end of line */
                        input_tab(&lastWasTab);
 #endif
                        break;
                case CNTRL('K'):
                        /* Control-k -- clear to end of line */
-                       *(command + cursor) = 0;
+                       command[cursor] = 0;
                        len = cursor;
                        printf("\033[J");
                        break;
                case CNTRL('L'):
                        len = cursor;
                        printf("\033[J");
                        break;
                case CNTRL('L'):
-               case VICMD(CNTRL('L')):
+               vi_case( case CNTRL('L')|vbit: )
                        /* Control-l -- clear screen */
                        printf("\033[H");
                        /* Control-l -- clear screen */
                        printf("\033[H");
-                       redraw(0, len-cursor);
+                       redraw(0, len - cursor);
                        break;
                        break;
-#if MAX_HISTORY >= 1
+#if MAX_HISTORY > 0
                case CNTRL('N'):
                case CNTRL('N'):
-               case VICMD(CNTRL('N')):
-               case VICMD('j'):
+               vi_case( case CNTRL('N')|vbit: )
+               vi_case( case 'j'|vbit: )
                        /* Control-n -- Get next command in history */
                        if (get_next_history())
                                goto rewrite_line;
                        break;
                case CNTRL('P'):
                        /* Control-n -- Get next command in history */
                        if (get_next_history())
                                goto rewrite_line;
                        break;
                case CNTRL('P'):
-               case VICMD(CNTRL('P')):
-               case VICMD('k'):
+               vi_case( case CNTRL('P')|vbit: )
+               vi_case( case 'k'|vbit: )
                        /* Control-p -- Get previous command from history */
                        if (cur_history > 0) {
                                get_previous_history();
                        /* Control-p -- Get previous command from history */
                        if (cur_history > 0) {
                                get_previous_history();
@@ -1556,7 +1501,7 @@ prepare_to_die:
                        break;
 #endif
                case CNTRL('U'):
                        break;
 #endif
                case CNTRL('U'):
-               case VICMD(CNTRL('U')):
+               vi_case( case CNTRL('U')|vbit: )
                        /* Control-U -- Clear line before cursor */
                        if (cursor) {
                                strcpy(command, command + cursor);
                        /* Control-U -- Clear line before cursor */
                        if (cursor) {
                                strcpy(command, command + cursor);
@@ -1564,131 +1509,130 @@ prepare_to_die:
                        }
                        break;
                case CNTRL('W'):
                        }
                        break;
                case CNTRL('W'):
-               case VICMD(CNTRL('W')):
+               vi_case( case CNTRL('W')|vbit: )
                        /* Control-W -- Remove the last word */
                        while (cursor > 0 && isspace(command[cursor-1]))
                                input_backspace();
                        while (cursor > 0 &&!isspace(command[cursor-1]))
                                input_backspace();
                        break;
                        /* Control-W -- Remove the last word */
                        while (cursor > 0 && isspace(command[cursor-1]))
                                input_backspace();
                        while (cursor > 0 &&!isspace(command[cursor-1]))
                                input_backspace();
                        break;
-#if CONFIG_FEATURE_COMMAND_EDITING_VI
-               case VICMD('i'):
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
+               case 'i'|vbit:
                        vi_cmdmode = 0;
                        break;
                        vi_cmdmode = 0;
                        break;
-               case VICMD('I'):
+               case 'I'|vbit:
                        input_backward(cursor);
                        vi_cmdmode = 0;
                        break;
                        input_backward(cursor);
                        vi_cmdmode = 0;
                        break;
-               case VICMD('a'):
+               case 'a'|vbit:
                        input_forward();
                        vi_cmdmode = 0;
                        break;
                        input_forward();
                        vi_cmdmode = 0;
                        break;
-               case VICMD('A'):
+               case 'A'|vbit:
                        input_end();
                        vi_cmdmode = 0;
                        break;
                        input_end();
                        vi_cmdmode = 0;
                        break;
-               case VICMD('x'):
+               case 'x'|vbit:
                        input_delete(1);
                        break;
                        input_delete(1);
                        break;
-               case VICMD('X'):
+               case 'X'|vbit:
                        if (cursor > 0) {
                                input_backward(1);
                                input_delete(1);
                        }
                        break;
                        if (cursor > 0) {
                                input_backward(1);
                                input_delete(1);
                        }
                        break;
-               case VICMD('W'):
+               case 'W'|vbit:
                        vi_Word_motion(command, 1);
                        break;
                        vi_Word_motion(command, 1);
                        break;
-               case VICMD('w'):
+               case 'w'|vbit:
                        vi_word_motion(command, 1);
                        break;
                        vi_word_motion(command, 1);
                        break;
-               case VICMD('E'):
+               case 'E'|vbit:
                        vi_End_motion(command);
                        break;
                        vi_End_motion(command);
                        break;
-               case VICMD('e'):
+               case 'e'|vbit:
                        vi_end_motion(command);
                        break;
                        vi_end_motion(command);
                        break;
-               case VICMD('B'):
+               case 'B'|vbit:
                        vi_Back_motion(command);
                        break;
                        vi_Back_motion(command);
                        break;
-               case VICMD('b'):
+               case 'b'|vbit:
                        vi_back_motion(command);
                        break;
                        vi_back_motion(command);
                        break;
-               case VICMD('C'):
+               case 'C'|vbit:
                        vi_cmdmode = 0;
                        /* fall through */
                        vi_cmdmode = 0;
                        /* fall through */
-               case VICMD('D'):
+               case 'D'|vbit:
                        goto clear_to_eol;
 
                        goto clear_to_eol;
 
-               case VICMD('c'):
+               case 'c'|vbit:
                        vi_cmdmode = 0;
                        /* fall through */
                        vi_cmdmode = 0;
                        /* fall through */
-               case VICMD('d'):
-                       {
+               case 'd'|vbit: {
                        int nc, sc;
                        sc = cursor;
                        prevc = ic;
                        if (safe_read(0, &c, 1) < 1)
                                goto prepare_to_die;
                        if (c == (prevc & 0xff)) {
                        int nc, sc;
                        sc = cursor;
                        prevc = ic;
                        if (safe_read(0, &c, 1) < 1)
                                goto prepare_to_die;
                        if (c == (prevc & 0xff)) {
-                           /* "cc", "dd" */
-                           input_backward(cursor);
-                           goto clear_to_eol;
-                           break;
+                               /* "cc", "dd" */
+                               input_backward(cursor);
+                               goto clear_to_eol;
+                               break;
                        }
                        }
-                       switch(c) {
+                       switch (c) {
                        case 'w':
                        case 'W':
                        case 'e':
                        case 'E':
                        case 'w':
                        case 'W':
                        case 'e':
                        case 'E':
-                           switch (c) {
-                           case 'w':   /* "dw", "cw" */
-                                   vi_word_motion(command, vi_cmdmode);
-                                   break;
-                           case 'W':   /* 'dW', 'cW' */
-                                   vi_Word_motion(command, vi_cmdmode);
-                                   break;
-                           case 'e':   /* 'de', 'ce' */
-                                   vi_end_motion(command);
-                                   input_forward();
-                                   break;
-                           case 'E':   /* 'dE', 'cE' */
-                                   vi_End_motion(command);
-                                   input_forward();
-                                   break;
-                           }
-                           nc = cursor;
-                           input_backward(cursor - sc);
-                           while (nc-- > cursor)
-                                   input_delete(1);
-                           break;
+                               switch (c) {
+                               case 'w':   /* "dw", "cw" */
+                                       vi_word_motion(command, vi_cmdmode);
+                                       break;
+                               case 'W':   /* 'dW', 'cW' */
+                                       vi_Word_motion(command, vi_cmdmode);
+                                       break;
+                               case 'e':   /* 'de', 'ce' */
+                                       vi_end_motion(command);
+                                       input_forward();
+                                       break;
+                               case 'E':   /* 'dE', 'cE' */
+                                       vi_End_motion(command);
+                                       input_forward();
+                                       break;
+                               }
+                               nc = cursor;
+                               input_backward(cursor - sc);
+                               while (nc-- > cursor)
+                                       input_delete(1);
+                               break;
                        case 'b':  /* "db", "cb" */
                        case 'B':  /* implemented as B */
                        case 'b':  /* "db", "cb" */
                        case 'B':  /* implemented as B */
-                           if (c == 'b')
-                                   vi_back_motion(command);
-                           else
-                                   vi_Back_motion(command);
-                           while (sc-- > cursor)
-                                   input_delete(1);
-                           break;
+                               if (c == 'b')
+                                       vi_back_motion(command);
+                               else
+                                       vi_Back_motion(command);
+                               while (sc-- > cursor)
+                                       input_delete(1);
+                               break;
                        case ' ':  /* "d ", "c " */
                        case ' ':  /* "d ", "c " */
-                           input_delete(1);
-                           break;
+                               input_delete(1);
+                               break;
                        case '$':  /* "d$", "c$" */
                        clear_to_eol:
                        case '$':  /* "d$", "c$" */
                        clear_to_eol:
-                           while (cursor < len)
-                                   input_delete(1);
-                           break;
-                       }
+                               while (cursor < len)
+                                       input_delete(1);
+                               break;
                        }
                        break;
                        }
                        break;
-               case VICMD('p'):
+               }
+               case 'p'|vbit:
                        input_forward();
                        /* fallthrough */
                        input_forward();
                        /* fallthrough */
-               case VICMD('P'):
+               case 'P'|vbit:
                        put();
                        break;
                        put();
                        break;
-               case VICMD('r'):
+               case 'r'|vbit:
                        if (safe_read(0, &c, 1) < 1)
                                goto prepare_to_die;
                        if (c == 0)
                        if (safe_read(0, &c, 1) < 1)
                                goto prepare_to_die;
                        if (c == 0)
@@ -1699,9 +1643,11 @@ prepare_to_die:
                                putchar('\b');
                        }
                        break;
                                putchar('\b');
                        }
                        break;
-#endif /* CONFIG_FEATURE_COMMAND_EDITING_VI */
-               case ESC:{
-#if CONFIG_FEATURE_COMMAND_EDITING_VI
+#endif /* FEATURE_COMMAND_EDITING_VI */
+
+               case ESC:
+
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
                        if (vi_mode) {
                                /* ESC: insert mode --> command mode */
                                vi_cmdmode = 1;
                        if (vi_mode) {
                                /* ESC: insert mode --> command mode */
                                vi_cmdmode = 1;
@@ -1714,8 +1660,8 @@ prepare_to_die:
                                goto prepare_to_die;
                        /* different vt100 emulations */
                        if (c == '[' || c == 'O') {
                                goto prepare_to_die;
                        /* different vt100 emulations */
                        if (c == '[' || c == 'O') {
-               case VICMD('['):
-               case VICMD('O'):
+               vi_case( case '['|vbit: )
+               vi_case( case 'O'|vbit: )
                                if (safe_read(0, &c, 1) < 1)
                                        goto prepare_to_die;
                        }
                                if (safe_read(0, &c, 1) < 1)
                                        goto prepare_to_die;
                        }
@@ -1724,17 +1670,17 @@ prepare_to_die:
 
                                if (safe_read(0, &dummy, 1) < 1)
                                        goto prepare_to_die;
 
                                if (safe_read(0, &dummy, 1) < 1)
                                        goto prepare_to_die;
-                               if(dummy != '~')
+                               if (dummy != '~')
                                        c = 0;
                        }
                        switch (c) {
                                        c = 0;
                        }
                        switch (c) {
-#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
                        case '\t':                      /* Alt-Tab */
 
                                input_tab(&lastWasTab);
                                break;
 #endif
                        case '\t':                      /* Alt-Tab */
 
                                input_tab(&lastWasTab);
                                break;
 #endif
-#if MAX_HISTORY >= 1
+#if MAX_HISTORY > 0
                        case 'A':
                                /* Up Arrow -- Get previous command from history */
                                if (cur_history > 0) {
                        case 'A':
                                /* Up Arrow -- Get previous command from history */
                                if (cur_history > 0) {
@@ -1753,7 +1699,7 @@ rewrite_line:
                                /* change command */
                                len = strlen(strcpy(command, history[cur_history]));
                                /* redraw and go to eol (bol, in vi */
                                /* change command */
                                len = strlen(strcpy(command, history[cur_history]));
                                /* redraw and go to eol (bol, in vi */
-#if CONFIG_FEATURE_COMMAND_EDITING_VI
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
                                redraw(cmdedit_y, vi_mode ? 9999:0);
 #else
                                redraw(cmdedit_y, 0);
                                redraw(cmdedit_y, vi_mode ? 9999:0);
 #else
                                redraw(cmdedit_y, 0);
@@ -1787,10 +1733,9 @@ rewrite_line:
                                beep();
                        }
                        break;
                                beep();
                        }
                        break;
-               }
 
                default:        /* If it's regular input, do the normal thing */
 
                default:        /* If it's regular input, do the normal thing */
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
                        /* Control-V -- Add non-printable symbol */
                        if (c == CNTRL('V')) {
                                if (safe_read(0, &c, 1) < 1)
                        /* Control-V -- Add non-printable symbol */
                        if (c == CNTRL('V')) {
                                if (safe_read(0, &c, 1) < 1)
@@ -1802,7 +1747,7 @@ rewrite_line:
                        } else
 #endif
                        {
                        } else
 #endif
                        {
-#if CONFIG_FEATURE_COMMAND_EDITING_VI
+#if ENABLE_FEATURE_COMMAND_EDITING_VI
                                if (vi_cmdmode)  /* don't self-insert */
                                        break;
 #endif
                                if (vi_cmdmode)  /* don't self-insert */
                                        break;
 #endif
@@ -1843,10 +1788,10 @@ rewrite_line:
        setTermSettings(0, (void *) &initial_settings);
        handlers_sets &= ~SET_RESET_TERM;
 
        setTermSettings(0, (void *) &initial_settings);
        handlers_sets &= ~SET_RESET_TERM;
 
-#if MAX_HISTORY >= 1
+#if MAX_HISTORY > 0
        /* Handle command history log */
        /* cleanup may be saved current command line */
        /* Handle command history log */
        /* cleanup may be saved current command line */
-       if (len> 0) {                                      /* no put empty line */
+       if (len > 0) {                                      /* no put empty line */
                int i = n_history;
 
                free(history[MAX_HISTORY]);
                int i = n_history;
 
                free(history[MAX_HISTORY]);
@@ -1854,47 +1799,45 @@ rewrite_line:
                        /* After max history, remove the oldest command */
                if (i >= MAX_HISTORY) {
                        free(history[0]);
                        /* After max history, remove the oldest command */
                if (i >= MAX_HISTORY) {
                        free(history[0]);
-                       for(i = 0; i < (MAX_HISTORY-1); i++)
+                       for (i = 0; i < MAX_HISTORY-1; i++)
                                history[i] = history[i+1];
                }
                                history[i] = history[i+1];
                }
-               history[i++] = bb_xstrdup(command);
+               history[i++] = xstrdup(command);
                cur_history = i;
                n_history = i;
                cur_history = i;
                n_history = i;
-#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
+#if ENABLE_FEATURE_SH_FANCY_PROMPT
                num_ok_lines++;
 #endif
        }
                num_ok_lines++;
 #endif
        }
-#else  /* MAX_HISTORY < 1 */
-#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
+#else  /* MAX_HISTORY == 0 */
+#if ENABLE_FEATURE_SH_FANCY_PROMPT
        if (len > 0) {              /* no put empty line */
                num_ok_lines++;
        }
 #endif
        if (len > 0) {              /* no put empty line */
                num_ok_lines++;
        }
 #endif
-#endif  /* MAX_HISTORY >= 1 */
+#endif  /* MAX_HISTORY > 0 */
        if (break_out > 0) {
                command[len++] = '\n';          /* set '\n' */
                command[len] = 0;
        }
        if (break_out > 0) {
                command[len++] = '\n';          /* set '\n' */
                command[len] = 0;
        }
-#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION)
+#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
        input_tab(0);                           /* strong free */
 #endif
        input_tab(0);                           /* strong free */
 #endif
-#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
+#if ENABLE_FEATURE_SH_FANCY_PROMPT
        free(cmdedit_prompt);
 #endif
        cmdedit_reset_term();
        return len;
 }
 
        free(cmdedit_prompt);
 #endif
        cmdedit_reset_term();
        return len;
 }
 
-
-
-#endif  /* CONFIG_FEATURE_COMMAND_EDITING */
+#endif  /* FEATURE_COMMAND_EDITING */
 
 
 #ifdef TEST
 
 
 
 #ifdef TEST
 
-const char *bb_applet_name = "debug stuff usage";
+const char *applet_name = "debug stuff usage";
 
 
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
 #include <locale.h>
 #endif
 
 #include <locale.h>
 #endif
 
@@ -1902,26 +1845,24 @@ int main(int argc, char **argv)
 {
        char buff[BUFSIZ];
        char *prompt =
 {
        char buff[BUFSIZ];
        char *prompt =
-#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
-               "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
-\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
-\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
+#if ENABLE_FEATURE_SH_FANCY_PROMPT
+               "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
+               "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
+               "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
 #else
                "% ";
 #endif
 
 #else
                "% ";
 #endif
 
-#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
        setlocale(LC_ALL, "");
 #endif
        setlocale(LC_ALL, "");
 #endif
-       while(1) {
+       while (1) {
                int l;
                l = cmdedit_read_input(prompt, buff);
                int l;
                l = cmdedit_read_input(prompt, buff);
-               if(l > 0 && buff[l-1] == '\n') {
-                       buff[l-1] = 0;
-                       printf("*** cmdedit_read_input() returned line =%s=\n", buff);
-               } else {
+               if (l <= 0 || buff[l-1] != '\n')
                        break;
                        break;
-               }
+               buff[l-1] = 0;
+               printf("*** cmdedit_read_input() returned line =%s=\n", buff);
        }
        printf("*** cmdedit_read_input() detect ^D\n");
        return 0;
        }
        printf("*** cmdedit_read_input() detect ^D\n");
        return 0;