655 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			655 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* misc.c -- miscellaneous bindable readline functions. */
 | 
						|
 | 
						|
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
 | 
						|
 | 
						|
   This file is part of the GNU Readline Library (Readline), a library
 | 
						|
   for reading lines of text with interactive input and history editing.      
 | 
						|
 | 
						|
   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.
 | 
						|
 | 
						|
   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.
 | 
						|
 | 
						|
   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)
 | 
						|
#  include <config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (HAVE_UNISTD_H)
 | 
						|
#  include <unistd.h>
 | 
						|
#endif /* HAVE_UNISTD_H */
 | 
						|
 | 
						|
#if defined (HAVE_STDLIB_H)
 | 
						|
#  include <stdlib.h>
 | 
						|
#else
 | 
						|
#  include "ansi_stdlib.h"
 | 
						|
#endif /* HAVE_STDLIB_H */
 | 
						|
 | 
						|
#if defined (HAVE_LOCALE_H)
 | 
						|
#  include <locale.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
/* System-specific feature definitions and include files. */
 | 
						|
#include "rldefs.h"
 | 
						|
#include "rlmbutil.h"
 | 
						|
 | 
						|
/* Some standard library routines. */
 | 
						|
#include "readline.h"
 | 
						|
#include "history.h"
 | 
						|
 | 
						|
#include "rlprivate.h"
 | 
						|
#include "rlshell.h"
 | 
						|
#include "xmalloc.h"
 | 
						|
 | 
						|
static int rl_digit_loop PARAMS((void));
 | 
						|
static void _rl_history_set_point PARAMS((void));
 | 
						|
 | 
						|
/* Forward declarations used in this file */
 | 
						|
void _rl_free_history_entry PARAMS((HIST_ENTRY *));
 | 
						|
 | 
						|
/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
 | 
						|
   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;
 | 
						|
 | 
						|
/* **************************************************************** */
 | 
						|
/*								    */
 | 
						|
/*			Numeric Arguments			    */
 | 
						|
/*								    */
 | 
						|
/* **************************************************************** */
 | 
						|
 | 
						|
int
 | 
						|
_rl_arg_overflow ()
 | 
						|
{
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_rl_arg_getchar ()
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
 | 
						|
  RL_SETSTATE(RL_STATE_MOREINPUT);
 | 
						|
  c = rl_read_key ();
 | 
						|
  RL_UNSETSTATE(RL_STATE_MOREINPUT);
 | 
						|
 | 
						|
  return c;
 | 
						|
}
 | 
						|
 | 
						|
/* 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 *= 4;
 | 
						|
	  return 1;
 | 
						|
	}
 | 
						|
      else if (RL_ISSTATE (RL_STATE_CALLBACK))
 | 
						|
        {
 | 
						|
          _rl_argcxt |= NUM_READONE;
 | 
						|
          return 0;	/* XXX */
 | 
						|
        }
 | 
						|
      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);
 | 
						|
	  if (key < 0)
 | 
						|
	    return -1;
 | 
						|
	  return (_rl_dispatch (key, _rl_keymap));
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  c = UNMETA (c);
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Handle C-u style numeric args, as well as M--, and M-digits. */
 | 
						|
static int
 | 
						|
rl_digit_loop ()
 | 
						|
{
 | 
						|
  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. */
 | 
						|
void
 | 
						|
_rl_reset_argument ()
 | 
						|
{
 | 
						|
  rl_numeric_arg = rl_arg_sign = 1;
 | 
						|
  rl_explicit_arg = 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.
 | 
						|
   Read a key.  If the key has nothing to do with arguments, then
 | 
						|
   dispatch on it.  If the key is the abort character then abort. */
 | 
						|
int
 | 
						|
rl_universal_argument (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  _rl_arg_init ();
 | 
						|
  rl_numeric_arg *= 4;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* **************************************************************** */
 | 
						|
/*								    */
 | 
						|
/*			History Utilities			    */
 | 
						|
/*								    */
 | 
						|
/* **************************************************************** */
 | 
						|
 | 
						|
/* We already have a history library, and that is what we use to control
 | 
						|
   the history features of readline.  This is our local interface to
 | 
						|
   the history mechanism. */
 | 
						|
 | 
						|
/* While we are editing the history, this is the saved
 | 
						|
   version of the original line. */
 | 
						|
HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
 | 
						|
 | 
						|
/* Set the history pointer back to the last entry in the history. */
 | 
						|
void
 | 
						|
_rl_start_using_history ()
 | 
						|
{
 | 
						|
  using_history ();
 | 
						|
  if (_rl_saved_line_for_history)
 | 
						|
    _rl_free_history_entry (_rl_saved_line_for_history);
 | 
						|
 | 
						|
  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* Free the contents (and containing structure) of a HIST_ENTRY. */
 | 
						|
void
 | 
						|
_rl_free_history_entry (entry)
 | 
						|
     HIST_ENTRY *entry;
 | 
						|
{
 | 
						|
  if (entry == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  FREE (entry->line);
 | 
						|
  FREE (entry->timestamp);
 | 
						|
 | 
						|
  free (entry);
 | 
						|
}
 | 
						|
 | 
						|
/* Perhaps put back the current line if it has changed. */
 | 
						|
int
 | 
						|
rl_maybe_replace_line ()
 | 
						|
{
 | 
						|
  HIST_ENTRY *temp;
 | 
						|
 | 
						|
  temp = current_history ();
 | 
						|
  /* If the current line has changed, save the changes. */
 | 
						|
  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->timestamp);
 | 
						|
      free (temp);
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Restore the _rl_saved_line_for_history if there is one. */
 | 
						|
int
 | 
						|
rl_maybe_unsave_line ()
 | 
						|
{
 | 
						|
  if (_rl_saved_line_for_history)
 | 
						|
    {
 | 
						|
      /* Can't call with `1' because rl_undo_list might point to an undo
 | 
						|
	 list from a history entry, as in rl_replace_from_history() below. */
 | 
						|
      rl_replace_line (_rl_saved_line_for_history->line, 0);
 | 
						|
      rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
 | 
						|
      _rl_free_history_entry (_rl_saved_line_for_history);
 | 
						|
      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
 | 
						|
      rl_point = rl_end;	/* rl_replace_line sets rl_end */
 | 
						|
    }
 | 
						|
  else
 | 
						|
    rl_ding ();
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Save the current line in _rl_saved_line_for_history. */
 | 
						|
int
 | 
						|
rl_maybe_save_line ()
 | 
						|
{
 | 
						|
  if (_rl_saved_line_for_history == 0)
 | 
						|
    {
 | 
						|
      _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;
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_rl_free_saved_history_line ()
 | 
						|
{
 | 
						|
  if (_rl_saved_line_for_history)
 | 
						|
    {
 | 
						|
      _rl_free_history_entry (_rl_saved_line_for_history);
 | 
						|
      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
_rl_history_set_point ()
 | 
						|
{
 | 
						|
  rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
 | 
						|
		? _rl_history_saved_point
 | 
						|
		: rl_end;
 | 
						|
  if (rl_point > rl_end)
 | 
						|
    rl_point = rl_end;
 | 
						|
 | 
						|
#if defined (VI_MODE)
 | 
						|
  if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
 | 
						|
    rl_point = 0;
 | 
						|
#endif /* VI_MODE */
 | 
						|
 | 
						|
  if (rl_editing_mode == emacs_mode)
 | 
						|
    rl_mark = (rl_point == rl_end ? 0 : rl_end);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
rl_replace_from_history (entry, flags)
 | 
						|
     HIST_ENTRY *entry;
 | 
						|
     int flags;			/* currently unused */
 | 
						|
{
 | 
						|
  /* Can't call with `1' because rl_undo_list might point to an undo list
 | 
						|
     from a history entry, just like we're setting up here. */
 | 
						|
  rl_replace_line (entry->line, 0);
 | 
						|
  rl_undo_list = (UNDO_LIST *)entry->data;
 | 
						|
  rl_point = rl_end;
 | 
						|
  rl_mark = 0;
 | 
						|
 | 
						|
#if defined (VI_MODE)
 | 
						|
  if (rl_editing_mode == vi_mode)
 | 
						|
    {
 | 
						|
      rl_point = 0;
 | 
						|
      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 */
 | 
						|
	  /* 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->data = 0;
 | 
						|
	}
 | 
						|
      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 */
 | 
						|
  free (lbuf);
 | 
						|
}  
 | 
						|
 | 
						|
/* **************************************************************** */
 | 
						|
/*								    */
 | 
						|
/*			History Commands			    */
 | 
						|
/*								    */
 | 
						|
/* **************************************************************** */
 | 
						|
 | 
						|
/* Meta-< goes to the start of the history. */
 | 
						|
int
 | 
						|
rl_beginning_of_history (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  return (rl_get_previous_history (1 + where_history (), key));
 | 
						|
}
 | 
						|
 | 
						|
/* Meta-> goes to the end of the history.  (The current line). */
 | 
						|
int
 | 
						|
rl_end_of_history (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  rl_maybe_replace_line ();
 | 
						|
  using_history ();
 | 
						|
  rl_maybe_unsave_line ();
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Move down to the next history line. */
 | 
						|
int
 | 
						|
rl_get_next_history (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  HIST_ENTRY *temp;
 | 
						|
 | 
						|
  if (count < 0)
 | 
						|
    return (rl_get_previous_history (-count, key));
 | 
						|
 | 
						|
  if (count == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  rl_maybe_replace_line ();
 | 
						|
 | 
						|
  /* either not saved by rl_newline or at end of line, so set appropriately. */
 | 
						|
  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
 | 
						|
    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
 | 
						|
 | 
						|
  temp = (HIST_ENTRY *)NULL;
 | 
						|
  while (count)
 | 
						|
    {
 | 
						|
      temp = next_history ();
 | 
						|
      if (!temp)
 | 
						|
	break;
 | 
						|
      --count;
 | 
						|
    }
 | 
						|
 | 
						|
  if (temp == 0)
 | 
						|
    rl_maybe_unsave_line ();
 | 
						|
  else
 | 
						|
    {
 | 
						|
      rl_replace_from_history (temp, 0);
 | 
						|
      _rl_history_set_point ();
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Get the previous item out of our interactive history, making it the current
 | 
						|
   line.  If there is no previous history, just ding. */
 | 
						|
int
 | 
						|
rl_get_previous_history (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  HIST_ENTRY *old_temp, *temp;
 | 
						|
 | 
						|
  if (count < 0)
 | 
						|
    return (rl_get_next_history (-count, key));
 | 
						|
 | 
						|
  if (count == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  /* either not saved by rl_newline or at end of line, so set appropriately. */
 | 
						|
  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
 | 
						|
    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
 | 
						|
 | 
						|
  /* If we don't have a line saved, then save this one. */
 | 
						|
  rl_maybe_save_line ();
 | 
						|
 | 
						|
  /* If the current line has changed, save the changes. */
 | 
						|
  rl_maybe_replace_line ();
 | 
						|
 | 
						|
  temp = old_temp = (HIST_ENTRY *)NULL;
 | 
						|
  while (count)
 | 
						|
    {
 | 
						|
      temp = previous_history ();
 | 
						|
      if (temp == 0)
 | 
						|
	break;
 | 
						|
 | 
						|
      old_temp = temp;
 | 
						|
      --count;
 | 
						|
    }
 | 
						|
 | 
						|
  /* If there was a large argument, and we moved back to the start of the
 | 
						|
     history, that is not an error.  So use the last value found. */
 | 
						|
  if (!temp && old_temp)
 | 
						|
    temp = old_temp;
 | 
						|
 | 
						|
  if (temp == 0)
 | 
						|
    rl_ding ();
 | 
						|
  else
 | 
						|
    {
 | 
						|
      rl_replace_from_history (temp, 0);
 | 
						|
      _rl_history_set_point ();
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* **************************************************************** */
 | 
						|
/*								    */
 | 
						|
/*			    Editing Modes			    */
 | 
						|
/*								    */
 | 
						|
/* **************************************************************** */
 | 
						|
/* How to toggle back and forth between editing modes. */
 | 
						|
int
 | 
						|
rl_vi_editing_mode (count, key)
 | 
						|
     int 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_insert_mode (1, key);
 | 
						|
#endif /* VI_MODE */
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rl_emacs_editing_mode (count, key)
 | 
						|
     int 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;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Function for the rest of the library to use to set insert/overwrite mode. */
 | 
						|
void
 | 
						|
_rl_set_insert_mode (im, force)
 | 
						|
     int im, force;
 | 
						|
{
 | 
						|
#ifdef CURSOR_MODE
 | 
						|
  _rl_set_cursor (im, force);
 | 
						|
#endif
 | 
						|
 | 
						|
  rl_insert_mode = im;
 | 
						|
}
 | 
						|
 | 
						|
/* Toggle overwrite mode.  A positive explicit argument selects overwrite
 | 
						|
   mode.  A negative or zero explicit argument selects insert mode. */
 | 
						|
int
 | 
						|
rl_overwrite_mode (count, key)
 | 
						|
     int count, key;
 | 
						|
{
 | 
						|
  if (rl_explicit_arg == 0)
 | 
						|
    _rl_set_insert_mode (rl_insert_mode ^ 1, 0);
 | 
						|
  else if (count > 0)
 | 
						|
    _rl_set_insert_mode (RL_IM_OVERWRITE, 0);
 | 
						|
  else
 | 
						|
    _rl_set_insert_mode (RL_IM_INSERT, 0);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 |