emacs-diffs
[Top][All Lists]
Advanced

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

master 0a9c8855b0: Don't decode text within XIM callbacks or handle_one_


From: Po Lu
Subject: master 0a9c8855b0: Don't decode text within XIM callbacks or handle_one_xevent
Date: Tue, 15 Feb 2022 21:38:46 -0500 (EST)

branch: master
commit 0a9c8855b0ce9618219ef70bb489107ce7194ba1
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Don't decode text within XIM callbacks or handle_one_xevent
    
    * src/keyboard.c (kbd_buffer_get_event_1):
    (kbd_buffer_get_event_2): New functions.
    (kbd_buffer_get_event): Accept a new meaning of
    MULTIBYTE_CHAR_KEYSTROKE_EVENT where .arg can be a unibyte
    string to be decoded in the locale coding system.
    
    * src/termhooks.h (enum event_kind): Document new meaning of
    .arg in a multibyte keystroke event.
    
    * src/xfns.c (struct x_xim_text_conversion_data): New struct.
    (x_xim_text_to_utf8_unix_1):
    (x_xim_text_to_utf8_unix_2): New functions.
    (x_xim_text_to_utf8_unix): Handle decode failure correctly.
    (xic_preedit_draw_callback): Abort IM context if text could not
    be decoded correctly.
    
    * src/xterm.c (handle_one_xevent): Utilize new meaning of
    MULTIBYTE_CHAR_KEYSTROKE_EVENT.
---
 src/keyboard.c  |  67 ++++++++++++++++++++++++++++--
 src/termhooks.h |  15 +++++--
 src/xfns.c      |  85 +++++++++++++++++++++++++++++---------
 src/xterm.c     | 126 ++++----------------------------------------------------
 4 files changed, 149 insertions(+), 144 deletions(-)

diff --git a/src/keyboard.c b/src/keyboard.c
index be9fb665d7..800632aa25 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3835,6 +3835,18 @@ clear_event (struct input_event *event)
   event->kind = NO_EVENT;
 }
 
+static Lisp_Object
+kbd_buffer_get_event_1 (Lisp_Object arg)
+{
+  return code_convert_string (arg, Vlocale_coding_system,
+                             Qnil, 0, false, 0);
+}
+
+static Lisp_Object
+kbd_buffer_get_event_2 (Lisp_Object val)
+{
+  return Qnil;
+}
 
 /* Read one event from the event buffer, waiting if necessary.
    The value is a Lisp object representing the event.
@@ -3847,7 +3859,7 @@ kbd_buffer_get_event (KBOARD **kbp,
                       bool *used_mouse_menu,
                       struct timespec *end_time)
 {
-  Lisp_Object obj;
+  Lisp_Object obj, str;
 
 #ifdef subprocesses
   if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4)
@@ -4120,6 +4132,47 @@ kbd_buffer_get_event (KBOARD **kbp,
                    }
                }
 
+             if (event->kind == MULTIBYTE_CHAR_KEYSTROKE_EVENT
+                 /* This string has to be decoded.  */
+                 && STRINGP (event->ie.arg))
+               {
+                 str = internal_condition_case_1 (kbd_buffer_get_event_1,
+                                                  event->ie.arg, Qt,
+                                                  kbd_buffer_get_event_2);
+
+                 /* Decoding the string failed, so use the original,
+                    where at least ASCII text will work.  */
+                 if (NILP (str))
+                   str = event->ie.arg;
+
+                 if (!SCHARS (str))
+                   {
+                     kbd_fetch_ptr = next_kbd_event (event);
+                     obj = Qnil;
+                     break;
+                   }
+
+                 /* car is the index of the next character in the
+                    string that will be sent and cdr is the string
+                    itself.  */
+                 event->ie.arg = Fcons (make_fixnum (0), str);
+               }
+
+             if (event->kind == MULTIBYTE_CHAR_KEYSTROKE_EVENT
+                 && CONSP (event->ie.arg))
+               {
+                 eassert (FIXNUMP (XCAR (event->ie.arg)));
+                 eassert (STRINGP (XCDR (event->ie.arg)));
+                 eassert (XFIXNUM (XCAR (event->ie.arg))
+                          < SCHARS (XCDR (event->ie.arg)));
+
+                 event->ie.code = XFIXNUM (Faref (XCDR (event->ie.arg),
+                                                  XCAR (event->ie.arg)));
+
+                 XSETCAR (event->ie.arg,
+                          make_fixnum (XFIXNUM (XCAR (event->ie.arg)) + 1));
+               }
+
              obj = make_lispy_event (&event->ie);
 
 #ifdef HAVE_EXT_MENU_BAR
@@ -4142,9 +4195,15 @@ kbd_buffer_get_event (KBOARD **kbp,
                *used_mouse_menu = true;
 #endif
 
-             /* Wipe out this event, to catch bugs.  */
-             clear_event (&event->ie);
-             kbd_fetch_ptr = next_kbd_event (event);
+             if (event->kind != MULTIBYTE_CHAR_KEYSTROKE_EVENT
+                 || !CONSP (event->ie.arg)
+                 || (XFIXNUM (XCAR (event->ie.arg))
+                     >= SCHARS (XCDR (event->ie.arg))))
+               {
+                 /* Wipe out this event, to catch bugs.  */
+                 clear_event (&event->ie);
+                 kbd_fetch_ptr = next_kbd_event (event);
+               }
            }
        }
       }
diff --git a/src/termhooks.h b/src/termhooks.h
index 518e855eae..4276d8ac2f 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -80,10 +80,17 @@ enum event_kind
                                   which the key was typed.
                                   .timestamp gives a timestamp (in
                                   milliseconds) for the keystroke.  */
-  MULTIBYTE_CHAR_KEYSTROKE_EVENT,      /* The multibyte char code is in .code,
-                                  perhaps with modifiers applied.
-                                  The others are the same as
-                                  ASCII_KEYSTROKE_EVENT.  */
+  MULTIBYTE_CHAR_KEYSTROKE_EVENT,      /* The multibyte char code is
+                                          in .code, perhaps with
+                                          modifiers applied.  The
+                                          others are the same as
+                                          ASCII_KEYSTROKE_EVENT,
+                                          except when ARG is a
+                                          string, which will be
+                                          decoded and the decoded
+                                          string's characters will be
+                                          used as .code
+                                          individually.  */
   NON_ASCII_KEYSTROKE_EVENT,   /* .code is a number identifying the
                                   function key.  A code N represents
                                   a key whose name is
diff --git a/src/xfns.c b/src/xfns.c
index 0f8d6933b3..f00b738908 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3139,14 +3139,64 @@ xic_preedit_done_callback (XIC xic, XPointer 
client_data,
     }
 }
 
+struct x_xim_text_conversion_data
+{
+  struct coding_system *coding;
+  char *source;
+};
+
+static Lisp_Object
+x_xim_text_to_utf8_unix_1 (ptrdiff_t nargs,
+                          Lisp_Object *args)
+{
+  struct x_xim_text_conversion_data *data;
+  ptrdiff_t nbytes;
+
+  data = xmint_pointer (args[0]);
+  nbytes = strlen (data->source);
+
+  data->coding->destination = NULL;
+
+  setup_coding_system (Vlocale_coding_system,
+                      data->coding);
+  data->coding->mode |= (CODING_MODE_LAST_BLOCK
+                        | CODING_MODE_SAFE_ENCODING);
+  data->coding->source = (const unsigned char *) data->source;
+  data->coding->dst_bytes = 2048;
+  data->coding->destination = xmalloc (2048);
+  decode_coding_object (data->coding, Qnil, 0, 0,
+                       nbytes, nbytes, Qnil);
+
+  return Qnil;
+}
+
+static Lisp_Object
+x_xim_text_to_utf8_unix_2 (Lisp_Object val,
+                          ptrdiff_t nargs,
+                          Lisp_Object *args)
+{
+  struct x_xim_text_conversion_data *data;
+
+  data = xmint_pointer (args[0]);
+
+  if (data->coding->destination)
+    xfree (data->coding->destination);
+
+  data->coding->destination = NULL;
+
+  return Qnil;
+}
+
 /* The string returned is not null-terminated.  */
 static char *
 x_xim_text_to_utf8_unix (XIMText *text, ptrdiff_t *length)
 {
   unsigned char *wchar_buf;
   ptrdiff_t wchar_actual_length, i;
-  ptrdiff_t nbytes;
   struct coding_system coding;
+  struct x_xim_text_conversion_data data;
+  bool was_waiting_for_input_p;
+  Lisp_Object arg;
 
   if (text->encoding_is_wchar)
     {
@@ -3161,17 +3211,16 @@ x_xim_text_to_utf8_unix (XIMText *text, ptrdiff_t 
*length)
       return (char *) wchar_buf;
     }
 
-  nbytes = strlen (text->string.multi_byte);
-  setup_coding_system (Vlocale_coding_system, &coding);
-  coding.mode |= (CODING_MODE_LAST_BLOCK
-                 | CODING_MODE_SAFE_ENCODING);
-  coding.source = (const unsigned char *) text->string.multi_byte;
-  coding.dst_bytes = 2048;
-  coding.destination = xmalloc (2048);
-  decode_coding_object (&coding, Qnil, 0, 0, nbytes, nbytes, Qnil);
+  data.coding = &coding;
+  data.source = text->string.multi_byte;
 
-  /* coding.destination has either been allocated by us, or
-     reallocated by decode_coding_object.  */
+  was_waiting_for_input_p = waiting_for_input;
+  /* Otherwise Fsignal will crash.  */
+  waiting_for_input = false;
+  arg = make_mint_ptr (&data);
+  internal_condition_case_n (x_xim_text_to_utf8_unix_1, 1, &arg,
+                            Qt, x_xim_text_to_utf8_unix_2);
+  waiting_for_input = was_waiting_for_input_p;
 
   *length = coding.produced;
   return (char *) coding.destination;
@@ -3198,16 +3247,14 @@ xic_preedit_draw_callback (XIC xic, XPointer 
client_data,
       if (!output->preedit_active)
        return;
 
-      /* If we don't bail out here then GTK can crash
-        from the resulting signal in `setup_coding_system'.  */
-      if (NILP (Fcoding_system_p (Vlocale_coding_system)))
+      if (call_data->text)
        {
-         text = NULL;
-         goto im_abort;
-       }
+         text = x_xim_text_to_utf8_unix (call_data->text, &text_length);
 
-      if (call_data->text)
-       text = x_xim_text_to_utf8_unix (call_data->text, &text_length);
+         if (!text)
+           /* Decoding the IM text failed.  */
+           goto im_abort;
+       }
       else
        text = NULL;
 
diff --git a/src/xterm.c b/src/xterm.c
index 23317bf695..568351d2e3 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -9124,7 +9124,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   int do_help = 0;
   ptrdiff_t nbytes = 0;
   struct frame *any, *f = NULL;
-  struct coding_system coding;
   Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
   /* This holds the state XLookupString needs to implement dead keys
      and other tricks known as "compose processing".  _X Window System_
@@ -9134,8 +9133,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   XEvent configureEvent;
   XEvent next_event;
 
-  USE_SAFE_ALLOCA;
-
   *finish = X_EVENT_NORMAL;
 
   EVENT_INIT (inev.ie);
@@ -9843,7 +9840,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
           unsigned char *copy_bufptr = copy_buffer;
           int copy_bufsiz = sizeof (copy_buffer);
           int modifiers;
-          Lisp_Object coding_system = Qlatin_1;
          Lisp_Object c;
          /* `xkey' will be modified, but it's not important to modify
             `event' itself.  */
@@ -9884,7 +9880,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             {
               Status status_return;
 
-              coding_system = Vlocale_coding_system;
               nbytes = XmbLookupString (FRAME_XIC (f),
                                         &xkey, (char *) copy_bufptr,
                                         copy_bufsiz, &keysym,
@@ -10051,64 +10046,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
          {     /* Raw bytes, not keysym.  */
            ptrdiff_t i;
-           int nchars, len;
-
-           for (i = 0, nchars = 0; i < nbytes; i++)
-             {
-               if (ASCII_CHAR_P (copy_bufptr[i]))
-                 nchars++;
-               STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
-             }
-
-           if (nchars < nbytes)
-             {
-               /* If we don't bail out here then GTK can crash
-                  from the resulting signal in `setup_coding_system'.  */
-               if (NILP (Fcoding_system_p (coding_system)))
-                 goto done_keysym;
-
-               /* Decode the input data.  */
-
-               /* The input should be decoded with `coding_system'
-                  which depends on which X*LookupString function
-                  we used just above and the locale.  */
-               setup_coding_system (coding_system, &coding);
-               coding.src_multibyte = false;
-               coding.dst_multibyte = true;
-               /* The input is converted to events, thus we can't
-                  handle composition.  Anyway, there's no XIM that
-                  gives us composition information.  */
-               coding.common_flags &= ~CODING_ANNOTATION_MASK;
-
-               SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
-                             nbytes);
-               coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
-               coding.mode |= CODING_MODE_LAST_BLOCK;
-               decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
-               nbytes = coding.produced;
-               nchars = coding.produced_char;
-               copy_bufptr = coding.destination;
-             }
 
-           /* Convert the input data to a sequence of
-              character events.  */
-           for (i = 0; i < nbytes; i += len)
-             {
-               int ch;
-               if (nchars == nbytes)
-                 ch = copy_bufptr[i], len = 1;
-               else
-                 ch = string_char_and_length (copy_bufptr + i, &len);
-               inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
-                               ? ASCII_KEYSTROKE_EVENT
-                               : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
-               inev.ie.code = ch;
-               kbd_buffer_store_buffered_event (&inev, hold_quit);
-             }
-
-           count += nchars;
+           for (i = 0; i < nbytes; i++)
+             STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
 
-           inev.ie.kind = NO_EVENT;  /* Already stored above.  */
+           inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+           inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes);
 
            if (keysym == NoSymbol)
              break;
@@ -11497,10 +11440,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              KeySym keysym;
              char copy_buffer[81];
              char *copy_bufptr = copy_buffer;
-             unsigned char *copy_ubufptr;
              int copy_bufsiz = sizeof (copy_buffer);
              ptrdiff_t i;
-             int nchars, len;
              struct xi_device_t *device;
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
@@ -11802,62 +11743,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      goto xi_done_keysym;
                    }
 
-                 for (i = 0, nchars = 0; i < nbytes; i++)
-                   {
-                     if (ASCII_CHAR_P (copy_bufptr[i]))
-                       nchars++;
-                     STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
-                   }
+                 for (i = 0; i < nbytes; i++)
+                   STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
 
-                 if (nchars < nbytes)
-                   {
-                     /* If we don't bail out here then GTK can crash
-                        from the resulting signal in `setup_coding_system'.  */
-                     if (NILP (Fcoding_system_p (Vlocale_coding_system)))
-                       goto xi_done_keysym;
-
-                     /* Decode the input data.  */
-
-                     setup_coding_system (Vlocale_coding_system, &coding);
-                     coding.src_multibyte = false;
-                     coding.dst_multibyte = true;
-                     /* The input is converted to events, thus we can't
-                        handle composition.  Anyway, there's no XIM that
-                        gives us composition information.  */
-                     coding.common_flags &= ~CODING_ANNOTATION_MASK;
-
-                     SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
-                                   nbytes);
-                     coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
-                     coding.mode |= CODING_MODE_LAST_BLOCK;
-                     decode_coding_c_string (&coding, (unsigned char *) 
copy_bufptr,
-                                             nbytes, Qnil);
-                     nbytes = coding.produced;
-                     nchars = coding.produced_char;
-                     copy_bufptr = (char *) coding.destination;
-                   }
-
-                 copy_ubufptr = (unsigned char *) copy_bufptr;
-
-                 /* Convert the input data to a sequence of
-                    character events.  */
-                 for (i = 0; i < nbytes; i += len)
-                   {
-                     int ch;
-                     if (nchars == nbytes)
-                       ch = copy_ubufptr[i], len = 1;
-                     else
-                       ch = string_char_and_length (copy_ubufptr + i, &len);
-                     inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
-                                     ? ASCII_KEYSTROKE_EVENT
-                                     : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
-                     inev.ie.code = ch;
-                     kbd_buffer_store_buffered_event (&inev, hold_quit);
-                   }
-
-                 inev.ie.kind = NO_EVENT;
+                 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+                 inev.ie.arg = make_unibyte_string (copy_bufptr, nbytes);
                  goto xi_done_keysym;
                }
+
              goto XI_OTHER;
            }
 
@@ -12352,7 +12245,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   /* Sometimes event processing draws to the frame outside redisplay.
      To ensure that these changes become visible, draw them here.  */
   flush_dirty_back_buffers ();
-  SAFE_FREE ();
   return count;
 }
 



reply via email to

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