This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 7/8] Backport shellword movement functions from bash 4.1


Index: bash-3.2/bashline.c
===================================================================
--- bash-3.2.orig/bashline.c
+++ bash-3.2/bashline.c
@@ -50,6 +50,8 @@
 #include "execute_cmd.h"
 #include "findcmd.h"
 #include "pathexp.h"
+#include "shmbutil.h"
+
 #include "builtins/common.h"
 #include <readline/rlconf.h>
 #include <readline/readline.h>
@@ -99,6 +101,11 @@ static int alias_expand_line __P((int, i
 static int history_and_alias_expand_line __P((int, int));
 #endif
 
+static int bash_forward_shellword __P((int, int));
+static int bash_backward_shellword __P((int, int));
+static int bash_kill_shellword __P((int, int));
+static int bash_backward_kill_shellword __P((int, int));
+
 /* Helper functions for Readline. */
 static void bash_directory_expansion __P((char **));
 static int bash_directory_completion_hook __P((char **));
@@ -360,6 +367,11 @@ initialize_readline ()
   rl_add_defun ("magic-space", tcsh_magic_space, -1);
 #endif
 
+  rl_add_defun ("shell-forward-word", bash_forward_shellword, -1);
+  rl_add_defun ("shell-backward-word", bash_backward_shellword, -1);
+  rl_add_defun ("shell-kill-word", bash_kill_shellword, -1);
+  rl_add_defun ("shell-backward-kill-word", bash_backward_kill_shellword, -1);
+
 #ifdef ALIAS
   rl_add_defun ("alias-expand-line", alias_expand_line, -1);
 #  ifdef BANG_HISTORY
@@ -912,6 +924,202 @@ posix_edit_macros (count, key)
 }
 #endif
 
+/* Bindable commands that move `shell-words': that is, sequences of
+   non-unquoted-metacharacters. */
+
+#define WORDDELIM(c)	(shellmeta(c) || shellblank(c))
+
+static int
+bash_forward_shellword (count, key)
+     int count, key;
+{
+  size_t slen;
+  int sindex, c, p;
+  DECLARE_MBSTATE;
+
+  if (count < 0)
+    return (bash_backward_shellword (-count, key));
+
+  /* The tricky part of this is deciding whether or not the first character
+     we're on is an unquoted metacharacter.  Not completely handled yet. */
+  /* XXX - need to test this stuff with backslash-escaped shell
+     metacharacters and unclosed single- and double-quoted strings. */
+
+  p = rl_point;
+  slen = rl_end;
+
+  while (count)
+    {
+      if (p == rl_end)
+	{
+	  rl_point = rl_end;
+	  return 0;
+	}
+
+      /* Move forward until we hit a non-metacharacter. */
+      while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c))
+	{
+	  switch (c)
+	    {
+	    default:
+	      ADVANCE_CHAR (rl_line_buffer, slen, p);
+	      continue;		/* straight back to loop, don't increment p */
+	    case '\\':
+	      if (p < rl_end && rl_line_buffer[p])
+		ADVANCE_CHAR (rl_line_buffer, slen, p);
+	      break;
+	    case '\'':
+	      p = skip_to_delim41 (rl_line_buffer, ++p, "'", SD_NOJMP);
+	      break;
+	    case '"':
+	      p = skip_to_delim41 (rl_line_buffer, ++p, "\"", SD_NOJMP);
+	      break;
+	    }
+
+	  if (p < rl_end)
+	    p++;
+	}
+
+      if (rl_line_buffer[p] == 0 || p == rl_end)
+        {
+	  rl_point = rl_end;
+	  rl_ding ();
+	  return 0;
+        }
+	
+      /* Now move forward until we hit a non-quoted metacharacter or EOL */
+      while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0)
+	{
+	  switch (c)
+	    {
+	    default:
+	      ADVANCE_CHAR (rl_line_buffer, slen, p);
+	      continue;		/* straight back to loop, don't increment p */
+	    case '\\':
+	      if (p < rl_end && rl_line_buffer[p])
+		ADVANCE_CHAR (rl_line_buffer, slen, p);
+	      break;
+	    case '\'':
+	      p = skip_to_delim41 (rl_line_buffer, ++p, "'", SD_NOJMP);
+	      break;
+	    case '"':
+	      p = skip_to_delim41 (rl_line_buffer, ++p, "\"", SD_NOJMP);
+	      break;
+	    }
+
+	  if (p < rl_end)
+	    p++;
+	}
+
+      if (p == rl_end || rl_line_buffer[p] == 0)
+	{
+	  rl_point = rl_end;
+	  return (0);
+	}
+
+      count--;      
+    }
+
+  rl_point = p;
+  return (0);
+}
+
+static int
+bash_backward_shellword (count, key)
+     int count, key;
+{
+  size_t slen;
+  int sindex, c, p;
+  DECLARE_MBSTATE;
+  
+  if (count < 0)
+    return (bash_forward_shellword (-count, key));
+
+  p = rl_point;
+  slen = rl_end;
+  
+  while (count)
+    {
+      if (p == 0)
+	{
+	  rl_point = 0;
+	  return 0;
+	}
+
+      /* Move backward until we hit a non-metacharacter. */
+      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 (p == 0)
+	{
+	  rl_point = 0;
+	  return 0;
+	}
+
+      /* Now move backward until we hit a metacharacter or BOL. */
+      while (p > 0)
+	{
+	  c = rl_line_buffer[p];
+	  if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0)
+	    break;
+	  BACKUP_CHAR (rl_line_buffer, slen, p);
+	}
+
+      count--;
+    }
+
+  rl_point = p;
+  return 0;
+}
+
+static int
+bash_kill_shellword (count, key)
+     int count, key;
+{
+  int p;
+
+  if (count < 0)
+    return (bash_backward_kill_shellword (-count, key));
+
+  p = rl_point;
+  bash_forward_shellword (count, key);
+
+  if (rl_point != p)
+    rl_kill_text (p, rl_point);
+
+  rl_point = p;
+  if (rl_editing_mode == 1)	/* 1 == emacs_mode */
+    rl_mark = rl_point;
+
+  return 0;
+}
+
+static int
+bash_backward_kill_shellword (count, key)
+     int count, key;
+{
+  int p;
+
+  if (count < 0)
+    return (bash_kill_shellword (-count, key));
+
+  p = rl_point;
+  bash_backward_shellword (count, key);
+
+  if (rl_point != p)
+    rl_kill_text (p, rl_point);
+
+  if (rl_editing_mode == 1)	/* 1 == emacs_mode */
+    rl_mark = rl_point;
+
+  return 0;
+}
+
 /* **************************************************************** */
 /*								    */
 /*			How To Do Shell Completion		    */
Index: bash-3.2/subst.c
===================================================================
--- bash-3.2.orig/subst.c
+++ bash-3.2/subst.c
@@ -1454,6 +1454,116 @@ unclosed_pair (string, eindex, openstr)
   return (openc);
 }
 
+/* (Backport from bash 4.1)
+
+   Skip characters in STRING until we find a character in DELIMS, and return
+   the index of that character.  START is the index into string at which we
+   begin.  This is similar in spirit to strpbrk, but it returns an index into
+   STRING and takes a starting index.  This little piece of code knows quite
+   a lot of shell syntax.  It's very similar to skip_double_quoted and other
+   functions of that ilk. */
+int
+skip_to_delim41 (string, start, delims, flags)
+     char *string;
+     int start;
+     char *delims;
+     int flags;
+{
+  int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
+  size_t slen;
+  char *temp;
+  DECLARE_MBSTATE;
+
+  slen = strlen (string + start) + start;
+  if (flags & SD_NOJMP)
+    no_longjmp_on_fatal_error = 1;
+  invert = (flags & SD_INVERT);
+  skipcmd = (flags & SD_NOSKIPCMD) == 0;
+
+  i = start;
+  pass_next = backq = 0;
+  while (c = string[i])
+    {
+      /* If this is non-zero, we should not let quote characters be delimiters
+	 and the current character is a single or double quote.  We should not
+	 test whether or not it's a delimiter until after we skip single- or
+	 double-quoted strings. */
+      skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
+      if (pass_next)
+	{
+	  pass_next = 0;
+	  if (c == 0)
+	    CQ_RETURN(i);
+	  ADVANCE_CHAR (string, slen, i);
+	  continue;
+	}
+      else if (c == '\\')
+	{
+	  pass_next = 1;
+	  i++;
+	  continue;
+	}
+      else if (backq)
+	{
+	  if (c == '`')
+	    backq = 0;
+	  ADVANCE_CHAR (string, slen, i);
+	  continue;
+	}
+      else if (c == '`')
+	{
+	  backq = 1;
+	  i++;
+	  continue;
+	}
+      else if (skipquote == 0 && invert == 0 && member (c, delims))
+	break;
+      else if (c == '\'' || c == '"')
+	{
+	  i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
+			  : skip_double_quoted (string, slen, ++i);
+	  /* no increment, the skip functions increment past the closing quote. */
+	}
+      else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
+	{
+	  si = i + 2;
+	  if (string[si] == '\0')
+	    CQ_RETURN(si);
+
+	  if (string[i+1] == LPAREN)
+	    temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
+	  else
+	    temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
+	  i = si;
+	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
+	    break;
+	  i++;
+	  continue;
+	}
+#if defined (PROCESS_SUBSTITUTION)
+      else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN)
+	{
+	  si = i + 2;
+	  if (string[si] == '\0')
+	    CQ_RETURN(si);
+	  temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
+	  i = si;
+	  if (string[i] == '\0')
+	    break;
+	  i++;
+	  continue;
+	}
+#endif /* PROCESS_SUBSTITUTION */
+      else if ((skipquote || invert) && (member (c, delims) == 0))
+	break;
+      else
+	ADVANCE_CHAR (string, slen, i);
+    }
+
+  CQ_RETURN(i);
+}
+
+
 /* Skip characters in STRING until we find a character in DELIMS, and return
    the index of that character.  START is the index into string at which we
    begin.  This is similar in spirit to strpbrk, but it returns an index into
Index: bash-3.2/subst.h
===================================================================
--- bash-3.2.orig/subst.h
+++ bash-3.2/subst.h
@@ -236,6 +236,14 @@ extern char *remove_backslashes __P((cha
 extern char *cond_expand_word __P((WORD_DESC *, int));
 #endif
 
+/* Flags for skip_to_delim41 */
+#define SD_NOJMP	0x01	/* don't longjmp on fatal error. */
+#define SD_INVERT	0x02	/* look for chars NOT in passed set */
+#define SD_NOQUOTEDELIM	0x04	/* don't let single or double quotes act as delimiters */
+#define SD_NOSKIPCMD	0x08	/* don't skip over $(, <(, or >( command/process substitution */
+
+extern int skip_to_delim41 __P((char *, int, char *, int));
+
 #if defined (READLINE)
 extern int char_is_quoted __P((char *, int));
 extern int unclosed_pair __P((char *, int, char *));


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]