From: Stu Grossman Date: Tue, 19 Nov 1991 05:59:18 +0000 (+0000) Subject: Integrate new readline from Brian Fox. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=870ca2534097fc727b6762fab958fad76722d638;p=binutils-gdb.git Integrate new readline from Brian Fox. --- diff --git a/readline/COPYING b/readline/COPYING index 9a170375811..1bb82d1b26d 100644 --- a/readline/COPYING +++ b/readline/COPYING @@ -3,22 +3,30 @@ Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +The Free Software Foundation has exempted Bash from the requirement of +Paragraph 2c of the General Public License. This is to say, there is +no requirement for Bash to print a notice when it is started +interactively in the usual way. We made this exception because users +and standards expect shells not to print such messages. This +exception applies to any program that serves as a shell and that is +based primarily on Bash as opposed to other GNU software. + Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The +software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make +price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free @@ -65,7 +73,7 @@ appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of +along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of @@ -114,7 +122,7 @@ Paragraphs 1 and 2 above provided that you also do one of the following: Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is + corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) @@ -130,7 +138,7 @@ accompany that operating system. Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received +the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. @@ -150,7 +158,7 @@ of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program +Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free @@ -160,7 +168,7 @@ Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free +to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and @@ -203,7 +211,7 @@ the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/readline/ChangeLog b/readline/ChangeLog index 75963072e63..81fe3d56941 100644 --- a/readline/ChangeLog +++ b/readline/ChangeLog @@ -1,40 +1,96 @@ -Mon Nov 11 20:50:29 1991 Steve Chamberlain (sac at cygnus.com) +Fri Nov 1 07:02:13 1991 Brian Fox (bfox at gnuwest.fsf.org) - * Makefile.in: Use the MINUS_G no-debug convention - * readline.c: (many_places) move all the declarations of rindex to - only one place, to reduce the number of warnings it makes. + * readline.c (rl_translate_keyseq) Make C-? translate to RUBOUT + unconditionally. -Sat Nov 9 03:19:40 1991 John Gilmore (gnu at cygnus.com) +Mon Oct 28 11:34:52 1991 Brian Fox (bfox at gnuwest.fsf.org) - * configure.in: Make a link for sysdep.h. Specify commontargets. - * sysdep-norm.h: The usual alloca declarations. - * sysdep-aix.h: What AIX 3.1 on RS/6000 needs for alloca. - * history.c, readline.c: Use sysdep.h. + * readline.c; Use Posix directory routines and macros. -Thu Oct 24 21:58:46 1991 John Gilmore (gnu at cygnus.com) + * funmap.c; Add entry for call-last-kbd-macro. - * configure.in: aix is a Sys V as far as we're concerned. - Switch to new config/hm-* scheme. + * readline.c (rl_prep_term); Use system EOF character on POSIX + systems also. -Thu Oct 24 02:08:50 1991 Fred Fish (fnf at cygnus.com) +Thu Oct 3 16:19:53 1991 Brian Fox (bfox at gnuwest.fsf.org) - * config/hmake-sysv: Send RANLIB (echo) output to /dev/null. + * readline.c; Make a distinction between having a TERMIOS tty + driver, and having POSIX signal handling. You might one without + the other. New defines used HAVE_POSIX_SIGNALS, and + TERMIOS_TTY_DRIVER. -Tue Sep 17 17:44:22 1991 Stu Grossman (grossman at cygnus.com) +Tue Jul 30 22:37:26 1991 Brian Fox (bfox at gnuwest.fsf.org) - * config/hmake-sysv: sgi/irix support. + * readline.c: rl_getc () If a call to read () returns without an + error, but with zero characters, the file is empty, so return EOF. -Sun May 19 07:49:34 1991 John Gilmore and Rich Pixley (at cygnus.com) +Thu Jul 11 20:58:38 1991 Brian Fox (bfox at gnuwest.fsf.org) - Make readline independent of the applications that use it. + * readline.c: (rl_get_next_history, rl_get_previous_history) + Reallocate the buffer space if the line being moved to is longer + the the current space allocated. Amazing that no one has found + this bug until now. - * readline.h, keymaps.h: include other include files with "foo.h" - rather than . This works here, and works when - included from other applications. +Sun Jul 7 02:37:05 1991 Brian Fox (bfox at gnuwest.fsf.org) - * Makefile.in: Create template for configurable Makefile. - This version is not ready for prime time, so we have left - Makefile itself (the original version) too. + * readline.c:(rl_parse_and_bind) Allow leading whitespace. + Make sure TERMIO and TERMIOS systems treat CR and NL + disctinctly. + +Tue Jun 25 04:09:27 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: Rework parsing conditionals to pay attention to the + prior states of the conditional stack. This makes $if statements + work correctly. + +Mon Jun 24 20:45:59 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: support for displaying key binding information + includes the functions rl_list_funmap_names (), + invoking_keyseqs_in_map (), rl_invoking_keyseqs (), + rl_dump_functions (), and rl_function_dumper (). + + funmap.c: support for same includes rl_funmap_names (). + + readline.c, funmap.c: no longer define STATIC_MALLOC. However, + update both version of xrealloc () to handle a null pointer. + +Thu Apr 25 12:03:49 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * vi_mode.c (rl_vi_fword, fWord, etc. All functions use + the macro `isident()'. Fixed movement bug which prevents + continious movement through the text. + +Fri Jul 27 16:47:01 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (parser_if) Allow "$if term=foo" construct. + +Wed May 23 16:10:33 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_dispatch) Correctly remember the last command + executed. Fixed typo in username_completion_function (). + +Mon Apr 9 19:55:48 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: username_completion_function (); For text passed in + with a leading `~', remember that this could be a filename (after + it is completed). + +Thu Apr 5 13:44:24 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: rl_search_history (): Correctly handle case of an + unfound search string, but a graceful exit (as with ESC). + + * readline.c: rl_restart_output (); The Apollo passes the address + of the file descriptor to TIOCSTART, not the descriptor itself. + +Tue Mar 20 05:38:55 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: rl_complete (); second call in a row causes possible + completions to be listed. + + * readline.c: rl_redisplay (), added prompt_this_line variable + which is the first character character following \n in prompt. Sun Mar 11 04:32:03 1990 Brian Fox (bfox at gnuwest.fsf.org) @@ -47,8 +103,10 @@ Wed Jan 17 19:24:09 1990 Brian Fox (bfox at sbphy.ucsb.edu) Thu Jan 11 10:54:04 1990 Brian Fox (bfox at sbphy.ucsb.edu) - * readline.c, readline.h: added rl_show_star to control the - display of an asterisk on modified history lines. + * readline.c: added mark_modified_lines to control the + display of an asterisk on modified history lines. Also + added a user variable called mark-modified-lines to the + `set' command. Thu Jan 4 10:38:05 1990 Brian Fox (bfox at sbphy.ucsb.edu) @@ -117,4 +175,3 @@ Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel) * Made readline and history into independent libraries. - diff --git a/readline/emacs_keymap.c b/readline/emacs_keymap.c index 24961de0773..0b07fb35ce0 100644 --- a/readline/emacs_keymap.c +++ b/readline/emacs_keymap.c @@ -40,7 +40,7 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { { ISFUNC, rl_end_of_line }, /* Control-e */ { ISFUNC, rl_forward }, /* Control-f */ { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, rl_rubout }, /* Control-h */ { ISFUNC, rl_complete }, /* Control-i */ { ISFUNC, rl_newline }, /* Control-j */ { ISFUNC, rl_kill_line }, /* Control-k */ @@ -188,7 +188,7 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */ { ISFUNC, rl_abort }, /* Meta-Control-g */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */ + { ISFUNC, rl_tab_insert }, /* Meta-Control-i */ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */ @@ -281,7 +281,7 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ /* Some more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* Meta-[ */ + { ISFUNC, rl_arrow_keys }, /* Meta-[ */ { ISFUNC, (Function *)0x0 }, /* Meta-\ */ { ISFUNC, (Function *)0x0 }, /* Meta-] */ { ISFUNC, (Function *)0x0 }, /* Meta-^ */ @@ -303,7 +303,7 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, rl_downcase_word }, /* Meta-l */ { ISFUNC, (Function *)0x0 }, /* Meta-m */ { ISFUNC, (Function *)0x0 }, /* Meta-n */ - { ISFUNC, (Function *)0x0 }, /* Meta-o */ + { ISFUNC, rl_arrow_keys }, /* Meta-o */ { ISFUNC, (Function *)0x0 }, /* Meta-p */ { ISFUNC, (Function *)0x0 }, /* Meta-q */ { ISFUNC, rl_revert_line }, /* Meta-r */ diff --git a/readline/funmap.c b/readline/funmap.c index 54af607121e..7ac6a4d8cd8 100644 --- a/readline/funmap.c +++ b/readline/funmap.c @@ -19,16 +19,16 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC +/* #define STATIC_MALLOC */ +#if !defined (STATIC_MALLOC) extern char *xmalloc (), *xrealloc (); #else static char *xmalloc (), *xrealloc (); -#endif +#endif /* STATIC_MALLOC */ -#ifndef FILE +#if !defined (BUFSIZ) #include -#endif /* FILE */ +#endif /* BUFSIZ */ #include "readline.h" @@ -36,92 +36,103 @@ FUNMAP **funmap = (FUNMAP **)NULL; static int funmap_size = 0; static int funmap_entry = 0; +/* After initializing the function map, this is the index of the first + program specific function. */ +int funmap_program_specific_entry_start; + static FUNMAP default_funmap[] = { - { "beginning-of-line", rl_beg_of_line }, + + { "abort", rl_abort }, + { "accept-line", rl_newline }, + { "arrow-key-prefix", rl_arrow_keys }, { "backward-char", rl_backward }, + { "backward-delete-char", rl_rubout }, + { "backward-kill-line", rl_backward_kill_line }, + { "backward-kill-word", rl_backward_kill_word }, + { "backward-word", rl_backward_word }, + { "beginning-of-history", rl_beginning_of_history }, + { "beginning-of-line", rl_beg_of_line }, + { "call-last-kbd-macro", rl_call_last_kbd_macro }, + { "capitalize-word", rl_capitalize_word }, + { "clear-screen", rl_clear_screen }, + { "complete", rl_complete }, { "delete-char", rl_delete }, + { "digit-argument", rl_digit_argument }, + { "do-lowercase-version", rl_do_lowercase_version }, + { "downcase-word", rl_downcase_word }, + { "dump-functions", rl_dump_functions }, + { "end-kbd-macro", rl_end_kbd_macro }, + { "end-of-history", rl_end_of_history }, { "end-of-line", rl_end_of_line }, { "forward-char", rl_forward }, - { "accept-line", rl_newline }, + { "forward-search-history", rl_forward_search_history }, + { "forward-word", rl_forward_word }, { "kill-line", rl_kill_line }, - { "clear-screen", rl_clear_screen }, + { "kill-word", rl_kill_word }, { "next-history", rl_get_next_history }, + { "possible-completions", rl_possible_completions }, { "previous-history", rl_get_previous_history }, { "quoted-insert", rl_quoted_insert }, + { "re-read-init-file", rl_re_read_init_file }, + { "redraw-current-line", rl_refresh_line}, { "reverse-search-history", rl_reverse_search_history }, - { "forward-search-history", rl_forward_search_history }, + { "revert-line", rl_revert_line }, + { "self-insert", rl_insert }, + { "start-kbd-macro", rl_start_kbd_macro }, + { "tab-insert", rl_tab_insert }, { "transpose-chars", rl_transpose_chars }, + { "transpose-words", rl_transpose_words }, + { "undo", rl_undo_command }, + { "universal-argument", rl_universal_argument }, { "unix-line-discard", rl_unix_line_discard }, { "unix-word-rubout", rl_unix_word_rubout }, + { "upcase-word", rl_upcase_word }, { "yank", rl_yank }, - { "yank-pop", rl_yank_pop }, { "yank-nth-arg", rl_yank_nth_arg }, - { "backward-delete-char", rl_rubout }, - { "backward-word", rl_backward_word }, - { "kill-word", rl_kill_word }, - { "forward-word", rl_forward_word }, - { "tab-insert", rl_tab_insert }, - { "backward-kill-word", rl_backward_kill_word }, - { "backward-kill-line", rl_backward_kill_line }, - { "transpose-words", rl_transpose_words }, - { "digit-argument", rl_digit_argument }, - { "complete", rl_complete }, - { "possible-completions", rl_possible_completions }, - { "do-lowercase-version", rl_do_lowercase_version }, - { "digit-argument", rl_digit_argument }, - { "universal-argument", rl_universal_argument }, - { "abort", rl_abort }, - { "undo", rl_undo_command }, - { "upcase-word", rl_upcase_word }, - { "downcase-word", rl_downcase_word }, - { "capitalize-word", rl_capitalize_word }, - { "revert-line", rl_revert_line }, - { "beginning-of-history", rl_beginning_of_history }, - { "end-of-history", rl_end_of_history }, - { "self-insert", rl_insert }, - { "start-kbd-macro", rl_start_kbd_macro }, - { "end-kbd-macro", rl_end_kbd_macro }, - { "re-read-init-file", rl_re_read_init_file }, -#ifdef VI_MODE - { "vi-movement-mode", rl_vi_movement_mode }, - { "vi-insertion-mode", rl_vi_insertion_mode }, + { "yank-pop", rl_yank_pop }, + +#if defined (VI_MODE) + + { "vi-append-eol", rl_vi_append_eol }, + { "vi-append-mode", rl_vi_append_mode }, { "vi-arg-digit", rl_vi_arg_digit }, - { "vi-prev-word", rl_vi_prev_word }, - { "vi-next-word", rl_vi_next_word }, + { "vi-bWord", rl_vi_bWord }, + { "vi-bracktype", rl_vi_bracktype }, + { "vi-bword", rl_vi_bword }, + { "vi-change-case", rl_vi_change_case }, + { "vi-change-char", rl_vi_change_char }, + { "vi-change-to", rl_vi_change_to }, { "vi-char-search", rl_vi_char_search }, + { "vi-column", rl_vi_column }, + { "vi-comment", rl_vi_comment }, + { "vi-complete", rl_vi_complete }, + { "vi-delete", rl_vi_delete }, + { "vi-delete-to", rl_vi_delete_to }, + { "vi-dosearch", rl_vi_dosearch }, + { "vi-eWord", rl_vi_eWord }, { "vi-editing-mode", rl_vi_editing_mode }, + { "vi-end-word", rl_vi_end_word }, { "vi-eof-maybe", rl_vi_eof_maybe }, - { "vi-append-mode", rl_vi_append_mode }, - { "vi-put", rl_vi_put }, - { "vi-append-eol", rl_vi_append_eol }, - { "vi-insert-beg", rl_vi_insert_beg }, - { "vi-delete", rl_vi_delete }, - { "vi-comment", rl_vi_comment }, + { "vi-eword", rl_vi_eword }, + { "vi-fWord", rl_vi_fWord }, { "vi-first-print", rl_vi_first_print }, { "vi-fword", rl_vi_fword }, - { "vi-fWord", rl_vi_fWord }, - { "vi-bword", rl_vi_bword }, - { "vi-bWord", rl_vi_bWord }, - { "vi-eword", rl_vi_eword }, - { "vi-eWord", rl_vi_eWord }, - { "vi-end-word", rl_vi_end_word }, - { "vi-change-case", rl_vi_change_case }, + { "vi-insert-beg", rl_vi_insert_beg }, + { "vi-insertion-mode", rl_vi_insertion_mode }, { "vi-match", rl_vi_match }, - { "vi-bracktype", rl_vi_bracktype }, - { "vi-change-char", rl_vi_change_char }, - { "vi-yank-arg", rl_vi_yank_arg }, - { "vi-search", rl_vi_search }, - { "vi-search-again", rl_vi_search_again }, - { "vi-dosearch", rl_vi_dosearch }, - { "vi-subst", rl_vi_subst }, + { "vi-movement-mode", rl_vi_movement_mode }, + { "vi-next-word", rl_vi_next_word }, { "vi-overstrike", rl_vi_overstrike }, { "vi-overstrike-delete", rl_vi_overstrike_delete }, + { "vi-prev-word", rl_vi_prev_word }, + { "vi-put", rl_vi_put }, { "vi-replace, ", rl_vi_replace }, - { "vi-column", rl_vi_column }, - { "vi-delete-to", rl_vi_delete_to }, - { "vi-change-to", rl_vi_change_to }, + { "vi-search", rl_vi_search }, + { "vi-search-again", rl_vi_search_again }, + { "vi-subst", rl_vi_subst }, + { "vi-yank-arg", rl_vi_yank_arg }, { "vi-yank-to", rl_vi_yank_to }, - { "vi-complete", rl_vi_complete }, + #endif /* VI_MODE */ {(char *)NULL, (Function *)NULL } @@ -159,6 +170,48 @@ rl_initialize_funmap () rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); funmap_initialized = 1; + funmap_program_specific_entry_start = i; +} + +/* Stupid comparison routine for qsort () ing strings. */ +static int +qsort_string_compare (s1, s2) + register char **s1, **s2; +{ + return (strcmp (*s1, *s2)); +} + +/* Produce a NULL terminated array of known function names. The array + is sorted. The array itself is allocated, but not the strings inside. + You should free () the array when you done, but not the pointrs. */ +char ** +rl_funmap_names () +{ + char **result = (char **)NULL; + int result_size, result_index; + + result_size = result_index = 0; + + /* Make sure that the function map has been initialized. */ + rl_initialize_funmap (); + + for (result_index = 0; funmap[result_index]; result_index++) + { + if (result_index + 2 > result_size) + { + if (!result) + result = (char **)xmalloc ((result_size = 20) * sizeof (char *)); + else + result = (char **) + xrealloc (result, (result_size += 20) * sizeof (char *)); + } + + result[result_index] = funmap[result_index]->name; + result[result_index + 1] = (char *)NULL; + } + + qsort (result, result_index, sizeof (char *), qsort_string_compare); + return (result); } /* Things that mean `Control'. */ @@ -170,7 +223,7 @@ char *possible_meta_prefixes[] = { "Meta", "M-", (char *)NULL }; -#ifdef STATIC_MALLOC +#if defined (STATIC_MALLOC) /* **************************************************************** */ /* */ @@ -196,7 +249,12 @@ xrealloc (pointer, bytes) char *pointer; int bytes; { - char *temp = (char *)realloc (pointer, bytes); + char *temp; + + if (!pointer) + temp = (char *)malloc (bytes); + else + temp = (char *)realloc (pointer, bytes); if (!temp) memory_error_and_abort (); diff --git a/readline/history.c b/readline/history.c index 3c07d11833d..9f0a41ec5a4 100644 --- a/readline/history.c +++ b/readline/history.c @@ -25,24 +25,27 @@ you can call. I think I have done that. */ /* Remove these declarations when we have a complete libgnu.a. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC +#if !defined (STATIC_MALLOC) extern char *xmalloc (), *xrealloc (); #else static char *xmalloc (), *xrealloc (); #endif #include +#include +#include +#include +#include -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else -#if defined (sparc) && defined (sun) -#include +#if defined (__GNUC__) +# define alloca __builtin_alloca #else +# if defined (sparc) || defined (HAVE_ALLOCA_H) +# include +# else extern char *alloca (); -#endif -#endif +# endif /* sparc || HAVE_ALLOCA_H */ +#endif /* !__GNU_C__ */ #include "history.h" @@ -64,7 +67,7 @@ extern char *alloca (); /* **************************************************************** */ /* */ -/* History functions */ +/* History Functions */ /* */ /* **************************************************************** */ @@ -73,18 +76,18 @@ static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; /* Non-zero means that we have enforced a limit on the amount of history that we save. */ -static int history_stifled = 0; +int history_stifled = 0; /* If HISTORY_STIFLED is non-zero, then this is the maximum number of entries to remember. */ -static int max_input_history; +int max_input_history; /* The current location of the interactive history pointer. Just makes life easier for outside callers. */ static int history_offset = 0; /* The number of strings currently stored in the input_history list. */ -static int history_length = 0; +int history_length = 0; /* The current number of slots allocated to the input_history. */ static int history_size = 0; @@ -121,6 +124,21 @@ using_history () history_offset = history_length; } +/* Return the number of bytes that the primary history entries are using. + This just adds up the lengths of the_history->lines. */ +int +history_total_bytes () +{ + register int i, result; + + result = 0; + + for (i = 0; the_history && the_history[i]; i++) + result += strlen (the_history[i]->line); + + return (result); +} + /* Place STRING at the end of the history list. The data field is set to NULL. */ void @@ -129,43 +147,50 @@ add_history (string) { HIST_ENTRY *temp; - if (history_stifled && (history_length == max_input_history)) { - register int i; - - /* If the history is stifled, and history_length is zero, - and it equals max_input_history, we don't save items. */ - if (!history_length) - return; + if (history_stifled && (history_length == max_input_history)) + { + register int i; - /* If there is something in the slot, then remove it. */ - if (the_history[0]) { - free (the_history[0]->line); - free (the_history[0]); - } + /* If the history is stifled, and history_length is zero, + and it equals max_input_history, we don't save items. */ + if (!history_length) + return; - for (i = 0; i < history_length; i++) - the_history[i] = the_history[i + 1]; + /* If there is something in the slot, then remove it. */ + if (the_history[0]) + { + free (the_history[0]->line); + free (the_history[0]); + } - history_base++; + for (i = 0; i < history_length; i++) + the_history[i] = the_history[i + 1]; - } else { + history_base++; - if (!history_size) { - the_history = - (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE) - * sizeof (HIST_ENTRY *)); - history_length = 1; + } + else + { + if (!history_size) + { + the_history = (HIST_ENTRY **) + xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE) + * sizeof (HIST_ENTRY *)); + history_length = 1; - } else { - if (history_length == (history_size - 1)) { - the_history = - (HIST_ENTRY **)xrealloc (the_history, - ((history_size += DEFAULT_HISTORY_GROW_SIZE) - * sizeof (HIST_ENTRY *))); - } - history_length++; + } + else + { + if (history_length == (history_size - 1)) + { + the_history = (HIST_ENTRY **) + xrealloc (the_history, + ((history_size += DEFAULT_HISTORY_GROW_SIZE) + * sizeof (HIST_ENTRY *))); + } + history_length++; + } } - } temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); temp->line = savestring (string); @@ -208,15 +233,22 @@ where_history () } /* Search the history for STRING, starting at history_offset. - If DIRECTION < 0, then the search is through previous entries, - else through subsequent. If the string is found, then - current_history () is the history entry, and the value of this function - is the offset in the line of that history entry that the string was - found in. Otherwise, nothing is changed, and a -1 is returned. */ -int -history_search (string, direction) + If DIRECTION < 0, then the search is through previous entries, else + through subsequent. If ANCHORED is non-zero, the string must + appear at the beginning of a history line, otherwise, the string + may appear anywhere in the line. If the string is found, then + current_history () is the history entry, and the value of this + function is the offset in the line of that history entry that the + string was found in. Otherwise, nothing is changed, and a -1 is + returned. */ + +#define ANCHORED_SEARCH 1 +#define NON_ANCHORED_SEARCH 0 + +static int +history_search_internal (string, direction, anchored) char *string; - int direction; + int direction, anchored; { register int i = history_offset; register int reverse = (direction < 0); @@ -248,7 +280,19 @@ history_search (string, direction) if (string_len > index) goto next_line; - /* Do the actual search. */ + /* Handle anchored searches first. */ + if (anchored == ANCHORED_SEARCH) + { + if (strncmp (string, line, string_len) == 0) + { + history_offset = i; + return (0); + } + + goto next_line; + } + + /* Do substring search. */ if (reverse) { index -= string_len; @@ -265,7 +309,7 @@ history_search (string, direction) } else { - register int limit = (string_len - index) + 1; + register int limit = index - string_len + 1; index = 0; while (index < limit) @@ -286,6 +330,24 @@ history_search (string, direction) } } +/* Do a non-anchored search for STRING through the history in DIRECTION. */ +int +history_search (string, direction) + char *string; + int direction; +{ + return (history_search_internal (string, direction, NON_ANCHORED_SEARCH)); +} + +/* Do an anchored search for string through the history in DIRECTION. */ +int +history_search_prefix (string, direction) + char *string; + int direction; +{ + return (history_search_internal (string, direction, ANCHORED_SEARCH)); +} + /* Remove history element WHICH from the history. The removed element is returned to you so you can free the line, data, and containing structure. */ @@ -307,6 +369,7 @@ remove_history (which) history_length--; } + return (return_value); } @@ -364,16 +427,11 @@ history_filename (filename) char *home = (char *)getenv ("HOME"); if (!home) home = "."; return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history")); - strcpy (return_val, home); - strcat (return_val, "/"); - strcat (return_val, ".history"); + sprintf (return_val, "%s/.history", home); } return (return_val); } -/* What to use until the line gets too big. */ -#define TYPICAL_LINE_SIZE 2048 - /* Add the contents of FILENAME to the history list, a line at a time. If FILENAME is NULL, then read from ~/.history. Returns 0 if successful, or errno if not. */ @@ -381,64 +439,206 @@ int read_history (filename) char *filename; { - char *input = history_filename (filename); - FILE *file = fopen (input, "r"); - char *line = (char *)xmalloc (TYPICAL_LINE_SIZE); - int line_size = TYPICAL_LINE_SIZE; - int done = 0; + return (read_history_range (filename, 0, -1)); +} - if (!file) +/* Read a range of lines from FILENAME, adding them to the history list. + Start reading at the FROM'th line and end at the TO'th. If FROM + is zero, start at the beginning. If TO is less than FROM, read + until the end of the file. If FILENAME is NULL, then read from + ~/.history. Returns 0 if successful, or errno if not. */ +int +read_history_range (filename, from, to) + char *filename; + int from, to; +{ + register int line_start, line_end; + char *input, *buffer = (char *)NULL; + int file, current_line; + struct stat finfo; + extern int errno; + + input = history_filename (filename); + file = open (input, O_RDONLY, 0666); + + if ((file < 0) || + (stat (input, &finfo) == -1)) + goto error_and_exit; + + buffer = (char *)xmalloc (finfo.st_size + 1); + + if (read (file, buffer, finfo.st_size) != finfo.st_size) + error_and_exit: { - extern int errno; - free (line); + if (file >= 0) + close (file); + + if (buffer) + free (buffer); + return (errno); } - while (!done) - { - int c; - int i; + close (file); - i = 0; - while (!(done = ((c = getc (file)) == EOF))) - { - if (c == '\n') - break; + /* Set TO to larger than end of file if negative. */ + if (to < 0) + to = finfo.st_size; - line [i++] = c; - if (i == line_size) - line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE); - } - line[i] = '\0'; - if (line[0]) - add_history (line); + /* Start at beginning of file, work to end. */ + line_start = line_end = current_line = 0; + + /* Skip lines until we are at FROM. */ + while (line_start < finfo.st_size && current_line < from) + { + for (line_end = line_start; line_end < finfo.st_size; line_end++) + if (buffer[line_end] == '\n') + { + current_line++; + line_start = line_end + 1; + if (current_line == from) + break; + } } - free (line); - fclose (file); + + /* If there are lines left to gobble, then gobble them now. */ + for (line_end = line_start; line_end < finfo.st_size; line_end++) + if (buffer[line_end] == '\n') + { + buffer[line_end] = '\0'; + + if (buffer[line_start]) + add_history (buffer + line_start); + + current_line++; + + if (current_line >= to) + break; + + line_start = line_end + 1; + } return (0); } -/* Overwrite FILENAME with the current history. If FILENAME is NULL, - then write the history list to ~/.history. Values returned - are as in read_history ().*/ -int -write_history (filename) +/* Truncate the history file FNAME, leaving only LINES trailing lines. + If FNAME is NULL, then use ~/.history. */ +history_truncate_file (fname, lines) + char *fname; + register int lines; +{ + register int i; + int file; + char *buffer = (char *)NULL, *filename; + struct stat finfo; + + filename = history_filename (fname); + if (stat (filename, &finfo) == -1) + goto truncate_exit; + + file = open (filename, O_RDONLY, 0666); + + if (file == -1) + goto truncate_exit; + + buffer = (char *)xmalloc (finfo.st_size + 1); + read (file, buffer, finfo.st_size); + close (file); + + /* Count backwards from the end of buffer until we have passed + LINES lines. */ + for (i = finfo.st_size; lines && i; i--) + { + if (buffer[i] == '\n') + lines--; + } + + /* If there are fewer lines in the file than we want to truncate to, + then we are all done. */ + if (!i) + goto truncate_exit; + + /* Otherwise, write from the start of this line until the end of the + buffer. */ + for (--i; i; i--) + if (buffer[i] == '\n') + { + i++; + break; + } + + file = open (filename, O_WRONLY | O_TRUNC | O_CREAT, 0666); + if (file == -1) + goto truncate_exit; + + write (file, buffer + i, finfo.st_size - i); + close (file); + + truncate_exit: + if (buffer) + free (buffer); + + free (filename); +} + +#define HISTORY_APPEND 0 +#define HISTORY_OVERWRITE 1 + +/* Workhorse function for writing history. Writes NELEMENT entries + from the history list to FILENAME. OVERWRITE is non-zero if you + wish to replace FILENAME with the entries. */ +static int +history_do_write (filename, nelements, overwrite) char *filename; + int nelements, overwrite; { extern int errno; - char *output = history_filename (filename); - FILE *file = fopen (output, "w"); register int i; + char *output = history_filename (filename); + int file, mode; + char cr = '\n'; + + if (overwrite) + mode = O_WRONLY | O_CREAT | O_TRUNC; + else + mode = O_WRONLY | O_APPEND; + + if ((file = open (output, mode, 0666)) == -1) + return (errno); - if (!file) return (errno); - if (!history_length) return (0); + if (nelements > history_length) + nelements = history_length; - for (i = 0; i < history_length; i++) - fprintf (file, "%s\n", the_history[i]->line); + for (i = history_length - nelements; i < history_length; i++) + { + if (write (file, the_history[i]->line, strlen (the_history[i]->line)) < 0) + break; + if (write (file, &cr, 1) < 0) + break; + } - fclose (file); + close (file); return (0); } + +/* Append NELEMENT entries to FILENAME. The entries appended are from + the end of the list minus NELEMENTs up to the end of the list. */ +int +append_history (nelements, filename) + int nelements; + char *filename; +{ + return (history_do_write (filename, nelements, HISTORY_APPEND)); +} + +/* Overwrite FILENAME with the current history. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history ().*/ +int +write_history (filename) + char *filename; +{ + return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); +} /* Return the history entry at the current position, as determined by history_offset. If there is no entry there, return a NULL pointer. */ @@ -653,7 +853,8 @@ get_history_event (string, caller_index, delimiting_quote) search_again: - index = history_search (temp, -1); + index = history_search_internal + (temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH); if (index < 0) search_lost: @@ -662,9 +863,7 @@ get_history_event (string, caller_index, delimiting_quote) return ((char *)NULL); } - if (index == 0 || substring_okay || - (strncmp (temp, the_history[history_offset]->line, - strlen (temp)) == 0)) + if (index == 0) { search_won: entry = current_history (); @@ -1174,7 +1373,7 @@ get_history_word_specifier (spec, from, caller_index) /* Extract the args specified, starting at FIRST, and ending at LAST. The args are taken from STRING. If either FIRST or LAST is < 0, then make that arg count from the right (subtract from the number of - tokens, so that FIRST = -1 means the next to last token on the line. */ + tokens, so that FIRST = -1 means the next to last token on the line). */ char * history_arg_extract (first, last, string) int first, last; @@ -1205,7 +1404,7 @@ history_arg_extract (first, last, string) last++; - if (first > len || last > len) + if (first > len || last > len || first < 0 || last < 0) result = ((char *)NULL); else { @@ -1353,7 +1552,7 @@ history_tokenize (string) return (result); } -#ifdef STATIC_MALLOC +#if defined (STATIC_MALLOC) /* **************************************************************** */ /* */ @@ -1379,10 +1578,16 @@ xrealloc (pointer, bytes) char *pointer; int bytes; { - char *temp = (char *)realloc (pointer, bytes); + char *temp; + + if (!pointer) + temp = (char *)xmalloc (bytes); + else + temp = (char *)realloc (pointer, bytes); if (!temp) memory_error_and_abort (); + return (temp); } diff --git a/readline/readline.c b/readline/readline.c index a8363c5dfa8..023407d22c0 100644 --- a/readline/readline.c +++ b/readline/readline.c @@ -23,12 +23,12 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Remove these declarations when we have a complete libgnu.a. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC +/* #define STATIC_MALLOC */ +#if !defined (STATIC_MALLOC) extern char *xmalloc (), *xrealloc (); #else static char *xmalloc (), *xrealloc (); -#endif +#endif /* STATIC_MALLOC */ #include #include @@ -36,47 +36,116 @@ static char *xmalloc (), *xrealloc (); #include #include -#include "sysdep.h" +#if defined (__GNUC__) +# define alloca __builtin_alloca +#else +# if defined (sparc) || defined (HAVE_ALLOCA_H) +# include +# endif +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif #define NEW_TTY_DRIVER -#if defined (SYSV) || defined (hpux) || defined (Xenix) -#undef NEW_TTY_DRIVER -#include -#else +#define HAVE_BSD_SIGNALS +/* #define USE_XON_XOFF */ + +/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */ +#if defined (USG) && !defined (hpux) +#undef HAVE_BSD_SIGNALS +#endif + +/* 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 #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 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 /* These next are for filename completion. Perhaps this belongs in a different place. */ -#include - #include -#ifdef SYSV +#if defined (USG) && !defined (isc386) && !defined (sgi) struct passwd *getpwuid (), *getpwent (); #endif -#define HACK_TERMCAP_MOTION - -#ifndef SYSV -#include -#else /* SYSV */ -#if defined (Xenix) -#include -#else -#ifdef hpux -#include -#else -#include -#define direct dirent -#define d_namlen d_reclen -#endif /* hpux */ -#endif /* xenix */ -#endif /* SYSV */ +/* #define HACK_TERMCAP_MOTION */ + +#if defined (_POSIX_VERSION) || defined (USGr3) +# include +# define direct dirent +# if defined (_POSIX_VERSION) +# define D_NAMLEN(d) (strlen ((d)->d_name)) +# else /* !_POSIX_VERSION */ +# define D_NAMLEN(d) ((d)->d_reclen) +# endif /* !_POSIX_VERSION */ +#else /* !_POSIX_VERSION && !USGr3 */ +# define D_NAMLEN(d) ((d)->d_namlen) +# if !defined (USG) +# include +# else /* USG */ +# if defined (Xenix) +# include +# else /* !Xenix */ +# include +# endif /* !Xenix */ +# endif /* USG */ +#endif /* !POSIX_VERSION && !USGr3 */ + +#if defined (USG) && defined (TIOCGWINSZ) +# include +# if defined (USGr4) || defined (USGr3) +# include +# endif /* USGr4 */ +#endif /* USG && TIOCGWINSZ */ /* Some standard library routines. */ #include "readline.h" @@ -95,7 +164,6 @@ struct passwd *getpwuid (), *getpwent (); #endif #ifndef member -char *index (); #define member(c, s) ((c) ? index ((s), (c)) : 0) #endif @@ -107,17 +175,27 @@ char *index (); #define exchange(x, y) {int temp = x; x = y; y = temp;} #endif +#if !defined (rindex) +extern char *rindex (); +#endif /* rindex */ + +#if !defined (index) +extern char *index (); +#endif /* index */ + +extern char *getenv (); +extern char *tilde_expand (); + static update_line (); static void output_character_function (); static delete_chars (); -static delete_chars (); static insert_some_chars (); -#ifdef VOID_SIGHANDLER -#define sighandler void +#if defined (VOID_SIGHANDLER) +# define sighandler void #else -#define sighandler int -#endif +# 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); */ @@ -137,6 +215,7 @@ typedef sighandler SigHandler (); By default, it is the standard emacs keymap. */ Keymap keymap = emacs_standard_keymap; +#define no_mode -1 #define vi_mode 0 #define emacs_mode 1 @@ -153,7 +232,7 @@ int rl_numeric_arg = 1; int rl_explicit_arg = 0; /* Temporary value used while generating the argument. */ -static int arg_sign = 1; +int rl_arg_sign = 1; /* Non-zero means we have been called at least once before. */ static int rl_initialized = 0; @@ -218,7 +297,7 @@ char *rl_terminal_name = (char *)NULL; /* Line buffer and maintenence. */ char *rl_line_buffer = (char *)NULL; -static int rl_line_buffer_len = 0; +int rl_line_buffer_len = 0; #define DEFAULT_BUFFER_SIZE 256 @@ -245,13 +324,14 @@ static int defining_kbd_macro = 0; /* */ /* **************************************************************** */ +static void rl_prep_terminal (), rl_deprep_terminal (); + /* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. A return value of NULL means that EOF was encountered. */ char * readline (prompt) char *prompt; { - static rl_prep_terminal (), rl_deprep_terminal (); char *readline_internal (); char *value; @@ -267,14 +347,14 @@ readline (prompt) rl_initialize (); rl_prep_terminal (); -#ifdef HANDLE_SIGNALS +#if defined (HANDLE_SIGNALS) rl_set_signals (); #endif value = readline_internal (); rl_deprep_terminal (); -#ifdef HANDLE_SIGNALS +#if defined (HANDLE_SIGNALS) rl_clear_signals (); #endif @@ -289,8 +369,11 @@ readline_internal () { int lastc, c, eof_found; - in_stream = rl_instream; out_stream = rl_outstream; - lastc = eof_found = 0; + in_stream = rl_instream; + out_stream = rl_outstream; + + lastc = -1; + eof_found = 0; if (rl_startup_hook) (*rl_startup_hook) (); @@ -307,7 +390,7 @@ readline_internal () { rl_on_new_line (); rl_redisplay (); -#ifdef VI_MODE +#if defined (VI_MODE) if (rl_editing_mode == vi_mode) rl_vi_insertion_mode (); #endif /* VI_MODE */ @@ -354,12 +437,12 @@ readline_internal () last_command_was_kill = 0; } -#ifdef VI_MODE +#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 +#endif /* VI_MODE */ if (!rl_done) rl_redisplay (); @@ -401,15 +484,16 @@ readline_internal () /* */ /* **************************************************************** */ -#ifdef SIGWINCH +#if defined (SIGWINCH) static SigHandler *old_sigwinch = (SigHandler *)NULL; static sighandler -rl_handle_sigwinch (sig, code, scp) - int sig, code; - struct sigcontext *scp; +rl_handle_sigwinch (sig) + int sig; { - char *term = rl_terminal_name, *getenv (); + char *term; + + term = rl_terminal_name; if (readline_echoing_p) { @@ -418,34 +502,43 @@ rl_handle_sigwinch (sig, code, scp) if (!term) term = "dumb"; rl_reset_terminal (term); -#ifdef NEVER +#if defined (NOTDEF) crlf (); rl_forced_update_display (); -#endif +#endif /* NOTDEF */ } if (old_sigwinch && old_sigwinch != (SigHandler *)SIG_IGN && old_sigwinch != (SigHandler *)SIG_DFL) - (*old_sigwinch)(sig, code, scp); + (*old_sigwinch) (sig); +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* VOID_SIGHANDLER */ } #endif /* SIGWINCH */ -#ifdef HANDLE_SIGNALS +#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; +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, code, scp) - int sig, code; - struct sigcontext *scp; +rl_signal_handler (sig) + int sig; { - static rl_prep_terminal (), rl_deprep_terminal (); +#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) { @@ -454,23 +547,39 @@ rl_signal_handler (sig, code, scp) rl_clear_message (); rl_init_argument (); -#ifdef SIGTSTP +#if defined (SIGTSTP) case SIGTSTP: case SIGTTOU: case SIGTTIN: -#endif - +#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 (); } + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* !VOID_SIGHANDLER */ } rl_set_signals () @@ -479,12 +588,16 @@ rl_set_signals () if (old_int == (SigHandler *)SIG_IGN) signal (SIGINT, SIG_IGN); -#ifdef SIGTSTP + 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); #endif -#ifdef SIGTTOU +#if defined (SIGTTOU) old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler); old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler); @@ -495,7 +608,7 @@ rl_set_signals () } #endif -#ifdef SIGWINCH +#if defined (SIGWINCH) old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch); #endif } @@ -503,17 +616,18 @@ rl_set_signals () rl_clear_signals () { signal (SIGINT, old_int); + signal (SIGALRM, old_alrm); -#ifdef SIGTSTP +#if defined (SIGTSTP) signal (SIGTSTP, old_tstp); #endif -#ifdef SIGTTOU +#if defined (SIGTTOU) signal (SIGTTOU, old_ttou); signal (SIGTTIN, old_ttin); #endif -#ifdef SIGWINCH +#if defined (SIGWINCH) signal (SIGWINCH, old_sigwinch); #endif } @@ -526,9 +640,12 @@ rl_clear_signals () /* */ /* **************************************************************** */ +#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 */ + static int pop_index = 0, push_index = 0, ibuffer_len = 511; static unsigned char ibuffer[512]; @@ -608,19 +725,29 @@ rl_gather_tyi () long chars_avail; char input; -#ifdef FIONREAD +#if defined (FIONREAD) result = ioctl (tty, FIONREAD, &chars_avail); #endif if (result == -1) { - fcntl (tty, F_SETFL, O_NDELAY); + int flags; + + flags = fcntl (tty, F_GETFL, 0); + + fcntl (tty, F_SETFL, (flags | O_NDELAY)); chars_avail = read (tty, &input, 1); - fcntl (tty, F_SETFL, 0); + + fcntl (tty, F_SETFL, flags); if (chars_avail == -1 && errno == EAGAIN) return; } + /* If there's nothing available, don't waste time trying to read + something. */ + if (chars_avail == 0) + return; + tem = ibuffer_space (); if (chars_avail > tem) @@ -645,6 +772,7 @@ rl_gather_tyi () } } +static int next_macro_key (); /* Read a key, including pending input. */ int rl_read_key () @@ -660,8 +788,6 @@ rl_read_key () } else { - static int next_macro_key (); - /* If input is coming from a macro, then use that. */ if (c = next_macro_key ()) return (c); @@ -682,23 +808,11 @@ rl_read_key () } } -#ifdef NEVER /* This breaks supdup to 4.0.3c machines. */ -#ifdef TIOCSTART - /* Ugh. But I can't think of a better way. */ - if (xoff_state && c == xon_char) - { - ioctl (fileno (in_stream), TIOCSTART, 0); - xoff_state = 0; - return (rl_read_key ()); - } -#endif /* TIOCSTART */ -#endif - return (c); } /* I'm beginning to hate the declaration rules for various compilers. */ -static void add_macro_char (); +static void add_macro_char (), with_macro_input (); /* Do the command associated with KEY in MAP. If the associated command is really a keymap, then read @@ -739,11 +853,17 @@ rl_dispatch (key, map) return; } - (*map[key].function)(rl_numeric_arg * arg_sign, key); + (*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 { - ding (); + rl_abort (); return; } } @@ -760,7 +880,7 @@ rl_dispatch (key, map) } else { - ding (); + rl_abort (); return; } break; @@ -768,19 +888,14 @@ rl_dispatch (key, map) case ISMACR: if (map[key].function != (Function *)NULL) { - static with_macro_input (); - char *macro = savestring ((char *)map[key].function); + char *macro; + macro = savestring ((char *)map[key].function); with_macro_input (macro); return; } break; } - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. */ - if (!rl_pending_input) - rl_last_func = map[key].function; } @@ -826,7 +941,7 @@ static void push_executing_macro (), pop_executing_macro (); /* Set up to read subsequent input from STRING. STRING is free ()'ed when we are done with it. */ -static +static void with_macro_input (string) char *string; { @@ -1010,7 +1125,7 @@ rl_initialize () readline_initialize_everything () { /* Find out if we are running in Emacs. */ - running_in_emacs = (char *)getenv ("EMACS"); + running_in_emacs = getenv ("EMACS"); /* Allocate data structures. */ if (!rl_line_buffer) @@ -1042,17 +1157,20 @@ readline_initialize_everything () /* If this system allows us to look at the values of the regular input editing characters, then bind them to their readline - equivalents. */ + equivalents, iff the characters are not bound to keymaps. */ readline_default_bindings () { -#ifdef NEW_TTY_DRIVER +#if defined (NEW_TTY_DRIVER) struct sgttyb ttybuff; int tty = fileno (rl_instream); if (ioctl (tty, TIOCGETP, &ttybuff) != -1) { - int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill; + int erase, kill; + + erase = ttybuff.sg_erase; + kill = ttybuff.sg_kill; if (erase != -1 && keymap[erase].type == ISFUNC) keymap[erase].function = rl_rubout; @@ -1061,13 +1179,16 @@ readline_default_bindings () keymap[kill].function = rl_unix_line_discard; } -#ifdef TIOCGLTC +#if defined (TIOCGLTC) { struct ltchars lt; if (ioctl (tty, TIOCGLTC, <) != -1) { - int erase = lt.t_werasc, nextc = lt.t_lnextc; + 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; @@ -1078,21 +1199,58 @@ readline_default_bindings () } #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 defined (TERMIOS_TTY_DRIVER) + if (tcgetattr (tty, &ttybuff) != -1) +#else if (ioctl (tty, TCGETA, &ttybuff) != -1) +#endif /* !TERMIOS_TTY_DRIVER */ { - int erase = ttybuff.c_cc[VERASE]; - int kill = ttybuff.c_cc[VKILL]; + int erase, kill; - if (erase != -1 && keymap[(unsigned char)erase].type == ISFUNC) + 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 != -1 && keymap[(unsigned char)kill].type == ISFUNC) + if (kill != _POSIX_VDISABLE && + keymap[(unsigned char)kill].type == ISFUNC) keymap[(unsigned char)kill].function = rl_unix_line_discard; + +#if defined (VLNEXT) + { + 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 */ + +#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 */ } -#endif /* NEW_TTY_DRIVER */ +#endif /* !NEW_TTY_DRIVER */ } @@ -1123,7 +1281,7 @@ rl_discard_argument () /* Create a default argument. */ rl_init_argument () { - rl_numeric_arg = arg_sign = 1; + rl_numeric_arg = rl_arg_sign = 1; rl_explicit_arg = 0; } @@ -1141,7 +1299,7 @@ rl_digit_loop () int key, c; while (1) { - rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg); + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); key = c = rl_read_key (); if (keymap[c].type == ISFUNC && @@ -1164,7 +1322,7 @@ rl_digit_loop () if (c == '-' && !rl_explicit_arg) { rl_numeric_arg = 1; - arg_sign = -1; + rl_arg_sign = -1; } else { @@ -1251,6 +1409,10 @@ static int horizontal_scroll_mode = 0; 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? */ @@ -1266,6 +1428,7 @@ 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. */ @@ -1308,13 +1471,24 @@ rl_redisplay () if (visible_line[0] != invisible_line[0]) rl_display_fixed = 0; - strncpy (line + out, rl_display_prompt, strlen (rl_display_prompt)); - out += strlen (rl_display_prompt); + 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 = the_line[in]; + c = (unsigned char)the_line[in]; if (out + 1 >= line_size) { @@ -1334,7 +1508,7 @@ rl_redisplay () line[out++] = c - 128; } #define DISPLAY_TABS -#ifdef DISPLAY_TABS +#if defined (DISPLAY_TABS) else if (c == '\t') { register int newout = (out | (int)7) + 1; @@ -1348,6 +1522,12 @@ rl_redisplay () line[out++] = '-'; line[out++] = c + 64; } + else if (c == 127) + { + line[out++] = 'C'; + line[out++] = '-'; + line[out++] = '?'; + } else line[out++] = c; } @@ -1497,7 +1677,7 @@ update_line (old, new, current_line) wsatend = 1; /* flag for trailing whitespace */ ols = oe - 1; /* find last same */ nls = ne - 1; - while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) + while ((*ols == *nls) && (ols > ofd) && (nls > nfd)) { if (*ols != ' ') wsatend = 0; @@ -1647,7 +1827,7 @@ move_cursor_relative (new, data) 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. */ -#ifdef HACK_TERMCAP_MOTION +#if defined (HACK_TERMCAP_MOTION) extern char *term_forward_char; if (term_forward_char) @@ -1683,7 +1863,7 @@ move_vert (to) for (i = 0; i < delta; i++) putc ('\n', out_stream); tputs (term_cr, 1, output_character_function); - last_c_pos = 0; /* because crlf() will do \r\n */ + last_c_pos = 0; } else { /* delta < 0 */ @@ -1705,7 +1885,7 @@ rl_show_char (c) c -= 128; } -#ifdef DISPLAY_TABS +#if defined (DISPLAY_TABS) if (c < 32 && c != '\t') #else if (c < 32) @@ -1719,7 +1899,7 @@ rl_show_char (c) fflush (out_stream); } -#ifdef DISPLAY_TABS +#if defined (DISPLAY_TABS) int rl_character_len (c, pos) register int c, pos; @@ -1792,13 +1972,16 @@ char *term_im, *term_ei, *term_ic, *term_ip, *term_IC; /* How to delete characters. */ char *term_dc, *term_DC; -#ifdef HACK_TERMCAP_MOTION +#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) @@ -1810,9 +1993,14 @@ rl_reset_terminal (terminal_name) init_terminal_io (terminal_name) char *terminal_name; { - char *term = (terminal_name? terminal_name : (char *)getenv ("TERM")); - char *tgetstr (), *buffer; + 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); @@ -1830,10 +2018,20 @@ init_terminal_io (terminal_name) 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; } - PC = tgetstr ("pc", &buffer)? *buffer : 0; + BC = tgetstr ("pc", &buffer); + PC = buffer ? *buffer : 0; term_backspace = tgetstr ("le", &buffer); @@ -1844,16 +2042,35 @@ init_terminal_io (terminal_name) if (!term_cr) term_cr = "\r"; -#ifdef HACK_TERMCAP_MOTION +#if defined (HACK_TERMCAP_MOTION) term_forward_char = tgetstr ("nd", &buffer); #endif /* HACK_TERMCAP_MOTION */ - screenwidth = tgetnum ("co"); + 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 = 80; - screenwidth--; /* PWP: avoid autowrap bugs */ + screenwidth = 79; - screenheight = tgetnum ("li"); if (screenheight <= 0) screenheight = 24; @@ -1871,6 +2088,8 @@ init_terminal_io (terminal_name) term_up = tgetstr ("up", &buffer); term_dc = tgetstr ("dc", &buffer); term_DC = tgetstr ("DC", &buffer); + + visible_bell = tgetstr ("vb", &buffer); } /* A function for the use of tputs () */ @@ -1890,7 +2109,6 @@ output_some_chars (string, count) fwrite (string, 1, count, out_stream); } - /* Delete COUNT characters from the display line. */ static delete_chars (count) @@ -1913,7 +2131,7 @@ delete_chars (count) } } -/* Insert COUNT character from STRING to the output stream. */ +/* Insert COUNT characters from STRING to the output stream. */ static insert_some_chars (string, count) char *string; @@ -1970,7 +2188,9 @@ backspace (count) /* 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); } @@ -2007,7 +2227,7 @@ clear_to_eol (count) /* Non-zero means that the terminal is in a prepped state. */ static int terminal_prepped = 0; -#ifdef NEW_TTY_DRIVER +#if defined (NEW_TTY_DRIVER) /* Standard flags, including ECHO. */ static int original_tty_flags = 0; @@ -2019,132 +2239,154 @@ static int local_mode_flags = 0; 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 +static void rl_prep_terminal () { int tty = fileno (rl_instream); - int oldmask = sigblock (sigmask (SIGINT)); +#if defined (HAVE_BSD_SIGNALS) + int oldmask; +#endif /* HAVE_BSD_SIGNALS */ - if (!terminal_prepped) - { - /* We always get the latest tty values. Maybe stty changed them. */ - ioctl (tty, TIOCGETP, &the_ttybuff); - original_tty_flags = the_ttybuff.sg_flags; + if (terminal_prepped) + return; + + oldmask = sigblock (sigmask (SIGINT)); - readline_echoing_p = (original_tty_flags & ECHO); + /* 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); + ioctl (tty, TIOCLGET, &local_mode_flags); #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 & ODDP) && (the_ttybuff.sg_flags & EVENP)) - { -#ifdef PASS8 - the_ttybuff.sg_flags |= PASS8; +#if !defined (ANYP) +# define ANYP (EVENP | ODDP) #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 - } - -#ifdef TIOCGETC - { - struct tchars temp; - - ioctl (tty, TIOCGETC, &original_tchars); - bcopy (&original_tchars, &temp, sizeof (struct tchars)); - /* 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); - - /* If there is an EOF char, bind eof_char to it. */ - if (temp.t_eofc != -1) - eof_char = temp.t_eofc; - -#ifdef NEVER - /* Get rid of C-\ and C-c. */ - temp.t_intrc = temp.t_quitc = -1; + /* 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 - ioctl (tty, TIOCSETC, &temp); + /* 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 */ -#ifdef TIOCGLTC - { - struct ltchars temp; +#if defined (TIOCGLTC) + { + struct ltchars temp; - ioctl (tty, TIOCGLTC, &original_ltchars); - bcopy (&original_ltchars, &temp, sizeof (struct ltchars)); + 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 */ + /* 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); - } + ioctl (tty, TIOCSLTC, &temp); + } #endif /* TIOCGLTC */ - the_ttybuff.sg_flags &= ~ECHO; - the_ttybuff.sg_flags |= CBREAK; - ioctl (tty, TIOCSETN, &the_ttybuff); + the_ttybuff.sg_flags &= ~(ECHO | CRMOD); + the_ttybuff.sg_flags |= CBREAK; + ioctl (tty, TIOCSETN, &the_ttybuff); - terminal_prepped = 1; - } + terminal_prepped = 1; + +#if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask); +#endif } /* Restore the terminal to its original state. */ -static +static void rl_deprep_terminal () { int tty = fileno (rl_instream); - int oldmask = sigblock (sigmask (SIGINT)); +#if defined (HAVE_BSD_SIGNALS) + int oldmask; +#endif - if (terminal_prepped) - { - the_ttybuff.sg_flags = original_tty_flags; - ioctl (tty, TIOCSETN, &the_ttybuff); - readline_echoing_p = 1; + 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); + ioctl (tty, TIOCLSET, &local_mode_flags); #endif -#ifdef TIOCSLTC - ioctl (tty, TIOCSLTC, &original_ltchars); +#if defined (TIOCSLTC) + ioctl (tty, TIOCSLTC, &original_ltchars); #endif -#ifdef TIOCSETC - ioctl (tty, TIOCSETC, &original_tchars); +#if defined (TIOCSETC) + ioctl (tty, TIOCSETC, &original_tchars); #endif - terminal_prepped = 0; - } + terminal_prepped = 0; +#if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask); +#endif } #else /* !defined (NEW_TTY_DRIVER) */ @@ -2157,38 +2399,164 @@ rl_deprep_terminal () #define VTIME VEOL #endif +#if defined (TERMIOS_TTY_DRIVER) +static struct termios otio; +#else static struct termio otio; +#endif /* !TERMIOS_TTY_DRIVER */ -static +static void rl_prep_terminal () { 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); - ioctl (tty, TCGETA, &otio); +#endif /* !TERMIOS_TTY_DRIVER */ + + otio = tio; readline_echoing_p = (tio.c_lflag & ECHO); tio.c_lflag &= ~(ICANON|ECHO); - tio.c_iflag &= ~(IXON|IXOFF|IXANY|ISTRIP|INPCK); + + 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 */ } -static +static void rl_deprep_terminal () { 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 /* NEW_TTY_DRIVER */ @@ -2204,12 +2572,11 @@ rl_deprep_terminal () int allow_pathname_alphabetic_chars = 0; char *pathname_alphabetic_chars = "/-_=~.#$"; -char *rindex (); + int alphabetic (c) int c; { - if (pure_alphabetic (c) || (numeric (c))) return (1); @@ -2233,8 +2600,13 @@ ding () { if (readline_echoing_p) { - fprintf (stderr, "\007"); - fflush (stderr); + if (prefer_visible_bell && visible_bell) + tputs (visible_bell, 1, output_character_function); + else + { + fprintf (stderr, "\007"); + fflush (stderr); + } } return (-1); } @@ -2251,12 +2623,17 @@ rl_abort () 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. */ -static char * +#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; { @@ -2264,11 +2641,12 @@ rl_copy (from, to) char *copy; /* Fix it if the caller is confused. */ - if (from > to) { - int t = from; - from = to; - to = t; - } + if (from > to) + { + int t = from; + from = to; + to = t; + } length = to - from; copy = (char *)xmalloc (1 + length); @@ -2277,6 +2655,20 @@ rl_copy (from, to) 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; +} + /* **************************************************************** */ /* */ @@ -2284,7 +2676,6 @@ rl_copy (from, to) /* */ /* **************************************************************** */ - /* 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. */ @@ -2293,13 +2684,9 @@ rl_insert_text (string) { extern int doing_an_undo; register int i, l = strlen (string); - while (rl_end + l >= rl_line_buffer_len) - { - rl_line_buffer = - (char *)xrealloc (rl_line_buffer, - rl_line_buffer_len += DEFAULT_BUFFER_SIZE); - the_line = rl_line_buffer; - } + + 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]; @@ -2332,11 +2719,12 @@ rl_delete_text (from, to) register char *text; /* Fix it if the caller is confused. */ - if (from > to) { - int t = from; - from = to; - to = t; - } + 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); @@ -2394,11 +2782,11 @@ rl_forward (count) else while (count) { -#ifdef VI_MODE +#if defined (VI_MODE) if (rl_point == (rl_end - (rl_editing_mode == vi_mode))) #else if (rl_point == rl_end) -#endif +#endif /* VI_MODE */ { ding (); return; @@ -2558,6 +2946,36 @@ rl_clear_screen () 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 (); + } +} + /* **************************************************************** */ /* */ @@ -2667,7 +3085,7 @@ rl_newline (count, key) rl_done = 1; -#ifdef VI_MODE +#if defined (VI_MODE) { extern int vi_doing_insert; if (vi_doing_insert) @@ -2826,7 +3244,6 @@ rl_unix_line_discard () /* Random and interesting things in here. */ - /* **************************************************************** */ /* */ /* Changing Case */ @@ -2990,25 +3407,33 @@ rl_transpose_chars (count) 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--; + 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 - rl_point++; + count--; } - if (count < 0) - count++; - else - count--; - } } @@ -3021,12 +3446,47 @@ rl_transpose_chars (count) rl_restart_output (count, key) int count, key; { - int fildes = fileno (stdin); -#ifdef TIOCSTART + 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. */ @@ -3047,13 +3507,20 @@ Function *rl_completion_entry_function = (Function *)NULL; 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; { - rl_complete_internal (TAB); + 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 (). */ @@ -3082,7 +3549,7 @@ 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\"\\'`@$><="; +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 @@ -3102,6 +3569,17 @@ int rl_ignore_completion_duplicates = 1; 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. @@ -3114,7 +3592,12 @@ rl_complete_internal (what_to_do) char **completion_matches (), **matches; Function *our_func; int start, end, delimiter = 0; - char *text; + char *text, *saved_line_buffer; + + 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; @@ -3126,13 +3609,14 @@ rl_complete_internal (what_to_do) /* We now look backwards for the start of a filename/variable word. */ end = rl_point; + if (rl_point) { 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 (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. */ @@ -3161,10 +3645,13 @@ rl_complete_internal (what_to_do) (char **)(*rl_attempted_completion_function) (text, start, end); if (matches) - goto after_usual_completion; + { + our_func = (Function *)NULL; + goto after_usual_completion; + } } - matches = completion_matches (text, our_func, start, end); + matches = completion_matches (text, our_func); after_usual_completion: free (text); @@ -3191,7 +3678,7 @@ rl_complete_internal (what_to_do) for (i = 0; matches[i]; i++); qsort (matches, i, sizeof (char *), compare_strings); - /* Remember the lowest common denimator for it may be unique. */ + /* Remember the lowest common denominator for it may be unique. */ lowest_common = savestring (matches[0]); for (i = 0; matches[i + 1]; i++) @@ -3212,12 +3699,16 @@ rl_complete_internal (what_to_do) (char **)malloc ((3 + newlen) * sizeof (char *)); for (i = 1, j = 1; matches[i]; i++) - if (matches[i] != (char *)-1) - temp_array[j++] = matches[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; @@ -3239,6 +3730,14 @@ rl_complete_internal (what_to_do) 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 (matches[0]) { rl_delete_text (start, rl_point); @@ -3265,11 +3764,10 @@ rl_complete_internal (what_to_do) if (rl_filename_completion_desired) { struct stat finfo; - char *tilde_expand (); char *filename = tilde_expand (matches[0]); if ((stat (filename, &finfo) == 0) && - ((finfo.st_mode & S_IFMT) == S_IFDIR)) + S_ISDIR (finfo.st_mode)) { if (the_line[rl_point] != '/') rl_insert_text ("/"); @@ -3313,7 +3811,6 @@ rl_complete_internal (what_to_do) } break; - case '?': { int len, count, limit, max = 0; @@ -3322,7 +3819,7 @@ rl_complete_internal (what_to_do) /* Handle simple case first. What if there is only one answer? */ if (!matches[1]) { - char *temp; + char *temp; if (rl_filename_completion_desired) temp = rindex (matches[0], '/'); @@ -3345,7 +3842,7 @@ rl_complete_internal (what_to_do) is. */ for (i = 1; matches[i]; i++) { - char *temp = (char *)NULL; + char *temp = (char *)NULL; /* If we are hacking filenames, then only count the characters after the last slash in the pathname. */ @@ -3387,6 +3884,11 @@ rl_complete_internal (what_to_do) 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; @@ -3412,7 +3914,7 @@ rl_complete_internal (what_to_do) } else { - char *temp = (char *)NULL; + char *temp = (char *)NULL; if (rl_filename_completion_desired) temp = rindex (matches[l], '/'); @@ -3446,6 +3948,17 @@ rl_complete_internal (what_to_do) 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. */ @@ -3466,13 +3979,21 @@ username_completion_function (text, state) { static char *username = (char *)NULL; static struct passwd *entry; - static int namelen; + static int namelen, first_char, first_char_loc; if (!state) { if (username) free (username); - username = savestring (&text[1]); + + 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 (); } @@ -3491,97 +4012,17 @@ username_completion_function (text, state) else { char *value = (char *)xmalloc (2 + strlen (entry->pw_name)); - *value = *text; - strcpy (value + 1, entry->pw_name); - rl_filename_completion_desired = 1; - return (value); - } -} -/* If non-null, this contains the address of a function to call if the - standard meaning for expanding a tilde fails. The function is called - with the text (sans tilde, as in "foo"), and returns a malloc()'ed string - which is the expansion, or a NULL pointer if there is no expansion. */ -Function *rl_tilde_expander = (Function *)NULL; - -/* Expand FILENAME if it begins with a tilde. This always returns - a new string. */ -char * -tilde_expand (filename) - char *filename; -{ - char *dirname = filename ? savestring (filename) : (char *)NULL; - - if (dirname && *dirname == '~') - { - char *temp_name; - if (!dirname[1] || dirname[1] == '/') - { - /* Prepend $HOME to the rest of the string. */ - char *temp_home = (char *)getenv ("HOME"); - - temp_name = (char *)alloca (1 + strlen (&dirname[1]) - + (temp_home? strlen (temp_home) : 0)); - temp_name[0] = '\0'; - if (temp_home) - strcpy (temp_name, temp_home); - strcat (temp_name, &dirname[1]); - free (dirname); - dirname = savestring (temp_name); - } - else - { - struct passwd *getpwnam (), *user_entry; - char *username = (char *)alloca (257); - int i, c; - - for (i = 1; c = dirname[i]; i++) - { - if (c == '/') break; - else username[i - 1] = c; - } - username[i - 1] = '\0'; + *value = *text; - if (!(user_entry = getpwnam (username))) - { - /* If the calling program has a special syntax for - expanding tildes, and we couldn't find a standard - expansion, then let them try. */ - if (rl_tilde_expander) - { - char *expansion; + strcpy (value + first_char_loc, entry->pw_name); - expansion = (char *)(*rl_tilde_expander) (username); + if (first_char == '~') + rl_filename_completion_desired = 1; - if (expansion) - { - temp_name = (char *)alloca (1 + strlen (expansion) - + strlen (&dirname[i])); - strcpy (temp_name, expansion); - strcat (temp_name, &dirname[i]); - free (expansion); - goto return_name; - } - } - /* - * We shouldn't report errors. - */ - } - else - { - temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir) - + strlen (&dirname[i])); - strcpy (temp_name, user_entry->pw_dir); - strcat (temp_name, &dirname[i]); - return_name: - free (dirname); - dirname = savestring (temp_name); - } - } + return (value); } - return (dirname); } - /* **************************************************************** */ /* */ @@ -3784,38 +4225,46 @@ 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); - } + 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) { - 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 { + 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; - } + 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; + } } - - /* **************************************************************** */ /* */ @@ -3866,9 +4315,20 @@ rl_get_next_history (count) 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 */ } } @@ -3914,24 +4374,24 @@ rl_get_previous_history (count) 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 = strlen (the_line); -#ifdef VI_MODE + rl_end = rl_point = line_len; + +#if defined (VI_MODE) if (rl_editing_mode == vi_mode) rl_point = 0; #endif /* VI_MODE */ } } -/* There is a command in ksh which yanks into this line, the last word - of the previous line. Here it is. We left it on M-. */ -rl_yank_previous_last_arg (ignore) - int ignore; -{ -} - - /* **************************************************************** */ /* */ @@ -3973,10 +4433,10 @@ rl_display_search (search_string, reverse_p, where) *message = '\0'; -#ifdef NEVER +#if defined (NOTDEF) if (where != -1) sprintf (message, "[%d]", where + history_base); -#endif +#endif /* NOTDEF */ strcat (message, "("); @@ -3995,7 +4455,7 @@ rl_display_search (search_string, reverse_p, where) /* 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 + DIRECTION is which direction to search; >= 0 means forward, < 0 means backwards. */ rl_search_history (direction, invoking_key) int direction; @@ -4016,12 +4476,11 @@ rl_search_history (direction, invoking_key) /* 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; - register int i = 0; - /* The line currently being searched. */ char *sline; @@ -4033,7 +4492,6 @@ rl_search_history (direction, invoking_key) 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++); @@ -4047,9 +4505,13 @@ rl_search_history (direction, invoking_key) if (saved_line_for_history) lines[i] = saved_line_for_history->line; else + /* So I have to type it in this way instead. */ { - /* So I have to type it in this way instead. */ - lines[i] = (char *)alloca (1 + strlen (the_line)); + 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]); } @@ -4062,6 +4524,12 @@ rl_search_history (direction, invoking_key) *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; @@ -4076,12 +4544,14 @@ rl_search_history (direction, invoking_key) Function *f = (Function *)NULL; if (keymap[c].type == ISFUNC) - f = keymap[c].function; + { + 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; + if (f == rl_reverse_search_history) + c = reverse ? -1 : -2; + else if (f == rl_forward_search_history) + c = !reverse ? -1 : -2; + } } switch (c) @@ -4143,9 +4613,8 @@ rl_search_history (direction, invoking_key) { while (index >= 0) if (strncmp - (search_string, - sline + index, - search_string_index) == 0) + (search_string, sline + index, search_string_index) + == 0) goto string_found; else index--; @@ -4199,18 +4668,30 @@ rl_search_history (direction, invoking_key) /* 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. */ - strcpy (the_line, lines[i]); - rl_point = index; - rl_end = strlen (the_line); - last_found_line = i; - rl_display_search (search_string, reverse, - (i == orig_line) ? -1 : i); + { + 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 user has won. They found the string that they wanted. Now all - we have to do is place them there. */ + + /* 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; @@ -4222,6 +4703,12 @@ rl_search_history (direction, invoking_key) 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 (); } @@ -4273,66 +4760,79 @@ rl_kill_text (from, to) char *text = rl_copy (from, to); /* Is there anything to kill? */ - if (from == to) { - free (text); - last_command_was_kill++; - return; - } + 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 *)); - } + 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; } - slot--; - } else { - slot = rl_kill_ring_length - 1; - } /* If the last command was a kill, prepend or append. */ - if (last_command_was_kill) { - 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; - } + 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++; } @@ -4341,7 +4841,6 @@ rl_kill_text (from, to) commands always make rl_point's original position be the FROM argument, and rl_point's extent be the TO argument. */ - /* **************************************************************** */ /* */ /* Killing Commands */ @@ -4484,22 +4983,27 @@ rl_yank_nth_arg (count, ignore) } 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 (); } -/* Vi Mode. */ -#ifdef VI_MODE -#include "vi_mode.c" -#endif /* VI_MODE */ - /* How to toggle back and forth between editing modes. */ rl_vi_editing_mode () { -#ifdef VI_MODE +#if defined (VI_MODE) rl_editing_mode = vi_mode; rl_vi_insertion_mode (); #endif /* VI_MODE */ @@ -4524,7 +5028,7 @@ 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 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 *). @@ -4556,9 +5060,8 @@ completion_matches (text, entry_function) 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 = (char **)xrealloc + (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); match_list[++matches] = string; match_list[matches + 1] = (char *)NULL; @@ -4639,7 +5142,7 @@ filename_completion_function (text, state) /* If we don't have any state, then do some initialization. */ if (!state) { - char *temp; + char *temp; if (dirname) free (dirname); if (filename) free (filename); @@ -4664,7 +5167,9 @@ filename_completion_function (text, state) /* Save the version of the directory that the user typed. */ users_dirname = savestring (dirname); { - char *tilde_expand (), *temp_dirname = tilde_expand (dirname); + char *temp_dirname; + + temp_dirname = tilde_expand (dirname); free (dirname); dirname = temp_dirname; @@ -4678,9 +5183,9 @@ filename_completion_function (text, state) } /* At this point we should entertain the possibility of hacking wildcarded - filenames, like /usr/man*\/te. If the directory name contains - globbing characters, then build an array of directories to glob on, and - glob on the first one. */ + 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. */ @@ -4698,13 +5203,8 @@ filename_completion_function (text, state) { /* Otherwise, if these match upto the length of filename, then it is a match. */ -#ifdef TMB_SYSV - if ((strlen (entry->d_name) >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) -#else - if ((entry->d_namlen >= filename_len) && + if (((int)D_NAMLEN (entry)) >= filename_len && (strncmp (filename, entry->d_name, filename_len) == 0)) -#endif /* TMB_SYSV */ { break; } @@ -4726,13 +5226,8 @@ filename_completion_function (text, state) if (dirname && (strcmp (dirname, ".") != 0)) { -#ifdef TMB_SYSV - temp = (char *)xmalloc (1 + strlen (users_dirname) - + strlen (entry->d_name)); -#else - temp = (char *)xmalloc (1 + strlen (users_dirname) - + entry->d_namlen); -#endif /* TMB_SYSV */ + temp = (char *) + xmalloc (1 + strlen (users_dirname) + D_NAMLEN (entry)); strcpy (temp, users_dirname); strcat (temp, entry->d_name); } @@ -4847,9 +5342,11 @@ rl_macro_bind (keyseq, macro, map) char *keyseq, *macro; Keymap map; { - char *macro_keys = (char *)xmalloc (2 * (strlen (macro))); + 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); @@ -4956,7 +5453,11 @@ rl_translate_keyseq (seq, array, len) case 'C': i += 2; - array[l++] = CTRL (to_upper (seq[i])); + /* Special hack for C-?... */ + if (seq[i] == '?') + array[l++] = RUBOUT; + else + array[l++] = CTRL (to_upper (seq[i])); break; case 'e': @@ -4996,7 +5497,7 @@ static char *last_readline_init_file = "~/.inputrc"; rl_re_read_init_file (count, ignore) int count, ignore; { - rl_read_init_file (last_readline_init_file); + rl_read_init_file ((char *)NULL); } /* Do key bindings from a file. If FILENAME is NULL it defaults @@ -5006,67 +5507,58 @@ int rl_read_init_file (filename) char *filename; { - extern int errno; - int line_size, line_index; - char *line = (char *)xmalloc (line_size = 100); - char *openname; - FILE *file; - - int c; + register int i; + char *buffer, *openname, *line, *end; + struct stat finfo; + int file; /* Default the filename. */ if (!filename) - filename = "~/.inputrc"; + filename = last_readline_init_file; openname = tilde_expand (filename); - /* Open the file. */ - file = fopen (openname, "r"); - free (openname); - - if (!file) - return (errno); + if ((stat (openname, &finfo) < 0) || + (file = open (openname, O_RDONLY, 0666)) < 0) + { + free (openname); + return (errno); + } + else + free (openname); last_readline_init_file = filename; - /* Loop reading lines from the file. Lines that start with `#' are - comments, all other lines are commands for readline initialization. */ - while ((c = rl_getc (file)) != EOF) - { - /* If comment, flush to EOL. */ - if (c == '#') - { - while ((c = rl_getc (file)) != EOF && c != '\n'); - if (c == EOF) - goto function_exit; - continue; - } + /* Read the file into BUFFER. */ + buffer = (char *)xmalloc (finfo.st_size + 1); + i = read (file, buffer, finfo.st_size); + close (file); - /* Otherwise, this is the start of a line. Read the - line from the file. */ - line_index = 0; - while (c != EOF && c != '\n') - { - line[line_index++] = c; - if (line_index == line_size) - line = (char *)xrealloc (line, line_size += 100); - c = rl_getc (file); - } - line[line_index] = '\0'; + if (i != finfo.st_size) + return (errno); - /* Parse the line. */ - rl_parse_and_bind (line); - } + /* 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'; -function_exit: + /* If the line is not a comment, then parse it. */ + if (*line != '#') + rl_parse_and_bind (line); - free (line); - /* Close up the file and exit. */ - fclose (file); + /* Move to the next line. */ + line += i + 1; + } return (0); } - /* **************************************************************** */ /* */ /* Parser Directives */ @@ -5099,8 +5591,10 @@ parser_if (args) } if_stack[if_stack_depth++] = parsing_conditionalized_out; - /* We only check to see if the first word in ARGS is the same as the - value stored in rl_readline_name. */ + /* 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++); @@ -5108,7 +5602,45 @@ parser_if (args) if (args[i]) args[i++] = '\0'; - if (stricmp (args, rl_readline_name) == 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; @@ -5118,12 +5650,22 @@ parser_if (args) parser_else (args) char *args; { - if (if_stack_depth) - parsing_conditionalized_out = !parsing_conditionalized_out; - else + register int i; + + if (!if_stack_depth) { - /* *** What, no error message? *** */ + /* 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 @@ -5187,6 +5729,11 @@ handle_parser_directive (statement) 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. @@ -5195,11 +5742,13 @@ rl_parse_and_bind (string) char *string; { extern char *possible_control_prefixes[], *possible_meta_prefixes[]; - char *funname, *kname; - static int substring_member_of_array (); + char *funname, *kname; register int c; int key, i; + while (string && whitespace (*string)) + string++; + if (!string || !*string || *string == '#') return; @@ -5341,6 +5890,17 @@ rl_parse_and_bind (string) 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)); } @@ -5352,9 +5912,15 @@ rl_variable_bind (name, value) { if (strnicmp (value, "vi", 2) == 0) { -#ifdef VI_MODE +#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) @@ -5377,6 +5943,27 @@ rl_variable_bind (name, value) 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. @@ -5388,18 +5975,17 @@ typedef struct { } assoc_list; assoc_list name_key_alist[] = { - { "Space", ' ' }, - { "SPC", ' ' }, - { "Rubout", 0x7f }, { "DEL", 0x7f }, - { "Tab", 0x09 }, + { "ESC", '\033' }, + { "Escape", '\033' }, + { "LFD", '\n' }, { "Newline", '\n' }, - { "Return", '\r' }, { "RET", '\r' }, - { "LFD", '\n' }, - { "Escape", '\033' }, - { "ESC", '\033' }, - + { "Return", '\r' }, + { "Rubout", 0x7f }, + { "SPC", ' ' }, + { "Space", ' ' }, + { "Tab", 0x09 }, { (char *)0x0, 0 } }; @@ -5416,6 +6002,232 @@ glean_key_from_name (name) 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); + } + } + } +} + /* **************************************************************** */ /* */ @@ -5423,13 +6235,13 @@ glean_key_from_name (name) /* */ /* **************************************************************** */ +static char *strindex (); + /* Return non-zero if any members of ARRAY are a substring in STRING. */ static int substring_member_of_array (string, array) char *string, **array; { - static char *strindex (); - while (*array) { if (strindex (string, *array)) @@ -5495,18 +6307,12 @@ strindex (s1, s2) /* **************************************************************** */ /* */ -/* SYSV Support */ +/* USG (System V) Support */ /* */ /* **************************************************************** */ -/* Since system V reads input differently than we do, I have to - make a special version of getc for that. */ - -#ifdef SYSV - -extern int errno; -#include - +/* 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; @@ -5517,23 +6323,24 @@ rl_getc (stream) 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); + + /* 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); } } -#else -int -rl_getc (stream) - FILE *stream; -{ - return (getc (stream)); -} -#endif -#ifdef STATIC_MALLOC +#if defined (STATIC_MALLOC) /* **************************************************************** */ /* */ @@ -5559,10 +6366,16 @@ xrealloc (pointer, bytes) char *pointer; int bytes; { - char *temp = (char *)realloc (pointer, bytes); + char *temp; + + if (!pointer) + temp = (char *)malloc (bytes); + else + temp = (char *)realloc (pointer, bytes); if (!temp) memory_error_and_abort (); + return (temp); } @@ -5581,7 +6394,7 @@ memory_error_and_abort () /* */ /* **************************************************************** */ -#ifdef TEST +#if defined (TEST) main () { @@ -5609,17 +6422,20 @@ main () 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); + 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); } } diff --git a/readline/readline.h b/readline/readline.h index 3e62976c505..2e319f69df7 100644 --- a/readline/readline.h +++ b/readline/readline.h @@ -1,55 +1,59 @@ /* Readline.h -- the names of functions callable from within readline. */ -#ifndef _READLINE_H_ +#if !defined (_READLINE_H_) #define _READLINE_H_ -#include +#include "keymaps.h" -#ifndef __FUNCTION_DEF +#if !defined (__FUNCTION_DEF) typedef int Function (); #define __FUNCTION_DEF -#endif +#endif /* __FUNCTION_DEF */ /* The functions for manipulating the text of the line within readline. Most of these functions are bound to keys by default. */ extern int -rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), -rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), -rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), -rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars -(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout -(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), -rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), -rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words -(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version -(), rl_digit_argument (), rl_universal_argument (), rl_abort (), -rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), -rl_end_of_history (), rl_forward_search_history (), rl_insert (), -rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), -rl_restart_output (), rl_re_read_init_file (); + rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), + rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), + rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), + rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars (), + rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout (), + rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), + rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), + rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words (), + rl_complete (), rl_possible_completions (), rl_do_lowercase_version (), + rl_digit_argument (), rl_universal_argument (), rl_abort (), + rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), + rl_end_of_history (), rl_forward_search_history (), rl_insert (), + rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), + rl_restart_output (), rl_re_read_init_file (), rl_dump_functions (); /* These are *both* defined even when VI_MODE is not. */ extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); -#ifdef VI_MODE +#if defined (VI_MODE) /* Things for vi mode. */ -extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), -rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), -rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), -rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), -rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), -rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), -rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (), -rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), -rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), -rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), -rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (); +extern int + rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), + rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), + rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), + rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), + rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), + rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), + rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), + rl_vi_change_char (), rl_vi_yank_arg (), rl_vi_search (), + rl_vi_search_again (), rl_vi_dosearch (), rl_vi_subst (), + rl_vi_overstrike (), rl_vi_overstrike_delete (), rl_vi_replace(), + rl_vi_column (), rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), + rl_vi_complete (), rl_vi_fetch_history (); #endif /* VI_MODE */ /* Keyboard macro commands. */ extern int rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro (); +extern int rl_arrow_keys(), rl_refresh_line (); + /* Maintaining the state of undo. We remember individual deletes and inserts on a chain of things to do. */ @@ -100,8 +104,8 @@ extern char *rl_terminal_name; extern FILE *rl_instream, *rl_outstream; /* 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. "n\"\\'`@$>". */ + completer routine. The initial contents of this variable is what + breaks words in the shell, i.e. "n\"\\'`@$>". */ extern char *rl_basic_word_break_characters; /* The list of characters that signal a break between words for @@ -119,6 +123,14 @@ extern char *rl_special_prefixes; completer. */ extern Function *rl_completion_entry_function; +/* If rl_ignore_some_completions_function is non-NULL it is the address + of a function to call after all of the possible matches have been + generated, but before the actual completion is done to the input line. + The function is called with one argument; a NULL terminated array + of (char *). If your function removes any of the elements, they + must be free()'ed. */ +extern Function *rl_ignore_some_completions_function; + /* 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 @@ -128,12 +140,6 @@ extern Function *rl_completion_entry_function; array of strings returned. */ extern Function *rl_attempted_completion_function; -/* If non-null, this contains the address of a function to call if the - standard meaning for expanding a tilde fails. The function is called - with the text (sans tilde, as in "foo"), and returns a malloc()'ed string - which is the expansion, or a NULL pointer if there is no expansion. */ -extern Function *rl_tilde_expander; - /* If non-zero, then this is the address of a function to call just before readline_internal () prints the first prompt. */ extern Function *rl_startup_hook; @@ -147,6 +153,29 @@ extern Function *rl_symbolic_link_hook; with an asterisk. */ extern int rl_show_star; + +/* **************************************************************** */ +/* */ +/* Tilde Variables That Can be Externally Set */ +/* */ +/* **************************************************************** */ + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern Function *tilde_expansion_failure_hook; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +extern char **tilde_additional_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `/' and `:'. */ +extern char **tilde_additional_suffixes; + /* **************************************************************** */ /* */ /* Well Published Functions */ @@ -167,4 +196,3 @@ extern char **completion_matches (); extern int rl_add_defun (); #endif /* _READLINE_H_ */ - diff --git a/readline/vi_keymap.c b/readline/vi_keymap.c index 81fbb9b8cd3..5464dad6138 100644 --- a/readline/vi_keymap.c +++ b/readline/vi_keymap.c @@ -19,9 +19,9 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef FILE +#ifndef BUFSIZ #include -#endif /* FILE */ +#endif /* BUFSIZ */ #include "readline.h" @@ -39,7 +39,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ { ISFUNC, (Function *)0x0 }, /* Control-f */ { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, rl_rubout }, /* Control-h */ { ISFUNC, (Function *)0x0 }, /* Control-i */ { ISFUNC, rl_newline }, /* Control-j */ { ISFUNC, rl_kill_line }, /* Control-k */ @@ -99,7 +99,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, (Function *)0x0 }, /* : */ { ISFUNC, rl_vi_char_search }, /* ; */ { ISFUNC, (Function *)0x0 }, /* < */ - { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, rl_vi_complete }, /* = */ { ISFUNC, (Function *)0x0 }, /* > */ { ISFUNC, rl_vi_search }, /* ? */ { ISFUNC, (Function *)0x0 }, /* @ */ @@ -111,7 +111,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_vi_delete_to }, /* D */ { ISFUNC, rl_vi_end_word }, /* E */ { ISFUNC, rl_vi_char_search }, /* F */ - { ISFUNC, (Function *)0x0 }, /* G */ + { ISFUNC, rl_vi_fetch_history }, /* G */ { ISFUNC, (Function *)0x0 }, /* H */ { ISFUNC, rl_vi_insert_beg }, /* I */ { ISFUNC, (Function *)0x0 }, /* J */ @@ -134,7 +134,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { /* Some more punctuation. */ { ISFUNC, (Function *)0x0 }, /* [ */ - { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, rl_vi_complete }, /* \ */ { ISFUNC, (Function *)0x0 }, /* ] */ { ISFUNC, rl_vi_first_print }, /* ^ */ { ISFUNC, rl_vi_yank_arg }, /* _ */ diff --git a/readline/vi_mode.c b/readline/vi_mode.c index 478af9194a0..bdc81072974 100644 --- a/readline/vi_mode.c +++ b/readline/vi_mode.c @@ -1,14 +1,83 @@ /* vi_mode.c -- A vi emulation mode for Bash. + Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ - Derived from code written by Jeff Sparkes (jeff1@????). - */ +/* Copyright (C) 1988, 1991 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ /* **************************************************************** */ /* */ /* VI Emulation Mode */ /* */ /* **************************************************************** */ +#if defined (VI_MODE) + +#include + +#if defined (__GNUC__) +# define alloca __builtin_alloca +#else +# if defined (sparc) || defined (HAVE_ALLOCA_H) +# include +# endif +#endif + +/* 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 + +#ifndef isident +#define isident(c) ((isletter(c) || digit(c) || c == '_')) +#endif + +#ifndef exchange +#define exchange(x, y) {int temp = x; x = y; y = temp;} +#endif + +/* Variables imported from readline.c */ +extern int rl_point, rl_end, rl_mark, rl_done; +extern FILE *rl_instream; +extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg; +extern Keymap keymap; +extern char *rl_prompt; +extern char *rl_line_buffer; +extern int rl_arg_sign; + +extern char *xmalloc (), *xrealloc (); +extern void rl_extend_line_buffer (); /* Last string searched for from `/' or `?'. */ static char *vi_last_search = (char *)NULL; @@ -17,6 +86,9 @@ static int vi_histpos; /* Non-zero means enter insertion mode. */ int vi_doing_insert = 0; +/* String inserted into the line by rl_vi_comment (). */ +char *rl_vi_comment_begin = (char *)NULL; + /* *** UNCLEAN *** */ /* Command keys which do movement for xxx_to commands. */ static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; @@ -26,13 +98,43 @@ static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; static Keymap vi_replace_map = (Keymap)NULL; /* The number of characters inserted in the last replace operation. */ -static vi_replace_count = 0; +static int vi_replace_count = 0; /* Yank the nth arg from the previous line into this line at point. */ rl_vi_yank_arg (count) int count; { - rl_yank_nth_arg (count, 0); + /* Readline thinks that the first word on a line is the 0th, while vi + thinks the first word on a line is the 1st. Compensate. */ + if (rl_explicit_arg) + rl_yank_nth_arg (count - 1, 0); + else + rl_yank_nth_arg ('$', 0); +} + +/* With an argument, move back that many history lines, else move to the + beginning of history. */ +rl_vi_fetch_history (count, c) + int count, c; +{ + extern int rl_explicit_arg; + int current = where_history (); + + /* Giving an argument of n means we want the nth command in the history + file. The command number is interpreted the same way that the bash + `history' command does it -- that is, giving an argument count of 450 + to this command would get the command listed as number 450 in the + output of `history'. */ + if (rl_explicit_arg) + { + int wanted = history_base + current - count; + if (wanted <= 0) + rl_beginning_of_history (0, 0); + else + rl_get_previous_history (wanted); + } + else + rl_beginning_of_history (count, 0); } /* Search again for the last thing searched for. */ @@ -78,7 +180,7 @@ rl_vi_search (count, key) save_pos = rl_point; /* Reuse the line input buffer to read the search string. */ - the_line[0] = 0; + rl_line_buffer[0] = 0; rl_end = rl_point = 0; p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0)); @@ -128,8 +230,38 @@ rl_vi_search (count, key) if (vi_last_search) free (vi_last_search); - vi_last_search = savestring (the_line); - rl_vi_dosearch (the_line, dir); + vi_last_search = savestring (rl_line_buffer); + rl_vi_dosearch (rl_line_buffer, dir); +} + +/* Search for STRING in the history list. DIR is < 0 for searching + backwards. POS is an absolute index into the history list at + which point to begin searching. If the first character of STRING + is `^', the string must match a prefix of a history line, otherwise + a full substring match is performed. */ +static int +vi_history_search_pos (string, dir, pos) + char *string; + int dir, pos; +{ + int ret, old = where_history (); + + history_set_pos (pos); + + if (*string == '^') + ret = history_search_prefix (string + 1, dir); + else + ret = history_search (string, dir); + + if (ret == -1) + { + history_set_pos (old); + return (-1); + } + + ret = where_history (); + history_set_pos (old); + return ret; } rl_vi_dosearch (string, dir) @@ -145,7 +277,7 @@ rl_vi_dosearch (string, dir) return; } - if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1) + if ((save = vi_history_search_pos (string, dir, vi_histpos + dir)) == -1) { maybe_unsave_line (); rl_clear_message (); @@ -161,9 +293,16 @@ rl_vi_dosearch (string, dir) h = current_history (); history_set_pos (old); - strcpy (the_line, h->line); + { + int line_len = strlen (h->line); + + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + strcpy (rl_line_buffer, h->line); + } + rl_undo_list = (UNDO_LIST *)h->data; - rl_end = strlen (the_line); + rl_end = strlen (rl_line_buffer); rl_point = 0; rl_clear_message (); } @@ -172,19 +311,21 @@ rl_vi_dosearch (string, dir) rl_vi_complete (ignore, key) int ignore, key; { - if (!whitespace (the_line[rl_point])) + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) { - if (!whitespace (the_line[rl_point + 1])) + if (!whitespace (rl_line_buffer[rl_point + 1])) rl_vi_end_word (1, 'E'); rl_point++; } if (key == '*') - rl_complete_internal ('*'); + rl_complete_internal ('*'); /* Expansion and replacement. */ + else if (key == '=') + rl_complete_internal ('?'); /* List possible completions. */ + else if (key == '\\') + rl_complete_internal (TAB); /* Standard Readline completion. */ else rl_complete (0, key); - - rl_vi_insertion_mode (); } /* Previous word in vi mode. */ @@ -197,6 +338,12 @@ rl_vi_prev_word (count, key) return; } + if (rl_point == 0) + { + ding (); + return; + } + if (uppercase_p (key)) rl_vi_bWord (count); else @@ -213,6 +360,12 @@ rl_vi_next_word (count, key) return; } + if (rl_point >= (rl_end - 1)) + { + ding (); + return; + } + if (uppercase_p (key)) rl_vi_fWord (count); else @@ -242,11 +395,11 @@ rl_vi_fWord (count) while (count-- && rl_point < (rl_end - 1)) { /* Skip until whitespace. */ - while (!whitespace (the_line[rl_point]) && rl_point < rl_end) + while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) rl_point++; /* Now skip whitespace. */ - while (whitespace (the_line[rl_point]) && rl_point < rl_end) + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) rl_point++; } } @@ -256,42 +409,71 @@ rl_vi_bWord (count) { while (count-- && rl_point > 0) { - while (rl_point-- >= 0 && whitespace (the_line[rl_point])); - while (rl_point >= 0 && !whitespace (the_line[rl_point])) + /* If we are at the start of a word, move back to whitespace so + we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) rl_point--; - rl_point++; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } } } rl_vi_eWord (count) int count; { - while (count -- && rl_point < (rl_end - 1)) + while (count-- && rl_point < (rl_end - 1)) { - while (rl_point++ < rl_end && whitespace (the_line[rl_point])); - while (rl_point++ < rl_end && !whitespace (the_line[rl_point])); - rl_point--; + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move to the next non-whitespace character (to the start of the + next word). */ + while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); + + if (rl_point && rl_point < rl_end) + { + /* Skip whitespace. */ + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Skip until whitespace. */ + while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move back to the last character of the word. */ + rl_point--; + } } } rl_vi_fword (count) int count; { - while (count -- && rl_point < (rl_end - 1)) + while (count-- && rl_point < (rl_end - 1)) { - if (isident (the_line[rl_point])) + /* Move to white space (really non-identifer). */ + if (isident (rl_line_buffer[rl_point])) { - while (isident (the_line[rl_point]) && rl_point < rl_end) - rl_point += 1; + while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; } - else if (!whitespace (the_line[rl_point])) + else /* if (!whitespace (rl_line_buffer[rl_point])) */ { - while (!isident (the_line[rl_point]) && - !whitespace (the_line[rl_point]) && rl_point < rl_end) - rl_point += 1; + while (!isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; } - while (whitespace (the_line[rl_point]) && rl_point < rl_end) + /* Move past whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) rl_point++; } } @@ -299,16 +481,35 @@ rl_vi_fword (count) rl_vi_bword (count) int count; { - while (count -- && rl_point > 0) + while (count-- && rl_point > 0) { - while (--rl_point > 0 && whitespace (the_line[rl_point])); + int last_is_ident; + + /* If we are at the start of a word, move back to whitespace + so we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + /* If this character and the previous character are `opposite', move + back so we don't get messed up by the rl_point++ down there in + the while loop. Without this code, words like `l;' screw up the + function. */ + last_is_ident = isident (rl_line_buffer[rl_point - 1]); + if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) || + (!isident (rl_line_buffer[rl_point]) && last_is_ident)) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + if (rl_point > 0) { - if (isident (the_line[rl_point])) - while (--rl_point >= 0 && isident (the_line[rl_point])); + if (isident (rl_line_buffer[rl_point])) + while (--rl_point >= 0 && isident (rl_line_buffer[rl_point])); else - while (--rl_point >= 0 && !isident (the_line[rl_point]) && - !whitespace (the_line[rl_point])); + while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point])); rl_point++; } } @@ -317,19 +518,23 @@ rl_vi_bword (count) rl_vi_eword (count) int count; { - while (count -- && rl_point < rl_end - 1) + while (count-- && rl_point < rl_end - 1) { - while (++rl_point < rl_end && whitespace (the_line[rl_point])); + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; if (rl_point < rl_end) { - if (isident (the_line[rl_point])) - while (++rl_point < rl_end && isident (the_line[rl_point])); + if (isident (rl_line_buffer[rl_point])) + while (++rl_point < rl_end && isident (rl_line_buffer[rl_point])); else - while (++rl_point < rl_end && !isident (the_line[rl_point]) - && !whitespace (the_line[rl_point])); - rl_point--; + while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point]) + && !whitespace (rl_line_buffer[rl_point])); } + rl_point--; } } @@ -398,35 +603,41 @@ rl_vi_arg_digit (count, c) rl_digit_argument (count, c); } -/* Doesn't take an arg count in vi */ -rl_vi_change_case (ignore1, ignore2) - int ignore1, ignore2; +rl_vi_change_case (count, ignore) + int count, ignore; { char c = 0; - if (uppercase_p (the_line[rl_point])) - c = to_lower (the_line[rl_point]); - else if (lowercase_p (the_line[rl_point])) - c = to_upper (the_line[rl_point]); + /* Don't try this on an empty line. */ + if (rl_point >= rl_end) + return; - /* Vi is kind of strange here. */ - if (c) + while (count-- && rl_point < rl_end) { - rl_begin_undo_group (); - rl_delete (1, c); - rl_insert (1, c); - rl_end_undo_group (); - rl_vi_check (); + if (uppercase_p (rl_line_buffer[rl_point])) + c = to_lower (rl_line_buffer[rl_point]); + else if (lowercase_p (rl_line_buffer[rl_point])) + c = to_upper (rl_line_buffer[rl_point]); + + /* Vi is kind of strange here. */ + if (c) + { + rl_begin_undo_group (); + rl_delete (1, c); + rl_insert (1, c); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward (1); } - else - rl_forward (1); } rl_vi_put (count, key) int count, key; { - if (!uppercase_p (key)) - rl_forward (1); + if (!uppercase_p (key) && (rl_point + 1 <= rl_end)) + rl_point++; rl_yank (); rl_backward (1); @@ -451,6 +662,9 @@ rl_vi_domove (key, nextkey) int key, *nextkey; { int c, save; + int old_end, added_blank; + + added_blank = 0; rl_mark = rl_point; c = rl_read_key (); @@ -461,10 +675,14 @@ rl_vi_domove (key, nextkey) if (digit (c)) { save = rl_numeric_arg; + rl_numeric_arg = digit_value (c); rl_digit_loop1 (); rl_numeric_arg *= save; + c = rl_read_key (); /* real command */ + *nextkey = c; } else if ((key == 'd' && c == 'd') || + (key == 'y' && c == 'y') || (key == 'c' && c == 'c')) { rl_mark = rl_end; @@ -475,15 +693,41 @@ rl_vi_domove (key, nextkey) return (-1); } + /* Append a blank character temporarily so that the motion routines + work right at the end of the line. */ + old_end = rl_end; + rl_line_buffer[rl_end++] = ' '; /* This looks pretty bogus to me??? */ + rl_line_buffer[rl_end] = '\0'; + added_blank++; + rl_dispatch (c, keymap); + /* Remove the blank that we added. */ + rl_end = old_end; + rl_line_buffer[rl_end] = '\0'; + if (rl_point > rl_end) + rl_point = rl_end - 1; + /* No change in position means the command failed. */ if (rl_mark == rl_point) return (-1); - if ((c == 'w' || c == 'W') && rl_point < rl_end) + /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next + word. If we are not at the end of the line, and we are on a + non-whitespace character, move back one (presumably to whitespace). */ + if ((c == 'w' || c == 'W') && (rl_point < rl_end) && + !whitespace (rl_line_buffer[rl_point])) rl_point--; + /* If cw or cW, back up to the end of a word, so the behaviour of ce + or cE is the actual result. Brute-force, no subtlety. Do the same + thing for dw or dW. */ + if (key == 'c' && (to_upper (c) == 'W')) + { + while (rl_point && whitespace (rl_line_buffer[rl_point])) + rl_point--; + } + if (rl_mark < rl_point) exchange (rl_point, rl_mark); @@ -498,7 +742,7 @@ rl_digit_loop1 () while (1) { - rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0); + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); key = c = rl_read_key (); if (keymap[c].type == ISFUNC && @@ -507,19 +751,21 @@ rl_digit_loop1 () rl_numeric_arg *= 4; continue; } + c = UNMETA (c); if (numeric (c)) { if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); + rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c); else - rl_numeric_arg = (c - '0'); + rl_numeric_arg = digit_value (c); rl_explicit_arg = 1; } else { rl_clear_message (); rl_stuff_char (key); + break; } } } @@ -538,7 +784,7 @@ rl_vi_delete_to (count, key) return; } - if ((c != '|') && (c != 'h') && rl_mark < rl_end) + if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) rl_mark++; rl_kill_text (rl_point, rl_mark); @@ -558,7 +804,7 @@ rl_vi_change_to (count, key) return; } - if ((c != '|') && (c != 'h') && rl_mark < rl_end) + if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) rl_mark++; rl_begin_undo_group (); @@ -581,6 +827,9 @@ rl_vi_yank_to (count, key) return; } + if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) + rl_mark++; + rl_begin_undo_group (); rl_kill_text (rl_point, rl_mark); rl_end_undo_group (); @@ -590,21 +839,36 @@ rl_vi_yank_to (count, key) rl_vi_delete (count) { - if (rl_point >= rl_end - 1) + int end; + + if (rl_end == 0) { - rl_delete (count, 0); - if (rl_point > 0) - rl_backward (1); + ding (); + return; } - else - rl_delete (count, 0); + + end = rl_point + count; + + if (end >= rl_end) + end = rl_end; + + rl_kill_text (rl_point, end); + + if (rl_point > 0 && rl_point == rl_end) + rl_backward (1); } -/* Turn the current line into a comment in shell history. A ksh function */ +/* Turn the current line into a comment in shell history. + A K*rn shell style function. */ rl_vi_comment () { rl_beg_of_line (); - rl_insert_text (": "); /* # doesn't work in interactive mode */ + + if (rl_vi_comment_begin != (char *)NULL) + rl_insert_text (rl_vi_comment_begin); + else + rl_insert_text (": "); /* Default. */ + rl_redisplay (); rl_newline (1, '\010'); } @@ -618,7 +882,7 @@ rl_back_to_indent (ignore1, ignore2) int ignore1, ignore2; { rl_beg_of_line (); - while (rl_point < rl_end && whitespace (the_line[rl_point])) + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) rl_point++; } @@ -639,70 +903,88 @@ rl_vi_char_search (count, key) dir = (key == ';' ? orig_dir : -orig_dir); else { - target = rl_getc (in_stream); + target = rl_getc (rl_instream); switch (key) - { - case 't': - orig_dir = dir = FTO; - break; - - case 'T': - orig_dir = dir = BTO; - break; - - case 'f': - orig_dir = dir = FFIND; - break; - - case 'F': - orig_dir = dir = BFIND; - break; - } + { + case 't': + orig_dir = dir = FTO; + break; + + case 'T': + orig_dir = dir = BTO; + break; + + case 'f': + orig_dir = dir = FFIND; + break; + + case 'F': + orig_dir = dir = BFIND; + break; + } } pos = rl_point; - if (dir < 0) + while (count--) { - pos--; - do + if (dir < 0) { - if (the_line[pos] == target) + if (pos == 0) { - if (dir == BTO) - rl_point = pos + 1; - else - rl_point = pos; + ding (); return; } - } - while (pos--); - if (pos < 0) - { - ding (); - return; - } - } - else - { /* dir > 0 */ - pos++; - do - { - if (the_line[pos] == target) + pos--; + do { - if (dir == FTO) - rl_point = pos - 1; - else - rl_point = pos; + if (rl_line_buffer[pos] == target) + { + if (dir == BTO) + rl_point = pos + 1; + else + rl_point = pos; + break; + } + } + while (pos--); + + if (pos < 0) + { + ding (); return; } } - while (++pos < rl_end); + else + { /* dir > 0 */ + if (pos >= rl_end) + { + ding (); + return; + } - if (pos >= (rl_end - 1)) - ding (); + pos++; + do + { + if (rl_line_buffer[pos] == target) + { + if (dir == FTO) + rl_point = pos - 1; + else + rl_point = pos; + break; + } + } + while (++pos < rl_end); + + if (pos >= (rl_end - 1)) + { + ding (); + return; + } + } } } @@ -712,9 +994,9 @@ rl_vi_match () int count = 1, brack, pos; pos = rl_point; - if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0) + if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) { - while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 && + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && rl_point < rl_end - 1) rl_forward (1); @@ -734,7 +1016,7 @@ rl_vi_match () { if (--pos >= 0) { - int b = rl_vi_bracktype (the_line[pos]); + int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) count--; else if (b == brack) @@ -753,7 +1035,7 @@ rl_vi_match () { if (++pos < rl_end) { - int b = rl_vi_bracktype (the_line[pos]); + int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) count--; else if (b == brack) @@ -785,24 +1067,26 @@ rl_vi_bracktype (c) } } -rl_vi_change_char () +rl_vi_change_char (count, key) + int count, key; { int c; - c = rl_getc (in_stream); + c = rl_getc (rl_instream); - switch (c) - { - case '\033': - case CTRL('C'): - return; + if (c == '\033' || c == CTRL ('C')) + return; - default: + while (count-- && rl_point < rl_end) + { rl_begin_undo_group (); + rl_delete (1, c); rl_insert (1, c); + if (count == 0) + rl_backward (1); + rl_end_undo_group (); - break; } } @@ -818,7 +1102,7 @@ rl_vi_subst (count, key) rl_kill_line (1); } else - rl_delete (1, key); + rl_delete (count, key); rl_vi_insertion_mode (); } @@ -880,21 +1164,33 @@ rl_vi_overstrike_delete (count) } } -rl_vi_replace () +rl_vi_replace (count, key) + int count, key; { int i; vi_replace_count = 0; - vi_replace_map = rl_make_bare_keymap (); + if (!vi_replace_map) + { + vi_replace_map = rl_make_bare_keymap (); - for (i = ' '; i < 127; i++) - vi_replace_map[i].function = rl_vi_overstrike; + for (i = ' '; i < 127; i++) + vi_replace_map[i].function = rl_vi_overstrike; - vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; - vi_replace_map[ESC].function = rl_vi_movement_mode; - vi_replace_map[RETURN].function = rl_newline; - vi_replace_map[NEWLINE].function = rl_newline; + vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; + vi_replace_map[ESC].function = rl_vi_movement_mode; + vi_replace_map[RETURN].function = rl_newline; + vi_replace_map[NEWLINE].function = rl_newline; + + /* If the normal vi insertion keymap has ^H bound to erase, do the + same here. Probably should remove the assignment to RUBOUT up + there, but I don't think it will make a difference in real life. */ + if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && + vi_insertion_keymap[CTRL ('H')].function == rl_rubout) + vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; + + } keymap = vi_replace_map; } @@ -907,12 +1203,12 @@ rl_vi_possible_completions() { int save_pos = rl_point; - if (!index (" ;", the_line[rl_point])) + if (!index (" ;", rl_line_buffer[rl_point])) { - while (!index(" ;", the_line[++rl_point])) + while (!index(" ;", rl_line_buffer[++rl_point])) ; } - else if (the_line[rl_point-1] == ';') + else if (rl_line_buffer[rl_point-1] == ';') { ding (); return (0); @@ -923,3 +1219,5 @@ rl_vi_possible_completions() return (0); } + +#endif /* VI_MODE */