bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Fix a bug that `bind -x '"metachar":command'' fails when rl-vari


From: Koichi Murase
Subject: [PATCH] Fix a bug that `bind -x '"metachar":command'' fails when rl-variable `convert-meta' is `on'
Date: Mon, 11 Feb 2019 15:57:18 +0900

Configuration Information [Automatically generated, do not change]:
Machine: i686
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -O2 -march=native -Wno-parentheses -Wno-format-security
uname output: Linux padparadscha 4.13.13-100.fc25.i686 #1 SMP Wed Nov
15 18:24:19 UTC 2017 i686 i686 i386 GNU/Linux
Machine Type: i686-pc-linux-gnu

Bash Version: 5.0
Patch Level: 0
Release Status: release

Description:

  When readline variable `convert-meta' is set to `on', `bind -x'
including meta characters in its keyseq fails to bind.

  For an actual example, see the next `Repeat-By' section. An
inconsistency comes from the condition whether to contain ESC (from
meta chars) in the keyseq stored in keymaps. For example, in
`rl_generic_bind' (lib/readline/bind.c), ESC is only contained when
the keymap already has a child ISKMAP entry at ESC as quoted below:

    if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
      {
        ic = UNMETA (ic);
        if (map[ESC].type == ISKMAP) /* <-- this condition */
          {
            prevmap = map;
            map = FUNCTION_TO_KEYMAP (map, ESC);
          }
      }

  In addition, the condition in `rl_translate_keyseq'
(lib/readline/bind.c) always refers to the current top-level keymap
`_rl_keymap' rather than the corresponding keymap entry in the target
keymap tree, which appears to be unreasonable:

    if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP)
        array[l++] = ESC; /* ESC is meta-prefix */

  `bind -x' stores data in two different keymaps: the selected keymap
and the keymap `cmd_xmap' defined in `bashline.c'. When one has a
child ISKMAP entry at ESC and the other doesn't have, the inconsisty
arises.

Repeat-By:

  The readline variable `convert-meta' is enabled by default when Bash
starts with `LANG=C'.

    $ LANG=C bash-5.0 --norc
    $ bind -v | grep convert-meta
    set convert-meta on

  `bind -x' whose keyseq contains meta characters stores the command
string to wrong places in `cmd_xmap'. In the following example, the
command string for `\M-c' is stored to the placeholder for `c'.

    $ bind -x '"c": "echo hello"'
    $ bind -x $'"\xE3": "echo world"'
    world # <-- somehow the binding for `\M-c' is invoked by typing `c'
    $
    bash-5.0: bash_execute_unix_command: cannot find keymap for
command # <-- error is produced by typing `\M-c'
    $ bind -X
    "c": "echo world"
    $

  For reference, usual macro key bindings work as expected.

    $ bind '"c": "hello"'
    $ bind $'"\xE3": "world"'
    $ echo helloworld # <-- `hello' and `world' is inserted by typing
`c' and `\M-c'
    helloworld
    $ bind -s
    "\ec": "world"
    "c": "hello"

Fix:

  Actually I'm not sure if there is a reason why stored keyseqs
contains ESC only when there is already ESC entry, but a possible
solution would be to create a new ISKMAP entry when there is no ISKMAP
entry at ESC. I attach a patch
`0001-translate-meta-characters-when-convert-meta-is-set.patch'. I
have changed `rl_bind_key' (lib/readeline/bind.c) so that the ISKMAP
entry is explicitly created. I have changed `rl_translate_keyseq'
(lib/readeline/bind.c) so that meta characters `c' are always
translated to `ESC' + `UNMETA (c)' when `convert-meta' is set. In this
way, the array `keys' in `rl_generic_bind' (lib/readeline/bind.c)
would never contain meta characters when `convert-meta' is set, so the
codes to check meta characters have been removed from
`rl_generic_bind'.

  By the way, in `rl_bind_key' (lib/readline/bind.c), isn't the range
condition for the argument `key' incomplete? I'm not confident, but
could you check the second patch
`0002-add-a-range-condition-to-rl_bind_key.patch'?

  Also, in `_rl_function_of_keyseq_internal' (lib/readline/bind.c),
shouldn't the end of the keyseq be detected using the keyseq length
`len'? The current implementation sees if the next key is '\0' or not,
but it misbehaves when the keyseq contains `\C-@' (NUL). Note that it
is possible to contain `\C-@' in the keyseq by using the interface
`rl_function_of_keyseq_len'. See the third patch
`0003-use-keyseq-length-to-check-the-end-of-keyseq.patch'.

----
Best regards,
Koichi

Attachment: 0001-translate-meta-characters-when-convert-meta-is-set.patch
Description: Binary data

Attachment: 0002-add-a-range-condition-to-rl_bind_key.patch
Description: Binary data

Attachment: 0003-use-keyseq-length-to-check-the-end-of-keyseq.patch
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]