From: Chet Ramey Date: Fri, 9 Dec 2011 01:13:24 +0000 (-0500) Subject: commit bash-20090730 snapshot X-Git-Tag: bash-4.3-alpha~217 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9dd88db75708ed30ccf6288859e24eee19de5122;p=thirdparty%2Fbash.git commit bash-20090730 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 4b428cc24..c248e0852 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8266,3 +8266,82 @@ execute_cmd.c trap for the eval/source/command builtins in the same way as we temporarily disable and restore the setting of the -e option. Fixes bug reported by Henning Garus + + 7/27 + ---- +shell.c + - add fflush(stdout) and fflush(stderr) to exit_shell before closing + any file descriptors at exit time (e.g., coproc pipes) + + 7/30 + ---- +lib/readline/complete.c + - new function rl_backward_menu_complete, just passes negative count + argument to rl_menu_complete + - change rl_menu_complete to act appropriately if rl_last_command is + rl_backward_menu_complete, so we can cycle forward and backward + through the list of completions + +lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 + - document new "menu-complete-backward" bindable readline function. + Suggested by Jason Spiro + +lib/readline/vi_keymap.c + - add binding of C-n to menu-complete and C-p to menu-complete-backward + in vi-insert keymap, as suggested by Jason Spiro + + +pcomplete.c + - fixed a bug in programmable_completions: the options it returned from + the compspec it found were set before generating the completions, + which meant that any changes made by "compopt" were overridden and + only in effect for the duration of the executing shell function + rather than the entire completion. Fixes bug reported by Ville + Skytta + + 7/31 + ---- +lib/readline/keymaps.c + - fixed memory leak in rl_discard_keymap by freeing storage associated + with hierarchical keymaps + - new convenience function, rl_free_keymap, that calls rl_discard_keymap + and frees the keymap passed as an argument + +lib/readline/util.c + - new bindable keymap function, _rl_null_function, to be used internally + +lib/readline/rlprivate.h + - extern declaration for _rl_null_function + +lib/readline/bind.c + - fix rl_generic_bind in the case where we are trying to override a + keymap with a null function (e.g., when trying to unbind it). We + can't use a NULL function pointer in ANYOTHERKEY since that's + indistinguishable from the keymap not having been overridden at all. + We use _rl_null_function instead, which simply does nothing. We + could add an rl_ding to it later. Fixes problem with hitting ESC + repeatedly while in vi command mode reported by James Rowell + + +builtins/bind.def + - call rl_bind_keyseq instead of rl_set_key for -r option + +lib/readline/readline.c + - Set vi_movement_keymap[ESC] to _rl_null_function after binding the + arrow keys in bind_arrow_keys() to allow vi-mode users to hit ESC + multiple times in vi command mode while still allowing the arrow + keys to work + + 8/2 + --- +bashline.c + - fix clear_hostname_list by setting hostname_list_initialized to 0 + after freeing all list members. Fixes bug reported by Freddy + Vulto + +lib/readline/display.c + - in update_line, if we copy data from one line to another because we + are wrapping a multibyte character from, say, the first line to the + second, we need to update OMAX and the line indices to account for + the moved data. Bug report and fix from Martin Hamrle + diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 3069cb0a2..e09ad370f 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -8258,3 +8258,83 @@ lib/readline/complete.c and unset RL_STATE_COMPLETING while generating the list of matches. Fixes debian bug #538013 reported by Jerome Reybert + + 7/25 + ---- +execute_cmd.c + - change execute_builtin to temporarily turn off and restore the ERR + trap for the eval/source/command builtins in the same way as we + temporarily disable and restore the setting of the -e option. + Fixes bug reported by Henning Garus + + 7/27 + ---- +shell.c + - add fflush(stdout) and fflush(stderr) to exit_shell before closing + any file descriptors at exit time (e.g., coproc pipes) + + 7/30 + ---- +lib/readline/complete.c + - new function rl_backward_menu_complete, just passes negative count + argument to rl_menu_complete + - change rl_menu_complete to act appropriately if rl_last_command is + rl_backward_menu_complete, so we can cycle forward and backward + through the list of completions + +lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 + - document new "menu-complete-backward" bindable readline function. + Suggested by Jason Spiro + +lib/readline/vi_keymap.c + - add binding of C-n to menu-complete and C-p to menu-complete-backward + in vi-insert keymap, as suggested by Jason Spiro + + +pcomplete.c + - fixed a bug in programmable_completions: the options it returned from + the compspec it found were set before generating the completions, + which meant that any changes made by "compopt" were overridden and + only in effect for the duration of the executing shell function + rather than the entire completion. Fixes bug reported by Ville + Skytta + + 7/31 + ---- +lib/readline/keymaps.c + - fixed memory leak in rl_discard_keymap by freeing storage associated + with hierarchical keymaps + - new convenience function, rl_free_keymap, that calls rl_discard_keymap + and frees the keymap passed as an argument + +lib/readline/util.c + - new bindable keymap function, _rl_null_function, to be used internally + +lib/readline/rlprivate.h + - extern declaration for _rl_null_function + +lib/readline/bind.c + - fix rl_generic_bind in the case where we are trying to override a + keymap with a null function (e.g., when trying to unbind it). We + can't use a NULL function pointer in ANYOTHERKEY since that's + indistinguishable from the keymap not having been overridden at all. + We use _rl_null_function instead, which simply does nothing. We + could add an rl_ding to it later. Fixes problem with hitting ESC + repeatedly while in vi command mode reported by James Rowell + + +builtins/bind.def + - call rl_bind_keyseq instead of rl_set_key for -r option + +lib/readline/readline.c + - Set vi_movement_keymap[ESC] to _rl_null_function after binding the + arrow keys in bind_arrow_keys() to allow vi-mode users to hit ESC + multiple times in vi command mode while still allowing the arrow + keys to work + + 8/2 + --- +bashline.c + - fix clear_hostname_list by setting hostname_list_initialized to 0 + after freeing all list members. Fixes bug reported by Freddy + Vulto diff --git a/bashline.c b/bashline.c index b07fd6123..7f19f57e1 100644 --- a/bashline.c +++ b/bashline.c @@ -752,7 +752,7 @@ clear_hostname_list () return; for (i = 0; i < hostname_list_length; i++) free (hostname_list[i]); - hostname_list_length = 0; + hostname_list_length = hostname_list_initialized = 0; } /* Return a NULL terminated list of hostnames which begin with TEXT. diff --git a/bashline.c~ b/bashline.c~ index d081a062e..b07fd6123 100644 --- a/bashline.c~ +++ b/bashline.c~ @@ -82,6 +82,9 @@ extern int bash_brace_completion __P((int, int)); #endif /* BRACE_COMPLETION */ +/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ +extern int tputs __P((const char *string, int nlines, int (*outx)(int))); + /* Forward declarations */ /* Functions bound to keys in Readline for Bash users. */ diff --git a/builtins/bind.def b/builtins/bind.def index fcc3bbb9a..d0c953bb8 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -255,7 +255,7 @@ bind_builtin (list) if ((flags & RFLAG) && remove_seq) { - if (rl_set_key (remove_seq, (rl_command_func_t *)NULL, rl_get_keymap ()) != 0) + if (rl_bind_keyseq (remove_seq, (rl_command_func_t *)NULL) != 0) { builtin_error (_("`%s': cannot unbind"), remove_seq); BIND_RETURN (EXECUTION_FAILURE); diff --git a/builtins/bind.def~ b/builtins/bind.def~ new file mode 100644 index 000000000..fcc3bbb9a --- /dev/null +++ b/builtins/bind.def~ @@ -0,0 +1,332 @@ +This file is bind.def, from which is created bind.c. +It implements the builtin "bind" in Bash. + +Copyright (C) 1987-2009 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +Bash is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Bash is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Bash. If not, see . + +$PRODUCES bind.c + +#include + +$BUILTIN bind +$DEPENDS_ON READLINE +$FUNCTION bind_builtin +$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command] +Set Readline key bindings and variables. + +Bind a key sequence to a Readline function or a macro, or set a +Readline variable. The non-option argument syntax is equivalent to +that found in ~/.inputrc, but must be passed as a single argument: +e.g., bind '"\C-x\C-r": re-read-init-file'. + +Options: + -m keymap Use KEYMAP as the keymap for the duration of this + command. Acceptable keymap names are emacs, + emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, + vi-command, and vi-insert. + -l List names of functions. + -P List function names and bindings. + -p List functions and bindings in a form that can be + reused as input. + -S List key sequences that invoke macros and their values + -s List key sequences that invoke macros and their values + in a form that can be reused as input. + -V List variable names and values + -v List variable names and values in a form that can + be reused as input. + -q function-name Query about which keys invoke the named function. + -u function-name Unbind all keys which are bound to the named function. + -r keyseq Remove the binding for KEYSEQ. + -f filename Read key bindings from FILENAME. + -x keyseq:shell-command Cause SHELL-COMMAND to be executed when + KEYSEQ is entered. + +Exit Status: +bind returns 0 unless an unrecognized option is given or an error occurs. +$END + +#if defined (READLINE) + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include +#include +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include +#include + +#include "../bashintl.h" + +#include "../shell.h" +#include "../bashline.h" +#include "bashgetopt.h" +#include "common.h" + +static int query_bindings __P((char *)); +static int unbind_command __P((char *)); + +extern int no_line_editing; + +#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0) + +#define LFLAG 0x0001 +#define PFLAG 0x0002 +#define FFLAG 0x0004 +#define VFLAG 0x0008 +#define QFLAG 0x0010 +#define MFLAG 0x0020 +#define RFLAG 0x0040 +#define PPFLAG 0x0080 +#define VVFLAG 0x0100 +#define SFLAG 0x0200 +#define SSFLAG 0x0400 +#define UFLAG 0x0800 +#define XFLAG 0x1000 + +int +bind_builtin (list) + WORD_LIST *list; +{ + int return_code; + Keymap kmap, saved_keymap; + int flags, opt; + char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq; + + if (no_line_editing) + { +#if 0 + builtin_error (_("line editing not enabled")); + return (EXECUTION_FAILURE); +#else + builtin_warning (_("line editing not enabled")); +#endif + } + + kmap = saved_keymap = (Keymap) NULL; + flags = 0; + initfile = map_name = fun_name = unbind_name = remove_seq = (char *)NULL; + return_code = EXECUTION_SUCCESS; + + if (bash_readline_initialized == 0) + initialize_readline (); + + begin_unwind_frame ("bind_builtin"); + unwind_protect_var (rl_outstream); + + rl_outstream = stdout; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "lvpVPsSf:q:u:m:r:x:")) != EOF) + { + switch (opt) + { + case 'l': + flags |= LFLAG; + break; + case 'v': + flags |= VFLAG; + break; + case 'p': + flags |= PFLAG; + break; + case 'f': + flags |= FFLAG; + initfile = list_optarg; + break; + case 'm': + flags |= MFLAG; + map_name = list_optarg; + break; + case 'q': + flags |= QFLAG; + fun_name = list_optarg; + break; + case 'u': + flags |= UFLAG; + unbind_name = list_optarg; + break; + case 'r': + flags |= RFLAG; + remove_seq = list_optarg; + break; + case 'V': + flags |= VVFLAG; + break; + case 'P': + flags |= PPFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'S': + flags |= SSFLAG; + break; + case 'x': + flags |= XFLAG; + cmd_seq = list_optarg; + break; + default: + builtin_usage (); + BIND_RETURN (EX_USAGE); + } + } + + list = loptend; + + /* First, see if we need to install a special keymap for this + command. Then start on the arguments. */ + + if ((flags & MFLAG) && map_name) + { + kmap = rl_get_keymap_by_name (map_name); + if (!kmap) + { + builtin_error (_("`%s': invalid keymap name"), map_name); + BIND_RETURN (EXECUTION_FAILURE); + } + } + + if (kmap) + { + saved_keymap = rl_get_keymap (); + rl_set_keymap (kmap); + } + + /* XXX - we need to add exclusive use tests here. It doesn't make sense + to use some of these options together. */ + /* Now hack the option arguments */ + if (flags & LFLAG) + rl_list_funmap_names (); + + if (flags & PFLAG) + rl_function_dumper (1); + + if (flags & PPFLAG) + rl_function_dumper (0); + + if (flags & SFLAG) + rl_macro_dumper (1); + + if (flags & SSFLAG) + rl_macro_dumper (0); + + if (flags & VFLAG) + rl_variable_dumper (1); + + if (flags & VVFLAG) + rl_variable_dumper (0); + + if ((flags & FFLAG) && initfile) + { + if (rl_read_init_file (initfile) != 0) + { + builtin_error (_("%s: cannot read: %s"), initfile, strerror (errno)); + BIND_RETURN (EXECUTION_FAILURE); + } + } + + if ((flags & QFLAG) && fun_name) + return_code = query_bindings (fun_name); + + if ((flags & UFLAG) && unbind_name) + return_code = unbind_command (unbind_name); + + if ((flags & RFLAG) && remove_seq) + { + if (rl_set_key (remove_seq, (rl_command_func_t *)NULL, rl_get_keymap ()) != 0) + { + builtin_error (_("`%s': cannot unbind"), remove_seq); + BIND_RETURN (EXECUTION_FAILURE); + } + } + + if (flags & XFLAG) + return_code = bind_keyseq_to_unix_command (cmd_seq); + + /* Process the rest of the arguments as binding specifications. */ + while (list) + { + rl_parse_and_bind (list->word->word); + list = list->next; + } + + bind_exit: + if (saved_keymap) + rl_set_keymap (saved_keymap); + + run_unwind_frame ("bind_builtin"); + + return (sh_chkwrite (return_code)); +} + +static int +query_bindings (name) + char *name; +{ + rl_command_func_t *function; + char **keyseqs; + int j; + + function = rl_named_function (name); + if (function == 0) + { + builtin_error (_("`%s': unknown function name"), name); + return EXECUTION_FAILURE; + } + + keyseqs = rl_invoking_keyseqs (function); + + if (!keyseqs) + { + printf (_("%s is not bound to any keys.\n"), name); + return EXECUTION_FAILURE; + } + + printf (_("%s can be invoked via "), name); + for (j = 0; j < 5 && keyseqs[j]; j++) + printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n"); + if (keyseqs[j]) + printf ("...\n"); + strvec_dispose (keyseqs); + return EXECUTION_SUCCESS; +} + +static int +unbind_command (name) + char *name; +{ + rl_command_func_t *function; + + function = rl_named_function (name); + if (function == 0) + { + builtin_error (_("`%s': unknown function name"), name); + return EXECUTION_FAILURE; + } + + rl_unbind_function_in_map (function, rl_get_keymap ()); + return EXECUTION_SUCCESS; +} +#endif /* READLINE */ diff --git a/doc/bash.0 b/doc/bash.0 index a59ca7043..8c870c56a 100644 --- a/doc/bash.0 +++ b/doc/bash.0 @@ -3164,7 +3164,11 @@ RREEAADDLLIINNEE moves _n positions forward in the list of matches; a negative argument may be used to move backward through the list. This command is intended to be bound to TTAABB, but is unbound by - default. + default.cc + mmeennuu--ccoommpplleettee--kkrrdd + Identicwwal to mmeennuu--ccoommpplleettee, but moves backward through the list + of possible completions, as if mmeennuu--ccoommpplleettee had been given a + negative argument. This command is unbound by default. ddeelleettee--cchhaarr--oorr--lliisstt Deletes the character under the cursor if not at the beginning or end of the line (like ddeelleettee--cchhaarr). If at the end of the @@ -5238,4 +5242,4 @@ BBUUGGSS -GNU Bash-4.0 2009 June 17 BASH(1) +GNU Bash-4.0 2009 July 30 BASH(1) diff --git a/doc/bash.1 b/doc/bash.1 index d68cfae66..8c2649a89 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet@po.cwru.edu .\" -.\" Last Change: Wed Jun 17 08:51:11 EDT 2009 +.\" Last Change: Thu Jul 30 09:25:13 EDT 2009 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2009 June 17" "GNU Bash-4.0" +.TH BASH 1 "2009 July 30" "GNU Bash-4.0" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -1847,7 +1847,8 @@ adds the contents of the new file to the existing list. If .SM .B HOSTFILE -is set, but has no value, \fBbash\fP attempts to read +is set, but has no value, or does not name a readable file, +\fBbash\fP attempts to read .FN /etc/hosts to obtain the list of possible hostname completions. When @@ -5494,6 +5495,11 @@ through the list. This command is intended to be bound to \fBTAB\fP, but is unbound by default. .TP +.B menu\-complete-\backward +Identical to \fBmenu\-complete\fP, but moves backward through the list +of possible completions, as if \fBmenu\-complete\fP had been given a +negative argument. This command is unbound by default. +.TP .B delete\-char\-or\-list Deletes the character under the cursor if not at the beginning or end of the line (like \fBdelete\-char\fP). diff --git a/doc/bash.1~ b/doc/bash.1~ index dbee2729b..8b30849d0 100644 --- a/doc/bash.1~ +++ b/doc/bash.1~ @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet@po.cwru.edu .\" -.\" Last Change: Tue May 26 17:03:43 EDT 2009 +.\" Last Change: Thu Jul 30 09:25:13 EDT 2009 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2009 May 26" "GNU Bash-4.0" +.TH BASH 1 "2009 July 30" "GNU Bash-4.0" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -5494,6 +5494,11 @@ through the list. This command is intended to be bound to \fBTAB\fP, but is unbound by default. .TP +.B menu\-complete-\backward +Identical to \fBmenu\-complete\fP, but moves backward through the list +of possible completions, as if \fBmenu\-complete\fP had been given a +negative argument. This command is unbound by default. +.TP .B delete\-char\-or\-list Deletes the character under the cursor if not at the beginning or end of the line (like \fBdelete\-char\fP). @@ -8273,9 +8278,10 @@ and group ids to be set to the real user and group ids. Exit after reading and executing one command. .TP 8 .B \-u -Treat unset variables as an error when performing +Treat unset variables and parameters other than the special +parameters "@" and "*" as an error when performing parameter expansion. If expansion is attempted on an -unset variable, the shell prints an error message, and, +unset variable or parameter, the shell prints an error message, and, if not interactive, exits with a non-zero status. .TP 8 .B \-v @@ -8942,7 +8948,7 @@ These are the same conditions obeyed by the \fBerrexit\fP option. .if n .sp 1 Signals ignored upon entry to the shell cannot be trapped or reset. Trapped signals that are not being ignored are reset to their original -values in a subshell or subshell environment. +values in a subshell or subshell environment when one is created. The return status is false if any .I sigspec is invalid; otherwise diff --git a/doc/bashref.texi b/doc/bashref.texi index 686ae9cee..35abc37a2 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -4974,7 +4974,8 @@ is running; the next time hostname completion is attempted after the value is changed, Bash adds the contents of the new file to the existing list. -If @env{HOSTFILE} is set, but has no value, Bash attempts to read +If @env{HOSTFILE} is set, but has no value, or does not name a readable file, +Bash attempts to read @file{/etc/hosts} to obtain the list of possible hostname completions. When @env{HOSTFILE} is unset, the hostname list is cleared. diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ index 6a996d667..686ae9cee 100644 --- a/doc/bashref.texi~ +++ b/doc/bashref.texi~ @@ -3196,7 +3196,7 @@ These are the same conditions obeyed by the @code{errexit} option. Signals ignored upon entry to the shell cannot be trapped or reset. Trapped signals that are not being ignored are reset to their original -values in a subshell or subshell environment. +values in a subshell or subshell environment when one is created. The return status is zero unless a @var{sigspec} does not specify a valid signal. @@ -4150,7 +4150,8 @@ and group ids to be set to the real user and group ids. Exit after reading and executing one command. @item -u -Treat unset variables as an error when performing parameter expansion. +Treat unset variables and parameters other than the special parameters +@samp{@@} or @samp{*} as an error when performing parameter expansion. An error message will be written to the standard error, and a non-interactive shell will exit. diff --git a/lib/readline/bind.c b/lib/readline/bind.c index 836f837b9..c8bef1c70 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -418,6 +418,13 @@ rl_generic_bind (type, keyseq, data, map) { map = FUNCTION_TO_KEYMAP (map, ic); ic = ANYOTHERKEY; + /* If we're trying to override a keymap with a null function + (e.g., trying to unbind it), we can't use a null pointer + here because that's indistinguishable from having not been + overridden. We use a special bindable function that does + nothing. */ + if (type == ISFUNC && data == 0) + data = (char *)_rl_null_function; } map[ic].function = KEYMAP_TO_FUNCTION (data); diff --git a/lib/readline/bind.c~ b/lib/readline/bind.c~ new file mode 100644 index 000000000..cfa669785 --- /dev/null +++ b/lib/readline/bind.c~ @@ -0,0 +1,2367 @@ +/* bind.c -- key binding and startup file support for the readline library. */ + +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. + + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + +#define READLINE_LIBRARY + +#if defined (__TANDEM) +# include +#endif + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include +#include +#if defined (HAVE_SYS_FILE_H) +# include +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +/* Variables exported by this file. */ +Keymap rl_binding_keymap; + +static char *_rl_read_file PARAMS((char *, size_t *)); +static void _rl_init_file_error PARAMS((const char *)); +static int _rl_read_init_file PARAMS((const char *, int)); +static int glean_key_from_name PARAMS((char *)); +static int find_boolean_var PARAMS((const char *)); + +static char *_rl_get_string_variable_value PARAMS((const char *)); +static int substring_member_of_array PARAMS((const char *, const char * const *)); + +static int currently_reading_init_file; + +/* used only in this file */ +static int _rl_prefer_visible_bell = 1; + +/* **************************************************************** */ +/* */ +/* Binding keys */ +/* */ +/* **************************************************************** */ + +/* rl_add_defun (char *name, rl_command_func_t *function, int key) + Add NAME to the list of named functions. Make FUNCTION be the function + that gets called. If KEY is not -1, then bind it. */ +int +rl_add_defun (name, function, key) + const char *name; + rl_command_func_t *function; + int key; +{ + if (key != -1) + rl_bind_key (key, function); + rl_add_funmap_entry (name, function); + return 0; +} + +/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ +int +rl_bind_key (key, function) + int key; + rl_command_func_t *function; +{ + if (key < 0) + return (key); + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (_rl_keymap[ESC].type == ISKMAP) + { + Keymap escmap; + + escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); + key = UNMETA (key); + escmap[key].type = ISFUNC; + escmap[key].function = function; + return (0); + } + return (key); + } + + _rl_keymap[key].type = ISFUNC; + _rl_keymap[key].function = function; + rl_binding_keymap = _rl_keymap; + return (0); +} + +/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid + KEY. */ +int +rl_bind_key_in_map (key, function, map) + int key; + rl_command_func_t *function; + Keymap map; +{ + int result; + Keymap oldmap; + + oldmap = _rl_keymap; + _rl_keymap = map; + result = rl_bind_key (key, function); + _rl_keymap = oldmap; + return (result); +} + +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ +int +rl_bind_key_if_unbound_in_map (key, default_func, kmap) + int key; + rl_command_func_t *default_func; + Keymap kmap; +{ + char keyseq[2]; + + keyseq[0] = (unsigned char)key; + keyseq[1] = '\0'; + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap)); +} + +int +rl_bind_key_if_unbound (key, default_func) + int key; + rl_command_func_t *default_func; +{ + char keyseq[2]; + + keyseq[0] = (unsigned char)key; + keyseq[1] = '\0'; + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); +} + +/* Make KEY do nothing in the currently selected keymap. + Returns non-zero in case of error. */ +int +rl_unbind_key (key) + int key; +{ + return (rl_bind_key (key, (rl_command_func_t *)NULL)); +} + +/* Make KEY do nothing in MAP. + Returns non-zero in case of error. */ +int +rl_unbind_key_in_map (key, map) + int key; + Keymap map; +{ + return (rl_bind_key_in_map (key, (rl_command_func_t *)NULL, map)); +} + +/* Unbind all keys bound to FUNCTION in MAP. */ +int +rl_unbind_function_in_map (func, map) + rl_command_func_t *func; + Keymap map; +{ + register int i, rval; + + for (i = rval = 0; i < KEYMAP_SIZE; i++) + { + if (map[i].type == ISFUNC && map[i].function == func) + { + map[i].function = (rl_command_func_t *)NULL; + rval = 1; + } + } + return rval; +} + +int +rl_unbind_command_in_map (command, map) + const char *command; + Keymap map; +{ + rl_command_func_t *func; + + func = rl_named_function (command); + if (func == 0) + return 0; + return (rl_unbind_function_in_map (func, map)); +} + +/* Bind the key sequence represented by the string KEYSEQ to + FUNCTION, starting in the current keymap. This makes new + keymaps as necessary. */ +int +rl_bind_keyseq (keyseq, function) + const char *keyseq; + rl_command_func_t *function; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap)); +} + +/* Bind the key sequence represented by the string KEYSEQ to + FUNCTION. This makes new keymaps as necessary. The initial + place to do bindings is in MAP. */ +int +rl_bind_keyseq_in_map (keyseq, function, map) + const char *keyseq; + rl_command_func_t *function; + Keymap map; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); +} + +/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */ +int +rl_set_key (keyseq, function, map) + const char *keyseq; + rl_command_func_t *function; + Keymap map; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); +} + +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ +int +rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap) + const char *keyseq; + rl_command_func_t *default_func; + Keymap kmap; +{ + rl_command_func_t *func; + + if (keyseq) + { + func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL); +#if defined (VI_MODE) + if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) +#else + if (!func || func == rl_do_lowercase_version) +#endif + return (rl_bind_keyseq_in_map (keyseq, default_func, kmap)); + else + return 1; + } + return 0; +} + +int +rl_bind_keyseq_if_unbound (keyseq, default_func) + const char *keyseq; + rl_command_func_t *default_func; +{ + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); +} + +/* Bind the key sequence represented by the string KEYSEQ to + the string of characters MACRO. This makes new keymaps as + necessary. The initial place to do bindings is in MAP. */ +int +rl_macro_bind (keyseq, macro, map) + const char *keyseq, *macro; + Keymap map; +{ + char *macro_keys; + int macro_keys_len; + + macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); + + if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) + { + xfree (macro_keys); + return -1; + } + rl_generic_bind (ISMACR, keyseq, macro_keys, map); + return 0; +} + +/* Bind the key sequence represented by the string KEYSEQ to + the arbitrary pointer DATA. TYPE says what kind of data is + pointed to by DATA, right now this can be a function (ISFUNC), + a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps + as necessary. The initial place to do bindings is in MAP. */ +int +rl_generic_bind (type, keyseq, data, map) + int type; + const char *keyseq; + char *data; + Keymap map; +{ + char *keys; + int keys_len; + register int i; + KEYMAP_ENTRY k; + + k.function = 0; + + /* If no keys to bind to, exit right away. */ + if (keyseq == 0 || *keyseq == 0) + { + if (type == ISMACR) + xfree (data); + return -1; + } + + keys = (char *)xmalloc (1 + (2 * strlen (keyseq))); + + /* Translate the ASCII representation of KEYSEQ into an array of + characters. Stuff the characters into KEYS, and the length of + KEYS into KEYS_LEN. */ + if (rl_translate_keyseq (keyseq, keys, &keys_len)) + { + xfree (keys); + return -1; + } + + /* Bind keys, making new keymaps as necessary. */ + for (i = 0; i < keys_len; i++) + { + unsigned char uc = keys[i]; + int ic; + + ic = uc; + if (ic < 0 || ic >= KEYMAP_SIZE) + { + xfree (keys); + return -1; + } + + if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) + { + ic = UNMETA (ic); + if (map[ESC].type == ISKMAP) + map = FUNCTION_TO_KEYMAP (map, ESC); + } + + if ((i + 1) < keys_len) + { + if (map[ic].type != ISKMAP) + { + /* We allow subsequences of keys. If a keymap is being + created that will `shadow' an existing function or macro + key binding, we save that keybinding into the ANYOTHERKEY + index in the new map. The dispatch code will look there + to find the function to execute if the subsequence is not + matched. ANYOTHERKEY was chosen to be greater than + UCHAR_MAX. */ + k = map[ic]; + + map[ic].type = ISKMAP; + map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); + } + map = FUNCTION_TO_KEYMAP (map, ic); + /* The dispatch code will return this function if no matching + key sequence is found in the keymap. This (with a little + help from the dispatch code in readline.c) allows `a' to be + mapped to something, `abc' to be mapped to something else, + and the function bound to `a' to be executed when the user + types `abx', leaving `bx' in the input queue. */ + if (k.function && ((k.type == ISFUNC && k.function != rl_do_lowercase_version) || k.type == ISMACR)) + { + map[ANYOTHERKEY] = k; + k.function = 0; + } + } + else + { + if (map[ic].type == ISMACR) + xfree ((char *)map[ic].function); + else if (map[ic].type == ISKMAP) + { + map = FUNCTION_TO_KEYMAP (map, ic); + ic = ANYOTHERKEY; + /* If we're trying to override a keymap with a null function + (e.g., trying to unbind it), we can't use a null pointer + here because that's indistinguishable from having not been + overridden. We use a special bindable function that does + nothing. */ + if (type == ISFUNC && data == 0) + data = _rl_null_function; + } + + map[ic].function = KEYMAP_TO_FUNCTION (data); + map[ic].type = type; + } + + rl_binding_keymap = map; + } + xfree (keys); + return 0; +} + +/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY, + an array of characters. LEN gets the final length of ARRAY. Return + non-zero if there was an error parsing SEQ. */ +int +rl_translate_keyseq (seq, array, len) + const char *seq; + char *array; + int *len; +{ + register int i, c, l, temp; + + for (i = l = 0; c = seq[i]; i++) + { + if (c == '\\') + { + c = seq[++i]; + + if (c == 0) + break; + + /* Handle \C- and \M- prefixes. */ + if ((c == 'C' || c == 'M') && seq[i + 1] == '-') + { + /* Handle special case of backwards define. */ + if (strncmp (&seq[i], "C-\\M-", 5) == 0) + { + array[l++] = ESC; /* ESC is meta-prefix */ + i += 5; + array[l++] = CTRL (_rl_to_upper (seq[i])); + if (seq[i] == '\0') + i--; + } + else if (c == 'M') + { + i++; /* seq[i] == '-' */ + /* XXX - obey convert-meta setting */ + if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP) + array[l++] = ESC; /* ESC is meta-prefix */ + else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-') + { + i += 4; + temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); + array[l++] = META (temp); + } + else + { + /* This doesn't yet handle things like \M-\a, which may + or may not have any reasonable meaning. You're + probably better off using straight octal or hex. */ + i++; + array[l++] = META (seq[i]); + } + } + else if (c == 'C') + { + i += 2; + /* Special hack for C-?... */ + array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); + } + continue; + } + + /* Translate other backslash-escaped characters. These are the + same escape sequences that bash's `echo' and `printf' builtins + handle, with the addition of \d -> RUBOUT. A backslash + preceding a character that is not special is stripped. */ + switch (c) + { + case 'a': + array[l++] = '\007'; + break; + case 'b': + array[l++] = '\b'; + break; + case 'd': + array[l++] = RUBOUT; /* readline-specific */ + break; + case 'e': + array[l++] = ESC; + break; + case 'f': + array[l++] = '\f'; + break; + case 'n': + array[l++] = NEWLINE; + break; + case 'r': + array[l++] = RETURN; + break; + case 't': + array[l++] = TAB; + break; + case 'v': + array[l++] = 0x0B; + break; + case '\\': + array[l++] = '\\'; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + i++; + for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++) + c = (c * 8) + OCTVALUE (seq[i]); + i--; /* auto-increment in for loop */ + array[l++] = c & largest_char; + break; + case 'x': + i++; + for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++) + c = (c * 16) + HEXVALUE (seq[i]); + if (temp == 2) + c = 'x'; + i--; /* auto-increment in for loop */ + array[l++] = c & largest_char; + break; + default: /* backslashes before non-special chars just add the char */ + array[l++] = c; + break; /* the backslash is stripped */ + } + continue; + } + + array[l++] = c; + } + + *len = l; + array[l] = '\0'; + return (0); +} + +char * +rl_untranslate_keyseq (seq) + int seq; +{ + static char kseq[16]; + int i, c; + + i = 0; + c = seq; + if (META_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'M'; + kseq[i++] = '-'; + c = UNMETA (c); + } + else if (c == ESC) + { + kseq[i++] = '\\'; + c = 'e'; + } + else if (CTRL_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + else if (c == RUBOUT) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = '?'; + } + + if (c == ESC) + { + kseq[i++] = '\\'; + c = 'e'; + } + else if (c == '\\' || c == '"') + { + kseq[i++] = '\\'; + } + + kseq[i++] = (unsigned char) c; + kseq[i] = '\0'; + return kseq; +} + +static char * +_rl_untranslate_macro_value (seq) + char *seq; +{ + char *ret, *r, *s; + int c; + + r = ret = (char *)xmalloc (7 * strlen (seq) + 1); + for (s = seq; *s; s++) + { + c = *s; + if (META_CHAR (c)) + { + *r++ = '\\'; + *r++ = 'M'; + *r++ = '-'; + c = UNMETA (c); + } + else if (c == ESC) + { + *r++ = '\\'; + c = 'e'; + } + else if (CTRL_CHAR (c)) + { + *r++ = '\\'; + *r++ = 'C'; + *r++ = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + else if (c == RUBOUT) + { + *r++ = '\\'; + *r++ = 'C'; + *r++ = '-'; + c = '?'; + } + + if (c == ESC) + { + *r++ = '\\'; + c = 'e'; + } + else if (c == '\\' || c == '"') + *r++ = '\\'; + + *r++ = (unsigned char)c; + } + *r = '\0'; + return ret; +} + +/* Return a pointer to the function that STRING represents. + If STRING doesn't have a matching function, then a NULL pointer + is returned. */ +rl_command_func_t * +rl_named_function (string) + const char *string; +{ + register int i; + + rl_initialize_funmap (); + + for (i = 0; funmap[i]; i++) + if (_rl_stricmp (funmap[i]->name, string) == 0) + return (funmap[i]->function); + return ((rl_command_func_t *)NULL); +} + +/* Return the function (or macro) definition which would be invoked via + KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is + used. TYPE, if non-NULL, is a pointer to an int which will receive the + type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap), + or ISMACR (macro). */ +rl_command_func_t * +rl_function_of_keyseq (keyseq, map, type) + const char *keyseq; + Keymap map; + int *type; +{ + register int i; + + if (map == 0) + map = _rl_keymap; + + for (i = 0; keyseq && keyseq[i]; i++) + { + unsigned char ic = keyseq[i]; + + if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type == ISKMAP) + { + map = FUNCTION_TO_KEYMAP (map, ESC); + ic = UNMETA (ic); + } + /* XXX - should we just return NULL here, since this obviously + doesn't match? */ + else + { + if (type) + *type = map[ESC].type; + + return (map[ESC].function); + } + } + + if (map[ic].type == ISKMAP) + { + /* If this is the last key in the key sequence, return the + map. */ + if (keyseq[i + 1] == '\0') + { + if (type) + *type = ISKMAP; + + return (map[ic].function); + } + else + map = FUNCTION_TO_KEYMAP (map, ic); + } + /* If we're not at the end of the key sequence, and the current key + is bound to something other than a keymap, then the entire key + sequence is not bound. */ + else if (map[ic].type != ISKMAP && keyseq[i+1]) + return ((rl_command_func_t *)NULL); + else /* map[ic].type != ISKMAP && keyseq[i+1] == 0 */ + { + if (type) + *type = map[ic].type; + + return (map[ic].function); + } + } + return ((rl_command_func_t *) NULL); +} + +/* The last key bindings file read. */ +static char *last_readline_init_file = (char *)NULL; + +/* The file we're currently reading key bindings from. */ +static const char *current_readline_init_file; +static int current_readline_init_include_level; +static int current_readline_init_lineno; + +/* Read FILENAME into a locally-allocated buffer and return the buffer. + The size of the buffer is returned in *SIZEP. Returns NULL if any + errors were encountered. */ +static char * +_rl_read_file (filename, sizep) + char *filename; + size_t *sizep; +{ + struct stat finfo; + size_t file_size; + char *buffer; + int i, file; + + if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0) + return ((char *)NULL); + + file_size = (size_t)finfo.st_size; + + /* check for overflow on very large files */ + if (file_size != finfo.st_size || file_size + 1 < file_size) + { + if (file >= 0) + close (file); +#if defined (EFBIG) + errno = EFBIG; +#endif + return ((char *)NULL); + } + + /* Read the file into BUFFER. */ + buffer = (char *)xmalloc (file_size + 1); + i = read (file, buffer, file_size); + close (file); + + if (i < 0) + { + xfree (buffer); + return ((char *)NULL); + } + + RL_CHECK_SIGNALS (); + + buffer[i] = '\0'; + if (sizep) + *sizep = i; + + return (buffer); +} + +/* Re-read the current keybindings file. */ +int +rl_re_read_init_file (count, ignore) + int count, ignore; +{ + int r; + r = rl_read_init_file ((const char *)NULL); + rl_set_keymap_from_edit_mode (); + return r; +} + +/* Do key bindings from a file. If FILENAME is NULL it defaults + to the first non-null filename from this list: + 1. the filename used for the previous call + 2. the value of the shell variable `INPUTRC' + 3. ~/.inputrc + 4. /etc/inputrc + If the file existed and could be opened and read, 0 is returned, + otherwise errno is returned. */ +int +rl_read_init_file (filename) + const char *filename; +{ + /* Default the filename. */ + if (filename == 0) + filename = last_readline_init_file; + if (filename == 0) + filename = sh_get_env_value ("INPUTRC"); + if (filename == 0 || *filename == 0) + { + filename = DEFAULT_INPUTRC; + /* Try to read DEFAULT_INPUTRC; fall back to SYS_INPUTRC on failure */ + if (_rl_read_init_file (filename, 0) == 0) + return 0; + filename = SYS_INPUTRC; + } + +#if defined (__MSDOS__) + if (_rl_read_init_file (filename, 0) == 0) + return 0; + filename = "~/_inputrc"; +#endif + return (_rl_read_init_file (filename, 0)); +} + +static int +_rl_read_init_file (filename, include_level) + const char *filename; + int include_level; +{ + register int i; + char *buffer, *openname, *line, *end; + size_t file_size; + + current_readline_init_file = filename; + current_readline_init_include_level = include_level; + + openname = tilde_expand (filename); + buffer = _rl_read_file (openname, &file_size); + xfree (openname); + + RL_CHECK_SIGNALS (); + if (buffer == 0) + return (errno); + + if (include_level == 0 && filename != last_readline_init_file) + { + FREE (last_readline_init_file); + last_readline_init_file = savestring (filename); + } + + currently_reading_init_file = 1; + + /* Loop over the lines in the file. Lines that start with `#' are + comments; all other lines are commands for readline initialization. */ + current_readline_init_lineno = 1; + line = buffer; + end = buffer + file_size; + while (line < end) + { + /* Find the end of this line. */ + for (i = 0; line + i != end && line[i] != '\n'; i++); + +#if defined (__CYGWIN__) + /* ``Be liberal in what you accept.'' */ + if (line[i] == '\n' && line[i-1] == '\r') + line[i - 1] = '\0'; +#endif + + /* Mark end of line. */ + line[i] = '\0'; + + /* Skip leading whitespace. */ + while (*line && whitespace (*line)) + { + line++; + i--; + } + + /* If the line is not a comment, then parse it. */ + if (*line && *line != '#') + rl_parse_and_bind (line); + + /* Move to the next line. */ + line += i + 1; + current_readline_init_lineno++; + } + + xfree (buffer); + currently_reading_init_file = 0; + return (0); +} + +static void +_rl_init_file_error (msg) + const char *msg; +{ + if (currently_reading_init_file) + _rl_errmsg ("%s: line %d: %s\n", current_readline_init_file, + current_readline_init_lineno, msg); + else + _rl_errmsg ("%s", msg); +} + +/* **************************************************************** */ +/* */ +/* Parser Directives */ +/* */ +/* **************************************************************** */ + +typedef int _rl_parser_func_t PARAMS((char *)); + +/* Things that mean `Control'. */ +const char * const _rl_possible_control_prefixes[] = { + "Control-", "C-", "CTRL-", (const char *)NULL +}; + +const char * const _rl_possible_meta_prefixes[] = { + "Meta", "M-", (const char *)NULL +}; + +/* Conditionals. */ + +/* Calling programs set this to have their argv[0]. */ +const char *rl_readline_name = "other"; + +/* Stack of previous values of parsing_conditionalized_out. */ +static unsigned char *if_stack = (unsigned char *)NULL; +static int if_stack_depth; +static int if_stack_size; + +/* Push _rl_parsing_conditionalized_out, and set parser state based + on ARGS. */ +static int +parser_if (args) + char *args; +{ + register int i; + + /* Push parser state. */ + if (if_stack_depth + 1 >= if_stack_size) + { + if (!if_stack) + if_stack = (unsigned char *)xmalloc (if_stack_size = 20); + else + if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); + } + if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out; + + /* If parsing is turned off, then nothing can turn it back on except + for finding the matching endif. In that case, return right now. */ + if (_rl_parsing_conditionalized_out) + return 0; + + /* Isolate first argument. */ + for (i = 0; args[i] && !whitespace (args[i]); i++); + + if (args[i]) + args[i++] = '\0'; + + /* Handle "$if term=foo" and "$if mode=emacs" constructs. If this + isn't term=foo, or mode=emacs, then check to see if the first + word in ARGS is the same as the value stored in rl_readline_name. */ + if (rl_terminal_name && _rl_strnicmp (args, "term=", 5) == 0) + { + char *tem, *tname; + + /* Terminals like "aaa-60" are equivalent to "aaa". */ + tname = savestring (rl_terminal_name); + tem = strchr (tname, '-'); + if (tem) + *tem = '\0'; + + /* Test the `long' and `short' forms of the terminal name so that + if someone has a `sun-cmd' and does not want to have bindings + that will be executed if the terminal is a `sun', they can put + `$if term=sun-cmd' into their .inputrc. */ + _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && + _rl_stricmp (args + 5, rl_terminal_name); + xfree (tname); + } +#if defined (VI_MODE) + else if (_rl_strnicmp (args, "mode=", 5) == 0) + { + int mode; + + if (_rl_stricmp (args + 5, "emacs") == 0) + mode = emacs_mode; + else if (_rl_stricmp (args + 5, "vi") == 0) + mode = vi_mode; + else + mode = no_mode; + + _rl_parsing_conditionalized_out = mode != rl_editing_mode; + } +#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 (_rl_stricmp (args, rl_readline_name) == 0) + _rl_parsing_conditionalized_out = 0; + else + _rl_parsing_conditionalized_out = 1; + return 0; +} + +/* Invert the current parser state if there is anything on the stack. */ +static int +parser_else (args) + char *args; +{ + register int i; + + if (if_stack_depth == 0) + { + _rl_init_file_error ("$else found without matching $if"); + return 0; + } + +#if 0 + /* 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++) +#else + /* Check the previous (n) levels of the stack to make sure that + we haven't previously turned off parsing. */ + for (i = 0; i < if_stack_depth; i++) +#endif + if (if_stack[i] == 1) + return 0; + + /* Invert the state of parsing if at top level. */ + _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out; + return 0; +} + +/* Terminate a conditional, popping the value of + _rl_parsing_conditionalized_out from the stack. */ +static int +parser_endif (args) + char *args; +{ + if (if_stack_depth) + _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; + else + _rl_init_file_error ("$endif without matching $if"); + return 0; +} + +static int +parser_include (args) + char *args; +{ + const char *old_init_file; + char *e; + int old_line_number, old_include_level, r; + + if (_rl_parsing_conditionalized_out) + return (0); + + old_init_file = current_readline_init_file; + old_line_number = current_readline_init_lineno; + old_include_level = current_readline_init_include_level; + + e = strchr (args, '\n'); + if (e) + *e = '\0'; + r = _rl_read_init_file ((const char *)args, old_include_level + 1); + + current_readline_init_file = old_init_file; + current_readline_init_lineno = old_line_number; + current_readline_init_include_level = old_include_level; + + return r; +} + +/* Associate textual names with actual functions. */ +static const struct { + const char * const name; + _rl_parser_func_t *function; +} parser_directives [] = { + { "if", parser_if }, + { "endif", parser_endif }, + { "else", parser_else }, + { "include", parser_include }, + { (char *)0x0, (_rl_parser_func_t *)0x0 } +}; + +/* Handle a parser directive. STATEMENT is the line of the directive + without any leading `$'. */ +static int +handle_parser_directive (statement) + char *statement; +{ + register int i; + char *directive, *args; + + /* Isolate the actual directive. */ + + /* Skip whitespace. */ + for (i = 0; whitespace (statement[i]); i++); + + directive = &statement[i]; + + for (; statement[i] && !whitespace (statement[i]); i++); + + if (statement[i]) + statement[i++] = '\0'; + + for (; statement[i] && whitespace (statement[i]); i++); + + args = &statement[i]; + + /* Lookup the command, and act on it. */ + for (i = 0; parser_directives[i].name; i++) + if (_rl_stricmp (directive, parser_directives[i].name) == 0) + { + (*parser_directives[i].function) (args); + return (0); + } + + /* display an error message about the unknown parser directive */ + _rl_init_file_error ("unknown parser directive"); + return (1); +} + +/* Read the binding command from STRING and perform it. + A key binding command looks like: Keyname: function-name\0, + a variable binding command looks like: set variable value. + A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ +int +rl_parse_and_bind (string) + char *string; +{ + char *funname, *kname; + register int c, i; + int key, equivalency; + + while (string && whitespace (*string)) + string++; + + if (!string || !*string || *string == '#') + return 0; + + /* If this is a parser directive, act on it. */ + if (*string == '$') + { + handle_parser_directive (&string[1]); + return 0; + } + + /* If we aren't supposed to be parsing right now, then we're done. */ + if (_rl_parsing_conditionalized_out) + return 0; + + i = 0; + /* If this keyname is a complex key expression surrounded by quotes, + advance to after the matching close quote. This code allows the + backslash to quote characters in the key expression. */ + if (*string == '"') + { + int passc = 0; + + for (i = 1; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc++; + continue; + } + + if (c == '"') + break; + } + /* If we didn't find a closing quote, abort the line. */ + if (string[i] == '\0') + { + _rl_init_file_error ("no closing `\"' in key binding"); + return 1; + } + } + + /* Advance to the colon (:) or whitespace which separates the two objects. */ + for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); + + equivalency = (c == ':' && string[i + 1] == '='); + + /* Mark the end of the command (or keyname). */ + if (string[i]) + string[i++] = '\0'; + + /* If doing assignment, skip the '=' sign as well. */ + if (equivalency) + string[i++] = '\0'; + + /* If this is a command to set a variable, then do that. */ + if (_rl_stricmp (string, "set") == 0) + { + char *var, *value, *e; + + var = string + i; + /* Make VAR point to start of variable name. */ + while (*var && whitespace (*var)) var++; + + /* Make VALUE point to start of value string. */ + value = var; + while (*value && !whitespace (*value)) value++; + if (*value) + *value++ = '\0'; + while (*value && whitespace (*value)) value++; + + /* Strip trailing whitespace from values to boolean variables. Temp + fix until I get a real quoted-string parser here. */ + i = find_boolean_var (var); + if (i >= 0) + { + /* remove trailing whitespace */ + e = value + strlen (value) - 1; + while (e >= value && whitespace (*e)) + e--; + e++; /* skip back to whitespace or EOS */ + if (*e && e >= value) + *e = '\0'; + } + + rl_variable_bind (var, value); + return 0; + } + + /* Skip any whitespace between keyname and funname. */ + for (; string[i] && whitespace (string[i]); i++); + funname = &string[i]; + + /* Now isolate funname. + For straight function names just look for whitespace, since + that will signify the end of the string. But this could be a + macro definition. In that case, the string is quoted, so skip + to the matching delimiter. We allow the backslash to quote the + delimiter characters in the macro body. */ + /* This code exists to allow whitespace in macro expansions, which + would otherwise be gobbled up by the next `for' loop.*/ + /* XXX - it may be desirable to allow backslash quoting only if " is + the quoted string delimiter, like the shell. */ + if (*funname == '\'' || *funname == '"') + { + int delimiter, passc; + + delimiter = string[i++]; + for (passc = 0; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc = 1; + continue; + } + + if (c == delimiter) + break; + } + if (c) + i++; + } + + /* Advance to the end of the string. */ + for (; string[i] && !whitespace (string[i]); i++); + + /* No extra whitespace at the end of the string. */ + string[i] = '\0'; + + /* Handle equivalency bindings here. Make the left-hand side be exactly + whatever the right-hand evaluates to, including keymaps. */ + if (equivalency) + { + return 0; + } + + /* If this is a new-style key-binding, then do the binding with + rl_bind_keyseq (). Otherwise, let the older code deal with it. */ + if (*string == '"') + { + char *seq; + register int j, k, passc; + + seq = (char *)xmalloc (1 + strlen (string)); + for (j = 1, k = passc = 0; string[j]; j++) + { + /* Allow backslash to quote characters, but leave them in place. + This allows a string to end with a backslash quoting another + backslash, or with a backslash quoting a double quote. The + backslashes are left in place for rl_translate_keyseq (). */ + if (passc || (string[j] == '\\')) + { + seq[k++] = string[j]; + passc = !passc; + continue; + } + + if (string[j] == '"') + break; + + seq[k++] = string[j]; + } + seq[k] = '\0'; + + /* Binding macro? */ + if (*funname == '\'' || *funname == '"') + { + j = strlen (funname); + + /* Remove the delimiting quotes from each end of FUNNAME. */ + if (j && funname[j - 1] == *funname) + funname[j - 1] = '\0'; + + rl_macro_bind (seq, &funname[1], _rl_keymap); + } + else + rl_bind_keyseq (seq, rl_named_function (funname)); + + xfree (seq); + return 0; + } + + /* Get the actual character we want to deal with. */ + kname = strrchr (string, '-'); + if (!kname) + kname = string; + else + kname++; + + key = glean_key_from_name (kname); + + /* Add in control and meta bits. */ + if (substring_member_of_array (string, _rl_possible_control_prefixes)) + key = CTRL (_rl_to_upper (key)); + + if (substring_member_of_array (string, _rl_possible_meta_prefixes)) + key = META (key); + + /* Temporary. Handle old-style keyname with macro-binding. */ + if (*funname == '\'' || *funname == '"') + { + char useq[2]; + int fl = strlen (funname); + + useq[0] = key; useq[1] = '\0'; + if (fl && funname[fl - 1] == *funname) + funname[fl - 1] = '\0'; + + rl_macro_bind (useq, &funname[1], _rl_keymap); + } +#if defined (PREFIX_META_HACK) + /* Ugly, but working hack to keep prefix-meta around. */ + else if (_rl_stricmp (funname, "prefix-meta") == 0) + { + char seq[2]; + + seq[0] = key; + seq[1] = '\0'; + rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap); + } +#endif /* PREFIX_META_HACK */ + else + rl_bind_key (key, rl_named_function (funname)); + return 0; +} + +/* Simple structure for boolean readline variables (i.e., those that can + have one of two values; either "On" or 1 for truth, or "Off" or 0 for + false. */ + +#define V_SPECIAL 0x1 + +static const struct { + const char * const name; + int *value; + int flags; +} boolean_varlist [] = { + { "bind-tty-special-chars", &_rl_bind_stty_chars, 0 }, + { "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL }, + { "byte-oriented", &rl_byte_oriented, 0 }, + { "completion-ignore-case", &_rl_completion_case_fold, 0 }, + { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, + { "disable-completion", &rl_inhibit_completion, 0 }, + { "enable-keypad", &_rl_enable_keypad, 0 }, + { "expand-tilde", &rl_complete_with_tilde_expansion, 0 }, + { "history-preserve-point", &_rl_history_preserve_point, 0 }, + { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode, 0 }, + { "input-meta", &_rl_meta_flag, 0 }, + { "mark-directories", &_rl_complete_mark_directories, 0 }, + { "mark-modified-lines", &_rl_mark_modified_lines, 0 }, + { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 }, + { "match-hidden-files", &_rl_match_hidden_files, 0 }, + { "meta-flag", &_rl_meta_flag, 0 }, + { "output-meta", &_rl_output_meta_chars, 0 }, + { "page-completions", &_rl_page_completions, 0 }, + { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, + { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, + { "revert-all-at-newline", &_rl_revert_all_at_newline, 0 }, + { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, + { "show-all-if-unmodified", &_rl_complete_show_unmodified, 0 }, +#if defined (VISIBLE_STATS) + { "visible-stats", &rl_visible_stats, 0 }, +#endif /* VISIBLE_STATS */ + { (char *)NULL, (int *)NULL } +}; + +static int +find_boolean_var (name) + const char *name; +{ + register int i; + + for (i = 0; boolean_varlist[i].name; i++) + if (_rl_stricmp (name, boolean_varlist[i].name) == 0) + return i; + return -1; +} + +/* Hooks for handling special boolean variables, where a + function needs to be called or another variable needs + to be changed when they're changed. */ +static void +hack_special_boolean_var (i) + int i; +{ + const char *name; + + name = boolean_varlist[i].name; + + if (_rl_stricmp (name, "blink-matching-paren") == 0) + _rl_enable_paren_matching (rl_blink_matching_paren); + else if (_rl_stricmp (name, "prefer-visible-bell") == 0) + { + if (_rl_prefer_visible_bell) + _rl_bell_preference = VISIBLE_BELL; + else + _rl_bell_preference = AUDIBLE_BELL; + } +} + +typedef int _rl_sv_func_t PARAMS((const char *)); + +/* These *must* correspond to the array indices for the appropriate + string variable. (Though they're not used right now.) */ +#define V_BELLSTYLE 0 +#define V_COMBEGIN 1 +#define V_EDITMODE 2 +#define V_ISRCHTERM 3 +#define V_KEYMAP 4 + +#define V_STRING 1 +#define V_INT 2 + +/* Forward declarations */ +static int sv_bell_style PARAMS((const char *)); +static int sv_combegin PARAMS((const char *)); +static int sv_dispprefix PARAMS((const char *)); +static int sv_compquery PARAMS((const char *)); +static int sv_editmode PARAMS((const char *)); +static int sv_histsize PARAMS((const char *)); +static int sv_isrchterm PARAMS((const char *)); +static int sv_keymap PARAMS((const char *)); + +static const struct { + const char * const name; + int flags; + _rl_sv_func_t *set_func; +} string_varlist[] = { + { "bell-style", V_STRING, sv_bell_style }, + { "comment-begin", V_STRING, sv_combegin }, + { "completion-prefix-display-length", V_INT, sv_dispprefix }, + { "completion-query-items", V_INT, sv_compquery }, + { "editing-mode", V_STRING, sv_editmode }, + { "history-size", V_INT, sv_histsize }, + { "isearch-terminators", V_STRING, sv_isrchterm }, + { "keymap", V_STRING, sv_keymap }, + { (char *)NULL, 0 } +}; + +static int +find_string_var (name) + const char *name; +{ + register int i; + + for (i = 0; string_varlist[i].name; i++) + if (_rl_stricmp (name, string_varlist[i].name) == 0) + return i; + return -1; +} + +/* A boolean value that can appear in a `set variable' command is true if + the value is null or empty, `on' (case-insenstive), or "1". Any other + values result in 0 (false). */ +static int +bool_to_int (value) + const char *value; +{ + return (value == 0 || *value == '\0' || + (_rl_stricmp (value, "on") == 0) || + (value[0] == '1' && value[1] == '\0')); +} + +char * +rl_variable_value (name) + const char *name; +{ + register int i; + + /* Check for simple variables first. */ + i = find_boolean_var (name); + if (i >= 0) + return (*boolean_varlist[i].value ? "on" : "off"); + + i = find_string_var (name); + if (i >= 0) + return (_rl_get_string_variable_value (string_varlist[i].name)); + + /* Unknown variable names return NULL. */ + return 0; +} + +int +rl_variable_bind (name, value) + const char *name, *value; +{ + register int i; + int v; + + /* Check for simple variables first. */ + i = find_boolean_var (name); + if (i >= 0) + { + *boolean_varlist[i].value = bool_to_int (value); + if (boolean_varlist[i].flags & V_SPECIAL) + hack_special_boolean_var (i); + return 0; + } + + i = find_string_var (name); + + /* For the time being, unknown variable names or string names without a + handler function are simply ignored. */ + if (i < 0 || string_varlist[i].set_func == 0) + return 0; + + v = (*string_varlist[i].set_func) (value); + return v; +} + +static int +sv_editmode (value) + const char *value; +{ + if (_rl_strnicmp (value, "vi", 2) == 0) + { +#if defined (VI_MODE) + _rl_keymap = vi_insertion_keymap; + rl_editing_mode = vi_mode; +#endif /* VI_MODE */ + return 0; + } + else if (_rl_strnicmp (value, "emacs", 5) == 0) + { + _rl_keymap = emacs_standard_keymap; + rl_editing_mode = emacs_mode; + return 0; + } + return 1; +} + +static int +sv_combegin (value) + const char *value; +{ + if (value && *value) + { + FREE (_rl_comment_begin); + _rl_comment_begin = savestring (value); + return 0; + } + return 1; +} + +static int +sv_dispprefix (value) + const char *value; +{ + int nval = 0; + + if (value && *value) + { + nval = atoi (value); + if (nval < 0) + nval = 0; + } + _rl_completion_prefix_display_length = nval; + return 0; +} + +static int +sv_compquery (value) + const char *value; +{ + int nval = 100; + + if (value && *value) + { + nval = atoi (value); + if (nval < 0) + nval = 0; + } + rl_completion_query_items = nval; + return 0; +} + +static int +sv_histsize (value) + const char *value; +{ + int nval = 500; + + if (value && *value) + { + nval = atoi (value); + if (nval < 0) + return 1; + } + stifle_history (nval); + return 0; +} + +static int +sv_keymap (value) + const char *value; +{ + Keymap kmap; + + kmap = rl_get_keymap_by_name (value); + if (kmap) + { + rl_set_keymap (kmap); + return 0; + } + return 1; +} + +static int +sv_bell_style (value) + const char *value; +{ + if (value == 0 || *value == '\0') + _rl_bell_preference = AUDIBLE_BELL; + else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0) + _rl_bell_preference = NO_BELL; + else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0) + _rl_bell_preference = AUDIBLE_BELL; + else if (_rl_stricmp (value, "visible") == 0) + _rl_bell_preference = VISIBLE_BELL; + else + return 1; + return 0; +} + +static int +sv_isrchterm (value) + const char *value; +{ + int beg, end, delim; + char *v; + + if (value == 0) + return 1; + + /* Isolate the value and translate it into a character string. */ + v = savestring (value); + FREE (_rl_isearch_terminators); + if (v[0] == '"' || v[0] == '\'') + { + delim = v[0]; + for (beg = end = 1; v[end] && v[end] != delim; end++) + ; + } + else + { + for (beg = end = 0; whitespace (v[end]) == 0; end++) + ; + } + + v[end] = '\0'; + + /* The value starts at v + beg. Translate it into a character string. */ + _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1); + rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end); + _rl_isearch_terminators[end] = '\0'; + + xfree (v); + return 0; +} + +/* Return the character which matches NAME. + For example, `Space' returns ' '. */ + +typedef struct { + const char * const name; + int value; +} assoc_list; + +static const assoc_list name_key_alist[] = { + { "DEL", 0x7f }, + { "ESC", '\033' }, + { "Escape", '\033' }, + { "LFD", '\n' }, + { "Newline", '\n' }, + { "RET", '\r' }, + { "Return", '\r' }, + { "Rubout", 0x7f }, + { "SPC", ' ' }, + { "Space", ' ' }, + { "Tab", 0x09 }, + { (char *)0x0, 0 } +}; + +static int +glean_key_from_name (name) + char *name; +{ + register int i; + + for (i = 0; name_key_alist[i].name; i++) + if (_rl_stricmp (name, name_key_alist[i].name) == 0) + return (name_key_alist[i].value); + + return (*(unsigned char *)name); /* XXX was return (*name) */ +} + +/* Auxiliary functions to manage keymaps. */ +static const struct { + const char * const name; + Keymap map; +} keymap_names[] = { + { "emacs", emacs_standard_keymap }, + { "emacs-standard", emacs_standard_keymap }, + { "emacs-meta", emacs_meta_keymap }, + { "emacs-ctlx", emacs_ctlx_keymap }, +#if defined (VI_MODE) + { "vi", vi_movement_keymap }, + { "vi-move", vi_movement_keymap }, + { "vi-command", vi_movement_keymap }, + { "vi-insert", vi_insertion_keymap }, +#endif /* VI_MODE */ + { (char *)0x0, (Keymap)0x0 } +}; + +Keymap +rl_get_keymap_by_name (name) + const char *name; +{ + register int i; + + for (i = 0; keymap_names[i].name; i++) + if (_rl_stricmp (name, keymap_names[i].name) == 0) + return (keymap_names[i].map); + return ((Keymap) NULL); +} + +char * +rl_get_keymap_name (map) + Keymap map; +{ + register int i; + for (i = 0; keymap_names[i].name; i++) + if (map == keymap_names[i].map) + return ((char *)keymap_names[i].name); + return ((char *)NULL); +} + +void +rl_set_keymap (map) + Keymap map; +{ + if (map) + _rl_keymap = map; +} + +Keymap +rl_get_keymap () +{ + return (_rl_keymap); +} + +void +rl_set_keymap_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + _rl_keymap = emacs_standard_keymap; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + _rl_keymap = vi_insertion_keymap; +#endif /* VI_MODE */ +} + +char * +rl_get_keymap_name_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + return "emacs"; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + return "vi"; +#endif /* VI_MODE */ + else + return "none"; +} + +/* **************************************************************** */ +/* */ +/* 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 () +{ + register int i; + const char **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]); + + xfree (funmap_names); +} + +static char * +_rl_get_keyname (key) + int key; +{ + char *keyname; + int i, c; + + keyname = (char *)xmalloc (8); + + c = key; + /* Since this is going to be used to write out keysequence-function + pairs for possible inclusion in an inputrc file, we don't want to + do any special meta processing on KEY. */ + +#if 1 + /* XXX - Experimental */ + /* We might want to do this, but the old version of the code did not. */ + + /* If this is an escape character, we don't want to do any more processing. + Just add the special ESC key sequence and return. */ + if (c == ESC) + { + keyname[0] = '\\'; + keyname[1] = 'e'; + keyname[2] = '\0'; + return keyname; + } +#endif + + /* RUBOUT is translated directly into \C-? */ + if (key == RUBOUT) + { + keyname[0] = '\\'; + keyname[1] = 'C'; + keyname[2] = '-'; + keyname[3] = '?'; + keyname[4] = '\0'; + return keyname; + } + + i = 0; + /* Now add special prefixes needed for control characters. This can + potentially change C. */ + if (CTRL_CHAR (c)) + { + keyname[i++] = '\\'; + keyname[i++] = 'C'; + keyname[i++] = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + + /* XXX experimental code. Turn the characters that are not ASCII or + ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237). + This changes C. */ + if (c >= 128 && c <= 159) + { + keyname[i++] = '\\'; + keyname[i++] = '2'; + c -= 128; + keyname[i++] = (c / 8) + '0'; + c = (c % 8) + '0'; + } + + /* Now, if the character needs to be quoted with a backslash, do that. */ + if (c == '\\' || c == '"') + keyname[i++] = '\\'; + + /* Now add the key, terminate the string, and return it. */ + keyname[i++] = (char) c; + keyname[i] = '\0'; + + return keyname; +} + +/* Return a NULL terminated array of strings which represent the key + sequences that are used to invoke FUNCTION in MAP. */ +char ** +rl_invoking_keyseqs_in_map (function, map) + rl_command_func_t *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 < KEYMAP_SIZE; 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; + + keyname = _rl_get_keyname (key); + + if (result_index + 2 > result_size) + { + result_size += 10; + result = (char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index++] = keyname; + result[result_index] = (char *)NULL; + } + break; + + case ISKMAP: + { + char **seqs; + register int i; + + /* 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 = + rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); + else + break; + + if (seqs == 0) + break; + + for (i = 0; seqs[i]; i++) + { + char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); + + if (key == ESC) + { + /* If ESC is the meta prefix and we're converting chars + with the eighth bit set to ESC-prefixed sequences, then + we can use \M-. Otherwise we need to use the sequence + for ESC. */ + if (_rl_convert_meta_chars_to_ascii && map[ESC].type == ISKMAP) + sprintf (keyname, "\\M-"); + else + sprintf (keyname, "\\e"); + } + else if (CTRL_CHAR (key)) + sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); + else if (key == RUBOUT) + sprintf (keyname, "\\C-?"); + else if (key == '\\' || key == '"') + { + keyname[0] = '\\'; + keyname[1] = (char) key; + keyname[2] = '\0'; + } + else + { + keyname[0] = (char) key; + keyname[1] = '\0'; + } + + strcat (keyname, seqs[i]); + xfree (seqs[i]); + + if (result_index + 2 > result_size) + { + result_size += 10; + result = (char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index++] = keyname; + result[result_index] = (char *)NULL; + } + + xfree (seqs); + } + 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) + rl_command_func_t *function; +{ + return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); +} + +/* 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; + const char **names; + const char *name; + + names = rl_funmap_names (); + + fprintf (rl_outstream, "\n"); + + for (i = 0; name = names[i]; i++) + { + rl_command_func_t *function; + char **invokers; + + function = rl_named_function (name); + invokers = rl_invoking_keyseqs_in_map (function, _rl_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); + xfree (invokers[j]); + } + + xfree (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++) + xfree (invokers[j]); + + xfree (invokers); + } + } + } +} + +/* 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, key) + int count, key; +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_function_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +static void +_rl_macro_dumper_internal (print_readably, map, prefix) + int print_readably; + Keymap map; + char *prefix; +{ + register int key; + char *keyname, *out; + int prefix_len; + + for (key = 0; key < KEYMAP_SIZE; key++) + { + switch (map[key].type) + { + case ISMACR: + keyname = _rl_get_keyname (key); + out = _rl_untranslate_macro_value ((char *)map[key].function); + + if (print_readably) + fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", + keyname, + out ? out : ""); + else + fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "", + keyname, + out ? out : ""); + xfree (keyname); + xfree (out); + break; + case ISFUNC: + break; + case ISKMAP: + prefix_len = prefix ? strlen (prefix) : 0; + if (key == ESC) + { + keyname = (char *)xmalloc (3 + prefix_len); + if (prefix) + strcpy (keyname, prefix); + keyname[prefix_len] = '\\'; + keyname[prefix_len + 1] = 'e'; + keyname[prefix_len + 2] = '\0'; + } + else + { + keyname = _rl_get_keyname (key); + if (prefix) + { + out = (char *)xmalloc (strlen (keyname) + prefix_len + 1); + strcpy (out, prefix); + strcpy (out + prefix_len, keyname); + xfree (keyname); + keyname = out; + } + } + + _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); + xfree (keyname); + break; + } + } +} + +void +rl_macro_dumper (print_readably) + int print_readably; +{ + _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL); +} + +int +rl_dump_macros (count, key) + int count, key; +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_macro_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +static char * +_rl_get_string_variable_value (name) + const char *name; +{ + static char numbuf[32]; + char *ret; + + if (_rl_stricmp (name, "bell-style") == 0) + { + switch (_rl_bell_preference) + { + case NO_BELL: + return "none"; + case VISIBLE_BELL: + return "visible"; + case AUDIBLE_BELL: + default: + return "audible"; + } + } + else if (_rl_stricmp (name, "comment-begin") == 0) + return (_rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); + else if (_rl_stricmp (name, "completion-prefix-display-length") == 0) + { + sprintf (numbuf, "%d", _rl_completion_prefix_display_length); + return (numbuf); + } + else if (_rl_stricmp (name, "completion-query-items") == 0) + { + sprintf (numbuf, "%d", rl_completion_query_items); + return (numbuf); + } + else if (_rl_stricmp (name, "editing-mode") == 0) + return (rl_get_keymap_name_from_edit_mode ()); + else if (_rl_stricmp (name, "history-size") == 0) + { + sprintf (numbuf, "%d", history_is_stifled() ? history_max_entries : 0); + return (numbuf); + } + else if (_rl_stricmp (name, "isearch-terminators") == 0) + { + if (_rl_isearch_terminators == 0) + return 0; + ret = _rl_untranslate_macro_value (_rl_isearch_terminators); + if (ret) + { + strncpy (numbuf, ret, sizeof (numbuf) - 1); + xfree (ret); + numbuf[sizeof(numbuf) - 1] = '\0'; + } + else + numbuf[0] = '\0'; + return numbuf; + } + else if (_rl_stricmp (name, "keymap") == 0) + { + ret = rl_get_keymap_name (_rl_keymap); + if (ret == 0) + ret = rl_get_keymap_name_from_edit_mode (); + return (ret ? ret : "none"); + } + else + return (0); +} + +void +rl_variable_dumper (print_readably) + int print_readably; +{ + int i; + char *v; + + for (i = 0; boolean_varlist[i].name; i++) + { + if (print_readably) + fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + else + fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + } + + for (i = 0; string_varlist[i].name; i++) + { + v = _rl_get_string_variable_value (string_varlist[i].name); + if (v == 0) /* _rl_isearch_terminators can be NULL */ + continue; + if (print_readably) + fprintf (rl_outstream, "set %s %s\n", string_varlist[i].name, v); + else + fprintf (rl_outstream, "%s is set to `%s'\n", string_varlist[i].name, v); + } +} + +/* Print all of the current variables and their values 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_variables (count, key) + int count, key; +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_variable_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +/* Return non-zero if any members of ARRAY are a substring in STRING. */ +static int +substring_member_of_array (string, array) + const char *string; + const char * const *array; +{ + while (*array) + { + if (_rl_strindex (string, *array)) + return (1); + array++; + } + return (0); +} diff --git a/lib/readline/complete.c b/lib/readline/complete.c index b4a468a41..a6ba46e3a 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -2330,7 +2330,7 @@ rl_menu_complete (count, ignore) /* The first time through, we generate the list of matches and set things up to insert them. */ - if (rl_last_func != rl_menu_complete || full_completion) + if ((rl_last_func != rl_menu_complete && rl_last_func != rl_backward_menu_complete) || full_completion) { /* Clean up from previous call, if any. */ FREE (orig_text); @@ -2470,3 +2470,12 @@ rl_menu_complete (count, ignore) completion_changed_buffer = 1; return (0); } + +int +rl_backward_menu_complete (count, key) + int count, key; +{ + /* Positive arguments to backward-menu-complete translate into negative + arguments for menu-complete, and vice versa. */ + return (rl_menu_complete (-count, key)); +} diff --git a/lib/readline/display.c b/lib/readline/display.c index c47cf1f37..11f6019ca 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -1319,7 +1319,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (tempwidth > 0) { - int count; + int count, i; bytes = ret; for (count = 0; count < bytes; count++) putc (new[count], rl_outstream); @@ -1330,10 +1330,13 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (ret != 0 && bytes != 0) { if (MB_INVALIDCH (ret)) - memmove (old+bytes, old+1, strlen (old+1)); - else - memmove (old+bytes, old+ret, strlen (old+ret)); + ret = 1; + memmove (old+bytes, old+ret, strlen (old+ret)); memcpy (old, new, bytes); + /* Fix up indices if we copy data from one line to another */ + omax += bytes - ret; + for (i = current_line+1; i < inv_botlin+1; i++) + vis_lbreaks[i] += bytes - ret; } } else diff --git a/lib/readline/display.c~ b/lib/readline/display.c~ index 32f96de72..b13bd409f 100644 --- a/lib/readline/display.c~ +++ b/lib/readline/display.c~ @@ -960,6 +960,11 @@ rl_redisplay () #define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) #define INV_LINE(line) (invisible_line + inv_lbreaks[line]) +#define OLD_CPOS_IN_PROMPT() (cpos_adjusted == 0 && \ + _rl_last_c_pos != o_cpos && \ + _rl_last_c_pos > wrap_offset && \ + o_cpos < prompt_last_invisible) + /* For each line in the buffer, do the updating display. */ for (linenum = 0; linenum <= inv_botlin; linenum++) { @@ -982,13 +987,7 @@ rl_redisplay () time update_line is called, then we can assume in our calculations that o_cpos does not need to be adjusted by wrap_offset. */ - /* XXX - if this is changed, change the version down below in - the horizontal scrolling section as well. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) + if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT()) _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && @@ -1205,14 +1204,8 @@ rl_redisplay () _rl_screenwidth + (lmargin ? 0 : wrap_offset), 0); - /* This should be identical to the code above in the non-horizontal - scrolling section. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ + if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT()) + _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ /* If the visible new line is shorter than the old, but the number of invisible characters is greater, and we are at the end of @@ -1326,7 +1319,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (tempwidth > 0) { - int count; + int count, i; bytes = ret; for (count = 0; count < bytes; count++) putc (new[count], rl_outstream); @@ -1337,10 +1330,15 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (ret != 0 && bytes != 0) { if (MB_INVALIDCH (ret)) - memmove (old+bytes, old+1, strlen (old+1)); - else - memmove (old+bytes, old+ret, strlen (old+ret)); + ret = 1; + memmove (old+bytes, old+ret, strlen (old+ret)); memcpy (old, new, bytes); +#if 0 + /* Fix up indices if we copy data from one line to another */ + omax += bytes - ret; + for (i = current_line+1; i < inv_botlin+1; i++) + vis_lbreaks[i] += bytes - ret; +#endif } } else @@ -1906,6 +1904,7 @@ _rl_move_cursor_relative (new, data) register int i; int woff; /* number of invisible chars on current line */ int cpos, dpos; /* current and desired cursor positions */ + int adjust; woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); cpos = _rl_last_c_pos; @@ -1921,15 +1920,34 @@ _rl_move_cursor_relative (new, data) as long as we are past them and they are counted by _rl_col_width. */ if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - dpos = _rl_col_width (data, 0, new); + adjust = 1; + /* Try to short-circuit common cases and eliminate a bunch of multibyte + character function calls. */ + /* 1. prompt string */ + if (new == local_prompt_len && memcmp (data, local_prompt, new) == 0) + { + dpos = prompt_visible_length; + cpos_adjusted = 1; + adjust = 0; + } + /* 2. prompt_string + line contents */ + else if (new > local_prompt_len && local_prompt && memcmp (data, local_prompt, local_prompt_len) == 0) + { + dpos = prompt_visible_length + _rl_col_width (data, local_prompt_len, new); + cpos_adjusted = 1; + adjust = 0; + } + else + dpos = _rl_col_width (data, 0, new); + /* Use NEW when comparing against the last invisible character in the prompt string, since they're both buffer indices and DPOS is a desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ + if (adjust && ((new > prompt_last_invisible) || /* XXX - don't use woff here */ (prompt_physical_chars >= _rl_screenwidth && _rl_last_v_pos == prompt_last_screen_line && wrap_offset >= woff && dpos >= woff && - new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))) + new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset)))) /* XXX last comparison might need to be >= */ { dpos -= woff; @@ -2593,6 +2611,20 @@ _rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); point = 0; max = end; + /* Try to short-circuit common cases. The adjustment to remove wrap_offset + is done by the caller. */ + /* 1. prompt string */ + if (start == 0 && end == local_prompt_len && memcmp (str, local_prompt, local_prompt_len) == 0) + return (prompt_visible_length + wrap_offset); + /* 2. prompt string + line contents */ + else if (start == 0 && end > local_prompt_len && local_prompt && memcmp (str, local_prompt, local_prompt_len) == 0) + { + tmp = prompt_visible_length + wrap_offset; + /* XXX - try to call ourselves recursively with non-prompt portion */ + tmp += _rl_col_width (str, local_prompt_len, end); + return (tmp); + } + while (point < start) { tmp = mbrlen (str + point, max, &ps); diff --git a/lib/readline/doc/readline.3 b/lib/readline/doc/readline.3 index 5d72952a8..0daa09a47 100644 --- a/lib/readline/doc/readline.3 +++ b/lib/readline/doc/readline.3 @@ -6,9 +6,9 @@ .\" Case Western Reserve University .\" chet@ins.CWRU.Edu .\" -.\" Last Change: Thu May 8 09:29:59 EDT 2008 +.\" Last Change: Thu Jul 30 09:22:50 EDT 2009 .\" -.TH READLINE 3 "2008 May 8" "GNU Readline 6.0" +.TH READLINE 3 "2009 Jul 30" "GNU Readline 6.0" .\" .\" File Name macro. This used to be `.PN', for Path Name, .\" but Sun doesn't seem to like that very much. @@ -924,6 +924,11 @@ through the list. This command is intended to be bound to \fBTAB\fP, but is unbound by default. .TP +.B menu\-complete-\backward +Identical to \fBmenu\-complete\fP, but moves backward through the list +of possible completions, as if \fBmenu\-complete\fP had been given a +negative argument. This command is unbound by default. +.TP .B delete\-char\-or\-list Deletes the character under the cursor if not at the beginning or end of the line (like \fBdelete-char\fP). diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi index c98d3b9b5..845f277e7 100644 --- a/lib/readline/doc/rltech.texi +++ b/lib/readline/doc/rltech.texi @@ -622,7 +622,7 @@ Readline which keymap to use. @deftypefun Keymap rl_make_bare_keymap (void) Returns a new, empty keymap. The space for the keymap is allocated with @code{malloc()}; the caller should free it by calling -@code{rl_discard_keymap()} when done. +@code{rl_free_keymap()} when done. @end deftypefun @deftypefun Keymap rl_copy_keymap (Keymap map) @@ -636,7 +636,13 @@ the Meta digits bound to produce numeric arguments. @end deftypefun @deftypefun void rl_discard_keymap (Keymap keymap) -Free the storage associated with @var{keymap}. +Free the storage associated with the data in @var{keymap}. +The caller should free @var{keymap}. +@end deftypefun + +@deftypefun void rl_free_keymap (Keymap keymap) +Free all storage associated with @var{keymap}. This calls +@code{rl_discard_keymap} to free subordindate keymaps and macros. @end deftypefun Readline has several internal keymaps. These functions allow you to diff --git a/lib/readline/doc/rltech.texi~ b/lib/readline/doc/rltech.texi~ new file mode 100644 index 000000000..11291e709 --- /dev/null +++ b/lib/readline/doc/rltech.texi~ @@ -0,0 +1,2385 @@ +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rltech.info +@comment %**end of header (This is for running Texinfo on a region.) + +@ifinfo +This document describes the GNU Readline Library, a utility for aiding +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +Copyright (C) 1988-2007 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@node Programming with GNU Readline +@chapter Programming with GNU Readline + +This chapter describes the interface between the @sc{gnu} Readline Library and +other programs. If you are a programmer, and you wish to include the +features found in @sc{gnu} Readline +such as completion, line editing, and interactive history manipulation +in your own programs, this section is for you. + +@menu +* Basic Behavior:: Using the default behavior of Readline. +* Custom Functions:: Adding your own functions to Readline. +* Readline Variables:: Variables accessible to custom + functions. +* Readline Convenience Functions:: Functions which Readline supplies to + aid in writing your own custom + functions. +* Readline Signal Handling:: How Readline behaves when it receives signals. +* Custom Completers:: Supplanting or supplementing Readline's + completion functions. +@end menu + +@node Basic Behavior +@section Basic Behavior + +Many programs provide a command line interface, such as @code{mail}, +@code{ftp}, and @code{sh}. For such programs, the default behaviour of +Readline is sufficient. This section describes how to use Readline in +the simplest way possible, perhaps to replace calls in your code to +@code{gets()} or @code{fgets()}. + +@findex readline +@cindex readline, function + +The function @code{readline()} prints a prompt @var{prompt} +and then reads and returns a single line of text from the user. +If @var{prompt} is @code{NULL} or the empty string, no prompt is displayed. +The line @code{readline} returns is allocated with @code{malloc()}; +the caller should @code{free()} the line when it has finished with it. +The declaration for @code{readline} in ANSI C is + +@example +@code{char *readline (const char *@var{prompt});} +@end example + +@noindent +So, one might say +@example +@code{char *line = readline ("Enter a line: ");} +@end example +@noindent +in order to read a line of text from the user. +The line returned has the final newline removed, so only the +text remains. + +If @code{readline} encounters an @code{EOF} while reading the line, and the +line is empty at that point, then @code{(char *)NULL} is returned. +Otherwise, the line is ended just as if a newline had been typed. + +If you want the user to be able to get at the line later, (with +@key{C-p} for example), you must call @code{add_history()} to save the +line away in a @dfn{history} list of such lines. + +@example +@code{add_history (line)}; +@end example + +@noindent +For full details on the GNU History Library, see the associated manual. + +It is preferable to avoid saving empty lines on the history list, since +users rarely have a burning need to reuse a blank line. Here is +a function which usefully replaces the standard @code{gets()} library +function, and has the advantage of no static buffer to overflow: + +@example +/* A static variable for holding the line. */ +static char *line_read = (char *)NULL; + +/* Read a string, and return a pointer to it. + Returns NULL on EOF. */ +char * +rl_gets () +@{ + /* If the buffer has already been allocated, + return the memory to the free pool. */ + if (line_read) + @{ + free (line_read); + line_read = (char *)NULL; + @} + + /* Get a line from the user. */ + line_read = readline (""); + + /* If the line has any text in it, + save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +@} +@end example + +This function gives the user the default behaviour of @key{TAB} +completion: completion on file names. If you do not want Readline to +complete on filenames, you can change the binding of the @key{TAB} key +with @code{rl_bind_key()}. + +@example +@code{int rl_bind_key (int @var{key}, rl_command_func_t *@var{function});} +@end example + +@code{rl_bind_key()} takes two arguments: @var{key} is the character that +you want to bind, and @var{function} is the address of the function to +call when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert()} +makes @key{TAB} insert itself. +@code{rl_bind_key()} returns non-zero if @var{key} is not a valid +ASCII character code (between 0 and 255). + +Thus, to disable the default @key{TAB} behavior, the following suffices: +@example +@code{rl_bind_key ('\t', rl_insert);} +@end example + +This code should be executed once at the start of your program; you +might write a function called @code{initialize_readline()} which +performs this and other desired initializations, such as installing +custom completers (@pxref{Custom Completers}). + +@node Custom Functions +@section Custom Functions + +Readline provides many functions for manipulating the text of +the line, but it isn't possible to anticipate the needs of all +programs. This section describes the various functions and variables +defined within the Readline library which allow a user program to add +customized functionality to Readline. + +Before declaring any functions that customize Readline's behavior, or +using any functionality Readline provides in other code, an +application writer should include the file @code{} +in any file that uses Readline's features. Since some of the definitions +in @code{readline.h} use the @code{stdio} library, the file +@code{} should be included before @code{readline.h}. + +@code{readline.h} defines a C preprocessor variable that should +be treated as an integer, @code{RL_READLINE_VERSION}, which may +be used to conditionally compile application code depending on +the installed Readline version. The value is a hexadecimal +encoding of the major and minor version numbers of the library, +of the form 0x@var{MMmm}. @var{MM} is the two-digit major +version number; @var{mm} is the two-digit minor version number. +For Readline 4.2, for example, the value of +@code{RL_READLINE_VERSION} would be @code{0x0402}. + +@menu +* Readline Typedefs:: C declarations to make code readable. +* Function Writing:: Variables and calling conventions. +@end menu + +@node Readline Typedefs +@subsection Readline Typedefs + +For readabilty, we declare a number of new object types, all pointers +to functions. + +The reason for declaring these new types is to make it easier to write +code describing pointers to C functions with appropriately prototyped +arguments and return values. + +For instance, say we want to declare a variable @var{func} as a pointer +to a function which takes two @code{int} arguments and returns an +@code{int} (this is the type of all of the Readline bindable functions). +Instead of the classic C declaration + +@code{int (*func)();} + +@noindent +or the ANSI-C style declaration + +@code{int (*func)(int, int);} + +@noindent +we may write + +@code{rl_command_func_t *func;} + +The full list of function pointer types available is + +@table @code +@item typedef int rl_command_func_t (int, int); + +@item typedef char *rl_compentry_func_t (const char *, int); + +@item typedef char **rl_completion_func_t (const char *, int, int); + +@item typedef char *rl_quote_func_t (char *, int, char *); + +@item typedef char *rl_dequote_func_t (char *, int); + +@item typedef int rl_compignore_func_t (char **); + +@item typedef void rl_compdisp_func_t (char **, int, int); + +@item typedef int rl_hook_func_t (void); + +@item typedef int rl_getc_func_t (FILE *); + +@item typedef int rl_linebuf_func_t (char *, int); + +@item typedef int rl_intfunc_t (int); +@item #define rl_ivoidfunc_t rl_hook_func_t +@item typedef int rl_icpfunc_t (char *); +@item typedef int rl_icppfunc_t (char **); + +@item typedef void rl_voidfunc_t (void); +@item typedef void rl_vintfunc_t (int); +@item typedef void rl_vcpfunc_t (char *); +@item typedef void rl_vcppfunc_t (char **); + +@end table + +@node Function Writing +@subsection Writing a New Function + +In order to write new functions for Readline, you need to know the +calling conventions for keyboard-invoked functions, and the names of the +variables that describe the current state of the line read so far. + +The calling sequence for a command @code{foo} looks like + +@example +@code{int foo (int count, int key)} +@end example + +@noindent +where @var{count} is the numeric argument (or 1 if defaulted) and +@var{key} is the key that invoked this function. + +It is completely up to the function as to what should be done with the +numeric argument. Some functions use it as a repeat count, some +as a flag, and others to choose alternate behavior (refreshing the current +line as opposed to refreshing the screen, for example). Some choose to +ignore it. In general, if a +function uses the numeric argument as a repeat count, it should be able +to do something useful with both negative and positive arguments. +At the very least, it should be aware that it can be passed a +negative argument. + +A command function should return 0 if its action completes successfully, +and a non-zero value if some error occurs. +This is the convention obeyed by all of the builtin Readline bindable +command functions. + +@node Readline Variables +@section Readline Variables + +These variables are available to function writers. + +@deftypevar {char *} rl_line_buffer +This is the line gathered so far. You are welcome to modify the +contents of the line, but see @ref{Allowing Undoing}. The +function @code{rl_extend_line_buffer} is available to increase +the memory allocated to @code{rl_line_buffer}. +@end deftypevar + +@deftypevar int rl_point +The offset of the current cursor position in @code{rl_line_buffer} +(the @emph{point}). +@end deftypevar + +@deftypevar int rl_end +The number of characters present in @code{rl_line_buffer}. When +@code{rl_point} is at the end of the line, @code{rl_point} and +@code{rl_end} are equal. +@end deftypevar + +@deftypevar int rl_mark +The @var{mark} (saved position) in the current line. If set, the mark +and point define a @emph{region}. +@end deftypevar + +@deftypevar int rl_done +Setting this to a non-zero value causes Readline to return the current +line immediately. +@end deftypevar + +@deftypevar int rl_num_chars_to_read +Setting this to a positive value before calling @code{readline()} causes +Readline to return after accepting that many characters, rather +than reading up to a character bound to @code{accept-line}. +@end deftypevar + +@deftypevar int rl_pending_input +Setting this to a value makes it the next keystroke read. This is a +way to stuff a single character into the input stream. +@end deftypevar + +@deftypevar int rl_dispatching +Set to a non-zero value if a function is being called from a key binding; +zero otherwise. Application functions can test this to discover whether +they were called directly or by Readline's dispatching mechanism. +@end deftypevar + +@deftypevar int rl_erase_empty_line +Setting this to a non-zero value causes Readline to completely erase +the current line, including any prompt, any time a newline is typed as +the only character on an otherwise-empty line. The cursor is moved to +the beginning of the newly-blank line. +@end deftypevar + +@deftypevar {char *} rl_prompt +The prompt Readline uses. This is set from the argument to +@code{readline()}, and should not be assigned to directly. +The @code{rl_set_prompt()} function (@pxref{Redisplay}) may +be used to modify the prompt string after calling @code{readline()}. +@end deftypevar + +@deftypevar {char *} rl_display_prompt +The string displayed as the prompt. This is usually identical to +@var{rl_prompt}, but may be changed temporarily by functions that +use the prompt string as a message area, such as incremental search. +@end deftypevar + +@deftypevar int rl_already_prompted +If an application wishes to display the prompt itself, rather than have +Readline do it the first time @code{readline()} is called, it should set +this variable to a non-zero value after displaying the prompt. +The prompt must also be passed as the argument to @code{readline()} so +the redisplay functions can update the display properly. +The calling application is responsible for managing the value; Readline +never sets it. +@end deftypevar + +@deftypevar {const char *} rl_library_version +The version number of this revision of the library. +@end deftypevar + +@deftypevar int rl_readline_version +An integer encoding the current version of the library. The encoding is +of the form 0x@var{MMmm}, where @var{MM} is the two-digit major version +number, and @var{mm} is the two-digit minor version number. +For example, for Readline-4.2, @code{rl_readline_version} would have the +value 0x0402. +@end deftypevar + +@deftypevar {int} rl_gnu_readline_p +Always set to 1, denoting that this is @sc{gnu} readline rather than some +emulation. +@end deftypevar + +@deftypevar {const char *} rl_terminal_name +The terminal type, used for initialization. If not set by the application, +Readline sets this to the value of the @env{TERM} environment variable +the first time it is called. +@end deftypevar + +@deftypevar {const char *} rl_readline_name +This variable is set to a unique name by each application using Readline. +The value allows conditional parsing of the inputrc file +(@pxref{Conditional Init Constructs}). +@end deftypevar + +@deftypevar {FILE *} rl_instream +The stdio stream from which Readline reads input. +If @code{NULL}, Readline defaults to @var{stdin}. +@end deftypevar + +@deftypevar {FILE *} rl_outstream +The stdio stream to which Readline performs output. +If @code{NULL}, Readline defaults to @var{stdout}. +@end deftypevar + +@deftypevar int rl_prefer_env_winsize +If non-zero, Readline gives values found in the @env{LINES} and +@env{COLUMNS} environment variables greater precedence than values fetched +from the kernel when computing the screen dimensions. +@end deftypevar + +@deftypevar {rl_command_func_t *} rl_last_func +The address of the last command function Readline executed. May be used to +test whether or not a function is being executed twice in succession, for +example. +@end deftypevar + +@deftypevar {rl_hook_func_t *} rl_startup_hook +If non-zero, this is the address of a function to call just +before @code{readline} prints the first prompt. +@end deftypevar + +@deftypevar {rl_hook_func_t *} rl_pre_input_hook +If non-zero, this is the address of a function to call after +the first prompt has been printed and just before @code{readline} +starts reading input characters. +@end deftypevar + +@deftypevar {rl_hook_func_t *} rl_event_hook +If non-zero, this is the address of a function to call periodically +when Readline is waiting for terminal input. +By default, this will be called at most ten times a second if there +is no keyboard input. +@end deftypevar + +@deftypevar {rl_getc_func_t *} rl_getc_function +If non-zero, Readline will call indirectly through this pointer +to get a character from the input stream. By default, it is set to +@code{rl_getc}, the default Readline character input function +(@pxref{Character Input}). +@end deftypevar + +@deftypevar {rl_voidfunc_t *} rl_redisplay_function +If non-zero, Readline will call indirectly through this pointer +to update the display with the current contents of the editing buffer. +By default, it is set to @code{rl_redisplay}, the default Readline +redisplay function (@pxref{Redisplay}). +@end deftypevar + +@deftypevar {rl_vintfunc_t *} rl_prep_term_function +If non-zero, Readline will call indirectly through this pointer +to initialize the terminal. The function takes a single argument, an +@code{int} flag that says whether or not to use eight-bit characters. +By default, this is set to @code{rl_prep_terminal} +(@pxref{Terminal Management}). +@end deftypevar + +@deftypevar {rl_voidfunc_t *} rl_deprep_term_function +If non-zero, Readline will call indirectly through this pointer +to reset the terminal. This function should undo the effects of +@code{rl_prep_term_function}. +By default, this is set to @code{rl_deprep_terminal} +(@pxref{Terminal Management}). +@end deftypevar + +@deftypevar {Keymap} rl_executing_keymap +This variable is set to the keymap (@pxref{Keymaps}) in which the +currently executing readline function was found. +@end deftypevar + +@deftypevar {Keymap} rl_binding_keymap +This variable is set to the keymap (@pxref{Keymaps}) in which the +last key binding occurred. +@end deftypevar + +@deftypevar {char *} rl_executing_macro +This variable is set to the text of any currently-executing macro. +@end deftypevar + +@deftypevar {int} rl_readline_state +A variable with bit values that encapsulate the current Readline state. +A bit is set with the @code{RL_SETSTATE} macro, and unset with the +@code{RL_UNSETSTATE} macro. Use the @code{RL_ISSTATE} macro to test +whether a particular state bit is set. Current state bits include: + +@table @code +@item RL_STATE_NONE +Readline has not yet been called, nor has it begun to intialize. +@item RL_STATE_INITIALIZING +Readline is initializing its internal data structures. +@item RL_STATE_INITIALIZED +Readline has completed its initialization. +@item RL_STATE_TERMPREPPED +Readline has modified the terminal modes to do its own input and redisplay. +@item RL_STATE_READCMD +Readline is reading a command from the keyboard. +@item RL_STATE_METANEXT +Readline is reading more input after reading the meta-prefix character. +@item RL_STATE_DISPATCHING +Readline is dispatching to a command. +@item RL_STATE_MOREINPUT +Readline is reading more input while executing an editing command. +@item RL_STATE_ISEARCH +Readline is performing an incremental history search. +@item RL_STATE_NSEARCH +Readline is performing a non-incremental history search. +@item RL_STATE_SEARCH +Readline is searching backward or forward through the history for a string. +@item RL_STATE_NUMERICARG +Readline is reading a numeric argument. +@item RL_STATE_MACROINPUT +Readline is currently getting its input from a previously-defined keyboard +macro. +@item RL_STATE_MACRODEF +Readline is currently reading characters defining a keyboard macro. +@item RL_STATE_OVERWRITE +Readline is in overwrite mode. +@item RL_STATE_COMPLETING +Readline is performing word completion. +@item RL_STATE_SIGHANDLER +Readline is currently executing the readline signal handler. +@item RL_STATE_UNDOING +Readline is performing an undo. +@item RL_STATE_INPUTPENDING +Readline has input pending due to a call to @code{rl_execute_next()}. +@item RL_STATE_TTYCSAVED +Readline has saved the values of the terminal's special characters. +@item RL_STATE_CALLBACK +Readline is currently using the alternate (callback) interface +(@pxref{Alternate Interface}). +@item RL_STATE_VIMOTION +Readline is reading the argument to a vi-mode "motion" command. +@item RL_STATE_MULTIKEY +Readline is reading a multiple-keystroke command. +@item RL_STATE_VICMDONCE +Readline has entered vi command (movement) mode at least one time during +the current call to @code{readline()}. +@item RL_STATE_DONE +Readline has read a key sequence bound to @code{accept-line} +and is about to return the line to the caller. +@end table + +@end deftypevar + +@deftypevar {int} rl_explicit_arg +Set to a non-zero value if an explicit numeric argument was specified by +the user. Only valid in a bindable command function. +@end deftypevar + +@deftypevar {int} rl_numeric_arg +Set to the value of any numeric argument explicitly specified by the user +before executing the current Readline function. Only valid in a bindable +command function. +@end deftypevar + +@deftypevar {int} rl_editing_mode +Set to a value denoting Readline's current editing mode. A value of +@var{1} means Readline is currently in emacs mode; @var{0} +means that vi mode is active. +@end deftypevar + + +@node Readline Convenience Functions +@section Readline Convenience Functions + +@menu +* Function Naming:: How to give a function you write a name. +* Keymaps:: Making keymaps. +* Binding Keys:: Changing Keymaps. +* Associating Function Names and Bindings:: Translate function names to + key sequences. +* Allowing Undoing:: How to make your functions undoable. +* Redisplay:: Functions to control line display. +* Modifying Text:: Functions to modify @code{rl_line_buffer}. +* Character Input:: Functions to read keyboard input. +* Terminal Management:: Functions to manage terminal settings. +* Utility Functions:: Generally useful functions and hooks. +* Miscellaneous Functions:: Functions that don't fall into any category. +* Alternate Interface:: Using Readline in a `callback' fashion. +* A Readline Example:: An example Readline function. +@end menu + +@node Function Naming +@subsection Naming a Function + +The user can dynamically change the bindings of keys while using +Readline. This is done by representing the function with a descriptive +name. The user is able to type the descriptive name when referring to +the function. Thus, in an init file, one might find + +@example +Meta-Rubout: backward-kill-word +@end example + +This binds the keystroke @key{Meta-Rubout} to the function +@emph{descriptively} named @code{backward-kill-word}. You, as the +programmer, should bind the functions you write to descriptive names as +well. Readline provides a function for doing that: + +@deftypefun int rl_add_defun (const char *name, rl_command_func_t *function, int key) +Add @var{name} to the list of named functions. Make @var{function} be +the function that gets called. If @var{key} is not -1, then bind it to +@var{function} using @code{rl_bind_key()}. +@end deftypefun + +Using this function alone is sufficient for most applications. +It is the recommended way to add a few functions to the default +functions that Readline has built in. +If you need to do something other than adding a function to Readline, +you may need to use the underlying functions described below. + +@node Keymaps +@subsection Selecting a Keymap + +Key bindings take place on a @dfn{keymap}. The keymap is the +association between the keys that the user types and the functions that +get run. You can make your own keymaps, copy existing keymaps, and tell +Readline which keymap to use. + +@deftypefun Keymap rl_make_bare_keymap (void) +Returns a new, empty keymap. The space for the keymap is allocated with +@code{malloc()}; the caller should free it by calling +@code{rl_discard_keymap()} when done. +@end deftypefun + +@deftypefun Keymap rl_copy_keymap (Keymap map) +Return a new keymap which is a copy of @var{map}. +@end deftypefun + +@deftypefun Keymap rl_make_keymap (void) +Return a new keymap with the printing characters bound to rl_insert, +the lowercase Meta characters bound to run their equivalents, and +the Meta digits bound to produce numeric arguments. +@end deftypefun + +@deftypefun void rl_discard_keymap (Keymap keymap) +Free the storage associated with the data in @var{keymap}. +The caller should free @var{keymap}. +@end deftypefun + +@deftypefun void rl_free_keymap (Keymap keymap) +Free all storage associated with @var{keymap}. +@end deftypefun + +Readline has several internal keymaps. These functions allow you to +change which keymap is active. + +@deftypefun Keymap rl_get_keymap (void) +Returns the currently active keymap. +@end deftypefun + +@deftypefun void rl_set_keymap (Keymap keymap) +Makes @var{keymap} the currently active keymap. +@end deftypefun + +@deftypefun Keymap rl_get_keymap_by_name (const char *name) +Return the keymap matching @var{name}. @var{name} is one which would +be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}). +@end deftypefun + +@deftypefun {char *} rl_get_keymap_name (Keymap keymap) +Return the name matching @var{keymap}. @var{name} is one which would +be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}). +@end deftypefun + +@node Binding Keys +@subsection Binding Keys + +Key sequences are associate with functions through the keymap. +Readline has several internal keymaps: @code{emacs_standard_keymap}, +@code{emacs_meta_keymap}, @code{emacs_ctlx_keymap}, +@code{vi_movement_keymap}, and @code{vi_insertion_keymap}. +@code{emacs_standard_keymap} is the default, and the examples in +this manual assume that. + +Since @code{readline()} installs a set of default key bindings the first +time it is called, there is always the danger that a custom binding +installed before the first call to @code{readline()} will be overridden. +An alternate mechanism is to install custom key bindings in an +initialization function assigned to the @code{rl_startup_hook} variable +(@pxref{Readline Variables}). + +These functions manage key bindings. + +@deftypefun int rl_bind_key (int key, rl_command_func_t *function) +Binds @var{key} to @var{function} in the currently active keymap. +Returns non-zero in the case of an invalid @var{key}. +@end deftypefun + +@deftypefun int rl_bind_key_in_map (int key, rl_command_func_t *function, Keymap map) +Bind @var{key} to @var{function} in @var{map}. +Returns non-zero in the case of an invalid @var{key}. +@end deftypefun + +@deftypefun int rl_bind_key_if_unbound (int key, rl_command_func_t *function) +Binds @var{key} to @var{function} if it is not already bound in the +currently active keymap. +Returns non-zero in the case of an invalid @var{key} or if @var{key} is +already bound. +@end deftypefun + +@deftypefun int rl_bind_key_if_unbound_in_map (int key, rl_command_func_t *function, Keymap map) +Binds @var{key} to @var{function} if it is not already bound in @var{map}. +Returns non-zero in the case of an invalid @var{key} or if @var{key} is +already bound. +@end deftypefun + +@deftypefun int rl_unbind_key (int key) +Bind @var{key} to the null function in the currently active keymap. +Returns non-zero in case of error. +@end deftypefun + +@deftypefun int rl_unbind_key_in_map (int key, Keymap map) +Bind @var{key} to the null function in @var{map}. +Returns non-zero in case of error. +@end deftypefun + +@deftypefun int rl_unbind_function_in_map (rl_command_func_t *function, Keymap map) +Unbind all keys that execute @var{function} in @var{map}. +@end deftypefun + +@deftypefun int rl_unbind_command_in_map (const char *command, Keymap map) +Unbind all keys that are bound to @var{command} in @var{map}. +@end deftypefun + +@deftypefun int rl_bind_keyseq (const char *keyseq, rl_command_func_t *function) +Bind the key sequence represented by the string @var{keyseq} to the function +@var{function}, beginning in the current keymap. +This makes new keymaps as necessary. +The return value is non-zero if @var{keyseq} is invalid. +@end deftypefun + +@deftypefun int rl_bind_keyseq_in_map (const char *keyseq, rl_command_func_t *function, Keymap map) +Bind the key sequence represented by the string @var{keyseq} to the function +@var{function}. This makes new keymaps as necessary. +Initial bindings are performed in @var{map}. +The return value is non-zero if @var{keyseq} is invalid. +@end deftypefun + +@deftypefun int rl_set_key (const char *keyseq, rl_command_func_t *function, Keymap map) +Equivalent to @code{rl_bind_keyseq_in_map}. +@end deftypefun + +@deftypefun int rl_bind_keyseq_if_unbound (const char *keyseq, rl_command_func_t *function) +Binds @var{keyseq} to @var{function} if it is not already bound in the +currently active keymap. +Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is +already bound. +@end deftypefun + +@deftypefun int rl_bind_keyseq_if_unbound_in_map (const char *keyseq, rl_command_func_t *function, Keymap map) +Binds @var{keyseq} to @var{function} if it is not already bound in @var{map}. +Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is +already bound. +@end deftypefun + +@deftypefun int rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) +Bind the key sequence represented by the string @var{keyseq} to the arbitrary +pointer @var{data}. @var{type} says what kind of data is pointed to by +@var{data}; this can be a function (@code{ISFUNC}), a macro +(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as +necessary. The initial keymap in which to do bindings is @var{map}. +@end deftypefun + +@deftypefun int rl_parse_and_bind (char *line) +Parse @var{line} as if it had been read from the @code{inputrc} file and +perform any key bindings and variable assignments found +(@pxref{Readline Init File}). +@end deftypefun + +@deftypefun int rl_read_init_file (const char *filename) +Read keybindings and variable assignments from @var{filename} +(@pxref{Readline Init File}). +@end deftypefun + +@node Associating Function Names and Bindings +@subsection Associating Function Names and Bindings + +These functions allow you to find out what keys invoke named functions +and the functions invoked by a particular key sequence. You may also +associate a new function name with an arbitrary function. + +@deftypefun {rl_command_func_t *} rl_named_function (const char *name) +Return the function with name @var{name}. +@end deftypefun + +@deftypefun {rl_command_func_t *} rl_function_of_keyseq (const char *keyseq, Keymap map, int *type) +Return the function invoked by @var{keyseq} in keymap @var{map}. +If @var{map} is @code{NULL}, the current keymap is used. If @var{type} is +not @code{NULL}, the type of the object is returned in the @code{int} variable +it points to (one of @code{ISFUNC}, @code{ISKMAP}, or @code{ISMACR}). +@end deftypefun + +@deftypefun {char **} rl_invoking_keyseqs (rl_command_func_t *function) +Return an array of strings representing the key sequences used to +invoke @var{function} in the current keymap. +@end deftypefun + +@deftypefun {char **} rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map) +Return an array of strings representing the key sequences used to +invoke @var{function} in the keymap @var{map}. +@end deftypefun + +@deftypefun void rl_function_dumper (int readable) +Print the readline function names and the key sequences currently +bound to them to @code{rl_outstream}. If @var{readable} is non-zero, +the list is formatted in such a way that it can be made part of an +@code{inputrc} file and re-read. +@end deftypefun + +@deftypefun void rl_list_funmap_names (void) +Print the names of all bindable Readline functions to @code{rl_outstream}. +@end deftypefun + +@deftypefun {const char **} rl_funmap_names (void) +Return 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, but not the pointers, using @code{free} or +@code{rl_free} when you are done. +@end deftypefun + +@deftypefun int rl_add_funmap_entry (const char *name, rl_command_func_t *function) +Add @var{name} to the list of bindable Readline command names, and make +@var{function} the function to be called when @var{name} is invoked. +@end deftypefun + +@node Allowing Undoing +@subsection Allowing Undoing + +Supporting the undo command is a painless thing, and makes your +functions much more useful. It is certainly easy to try +something if you know you can undo it. + +If your function simply inserts text once, or deletes text once, and +uses @code{rl_insert_text()} or @code{rl_delete_text()} to do it, then +undoing is already done for you automatically. + +If you do multiple insertions or multiple deletions, or any combination +of these operations, you should group them together into one operation. +This is done with @code{rl_begin_undo_group()} and +@code{rl_end_undo_group()}. + +The types of events that can be undone are: + +@smallexample +enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @}; +@end smallexample + +Notice that @code{UNDO_DELETE} means to insert some text, and +@code{UNDO_INSERT} means to delete some text. That is, the undo code +tells what to undo, not how to undo it. @code{UNDO_BEGIN} and +@code{UNDO_END} are tags added by @code{rl_begin_undo_group()} and +@code{rl_end_undo_group()}. + +@deftypefun int rl_begin_undo_group (void) +Begins saving undo information in a group construct. The undo +information usually comes from calls to @code{rl_insert_text()} and +@code{rl_delete_text()}, but could be the result of calls to +@code{rl_add_undo()}. +@end deftypefun + +@deftypefun int rl_end_undo_group (void) +Closes the current undo group started with @code{rl_begin_undo_group +()}. There should be one call to @code{rl_end_undo_group()} +for each call to @code{rl_begin_undo_group()}. +@end deftypefun + +@deftypefun void rl_add_undo (enum undo_code what, int start, int end, char *text) +Remember how to undo an event (according to @var{what}). The affected +text runs from @var{start} to @var{end}, and encompasses @var{text}. +@end deftypefun + +@deftypefun void rl_free_undo_list (void) +Free the existing undo list. +@end deftypefun + +@deftypefun int rl_do_undo (void) +Undo the first thing on the undo list. Returns @code{0} if there was +nothing to undo, non-zero if something was undone. +@end deftypefun + +Finally, if you neither insert nor delete text, but directly modify the +existing text (e.g., change its case), call @code{rl_modifying()} +once, just before you modify the text. You must supply the indices of +the text range that you are going to modify. + +@deftypefun int rl_modifying (int start, int end) +Tell Readline to save the text between @var{start} and @var{end} as a +single undo unit. It is assumed that you will subsequently modify +that text. +@end deftypefun + +@node Redisplay +@subsection Redisplay + +@deftypefun void rl_redisplay (void) +Change what's displayed on the screen to reflect the current contents +of @code{rl_line_buffer}. +@end deftypefun + +@deftypefun int rl_forced_update_display (void) +Force the line to be updated and redisplayed, whether or not +Readline thinks the screen display is correct. +@end deftypefun + +@deftypefun int rl_on_new_line (void) +Tell the update functions that we have moved onto a new (empty) line, +usually after ouputting a newline. +@end deftypefun + +@deftypefun int rl_on_new_line_with_prompt (void) +Tell the update functions that we have moved onto a new line, with +@var{rl_prompt} already displayed. +This could be used by applications that want to output the prompt string +themselves, but still need Readline to know the prompt string length for +redisplay. +It should be used after setting @var{rl_already_prompted}. +@end deftypefun + +@deftypefun int rl_reset_line_state (void) +Reset the display state to a clean state and redisplay the current line +starting on a new line. +@end deftypefun + +@deftypefun int rl_crlf (void) +Move the cursor to the start of the next screen line. +@end deftypefun + +@deftypefun int rl_show_char (int c) +Display character @var{c} on @code{rl_outstream}. +If Readline has not been set to display meta characters directly, this +will convert meta characters to a meta-prefixed key sequence. +This is intended for use by applications which wish to do their own +redisplay. +@end deftypefun + +@deftypefun int rl_message (const char *, @dots{}) +The arguments are a format string as would be supplied to @code{printf}, +possibly containing conversion specifications such as @samp{%d}, and +any additional arguments necessary to satisfy the conversion specifications. +The resulting string is displayed in the @dfn{echo area}. The echo area +is also used to display numeric arguments and search strings. +You should call @code{rl_save_prompt} to save the prompt information +before calling this function. +@end deftypefun + +@deftypefun int rl_clear_message (void) +Clear the message in the echo area. If the prompt was saved with a call to +@code{rl_save_prompt} before the last call to @code{rl_message}, +call @code{rl_restore_prompt} before calling this function. +@end deftypefun + +@deftypefun void rl_save_prompt (void) +Save the local Readline prompt display state in preparation for +displaying a new message in the message area with @code{rl_message()}. +@end deftypefun + +@deftypefun void rl_restore_prompt (void) +Restore the local Readline prompt display state saved by the most +recent call to @code{rl_save_prompt}. +if @code{rl_save_prompt} was called to save the prompt before a call +to @code{rl_message}, this function should be called before the +corresponding call to @code{rl_clear_message}. +@end deftypefun + +@deftypefun int rl_expand_prompt (char *prompt) +Expand any special character sequences in @var{prompt} and set up the +local Readline prompt redisplay variables. +This function is called by @code{readline()}. It may also be called to +expand the primary prompt if the @code{rl_on_new_line_with_prompt()} +function or @code{rl_already_prompted} variable is used. +It returns the number of visible characters on the last line of the +(possibly multi-line) prompt. +Applications may indicate that the prompt contains characters that take +up no physical screen space when displayed by bracketing a sequence of +such characters with the special markers @code{RL_PROMPT_START_IGNORE} +and @code{RL_PROMPT_END_IGNORE} (declared in @file{readline.h}. This may +be used to embed terminal-specific escape sequences in prompts. +@end deftypefun + +@deftypefun int rl_set_prompt (const char *prompt) +Make Readline use @var{prompt} for subsequent redisplay. This calls +@code{rl_expand_prompt()} to expand the prompt and sets @code{rl_prompt} +to the result. +@end deftypefun + +@node Modifying Text +@subsection Modifying Text + +@deftypefun int rl_insert_text (const char *text) +Insert @var{text} into the line at the current cursor position. +Returns the number of characters inserted. +@end deftypefun + +@deftypefun int rl_delete_text (int start, int end) +Delete the text between @var{start} and @var{end} in the current line. +Returns the number of characters deleted. +@end deftypefun + +@deftypefun {char *} rl_copy_text (int start, int end) +Return a copy of the text between @var{start} and @var{end} in +the current line. +@end deftypefun + +@deftypefun int rl_kill_text (int start, int end) +Copy the text between @var{start} and @var{end} in the current line +to the kill ring, appending or prepending to the last kill if the +last command was a kill command. The text is deleted. +If @var{start} is less than @var{end}, +the text is appended, otherwise prepended. If the last command was +not a kill, a new kill ring slot is used. +@end deftypefun + +@deftypefun int rl_push_macro_input (char *macro) +Cause @var{macro} to be inserted into the line, as if it had been invoked +by a key bound to a macro. Not especially useful; use +@code{rl_insert_text()} instead. +@end deftypefun + +@node Character Input +@subsection Character Input + +@deftypefun int rl_read_key (void) +Return the next character available from Readline's current input stream. +This handles input inserted into +the input stream via @var{rl_pending_input} (@pxref{Readline Variables}) +and @code{rl_stuff_char()}, macros, and characters read from the keyboard. +While waiting for input, this function will call any function assigned to +the @code{rl_event_hook} variable. +@end deftypefun + +@deftypefun int rl_getc (FILE *stream) +Return the next character available from @var{stream}, which is assumed to +be the keyboard. +@end deftypefun + +@deftypefun int rl_stuff_char (int c) +Insert @var{c} into the Readline input stream. It will be "read" +before Readline attempts to read characters from the terminal with +@code{rl_read_key()}. Up to 512 characters may be pushed back. +@code{rl_stuff_char} returns 1 if the character was successfully inserted; +0 otherwise. +@end deftypefun + +@deftypefun int rl_execute_next (int c) +Make @var{c} be the next command to be executed when @code{rl_read_key()} +is called. This sets @var{rl_pending_input}. +@end deftypefun + +@deftypefun int rl_clear_pending_input (void) +Unset @var{rl_pending_input}, effectively negating the effect of any +previous call to @code{rl_execute_next()}. This works only if the +pending input has not already been read with @code{rl_read_key()}. +@end deftypefun + +@deftypefun int rl_set_keyboard_input_timeout (int u) +While waiting for keyboard input in @code{rl_read_key()}, Readline will +wait for @var{u} microseconds for input before calling any function +assigned to @code{rl_event_hook}. @var{u} must be greater than or equal +to zero (a zero-length timeout is equivalent to a poll). +The default waiting period is one-tenth of a second. +Returns the old timeout value. +@end deftypefun + +@node Terminal Management +@subsection Terminal Management + +@deftypefun void rl_prep_terminal (int meta_flag) +Modify the terminal settings for Readline's use, so @code{readline()} +can read a single character at a time from the keyboard. +The @var{meta_flag} argument should be non-zero if Readline should +read eight-bit input. +@end deftypefun + +@deftypefun void rl_deprep_terminal (void) +Undo the effects of @code{rl_prep_terminal()}, leaving the terminal in +the state in which it was before the most recent call to +@code{rl_prep_terminal()}. +@end deftypefun + +@deftypefun void rl_tty_set_default_bindings (Keymap kmap) +Read the operating system's terminal editing characters (as would be +displayed by @code{stty}) to their Readline equivalents. +The bindings are performed in @var{kmap}. +@end deftypefun + +@deftypefun void rl_tty_unset_default_bindings (Keymap kmap) +Reset the bindings manipulated by @code{rl_tty_set_default_bindings} so +that the terminal editing characters are bound to @code{rl_insert}. +The bindings are performed in @var{kmap}. +@end deftypefun + +@deftypefun int rl_reset_terminal (const char *terminal_name) +Reinitialize Readline's idea of the terminal settings using +@var{terminal_name} as the terminal type (e.g., @code{vt100}). +If @var{terminal_name} is @code{NULL}, the value of the @code{TERM} +environment variable is used. +@end deftypefun + +@node Utility Functions +@subsection Utility Functions + +@deftypefun int rl_save_state (struct readline_state *sp) +Save a snapshot of Readline's internal state to @var{sp}. +The contents of the @var{readline_state} structure are documented +in @file{readline.h}. +The caller is responsible for allocating the structure. +@end deftypefun + +@deftypefun int rl_restore_state (struct readline_state *sp) +Restore Readline's internal state to that stored in @var{sp}, which must +have been saved by a call to @code{rl_save_state}. +The contents of the @var{readline_state} structure are documented +in @file{readline.h}. +The caller is responsible for freeing the structure. +@end deftypefun + +@deftypefun void rl_free (void *mem) +Deallocate the memory pointed to by @var{mem}. @var{mem} must have been +allocated by @code{malloc}. +@end deftypefun + +@deftypefun void rl_replace_line (const char *text, int clear_undo) +Replace the contents of @code{rl_line_buffer} with @var{text}. +The point and mark are preserved, if possible. +If @var{clear_undo} is non-zero, the undo list associated with the +current line is cleared. +@end deftypefun + +@deftypefun void rl_extend_line_buffer (int len) +Ensure that @code{rl_line_buffer} has enough space to hold @var{len} +characters, possibly reallocating it if necessary. +@end deftypefun + +@deftypefun int rl_initialize (void) +Initialize or re-initialize Readline's internal state. +It's not strictly necessary to call this; @code{readline()} calls it before +reading any input. +@end deftypefun + +@deftypefun int rl_ding (void) +Ring the terminal bell, obeying the setting of @code{bell-style}. +@end deftypefun + +@deftypefun int rl_alphabetic (int c) +Return 1 if @var{c} is an alphabetic character. +@end deftypefun + +@deftypefun void rl_display_match_list (char **matches, int len, int max) +A convenience function for displaying a list of strings in +columnar format on Readline's output stream. @code{matches} is the list +of strings, in argv format, such as a list of completion matches. +@code{len} is the number of strings in @code{matches}, and @code{max} +is the length of the longest string in @code{matches}. This function uses +the setting of @code{print-completions-horizontally} to select how the +matches are displayed (@pxref{Readline Init File Syntax}). +@end deftypefun + +The following are implemented as macros, defined in @code{chardefs.h}. +Applications should refrain from using them. + +@deftypefun int _rl_uppercase_p (int c) +Return 1 if @var{c} is an uppercase alphabetic character. +@end deftypefun + +@deftypefun int _rl_lowercase_p (int c) +Return 1 if @var{c} is a lowercase alphabetic character. +@end deftypefun + +@deftypefun int _rl_digit_p (int c) +Return 1 if @var{c} is a numeric character. +@end deftypefun + +@deftypefun int _rl_to_upper (int c) +If @var{c} is a lowercase alphabetic character, return the corresponding +uppercase character. +@end deftypefun + +@deftypefun int _rl_to_lower (int c) +If @var{c} is an uppercase alphabetic character, return the corresponding +lowercase character. +@end deftypefun + +@deftypefun int _rl_digit_value (int c) +If @var{c} is a number, return the value it represents. +@end deftypefun + +@node Miscellaneous Functions +@subsection Miscellaneous Functions + +@deftypefun int rl_macro_bind (const char *keyseq, const char *macro, Keymap map) +Bind the key sequence @var{keyseq} to invoke the macro @var{macro}. +The binding is performed in @var{map}. When @var{keyseq} is invoked, the +@var{macro} will be inserted into the line. This function is deprecated; +use @code{rl_generic_bind()} instead. +@end deftypefun + +@deftypefun void rl_macro_dumper (int readable) +Print the key sequences bound to macros and their values, using +the current keymap, to @code{rl_outstream}. +If @var{readable} is non-zero, the list is formatted in such a way +that it can be made part of an @code{inputrc} file and re-read. +@end deftypefun + +@deftypefun int rl_variable_bind (const char *variable, const char *value) +Make the Readline variable @var{variable} have @var{value}. +This behaves as if the readline command +@samp{set @var{variable} @var{value}} had been executed in an @code{inputrc} +file (@pxref{Readline Init File Syntax}). +@end deftypefun + +@deftypefun {char *} rl_variable_value (const char *variable) +Return a string representing the value of the Readline variable @var{variable}. +For boolean variables, this string is either @samp{on} or @samp{off}. +@end deftypefun + +@deftypefun void rl_variable_dumper (int readable) +Print the readline variable names and their current values +to @code{rl_outstream}. +If @var{readable} is non-zero, the list is formatted in such a way +that it can be made part of an @code{inputrc} file and re-read. +@end deftypefun + +@deftypefun int rl_set_paren_blink_timeout (int u) +Set the time interval (in microseconds) that Readline waits when showing +a balancing character when @code{blink-matching-paren} has been enabled. +@end deftypefun + +@deftypefun {char *} rl_get_termcap (const char *cap) +Retrieve the string value of the termcap capability @var{cap}. +Readline fetches the termcap entry for the current terminal name and +uses those capabilities to move around the screen line and perform other +terminal-specific operations, like erasing a line. Readline does not +use all of a terminal's capabilities, and this function will return +values for only those capabilities Readline uses. +@end deftypefun + +@node Alternate Interface +@subsection Alternate Interface + +An alternate interface is available to plain @code{readline()}. Some +applications need to interleave keyboard I/O with file, device, or +window system I/O, typically by using a main loop to @code{select()} +on various file descriptors. To accomodate this need, readline can +also be invoked as a `callback' function from an event loop. There +are functions available to make this easy. + +@deftypefun void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler) +Set up the terminal for readline I/O and display the initial +expanded value of @var{prompt}. Save the value of @var{lhandler} to +use as a function to call when a complete line of input has been entered. +The function takes the text of the line as an argument. +@end deftypefun + +@deftypefun void rl_callback_read_char (void) +Whenever an application determines that keyboard input is available, it +should call @code{rl_callback_read_char()}, which will read the next +character from the current input source. +If that character completes the line, @code{rl_callback_read_char} will +invoke the @var{lhandler} function saved by @code{rl_callback_handler_install} +to process the line. +Before calling the @var{lhandler} function, the terminal settings are +reset to the values they had before calling +@code{rl_callback_handler_install}. +If the @var{lhandler} function returns, +the terminal settings are modified for Readline's use again. +@code{EOF} is indicated by calling @var{lhandler} with a +@code{NULL} line. +@end deftypefun + +@deftypefun void rl_callback_handler_remove (void) +Restore the terminal to its initial state and remove the line handler. +This may be called from within a callback as well as independently. +If the @var{lhandler} installed by @code{rl_callback_handler_install} +does not exit the program, either this function or the function referred +to by the value of @code{rl_deprep_term_function} should be called before +the program exits to reset the terminal settings. +@end deftypefun + +@node A Readline Example +@subsection A Readline Example + +Here is a function which changes lowercase characters to their uppercase +equivalents, and uppercase characters to lowercase. If +this function was bound to @samp{M-c}, then typing @samp{M-c} would +change the case of the character under point. Typing @samp{M-1 0 M-c} +would change the case of the following 10 characters, leaving the cursor on +the last character changed. + +@example +/* Invert the case of the COUNT following characters. */ +int +invert_case_line (count, key) + int count, key; +@{ + register int start, end, i; + + start = rl_point; + + if (rl_point >= rl_end) + return (0); + + if (count < 0) + @{ + direction = -1; + count = -count; + @} + else + direction = 1; + + /* Find the end of the range to modify. */ + end = start + (count * direction); + + /* Force it to be within range. */ + if (end > rl_end) + end = rl_end; + else if (end < 0) + end = 0; + + if (start == end) + return (0); + + if (start > end) + @{ + int temp = start; + start = end; + end = temp; + @} + + /* Tell readline that we are modifying the line, + so it will save the undo information. */ + rl_modifying (start, end); + + for (i = start; i != end; i++) + @{ + if (_rl_uppercase_p (rl_line_buffer[i])) + rl_line_buffer[i] = _rl_to_lower (rl_line_buffer[i]); + else if (_rl_lowercase_p (rl_line_buffer[i])) + rl_line_buffer[i] = _rl_to_upper (rl_line_buffer[i]); + @} + /* Move point to on top of the last character changed. */ + rl_point = (direction == 1) ? end - 1 : start; + return (0); +@} +@end example + +@node Readline Signal Handling +@section Readline Signal Handling + +Signals are asynchronous events sent to a process by the Unix kernel, +sometimes on behalf of another process. They are intended to indicate +exceptional events, like a user pressing the interrupt key on his terminal, +or a network connection being broken. There is a class of signals that can +be sent to the process currently reading input from the keyboard. Since +Readline changes the terminal attributes when it is called, it needs to +perform special processing when such a signal is received in order to +restore the terminal to a sane state, or provide application writers with +functions to do so manually. + +Readline contains an internal signal handler that is installed for a +number of signals (@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, +@code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}). +When one of these signals is received, the signal handler +will reset the terminal attributes to those that were in effect before +@code{readline()} was called, reset the signal handling to what it was +before @code{readline()} was called, and resend the signal to the calling +application. +If and when the calling application's signal handler returns, Readline +will reinitialize the terminal and continue to accept input. +When a @code{SIGINT} is received, the Readline signal handler performs +some additional work, which will cause any partially-entered line to be +aborted (see the description of @code{rl_free_line_state()} below). + +There is an additional Readline signal handler, for @code{SIGWINCH}, which +the kernel sends to a process whenever the terminal's size changes (for +example, if a user resizes an @code{xterm}). The Readline @code{SIGWINCH} +handler updates Readline's internal screen size information, and then calls +any @code{SIGWINCH} signal handler the calling application has installed. +Readline calls the application's @code{SIGWINCH} signal handler without +resetting the terminal to its original state. If the application's signal +handler does more than update its idea of the terminal size and return (for +example, a @code{longjmp} back to a main processing loop), it @emph{must} +call @code{rl_cleanup_after_signal()} (described below), to restore the +terminal state. + +Readline provides two variables that allow application writers to +control whether or not it will catch certain signals and act on them +when they are received. It is important that applications change the +values of these variables only when calling @code{readline()}, not in +a signal handler, so Readline's internal signal state is not corrupted. + +@deftypevar int rl_catch_signals +If this variable is non-zero, Readline will install signal handlers for +@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, @code{SIGALRM}, +@code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}. + +The default value of @code{rl_catch_signals} is 1. +@end deftypevar + +@deftypevar int rl_catch_sigwinch +If this variable is non-zero, Readline will install a signal handler for +@code{SIGWINCH}. + +The default value of @code{rl_catch_sigwinch} is 1. +@end deftypevar + +If an application does not wish to have Readline catch any signals, or +to handle signals other than those Readline catches (@code{SIGHUP}, +for example), +Readline provides convenience functions to do the necessary terminal +and internal state cleanup upon receipt of a signal. + +@deftypefun void rl_cleanup_after_signal (void) +This function will reset the state of the terminal to what it was before +@code{readline()} was called, and remove the Readline signal handlers for +all signals, depending on the values of @code{rl_catch_signals} and +@code{rl_catch_sigwinch}. +@end deftypefun + +@deftypefun void rl_free_line_state (void) +This will free any partial state associated with the current input line +(undo information, any partial history entry, any partially-entered +keyboard macro, and any partially-entered numeric argument). This +should be called before @code{rl_cleanup_after_signal()}. The +Readline signal handler for @code{SIGINT} calls this to abort the +current input line. +@end deftypefun + +@deftypefun void rl_reset_after_signal (void) +This will reinitialize the terminal and reinstall any Readline signal +handlers, depending on the values of @code{rl_catch_signals} and +@code{rl_catch_sigwinch}. +@end deftypefun + +If an application does not wish Readline to catch @code{SIGWINCH}, it may +call @code{rl_resize_terminal()} or @code{rl_set_screen_size()} to force +Readline to update its idea of the terminal size when a @code{SIGWINCH} +is received. + +@deftypefun void rl_echo_signal_char (int sig) +If an application wishes to install its own signal handlers, but still +have readline display characters that generate signals, calling this +function with @var{sig} set to @code{SIGINT}, @code{SIGQUIT}, or +@code{SIGTSTP} will display the character generating that signal. +@end deftypefun + +@deftypefun void rl_resize_terminal (void) +Update Readline's internal screen size by reading values from the kernel. +@end deftypefun + +@deftypefun void rl_set_screen_size (int rows, int cols) +Set Readline's idea of the terminal size to @var{rows} rows and +@var{cols} columns. If either @var{rows} or @var{columns} is less than +or equal to 0, Readline's idea of that terminal dimension is unchanged. +@end deftypefun + +If an application does not want to install a @code{SIGWINCH} handler, but +is still interested in the screen dimensions, Readline's idea of the screen +size may be queried. + +@deftypefun void rl_get_screen_size (int *rows, int *cols) +Return Readline's idea of the terminal's size in the +variables pointed to by the arguments. +@end deftypefun + +@deftypefun void rl_reset_screen_size (void) +Cause Readline to reobtain the screen size and recalculate its dimensions. +@end deftypefun + +The following functions install and remove Readline's signal handlers. + +@deftypefun int rl_set_signals (void) +Install Readline's signal handler for @code{SIGINT}, @code{SIGQUIT}, +@code{SIGTERM}, @code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, +@code{SIGTTOU}, and @code{SIGWINCH}, depending on the values of +@code{rl_catch_signals} and @code{rl_catch_sigwinch}. +@end deftypefun + +@deftypefun int rl_clear_signals (void) +Remove all of the Readline signal handlers installed by +@code{rl_set_signals()}. +@end deftypefun + +@node Custom Completers +@section Custom Completers +@cindex application-specific completion functions + +Typically, a program that reads commands from the user has a way of +disambiguating commands and data. If your program is one of these, then +it can provide completion for commands, data, or both. +The following sections describe how your program and Readline +cooperate to provide this service. + +@menu +* How Completing Works:: The logic used to do completion. +* Completion Functions:: Functions provided by Readline. +* Completion Variables:: Variables which control completion. +* A Short Completion Example:: An example of writing completer subroutines. +@end menu + +@node How Completing Works +@subsection How Completing Works + +In order to complete some text, the full list of possible completions +must be available. That is, it is not possible to accurately +expand a partial word without knowing all of the possible words +which make sense in that context. The Readline library provides +the user interface to completion, and two of the most common +completion functions: filename and username. For completing other types +of text, you must write your own completion function. This section +describes exactly what such functions must do, and provides an example. + +There are three major functions used to perform completion: + +@enumerate +@item +The user-interface function @code{rl_complete()}. This function is +called with the same arguments as other bindable Readline functions: +@var{count} and @var{invoking_key}. +It isolates the word to be completed and calls +@code{rl_completion_matches()} to generate a list of possible completions. +It then either lists the possible completions, inserts the possible +completions, or actually performs the +completion, depending on which behavior is desired. + +@item +The internal function @code{rl_completion_matches()} uses an +application-supplied @dfn{generator} function to generate the list of +possible matches, and then returns the array of these matches. +The caller should place the address of its generator function in +@code{rl_completion_entry_function}. + +@item +The generator function is called repeatedly from +@code{rl_completion_matches()}, returning a string each time. The +arguments to the generator function are @var{text} and @var{state}. +@var{text} is the partial word to be completed. @var{state} is zero the +first time the function is called, allowing the generator to perform +any necessary initialization, and a positive non-zero integer for +each subsequent call. The generator function returns +@code{(char *)NULL} to inform @code{rl_completion_matches()} that there are +no more possibilities left. Usually the generator function computes the +list of possible completions when @var{state} is zero, and returns them +one at a time on subsequent calls. Each string the generator function +returns as a match must be allocated with @code{malloc()}; Readline +frees the strings when it has finished with them. +Such a generator function is referred to as an +@dfn{application-specific completion function}. + +@end enumerate + +@deftypefun int rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{rl_completion_matches()}). The default is to do filename completion. +@end deftypefun + +@deftypevar {rl_compentry_func_t *} rl_completion_entry_function +This is a pointer to the generator function for +@code{rl_completion_matches()}. +If the value of @code{rl_completion_entry_function} is +@code{NULL} then the default filename generator +function, @code{rl_filename_completion_function()}, is used. +An @dfn{application-specific completion function} is a function whose +address is assigned to @code{rl_completion_entry_function} and whose +return values are used to generate possible completions. +@end deftypevar + +@node Completion Functions +@subsection Completion Functions + +Here is the complete list of callable completion functions present in +Readline. + +@deftypefun int rl_complete_internal (int what_to_do) +Complete the word at or before point. @var{what_to_do} says what to do +with the completion. A value of @samp{?} means list the possible +completions. @samp{TAB} means do standard completion. @samp{*} means +insert all of the possible completions. @samp{!} means to display +all of the possible completions, if there is more than one, as well as +performing partial completion. @samp{@@} is similar to @samp{!}, but +possible completions are not listed if the possible completions share +a common prefix. +@end deftypefun + +@deftypefun int rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{rl_completion_matches()} and @code{rl_completion_entry_function}). +The default is to do filename +completion. This calls @code{rl_complete_internal()} with an +argument depending on @var{invoking_key}. +@end deftypefun + +@deftypefun int rl_possible_completions (int count, int invoking_key) +List the possible completions. See description of @code{rl_complete +()}. This calls @code{rl_complete_internal()} with an argument of +@samp{?}. +@end deftypefun + +@deftypefun int rl_insert_completions (int count, int invoking_key) +Insert the list of possible completions into the line, deleting the +partially-completed word. See description of @code{rl_complete()}. +This calls @code{rl_complete_internal()} with an argument of @samp{*}. +@end deftypefun + +@deftypefun int rl_completion_mode (rl_command_func_t *cfunc) +Returns the apppriate value to pass to @code{rl_complete_internal()} +depending on whether @var{cfunc} was called twice in succession and +the values of the @code{show-all-if-ambiguous} and +@code{show-all-if-unmodified} variables. +Application-specific completion functions may use this function to present +the same interface as @code{rl_complete()}. +@end deftypefun + +@deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func) +Returns an array of strings which is a list of completions for +@var{text}. If there are no completions, returns @code{NULL}. +The first entry in the returned array is the substitution for @var{text}. +The remaining entries are the possible completions. The array is +terminated with a @code{NULL} pointer. + +@var{entry_func} is a function of two args, and returns a +@code{char *}. The first argument is @var{text}. The second is a +state argument; it is zero on the first call, and non-zero on subsequent +calls. @var{entry_func} returns a @code{NULL} pointer to the caller +when there are no more matches. +@end deftypefun + +@deftypefun {char *} rl_filename_completion_function (const char *text, int state) +A generator function for filename completion in the general case. +@var{text} is a partial filename. +The Bash source is a useful reference for writing application-specific +completion functions (the Bash completion functions call this and other +Readline functions). +@end deftypefun + +@deftypefun {char *} rl_username_completion_function (const char *text, int state) +A completion generator for usernames. @var{text} contains a partial +username preceded by a random character (usually @samp{~}). As with all +completion generators, @var{state} is zero on the first call and non-zero +for subsequent calls. +@end deftypefun + +@node Completion Variables +@subsection Completion Variables + +@deftypevar {rl_compentry_func_t *} rl_completion_entry_function +A pointer to the generator function for @code{rl_completion_matches()}. +@code{NULL} means to use @code{rl_filename_completion_function()}, +the default filename completer. +@end deftypevar + +@deftypevar {rl_completion_func_t *} rl_attempted_completion_function +A pointer to an alternative function to create matches. +The function is called with @var{text}, @var{start}, and @var{end}. +@var{start} and @var{end} are indices in @code{rl_line_buffer} defining +the boundaries of @var{text}, which is a character string. +If this function exists and returns @code{NULL}, or if this variable is +set to @code{NULL}, then @code{rl_complete()} will call the value of +@code{rl_completion_entry_function} to generate matches, otherwise the +array of strings returned will be used. +If this function sets the @code{rl_attempted_completion_over} +variable to a non-zero value, Readline will not perform its default +completion even if this function returns no matches. +@end deftypevar + +@deftypevar {rl_quote_func_t *} rl_filename_quoting_function +A pointer to a function that will quote a filename in an +application-specific fashion. This is called if filename completion is being +attempted and one of the characters in @code{rl_filename_quote_characters} +appears in a completed filename. The function is called with +@var{text}, @var{match_type}, and @var{quote_pointer}. The @var{text} +is the filename to be quoted. The @var{match_type} is either +@code{SINGLE_MATCH}, if there is only one completion match, or +@code{MULT_MATCH}. Some functions use this to decide whether or not to +insert a closing quote character. The @var{quote_pointer} is a pointer +to any opening quote character the user typed. Some functions choose +to reset this character. +@end deftypevar + +@deftypevar {rl_dequote_func_t *} rl_filename_dequoting_function +A pointer to a function that will remove application-specific quoting +characters from a filename before completion is attempted, so those +characters do not interfere with matching the text against names in +the filesystem. It is called with @var{text}, the text of the word +to be dequoted, and @var{quote_char}, which is the quoting character +that delimits the filename (usually @samp{'} or @samp{"}). If +@var{quote_char} is zero, the filename was not in an embedded string. +@end deftypevar + +@deftypevar {rl_linebuf_func_t *} rl_char_is_quoted_p +A pointer to a function to call that determines whether or not a specific +character in the line buffer is quoted, according to whatever quoting +mechanism the program calling Readline uses. The function is called with +two arguments: @var{text}, the text of the line, and @var{index}, the +index of the character in the line. It is used to decide whether a +character found in @code{rl_completer_word_break_characters} should be +used to break words for the completer. +@end deftypevar + +@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function +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 @code{NULL} terminated array of matches. +The first element (@code{matches[0]}) is the +maximal substring common to all matches. This function can +re-arrange the list of matches as required, but each element deleted +from the array must be freed. +@end deftypevar + +@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook +This function, if defined, is allowed to modify the directory portion +of filenames Readline completes. It is called with the address of a +string (the current directory name) as an argument, and may modify that string. +If the string is replaced with a new string, the old value should be freed. +Any modified directory name should have a trailing slash. +The modified value will be displayed as part of the completion, replacing +the directory portion of the pathname the user typed. +It returns an integer that should be non-zero if the function modifies +its directory argument. +It could be used to expand symbolic links or shell variables in pathnames. +At the least, even if no other expansion is performed, this function should +remove any quote characters from the directory name, because its result will +be passed directly to @code{opendir()}. +@end deftypevar + +@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook +If non-zero, then this is the address of a function to call when +completing a word would normally display the list of possible matches. +This function is called in lieu of Readline displaying the list. +It takes three arguments: +(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length}) +where @var{matches} is the array of matching strings, +@var{num_matches} is the number of strings in that array, and +@var{max_length} is the length of the longest string in that array. +Readline provides a convenience function, @code{rl_display_match_list}, +that takes care of doing the display to Readline's output stream. That +function may be called from this hook. +@end deftypevar + +@deftypevar {const char *} rl_basic_word_break_characters +The basic list of characters that signal a break between words for the +completer routine. The default value of this variable is the characters +which break words for completion in Bash: +@code{" \t\n\"\\'`@@$><=;|&@{("}. +@end deftypevar + +@deftypevar {const char *} rl_basic_quote_characters +A list of quote characters which can cause a word break. +@end deftypevar + +@deftypevar {const char *} rl_completer_word_break_characters +The list of characters that signal a break between words for +@code{rl_complete_internal()}. The default list is the value of +@code{rl_basic_word_break_characters}. +@end deftypevar + +@deftypevar {rl_cpvfunc_t *} rl_completion_word_break_hook +If non-zero, this is the address of a function to call when Readline is +deciding where to separate words for word completion. It should return +a character string like @code{rl_completer_word_break_characters} to be +used to perform the current completion. The function may choose to set +@code{rl_completer_word_break_characters} itself. If the function +returns @code{NULL}, @code{rl_completer_word_break_characters} is used. +@end deftypevar + +@deftypevar {const char *} rl_completer_quote_characters +A list of characters which can be used to quote a substring of the line. +Completion occurs on the entire substring, and within the substring +@code{rl_completer_word_break_characters} are treated as any other character, +unless they also appear within this list. +@end deftypevar + +@deftypevar {const char *} rl_filename_quote_characters +A list of characters that cause a filename to be quoted by the completer +when they appear in a completed filename. The default is the null string. +@end deftypevar + +@deftypevar {const char *} rl_special_prefixes +The list of characters that are word break characters, but should be +left in @var{text} when it is passed to the completion function. +Programs can use this to help determine what kind of completing to do. +For instance, Bash sets this variable to "$@@" so that it can complete +shell variables and hostnames. +@end deftypevar + +@deftypevar int rl_completion_query_items +Up to this many items will be displayed in response to a +possible-completions call. After that, readline asks the user if she is sure +she wants to see them all. The default value is 100. A negative value +indicates that Readline should never ask the user. +@end deftypevar + +@deftypevar {int} rl_completion_append_character +When a single completion alternative matches at the end of the command +line, this character is appended to the inserted completion text. The +default is a space character (@samp{ }). Setting this to the null +character (@samp{\0}) prevents anything being appended automatically. +This can be changed in application-specific completion functions to +provide the ``most sensible word separator character'' according to +an application-specific command line syntax specification. +@end deftypevar + +@deftypevar int rl_completion_suppress_append +If non-zero, @var{rl_completion_append_character} is not appended to +matches at the end of the command line, as described above. +It is set to 0 before any application-specific completion function +is called, and may only be changed within such a function. +@end deftypevar + +@deftypevar int rl_completion_quote_character +When Readline is completing quoted text, as delimited by one of the +characters in @var{rl_completer_quote_characters}, it sets this variable +to the quoting character found. +This is set before any application-specific completion function is called. +@end deftypevar + +@deftypevar int rl_completion_suppress_quote +If non-zero, Readline does not append a matching quote character when +performing completion on a quoted string. +It is set to 0 before any application-specific completion function +is called, and may only be changed within such a function. +@end deftypevar + +@deftypevar int rl_completion_found_quote +When Readline is completing quoted text, it sets this variable +to a non-zero value if the word being completed contains or is delimited +by any quoting characters, including backslashes. +This is set before any application-specific completion function is called. +@end deftypevar + +@deftypevar int rl_completion_mark_symlink_dirs +If non-zero, a slash will be appended to completed filenames that are +symbolic links to directory names, subject to the value of the +user-settable @var{mark-directories} variable. +This variable exists so that application-specific completion functions +can override the user's global preference (set via the +@var{mark-symlinked-directories} Readline variable) if appropriate. +This variable is set to the user's preference before any +application-specific completion function is called, so unless that +function modifies the value, the user's preferences are honored. +@end deftypevar + +@deftypevar int rl_ignore_completion_duplicates +If non-zero, then duplicates in the matches are removed. +The default is 1. +@end deftypevar + +@deftypevar int rl_filename_completion_desired +Non-zero means that the results of the matches are to be treated as +filenames. This is @emph{always} zero when completion is attempted, +and can only be changed +within an application-specific completion function. If it is set to a +non-zero value by such a function, directory names have a slash appended +and Readline attempts to quote completed filenames if they contain any +characters in @code{rl_filename_quote_characters} and +@code{rl_filename_quoting_desired} is set to a non-zero value. +@end deftypevar + +@deftypevar int rl_filename_quoting_desired +Non-zero means that the results of the matches are to be quoted using +double quotes (or an application-specific quoting mechanism) if the +completed filename contains any characters in +@code{rl_filename_quote_chars}. This is @emph{always} non-zero +when completion is attempted, and can only be changed within an +application-specific completion function. +The quoting is effected via a call to the function pointed to +by @code{rl_filename_quoting_function}. +@end deftypevar + +@deftypevar int rl_attempted_completion_over +If an application-specific completion function assigned to +@code{rl_attempted_completion_function} sets this variable to a non-zero +value, Readline will not perform its default filename completion even +if the application's completion function returns no matches. +It should be set only by an application's completion function. +@end deftypevar + +@deftypevar int rl_sort_completion_matches +If an application sets this variable to 0, Readline will not sort the +list of completions (which implies that it cannot remove any duplicate +completions). The default value is 1, which means that Readline will +sort the completions and, depending on the value of +@code{rl_ignore_completion_duplicates}, will attempt to remove duplicate +matches. +@end deftypevar + +@deftypevar int rl_completion_type +Set to a character describing the type of completion Readline is currently +attempting; see the description of @code{rl_complete_internal()} +(@pxref{Completion Functions}) for the list of characters. +This is set to the appropriate value before any application-specific +completion function is called, allowing such functions to present +the same interface as @code{rl_complete()}. +@end deftypevar + +@deftypevar int rl_completion_invoking_key +Set to the final character in the key sequence that invoked one of the +completion functions that call @code{rl_complete_internal()}. This is +set to the appropriate value before any application-specific completion +function is called. +@end deftypevar + +@deftypevar int rl_inhibit_completion +If this variable is non-zero, completion is inhibited. The completion +character will be inserted as any other bound to @code{self-insert}. +@end deftypevar + +@node A Short Completion Example +@subsection A Short Completion Example + +Here is a small application demonstrating the use of the GNU Readline +library. It is called @code{fileman}, and the source code resides in +@file{examples/fileman.c}. This sample application provides +completion of command names, line editing features, and access to the +history list. + +@page +@smallexample +/* fileman.c -- A tiny application which demonstrates how to use the + GNU Readline library. This application interactively allows users + to manipulate files and their modes. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef HAVE_SYS_FILE_H +# include +#endif +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include + +#include +#include + +extern char *xmalloc PARAMS((size_t)); + +/* The names of functions that actually do the manipulation. */ +int com_list PARAMS((char *)); +int com_view PARAMS((char *)); +int com_rename PARAMS((char *)); +int com_stat PARAMS((char *)); +int com_pwd PARAMS((char *)); +int com_delete PARAMS((char *)); +int com_help PARAMS((char *)); +int com_cd PARAMS((char *)); +int com_quit PARAMS((char *)); + +/* A structure which contains information on the commands this program + can understand. */ + +typedef struct @{ + char *name; /* User printable name of the function. */ + rl_icpfunc_t *func; /* Function to call to do the job. */ + char *doc; /* Documentation for this function. */ +@} COMMAND; + +COMMAND commands[] = @{ + @{ "cd", com_cd, "Change to directory DIR" @}, + @{ "delete", com_delete, "Delete FILE" @}, + @{ "help", com_help, "Display this text" @}, + @{ "?", com_help, "Synonym for `help'" @}, + @{ "list", com_list, "List files in DIR" @}, + @{ "ls", com_list, "Synonym for `list'" @}, + @{ "pwd", com_pwd, "Print the current working directory" @}, + @{ "quit", com_quit, "Quit using Fileman" @}, + @{ "rename", com_rename, "Rename FILE to NEWNAME" @}, + @{ "stat", com_stat, "Print out statistics on FILE" @}, + @{ "view", com_view, "View the contents of FILE" @}, + @{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL @} +@}; + +/* Forward declarations. */ +char *stripwhite (); +COMMAND *find_command (); + +/* The name of this program, as taken from argv[0]. */ +char *progname; + +/* When non-zero, this global means the user is done using this program. */ +int done; + +char * +dupstr (s) + char *s; +@{ + char *r; + + r = xmalloc (strlen (s) + 1); + strcpy (r, s); + return (r); +@} + +main (argc, argv) + int argc; + char **argv; +@{ + char *line, *s; + + progname = argv[0]; + + initialize_readline (); /* Bind our completer. */ + + /* Loop reading and executing lines until the user quits. */ + for ( ; done == 0; ) + @{ + line = readline ("FileMan: "); + + if (!line) + break; + + /* Remove leading and trailing whitespace from the line. + Then, if there is anything left, add it to the history list + and execute it. */ + s = stripwhite (line); + + if (*s) + @{ + add_history (s); + execute_line (s); + @} + + free (line); + @} + exit (0); +@} + +/* Execute a command line. */ +int +execute_line (line) + char *line; +@{ + register int i; + COMMAND *command; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && whitespace (line[i])) + i++; + word = line + i; + + while (line[i] && !whitespace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + command = find_command (word); + + if (!command) + @{ + fprintf (stderr, "%s: No such command for FileMan.\n", word); + return (-1); + @} + + /* Get argument to command, if any. */ + while (whitespace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + return ((*(command->func)) (word)); +@} + +/* Look up NAME as the name of a command, and return a pointer to that + command. Return a NULL pointer if NAME isn't a command name. */ +COMMAND * +find_command (name) + char *name; +@{ + register int i; + + for (i = 0; commands[i].name; i++) + if (strcmp (name, commands[i].name) == 0) + return (&commands[i]); + + return ((COMMAND *)NULL); +@} + +/* Strip whitespace from the start and end of STRING. Return a pointer + into STRING. */ +char * +stripwhite (string) + char *string; +@{ + register char *s, *t; + + for (s = string; whitespace (*s); s++) + ; + + if (*s == 0) + return (s); + + t = s + strlen (s) - 1; + while (t > s && whitespace (*t)) + t--; + *++t = '\0'; + + return s; +@} + +/* **************************************************************** */ +/* */ +/* Interface to Readline Completion */ +/* */ +/* **************************************************************** */ + +char *command_generator PARAMS((const char *, int)); +char **fileman_completion PARAMS((const char *, int, int)); + +/* Tell the GNU Readline library how to complete. We want to try to complete + on command names if this is the first word in the line, or on filenames + if not. */ +initialize_readline () +@{ + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "FileMan"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = fileman_completion; +@} + +/* Attempt to complete on the contents of TEXT. START and END bound the + region of rl_line_buffer that contains the word to complete. TEXT is + the word to complete. We can use the entire contents of rl_line_buffer + in case we want to do some simple parsing. Return the array of matches, + or NULL if there aren't any. */ +char ** +fileman_completion (text, start, end) + const char *text; + int start, end; +@{ + char **matches; + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + to complete. Otherwise it is the name of a file in the current + directory. */ + if (start == 0) + matches = rl_completion_matches (text, command_generator); + + return (matches); +@} + +/* Generator function for command completion. STATE lets us know whether + to start from scratch; without any state (i.e. STATE == 0), then we + start at the top of the list. */ +char * +command_generator (text, state) + const char *text; + int state; +@{ + static int list_index, len; + char *name; + + /* If this is a new word to complete, initialize now. This includes + saving the length of TEXT for efficiency, and initializing the index + variable to 0. */ + if (!state) + @{ + list_index = 0; + len = strlen (text); + @} + + /* Return the next name which partially matches from the command list. */ + while (name = commands[list_index].name) + @{ + list_index++; + + if (strncmp (name, text, len) == 0) + return (dupstr(name)); + @} + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +@} + +/* **************************************************************** */ +/* */ +/* FileMan Commands */ +/* */ +/* **************************************************************** */ + +/* String to pass to system (). This is for the LIST, VIEW and RENAME + commands. */ +static char syscom[1024]; + +/* List the file(s) named in arg. */ +com_list (arg) + char *arg; +@{ + if (!arg) + arg = ""; + + sprintf (syscom, "ls -FClg %s", arg); + return (system (syscom)); +@} + +com_view (arg) + char *arg; +@{ + if (!valid_argument ("view", arg)) + return 1; + +#if defined (__MSDOS__) + /* more.com doesn't grok slashes in pathnames */ + sprintf (syscom, "less %s", arg); +#else + sprintf (syscom, "more %s", arg); +#endif + return (system (syscom)); +@} + +com_rename (arg) + char *arg; +@{ + too_dangerous ("rename"); + return (1); +@} + +com_stat (arg) + char *arg; +@{ + struct stat finfo; + + if (!valid_argument ("stat", arg)) + return (1); + + if (stat (arg, &finfo) == -1) + @{ + perror (arg); + return (1); + @} + + printf ("Statistics for `%s':\n", arg); + + printf ("%s has %d link%s, and is %d byte%s in length.\n", + arg, + finfo.st_nlink, + (finfo.st_nlink == 1) ? "" : "s", + finfo.st_size, + (finfo.st_size == 1) ? "" : "s"); + printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime)); + printf (" Last access at: %s", ctime (&finfo.st_atime)); + printf (" Last modified at: %s", ctime (&finfo.st_mtime)); + return (0); +@} + +com_delete (arg) + char *arg; +@{ + too_dangerous ("delete"); + return (1); +@} + +/* Print out help for ARG, or for all of the commands if ARG is + not present. */ +com_help (arg) + char *arg; +@{ + register int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) + @{ + if (!*arg || (strcmp (arg, commands[i].name) == 0)) + @{ + printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); + printed++; + @} + @} + + if (!printed) + @{ + printf ("No commands match `%s'. Possibilties are:\n", arg); + + for (i = 0; commands[i].name; i++) + @{ + /* Print in six columns. */ + if (printed == 6) + @{ + printed = 0; + printf ("\n"); + @} + + printf ("%s\t", commands[i].name); + printed++; + @} + + if (printed) + printf ("\n"); + @} + return (0); +@} + +/* Change to the directory ARG. */ +com_cd (arg) + char *arg; +@{ + if (chdir (arg) == -1) + @{ + perror (arg); + return 1; + @} + + com_pwd (""); + return (0); +@} + +/* Print out the current working directory. */ +com_pwd (ignore) + char *ignore; +@{ + char dir[1024], *s; + + s = getcwd (dir, sizeof(dir) - 1); + if (s == 0) + @{ + printf ("Error getting pwd: %s\n", dir); + return 1; + @} + + printf ("Current directory is %s\n", dir); + return 0; +@} + +/* The user wishes to quit using this program. Just set DONE non-zero. */ +com_quit (arg) + char *arg; +@{ + done = 1; + return (0); +@} + +/* Function which tells you that you can't do this. */ +too_dangerous (caller) + char *caller; +@{ + fprintf (stderr, + "%s: Too dangerous for me to distribute. Write it yourself.\n", + caller); +@} + +/* Return non-zero if ARG is a valid argument for CALLER, else print + an error message and return zero. */ +int +valid_argument (caller, arg) + char *caller, *arg; +@{ + if (!arg || !*arg) + @{ + fprintf (stderr, "%s: Argument required.\n", caller); + return (0); + @} + + return (1); +@} +@end smallexample diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi index 4a367ed32..71518e1e1 100644 --- a/lib/readline/doc/rluser.texi +++ b/lib/readline/doc/rluser.texi @@ -1292,6 +1292,11 @@ through the list. This command is intended to be bound to @key{TAB}, but is unbound by default. +@item menu-complete-backward () +Identical to @code{menu-complete}, but moves backward through the list +of possible completions, as if @code{menu-complete} had been given a +negative argument. + @item delete-char-or-list () Deletes the character under the cursor if not at the beginning or end of the line (like @code{delete-char}). diff --git a/lib/readline/doc/version.texi b/lib/readline/doc/version.texi index 913a62e0b..d9c101e05 100644 --- a/lib/readline/doc/version.texi +++ b/lib/readline/doc/version.texi @@ -4,7 +4,7 @@ Copyright (C) 1988-2009 Free Software Foundation, Inc. @set EDITION 6.0 @set VERSION 6.0 -@set UPDATED 28 October 2008 -@set UPDATED-MONTH October 2008 +@set UPDATED 31 July 2009 +@set UPDATED-MONTH July 2009 -@set LASTCHANGE Tue Oct 28 11:25:24 EDT 2008 +@set LASTCHANGE Fri Jul 31 20:18:23 EDT 2009 diff --git a/lib/readline/doc/version.texi~ b/lib/readline/doc/version.texi~ new file mode 100644 index 000000000..208412e4d --- /dev/null +++ b/lib/readline/doc/version.texi~ @@ -0,0 +1,10 @@ +@ignore +Copyright (C) 1988-2009 Free Software Foundation, Inc. +@end ignore + +@set EDITION 6.0 +@set VERSION 6.0 +@set UPDATED 30 July 2009 +@set UPDATED-MONTH July 2009 + +@set LASTCHANGE Thu Jul 30 09:23:36 EDT 2009 diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c index 06d2b9243..314ecf8f5 100644 --- a/lib/readline/funmap.c +++ b/lib/readline/funmap.c @@ -105,6 +105,7 @@ static const FUNMAP default_funmap[] = { { "kill-region", rl_kill_region }, { "kill-word", rl_kill_word }, { "menu-complete", rl_menu_complete }, + { "menu-complete-backward", rl_backward_menu_complete }, { "next-history", rl_get_next_history }, { "non-incremental-forward-search-history", rl_noninc_forward_search }, { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, diff --git a/lib/readline/keymaps.c b/lib/readline/keymaps.c index a033d5ecd..9379dec5a 100644 --- a/lib/readline/keymaps.c +++ b/lib/readline/keymaps.c @@ -57,8 +57,9 @@ Keymap rl_make_bare_keymap () { register int i; - Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY)); + Keymap keymap; + keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY)); for (i = 0; i < KEYMAP_SIZE; i++) { keymap[i].type = ISFUNC; @@ -76,7 +77,8 @@ rl_make_bare_keymap () return (keymap); } -/* Return a new keymap which is a copy of MAP. */ +/* Return a new keymap which is a copy of MAP. Just copies pointers, does + not copy text of macros or descend into child keymaps. */ Keymap rl_copy_keymap (map) Keymap map; @@ -128,7 +130,7 @@ rl_discard_keymap (map) { int i; - if (!map) + if (map == 0) return; for (i = 0; i < KEYMAP_SIZE; i++) @@ -140,6 +142,7 @@ rl_discard_keymap (map) case ISKMAP: rl_discard_keymap ((Keymap)map[i].function); + free ((char *)map[i].function); break; case ISMACR: @@ -148,3 +151,12 @@ rl_discard_keymap (map) } } } + +/* Convenience function that discards, then frees, MAP. */ +void +rl_free_keymap (map) + Keymap map; +{ + rl_discard_keymap (map); + free ((char *)map); +} diff --git a/lib/readline/keymaps.c~ b/lib/readline/keymaps.c~ new file mode 100644 index 000000000..a033d5ecd --- /dev/null +++ b/lib/readline/keymaps.c~ @@ -0,0 +1,150 @@ +/* keymaps.c -- Functions and keymaps for the GNU Readline library. */ + +/* Copyright (C) 1988,1989-2009 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. + + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include /* for FILE * definition for readline.h */ + +#include "readline.h" +#include "rlconf.h" + +#include "emacs_keymap.c" + +#if defined (VI_MODE) +#include "vi_keymap.c" +#endif + +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Functions for manipulating Keymaps. */ +/* */ +/* **************************************************************** */ + + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap +rl_make_bare_keymap () +{ + register int i; + Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY)); + + for (i = 0; i < KEYMAP_SIZE; i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = (rl_command_func_t *)NULL; + } + +#if 0 + for (i = 'A'; i < ('Z' + 1); i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = rl_do_lowercase_version; + } +#endif + + return (keymap); +} + +/* Return a new keymap which is a copy of MAP. */ +Keymap +rl_copy_keymap (map) + Keymap map; +{ + register int i; + Keymap temp; + + temp = rl_make_bare_keymap (); + for (i = 0; i < KEYMAP_SIZE; i++) + { + temp[i].type = map[i].type; + temp[i].function = map[i].function; + } + return (temp); +} + +/* Return a new keymap with the printing characters bound to rl_insert, + the uppercase Meta characters bound to run their lowercase equivalents, + and the Meta digits bound to produce numeric arguments. */ +Keymap +rl_make_keymap () +{ + register int i; + Keymap newmap; + + newmap = rl_make_bare_keymap (); + + /* All ASCII printing characters are self-inserting. */ + for (i = ' '; i < 127; i++) + newmap[i].function = rl_insert; + + newmap[TAB].function = rl_insert; + newmap[RUBOUT].function = rl_rubout; /* RUBOUT == 127 */ + newmap[CTRL('H')].function = rl_rubout; + +#if KEYMAP_SIZE > 128 + /* Printing characters in ISO Latin-1 and some 8-bit character sets. */ + for (i = 128; i < 256; i++) + newmap[i].function = rl_insert; +#endif /* KEYMAP_SIZE > 128 */ + + return (newmap); +} + +/* Free the storage associated with MAP. */ +void +rl_discard_keymap (map) + Keymap map; +{ + int i; + + if (!map) + return; + + for (i = 0; i < KEYMAP_SIZE; i++) + { + switch (map[i].type) + { + case ISFUNC: + break; + + case ISKMAP: + rl_discard_keymap ((Keymap)map[i].function); + break; + + case ISMACR: + free ((char *)map[i].function); + break; + } + } +} diff --git a/lib/readline/readline.c b/lib/readline/readline.c index 270eed230..fee2d463d 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -1169,6 +1169,10 @@ bind_arrow_keys () #if defined (VI_MODE) bind_arrow_keys_internal (vi_movement_keymap); + /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC + in vi command mode while still allowing the arrow keys to work. */ + if (vi_movement_keymap[ESC].type == ISKMAP) + rl_bind_keyseq_in_map ("\033", (rl_command_func_t *)NULL, vi_movement_keymap); bind_arrow_keys_internal (vi_insertion_keymap); #endif } diff --git a/lib/readline/readline.c~ b/lib/readline/readline.c~ new file mode 100644 index 000000000..67dd0b5a3 --- /dev/null +++ b/lib/readline/readline.c~ @@ -0,0 +1,1252 @@ +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. + + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include "posixstat.h" +#include +#if defined (HAVE_SYS_FILE_H) +# include +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include "posixjmp.h" +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (__EMX__) +# define INCL_DOSPROCESS +# include +#endif /* __EMX__ */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +#ifndef RL_LIBRARY_VERSION +# define RL_LIBRARY_VERSION "5.1" +#endif + +#ifndef RL_READLINE_VERSION +# define RL_READLINE_VERSION 0x0501 +#endif + +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +/* Forward declarations used in this file. */ +static char *readline_internal PARAMS((void)); +static void readline_initialize_everything PARAMS((void)); + +static void bind_arrow_keys_internal PARAMS((Keymap)); +static void bind_arrow_keys PARAMS((void)); + +static void readline_default_bindings PARAMS((void)); +static void reset_default_bindings PARAMS((void)); + +static int _rl_subseq_result PARAMS((int, Keymap, int, int)); +static int _rl_subseq_getchar PARAMS((int)); + +/* **************************************************************** */ +/* */ +/* Line editing input utility */ +/* */ +/* **************************************************************** */ + +const char *rl_library_version = RL_LIBRARY_VERSION; + +int rl_readline_version = RL_READLINE_VERSION; + +/* True if this is `real' readline as opposed to some stub substitute. */ +int rl_gnu_readline_p = 1; + +/* A pointer to the keymap that is currently in use. + By default, it is the standard emacs keymap. */ +Keymap _rl_keymap = emacs_standard_keymap; + + +/* The current style of editing. */ +int rl_editing_mode = emacs_mode; + +/* The current insert mode: input (the default) or overwrite */ +int rl_insert_mode = RL_IM_DEFAULT; + +/* Non-zero if we called this function from _rl_dispatch(). It's present + so functions can find out whether they were called from a key binding + or directly from an application. */ +int rl_dispatching; + +/* Non-zero if the previous command was a kill command. */ +int _rl_last_command_was_kill = 0; + +/* The current value of the numeric argument specified by the user. */ +int rl_numeric_arg = 1; + +/* Non-zero if an argument was typed. */ +int rl_explicit_arg = 0; + +/* Temporary value used while generating the argument. */ +int rl_arg_sign = 1; + +/* Non-zero means we have been called at least once before. */ +static int rl_initialized; + +#if 0 +/* If non-zero, this program is running in an EMACS buffer. */ +static int running_in_emacs; +#endif + +/* Flags word encapsulating the current readline state. */ +int rl_readline_state = RL_STATE_NONE; + +/* The current offset in the current input line. */ +int rl_point; + +/* Mark in the current input line. */ +int rl_mark; + +/* Length of the current input line. */ +int rl_end; + +/* Make this non-zero to return the current input_line. */ +int rl_done; + +/* The last function executed by readline. */ +rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; + +/* Top level environment for readline_internal (). */ +procenv_t _rl_top_level; + +/* The streams we interact with. */ +FILE *_rl_in_stream, *_rl_out_stream; + +/* The names of the streams that we do input and output to. */ +FILE *rl_instream = (FILE *)NULL; +FILE *rl_outstream = (FILE *)NULL; + +/* Non-zero means echo characters as they are read. Defaults to no echo; + set to 1 if there is a controlling terminal, we can get its attributes, + and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings + for the code that sets it. */ +int _rl_echoing_p = 0; + +/* Current prompt. */ +char *rl_prompt = (char *)NULL; +int rl_visible_prompt_length = 0; + +/* Set to non-zero by calling application if it has already printed rl_prompt + and does not want readline to do it the first time. */ +int rl_already_prompted = 0; + +/* The number of characters read in order to type this complete command. */ +int rl_key_sequence_length = 0; + +/* If non-zero, then this is the address of a function to call just + before readline_internal_setup () prints the first prompt. */ +rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; + +/* If non-zero, this is the address of a function to call just before + readline_internal_setup () returns and readline_internal starts + reading input characters. */ +rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; + +/* What we use internally. You should always refer to RL_LINE_BUFFER. */ +static char *the_line; + +/* The character that can generate an EOF. Really read from + the terminal driver... just defaulted here. */ +int _rl_eof_char = CTRL ('D'); + +/* Non-zero makes this the next keystroke to read. */ +int rl_pending_input = 0; + +/* Pointer to a useful terminal name. */ +const char *rl_terminal_name = (const char *)NULL; + +/* Non-zero means to always use horizontal scrolling in line display. */ +int _rl_horizontal_scroll_mode = 0; + +/* Non-zero means to display an asterisk at the starts of history lines + which have been modified. */ +int _rl_mark_modified_lines = 0; + +/* The style of `bell' notification preferred. This can be set to NO_BELL, + AUDIBLE_BELL, or VISIBLE_BELL. */ +int _rl_bell_preference = AUDIBLE_BELL; + +/* String inserted into the line by rl_insert_comment (). */ +char *_rl_comment_begin; + +/* Keymap holding the function currently being executed. */ +Keymap rl_executing_keymap; + +/* Keymap we're currently using to dispatch. */ +Keymap _rl_dispatching_keymap; + +/* Non-zero means to erase entire line, including prompt, on empty input lines. */ +int rl_erase_empty_line = 0; + +/* Non-zero means to read only this many characters rather than up to a + character bound to accept-line. */ +int rl_num_chars_to_read; + +/* Line buffer and maintenence. */ +char *rl_line_buffer = (char *)NULL; +int rl_line_buffer_len = 0; + +/* Key sequence `contexts' */ +_rl_keyseq_cxt *_rl_kscxt = 0; + +/* Forward declarations used by the display, termcap, and history code. */ + +/* **************************************************************** */ +/* */ +/* `Forward' declarations */ +/* */ +/* **************************************************************** */ + +/* Non-zero means do not parse any lines other than comments and + parser directives. */ +unsigned char _rl_parsing_conditionalized_out = 0; + +/* Non-zero means to convert characters with the meta bit set to + escape-prefixed characters so we can indirect through + emacs_meta_keymap or vi_escape_keymap. */ +int _rl_convert_meta_chars_to_ascii = 1; + +/* Non-zero means to output characters with the meta bit set directly + rather than as a meta-prefixed escape sequence. */ +int _rl_output_meta_chars = 0; + +/* Non-zero means to look at the termios special characters and bind + them to equivalent readline functions at startup. */ +int _rl_bind_stty_chars = 1; + +/* Non-zero means to go through the history list at every newline (or + whenever rl_done is set and readline returns) and revert each line to + its initial state. */ +int _rl_revert_all_at_newline = 0; + +/* **************************************************************** */ +/* */ +/* Top Level Functions */ +/* */ +/* **************************************************************** */ + +/* Non-zero means treat 0200 bit in terminal input as Meta bit. */ +int _rl_meta_flag = 0; /* Forward declaration */ + +/* Set up the prompt and expand it. Called from readline() and + rl_callback_handler_install (). */ +int +rl_set_prompt (prompt) + const char *prompt; +{ + FREE (rl_prompt); + rl_prompt = prompt ? savestring (prompt) : (char *)NULL; + rl_display_prompt = rl_prompt ? rl_prompt : ""; + + rl_visible_prompt_length = rl_expand_prompt (rl_prompt); + return 0; +} + +/* Read a line of input. Prompt with PROMPT. An empty PROMPT means + none. A return value of NULL means that EOF was encountered. */ +char * +readline (prompt) + const char *prompt; +{ + char *value; +#if 0 + int in_callback; +#endif + + /* If we are at EOF return a NULL string. */ + if (rl_pending_input == EOF) + { + rl_clear_pending_input (); + return ((char *)NULL); + } + +#if 0 + /* If readline() is called after installing a callback handler, temporarily + turn off the callback state to avoid ensuing messiness. Patch supplied + by the gdb folks. XXX -- disabled. This can be fooled and readline + left in a strange state by a poorly-timed longjmp. */ + if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK)) + RL_UNSETSTATE (RL_STATE_CALLBACK); +#endif + + rl_set_prompt (prompt); + + rl_initialize (); + if (rl_prep_term_function) + (*rl_prep_term_function) (_rl_meta_flag); + +#if defined (HANDLE_SIGNALS) + rl_set_signals (); +#endif + + value = readline_internal (); + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); + +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + +#if 0 + if (in_callback) + RL_SETSTATE (RL_STATE_CALLBACK); +#endif + + return (value); +} + +#if defined (READLINE_CALLBACKS) +# define STATIC_CALLBACK +#else +# define STATIC_CALLBACK static +#endif + +STATIC_CALLBACK void +readline_internal_setup () +{ + char *nprompt; + + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; + + if (rl_startup_hook) + (*rl_startup_hook) (); + + /* If we're not echoing, we still want to at least print a prompt, because + rl_redisplay will not do it for us. If the calling application has a + custom redisplay function, though, let that function handle it. */ + if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay) + { + if (rl_prompt && rl_already_prompted == 0) + { + nprompt = _rl_strip_prompt (rl_prompt); + fprintf (_rl_out_stream, "%s", nprompt); + fflush (_rl_out_stream); + free (nprompt); + } + } + else + { + if (rl_prompt && rl_already_prompted) + rl_on_new_line_with_prompt (); + else + rl_on_new_line (); + (*rl_redisplay_function) (); + } + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_vi_insert_mode (1, 'i'); +#endif /* VI_MODE */ + + if (rl_pre_input_hook) + (*rl_pre_input_hook) (); + + RL_CHECK_SIGNALS (); +} + +STATIC_CALLBACK char * +readline_internal_teardown (eof) + int eof; +{ + char *temp; + HIST_ENTRY *entry; + + RL_CHECK_SIGNALS (); + + /* Restore the original of this history line, iff the line that we + are editing was originally in the history, AND the line has changed. */ + entry = current_history (); + + if (entry && rl_undo_list) + { + temp = savestring (the_line); + rl_revert_line (1, 0); + entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); + _rl_free_history_entry (entry); + + strcpy (the_line, temp); + free (temp); + } + + if (_rl_revert_all_at_newline) + _rl_revert_all_lines (); + + /* At any rate, it is highly likely that this line has an undo list. Get + rid of it now. */ + if (rl_undo_list) + rl_free_undo_list (); + + /* Restore normal cursor, if available. */ + _rl_set_insert_mode (RL_IM_INSERT, 0); + + return (eof ? (char *)NULL : savestring (the_line)); +} + +void +_rl_internal_char_cleanup () +{ +#if defined (VI_MODE) + /* In vi mode, when you exit insert mode, the cursor moves back + over the previous character. We explicitly check for that here. */ + if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) + rl_vi_check (); +#endif /* VI_MODE */ + + if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + rl_newline (1, '\n'); + } + + if (rl_done == 0) + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + } + + /* If the application writer has told us to erase the entire line if + the only character typed was something bound to rl_newline, do so. */ + if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && + rl_point == 0 && rl_end == 0) + _rl_erase_entire_line (); +} + +STATIC_CALLBACK int +#if defined (READLINE_CALLBACKS) +readline_internal_char () +#else +readline_internal_charloop () +#endif +{ + static int lastc, eof_found; + int c, code, lk; + + lastc = -1; + eof_found = 0; + +#if !defined (READLINE_CALLBACKS) + while (rl_done == 0) + { +#endif + lk = _rl_last_command_was_kill; + + code = setjmp (_rl_top_level); + + if (code) + { + (*rl_redisplay_function) (); + _rl_want_redisplay = 0; + /* If we get here, we're not being called from something dispatched + from _rl_callback_read_char(), which sets up its own value of + _rl_top_level (saving and restoring the old, of course), so + we can just return here. */ + if (RL_ISSTATE (RL_STATE_CALLBACK)) + return (0); + } + + if (rl_pending_input == 0) + { + /* Then initialize the argument and number of keys read. */ + _rl_reset_argument (); + rl_key_sequence_length = 0; + } + + RL_SETSTATE(RL_STATE_READCMD); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_READCMD); + + /* look at input.c:rl_getc() for the circumstances under which this will + be returned; punt immediately on read error without converting it to + a newline. */ + if (c == READERR) + { +#if defined (READLINE_CALLBACKS) + RL_SETSTATE(RL_STATE_DONE); + return (rl_done = 1); +#else + eof_found = 1; + break; +#endif + } + + /* EOF typed to a non-blank line is a . */ + if (c == EOF && rl_end) + c = NEWLINE; + + /* The character _rl_eof_char typed to blank line, and not as the + previous character is interpreted as EOF. */ + if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) + { +#if defined (READLINE_CALLBACKS) + RL_SETSTATE(RL_STATE_DONE); + return (rl_done = 1); +#else + eof_found = 1; + break; +#endif + } + + lastc = c; + _rl_dispatch ((unsigned char)c, _rl_keymap); + RL_CHECK_SIGNALS (); + + /* If there was no change in _rl_last_command_was_kill, then no kill + has taken place. Note that if input is pending we are reading + a prefix command, so nothing has changed yet. */ + if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) + _rl_last_command_was_kill = 0; + + _rl_internal_char_cleanup (); + +#if defined (READLINE_CALLBACKS) + return 0; +#else + } + + return (eof_found); +#endif +} + +#if defined (READLINE_CALLBACKS) +static int +readline_internal_charloop () +{ + int eof = 1; + + while (rl_done == 0) + eof = readline_internal_char (); + return (eof); +} +#endif /* READLINE_CALLBACKS */ + +/* Read a line of input from the global rl_instream, doing output on + the global rl_outstream. + If rl_prompt is non-null, then that is our prompt. */ +static char * +readline_internal () +{ + int eof; + + readline_internal_setup (); + eof = readline_internal_charloop (); + return (readline_internal_teardown (eof)); +} + +void +_rl_init_line_state () +{ + rl_point = rl_end = rl_mark = 0; + the_line = rl_line_buffer; + the_line[0] = 0; +} + +void +_rl_set_the_line () +{ + the_line = rl_line_buffer; +} + +#if defined (READLINE_CALLBACKS) +_rl_keyseq_cxt * +_rl_keyseq_cxt_alloc () +{ + _rl_keyseq_cxt *cxt; + + cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); + + cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; + + cxt->okey = 0; + cxt->ocxt = _rl_kscxt; + cxt->childval = 42; /* sentinel value */ + + return cxt; +} + +void +_rl_keyseq_cxt_dispose (cxt) + _rl_keyseq_cxt *cxt; +{ + free (cxt); +} + +void +_rl_keyseq_chain_dispose () +{ + _rl_keyseq_cxt *cxt; + + while (_rl_kscxt) + { + cxt = _rl_kscxt; + _rl_kscxt = _rl_kscxt->ocxt; + _rl_keyseq_cxt_dispose (cxt); + } +} +#endif + +static int +_rl_subseq_getchar (key) + int key; +{ + int k; + + if (key == ESC) + RL_SETSTATE(RL_STATE_METANEXT); + RL_SETSTATE(RL_STATE_MOREINPUT); + k = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (key == ESC) + RL_UNSETSTATE(RL_STATE_METANEXT); + + return k; +} + +#if defined (READLINE_CALLBACKS) +int +_rl_dispatch_callback (cxt) + _rl_keyseq_cxt *cxt; +{ + int nkey, r; + + /* For now */ + /* The first time this context is used, we want to read input and dispatch + on it. When traversing the chain of contexts back `up', we want to use + the value from the next context down. We're simulating recursion using + a chain of contexts. */ + if ((cxt->flags & KSEQ_DISPATCHED) == 0) + { + nkey = _rl_subseq_getchar (cxt->okey); + if (nkey < 0) + { + _rl_abort_internal (); + return -1; + } + r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); + cxt->flags |= KSEQ_DISPATCHED; + } + else + r = cxt->childval; + + /* For now */ + r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ)); + + RL_CHECK_SIGNALS (); + if (r == 0) /* success! */ + { + _rl_keyseq_chain_dispose (); + RL_UNSETSTATE (RL_STATE_MULTIKEY); + return r; + } + + if (r != -3) /* magic value that says we added to the chain */ + _rl_kscxt = cxt->ocxt; + if (_rl_kscxt) + _rl_kscxt->childval = r; + if (r != -3) + _rl_keyseq_cxt_dispose (cxt); + + return r; +} +#endif /* READLINE_CALLBACKS */ + +/* Do the command associated with KEY in MAP. + If the associated command is really a keymap, then read + another key, and dispatch into that map. */ +int +_rl_dispatch (key, map) + register int key; + Keymap map; +{ + _rl_dispatching_keymap = map; + return _rl_dispatch_subseq (key, map, 0); +} + +int +_rl_dispatch_subseq (key, map, got_subseq) + register int key; + Keymap map; + int got_subseq; +{ + int r, newkey; + char *macro; + rl_command_func_t *func; +#if defined (READLINE_CALLBACKS) + _rl_keyseq_cxt *cxt; +#endif + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type == ISKMAP) + { + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (ESC); + map = FUNCTION_TO_KEYMAP (map, ESC); + key = UNMETA (key); + rl_key_sequence_length += 2; + return (_rl_dispatch (key, map)); + } + else + rl_ding (); + return 0; + } + + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (key); + + r = 0; + switch (map[key].type) + { + case ISFUNC: + func = map[key].function; + if (func) + { + /* Special case rl_do_lowercase_version (). */ + if (func == rl_do_lowercase_version) + return (_rl_dispatch (_rl_to_lower (key), map)); + + rl_executing_keymap = map; + + rl_dispatching = 1; + RL_SETSTATE(RL_STATE_DISPATCHING); + (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); + RL_UNSETSTATE(RL_STATE_DISPATCHING); + rl_dispatching = 0; + + /* If we have input pending, then the last command was a prefix + command. Don't change the state of rl_last_func. Otherwise, + remember the last command executed in this variable. */ + if (rl_pending_input == 0 && map[key].function != rl_digit_argument) + rl_last_func = map[key].function; + + RL_CHECK_SIGNALS (); + } + else if (map[ANYOTHERKEY].function) + { + /* OK, there's no function bound in this map, but there is a + shadow function that was overridden when the current keymap + was created. Return -2 to note that. */ + _rl_unget_char (key); + return -2; + } + else if (got_subseq) + { + /* Return -1 to note that we're in a subsequence, but we don't + have a matching key, nor was one overridden. This means + we need to back up the recursion chain and find the last + subsequence that is bound to a function. */ + _rl_unget_char (key); + return -1; + } + else + { +#if defined (READLINE_CALLBACKS) + RL_UNSETSTATE (RL_STATE_MULTIKEY); + _rl_keyseq_chain_dispose (); +#endif + _rl_abort_internal (); + return -1; + } + break; + + case ISKMAP: + if (map[key].function != 0) + { +#if defined (VI_MODE) + /* The only way this test will be true is if a subsequence has been + bound starting with ESC, generally the arrow keys. What we do is + check whether there's input in the queue, which there generally + will be if an arrow key has been pressed, and, if there's not, + just dispatch to (what we assume is) rl_vi_movement_mode right + away. This is essentially an input test with a zero timeout. */ + if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap + && _rl_input_queued (0) == 0) + return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); +#endif + + rl_key_sequence_length++; + _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key); + + /* Allocate new context here. Use linked contexts (linked through + cxt->ocxt) to simulate recursion */ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + /* Return 0 only the first time, to indicate success to + _rl_callback_read_char. The rest of the time, we're called + from _rl_dispatch_callback, so we return 3 to indicate + special handling is necessary. */ + r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0; + cxt = _rl_keyseq_cxt_alloc (); + + if (got_subseq) + cxt->flags |= KSEQ_SUBSEQ; + cxt->okey = key; + cxt->oldmap = map; + cxt->dmap = _rl_dispatching_keymap; + cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function; + + RL_SETSTATE (RL_STATE_MULTIKEY); + _rl_kscxt = cxt; + + return r; /* don't indicate immediate success */ + } +#endif + + newkey = _rl_subseq_getchar (key); + if (newkey < 0) + { + _rl_abort_internal (); + return -1; + } + + r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function); + return _rl_subseq_result (r, map, key, got_subseq); + } + else + { + _rl_abort_internal (); + return -1; + } + break; + + case ISMACR: + if (map[key].function != 0) + { + macro = savestring ((char *)map[key].function); + _rl_with_macro_input (macro); + return 0; + } + break; + } +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && + key != ANYOTHERKEY && + _rl_vi_textmod_command (key)) + _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); +#endif + + return (r); +} + +static int +_rl_subseq_result (r, map, key, got_subseq) + int r; + Keymap map; + int key, got_subseq; +{ + Keymap m; + int type, nt; + rl_command_func_t *func, *nf; + + if (r == -2) + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ + { + m = _rl_dispatching_keymap; + type = m[ANYOTHERKEY].type; + func = m[ANYOTHERKEY].function; + if (type == ISFUNC && func == rl_do_lowercase_version) + r = _rl_dispatch (_rl_to_lower (key), map); + else if (type == ISFUNC && func == rl_insert) + { + /* If the function that was shadowed was self-insert, we + somehow need a keymap with map[key].func == self-insert. + Let's use this one. */ + nt = m[key].type; + nf = m[key].function; + + m[key].type = type; + m[key].function = func; + r = _rl_dispatch (key, m); + m[key].type = nt; + m[key].function = nf; + } + else + r = _rl_dispatch (ANYOTHERKEY, m); + } + else if (r && map[ANYOTHERKEY].function) + { + /* We didn't match (r is probably -1), so return something to + tell the caller that it should try ANYOTHERKEY for an + overridden function. */ + _rl_unget_char (key); + _rl_dispatching_keymap = map; + return -2; + } + else if (r && got_subseq) + { + /* OK, back up the chain. */ + _rl_unget_char (key); + _rl_dispatching_keymap = map; + return -1; + } + + return r; +} + +/* **************************************************************** */ +/* */ +/* Initializations */ +/* */ +/* **************************************************************** */ + +/* Initialize readline (and terminal if not already). */ +int +rl_initialize () +{ + /* If we have never been called before, initialize the + terminal and data structures. */ + if (!rl_initialized) + { + RL_SETSTATE(RL_STATE_INITIALIZING); + readline_initialize_everything (); + RL_UNSETSTATE(RL_STATE_INITIALIZING); + rl_initialized++; + RL_SETSTATE(RL_STATE_INITIALIZED); + } + + /* Initalize the current line information. */ + _rl_init_line_state (); + + /* We aren't done yet. We haven't even gotten started yet! */ + rl_done = 0; + RL_UNSETSTATE(RL_STATE_DONE); + + /* Tell the history routines what is going on. */ + _rl_start_using_history (); + + /* Make the display buffer match the state of the line. */ + rl_reset_line_state (); + + /* No such function typed yet. */ + rl_last_func = (rl_command_func_t *)NULL; + + /* Parsing of key-bindings begins in an enabled state. */ + _rl_parsing_conditionalized_out = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + _rl_vi_initialize_line (); +#endif + + /* Each line starts in insert mode (the default). */ + _rl_set_insert_mode (RL_IM_DEFAULT, 1); + + return 0; +} + +#if 0 +#if defined (__EMX__) +static void +_emx_build_environ () +{ + TIB *tibp; + PIB *pibp; + char *t, **tp; + int c; + + DosGetInfoBlocks (&tibp, &pibp); + t = pibp->pib_pchenv; + for (c = 1; *t; c++) + t += strlen (t) + 1; + tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *)); + t = pibp->pib_pchenv; + while (*t) + { + *tp++ = t; + t += strlen (t) + 1; + } + *tp = 0; +} +#endif /* __EMX__ */ +#endif + +/* Initialize the entire state of the world. */ +static void +readline_initialize_everything () +{ +#if 0 +#if defined (__EMX__) + if (environ == 0) + _emx_build_environ (); +#endif +#endif + +#if 0 + /* Find out if we are running in Emacs -- UNUSED. */ + running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; +#endif + + /* Set up input and output if they are not already set up. */ + if (!rl_instream) + rl_instream = stdin; + + if (!rl_outstream) + rl_outstream = stdout; + + /* Bind _rl_in_stream and _rl_out_stream immediately. These values + may change, but they may also be used before readline_internal () + is called. */ + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; + + /* Allocate data structures. */ + if (rl_line_buffer == 0) + rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); + + /* Initialize the terminal interface. */ + if (rl_terminal_name == 0) + rl_terminal_name = sh_get_env_value ("TERM"); + _rl_init_terminal_io (rl_terminal_name); + + /* Bind tty characters to readline functions. */ + readline_default_bindings (); + + /* Initialize the function names. */ + rl_initialize_funmap (); + + /* Decide whether we should automatically go into eight-bit mode. */ + _rl_init_eightbit (); + + /* Read in the init file. */ + rl_read_init_file ((char *)NULL); + + /* XXX */ + if (_rl_horizontal_scroll_mode && _rl_term_autowrap) + { + _rl_screenwidth--; + _rl_screenchars -= _rl_screenheight; + } + + /* Override the effect of any `set keymap' assignments in the + inputrc file. */ + rl_set_keymap_from_edit_mode (); + + /* Try to bind a common arrow key prefix, if not already bound. */ + bind_arrow_keys (); + + /* Enable the meta key, if this terminal has one. */ + if (_rl_enable_meta) + _rl_enable_meta_key (); + + /* If the completion parser's default word break characters haven't + been set yet, then do so now. */ + if (rl_completer_word_break_characters == (char *)NULL) + rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; +} + +/* If this system allows us to look at the values of the regular + input editing characters, then bind them to their readline + equivalents, iff the characters are not bound to keymaps. */ +static void +readline_default_bindings () +{ + if (_rl_bind_stty_chars) + rl_tty_set_default_bindings (_rl_keymap); +} + +/* Reset the default bindings for the terminal special characters we're + interested in back to rl_insert and read the new ones. */ +static void +reset_default_bindings () +{ + if (_rl_bind_stty_chars) + { + rl_tty_unset_default_bindings (_rl_keymap); + rl_tty_set_default_bindings (_rl_keymap); + } +} + +/* Bind some common arrow key sequences in MAP. */ +static void +bind_arrow_keys_internal (map) + Keymap map; +{ + Keymap xkeymap; + + xkeymap = _rl_keymap; + _rl_keymap = map; + +#if defined (__MSDOS__) + rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); +#endif + + rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); + + rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); + +#if defined (__MINGW32__) + rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\340M", rl_forward_char); + rl_bind_keyseq_if_unbound ("\340K", rl_backward_char); +#endif + + _rl_keymap = xkeymap; +} + +/* Try and bind the common arrow key prefixes after giving termcap and + the inputrc file a chance to bind them and create `real' keymaps + for the arrow key prefix. */ +static void +bind_arrow_keys () +{ + bind_arrow_keys_internal (emacs_standard_keymap); + +#if defined (VI_MODE) + bind_arrow_keys_internal (vi_movement_keymap); + /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC + in vi command mode while still allowing the arrow keys to work. */ + if (vi_movement_keymap[ESC].type == ISKMAP) + rl_bind_key_in_map (ESC, (rl_command_func_t *)NULL, vi_movement_keymap); + bind_arrow_keys_internal (vi_insertion_keymap); +#endif +} + +/* **************************************************************** */ +/* */ +/* Saving and Restoring Readline's state */ +/* */ +/* **************************************************************** */ + +int +rl_save_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + sp->point = rl_point; + sp->end = rl_end; + sp->mark = rl_mark; + sp->buffer = rl_line_buffer; + sp->buflen = rl_line_buffer_len; + sp->ul = rl_undo_list; + sp->prompt = rl_prompt; + + sp->rlstate = rl_readline_state; + sp->done = rl_done; + sp->kmap = _rl_keymap; + + sp->lastfunc = rl_last_func; + sp->insmode = rl_insert_mode; + sp->edmode = rl_editing_mode; + sp->kseqlen = rl_key_sequence_length; + sp->inf = rl_instream; + sp->outf = rl_outstream; + sp->pendingin = rl_pending_input; + sp->macro = rl_executing_macro; + + sp->catchsigs = rl_catch_signals; + sp->catchsigwinch = rl_catch_sigwinch; + + return (0); +} + +int +rl_restore_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + rl_point = sp->point; + rl_end = sp->end; + rl_mark = sp->mark; + the_line = rl_line_buffer = sp->buffer; + rl_line_buffer_len = sp->buflen; + rl_undo_list = sp->ul; + rl_prompt = sp->prompt; + + rl_readline_state = sp->rlstate; + rl_done = sp->done; + _rl_keymap = sp->kmap; + + rl_last_func = sp->lastfunc; + rl_insert_mode = sp->insmode; + rl_editing_mode = sp->edmode; + rl_key_sequence_length = sp->kseqlen; + rl_instream = sp->inf; + rl_outstream = sp->outf; + rl_pending_input = sp->pendingin; + rl_executing_macro = sp->macro; + + rl_catch_signals = sp->catchsigs; + rl_catch_sigwinch = sp->catchsigwinch; + + return (0); +} diff --git a/lib/readline/readline.h b/lib/readline/readline.h index fa02dec0d..94c258992 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -151,6 +151,7 @@ extern int rl_complete PARAMS((int, int)); extern int rl_possible_completions PARAMS((int, int)); extern int rl_insert_completions PARAMS((int, int)); extern int rl_menu_complete PARAMS((int, int)); +extern int rl_backward_menu_complete PARAMS((int, int)); /* Bindable commands for killing and yanking text, and managing the kill ring. */ extern int rl_kill_word PARAMS((int, int)); diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 8ae795a53..492185b9a 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -349,6 +349,7 @@ extern void _rl_trace (); extern int _rl_tropen PARAMS((void)); extern int _rl_abort_internal PARAMS((void)); +extern int _rl_null_function PARAMS((int, int)); extern char *_rl_strindex PARAMS((const char *, const char *)); extern int _rl_qsort_string_compare PARAMS((char **, char **)); extern int (_rl_uppercase_p) PARAMS((int)); diff --git a/lib/readline/rlprivate.h~ b/lib/readline/rlprivate.h~ index f575c14a9..8ae795a53 100644 --- a/lib/readline/rlprivate.h~ +++ b/lib/readline/rlprivate.h~ @@ -300,6 +300,8 @@ extern void _rl_signal_handler PARAMS((int)); extern void _rl_block_sigint PARAMS((void)); extern void _rl_release_sigint PARAMS((void)); +extern void _rl_block_sigwinch PARAMS((void)); +extern void _rl_release_sigwinch PARAMS((void)); /* terminal.c */ extern void _rl_get_screen_size PARAMS((int, int)); diff --git a/lib/readline/util.c b/lib/readline/util.c index 3a3e91ecf..a07cb1043 100644 --- a/lib/readline/util.c +++ b/lib/readline/util.c @@ -120,6 +120,13 @@ rl_abort (count, key) return (_rl_abort_internal ()); } +int +_rl_null_function (count, key) + int count, key; +{ + return 0; +} + int rl_tty_status (count, key) int count, key; diff --git a/lib/readline/util.c~ b/lib/readline/util.c~ new file mode 100644 index 000000000..991af24f7 --- /dev/null +++ b/lib/readline/util.c~ @@ -0,0 +1,512 @@ +/* util.c -- readline utility functions */ + +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. + + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include +#include "posixjmp.h" + +#if defined (HAVE_UNISTD_H) +# include /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (TIOCSTAT_IN_SYS_IOCTL) +# include +#endif /* TIOCSTAT_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Return 0 if C is not a member of the class of characters that belong + in words, or 1 if it is. */ + +int _rl_allow_pathname_alphabetic_chars = 0; +static const char * const pathname_alphabetic_chars = "/-_=~.#$"; + +int +rl_alphabetic (c) + int c; +{ + if (ALPHABETIC (c)) + return (1); + + return (_rl_allow_pathname_alphabetic_chars && + strchr (pathname_alphabetic_chars, c) != NULL); +} + +#if defined (HANDLE_MULTIBYTE) +int +_rl_walphabetic (wc) + wchar_t wc; +{ + int c; + + if (iswalnum (wc)) + return (1); + + c = wc & 0177; + return (_rl_allow_pathname_alphabetic_chars && + strchr (pathname_alphabetic_chars, c) != NULL); +} +#endif + +/* How to abort things. */ +int +_rl_abort_internal () +{ + rl_ding (); + rl_clear_message (); + _rl_reset_argument (); + rl_clear_pending_input (); + + RL_UNSETSTATE (RL_STATE_MACRODEF); + while (rl_executing_macro) + _rl_pop_executing_macro (); + + rl_last_func = (rl_command_func_t *)NULL; + longjmp (_rl_top_level, 1); + return (0); +} + +int +rl_abort (count, key) + int count, key; +{ + return (_rl_abort_internal ()); +} + +int +_rl_null_func (count, key) + int count, key; +{ + return 0; +} + +int +rl_tty_status (count, key) + int count, key; +{ +#if defined (TIOCSTAT) + ioctl (1, TIOCSTAT, (char *)0); + rl_refresh_line (count, key); +#else + rl_ding (); +#endif + return 0; +} + +/* Return a copy of the string between FROM and TO. + FROM is inclusive, TO is not. */ +char * +rl_copy_text (from, to) + int from, to; +{ + register int length; + char *copy; + + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + length = to - from; + copy = (char *)xmalloc (1 + length); + strncpy (copy, rl_line_buffer + from, length); + copy[length] = '\0'; + return (copy); +} + +/* Increase the size of RL_LINE_BUFFER until it has enough space to hold + LEN characters. */ +void +rl_extend_line_buffer (len) + int len; +{ + while (len >= rl_line_buffer_len) + { + rl_line_buffer_len += DEFAULT_BUFFER_SIZE; + rl_line_buffer = (char *)xrealloc (rl_line_buffer, rl_line_buffer_len); + } + + _rl_set_the_line (); +} + + +/* A function for simple tilde expansion. */ +int +rl_tilde_expand (ignore, key) + int ignore, key; +{ + register int start, end; + char *homedir, *temp; + int len; + + end = rl_point; + start = end - 1; + + if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') + { + homedir = tilde_expand ("~"); + _rl_replace_text (homedir, start, end); + xfree (homedir); + return (0); + } + else if (rl_line_buffer[start] != '~') + { + for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) + ; + start++; + } + + end = start; + do + end++; + while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); + + if (whitespace (rl_line_buffer[end]) || end >= rl_end) + end--; + + /* If the first character of the current word is a tilde, perform + tilde expansion and insert the result. If not a tilde, do + nothing. */ + if (rl_line_buffer[start] == '~') + { + len = end - start + 1; + temp = (char *)xmalloc (len + 1); + strncpy (temp, rl_line_buffer + start, len); + temp[len] = '\0'; + homedir = tilde_expand (temp); + xfree (temp); + + _rl_replace_text (homedir, start, end); + xfree (homedir); + } + + return (0); +} + +#if defined (USE_VARARGS) +void +#if defined (PREFER_STDARG) +_rl_ttymsg (const char *format, ...) +#else +_rl_ttymsg (va_alist) + va_dcl +#endif +{ + va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); + format = va_arg (args, char *); +#endif + + fprintf (stderr, "readline: "); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + fflush (stderr); + + va_end (args); + + rl_forced_update_display (); +} + +void +#if defined (PREFER_STDARG) +_rl_errmsg (const char *format, ...) +#else +_rl_errmsg (va_alist) + va_dcl +#endif +{ + va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); + format = va_arg (args, char *); +#endif + + fprintf (stderr, "readline: "); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + fflush (stderr); + + va_end (args); +} + +#else /* !USE_VARARGS */ +void +_rl_ttymsg (format, arg1, arg2) + char *format; +{ + fprintf (stderr, "readline: "); + fprintf (stderr, format, arg1, arg2); + fprintf (stderr, "\n"); + + rl_forced_update_display (); +} + +void +_rl_errmsg (format, arg1, arg2) + char *format; +{ + fprintf (stderr, "readline: "); + fprintf (stderr, format, arg1, arg2); + fprintf (stderr, "\n"); +} +#endif /* !USE_VARARGS */ + +/* **************************************************************** */ +/* */ +/* String Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Determine if s2 occurs in s1. If so, return a pointer to the + match in s1. The compare is case insensitive. */ +char * +_rl_strindex (s1, s2) + register const char *s1, *s2; +{ + register int i, l, len; + + for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++) + if (_rl_strnicmp (s1 + i, s2, l) == 0) + return ((char *) (s1 + i)); + return ((char *)NULL); +} + +#ifndef HAVE_STRPBRK +/* Find the first occurrence in STRING1 of any character from STRING2. + Return a pointer to the character in STRING1. */ +char * +_rl_strpbrk (string1, string2) + const char *string1, *string2; +{ + register const char *scan; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + register int i, v; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + for (; *string1; string1++) + { + for (scan = string2; *scan; scan++) + { + if (*string1 == *scan) + return ((char *)string1); + } +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + v = _rl_get_char_len (string1, &ps); + if (v > 1) + string1 += v - 1; /* -1 to account for auto-increment in loop */ + } +#endif + } + return ((char *)NULL); +} +#endif + +#if !defined (HAVE_STRCASECMP) +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +_rl_strnicmp (string1, string2, count) + char *string1, *string2; + int count; +{ + register char ch1, ch2; + + while (count) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) == _rl_to_upper(ch2)) + count--; + else + break; + } + return (count); +} + +/* strcmp (), but caseless. */ +int +_rl_stricmp (string1, string2) + char *string1, *string2; +{ + register char ch1, ch2; + + while (*string1 && *string2) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) != _rl_to_upper(ch2)) + return (1); + } + return (*string1 - *string2); +} +#endif /* !HAVE_STRCASECMP */ + +/* Stupid comparison routine for qsort () ing strings. */ +int +_rl_qsort_string_compare (s1, s2) + char **s1, **s2; +{ +#if defined (HAVE_STRCOLL) + return (strcoll (*s1, *s2)); +#else + int result; + + result = **s1 - **s2; + if (result == 0) + result = strcmp (*s1, *s2); + + return result; +#endif +} + +/* Function equivalents for the macros defined in chardefs.h. */ +#define FUNCTION_FOR_MACRO(f) int (f) (c) int c; { return f (c); } + +FUNCTION_FOR_MACRO (_rl_digit_p) +FUNCTION_FOR_MACRO (_rl_digit_value) +FUNCTION_FOR_MACRO (_rl_lowercase_p) +FUNCTION_FOR_MACRO (_rl_pure_alphabetic) +FUNCTION_FOR_MACRO (_rl_to_lower) +FUNCTION_FOR_MACRO (_rl_to_upper) +FUNCTION_FOR_MACRO (_rl_uppercase_p) + +/* A convenience function, to force memory deallocation to be performed + by readline. DLLs on Windows apparently require this. */ +void +rl_free (mem) + void *mem; +{ + if (mem) + free (mem); +} + +/* Backwards compatibility, now that savestring has been removed from + all `public' readline header files. */ +#undef _rl_savestring +char * +_rl_savestring (s) + const char *s; +{ + return (strcpy ((char *)xmalloc (1 + (int)strlen (s)), (s))); +} + +#if defined (USE_VARARGS) +static FILE *_rl_tracefp; + +void +#if defined (PREFER_STDARG) +_rl_trace (const char *format, ...) +#else +_rl_trace (va_alist) + va_dcl +#endif +{ + va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); + format = va_arg (args, char *); +#endif + + if (_rl_tracefp == 0) + _rl_tropen (); + vfprintf (_rl_tracefp, format, args); + fprintf (_rl_tracefp, "\n"); + fflush (_rl_tracefp); + + va_end (args); +} + +int +_rl_tropen () +{ + char fnbuf[128]; + + if (_rl_tracefp) + fclose (_rl_tracefp); + sprintf (fnbuf, "/var/tmp/rltrace.%ld", getpid()); + unlink(fnbuf); + _rl_tracefp = fopen (fnbuf, "w+"); + return _rl_tracefp != 0; +} + +int +_rl_trclose () +{ + int r; + + r = fclose (_rl_tracefp); + _rl_tracefp = 0; + return r; +} + +#endif diff --git a/lib/readline/vi_keymap.c b/lib/readline/vi_keymap.c index 36631730e..ba5a27ba6 100644 --- a/lib/readline/vi_keymap.c +++ b/lib/readline/vi_keymap.c @@ -326,9 +326,9 @@ KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { { ISFUNC, rl_insert }, /* Control-k */ { ISFUNC, rl_insert }, /* Control-l */ { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_insert }, /* Control-n */ + { ISFUNC, rl_menu_complete}, /* Control-n */ { ISFUNC, rl_insert }, /* Control-o */ - { ISFUNC, rl_insert }, /* Control-p */ + { ISFUNC, rl_backward_menu_complete }, /* Control-p */ { ISFUNC, rl_insert }, /* Control-q */ { ISFUNC, rl_reverse_search_history }, /* Control-r */ { ISFUNC, rl_forward_search_history }, /* Control-s */ diff --git a/pcomplete.c b/pcomplete.c index aa99774ce..4dc5a5c8a 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -653,7 +653,7 @@ gen_matches_from_itemlist (itp, text) if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) || (itp->flags & LIST_INITIALIZED) == 0) { - if (itp->flags & (LIST_DIRTY | LIST_DYNAMIC)) + if (itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) clean_itemlist (itp); if ((itp->flags & LIST_INITIALIZED) == 0) initialize_itemlist (itp); @@ -1437,16 +1437,16 @@ programmable_completions (cmd, word, start, end, foundp) pcomp_curcs = cs; pcomp_curcmd = cmd; - /* Signal the caller that we found a COMPSPEC for this command, and pass - back any meta-options associated with the compspec. */ - if (foundp) - *foundp = 1|cs->options; - ret = gen_compspec_completions (cs, cmd, word, start, end); pcomp_curcs = oldcs; pcomp_curcmd = oldcmd; + /* Signal the caller that we found a COMPSPEC for this command, and pass + back any meta-options associated with the compspec. */ + if (foundp) + *foundp = 1|cs->options; + compspec_dispose (cs); if (ret) diff --git a/pcomplete.c~ b/pcomplete.c~ index e1ccaac86..44740e515 100644 --- a/pcomplete.c~ +++ b/pcomplete.c~ @@ -1032,6 +1032,7 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw) cmdlist = build_arg_list (funcname, text, lwords, cw); pps = &ps; + save_parser_state (pps); begin_unwind_frame ("gen-shell-function-matches"); add_unwind_protect (restore_parser_state, (char *)pps); add_unwind_protect (dispose_words, (char *)cmdlist); @@ -1436,16 +1437,16 @@ programmable_completions (cmd, word, start, end, foundp) pcomp_curcs = cs; pcomp_curcmd = cmd; - /* Signal the caller that we found a COMPSPEC for this command, and pass - back any meta-options associated with the compspec. */ - if (foundp) - *foundp = 1|cs->options; - ret = gen_compspec_completions (cs, cmd, word, start, end); pcomp_curcs = oldcs; pcomp_curcmd = oldcmd; + /* Signal the caller that we found a COMPSPEC for this command, and pass + back any meta-options associated with the compspec. */ + if (foundp) + *foundp = 1|cs->options; + compspec_dispose (cs); if (ret) diff --git a/shell.c b/shell.c index 1ec062fce..c5f6d8b8f 100644 --- a/shell.c +++ b/shell.c @@ -892,6 +892,9 @@ void exit_shell (s) int s; { + fflush (stdout); /* XXX */ + fflush (stderr); + /* Do trap[0] if defined. Allow it to override the exit status passed to us. */ if (signal_is_trapped (0)) diff --git a/subst.c b/subst.c index bb73131b6..63218f2d9 100644 --- a/subst.c +++ b/subst.c @@ -314,6 +314,135 @@ static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); /* */ /* **************************************************************** */ +#if defined (DEBUG) +void +dump_word_flags (flags) + int flags; +{ + int f; + + f = flags; + fprintf (stderr, "%d -> ", f); + if (f & W_ASSIGNASSOC) + { + f &= ~W_ASSIGNASSOC; + fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); + } + if (f & W_HASCTLESC) + { + f &= ~W_HASCTLESC; + fprintf (stderr, "W_HASCTLESC%s", f ? "|" : ""); + } + if (f & W_NOPROCSUB) + { + f &= ~W_NOPROCSUB; + fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); + } + if (f & W_DQUOTE) + { + f &= ~W_DQUOTE; + fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); + } + if (f & W_HASQUOTEDNULL) + { + f &= ~W_HASQUOTEDNULL; + fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); + } + if (f & W_ASSIGNARG) + { + f &= ~W_ASSIGNARG; + fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); + } + if (f & W_ASSNBLTIN) + { + f &= ~W_ASSNBLTIN; + fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); + } + if (f & W_COMPASSIGN) + { + f &= ~W_COMPASSIGN; + fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); + } + if (f & W_NOEXPAND) + { + f &= ~W_NOEXPAND; + fprintf (stderr, "W_NOEXPAND%s", f ? "|" : ""); + } + if (f & W_ITILDE) + { + f &= ~W_ITILDE; + fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); + } + if (f & W_NOTILDE) + { + f &= ~W_NOTILDE; + fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); + } + if (f & W_ASSIGNRHS) + { + f &= ~W_ASSIGNRHS; + fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); + } + if (f & W_NOCOMSUB) + { + f &= ~W_NOCOMSUB; + fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); + } + if (f & W_DOLLARSTAR) + { + f &= ~W_DOLLARSTAR; + fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); + } + if (f & W_DOLLARAT) + { + f &= ~W_DOLLARAT; + fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); + } + if (f & W_TILDEEXP) + { + f &= ~W_TILDEEXP; + fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); + } + if (f & W_NOSPLIT2) + { + f &= ~W_NOSPLIT2; + fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); + } + if (f & W_NOGLOB) + { + f &= ~W_NOGLOB; + fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); + } + if (f & W_NOSPLIT) + { + f &= ~W_NOSPLIT; + fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); + } + if (f & W_GLOBEXP) + { + f &= ~W_GLOBEXP; + fprintf (stderr, "W_GLOBEXP%s", f ? "|" : ""); + } + if (f & W_ASSIGNMENT) + { + f &= ~W_ASSIGNMENT; + fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); + } + if (f & W_QUOTED) + { + f &= ~W_QUOTED; + fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); + } + if (f & W_HASDOLLAR) + { + f &= ~W_HASDOLLAR; + fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); + } + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif + #ifdef INCLUDE_UNUSED static char * quoted_substring (string, start, end) diff --git a/variables.c~ b/variables.c~ index 8920bad1d..1d1fa7472 100644 --- a/variables.c~ +++ b/variables.c~ @@ -221,9 +221,11 @@ static SHELL_VAR *get_groupset __P((SHELL_VAR *)); static SHELL_VAR *build_hashcmd __P((SHELL_VAR *)); static SHELL_VAR *get_hashcmd __P((SHELL_VAR *)); static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) static SHELL_VAR *build_aliasvar __P((SHELL_VAR *)); static SHELL_VAR *get_aliasvar __P((SHELL_VAR *)); static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *)); +# endif #endif static SHELL_VAR *get_funcname __P((SHELL_VAR *)); @@ -252,6 +254,7 @@ static SHELL_VAR **fapply __P((sh_var_map_func_t *)); static int visible_var __P((SHELL_VAR *)); static int visible_and_exported __P((SHELL_VAR *)); +static int export_environment_candidate __P((SHELL_VAR *)); static int local_and_exported __P((SHELL_VAR *)); static int variable_in_context __P((SHELL_VAR *)); #if defined (ARRAY_VARS) @@ -375,10 +378,17 @@ initialize_shell_variables (env, privmode) } # endif #endif +#if 0 else if (legal_identifier (name)) +#else + else +#endif { temp_var = bind_variable (name, string, 0); - VSETATTR (temp_var, (att_exported | att_imported)); + if (legal_identifier (name)) + VSETATTR (temp_var, (att_exported | att_imported)); + else + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); array_needs_making = 1; } @@ -867,7 +877,7 @@ make_vers_array () vv = make_new_array_variable ("BASH_VERSINFO"); av = array_cell (vv); strcpy (d, dist_version); - s = xstrchr (d, '.'); + s = strchr (d, '.'); if (s) *s++ = '\0'; array_insert (av, 0, d); @@ -1548,6 +1558,7 @@ assign_hashcmd (self, value, ind, key) return (build_hashcmd (self)); } +#if defined (ALIAS) static SHELL_VAR * build_aliasvar (self) SHELL_VAR *self; @@ -1600,6 +1611,8 @@ assign_aliasvar (self, value, ind, key) add_alias (key, value); return (build_aliasvar (self)); } +#endif /* ALIAS */ + #endif /* ARRAY_VARS */ /* If ARRAY_VARS is not defined, this just returns the name of any @@ -1695,7 +1708,9 @@ initialize_dynamic_variables () v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif #endif v = init_funcname_var (); @@ -3082,6 +3097,16 @@ visible_and_exported (var) return (invisible_p (var) == 0 && exported_p (var)); } +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + /* Return non-zero if VAR is a local variable in the current context and is exported. */ static int @@ -3438,7 +3463,11 @@ make_var_export_array (vcxt) char **list; SHELL_VAR **vars; +#if 0 vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif if (vars == 0) return (char **)NULL; @@ -3587,7 +3616,7 @@ maybe_make_export_env () } export_env[export_env_index = 0] = (char *)NULL; - /* Make a dummy variable context from the temporary_env, stick it on + /* Make a dummy variable context from the temporary_env, stick it on the front of shell_variables, call make_var_export_array on the whole thing to flatten it, and convert the list of SHELL_VAR *s to the form needed by the environment. */ @@ -4275,6 +4304,12 @@ sv_hostfile (name) clear_hostname_list (); else hostname_list_initialized = 0; + +#if 0 +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_hostnames); +#endif +#endif } #if defined (STRICT_POSIX)