bash-5.0 distribution sources and documentation
diff --git a/bashline.c b/bashline.c
index 0275844..2846aab 100644
--- a/bashline.c
+++ b/bashline.c
@@ -1,6 +1,6 @@
/* bashline.c -- Bash's interface to the readline library. */
-/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -46,6 +46,7 @@
#include "shell.h"
#include "input.h"
+#include "parser.h"
#include "builtins.h"
#include "bashhist.h"
#include "bashline.h"
@@ -65,6 +66,7 @@
#include <readline/rlconf.h>
#include <readline/readline.h>
#include <readline/history.h>
+#include <readline/rlmbutil.h>
#include <glob/glob.h>
@@ -200,19 +202,8 @@
static char **prog_complete_matches;
#endif
-/* Variables used here but defined in other files. */
-#if defined (BANG_HISTORY)
-extern int hist_verify;
-#endif
-
-extern int current_command_line_count, saved_command_line_count;
-extern int last_command_exit_value;
-extern int array_needs_making;
-extern int posixly_correct, no_symbolic_links;
-extern int sigalrm_seen;
-extern char *current_prompt_string, *ps1_prompt;
+extern int no_symbolic_links;
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
@@ -919,9 +910,9 @@
rl_newline (1, c);
/* Find the current line, and find the next line to use. */
- where = where_history ();
+ where = rl_explicit_arg ? count : where_history ();
- if (HISTORY_FULL () || (where >= history_length - 1))
+ if (HISTORY_FULL () || (where >= history_length - 1) || rl_explicit_arg)
saved_history_line_to_use = where;
else
saved_history_line_to_use = where + 1;
@@ -969,8 +960,11 @@
/* This breaks down when using command-oriented history and are not
finished with the command, so we should not ignore the last command */
using_history ();
- current_command_line_count++; /* for rl_newline above */
- bash_add_history (rl_line_buffer);
+ if (rl_line_buffer[0])
+ {
+ current_command_line_count++; /* for rl_newline above */
+ bash_add_history (rl_line_buffer);
+ }
current_command_line_count = 0; /* for dummy history entry */
bash_add_history ("");
history_lines_this_session++;
@@ -999,6 +993,11 @@
rl_done = 0;
rl_readline_state = rrs;
+#if defined (VI_MODE)
+ if (editing_mode == VI_EDITING_MODE)
+ rl_vi_insertion_mode (1, c);
+#endif
+
rl_forced_update_display ();
return r;
@@ -1056,7 +1055,7 @@
int count, key;
{
size_t slen;
- int sindex, c, p;
+ int c, p;
DECLARE_MBSTATE;
if (count < 0)
@@ -1165,15 +1164,18 @@
int count, key;
{
size_t slen;
- int sindex, c, p;
+ int c, p;
DECLARE_MBSTATE;
-
+
if (count < 0)
return (bash_forward_shellword (-count, key));
p = rl_point;
slen = rl_end;
-
+
+ if (p == rl_end && p > 0)
+ p--;
+
while (count)
{
if (p == 0)
@@ -1186,9 +1188,9 @@
while (p > 0)
{
c = rl_line_buffer[p];
- if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0)
- BACKUP_CHAR (rl_line_buffer, slen, p);
- break;
+ if (WORDDELIM (c) == 0 || char_is_quoted (rl_line_buffer, p))
+ break;
+ BACKUP_CHAR (rl_line_buffer, slen, p);
}
if (p == 0)
@@ -1420,10 +1422,11 @@
const char *text;
int start, end;
{
- int in_command_position, ti, saveti, qc, dflags;
+ int in_command_position, ti, qc, dflags;
char **matches, *command_separator_chars;
#if defined (PROGRAMMABLE_COMPLETION)
int have_progcomps, was_assignment;
+ COMPSPEC *iw_compspec;
#endif
command_separator_chars = COMMAND_SEPARATORS;
@@ -1442,7 +1445,7 @@
appears after a character that separates commands. It cannot be a
command word if we aren't at the top-level prompt. */
ti = start - 1;
- saveti = qc = -1;
+ qc = -1;
while ((ti > -1) && (whitespace (rl_line_buffer[ti])))
ti--;
@@ -1453,7 +1456,7 @@
if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\''))
{
qc = rl_line_buffer[ti];
- saveti = ti--;
+ ti--;
while (ti > -1 && (whitespace (rl_line_buffer[ti])))
ti--;
}
@@ -1508,7 +1511,9 @@
#if defined (PROGRAMMABLE_COMPLETION)
/* Attempt programmable completion. */
have_progcomps = prog_completion_enabled && (progcomp_size () > 0);
- if (matches == 0 && (in_command_position == 0 || text[0] == '\0') &&
+ iw_compspec = progcomp_search (INITIALWORD);
+ if (matches == 0 &&
+ (in_command_position == 0 || text[0] == '\0' || (in_command_position && iw_compspec)) &&
current_prompt_string == ps1_prompt)
{
int s, e, s1, e1, os, foundcs;
@@ -1562,7 +1567,7 @@
else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */
foundcs = 0;
else if (e == 0 && e == s && text[0] == '\0' && have_progcomps) /* beginning of empty line */
- prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs);
+ prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs);
else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start]))
foundcs = 0; /* whitespace before command name */
else if (e > s && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0)
@@ -1576,7 +1581,10 @@
{
prog_complete_matches = programmable_completions (n, text, s, e, &foundcs);
/* command completion if programmable completion fails */
- in_command_position = s == start && STREQ (n, text); /* XXX */
+ /* If we have a completion for the initial word, we can prefer that */
+ in_command_position = s == start && (iw_compspec || STREQ (n, text)); /* XXX */
+ if (iw_compspec && in_command_position)
+ foundcs = 0;
}
/* empty command name following command separator */
else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0 &&
@@ -1587,8 +1595,8 @@
}
else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0)
{
- foundcs = 0; /* empty command name following assignments */
- in_command_position = was_assignment;
+ foundcs = 0; /* empty command name following optional assignments */
+ in_command_position += was_assignment;
}
else if (s == start && e == end && STREQ (n, text) && start > 0)
{
@@ -1597,6 +1605,12 @@
}
else
foundcs = 0;
+
+ /* If we have defined a compspec for the initial (command) word, call
+ it and process the results like any other programmable completion. */
+ if (in_command_position && have_progcomps && foundcs == 0 && iw_compspec)
+ prog_complete_matches = programmable_completions (INITIALWORD, text, s, e, &foundcs);
+
FREE (n);
/* XXX - if we found a COMPSPEC for the command, just return whatever
the programmable completion code returns, and disable the default
@@ -1639,7 +1653,7 @@
matches = (char **)NULL;
/* New posix-style command substitution or variable name? */
- if (!matches && *text == '$')
+ if (*text == '$')
{
if (qc != '\'' && text[1] == '(') /* ) */
matches = rl_completion_matches (text, command_subst_completion_function);
@@ -1803,7 +1817,7 @@
static char *dequoted_hint = (char *)NULL;
static char *directory_part = (char *)NULL;
static char **glob_matches = (char **)NULL;
- static int path_index, hint_len, dequoted_len, istate, igncase;
+ static int path_index, hint_len, istate, igncase;
static int mapping_over, local_index, searching_path, hint_is_dir;
static int old_glob_ignore_case, globpat;
static SHELL_VAR **varlist = (SHELL_VAR **)NULL;
@@ -1881,7 +1895,7 @@
free (hint);
hint = dequoted_hint;
}
- dequoted_len = hint_len = strlen (hint);
+ hint_len = strlen (hint);
if (filename_hint)
free (filename_hint);
@@ -1909,13 +1923,10 @@
}
dequoted_hint = hint = savestring (hint_text);
- dequoted_len = hint_len = strlen (hint);
+ 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);
- }
+ dequoted_hint = bash_dequote_filename (hint, 0);
path = get_string_value ("PATH");
path_index = dot_in_path = 0;
@@ -1949,7 +1960,9 @@
alias = alias_list[local_index++]->name;
- if (STREQN (alias, hint, hint_len))
+ if (igncase == 0 && (STREQN (alias, hint, hint_len)))
+ return (savestring (alias));
+ else if (igncase && strncasecmp (alias, hint, hint_len) == 0)
return (savestring (alias));
}
#endif /* ALIAS */
@@ -1978,7 +1991,10 @@
varname = varlist[local_index++]->name;
- if (STREQN (varname, hint, hint_len))
+ /* Honor completion-ignore-case for shell function names. */
+ if (igncase == 0 && (STREQN (varname, hint, hint_len)))
+ return (savestring (varname));
+ else if (igncase && strncasecmp (varname, hint, hint_len) == 0)
return (savestring (varname));
}
local_index = 0;
@@ -2304,7 +2320,6 @@
static char **varlist = (char **)NULL;
static int varlist_index;
static char *varname = (char *)NULL;
- static int namelen;
static int first_char, first_char_loc;
if (!state)
@@ -2323,7 +2338,6 @@
varname = savestring (text + first_char_loc);
- namelen = strlen (varname);
if (varlist)
strvec_dispose (varlist);
@@ -2411,7 +2425,7 @@
#else
static char *sname = (char *)NULL;
static struct servent *srvent;
- static int snamelen, firstc;
+ static int snamelen;
char *value;
char **alist, *aentry;
int afound;
@@ -2419,7 +2433,6 @@
if (state == 0)
{
FREE (sname);
- firstc = *text;
sname = savestring (text);
snamelen = strlen (sname);
@@ -2552,7 +2565,7 @@
maybe_make_readline_line (new_line)
char *new_line;
{
- if (strcmp (new_line, rl_line_buffer) != 0)
+ if (new_line && strcmp (new_line, rl_line_buffer) != 0)
{
rl_point = rl_end;
@@ -2704,6 +2717,7 @@
{
char *new_line;
WORD_LIST *expanded_string;
+ WORD_DESC *w;
new_line = 0;
#if defined (BANG_HISTORY)
@@ -2733,9 +2747,19 @@
/* If there is variable expansion to perform, do that as a separate
operation to be undone. */
+
+#if 1
+ w = alloc_word_desc ();
+ w->word = savestring (rl_line_buffer);
+ w->flags = rl_explicit_arg ? (W_NOPROCSUB|W_NOCOMSUB) : 0;
+ expanded_string = expand_word (w, rl_explicit_arg ? Q_HERE_DOCUMENT : 0);
+ dispose_word (w);
+#else
new_line = savestring (rl_line_buffer);
expanded_string = expand_string (new_line, 0);
FREE (new_line);
+#endif
+
if (expanded_string == 0)
{
new_line = (char *)xmalloc (1);
@@ -2967,7 +2991,7 @@
char *val, *directory_part;
{
int l, vl, dl2, xl;
- char *dh2, *expdir, *ret;
+ char *dh2, *expdir, *ret, *v;
vl = strlen (val);
@@ -2979,6 +3003,22 @@
expdir = bash_tilde_expand (directory_part, 0);
xl = strlen (expdir);
+ if (*directory_part == '~' && STREQ (directory_part, expdir))
+ {
+ /* tilde expansion failed, so what should we return? we use what the
+ user typed. */
+ v = mbschr (val, '/');
+ vl = STRLEN (v);
+ ret = (char *)xmalloc (xl + vl + 2);
+ strcpy (ret, directory_part);
+ if (v && *v)
+ strcpy (ret + xl, v);
+
+ free (dh2);
+ free (expdir);
+
+ return ret;
+ }
free (expdir);
/*
@@ -2989,6 +3029,11 @@
l = length of remainder after tilde-prefix
*/
l = (vl - xl) + 1;
+ if (l <= 0)
+ {
+ free (dh2);
+ return (savestring (val)); /* XXX - just punt */
+ }
ret = (char *)xmalloc (dl2 + 2 + l);
strcpy (ret, dh2);
@@ -3138,7 +3183,6 @@
int should_expand_dirname, return_value;
int global_nounset;
WORD_LIST *wl;
- struct stat sb;
local_dirname = *dirname;
should_expand_dirname = return_value = 0;
@@ -3216,10 +3260,8 @@
char **dirname;
{
char *local_dirname, *new_dirname, *t;
- int return_value, should_expand_dirname, nextch, closer, changed;
- size_t local_dirlen;
+ int return_value, should_expand_dirname, nextch, closer;
WORD_LIST *wl;
- struct stat sb;
return_value = should_expand_dirname = nextch = closer = 0;
local_dirname = *dirname;
@@ -3236,6 +3278,17 @@
closer = '}';
else
nextch = 0;
+
+ if (closer)
+ {
+ int p;
+ char delims[2];
+
+ delims[0] = closer; delims[1] = 0;
+ p = skip_to_delim (t, 1, delims, SD_NOJMP|SD_COMPLETE);
+ if (t[p] != closer)
+ should_expand_dirname = 0;
+ }
}
else if (local_dirname[0] == '~')
should_expand_dirname = '~';
@@ -3450,6 +3503,7 @@
while (history_completion_array && history_completion_array[local_index])
{
+ /* XXX - should this use completion-ignore-case? */
if (strncmp (text, history_completion_array[local_index++], len) == 0)
return (savestring (history_completion_array[local_index - 1]));
}
@@ -3870,7 +3924,7 @@
*r++ = *p;
/* Backslashes are preserved within double quotes unless the
character is one that is defined to be escaped */
- else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0))
+ else if (quoted == '"' && ((sh_syntaxtab[(unsigned char)p[1]] & CBSDQUOTE) == 0))
*r++ = *p;
*r++ = *++p;
@@ -4071,21 +4125,18 @@
int count; /* ignored */
int key;
{
- Keymap ckmap; /* current keymap */
- Keymap xkmap; /* unix command executing keymap */
- rl_command_func_t *func;
int type;
register int i, r;
intmax_t mi;
sh_parser_state_t ps;
- char *cmd, *value, *l, *l1, *ce;
+ char *cmd, *value, *ce, old_ch;
SHELL_VAR *v;
char ibuf[INT_STRLEN_BOUND(int) + 1];
/* First, we need to find the right command to execute. This is tricky,
because we might have already indirected into another keymap, so we
have to walk cmd_xmap using the entire key sequence. */
- cmd = (char *)rl_function_of_keyseq (rl_executing_keyseq, cmd_xmap, &type);
+ cmd = (char *)rl_function_of_keyseq_len (rl_executing_keyseq, rl_key_sequence_length, cmd_xmap, &type);
if (cmd == 0 || type != ISMACR)
{
@@ -4112,25 +4163,37 @@
v = bind_variable ("READLINE_LINE", rl_line_buffer, 0);
if (v)
VSETATTR (v, att_exported);
- l = v ? value_cell (v) : 0;
- value = inttostr (rl_point, ibuf, sizeof (ibuf));
- v = bind_int_variable ("READLINE_POINT", value);
+ i = rl_point;
+#if defined (HANDLE_MULTIBYTE)
+ if (MB_CUR_MAX > 1)
+ {
+ old_ch = rl_line_buffer[rl_point];
+ rl_line_buffer[rl_point] = '\0';
+ i = MB_STRLEN (rl_line_buffer);
+ rl_line_buffer[rl_point] = old_ch;
+ }
+#endif
+ value = inttostr (i, ibuf, sizeof (ibuf));
+ v = bind_int_variable ("READLINE_POINT", value, 0);
if (v)
VSETATTR (v, att_exported);
array_needs_making = 1;
save_parser_state (&ps);
- r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
+ r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
restore_parser_state (&ps);
v = find_variable ("READLINE_LINE");
- l1 = v ? value_cell (v) : 0;
- if (l1 != l)
- maybe_make_readline_line (value_cell (v));
+ maybe_make_readline_line (v ? value_cell (v) : 0);
+
v = find_variable ("READLINE_POINT");
if (v && legal_number (value_cell (v), &mi))
{
i = mi;
+#if defined (HANDLE_MULTIBYTE)
+ if (i > 0 && MB_CUR_MAX > 1)
+ i = _rl_find_next_mbchar (rl_line_buffer, 0, i, 0);
+#endif
if (i != rl_point)
{
rl_point = i;