Imported from ../bash-4.0-rc1.tar.gz.
[platform/upstream/bash.git] / lib / readline / text.c
index 2a7b724..652b306 100644 (file)
@@ -1,24 +1,24 @@
 /* text.c -- text handling commands for readline. */
 
-/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
 
-   This file is part of the GNU Readline Library, a library for
-   reading lines of text with interactive input and history editing.
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
 
-   The GNU Readline Library is free software; you can redistribute it
-   and/or modify it under the terms of the GNU General Public License
-   as published by the Free Software Foundation; either version 2, or
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
-   The GNU Readline Library is distributed in the hope that it will be
-   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   Readline is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
-   The GNU General Public License is often shipped with GNU software, and
-   is generally kept in a file called COPYING or LICENSE.  If you do not
-   have a copy of the license, write to the Free Software Foundation,
-   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
 #define READLINE_LIBRARY
 
 #if defined (HAVE_CONFIG_H)
 static int rl_change_case PARAMS((int, int));
 static int _rl_char_search PARAMS((int, int, int));
 
+#if defined (READLINE_CALLBACKS)
+static int _rl_insert_next_callback PARAMS((_rl_callback_generic_arg *));
+static int _rl_char_search_callback PARAMS((_rl_callback_generic_arg *));
+#endif
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Insert and Delete                           */
@@ -170,6 +175,9 @@ _rl_fix_point (fix_mark_too)
 }
 #undef _RL_FIX_POINT
 
+/* Replace the contents of the line buffer between START and END with
+   TEXT.  The operation is undoable.  To replace the entire line in an
+   undoable mode, use _rl_replace_text(text, 0, rl_end); */
 int
 _rl_replace_text (text, start, end)
      const char *text;
@@ -252,7 +260,7 @@ rl_forward_byte (count, key)
     {
       int end = rl_point + count;
 #if defined (VI_MODE)
-      int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end;
+      int lend = rl_end > 0 ? rl_end - (VI_COMMAND_MODE()) : rl_end;
 #else
       int lend = rl_end;
 #endif
@@ -288,10 +296,16 @@ rl_forward_char (count, key)
 
   if (count > 0)
     {
+      if (rl_point == rl_end && EMACS_MODE())
+       {
+         rl_ding ();
+         return 0;
+       }
+
       point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
 
 #if defined (VI_MODE)
-      if (rl_end <= point && rl_editing_mode == vi_mode)
+      if (point >= rl_end && VI_COMMAND_MODE())
        point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO);
 #endif
 
@@ -417,8 +431,7 @@ rl_end_of_line (count, key)
   return 0;
 }
 
-/* XXX - these might need changes for multibyte characters */
-/* Move forward a word.  We do what Emacs does. */
+/* Move forward a word.  We do what Emacs does.  Handles multibyte chars. */
 int
 rl_forward_word (count, key)
      int count, key;
@@ -435,68 +448,80 @@ rl_forward_word (count, key)
 
       /* If we are not in a word, move forward until we are in one.
         Then, move forward until we hit a non-alphabetic character. */
-      c = rl_line_buffer[rl_point];
-      if (rl_alphabetic (c) == 0)
+      c = _rl_char_value (rl_line_buffer, rl_point);
+
+      if (_rl_walphabetic (c) == 0)
        {
-         while (++rl_point < rl_end)
+         rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
+         while (rl_point < rl_end)
            {
-             c = rl_line_buffer[rl_point];
-             if (rl_alphabetic (c))
+             c = _rl_char_value (rl_line_buffer, rl_point);
+             if (_rl_walphabetic (c))
                break;
+             rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
            }
        }
 
       if (rl_point == rl_end)
        return 0;
 
-      while (++rl_point < rl_end)
+      rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
+      while (rl_point < rl_end)
        {
-         c = rl_line_buffer[rl_point];
-         if (rl_alphabetic (c) == 0)
+         c = _rl_char_value (rl_line_buffer, rl_point);
+         if (_rl_walphabetic (c) == 0)
            break;
+         rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
        }
+
       --count;
     }
 
   return 0;
 }
 
-/* Move backward a word.  We do what Emacs does. */
+/* Move backward a word.  We do what Emacs does.  Handles multibyte chars. */
 int
 rl_backward_word (count, key)
      int count, key;
 {
-  int c;
+  int c, p;
 
   if (count < 0)
     return (rl_forward_word (-count, key));
 
   while (count)
     {
-      if (!rl_point)
+      if (rl_point == 0)
        return 0;
 
       /* Like rl_forward_word (), except that we look at the characters
         just before point. */
 
-      c = rl_line_buffer[rl_point - 1];
-      if (rl_alphabetic (c) == 0)
+      p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+      c = _rl_char_value (rl_line_buffer, p);
+
+      if (_rl_walphabetic (c) == 0)
        {
-         while (--rl_point)
+         rl_point = p;
+         while (rl_point > 0)
            {
-             c = rl_line_buffer[rl_point - 1];
-             if (rl_alphabetic (c))
+             p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+             c = _rl_char_value (rl_line_buffer, p);
+             if (_rl_walphabetic (c))
                break;
+             rl_point = p;
            }
        }
 
       while (rl_point)
        {
-         c = rl_line_buffer[rl_point - 1];
-         if (rl_alphabetic (c) == 0)
+         p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+         c = _rl_char_value (rl_line_buffer, p);         
+         if (_rl_walphabetic (c) == 0)
            break;
          else
-           --rl_point;
+           rl_point = p;
        }
 
       --count;
@@ -753,10 +778,8 @@ _rl_insert_char (count, c)
       return 0;
     }
 
-#if defined (HANDLE_MULTIBYTE)
   if (MB_CUR_MAX == 1 || rl_byte_oriented)
     {
-#endif
       /* We are inserting a single character.
         If there is pending input, then make a string of all of the
         pending characters that are bound to rl_insert, and insert
@@ -772,8 +795,8 @@ _rl_insert_char (count, c)
          str[0] = c;
          rl_insert_text (str);
        }
-#if defined (HANDLE_MULTIBYTE)
     }
+#if defined (HANDLE_MULTIBYTE)
   else
     {
       rl_insert_text (incoming);
@@ -801,13 +824,10 @@ _rl_overwrite_char (count, c)
     k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX);
 #endif
 
+  rl_begin_undo_group ();
+
   for (i = 0; i < count; i++)
     {
-      rl_begin_undo_group ();
-
-      if (rl_point < rl_end)
-       rl_delete (1, c);
-
 #if defined (HANDLE_MULTIBYTE)
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
        rl_insert_text (mbkey);
@@ -815,9 +835,12 @@ _rl_overwrite_char (count, c)
 #endif
        _rl_insert_char (1, c);
 
-      rl_end_undo_group ();
+      if (rl_point < rl_end)
+       rl_delete (1, c);
     }
 
+  rl_end_undo_group ();
+
   return 0;
 }
 
@@ -830,27 +853,66 @@ rl_insert (count, c)
 }
 
 /* Insert the next typed character verbatim. */
-int
-rl_quoted_insert (count, key)
-     int count, key;
+static int
+_rl_insert_next (count)
+     int count;
 {
   int c;
 
-#if defined (HANDLE_SIGNALS)
-  _rl_disable_tty_signals ();
-#endif
-
   RL_SETSTATE(RL_STATE_MOREINPUT);
   c = rl_read_key ();
   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 
+  if (c < 0)
+    return -1;
+
 #if defined (HANDLE_SIGNALS)
-  _rl_restore_tty_signals ();
+  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
+    _rl_restore_tty_signals ();
 #endif
 
   return (_rl_insert_char (count, c));  
 }
 
+#if defined (READLINE_CALLBACKS)
+static int
+_rl_insert_next_callback (data)
+     _rl_callback_generic_arg *data;
+{
+  int count;
+
+  count = data->count;
+
+  /* Deregister function, let rl_callback_read_char deallocate data */
+  _rl_callback_func = 0;
+  _rl_want_redisplay = 1;
+  return _rl_insert_next (count);
+}
+#endif
+  
+int
+rl_quoted_insert (count, key)
+     int count, key;
+{
+  /* Let's see...should the callback interface futz with signal handling? */
+#if defined (HANDLE_SIGNALS)
+  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
+    _rl_disable_tty_signals ();
+#endif
+
+#if defined (READLINE_CALLBACKS)
+  if (RL_ISSTATE (RL_STATE_CALLBACK))
+    {
+      _rl_callback_data = _rl_callback_data_alloc (count);
+      _rl_callback_func = _rl_insert_next_callback;
+      return (0);
+    }
+#endif
+      
+  return _rl_insert_next (count);
+}
+
 /* Insert a tab character. */
 int
 rl_tab_insert (count, key)
@@ -877,7 +939,8 @@ rl_newline (count, key)
   if (rl_editing_mode == vi_mode)
     {
       _rl_vi_done_inserting ();
-      _rl_vi_reset_last ();
+      if (_rl_vi_textmod_command (_rl_vi_last_command) == 0)   /* XXX */
+       _rl_vi_reset_last ();
     }
 #endif /* VI_MODE */
 
@@ -886,7 +949,7 @@ rl_newline (count, key)
   if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
     return 0;
 
-  if (readline_echoing_p)
+  if (_rl_echoing_p)
     _rl_update_final ();
   return 0;
 }
@@ -935,9 +998,12 @@ _rl_overwrite_rubout (count, key)
     rl_delete_text (opoint, rl_point);
 
   /* Emacs puts point at the beginning of the sequence of spaces. */
-  opoint = rl_point;
-  _rl_insert_char (l, ' ');
-  rl_point = opoint;
+  if (rl_point < rl_end)
+    {
+      opoint = rl_point;
+      _rl_insert_char (l, ' ');
+      rl_point = opoint;
+    }
 
   rl_end_undo_group ();
 
@@ -981,43 +1047,17 @@ _rl_rubout_char (count, key)
       return -1;
     }
 
+  orig_point = rl_point;
   if (count > 1 || rl_explicit_arg)
     {
-      orig_point = rl_point;
-#if defined (HANDLE_MULTIBYTE)
-      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-       rl_backward_char (count, key);
-      else
-#endif
-        rl_backward_byte (count, key);
+      rl_backward_char (count, key);
       rl_kill_text (orig_point, rl_point);
     }
-  else
+  else if (MB_CUR_MAX == 1 || rl_byte_oriented)
     {
-#if defined (HANDLE_MULTIBYTE)
-      if (MB_CUR_MAX == 1 || rl_byte_oriented)
-       {
-#endif
-         c = rl_line_buffer[--rl_point];
-         rl_delete_text (rl_point, rl_point + 1);
-#if defined (HANDLE_MULTIBYTE)
-       }
-      else
-       {
-         int orig_point;
-
-         orig_point = rl_point;
-         rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
-         c = rl_line_buffer[rl_point];
-         rl_delete_text (rl_point, orig_point);
-       }
-#endif /* HANDLE_MULTIBYTE */
-
-      /* I don't think that the hack for end of line is needed for
-        multibyte chars. */
-#if defined (HANDLE_MULTIBYTE)
-      if (MB_CUR_MAX == 1 || rl_byte_oriented)
-#endif
+      c = rl_line_buffer[--rl_point];
+      rl_delete_text (rl_point, orig_point);
+      /* The erase-at-end-of-line hack is of questionable merit now. */
       if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos)
        {
          int l;
@@ -1025,6 +1065,11 @@ _rl_rubout_char (count, key)
          _rl_erase_at_end_of_line (l);
        }
     }
+  else
+    {
+      rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
+      rl_delete_text (rl_point, orig_point);
+    }
 
   return 0;
 }
@@ -1035,7 +1080,7 @@ int
 rl_delete (count, key)
      int count, key;
 {
-  int r;
+  int xpoint;
 
   if (count < 0)
     return (_rl_rubout_char (-count, key));
@@ -1048,28 +1093,21 @@ rl_delete (count, key)
 
   if (count > 1 || rl_explicit_arg)
     {
-      int orig_point = rl_point;
-#if defined (HANDLE_MULTIBYTE)
+      xpoint = rl_point;
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
        rl_forward_char (count, key);
       else
-#endif
        rl_forward_byte (count, key);
 
-      r = rl_kill_text (orig_point, rl_point);
-      rl_point = orig_point;
-      return r;
+      rl_kill_text (xpoint, rl_point);
+      rl_point = xpoint;
     }
   else
     {
-      int new_point;
-      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-       new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
-      else
-       new_point = rl_point + 1;
-       
-      return (rl_delete_text (rl_point, new_point));
+      xpoint = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
+      rl_delete_text (rl_point, xpoint);
     }
+  return 0;
 }
 
 /* Delete the character under the cursor, unless the insertion
@@ -1106,6 +1144,10 @@ rl_delete_horizontal_space (count, ignore)
       rl_delete_text (start, rl_point);
       rl_point = start;
     }
+
+  if (rl_point < 0)
+    rl_point = 0;
+
   return 0;
 }
 
@@ -1199,42 +1241,80 @@ static int
 rl_change_case (count, op)
      int count, op;
 {
-  register int start, end;
-  int inword, c;
+  int start, next, end;
+  int inword, c, nc, nop;
+#if defined (HANDLE_MULTIBYTE)
+  wchar_t wc, nwc;
+  char mb[MB_LEN_MAX+1];
+  int mlen;
+  mbstate_t mps;
+#endif
 
   start = rl_point;
   rl_forward_word (count, 0);
   end = rl_point;
 
+  if (op != UpCase && op != DownCase && op != CapCase)
+    {
+      rl_ding ();
+      return -1;
+    }
+
   if (count < 0)
     SWAP (start, end);
 
+#if defined (HANDLE_MULTIBYTE)
+  memset (&mps, 0, sizeof (mbstate_t));
+#endif
+
   /* We are going to modify some text, so let's prepare to undo it. */
   rl_modifying (start, end);
 
-  for (inword = 0; start < end; start++)
+  inword = 0;
+  while (start < end)
     {
-      c = rl_line_buffer[start];
-      switch (op)
-       {
-       case UpCase:
-         rl_line_buffer[start] = _rl_to_upper (c);
-         break;
-
-       case DownCase:
-         rl_line_buffer[start] = _rl_to_lower (c);
-         break;
+      c = _rl_char_value (rl_line_buffer, start);
+      /*  This assumes that the upper and lower case versions are the same width. */
+      next = MB_NEXTCHAR (rl_line_buffer, start, 1, MB_FIND_NONZERO);
 
-       case CapCase:
-         rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c);
-         inword = rl_alphabetic (rl_line_buffer[start]);
-         break;
+      if (_rl_walphabetic (c) == 0)
+       {
+         inword = 0;
+         start = next;
+         continue;
+       }
 
-       default:
-         rl_ding ();
-         return -1;
+      if (op == CapCase)
+       {
+         nop = inword ? DownCase : UpCase;
+         inword = 1;
        }
+      else
+       nop = op;
+      if (MB_CUR_MAX == 1 || rl_byte_oriented || isascii (c))
+       {
+         nc = (nop == UpCase) ? _rl_to_upper (c) : _rl_to_lower (c);
+         rl_line_buffer[start] = nc;
+       }
+#if defined (HANDLE_MULTIBYTE)
+      else
+       {
+         mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
+         nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
+         if  (nwc != wc)       /*  just skip unchanged characters */
+           {
+             mlen = wcrtomb (mb, nwc, &mps);
+             if (mlen > 0)
+               mb[mlen] = '\0';
+             /* Assume the same width */
+             strncpy (rl_line_buffer + start, mb, mlen);
+           }
+       }
+#endif
+
+      start = next;
     }
+
   rl_point = end;
   return 0;
 }
@@ -1314,11 +1394,11 @@ rl_transpose_chars (count, key)
 {
 #if defined (HANDLE_MULTIBYTE)
   char *dummy;
-  int i, prev_point;
+  int i;
 #else
   char dummy[2];
 #endif
-  int char_length;
+  int char_length, prev_point;
 
   if (count == 0)
     return 0;
@@ -1333,20 +1413,12 @@ rl_transpose_chars (count, key)
 
   if (rl_point == rl_end)
     {
-      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-       rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
-      else
-       --rl_point;
+      rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
       count = 1;
     }
 
-#if defined (HANDLE_MULTIBYTE)
   prev_point = rl_point;
-  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-    rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
-  else
-#endif
-    rl_point--;
+  rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
 
 #if defined (HANDLE_MULTIBYTE)
   char_length = prev_point - rl_point;
@@ -1457,6 +1529,9 @@ _rl_char_search (count, fdir, bdir)
 
   mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
 
+  if (mb_len <= 0)
+    return -1;
+
   if (count < 0)
     return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
   else
@@ -1473,6 +1548,9 @@ _rl_char_search (count, fdir, bdir)
   c = rl_read_key ();
   RL_UNSETSTATE(RL_STATE_MOREINPUT);
 
+  if (c < 0)
+    return -1;
+
   if (count < 0)
     return (_rl_char_search_internal (-count, bdir, c));
   else
@@ -1480,10 +1558,33 @@ _rl_char_search (count, fdir, bdir)
 }
 #endif /* !HANDLE_MULTIBYTE */
 
+#if defined (READLINE_CALLBACKS)
+static int
+_rl_char_search_callback (data)
+     _rl_callback_generic_arg *data;
+{
+  _rl_callback_func = 0;
+  _rl_want_redisplay = 1;
+
+  return (_rl_char_search (data->count, data->i1, data->i2));
+}
+#endif
+
 int
 rl_char_search (count, key)
      int count, key;
 {
+#if defined (READLINE_CALLBACKS)
+  if (RL_ISSTATE (RL_STATE_CALLBACK))
+    {
+      _rl_callback_data = _rl_callback_data_alloc (count);
+      _rl_callback_data->i1 = FFIND;
+      _rl_callback_data->i2 = BFIND;
+      _rl_callback_func = _rl_char_search_callback;
+      return (0);
+    }
+#endif
+  
   return (_rl_char_search (count, FFIND, BFIND));
 }
 
@@ -1491,6 +1592,17 @@ int
 rl_backward_char_search (count, key)
      int count, key;
 {
+#if defined (READLINE_CALLBACKS)
+  if (RL_ISSTATE (RL_STATE_CALLBACK))
+    {
+      _rl_callback_data = _rl_callback_data_alloc (count);
+      _rl_callback_data->i1 = BFIND;
+      _rl_callback_data->i2 = FFIND;
+      _rl_callback_func = _rl_char_search_callback;
+      return (0);
+    }
+#endif
+
   return (_rl_char_search (count, BFIND, FFIND));
 }