From 3c460b005c3c422fe73dc464902e0626fc57938a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 3 Sep 2010 12:56:36 +0200 Subject: [PATCH] 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 --- libbb/lineedit.c | 86 ++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index dd9d85b28..e40917f62 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -638,14 +638,16 @@ static char *username_path_completion(char *ud) return tilde_name; } -/* ~use - find all users with this prefix */ -static NOINLINE void complete_username(const char *ud) +/* ~use - 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 -- 2.25.1