lineedit: return prefix len from tab completion helpers

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>
This commit is contained in:
Denys Vlasenko 2010-09-03 12:56:36 +02:00
parent 2679e3c8cc
commit 3c460b005c

View File

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