Initial devel branch import from bash-3.0-alpha

This commit is contained in:
Chet Ramey
2011-11-28 14:41:26 -05:00
parent 7117c2d221
commit d3a24ed242
261 changed files with 24280 additions and 6327 deletions
+176 -78
View File
@@ -150,10 +150,15 @@ static char **prog_complete_matches;
#endif
/* Variables used here but defined in other files. */
extern int current_command_line_count;
#if defined (BANG_HISTORY)
extern int hist_verify;
#endif
extern int current_command_line_count, last_command_exit_value;
extern int posixly_correct, no_symbolic_links;
extern char *current_prompt_string, *ps1_prompt;
extern STRING_INT_ALIST word_token_alist[];
extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual
completion functions which indicate what type of completion should be
@@ -205,8 +210,14 @@ int perform_hostname_completion = 1;
/* If non-zero, we don't do command completion on an empty line. */
int no_empty_command_completion;
/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the
only possible matches. Set to 0 if you want to match filenames if they
are the only possible matches, even if FIGNORE says to. */
int force_fignore = 1;
static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:";
static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:";
/* )) */
static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL;
@@ -233,11 +244,14 @@ posix_readline_initialize (on_or_off)
#endif
}
/* When this function returns, rl_completer_word_break_characters points to
dynamically allocated memory. */
int
enable_hostname_completion (on_or_off)
int on_or_off;
{
int old_value;
char *at, *nv, *nval;
old_value = perform_hostname_completion;
@@ -245,13 +259,60 @@ enable_hostname_completion (on_or_off)
{
perform_hostname_completion = 1;
rl_special_prefixes = "$@";
rl_completer_word_break_characters = bash_completer_word_break_characters;
}
else
{
perform_hostname_completion = 0;
rl_special_prefixes = "$";
rl_completer_word_break_characters = bash_nohostname_word_break_characters;
}
/* Now we need to figure out how to appropriately modify and assign
rl_completer_word_break_characters depending on whether we want
hostname completion on or off. */
/* If this is the first time this has been called
(bash_readline_initialized == 0), use the sames values as before, but
allocate new memory for rl_completer_word_break_characters. */
if (bash_readline_initialized == 0 &&
(rl_completer_word_break_characters == 0 ||
rl_completer_word_break_characters == rl_basic_word_break_characters))
{
if (on_or_off)
rl_completer_word_break_characters = savestring (bash_completer_word_break_characters);
else
rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters);
}
else
{
/* See if we have anything to do. */
at = strchr (rl_completer_word_break_characters, '@');
if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0))
return;
/* We have something to do. Do it. */
nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off);
if (on_or_off == 0)
{
/* Turn it off -- just remove `@' from word break chars. We want
to remove all occurrences of `@' from the char list, so we loop
rather than just copy the rest of the list over AT. */
for (nv = nval, at = rl_completer_word_break_characters; *at; )
if (*at != '@')
*nv++ = *at++;
else
at++;
*nv = '\0';
}
else
{
nval[0] = '@';
strcpy (nval + 1, rl_completer_word_break_characters);
}
free (rl_completer_word_break_characters);
rl_completer_word_break_characters = nval;
}
return (old_value);
@@ -320,15 +381,14 @@ initialize_readline ()
rl_initialize ();
/* Bind up our special shell functions. */
rl_bind_key_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap);
/* Bind up our special shell functions. */
#ifdef BANG_HISTORY
rl_bind_key_in_map ('^', history_expand_line, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap);
#endif
rl_bind_key_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap);
rl_bind_key_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap);
rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap);
/* In Bash, the user can switch editing modes with "set -o [vi emacs]",
so it is not necessary to allow C-M-j for context switching. Turn
@@ -340,32 +400,32 @@ initialize_readline ()
#endif
#if defined (BRACE_COMPLETION)
rl_bind_key_in_map ('{', bash_brace_completion, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/
#endif /* BRACE_COMPLETION */
#if defined (SPECIFIC_COMPLETION_FUNCTIONS)
rl_bind_key_in_map ('/', bash_complete_filename, emacs_meta_keymap);
rl_bind_key_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap);
rl_bind_key_in_map ('~', bash_complete_username, emacs_meta_keymap);
rl_bind_key_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('~', bash_complete_username, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap);
rl_bind_key_in_map ('@', bash_complete_hostname, emacs_meta_keymap);
rl_bind_key_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap);
rl_bind_key_in_map ('$', bash_complete_variable, emacs_meta_keymap);
rl_bind_key_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap);
rl_bind_key_in_map ('!', bash_complete_command, emacs_meta_keymap);
rl_bind_key_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap);
rl_bind_key_in_map ('g', bash_glob_complete_word, emacs_meta_keymap);
rl_bind_key_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap);
rl_bind_key_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap);
rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap);
#endif /* SPECIFIC_COMPLETION_FUNCTIONS */
rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap);
rl_bind_key_if_unbound_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;
@@ -378,11 +438,11 @@ initialize_readline ()
rl_ignore_some_completions_function = filename_completion_ignore;
/* Bind C-xC-e to invoke emacs and run result as commands. */
rl_bind_key_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap);
rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap);
#if defined (VI_MODE)
rl_bind_key_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap);
rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap);
# if defined (ALIAS)
rl_bind_key_in_map ('@', posix_edit_macros, vi_movement_keymap);
rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap);
# endif
#endif
@@ -708,8 +768,8 @@ operate_and_get_next (count, c)
command being entered (if no explicit argument is given), otherwise on
a command from the history file. */
#define VI_EDIT_COMMAND "fc -e ${VISUAL:-${EDITOR:-vi}}"
#define EMACS_EDIT_COMMAND "fc -e ${VISUAL:-${EDITOR:-emacs}}"
#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\""
#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\""
static int
edit_and_execute_command (count, c, editing_mode, edit_command)
@@ -810,6 +870,7 @@ posix_edit_macros (count, key)
/* **************************************************************** */
#define COMMAND_SEPARATORS ";|&{(`"
/* )} */
static int
check_redir (ti)
@@ -1008,11 +1069,27 @@ attempt_shell_completion (text, start, end)
matches = rl_completion_matches (text, prog_complete_return);
if ((foundcs & COPT_DEFAULT) == 0)
rl_attempted_completion_over = 1; /* no default */
return (matches);
if (matches || ((foundcs & COPT_BASHDEFAULT) == 0))
return (matches);
}
}
#endif
if (matches == 0)
matches = bash_default_completion (text, start, end, qc, in_command_position);
return matches;
}
char **
bash_default_completion (text, start, end, qc, in_command_position)
const char *text;
int start, end, qc, in_command_position;
{
char **matches;
matches = (char **)NULL;
/* New posix-style command substitution or variable name? */
if (!matches && *text == '$')
{
@@ -1044,7 +1121,10 @@ attempt_shell_completion (text, start, end)
}
else
{
#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x))
matches = rl_completion_matches (text, command_word_completion_function);
/* If we are attempting command completion and nothing matches, we
do not want readline to perform filename completion for us. We
still want to be able to complete partial pathnames, so set the
@@ -1052,7 +1132,8 @@ attempt_shell_completion (text, start, end)
filenames and leave directories in the match list. */
if (matches == (char **)NULL)
rl_ignore_some_completions_function = bash_ignore_filenames;
else if (matches[1] == 0 && *matches[0] != '/')
#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.
@@ -1061,7 +1142,7 @@ attempt_shell_completion (text, start, end)
looking in the current directory anyway, so there's no
conflict. */
rl_filename_completion_desired = 0;
else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && *matches[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
@@ -1071,6 +1152,7 @@ attempt_shell_completion (text, start, end)
completion. If there are multiple completions this won't
make a difference and the problem won't occur. */
rl_filename_completion_desired = 0;
#endif
}
}
@@ -1631,8 +1713,13 @@ history_expand_line_internal (line)
char *line;
{
char *new_line;
int old_verify;
old_verify = hist_verify;
hist_verify = 0;
new_line = pre_process_line (line, 0, 0);
hist_verify = old_verify;
return (new_line == line) ? savestring (line) : new_line;
}
#endif
@@ -1643,9 +1730,18 @@ static void
cleanup_expansion_error ()
{
char *to_free;
#if defined (BANG_HISTORY)
int old_verify;
old_verify = hist_verify;
hist_verify = 0;
#endif
fprintf (rl_outstream, "\r\n");
to_free = pre_process_line (rl_line_buffer, 1, 0);
#if defined (BANG_HISTORY)
hist_verify = old_verify;
#endif
if (to_free != rl_line_buffer)
free (to_free);
putc ('\r', rl_outstream);
@@ -1773,9 +1869,7 @@ history_and_alias_expand_line (count, ignore)
{
char *new_line;
new_line = pre_process_line (rl_line_buffer, 0, 0);
if (new_line == rl_line_buffer)
new_line = savestring (new_line);
new_line = history_expand_line_internal (rl_line_buffer);
#if defined (ALIAS)
if (new_line)
@@ -1811,9 +1905,7 @@ shell_expand_line (count, ignore)
char *new_line;
WORD_LIST *expanded_string;
new_line = pre_process_line (rl_line_buffer, 0, 0);
if (new_line == rl_line_buffer)
new_line = savestring (new_line);
new_line = history_expand_line_internal (rl_line_buffer);
#if defined (ALIAS)
if (new_line)
@@ -1873,10 +1965,6 @@ shell_expand_line (count, ignore)
}
}
/* Define NO_FORCE_FIGNORE if you want to match filenames that would
otherwise be ignored if they are the only possible matches. */
/* #define NO_FORCE_FIGNORE */
/* If FIGNORE is set, then don't match files with the given suffixes when
completing filenames. If only one of the possibilities has an acceptable
suffix, delete the others, else just return and let the completer
@@ -1901,10 +1989,8 @@ _ignore_completion_names (names, name_func)
{
char **newnames;
int idx, nidx;
#ifdef NO_FORCE_FIGNORE
char **oldnames;
int oidx;
#endif
/* If there is only one completion, see if it is acceptable. If it is
not, free it up. In any case, short-circuit and return. This is a
@@ -1912,13 +1998,13 @@ _ignore_completion_names (names, name_func)
if there is only one completion; it is the completion itself. */
if (names[1] == (char *)0)
{
#ifndef NO_FORCE_FIGNORE
if ((*name_func) (names[0]) == 0)
{
free (names[0]);
names[0] = (char *)NULL;
}
#endif
if (force_fignore)
if ((*name_func) (names[0]) == 0)
{
free (names[0]);
names[0] = (char *)NULL;
}
return;
}
@@ -1927,22 +2013,22 @@ _ignore_completion_names (names, name_func)
for (nidx = 1; names[nidx]; nidx++)
;
newnames = strvec_create (nidx + 1);
#ifdef NO_FORCE_FIGNORE
oldnames = strvec_create (nidx - 1);
oidx = 0;
#endif
if (force_fignore == 0)
{
oldnames = strvec_create (nidx - 1);
oidx = 0;
}
newnames[0] = names[0];
for (idx = nidx = 1; names[idx]; idx++)
{
if ((*name_func) (names[idx]))
newnames[nidx++] = names[idx];
else
#ifndef NO_FORCE_FIGNORE
free (names[idx]);
#else
else if (force_fignore == 0)
oldnames[oidx++] = names[idx];
#endif
else
free (names[idx]);
}
newnames[nidx] = (char *)NULL;
@@ -1950,21 +2036,24 @@ _ignore_completion_names (names, name_func)
/* If none are acceptable then let the completer handle it. */
if (nidx == 1)
{
#ifndef NO_FORCE_FIGNORE
free (names[0]);
names[0] = (char *)NULL;
#else
free (oldnames);
#endif
if (force_fignore)
{
free (names[0]);
names[0] = (char *)NULL;
}
else
free (oldnames);
free (newnames);
return;
}
#ifdef NO_FORCE_FIGNORE
while (oidx)
free (oldnames[--oidx]);
free (oldnames);
#endif
if (force_fignore == 0)
{
while (oidx)
free (oldnames[--oidx]);
free (oldnames);
}
/* If only one is acceptable, copy it to names[0] and return. */
if (nidx == 2)
@@ -2292,7 +2381,7 @@ bash_complete_filename_internal (what_to_do)
rl_compentry_func_t *orig_func;
rl_completion_func_t *orig_attempt_func;
rl_icppfunc_t *orig_dir_func;
const char *orig_rl_completer_word_break_characters;
/*const*/ char *orig_rl_completer_word_break_characters;
int r;
orig_func = rl_completion_entry_function;
@@ -2676,8 +2765,7 @@ bash_execute_unix_command (count, key)
Keymap xkmap; /* unix command executing keymap */
register int i;
char *cmd;
int old_line_count;
int *ts;
sh_parser_state_t ps;
/* First, we need to find the right command to execute. This is tricky,
because we might have already indirected into another keymap. */
@@ -2713,14 +2801,12 @@ bash_execute_unix_command (count, key)
rl_crlf (); /* move to a new line */
old_line_count = current_command_line_count;
ts = save_token_state ();
save_parser_state (&ps);
cmd = savestring (cmd);
parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST);
current_command_line_count = old_line_count;
restore_token_state (ts);
restore_parser_state (&ps);
/* and restore the readline buffer and display after command execution. */
rl_forced_update_display ();
@@ -2825,7 +2911,7 @@ bind_keyseq_to_unix_command (line)
/* and bind the key sequence in the current keymap to a function that
understands how to execute from CMD_XMAP */
rl_set_key (kseq, bash_execute_unix_command, kmap);
rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap);
return 0;
}
@@ -2854,4 +2940,16 @@ bash_directory_completion_matches (text)
(void)bash_ignore_filenames (m1);
return m1;
}
char *
bash_dequote_text (text)
const char *text;
{
char *dtxt;
int qc;
qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0;
dtxt = bash_dequote_filename ((char *)text, qc);
return (dtxt);
}
#endif /* READLINE */