Imported from ../bash-2.01.tar.gz.
[platform/upstream/bash.git] / bashline.c
index 7d2e5d7..fbd196a 100644 (file)
@@ -56,6 +56,11 @@ extern void bash_brace_completion ();
 static void shell_expand_line ();
 static void display_shell_version (), operate_and_get_next ();
 static void history_expand_line (), bash_ignore_filenames ();
+#ifdef ALIAS
+static void alias_expand_line ();
+#endif
+static void history_and_alias_expand_line ();
+static void cleanup_expansion_error (), set_up_new_line ();
 
 /* Helper functions for Readline. */
 static int bash_directory_completion_hook ();
@@ -194,6 +199,11 @@ initialize_readline ()
   rl_add_defun ("history-expand-line", (Function *)history_expand_line, -1);
   rl_bind_key_in_map ('^', (Function *)history_expand_line, emacs_meta_keymap);
 
+#ifdef ALIAS
+  rl_add_defun ("alias-expand-line", (Function *)alias_expand_line, -1);
+  rl_add_defun ("history-and-alias-expand-line", (Function *)history_and_alias_expand_line, -1);
+#endif
+
   /* Backwards compatibility. */
   rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1);
 
@@ -285,7 +295,7 @@ initialize_readline ()
   enable_hostname_completion (perform_hostname_completion);
 
   /* characters that need to be quoted when appearing in filenames. */
-  rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!";
+  rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:";
   rl_filename_quoting_function = bash_quote_filename;
   rl_filename_dequoting_function = bash_dequote_filename;
   rl_char_is_quoted_p = char_is_quoted;
@@ -592,13 +602,13 @@ vi_edit_and_execute_command (count, c)
         the end of the history because fc ignores the last command (assumes
         it's supposed to deal with the command before the `fc'). */
       using_history ();
-      add_history (rl_line_buffer);
-      add_history ("");
+      bash_add_history (rl_line_buffer);
+      bash_add_history ("");
       history_lines_this_session++;
       using_history ();
       command = savestring (VI_EDIT_COMMAND);
     }
-  parse_and_execute (command, "v", -1);
+  parse_and_execute (command, "v", SEVAL_NOHIST);
   rl_line_buffer[0] = '\0';    /* XXX */
 }
 #endif /* VI_MODE */
@@ -688,8 +698,18 @@ attempt_shell_completion (text, start, end)
         assignments. */
     }
 
-  /* Special handling for command substitution. */
-  if (*text == '`' && unclosed_pair (rl_line_buffer, start, "`"))
+  /* Check that we haven't incorrectly flagged a closed command substitution
+     as indicating we're in a command position. */
+  if (in_command_position && rl_line_buffer[ti] == '`' && *text != '`' && 
+       unclosed_pair (rl_line_buffer, 0, "`") == 0)
+    in_command_position = 0;
+
+  /* Special handling for command substitution.  If *TEXT is a backquote,
+     it can be the start or end of an old-style command substitution, or
+     unmatched.  If it's unmatched, both calls to unclosed_pair will
+     succeed.  */
+  if (*text == '`' && unclosed_pair (rl_line_buffer, start, "`") &&
+       unclosed_pair (rl_line_buffer, end, "`"))
     matches = completion_matches (text, command_subst_completion_function);
 
   /* Variable name? */
@@ -928,7 +948,7 @@ command_word_completion_function (hint_text, state)
     }
   else
     {
-      int match;
+      int match, freetemp;
       char *temp;
 
       if (absolute_program (hint))
@@ -948,6 +968,7 @@ command_word_completion_function (hint_text, state)
            }
          else
            temp = savestring (val);
+         freetemp = 1;
        }
       else
        {
@@ -956,12 +977,12 @@ command_word_completion_function (hint_text, state)
          if (temp)
            {
              temp++;
-             match = strncmp (temp, hint, hint_len) == 0;
+             freetemp = match = strncmp (temp, hint, hint_len) == 0;
              if (match)
                temp = savestring (temp);
            }
          else
-           match = 0;
+           freetemp = match = 0;
        }
 
       /* If we have found a match, and it is an executable file or a
@@ -974,12 +995,15 @@ command_word_completion_function (hint_text, state)
        }
       else
        {
+         if (freetemp)
+           free (temp);
          free (val);
          goto inner;
        }
     }
 }
 
+/* Completion inside an unterminated command substitution. */
 static char *
 command_subst_completion_function (text, state)
      char *text;
@@ -1148,19 +1172,23 @@ history_expand_line_internal (line)
   char *new_line;
 
   new_line = pre_process_line (line, 0, 0);
-  return new_line;
+  return (new_line == line) ? savestring (line) : new_line;
 }
 
 #if defined (ALIAS)
-/* Perform alias expansion on LINE and return the new line. */
-static char *
-alias_expand_line_internal (line)
-     char *line;
+/* Expand aliases in the current readline line. */
+static void
+alias_expand_line (ignore)
+     int ignore;
 {
-  char *alias_line;
+  char *new_line;
+
+  new_line = alias_expand (rl_line_buffer);
 
-  alias_line = alias_expand (line);
-  return alias_line;
+  if (new_line)
+    set_up_new_line (new_line);
+  else
+    cleanup_expansion_error ();
 }
 #endif
 
@@ -1173,7 +1201,8 @@ cleanup_expansion_error ()
 
   fprintf (rl_outstream, "\r\n");
   to_free = pre_process_line (rl_line_buffer, 1, 0);
-  free (to_free);
+  if (to_free != rl_line_buffer)
+    free (to_free);
   putc ('\r', rl_outstream);
   rl_forced_update_display ();
 }
@@ -1244,6 +1273,8 @@ history_and_alias_expand_line (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);
 
 #if defined (ALIAS)
   if (new_line)
@@ -1272,6 +1303,8 @@ shell_expand_line (ignore)
   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);
 
 #if defined (ALIAS)
   if (new_line)
@@ -1296,7 +1329,9 @@ shell_expand_line (ignore)
 
       /* If there is variable expansion to perform, do that as a separate
         operation to be undone. */
-      expanded_string = expand_string (rl_line_buffer, 0);
+      new_line = savestring (rl_line_buffer);
+      expanded_string = expand_string (new_line, 0);
+      FREE (new_line);
       if (expanded_string == 0)
        {
          new_line = xmalloc (1);
@@ -1862,7 +1897,44 @@ bash_dequote_filename (text, quote_char)
   return ret;
 }
 
-/* Quote a filename using double quotes. */
+/* Quote characters that the readline completion code would treat as
+   word break characters with backslashes.  Pass backslash-quoted
+   characters through without examination. */
+static char *
+quote_word_break_chars (text)
+     char *text;
+{
+  char *ret, *r, *s;
+  int l;
+
+  l = strlen (text);
+  ret = xmalloc ((2 * l) + 1);
+  for (s = text, r = ret; *s; s++)
+    {
+      /* Pass backslash-quoted characters through, including the backslash. */
+      if (*s == '\\')
+       {
+         *r++ = '\\';
+         *r++ = *++s;
+         if (*s == '\0')
+           break;
+         continue;
+       }
+      /* OK, we have an unquoted character.  Check its presence in
+        rl_completer_word_break_characters. */
+      if (strchr (rl_completer_word_break_characters, *s))
+        *r++ = '\\';
+      *r++ = *s;
+    }
+  *r = '\0';
+  return ret;
+}
+
+/* Quote a filename using double quotes, single quotes, or backslashes
+   depending on the value of completion_quoting_style.  If we're
+   completing using backslashes, we need to quote some additional
+   characters (those that readline treats as word breaks), so we call
+   quote_word_break_chars on the result. */
 static char *
 bash_quote_filename (s, rtype, qcp)
      char *s;
@@ -1896,6 +1968,13 @@ bash_quote_filename (s, rtype, qcp)
   else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE &&
           history_expansion_inhibited == 0 && strchr (mtext, '!'))
     cs = COMPLETE_BSQUOTE;
+
+  if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE &&
+        history_expansion_inhibited == 0 && strchr (mtext, '!'))
+    {
+      cs = COMPLETE_BSQUOTE;
+      *qcp = '\0';
+    }
 #endif
 
   switch (cs)
@@ -1914,6 +1993,15 @@ bash_quote_filename (s, rtype, qcp)
   if (mtext != s)
     free (mtext);
 
+  /* We may need to quote additional characters: those that readline treats
+     as word breaks that are not quoted by backslash_quote. */
+  if (rtext && cs == COMPLETE_BSQUOTE)
+    {
+      mtext = quote_word_break_chars (rtext);
+      free (rtext);
+      rtext = mtext;
+    }
+
   /* Leave the opening quote intact.  The readline completion code takes
      care of avoiding doubled opening quotes. */
   rlen = strlen (rtext);