diff options
Diffstat (limited to 'bind.c')
-rw-r--r-- | bind.c | 252 |
1 files changed, 150 insertions, 102 deletions
@@ -1,6 +1,6 @@ /* bind.c -- key binding and startup file support for the readline library. */ -/* Copyright (C) 1987-2017 Free Software Foundation, Inc. +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -135,12 +135,13 @@ rl_add_defun (const char *name, rl_command_func_t *function, int key) int rl_bind_key (int key, rl_command_func_t *function) { - char keyseq[3]; + char keyseq[4]; int l; - if (key < 0) + if (key < 0 || key > largest_char) return (key); + /* Want to make this a multi-character key sequence with an ESC prefix */ if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) { if (_rl_keymap[ESC].type == ISKMAP) @@ -153,24 +154,43 @@ rl_bind_key (int key, rl_command_func_t *function) escmap[key].function = function; return (0); } - return (key); + + /* Otherwise, let's just let rl_generic_bind handle the key sequence. + We start it off with ESC here and let the code below add the rest + of the sequence. */ + keyseq[0] = ESC; + l = 1; + key = UNMETA(key); + goto bind_keyseq; } /* If it's bound to a function or macro, just overwrite. Otherwise we have to treat it as a key sequence so rl_generic_bind handles shadow keymaps - for us. If we are binding '\' make sure to escape it so it makes it - through the call to rl_translate_keyseq. */ + for us. If we are binding '\' or \C-@ (NUL) make sure to escape it so + it makes it through the call to rl_translate_keyseq. */ if (_rl_keymap[key].type != ISKMAP) { + if (_rl_keymap[key].type == ISMACR) + xfree ((char *)_rl_keymap[key].function); _rl_keymap[key].type = ISFUNC; _rl_keymap[key].function = function; } else { l = 0; +bind_keyseq: if (key == '\\') - keyseq[l++] = '\\'; - keyseq[l++] = key; + { + keyseq[l++] = '\\'; + keyseq[l++] = '\\'; + } + else if (key == '\0') + { + keyseq[l++] = '\\'; + keyseq[l++] = '0'; + } + else + keyseq[l++] = key; keyseq[l] = '\0'; rl_bind_keyseq (keyseq, function); } @@ -242,6 +262,13 @@ rl_unbind_function_in_map (rl_command_func_t *func, Keymap map) map[i].function = (rl_command_func_t *)NULL; rval = 1; } + else if (map[i].type == ISKMAP) /* TAG:readline-8.1 */ + { + int r; + r = rl_unbind_function_in_map (func, FUNCTION_TO_KEYMAP (map, i)); + if (r == 1) + rval = 1; + } } return rval; } @@ -352,7 +379,7 @@ int rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) { char *keys; - int keys_len, prevkey; + int keys_len, prevkey, ic; register int i; KEYMAP_ENTRY k; Keymap prevmap; @@ -385,7 +412,6 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) for (i = 0; i < keys_len; i++) { unsigned char uc = keys[i]; - int ic; if (i > 0) prevkey = ic; @@ -397,6 +423,9 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) return -1; } + /* We now rely on rl_translate_keyseq to do this conversion, so this + check is superfluous. */ +#if 0 if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) { ic = UNMETA (ic); @@ -406,6 +435,7 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) map = FUNCTION_TO_KEYMAP (map, ESC); } } +#endif if ((i + 1) < keys_len) { @@ -439,9 +469,7 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) } else { - if (map[ic].type == ISMACR) - xfree ((char *)map[ic].function); - else if (map[ic].type == ISKMAP) + if (map[ic].type == ISKMAP) { prevmap = map; map = FUNCTION_TO_KEYMAP (map, ic); @@ -454,6 +482,8 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) if (type == ISFUNC && data == 0) data = (char *)_rl_null_function; } + if (map[ic].type == ISMACR) + xfree ((char *)map[ic].function); map[ic].function = KEYMAP_TO_FUNCTION (data); map[ic].type = type; @@ -492,59 +522,38 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) int rl_translate_keyseq (const char *seq, char *array, int *len) { - register int i, c, l, temp; + register int i, l, temp; + int has_control, has_meta; + unsigned char c; - for (i = l = 0; c = seq[i]; i++) + has_control = 0; + has_meta = 0; + + /* 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'. + */ + for (i = l = 0; (c = seq[i]) || has_control || has_meta; i++) { - if (c == '\\') + /* Only backslashes followed by a non-null character are handled + specially. Trailing backslash (backslash followed by '\0') is + processed as a normal character. + */ + if (c == '\\' && seq[i + 1] != '\0') { c = seq[++i]; - if (c == 0) + /* Handle \C- and \M- prefixes. */ + if (c == 'C' && seq[i + 1] == '-') { - array[l++] = '\\'; /* preserve trailing backslash */ - break; + i++; + has_control = 1; + continue; } - - /* Handle \C- and \M- prefixes. */ - if ((c == 'C' || c == 'M') && seq[i + 1] == '-') + else if (c == 'M' && seq[i + 1] == '-') { - /* Handle special case of backwards define. */ - if (strncmp (&seq[i], "C-\\M-", 5) == 0) - { - array[l++] = ESC; /* ESC is meta-prefix */ - i += 5; - array[l++] = CTRL (_rl_to_upper (seq[i])); - } - else if (c == 'M') - { - i++; /* seq[i] == '-' */ - /* XXX - obey convert-meta setting */ - if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP) - array[l++] = ESC; /* ESC is meta-prefix */ - else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-') - { - i += 4; - temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - array[l++] = META (temp); - } - else - { - /* This doesn't yet handle things like \M-\a, which may - or may not have any reasonable meaning. You're - probably better off using straight octal or hex. */ - i++; - array[l++] = META (seq[i]); - } - } - else if (c == 'C') - { - i += 2; - /* Special hack for C-?... */ - array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - } - if (seq[i] == '\0') - break; + i++; + has_meta = 1; continue; } @@ -555,34 +564,34 @@ rl_translate_keyseq (const char *seq, char *array, int *len) switch (c) { case 'a': - array[l++] = '\007'; + c = '\007'; break; case 'b': - array[l++] = '\b'; + c = '\b'; break; case 'd': - array[l++] = RUBOUT; /* readline-specific */ + c = RUBOUT; /* readline-specific */ break; case 'e': - array[l++] = ESC; + c = ESC; break; case 'f': - array[l++] = '\f'; + c = '\f'; break; case 'n': - array[l++] = NEWLINE; + c = NEWLINE; break; case 'r': - array[l++] = RETURN; + c = RETURN; break; case 't': - array[l++] = TAB; + c = TAB; break; case 'v': - array[l++] = 0x0B; + c = 0x0B; break; case '\\': - array[l++] = '\\'; + c = '\\'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': @@ -590,7 +599,7 @@ rl_translate_keyseq (const char *seq, char *array, int *len) for (temp = 2, c -= '0'; ISOCTAL ((unsigned char)seq[i]) && temp--; i++) c = (c * 8) + OCTVALUE (seq[i]); i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; + c &= largest_char; break; case 'x': i++; @@ -599,16 +608,40 @@ rl_translate_keyseq (const char *seq, char *array, int *len) if (temp == 2) c = 'x'; i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; + c &= largest_char; break; default: /* backslashes before non-special chars just add the char */ - array[l++] = c; + c &= largest_char; break; /* the backslash is stripped */ } - continue; } - array[l++] = c; + /* Process \C- and \M- flags */ + if (has_control) + { + /* Special treatment for C-? */ + c = (c == '?') ? RUBOUT : CTRL (_rl_to_upper (c)); + has_control = 0; + } + if (has_meta) + { + c = META (c); + has_meta = 0; + } + + /* 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); + } + else + array[l++] = (c); + + /* Null characters may be processed for incomplete prefixes at the end of + sequence */ + if (seq[i] == '\0') + break; } *len = l; @@ -756,7 +789,7 @@ _rl_untranslate_macro_value (char *seq, int use_escapes) /* Return a pointer to the function that STRING represents. If STRING doesn't have a matching function, then a NULL pointer - is returned. */ + is returned. The string match is case-insensitive. */ rl_command_func_t * rl_named_function (const char *string) { @@ -809,7 +842,7 @@ _rl_function_of_keyseq_internal (const char *keyseq, size_t len, Keymap map, int { /* If this is the last key in the key sequence, return the map. */ - if (keyseq[i + 1] == '\0') + if (i + 1 == len) { if (type) *type = ISKMAP; @@ -822,9 +855,9 @@ _rl_function_of_keyseq_internal (const char *keyseq, size_t len, Keymap map, int /* 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]) + else if (map[ic].type != ISKMAP && i+1 < len) return ((rl_command_func_t *)NULL); - else /* map[ic].type != ISKMAP && keyseq[i+1] == 0 */ + else /* map[ic].type != ISKMAP && i+1 == len */ { if (type) *type = map[ic].type; @@ -1569,15 +1602,11 @@ rl_parse_and_bind (char *string) /* Strip trailing whitespace from values of boolean variables. */ if (find_boolean_var (var) >= 0) { - /* remove trailing whitespace */ -remove_trailing: - e = value + strlen (value) - 1; - while (e >= value && whitespace (*e)) - e--; - e++; /* skip back to whitespace or EOS */ - - if (*e && e >= value) - *e = '\0'; + /* just read a whitespace-delimited word or empty string */ + for (e = value; *e && whitespace (*e) == 0; e++) + ; + if (e > value) + *e = '\0'; /* cut off everything trailing */ } else if ((i = find_string_var (var)) >= 0) { @@ -1589,9 +1618,24 @@ remove_trailing: value++; /* skip past the quote */ } else - goto remove_trailing; + { + /* 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'; + } } - + else + { + /* avoid calling rl_variable_bind just to find this out */ + _rl_init_file_error ("%s: unknown variable name", var); + return 1; + } + rl_variable_bind (var, value); return 0; } @@ -1903,7 +1947,7 @@ string_varname (int i) } /* A boolean value that can appear in a `set variable' command is true if - the value is null or empty, `on' (case-insensitive), or "1". Any other + the value is null or empty, `on' (case-insensitive), or "1". All other values result in 0 (false). */ static int bool_to_int (const char *value) @@ -1928,7 +1972,7 @@ rl_variable_value (const char *name) return (_rl_get_string_variable_value (string_varlist[i].name)); /* Unknown variable names return NULL. */ - return 0; + return (char *)NULL; } int @@ -1959,6 +2003,8 @@ rl_variable_bind (const char *name, const char *value) } v = (*string_varlist[i].set_func) (value); + if (v != 0) + _rl_init_file_error ("%s: could not set value to `%s'", name, value); return v; } @@ -2581,20 +2627,22 @@ rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map) 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'; + 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]); |