(Ftranspose_regions): Use BYTE_POS_ADDR to get an
[bpt/emacs.git] / src / editfns.c
index aca1a34..f31c7f6 100644 (file)
@@ -490,20 +490,26 @@ See also `gap-position'.")
 }
 
 DEFUN ("position-bytes", Fposition_bytes, Sposition_bytes, 1, 1, 0,
-  "Return the byte position for character position POSITION.")
+  "Return the byte position for character position POSITION.\n\
+If POSITION is out of range, the value is nil.")
   (position)
      Lisp_Object position;
 {
   CHECK_NUMBER_COERCE_MARKER (position, 1);
+  if (XINT (position) < BEG || XINT (position) > Z)
+    return Qnil;
   return make_number (CHAR_TO_BYTE (XINT (position)));
 }
 
 DEFUN ("byte-to-position", Fbyte_to_position, Sbyte_to_position, 1, 1, 0,
-  "Return the character position for byte position BYTEPOS.")
+  "Return the character position for byte position BYTEPOS.\n\
+If BYTEPOS is out of range, the value is nil.")
   (bytepos)
      Lisp_Object bytepos;
 {
   CHECK_NUMBER (bytepos, 1);
+  if (XINT (bytepos) < BEG_BYTE || XINT (bytepos) > Z_BYTE)
+    return Qnil;
   return make_number (BYTE_TO_CHAR (XINT (bytepos)));
 }
 \f
@@ -1326,7 +1332,13 @@ general_insert_function (insert_func, insert_from_string_func,
          if (!NILP (current_buffer->enable_multibyte_characters))
            len = CHAR_STRING (XFASTINT (val), workbuf, str);
          else
-           workbuf[0] = XINT (val), str = workbuf, len = 1;
+           {
+             workbuf[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
+                           ? XINT (val)
+                           : multibyte_char_to_unibyte (XINT (val), Qnil));
+             str = workbuf;
+             len = 1;
+           }
          (*insert_func) (str, len);
        }
       else if (STRINGP (val))
@@ -1938,9 +1950,44 @@ Both characters must have the same length of multi-byte form.")
              changed = 1;
            }
 
-         if (NILP (noundo))
-           record_change (pos, 1);
-         for (i = 0; i < len; i++) *p++ = tostr[i];
+         /* Take care of the case where the new character
+            combines with neighboring bytes.  */ 
+         if (len == 1
+             && ((! CHAR_HEAD_P (tostr[0])
+                  && pos_byte > BEGV_BYTE
+                  && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
+                 ||
+                 (! ASCII_BYTE_P (tostr[0])
+                  && pos_byte + 1 < ZV_BYTE
+                  && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)))))
+           {
+             Lisp_Object tem, string;
+
+             struct gcpro gcpro1;
+
+             tem = current_buffer->undo_list;
+             GCPRO1 (tem);
+
+             /* Make a multibyte string containing this
+                single-byte character.  */
+             string = Fmake_string (make_number (1),
+                                    make_number (tochar));
+             SET_STRING_BYTES (XSTRING (string), 1);
+             /* replace_range is less efficient, because it moves the gap,
+                but it handles combining correctly.  */
+             replace_range (pos, pos + 1, string,
+                            0, 0, 0);
+             if (! NILP (noundo))
+               current_buffer->undo_list = tem;
+
+             UNGCPRO;
+           }
+         else
+           {
+             if (NILP (noundo))
+               record_change (pos, 1);
+             for (i = 0; i < len; i++) *p++ = tostr[i];
+           }
        }
       INC_BOTH (pos, pos_byte);
     }
@@ -1995,9 +2042,33 @@ It returns the number of characters changed.")
          nc = tt[oc];
          if (nc != oc)
            {
-             record_change (pos, 1);
-             *p = nc;
-             signal_after_change (pos, 1, 1);
+             /* Take care of the case where the new character
+                combines with neighboring bytes.  */ 
+             if ((! CHAR_HEAD_P (nc)
+                  && pos_byte > BEGV_BYTE
+                  && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
+                 ||
+                 (! ASCII_BYTE_P (nc)
+                  && pos_byte + 1 < ZV_BYTE
+                  && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))))
+               {
+                 Lisp_Object string;
+
+                 string = Fmake_string (make_number (1),
+                                        make_number (nc));
+                 SET_STRING_BYTES (XSTRING (string), 1);
+
+                 /* This is less efficient, because it moves the gap,
+                    but it handles combining correctly.  */
+                 replace_range (pos, pos + 1, string,
+                                1, 0, 0);
+               }
+             else
+               {
+                 record_change (pos, 1);
+                 *p = nc;
+                 signal_after_change (pos, 1, 1);
+               }
              ++cnt;
            }
        }
@@ -2875,8 +2946,8 @@ Transposing beyond buffer boundaries is an error.")
                         start1_byte, start1_byte + len1_byte,
                         start2_byte, start2_byte + len2_byte);
 
-      replace_range (start2, end2, text1, 1, 0, 1);
-      replace_range (start1, end1, text2, 1, 0, 1);
+      replace_range (start2, end2, text1, 1, 0, 0);
+      replace_range (start1, end1, text2, 1, 0, 0);
 
       UNGCPRO;
       return Qnil;
@@ -2914,8 +2985,8 @@ Transposing beyond buffer boundaries is an error.")
          /* Don't precompute these addresses.  We have to compute them
             at the last minute, because the relocating allocator might
             have moved the buffer around during the xmalloc.  */
-         start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
-         start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+         start1_addr = BYTE_POS_ADDR (start1_byte);
+         start2_addr = BYTE_POS_ADDR (start2_byte);
 
           bcopy (start2_addr, temp, len2_byte);
           bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
@@ -2930,8 +3001,8 @@ Transposing beyond buffer boundaries is an error.")
            temp = (unsigned char *) xmalloc (len1_byte);
          else
            temp = (unsigned char *) alloca (len1_byte);
-         start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
-         start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+         start1_addr = BYTE_POS_ADDR (start1_byte);
+         start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start1_addr + len2_byte, len1_byte);
@@ -2970,8 +3041,8 @@ Transposing beyond buffer boundaries is an error.")
            temp = (unsigned char *) xmalloc (len1_byte);
          else
            temp = (unsigned char *) alloca (len1_byte);
-         start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
-         start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+         start1_addr = BYTE_POS_ADDR (start1_byte);
+         start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start2_addr, len1_byte);
@@ -3003,8 +3074,8 @@ Transposing beyond buffer boundaries is an error.")
            temp = (unsigned char *) xmalloc (len2_byte);
          else
            temp = (unsigned char *) alloca (len2_byte);
-         start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
-         start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+         start1_addr = BYTE_POS_ADDR (start1_byte);
+         start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start2_addr, temp, len2_byte);
           bcopy (start1_addr, start1_addr + len_mid + len2_byte, len1_byte);
           safe_bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
@@ -3039,8 +3110,8 @@ Transposing beyond buffer boundaries is an error.")
            temp = (unsigned char *) xmalloc (len1_byte);
          else
            temp = (unsigned char *) alloca (len1_byte);
-         start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
-         start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+         start1_addr = BYTE_POS_ADDR (start1_byte);
+         start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);