lineedit: return prefix len from tab completion helpers
authorDenys Vlasenko <dvlasenk@redhat.com>
Fri, 3 Sep 2010 10:56:36 +0000 (12:56 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Fri, 3 Sep 2010 10:56:36 +0000 (12:56 +0200)
This kills horrific logic which deletes and re-adds prefix (!)

function                                             old     new   delta
complete_cmd_dir_file                                705     731     +26
complete_username                                    121     124      +3
input_tab                                           1041    1016     -25
build_match_prefix                                   838     804     -34
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 29/-59)            Total: -30 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
libbb/lineedit.c

index dd9d85b28246185042bc0a65e5e7d4efb3bef291..e40917f620a00138623b0bde2ef7d0fca61529f3 100644 (file)
@@ -638,14 +638,16 @@ static char *username_path_completion(char *ud)
        return tilde_name;
 }
 
-/* ~use<tab> - find all users with this prefix */
-static NOINLINE void complete_username(const char *ud)
+/* ~use<tab> - find all users with this prefix.
+ * Return the length of the prefix used for matching.
+ */
+static NOINLINE unsigned complete_username(const char *ud)
 {
        /* Using _r function to avoid pulling in static buffers */
        char line_buff[256];
        struct passwd pwd;
        struct passwd *result;
-       int userlen;
+       unsigned userlen;
 
        ud++; /* skip ~ */
        userlen = strlen(ud);
@@ -658,6 +660,8 @@ static NOINLINE void complete_username(const char *ud)
                }
        }
        endpwent();
+
+       return 1 + userlen;
 }
 #endif  /* FEATURE_USERNAME_COMPLETION */
 
@@ -710,14 +714,17 @@ static int path_parse(char ***p)
        return npth;
 }
 
-static NOINLINE void complete_cmd_dir_file(char *command, int type)
+/* Complete command, directory or file name.
+ * Return the length of the prefix used for matching.
+ */
+static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
 {
        char *path1[1];
        char **paths = path1;
        int npaths;
        int i;
        unsigned pf_len;
-       char *pfind;
+       const char *pfind;
        char *dirbuf = NULL;
 
        npaths = 1;
@@ -797,8 +804,12 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type)
        if (paths != path1) {
                free(paths[0]); /* allocated memory is only in first member */
                free(paths);
+       } else if (dirbuf) {
+               pf_len += strlen(dirbuf);
+               free(dirbuf);
        }
-       free(dirbuf);
+
+       return pf_len;
 }
 
 /* build_match_prefix:
@@ -829,7 +840,7 @@ static void collapse_pos(int beg, int end)
                bb_putchar('\n');
        }
 }
-static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
+static NOINLINE int build_match_prefix(char *matchBuf)
 {
        int i, j;
        int command_mode;
@@ -992,9 +1003,6 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
                        pos = pos_buf[i] + 1;
                }
                matchBuf[j] = '\0';
-               /* old length matchBuf with quotes symbols */
-               *len_with_quotes = pos ? pos - pos_buf[0] : 0;
-               if (dbg_bmp) printf("len_with_quotes:%d\n", *len_with_quotes);
        }
 
        return command_mode;
@@ -1067,12 +1075,13 @@ static NOINLINE void input_tab(smallint *lastWasTab)
                return;
 
        if (!*lastWasTab) {
-               char *tmp, *tmp1;
+               char *tmp;
                size_t len_found;
 /*             char matchBuf[MAX_LINELEN]; */
 #define matchBuf (S.input_tab__matchBuf)
+               /* Length of string used for matching */
+               unsigned match_pfx_len = match_pfx_len;
                int find_type;
-               int recalc_pos;
 #if ENABLE_UNICODE_SUPPORT
                /* cursor pos in command converted to multibyte form */
                int cursor_mb;
@@ -1095,7 +1104,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
 #endif
                tmp = matchBuf;
 
-               find_type = build_match_prefix(matchBuf, &recalc_pos);
+               find_type = build_match_prefix(matchBuf);
 
                /* Free up any memory already allocated */
                free_tab_completion_data();
@@ -1105,11 +1114,11 @@ static NOINLINE void input_tab(smallint *lastWasTab)
                 * then try completing this word as a username. */
                if (state->flags & USERNAME_COMPLETION)
                        if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL)
-                               complete_username(matchBuf);
+                               match_pfx_len = complete_username(matchBuf);
 #endif
                /* Try to match a command in $PATH, or a directory, or a file */
                if (!matches)
-                       complete_cmd_dir_file(matchBuf, find_type);
+                       match_pfx_len = complete_cmd_dir_file(matchBuf, find_type);
                /* Remove duplicates */
                if (matches) {
                        unsigned i;
@@ -1130,23 +1139,26 @@ static NOINLINE void input_tab(smallint *lastWasTab)
                }
                /* Did we find exactly one match? */
                if (num_matches != 1) { /* no */
+                       char *tmp1;
                        beep();
                        if (!matches)
                                return; /* no matches at all */
                        /* Find common prefix */
                        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) {
-                                               *tmp = '\0';
-                                               break;
+                               unsigned n;
+                               for (n = 1; n < num_matches; n++) {
+                                       if (matches[n][tmp - tmp1] != *tmp) {
+                                               goto stop;
                                        }
                                }
                        }
-                       if (*tmp1 == '\0') { /* have unique prefix? */
+ stop:
+                       if (tmp1 == tmp) { /* have unique prefix? */
                                free(tmp1); /* no */
                                return;
                        }
+                       *tmp = '\0';
                        tmp = add_quote_for_spec_chars(tmp1);
                        free(tmp1);
                        len_found = strlen(tmp);
@@ -1163,41 +1175,43 @@ static NOINLINE void input_tab(smallint *lastWasTab)
                }
 
 #if !ENABLE_UNICODE_SUPPORT
-               /* have space to place the match? */
+               /* Have space to place the match? */
                /* The result consists of three parts with these lengths: */
-               /* (cursor - recalc_pos) + len_found + (command_len - cursor) */
+               /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */
                /* it simplifies into: */
-               if ((int)(len_found + command_len - recalc_pos) < S.maxsize) {
+               if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) {
+                       int pos;
                        /* save tail */
-                       strcpy(matchBuf, command_ps + cursor);
+                       strcpy(matchBuf, &command_ps[cursor]);
                        /* add match and tail */
-                       sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf);
+                       sprintf(&command_ps[cursor], "%s%s", tmp + match_pfx_len, matchBuf);
                        command_len = strlen(command_ps);
                        /* new pos */
-                       recalc_pos = cursor - recalc_pos + len_found;
+                       pos = cursor + len_found - match_pfx_len;
                        /* write out the matched command */
-                       redraw(cmdedit_y, command_len - recalc_pos);
+                       redraw(cmdedit_y, command_len - pos);
                }
 #else
                {
                        char command[MAX_LINELEN];
                        int len = save_string(command, sizeof(command));
-                       /* have space to place the match? */
-                       /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */
-                       if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) {
+                       /* Have space to place the match? */
+                       /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */
+                       if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) {
+                               int pos;
                                /* save tail */
-                               strcpy(matchBuf, command + cursor_mb);
+                               strcpy(matchBuf, &command[cursor_mb]);
                                /* where do we want to have cursor after all? */
-                               strcpy(&command[cursor_mb - recalc_pos], tmp);
+                               strcpy(&command[cursor_mb], tmp + match_pfx_len);
                                len = load_string(command, S.maxsize);
                                /* add match and tail */
-                               sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf);
+                               sprintf(&command[cursor_mb], "%s%s", tmp + match_pfx_len, matchBuf);
                                command_len = load_string(command, S.maxsize);
                                /* write out the matched command */
                                /* paranoia: load_string can return 0 on conv error,
-                                * prevent passing len = (0 - 12) to redraw */
-                               len = command_len - len;
-                               redraw(cmdedit_y, len >= 0 ? len : 0);
+                                * prevent passing pos = (0 - 12) to redraw */
+                               pos = command_len - len;
+                               redraw(cmdedit_y, pos >= 0 ? pos : 0);
                        }
                }
 #endif