X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=readline%2Freadline.c;h=071e1aa082e1ea13748e3beb57366c6dd6287a68;hb=8b8c7c9f49992750f66f81b4601d593a3858d98c;hp=2c6aef68f48ff7e74a97c581568a4a81bc3bd17b;hpb=1b17e766659d93d1e7bd6633bf78132e1abb3568;p=deliverable%2Fbinutils-gdb.git diff --git a/readline/readline.c b/readline/readline.c index 2c6aef68f4..071e1aa082 100644 --- a/readline/readline.c +++ b/readline/readline.c @@ -1,25 +1,25 @@ /* 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. +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) @@ -49,9 +49,15 @@ #include #include "posixjmp.h" +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ /* System-specific feature definitions and include files. */ #include "rldefs.h" +#include "rlmbutil.h" #if defined (__EMX__) # define INCL_DOSPROCESS @@ -67,22 +73,27 @@ #include "xmalloc.h" #ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "4.1" +# define RL_LIBRARY_VERSION "5.1" +#endif + +#ifndef RL_READLINE_VERSION +# define RL_READLINE_VERSION 0x0501 #endif -/* Evaluates its arguments multiple times. */ -#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); /* Forward declarations used in this file. */ -void _rl_free_history_entry __P((HIST_ENTRY *)); +static char *readline_internal PARAMS((void)); +static void readline_initialize_everything PARAMS((void)); + +static void bind_arrow_keys_internal PARAMS((Keymap)); +static void bind_arrow_keys PARAMS((void)); -static char *readline_internal __P((void)); -static void readline_initialize_everything __P((void)); -static void start_using_history __P((void)); -static void bind_arrow_keys __P((void)); -static int rl_change_case __P((int, int)); +static void readline_default_bindings PARAMS((void)); +static void reset_default_bindings PARAMS((void)); -static void readline_default_bindings __P((void)); +static int _rl_subseq_result PARAMS((int, Keymap, int, int)); +static int _rl_subseq_getchar PARAMS((int)); /* **************************************************************** */ /* */ @@ -90,17 +101,24 @@ static void readline_default_bindings __P((void)); /* */ /* **************************************************************** */ -char *rl_library_version = RL_LIBRARY_VERSION; +const char *rl_library_version = RL_LIBRARY_VERSION; +int rl_readline_version = RL_READLINE_VERSION; + +/* True if this is `real' readline as opposed to some stub substitute. */ int rl_gnu_readline_p = 1; /* 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; +/* The current insert mode: input (the default) or overwrite */ +int rl_insert_mode = RL_IM_DEFAULT; + /* 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. */ @@ -121,8 +139,13 @@ int rl_arg_sign = 1; /* Non-zero means we have been called at least once before. */ static int rl_initialized; +#if 0 /* If non-zero, this program is running in an EMACS buffer. */ static int running_in_emacs; +#endif + +/* Flags word encapsulating the current readline state. */ +int rl_readline_state = RL_STATE_NONE; /* The current offset in the current input line. */ int rl_point; @@ -137,10 +160,10 @@ int rl_end; int rl_done; /* The last function executed by readline. */ -Function *rl_last_func = (Function *)NULL; +rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; /* Top level environment for readline_internal (). */ -procenv_t readline_top_level; +procenv_t _rl_top_level; /* The streams we interact with. */ FILE *_rl_in_stream, *_rl_out_stream; @@ -149,11 +172,14 @@ FILE *_rl_in_stream, *_rl_out_stream; FILE *rl_instream = (FILE *)NULL; FILE *rl_outstream = (FILE *)NULL; -/* Non-zero means echo characters as they are read. */ -int readline_echoing_p = 1; +/* Non-zero means echo characters as they are read. Defaults to no echo; + set to 1 if there is a controlling terminal, we can get its attributes, + and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings + for the code that sets it. */ +int _rl_echoing_p = 0; /* Current prompt. */ -char *rl_prompt; +char *rl_prompt = (char *)NULL; int rl_visible_prompt_length = 0; /* Set to non-zero by calling application if it has already printed rl_prompt @@ -165,12 +191,12 @@ int rl_key_sequence_length = 0; /* If non-zero, then this is the address of a function to call just before readline_internal_setup () prints the first prompt. */ -Function *rl_startup_hook = (Function *)NULL; +rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; /* If non-zero, this is the address of a function to call just before readline_internal_setup () returns and readline_internal starts reading input characters. */ -Function *rl_pre_input_hook = (Function *)NULL; +rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; /* What we use internally. You should always refer to RL_LINE_BUFFER. */ static char *the_line; @@ -183,7 +209,7 @@ int _rl_eof_char = CTRL ('D'); int rl_pending_input = 0; /* Pointer to a useful terminal name. */ -char *rl_terminal_name = (char *)NULL; +const char *rl_terminal_name = (const char *)NULL; /* Non-zero means to always use horizontal scrolling in line display. */ int _rl_horizontal_scroll_mode = 0; @@ -202,6 +228,9 @@ char *_rl_comment_begin; /* Keymap holding the function currently being executed. */ Keymap rl_executing_keymap; +/* Keymap we're currently using to dispatch. */ +Keymap _rl_dispatching_keymap; + /* Non-zero means to erase entire line, including prompt, on empty input lines. */ int rl_erase_empty_line = 0; @@ -213,7 +242,10 @@ int rl_num_chars_to_read; char *rl_line_buffer = (char *)NULL; int rl_line_buffer_len = 0; -/* Forward declarations used by the display and termcap code. */ +/* Key sequence `contexts' */ +_rl_keyseq_cxt *_rl_kscxt = 0; + +/* Forward declarations used by the display, termcap, and history code. */ /* **************************************************************** */ /* */ @@ -234,6 +266,19 @@ int _rl_convert_meta_chars_to_ascii = 1; rather than as a meta-prefixed escape sequence. */ int _rl_output_meta_chars = 0; +/* Non-zero means to look at the termios special characters and bind + them to equivalent readline functions at startup. */ +int _rl_bind_stty_chars = 1; + +/* Non-zero means to go through the history list at every newline (or + whenever rl_done is set and readline returns) and revert each line to + its initial state. */ +int _rl_revert_all_at_newline = 0; + +/* Non-zero means to honor the termios ECHOCTL bit and echo control + characters corresponding to keyboard-generated signals. */ +int _rl_echo_control_chars = 1; + /* **************************************************************** */ /* */ /* Top Level Functions */ @@ -243,39 +288,70 @@ int _rl_output_meta_chars = 0; /* Non-zero means treat 0200 bit in terminal input as Meta bit. */ int _rl_meta_flag = 0; /* Forward declaration */ +/* Set up the prompt and expand it. Called from readline() and + rl_callback_handler_install (). */ +int +rl_set_prompt (prompt) + const char *prompt; +{ + FREE (rl_prompt); + rl_prompt = prompt ? savestring (prompt) : (char *)NULL; + rl_display_prompt = rl_prompt ? rl_prompt : ""; + + rl_visible_prompt_length = rl_expand_prompt (rl_prompt); + return 0; +} + /* 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; + const char *prompt; { char *value; - - rl_prompt = prompt; +#if 0 + int in_callback; +#endif /* If we are at EOF return a NULL string. */ if (rl_pending_input == EOF) { - rl_pending_input = 0; + rl_clear_pending_input (); return ((char *)NULL); } - rl_visible_prompt_length = rl_expand_prompt (rl_prompt); +#if 0 + /* If readline() is called after installing a callback handler, temporarily + turn off the callback state to avoid ensuing messiness. Patch supplied + by the gdb folks. XXX -- disabled. This can be fooled and readline + left in a strange state by a poorly-timed longjmp. */ + if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK)) + RL_UNSETSTATE (RL_STATE_CALLBACK); +#endif + + rl_set_prompt (prompt); rl_initialize (); - (*rl_prep_term_function) (_rl_meta_flag); + if (rl_prep_term_function) + (*rl_prep_term_function) (_rl_meta_flag); #if defined (HANDLE_SIGNALS) rl_set_signals (); #endif value = readline_internal (); - (*rl_deprep_term_function) (); + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); #if defined (HANDLE_SIGNALS) rl_clear_signals (); #endif +#if 0 + if (in_callback) + RL_SETSTATE (RL_STATE_CALLBACK); +#endif + return (value); } @@ -296,14 +372,17 @@ readline_internal_setup () if (rl_startup_hook) (*rl_startup_hook) (); - if (readline_echoing_p == 0) + /* If we're not echoing, we still want to at least print a prompt, because + rl_redisplay will not do it for us. If the calling application has a + custom redisplay function, though, let that function handle it. */ + if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay) { if (rl_prompt && rl_already_prompted == 0) { nprompt = _rl_strip_prompt (rl_prompt); fprintf (_rl_out_stream, "%s", nprompt); fflush (_rl_out_stream); - free (nprompt); + xfree (nprompt); } } else @@ -313,14 +392,17 @@ readline_internal_setup () else rl_on_new_line (); (*rl_redisplay_function) (); + } + #if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (1, 0); + if (rl_editing_mode == vi_mode) + rl_vi_insert_mode (1, 'i'); #endif /* VI_MODE */ - } if (rl_pre_input_hook) (*rl_pre_input_hook) (); + + RL_CHECK_SIGNALS (); } STATIC_CALLBACK char * @@ -330,6 +412,8 @@ readline_internal_teardown (eof) char *temp; HIST_ENTRY *entry; + RL_CHECK_SIGNALS (); + /* 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 (); @@ -342,17 +426,53 @@ readline_internal_teardown (eof) _rl_free_history_entry (entry); strcpy (the_line, temp); - free (temp); + xfree (temp); } + if (_rl_revert_all_at_newline) + _rl_revert_all_lines (); + /* 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 (); + rl_free_undo_list (); + + /* Restore normal cursor, if available. */ + _rl_set_insert_mode (RL_IM_INSERT, 0); return (eof ? (char *)NULL : savestring (the_line)); } +void +_rl_internal_char_cleanup () +{ +#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_num_chars_to_read && rl_end >= rl_num_chars_to_read) + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + rl_newline (1, '\n'); + } + + if (rl_done == 0) + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + } + + /* If the application writer has told us to erase the entire line if + the only character typed was something bound to rl_newline, do so. */ + if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && + rl_point == 0 && rl_end == 0) + _rl_erase_entire_line (); +} + STATIC_CALLBACK int #if defined (READLINE_CALLBACKS) readline_internal_char () @@ -372,19 +492,44 @@ readline_internal_charloop () #endif lk = _rl_last_command_was_kill; - code = setjmp (readline_top_level); + code = setjmp (_rl_top_level); if (code) - (*rl_redisplay_function) (); + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + /* If we get here, we're not being called from something dispatched + from _rl_callback_read_char(), which sets up its own value of + _rl_top_level (saving and restoring the old, of course), so + we can just return here. */ + if (RL_ISSTATE (RL_STATE_CALLBACK)) + return (0); + } if (rl_pending_input == 0) { /* Then initialize the argument and number of keys read. */ - _rl_init_argument (); + _rl_reset_argument (); rl_key_sequence_length = 0; } + RL_SETSTATE(RL_STATE_READCMD); c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_READCMD); + + /* look at input.c:rl_getc() for the circumstances under which this will + be returned; punt immediately on read error without converting it to + a newline. */ + if (c == READERR) + { +#if defined (READLINE_CALLBACKS) + RL_SETSTATE(RL_STATE_DONE); + return (rl_done = 1); +#else + eof_found = 1; + break; +#endif + } /* EOF typed to a non-blank line is a . */ if (c == EOF && rl_end) @@ -395,6 +540,7 @@ readline_internal_charloop () if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) { #if defined (READLINE_CALLBACKS) + RL_SETSTATE(RL_STATE_DONE); return (rl_done = 1); #else eof_found = 1; @@ -404,6 +550,7 @@ readline_internal_charloop () lastc = c; _rl_dispatch ((unsigned char)c, _rl_keymap); + RL_CHECK_SIGNALS (); /* 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 @@ -411,27 +558,7 @@ readline_internal_charloop () 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_num_chars_to_read && rl_end >= rl_num_chars_to_read) - { - (*rl_redisplay_function) (); - rl_newline (1, '\n'); - } - - if (rl_done == 0) - (*rl_redisplay_function) (); - - /* If the application writer has told us to erase the entire line if - the only character typed was something bound to rl_newline, do so. */ - if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && - rl_point == 0 && rl_end == 0) - _rl_erase_entire_line (); + _rl_internal_char_cleanup (); #if defined (READLINE_CALLBACKS) return 0; @@ -470,7 +597,7 @@ readline_internal () void _rl_init_line_state () { - rl_point = rl_end = 0; + rl_point = rl_end = rl_mark = 0; the_line = rl_line_buffer; the_line[0] = 0; } @@ -481,6 +608,110 @@ _rl_set_the_line () the_line = rl_line_buffer; } +#if defined (READLINE_CALLBACKS) +_rl_keyseq_cxt * +_rl_keyseq_cxt_alloc () +{ + _rl_keyseq_cxt *cxt; + + cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); + + cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; + + cxt->okey = 0; + cxt->ocxt = _rl_kscxt; + cxt->childval = 42; /* sentinel value */ + + return cxt; +} + +void +_rl_keyseq_cxt_dispose (cxt) + _rl_keyseq_cxt *cxt; +{ + xfree (cxt); +} + +void +_rl_keyseq_chain_dispose () +{ + _rl_keyseq_cxt *cxt; + + while (_rl_kscxt) + { + cxt = _rl_kscxt; + _rl_kscxt = _rl_kscxt->ocxt; + _rl_keyseq_cxt_dispose (cxt); + } +} +#endif + +static int +_rl_subseq_getchar (key) + int key; +{ + int k; + + if (key == ESC) + RL_SETSTATE(RL_STATE_METANEXT); + RL_SETSTATE(RL_STATE_MOREINPUT); + k = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (key == ESC) + RL_UNSETSTATE(RL_STATE_METANEXT); + + return k; +} + +#if defined (READLINE_CALLBACKS) +int +_rl_dispatch_callback (cxt) + _rl_keyseq_cxt *cxt; +{ + int nkey, r; + + /* For now */ + /* The first time this context is used, we want to read input and dispatch + on it. When traversing the chain of contexts back `up', we want to use + the value from the next context down. We're simulating recursion using + a chain of contexts. */ + if ((cxt->flags & KSEQ_DISPATCHED) == 0) + { + nkey = _rl_subseq_getchar (cxt->okey); + if (nkey < 0) + { + _rl_abort_internal (); + return -1; + } + r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); + cxt->flags |= KSEQ_DISPATCHED; + } + else + r = cxt->childval; + + /* For now */ + if (r != -3) /* don't do this if we indicate there will be other matches */ + r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ)); + + RL_CHECK_SIGNALS (); + if (r == 0) /* success! */ + { + _rl_keyseq_chain_dispose (); + RL_UNSETSTATE (RL_STATE_MULTIKEY); + return r; + } + + if (r != -3) /* magic value that says we added to the chain */ + _rl_kscxt = cxt->ocxt; + if (_rl_kscxt) + _rl_kscxt->childval = r; + if (r != -3) + _rl_keyseq_cxt_dispose (cxt); + + return r; +} +#endif /* READLINE_CALLBACKS */ + /* 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. */ @@ -488,16 +719,29 @@ int _rl_dispatch (key, map) register int key; Keymap map; +{ + _rl_dispatching_keymap = map; + return _rl_dispatch_subseq (key, map, 0); +} + +int +_rl_dispatch_subseq (key, map, got_subseq) + register int key; + Keymap map; + int got_subseq; { int r, newkey; char *macro; - Function *func; + rl_command_func_t *func; +#if defined (READLINE_CALLBACKS) + _rl_keyseq_cxt *cxt; +#endif if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) { if (map[ESC].type == ISKMAP) { - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) _rl_add_macro_char (ESC); map = FUNCTION_TO_KEYMAP (map, ESC); key = UNMETA (key); @@ -505,11 +749,11 @@ _rl_dispatch (key, map) return (_rl_dispatch (key, map)); } else - ding (); + rl_ding (); return 0; } - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) _rl_add_macro_char (key); r = 0; @@ -517,7 +761,7 @@ _rl_dispatch (key, map) { case ISFUNC: func = map[key].function; - if (func != (Function *)NULL) + if (func) { /* Special case rl_do_lowercase_version (). */ if (func == rl_do_lowercase_version) @@ -525,33 +769,101 @@ _rl_dispatch (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_SETSTATE(RL_STATE_DISPATCHING); + (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); + RL_UNSETSTATE(RL_STATE_DISPATCHING); 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) + if (rl_pending_input == 0 && map[key].function != rl_digit_argument) rl_last_func = map[key].function; + + RL_CHECK_SIGNALS (); + } + else if (map[ANYOTHERKEY].function) + { + /* OK, there's no function bound in this map, but there is a + shadow function that was overridden when the current keymap + was created. Return -2 to note that. */ + _rl_unget_char (key); + return -2; + } + else if (got_subseq) + { + /* Return -1 to note that we're in a subsequence, but we don't + have a matching key, nor was one overridden. This means + we need to back up the recursion chain and find the last + subsequence that is bound to a function. */ + _rl_unget_char (key); + return -1; } else { +#if defined (READLINE_CALLBACKS) + RL_UNSETSTATE (RL_STATE_MULTIKEY); + _rl_keyseq_chain_dispose (); +#endif _rl_abort_internal (); return -1; } break; case ISKMAP: - if (map[key].function != (Function *)NULL) + if (map[key].function != 0) { +#if defined (VI_MODE) + /* The only way this test will be true is if a subsequence has been + bound starting with ESC, generally the arrow keys. What we do is + check whether there's input in the queue, which there generally + will be if an arrow key has been pressed, and, if there's not, + just dispatch to (what we assume is) rl_vi_movement_mode right + away. This is essentially an input test with a zero timeout. */ + if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap + && _rl_input_queued (0) == 0) + return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); +#endif + rl_key_sequence_length++; - newkey = rl_read_key (); - r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key)); + _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key); + + /* Allocate new context here. Use linked contexts (linked through + cxt->ocxt) to simulate recursion */ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + /* Return 0 only the first time, to indicate success to + _rl_callback_read_char. The rest of the time, we're called + from _rl_dispatch_callback, so we return -3 to indicate + special handling is necessary. */ + r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0; + cxt = _rl_keyseq_cxt_alloc (); + + if (got_subseq) + cxt->flags |= KSEQ_SUBSEQ; + cxt->okey = key; + cxt->oldmap = map; + cxt->dmap = _rl_dispatching_keymap; + cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function; + + RL_SETSTATE (RL_STATE_MULTIKEY); + _rl_kscxt = cxt; + + return r; /* don't indicate immediate success */ + } +#endif + + newkey = _rl_subseq_getchar (key); + if (newkey < 0) + { + _rl_abort_internal (); + return -1; + } + + r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function); + return _rl_subseq_result (r, map, key, got_subseq); } else { @@ -561,7 +873,7 @@ _rl_dispatch (key, map) break; case ISMACR: - if (map[key].function != (Function *)NULL) + if (map[key].function != 0) { macro = savestring ((char *)map[key].function); _rl_with_macro_input (macro); @@ -571,12 +883,73 @@ _rl_dispatch (key, map) } #if defined (VI_MODE) if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && + key != ANYOTHERKEY && _rl_vi_textmod_command (key)) _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); #endif + return (r); } +static int +_rl_subseq_result (r, map, key, got_subseq) + int r; + Keymap map; + int key, got_subseq; +{ + Keymap m; + int type, nt; + rl_command_func_t *func, *nf; + + if (r == -2) + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ + { + m = _rl_dispatching_keymap; + type = m[ANYOTHERKEY].type; + func = m[ANYOTHERKEY].function; + if (type == ISFUNC && func == rl_do_lowercase_version) + r = _rl_dispatch (_rl_to_lower (key), map); + else if (type == ISFUNC && func == rl_insert) + { + /* If the function that was shadowed was self-insert, we + somehow need a keymap with map[key].func == self-insert. + Let's use this one. */ + nt = m[key].type; + nf = m[key].function; + + m[key].type = type; + m[key].function = func; + r = _rl_dispatch (key, m); + m[key].type = nt; + m[key].function = nf; + } + else + r = _rl_dispatch (ANYOTHERKEY, m); + } + else if (r && map[ANYOTHERKEY].function) + { + /* We didn't match (r is probably -1), so return something to + tell the caller that it should try ANYOTHERKEY for an + overridden function. */ + _rl_unget_char (key); + _rl_dispatching_keymap = map; + return -2; + } + else if (r && got_subseq) + { + /* OK, back up the chain. */ + _rl_unget_char (key); + _rl_dispatching_keymap = map; + return -1; + } + + return r; +} + /* **************************************************************** */ /* */ /* Initializations */ @@ -591,8 +964,11 @@ rl_initialize () terminal and data structures. */ if (!rl_initialized) { + RL_SETSTATE(RL_STATE_INITIALIZING); readline_initialize_everything (); + RL_UNSETSTATE(RL_STATE_INITIALIZING); rl_initialized++; + RL_SETSTATE(RL_STATE_INITIALIZED); } /* Initalize the current line information. */ @@ -600,15 +976,16 @@ rl_initialize () /* We aren't done yet. We haven't even gotten started yet! */ rl_done = 0; + RL_UNSETSTATE(RL_STATE_DONE); /* Tell the history routines what is going on. */ - start_using_history (); + _rl_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; + rl_last_func = (rl_command_func_t *)NULL; /* Parsing of key-bindings begins in an enabled state. */ _rl_parsing_conditionalized_out = 0; @@ -618,6 +995,9 @@ rl_initialize () _rl_vi_initialize_line (); #endif + /* Each line starts in insert mode (the default). */ + _rl_set_insert_mode (RL_IM_DEFAULT, 1); + return 0; } @@ -658,8 +1038,10 @@ readline_initialize_everything () #endif #endif - /* Find out if we are running in Emacs. */ - running_in_emacs = get_env_value ("EMACS") != (char *)0; +#if 0 + /* Find out if we are running in Emacs -- UNUSED. */ + running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; +#endif /* Set up input and output if they are not already set up. */ if (!rl_instream) @@ -676,10 +1058,12 @@ readline_initialize_everything () /* Allocate data structures. */ if (rl_line_buffer == 0) - rl_line_buffer = xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); + rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); /* Initialize the terminal interface. */ - _rl_init_terminal_io ((char *)NULL); + if (rl_terminal_name == 0) + rl_terminal_name = sh_get_env_value ("TERM"); + _rl_init_terminal_io (rl_terminal_name); /* Bind tty characters to readline functions. */ readline_default_bindings (); @@ -696,8 +1080,8 @@ readline_initialize_everything () /* XXX */ if (_rl_horizontal_scroll_mode && _rl_term_autowrap) { - screenwidth--; - screenchars -= screenheight; + _rl_screenwidth--; + _rl_screenchars -= _rl_screenheight; } /* Override the effect of any `set keymap' assignments in the @@ -714,7 +1098,7 @@ readline_initialize_everything () /* 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; + rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; } /* If this system allows us to look at the values of the regular @@ -723,1367 +1107,155 @@ readline_initialize_everything () static void readline_default_bindings () { - rltty_set_default_bindings (_rl_keymap); + if (_rl_bind_stty_chars) + rl_tty_set_default_bindings (_rl_keymap); } +/* Reset the default bindings for the terminal special characters we're + interested in back to rl_insert and read the new ones. */ static void -bind_arrow_keys_internal () +reset_default_bindings () { - Function *f; - -#if defined (__MSDOS__) - f = rl_function_of_keyseq ("\033[0A", _rl_keymap, (int *)NULL); - if (!f || f == rl_do_lowercase_version) - { - _rl_bind_if_unbound ("\033[0A", rl_get_previous_history); - _rl_bind_if_unbound ("\033[0B", rl_backward); - _rl_bind_if_unbound ("\033[0C", rl_forward); - _rl_bind_if_unbound ("\033[0D", rl_get_next_history); - } -#endif - - f = rl_function_of_keyseq ("\033[A", _rl_keymap, (int *)NULL); - if (!f || f == rl_do_lowercase_version) + if (_rl_bind_stty_chars) { - _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); + rl_tty_unset_default_bindings (_rl_keymap); + rl_tty_set_default_bindings (_rl_keymap); } } -/* 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. */ +/* Bind some common arrow key sequences in MAP. */ static void -bind_arrow_keys () +bind_arrow_keys_internal (map) + Keymap map; { Keymap xkeymap; xkeymap = _rl_keymap; + _rl_keymap = map; - _rl_keymap = emacs_standard_keymap; - bind_arrow_keys_internal (); +#if defined (__MSDOS__) + rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); +#endif -#if defined (VI_MODE) - _rl_keymap = vi_movement_keymap; - bind_arrow_keys_internal (); + rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); + + rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); + +#if defined (__MINGW32__) + rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\340M", rl_forward_char); + rl_bind_keyseq_if_unbound ("\340K", rl_backward_char); + rl_bind_keyseq_if_unbound ("\340G", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\340O", rl_end_of_line); + rl_bind_keyseq_if_unbound ("\340S", rl_delete); + rl_bind_keyseq_if_unbound ("\340R", rl_overwrite_mode); #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) - { - if (rl_numeric_arg > 1000000) - { - sawdigits = rl_explicit_arg = rl_numeric_arg = 0; - ding (); - rl_restore_prompt (); - rl_clear_message (); - return 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 () +/* Try and bind the common arrow key prefixes 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 () { - rl_numeric_arg = rl_arg_sign = 1; - rl_explicit_arg = 0; - return 0; -} + bind_arrow_keys_internal (emacs_standard_keymap); -/* 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 ()); +#if defined (VI_MODE) + bind_arrow_keys_internal (vi_movement_keymap); + /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC + in vi command mode while still allowing the arrow keys to work. */ + if (vi_movement_keymap[ESC].type == ISKMAP) + rl_bind_keyseq_in_map ("\033", (rl_command_func_t *)NULL, vi_movement_keymap); + bind_arrow_keys_internal (vi_insertion_keymap); +#endif } /* **************************************************************** */ /* */ -/* Insert and Delete */ +/* Saving and Restoring Readline's state */ /* */ /* **************************************************************** */ -/* 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; +rl_save_state (sp) + struct readline_state *sp; { - register int i, l = strlen (string); - - if (rl_end + l >= rl_line_buffer_len) - rl_extend_line_buffer (rl_end + l); + if (sp == 0) + return -1; - for (i = rl_end; i >= rl_point; i--) - the_line[i + l] = the_line[i]; - strncpy (the_line + rl_point, string, l); + sp->point = rl_point; + sp->end = rl_end; + sp->mark = rl_mark; + sp->buffer = rl_line_buffer; + sp->buflen = rl_line_buffer_len; + sp->ul = rl_undo_list; + sp->prompt = rl_prompt; + + sp->rlstate = rl_readline_state; + sp->done = rl_done; + sp->kmap = _rl_keymap; + + sp->lastfunc = rl_last_func; + sp->insmode = rl_insert_mode; + sp->edmode = rl_editing_mode; + sp->kseqlen = rl_key_sequence_length; + sp->inf = rl_instream; + sp->outf = rl_outstream; + sp->pendingin = rl_pending_input; + sp->macro = rl_executing_macro; + + sp->catchsigs = rl_catch_signals; + sp->catchsigwinch = rl_catch_sigwinch; - /* 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; + return (0); } -/* Delete the string between FROM and TO. FROM is - inclusive, TO is not. */ int -rl_delete_text (from, to) - int from, to; +rl_restore_state (sp) + struct readline_state *sp; { - 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. */ + if (sp == 0) + return -1; -#define _RL_FIX_POINT(x) \ - do { \ - if (x > rl_end) \ - x = rl_end; \ - else if (x < 0) \ - x = 0; \ - } while (0) + rl_point = sp->point; + rl_end = sp->end; + rl_mark = sp->mark; + the_line = rl_line_buffer = sp->buffer; + rl_line_buffer_len = sp->buflen; + rl_undo_list = sp->ul; + rl_prompt = sp->prompt; + + rl_readline_state = sp->rlstate; + rl_done = sp->done; + _rl_keymap = sp->kmap; + + rl_last_func = sp->lastfunc; + rl_insert_mode = sp->insmode; + rl_editing_mode = sp->edmode; + rl_key_sequence_length = sp->kseqlen; + rl_instream = sp->inf; + rl_outstream = sp->outf; + rl_pending_input = sp->pendingin; + rl_executing_macro = sp->macro; + + rl_catch_signals = sp->catchsigs; + rl_catch_sigwinch = sp->catchsigwinch; -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 - -void -_rl_replace_text (text, start, end) - char *text; - int start, end; -{ - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - rl_insert_text (text); - rl_end_undo_group (); -} - -/* **************************************************************** */ -/* */ -/* 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; - } - - if (rl_end < 0) - rl_end = 0; - - 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 (ignore1, ignore2) - int ignore1, ignore2; -{ - int curr_line; - - curr_line = _rl_current_display_line (); - - _rl_move_vert (curr_line); - _rl_move_cursor_relative (0, the_line); /* XXX is this right */ - - _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ - - 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 (count, key); - 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; - -#if defined (HANDLE_SIGNALS) - _rl_disable_tty_signals (); -#endif - c = rl_read_key (); -#if defined (HANDLE_SIGNALS) - _rl_restore_tty_signals (); -#endif - - 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 we've been asked to erase empty lines, suppress the final update, - since _rl_update_final calls crlf(). */ - if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) - return 0; - - 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 the character under the cursor, unless the insertion - point is at the end of the line, in which case the character - behind the cursor is deleted. COUNT is obeyed and may be used - to delete forward or backward that many characters. */ -int -rl_rubout_or_delete (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_rubout (count, key)); - else - return (rl_delete (count, key)); -} - -/* 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; -} - -/* Like the tcsh editing function delete-char-or-list. The eof character - is caught before this is invoked, so this really does the same thing as - delete-char-or-list-or-eof, as long as it's bound to the eof character. */ -int -rl_delete_or_show_completions (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_possible_completions (count, key)); - else - return (rl_delete (count, key)); -} - -#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 - -/* 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, (histdata_t)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; -}