]> git.eshelyaron.com Git - emacs.git/commitdiff
read_key_sequence: correct the handling of raw_keybuf in recursive calls
authorAlan Mackenzie <acm@muc.de>
Mon, 20 Nov 2017 18:05:33 +0000 (18:05 +0000)
committerAlan Mackenzie <acm@muc.de>
Mon, 20 Nov 2017 18:08:43 +0000 (18:08 +0000)
This fixes bug #29349.

* src/keyboard.c (raw_keybuf_buffer, raw_keybuf_count_buffer): New variables
pointed to by ...
(raw_keybuf, raw_keybuf_count): Variables converted to pointers.
(GROW_RAW_KEYBUF): enhance with a length argument.
(command_loop_1): Initialize the above two pointers to their canonical values.

(read_key_sequence): In recursive calls (for menus) the function was
overwriting the raw event buffer of the outer call.  Correct this by
introducing a local buffer for each level of call, and setting this up to be
used by the call to read_char.  Any contents of this local buffer are appended
to the global buffer afterwards.

src/keyboard.c

index 6b7a6bfa7436dafc0ca699320f3cec743724cc31..b18dc1abbe7cf3cae0010749e8dbf17c7a407987 100644 (file)
@@ -121,12 +121,17 @@ ptrdiff_t this_command_key_count;
 
 /* This vector is used as a buffer to record the events that were actually read
    by read_key_sequence.  */
-static Lisp_Object raw_keybuf;
-static int raw_keybuf_count;
-
-#define GROW_RAW_KEYBUF                                                        \
- if (raw_keybuf_count == ASIZE (raw_keybuf))                           \
-   raw_keybuf = larger_vector (raw_keybuf, 1, -1)
+static Lisp_Object raw_keybuf_buffer;
+static int raw_keybuf_count_buffer;
+static Lisp_Object *raw_keybuf = &raw_keybuf_buffer;
+static int *raw_keybuf_count = &raw_keybuf_count_buffer;
+
+#define GROW_RAW_KEYBUF(inc)                                            \
+  if (*raw_keybuf_count > ASIZE (*raw_keybuf) - (inc))                  \
+    *raw_keybuf =                                                       \
+      larger_vector (*raw_keybuf,                                       \
+                     (inc) + *raw_keybuf_count - ASIZE (*raw_keybuf),   \
+                     -1)
 
 /* Number of elements of this_command_keys
    that precede this key sequence.  */
@@ -1365,6 +1370,8 @@ command_loop_1 (void)
       Vthis_command_keys_shift_translated = Qnil;
 
       /* Read next key sequence; i gets its length.  */
+      raw_keybuf_count = &raw_keybuf_count_buffer; /* For safety */
+      raw_keybuf = &raw_keybuf_buffer;             /* Ditto */
       i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
                             Qnil, 0, 1, 1, 0);
 
@@ -8913,6 +8920,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   /* How many keys there are in the current key sequence.  */
   int t;
 
+  int *outer_raw_keybuf_count;
+  Lisp_Object *outer_raw_keybuf;
+  int inner_raw_keybuf_count_buffer;
+  Lisp_Object inner_raw_keybuf_buffer = Fmake_vector (make_number (30), Qnil);
+
   /* The length of the echo buffer when we started reading, and
      the length of this_command_keys when we started reading.  */
   ptrdiff_t echo_start UNINIT;
@@ -8973,7 +8985,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   /* List of events for which a fake prefix key has been generated.  */
   Lisp_Object fake_prefixed_keys = Qnil;
 
-  raw_keybuf_count = 0;
+  *raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
 
@@ -9145,11 +9157,23 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          {
            KBOARD *interrupted_kboard = current_kboard;
            struct frame *interrupted_frame = SELECTED_FRAME ();
+            int i;
+            outer_raw_keybuf_count = raw_keybuf_count;
+            outer_raw_keybuf = raw_keybuf;
+            inner_raw_keybuf_count_buffer = 0;
+            raw_keybuf_count = &inner_raw_keybuf_count_buffer;
+            raw_keybuf = &inner_raw_keybuf_buffer;
            /* Calling read_char with COMMANDFLAG = -2 avoids
               redisplay in read_char and its subroutines.  */
            key = read_char (prevent_redisplay ? -2 : NILP (prompt),
                             current_binding, last_nonmenu_event,
                              &used_mouse_menu, NULL);
+            raw_keybuf_count = outer_raw_keybuf_count;
+            raw_keybuf = outer_raw_keybuf;
+            GROW_RAW_KEYBUF (inner_raw_keybuf_count_buffer);
+            for (i = 0; i < inner_raw_keybuf_count_buffer; i++)
+              ASET (*raw_keybuf, (*raw_keybuf_count)++,
+                    AREF (inner_raw_keybuf_buffer, i));
            if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
                /* When switching to a new tty (with a new keyboard),
                   read_char returns the new buffer, rather than -2
@@ -9257,9 +9281,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
              && XINT (key) == quit_char
              && current_buffer != starting_buffer)
            {
-             GROW_RAW_KEYBUF;
-             ASET (raw_keybuf, raw_keybuf_count, key);
-             raw_keybuf_count++;
+             GROW_RAW_KEYBUF (1);
+             ASET (*raw_keybuf, *raw_keybuf_count, key);
+             (*raw_keybuf_count)++;
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
@@ -9298,9 +9322,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
              current_binding = active_maps (first_event);
            }
 
-         GROW_RAW_KEYBUF;
-         ASET (raw_keybuf, raw_keybuf_count, key);
-         raw_keybuf_count++;
+         GROW_RAW_KEYBUF (1);
+         ASET (*raw_keybuf, *raw_keybuf_count, key);
+         (*raw_keybuf_count)++;
        }
 
       /* Clicks in non-text areas get prefixed by the symbol
@@ -9346,8 +9370,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                      && BUFFERP (XWINDOW (window)->contents)
                      && XBUFFER (XWINDOW (window)->contents) != current_buffer)
                    {
-                     ASET (raw_keybuf, raw_keybuf_count, key);
-                     raw_keybuf_count++;
+                     GROW_RAW_KEYBUF (1);
+                      ASET (*raw_keybuf, *raw_keybuf_count, key);
+                     (*raw_keybuf_count)++;
                      keybuf[t] = key;
                      mock_input = t + 1;
 
@@ -10120,7 +10145,7 @@ shows the events before all translations (except for input methods).
 The value is always a vector.  */)
   (void)
 {
-  return Fvector (raw_keybuf_count, XVECTOR (raw_keybuf)->contents);
+  return Fvector (*raw_keybuf_count, XVECTOR (*raw_keybuf)->contents);
 }
 
 DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
@@ -11265,8 +11290,8 @@ syms_of_keyboard (void)
   this_command_keys = Fmake_vector (make_number (40), Qnil);
   staticpro (&this_command_keys);
 
-  raw_keybuf = Fmake_vector (make_number (30), Qnil);
-  staticpro (&raw_keybuf);
+  raw_keybuf_buffer = Fmake_vector (make_number (30), Qnil);
+  staticpro (raw_keybuf);
 
   DEFSYM (Qcommand_execute, "command-execute");
   DEFSYM (Qinternal_echo_keystrokes_prefix, "internal-echo-keystrokes-prefix");