diff options
author | Jari Aalto <jari.aalto@cante.net> | 2005-12-07 14:08:12 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:57 +0000 |
commit | 95732b497d12c98613bb3c5db16b61f377501a59 (patch) | |
tree | 5e1cdf79eb0407e09dca4c0ec29e11442c7d1d15 /bashline.c | |
parent | eb87367179effbe5f430236db8259006d71438b7 (diff) | |
download | android_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.tar.gz android_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.tar.bz2 android_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.zip |
Imported from ../bash-3.1.tar.gz.
Diffstat (limited to 'bashline.c')
-rw-r--r-- | bashline.c | 144 |
1 files changed, 105 insertions, 39 deletions
@@ -1,6 +1,6 @@ /* bashline.c -- Bash's interface to the readline library. */ -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. +/* Copyright (C) 1987-2005 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -100,7 +100,7 @@ static int history_and_alias_expand_line __P((int, int)); #endif /* Helper functions for Readline. */ -static int bash_directory_expansion __P((char **)); +static void bash_directory_expansion __P((char **)); static int bash_directory_completion_hook __P((char **)); static int filename_completion_ignore __P((char **)); static int bash_push_line __P((void)); @@ -226,6 +226,8 @@ static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; +static int dot_in_path = 0; + /* What kind of quoting is performed by bash_quote_filename: COMPLETE_DQUOTE = double-quoting the filename COMPLETE_SQUOTE = single_quoting the filename @@ -447,7 +449,11 @@ initialize_readline () #endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - rl_bind_key_if_unbound_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); + kseq[0] = TAB; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tab_insert) + rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); /* Tell the completer that we want a crack first. */ rl_attempted_completion_function = attempt_shell_completion; @@ -796,6 +802,7 @@ operate_and_get_next (count, c) #define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" #define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" +#define POSIX_VI_EDIT_COMMAND "fc -e vi" static int edit_and_execute_command (count, c, editing_mode, edit_command) @@ -855,7 +862,10 @@ static int vi_edit_and_execute_command (count, c) int count, c; { - return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); + if (posixly_correct) + return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); + else + return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); } #endif /* VI_MODE */ @@ -1071,7 +1081,7 @@ attempt_shell_completion (text, start, end) s = find_cmd_start (start); e = find_cmd_end (end); n = find_cmd_name (s); - if (e > s) + if (e > s && assignment (n, 0) == 0) prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); else foundcs = 0; @@ -1149,6 +1159,7 @@ bash_default_completion (text, start, end, qc, in_command_position) { #define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) + dot_in_path = 0; matches = rl_completion_matches (text, command_word_completion_function); /* If we are attempting command completion and nothing matches, we @@ -1158,27 +1169,28 @@ bash_default_completion (text, start, end, qc, in_command_position) filenames and leave directories in the match list. */ if (matches == (char **)NULL) rl_ignore_some_completions_function = bash_ignore_filenames; -#if 0 - else if (matches[1] == 0 && CMD_IS_DIR(matches[0])) - /* Turn off rl_filename_completion_desired so readline doesn't - append a slash if there is a directory with the same name - in the current directory, or other filename-specific things. - If the name begins with a slash, we're either completing a - full pathname or a directory pathname, and readline won't be - looking in the current directory anyway, so there's no - conflict. */ - rl_filename_completion_desired = 0; + else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) + /* If we found a single match, without looking in the current + directory (because it's not in $PATH), but the found name is + also a command in the current directory, suppress appending any + terminating character, since it's ambiguous. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) /* There are multiple instances of the same match (duplicate completions haven't yet been removed). In this case, all of the matches will be the same, and the duplicate removal code - will distill them all down to one. We turn off - rl_filename_completion_desired for the same reason as above. + will distill them all down to one. We turn on + rl_completion_suppress_append for the same reason as above. Remember: we only care if there's eventually a single unique completion. If there are multiple completions this won't make a difference and the problem won't occur. */ - rl_filename_completion_desired = 0; -#endif + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } } } @@ -1212,23 +1224,30 @@ command_word_completion_function (hint_text, state) static char *path = (char *)NULL; static char *val = (char *)NULL; static char *filename_hint = (char *)NULL; - static int path_index, hint_len, istate; + static char *dequoted_hint = (char *)NULL; + static int path_index, hint_len, dequoted_len, istate, igncase; static int mapping_over, local_index; static SHELL_VAR **varlist = (SHELL_VAR **)NULL; #if defined (ALIAS) static alias_t **alias_list = (alias_t **)NULL; #endif /* ALIAS */ + char *temp; /* We have to map over the possibilities for command words. If we have no state, then make one just for that purpose. */ if (!state) { + if (dequoted_hint && dequoted_hint != hint) + free (dequoted_hint); if (hint) free (hint); mapping_over = 0; val = (char *)NULL; + temp = rl_variable_value ("completion-ignore-case"); + igncase = strcmp (temp, "on") == 0; + /* If this is an absolute program name, do not check it against aliases, reserved words, functions or builtins. We must check whether or not it is unique, and, if so, whether that filename @@ -1241,10 +1260,24 @@ command_word_completion_function (hint_text, state) hint = bash_tilde_expand (hint_text, 0); else hint = savestring (hint_text); - hint_len = strlen (hint); + + dequoted_hint = hint; + /* If readline's completer found a quote character somewhere, but + didn't set the quote character, there must have been a quote + character embedded in the filename. It can't be at the start of + the filename, so we need to dequote the filename before we look + in the file system for it. */ + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + free (hint); + hint = dequoted_hint; + } + dequoted_len = hint_len = strlen (hint); if (filename_hint) free (filename_hint); + filename_hint = savestring (hint); mapping_over = 4; @@ -1252,11 +1285,17 @@ command_word_completion_function (hint_text, state) goto inner; } - hint = savestring (hint_text); - hint_len = strlen (hint); + dequoted_hint = hint = savestring (hint_text); + dequoted_len = hint_len = strlen (hint); + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + dequoted_len = strlen (dequoted_hint); + } + path = get_string_value ("PATH"); - path_index = 0; + path_index = dot_in_path = 0; /* Initialize the variables for each type of command word. */ local_index = 0; @@ -1374,11 +1413,13 @@ command_word_completion_function (hint_text, state) current_path = t; } + if (current_path[0] == '.' && current_path[1] == '\0') + dot_in_path = 1; + if (filename_hint) free (filename_hint); filename_hint = sh_makepath (current_path, hint, 0); - free (current_path); } @@ -1402,7 +1443,11 @@ command_word_completion_function (hint_text, state) if (absolute_program (hint)) { - match = strncmp (val, hint, hint_len) == 0; + if (igncase == 0) + match = strncmp (val, hint, hint_len) == 0; + else + match = strncasecmp (val, hint, hint_len) == 0; + /* If we performed tilde expansion, restore the original filename. */ if (*hint_text == '~') @@ -1435,7 +1480,10 @@ command_word_completion_function (hint_text, state) if (temp) { temp++; - freetemp = match = strncmp (temp, hint, hint_len) == 0; + if (igncase == 0) + freetemp = match = strncmp (temp, hint, hint_len) == 0; + else + freetemp = match = strncasecmp (temp, hint, hint_len) == 0; if (match) temp = savestring (temp); } @@ -1514,6 +1562,13 @@ command_subst_completion_function (text, state) /* If there is more than one match, rl_completion_matches has already put the lcd in matches[0]. Skip over it. */ cmd_index = matches && matches[0] && matches[1]; + + /* If there's a single match and it's a directory, set the append char + to the expected `/'. Otherwise, don't append anything. */ + if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) + rl_completion_append_character = '/'; + else + rl_completion_suppress_append = 1; } if (!matches || !matches[cmd_index]) @@ -1898,7 +1953,7 @@ tcsh_magic_space (count, ignore) else return (1); } -#endif +#endif /* BANG_HISTORY */ /* History and alias expand the line. */ static int @@ -1907,7 +1962,10 @@ history_and_alias_expand_line (count, ignore) { char *new_line; + new_line = 0; +#if defined (BANG_HISTORY) new_line = history_expand_line_internal (rl_line_buffer); +#endif #if defined (ALIAS) if (new_line) @@ -1943,7 +2001,10 @@ shell_expand_line (count, ignore) char *new_line; WORD_LIST *expanded_string; + new_line = 0; +#if defined (BANG_HISTORY) new_line = history_expand_line_internal (rl_line_buffer); +#endif #if defined (ALIAS) if (new_line) @@ -2200,7 +2261,7 @@ bash_ignore_everything (names) /* Simulate the expansions that will be performed by rl_filename_completion_function. This must be called with the address of a pointer to malloc'd memory. */ -static int +static void bash_directory_expansion (dirname) char **dirname; { @@ -2296,9 +2357,12 @@ bash_directory_completion_hook (dirname) if (temp1[len1 - 1] == '/') { len2 = strlen (temp2); - temp2 = (char *)xrealloc (temp2, len2 + 2); - temp2[len2] = '/'; - temp2[len2 + 1] = '\0'; + if (len2 > 2) /* don't append `/' to `/' or `//' */ + { + temp2 = (char *)xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } } free (local_dirname); *dirname = temp2; @@ -2815,10 +2879,6 @@ bash_quote_filename (s, rtype, qcp) to perform tilde expansion, because single and double quotes inhibit tilde expansion by the shell. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH) - mtext = bash_tilde_expand (s, 0); - cs = completion_quoting_style; /* Might need to modify the default completion style based on *qcp, since it's set to any user-provided opening quote. We also change @@ -2826,7 +2886,7 @@ bash_quote_filename (s, rtype, qcp) the word being completed contains newlines, since those are not quoted correctly using backslashes (a backslash-newline pair is special to the shell parser). */ - if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && xstrchr (mtext, '\n')) + if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && xstrchr (s, '\n')) cs = COMPLETE_SQUOTE; else if (*qcp == '"') cs = COMPLETE_DQUOTE; @@ -2834,17 +2894,23 @@ bash_quote_filename (s, rtype, qcp) cs = COMPLETE_SQUOTE; #if defined (BANG_HISTORY) else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (mtext, '!')) + history_expansion_inhibited == 0 && xstrchr (s, '!')) cs = COMPLETE_BSQUOTE; if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (mtext, '!')) + history_expansion_inhibited == 0 && xstrchr (s, '!')) { cs = COMPLETE_BSQUOTE; *qcp = '\0'; } #endif + /* Don't tilde-expand backslash-quoted filenames, since only single and + double quotes inhibit tilde expansion. */ + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) + mtext = bash_tilde_expand (s, 0); + switch (cs) { case COMPLETE_DQUOTE: |