From: Chet Ramey Date: Tue, 8 Aug 2023 14:49:46 +0000 (-0400) Subject: several fixes for printing readline key bindings and macro values containing characte... X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1d0c4ceb491133495e527783356ede3a44ac644c;p=thirdparty%2Fbash.git several fixes for printing readline key bindings and macro values containing characters with the high bit set --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5b5f3bab1..4b992109d 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + + 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 + - 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 + - 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 diff --git a/builtins/bind.def b/builtins/bind.def index 99dd1fa97..3cf901541 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -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); diff --git a/execute_cmd.c b/execute_cmd.c index 0c02a7df0..53537c417 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -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, diff --git a/lib/readline/bind.c b/lib/readline/bind.c index a8b139f0b..3a44fefb9 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -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,35 +697,22 @@ rl_untranslate_keyseq (int seq) kseq[i++] = '-'; c = UNMETA (c); } - else if (c == ESC) + + if (c == ESC) { kseq[i++] = '\\'; c = 'e'; } - else if (CTRL_CHAR (c)) + else if (CTRL_CHAR (c) || c == RUBOUT) { 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 = '?'; + c = (c == RUBOUT) ? '?' : _rl_to_lower (UNCTRL (c)); } - if (c == ESC) - { - kseq[i++] = '\\'; - c = 'e'; - } - else if (c == '\\' || c == '"') - { - kseq[i++] = '\\'; - } + if (c == '\\' || c == '"') + kseq[i++] = '\\'; kseq[i++] = (unsigned char) c; kseq[i] = '\0'; @@ -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,73 +2725,72 @@ rl_invoking_keyseqs (rl_command_func_t *function) return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); } -/* Print all of the functions and their bindings to rl_outstream. If - PRINT_READABLY is non-zero, then print the output in such a way - that it can be read back in. */ void -rl_function_dumper (int print_readably) +rl_print_keybinding (const char *name, Keymap kmap, int print_readably) { - register int i; - const char **names; - const char *name; - - names = rl_funmap_names (); + rl_command_func_t *function; + char **invokers; - fprintf (rl_outstream, "\n"); + function = rl_named_function (name); + invokers = rl_invoking_keyseqs_in_map (function, kmap ? kmap : _rl_keymap); - for (i = 0; name = names[i]; i++) + if (print_readably) { - 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 { - 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]); - } + register int j; - xfree (invokers); + 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 { - if (!invokers) - fprintf (rl_outstream, "%s is not bound to any keys\n", - name); - else - { - register int j; + register int j; - fprintf (rl_outstream, "%s can be found on ", name); + 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"); - } + 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"); + if (j == 5 && invokers[j]) + fprintf (rl_outstream, "...\n"); - for (j = 0; invokers[j]; j++) - xfree (invokers[j]); + for (j = 0; invokers[j]; j++) + xfree (invokers[j]); - xfree (invokers); - } + 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. */ +void +rl_function_dumper (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_print_keybinding (name, _rl_keymap, print_readably); xfree (names); } diff --git a/lib/readline/chardefs.h b/lib/readline/chardefs.h index 24a25f1f1..02f7e17e2 100644 --- a/lib/readline/chardefs.h +++ b/lib/readline/chardefs.h @@ -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) diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi index ad3edf897..c83d99d51 100644 --- a/lib/readline/doc/rltech.texi +++ b/lib/readline/doc/rltech.texi @@ -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 diff --git a/lib/readline/readline.h b/lib/readline/readline.h index acd3a9fdd..828a42a62 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -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);