X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=readline%2Freadline.c;h=071e1aa082e1ea13748e3beb57366c6dd6287a68;hb=2376c3702e43ad8a717d80888b34e1e7eaeacaa8;hp=db22c7fd3379a4cdc36366bdb3053e425ad5598f;hpb=7c88553a91c2ba29a60cf9f6c3eb62aceb7ebc17;p=deliverable%2Fbinutils-gdb.git diff --git a/readline/readline.c b/readline/readline.c index db22c7fd33..071e1aa082 100644 --- a/readline/readline.c +++ b/readline/readline.c @@ -1,208 +1,131 @@ /* readline.c -- a general facility for reading lines of input with emacs style editing and completion. */ -/* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. - The Library is free software; you can redistribute it and/or modify + 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 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - The Library is distributed in the hope that it will be useful, + Readline is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + along with Readline. If not, see . +*/ -/* Remove these declarations when we have a complete libgnu.a. */ -/* #define STATIC_MALLOC */ -#if !defined (STATIC_MALLOC) -extern char *xmalloc (), *xrealloc (); -#else -static char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif -#include "sysdep.h" #include -#include +#include "posixstat.h" #include -#ifndef NO_SYS_FILE -#include -#endif -#include +#if defined (HAVE_SYS_FILE_H) +# include +#endif /* HAVE_SYS_FILE_H */ #if defined (HAVE_UNISTD_H) # include -#endif - -#define NEW_TTY_DRIVER -#define HAVE_BSD_SIGNALS -/* #define USE_XON_XOFF */ +#endif /* HAVE_UNISTD_H */ -#ifdef __MSDOS__ -#undef NEW_TTY_DRIVER -#undef HAVE_BSD_SIGNALS -#endif - -/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */ -#if defined (USG) && !defined (hpux) -#undef HAVE_BSD_SIGNALS -#endif +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ -/* System V machines use termio. */ -#if !defined (_POSIX_VERSION) -# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) -# undef NEW_TTY_DRIVER -# define TERMIO_TTY_DRIVER -# include -# if !defined (TCOON) -# define TCOON 1 -# endif -# endif /* USG || hpux || Xenix || sgi || DUGX */ -#endif /* !_POSIX_VERSION */ - -/* Posix systems use termios and the Posix signal functions. */ -#if defined (_POSIX_VERSION) -# if !defined (TERMIOS_MISSING) -# undef NEW_TTY_DRIVER -# define TERMIOS_TTY_DRIVER -# include -# endif /* !TERMIOS_MISSING */ -# define HAVE_POSIX_SIGNALS -# if !defined (O_NDELAY) -# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ -# endif /* O_NDELAY */ -#endif /* _POSIX_VERSION */ - -/* Other (BSD) machines use sgtty. */ -#if defined (NEW_TTY_DRIVER) -#include +#if defined (HAVE_LOCALE_H) +# include #endif -/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and - it is not already defined. It is used both to determine if a - special character is disabled and to disable certain special - characters. Posix systems should set to 0, USG systems to -1. */ -#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) -# if defined (_POSIX_VERSION) -# define _POSIX_VDISABLE 0 -# else /* !_POSIX_VERSION */ -# define _POSIX_VDISABLE -1 -# endif /* !_POSIX_VERSION */ -#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ - +#include +#include "posixjmp.h" #include -extern int errno; - -#include -#include -/* Posix macro to check file in statbuf for directory-ness. */ -#if defined (S_IFDIR) && !defined (S_ISDIR) -#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) -#endif - -#ifndef __MSDOS__ -/* These next are for filename completion. Perhaps this belongs - in a different place. */ -#include -#endif /* __MSDOS__ */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ -#if defined (USG) && !defined (isc386) && !defined (sgi) -struct passwd *getpwuid (), *getpwent (); -#endif +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" -/* #define HACK_TERMCAP_MOTION */ +#if defined (__EMX__) +# define INCL_DOSPROCESS +# include +#endif /* __EMX__ */ /* Some standard library routines. */ #include "readline.h" #include "history.h" -#ifndef digit -#define digit(c) ((c) >= '0' && (c) <= '9') -#endif - -#ifndef isletter -#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) -#endif - -#ifndef digit_value -#define digit_value(c) ((c) - '0') -#endif - -#ifndef member -#define member(c, s) ((c) ? index ((s), (c)) : 0) -#endif +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" -#ifndef isident -#define isident(c) ((isletter(c) || digit(c) || c == '_')) +#ifndef RL_LIBRARY_VERSION +# define RL_LIBRARY_VERSION "5.1" #endif -#ifndef exchange -#define exchange(x, y) {int temp = x; x = y; y = temp;} +#ifndef RL_READLINE_VERSION +# define RL_READLINE_VERSION 0x0501 #endif -#if !defined (rindex) -extern char *rindex (); -#endif /* rindex */ - -#if !defined (index) -extern char *index (); -#endif /* index */ +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); -extern char *getenv (); -extern char *tilde_expand (); +/* Forward declarations used in this file. */ +static char *readline_internal PARAMS((void)); +static void readline_initialize_everything PARAMS((void)); -static update_line (); -static void output_character_function (); -static delete_chars (); -static void insert_some_chars (); +static void bind_arrow_keys_internal PARAMS((Keymap)); +static void bind_arrow_keys PARAMS((void)); -#if defined (VOID_SIGHANDLER) -# define sighandler void -#else -# define sighandler int -#endif /* VOID_SIGHANDLER */ - -/* This typedef is equivalant to the one for Function; it allows us - to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef sighandler SigHandler (); +static void readline_default_bindings PARAMS((void)); +static void reset_default_bindings PARAMS((void)); -/* If on, then readline handles signals in a way that doesn't screw. */ -#define HANDLE_SIGNALS - -#ifdef __GO32__ -#include -#undef HANDLE_SIGNALS -#endif +static int _rl_subseq_result PARAMS((int, Keymap, int, int)); +static int _rl_subseq_getchar PARAMS((int)); - /* **************************************************************** */ /* */ /* Line editing input utility */ /* */ /* **************************************************************** */ +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 keymap = emacs_standard_keymap; +Keymap _rl_keymap = emacs_standard_keymap; -#define no_mode -1 -#define vi_mode 0 -#define emacs_mode 1 /* 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. */ +int rl_dispatching; + /* Non-zero if the previous command was a kill command. */ -static int last_command_was_kill = 0; +int _rl_last_command_was_kill = 0; /* The current value of the numeric argument specified by the user. */ int rl_numeric_arg = 1; @@ -214,10 +137,15 @@ int rl_explicit_arg = 0; int rl_arg_sign = 1; /* Non-zero means we have been called at least once before. */ -static int rl_initialized = 0; +static int rl_initialized; +#if 0 /* If non-zero, this program is running in an EMACS buffer. */ -static char *running_in_emacs = (char *)NULL; +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; @@ -232,54 +160,93 @@ 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 (). */ -static jmp_buf readline_top_level; +procenv_t _rl_top_level; /* The streams we interact with. */ -static FILE *in_stream, *out_stream; +FILE *_rl_in_stream, *_rl_out_stream; /* The names of the streams that we do input and output to. */ -FILE *rl_instream, *rl_outstream; +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 + and does not want readline to do it the first time. */ +int rl_already_prompted = 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; + before readline_internal_setup () prints the first prompt. */ +rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; -/* If non-zero, then this is the address of a function to call when - completing on a directory name. The function is called with - the address of a string (the current directory name) as an arg. */ -Function *rl_symbolic_link_hook = (Function *)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. */ +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; /* The character that can generate an EOF. Really read from the terminal driver... just defaulted here. */ -static int eof_char = CTRL ('D'); +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; +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; + +/* 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; + +/* 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; + +/* Non-zero means to read only this many characters rather than up to a + character bound to accept-line. */ +int rl_num_chars_to_read; /* Line buffer and maintenence. */ char *rl_line_buffer = (char *)NULL; int rl_line_buffer_len = 0; -#define DEFAULT_BUFFER_SIZE 256 - +/* Key sequence `contexts' */ +_rl_keyseq_cxt *_rl_kscxt = 0; + +/* Forward declarations used by the display, termcap, and history code. */ + /* **************************************************************** */ /* */ /* `Forward' declarations */ @@ -288,851 +255,815 @@ int rl_line_buffer_len = 0; /* Non-zero means do not parse any lines other than comments and parser directives. */ -static unsigned char parsing_conditionalized_out = 0; +unsigned char _rl_parsing_conditionalized_out = 0; -/* Caseless strcmp (). */ -static int stricmp (), strnicmp (); -static char *strpbrk (); +/* 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 save keys that we dispatch on in a kbd macro. */ -static int defining_kbd_macro = 0; +/* 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; + +/* 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 */ /* */ /* **************************************************************** */ -static void rl_prep_terminal (), rl_deprep_terminal (); +/* 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 : ""; -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means + 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 *readline_internal (); 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); } +#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_terminal (); + 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_terminal (); + 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); } -/* 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. */ -char * -readline_internal () -{ - int lastc, c, eof_found; +#if defined (READLINE_CALLBACKS) +# define STATIC_CALLBACK +#else +# define STATIC_CALLBACK static +#endif - in_stream = rl_instream; - out_stream = rl_outstream; +STATIC_CALLBACK void +readline_internal_setup () +{ + char *nprompt; - lastc = -1; - eof_found = 0; + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; if (rl_startup_hook) (*rl_startup_hook) (); - if (!readline_echoing_p) + /* 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) + if (rl_prompt && rl_already_prompted == 0) { - fprintf (out_stream, "%s", rl_prompt); - fflush (out_stream); + nprompt = _rl_strip_prompt (rl_prompt); + fprintf (_rl_out_stream, "%s", nprompt); + fflush (_rl_out_stream); + xfree (nprompt); } } else { - rl_on_new_line (); - rl_redisplay (); -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (); -#endif /* VI_MODE */ + if (rl_prompt && rl_already_prompted) + rl_on_new_line_with_prompt (); + else + rl_on_new_line (); + (*rl_redisplay_function) (); } - while (!rl_done) - { - int lk = last_command_was_kill; - int code = setjmp (readline_top_level); - - if (code) - rl_redisplay (); - - if (!rl_pending_input) - { - /* Then initialize the argument and number of keys read. */ - rl_init_argument (); - rl_key_sequence_length = 0; - } +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_vi_insert_mode (1, 'i'); +#endif /* VI_MODE */ - c = rl_read_key (); + if (rl_pre_input_hook) + (*rl_pre_input_hook) (); - /* EOF typed to a non-blank line is a . */ - if (c == EOF && rl_end) - c = NEWLINE; + RL_CHECK_SIGNALS (); +} - /* The character eof_char typed to blank line, and not as the - previous character is interpreted as EOF. */ - if (((c == eof_char && lastc != c) || c == EOF) && !rl_end) - { - eof_found = 1; - break; - } +STATIC_CALLBACK char * +readline_internal_teardown (eof) + int eof; +{ + char *temp; + HIST_ENTRY *entry; - lastc = c; - rl_dispatch (c, keymap); + RL_CHECK_SIGNALS (); - /* If there was no change in 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) - { - if (lk == last_command_was_kill) - last_command_was_kill = 0; - } + /* 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 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 && keymap == vi_movement_keymap) - rl_vi_check (); -#endif /* VI_MODE */ + if (entry && rl_undo_list) + { + temp = savestring (the_line); + rl_revert_line (1, 0); + entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); + _rl_free_history_entry (entry); - if (!rl_done) - rl_redisplay (); + strcpy (the_line, temp); + xfree (temp); } - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - { - HIST_ENTRY *entry = current_history (); - - if (entry && rl_undo_list) - { - char *temp = savestring (the_line); - rl_revert_line (); - entry = replace_history_entry (where_history (), the_line, - (HIST_ENTRY *)NULL); - free_history_entry (entry); - - strcpy (the_line, temp); - free (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 (); - - if (eof_found) - return (char *)NULL; - else - return (savestring (the_line)); -} + rl_free_undo_list (); - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ + /* Restore normal cursor, if available. */ + _rl_set_insert_mode (RL_IM_INSERT, 0); -#if defined (SIGWINCH) -static SigHandler *old_sigwinch = (SigHandler *)NULL; + return (eof ? (char *)NULL : savestring (the_line)); +} -static sighandler -rl_handle_sigwinch (sig) - int sig; +void +_rl_internal_char_cleanup () { - char *term; - - term = rl_terminal_name; +#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 (readline_echoing_p) + if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) { - if (!term) - term = getenv ("TERM"); - if (!term) - term = "dumb"; - rl_reset_terminal (term); -#if defined (NOTDEF) - crlf (); - rl_forced_update_display (); -#endif /* NOTDEF */ + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + rl_newline (1, '\n'); } - if (old_sigwinch && - old_sigwinch != (SigHandler *)SIG_IGN && - old_sigwinch != (SigHandler *)SIG_DFL) - (*old_sigwinch) (sig); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ -} -#endif /* SIGWINCH */ - -#if defined (HANDLE_SIGNALS) -/* Interrupt handling. */ -static SigHandler - *old_int = (SigHandler *)NULL, - *old_tstp = (SigHandler *)NULL, - *old_ttou = (SigHandler *)NULL, - *old_ttin = (SigHandler *)NULL, - *old_cont = (SigHandler *)NULL, - *old_alrm = (SigHandler *)NULL; - -/* Handle an interrupt character. */ -static sighandler -rl_signal_handler (sig) - int sig; -{ -#if !defined (HAVE_BSD_SIGNALS) - /* Since the signal will not be blocked while we are in the signal - handler, ignore it until rl_clear_signals resets the catcher. */ - if (sig == SIGINT) - signal (sig, SIG_IGN); -#endif /* !HAVE_BSD_SIGNALS */ - - switch (sig) + if (rl_done == 0) { - case SIGINT: - free_undo_list (); - rl_clear_message (); - rl_init_argument (); - -#if defined (SIGTSTP) - case SIGTSTP: - case SIGTTOU: - case SIGTTIN: -#endif /* SIGTSTP */ - case SIGALRM: - rl_clean_up_for_exit (); - rl_deprep_terminal (); - rl_clear_signals (); - rl_pending_input = 0; - - kill (getpid (), sig); - -#if defined (HAVE_POSIX_SIGNALS) - { - sigset_t set; - - sigemptyset (&set); - sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); - } -#else -#if defined (HAVE_BSD_SIGNALS) - sigsetmask (0); -#endif /* HAVE_BSD_SIGNALS */ -#endif /* HAVE_POSIX_SIGNALS */ - - rl_prep_terminal (); - rl_set_signals (); + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; } -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + /* 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_set_signals () -{ - old_int = (SigHandler *)signal (SIGINT, rl_signal_handler); - if (old_int == (SigHandler *)SIG_IGN) - signal (SIGINT, SIG_IGN); - - old_alrm = (SigHandler *)signal (SIGALRM, rl_signal_handler); - if (old_alrm == (SigHandler *)SIG_IGN) - signal (SIGALRM, SIG_IGN); - -#if defined (SIGTSTP) - old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler); - if (old_tstp == (SigHandler *)SIG_IGN) - signal (SIGTSTP, SIG_IGN); +STATIC_CALLBACK int +#if defined (READLINE_CALLBACKS) +readline_internal_char () +#else +readline_internal_charloop () #endif -#if defined (SIGTTOU) - old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler); - old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler); +{ + static int lastc, eof_found; + int c, code, lk; + + lastc = -1; + eof_found = 0; - if (old_tstp == (SigHandler *)SIG_IGN) +#if !defined (READLINE_CALLBACKS) + while (rl_done == 0) { - signal (SIGTTOU, SIG_IGN); - signal (SIGTTIN, SIG_IGN); - } #endif + lk = _rl_last_command_was_kill; -#if defined (SIGWINCH) - old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch); -#endif -} + code = setjmp (_rl_top_level); -rl_clear_signals () -{ - signal (SIGINT, old_int); - signal (SIGALRM, old_alrm); + if (code) + { + (*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 defined (SIGTSTP) - signal (SIGTSTP, old_tstp); -#endif + if (rl_pending_input == 0) + { + /* Then initialize the argument and number of keys read. */ + _rl_reset_argument (); + rl_key_sequence_length = 0; + } -#if defined (SIGTTOU) - signal (SIGTTOU, old_ttou); - signal (SIGTTIN, old_ttin); -#endif + RL_SETSTATE(RL_STATE_READCMD); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_READCMD); -#if defined (SIGWINCH) - signal (SIGWINCH, old_sigwinch); + /* 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 -} -#endif /* HANDLE_SIGNALS */ + } - -/* **************************************************************** */ -/* */ -/* Character Input Buffering */ -/* */ -/* **************************************************************** */ + /* EOF typed to a non-blank line is a . */ + if (c == EOF && rl_end) + c = NEWLINE; -#if defined (USE_XON_XOFF) -/* If the terminal was in xoff state when we got to it, then xon_char - contains the character that is supposed to start it again. */ -static int xon_char, xoff_state; -#endif /* USE_XON_XOFF */ + /* 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) + RL_SETSTATE(RL_STATE_DONE); + return (rl_done = 1); +#else + eof_found = 1; + break; +#endif + } -static int pop_index = 0, push_index = 0, ibuffer_len = 511; -static unsigned char ibuffer[512]; + lastc = c; + _rl_dispatch ((unsigned char)c, _rl_keymap); + RL_CHECK_SIGNALS (); -/* Non-null means it is a pointer to a function to run while waiting for - character input. */ -Function *rl_event_hook = (Function *)NULL; + /* 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; -#define any_typein (push_index != pop_index) + _rl_internal_char_cleanup (); -/* Add KEY to the buffer of characters to be read. */ -rl_stuff_char (key) - int key; -{ - if (key == EOF) - { - key = NEWLINE; - rl_pending_input = EOF; +#if defined (READLINE_CALLBACKS) + return 0; +#else } - ibuffer[push_index++] = key; - if (push_index >= ibuffer_len) - push_index = 0; + + return (eof_found); +#endif } -/* Return the amount of space available in the - buffer for stuffing characters. */ -int -ibuffer_space () +#if defined (READLINE_CALLBACKS) +static int +readline_internal_charloop () { - if (pop_index > push_index) - return (pop_index - push_index); - else - return (ibuffer_len - (push_index - pop_index)); + int eof = 1; + + while (rl_done == 0) + eof = readline_internal_char (); + return (eof); } +#endif /* READLINE_CALLBACKS */ -/* Get a key from the buffer of characters to be read. - Return the key in KEY. - Result is KEY if there was a key, or 0 if there wasn't. */ -int -rl_get_char (key) - int *key; +/* 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 () { - if (push_index == pop_index) - return (0); - - *key = ibuffer[pop_index++]; + int eof; - if (pop_index >= ibuffer_len) - pop_index = 0; + readline_internal_setup (); + eof = readline_internal_charloop (); + return (readline_internal_teardown (eof)); +} - return (1); +void +_rl_init_line_state () +{ + rl_point = rl_end = rl_mark = 0; + the_line = rl_line_buffer; + the_line[0] = 0; } -/* Stuff KEY into the *front* of the input buffer. - Returns non-zero if successful, zero if there is - no space left in the buffer. */ -int -rl_unget_char (key) - int key; +void +_rl_set_the_line () { - if (ibuffer_space ()) - { - pop_index--; - if (pop_index < 0) - pop_index = ibuffer_len - 1; - ibuffer[pop_index] = key; - return (1); - } - return (0); + the_line = rl_line_buffer; } -/* If a character is available to be read, then read it - and stuff it into IBUFFER. Otherwise, just return. */ -rl_gather_tyi () +#if defined (READLINE_CALLBACKS) +_rl_keyseq_cxt * +_rl_keyseq_cxt_alloc () { -#ifdef __GO32__ - char input; - if (isatty(0)) - { - int i = rl_getc(); - if (i != EOF) - rl_stuff_char(i); - } - else - if (kbhit() && ibuffer_space()) - rl_stuff_char(getkey()); -#else - int tty = fileno (in_stream); - register int tem, result = -1; - long chars_avail; - char input; + _rl_keyseq_cxt *cxt; -#if defined (FIONREAD) - result = ioctl (tty, FIONREAD, &chars_avail); -#endif + cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); - if (result == -1) - { - int flags; + cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; - flags = fcntl (tty, F_GETFL, 0); + cxt->okey = 0; + cxt->ocxt = _rl_kscxt; + cxt->childval = 42; /* sentinel value */ - fcntl (tty, F_SETFL, (flags | O_NDELAY)); - chars_avail = read (tty, &input, 1); + return cxt; +} - fcntl (tty, F_SETFL, flags); - if (chars_avail == -1 && errno == EAGAIN) - return; - } +void +_rl_keyseq_cxt_dispose (cxt) + _rl_keyseq_cxt *cxt; +{ + xfree (cxt); +} - /* If there's nothing available, don't waste time trying to read - something. */ - if (chars_avail == 0) - return; +void +_rl_keyseq_chain_dispose () +{ + _rl_keyseq_cxt *cxt; - tem = ibuffer_space (); + while (_rl_kscxt) + { + cxt = _rl_kscxt; + _rl_kscxt = _rl_kscxt->ocxt; + _rl_keyseq_cxt_dispose (cxt); + } +} +#endif - if (chars_avail > tem) - chars_avail = tem; +static int +_rl_subseq_getchar (key) + int key; +{ + int k; - /* One cannot read all of the available input. I can only read a single - character at a time, or else programs which require input can be - thwarted. If the buffer is larger than one character, I lose. - Damn! */ - if (tem < ibuffer_len) - chars_avail = 0; + 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); - if (result != -1) - { - while (chars_avail--) - rl_stuff_char (rl_getc (in_stream)); - } - else - { - if (chars_avail) - rl_stuff_char (input); - } -#endif /* def __GO32__/else */ + return k; } -static int next_macro_key (); -/* Read a key, including pending input. */ +#if defined (READLINE_CALLBACKS) int -rl_read_key () +_rl_dispatch_callback (cxt) + _rl_keyseq_cxt *cxt; { - int c; + int nkey, r; - rl_key_sequence_length++; - - if (rl_pending_input) - { - c = rl_pending_input; - rl_pending_input = 0; - } - else + /* 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) { - /* If input is coming from a macro, then use that. */ - if (c = next_macro_key ()) - return (c); - - /* If the user has an event function, then call it periodically. */ - if (rl_event_hook) - { - while (rl_event_hook && !rl_get_char (&c)) - { - (*rl_event_hook) (); - rl_gather_tyi (); - } - } - else + nkey = _rl_subseq_getchar (cxt->okey); + if (nkey < 0) { - if (!rl_get_char (&c)) - c = rl_getc (in_stream); + _rl_abort_internal (); + return -1; } + r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); + cxt->flags |= KSEQ_DISPATCHED; } + else + r = cxt->childval; - return (c); -} + /* 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; + } -/* I'm beginning to hate the declaration rules for various compilers. */ -static void add_macro_char (), with_macro_input (); + 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. */ -rl_dispatch (key, map) +int +_rl_dispatch (key, map) register int key; Keymap map; { + _rl_dispatching_keymap = map; + return _rl_dispatch_subseq (key, map, 0); +} - if (defining_kbd_macro) - add_macro_char (key); +int +_rl_dispatch_subseq (key, map, got_subseq) + register int key; + Keymap map; + int got_subseq; +{ + int r, newkey; + char *macro; + rl_command_func_t *func; +#if defined (READLINE_CALLBACKS) + _rl_keyseq_cxt *cxt; +#endif - if (key > 127 && key < 256) + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) { if (map[ESC].type == ISKMAP) { - map = (Keymap)map[ESC].function; - key -= 128; - rl_dispatch (key, map); + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _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; + rl_ding (); + return 0; } + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (key); + + r = 0; switch (map[key].type) { case ISFUNC: - { - Function *func = map[key].function; - - if (func != (Function *)NULL) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - { - rl_dispatch (to_lower (key), map); - return; - } - - (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); - - /* 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) - rl_last_func = map[key].function; - } - else - { - rl_abort (); - return; - } - } - break; + func = map[key].function; + if (func) + { + /* Special case rl_do_lowercase_version (). */ + if (func == rl_do_lowercase_version) + return (_rl_dispatch (_rl_to_lower (key), map)); + + rl_executing_keymap = map; + + rl_dispatching = 1; + 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 == 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) { - int newkey; +#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 (); - rl_dispatch (newkey, (Keymap)map[key].function); + _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 { - rl_abort (); - return; + _rl_abort_internal (); + return -1; } break; case ISMACR: - if (map[key].function != (Function *)NULL) + if (map[key].function != 0) { - char *macro; - macro = savestring ((char *)map[key].function); - with_macro_input (macro); - return; + _rl_with_macro_input (macro); + return 0; } break; } -} - - -/* **************************************************************** */ -/* */ -/* Hacking Keyboard Macros */ -/* */ -/* **************************************************************** */ - -/* The currently executing macro string. If this is non-zero, - then it is a malloc ()'ed string where input is coming from. */ -static char *executing_macro = (char *)NULL; - -/* The offset in the above string to the next character to be read. */ -static int executing_macro_index = 0; - -/* The current macro string being built. Characters get stuffed - in here by add_macro_char (). */ -static char *current_macro = (char *)NULL; - -/* The size of the buffer allocated to current_macro. */ -static int current_macro_size = 0; - -/* The index at which characters are being added to current_macro. */ -static int current_macro_index = 0; - -/* A structure used to save nested macro strings. - It is a linked list of string/index for each saved macro. */ -struct saved_macro { - struct saved_macro *next; - char *string; - int index; -}; - -/* The list of saved macros. */ -struct saved_macro *macro_list = (struct saved_macro *)NULL; - -/* Forward declarations of static functions. Thank you C. */ -static void push_executing_macro (), pop_executing_macro (); - -/* This one has to be declared earlier in the file. */ -/* static void add_macro_char (); */ +#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 -/* Set up to read subsequent input from STRING. - STRING is free ()'ed when we are done with it. */ -static void -with_macro_input (string) - char *string; -{ - push_executing_macro (); - executing_macro = string; - executing_macro_index = 0; + return (r); } -/* Return the next character available from a macro, or 0 if - there are no macro characters. */ static int -next_macro_key () -{ - if (!executing_macro) - return (0); - - if (!executing_macro[executing_macro_index]) - { - pop_executing_macro (); - return (next_macro_key ()); - } - - return (executing_macro[executing_macro_index++]); -} - -/* Save the currently executing macro on a stack of saved macros. */ -static void -push_executing_macro () -{ - struct saved_macro *saver; - - saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro)); - saver->next = macro_list; - saver->index = executing_macro_index; - saver->string = executing_macro; - - macro_list = saver; -} - -/* Discard the current macro, replacing it with the one - on the top of the stack of saved macros. */ -static void -pop_executing_macro () -{ - if (executing_macro) - free (executing_macro); - - executing_macro = (char *)NULL; - executing_macro_index = 0; - - if (macro_list) - { - struct saved_macro *disposer = macro_list; - executing_macro = macro_list->string; - executing_macro_index = macro_list->index; - macro_list = macro_list->next; - free (disposer); +_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); } -} - -/* Add a character to the macro being built. */ -static void -add_macro_char (c) - int c; -{ - if (current_macro_index + 1 >= current_macro_size) + else if (r && map[ANYOTHERKEY].function) { - if (!current_macro) - current_macro = (char *)xmalloc (current_macro_size = 25); - else - current_macro = - (char *)xrealloc (current_macro, current_macro_size += 25); + /* 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; } - - current_macro[current_macro_index++] = c; - current_macro[current_macro_index] = '\0'; -} - -/* Begin defining a keyboard macro. - Keystrokes are recorded as they are executed. - End the definition with rl_end_kbd_macro (). - If a numeric argument was explicitly typed, then append this - definition to the end of the existing macro, and start by - re-executing the existing macro. */ -rl_start_kbd_macro (ignore1, ignore2) - int ignore1, ignore2; -{ - if (defining_kbd_macro) - rl_abort (); - - if (rl_explicit_arg) + else if (r && got_subseq) { - if (current_macro) - with_macro_input (savestring (current_macro)); + /* OK, back up the chain. */ + _rl_unget_char (key); + _rl_dispatching_keymap = map; + return -1; } - else - current_macro_index = 0; - - defining_kbd_macro = 1; -} - -/* Stop defining a keyboard macro. - A numeric argument says to execute the macro right now, - that many times, counting the definition as the first time. */ -rl_end_kbd_macro (count, ignore) - int count, ignore; -{ - if (!defining_kbd_macro) - rl_abort (); - current_macro_index -= (rl_key_sequence_length - 1); - current_macro[current_macro_index] = '\0'; - - defining_kbd_macro = 0; - - rl_call_last_kbd_macro (--count, 0); -} - -/* Execute the most recently defined keyboard macro. - COUNT says how many times to execute it. */ -rl_call_last_kbd_macro (count, ignore) - int count, ignore; -{ - if (!current_macro) - rl_abort (); - - while (count--) - with_macro_input (savestring (current_macro)); + return r; } - /* **************************************************************** */ /* */ /* Initializations */ /* */ /* **************************************************************** */ -/* Initliaze readline (and terminal if not already). */ +/* Initialize readline (and terminal if not already). */ +int rl_initialize () { - extern char *rl_display_prompt; - /* If we have never been called before, initialize the 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. */ - rl_point = rl_end = 0; - the_line = rl_line_buffer; - the_line[0] = 0; + _rl_init_line_state (); /* 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. */ - { - extern char *rl_display_prompt; - extern int forced_display; - - rl_on_new_line (); - - rl_display_prompt = rl_prompt ? rl_prompt : ""; - forced_display = 1; - } + 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. */ - parsing_conditionalized_out = 0; + _rl_parsing_conditionalized_out = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + _rl_vi_initialize_line (); +#endif + + /* Each line starts in insert mode (the default). */ + _rl_set_insert_mode (RL_IM_DEFAULT, 1); + + return 0; +} + +#if 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__ */ +#endif /* Initialize the entire state of the world. */ +static void readline_initialize_everything () { - /* Find out if we are running in Emacs. */ - running_in_emacs = getenv ("EMACS"); +#if 0 +#if defined (__EMX__) + if (environ == 0) + _emx_build_environ (); +#endif +#endif + +#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 aren't already. */ + /* 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) - rl_line_buffer = - (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); + if (rl_line_buffer == 0) + rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); /* Initialize the terminal interface. */ - 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 (); @@ -1140,5501 +1071,191 @@ readline_initialize_everything () /* 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) + { + _rl_screenwidth--; + _rl_screenchars -= _rl_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. */ - { - extern char *rl_completer_word_break_characters; - extern char *rl_basic_word_break_characters; - - if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = rl_basic_word_break_characters; - } + if (rl_completer_word_break_characters == (char *)NULL) + rl_completer_word_break_characters = (char *)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 () { -#ifndef __GO32__ - -#if defined (NEW_TTY_DRIVER) - struct sgttyb ttybuff; - int tty = fileno (rl_instream); - - if (ioctl (tty, TIOCGETP, &ttybuff) != -1) - { - int erase, kill; - - erase = ttybuff.sg_erase; - kill = ttybuff.sg_kill; - - if (erase != -1 && keymap[erase].type == ISFUNC) - keymap[erase].function = rl_rubout; - - if (kill != -1 && keymap[kill].type == ISFUNC) - keymap[kill].function = rl_unix_line_discard; - } - -#if defined (TIOCGLTC) - { - struct ltchars lt; - - if (ioctl (tty, TIOCGLTC, <) != -1) - { - int erase, nextc; - - erase = lt.t_werasc; - nextc = lt.t_lnextc; - - if (erase != -1 && keymap[erase].type == ISFUNC) - keymap[erase].function = rl_unix_word_rubout; - - if (nextc != -1 && keymap[nextc].type == ISFUNC) - keymap[nextc].function = rl_quoted_insert; - } - } -#endif /* TIOCGLTC */ -#else /* not NEW_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - struct termios ttybuff; -#else - struct termio ttybuff; -#endif /* TERMIOS_TTY_DRIVER */ - int tty = fileno (rl_instream); + if (_rl_bind_stty_chars) + rl_tty_set_default_bindings (_rl_keymap); +} -#if defined (TERMIOS_TTY_DRIVER) - if (tcgetattr (tty, &ttybuff) != -1) -#else - if (ioctl (tty, TCGETA, &ttybuff) != -1) -#endif /* !TERMIOS_TTY_DRIVER */ +/* Reset the default bindings for the terminal special characters we're + interested in back to rl_insert and read the new ones. */ +static void +reset_default_bindings () +{ + if (_rl_bind_stty_chars) { - int erase, kill; - - erase = ttybuff.c_cc[VERASE]; - kill = ttybuff.c_cc[VKILL]; - - if (erase != _POSIX_VDISABLE && - keymap[(unsigned char)erase].type == ISFUNC) - keymap[(unsigned char)erase].function = rl_rubout; - - if (kill != _POSIX_VDISABLE && - keymap[(unsigned char)kill].type == ISFUNC) - keymap[(unsigned char)kill].function = rl_unix_line_discard; - -#if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - { - int nextc; - - nextc = ttybuff.c_cc[VLNEXT]; - - if (nextc != _POSIX_VDISABLE && - keymap[(unsigned char)nextc].type == ISFUNC) - keymap[(unsigned char)nextc].function = rl_quoted_insert; - } -#endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -#if defined (VWERASE) - { - int werase; - - werase = ttybuff.c_cc[VWERASE]; - - if (werase != _POSIX_VDISABLE && - keymap[(unsigned char)werase].type == ISFUNC) - keymap[(unsigned char)werase].function = rl_unix_word_rubout; - } -#endif /* VWERASE */ + rl_tty_unset_default_bindings (_rl_keymap); + rl_tty_set_default_bindings (_rl_keymap); } -#endif /* !NEW_TTY_DRIVER */ -#endif /* def __GO32__ */ } - -/* **************************************************************** */ -/* */ -/* Numeric Arguments */ -/* */ -/* **************************************************************** */ - -/* Handle C-u style numeric args, as well as M--, and M-digits. */ - -/* Add the current digit to the argument in progress. */ -rl_digit_argument (ignore, key) - int ignore, key; +/* Bind some common arrow key sequences in MAP. */ +static void +bind_arrow_keys_internal (map) + Keymap map; { - rl_pending_input = key; - rl_digit_loop (); -} + Keymap xkeymap; -/* What to do when you abort reading an argument. */ -rl_discard_argument () -{ - ding (); - rl_clear_message (); - rl_init_argument (); -} + xkeymap = _rl_keymap; + _rl_keymap = map; -/* Create a default argument. */ -rl_init_argument () -{ - rl_numeric_arg = rl_arg_sign = 1; - rl_explicit_arg = 0; -} +#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 -/* 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. */ -rl_universal_argument () -{ - rl_numeric_arg *= 4; - rl_digit_loop (); + 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; } -rl_digit_loop () +/* 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 () { - int key, c; - while (1) - { - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - key = c = rl_read_key (); + bind_arrow_keys_internal (emacs_standard_keymap); - if (keymap[c].type == ISFUNC && - keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } - c = UNMETA (c); - if (numeric (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); - else - rl_numeric_arg = (c - '0'); - rl_explicit_arg = 1; - } - else - { - if (c == '-' && !rl_explicit_arg) - { - rl_numeric_arg = 1; - rl_arg_sign = -1; - } - else - { - rl_clear_message (); - rl_dispatch (key, keymap); - return; - } - } - } +#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 } - /* **************************************************************** */ /* */ -/* Display stuff */ +/* Saving and Restoring Readline's state */ /* */ /* **************************************************************** */ -/* This is the stuff that is hard for me. I never seem to write good - display routines in C. Let's see how I do this time. */ - -/* (PWP) Well... Good for a simple line updater, but totally ignores - the problems of input lines longer than the screen width. - - update_line and the code that calls it makes a multiple line, - automatically wrapping line update. Carefull attention needs - to be paid to the vertical position variables. - - handling of terminals with autowrap on (incl. DEC braindamage) - could be improved a bit. Right now I just cheat and decrement - screenwidth by one. */ - -/* Keep two buffers; one which reflects the current contents of the - screen, and the other to draw what we think the new contents should - be. Then compare the buffers, and make whatever changes to the - screen itself that we should. Finally, make the buffer that we - just drew into be the one which reflects the current contents of the - screen, and place the cursor where it belongs. - - Commands that want to can fix the display themselves, and then let - this function know that the display has been fixed by setting the - RL_DISPLAY_FIXED variable. This is good for efficiency. */ - -/* Termcap variables: */ -extern char *term_up, *term_dc, *term_cr; -extern int screenheight, screenwidth, terminal_can_insert; - -/* What YOU turn on when you have handled all redisplay yourself. */ -int rl_display_fixed = 0; - -/* The visible cursor position. If you print some text, adjust this. */ -int last_c_pos = 0; -int last_v_pos = 0; - -/* The last left edge of text that was displayed. This is used when - doing horizontal scrolling. It shifts in thirds of a screenwidth. */ -static int last_lmargin = 0; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static char *visible_line = (char *)NULL; -static char *invisible_line = (char *)NULL; - -/* Number of lines currently on screen minus 1. */ -int vis_botlin = 0; - -/* A buffer for `modeline' messages. */ -char msg_buf[128]; - -/* Non-zero forces the redisplay even if we thought it was unnecessary. */ -int forced_display = 0; - -/* The stuff that gets printed out before the actual text of the line. - This is usually pointing to rl_prompt. */ -char *rl_display_prompt = (char *)NULL; - -/* Default and initial buffer size. Can grow. */ -static int line_size = 1024; - -/* Non-zero means to always use horizontal scrolling in line display. */ -static int horizontal_scroll_mode = 0; - -/* Non-zero means to display an asterisk at the starts of history lines - which have been modified. */ -static int mark_modified_lines = 0; - -/* Non-zero means to use a visible bell if one is available rather than - simply ringing the terminal bell. */ -static int prefer_visible_bell = 0; - -/* I really disagree with this, but my boss (among others) insists that we - support compilers that don't work. I don't think we are gaining by doing - so; what is the advantage in producing better code if we can't use it? */ -/* The following two declarations belong inside the - function block, not here. */ -static void move_cursor_relative (); -static void output_some_chars (); -static void output_character_function (); -static int compare_strings (); - -/* Basic redisplay algorithm. */ -rl_redisplay () -{ - register int in, out, c, linenum; - register char *line = invisible_line; - char *prompt_this_line; - int c_pos = 0; - int inv_botlin = 0; /* Number of lines in newly drawn buffer. */ - - extern int readline_echoing_p; - - if (!readline_echoing_p) - return; - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (!invisible_line) - { - visible_line = (char *)xmalloc (line_size); - invisible_line = (char *)xmalloc (line_size); - line = invisible_line; - for (in = 0; in < line_size; in++) - { - visible_line[in] = 0; - invisible_line[in] = 1; - } - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - c_pos = -1; - - /* Mark the line as modified or not. We only do this for history - lines. */ - out = 0; - if (mark_modified_lines && current_history () && rl_undo_list) - { - line[out++] = '*'; - line[out] = '\0'; - } - - /* If someone thought that the redisplay was handled, but the currently - visible line has a different modification state than the one about - to become visible, then correct the callers misconception. */ - if (visible_line[0] != invisible_line[0]) - rl_display_fixed = 0; - - prompt_this_line = rindex (rl_display_prompt, '\n'); - if (!prompt_this_line) - prompt_this_line = rl_display_prompt; - else - { - prompt_this_line++; - if (forced_display) - output_some_chars (rl_display_prompt, - prompt_this_line - rl_display_prompt); - } - - strncpy (line + out, prompt_this_line, strlen (prompt_this_line)); - out += strlen (prompt_this_line); - line[out] = '\0'; - - for (in = 0; in < rl_end; in++) - { - c = (unsigned char)the_line[in]; - - if (out + 1 >= line_size) - { - line_size *= 2; - visible_line = (char *)xrealloc (visible_line, line_size); - invisible_line = (char *)xrealloc (invisible_line, line_size); - line = invisible_line; - } - - if (in == rl_point) - c_pos = out; - - if (c > 127) - { - line[out++] = 'M'; - line[out++] = '-'; - line[out++] = c - 128; - } -#define DISPLAY_TABS -#if defined (DISPLAY_TABS) - else if (c == '\t') - { - register int newout = (out | (int)7) + 1; - while (out < newout) - line[out++] = ' '; - } -#endif - else if (c < 32) - { - line[out++] = 'C'; - line[out++] = '-'; - line[out++] = c + 64; - } - else if (c == 127) - { - line[out++] = 'C'; - line[out++] = '-'; - line[out++] = '?'; - } - else - line[out++] = c; - } - line[out] = '\0'; - if (c_pos < 0) - c_pos = out; - - /* PWP: now is when things get a bit hairy. The visible and invisible - line buffers are really multiple lines, which would wrap every - (screenwidth - 1) characters. Go through each in turn, finding - the changed region and updating it. The line order is top to bottom. */ - - /* If we can move the cursor up and down, then use multiple lines, - otherwise, let long lines display in a single terminal line, and - horizontally scroll it. */ - - if (!horizontal_scroll_mode && term_up && *term_up) - { - int total_screen_chars = (screenwidth * screenheight); - - if (!rl_display_fixed || forced_display) - { - forced_display = 0; - - /* If we have more than a screenful of material to display, then - only display a screenful. We should display the last screen, - not the first. I'll fix this in a minute. */ - if (out >= total_screen_chars) - out = total_screen_chars - 1; - - /* Number of screen lines to display. */ - inv_botlin = out / screenwidth; - - /* For each line in the buffer, do the updating display. */ - for (linenum = 0; linenum <= inv_botlin; linenum++) - update_line (linenum > vis_botlin ? "" - : &visible_line[linenum * screenwidth], - &invisible_line[linenum * screenwidth], - linenum); - - /* We may have deleted some lines. If so, clear the left over - blank ones at the bottom out. */ - if (vis_botlin > inv_botlin) - { - char *tt; - for (; linenum <= vis_botlin; linenum++) - { - tt = &visible_line[linenum * screenwidth]; - move_vert (linenum); - move_cursor_relative (0, tt); - clear_to_eol ((linenum == vis_botlin)? - strlen (tt) : screenwidth); - } - } - vis_botlin = inv_botlin; - - /* Move the cursor where it should be. */ - move_vert (c_pos / screenwidth); - move_cursor_relative (c_pos % screenwidth, - &invisible_line[(c_pos / screenwidth) * screenwidth]); - } - } - else /* Do horizontal scrolling. */ - { - int lmargin; - - /* Always at top line. */ - last_v_pos = 0; - - /* If the display position of the cursor would be off the edge - of the screen, start the display of this line at an offset that - leaves the cursor on the screen. */ - if (c_pos - last_lmargin > screenwidth - 2) - lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3); - else if (c_pos - last_lmargin < 1) - lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3); - else - lmargin = last_lmargin; +int +rl_save_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + 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; - /* If the first character on the screen isn't the first character - in the display line, indicate this with a special character. */ - if (lmargin > 0) - line[lmargin] = '<'; + return (0); +} - if (lmargin + screenwidth < out) - line[lmargin + screenwidth - 1] = '>'; +int +rl_restore_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + 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; - if (!rl_display_fixed || forced_display || lmargin != last_lmargin) - { - forced_display = 0; - update_line (&visible_line[last_lmargin], - &invisible_line[lmargin], 0); - - move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (out_stream); - - /* Swap visible and non-visible lines. */ - { - char *temp = visible_line; - visible_line = invisible_line; - invisible_line = temp; - rl_display_fixed = 0; - } -} - -/* PWP: update_line() is based on finding the middle difference of each - line on the screen; vis: - - /old first difference - /beginning of line | /old last same /old EOL - v v v v -old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as -new: eddie> Oh, my little buggy says to me, as lurgid as - ^ ^ ^ ^ - \beginning of line | \new last same \new end of line - \new first difference - - All are character pointers for the sake of speed. Special cases for - no differences, as well as for end of line additions must be handeled. - - Could be made even smarter, but this works well enough */ -static -update_line (old, new, current_line) - register char *old, *new; - int current_line; -{ - register char *ofd, *ols, *oe, *nfd, *nls, *ne; - int lendiff, wsatend; - - /* Find first difference. */ - for (ofd = old, nfd = new; - (ofd - old < screenwidth) && *ofd && (*ofd == *nfd); - ofd++, nfd++) - ; - - /* Move to the end of the screen line. */ - for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++); - for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++); - - /* If no difference, continue to next line. */ - if (ofd == oe && nfd == ne) - return; - - wsatend = 1; /* flag for trailing whitespace */ - ols = oe - 1; /* find last same */ - nls = ne - 1; - while ((*ols == *nls) && (ols > ofd) && (nls > nfd)) - { - if (*ols != ' ') - wsatend = 0; - ols--; - nls--; - } - - if (wsatend) - { - ols = oe; - nls = ne; - } - else if (*ols != *nls) - { - if (*ols) /* don't step past the NUL */ - ols++; - if (*nls) - nls++; - } - - move_vert (current_line); - move_cursor_relative (ofd - old, old); - - /* if (len (new) > len (old)) */ - lendiff = (nls - nfd) - (ols - ofd); - - /* Insert (diff(len(old),len(new)) ch */ - if (lendiff > 0) - { - if (terminal_can_insert) - { - extern char *term_IC; - - /* Sometimes it is cheaper to print the characters rather than - use the terminal's capabilities. */ - if ((2 * (ne - nfd)) < lendiff && !term_IC) - { - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - } - else - { - if (*ols) - { - insert_some_chars (nfd, lendiff); - last_c_pos += lendiff; - } - else - { - /* At the end of a line the characters do not have to - be "inserted". They can just be placed on the screen. */ - output_some_chars (nfd, lendiff); - last_c_pos += lendiff; - } - /* Copy (new) chars to screen from first diff to last match. */ - if (((nls - nfd) - lendiff) > 0) - { - output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff)); - last_c_pos += ((nls - nfd) - lendiff); - } - } - } - else - { /* cannot insert chars, write to EOL */ - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - } - } - else /* Delete characters from line. */ - { - /* If possible and inexpensive to use terminal deletion, then do so. */ - if (term_dc && (2 * (ne - nfd)) >= (-lendiff)) - { - if (lendiff) - delete_chars (-lendiff); /* delete (diff) characters */ - - /* Copy (new) chars to screen from first diff to last match */ - if ((nls - nfd) > 0) - { - output_some_chars (nfd, (nls - nfd)); - last_c_pos += (nls - nfd); - } - } - /* Otherwise, print over the existing material. */ - else - { - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - clear_to_eol ((oe - old) - (ne - new)); - } - } -} - -/* (PWP) tell the update routines that we have moved onto a - new (empty) line. */ -rl_on_new_line () -{ - if (visible_line) - visible_line[0] = '\0'; - - last_c_pos = last_v_pos = 0; - vis_botlin = last_lmargin = 0; -} - -/* Actually update the display, period. */ -rl_forced_update_display () -{ - if (visible_line) - { - register char *temp = visible_line; - - while (*temp) *temp++ = '\0'; - } - rl_on_new_line (); - forced_display++; - rl_redisplay (); -} - -/* Move the cursor from last_c_pos to NEW, which are buffer indices. - DATA is the contents of the screen line of interest; i.e., where - the movement is being done. */ -static void -move_cursor_relative (new, data) - int new; - char *data; -{ - register int i; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - if (new + 1 < last_c_pos - new) - { -#ifdef __MSDOS__ - putc('\r', out_stream); -#else - tputs (term_cr, 1, output_character_function); -#endif - last_c_pos = 0; - } - - if (last_c_pos == new) return; - - if (last_c_pos < new) - { - /* Move the cursor forward. We do it by printing the command - to move the cursor forward if there is one, else print that - portion of the output buffer again. Which is cheaper? */ - - /* The above comment is left here for posterity. It is faster - to print one character (non-control) than to print a control - sequence telling the terminal to move forward one character. - That kind of control is for people who don't know what the - data is underneath the cursor. */ -#if defined (HACK_TERMCAP_MOTION) - extern char *term_forward_char; - - if (term_forward_char) - for (i = last_c_pos; i < new; i++) - tputs (term_forward_char, 1, output_character_function); - else - for (i = last_c_pos; i < new; i++) - putc (data[i], out_stream); -#else - for (i = last_c_pos; i < new; i++) - putc (data[i], out_stream); -#endif /* HACK_TERMCAP_MOTION */ - } - else - backspace (last_c_pos - new); - last_c_pos = new; -} - -/* PWP: move the cursor up or down. */ -move_vert (to) - int to; -{ - void output_character_function (); - register int delta, i; - - if (last_v_pos == to) return; - - if (to > screenheight) - return; - -#ifdef __GO32__ - { - int cur_r, cur_c; - ScreenGetCursor(&cur_r, &cur_c); - ScreenSetCursor(cur_r+to-last_v_pos, cur_c); - } -#else /* __GO32__ */ - if ((delta = to - last_v_pos) > 0) - { - for (i = 0; i < delta; i++) - putc ('\n', out_stream); - tputs (term_cr, 1, output_character_function); - last_c_pos = 0; - } - else - { /* delta < 0 */ - if (term_up && *term_up) - for (i = 0; i < -delta; i++) - tputs (term_up, 1, output_character_function); - } -#endif /* __GO32__ */ - last_v_pos = to; /* now to is here */ -} - -/* Physically print C on out_stream. This is for functions which know - how to optimize the display. */ -rl_show_char (c) - int c; -{ - if (c > 127) - { - fprintf (out_stream, "M-"); - c -= 128; - } - -#if defined (DISPLAY_TABS) - if (c < 32 && c != '\t') -#else - if (c < 32) -#endif - { - - c += 64; - } - - putc (c, out_stream); - fflush (out_stream); -} - -#if defined (DISPLAY_TABS) -int -rl_character_len (c, pos) - register int c, pos; -{ - if (c < ' ' || c > 126) - { - if (c == '\t') - return (((pos | (int)7) + 1) - pos); - else - return (3); - } - else - return (1); -} -#else -int -rl_character_len (c) - int c; -{ - if (c < ' ' || c > 126) - return (3); - else - return (1); -} -#endif /* DISPLAY_TAB */ - -/* How to print things in the "echo-area". The prompt is treated as a - mini-modeline. */ -rl_message (string, arg1, arg2) - char *string; -{ - sprintf (msg_buf, string, arg1, arg2); - rl_display_prompt = msg_buf; - rl_redisplay (); -} - -/* How to clear things from the "echo-area". */ -rl_clear_message () -{ - rl_display_prompt = rl_prompt; - rl_redisplay (); -} - -/* **************************************************************** */ -/* */ -/* Terminal and Termcap */ -/* */ -/* **************************************************************** */ - -static char *term_buffer = (char *)NULL; -static char *term_string_buffer = (char *)NULL; - -/* Non-zero means this terminal can't really do anything. */ -int dumb_term = 0; - -/* On Solaris2, sys/types.h brings in sys/reg.h, - which screws up the Termcap variable PC, used below. */ - -#undef PC - -char PC; -char *BC, *UP; - -/* Some strings to control terminal actions. These are output by tputs (). */ -char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; - -int screenwidth, screenheight; - -/* Non-zero if we determine that the terminal can do character insertion. */ -int terminal_can_insert = 0; - -/* How to insert characters. */ -char *term_im, *term_ei, *term_ic, *term_ip, *term_IC; - -/* How to delete characters. */ -char *term_dc, *term_DC; - -#if defined (HACK_TERMCAP_MOTION) -char *term_forward_char; -#endif /* HACK_TERMCAP_MOTION */ - -/* How to go up a line. */ -char *term_up; - -/* A visible bell, if the terminal can be made to flash the screen. */ -char *visible_bell; - -/* Re-initialize the terminal considering that the TERM/TERMCAP variable - has changed. */ -rl_reset_terminal (terminal_name) - char *terminal_name; -{ - init_terminal_io (terminal_name); -} - -init_terminal_io (terminal_name) - char *terminal_name; -{ -#ifdef __GO32__ - screenwidth = ScreenCols(); - screenheight = ScreenRows(); - term_cr = "\r"; - term_im = term_ei = term_ic = term_IC = (char *)NULL; - term_up = term_dc = term_DC = visible_bell = (char *)NULL; -#if defined (HACK_TERMCAP_MOTION) - term_forward_char = (char *)NULL; -#endif - terminal_can_insert = 0; - return; -#else - extern char *tgetstr (); - char *term, *buffer; -#if defined (TIOCGWINSZ) - struct winsize window_size; -#endif - int tty; - - term = terminal_name ? terminal_name : getenv ("TERM"); - - if (!term_string_buffer) - term_string_buffer = (char *)xmalloc (2048); - - if (!term_buffer) - term_buffer = (char *)xmalloc (2048); - - buffer = term_string_buffer; - - term_clrpag = term_cr = term_clreol = (char *)NULL; - - if (!term) - term = "dumb"; - - if (tgetent (term_buffer, term) < 0) - { - dumb_term = 1; - screenwidth = 79; - screenheight = 24; - term_cr = "\r"; - term_im = term_ei = term_ic = term_IC = (char *)NULL; - term_up = term_dc = term_DC = visible_bell = (char *)NULL; -#if defined (HACK_TERMCAP_MOTION) - term_forward_char = (char *)NULL; -#endif - terminal_can_insert = 0; - return; - } - - BC = tgetstr ("pc", &buffer); - PC = buffer ? *buffer : 0; - - term_backspace = tgetstr ("le", &buffer); - - term_cr = tgetstr ("cr", &buffer); - term_clreol = tgetstr ("ce", &buffer); - term_clrpag = tgetstr ("cl", &buffer); - - if (!term_cr) - term_cr = "\r"; - -#if defined (HACK_TERMCAP_MOTION) - term_forward_char = tgetstr ("nd", &buffer); -#endif /* HACK_TERMCAP_MOTION */ - - if (rl_instream) - tty = fileno (rl_instream); - else - tty = 0; - - screenwidth = screenheight = 0; -#if defined (TIOCGWINSZ) - if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) - { - screenwidth = (int) window_size.ws_col; - screenheight = (int) window_size.ws_row; - } -#endif - - if (screenwidth <= 0 || screenheight <= 0) - { - screenwidth = tgetnum ("co"); - screenheight = tgetnum ("li"); - } - - screenwidth--; - - if (screenwidth <= 0) - screenwidth = 79; - - if (screenheight <= 0) - screenheight = 24; - - term_im = tgetstr ("im", &buffer); - term_ei = tgetstr ("ei", &buffer); - term_IC = tgetstr ("IC", &buffer); - term_ic = tgetstr ("ic", &buffer); - - /* "An application program can assume that the terminal can do - character insertion if *any one of* the capabilities `IC', - `im', `ic' or `ip' is provided." But we can't do anything if - only `ip' is provided, so... */ - terminal_can_insert = (term_IC || term_im || term_ic); - - term_up = tgetstr ("up", &buffer); - term_dc = tgetstr ("dc", &buffer); - term_DC = tgetstr ("DC", &buffer); - - visible_bell = tgetstr ("vb", &buffer); -#endif /* !__GO32__ */ -} - -/* A function for the use of tputs () */ -static void -output_character_function (c) - int c; -{ - putc (c, out_stream); -} - -/* Write COUNT characters from STRING to the output stream. */ -static void -output_some_chars (string, count) - char *string; - int count; -{ - fwrite (string, 1, count, out_stream); -} - -/* Delete COUNT characters from the display line. */ -static -delete_chars (count) - int count; -{ -#ifdef __GO32__ - int r, c, w; - ScreenGetCursor(&r, &c); - w = ScreenCols(); - memcpy(ScreenPrimary+r*w+c, ScreenPrimary+r*w+c+count, w-c-count); - memset(ScreenPrimary+r*w+w-count, 0, count*2); -#else /* __GO32__ */ - if (count > screenwidth) - return; - - if (term_DC && *term_DC) - { - char *tgoto (), *buffer; - buffer = tgoto (term_DC, 0, count); - tputs (buffer, 1, output_character_function); - } - else - { - if (term_dc && *term_dc) - while (count--) - tputs (term_dc, 1, output_character_function); - } -#endif /* __GO32__ */ -} - -/* Insert COUNT characters from STRING to the output stream. */ -static void -insert_some_chars (string, count) - char *string; - int count; -{ -#ifdef __GO32__ - int r, c, w; - ScreenGetCursor(&r, &c); - w = ScreenCols(); - memcpy(ScreenPrimary+r*w+c+count, ScreenPrimary+r*w+c, w-c-count); - /* Print the text. */ - output_some_chars (string, count); -#else /* __GO32__ */ - /* If IC is defined, then we do not have to "enter" insert mode. */ - if (term_IC) - { - char *tgoto (), *buffer; - buffer = tgoto (term_IC, 0, count); - tputs (buffer, 1, output_character_function); - output_some_chars (string, count); - } - else - { - register int i; - - /* If we have to turn on insert-mode, then do so. */ - if (term_im && *term_im) - tputs (term_im, 1, output_character_function); - - /* If there is a special command for inserting characters, then - use that first to open up the space. */ - if (term_ic && *term_ic) - { - for (i = count; i--; ) - tputs (term_ic, 1, output_character_function); - } - - /* Print the text. */ - output_some_chars (string, count); - - /* If there is a string to turn off insert mode, we had best use - it now. */ - if (term_ei && *term_ei) - tputs (term_ei, 1, output_character_function); - } -#endif /* __GO32__ */ -} - -/* Move the cursor back. */ -backspace (count) - int count; -{ - register int i; - -#ifndef __GO32__ - if (term_backspace) - for (i = 0; i < count; i++) - tputs (term_backspace, 1, output_character_function); - else -#endif /* !__GO32__ */ - for (i = 0; i < count; i++) - putc ('\b', out_stream); -} - -/* Move to the start of the next line. */ -crlf () -{ -#if defined (NEW_TTY_DRIVER) - tputs (term_cr, 1, output_character_function); -#endif /* NEW_TTY_DRIVER */ - putc ('\n', out_stream); -} - -/* Clear to the end of the line. COUNT is the minimum - number of character spaces to clear, */ -clear_to_eol (count) - int count; -{ -#ifndef __GO32__ - if (term_clreol) - { - tputs (term_clreol, 1, output_character_function); - } - else -#endif /* !__GO32__ */ - { - register int i; - - /* Do one more character space. */ - count++; - - for (i = 0; i < count; i++) - putc (' ', out_stream); - - backspace (count); - } -} - - -/* **************************************************************** */ -/* */ -/* Saving and Restoring the TTY */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that the terminal is in a prepped state. */ -static int terminal_prepped = 0; - -#if defined (NEW_TTY_DRIVER) - -/* Standard flags, including ECHO. */ -static int original_tty_flags = 0; - -/* Local mode flags, like LPASS8. */ -static int local_mode_flags = 0; - -/* Terminal characters. This has C-s and C-q in it. */ -static struct tchars original_tchars; - -/* Local special characters. This has the interrupt characters in it. */ -#if defined (TIOCGLTC) -static struct ltchars original_ltchars; -#endif - -/* We use this to get and set the tty_flags. */ -static struct sgttyb the_ttybuff; - -/* Put the terminal in CBREAK mode so that we can detect key presses. */ -static void -rl_prep_terminal () -{ -#ifndef __GO32__ - int tty = fileno (rl_instream); -#if defined (HAVE_BSD_SIGNALS) - int oldmask; -#endif /* HAVE_BSD_SIGNALS */ - - if (terminal_prepped) - return; - - oldmask = sigblock (sigmask (SIGINT)); - - /* We always get the latest tty values. Maybe stty changed them. */ - ioctl (tty, TIOCGETP, &the_ttybuff); - original_tty_flags = the_ttybuff.sg_flags; - - readline_echoing_p = (original_tty_flags & ECHO); - -#if defined (TIOCLGET) - ioctl (tty, TIOCLGET, &local_mode_flags); -#endif - -#if !defined (ANYP) -# define ANYP (EVENP | ODDP) -#endif - - /* If this terminal doesn't care how the 8th bit is used, - then we can use it for the meta-key. We check by seeing - if BOTH odd and even parity are allowed. */ - if (the_ttybuff.sg_flags & ANYP) - { -#if defined (PASS8) - the_ttybuff.sg_flags |= PASS8; -#endif - - /* Hack on local mode flags if we can. */ -#if defined (TIOCLGET) && defined (LPASS8) - { - int flags; - flags = local_mode_flags | LPASS8; - ioctl (tty, TIOCLSET, &flags); - } -#endif /* TIOCLGET && LPASS8 */ - } - -#if defined (TIOCGETC) - { - struct tchars temp; - - ioctl (tty, TIOCGETC, &original_tchars); - temp = original_tchars; - -#if defined (USE_XON_XOFF) - /* Get rid of C-s and C-q. - We remember the value of startc (C-q) so that if the terminal is in - xoff state, the user can xon it by pressing that character. */ - xon_char = temp.t_startc; - temp.t_stopc = -1; - temp.t_startc = -1; - - /* If there is an XON character, bind it to restart the output. */ - if (xon_char != -1) - rl_bind_key (xon_char, rl_restart_output); -#endif /* USE_XON_XOFF */ - - /* If there is an EOF char, bind eof_char to it. */ - if (temp.t_eofc != -1) - eof_char = temp.t_eofc; - -#if defined (NO_KILL_INTR) - /* Get rid of C-\ and C-c. */ - temp.t_intrc = temp.t_quitc = -1; -#endif /* NO_KILL_INTR */ - - ioctl (tty, TIOCSETC, &temp); - } -#endif /* TIOCGETC */ - -#if defined (TIOCGLTC) - { - struct ltchars temp; - - ioctl (tty, TIOCGLTC, &original_ltchars); - temp = original_ltchars; - - /* Make the interrupt keys go away. Just enough to make people - happy. */ - temp.t_dsuspc = -1; /* C-y */ - temp.t_lnextc = -1; /* C-v */ - - ioctl (tty, TIOCSLTC, &temp); - } -#endif /* TIOCGLTC */ - - the_ttybuff.sg_flags &= ~(ECHO | CRMOD); - the_ttybuff.sg_flags |= CBREAK; - ioctl (tty, TIOCSETN, &the_ttybuff); - - terminal_prepped = 1; - -#if defined (HAVE_BSD_SIGNALS) - sigsetmask (oldmask); -#endif -#endif /* !__GO32__ */ -} - -/* Restore the terminal to its original state. */ -static void -rl_deprep_terminal () -{ -#ifndef __GO32__ - int tty = fileno (rl_instream); -#if defined (HAVE_BSD_SIGNALS) - int oldmask; -#endif - - if (!terminal_prepped) - return; - - oldmask = sigblock (sigmask (SIGINT)); - - the_ttybuff.sg_flags = original_tty_flags; - ioctl (tty, TIOCSETN, &the_ttybuff); - readline_echoing_p = 1; - -#if defined (TIOCLGET) - ioctl (tty, TIOCLSET, &local_mode_flags); -#endif - -#if defined (TIOCSLTC) - ioctl (tty, TIOCSLTC, &original_ltchars); -#endif - -#if defined (TIOCSETC) - ioctl (tty, TIOCSETC, &original_tchars); -#endif - terminal_prepped = 0; - -#if defined (HAVE_BSD_SIGNALS) - sigsetmask (oldmask); -#endif -#endif /* !__GO32 */ -} - -#else /* !defined (NEW_TTY_DRIVER) */ - -#if !defined (VMIN) -#define VMIN VEOF -#endif - -#if !defined (VTIME) -#define VTIME VEOL -#endif - -#ifndef __GO32__ -#if defined (TERMIOS_TTY_DRIVER) -static struct termios otio; -#else -static struct termio otio; -#endif /* !TERMIOS_TTY_DRIVER */ -#endif /* __GO32__ */ - -static void -rl_prep_terminal () -{ -#ifndef __GO32__ - int tty = fileno (rl_instream); -#if defined (TERMIOS_TTY_DRIVER) - struct termios tio; -#else - struct termio tio; -#endif /* !TERMIOS_TTY_DRIVER */ - -#if defined (HAVE_POSIX_SIGNALS) - sigset_t set, oset; -#else -# if defined (HAVE_BSD_SIGNALS) - int oldmask; -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - if (terminal_prepped) - return; - - /* Try to keep this function from being INTerrupted. We can do it - on POSIX and systems with BSD-like signal handling. */ -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&set); - sigaddset (&set, SIGINT); - sigprocmask (SIG_BLOCK, &set, &oset); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - oldmask = sigblock (sigmask (SIGINT)); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#if defined (TERMIOS_TTY_DRIVER) - tcgetattr (tty, &tio); -#else - ioctl (tty, TCGETA, &tio); -#endif /* !TERMIOS_TTY_DRIVER */ - - otio = tio; - - readline_echoing_p = (tio.c_lflag & ECHO); - - tio.c_lflag &= ~(ICANON|ECHO); - - if (otio.c_cc[VEOF] != _POSIX_VDISABLE) - eof_char = otio.c_cc[VEOF]; - -#if defined (USE_XON_XOFF) -#if defined (IXANY) - tio.c_iflag &= ~(IXON|IXOFF|IXANY); -#else - /* `strict' Posix systems do not define IXANY. */ - tio.c_iflag &= ~(IXON|IXOFF); -#endif /* IXANY */ -#endif /* USE_XON_XOFF */ - - /* Only turn this off if we are using all 8 bits. */ - /* |ISTRIP|INPCK */ - tio.c_iflag &= ~(ISTRIP | INPCK); - - /* Make sure we differentiate between CR and NL on input. */ - tio.c_iflag &= ~(ICRNL | INLCR); - -#if !defined (HANDLE_SIGNALS) - tio.c_lflag &= ~ISIG; -#else - tio.c_lflag |= ISIG; -#endif - - tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; - - /* Turn off characters that we need on Posix systems with job control, - just to be sure. This includes ^Y and ^V. This should not really - be necessary. */ -#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL) - -#if defined (VLNEXT) - tio.c_cc[VLNEXT] = _POSIX_VDISABLE; -#endif - -#if defined (VDSUSP) - tio.c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif - -#endif /* POSIX && JOB_CONTROL */ - -#if defined (TERMIOS_TTY_DRIVER) - tcsetattr (tty, TCSADRAIN, &tio); - tcflow (tty, TCOON); /* Simulate a ^Q. */ -#else - ioctl (tty, TCSETAW, &tio); - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -#endif /* !TERMIOS_TTY_DRIVER */ - - terminal_prepped = 1; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (oldmask); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ -#endif /* !__GO32__ */ -} - -static void -rl_deprep_terminal () -{ -#ifndef __GO32__ - int tty = fileno (rl_instream); - - /* Try to keep this function from being INTerrupted. We can do it - on POSIX and systems with BSD-like signal handling. */ -#if defined (HAVE_POSIX_SIGNALS) - sigset_t set, oset; -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - int oldmask; -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - if (!terminal_prepped) - return; - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&set); - sigaddset (&set, SIGINT); - sigprocmask (SIG_BLOCK, &set, &oset); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - oldmask = sigblock (sigmask (SIGINT)); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#if defined (TERMIOS_TTY_DRIVER) - tcsetattr (tty, TCSADRAIN, &otio); - tcflow (tty, TCOON); /* Simulate a ^Q. */ -#else /* TERMIOS_TTY_DRIVER */ - ioctl (tty, TCSETAW, &otio); - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -#endif /* !TERMIOS_TTY_DRIVER */ - - terminal_prepped = 0; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (oldmask); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ -#endif /* !__GO32__ */ -} -#endif /* NEW_TTY_DRIVER */ - - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Return 0 if C is not a member of the class of characters that belong - in words, or 1 if it is. */ - -int allow_pathname_alphabetic_chars = 0; -char *pathname_alphabetic_chars = "/-_=~.#$"; - -int -alphabetic (c) - int c; -{ - if (pure_alphabetic (c) || (numeric (c))) - return (1); - - if (allow_pathname_alphabetic_chars) - return ((int)rindex (pathname_alphabetic_chars, c)); - else - return (0); -} - -/* Return non-zero if C is a numeric character. */ -int -numeric (c) - int c; -{ - return (c >= '0' && c <= '9'); -} - -/* Ring the terminal bell. */ -int -ding () -{ - if (readline_echoing_p) - { -#ifndef __GO32__ - if (prefer_visible_bell && visible_bell) - tputs (visible_bell, 1, output_character_function); - else -#endif /* !__GO32__ */ - { - fprintf (stderr, "\007"); - fflush (stderr); - } - } - return (-1); -} - -/* How to abort things. */ -rl_abort () -{ - ding (); - rl_clear_message (); - rl_init_argument (); - rl_pending_input = 0; - - defining_kbd_macro = 0; - while (executing_macro) - pop_executing_macro (); - - rl_last_func = (Function *)NULL; - longjmp (readline_top_level, 1); -} - -/* Return a copy of the string between FROM and TO. - FROM is inclusive, TO is not. */ -#if defined (sun) /* Yes, that's right, some crufty function in sunview is - called rl_copy (). */ -static -#endif -char * -rl_copy (from, to) - int from, to; -{ - register int length; - char *copy; - - /* Fix it if the caller is confused. */ - if (from > to) - { - int t = from; - from = to; - to = t; - } - - length = to - from; - copy = (char *)xmalloc (1 + length); - strncpy (copy, the_line + from, length); - copy[length] = '\0'; - return (copy); -} - -/* Increase the size of RL_LINE_BUFFER until it has enough space to hold - LEN characters. */ -void -rl_extend_line_buffer (len) - int len; -{ - while (len >= rl_line_buffer_len) - rl_line_buffer = - (char *)xrealloc - (rl_line_buffer, rl_line_buffer_len += DEFAULT_BUFFER_SIZE); - - the_line = rl_line_buffer; -} - - -/* **************************************************************** */ -/* */ -/* 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. */ -rl_insert_text (string) - char *string; -{ - extern int doing_an_undo; - 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 (!doing_an_undo) - { - /* If possible and desirable, concatenate the undos. */ - if ((strlen (string) == 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'; -} - -/* Delete the string between FROM and TO. FROM is - inclusive, TO is not. */ -rl_delete_text (from, to) - int from, to; -{ - extern int doing_an_undo; - register char *text; - - /* Fix it if the caller is confused. */ - if (from > to) - { - int t = from; - from = to; - to = t; - } - text = rl_copy (from, to); - strncpy (the_line + from, the_line + to, rl_end - to); - - /* Remember how to undo this delete. */ - if (!doing_an_undo) - rl_add_undo (UNDO_DELETE, from, to, text); - else - free (text); - - rl_end -= (to - from); - the_line[rl_end] = '\0'; -} - - -/* **************************************************************** */ -/* */ -/* 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. */ -rl_forward (count) - int count; -{ - if (count < 0) - rl_backward (-count); - else - while (count) - { -#if defined (VI_MODE) - if (rl_point == (rl_end - (rl_editing_mode == vi_mode))) -#else - if (rl_point == rl_end) -#endif /* VI_MODE */ - { - ding (); - return; - } - else - rl_point++; - --count; - } -} - -/* Move backward COUNT characters. */ -rl_backward (count) - int count; -{ - if (count < 0) - rl_forward (-count); - else - while (count) - { - if (!rl_point) - { - ding (); - return; - } - else - --rl_point; - --count; - } -} - -/* Move to the beginning of the line. */ -rl_beg_of_line () -{ - rl_point = 0; -} - -/* Move to the end of the line. */ -rl_end_of_line () -{ - rl_point = rl_end; -} - -/* Move forward a word. We do what Emacs does. */ -rl_forward_word (count) - int count; -{ - int c; - - if (count < 0) - { - rl_backward_word (-count); - return; - } - - while (count) - { - if (rl_point == rl_end) - return; - - /* 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)) - { - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (alphabetic (c)) break; - } - } - if (rl_point == rl_end) return; - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (!alphabetic (c)) break; - } - --count; - } -} - -/* Move backward a word. We do what Emacs does. */ -rl_backward_word (count) - int count; -{ - int c; - - if (count < 0) - { - rl_forward_word (-count); - return; - } - - while (count) - { - if (!rl_point) - return; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - c = the_line[rl_point - 1]; - if (!alphabetic (c)) - { - 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)) - break; - else --rl_point; - } - --count; - } -} - -/* Clear the current line. Numeric argument to C-l does this. */ -rl_refresh_line () -{ - int curr_line = last_c_pos / screenwidth; - extern char *term_clreol; - - move_vert(curr_line); - move_cursor_relative (0, the_line); /* XXX is this right */ - -#ifdef __GO32__ - { - int r, c, w; - ScreenGetCursor(&r, &c); - w = ScreenCols(); - memset(ScreenPrimary+r*w+c, 0, (w-c)*2); - } -#else /* __GO32__ */ - if (term_clreol) - tputs (term_clreol, 1, output_character_function); -#endif /* __GO32__/else */ - - rl_forced_update_display (); - rl_display_fixed = 1; -} - -/* 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. */ -rl_clear_screen () -{ - extern char *term_clrpag; - - if (rl_explicit_arg) - { - rl_refresh_line (); - return; - } - -#ifndef __GO32__ - if (term_clrpag) - tputs (term_clrpag, 1, output_character_function); - else -#endif /* !__GO32__ */ - crlf (); - - rl_forced_update_display (); - rl_display_fixed = 1; -} - -rl_arrow_keys (count, c) - int count, c; -{ - int ch; - - ch = rl_read_key (); - - switch (to_upper (ch)) - { - case 'A': - rl_get_previous_history (count); - break; - - case 'B': - rl_get_next_history (count); - break; - - case 'C': - rl_forward (count); - break; - - case 'D': - rl_backward (count); - break; - - default: - ding (); - } -} - - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -/* Insert the character C at the current location, moving point forward. */ -rl_insert (count, c) - int count, c; -{ - register int i; - char *string; - - if (count <= 0) - return; - - /* 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 = (char *)alloca (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; - - string[i] = '\0'; - rl_insert_text (string); - return; - } - - if (count > 1024) - { - int decreaser; - - string = (char *)alloca (1024 + 1); - - for (i = 0; i < 1024; i++) - string[i] = c; - - while (count) - { - decreaser = (count > 1024 ? 1024 : count); - string[decreaser] = '\0'; - rl_insert_text (string); - count -= decreaser; - } - return; - } - - /* 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 (any_typein) - { - int key = 0, t; - - i = 0; - string = (char *)alloca (ibuffer_len + 1); - string[i++] = c; - - while ((t = rl_get_char (&key)) && - (keymap[key].type == ISFUNC && - keymap[key].function == rl_insert)) - string[i++] = key; - - if (t) - rl_unget_char (key); - - string[i] = '\0'; - rl_insert_text (string); - return; - } - else - { - /* Inserting a single character. */ - string = (char *)alloca (2); - - string[1] = '\0'; - string[0] = c; - rl_insert_text (string); - } -} - -/* Insert the next typed character verbatim. */ -rl_quoted_insert (count) - int count; -{ - int c = rl_read_key (); - rl_insert (count, c); -} - -/* Insert a tab character. */ -rl_tab_insert (count) - int count; -{ - 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. */ -rl_newline (count, key) - int count, key; -{ - - rl_done = 1; - -#if defined (VI_MODE) - { - extern int vi_doing_insert; - if (vi_doing_insert) - { - rl_end_undo_group (); - vi_doing_insert = 0; - } - } -#endif /* VI_MODE */ - - if (readline_echoing_p) - { - move_vert (vis_botlin); - vis_botlin = 0; - crlf (); - fflush (out_stream); - rl_display_fixed++; - } -} - -rl_clean_up_for_exit () -{ - if (readline_echoing_p) - { - move_vert (vis_botlin); - vis_botlin = 0; - fflush (out_stream); - rl_restart_output (); - } -} - -/* 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. */ -rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; -{ -} - -/* Rubout the character behind point. */ -rl_rubout (count) - int count; -{ - if (count < 0) - { - rl_delete (-count); - return; - } - - if (!rl_point) - { - ding (); - return; - } - - if (count > 1) - { - int orig_point = rl_point; - rl_backward (count); - 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 && alphabetic (c) && last_c_pos) - { - backspace (1); - putc (' ', out_stream); - backspace (1); - last_c_pos--; - visible_line[last_c_pos] = '\0'; - rl_display_fixed++; - } - } -} - -/* Delete the character under the cursor. Given a numeric argument, - kill that many characters instead. */ -rl_delete (count, invoking_key) - int count, invoking_key; -{ - if (count < 0) - { - rl_rubout (-count); - return; - } - - if (rl_point == rl_end) - { - ding (); - return; - } - - if (count > 1) - { - int orig_point = rl_point; - rl_forward (count); - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - } - else - rl_delete_text (rl_point, rl_point + 1); -} - - -/* **************************************************************** */ -/* */ -/* Kill commands */ -/* */ -/* **************************************************************** */ - -/* The next two functions mimic unix line editing behaviour, except they - save the deleted text on the kill ring. This is safer than not saving - it, and since we have a ring, nobody should get screwed. */ - -/* This does what C-w does in Unix. We can't prevent people from - using behaviour that they expect. */ -rl_unix_word_rubout () -{ - if (!rl_point) ding (); - else { - int orig_point = rl_point; - while (rl_point && whitespace (the_line[rl_point - 1])) - rl_point--; - while (rl_point && !whitespace (the_line[rl_point - 1])) - rl_point--; - rl_kill_text (rl_point, orig_point); - } -} - -/* Here is C-u doing what Unix does. You don't *have* to use these - key-bindings. We have a choice of killing the entire line, or - killing from where we are to the start of the line. We choose the - latter, because if you are a Unix weenie, then you haven't backspaced - into the line at all, and if you aren't, then you know what you are - doing. */ -rl_unix_line_discard () -{ - if (!rl_point) ding (); - else { - rl_kill_text (rl_point, 0); - rl_point = 0; - } -} - - - -/* **************************************************************** */ -/* */ -/* Commands For Typos */ -/* */ -/* **************************************************************** */ - -/* Random and interesting things in here. */ - -/* **************************************************************** */ -/* */ -/* 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. */ -rl_upcase_word (count) - int count; -{ - rl_change_case (count, UpCase); -} - -/* Lowercase the word at point. */ -rl_downcase_word (count) - int count; -{ - rl_change_case (count, DownCase); -} - -/* Upcase the first letter, downcase the rest. */ -rl_capitalize_word (count) - int count; -{ - 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. */ -rl_change_case (count, op) - int count, op; -{ - register int start = rl_point, end; - int state = 0; - - rl_forward_word (count); - end = rl_point; - - if (count < 0) - { - int temp = start; - start = end; - end = temp; - } - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - for (; start < end; start++) - { - switch (op) - { - case UpCase: - the_line[start] = to_upper (the_line[start]); - break; - - case DownCase: - the_line[start] = to_lower (the_line[start]); - break; - - case CapCase: - if (state == 0) - { - the_line[start] = to_upper (the_line[start]); - state = 1; - } - else - { - the_line[start] = to_lower (the_line[start]); - } - if (!pure_alphabetic (the_line[start])) - state = 0; - break; - - default: - abort (); - } - } - rl_point = end; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. */ -rl_transpose_words (count) - int count; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) return; - - /* Find the two words. */ - rl_forward_word (count); - w2_end = rl_point; - rl_backward_word (1); - w2_beg = rl_point; - rl_backward_word (count); - w1_beg = rl_point; - rl_forward_word (1); - 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; - } - - /* Get the text of the words. */ - word1 = rl_copy (w1_beg, w1_end); - word2 = rl_copy (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); -} - -/* Transpose the characters at point. If point is at the end of the line, - then transpose the characters before point. */ -rl_transpose_chars (count) - int count; -{ - if (!count) - return; - - if (!rl_point || rl_end < 2) { - ding (); - return; - } - - while (count) - { - if (rl_point == rl_end) - { - int t = the_line[rl_point - 1]; - - the_line[rl_point - 1] = the_line[rl_point - 2]; - the_line[rl_point - 2] = t; - } - else - { - int t = the_line[rl_point]; - - the_line[rl_point] = the_line[rl_point - 1]; - the_line[rl_point - 1] = t; - - if (count < 0 && rl_point) - rl_point--; - else - rl_point++; - } - - if (count < 0) - count++; - else - count--; - } -} - - -/* **************************************************************** */ -/* */ -/* Bogus Flow Control */ -/* */ -/* **************************************************************** */ - -rl_restart_output (count, key) - int count, key; -{ - int fildes = fileno (rl_outstream); -#if defined (TIOCSTART) -#if defined (apollo) - ioctl (&fildes, TIOCSTART, 0); -#else - ioctl (fildes, TIOCSTART, 0); -#endif /* apollo */ - -#else -# if defined (TERMIOS_TTY_DRIVER) - tcflow (fildes, TCOON); -# else -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* TIOCSTART */ -} - -rl_stop_output (count, key) - int count, key; -{ - int fildes = fileno (rl_instream); - -#if defined (TIOCSTOP) -# if defined (apollo) - ioctl (&fildes, TIOCSTOP, 0); -# else - ioctl (fildes, TIOCSTOP, 0); -# endif /* apollo */ -#else -# if defined (TERMIOS_TTY_DRIVER) - tcflow (fildes, TCOOFF); -# else -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* TIOCSTOP */ -} - -/* **************************************************************** */ -/* */ -/* Completion matching, from readline's point of view. */ -/* */ -/* **************************************************************** */ - -/* Pointer to the generator function for completion_matches (). - NULL means to use filename_entry_function (), the default filename - completer. */ -Function *rl_completion_entry_function = (Function *)NULL; - -/* Pointer to alternative function to create matches. - Function is called with TEXT, START, and END. - START and END are indices in RL_LINE_BUFFER saying what the boundaries - of TEXT are. - If this function exists and returns NULL then call the value of - rl_completion_entry_function to try to match, otherwise use the - array of strings returned. */ -Function *rl_attempted_completion_function = (Function *)NULL; - -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer = 0; - -/* Complete the word at or before point. You have supplied the function - that does the initial simple matching selection algorithm (see - completion_matches ()). The default is to do filename completion. */ - -rl_complete (ignore, invoking_key) - int ignore, invoking_key; -{ - if (rl_last_func == rl_complete && !completion_changed_buffer) - rl_complete_internal ('?'); - else - rl_complete_internal (TAB); -} - -/* List the possible completions. See description of rl_complete (). */ -rl_possible_completions () -{ - rl_complete_internal ('?'); -} - -/* The user must press "y" or "n". Non-zero return means "y" pressed. */ -get_y_or_n () -{ - int c; - loop: - c = rl_read_key (); - if (c == 'y' || c == 'Y') return (1); - if (c == 'n' || c == 'N') return (0); - if (c == ABORT_CHAR) rl_abort (); - ding (); goto loop; -} - -/* Up to this many items will be displayed in response to a - possible-completions call. After that, we ask the user if - she is sure she wants to see them all. */ -int rl_completion_query_items = 100; - -/* The basic list of characters that signal a break between words for the - completer routine. The contents of this variable is what breaks words - in the shell, i.e. " \t\n\"\\'`@$><=" */ -char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; - -/* The list of characters that signal a break between words for - rl_complete_internal. The default list is the contents of - rl_basic_word_break_characters. */ -char *rl_completer_word_break_characters = (char *)NULL; - -/* The list of characters which are used to quote a substring of the command - line. Command completion occurs on the entire substring, and within the - substring rl_completer_word_break_characters are treated as any other - character, unless they also appear within this list. */ -char *rl_completer_quote_characters = (char *)NULL; - -/* List of characters that are word break characters, but should be left - in TEXT when it is passed to the completion function. The shell uses - this to help determine what kind of completing to do. */ -char *rl_special_prefixes = (char *)NULL; - -/* If non-zero, then disallow duplicates in the matches. */ -int rl_ignore_completion_duplicates = 1; - -/* Non-zero means that the results of the matches are to be treated - as filenames. This is ALWAYS zero on entry, and can only be changed - within a completion entry finder function. */ -int rl_filename_completion_desired = 0; - -/* This function, if defined, is called by the completer when real - filename completion is done, after all the matching names have been - generated. It is passed a (char**) known as matches in the code below. - It consists of a NULL-terminated array of pointers to potential - matching strings. The 1st element (matches[0]) is the maximal - substring that is common to all matches. This function can re-arrange - the list of matches as required, but all elements of the array must be - free()'d if they are deleted. The main intent of this function is - to implement FIGNORE a la SunOS csh. */ -Function *rl_ignore_some_completions_function = (Function *)NULL; - -/* Complete the word at or before point. - WHAT_TO_DO says what to do with the completion. - `?' means list the possible completions. - TAB means do standard completion. - `*' means insert all of the possible completions. */ -rl_complete_internal (what_to_do) - int what_to_do; -{ - char *filename_completion_function (); - char **completion_matches (), **matches; - Function *our_func; - int start, scan, end, delimiter = 0; - char *text, *saved_line_buffer; - char quote_char = '\0'; - char *replacement; - - if (the_line) - saved_line_buffer = savestring (the_line); - else - saved_line_buffer = (char *)NULL; - - if (rl_completion_entry_function) - our_func = rl_completion_entry_function; - else - our_func = (int (*)())filename_completion_function; - - /* Only the completion entry function can change this. */ - rl_filename_completion_desired = 0; - - /* We now look backwards for the start of a filename/variable word. */ - end = rl_point; - - if (rl_point) - { - if (rl_completer_quote_characters) - { - /* We have a list of characters which can be used in pairs to quote - substrings for completion. Try to find the start of an unclosed - quoted substring. - FIXME: Doesn't yet handle '\' escapes to hid embedded quotes */ - for (scan = 0; scan < end; scan++) - { - if (quote_char != '\0') - { - /* Ignore everything until the matching close quote char */ - if (the_line[scan] == quote_char) - { - /* Found matching close quote. Abandon this substring. */ - quote_char = '\0'; - rl_point = end; - } - } - else if (rindex (rl_completer_quote_characters, the_line[scan])) - { - /* Found start of a quoted substring. */ - quote_char = the_line[scan]; - rl_point = scan + 1; - } - } - } - if (rl_point == end) - { - /* We didn't find an unclosed quoted substring upon which to do - completion, so use the word break characters to find the - substring on which to do completion. */ - while (--rl_point && - !rindex (rl_completer_word_break_characters, - the_line[rl_point])) {;} - } - - /* If we are at a word break, then advance past it. */ - if (rindex (rl_completer_word_break_characters, the_line[rl_point])) - { - /* If the character that caused the word break was a quoting - character, then remember it as the delimiter. */ - if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1) - delimiter = the_line[rl_point]; - - /* If the character isn't needed to determine something special - about what kind of completion to perform, then advance past it. */ - - if (!rl_special_prefixes || - !rindex (rl_special_prefixes, the_line[rl_point])) - rl_point++; - } - } - - start = rl_point; - rl_point = end; - text = rl_copy (start, end); - - /* If the user wants to TRY to complete, but then wants to give - up and use the default completion function, they set the - variable rl_attempted_completion_function. */ - if (rl_attempted_completion_function) - { - matches = - (char **)(*rl_attempted_completion_function) (text, start, end); - - if (matches) - { - our_func = (Function *)NULL; - goto after_usual_completion; - } - } - - matches = completion_matches (text, our_func); - - after_usual_completion: - free (text); - - if (!matches) - ding (); - else - { - register int i; - - some_matches: - - /* It seems to me that in all the cases we handle we would like - to ignore duplicate possibilities. Scan for the text to - insert being identical to the other completions. */ - if (rl_ignore_completion_duplicates) - { - char *lowest_common; - int j, newlen = 0; - - /* Sort the items. */ - /* It is safe to sort this array, because the lowest common - denominator found in matches[0] will remain in place. */ - for (i = 0; matches[i]; i++); - qsort (matches, i, sizeof (char *), compare_strings); - - /* Remember the lowest common denominator for it may be unique. */ - lowest_common = savestring (matches[0]); - - for (i = 0; matches[i + 1]; i++) - { - if (strcmp (matches[i], matches[i + 1]) == 0) - { - free (matches[i]); - matches[i] = (char *)-1; - } - else - newlen++; - } - - /* We have marked all the dead slots with (char *)-1. - Copy all the non-dead entries into a new array. */ - { - char **temp_array = - (char **)malloc ((3 + newlen) * sizeof (char *)); - - for (i = 1, j = 1; matches[i]; i++) - { - if (matches[i] != (char *)-1) - temp_array[j++] = matches[i]; - } - - temp_array[j] = (char *)NULL; - - if (matches[0] != (char *)-1) - free (matches[0]); - - free (matches); - - matches = temp_array; - } - - /* Place the lowest common denominator back in [0]. */ - matches[0] = lowest_common; - - /* If there is one string left, and it is identical to the - lowest common denominator, then the LCD is the string to - insert. */ - if (j == 2 && strcmp (matches[0], matches[1]) == 0) - { - free (matches[1]); - matches[1] = (char *)NULL; - } - } - - switch (what_to_do) - { - case TAB: - /* If we are matching filenames, then here is our chance to - do clever processing by re-examining the list. Call the - ignore function with the array as a parameter. It can - munge the array, deleting matches as it desires. */ - if (rl_ignore_some_completions_function && - our_func == (int (*)())filename_completion_function) - (void)(*rl_ignore_some_completions_function)(matches); - - /* If we are doing completions on quoted substrings, and any matches - contain any of the completer word break characters, then auto- - matically prepend the substring with a quote character (just - pick the first one from the list of such) if it does not already - begin with a quote string. FIXME: Need to remove any such - automatically inserted quote character when it no longer is - necessary, such as if we change the string we are completing on - and the new set of matches don't require a quoted substring? */ - - replacement = matches[0]; - if (matches[0] != NULL - && rl_completer_quote_characters != NULL - && (quote_char == '\0')) - { - for (i = 1; matches[i] != NULL; i++) - { - if (strpbrk (matches[i], rl_completer_word_break_characters)) - { - /* Found an embedded word break character in a potential - match, so need to prepend a quote character if we are - replacing the completion string. */ - replacement = alloca (strlen (matches[0]) + 2); - quote_char = *rl_completer_quote_characters; - *replacement = quote_char; - strcpy (replacement + 1, matches[0]); - break; - } - } - } - if (replacement) - { - rl_delete_text (start, rl_point); - rl_point = start; - rl_insert_text (replacement); - } - - /* If there are more matches, ring the bell to indicate. - If this was the only match, and we are hacking files, - check the file to see if it was a directory. If so, - add a '/' to the name. If not, and we are at the end - of the line, then add a space. */ - if (matches[1]) - { - ding (); /* There are other matches remaining. */ - } - else - { - char temp_string[16]; - int temp_index = 0; - - if (quote_char) - { - temp_string[temp_index++] = quote_char; - } - temp_string[temp_index++] = delimiter ? delimiter : ' '; - temp_string[temp_index++] = '\0'; - - if (rl_filename_completion_desired) - { - struct stat finfo; - char *filename = tilde_expand (matches[0]); - - if ((stat (filename, &finfo) == 0) && - S_ISDIR (finfo.st_mode)) - { - if (the_line[rl_point] != '/') - rl_insert_text ("/"); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - free (filename); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - } - break; - - case '*': - { - int i = 1; - - rl_delete_text (start, rl_point); - rl_point = start; - rl_begin_undo_group (); - if (matches[1]) - { - while (matches[i]) - { - rl_insert_text (matches[i++]); - rl_insert_text (" "); - } - } - else - { - rl_insert_text (matches[0]); - rl_insert_text (" "); - } - rl_end_undo_group (); - } - break; - - case '?': - { - int len, count, limit, max = 0; - int j, k, l; - - /* Handle simple case first. What if there is only one answer? */ - if (!matches[1]) - { - char *temp; - - if (rl_filename_completion_desired) - temp = rindex (matches[0], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[0]; - else - temp++; - - crlf (); - fprintf (out_stream, "%s", temp); - crlf (); - goto restart; - } - - /* There is more than one answer. Find out how many there are, - and find out what the maximum printed length of a single entry - is. */ - for (i = 1; matches[i]; i++) - { - char *temp = (char *)NULL; - - /* If we are hacking filenames, then only count the characters - after the last slash in the pathname. */ - if (rl_filename_completion_desired) - temp = rindex (matches[i], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[i]; - else - temp++; - - if (strlen (temp) > max) - max = strlen (temp); - } - - len = i; - - /* If there are many items, then ask the user if she - really wants to see them all. */ - if (len >= rl_completion_query_items) - { - crlf (); - fprintf (out_stream, - "There are %d possibilities. Do you really", len); - crlf (); - fprintf (out_stream, "wish to see them all? (y or n)"); - fflush (out_stream); - if (!get_y_or_n ()) - { - crlf (); - goto restart; - } - } - /* How many items of MAX length can we fit in the screen window? */ - max += 2; - limit = screenwidth / max; - if (limit != 1 && (limit * max == screenwidth)) - limit--; - - /* Avoid a possible floating exception. If max > screenwidth, - limit will be 0 and a divide-by-zero fault will result. */ - if (limit == 0) - limit = 1; - - /* How many iterations of the printing loop? */ - count = (len + (limit - 1)) / limit; - - /* Watch out for special case. If LEN is less than LIMIT, then - just do the inner printing loop. */ - if (len < limit) count = 1; - - /* Sort the items if they are not already sorted. */ - if (!rl_ignore_completion_duplicates) - qsort (matches, len, sizeof (char *), compare_strings); - - /* Print the sorted items, up-and-down alphabetically, like - ls might. */ - crlf (); - - for (i = 1; i < count + 1; i++) - { - for (j = 0, l = i; j < limit; j++) - { - if (l > len || !matches[l]) - { - break; - } - else - { - char *temp = (char *)NULL; - - if (rl_filename_completion_desired) - temp = rindex (matches[l], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[l]; - else - temp++; - - fprintf (out_stream, "%s", temp); - for (k = 0; k < max - strlen (temp); k++) - putc (' ', out_stream); - } - l += count; - } - crlf (); - } - restart: - - rl_on_new_line (); - } - break; - - default: - abort (); - } - - for (i = 0; matches[i]; i++) - free (matches[i]); - free (matches); - } - - /* Check to see if the line has changed through all of this manipulation. */ - if (saved_line_buffer) - { - if (strcmp (the_line, saved_line_buffer) != 0) - completion_changed_buffer = 1; - else - completion_changed_buffer = 0; - - free (saved_line_buffer); - } -} - -/* Stupid comparison routine for qsort () ing strings. */ -static int -compare_strings (s1, s2) - char **s1, **s2; -{ - return (strcmp (*s1, *s2)); -} - -/* A completion function for usernames. - TEXT contains a partial username preceded by a random - character (usually `~'). */ -char * -username_completion_function (text, state) - int state; - char *text; -{ -#ifdef __GO32__ - return (char *)NULL; -#else /* !__GO32__ */ - static char *username = (char *)NULL; - static struct passwd *entry; - static int namelen, first_char, first_char_loc; - - if (!state) - { - if (username) - free (username); - - first_char = *text; - - if (first_char == '~') - first_char_loc = 1; - else - first_char_loc = 0; - - username = savestring (&text[first_char_loc]); - namelen = strlen (username); - setpwent (); - } - - while (entry = getpwent ()) - { - if (strncmp (username, entry->pw_name, namelen) == 0) - break; - } - - if (!entry) - { - endpwent (); - return ((char *)NULL); - } - else - { - char *value = (char *)xmalloc (2 + strlen (entry->pw_name)); - - *value = *text; - - strcpy (value + first_char_loc, entry->pw_name); - - if (first_char == '~') - rl_filename_completion_desired = 1; - - return (value); - } -#endif /* !__GO32__ */ -} - -/* **************************************************************** */ -/* */ -/* Undo, and Undoing */ -/* */ -/* **************************************************************** */ - -/* Non-zero tells rl_delete_text and rl_insert_text to not add to - the undo list. */ -int doing_an_undo = 0; - -/* The current undo list for THE_LINE. */ -UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; - -/* Remember how to undo something. Concatenate some undos if that - seems right. */ -rl_add_undo (what, start, end, text) - enum undo_code what; - int start, end; - char *text; -{ - UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); - temp->what = what; - temp->start = start; - temp->end = end; - temp->text = text; - temp->next = rl_undo_list; - rl_undo_list = temp; -} - -/* Free the existing undo list. */ -free_undo_list () -{ - while (rl_undo_list) { - UNDO_LIST *release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - - if (release->what == UNDO_DELETE) - free (release->text); - - free (release); - } -} - -/* Undo the next thing in the list. Return 0 if there - is nothing to undo, or non-zero if there was. */ -int -rl_do_undo () -{ - UNDO_LIST *release; - int waiting_for_begin = 0; - -undo_thing: - if (!rl_undo_list) - return (0); - - doing_an_undo = 1; - - switch (rl_undo_list->what) { - - /* Undoing deletes means inserting some text. */ - case UNDO_DELETE: - rl_point = rl_undo_list->start; - rl_insert_text (rl_undo_list->text); - free (rl_undo_list->text); - break; - - /* Undoing inserts means deleting some text. */ - case UNDO_INSERT: - rl_delete_text (rl_undo_list->start, rl_undo_list->end); - rl_point = rl_undo_list->start; - break; - - /* Undoing an END means undoing everything 'til we get to - a BEGIN. */ - case UNDO_END: - waiting_for_begin++; - break; - - /* Undoing a BEGIN means that we are done with this group. */ - case UNDO_BEGIN: - if (waiting_for_begin) - waiting_for_begin--; - else - abort (); - break; - } - - doing_an_undo = 0; - - release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - free (release); - - if (waiting_for_begin) - goto undo_thing; - - return (1); -} - -/* Begin a group. Subsequent undos are undone as an atomic operation. */ -rl_begin_undo_group () -{ - rl_add_undo (UNDO_BEGIN, 0, 0, 0); -} - -/* End an undo group started with rl_begin_undo_group (). */ -rl_end_undo_group () -{ - rl_add_undo (UNDO_END, 0, 0, 0); -} - -/* Save an undo entry for the text from START to END. */ -rl_modifying (start, end) - int start, end; -{ - if (start > end) - { - int t = start; - start = end; - end = t; - } - - if (start != end) - { - char *temp = rl_copy (start, end); - rl_begin_undo_group (); - rl_add_undo (UNDO_DELETE, start, end, temp); - rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); - rl_end_undo_group (); - } -} - -/* Revert the current line to its previous state. */ -rl_revert_line () -{ - if (!rl_undo_list) ding (); - else { - while (rl_undo_list) - rl_do_undo (); - } -} - -/* Do some undoing of things that were done. */ -rl_undo_command (count) -{ - if (count < 0) return; /* Nothing to do. */ - - while (count) - { - if (rl_do_undo ()) - { - count--; - } - else - { - ding (); - break; - } - } -} - -/* **************************************************************** */ -/* */ -/* History Utilities */ -/* */ -/* **************************************************************** */ - -/* We already have a history library, and that is what we use to control - the history features of readline. However, 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. */ -start_using_history () -{ - using_history (); - if (saved_line_for_history) - free_history_entry (saved_line_for_history); - - saved_line_for_history = (HIST_ENTRY *)NULL; -} - -/* Free the contents (and containing structure) of a HIST_ENTRY. */ -free_history_entry (entry) - HIST_ENTRY *entry; -{ - if (!entry) return; - if (entry->line) - free (entry->line); - free (entry); -} - -/* Perhaps put back the current line if it has changed. */ -maybe_replace_line () -{ - HIST_ENTRY *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); - } -} - -/* Put back the saved_line_for_history if there is one. */ -maybe_unsave_line () -{ - if (saved_line_for_history) - { - int line_len; - - 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; - free_history_entry (saved_line_for_history); - saved_line_for_history = (HIST_ENTRY *)NULL; - rl_end = rl_point = strlen (the_line); - } - else - ding (); -} - -/* Save the current line in saved_line_for_history. */ -maybe_save_line () -{ - if (!saved_line_for_history) - { - 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; - } -} - -/* **************************************************************** */ -/* */ -/* History Commands */ -/* */ -/* **************************************************************** */ - -/* Meta-< goes to the start of the history. */ -rl_beginning_of_history () -{ - rl_get_previous_history (1 + where_history ()); -} - -/* Meta-> goes to the end of the history. (The current line). */ -rl_end_of_history () -{ - maybe_replace_line (); - using_history (); - maybe_unsave_line (); -} - -/* Move down to the next history line. */ -rl_get_next_history (count) - int count; -{ - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; - - if (count < 0) - { - rl_get_previous_history (-count); - return; - } - - if (!count) - return; - - maybe_replace_line (); - - while (count) - { - temp = next_history (); - if (!temp) - break; - --count; - } - - if (!temp) - maybe_unsave_line (); - else - { - int line_len; - - 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 */ - } -} - -/* Get the previous item out of our interactive history, making it the current - line. If there is no previous history, just ding. */ -rl_get_previous_history (count) - int count; -{ - HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL; - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; - - if (count < 0) - { - rl_get_next_history (-count); - return; - } - - if (!count) - return; - - /* 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 (); - - while (count) - { - temp = previous_history (); - if (!temp) - break; - else - 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) - ding (); - else - { - int line_len; - - 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 */ - } -} - - -/* **************************************************************** */ -/* */ -/* I-Search and Searching */ -/* */ -/* **************************************************************** */ - -/* Search backwards through the history looking for a string which is typed - interactively. Start with the current line. */ -rl_reverse_search_history (sign, key) - int sign; - int key; -{ - rl_search_history (-sign, key); -} - -/* Search forwards through the history looking for a string which is typed - interactively. Start with the current line. */ -rl_forward_search_history (sign, key) - int sign; - int key; -{ - rl_search_history (sign, key); -} - -/* Display the current state of the search in the echo-area. - SEARCH_STRING contains the string that is being searched for, - DIRECTION is zero for forward, or 1 for reverse, - WHERE is the history list number of the current line. If it is - -1, then this line is the starting one. */ -rl_display_search (search_string, reverse_p, where) - char *search_string; - int reverse_p, where; -{ - char *message = (char *)NULL; - - message = - (char *)alloca (1 + (search_string ? strlen (search_string) : 0) + 30); - - *message = '\0'; - -#if defined (NOTDEF) - if (where != -1) - sprintf (message, "[%d]", where + history_base); -#endif /* NOTDEF */ - - strcat (message, "("); - - if (reverse_p) - strcat (message, "reverse-"); - - strcat (message, "i-search)`"); - - if (search_string) - strcat (message, search_string); - - strcat (message, "': "); - rl_message (message, 0, 0); - rl_redisplay (); -} - -/* Search through the history looking for an interactively typed string. - This is analogous to i-search. We start the search in the current line. - DIRECTION is which direction to search; >= 0 means forward, < 0 means - backwards. */ -rl_search_history (direction, invoking_key) - int direction; - int invoking_key; -{ - /* The string that the user types in to search for. */ - char *search_string = (char *)alloca (128); - - /* The current length of SEARCH_STRING. */ - int search_string_index; - - /* The list of lines to search through. */ - char **lines; - - /* The length of LINES. */ - int hlen; - - /* Where we get LINES from. */ - HIST_ENTRY **hlist = history_list (); - - register int i = 0; - int orig_point = rl_point; - int orig_line = where_history (); - int last_found_line = orig_line; - int c, done = 0; - - /* The line currently being searched. */ - char *sline; - - /* Offset in that line. */ - int index; - - /* Non-zero if we are doing a reverse search. */ - int reverse = (direction < 0); - - /* Create an arrary of pointers to the lines that we want to search. */ - maybe_replace_line (); - if (hlist) - for (i = 0; hlist[i]; i++); - - /* Allocate space for this many lines, +1 for the current input line, - and remember those lines. */ - lines = (char **)alloca ((1 + (hlen = i)) * sizeof (char *)); - for (i = 0; i < hlen; i++) - lines[i] = hlist[i]->line; - - if (saved_line_for_history) - lines[i] = saved_line_for_history->line; - else - /* So I have to type it in this way instead. */ - { - char *alloced_line; - - /* Keep that mips alloca happy. */ - alloced_line = (char *)alloca (1 + strlen (the_line)); - lines[i] = alloced_line; - strcpy (lines[i], &the_line[0]); - } - - hlen++; - - /* The line where we start the search. */ - i = orig_line; - - /* Initialize search parameters. */ - *search_string = '\0'; - search_string_index = 0; - - /* Normalize DIRECTION into 1 or -1. */ - if (direction >= 0) - direction = 1; - else - direction = -1; - - rl_display_search (search_string, reverse, -1); - - sline = the_line; - index = rl_point; - - while (!done) - { - c = rl_read_key (); - - /* Hack C to Do What I Mean. */ - { - Function *f = (Function *)NULL; - - if (keymap[c].type == ISFUNC) - { - f = keymap[c].function; - - if (f == rl_reverse_search_history) - c = reverse ? -1 : -2; - else if (f == rl_forward_search_history) - c = !reverse ? -1 : -2; - } - } - - switch (c) - { - case ESC: - done = 1; - continue; - - /* case invoking_key: */ - case -1: - goto search_again; - - /* switch directions */ - case -2: - direction = -direction; - reverse = (direction < 0); - - goto do_search; - - case CTRL ('G'): - strcpy (the_line, lines[orig_line]); - rl_point = orig_point; - rl_end = strlen (the_line); - rl_clear_message (); - return; - - default: - if (c < 32 || c > 126) - { - rl_execute_next (c); - done = 1; - continue; - } - else - { - search_string[search_string_index++] = c; - search_string[search_string_index] = '\0'; - goto do_search; - - search_again: - - if (!search_string_index) - continue; - else - { - if (reverse) - --index; - else - if (index != strlen (sline)) - ++index; - else - ding (); - } - do_search: - - while (1) - { - if (reverse) - { - while (index >= 0) - if (strncmp - (search_string, sline + index, search_string_index) - == 0) - goto string_found; - else - index--; - } - else - { - register int limit = - (strlen (sline) - search_string_index) + 1; - - while (index < limit) - { - if (strncmp (search_string, - sline + index, - search_string_index) == 0) - goto string_found; - index++; - } - } - - next_line: - i += direction; - - /* At limit for direction? */ - if ((reverse && i < 0) || - (!reverse && i == hlen)) - goto search_failed; - - sline = lines[i]; - if (reverse) - index = strlen (sline); - else - index = 0; - - /* If the search string is longer than the current - line, no match. */ - if (search_string_index > strlen (sline)) - goto next_line; - - /* Start actually searching. */ - if (reverse) - index -= search_string_index; - } - - search_failed: - /* We cannot find the search string. Ding the bell. */ - ding (); - i = last_found_line; - break; - - string_found: - /* We have found the search string. Just display it. But don't - actually move there in the history list until the user accepts - the location. */ - { - int line_len; - - line_len = strlen (lines[i]); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (the_line, lines[i]); - rl_point = index; - rl_end = line_len; - last_found_line = i; - rl_display_search - (search_string, reverse, (i == orig_line) ? -1 : i); - } - } - } - continue; - } - - /* The searching is over. The user may have found the string that she - was looking for, or else she may have exited a failing search. If - INDEX is -1, then that shows that the string searched for was not - found. We use this to determine where to place rl_point. */ - { - int now = last_found_line; - - /* First put back the original state. */ - strcpy (the_line, lines[orig_line]); - - if (now < orig_line) - rl_get_previous_history (orig_line - now); - else - rl_get_next_history (now - orig_line); - - /* If the index of the "matched" string is less than zero, then the - final search string was never matched, so put point somewhere - reasonable. */ - if (index < 0) - index = strlen (the_line); - - rl_point = index; - rl_clear_message (); - } -} - -/* Make C be the next command to be executed. */ -rl_execute_next (c) - int c; -{ - rl_pending_input = c; -} - -/* **************************************************************** */ -/* */ -/* Killing Mechanism */ -/* */ -/* **************************************************************** */ - -/* What we assume for a max number of kills. */ -#define DEFAULT_MAX_KILLS 10 - -/* The real variable to look at to find out when to flush kills. */ -int rl_max_kills = DEFAULT_MAX_KILLS; - -/* Where to store killed text. */ -char **rl_kill_ring = (char **)NULL; - -/* Where we are in the kill ring. */ -int rl_kill_index = 0; - -/* How many slots we have in the kill ring. */ -int rl_kill_ring_length = 0; - -/* How to say that you only want to save a certain amount - of kill material. */ -rl_set_retained_kills (num) - int num; -{} - -/* The way to kill something. This appends or prepends to the last - kill, if the last command was a kill command. if FROM is less - than TO, then the text is appended, otherwise prepended. If the - last command was not a kill command, then a new slot is made for - this kill. */ -rl_kill_text (from, to) - int from, to; -{ - int slot; - char *text = rl_copy (from, to); - - /* Is there anything to kill? */ - if (from == to) - { - free (text); - last_command_was_kill++; - return; - } - - /* Delete the copied text from the line. */ - rl_delete_text (from, to); - - /* First, find the slot to work with. */ - if (!last_command_was_kill) - { - /* Get a new slot. */ - if (!rl_kill_ring) - { - /* If we don't have any defined, then make one. */ - rl_kill_ring = (char **) - xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); - slot = 1; - } - else - { - /* We have to add a new slot on the end, unless we have - exceeded the max limit for remembering kills. */ - slot = rl_kill_ring_length; - if (slot == rl_max_kills) - { - register int i; - free (rl_kill_ring[0]); - for (i = 0; i < slot; i++) - rl_kill_ring[i] = rl_kill_ring[i + 1]; - } - else - { - rl_kill_ring = - (char **) - xrealloc (rl_kill_ring, - ((slot = (rl_kill_ring_length += 1)) + 1) - * sizeof (char *)); - } - } - slot--; - } - else - { - slot = rl_kill_ring_length - 1; - } - - /* If the last command was a kill, prepend or append. */ - if (last_command_was_kill && rl_editing_mode != vi_mode) - { - char *old = rl_kill_ring[slot]; - char *new = (char *)xmalloc (1 + strlen (old) + strlen (text)); - - if (from < to) - { - strcpy (new, old); - strcat (new, text); - } - else - { - strcpy (new, text); - strcat (new, old); - } - free (old); - free (text); - rl_kill_ring[slot] = new; - } - else - { - rl_kill_ring[slot] = text; - } - rl_kill_index = slot; - last_command_was_kill++; -} - -/* Now REMEMBER! In order to do prepending or appending correctly, kill - commands always make rl_point's original position be the FROM argument, - and rl_point's extent be the TO argument. */ - -/* **************************************************************** */ -/* */ -/* Killing Commands */ -/* */ -/* **************************************************************** */ - -/* Delete the word at point, saving the text in the kill ring. */ -rl_kill_word (count) - int count; -{ - int orig_point = rl_point; - - if (count < 0) - rl_backward_kill_word (-count); - else - { - rl_forward_word (count); - - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); - - rl_point = orig_point; - } -} - -/* Rubout the word before point, placing it on the kill ring. */ -rl_backward_kill_word (count) - int count; -{ - int orig_point = rl_point; - - if (count < 0) - rl_kill_word (-count); - else - { - rl_backward_word (count); - - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); - } -} - -/* Kill from here to the end of the line. If DIRECTION is negative, kill - back to the line start instead. */ -rl_kill_line (direction) - int direction; -{ - int orig_point = rl_point; - - if (direction < 0) - rl_backward_kill_line (1); - else - { - rl_end_of_line (); - if (orig_point != rl_point) - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - } -} - -/* Kill backwards to the start of the line. If DIRECTION is negative, kill - forwards to the line end instead. */ -rl_backward_kill_line (direction) - int direction; -{ - int orig_point = rl_point; - - if (direction < 0) - rl_kill_line (1); - else - { - if (!rl_point) - ding (); - else - { - rl_beg_of_line (); - rl_kill_text (orig_point, rl_point); - } - } -} - -/* Yank back the last killed text. This ignores arguments. */ -rl_yank () -{ - if (!rl_kill_ring) rl_abort (); - rl_insert_text (rl_kill_ring[rl_kill_index]); -} - -/* If the last command was yank, or yank_pop, and the text just - before point is identical to the current kill item, then - delete that text from the line, rotate the index down, and - yank back some other text. */ -rl_yank_pop () -{ - int l; - - if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || - !rl_kill_ring) - { - rl_abort (); - } - - l = strlen (rl_kill_ring[rl_kill_index]); - if (((rl_point - l) >= 0) && - (strncmp (the_line + (rl_point - l), - rl_kill_ring[rl_kill_index], l) == 0)) - { - rl_delete_text ((rl_point - l), rl_point); - rl_point -= l; - rl_kill_index--; - if (rl_kill_index < 0) - rl_kill_index = rl_kill_ring_length - 1; - rl_yank (); - } - else - rl_abort (); - -} - -/* Yank the COUNTth argument from the previous history line. */ -rl_yank_nth_arg (count, ignore) - int count; -{ - register HIST_ENTRY *entry = previous_history (); - char *arg; - - if (entry) - next_history (); - else - { - ding (); - return; - } - - arg = history_arg_extract (count, count, entry->line); - if (!arg || !*arg) - { - ding (); - return; - } - - rl_begin_undo_group (); - -#if defined (VI_MODE) - /* Vi mode always inserts a space befoe yanking the argument, and it - inserts it right *after* rl_point. */ - if (rl_editing_mode == vi_mode) - rl_point++; -#endif /* VI_MODE */ - - if (rl_point && the_line[rl_point - 1] != ' ') - rl_insert_text (" "); - - rl_insert_text (arg); - free (arg); - - rl_end_undo_group (); -} - -/* How to toggle back and forth between editing modes. */ -rl_vi_editing_mode () -{ -#if defined (VI_MODE) - rl_editing_mode = vi_mode; - rl_vi_insertion_mode (); -#endif /* VI_MODE */ -} - -rl_emacs_editing_mode () -{ - rl_editing_mode = emacs_mode; - keymap = emacs_standard_keymap; -} - - -/* **************************************************************** */ -/* */ -/* Completion */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that case is not significant in completion. */ -int completion_case_fold = 0; - -/* Return an array of (char *) which is a list of completions for TEXT. - If there are no completions, return a NULL pointer. - The first entry in the returned array is the substitution for TEXT. - The remaining entries are the possible completions. - The array is terminated with a NULL pointer. - - ENTRY_FUNCTION is a function of two args, and returns a (char *). - The first argument is TEXT. - The second is a state argument; it should be zero on the first call, and - non-zero on subsequent calls. It returns a NULL pointer to the caller - when there are no more matches. - */ -char ** -completion_matches (text, entry_function) - char *text; - char *(*entry_function) (); -{ - /* Number of slots in match_list. */ - int match_list_size; - - /* The list of matches. */ - char **match_list = - (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *)); - - /* Number of matches actually found. */ - int matches = 0; - - /* Temporary string binder. */ - char *string; - - match_list[1] = (char *)NULL; - - while (string = (*entry_function) (text, matches)) - { - if (matches + 1 == match_list_size) - match_list = (char **)xrealloc - (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); - - match_list[++matches] = string; - match_list[matches + 1] = (char *)NULL; - } - - /* If there were any matches, then look through them finding out the - lowest common denominator. That then becomes match_list[0]. */ - if (matches) - { - register int i = 1; - int low = 100000; /* Count of max-matched characters. */ - - /* If only one match, just use that. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - } - else - { - /* Otherwise, compare each member of the list with - the next, finding out where they stop matching. */ - - while (i < matches) - { - register int c1, c2, si; - - if (completion_case_fold) - { - for (si = 0; - (c1 = to_lower(match_list[i][si])) && - (c2 = to_lower(match_list[i + 1][si])); - si++) - if (c1 != c2) break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) - if (c1 != c2) break; - } - - if (low > si) low = si; - i++; - } - match_list[0] = (char *)xmalloc (low + 1); - strncpy (match_list[0], match_list[1], low); - match_list[0][low] = '\0'; - } - } - else /* There were no matches. */ - { - free (match_list); - match_list = (char **)NULL; - } - return (match_list); -} - -/* Okay, now we write the entry_function for filename completion. In the - general case. Note that completion in the shell is a little different - because of all the pathnames that must be followed when looking up the - completion for a command. */ -char * -filename_completion_function (text, state) - int state; - char *text; -{ - static DIR *directory; - static char *filename = (char *)NULL; - static char *dirname = (char *)NULL; - static char *users_dirname = (char *)NULL; - static int filename_len; - - dirent *entry = (dirent *)NULL; - - /* If we don't have any state, then do some initialization. */ - if (!state) - { - char *temp; - - if (dirname) free (dirname); - if (filename) free (filename); - if (users_dirname) free (users_dirname); - - filename = savestring (text); - if (!*text) text = "."; - dirname = savestring (text); - - temp = rindex (dirname, '/'); - - if (temp) - { - strcpy (filename, ++temp); - *temp = '\0'; - } - else - strcpy (dirname, "."); - - /* We aren't done yet. We also support the "~user" syntax. */ - - /* Save the version of the directory that the user typed. */ - users_dirname = savestring (dirname); - { - char *temp_dirname; - - temp_dirname = tilde_expand (dirname); - free (dirname); - dirname = temp_dirname; - - if (rl_symbolic_link_hook) - (*rl_symbolic_link_hook) (&dirname); - } - directory = opendir (dirname); - filename_len = strlen (filename); - - rl_filename_completion_desired = 1; - } - - /* At this point we should entertain the possibility of hacking wildcarded - filenames, like /usr/man/man/te. If the directory name - contains globbing characters, then build an array of directories to - glob on, and glob on the first one. */ - - /* Now that we have some state, we can read the directory. */ - - while (directory && (entry = readdir (directory))) - { - /* Special case for no filename. - All entries except "." and ".." match. */ - if (!filename_len) - { - if ((strcmp (entry->d_name, ".") != 0) && - (strcmp (entry->d_name, "..") != 0)) - break; - } - else - { - /* Otherwise, if these match upto the length of filename, then - it is a match. */ - if (entry->d_name[0] == filename[0] && /* Quick test */ - (strncmp (filename, entry->d_name, filename_len) == 0)) - { - break; - } - } - } - - if (!entry) - { - if (directory) - { - closedir (directory); - directory = (DIR *)NULL; - } - return (char *)NULL; - } - else - { - char *temp; - - if (dirname && (strcmp (dirname, ".") != 0)) - { - temp = (char *) - xmalloc (1 + strlen (users_dirname) + strlen (entry->d_name)); - strcpy (temp, users_dirname); - strcat (temp, entry->d_name); - } - else - { - temp = (savestring (entry->d_name)); - } - return (temp); - } -} - - -/* **************************************************************** */ -/* */ -/* Binding keys */ -/* */ -/* **************************************************************** */ - -/* rl_add_defun (char *name, Function *function, int key) - Add NAME to the list of named functions. Make FUNCTION - be the function that gets called. - If KEY is not -1, then bind it. */ -rl_add_defun (name, function, key) - char *name; - Function *function; - int key; -{ - if (key != -1) - rl_bind_key (key, function); - rl_add_funmap_entry (name, function); -} - -/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ -int -rl_bind_key (key, function) - int key; - Function *function; -{ - if (key < 0) - return (key); - - if (key > 127 && key < 256) - { - if (keymap[ESC].type == ISKMAP) - { - Keymap escmap = (Keymap)keymap[ESC].function; - - key -= 128; - escmap[key].type = ISFUNC; - escmap[key].function = function; - return (0); - } - return (key); - } - - keymap[key].type = ISFUNC; - keymap[key].function = function; - return (0); -} - -/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid - KEY. */ -int -rl_bind_key_in_map (key, function, map) - int key; - Function *function; - Keymap map; -{ - int result; - Keymap oldmap = keymap; - - keymap = map; - result = rl_bind_key (key, function); - keymap = oldmap; - return (result); -} - -/* Make KEY do nothing in the currently selected keymap. - Returns non-zero in case of error. */ -int -rl_unbind_key (key) - int key; -{ - return (rl_bind_key (key, (Function *)NULL)); -} - -/* Make KEY do nothing in MAP. - Returns non-zero in case of error. */ -int -rl_unbind_key_in_map (key, map) - int key; - Keymap map; -{ - return (rl_bind_key_in_map (key, (Function *)NULL, map)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION. This makes new keymaps as necessary. The initial - place to do bindings is in MAP. */ -rl_set_key (keyseq, function, map) - char *keyseq; - Function *function; - Keymap map; -{ - rl_generic_bind (ISFUNC, keyseq, function, map); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the string of characters MACRO. This makes new keymaps as - necessary. The initial place to do bindings is in MAP. */ -rl_macro_bind (keyseq, macro, map) - char *keyseq, *macro; - Keymap map; -{ - char *macro_keys; - int macro_keys_len; - - macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); - - if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) - { - free (macro_keys); - return; - } - rl_generic_bind (ISMACR, keyseq, macro_keys, map); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the arbitrary pointer DATA. TYPE says what kind of data is - pointed to by DATA, right now this can be a function (ISFUNC), - a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps - as necessary. The initial place to do bindings is in MAP. */ -rl_generic_bind (type, keyseq, data, map) - int type; - char *keyseq, *data; - Keymap map; -{ - char *keys; - int keys_len; - register int i; - - /* If no keys to bind to, exit right away. */ - if (!keyseq || !*keyseq) - { - if (type == ISMACR) - free (data); - return; - } - - keys = (char *)alloca (1 + (2 * strlen (keyseq))); - - /* Translate the ASCII representation of KEYSEQ into an array - of characters. Stuff the characters into ARRAY, and the - length of ARRAY into LENGTH. */ - if (rl_translate_keyseq (keyseq, keys, &keys_len)) - return; - - /* Bind keys, making new keymaps as necessary. */ - for (i = 0; i < keys_len; i++) - { - if (i + 1 < keys_len) - { - if (map[keys[i]].type != ISKMAP) - { - if (map[i].type == ISMACR) - free ((char *)map[i].function); - - map[keys[i]].type = ISKMAP; - map[keys[i]].function = (Function *)rl_make_bare_keymap (); - } - map = (Keymap)map[keys[i]].function; - } - else - { - if (map[keys[i]].type == ISMACR) - free ((char *)map[keys[i]].function); - - map[keys[i]].function = (Function *)data; - map[keys[i]].type = type; - } - } -} - -/* Translate the ASCII representation of SEQ, stuffing the - values into ARRAY, an array of characters. LEN gets the - final length of ARRAY. Return non-zero if there was an - error parsing SEQ. */ -rl_translate_keyseq (seq, array, len) - char *seq, *array; - int *len; -{ - register int i, c, l = 0; - - for (i = 0; c = seq[i]; i++) - { - if (c == '\\') - { - c = seq[++i]; - - if (!c) - break; - - if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || - (c == 'e')) - { - /* Handle special case of backwards define. */ - if (strncmp (&seq[i], "C-\\M-", 5) == 0) - { - array[l++] = ESC; - i += 5; - array[l++] = CTRL (to_upper (seq[i])); - if (!seq[i]) - i--; - continue; - } - - switch (c) - { - case 'M': - i++; - array[l++] = ESC; - break; - - case 'C': - i += 2; - /* Special hack for C-?... */ - if (seq[i] == '?') - array[l++] = RUBOUT; - else - array[l++] = CTRL (to_upper (seq[i])); - break; - - case 'e': - array[l++] = ESC; - } - - continue; - } - } - array[l++] = c; - } - - *len = l; - array[l] = '\0'; - return (0); -} - -/* Return a pointer to the function that STRING represents. - If STRING doesn't have a matching function, then a NULL pointer - is returned. */ -Function * -rl_named_function (string) - char *string; -{ - register int i; - - for (i = 0; funmap[i]; i++) - if (stricmp (funmap[i]->name, string) == 0) - return (funmap[i]->function); - return ((Function *)NULL); -} - -/* The last key bindings file read. */ -#ifdef __MSDOS__ -/* Don't know what to do, but this is a guess */ -static char *last_readline_init_file = "/INPUTRC"; -#else -static char *last_readline_init_file = "~/inputrc"; -#endif - -/* Re-read the current keybindings file. */ -rl_re_read_init_file (count, ignore) - int count, ignore; -{ - rl_read_init_file ((char *)NULL); -} - -/* Do key bindings from a file. If FILENAME is NULL it defaults - to `~/.inputrc'. If the file existed and could be opened and - read, 0 is returned, otherwise errno is returned. */ -int -rl_read_init_file (filename) - char *filename; -{ - register int i; - char *buffer, *openname, *line, *end; - struct stat finfo; - int file; - - /* Default the filename. */ - if (!filename) - filename = last_readline_init_file; - - openname = tilde_expand (filename); - - if (!openname || *openname == '\000') - return ENOENT; - - if ((stat (openname, &finfo) < 0) || - (file = open (openname, O_RDONLY, 0666)) < 0) - { - free (openname); - return (errno); - } - else - free (openname); - - last_readline_init_file = filename; - - /* Read the file into BUFFER. */ - buffer = (char *)xmalloc (finfo.st_size + 1); - i = read (file, buffer, finfo.st_size); - close (file); - - if (i != finfo.st_size) - return (errno); - - /* Loop over the lines in the file. Lines that start with `#' are - comments; all other lines are commands for readline initialization. */ - line = buffer; - end = buffer + finfo.st_size; - while (line < end) - { - /* Find the end of this line. */ - for (i = 0; line + i != end && line[i] != '\n'; i++); - - /* Mark end of line. */ - line[i] = '\0'; - - /* If the line is not a comment, then parse it. */ - if (*line != '#') - rl_parse_and_bind (line); - - /* Move to the next line. */ - line += i + 1; - } - return (0); -} - -/* **************************************************************** */ -/* */ -/* Parser Directives */ -/* */ -/* **************************************************************** */ - -/* Conditionals. */ - -/* Calling programs set this to have their argv[0]. */ -char *rl_readline_name = "other"; - -/* Stack of previous values of parsing_conditionalized_out. */ -static unsigned char *if_stack = (unsigned char *)NULL; -static int if_stack_depth = 0; -static int if_stack_size = 0; - -/* Push parsing_conditionalized_out, and set parser state based on ARGS. */ -parser_if (args) - char *args; -{ - register int i; - - /* Push parser state. */ - if (if_stack_depth + 1 >= if_stack_size) - { - if (!if_stack) - if_stack = (unsigned char *)xmalloc (if_stack_size = 20); - else - if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); - } - if_stack[if_stack_depth++] = parsing_conditionalized_out; - - /* If parsing is turned off, then nothing can turn it back on except - for finding the matching endif. In that case, return right now. */ - if (parsing_conditionalized_out) - return; - - /* Isolate first argument. */ - for (i = 0; args[i] && !whitespace (args[i]); i++); - - if (args[i]) - args[i++] = '\0'; - - /* Handle "if term=foo" and "if mode=emacs" constructs. If this - isn't term=foo, or mode=emacs, then check to see if the first - word in ARGS is the same as the value stored in rl_readline_name. */ - if (rl_terminal_name && strnicmp (args, "term=", 5) == 0) - { - char *tem, *tname; - - /* Terminals like "aaa-60" are equivalent to "aaa". */ - tname = savestring (rl_terminal_name); - tem = rindex (tname, '-'); - if (tem) - *tem = '\0'; - - if (stricmp (args + 5, tname) == 0) - parsing_conditionalized_out = 0; - else - parsing_conditionalized_out = 1; - } -#if defined (VI_MODE) - else if (strnicmp (args, "mode=", 5) == 0) - { - int mode; - - if (stricmp (args + 5, "emacs") == 0) - mode = emacs_mode; - else if (stricmp (args + 5, "vi") == 0) - mode = vi_mode; - else - mode = no_mode; - - if (mode == rl_editing_mode) - parsing_conditionalized_out = 0; - else - parsing_conditionalized_out = 1; - } -#endif /* VI_MODE */ - /* Check to see if the first word in ARGS is the same as the - value stored in rl_readline_name. */ - else if (stricmp (args, rl_readline_name) == 0) - parsing_conditionalized_out = 0; - else - parsing_conditionalized_out = 1; -} - -/* Invert the current parser state if there is anything on the stack. */ -parser_else (args) - char *args; -{ - register int i; - - if (!if_stack_depth) - { - /* Error message? */ - return; - } - - /* Check the previous (n - 1) levels of the stack to make sure that - we haven't previously turned off parsing. */ - for (i = 0; i < if_stack_depth - 1; i++) - if (if_stack[i] == 1) - return; - - /* Invert the state of parsing if at top level. */ - parsing_conditionalized_out = !parsing_conditionalized_out; -} - -/* Terminate a conditional, popping the value of - parsing_conditionalized_out from the stack. */ -parser_endif (args) - char *args; -{ - if (if_stack_depth) - parsing_conditionalized_out = if_stack[--if_stack_depth]; - else - { - /* *** What, no error message? *** */ - } -} - -/* Associate textual names with actual functions. */ -static struct { - char *name; - Function *function; -} parser_directives [] = { - { "if", parser_if }, - { "endif", parser_endif }, - { "else", parser_else }, - { (char *)0x0, (Function *)0x0 } -}; - -/* Handle a parser directive. STATEMENT is the line of the directive - without any leading `$'. */ -static int -handle_parser_directive (statement) - char *statement; -{ - register int i; - char *directive, *args; - - /* Isolate the actual directive. */ - - /* Skip whitespace. */ - for (i = 0; whitespace (statement[i]); i++); - - directive = &statement[i]; - - for (; statement[i] && !whitespace (statement[i]); i++); - - if (statement[i]) - statement[i++] = '\0'; - - for (; statement[i] && whitespace (statement[i]); i++); - - args = &statement[i]; - - /* Lookup the command, and act on it. */ - for (i = 0; parser_directives[i].name; i++) - if (stricmp (directive, parser_directives[i].name) == 0) - { - (*parser_directives[i].function) (args); - return (0); - } - - /* *** Should an error message be output? */ - return (1); -} - -/* Ugly but working hack for binding prefix meta. */ -#define PREFIX_META_HACK - -static int substring_member_of_array (); - -/* Read the binding command from STRING and perform it. - A key binding command looks like: Keyname: function-name\0, - a variable binding command looks like: set variable value. - A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ -rl_parse_and_bind (string) - char *string; -{ - extern char *possible_control_prefixes[], *possible_meta_prefixes[]; - char *funname, *kname; - register int c; - int key, i; - - while (string && whitespace (*string)) - string++; - - if (!string || !*string || *string == '#') - return; - - /* If this is a parser directive, act on it. */ - if (*string == '$') - { - handle_parser_directive (&string[1]); - return; - } - - /* If we are supposed to be skipping parsing right now, then do it. */ - if (parsing_conditionalized_out) - return; - - i = 0; - /* If this keyname is a complex key expression surrounded by quotes, - advance to after the matching close quote. */ - if (*string == '"') - { - for (i = 1; c = string[i]; i++) - { - if (c == '"' && string[i - 1] != '\\') - break; - } - } - - /* Advance to the colon (:) or whitespace which separates the two objects. */ - for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); - - /* Mark the end of the command (or keyname). */ - if (string[i]) - string[i++] = '\0'; - - /* If this is a command to set a variable, then do that. */ - if (stricmp (string, "set") == 0) - { - char *var = string + i; - char *value; - - /* Make VAR point to start of variable name. */ - while (*var && whitespace (*var)) var++; - - /* Make value point to start of value string. */ - value = var; - while (*value && !whitespace (*value)) value++; - if (*value) - *value++ = '\0'; - while (*value && whitespace (*value)) value++; - - rl_variable_bind (var, value); - return; - } - - /* Skip any whitespace between keyname and funname. */ - for (; string[i] && whitespace (string[i]); i++); - funname = &string[i]; - - /* Now isolate funname. - For straight function names just look for whitespace, since - that will signify the end of the string. But this could be a - macro definition. In that case, the string is quoted, so skip - to the matching delimiter. */ - if (*funname == '\'' || *funname == '"') - { - int delimiter = string[i++]; - - for (; c = string[i]; i++) - { - if (c == delimiter && string[i - 1] != '\\') - break; - } - if (c) - i++; - } - - /* Advance to the end of the string. */ - for (; string[i] && !whitespace (string[i]); i++); - - /* No extra whitespace at the end of the string. */ - string[i] = '\0'; - - /* If this is a new-style key-binding, then do the binding with - rl_set_key (). Otherwise, let the older code deal with it. */ - if (*string == '"') - { - char *seq = (char *)alloca (1 + strlen (string)); - register int j, k = 0; - - for (j = 1; string[j]; j++) - { - if (string[j] == '"' && string[j - 1] != '\\') - break; - - seq[k++] = string[j]; - } - seq[k] = '\0'; - - /* Binding macro? */ - if (*funname == '\'' || *funname == '"') - { - j = strlen (funname); - - if (j && funname[j - 1] == *funname) - funname[j - 1] = '\0'; - - rl_macro_bind (seq, &funname[1], keymap); - } - else - rl_set_key (seq, rl_named_function (funname), keymap); - - return; - } - - /* Get the actual character we want to deal with. */ - kname = rindex (string, '-'); - if (!kname) - kname = string; - else - kname++; - - key = glean_key_from_name (kname); - - /* Add in control and meta bits. */ - if (substring_member_of_array (string, possible_control_prefixes)) - key = CTRL (to_upper (key)); - - if (substring_member_of_array (string, possible_meta_prefixes)) - key = META (key); - - /* Temporary. Handle old-style keyname with macro-binding. */ - if (*funname == '\'' || *funname == '"') - { - char seq[2]; - int fl = strlen (funname); - - seq[0] = key; seq[1] = '\0'; - if (fl && funname[fl - 1] == *funname) - funname[fl - 1] = '\0'; - - rl_macro_bind (seq, &funname[1], keymap); - } -#if defined (PREFIX_META_HACK) - /* Ugly, but working hack to keep prefix-meta around. */ - else if (stricmp (funname, "prefix-meta") == 0) - { - char seq[2]; - - seq[0] = key; - seq[1] = '\0'; - rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, keymap); - } -#endif /* PREFIX_META_HACK */ - else - rl_bind_key (key, rl_named_function (funname)); -} - -rl_variable_bind (name, value) - char *name, *value; -{ - if (stricmp (name, "editing-mode") == 0) - { - if (strnicmp (value, "vi", 2) == 0) - { -#if defined (VI_MODE) - keymap = vi_insertion_keymap; - rl_editing_mode = vi_mode; -#else -#if defined (NOTDEF) - /* What state is the terminal in? I'll tell you: - non-determinate! That means we cannot do any output. */ - ding (); -#endif /* NOTDEF */ -#endif /* VI_MODE */ - } - else if (strnicmp (value, "emacs", 5) == 0) - { - keymap = emacs_standard_keymap; - rl_editing_mode = emacs_mode; - } - } - else if (stricmp (name, "horizontal-scroll-mode") == 0) - { - if (!*value || stricmp (value, "On") == 0) - horizontal_scroll_mode = 1; - else - horizontal_scroll_mode = 0; - } - else if (stricmp (name, "mark-modified-lines") == 0) - { - if (!*value || stricmp (value, "On") == 0) - mark_modified_lines = 1; - else - mark_modified_lines = 0; - } - else if (stricmp (name, "prefer-visible-bell") == 0) - { - if (!*value || stricmp (value, "On") == 0) - prefer_visible_bell = 1; - else - prefer_visible_bell = 0; - } - else if (stricmp (name, "comment-begin") == 0) - { -#if defined (VI_MODE) - extern char *rl_vi_comment_begin; - - if (*value) - { - if (rl_vi_comment_begin) - free (rl_vi_comment_begin); - - rl_vi_comment_begin = savestring (value); - } -#endif /* VI_MODE */ - } -} - -/* Return the character which matches NAME. - For example, `Space' returns ' '. */ - -typedef struct { - char *name; - int value; -} assoc_list; - -assoc_list name_key_alist[] = { - { "DEL", 0x7f }, - { "ESC", '\033' }, - { "Escape", '\033' }, - { "LFD", '\n' }, - { "Newline", '\n' }, - { "RET", '\r' }, - { "Return", '\r' }, - { "Rubout", 0x7f }, - { "SPC", ' ' }, - { "Space", ' ' }, - { "Tab", 0x09 }, - { (char *)0x0, 0 } -}; - -int -glean_key_from_name (name) - char *name; -{ - register int i; - - for (i = 0; name_key_alist[i].name; i++) - if (stricmp (name, name_key_alist[i].name) == 0) - return (name_key_alist[i].value); - - return (*name); -} - - -/* **************************************************************** */ -/* */ -/* Key Binding and Function Information */ -/* */ -/* **************************************************************** */ - -/* Each of the following functions produces information about the - state of keybindings and functions known to Readline. The info - is always printed to rl_outstream, and in such a way that it can - be read back in (i.e., passed to rl_parse_and_bind (). */ - -/* Print the names of functions known to Readline. */ -void -rl_list_funmap_names (ignore) - int ignore; -{ - register int i; - char **funmap_names; - extern char **rl_funmap_names (); - - funmap_names = rl_funmap_names (); - - if (!funmap_names) - return; - - for (i = 0; funmap_names[i]; i++) - fprintf (rl_outstream, "%s\n", funmap_names[i]); - - free (funmap_names); -} - -/* Return a NULL terminated array of strings which represent the key - sequences that are used to invoke FUNCTION in MAP. */ -static char ** -invoking_keyseqs_in_map (function, map) - Function *function; - Keymap map; -{ - register int key; - char **result; - int result_index, result_size; - - result = (char **)NULL; - result_index = result_size = 0; - - for (key = 0; key < 128; key++) - { - switch (map[key].type) - { - case ISMACR: - /* Macros match, if, and only if, the pointers are identical. - Thus, they are treated exactly like functions in here. */ - case ISFUNC: - /* If the function in the keymap is the one we are looking for, - then add the current KEY to the list of invoking keys. */ - if (map[key].function == function) - { - char *keyname = (char *)xmalloc (5); - - if (CTRL_P (key)) - sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else - sprintf (keyname, "%c", key); - - if (result_index + 2 > result_size) - { - if (!result) - result = (char **) xmalloc - ((result_size = 10) * sizeof (char *)); - else - result = (char **) xrealloc - (result, (result_size += 10) * sizeof (char *)); - } - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; - } - break; - - case ISKMAP: - { - char **seqs = (char **)NULL; - - /* Find the list of keyseqs in this map which have FUNCTION as - their target. Add the key sequences found to RESULT. */ - if (map[key].function) - seqs = - invoking_keyseqs_in_map (function, (Keymap)map[key].function); - - if (seqs) - { - register int i; - - for (i = 0; seqs[i]; i++) - { - char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - - if (key == ESC) - sprintf (keyname, "\\e"); - else if (CTRL_P (key)) - sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else - sprintf (keyname, "%c", key); - - strcat (keyname, seqs[i]); - - if (result_index + 2 > result_size) - { - if (!result) - result = (char **) - xmalloc ((result_size = 10) * sizeof (char *)); - else - result = (char **) - xrealloc (result, - (result_size += 10) * sizeof (char *)); - } - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; - } - } - } - break; - } - } - return (result); -} - -/* Return a NULL terminated array of strings which represent the key - sequences that can be used to invoke FUNCTION using the current keymap. */ -char ** -rl_invoking_keyseqs (function) - Function *function; -{ - return (invoking_keyseqs_in_map (function, keymap)); -} - -/* Print all of the current functions and their bindings to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_functions (count) - int count; -{ - void rl_function_dumper (); - - rl_function_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -/* Print all of the functions and their bindings to rl_outstream. If - PRINT_READABLY is non-zero, then print the output in such a way - that it can be read back in. */ -void -rl_function_dumper (print_readably) - int print_readably; -{ - register int i; - char **rl_funmap_names (), **names; - char *name; - - names = rl_funmap_names (); - - fprintf (rl_outstream, "\n"); - - for (i = 0; name = names[i]; i++) - { - Function *function; - char **invokers; - - function = rl_named_function (name); - invokers = invoking_keyseqs_in_map (function, keymap); - - if (print_readably) - { - if (!invokers) - fprintf (rl_outstream, "# %s (not bound)\n", name); - else - { - register int j; - - for (j = 0; invokers[j]; j++) - { - fprintf (rl_outstream, "\"%s\": %s\n", - invokers[j], name); - free (invokers[j]); - } - - free (invokers); - } - } - else - { - if (!invokers) - fprintf (rl_outstream, "%s is not bound to any keys\n", - name); - else - { - register int j; - - fprintf (rl_outstream, "%s can be found on ", name); - - for (j = 0; invokers[j] && j < 5; j++) - { - fprintf (rl_outstream, "\"%s\"%s", invokers[j], - invokers[j + 1] ? ", " : ".\n"); - } - - if (j == 5 && invokers[j]) - fprintf (rl_outstream, "...\n"); - - for (j = 0; invokers[j]; j++) - free (invokers[j]); - - free (invokers); - } - } - } -} - - -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -static char *strindex (); - -/* Return pointer to first occurance in STRING1 of any character from STRING2, - or NULL if no occurance found. */ -static char * -strpbrk (string1, string2) - char *string1, *string2; -{ - register char *scan; - - for (; *string1 != '\0'; string1++) - { - for (scan = string2; *scan != '\0'; scan++) - { - if (*string1 == *scan) - { - return (string1); - } - } - } - return (NULL); -} - -/* Return non-zero if any members of ARRAY are a substring in STRING. */ -static int -substring_member_of_array (string, array) - char *string, **array; -{ - while (*array) - { - if (strindex (string, *array)) - return (1); - array++; - } return (0); } - -/* Whoops, Unix doesn't have strnicmp. */ - -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -static int -strnicmp (string1, string2, count) - char *string1, *string2; -{ - register char ch1, ch2; - - while (count) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) == to_upper(ch2)) - count--; - else break; - } - return (count); -} - -/* strcmp (), but caseless. */ -static int -stricmp (string1, string2) - char *string1, *string2; -{ - register char ch1, ch2; - - while (*string1 && *string2) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) != to_upper(ch2)) - return (1); - } - return (*string1 | *string2); -} - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -static char * -strindex (s1, s2) - register char *s1, *s2; -{ - register int i, l = strlen (s2); - register int len = strlen (s1); - - for (i = 0; (len - i) >= l; i++) - if (strnicmp (&s1[i], s2, l) == 0) - return (s1 + i); - return ((char *)NULL); -} - - -/* **************************************************************** */ -/* */ -/* USG (System V) Support */ -/* */ -/* **************************************************************** */ - -/* When compiling and running in the `Posix' environment, Ultrix does - not restart system calls, so this needs to do it. */ -int -rl_getc (stream) - FILE *stream; -{ - int result; - unsigned char c; - -#ifdef __GO32__ - if (isatty(0)) - return getkey(); -#endif /* __GO32__ */ - - while (1) - { - result = read (fileno (stream), &c, sizeof (char)); - - if (result == sizeof (char)) - return (c); - - /* If zero characters are returned, then the file that we are - reading from is empty! Return EOF in that case. */ - if (result == 0) - return (EOF); - -#ifndef __GO32__ - /* If the error that we received was SIGINT, then try again, - this is simply an interrupted system call to read (). - Otherwise, some error ocurred, also signifying EOF. */ - if (errno != EINTR) - return (EOF); -#endif /* !__GO32__ */ - } -} - -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ - - -/* **************************************************************** */ -/* */ -/* Testing Readline */ -/* */ -/* **************************************************************** */ - -#if defined (TEST) - -main () -{ - HIST_ENTRY **history_list (); - char *temp = (char *)NULL; - char *prompt = "readline% "; - int done = 0; - - while (!done) - { - temp = readline (prompt); - - /* Test for EOF. */ - if (!temp) - exit (1); - - /* If there is anything on the line, print it and remember it. */ - if (*temp) - { - fprintf (stderr, "%s\r\n", temp); - add_history (temp); - } - - /* Check for `command' that we handle. */ - if (strcmp (temp, "quit") == 0) - done = 1; - - if (strcmp (temp, "list") == 0) - { - HIST_ENTRY **list = history_list (); - register int i; - if (list) - { - for (i = 0; list[i]; i++) - { - fprintf (stderr, "%d: %s\r\n", i, list[i]->line); - free (list[i]->line); - } - free (list); - } - } - free (temp); - } -} - -#endif /* TEST */ - - -/* - * Local variables: - * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap" - * end: - */