2087 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2087 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* readline.c -- a general facility for reading lines of input
 | ||
|    with emacs style editing and completion. */
 | ||
| 
 | ||
| /* Copyright (C) 1987, 1989, 1992 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.
 | ||
| 
 | ||
|    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 1, 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
 | ||
|    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,
 | ||
|    675 Mass Ave, Cambridge, MA 02139, USA. */
 | ||
| #define READLINE_LIBRARY
 | ||
| 
 | ||
| #if defined (HAVE_CONFIG_H)
 | ||
| #  include <config.h>
 | ||
| #endif
 | ||
| 
 | ||
| #include <sys/types.h>
 | ||
| #include "posixstat.h"
 | ||
| #include <fcntl.h>
 | ||
| #if defined (HAVE_SYS_FILE_H)
 | ||
| #  include <sys/file.h>
 | ||
| #endif /* HAVE_SYS_FILE_H */
 | ||
| 
 | ||
| #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 <signal.h>
 | ||
| #include <stdio.h>
 | ||
| #include "posixjmp.h"
 | ||
| 
 | ||
| /* System-specific feature definitions and include files. */
 | ||
| #include "rldefs.h"
 | ||
| 
 | ||
| #if defined (__EMX__)
 | ||
| #  define INCL_DOSPROCESS
 | ||
| #  include <os2.h>
 | ||
| #endif /* __EMX__ */
 | ||
| 
 | ||
| /* Some standard library routines. */
 | ||
| #include "readline.h"
 | ||
| #include "history.h"
 | ||
| 
 | ||
| #ifndef RL_LIBRARY_VERSION
 | ||
| #  define RL_LIBRARY_VERSION "2.1-bash"
 | ||
| #endif
 | ||
| 
 | ||
| /* Evaluates its arguments multiple times. */
 | ||
| #define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
 | ||
| 
 | ||
| /* NOTE: Functions and variables prefixed with `_rl_' are
 | ||
|    pseudo-global: they are global so they can be shared
 | ||
|    between files in the readline library, but are not intended
 | ||
|    to be visible to readline callers. */
 | ||
| 
 | ||
| /* Variables and functions imported from terminal.c */
 | ||
| extern int _rl_init_terminal_io ();
 | ||
| extern void _rl_enable_meta_key ();
 | ||
| extern int _rl_output_character_function ();
 | ||
| extern void _rl_get_screen_size ();
 | ||
| 
 | ||
| extern int _rl_enable_meta;
 | ||
| extern int _rl_term_autowrap;
 | ||
| extern int screenwidth, screenheight, screenchars;
 | ||
| 
 | ||
| /* Variables and functions imported from rltty.c. */
 | ||
| extern void rl_prep_terminal (), rl_deprep_terminal ();
 | ||
| extern void rltty_set_default_bindings ();
 | ||
| 
 | ||
| /* Functions imported from util.c. */
 | ||
| extern void _rl_abort_internal ();
 | ||
| extern void rl_extend_line_buffer ();
 | ||
| extern int alphabetic ();
 | ||
| 
 | ||
| /* Functions imported from bind.c. */
 | ||
| extern void _rl_bind_if_unbound ();
 | ||
| extern int rl_set_keymap_from_edit_mode ();
 | ||
| 
 | ||
| /* Functions imported from input.c. */
 | ||
| extern int _rl_any_typein ();
 | ||
| extern void _rl_insert_typein ();
 | ||
| extern int rl_read_key ();
 | ||
| 
 | ||
| /* Functions imported from nls.c */
 | ||
| extern int _rl_init_eightbit ();
 | ||
| 
 | ||
| /* Functions imported from shell.c */
 | ||
| extern char *get_env_value ();
 | ||
| 
 | ||
| /* External redisplay functions and variables from display.c */
 | ||
| extern void _rl_move_vert ();
 | ||
| extern void _rl_update_final ();
 | ||
| extern void _rl_clear_to_eol ();
 | ||
| extern void _rl_clear_screen ();
 | ||
| 
 | ||
| extern void _rl_save_prompt ();
 | ||
| extern void _rl_restore_prompt ();
 | ||
| 
 | ||
| extern void _rl_erase_at_end_of_line ();
 | ||
| extern void _rl_move_cursor_relative ();
 | ||
| 
 | ||
| extern int _rl_vis_botlin;
 | ||
| extern int _rl_last_c_pos;
 | ||
| extern int _rl_horizontal_scroll_mode;
 | ||
| extern int rl_display_fixed;
 | ||
| extern int _rl_suppress_redisplay;
 | ||
| extern char *rl_display_prompt;
 | ||
| 
 | ||
| /* Variables imported from complete.c. */
 | ||
| extern char *rl_completer_word_break_characters;
 | ||
| extern char *rl_basic_word_break_characters;
 | ||
| extern int rl_completion_query_items;
 | ||
| extern int rl_complete_with_tilde_expansion;
 | ||
| 
 | ||
| /* Variables and functions from macro.c. */
 | ||
| extern void _rl_add_macro_char ();
 | ||
| extern void _rl_with_macro_input ();
 | ||
| extern int _rl_next_macro_key ();
 | ||
| extern int _rl_defining_kbd_macro;
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
| /* Functions imported from vi_mode.c. */
 | ||
| extern void _rl_vi_set_last ();
 | ||
| extern void _rl_vi_reset_last ();
 | ||
| extern void _rl_vi_done_inserting ();
 | ||
| extern int _rl_vi_textmod_command ();
 | ||
| extern void _rl_vi_initialize_line ();
 | ||
| #endif /* VI_MODE */
 | ||
| 
 | ||
| extern UNDO_LIST *rl_undo_list;
 | ||
| extern int _rl_doing_an_undo;
 | ||
| 
 | ||
| /* Forward declarations used in this file. */
 | ||
| void _rl_free_history_entry ();
 | ||
| 
 | ||
| int _rl_dispatch ();
 | ||
| int _rl_init_argument ();
 | ||
| 
 | ||
| static char *readline_internal ();
 | ||
| static void readline_initialize_everything ();
 | ||
| static void start_using_history ();
 | ||
| static void bind_arrow_keys ();
 | ||
| 
 | ||
| #if !defined (__GO32__)
 | ||
| static void readline_default_bindings ();
 | ||
| #endif /* !__GO32__ */
 | ||
| 
 | ||
| #if defined (__GO32__)
 | ||
| #  include <go32.h>
 | ||
| #  include <pc.h>
 | ||
| #  undef HANDLE_SIGNALS
 | ||
| #endif /* __GO32__ */
 | ||
| 
 | ||
| extern char *xmalloc (), *xrealloc ();
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Line editing input utility		    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| char *rl_library_version = RL_LIBRARY_VERSION;
 | ||
| 
 | ||
| /* A pointer to the keymap that is currently in use.
 | ||
|    By default, it is the standard emacs keymap. */
 | ||
| Keymap _rl_keymap = emacs_standard_keymap;
 | ||
| 
 | ||
| /* The current style of editing. */
 | ||
| int rl_editing_mode = emacs_mode;
 | ||
| 
 | ||
| /* Non-zero if we called this function from _rl_dispatch().  It's present
 | ||
|    so functions can find out whether they were called from a key binding
 | ||
|    or directly from an application. */
 | ||
| int rl_dispatching;
 | ||
| 
 | ||
| /* Non-zero if the previous command was a kill command. */
 | ||
| int _rl_last_command_was_kill = 0;
 | ||
| 
 | ||
| /* The current value of the numeric argument specified by the user. */
 | ||
| int rl_numeric_arg = 1;
 | ||
| 
 | ||
| /* Non-zero if an argument was typed. */
 | ||
| int rl_explicit_arg = 0;
 | ||
| 
 | ||
| /* Temporary value used while generating the argument. */
 | ||
| int rl_arg_sign = 1;
 | ||
| 
 | ||
| /* Non-zero means we have been called at least once before. */
 | ||
| static int rl_initialized;
 | ||
| 
 | ||
| /* If non-zero, this program is running in an EMACS buffer. */
 | ||
| static int running_in_emacs;
 | ||
| 
 | ||
| /* The current offset in the current input line. */
 | ||
| int rl_point;
 | ||
| 
 | ||
| /* Mark in the current input line. */
 | ||
| int rl_mark;
 | ||
| 
 | ||
| /* Length of the current input line. */
 | ||
| int rl_end;
 | ||
| 
 | ||
| /* Make this non-zero to return the current input_line. */
 | ||
| int rl_done;
 | ||
| 
 | ||
| /* The last function executed by readline. */
 | ||
| Function *rl_last_func = (Function *)NULL;
 | ||
| 
 | ||
| /* Top level environment for readline_internal (). */
 | ||
| procenv_t readline_top_level;
 | ||
| 
 | ||
| /* The streams we interact with. */
 | ||
| FILE *_rl_in_stream, *_rl_out_stream;
 | ||
| 
 | ||
| /* The names of the streams that we do input and output to. */
 | ||
| FILE *rl_instream = (FILE *)NULL;
 | ||
| FILE *rl_outstream = (FILE *)NULL;
 | ||
| 
 | ||
| /* Non-zero means echo characters as they are read. */
 | ||
| int readline_echoing_p = 1;
 | ||
| 
 | ||
| /* Current prompt. */
 | ||
| char *rl_prompt;
 | ||
| int rl_visible_prompt_length = 0;
 | ||
| 
 | ||
| /* The number of characters read in order to type this complete command. */
 | ||
| int rl_key_sequence_length = 0;
 | ||
| 
 | ||
| /* If non-zero, then this is the address of a function to call just
 | ||
|    before readline_internal () prints the first prompt. */
 | ||
| Function *rl_startup_hook = (Function *)NULL;
 | ||
| 
 | ||
| /* What we use internally.  You should always refer to RL_LINE_BUFFER. */
 | ||
| static char *the_line;
 | ||
| 
 | ||
| /* The character that can generate an EOF.  Really read from
 | ||
|    the terminal driver... just defaulted here. */
 | ||
| int _rl_eof_char = CTRL ('D');
 | ||
| 
 | ||
| /* Non-zero makes this the next keystroke to read. */
 | ||
| int rl_pending_input = 0;
 | ||
| 
 | ||
| /* Pointer to a useful terminal name. */
 | ||
| char *rl_terminal_name = (char *)NULL;
 | ||
| 
 | ||
| /* Non-zero means to always use horizontal scrolling in line display. */
 | ||
| int _rl_horizontal_scroll_mode = 0;
 | ||
| 
 | ||
| /* Non-zero means to display an asterisk at the starts of history lines
 | ||
|    which have been modified. */
 | ||
| int _rl_mark_modified_lines = 0;  
 | ||
| 
 | ||
| /* The style of `bell' notification preferred.  This can be set to NO_BELL,
 | ||
|    AUDIBLE_BELL, or VISIBLE_BELL. */
 | ||
| int _rl_bell_preference = AUDIBLE_BELL;
 | ||
|      
 | ||
| /* String inserted into the line by rl_insert_comment (). */
 | ||
| char *_rl_comment_begin;
 | ||
| 
 | ||
| /* Keymap holding the function currently being executed. */
 | ||
| Keymap rl_executing_keymap;
 | ||
| 
 | ||
| /* Line buffer and maintenence. */
 | ||
| char *rl_line_buffer = (char *)NULL;
 | ||
| int rl_line_buffer_len = 0;
 | ||
| 
 | ||
| /* Forward declarations used by the display and termcap code. */
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			`Forward' declarations  		    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Non-zero means do not parse any lines other than comments and
 | ||
|    parser directives. */
 | ||
| unsigned char _rl_parsing_conditionalized_out = 0;
 | ||
| 
 | ||
| /* Non-zero means to convert characters with the meta bit set to
 | ||
|    escape-prefixed characters so we can indirect through
 | ||
|    emacs_meta_keymap or vi_escape_keymap. */
 | ||
| int _rl_convert_meta_chars_to_ascii = 1;
 | ||
| 
 | ||
| /* Non-zero means to output characters with the meta bit set directly
 | ||
|    rather than as a meta-prefixed escape sequence. */
 | ||
| int _rl_output_meta_chars = 0;
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Top Level Functions			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Non-zero means treat 0200 bit in terminal input as Meta bit. */
 | ||
| int _rl_meta_flag = 0;	/* Forward declaration */
 | ||
| 
 | ||
| /* Read a line of input.  Prompt with PROMPT.  An empty PROMPT means
 | ||
|    none.  A return value of NULL means that EOF was encountered. */
 | ||
| char *
 | ||
| readline (prompt)
 | ||
|      char *prompt;
 | ||
| {
 | ||
|   char *value;
 | ||
| 
 | ||
|   rl_prompt = prompt;
 | ||
| 
 | ||
|   /* If we are at EOF return a NULL string. */
 | ||
|   if (rl_pending_input == EOF)
 | ||
|     {
 | ||
|       rl_pending_input = 0;
 | ||
|       return ((char *)NULL);
 | ||
|     }
 | ||
| 
 | ||
|   rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
 | ||
| 
 | ||
|   rl_initialize ();
 | ||
|   (*rl_prep_term_function) (_rl_meta_flag);
 | ||
| 
 | ||
| #if defined (HANDLE_SIGNALS)
 | ||
|   rl_set_signals ();
 | ||
| #endif
 | ||
| 
 | ||
|   value = readline_internal ();
 | ||
|   (*rl_deprep_term_function) ();
 | ||
| 
 | ||
| #if defined (HANDLE_SIGNALS)
 | ||
|   rl_clear_signals ();
 | ||
| #endif
 | ||
| 
 | ||
|   return (value);
 | ||
| }
 | ||
| 
 | ||
| #if defined (READLINE_CALLBACKS)
 | ||
| #  define STATIC_CALLBACK
 | ||
| #else
 | ||
| #  define STATIC_CALLBACK static
 | ||
| #endif
 | ||
| 
 | ||
| STATIC_CALLBACK void
 | ||
| readline_internal_setup ()
 | ||
| {
 | ||
|   _rl_in_stream = rl_instream;
 | ||
|   _rl_out_stream = rl_outstream;
 | ||
| 
 | ||
|   if (rl_startup_hook)
 | ||
|     (*rl_startup_hook) ();
 | ||
| 
 | ||
|   if (readline_echoing_p == 0)
 | ||
|     {
 | ||
|       if (rl_prompt)
 | ||
| 	{
 | ||
| 	  fprintf (_rl_out_stream, "%s", rl_prompt);
 | ||
| 	  fflush (_rl_out_stream);
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       rl_on_new_line ();
 | ||
|       (*rl_redisplay_function) ();
 | ||
| #if defined (VI_MODE)
 | ||
|       if (rl_editing_mode == vi_mode)
 | ||
| 	rl_vi_insertion_mode (1, 0);
 | ||
| #endif /* VI_MODE */
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| STATIC_CALLBACK char *
 | ||
| readline_internal_teardown (eof)
 | ||
|      int eof;
 | ||
| {
 | ||
|   char *temp;
 | ||
|   HIST_ENTRY *entry;
 | ||
| 
 | ||
|   /* Restore the original of this history line, iff the line that we
 | ||
|      are editing was originally in the history, AND the line has changed. */
 | ||
|   entry = current_history ();
 | ||
| 
 | ||
|   if (entry && rl_undo_list)
 | ||
|     {
 | ||
|       temp = savestring (the_line);
 | ||
|       rl_revert_line (1, 0);
 | ||
|       entry = replace_history_entry (where_history (), the_line, (HIST_ENTRY *)NULL);
 | ||
|       _rl_free_history_entry (entry);
 | ||
| 
 | ||
|       strcpy (the_line, temp);
 | ||
|       free (temp);
 | ||
|     }
 | ||
| 
 | ||
|   /* At any rate, it is highly likely that this line has an undo list.  Get
 | ||
|      rid of it now. */
 | ||
|   if (rl_undo_list)
 | ||
|     free_undo_list ();
 | ||
| 
 | ||
|   return (eof ? (char *)NULL : savestring (the_line));
 | ||
| }
 | ||
| 
 | ||
| STATIC_CALLBACK int
 | ||
| #if defined (READLINE_CALLBACKS)
 | ||
| readline_internal_char ()
 | ||
| #else
 | ||
| readline_internal_charloop ()
 | ||
| #endif
 | ||
| {
 | ||
|   static int lastc, eof_found;
 | ||
|   int c, code, lk;
 | ||
| 
 | ||
|   lastc = -1;
 | ||
|   eof_found = 0;
 | ||
| 
 | ||
| #if !defined (READLINE_CALLBACKS)
 | ||
|   while (rl_done == 0)
 | ||
|     {
 | ||
| #endif
 | ||
|       lk = _rl_last_command_was_kill;
 | ||
| 
 | ||
|       code = setjmp (readline_top_level);
 | ||
| 
 | ||
|       if (code)
 | ||
| 	(*rl_redisplay_function) ();
 | ||
| 
 | ||
|       if (rl_pending_input == 0)
 | ||
| 	{
 | ||
| 	  /* Then initialize the argument and number of keys read. */
 | ||
| 	  _rl_init_argument ();
 | ||
| 	  rl_key_sequence_length = 0;
 | ||
| 	}
 | ||
| 
 | ||
|       c = rl_read_key ();
 | ||
| 
 | ||
|       /* EOF typed to a non-blank line is a <NL>. */
 | ||
|       if (c == EOF && rl_end)
 | ||
| 	c = NEWLINE;
 | ||
| 
 | ||
|       /* The character _rl_eof_char typed to blank line, and not as the
 | ||
| 	 previous character is interpreted as EOF. */
 | ||
|       if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
 | ||
| 	{
 | ||
| #if defined (READLINE_CALLBACKS)
 | ||
| 	  return (rl_done = 1);
 | ||
| #else
 | ||
| 	  eof_found = 1;
 | ||
| 	  break;
 | ||
| #endif
 | ||
| 	}
 | ||
| 
 | ||
|       lastc = c;
 | ||
|       _rl_dispatch (c, _rl_keymap);
 | ||
| 
 | ||
|       /* If there was no change in _rl_last_command_was_kill, then no kill
 | ||
| 	 has taken place.  Note that if input is pending we are reading
 | ||
| 	 a prefix command, so nothing has changed yet. */
 | ||
|       if (rl_pending_input == 0 && lk == _rl_last_command_was_kill)
 | ||
| 	_rl_last_command_was_kill = 0;
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
|       /* In vi mode, when you exit insert mode, the cursor moves back
 | ||
| 	 over the previous character.  We explicitly check for that here. */
 | ||
|       if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
 | ||
| 	rl_vi_check ();
 | ||
| #endif /* VI_MODE */
 | ||
| 
 | ||
|       if (rl_done == 0)
 | ||
| 	(*rl_redisplay_function) ();
 | ||
| 
 | ||
| #if defined (READLINE_CALLBACKS)
 | ||
|       return 0;
 | ||
| #else
 | ||
|     }
 | ||
| 
 | ||
|   return (eof_found);
 | ||
| #endif
 | ||
| }
 | ||
| 
 | ||
| #if defined (READLINE_CALLBACKS)
 | ||
| static int
 | ||
| readline_internal_charloop ()
 | ||
| {
 | ||
|   int eof;
 | ||
| 
 | ||
|   while (rl_done == 0)
 | ||
|     eof = readline_internal_char ();
 | ||
|   return (eof);
 | ||
| }
 | ||
| #endif /* READLINE_CALLBACKS */
 | ||
| 
 | ||
| /* Read a line of input from the global rl_instream, doing output on
 | ||
|    the global rl_outstream.
 | ||
|    If rl_prompt is non-null, then that is our prompt. */
 | ||
| static char *
 | ||
| readline_internal ()
 | ||
| {
 | ||
|   int eof;
 | ||
| 
 | ||
|   readline_internal_setup ();
 | ||
|   eof = readline_internal_charloop ();
 | ||
|   return (readline_internal_teardown (eof));
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| _rl_init_line_state ()
 | ||
| {
 | ||
|   rl_point = rl_end = 0;
 | ||
|   the_line = rl_line_buffer;
 | ||
|   the_line[0] = 0;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| _rl_set_the_line ()
 | ||
| {
 | ||
|   the_line = rl_line_buffer;
 | ||
| }
 | ||
| 
 | ||
| /* Do the command associated with KEY in MAP.
 | ||
|    If the associated command is really a keymap, then read
 | ||
|    another key, and dispatch into that map. */
 | ||
| int
 | ||
| _rl_dispatch (key, map)
 | ||
|      register int key;
 | ||
|      Keymap map;
 | ||
| {
 | ||
|   int r, newkey;
 | ||
|   char *macro;
 | ||
|   Function *func;
 | ||
| 
 | ||
|   if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
 | ||
|     {
 | ||
|       if (map[ESC].type == ISKMAP)
 | ||
| 	{
 | ||
| 	  if (_rl_defining_kbd_macro)
 | ||
| 	    _rl_add_macro_char (ESC);
 | ||
| 	  map = FUNCTION_TO_KEYMAP (map, ESC);
 | ||
| 	  key = UNMETA (key);
 | ||
| 	  rl_key_sequence_length += 2;
 | ||
| 	  return (_rl_dispatch (key, map));
 | ||
| 	}
 | ||
|       else
 | ||
| 	ding ();
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   if (_rl_defining_kbd_macro)
 | ||
|     _rl_add_macro_char (key);
 | ||
| 
 | ||
|   r = 0;
 | ||
|   switch (map[key].type)
 | ||
|     {
 | ||
|     case ISFUNC:
 | ||
|       func = map[key].function;
 | ||
|       if (func != (Function *)NULL)
 | ||
| 	{
 | ||
| 	  /* Special case rl_do_lowercase_version (). */
 | ||
| 	  if (func == rl_do_lowercase_version)
 | ||
| 	    return (_rl_dispatch (_rl_to_lower (key), map));
 | ||
| 
 | ||
| 	  rl_executing_keymap = map;
 | ||
| 
 | ||
| #if 0
 | ||
| 	  _rl_suppress_redisplay = (map[key].function == rl_insert) && _rl_input_available ();
 | ||
| #endif
 | ||
| 
 | ||
| 	  rl_dispatching = 1;
 | ||
| 	  r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key);
 | ||
| 	  rl_dispatching = 0;
 | ||
| 
 | ||
| 	  /* If we have input pending, then the last command was a prefix
 | ||
| 	     command.  Don't change the state of rl_last_func.  Otherwise,
 | ||
| 	     remember the last command executed in this variable. */
 | ||
| 	  if (!rl_pending_input && map[key].function != rl_digit_argument)
 | ||
| 	    rl_last_func = map[key].function;
 | ||
| 	}
 | ||
|       else
 | ||
| 	{
 | ||
| 	  _rl_abort_internal ();
 | ||
| 	  return -1;
 | ||
| 	}
 | ||
|       break;
 | ||
| 
 | ||
|     case ISKMAP:
 | ||
|       if (map[key].function != (Function *)NULL)
 | ||
| 	{
 | ||
| 	  rl_key_sequence_length++;
 | ||
| 	  newkey = rl_read_key ();
 | ||
| 	  r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key));
 | ||
| 	}
 | ||
|       else
 | ||
| 	{
 | ||
| 	  _rl_abort_internal ();
 | ||
| 	  return -1;
 | ||
| 	}
 | ||
|       break;
 | ||
| 
 | ||
|     case ISMACR:
 | ||
|       if (map[key].function != (Function *)NULL)
 | ||
| 	{
 | ||
| 	  macro = savestring ((char *)map[key].function);
 | ||
| 	  _rl_with_macro_input (macro);
 | ||
| 	  return 0;
 | ||
| 	}
 | ||
|       break;
 | ||
|     }
 | ||
| #if defined (VI_MODE)
 | ||
|   if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
 | ||
|       _rl_vi_textmod_command (key))
 | ||
|     _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
 | ||
| #endif
 | ||
|   return (r);
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Initializations 			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Initialize readline (and terminal if not already). */
 | ||
| int
 | ||
| rl_initialize ()
 | ||
| {
 | ||
|   /* If we have never been called before, initialize the
 | ||
|      terminal and data structures. */
 | ||
|   if (!rl_initialized)
 | ||
|     {
 | ||
|       readline_initialize_everything ();
 | ||
|       rl_initialized++;
 | ||
|     }
 | ||
| 
 | ||
|   /* Initalize the current line information. */
 | ||
|   _rl_init_line_state ();
 | ||
| 
 | ||
|   /* We aren't done yet.  We haven't even gotten started yet! */
 | ||
|   rl_done = 0;
 | ||
| 
 | ||
|   /* Tell the history routines what is going on. */
 | ||
|   start_using_history ();
 | ||
| 
 | ||
|   /* Make the display buffer match the state of the line. */
 | ||
|   rl_reset_line_state ();
 | ||
| 
 | ||
|   /* No such function typed yet. */
 | ||
|   rl_last_func = (Function *)NULL;
 | ||
| 
 | ||
|   /* Parsing of key-bindings begins in an enabled state. */
 | ||
|   _rl_parsing_conditionalized_out = 0;
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
|   if (rl_editing_mode == vi_mode)
 | ||
|     _rl_vi_initialize_line ();
 | ||
| #endif
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| #if defined (__EMX__)
 | ||
| static void
 | ||
| _emx_build_environ ()
 | ||
| {
 | ||
|   TIB *tibp;
 | ||
|   PIB *pibp;
 | ||
|   char *t, **tp;
 | ||
|   int c;
 | ||
| 
 | ||
|   DosGetInfoBlocks (&tibp, &pibp);
 | ||
|   t = pibp->pib_pchenv;
 | ||
|   for (c = 1; *t; c++)
 | ||
|     t += strlen (t) + 1;
 | ||
|   tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *));
 | ||
|   t = pibp->pib_pchenv;
 | ||
|   while (*t)
 | ||
|     {
 | ||
|       *tp++ = t;
 | ||
|       t += strlen (t) + 1;
 | ||
|     }
 | ||
|   *tp = 0;
 | ||
| }
 | ||
| #endif /* __EMX__ */
 | ||
| 
 | ||
| /* Initialize the entire state of the world. */
 | ||
| static void
 | ||
| readline_initialize_everything ()
 | ||
| {
 | ||
| #if defined (__EMX__)
 | ||
|   if (environ == 0)
 | ||
|     _emx_build_environ ();
 | ||
| #endif
 | ||
| 
 | ||
|   /* Find out if we are running in Emacs. */
 | ||
|   running_in_emacs = get_env_value ("EMACS") != (char *)0;
 | ||
| 
 | ||
|   /* Set up input and output if they are not already set up. */
 | ||
|   if (!rl_instream)
 | ||
|     rl_instream = stdin;
 | ||
| 
 | ||
|   if (!rl_outstream)
 | ||
|     rl_outstream = stdout;
 | ||
| 
 | ||
|   /* Bind _rl_in_stream and _rl_out_stream immediately.  These values
 | ||
|      may change, but they may also be used before readline_internal ()
 | ||
|      is called. */
 | ||
|   _rl_in_stream = rl_instream;
 | ||
|   _rl_out_stream = rl_outstream;
 | ||
| 
 | ||
|   /* Allocate data structures. */
 | ||
|   if (rl_line_buffer == 0)
 | ||
|     rl_line_buffer = xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
 | ||
| 
 | ||
|   /* Initialize the terminal interface. */
 | ||
|   _rl_init_terminal_io ((char *)NULL);
 | ||
| 
 | ||
| #if !defined (__GO32__)
 | ||
|   /* Bind tty characters to readline functions. */
 | ||
|   readline_default_bindings ();
 | ||
| #endif /* !__GO32__ */
 | ||
| 
 | ||
|   /* Initialize the function names. */
 | ||
|   rl_initialize_funmap ();
 | ||
| 
 | ||
|   /* Decide whether we should automatically go into eight-bit mode. */
 | ||
|   _rl_init_eightbit ();
 | ||
|       
 | ||
|   /* Read in the init file. */
 | ||
|   rl_read_init_file ((char *)NULL);
 | ||
| 
 | ||
|   /* XXX */
 | ||
|   if (_rl_horizontal_scroll_mode && _rl_term_autowrap)
 | ||
|     {
 | ||
|       screenwidth--;
 | ||
|       screenchars -= screenheight;
 | ||
|     }
 | ||
| 
 | ||
|   /* Override the effect of any `set keymap' assignments in the
 | ||
|      inputrc file. */
 | ||
|   rl_set_keymap_from_edit_mode ();
 | ||
| 
 | ||
|   /* Try to bind a common arrow key prefix, if not already bound. */
 | ||
|   bind_arrow_keys ();
 | ||
| 
 | ||
|   /* Enable the meta key, if this terminal has one. */
 | ||
|   if (_rl_enable_meta)
 | ||
|     _rl_enable_meta_key ();
 | ||
| 
 | ||
|   /* If the completion parser's default word break characters haven't
 | ||
|      been set yet, then do so now. */
 | ||
|   if (rl_completer_word_break_characters == (char *)NULL)
 | ||
|     rl_completer_word_break_characters = rl_basic_word_break_characters;
 | ||
| }
 | ||
| 
 | ||
| /* If this system allows us to look at the values of the regular
 | ||
|    input editing characters, then bind them to their readline
 | ||
|    equivalents, iff the characters are not bound to keymaps. */
 | ||
| static void
 | ||
| readline_default_bindings ()
 | ||
| {
 | ||
|   rltty_set_default_bindings (_rl_keymap);
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| bind_arrow_keys_internal ()
 | ||
| {
 | ||
|   Function *f;
 | ||
| 
 | ||
|   f = rl_function_of_keyseq ("\033[A", _rl_keymap, (int *)NULL);
 | ||
|   if (!f || f == rl_do_lowercase_version)
 | ||
|     {
 | ||
|       _rl_bind_if_unbound ("\033[A", rl_get_previous_history);
 | ||
|       _rl_bind_if_unbound ("\033[B", rl_get_next_history);
 | ||
|       _rl_bind_if_unbound ("\033[C", rl_forward);
 | ||
|       _rl_bind_if_unbound ("\033[D", rl_backward);
 | ||
|     }
 | ||
| 
 | ||
|   f = rl_function_of_keyseq ("\033OA", _rl_keymap, (int *)NULL);
 | ||
|   if (!f || f == rl_do_lowercase_version)
 | ||
|     {
 | ||
|       _rl_bind_if_unbound ("\033OA", rl_get_previous_history);
 | ||
|       _rl_bind_if_unbound ("\033OB", rl_get_next_history);
 | ||
|       _rl_bind_if_unbound ("\033OC", rl_forward);
 | ||
|       _rl_bind_if_unbound ("\033OD", rl_backward);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /* Try and bind the common arrow key prefix after giving termcap and
 | ||
|    the inputrc file a chance to bind them and create `real' keymaps
 | ||
|    for the arrow key prefix. */
 | ||
| static void
 | ||
| bind_arrow_keys ()
 | ||
| {
 | ||
|   Keymap xkeymap;
 | ||
| 
 | ||
|   xkeymap = _rl_keymap;
 | ||
| 
 | ||
|   _rl_keymap = emacs_standard_keymap;
 | ||
|   bind_arrow_keys_internal ();
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
|   _rl_keymap = vi_movement_keymap;
 | ||
|   bind_arrow_keys_internal ();
 | ||
| #endif
 | ||
| 
 | ||
|   _rl_keymap = xkeymap;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Numeric Arguments			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Handle C-u style numeric args, as well as M--, and M-digits. */
 | ||
| static int
 | ||
| rl_digit_loop ()
 | ||
| {
 | ||
|   int key, c, sawminus, sawdigits;
 | ||
| 
 | ||
|   _rl_save_prompt ();
 | ||
| 
 | ||
|   sawminus = sawdigits = 0;
 | ||
|   while (1)
 | ||
|     {
 | ||
|       rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
 | ||
|       key = c = rl_read_key ();
 | ||
| 
 | ||
|       /* 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
 | ||
| 	    {
 | ||
| 	      key = rl_read_key ();
 | ||
| 	      _rl_restore_prompt ();
 | ||
| 	      rl_clear_message ();
 | ||
| 	      return (_rl_dispatch (key, _rl_keymap));
 | ||
| 	    }
 | ||
| 	}
 | ||
| 
 | ||
|       c = UNMETA (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)
 | ||
| 	{
 | ||
| 	  rl_numeric_arg = sawminus = 1;
 | ||
| 	  rl_arg_sign = -1;
 | ||
| 	}
 | ||
|       else
 | ||
| 	{
 | ||
| 	  /* Make M-- command equivalent to M--1 command. */
 | ||
| 	  if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
 | ||
| 	    rl_explicit_arg = 1;
 | ||
| 	  _rl_restore_prompt ();
 | ||
| 	  rl_clear_message ();
 | ||
| 	  return (_rl_dispatch (key, _rl_keymap));
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Add the current digit to the argument in progress. */
 | ||
| int
 | ||
| rl_digit_argument (ignore, key)
 | ||
|      int ignore, key;
 | ||
| {
 | ||
|   rl_pending_input = key;
 | ||
|   return (rl_digit_loop ());
 | ||
| }
 | ||
| 
 | ||
| /* What to do when you abort reading an argument. */
 | ||
| int
 | ||
| rl_discard_argument ()
 | ||
| {
 | ||
|   ding ();
 | ||
|   rl_clear_message ();
 | ||
|   _rl_init_argument ();
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Create a default argument. */
 | ||
| int
 | ||
| _rl_init_argument ()
 | ||
| {
 | ||
|   rl_numeric_arg = rl_arg_sign = 1;
 | ||
|   rl_explicit_arg = 0;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* 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_numeric_arg *= 4;
 | ||
|   return (rl_digit_loop ());
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Insert and Delete			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Insert a string of text into the line at point.  This is the only
 | ||
|    way that you should do insertion.  rl_insert () calls this
 | ||
|    function. */
 | ||
| int
 | ||
| rl_insert_text (string)
 | ||
|      char *string;
 | ||
| {
 | ||
|   register int i, l = strlen (string);
 | ||
| 
 | ||
|   if (rl_end + l >= rl_line_buffer_len)
 | ||
|     rl_extend_line_buffer (rl_end + l);
 | ||
| 
 | ||
|   for (i = rl_end; i >= rl_point; i--)
 | ||
|     the_line[i + l] = the_line[i];
 | ||
|   strncpy (the_line + rl_point, string, l);
 | ||
| 
 | ||
|   /* Remember how to undo this if we aren't undoing something. */
 | ||
|   if (!_rl_doing_an_undo)
 | ||
|     {
 | ||
|       /* If possible and desirable, concatenate the undos. */
 | ||
|       if ((l == 1) &&
 | ||
| 	  rl_undo_list &&
 | ||
| 	  (rl_undo_list->what == UNDO_INSERT) &&
 | ||
| 	  (rl_undo_list->end == rl_point) &&
 | ||
| 	  (rl_undo_list->end - rl_undo_list->start < 20))
 | ||
| 	rl_undo_list->end++;
 | ||
|       else
 | ||
| 	rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
 | ||
|     }
 | ||
|   rl_point += l;
 | ||
|   rl_end += l;
 | ||
|   the_line[rl_end] = '\0';
 | ||
|   return l;
 | ||
| }
 | ||
| 
 | ||
| /* Delete the string between FROM and TO.  FROM is
 | ||
|    inclusive, TO is not. */
 | ||
| int
 | ||
| rl_delete_text (from, to)
 | ||
|      int from, to;
 | ||
| {
 | ||
|   register char *text;
 | ||
|   register int diff, i;
 | ||
| 
 | ||
|   /* Fix it if the caller is confused. */
 | ||
|   if (from > to)
 | ||
|     SWAP (from, to);
 | ||
| 
 | ||
|   /* fix boundaries */
 | ||
|   if (to > rl_end)
 | ||
|     {
 | ||
|       to = rl_end;
 | ||
|       if (from > to)
 | ||
|         from = to;
 | ||
|     }
 | ||
| 
 | ||
|   text = rl_copy_text (from, to);
 | ||
| 
 | ||
|   /* Some versions of strncpy() can't handle overlapping arguments. */
 | ||
|   diff = to - from;
 | ||
|   for (i = from; i < rl_end - diff; i++)
 | ||
|     the_line[i] = the_line[i + diff];
 | ||
| 
 | ||
|   /* Remember how to undo this delete. */
 | ||
|   if (_rl_doing_an_undo == 0)
 | ||
|     rl_add_undo (UNDO_DELETE, from, to, text);
 | ||
|   else
 | ||
|     free (text);
 | ||
| 
 | ||
|   rl_end -= diff;
 | ||
|   the_line[rl_end] = '\0';
 | ||
|   return (diff);
 | ||
| }
 | ||
| 
 | ||
| /* Fix up point so that it is within the line boundaries after killing
 | ||
|    text.  If FIX_MARK_TOO is non-zero, the mark is forced within line
 | ||
|    boundaries also. */
 | ||
| 
 | ||
| #define _RL_FIX_POINT(x) \
 | ||
| 	do { \
 | ||
| 	if (x > rl_end) \
 | ||
| 	  x = rl_end; \
 | ||
| 	else if (x < 0) \
 | ||
| 	  x = 0; \
 | ||
| 	} while (0)
 | ||
| 
 | ||
| void
 | ||
| _rl_fix_point (fix_mark_too)
 | ||
|      int fix_mark_too;
 | ||
| {
 | ||
|   _RL_FIX_POINT (rl_point);
 | ||
|   if (fix_mark_too)
 | ||
|     _RL_FIX_POINT (rl_mark);
 | ||
| }
 | ||
| #undef _RL_FIX_POINT
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Readline character functions		    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* This is not a gap editor, just a stupid line input routine.  No hair
 | ||
|    is involved in writing any of the functions, and none should be. */
 | ||
| 
 | ||
| /* Note that:
 | ||
| 
 | ||
|    rl_end is the place in the string that we would place '\0';
 | ||
|    i.e., it is always safe to place '\0' there.
 | ||
| 
 | ||
|    rl_point is the place in the string where the cursor is.  Sometimes
 | ||
|    this is the same as rl_end.
 | ||
| 
 | ||
|    Any command that is called interactively receives two arguments.
 | ||
|    The first is a count: the numeric arg pased to this command.
 | ||
|    The second is the key which invoked this command.
 | ||
| */
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Movement Commands			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Note that if you `optimize' the display for these functions, you cannot
 | ||
|    use said functions in other functions which do not do optimizing display.
 | ||
|    I.e., you will have to update the data base for rl_redisplay, and you
 | ||
|    might as well let rl_redisplay do that job. */
 | ||
| 
 | ||
| /* Move forward COUNT characters. */
 | ||
| int
 | ||
| rl_forward (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (count < 0)
 | ||
|     rl_backward (-count, key);
 | ||
|   else if (count > 0)
 | ||
|     {
 | ||
|       int end = rl_point + count;
 | ||
| #if defined (VI_MODE)
 | ||
|       int lend = rl_end - (rl_editing_mode == vi_mode);
 | ||
| #else
 | ||
|       int lend = rl_end;
 | ||
| #endif
 | ||
| 
 | ||
|       if (end > lend)
 | ||
| 	{
 | ||
| 	  rl_point = lend;
 | ||
| 	  ding ();
 | ||
| 	}
 | ||
|       else
 | ||
| 	rl_point = end;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Move backward COUNT characters. */
 | ||
| int
 | ||
| rl_backward (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (count < 0)
 | ||
|     rl_forward (-count, key);
 | ||
|   else if (count > 0)
 | ||
|     {
 | ||
|       if (rl_point < count)
 | ||
| 	{
 | ||
| 	  rl_point = 0;
 | ||
| 	  ding ();
 | ||
| 	}
 | ||
|       else
 | ||
|         rl_point -= count;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Move to the beginning of the line. */
 | ||
| int
 | ||
| rl_beg_of_line (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   rl_point = 0;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Move to the end of the line. */
 | ||
| int
 | ||
| rl_end_of_line (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   rl_point = rl_end;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Move forward a word.  We do what Emacs does. */
 | ||
| int
 | ||
| rl_forward_word (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   int c;
 | ||
| 
 | ||
|   if (count < 0)
 | ||
|     {
 | ||
|       rl_backward_word (-count, key);
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   while (count)
 | ||
|     {
 | ||
|       if (rl_point == rl_end)
 | ||
| 	return 0;
 | ||
| 
 | ||
|       /* 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 = the_line[rl_point];
 | ||
|       if (alphabetic (c) == 0)
 | ||
| 	{
 | ||
| 	  while (++rl_point < rl_end)
 | ||
| 	    {
 | ||
| 	      c = the_line[rl_point];
 | ||
| 	      if (alphabetic (c))
 | ||
| 		break;
 | ||
| 	    }
 | ||
| 	}
 | ||
|       if (rl_point == rl_end)
 | ||
| 	return 0;
 | ||
|       while (++rl_point < rl_end)
 | ||
| 	{
 | ||
| 	  c = the_line[rl_point];
 | ||
| 	  if (alphabetic (c) == 0)
 | ||
| 	    break;
 | ||
| 	}
 | ||
|       --count;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Move backward a word.  We do what Emacs does. */
 | ||
| int
 | ||
| rl_backward_word (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   int c;
 | ||
| 
 | ||
|   if (count < 0)
 | ||
|     {
 | ||
|       rl_forward_word (-count, key);
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   while (count)
 | ||
|     {
 | ||
|       if (!rl_point)
 | ||
| 	return 0;
 | ||
| 
 | ||
|       /* Like rl_forward_word (), except that we look at the characters
 | ||
| 	 just before point. */
 | ||
| 
 | ||
|       c = the_line[rl_point - 1];
 | ||
|       if (alphabetic (c) == 0)
 | ||
| 	{
 | ||
| 	  while (--rl_point)
 | ||
| 	    {
 | ||
| 	      c = the_line[rl_point - 1];
 | ||
| 	      if (alphabetic (c))
 | ||
| 		break;
 | ||
| 	    }
 | ||
| 	}
 | ||
| 
 | ||
|       while (rl_point)
 | ||
| 	{
 | ||
| 	  c = the_line[rl_point - 1];
 | ||
| 	  if (alphabetic (c) == 0)
 | ||
| 	    break;
 | ||
| 	  else
 | ||
| 	    --rl_point;
 | ||
| 	}
 | ||
|       --count;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Clear the current line.  Numeric argument to C-l does this. */
 | ||
| int
 | ||
| rl_refresh_line ()
 | ||
| {
 | ||
|   int curr_line, nleft;
 | ||
| 
 | ||
|   /* Find out whether or not there might be invisible characters in the
 | ||
|      editing buffer. */
 | ||
|   if (rl_display_prompt == rl_prompt)
 | ||
|     nleft = _rl_last_c_pos - screenwidth - rl_visible_prompt_length;
 | ||
|   else
 | ||
|     nleft = _rl_last_c_pos - screenwidth;
 | ||
| 
 | ||
|   if (nleft > 0)
 | ||
|     curr_line = 1 + nleft / screenwidth;
 | ||
|   else
 | ||
|     curr_line = 0;
 | ||
| 
 | ||
|   _rl_move_vert (curr_line);
 | ||
|   _rl_move_cursor_relative (0, the_line);   /* XXX is this right */
 | ||
| 
 | ||
| #if defined (__GO32__)
 | ||
|   {
 | ||
|     int row, col, width, row_start;
 | ||
| 
 | ||
|     ScreenGetCursor (&row, &col);
 | ||
|     width = ScreenCols ();
 | ||
|     row_start = ScreenPrimary + (row * width);
 | ||
|     memset (row_start + col, 0, (width - col) * 2);
 | ||
|   }
 | ||
| #else /* !__GO32__ */
 | ||
|   _rl_clear_to_eol (0);		/* arg of 0 means to not use spaces */
 | ||
| #endif /* !__GO32__ */
 | ||
| 
 | ||
|   rl_forced_update_display ();
 | ||
|   rl_display_fixed = 1;
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* C-l typed to a line without quoting clears the screen, and then reprints
 | ||
|    the prompt and the current input line.  Given a numeric arg, redraw only
 | ||
|    the current line. */
 | ||
| int
 | ||
| rl_clear_screen (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (rl_explicit_arg)
 | ||
|     {
 | ||
|       rl_refresh_line ();
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   _rl_clear_screen ();		/* calls termcap function to clear screen */
 | ||
|   rl_forced_update_display ();
 | ||
|   rl_display_fixed = 1;
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| rl_arrow_keys (count, c)
 | ||
|      int count, c;
 | ||
| {
 | ||
|   int ch;
 | ||
| 
 | ||
|   ch = rl_read_key ();
 | ||
| 
 | ||
|   switch (_rl_to_upper (ch))
 | ||
|     {
 | ||
|     case 'A':
 | ||
|       rl_get_previous_history (count, ch);
 | ||
|       break;
 | ||
| 
 | ||
|     case 'B':
 | ||
|       rl_get_next_history (count, ch);
 | ||
|       break;
 | ||
| 
 | ||
|     case 'C':
 | ||
|       rl_forward (count, ch);
 | ||
|       break;
 | ||
| 
 | ||
|     case 'D':
 | ||
|       rl_backward (count, ch);
 | ||
|       break;
 | ||
| 
 | ||
|     default:
 | ||
|       ding ();
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Text commands				    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Insert the character C at the current location, moving point forward. */
 | ||
| int
 | ||
| rl_insert (count, c)
 | ||
|      int count, c;
 | ||
| {
 | ||
|   register int i;
 | ||
|   char *string;
 | ||
| 
 | ||
|   if (count <= 0)
 | ||
|     return 0;
 | ||
| 
 | ||
|   /* If we can optimize, then do it.  But don't let people crash
 | ||
|      readline because of extra large arguments. */
 | ||
|   if (count > 1 && count <= 1024)
 | ||
|     {
 | ||
|       string = xmalloc (1 + count);
 | ||
| 
 | ||
|       for (i = 0; i < count; i++)
 | ||
| 	string[i] = c;
 | ||
| 
 | ||
|       string[i] = '\0';
 | ||
|       rl_insert_text (string);
 | ||
|       free (string);
 | ||
| 
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   if (count > 1024)
 | ||
|     {
 | ||
|       int decreaser;
 | ||
|       char str[1024+1];
 | ||
| 
 | ||
|       for (i = 0; i < 1024; i++)
 | ||
| 	str[i] = c;
 | ||
| 
 | ||
|       while (count)
 | ||
| 	{
 | ||
| 	  decreaser = (count > 1024 ? 1024 : count);
 | ||
| 	  str[decreaser] = '\0';
 | ||
| 	  rl_insert_text (str);
 | ||
| 	  count -= decreaser;
 | ||
| 	}
 | ||
| 
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   /* 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
 | ||
|      them all. */
 | ||
|   if (_rl_any_typein ())
 | ||
|     _rl_insert_typein (c);
 | ||
|   else
 | ||
|     {
 | ||
|       /* Inserting a single character. */
 | ||
|       char str[2];
 | ||
| 
 | ||
|       str[1] = '\0';
 | ||
|       str[0] = c;
 | ||
|       rl_insert_text (str);
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Insert the next typed character verbatim. */
 | ||
| int
 | ||
| rl_quoted_insert (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   int c;
 | ||
| 
 | ||
|   c = rl_read_key ();
 | ||
|   return (rl_insert (count, c));  
 | ||
| }
 | ||
| 
 | ||
| /* Insert a tab character. */
 | ||
| int
 | ||
| rl_tab_insert (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (rl_insert (count, '\t'));
 | ||
| }
 | ||
| 
 | ||
| /* What to do when a NEWLINE is pressed.  We accept the whole line.
 | ||
|    KEY is the key that invoked this command.  I guess it could have
 | ||
|    meaning in the future. */
 | ||
| int
 | ||
| rl_newline (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   rl_done = 1;
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
|   if (rl_editing_mode == vi_mode)
 | ||
|     {
 | ||
|       _rl_vi_done_inserting ();
 | ||
|       _rl_vi_reset_last ();
 | ||
|     }
 | ||
| #endif /* VI_MODE */
 | ||
| 
 | ||
|   if (readline_echoing_p)
 | ||
|     _rl_update_final ();
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* What to do for some uppercase characters, like meta characters,
 | ||
|    and some characters appearing in emacs_ctlx_keymap.  This function
 | ||
|    is just a stub, you bind keys to it and the code in _rl_dispatch ()
 | ||
|    is special cased. */
 | ||
| int
 | ||
| rl_do_lowercase_version (ignore1, ignore2)
 | ||
|      int ignore1, ignore2;
 | ||
| {
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Rubout the character behind point. */
 | ||
| int
 | ||
| rl_rubout (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (count < 0)
 | ||
|     {
 | ||
|       rl_delete (-count, key);
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   if (!rl_point)
 | ||
|     {
 | ||
|       ding ();
 | ||
|       return -1;
 | ||
|     }
 | ||
| 
 | ||
|   if (count > 1 || rl_explicit_arg)
 | ||
|     {
 | ||
|       int orig_point = rl_point;
 | ||
|       rl_backward (count, key);
 | ||
|       rl_kill_text (orig_point, rl_point);
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       int c = the_line[--rl_point];
 | ||
|       rl_delete_text (rl_point, rl_point + 1);
 | ||
| 
 | ||
|       if (rl_point == rl_end && isprint (c) && _rl_last_c_pos)
 | ||
| 	{
 | ||
| 	  int l;
 | ||
| 	  l = rl_character_len (c, rl_point);
 | ||
| 	  _rl_erase_at_end_of_line (l);
 | ||
| 	}
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Delete the character under the cursor.  Given a numeric argument,
 | ||
|    kill that many characters instead. */
 | ||
| int
 | ||
| rl_delete (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (count < 0)
 | ||
|     return (rl_rubout (-count, key));
 | ||
| 
 | ||
|   if (rl_point == rl_end)
 | ||
|     {
 | ||
|       ding ();
 | ||
|       return -1;
 | ||
|     }
 | ||
| 
 | ||
|   if (count > 1 || rl_explicit_arg)
 | ||
|     {
 | ||
|       int orig_point = rl_point;
 | ||
|       rl_forward (count, key);
 | ||
|       rl_kill_text (orig_point, rl_point);
 | ||
|       rl_point = orig_point;
 | ||
|       return 0;
 | ||
|     }
 | ||
|   else
 | ||
|     return (rl_delete_text (rl_point, rl_point + 1));
 | ||
|   
 | ||
| }
 | ||
| 
 | ||
| /* Delete all spaces and tabs around point. */
 | ||
| int
 | ||
| rl_delete_horizontal_space (count, ignore)
 | ||
|      int count, ignore;
 | ||
| {
 | ||
|   int start = rl_point;
 | ||
| 
 | ||
|   while (rl_point && whitespace (the_line[rl_point - 1]))
 | ||
|     rl_point--;
 | ||
| 
 | ||
|   start = rl_point;
 | ||
| 
 | ||
|   while (rl_point < rl_end && whitespace (the_line[rl_point]))
 | ||
|     rl_point++;
 | ||
| 
 | ||
|   if (start != rl_point)
 | ||
|     {
 | ||
|       rl_delete_text (start, rl_point);
 | ||
|       rl_point = start;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| #ifndef RL_COMMENT_BEGIN_DEFAULT
 | ||
| #define RL_COMMENT_BEGIN_DEFAULT "#"
 | ||
| #endif
 | ||
| 
 | ||
| /* Turn the current line into a comment in shell history.
 | ||
|    A K*rn shell style function. */
 | ||
| int
 | ||
| rl_insert_comment (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   rl_beg_of_line (1, key);
 | ||
|   rl_insert_text (_rl_comment_begin ? _rl_comment_begin
 | ||
| 				    : RL_COMMENT_BEGIN_DEFAULT);
 | ||
|   (*rl_redisplay_function) ();
 | ||
|   rl_newline (1, '\n');
 | ||
|   return (0);
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Changing Case				    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* The three kinds of things that we know how to do. */
 | ||
| #define UpCase 1
 | ||
| #define DownCase 2
 | ||
| #define CapCase 3
 | ||
| 
 | ||
| static int rl_change_case ();
 | ||
| 
 | ||
| /* Uppercase the word at point. */
 | ||
| int
 | ||
| rl_upcase_word (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (rl_change_case (count, UpCase));
 | ||
| }
 | ||
| 
 | ||
| /* Lowercase the word at point. */
 | ||
| int
 | ||
| rl_downcase_word (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (rl_change_case (count, DownCase));
 | ||
| }
 | ||
| 
 | ||
| /* Upcase the first letter, downcase the rest. */
 | ||
| int
 | ||
| rl_capitalize_word (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|  return (rl_change_case (count, CapCase));
 | ||
| }
 | ||
| 
 | ||
| /* The meaty function.
 | ||
|    Change the case of COUNT words, performing OP on them.
 | ||
|    OP is one of UpCase, DownCase, or CapCase.
 | ||
|    If a negative argument is given, leave point where it started,
 | ||
|    otherwise, leave it where it moves to. */
 | ||
| static int
 | ||
| rl_change_case (count, op)
 | ||
|      int count, op;
 | ||
| {
 | ||
|   register int start, end;
 | ||
|   int inword, c;
 | ||
| 
 | ||
|   start = rl_point;
 | ||
|   rl_forward_word (count, 0);
 | ||
|   end = rl_point;
 | ||
| 
 | ||
|   if (count < 0)
 | ||
|     SWAP (start, end);
 | ||
| 
 | ||
|   /* We are going to modify some text, so let's prepare to undo it. */
 | ||
|   rl_modifying (start, end);
 | ||
| 
 | ||
|   for (inword = 0; start < end; start++)
 | ||
|     {
 | ||
|       c = the_line[start];
 | ||
|       switch (op)
 | ||
| 	{
 | ||
| 	case UpCase:
 | ||
| 	  the_line[start] = _rl_to_upper (c);
 | ||
| 	  break;
 | ||
| 
 | ||
| 	case DownCase:
 | ||
| 	  the_line[start] = _rl_to_lower (c);
 | ||
| 	  break;
 | ||
| 
 | ||
| 	case CapCase:
 | ||
| 	  the_line[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c);
 | ||
| 	  inword = alphabetic (the_line[start]);
 | ||
| 	  break;
 | ||
| 
 | ||
| 	default:
 | ||
| 	  ding ();
 | ||
| 	  return -1;
 | ||
| 	}
 | ||
|     }
 | ||
|   rl_point = end;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Transposition				    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Transpose the words at point. */
 | ||
| int
 | ||
| rl_transpose_words (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   char *word1, *word2;
 | ||
|   int w1_beg, w1_end, w2_beg, w2_end;
 | ||
|   int orig_point = rl_point;
 | ||
| 
 | ||
|   if (!count)
 | ||
|     return 0;
 | ||
| 
 | ||
|   /* Find the two words. */
 | ||
|   rl_forward_word (count, key);
 | ||
|   w2_end = rl_point;
 | ||
|   rl_backward_word (1, key);
 | ||
|   w2_beg = rl_point;
 | ||
|   rl_backward_word (count, key);
 | ||
|   w1_beg = rl_point;
 | ||
|   rl_forward_word (1, key);
 | ||
|   w1_end = rl_point;
 | ||
| 
 | ||
|   /* Do some check to make sure that there really are two words. */
 | ||
|   if ((w1_beg == w2_beg) || (w2_beg < w1_end))
 | ||
|     {
 | ||
|       ding ();
 | ||
|       rl_point = orig_point;
 | ||
|       return -1;
 | ||
|     }
 | ||
| 
 | ||
|   /* Get the text of the words. */
 | ||
|   word1 = rl_copy_text (w1_beg, w1_end);
 | ||
|   word2 = rl_copy_text (w2_beg, w2_end);
 | ||
| 
 | ||
|   /* We are about to do many insertions and deletions.  Remember them
 | ||
|      as one operation. */
 | ||
|   rl_begin_undo_group ();
 | ||
| 
 | ||
|   /* Do the stuff at word2 first, so that we don't have to worry
 | ||
|      about word1 moving. */
 | ||
|   rl_point = w2_beg;
 | ||
|   rl_delete_text (w2_beg, w2_end);
 | ||
|   rl_insert_text (word1);
 | ||
| 
 | ||
|   rl_point = w1_beg;
 | ||
|   rl_delete_text (w1_beg, w1_end);
 | ||
|   rl_insert_text (word2);
 | ||
| 
 | ||
|   /* This is exactly correct since the text before this point has not
 | ||
|      changed in length. */
 | ||
|   rl_point = w2_end;
 | ||
| 
 | ||
|   /* I think that does it. */
 | ||
|   rl_end_undo_group ();
 | ||
|   free (word1);
 | ||
|   free (word2);
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Transpose the characters at point.  If point is at the end of the line,
 | ||
|    then transpose the characters before point. */
 | ||
| int
 | ||
| rl_transpose_chars (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   char dummy[2];
 | ||
| 
 | ||
|   if (!count)
 | ||
|     return 0;
 | ||
| 
 | ||
|   if (!rl_point || rl_end < 2)
 | ||
|     {
 | ||
|       ding ();
 | ||
|       return -1;
 | ||
|     }
 | ||
| 
 | ||
|   rl_begin_undo_group ();
 | ||
| 
 | ||
|   if (rl_point == rl_end)
 | ||
|     {
 | ||
|       --rl_point;
 | ||
|       count = 1;
 | ||
|     }
 | ||
|   rl_point--;
 | ||
| 
 | ||
|   dummy[0] = the_line[rl_point];
 | ||
|   dummy[1] = '\0';
 | ||
| 
 | ||
|   rl_delete_text (rl_point, rl_point + 1);
 | ||
| 
 | ||
|   rl_point += count;
 | ||
|   _rl_fix_point (0);
 | ||
|   rl_insert_text (dummy);
 | ||
| 
 | ||
|   rl_end_undo_group ();
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			Character Searching			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| int
 | ||
| _rl_char_search_internal (count, dir, schar)
 | ||
|      int count, dir, schar;
 | ||
| {
 | ||
|   int pos, inc;
 | ||
| 
 | ||
|   pos = rl_point;
 | ||
|   inc = (dir < 0) ? -1 : 1;
 | ||
|   while (count)
 | ||
|     {
 | ||
|       if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
 | ||
| 	{
 | ||
| 	  ding ();
 | ||
| 	  return -1;
 | ||
| 	}
 | ||
| 
 | ||
|       pos += inc;
 | ||
|       do
 | ||
| 	{
 | ||
| 	  if (rl_line_buffer[pos] == schar)
 | ||
| 	    {
 | ||
| 	      count--;
 | ||
| 	      if (dir < 0)
 | ||
| 	        rl_point = (dir == BTO) ? pos + 1 : pos;
 | ||
| 	      else
 | ||
| 		rl_point = (dir == FTO) ? pos - 1 : pos;
 | ||
| 	      break;
 | ||
| 	    }
 | ||
| 	}
 | ||
|       while ((dir < 0) ? pos-- : ++pos < rl_end);
 | ||
|     }
 | ||
|   return (0);
 | ||
| }
 | ||
| 
 | ||
| /* Search COUNT times for a character read from the current input stream.
 | ||
|    FDIR is the direction to search if COUNT is non-negative; otherwise
 | ||
|    the search goes in BDIR. */
 | ||
| static int
 | ||
| _rl_char_search (count, fdir, bdir)
 | ||
|      int count, fdir, bdir;
 | ||
| {
 | ||
|   int c;
 | ||
| 
 | ||
|   c = rl_read_key ();
 | ||
|   if (count < 0)
 | ||
|     return (_rl_char_search_internal (-count, bdir, c));
 | ||
|   else
 | ||
|     return (_rl_char_search_internal (count, fdir, c));
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| rl_char_search (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (_rl_char_search (count, FFIND, BFIND));
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| rl_backward_char_search (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (_rl_char_search (count, BFIND, FFIND));
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			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 *saved_line_for_history = (HIST_ENTRY *)NULL;
 | ||
| 
 | ||
| /* Set the history pointer back to the last entry in the history. */
 | ||
| static void
 | ||
| start_using_history ()
 | ||
| {
 | ||
|   using_history ();
 | ||
|   if (saved_line_for_history)
 | ||
|     _rl_free_history_entry (saved_line_for_history);
 | ||
| 
 | ||
|   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;
 | ||
|   if (entry->line)
 | ||
|     free (entry->line);
 | ||
|   free (entry);
 | ||
| }
 | ||
| 
 | ||
| /* Perhaps put back the current line if it has changed. */
 | ||
| int
 | ||
| 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 (), the_line, rl_undo_list);
 | ||
|       free (temp->line);
 | ||
|       free (temp);
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Put back the saved_line_for_history if there is one. */
 | ||
| int
 | ||
| maybe_unsave_line ()
 | ||
| {
 | ||
|   int line_len;
 | ||
| 
 | ||
|   if (saved_line_for_history)
 | ||
|     {
 | ||
|       line_len = strlen (saved_line_for_history->line);
 | ||
| 
 | ||
|       if (line_len >= rl_line_buffer_len)
 | ||
| 	rl_extend_line_buffer (line_len);
 | ||
| 
 | ||
|       strcpy (the_line, saved_line_for_history->line);
 | ||
|       rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
 | ||
|       _rl_free_history_entry (saved_line_for_history);
 | ||
|       saved_line_for_history = (HIST_ENTRY *)NULL;
 | ||
|       rl_end = rl_point = strlen (the_line);
 | ||
|     }
 | ||
|   else
 | ||
|     ding ();
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* Save the current line in saved_line_for_history. */
 | ||
| int
 | ||
| maybe_save_line ()
 | ||
| {
 | ||
|   if (saved_line_for_history == 0)
 | ||
|     {
 | ||
|       saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
 | ||
|       saved_line_for_history->line = savestring (the_line);
 | ||
|       saved_line_for_history->data = (char *)rl_undo_list;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*			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;
 | ||
| {
 | ||
|   maybe_replace_line ();
 | ||
|   using_history ();
 | ||
|   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;
 | ||
|   int line_len;
 | ||
| 
 | ||
|   if (count < 0)
 | ||
|     return (rl_get_previous_history (-count, key));
 | ||
| 
 | ||
|   if (count == 0)
 | ||
|     return 0;
 | ||
| 
 | ||
|   maybe_replace_line ();
 | ||
| 
 | ||
|   temp = (HIST_ENTRY *)NULL;
 | ||
|   while (count)
 | ||
|     {
 | ||
|       temp = next_history ();
 | ||
|       if (!temp)
 | ||
| 	break;
 | ||
|       --count;
 | ||
|     }
 | ||
| 
 | ||
|   if (temp == 0)
 | ||
|     maybe_unsave_line ();
 | ||
|   else
 | ||
|     {
 | ||
|       line_len = strlen (temp->line);
 | ||
| 
 | ||
|       if (line_len >= rl_line_buffer_len)
 | ||
| 	rl_extend_line_buffer (line_len);
 | ||
| 
 | ||
|       strcpy (the_line, temp->line);
 | ||
|       rl_undo_list = (UNDO_LIST *)temp->data;
 | ||
|       rl_end = rl_point = strlen (the_line);
 | ||
| #if defined (VI_MODE)
 | ||
|       if (rl_editing_mode == vi_mode)
 | ||
| 	rl_point = 0;
 | ||
| #endif /* VI_MODE */
 | ||
|     }
 | ||
|   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;
 | ||
|   int line_len;
 | ||
| 
 | ||
|   if (count < 0)
 | ||
|     return (rl_get_next_history (-count, key));
 | ||
| 
 | ||
|   if (count == 0)
 | ||
|     return 0;
 | ||
| 
 | ||
|   /* If we don't have a line saved, then save this one. */
 | ||
|   maybe_save_line ();
 | ||
| 
 | ||
|   /* If the current line has changed, save the changes. */
 | ||
|   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)
 | ||
|     ding ();
 | ||
|   else
 | ||
|     {
 | ||
|       line_len = strlen (temp->line);
 | ||
| 
 | ||
|       if (line_len >= rl_line_buffer_len)
 | ||
| 	rl_extend_line_buffer (line_len);
 | ||
| 
 | ||
|       strcpy (the_line, temp->line);
 | ||
|       rl_undo_list = (UNDO_LIST *)temp->data;
 | ||
|       rl_end = rl_point = line_len;
 | ||
| 
 | ||
| #if defined (VI_MODE)
 | ||
|       if (rl_editing_mode == vi_mode)
 | ||
| 	rl_point = 0;
 | ||
| #endif /* VI_MODE */
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* **************************************************************** */
 | ||
| /*								    */
 | ||
| /*		   The Mark and the Region.			    */
 | ||
| /*								    */
 | ||
| /* **************************************************************** */
 | ||
| 
 | ||
| /* Set the mark at POSITION. */
 | ||
| int
 | ||
| _rl_set_mark_at_pos (position)
 | ||
|      int position;
 | ||
| {
 | ||
|   if (position > rl_end)
 | ||
|     return -1;
 | ||
| 
 | ||
|   rl_mark = position;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| /* A bindable command to set the mark. */
 | ||
| int
 | ||
| rl_set_mark (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
 | ||
| }
 | ||
| 
 | ||
| /* Exchange the position of mark and point. */
 | ||
| int
 | ||
| rl_exchange_point_and_mark (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   if (rl_mark > rl_end)
 | ||
|     rl_mark = -1;
 | ||
| 
 | ||
|   if (rl_mark == -1)
 | ||
|     {
 | ||
|       ding ();
 | ||
|       return -1;
 | ||
|     }
 | ||
|   else
 | ||
|     SWAP (rl_point, rl_mark);
 | ||
| 
 | ||
|   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_editing_mode = vi_mode;
 | ||
|   rl_vi_insertion_mode (1, key);
 | ||
| #endif /* VI_MODE */
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| rl_emacs_editing_mode (count, key)
 | ||
|      int count, key;
 | ||
| {
 | ||
|   rl_editing_mode = emacs_mode;
 | ||
|   _rl_keymap = emacs_standard_keymap;
 | ||
|   return 0;
 | ||
| }
 | 
