]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - bashline.c
fix quoting for positional parameters if not word splitting; retry open for startup...
[thirdparty/bash.git] / bashline.c
index 8ba34a8162c1db7ab755af9f979955b0734d20e9..353e8b1e68aab2578cbcb2db8e003e14a8aa6dd3 100644 (file)
@@ -1,6 +1,6 @@
 /* bashline.c -- Bash's interface to the readline library. */
 
-/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -606,6 +606,7 @@ initialize_readline (void)
   rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap);
 #  endif
 
+  rl_add_defun ("bash-vi-complete", bash_vi_complete, -1);
   rl_bind_key_in_map ('\\', bash_vi_complete, vi_movement_keymap);
   rl_bind_key_in_map ('*', bash_vi_complete, vi_movement_keymap);
   rl_bind_key_in_map ('=', bash_vi_complete, vi_movement_keymap);
@@ -797,7 +798,11 @@ snarf_hosts_from_file (const char *filename)
   char *temp, buffer[256], name[256];
   register int i, start;
 
+#ifdef __MSYS__
+  file = fopen (filename, "rt");
+#else
   file = fopen (filename, "r");
+#endif
   if (file == 0)
     return;
 
@@ -948,8 +953,11 @@ edit_and_execute_command (int count, int c, int editing_mode, const char *edit_c
 
   if (rl_explicit_arg)
     {
-      command = (char *)xmalloc (strlen (edit_command) + 8);
-      sprintf (command, "%s %d", edit_command, count);
+      size_t clen;
+      /* 32 exceeds strlen (itos (INTMAX_MAX)) (19) */
+      clen = strlen (edit_command) + 32;
+      command = (char *)xmalloc (clen);
+      snprintf (command, clen, "%s %d", edit_command, count);
     }
   else
     {
@@ -1385,17 +1393,18 @@ bash_spell_correct_shellword (int count, int key)
 static inline int
 check_redir (int ti)
 {
-  register int this_char, prev_char;
+  int this_char, prev_char, next_char;
 
   /* Handle the two character tokens `>&', `<&', and `>|'.
      We are not in a command position after one of these. */
   this_char = rl_line_buffer[ti];
   prev_char = (ti > 0) ? rl_line_buffer[ti - 1] : 0;
+  next_char = (ti < rl_end) ? rl_line_buffer[ti + 1] : 0;
 
   if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
       (this_char == '|' && prev_char == '>'))
     return (1);
-  else if (this_char == '{' && prev_char == '$') /*}*/
+  else if (this_char == '{' && prev_char == '$' && FUNSUB_CHAR (next_char) == 0) /*}*/
     return (1);
 #if 0  /* Not yet */
   else if (this_char == '(' && prev_char == '$') /*)*/
@@ -1789,6 +1798,8 @@ bash_default_completion (const char *text, int start, int end, int qc, int compf
     {
       if (qc != '\'' && text[1] == '(') /* ) */
        matches = rl_completion_matches (text, command_subst_completion_function);
+      else if (qc != '\'' && text[1] == '{' && FUNSUB_CHAR (text[2])) /* } */
+       matches = rl_completion_matches (text, command_subst_completion_function);
       else
        {
          matches = rl_completion_matches (text, variable_completion_function);
@@ -2401,6 +2412,8 @@ command_subst_completion_function (const char *text, int state)
        text++;
       else if (*text == '$' && text[1] == '(') /* ) */
        text += 2;
+      else if (*text == '$' && text[1] == '{' && FUNSUB_CHAR (text[2])) /*}*/
+       text += 3;      /* nofork command substitution */
       /* If the text was quoted, suppress any quote character that the
         readline completion code would insert. */
       rl_completion_suppress_quote = 1;
@@ -3120,6 +3133,19 @@ test_for_directory (const char *name)
   int r;
 
   fn = bash_tilde_expand (name, 0);
+
+#if __CYGWIN
+  /* stat("//server") can only be successful as a directory, but can take
+     seconds to time out on failure.  It is much faster to assume that
+     "//server" is a valid name than it is to wait for a stat, even if it
+     gives false positives on bad names.  */
+  if (fn[0] == '/' && fn[1] == '/' && ! strchr (&fn[2], '/'))
+    {
+      free (fn);
+      return 1;
+    }
+#endif
+
   r = file_isdir (fn);
   free (fn);
 
@@ -4007,10 +4033,38 @@ bash_specific_completion (int what_to_do, rl_compentry_func_t *generator)
 #endif /* SPECIFIC_COMPLETION_FUNCTIONS */
 
 #if defined (VI_MODE)
+/* This does pretty much what _rl_vi_advance_point does. */
+static inline int
+vi_advance_point (void)
+{
+  int point;
+  DECLARE_MBSTATE;
+
+  point = rl_point;
+  if (rl_point < rl_end)
+#if defined (HANDLE_MULTIBYTE)
+    {
+      if (locale_mb_cur_max == 1)
+       rl_point++;
+      else
+       {
+         point = rl_point;
+         ADVANCE_CHAR (rl_line_buffer, rl_end, rl_point);
+         if (point == rl_point || rl_point > rl_end)
+           rl_point = rl_end;
+       }
+    }
+#else
+    rl_point++:
+#endif
+  return point;
+}
+
 /* Completion, from vi mode's point of view.  This is a modified version of
    rl_vi_complete which uses the bash globbing code to implement what POSIX
-   specifies, which is to append a `*' and attempt filename generation (which
-   has the side effect of expanding any globbing characters in the word). */
+   specifies, which is to optinally append a `*' and attempt filename
+   generation (which has the side effect of expanding any globbing characters
+   in the word). */
 static int
 bash_vi_complete (int count, int key)
 {
@@ -4022,7 +4076,7 @@ bash_vi_complete (int count, int key)
     {
       if (!whitespace (rl_line_buffer[rl_point + 1]))
        rl_vi_end_word (1, 'E');
-      rl_point++;
+      vi_advance_point ();
     }
 
   /* Find boundaries of current word, according to vi definition of a