- don't free user-supplied string (via -e)
[oweals/busybox.git] / libbb / lineedit.c
index d1a7a4bac8d84c8a393945badfe303a385f73277..3e16f642311c3e95c9488c6f5cfb4c3fac53326a 100644 (file)
  */
 
 /*
-   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
-   to work in an Xterm and console. Ctrl-A also works as Home.
-   Ctrl-E also works as End.
-
-   Small bugs (simple effect):
-   - not true viewing if terminal size (x*y symbols) less
-     size (prompt + editor's line + 2 symbols)
-   - not true viewing if length prompt less terminal width
+ * 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
+ * to work in an Xterm and console. Ctrl-A also works as Home.
+ * Ctrl-E also works as End.
+ *
+ * lineedit does not know that the terminal escape sequences do not
+ * take up space on the screen. The redisplay code assumes, unless
+ * told otherwise, that each character in the prompt is a printable
+ * character that takes up one character position on the screen.
+ * You need to tell lineedit that some sequences of characters
+ * in the prompt take up no screen space. Compatibly with readline,
+ * use the \[ escape to begin a sequence of non-printing characters,
+ * and the \] escape to signal the end of such a sequence. Example:
+ *
+ * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
  */
 
 #include "libbb.h"
@@ -80,10 +86,9 @@ struct lineedit_statics {
        volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
        sighandler_t previous_SIGWINCH_handler;
 
-
-       int cmdedit_x;           /* real x terminal position */
-       int cmdedit_y;           /* pseudoreal y terminal position */
-       int cmdedit_prmt_len;    /* length of prompt (without colors etc) */
+       unsigned cmdedit_x;        /* real x terminal position */
+       unsigned cmdedit_y;        /* pseudoreal y terminal position */
+       unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
 
        unsigned cursor;
        unsigned command_len;
@@ -266,8 +271,8 @@ static void input_backward(unsigned num)
                cmdedit_x -= num;
                if (num <= 4) {
                        /* This is longer by 5 bytes on x86.
-                        * Also gets mysteriously
-                        * miscompiled for some ARM users.
+                        * Also gets miscompiled for ARM users
+                        * (busybox.net/bugs/view.php?id=2274).
                         * printf(("\b\b\b\b" + 4) - num);
                         * return;
                         */
@@ -282,9 +287,12 @@ static void input_backward(unsigned num)
 
        /* Need to go one or more lines up */
        num -= cmdedit_x;
-       count_y = 1 + (num / cmdedit_termw);
-       cmdedit_y -= count_y;
-       cmdedit_x = cmdedit_termw * count_y - num;
+       {
+               unsigned w = cmdedit_termw; /* volatile var */
+               count_y = 1 + (num / w);
+               cmdedit_y -= count_y;
+               cmdedit_x = w * count_y - num;
+       }
        /* go to 1st column; go up; go to correct column */
        printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);
 }
@@ -292,10 +300,12 @@ static void input_backward(unsigned num)
 static void put_prompt(void)
 {
        out1str(cmdedit_prompt);
-       cmdedit_x = cmdedit_prmt_len;
        cursor = 0;
-// Huh? what if cmdedit_prmt_len >= width?
-       cmdedit_y = 0;                  /* new quasireal y */
+       {
+               unsigned w = cmdedit_termw; /* volatile var */
+               cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
+               cmdedit_x = cmdedit_prmt_len % w;
+       }
 }
 
 /* draw prompt, editor line, and clear tail */
@@ -321,7 +331,7 @@ static void input_delete(int save)
 {
        int j = cursor;
 
-       if (j == command_len)
+       if (j == (int)command_len)
                return;
 
 #if ENABLE_FEATURE_EDITING_VI
@@ -335,7 +345,7 @@ static void input_delete(int save)
        }
 #endif
 
-       strcpy(command_ps + j, command_ps + j + 1);
+       overlapping_strcpy(command_ps + j, command_ps + j + 1);
        command_len--;
        input_end();                    /* rewrite new line */
        cmdedit_set_out_char(' ');      /* erase char */
@@ -390,11 +400,8 @@ static void free_tab_completion_data(void)
 
 static void add_match(char *matched)
 {
-       int nm = num_matches;
-       int nm1 = nm + 1;
-
-       matches = xrealloc(matches, nm1 * sizeof(char *));
-       matches[nm] = matched;
+       matches = xrealloc_vector(matches, 4, num_matches);
+       matches[num_matches] = matched;
        num_matches++;
 }
 
@@ -830,7 +837,7 @@ static void input_tab(smallint *lastWasTab)
 
        if (!*lastWasTab) {
                char *tmp, *tmp1;
-               int len_found;
+               size_t len_found;
 /*             char matchBuf[MAX_LINELEN]; */
 #define matchBuf (S.input_tab__matchBuf)
                int find_type;
@@ -861,7 +868,8 @@ static void input_tab(smallint *lastWasTab)
                        exe_n_cwd_tab_completion(matchBuf, find_type);
                /* Sort, then remove any duplicates found */
                if (matches) {
-                       int i, n = 0;
+                       unsigned i;
+                       int n = 0;
                        qsort_string_vector(matches, num_matches);
                        for (i = 0; i < num_matches - 1; ++i) {
                                if (matches[i] && matches[i+1]) { /* paranoia */
@@ -981,7 +989,7 @@ static void load_history(const char *fromfile)
 
        /* NB: do not trash old history if file can't be opened */
 
-       fp = fopen(fromfile, "r");
+       fp = fopen_for_read(fromfile);
        if (fp) {
                /* clean up old history */
                for (hi = state->cnt_history; hi > 0;) {
@@ -1014,7 +1022,7 @@ static void save_history(const char *tofile)
 {
        FILE *fp;
 
-       fp = fopen(tofile, "w");
+       fp = fopen_for_write(tofile);
        if (fp) {
                int i;
 
@@ -1317,7 +1325,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg)
 
 static void win_changed(int nsig)
 {
-       int width;
+       unsigned width;
        get_terminal_width_height(0, &width, NULL);
        cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
        if (nsig == SIGWINCH)
@@ -1347,12 +1355,12 @@ static void win_changed(int nsig)
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-int read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
+int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
 {
 #if ENABLE_FEATURE_TAB_COMPLETION
        smallint lastWasTab = FALSE;
 #endif
-       unsigned int ic;
+       unsigned ic;
        unsigned char c;
        smallint break_out = 0;
 #if ENABLE_FEATURE_EDITING_VI
@@ -1544,7 +1552,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t
                vi_case(CTRL('U')|vbit:)
                        /* Control-U -- Clear line before cursor */
                        if (cursor) {
-                               strcpy(command, command + cursor);
+                               overlapping_strcpy(command, command + cursor);
                                command_len -= cursor;
                                redraw(cmdedit_y, command_len);
                        }
@@ -1787,7 +1795,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t
                        if (vi_cmdmode)  /* Don't self-insert */
                                break;
 #endif
-                       if (command_len >= (maxsize - 2))        /* Need to leave space for enter */
+                       if ((int)command_len >= (maxsize - 2))        /* Need to leave space for enter */
                                break;
 
                        command_len++;
@@ -1840,7 +1848,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t
        return command_len;
 }
 
-line_input_t *new_line_input_t(int flags)
+line_input_t* FAST_FUNC new_line_input_t(int flags)
 {
        line_input_t *n = xzalloc(sizeof(*n));
        n->flags = flags;
@@ -1850,7 +1858,7 @@ line_input_t *new_line_input_t(int flags)
 #else
 
 #undef read_line_input
-int read_line_input(const char* prompt, char* command, int maxsize)
+int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
 {
        fputs(prompt, stdout);
        fflush(stdout);