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;