]> code.delx.au - gnu-emacs/commitdiff
(Ftranslate_region): Handle multibyte chars in the arg
authorKenichi Handa <handa@m17n.org>
Mon, 1 Mar 2004 06:19:10 +0000 (06:19 +0000)
committerKenichi Handa <handa@m17n.org>
Mon, 1 Mar 2004 06:19:10 +0000 (06:19 +0000)
TABLE correctly.

src/editfns.c

index 9a1ce81f31637ec9f73df3a3189a41703f7ace4f..31493e3c7742bfc7255e638f73726bea6b08d243 100644 (file)
@@ -2741,7 +2741,6 @@ DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
        doc: /* From START to END, translate characters according to TABLE.
 TABLE is a string; the Nth character in it is the mapping
 for the character with code N.
-This function does not alter multibyte characters.
 It returns the number of characters changed.  */)
      (start, end, table)
      Lisp_Object start;
@@ -2755,11 +2754,18 @@ It returns the number of characters changed.  */)
   int size;                    /* Size of translate table. */
   int pos;
   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  int string_multibyte;
 
   validate_region (&start, &end);
   CHECK_STRING (table);
 
-  size = SBYTES (table);
+  if (multibyte != (SCHARS (table) < SBYTES (table)))
+    table = (multibyte
+            ? string_make_multibyte (table)
+            : string_make_unibyte (table));
+  string_multibyte = SCHARS (table) < SBYTES (table);
+
+  size = SCHARS (table);
   tt = SDATA (table);
 
   pos_byte = CHAR_TO_BYTE (XINT (start));
@@ -2771,7 +2777,8 @@ It returns the number of characters changed.  */)
   for (; pos_byte < stop; )
     {
       register unsigned char *p = BYTE_POS_ADDR (pos_byte);
-      int len;
+      unsigned char *str;
+      int len, str_len;
       int oc;
       int pos_byte_next;
 
@@ -2780,22 +2787,27 @@ It returns the number of characters changed.  */)
       else
        oc = *p, len = 1;
       pos_byte_next = pos_byte + len;
-      if (oc < size && len == 1)
+      if (oc < size)
        {
-         nc = tt[oc];
+         if (string_multibyte)
+           {
+             str = tt + string_char_to_byte (table, oc);
+             nc = STRING_CHAR_AND_LENGTH (str, MAX_MULTIBYTE_LENGTH, str_len);
+           }
+         else
+           {
+             str = tt + oc;
+             nc = tt[oc], str_len = 1;
+           }
          if (nc != oc)
            {
              /* Take care of the case where the new character
                 combines with neighboring bytes.  */
-             if (!ASCII_BYTE_P (nc)
-                 && (CHAR_HEAD_P (nc)
-                     ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
-                     : (pos_byte > BEG_BYTE
-                        && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
+             if (len > 1 || str_len > 1)
                {
                  Lisp_Object string;
 
-                 string = make_multibyte_string (tt + oc, 1, 1);
+                 string = make_multibyte_string (str, 1, str_len);
                  /* This is less efficient, because it moves the gap,
                     but it handles combining correctly.  */
                  replace_range (pos, pos + 1, string,
@@ -2812,7 +2824,8 @@ It returns the number of characters changed.  */)
              else
                {
                  record_change (pos, 1);
-                 *p = nc;
+                 while (str_len-- > 0)
+                   *p++ = *str++;
                  signal_after_change (pos, 1, 1);
                  update_compositions (pos, pos + 1, CHECK_BORDER);
                }