]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
Bash-5.2 patch 36: fix for reading partial invalid multibyte characters
authorChet Ramey <chet.ramey@case.edu>
Mon, 23 Sep 2024 22:17:46 +0000 (18:17 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 23 Sep 2024 22:17:46 +0000 (18:17 -0400)
lib/readline/text.c
patchlevel.h

index 91c3f330d897d03c88ad3459fbcdf090acb4f2fd..8f092f5881e29a34c37606e7ef7383fefde2b7be 100644 (file)
@@ -85,7 +85,8 @@ int _rl_optimize_typeahead = 1;       /* rl_insert tries to read typeahead */
 int
 rl_insert_text (const char *string)
 {
-  register int i, l;
+  register int i;
+  size_t l;
 
   l = (string && *string) ? strlen (string) : 0;
   if (l == 0)
@@ -704,7 +705,11 @@ static mbstate_t ps = {0};
 
 /* Insert the character C at the current location, moving point forward.
    If C introduces a multibyte sequence, we read the whole sequence and
-   then insert the multibyte char into the line buffer. */
+   then insert the multibyte char into the line buffer.
+   If C == 0, we immediately insert any pending partial multibyte character,
+   assuming that we have read a character that doesn't map to self-insert.
+   This doesn't completely handle characters that are part of a multibyte
+   character but map to editing functions. */
 int
 _rl_insert_char (int count, int c)
 {
@@ -718,11 +723,28 @@ _rl_insert_char (int count, int c)
   static int stored_count = 0;
 #endif
 
+#if !defined (HANDLE_MULTIBYTE)
   if (count <= 0)
     return 0;
+#else
+  if (count < 0)
+    return 0;
+  if (count == 0)
+    {
+      if (pending_bytes_length == 0)
+       return 0;
+      if (stored_count <= 0)
+       stored_count = count;
+      else
+       count = stored_count;
 
-#if defined (HANDLE_MULTIBYTE)
-  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+      memcpy (incoming, pending_bytes, pending_bytes_length);
+      incoming[pending_bytes_length] = '\0';
+      incoming_length = pending_bytes_length;
+      pending_bytes_length = 0;
+      memset (&ps, 0, sizeof (mbstate_t));
+    }
+  else if (MB_CUR_MAX == 1 || rl_byte_oriented)
     {
       incoming[0] = c;
       incoming[1] = '\0';
@@ -730,6 +752,9 @@ _rl_insert_char (int count, int c)
     }
   else if (_rl_utf8locale && (c & 0x80) == 0)
     {
+      if (pending_bytes_length)
+       _rl_insert_char (0, 0);
+
       incoming[0] = c;
       incoming[1] = '\0';
       incoming_length = 1;
@@ -764,7 +789,8 @@ _rl_insert_char (int count, int c)
          incoming[1] = '\0';
          incoming_length = 1;
          pending_bytes_length--;
-         memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
+         if (pending_bytes_length)
+           memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
          /* Clear the state of the byte sequence, because in this case the
             effect of mbstate is undefined. */
          memset (&ps, 0, sizeof (mbstate_t));
@@ -827,7 +853,11 @@ _rl_insert_char (int count, int c)
       rl_insert_text (string);
       xfree (string);
 
+#if defined (HANDLE_MULTIBYTE)
+      return (pending_bytes_length != 0);
+#else
       return 0;
+#endif
     }
 
   if (count > TEXT_COUNT_MAX)
@@ -860,6 +890,8 @@ _rl_insert_char (int count, int c)
       xfree (string);
       incoming_length = 0;
       stored_count = 0;
+
+      return (pending_bytes_length != 0);
 #else /* !HANDLE_MULTIBYTE */
       char str[TEXT_COUNT_MAX+1];
 
@@ -873,9 +905,9 @@ _rl_insert_char (int count, int c)
          rl_insert_text (str);
          count -= decreaser;
        }
-#endif /* !HANDLE_MULTIBYTE */
 
       return 0;
+#endif /* !HANDLE_MULTIBYTE */
     }
 
   if (MB_CUR_MAX == 1 || rl_byte_oriented)
@@ -903,9 +935,11 @@ _rl_insert_char (int count, int c)
       rl_insert_text (incoming);
       stored_count = 0;
     }
-#endif
-
+  
+  return (pending_bytes_length != 0);
+#else
   return 0;
+#endif
 }
 
 /* Overwrite the character at point (or next COUNT characters) with C.
@@ -983,6 +1017,11 @@ rl_insert (int count, int c)
        break;
     }
 
+  /* If we didn't insert n and there are pending bytes, we need to insert
+     them if _rl_insert_char didn't do that on its own. */
+  if (r == 1 && rl_insert_mode == RL_IM_INSERT)
+    r = _rl_insert_char (0, 0);                /* flush partial multibyte char */
+
   if (n != (unsigned short)-2)         /* -2 = sentinel value for having inserted N */
     {
       /* setting rl_pending_input inhibits setting rl_last_func so we do it
@@ -1054,6 +1093,8 @@ _rl_insert_next_callback (_rl_callback_generic_arg *data)
 int
 rl_quoted_insert (int count, int key)
 {
+  int r;
+
   /* Let's see...should the callback interface futz with signal handling? */
 #if defined (HANDLE_SIGNALS)
   if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
@@ -1072,15 +1113,17 @@ rl_quoted_insert (int count, int key)
   /* A negative count means to quote the next -COUNT characters. */
   if (count < 0)
     {
-      int r;
-
       do
        r = _rl_insert_next (1);
       while (r == 0 && ++count < 0);
-      return r;
     }
+  else
+    r = _rl_insert_next (count);
 
-  return _rl_insert_next (count);
+  if (r == 1)
+    _rl_insert_char (0, 0);    /* insert partial multibyte character */
+
+  return r;
 }
 
 /* Insert a tab character. */
index c6775026de6bba732172139712d84f59da196042..0134ea1ae4de76f60aef3430d86a9b9890b57e7f 100644 (file)
@@ -25,6 +25,6 @@
    regexp `^#define[   ]*PATCHLEVEL', since that's what support/mkversion.sh
    looks for to find the patch level (for the sccs version string). */
 
-#define PATCHLEVEL 35
+#define PATCHLEVEL 36
 
 #endif /* _PATCHLEVEL_H_ */