X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=readline%2Fbind.c;h=a939528862ff194c2c9999ccd9ae3cd3435440e0;hb=722a5e98ea14fbc41acfb561ff4db6bfc43593bf;hp=a7ffe25dfa6145d718efdab963bbfe0f27977ed5;hpb=5e98bbab1738932aeeb251684bba6aa550f5885a;p=deliverable%2Fbinutils-gdb.git diff --git a/readline/bind.c b/readline/bind.c index a7ffe25dfa..a939528862 100644 --- a/readline/bind.c +++ b/readline/bind.c @@ -1,39 +1,59 @@ /* bind.c -- key binding and startup file support for the readline library. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2010 Free Software Foundation, Inc. - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 1, or + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 "sysdep.h" #include #include #include -#ifndef NO_SYS_FILE -#include -#endif +#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 -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ + #if !defined (errno) extern int errno; #endif /* !errno */ +#include "posixstat.h" + /* System-specific feature definitions and include files. */ #include "rldefs.h" @@ -41,42 +61,30 @@ extern int errno; #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__ */ -extern char *tilde_expand (); - -extern int _rl_horizontal_scroll_mode; -extern int _rl_mark_modified_lines; -extern int _rl_prefer_visible_bell; -extern int _rl_meta_flag; -extern int rl_blink_matching_paren; -extern int _rl_convert_meta_chars_to_ascii; -#if defined (VISIBLE_STATS) -extern int rl_visible_stats; -#endif /* VISIBLE_STATS */ -extern int rl_complete_with_tilde_expansion; -extern int rl_completion_query_items; - -extern int rl_explicit_arg; -extern int rl_editing_mode; -extern unsigned short _rl_parsing_conditionalized_out; -extern Keymap _rl_keymap; +/* Variables exported by this file. */ +Keymap rl_binding_keymap; -extern char *possible_control_prefixes[], *possible_meta_prefixes[]; +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 *)); -extern char **rl_funmap_names (); +static char *_rl_get_string_variable_value PARAMS((const char *)); +static int substring_member_of_array PARAMS((const char *, const char * const *)); -static void rl_generic_bind (); -static int glean_key_from_name (); -static int stricmp (), strnicmp (); +static int currently_reading_init_file; -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else -extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ +/* used only in this file */ +static int _rl_prefer_visible_bell = 1; /* **************************************************************** */ /* */ @@ -84,24 +92,26 @@ extern char *xmalloc (), *xrealloc (); /* */ /* **************************************************************** */ -/* rl_add_defun (char *name, Function *function, int key) +/* 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) - char *name; - Function *function; + 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; - Function *function; + rl_command_func_t *function; { if (key < 0) return (key); @@ -110,8 +120,9 @@ rl_bind_key (key, function) { if (_rl_keymap[ESC].type == ISKMAP) { - Keymap escmap = (Keymap)_rl_keymap[ESC].function; + Keymap escmap; + escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); key = UNMETA (key); escmap[key].type = ISFUNC; escmap[key].function = function; @@ -122,6 +133,7 @@ rl_bind_key (key, function) _rl_keymap[key].type = ISFUNC; _rl_keymap[key].function = function; + rl_binding_keymap = _rl_keymap; return (0); } @@ -130,25 +142,54 @@ rl_bind_key (key, function) int rl_bind_key_in_map (key, function, map) int key; - Function *function; + rl_command_func_t *function; Keymap map; { int result; - Keymap oldmap = _rl_keymap; + 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, (Function *)NULL)); + return (rl_bind_key (key, (rl_command_func_t *)NULL)); } /* Make KEY do nothing in MAP. @@ -158,25 +199,114 @@ rl_unbind_key_in_map (key, map) int key; Keymap map; { - return (rl_bind_key_in_map (key, (Function *)NULL, 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) - char *keyseq; - Function *function; + const char *keyseq; + rl_command_func_t *function; Keymap map; { - rl_generic_bind (ISFUNC, keyseq, function, 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) - char *keyseq, *macro; + const char *keyseq, *macro; Keymap map; { char *macro_keys; @@ -186,10 +316,11 @@ rl_macro_bind (keyseq, macro, map) if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) { - free (macro_keys); - return; + 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 @@ -197,123 +328,237 @@ rl_macro_bind (keyseq, macro, map) 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. */ - -static void +int rl_generic_bind (type, keyseq, data, map) int type; - char *keyseq, *data; + 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 || !*keyseq) + if (keyseq == 0 || *keyseq == 0) { if (type == ISMACR) - free (data); - return; + xfree (data); + return -1; } - keys = (char *)alloca (1 + (2 * strlen (keyseq))); + 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)) - return; + { + xfree (keys); + return -1; + } /* Bind keys, making new keymaps as necessary. */ for (i = 0; i < keys_len; i++) { - int ic = (int) ((unsigned char)keys[i]); + unsigned char uc = keys[i]; + int ic; + + ic = uc; + if (ic < 0 || ic >= KEYMAP_SIZE) + { + xfree (keys); + return -1; + } - if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic)) + if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) { ic = UNMETA (ic); if (map[ESC].type == ISKMAP) - map = (Keymap) map[ESC].function; + map = FUNCTION_TO_KEYMAP (map, ESC); } if ((i + 1) < keys_len) { if (map[ic].type != ISKMAP) { - if (map[ic].type == ISMACR) - free ((char *)map[ic].function); + /* 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 = (Function *)rl_make_bare_keymap (); + 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; } - map = (Keymap)map[ic].function; } else { if (map[ic].type == ISMACR) - free ((char *)map[ic].function); + 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 = (char *)_rl_null_function; + } - map[ic].function = (Function *)data; + 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) - char *seq, *array; + const char *seq; + char *array; int *len; { - register int i, c, l = 0; + register int i, c, l, temp; - for (i = 0; c = seq[i]; i++) + for (i = l = 0; c = seq[i]; i++) { if (c == '\\') { c = seq[++i]; - if (!c) + if (c == 0) break; - if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || - (c == 'e')) + /* 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; + array[l++] = ESC; /* ESC is meta-prefix */ i += 5; - array[l++] = CTRL (to_upper (seq[i])); - if (!seq[i]) + array[l++] = CTRL (_rl_to_upper (seq[i])); + if (seq[i] == '\0') i--; - continue; } - - switch (c) + 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') { - case 'M': - i++; - array[l++] = ESC; - break; - - case 'C': i += 2; /* Special hack for C-?... */ - if (seq[i] == '?') - array[l++] = RUBOUT; - else - array[l++] = CTRL (to_upper (seq[i])); - break; - - case 'e': - array[l++] = ESC; + 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; } @@ -322,21 +567,124 @@ rl_translate_keyseq (seq, array, len) 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. */ -Function * +rl_command_func_t * rl_named_function (string) - char *string; + const char *string; { register int i; rl_initialize_funmap (); for (i = 0; funmap[i]; i++) - if (stricmp (funmap[i]->name, string) == 0) + if (_rl_stricmp (funmap[i]->name, string) == 0) return (funmap[i]->function); - return ((Function *)NULL); + return ((rl_command_func_t *)NULL); } /* Return the function (or macro) definition which would be invoked via @@ -344,42 +692,44 @@ rl_named_function (string) 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). */ -Function * +rl_command_func_t * rl_function_of_keyseq (keyseq, map, type) - char *keyseq; + const char *keyseq; Keymap map; int *type; { register int i; - if (!map) + if (map == 0) map = _rl_keymap; for (i = 0; keyseq && keyseq[i]; i++) { - int ic = keyseq[i]; + unsigned char ic = keyseq[i]; if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) { - if (map[ESC].type != ISKMAP) + 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); } - else - { - map = (Keymap)map[ESC].function; - ic = UNMETA (ic); - } } if (map[ic].type == ISKMAP) { /* If this is the last key in the key sequence, return the map. */ - if (!keyseq[i + 1]) + if (keyseq[i + 1] == '\0') { if (type) *type = ISKMAP; @@ -387,9 +737,14 @@ rl_function_of_keyseq (keyseq, map, type) return (map[ic].function); } else - map = (Keymap)map[ic].function; + map = FUNCTION_TO_KEYMAP (map, ic); } - else + /* 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; @@ -397,112 +752,216 @@ rl_function_of_keyseq (keyseq, map, 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; { - rl_read_init_file ((char *)NULL); + int r; + r = rl_read_init_file ((const char *)NULL); + rl_set_keymap_from_edit_mode (); + return r; } -/* The final, last-ditch effort file name for an init file. */ -#ifdef __MSDOS__ -/* Don't know what to do, but this is a guess */ -#define DEFAULT_INPUTRC "/INPUTRC"; -#else -#define DEFAULT_INPUTRC "~/.inputrc" -#endif - /* Do key bindings from a file. If FILENAME is NULL it defaults - to `~/.inputrc'. If the file existed and could be opened and - read, 0 is returned, otherwise errno is returned. */ + 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) - char *filename; + const char *filename; { - register int i; - char *buffer, *openname, *line, *end; - struct stat finfo; - int file; - /* Default the filename. */ - if (!filename) + if (filename == 0) + filename = last_readline_init_file; + if (filename == 0) + filename = sh_get_env_value ("INPUTRC"); + if (filename == 0 || *filename == 0) { - if (last_readline_init_file) - filename = last_readline_init_file; - else - filename = DEFAULT_INPUTRC; + 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; } - openname = tilde_expand (filename); - - if (!openname || *openname == '\000') - return ENOENT; - - if ((stat (openname, &finfo) < 0) || - (file = open (openname, O_RDONLY, 0666)) < 0) - { - free (openname); - return (errno); - } - else - free (openname); +#if defined (__MSDOS__) + if (_rl_read_init_file (filename, 0) == 0) + return 0; + filename = "~/_inputrc"; +#endif + return (_rl_read_init_file (filename, 0)); +} - if (last_readline_init_file) - free (last_readline_init_file); +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; - last_readline_init_file = savestring (filename); + current_readline_init_file = filename; + current_readline_init_include_level = include_level; - /* Read the file into BUFFER. */ - buffer = (char *)xmalloc ((int)finfo.st_size + 1); - i = read (file, buffer, finfo.st_size); - close (file); + openname = tilde_expand (filename); + buffer = _rl_read_file (openname, &file_size); + xfree (openname); - if (i != finfo.st_size) + 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 + finfo.st_size; + 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++; } - free (buffer); + + 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]. */ -char *rl_readline_name = "other"; +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 = 0; -static int if_stack_size = 0; +static int if_stack_depth; +static int if_stack_size; /* Push _rl_parsing_conditionalized_out, and set parser state based on ARGS. */ @@ -533,16 +992,16 @@ parser_if (args) if (args[i]) args[i++] = '\0'; - /* Handle "if term=foo" and "if mode=emacs" constructs. If this + /* Handle "$if term=foo" and "$if mode=emacs" constructs. If this isn't term=foo, or mode=emacs, then check to see if the first word in ARGS is the same as the value stored in rl_readline_name. */ - if (rl_terminal_name && strnicmp (args, "term=", 5) == 0) + 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 = (char*) strrchr (tname, '-'); + tem = strchr (tname, '-'); if (tem) *tem = '\0'; @@ -550,35 +1009,28 @@ parser_if (args) 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. */ - if ((stricmp (args + 5, tname) == 0) || - (stricmp (args + 5, rl_terminal_name) == 0)) - _rl_parsing_conditionalized_out = 0; - else - _rl_parsing_conditionalized_out = 1; - - free (tname); + _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && + _rl_stricmp (args + 5, rl_terminal_name); + xfree (tname); } #if defined (VI_MODE) - else if (strnicmp (args, "mode=", 5) == 0) + else if (_rl_strnicmp (args, "mode=", 5) == 0) { int mode; - if (stricmp (args + 5, "emacs") == 0) + if (_rl_stricmp (args + 5, "emacs") == 0) mode = emacs_mode; - else if (stricmp (args + 5, "vi") == 0) + else if (_rl_stricmp (args + 5, "vi") == 0) mode = vi_mode; else mode = no_mode; - if (mode == rl_editing_mode) - _rl_parsing_conditionalized_out = 0; - else - _rl_parsing_conditionalized_out = 1; + _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 (stricmp (args, rl_readline_name) == 0) + else if (_rl_stricmp (args, rl_readline_name) == 0) _rl_parsing_conditionalized_out = 0; else _rl_parsing_conditionalized_out = 1; @@ -592,15 +1044,21 @@ parser_else (args) { register int i; - if (!if_stack_depth) + if (if_stack_depth == 0) { - /* Error message? */ + _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; @@ -618,21 +1076,47 @@ parser_endif (args) if (if_stack_depth) _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; else - { - /* *** What, no error message? *** */ - } + _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 struct { - char *name; - Function *function; +static const struct { + const char * const name; + _rl_parser_func_t *function; } parser_directives [] = { { "if", parser_if }, { "endif", parser_endif }, { "else", parser_else }, - { (char *)0x0, (Function *)0x0 } + { "include", parser_include }, + { (char *)0x0, (_rl_parser_func_t *)0x0 } }; /* Handle a parser directive. STATEMENT is the line of the directive @@ -662,25 +1146,22 @@ handle_parser_directive (statement) /* Lookup the command, and act on it. */ for (i = 0; parser_directives[i].name; i++) - if (stricmp (directive, parser_directives[i].name) == 0) + if (_rl_stricmp (directive, parser_directives[i].name) == 0) { (*parser_directives[i].function) (args); return (0); } - /* *** Should an error message be output? */ + /* display an error message about the unknown parser directive */ + _rl_init_file_error ("unknown parser directive"); return (1); } -/* Ugly but working hack for binding prefix meta. */ -#define PREFIX_META_HACK - -static int substring_member_of_array (); - /* Read the binding command from STRING and perform it. A key binding command looks like: Keyname: function-name\0, a variable binding command looks like: set variable value. A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ +int rl_parse_and_bind (string) char *string; { @@ -692,18 +1173,18 @@ rl_parse_and_bind (string) string++; if (!string || !*string || *string == '#') - return; + return 0; /* If this is a parser directive, act on it. */ if (*string == '$') { handle_parser_directive (&string[1]); - return; + return 0; } /* If we aren't supposed to be parsing right now, then we're done. */ if (_rl_parsing_conditionalized_out) - return; + return 0; i = 0; /* If this keyname is a complex key expression surrounded by quotes, @@ -730,6 +1211,12 @@ rl_parse_and_bind (string) 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. */ @@ -746,23 +1233,37 @@ rl_parse_and_bind (string) string[i++] = '\0'; /* If this is a command to set a variable, then do that. */ - if (stricmp (string, "set") == 0) + if (_rl_stricmp (string, "set") == 0) { - char *var = string + i; - char *value; + 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. */ + /* 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; + return 0; } /* Skip any whitespace between keyname and funname. */ @@ -781,10 +1282,10 @@ rl_parse_and_bind (string) the quoted string delimiter, like the shell. */ if (*funname == '\'' || *funname == '"') { - int delimiter = string[i++]; - int passc = 0; + int delimiter, passc; - for (; c = string[i]; i++) + delimiter = string[i++]; + for (passc = 0; c = string[i]; i++) { if (passc) { @@ -815,18 +1316,18 @@ rl_parse_and_bind (string) whatever the right-hand evaluates to, including keymaps. */ if (equivalency) { - return; + return 0; } /* If this is a new-style key-binding, then do the binding with - rl_set_key (). Otherwise, let the older code deal with it. */ + rl_bind_keyseq (). Otherwise, let the older code deal with it. */ if (*string == '"') { - char *seq = (char *)alloca (1 + strlen (string)); - register int j, k = 0; - int passc = 0; + char *seq; + register int j, k, passc; - for (j = 1; string[j]; j++) + 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 @@ -858,13 +1359,14 @@ rl_parse_and_bind (string) rl_macro_bind (seq, &funname[1], _rl_keymap); } else - rl_set_key (seq, rl_named_function (funname), _rl_keymap); + rl_bind_keyseq (seq, rl_named_function (funname)); - return; + xfree (seq); + return 0; } /* Get the actual character we want to deal with. */ - kname = (char*) strrchr (string, '-'); + kname = strrchr (string, '-'); if (!kname) kname = string; else @@ -873,27 +1375,27 @@ rl_parse_and_bind (string) key = glean_key_from_name (kname); /* Add in control and meta bits. */ - if (substring_member_of_array (string, possible_control_prefixes)) - key = CTRL (to_upper (key)); + if (substring_member_of_array (string, _rl_possible_control_prefixes)) + key = CTRL (_rl_to_upper (key)); - if (substring_member_of_array (string, possible_meta_prefixes)) + 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 seq[2]; + char useq[2]; int fl = strlen (funname); - seq[0] = key; seq[1] = '\0'; + useq[0] = key; useq[1] = '\0'; if (fl && funname[fl - 1] == *funname) funname[fl - 1] = '\0'; - rl_macro_bind (seq, &funname[1], _rl_keymap); + rl_macro_bind (useq, &funname[1], _rl_keymap); } #if defined (PREFIX_META_HACK) /* Ugly, but working hack to keep prefix-meta around. */ - else if (stricmp (funname, "prefix-meta") == 0) + else if (_rl_stricmp (funname, "prefix-meta") == 0) { char seq[2]; @@ -904,112 +1406,372 @@ rl_parse_and_bind (string) #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. */ -static struct { - char *name; +#define V_SPECIAL 0x1 + +static const struct { + const char * const name; int *value; + int flags; } boolean_varlist [] = { - { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode }, - { "mark-modified-lines", &_rl_mark_modified_lines }, - { "prefer-visible-bell", &_rl_prefer_visible_bell }, - { "meta-flag", &_rl_meta_flag }, - { "blink-matching-paren", &rl_blink_matching_paren }, - { "convert-meta", &_rl_convert_meta_chars_to_ascii }, + { "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 }, + { "completion-map-case", &_rl_completion_case_map, 0 }, + { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, + { "disable-completion", &rl_inhibit_completion, 0 }, + { "echo-control-characters", &_rl_echo_control_chars, 0 }, + { "enable-keypad", &_rl_enable_keypad, 0 }, + { "enable-meta-key", &_rl_enable_meta, 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 }, + { "menu-complete-display-prefix", &_rl_menu_complete_prefix_first, 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 }, + { "skip-completed-text", &_rl_skip_completed_text, 0 }, #if defined (VISIBLE_STATS) - { "visible-stats", &rl_visible_stats }, + { "visible-stats", &rl_visible_stats, 0 }, #endif /* VISIBLE_STATS */ - { "expand-tilde", &rl_complete_with_tilde_expansion }, - { (char *)NULL, (int *)NULL } + { (char *)NULL, (int *)NULL, 0 } }; -rl_variable_bind (name, value) - char *name, *value; +static int +find_boolean_var (name) + const char *name; { register int i; - /* Check for simple variables first. */ 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 (stricmp (name, boolean_varlist[i].name) == 0) - { - /* A variable is TRUE if the "value" is "on", "1" or "". */ - if ((!*value) || - (stricmp (value, "On") == 0) || - (value[0] == '1' && value[1] == '\0')) - *boolean_varlist[i].value = 1; - else - *boolean_varlist[i].value = 0; - return; - } + 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_compwidth 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-display-width", V_INT, sv_compwidth }, + { "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, (_rl_sv_func_t *)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; +} - /* Not a boolean variable, so check for specials. */ +/* 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"); - /* Editing mode change? */ - if (stricmp (name, "editing-mode") == 0) + 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 (strnicmp (value, "vi", 2) == 0) - { #if defined (VI_MODE) - _rl_keymap = vi_insertion_keymap; - rl_editing_mode = vi_mode; -#else -#if defined (NOTDEF) - /* What state is the terminal in? I'll tell you: - non-determinate! That means we cannot do any output. */ - ding (); -#endif /* NOTDEF */ + _rl_keymap = vi_insertion_keymap; + rl_editing_mode = vi_mode; #endif /* VI_MODE */ - } - else if (strnicmp (value, "emacs", 5) == 0) - { - _rl_keymap = emacs_standard_keymap; - rl_editing_mode = emacs_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; +} - /* Comment string change? */ - else if (stricmp (name, "comment-begin") == 0) +static int +sv_combegin (value) + const char *value; +{ + if (value && *value) { -#if defined (VI_MODE) - extern char *rl_vi_comment_begin; + FREE (_rl_comment_begin); + _rl_comment_begin = savestring (value); + return 0; + } + return 1; +} - if (*value) - { - if (rl_vi_comment_begin) - free (rl_vi_comment_begin); +static int +sv_dispprefix (value) + const char *value; +{ + int nval = 0; - rl_vi_comment_begin = savestring (value); - } -#endif /* VI_MODE */ + if (value && *value) + { + nval = atoi (value); + if (nval < 0) + nval = 0; } - else if (stricmp (name, "completion-query-items") == 0) + _rl_completion_prefix_display_length = nval; + return 0; +} + +static int +sv_compquery (value) + const char *value; +{ + int nval = 100; + + if (value && *value) { - int nval = 100; - if (*value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - rl_completion_query_items = nval; + nval = atoi (value); + if (nval < 0) + nval = 0; + } + rl_completion_query_items = nval; + return 0; +} + +static int +sv_compwidth (value) + const char *value; +{ + int nval = -1; + + if (value && *value) + nval = atoi (value); + + _rl_completion_columns = 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 { - char *name; + const char * const name; int value; } assoc_list; -static assoc_list name_key_alist[] = { +static const assoc_list name_key_alist[] = { { "DEL", 0x7f }, { "ESC", '\033' }, { "Escape", '\033' }, @@ -1031,15 +1793,15 @@ glean_key_from_name (name) register int i; for (i = 0; name_key_alist[i].name; i++) - if (stricmp (name, name_key_alist[i].name) == 0) + 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 struct { - char *name; +static const struct { + const char * const name; Keymap map; } keymap_names[] = { { "emacs", emacs_standard_keymap }, @@ -1057,16 +1819,27 @@ static struct { Keymap rl_get_keymap_by_name (name) - char *name; + const char *name; { register int i; for (i = 0; keymap_names[i].name; i++) - if (strcmp (name, keymap_names[i].name) == 0) + 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; @@ -1086,10 +1859,25 @@ 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 */ @@ -1099,15 +1887,14 @@ rl_set_keymap_from_edit_mode () /* 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 (). */ + be read back in (i.e., passed to rl_parse_and_bind ()). */ /* Print the names of functions known to Readline. */ void -rl_list_funmap_names (ignore) - int ignore; +rl_list_funmap_names () { register int i; - char **funmap_names; + const char **funmap_names; funmap_names = rl_funmap_names (); @@ -1117,14 +1904,88 @@ rl_list_funmap_names (ignore) for (i = 0; funmap_names[i]; i++) fprintf (rl_outstream, "%s\n", funmap_names[i]); - free (funmap_names); + 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. */ -static char ** -invoking_keyseqs_in_map (function, map) - Function *function; +char ** +rl_invoking_keyseqs_in_map (function, map) + rl_command_func_t *function; Keymap map; { register int key; @@ -1134,7 +1995,7 @@ invoking_keyseqs_in_map (function, map) result = (char **)NULL; result_index = result_size = 0; - for (key = 0; key < 128; key++) + for (key = 0; key < KEYMAP_SIZE; key++) { switch (map[key].type) { @@ -1146,27 +2007,15 @@ invoking_keyseqs_in_map (function, map) then add the current KEY to the list of invoking keys. */ if (map[key].function == function) { - char *keyname = (char *)xmalloc (5); + char *keyname; - if (CTRL_P (key)) - sprintf (keyname, "\\C-%c", 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'; - } + keyname = _rl_get_keyname (key); if (result_index + 2 > result_size) - result = (char **) xrealloc - (result, (result_size += 10) * sizeof (char *)); + { + result_size += 10; + result = (char **)xrealloc (result, result_size * sizeof (char *)); + } result[result_index++] = keyname; result[result_index] = (char *)NULL; @@ -1175,50 +2024,65 @@ invoking_keyseqs_in_map (function, map) case ISKMAP: { - char **seqs = (char **)NULL; + 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 = - invoking_keyseqs_in_map (function, (Keymap)map[key].function); + rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); + else + break; + + if (seqs == 0) + break; - if (seqs) + for (i = 0; seqs[i]; i++) { - register int i; + char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - for (i = 0; seqs[i]; i++) + if (key == ESC) { - char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - - if (key == ESC) - sprintf (keyname, "\\e"); - else if (CTRL_P (key)) - sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } + /* 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 - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } - - strcat (keyname, seqs[i]); - - if (result_index + 2 > result_size) - result = (char **) xrealloc - (result, (result_size += 10) * sizeof (char *)); + 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]); - result[result_index++] = keyname; - result[result_index] = (char *)NULL; + 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; } @@ -1230,23 +2094,9 @@ invoking_keyseqs_in_map (function, map) sequences that can be used to invoke FUNCTION using the current keymap. */ char ** rl_invoking_keyseqs (function) - Function *function; -{ - return (invoking_keyseqs_in_map (function, _rl_keymap)); -} - -/* Print all of the current functions and their bindings to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_functions (count) - int count; + rl_command_func_t *function; { - void rl_function_dumper (); - - rl_function_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); + return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); } /* Print all of the functions and their bindings to rl_outstream. If @@ -1257,8 +2107,8 @@ rl_function_dumper (print_readably) int print_readably; { register int i; - char **names; - char *name; + const char **names; + const char *name; names = rl_funmap_names (); @@ -1266,11 +2116,11 @@ rl_function_dumper (print_readably) for (i = 0; name = names[i]; i++) { - Function *function; + rl_command_func_t *function; char **invokers; function = rl_named_function (name); - invokers = invoking_keyseqs_in_map (function, _rl_keymap); + invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap); if (print_readably) { @@ -1284,10 +2134,10 @@ rl_function_dumper (print_readably) { fprintf (rl_outstream, "\"%s\": %s\n", invokers[j], name); - free (invokers[j]); + xfree (invokers[j]); } - free (invokers); + xfree (invokers); } } else @@ -1311,86 +2161,233 @@ rl_function_dumper (print_readably) fprintf (rl_outstream, "...\n"); for (j = 0; invokers[j]; j++) - free (invokers[j]); + xfree (invokers[j]); - free (invokers); + xfree (invokers); } } } + free (names); } - -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -static char *strindex (); +/* 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); +} -/* Return non-zero if any members of ARRAY are a substring in STRING. */ -static int -substring_member_of_array (string, array) - char *string, **array; +static void +_rl_macro_dumper_internal (print_readably, map, prefix) + int print_readably; + Keymap map; + char *prefix; { - while (*array) + register int key; + char *keyname, *out; + int prefix_len; + + for (key = 0; key < KEYMAP_SIZE; key++) { - if (strindex (string, *array)) - return (1); - array++; + 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; + } } - return (0); } -/* Whoops, Unix doesn't have strnicmp. */ +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); +} -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -static int -strnicmp (string1, string2, count) - char *string1, *string2; +static char * +_rl_get_string_variable_value (name) + const char *name; { - register char ch1, ch2; + static char numbuf[32]; + char *ret; - while (count) + if (_rl_stricmp (name, "bell-style") == 0) { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) == to_upper(ch2)) - count--; - else break; + switch (_rl_bell_preference) + { + case NO_BELL: + return "none"; + case VISIBLE_BELL: + return "visible"; + case AUDIBLE_BELL: + default: + return "audible"; + } } - return (count); + 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-display-width") == 0) + { + sprintf (numbuf, "%d", _rl_completion_columns); + return (numbuf); + } + 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); } -/* strcmp (), but caseless. */ -static int -stricmp (string1, string2) - char *string1, *string2; +void +rl_variable_dumper (print_readably) + int print_readably; { - register char ch1, ch2; + int i; + char *v; - while (*string1 && *string2) + for (i = 0; boolean_varlist[i].name; i++) { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) != to_upper(ch2)) - return (1); + 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); } - return (*string1 | *string2); } -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -static char * -strindex (s1, s2) - register char *s1, *s2; +/* 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; { - register int i, l = strlen (s2); - register int len = strlen (s1); + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_variable_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} - for (i = 0; (len - i) >= l; i++) - if (strnicmp (&s1[i], s2, l) == 0) - return (s1 + i); - return ((char *)NULL); +/* 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); }