bug-bash
[Top][All Lists]
Advanced

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

Re: [PATCH] fix bind -X quoting


From: Grisha Levit
Subject: Re: [PATCH] fix bind -X quoting
Date: Wed, 26 Jul 2023 17:57:24 -0400

On Wed, Jul 26, 2023, 16:06 Chet Ramey <chet.ramey@case.edu> wrote:
>
> On 7/24/23 1:13 PM, Chet Ramey wrote:
>
> > You could do it if you allowed, say
> >
> > bind -x '"\eX": \"command with spaces\" \"x\"'
> >
> > and then stripped the backslashes before calling rl_generic_bind, but
> > that's not exactly backwards compatible either.
>
> Thinking about it some more, you can do it like this:
>
> bind -x $'"\\eX": \'"command with spaces" "x"\''
>
> since bind -x allows single-quoted strings as the command to execute,
> and $'...' allows backslash-escaped single quotes.
>
> If we ran the command string through rl_translate_keyseq, it would allow
> backslash-escaped double quotes and strip the backslashes, but you get
> the rest of the backslash processing that you probably don't want.
>
> It's just not transitive.


Another issue I didn't think of with printing the unquoted translated
command is that it can include newlines, which is a problem since you
have to read the `bind -X' output one line at a time to reuse it with
`bind -x'.

If there isn't a backwards compatible way to produce output that is
reusable given the current input format, I wonder if we can leverage a
format that's not currently valid as input.  `bind -x' currently
requires a colon following the key sequence but we could change it to
also allow input without it and use rl_macro_bind instead of
rl_generic_bind if we get such input.  If we have `bind -X' produce
untranslated output as it did before, but without the `:', everything
should match up and existing valid `bind -X' commands will be
unaffected.
---
diff --git a/bashline.c b/bashline.c
index 5dac2e9e..9d99c536 100644
--- a/bashline.c
+++ b/bashline.c
@@ -4702,7 +4702,7 @@ bind_keyseq_to_unix_command (char *line)
 {
   Keymap kmap, cmd_xmap;
   char *kseq, *value;
-  int i, kstart;
+  int i, kstart, translate;

   kmap = rl_get_keymap ();

@@ -4716,16 +4716,13 @@ bind_keyseq_to_unix_command (char *line)
   /* Create the key sequence string to pass to rl_generic_bind */
   kseq = substring (line, kstart, i);

-  for ( ; line[i] && line[i] != ':'; i++)
+  /* Advance to the colon (:) or whitespace which separates the two objects. */
+  for ( ; line[i] && line[i] != ':' && line[i] != ' ' && line[i] != '\t'; i++)
     ;
-  if (line[i] != ':')
-    {
-      builtin_error (_("%s: missing colon separator"), line);
-      FREE (kseq);
-      return -1;
-    }

-  i = isolate_sequence (line, i + 1, 0, &kstart);
+  translate = (line[i] != ':');
+
+  i = isolate_sequence (line, i + 1, translate, &kstart);
   if (i < 0)
     {
       FREE (kseq);
@@ -4737,7 +4734,10 @@ bind_keyseq_to_unix_command (char *line)

   /* Save the command to execute and the key sequence in the CMD_XMAP */
   cmd_xmap = get_cmd_xmap_from_keymap (kmap);
-  rl_generic_bind (ISMACR, kseq, value, cmd_xmap);
+  if (translate)
+    rl_macro_bind (kseq, value, cmd_xmap);
+  else
+    rl_generic_bind (ISMACR, kseq, value, cmd_xmap);

   /* and bind the key sequence in the current keymap to a function that
      understands how to execute from CMD_XMAP */
diff --git a/lib/readline/bind.c b/lib/readline/bind.c
index dc30dd84..9d4817a3 100644
--- a/lib/readline/bind.c
+++ b/lib/readline/bind.c
@@ -2861,18 +2861,12 @@ _rl_macro_dumper_internal (int print_readably,
Keymap map, char *prefix)
        {
        case ISMACR:
          keyname = _rl_get_keyname (key);
-         if (print_readably < 0)
-           out = savestring ((char *)map[key].function);
-         else
-           out = _rl_untranslate_macro_value ((char *)map[key].function, 0);
+         out = _rl_untranslate_macro_value ((char *)map[key].function, 0);

-         if (print_readably < 0)
-           fprintf (rl_outstream, "\"%s%s\": %s\n", prefix ? prefix : "",
-                                                        keyname,
-                                                        out ? out : "");
-         else if (print_readably > 0)
-           fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
+         if (print_readably)
+           fprintf (rl_outstream, "\"%s%s\"%s \"%s\"\n", prefix ? prefix : "",
                                                         keyname,
+                                                        print_readably > 0 ? 
":" : "",
                                                         out ? out : "");
          else
            fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",



reply via email to

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