several fixes for printing readline key bindings and macro values containing characters with the high bit set

This commit is contained in:
Chet Ramey
2023-08-08 10:49:46 -04:00
parent dc91b3f509
commit 1d0c4ceb49
7 changed files with 173 additions and 155 deletions
+29
View File
@@ -7360,3 +7360,32 @@ subst.c
- do_compound_assignment: don't attempt to convert a global associative
array to an indexed array with declare -g.
From a report and patch by Grisha Levit <grishalevit@gmail.com>
8/7
---
lib/readline/bind.c
- rl_print_keybinding: new function, prints a the key bindings for a
single function specified by name
- rl_function_dumper: call rl_print_keybinding for every function name
lib/readline/readline.h
- rl_print_keybinding: extern declaration
lib/readline/bind.c
- _rl_untranslate_macro_value: make sure characters betweeen 128 and
159 (metafied control characters) are printed using the \M-\C-
notation instead of directly writing the control character.
From a report and patch by Grisha Levit <grishalevit@gmail.com>
- rl_get_keyname: if a key binding shadows a function or macro, print
the ANYOTHERKEY binding as a null string
From a report and patch by Grisha Levit <grishalevit@gmail.com>
- rl_untranslate_keyseq: make changes analogous to
_rl_untranslate_macro_value so that we don't print control characters
directly
- rl_invoking_keyseqs_in_map: if the key corresponds to a keymap, use
_rl_get_keyname to get its text representation, so this function
returns consistent results
- rl_translate_keyseq: if convert-meta is on, don't convert meta chars
that are, e.g., \M-\C-@ (128) into \e followed by a NUL, resulting
in truncated key sequences. Just don't honor convert-meta in this
case
+30 -10
View File
@@ -116,14 +116,7 @@ bind_builtin (WORD_LIST *list)
char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq, *t;
if (no_line_editing)
{
#if 0
builtin_error (_("line editing not enabled"));
return (EXECUTION_FAILURE);
#else
builtin_warning (_("line editing not enabled"));
#endif
}
builtin_warning (_("line editing not enabled"));
kmap = saved_keymap = (Keymap) NULL;
flags = 0;
@@ -226,10 +219,37 @@ bind_builtin (WORD_LIST *list)
rl_list_funmap_names ();
if (flags & PFLAG)
rl_function_dumper (1);
{
#if 0 /* TAG:bash-5.3 */
if (list == 0)
rl_function_dumper (1);
else
while (list)
{
rl_print_keybinding (list->word->word, kmap, 1);
list = list->next;
}
#else
rl_function_dumper (1);
#endif
}
if (flags & PPFLAG)
rl_function_dumper (0);
{
#if 0 /* TAG:bash-5.3 */
if (list == 0)
rl_function_dumper (0);
else
while (list)
{
rl_print_keybinding (list->word->word, kmap, 0);
list = list->next;
}
#else
rl_function_dumper (0);
#endif
}
if (flags & SFLAG)
rl_macro_dumper (1);
+1 -1
View File
@@ -4729,7 +4729,7 @@ run_builtin:
setup_async_signals ();
}
if (async == 0)
if (async == 0) /* XXX why async == 0? */
subshell_level++;
execute_subshell_builtin_or_function
(words, simple_command->redirects, builtin, func,
+98 -141
View File
@@ -526,8 +526,7 @@ rl_translate_keyseq (const char *seq, char *array, int *len)
/* When there are incomplete prefixes \C- or \M- (has_control || has_meta)
without base character at the end of SEQ, they are processed as the
prefixes for '\0'.
*/
prefixes for '\0'. */
for (i = l = 0; (c = seq[i]) || has_control || has_meta; i++)
{
/* Only backslashes followed by a non-null character are handled
@@ -624,11 +623,17 @@ rl_translate_keyseq (const char *seq, char *array, int *len)
has_meta = 0;
}
/* If convert-meta is turned on, convert a meta char to a key sequence */
/* If convert-meta is turned on, convert a meta char to a key sequence */
if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii)
{
array[l++] = ESC; /* ESC is meta-prefix */
array[l++] = UNMETA (c);
int x = UNMETA (c);
if (x)
{
array[l++] = ESC; /* ESC is meta-prefix */
array[l++] = x;
}
else
array[l++] = c; /* just do the best we can without sticking a NUL in there. */
}
else
array[l++] = (c);
@@ -680,7 +685,8 @@ char *
rl_untranslate_keyseq (int seq)
{
static char kseq[16];
int i, c;
int i;
unsigned char c;
i = 0;
c = seq;
@@ -691,36 +697,23 @@ rl_untranslate_keyseq (int seq)
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 == '"')
else if (CTRL_CHAR (c) || c == RUBOUT)
{
kseq[i++] = '\\';
kseq[i++] = 'C';
kseq[i++] = '-';
c = (c == RUBOUT) ? '?' : _rl_to_lower (UNCTRL (c));
}
if (c == '\\' || c == '"')
kseq[i++] = '\\';
kseq[i++] = (unsigned char) c;
kseq[i] = '\0';
return kseq;
@@ -730,9 +723,9 @@ char *
_rl_untranslate_macro_value (char *seq, int use_escapes)
{
char *ret, *r, *s;
int c;
unsigned char c;
r = ret = (char *)xmalloc (7 * strlen (seq) + 1);
r = ret = (char *)xmalloc (8 * strlen (seq) + 1);
for (s = seq; *s; s++)
{
c = *s;
@@ -743,7 +736,9 @@ _rl_untranslate_macro_value (char *seq, int use_escapes)
*r++ = '-';
c = UNMETA (c);
}
else if (c == ESC)
/* We want to keep from printing literal control chars */
if (c == ESC)
{
*r++ = '\\';
c = 'e';
@@ -768,15 +763,10 @@ _rl_untranslate_macro_value (char *seq, int use_escapes)
c = '?';
}
if (c == ESC)
{
*r++ = '\\';
c = 'e';
}
else if (c == '\\' || c == '"')
if (c == '\\' || c == '"')
*r++ = '\\';
*r++ = (unsigned char)c;
*r++ = c;
}
*r = '\0';
return ret;
@@ -2574,17 +2564,13 @@ _rl_get_keyname (int key)
char *keyname;
int i, c;
keyname = (char *)xmalloc (8);
keyname = (char *)xmalloc (9);
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)
@@ -2594,28 +2580,23 @@ _rl_get_keyname (int key)
keyname[2] = '\0';
return keyname;
}
#endif
/* RUBOUT is translated directly into \C-? */
if (key == RUBOUT)
if (key == ANYOTHERKEY)
{
keyname[0] = '\\';
keyname[1] = 'C';
keyname[2] = '-';
keyname[3] = '?';
keyname[4] = '\0';
keyname[0] = '\0';
return keyname;
}
i = 0;
/* Now add special prefixes needed for control characters. This can
potentially change C. */
if (CTRL_CHAR (c))
if (CTRL_CHAR (c) || c == RUBOUT)
{
keyname[i++] = '\\';
keyname[i++] = 'C';
keyname[i++] = '-';
c = _rl_to_lower (UNCTRL (c));
c = (c == RUBOUT) ? '?' : _rl_to_lower (UNCTRL (c));
}
/* XXX experimental code. Turn the characters that are not ASCII or
@@ -2693,53 +2674,24 @@ rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map)
{
char **seqs;
register int i;
char *keyname;
size_t knlen;
/* Find the list of keyseqs in this map which have FUNCTION as
their target. Add the key sequences found to RESULT. */
if (map[key].function)
seqs =
rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key));
else
if (map[key].function == 0)
break;
seqs = rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key));
if (seqs == 0)
break;
keyname = _rl_get_keyname (key);
knlen = RL_STRLEN (keyname);
for (i = 0; seqs[i]; i++)
{
char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
if (key == ESC)
{
/* If ESC is the meta prefix and we're converting chars
with the eighth bit set to ESC-prefixed sequences, then
we can use \M-. Otherwise we need to use the sequence
for ESC. */
if (_rl_convert_meta_chars_to_ascii && map[ESC].type == ISKMAP)
sprintf (keyname, "\\M-");
else
sprintf (keyname, "\\e");
}
else
{
int c = key, l = 0;
if (CTRL_CHAR (c) || c == RUBOUT)
{
keyname[l++] = '\\';
keyname[l++] = 'C';
keyname[l++] = '-';
c = (c == RUBOUT) ? '?' : _rl_to_lower (UNCTRL (c));
}
if (c == '\\' || c == '"')
keyname[l++] = '\\';
keyname[l++] = (char) c;
keyname[l++] = '\0';
}
strcat (keyname, seqs[i]);
xfree (seqs[i]);
char *x;
if (result_index + 2 > result_size)
{
@@ -2747,10 +2699,16 @@ rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map)
result = (char **)xrealloc (result, result_size * sizeof (char *));
}
result[result_index++] = keyname;
x = xmalloc (knlen + RL_STRLEN (seqs[i]) + 1);
strcpy (x, keyname);
strcpy (x + knlen, seqs[i]);
xfree (seqs[i]);
result[result_index++] = x;
result[result_index] = (char *)NULL;
}
xfree (keyname);
xfree (seqs);
}
break;
@@ -2767,6 +2725,56 @@ rl_invoking_keyseqs (rl_command_func_t *function)
return (rl_invoking_keyseqs_in_map (function, _rl_keymap));
}
void
rl_print_keybinding (const char *name, Keymap kmap, int print_readably)
{
rl_command_func_t *function;
char **invokers;
function = rl_named_function (name);
invokers = rl_invoking_keyseqs_in_map (function, kmap ? kmap : _rl_keymap);
if (print_readably)
{
if (!invokers)
fprintf (rl_outstream, "# %s (not bound)\n", name);
else
{
register int j;
for (j = 0; invokers[j]; j++)
{
fprintf (rl_outstream, "\"%s\": %s\n", invokers[j], name);
xfree (invokers[j]);
}
xfree (invokers);
}
}
else
{
if (!invokers)
fprintf (rl_outstream, "%s is not bound to any keys\n", name);
else
{
register int j;
fprintf (rl_outstream, "%s can be found on ", name);
for (j = 0; invokers[j] && j < 5; j++)
fprintf (rl_outstream, "\"%s\"%s", invokers[j], invokers[j + 1] ? ", " : ".\n");
if (j == 5 && invokers[j])
fprintf (rl_outstream, "...\n");
for (j = 0; invokers[j]; j++)
xfree (invokers[j]);
xfree (invokers);
}
}
}
/* Print all of the functions and their bindings to rl_outstream. If
PRINT_READABLY is non-zero, then print the output in such a way
that it can be read back in. */
@@ -2782,58 +2790,7 @@ rl_function_dumper (int print_readably)
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_print_keybinding (name, _rl_keymap, print_readably);
xfree (names);
}
+1 -1
View File
@@ -55,7 +55,7 @@
#define largest_char 255 /* Largest character value. */
#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
#define META_CHAR(c) ((unsigned char)(c) > meta_character_threshold && (unsigned char)(c) <= largest_char)
#define CTRL(c) ((c) & control_character_mask)
#define META(c) ((c) | meta_character_bit)
+11 -1
View File
@@ -926,9 +926,19 @@ Return an array of strings representing the key sequences used to
invoke @var{function} in the keymap @var{map}.
@end deftypefun
@deftypefun void rl_print_keybinding (const char *name, Keymap map, int readable)
Print key sequences bound to Readline function name @var{name} in
keymap @var{map}.
If @var{map} is NULL, this uses the current keymap.
If @var{readable} is non-zero,
the list is formatted in such a way that it can be made part of an
@code{inputrc} file and re-read.
@end deftypefun
@deftypefun void rl_function_dumper (int readable)
Print the Readline function names and the key sequences currently
bound to them to @code{rl_outstream}. If @var{readable} is non-zero,
bound to them to @code{rl_outstream}.
If @var{readable} is non-zero,
the list is formatted in such a way that it can be made part of an
@code{inputrc} file and re-read.
@end deftypefun
+3 -1
View File
@@ -341,7 +341,9 @@ extern int rl_trim_arg_from_keyseq (const char *, size_t, Keymap);
extern void rl_list_funmap_names (void);
extern char **rl_invoking_keyseqs_in_map (rl_command_func_t *, Keymap);
extern char **rl_invoking_keyseqs (rl_command_func_t *);
extern void rl_print_keybinding (const char *, Keymap, int);
extern void rl_function_dumper (int);
extern void rl_macro_dumper (int);
extern void rl_variable_dumper (int);