preparatory cleanup patch for tab completion fixes

renames and deinlines a few functions

function                                             old     new   delta
input_tab                                              -    1041   +1041
complete_cmd_dir_file                                  -     699    +699
complete_username                                      -     121    +121
username_completion                                  121       -    -121
read_line_input                                     5002    3313   -1689
------------------------------------------------------------------------------
(add/remove: 3/1 grow/shrink: 0/1 up/down: 1861/-1810)         Total: 51 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-03 12:51:36 +02:00
parent 7063e86d0d
commit 57ea9b488b

View File

@ -1,6 +1,6 @@
/* vi: set sw=4 ts=4: */ /* vi: set sw=4 ts=4: */
/* /*
* Termios command line History and Editing. * Command line editing.
* *
* Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
* Written by: Vladimir Oleynik <dzo@simtreas.ru> * Written by: Vladimir Oleynik <dzo@simtreas.ru>
@ -194,7 +194,7 @@ static void deinit_S(void)
{ {
#if ENABLE_FEATURE_EDITING_FANCY_PROMPT #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
/* This one is allocated only if FANCY_PROMPT is on /* This one is allocated only if FANCY_PROMPT is on
* (otherwise it points to verbatim prompt (NOT malloced) */ * (otherwise it points to verbatim prompt (NOT malloced)) */
free((char*)cmdedit_prompt); free((char*)cmdedit_prompt);
#endif #endif
#if ENABLE_USERNAME_OR_HOMEDIR #if ENABLE_USERNAME_OR_HOMEDIR
@ -213,7 +213,7 @@ static size_t load_string(const char *src, int maxsize)
ssize_t len = mbstowcs(command_ps, src, maxsize - 1); ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
if (len < 0) if (len < 0)
len = 0; len = 0;
command_ps[len] = 0; command_ps[len] = BB_NUL;
return len; return len;
} }
static unsigned save_string(char *dst, unsigned maxsize) static unsigned save_string(char *dst, unsigned maxsize)
@ -234,17 +234,17 @@ static unsigned save_string(char *dst, unsigned maxsize)
int n = srcpos; int n = srcpos;
/* Convert up to 1st invalid byte (or up to end) */ /* Convert up to 1st invalid byte (or up to end) */
while ((wc = command_ps[srcpos]) != 0 while ((wc = command_ps[srcpos]) != BB_NUL
&& !unicode_is_raw_byte(wc) && !unicode_is_raw_byte(wc)
) { ) {
srcpos++; srcpos++;
} }
command_ps[srcpos] = 0; command_ps[srcpos] = BB_NUL;
n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
if (n < 0) /* should not happen */ if (n < 0) /* should not happen */
break; break;
dstpos += n; dstpos += n;
if (wc == 0) /* usually is */ if (wc == BB_NUL) /* usually is */
break; break;
/* We do have invalid byte here! */ /* We do have invalid byte here! */
@ -639,7 +639,7 @@ static char *username_path_completion(char *ud)
} }
/* ~use<tab> - find all users with this prefix */ /* ~use<tab> - find all users with this prefix */
static NOINLINE void username_completion(const char *ud) static NOINLINE void 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];
@ -659,7 +659,7 @@ static NOINLINE void username_completion(const char *ud)
} }
endpwent(); endpwent();
} }
#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */ #endif /* FEATURE_USERNAME_COMPLETION */
enum { enum {
FIND_EXE_ONLY = 0, FIND_EXE_ONLY = 0,
@ -710,7 +710,7 @@ static int path_parse(char ***p)
return npth; return npth;
} }
static void exe_n_cwd_tab_completion(char *command, int type) static NOINLINE void complete_cmd_dir_file(char *command, int type)
{ {
char *path1[1]; char *path1[1];
char **paths = path1; char **paths = path1;
@ -799,24 +799,25 @@ static void exe_n_cwd_tab_completion(char *command, int type)
free(dirbuf); free(dirbuf);
} }
/* QUOT is used on elements of int_buf[], which are bytes, /* build_match_prefix:
* not Unicode chars. Therefore it works correctly even in Unicode mode. * On entry, matchBuf contains everything up to cursor at the moment <tab>
*/
#define QUOT (UCHAR_MAX+1)
#define int_buf (S.find_match__int_buf)
#define pos_buf (S.find_match__pos_buf)
/* is must be <= in */
static void collapse_pos(int is, int in)
{
memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in) * sizeof(int_buf[0]));
memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in) * sizeof(pos_buf[0]));
}
/* On entry, matchBuf contains everything up to cursor at the moment <tab>
* was pressed. This function looks at it, figures out what part of it * was pressed. This function looks at it, figures out what part of it
* constitutes the command/file/directory prefix to use for completion, * constitutes the command/file/directory prefix to use for completion,
* and rewrites matchBuf to contain only that part. * and rewrites matchBuf to contain only that part.
*/ */
/* Helpers: */
/* QUOT is used on elements of int_buf[], which are bytes,
* not Unicode chars. Therefore it works correctly even in Unicode mode.
*/
#define QUOT (UCHAR_MAX+1)
#define int_buf (S.find_match__int_buf)
#define pos_buf (S.find_match__pos_buf)
static void collapse_pos(int beg, int end)
{
/* beg must be <= end */
memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0]));
memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0]));
}
static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
{ {
int i, j; int i, j;
@ -826,17 +827,16 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
/* int16_t int_buf[MAX_LINELEN + 1]; */ /* int16_t int_buf[MAX_LINELEN + 1]; */
/* int16_t pos_buf[MAX_LINELEN + 1]; */ /* int16_t pos_buf[MAX_LINELEN + 1]; */
/* set to integer dimension characters and own positions */
for (i = 0;; i++) { for (i = 0;; i++) {
int_buf[i] = (unsigned char)matchBuf[i]; int_buf[i] = (unsigned char)matchBuf[i];
if (int_buf[i] == 0) { if (int_buf[i] == 0) {
pos_buf[i] = -1; /* end-fo-line indicator */ pos_buf[i] = -1; /* end-of-line indicator */
break; break;
} }
pos_buf[i] = i; pos_buf[i] = i;
} }
/* mask \+symbol and convert '\t' to ' ' */ /* Mark every \c as "quoted c" */
for (i = j = 0; matchBuf[i]; i++, j++) { for (i = j = 0; matchBuf[i]; i++, j++) {
if (matchBuf[i] == '\\') { if (matchBuf[i] == '\\') {
collapse_pos(j, j + 1); collapse_pos(j, j + 1);
@ -844,7 +844,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
i++; i++;
} }
} }
/* mask "symbols" or 'symbols' */ /* Quote-mark "chars" and 'chars' */
c2 = 0; c2 = 0;
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
c = int_buf[i]; c = int_buf[i];
@ -861,8 +861,10 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
int_buf[i] |= QUOT; int_buf[i] |= QUOT;
} }
/* skip commands with arguments if line has commands delimiters */ /* Remove everything up to command delimiters:
/* ';' ';;' '&' '|' '&&' '||' but '>&' '<&' '>|' */ * ';' ';;' '&' '|' '&&' '||',
* but careful with '>&' '<&' '>|'
*/
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
int n; int n;
c = int_buf[i]; c = int_buf[i];
@ -879,28 +881,29 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
} }
if (n) { if (n) {
collapse_pos(0, i + n); collapse_pos(0, i + n);
i = -1; /* hack incremet */ i = -1; /* hack increment */
} }
} }
/* collapse `command...` */ /* Remove all `cmd` */
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
if (int_buf[i] == '`') { if (int_buf[i] == '`') {
for (j = i + 1; int_buf[j]; j++) for (j = i + 1; int_buf[j]; j++) {
if (int_buf[j] == '`') { if (int_buf[j] == '`') {
collapse_pos(i, j + 1); collapse_pos(i, j + 1);
j = 0; j = 0;
break; break;
} }
}
if (j) { if (j) {
/* not found closing ` - command mode, collapse all previous */ /* No closing ` - command mode, remove all up to ` */
collapse_pos(0, i + 1); collapse_pos(0, i + 1);
break; break;
} else }
i--; /* hack incremet */ i--; /* hack increment */
} }
} }
/* collapse (command...(command...)...) or {command...{command...}...} */ /* Remove (command...(command...)...) and {command...{command...}...} */
c = 0; /* "recursive" level */ c = 0; /* "recursive" level */
c2 = 0; c2 = 0;
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
@ -910,7 +913,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
else else
c2++; c2++;
collapse_pos(0, i + 1); collapse_pos(0, i + 1);
i = -1; /* hack incremet */ i = -1; /* hack increment */
} }
} }
for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) { for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) {
@ -920,22 +923,23 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
else else
c2--; c2--;
collapse_pos(0, i + 1); collapse_pos(0, i + 1);
i = -1; /* hack incremet */ i = -1; /* hack increment */
} }
} }
/* skip first not quote space */ /* Remove leading unquoted spaces */
for (i = 0; int_buf[i]; i++) for (i = 0; int_buf[i]; i++)
if (int_buf[i] != ' ') if (int_buf[i] != ' ')
break; break;
if (i) if (i)
collapse_pos(0, i); collapse_pos(0, i);
/* set find mode for completion */ /* Determine completion mode */
command_mode = FIND_EXE_ONLY; command_mode = FIND_EXE_ONLY;
for (i = 0; int_buf[i]; i++) { for (i = 0; int_buf[i]; i++) {
if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY if (int_buf[i] == ' '
&& command_mode == FIND_EXE_ONLY
&& matchBuf[pos_buf[0]] == 'c' && matchBuf[pos_buf[0]] == 'c'
&& matchBuf[pos_buf[1]] == 'd' && matchBuf[pos_buf[1]] == 'd'
) { ) {
@ -946,9 +950,10 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
} }
} }
} }
/* Remove everything except last word */
for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
continue; continue;
/* find last word */
for (--i; i >= 0; i--) { for (--i; i >= 0; i--) {
c = int_buf[i]; c = int_buf[i];
if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
@ -956,7 +961,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
break; break;
} }
} }
/* skip first not quoted '\'' or '"' */ /* Skip all leading unquoted ' or " */
for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
continue; continue;
/* collapse quote or unquote // or /~ */ /* collapse quote or unquote // or /~ */
@ -982,8 +987,8 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
#undef pos_buf #undef pos_buf
/* /*
* display by column (original idea from ls applet, * Display by column (original idea from ls applet,
* very optimized by me :) * very optimized by me [Vladimir] :)
*/ */
static void showfiles(void) static void showfiles(void)
{ {
@ -1040,7 +1045,7 @@ static char *add_quote_for_spec_chars(char *found)
} }
/* Do TAB completion */ /* Do TAB completion */
static void input_tab(smallint *lastWasTab) static NOINLINE void input_tab(smallint *lastWasTab)
{ {
if (!(state->flags & TAB_COMPLETION)) if (!(state->flags & TAB_COMPLETION))
return; return;
@ -1057,7 +1062,7 @@ static void input_tab(smallint *lastWasTab)
int cursor_mb; int cursor_mb;
#endif #endif
*lastWasTab = TRUE; /* flop trigger */ *lastWasTab = 1;
/* Make a local copy of the string -- /* Make a local copy of the string --
* up to the position of the cursor */ * up to the position of the cursor */
@ -1066,7 +1071,7 @@ static void input_tab(smallint *lastWasTab)
#else #else
{ {
CHAR_T wc = command_ps[cursor]; CHAR_T wc = command_ps[cursor];
command_ps[cursor] = 0; command_ps[cursor] = BB_NUL;
save_string(matchBuf, MAX_LINELEN); save_string(matchBuf, MAX_LINELEN);
command_ps[cursor] = wc; command_ps[cursor] = wc;
cursor_mb = strlen(matchBuf); cursor_mb = strlen(matchBuf);
@ -1084,26 +1089,25 @@ static 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)
username_completion(matchBuf); complete_username(matchBuf);
#endif #endif
/* Try to match any executable in our path and everything /* Try to match a command in $PATH, or a directory, or a file */
* in the current working directory */
if (!matches) if (!matches)
exe_n_cwd_tab_completion(matchBuf, find_type); complete_cmd_dir_file(matchBuf, find_type);
/* Sort, then remove any duplicates found */ /* Remove duplicates */
if (matches) { if (matches) {
unsigned i; unsigned i;
unsigned n = 0; unsigned n = 0;
qsort_string_vector(matches, num_matches); qsort_string_vector(matches, num_matches);
for (i = 0; i < num_matches - 1; ++i) { for (i = 0; i < num_matches - 1; ++i) {
if (matches[i] && matches[i+1]) { /* paranoia */ //if (matches[i] && matches[i+1]) { /* paranoia */
if (strcmp(matches[i], matches[i+1]) == 0) { if (strcmp(matches[i], matches[i+1]) == 0) {
free(matches[i]); free(matches[i]);
matches[i] = NULL; /* paranoia */ //matches[i] = NULL; /* paranoia */
} else { } else {
matches[n++] = matches[i]; matches[n++] = matches[i];
} }
} //}
} }
matches[n++] = matches[i]; matches[n++] = matches[i];
num_matches = n; num_matches = n;
@ -1113,7 +1117,7 @@ static void input_tab(smallint *lastWasTab)
beep(); beep();
if (!matches) if (!matches)
return; /* no matches at all */ return; /* no matches at all */
/* find minimal match */ /* 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++) { for (len_found = 1; len_found < num_matches; len_found++) {
@ -1123,7 +1127,7 @@ static void input_tab(smallint *lastWasTab)
} }
} }
} }
if (*tmp1 == '\0') { /* have unique pfx? */ if (*tmp1 == '\0') { /* have unique prefix? */
free(tmp1); /* no */ free(tmp1); /* no */
return; return;
} }
@ -1131,10 +1135,10 @@ static void input_tab(smallint *lastWasTab)
free(tmp1); free(tmp1);
len_found = strlen(tmp); len_found = strlen(tmp);
} else { /* exactly one match */ } else { /* exactly one match */
tmp = add_quote_for_spec_chars(matches[0]); /* Next <tab> is not a double-tab */
/* for next completion current found */ *lastWasTab = 0;
*lastWasTab = FALSE;
tmp = add_quote_for_spec_chars(matches[0]);
len_found = strlen(tmp); len_found = strlen(tmp);
if (tmp[len_found-1] != '/') { if (tmp[len_found-1] != '/') {
tmp[len_found] = ' '; tmp[len_found] = ' ';
@ -1199,7 +1203,7 @@ static void input_tab(smallint *lastWasTab)
} }
} }
#endif /* FEATURE_COMMAND_TAB_COMPLETION */ #endif /* FEATURE_TAB_COMPLETION */
line_input_t* FAST_FUNC new_line_input_t(int flags) line_input_t* FAST_FUNC new_line_input_t(int flags)
@ -1899,7 +1903,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
{ {
int len; int len;
#if ENABLE_FEATURE_TAB_COMPLETION #if ENABLE_FEATURE_TAB_COMPLETION
smallint lastWasTab = FALSE; smallint lastWasTab = 0;
#endif #endif
smallint break_out = 0; smallint break_out = 0;
#if ENABLE_FEATURE_EDITING_VI #if ENABLE_FEATURE_EDITING_VI
@ -2375,7 +2379,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
#if ENABLE_FEATURE_TAB_COMPLETION #if ENABLE_FEATURE_TAB_COMPLETION
if (ic_raw != '\t') if (ic_raw != '\t')
lastWasTab = FALSE; lastWasTab = 0;
#endif #endif
} /* while (1) */ } /* while (1) */
@ -2469,7 +2473,7 @@ int main(int argc, char **argv)
l = read_line_input(prompt, buff); l = read_line_input(prompt, buff);
if (l <= 0 || buff[l-1] != '\n') if (l <= 0 || buff[l-1] != '\n')
break; break;
buff[l-1] = 0; buff[l-1] = '\0';
printf("*** read_line_input() returned line =%s=\n", buff); printf("*** read_line_input() returned line =%s=\n", buff);
} }
printf("*** read_line_input() detect ^D\n"); printf("*** read_line_input() detect ^D\n");