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 <http://www.gnu.org/licenses/>.
*/
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#if defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif
#include "posixstat.h"
#include "rldefs.h"
#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
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;
static int _rl_prefer_visible_bell = 1;
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;
}
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);
}
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);
}
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));
}
Returns non-zero in case of error. */
int
rl_unbind_key (key)
int key;
{
return (rl_bind_key (key, (rl_command_func_t *)NULL));
}
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));
}
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));
}
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));
}
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));
}
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));
}
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));
}
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;
}
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 (keyseq == 0 || *keyseq == 0)
{
if (type == ISMACR)
xfree (data);
return -1;
}
keys = (char *)xmalloc (1 + (2 * strlen (keyseq)));
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;
}
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)
{
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);
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;
}
map[ic].function = KEYMAP_TO_FUNCTION (data);
map[ic].type = type;
}
rl_binding_keymap = map;
}
xfree (keys);
return 0;
}
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;
if ((c == 'C' || c == 'M') && seq[i + 1] == '-')
{
if (strncmp (&seq[i], "C-\\M-", 5) == 0)
{
array[l++] = ESC;
i += 5;
array[l++] = CTRL (_rl_to_upper (seq[i]));
if (seq[i] == '\0')
i--;
}
else if (c == 'M')
{
i++;
if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP)
array[l++] = ESC;
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
{
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;
array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
}
continue;
}
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;
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--;
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--;
array[l++] = c & largest_char;
break;
default:
array[l++] = c;
break;
}
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;
}
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);
}
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);
}
doesn't match? */
else
{
if (type)
*type = map[ESC].type;
return (map[ESC].function);
}
}
if (map[ic].type == ISKMAP)
{
map. */
if (keyseq[i + 1] == '\0')
{
if (type)
*type = ISKMAP;
return (map[ic].function);
}
else
map = FUNCTION_TO_KEYMAP (map, ic);
}
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
{
if (type)
*type = map[ic].type;
return (map[ic].function);
}
}
return ((rl_command_func_t *) NULL);
}
static char *last_readline_init_file = (char *)NULL;
static const char *current_readline_init_file;
static int current_readline_init_include_level;
static int current_readline_init_lineno;
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;
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);
}
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);
}
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;
}
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;
{
int result;
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;
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
result = (_rl_read_init_file (filename, 0));
if (result != 0 && filename == DEFAULT_INPUTRC)
result = (_rl_read_init_file ("/etc/inputrc", 0));
return result;
}
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;
comments; all other lines are commands for readline initialization. */
current_readline_init_lineno = 1;
line = buffer;
end = buffer + file_size;
while (line < end)
{
for (i = 0; line + i != end && line[i] != '\n'; i++);
#if defined (__CYGWIN__)
if (line[i] == '\n' && line[i-1] == '\r')
line[i - 1] = '\0';
#endif
line[i] = '\0';
while (*line && whitespace (*line))
{
line++;
i--;
}
if (*line && *line != '#')
rl_parse_and_bind (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);
}
typedef int _rl_parser_func_t PARAMS((char *));
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
};
const char *rl_readline_name = "other";
static unsigned char *if_stack = (unsigned char *)NULL;
static int if_stack_depth;
static int if_stack_size;
on ARGS. */
static int
parser_if (args)
char *args;
{
register int i;
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;
for finding the matching endif. In that case, return right now. */
if (_rl_parsing_conditionalized_out)
return 0;
for (i = 0; args[i] && !whitespace (args[i]); i++);
if (args[i])
args[i++] = '\0';
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;
tname = savestring (rl_terminal_name);
tem = strchr (tname, '-');
if (tem)
*tem = '\0';
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
/* 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;
}
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
we haven't previously turned off parsing. */
for (i = 0; i < if_stack_depth - 1; i++)
#else
we haven't previously turned off parsing. */
for (i = 0; i < if_stack_depth; i++)
#endif
if (if_stack[i] == 1)
return 0;
_rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out;
return 0;
}
_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;
}
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 }
};
without any leading `$'. */
static int
handle_parser_directive (statement)
char *statement;
{
register int i;
char *directive, *args;
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];
for (i = 0; parser_directives[i].name; i++)
if (_rl_stricmp (directive, parser_directives[i].name) == 0)
{
(*parser_directives[i].function) (args);
return (0);
}
_rl_init_file_error ("unknown parser directive");
return (1);
}
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 (*string == '$')
{
handle_parser_directive (&string[1]);
return 0;
}
if (_rl_parsing_conditionalized_out)
return 0;
i = 0;
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 (string[i] == '\0')
{
_rl_init_file_error ("no closing `\"' in key binding");
return 1;
}
}
for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
equivalency = (c == ':' && string[i + 1] == '=');
if (string[i])
string[i++] = '\0';
if (equivalency)
string[i++] = '\0';
if (_rl_stricmp (string, "set") == 0)
{
char *var, *value, *e;
var = string + i;
while (*var && whitespace (*var)) var++;
value = var;
while (*value && !whitespace (*value)) value++;
if (*value)
*value++ = '\0';
while (*value && whitespace (*value)) value++;
fix until I get a real quoted-string parser here. */
i = find_boolean_var (var);
if (i >= 0)
{
e = value + strlen (value) - 1;
while (e >= value && whitespace (*e))
e--;
e++;
if (*e && e >= value)
*e = '\0';
}
rl_variable_bind (var, value);
return 0;
}
for (; string[i] && whitespace (string[i]); i++);
funname = &string[i];
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. */
would otherwise be gobbled up by the next `for' loop.*/
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++;
}
for (; string[i] && !whitespace (string[i]); i++);
string[i] = '\0';
whatever the right-hand evaluates to, including keymaps. */
if (equivalency)
{
return 0;
}
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++)
{
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';
if (*funname == '\'' || *funname == '"')
{
j = strlen (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;
}
kname = strrchr (string, '-');
if (!kname)
kname = string;
else
kname++;
key = glean_key_from_name (kname);
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);
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)
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
else
rl_bind_key (key, rl_named_function (funname));
return 0;
}
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
{ (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;
}
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 *));
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
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;
}
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;
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));
return 0;
}
int
rl_variable_bind (name, value)
const char *name, *value;
{
register int i;
int v;
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);
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
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;
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';
_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;
}
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);
}
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
{ (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
}
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
else
return "none";
}
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 ()). */
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;
pairs for possible inclusion in an inputrc file, we don't want to
do any special meta processing on KEY. */
#if 1
Just add the special ESC key sequence and return. */
if (c == ESC)
{
keyname[0] = '\\';
keyname[1] = 'e';
keyname[2] = '\0';
return keyname;
}
#endif
if (key == RUBOUT)
{
keyname[0] = '\\';
keyname[1] = 'C';
keyname[2] = '-';
keyname[3] = '?';
keyname[4] = '\0';
return keyname;
}
i = 0;
potentially change C. */
if (CTRL_CHAR (c))
{
keyname[i++] = '\\';
keyname[i++] = 'C';
keyname[i++] = '-';
c = _rl_to_lower (UNCTRL (c));
}
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';
}
if (c == '\\' || c == '"')
keyname[i++] = '\\';
keyname[i++] = (char) c;
keyname[i] = '\0';
return keyname;
}
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:
Thus, they are treated exactly like functions in here. */
case ISFUNC:
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;
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)
{
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);
}
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_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);
}
}
}
}
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)
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);
}
}
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);
}
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);
}