No specific user configuration
[platform/upstream/bash.git] / lib / readline / misc.c
index 403313a..a890cda 100644 (file)
@@ -1,24 +1,24 @@
 /* misc.c -- miscellaneous bindable readline functions. */
 
-/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2012 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)
@@ -56,6 +56,8 @@
 static int rl_digit_loop PARAMS((void));
 static void _rl_history_set_point PARAMS((void));
 
+extern int history_offset;
+
 /* Forward declarations used in this file */
 void _rl_free_history_entry PARAMS((HIST_ENTRY *));
 
@@ -63,6 +65,8 @@ void _rl_free_history_entry PARAMS((HIST_ENTRY *));
    to preserve the value of rl_point from line to line. */
 int _rl_history_preserve_point = 0;
 
+_rl_arg_cxt _rl_argcxt;
+
 /* Saved target point for when _rl_history_preserve_point is set.  Special
    value of -1 means that point is at the end of the line. */
 int _rl_history_saved_point = -1;
@@ -73,113 +77,175 @@ int _rl_history_saved_point = -1;
 /*                                                                 */
 /* **************************************************************** */
 
-/* Handle C-u style numeric args, as well as M--, and M-digits. */
-static int
-rl_digit_loop ()
+int
+_rl_arg_overflow ()
 {
-  int key, c, sawminus, sawdigits;
+  if (rl_numeric_arg > 1000000)
+    {
+      _rl_argcxt = 0;
+      rl_explicit_arg = rl_numeric_arg = 0;
+      rl_ding ();
+      rl_restore_prompt ();
+      rl_clear_message ();
+      RL_UNSETSTATE(RL_STATE_NUMERICARG);
+      return 1;
+    }
+  return 0;
+}
 
+void
+_rl_arg_init ()
+{
   rl_save_prompt ();
-
+  _rl_argcxt = 0;
   RL_SETSTATE(RL_STATE_NUMERICARG);
-  sawminus = sawdigits = 0;
-  while (1)
-    {
-      if (rl_numeric_arg > 1000000)
-       {
-         sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
-         rl_ding ();
-         rl_restore_prompt ();
-         rl_clear_message ();
-         RL_UNSETSTATE(RL_STATE_NUMERICARG);
-         return 1;
-       }
-      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
-      RL_SETSTATE(RL_STATE_MOREINPUT);
-      key = c = rl_read_key ();
-      RL_UNSETSTATE(RL_STATE_MOREINPUT);
+}
 
-      if (c < 0)
-       {
-         _rl_abort_internal ();
-         return -1;
-       }
+int
+_rl_arg_getchar ()
+{
+  int c;
 
-      /* If we see a key bound to `universal-argument' after seeing digits,
-        it ends the argument but is otherwise ignored. */
-      if (_rl_keymap[c].type == ISFUNC &&
-         _rl_keymap[c].function == rl_universal_argument)
-       {
-         if (sawdigits == 0)
-           {
-             rl_numeric_arg *= 4;
-             continue;
-           }
-         else
-           {
-             RL_SETSTATE(RL_STATE_MOREINPUT);
-             key = rl_read_key ();
-             RL_UNSETSTATE(RL_STATE_MOREINPUT);
-             rl_restore_prompt ();
-             rl_clear_message ();
-             RL_UNSETSTATE(RL_STATE_NUMERICARG);
-             return (_rl_dispatch (key, _rl_keymap));
-           }
-       }
+  rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  c = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
 
-      c = UNMETA (c);
+  return c;
+}
 
-      if (_rl_digit_p (c))
-       {
-         rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
-         sawdigits = rl_explicit_arg = 1;
-       }
-      else if (c == '-' && rl_explicit_arg == 0)
+/* Process C as part of the current numeric argument.  Return -1 if the
+   argument should be aborted, 0 if we should not read any more chars, and
+   1 if we should continue to read chars. */
+int
+_rl_arg_dispatch (cxt, c)
+     _rl_arg_cxt cxt;
+     int c;
+{
+  int key, r;
+
+  key = c;
+
+  /* If we see a key bound to `universal-argument' after seeing digits,
+      it ends the argument but is otherwise ignored. */
+  if (_rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
+    {
+      if ((cxt & NUM_SAWDIGITS) == 0)
        {
-         rl_numeric_arg = sawminus = 1;
-         rl_arg_sign = -1;
+         rl_numeric_arg *= 4;
+         return 1;
        }
+      else if (RL_ISSTATE (RL_STATE_CALLBACK))
+        {
+          _rl_argcxt |= NUM_READONE;
+          return 0;    /* XXX */
+        }
       else
        {
-         /* Make M-- command equivalent to M--1 command. */
-         if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
-           rl_explicit_arg = 1;
+         RL_SETSTATE(RL_STATE_MOREINPUT);
+         key = rl_read_key ();
+         RL_UNSETSTATE(RL_STATE_MOREINPUT);
          rl_restore_prompt ();
          rl_clear_message ();
          RL_UNSETSTATE(RL_STATE_NUMERICARG);
+         if (key < 0)
+           return -1;
          return (_rl_dispatch (key, _rl_keymap));
        }
     }
 
-  /*NOTREACHED*/
-}
+  c = UNMETA (c);
 
-/* Add the current digit to the argument in progress. */
-int
-rl_digit_argument (ignore, key)
-     int ignore, key;
-{
-  rl_execute_next (key);
-  return (rl_digit_loop ());
+  if (_rl_digit_p (c))
+    {
+      r = _rl_digit_value (c);         
+      rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) +  r : r;
+      rl_explicit_arg = 1;
+      _rl_argcxt |= NUM_SAWDIGITS;
+    }
+  else if (c == '-' && rl_explicit_arg == 0)
+    {
+      rl_numeric_arg = 1;
+      _rl_argcxt |= NUM_SAWMINUS;
+      rl_arg_sign = -1;
+    }
+  else
+    {
+      /* Make M-- command equivalent to M--1 command. */
+      if ((_rl_argcxt & NUM_SAWMINUS) && rl_numeric_arg == 1 && rl_explicit_arg == 0)
+       rl_explicit_arg = 1;
+      rl_restore_prompt ();
+      rl_clear_message ();
+      RL_UNSETSTATE(RL_STATE_NUMERICARG);
+
+      r = _rl_dispatch (key, _rl_keymap);
+      if (RL_ISSTATE (RL_STATE_CALLBACK))
+       {
+         /* At worst, this will cause an extra redisplay.  Otherwise,
+            we have to wait until the next character comes in. */
+         if (rl_done == 0)
+           (*rl_redisplay_function) ();
+         r = 0;
+       }
+      return r;
+    }
+
+  return 1;
 }
 
-/* What to do when you abort reading an argument. */
-int
-rl_discard_argument ()
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+static int
+rl_digit_loop ()
 {
-  rl_ding ();
-  rl_clear_message ();
-  _rl_init_argument ();
-  return 0;
+  int c, r;
+
+  while (1)
+    {
+      if (_rl_arg_overflow ())
+       return 1;
+
+      c = _rl_arg_getchar ();
+
+      if (c < 0)
+       {
+         _rl_abort_internal ();
+         return -1;
+       }
+
+      r = _rl_arg_dispatch (_rl_argcxt, c);
+      if (r <= 0 || (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
+        break;
+    }
+
+  return r;
 }
 
 /* Create a default argument. */
-int
-_rl_init_argument ()
+void
+_rl_reset_argument ()
 {
   rl_numeric_arg = rl_arg_sign = 1;
   rl_explicit_arg = 0;
-  return 0;
+  _rl_argcxt = 0;
+}
+
+/* Start a numeric argument with initial value KEY */
+int
+rl_digit_argument (ignore, key)
+     int ignore, key;
+{
+  _rl_arg_init ();
+  if (RL_ISSTATE (RL_STATE_CALLBACK))
+    {
+      _rl_arg_dispatch (_rl_argcxt, key);
+      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
+      return 0;
+    }
+  else
+    {
+      rl_execute_next (key);
+      return (rl_digit_loop ());
+    }
 }
 
 /* C-u, universal argument.  Multiply the current argument by 4.
@@ -189,8 +255,43 @@ int
 rl_universal_argument (count, key)
      int count, key;
 {
+  _rl_arg_init ();
   rl_numeric_arg *= 4;
-  return (rl_digit_loop ());
+
+  return (RL_ISSTATE (RL_STATE_CALLBACK) ? 0 : rl_digit_loop ());
+}
+
+int
+_rl_arg_callback (cxt)
+     _rl_arg_cxt cxt;
+{
+  int c, r;
+
+  c = _rl_arg_getchar ();
+
+  if (_rl_argcxt & NUM_READONE)
+    {
+      _rl_argcxt &= ~NUM_READONE;
+      rl_restore_prompt ();
+      rl_clear_message ();
+      RL_UNSETSTATE(RL_STATE_NUMERICARG);
+      rl_execute_next (c);
+      return 0;
+    }
+
+  r = _rl_arg_dispatch (cxt, c);
+  return (r != 1);
+}
+
+/* What to do when you abort reading an argument. */
+int
+rl_discard_argument ()
+{
+  rl_ding ();
+  rl_clear_message ();
+  _rl_reset_argument ();
+
+  return 0;
 }
 
 /* **************************************************************** */
@@ -225,9 +326,11 @@ _rl_free_history_entry (entry)
 {
   if (entry == 0)
     return;
-  if (entry->line)
-    free (entry->line);
-  free (entry);
+
+  FREE (entry->line);
+  FREE (entry->timestamp);
+
+  xfree (entry);
 }
 
 /* Perhaps put back the current line if it has changed. */
@@ -241,8 +344,9 @@ rl_maybe_replace_line ()
   if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
     {
       temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
-      free (temp->line);
-      free (temp);
+      xfree (temp->line);
+      FREE (temp->timestamp);
+      xfree (temp);
     }
   return 0;
 }
@@ -274,6 +378,7 @@ rl_maybe_save_line ()
     {
       _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
       _rl_saved_line_for_history->line = savestring (rl_line_buffer);
+      _rl_saved_line_for_history->timestamp = (char *)NULL;
       _rl_saved_line_for_history->data = (char *)rl_undo_list;
     }
 
@@ -328,8 +433,89 @@ rl_replace_from_history (entry, flags)
       rl_mark = rl_end;
     }
 #endif
+}
+
+/* Process and free undo lists attached to each history entry prior to the
+   current entry, inclusive, reverting each line to its saved state.  This 
+   is destructive, and state about the current line is lost.  This is not
+   intended to be called while actively editing, and the current line is
+   not assumed to have been added to the history list. */
+void
+_rl_revert_all_lines ()
+{
+  int hpos;
+  HIST_ENTRY *entry;
+  UNDO_LIST *ul, *saved_undo_list;
+  char *lbuf;
+
+  lbuf = savestring (rl_line_buffer);
+  saved_undo_list = rl_undo_list;
+  hpos = where_history ();
+
+  entry = (hpos == history_length) ? previous_history () : current_history ();
+  while (entry)
+    {
+      if (ul = (UNDO_LIST *)entry->data)
+       {
+         if (ul == saved_undo_list)
+           saved_undo_list = 0;
+         /* Set up rl_line_buffer and other variables from history entry */
+         rl_replace_from_history (entry, 0);   /* entry->line is now current */
+         entry->data = 0;                      /* entry->data is now current undo list */
+         /* Undo all changes to this history entry */
+         while (rl_undo_list)
+           rl_do_undo ();
+         /* And copy the reverted line back to the history entry, preserving
+            the timestamp. */
+         FREE (entry->line);
+         entry->line = savestring (rl_line_buffer);
+       }
+      entry = previous_history ();
+    }
+
+  /* Restore history state */
+  rl_undo_list = saved_undo_list;      /* may have been set to null */
+  history_set_pos (hpos);
+  
+  /* reset the line buffer */
+  rl_replace_line (lbuf, 0);
+  _rl_set_the_line ();
+
+  /* and clean up */
+  xfree (lbuf);
 }  
 
+/* Free the history list, including private readline data and take care
+   of pointer aliases to history data.  Resets rl_undo_list if it points
+   to an UNDO_LIST * saved as some history entry's data member.  This
+   should not be called while editing is active. */
+void
+rl_clear_history ()
+{
+  HIST_ENTRY **hlist, *hent;
+  register int i;
+  UNDO_LIST *ul, *saved_undo_list;
+
+  saved_undo_list = rl_undo_list;
+  hlist = history_list ();             /* direct pointer, not copy */
+
+  for (i = 0; i < history_length; i++)
+    {
+      hent = hlist[i];
+      if (ul = (UNDO_LIST *)hent->data)
+       {
+         if (ul == saved_undo_list)
+           saved_undo_list = 0;
+         _rl_free_undo_list (ul);
+         hent->data = 0;
+       }
+      _rl_free_history_entry (hent);
+    }
+
+  history_offset = history_length = 0;
+  rl_undo_list = saved_undo_list;      /* should be NULL */
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     History Commands                            */
@@ -457,7 +643,7 @@ rl_vi_editing_mode (count, key)
 #if defined (VI_MODE)
   _rl_set_insert_mode (RL_IM_INSERT, 1);       /* vi mode ignores insert mode */
   rl_editing_mode = vi_mode;
-  rl_vi_insertion_mode (1, key);
+  rl_vi_insert_mode (1, key);
 #endif /* VI_MODE */
 
   return 0;
@@ -470,6 +656,10 @@ rl_emacs_editing_mode (count, key)
   rl_editing_mode = emacs_mode;
   _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
   _rl_keymap = emacs_standard_keymap;
+
+  if (_rl_show_mode_in_prompt)
+    _rl_reset_prompt ();
+
   return 0;
 }