changeset 20608:a6cca06d5aaf

(count_size_as_multibyte): New function. (insert_from_string_1, insert_from_buffer_1): Use it. (copy_text): New function. (insert_from_buffer_1): Call copy_text to convert between single-byte and multibyte text. (insert_from_string_1): Likewise. (insert_1_both): New function. (insert_from_string): New args POS_BYTE, LENGTH. (insert_from_string_before_markers): (insert_from_string_1): New arg POS_BYTE. Swap args NCHARS, NBYTES. Don't fail to use POS_BYTE! (insert_from_buffer_1): Get both inschars and insbytes from NEW.
author Richard M. Stallman <rms@gnu.org>
date Fri, 09 Jan 1998 22:46:07 +0000
parents 04a436e5760b
children 4bf29951648f
files src/insdel.c
diffstat 1 files changed, 295 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/src/insdel.c	Fri Jan 09 22:41:43 1998 +0000
+++ b/src/insdel.c	Fri Jan 09 22:46:07 1998 +0000
@@ -33,7 +33,7 @@
 
 #define min(x, y) ((x) < (y) ? (x) : (y))
 
-static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int));
+static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int));
 static void insert_from_buffer_1 ();
 static void gap_left P_ ((int, int, int));
 static void gap_right P_ ((int, int));
@@ -63,6 +63,8 @@
 /* Buffer which combine_after_change_list is about.  */
 Lisp_Object combine_after_change_buffer;
 
+#define DEFAULT_NONASCII_INSERT_OFFSET 0x800
+
 /* Move gap to position CHARPOS.
    Note that this can quit!  */
 
@@ -262,7 +264,7 @@
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
   QUIT;
 }
-
+
 /* Add AMOUNT to the byte position of every marker in the current buffer
    whose current byte position is between FROM (exclusive) and TO (inclusive).
 
@@ -324,7 +326,7 @@
     }
 #endif
 }
-
+
 /* Adjust all markers for a deletion
    whose range in bytes is FROM_BYTE to TO_BYTE.
    The range in charpos is FROM to TO.
@@ -389,7 +391,7 @@
       marker = m->chain;
     }
 }
-
+
 /* Adjust markers for an insertion at CHARPOS / BYTEPOS
    consisting of NCHARS chars, which are NBYTES bytes.
 
@@ -542,7 +544,107 @@
   Vinhibit_quit = tem;
 }
 
+/* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
+   FROM_MULTIBYTE says whether the incoming text is multibyte.
+   TO_MULTIBYTE says whether to store the text as multibyte.
+   If FROM_MULTIBYTE != TO_MULTIBYTE, we convert.
+
+   Return the number of bytes stored at TO_ADDR.  */
+
+int
+copy_text (from_addr, to_addr, nbytes,
+	   from_multibyte, to_multibyte)
+     unsigned char *from_addr;
+     unsigned char *to_addr;
+     int nbytes;
+     int from_multibyte, to_multibyte;
+{
+  if (from_multibyte == to_multibyte)
+    {
+      bcopy (from_addr, to_addr, nbytes);
+      return nbytes;
+    }
+  else if (from_multibyte)
+    {
+      int nchars = 0;
+      int bytes_left = nbytes;
+
+      /* Convert multibyte to single byte.  */
+      while (bytes_left > 0)
+	{
+	  int thislen, c;
+	  c = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
+	  *to_addr++ = (c & 0177) + 0200;
+	  from_addr += thislen;
+	  bytes_left--;
+	  nchars++;
+	}
+      return nchars;
+    }
+  else
+    {
+      unsigned char *initial_to_addr = to_addr;
+
+      /* Convert single-byte to multibyte.  */
+      while (nbytes > 0)
+	{
+	  int c = *from_addr++;
+	  unsigned char workbuf[4], *str;
+	  int len;
+
+	  if (c >= 0200 && c < 0400)
+	    {
+	      if (nonascii_insert_offset > 0)
+		c += nonascii_insert_offset;
+	      else
+		c += DEFAULT_NONASCII_INSERT_OFFSET;
+
+	      len = CHAR_STRING (c, workbuf, str);
+	      bcopy (str, to_addr, len);
+	      to_addr += len;
+	      nbytes--;
+	    }
+	  else
+	    /* Special case for speed.  */
+	    *to_addr++ = c, nbytes--;
+	}
+      return to_addr - initial_to_addr;
+    }
+}
+
+/* Return the number of bytes it would take
+   to convert some single-byte text to multibyte.
+   The single-byte text consists of NBYTES bytes at PTR.  */
+
+int
+count_size_as_multibyte (ptr, nbytes)
+     unsigned char *ptr;
+     int nbytes;
+{
+  int i;
+  int outgoing_nbytes = 0;
+
+  for (i = 0; i < nbytes; i++)
+    {
+      unsigned int c = *ptr++;
+      if (c >= 0200 && c < 0400)
+	{
+	  if (nonascii_insert_offset > 0)
+	    c += nonascii_insert_offset;
+	  else
+	    c += DEFAULT_NONASCII_INSERT_OFFSET;
+	}
+      outgoing_nbytes += XINT (Fchar_bytes (make_number (c)));
+    }
+
+  return outgoing_nbytes;
+}
+
 /* Insert a string of specified length before point.
+   This function judges multibyteness based on
+   enable_multibyte_characters in the current buffer;
+   it never converts between single-byte and multibyte.
+
    DO NOT use this for the contents of a Lisp string or a Lisp buffer!
    prepare_to_modify_buffer could relocate the text.  */
 
@@ -559,6 +661,8 @@
     }
 }
 
+/* Likewise, but inherit text properties from neighboring characters.  */
+
 void
 insert_and_inherit (string, nbytes)
      register unsigned char *string;
@@ -572,19 +676,28 @@
     }
 }
 
-/* Insert the character C before point */
+/* Insert the character C before point.  Do not inherit text properties.  */
 
 void
 insert_char (c)
      int c;
 {
   unsigned char workbuf[4], *str;
-  int len = CHAR_STRING (c, workbuf, str);
+  int len;
+
+  if (! NILP (current_buffer->enable_multibyte_characters))
+    len = CHAR_STRING (c, workbuf, str);
+  else
+    {
+      len = 1;
+      workbuf[0] = c;
+      str = workbuf;
+    }
 
   insert (str, len);
 }
 
-/* Insert the null-terminated string S before point */
+/* Insert the null-terminated string S before point.  */
 
 void
 insert_string (s)
@@ -612,6 +725,8 @@
     }
 }
 
+/* Likewise, but inherit text properties from neighboring characters.  */
+
 void
 insert_before_markers_and_inherit (string, nbytes)
      unsigned char *string;
@@ -625,7 +740,7 @@
       signal_after_change (opoint, 0, PT - opoint);
     }
 }
-
+
 /* Subroutine used by the insert functions above.  */
 
 void
@@ -678,71 +793,21 @@
 			  Qnil, Qnil);
 #endif
 }
-
-/* Insert the part of the text of STRING, a Lisp object assumed to be
-   of type string, consisting of the LENGTH characters starting at
-   position POS.  If the text of STRING has properties, they are absorbed
-   into the buffer.
 
-   It does not work to use `insert' for this, because a GC could happen
-   before we bcopy the stuff into the buffer, and relocate the string
-   without insert noticing.  */
-
-void
-insert_from_string (string, pos, length, inherit)
-     Lisp_Object string;
-     register int pos, length;
-     int inherit;
-{
-  if (length > 0)
-    {
-      int opoint = PT;
-      int nchars = chars_in_text (XSTRING (string)->data + pos, length);
-      insert_from_string_1 (string, pos, length, nchars, inherit, 0);
-      signal_after_change (opoint, 0, PT - opoint);
-    }
-}
-
-/* Like `insert' except that all markers pointing at the place where
-   the insertion happens are adjusted to point after it.
-   Don't use this function to insert part of a Lisp string,
-   since gc could happen and relocate it.  */
-
-/* Insert part of a Lisp string, relocating markers after.  */
+/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
+   starting at STRING.  INHERIT, PREPARE and BEFORE_MARKERS
+   are the same as in insert_1.  */
 
 void
-insert_from_string_before_markers (string, pos, length, inherit)
-     Lisp_Object string;
-     register int pos, length;
-     int inherit;
-{
-  if (length > 0)
-    {
-      int opoint = PT;
-      int nchars = chars_in_text (XSTRING (string)->data + pos, length);
-      insert_from_string_1 (string, pos, length, nchars, inherit, 1);
-      signal_after_change (opoint, 0, PT - opoint);
-    }
-}
-
-/* Subroutine of the insertion functions above.  */
-
-static void
-insert_from_string_1 (string, pos, nbytes, nchars, inherit, before_markers)
-     Lisp_Object string;
-     register int pos, nbytes, nchars;
-     int inherit, before_markers;
+insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
+     register unsigned char *string;
+     register int nchars, nbytes;
+     int inherit, prepare, before_markers;
 {
   register Lisp_Object temp;
-  struct gcpro gcpro1;
 
-  /* Make sure point-max won't overflow after this insertion.  */
-  XSETINT (temp, nbytes + Z_BYTE);
-  if (nbytes + Z_BYTE != XINT (temp))
-    error ("Maximum buffer size exceeded");
-
-  GCPRO1 (string);
-  prepare_to_modify_buffer (PT, PT, NULL);
+  if (prepare)
+    prepare_to_modify_buffer (PT, PT, NULL);
 
   if (PT != GPT)
     move_gap_both (PT, PT_BYTE);
@@ -751,12 +816,14 @@
 
   record_insert (PT, nchars);
   MODIFF++;
-  UNGCPRO;
+
+  bcopy (string, GPT_ADDR, nbytes);
 
-  bcopy (XSTRING (string)->data, GPT_ADDR, nbytes);
-
-  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  offset_intervals (current_buffer, PT, nchars);
+#ifdef USE_TEXT_PROPERTIES
+  if (BUF_INTERVALS (current_buffer) != 0)
+    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
+    offset_intervals (current_buffer, PT, nchars);
+#endif
 
   GAP_SIZE -= nbytes;
   GPT += nchars;
@@ -769,15 +836,134 @@
   adjust_overlays_for_insert (PT, nchars);
   adjust_markers_for_insert (PT, PT_BYTE, PT + nchars, PT_BYTE + nbytes,
 			     before_markers);
+  adjust_point (nchars, nbytes);
 
   if (GPT_BYTE < GPT)
     abort ();
 
+#ifdef USE_TEXT_PROPERTIES
+  if (!inherit && BUF_INTERVALS (current_buffer) != 0)
+    Fset_text_properties (make_number (PT - nchars), make_number (PT),
+			  Qnil, Qnil);
+#endif
+}
+
+/* Insert the part of the text of STRING, a Lisp object assumed to be
+   of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes)
+   starting at position POS / POS_BYTE.  If the text of STRING has properties,
+   copy them into the buffer.
+
+   It does not work to use `insert' for this, because a GC could happen
+   before we bcopy the stuff into the buffer, and relocate the string
+   without insert noticing.  */
+
+void
+insert_from_string (string, pos, pos_byte, length, length_byte, inherit)
+     Lisp_Object string;
+     register int pos, pos_byte, length, length_byte;
+     int inherit;
+{
+  if (length > 0)
+    {
+      int opoint = PT;
+      insert_from_string_1 (string, pos, pos_byte, length, length_byte,
+			    inherit, 0);
+      signal_after_change (opoint, 0, PT - opoint);
+    }
+}
+
+/* Like `insert_from_string' except that all markers pointing
+   at the place where the insertion happens are adjusted to point after it.  */
+
+void
+insert_from_string_before_markers (string, pos, pos_byte,
+				   length, length_byte, inherit)
+     Lisp_Object string;
+     register int pos, pos_byte, length, length_byte;
+     int inherit;
+{
+  if (length > 0)
+    {
+      int opoint = PT;
+      insert_from_string_1 (string, pos, pos_byte, length, length_byte,
+			    inherit, 1);
+      signal_after_change (opoint, 0, PT - opoint);
+    }
+}
+
+/* Subroutine of the insertion functions above.  */
+
+static void
+insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
+		      inherit, before_markers)
+     Lisp_Object string;
+     register int pos, pos_byte, nchars, nbytes;
+     int inherit, before_markers;
+{
+  register Lisp_Object temp;
+  struct gcpro gcpro1;
+  int outgoing_nbytes = nbytes;
+
+  /* Make OUTGOING_NBYTES describe the text
+     as it will be inserted in this buffer.  */
+
+  if (NILP (current_buffer->enable_multibyte_characters))
+    outgoing_nbytes = nchars;
+  else if (nchars == nbytes)
+    outgoing_nbytes
+      = count_size_as_multibyte (&XSTRING (string)->data[pos_byte],
+				 nbytes);
+
+  /* Make sure point-max won't overflow after this insertion.  */
+  XSETINT (temp, outgoing_nbytes + Z);
+  if (outgoing_nbytes + Z != XINT (temp))
+    error ("Maximum buffer size exceeded");
+
+  GCPRO1 (string);
+  prepare_to_modify_buffer (PT, PT, NULL);
+
+  if (PT != GPT)
+    move_gap_both (PT, PT_BYTE);
+  if (GAP_SIZE < nbytes)
+    make_gap (outgoing_nbytes - GAP_SIZE);
+
+  record_insert (PT, nchars);
+  MODIFF++;
+  UNGCPRO;
+
+  /* Copy the string text into the buffer, perhaps converting
+     between single-byte and multibyte.  */
+  copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes,
+	     /* If these are equal, it is a single-byte string.
+		Its chars are either ASCII, in which case copy_text
+		won't change it, or single-byte non-ASCII chars,
+		that need to be changed.  */
+	     nchars != nbytes,
+	     ! NILP (current_buffer->enable_multibyte_characters));
+
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+  offset_intervals (current_buffer, PT, nchars);
+
+  GAP_SIZE -= nbytes;
+  GPT += nchars;
+  ZV += nchars;
+  Z += nchars;
+  GPT_BYTE += outgoing_nbytes;
+  ZV_BYTE += outgoing_nbytes;
+  Z_BYTE += outgoing_nbytes;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
+  adjust_overlays_for_insert (PT, nchars);
+  adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
+			     PT_BYTE + outgoing_nbytes,
+			     before_markers);
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
   graft_intervals_into_buffer (XSTRING (string)->intervals, PT, nchars,
 			       current_buffer, inherit);
 
-  adjust_point (nchars, nbytes);
+  adjust_point (nchars, outgoing_nbytes);
 }
 
 /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
@@ -812,19 +998,30 @@
   int chunk;
   int from_byte = buf_charpos_to_bytepos (buf, from);
   int to_byte = buf_charpos_to_bytepos (buf, from + nchars);
-  int nbytes = to_byte - from_byte;
+  int incoming_nbytes = to_byte - from_byte;
+  int outgoing_nbytes = incoming_nbytes;
+
+  /* Make OUTGOING_NBYTES describe the text
+     as it will be inserted in this buffer.  */
+
+  if (NILP (current_buffer->enable_multibyte_characters))
+    outgoing_nbytes = nchars;
+  else if (NILP (buf->enable_multibyte_characters))
+    outgoing_nbytes
+      = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
+				 incoming_nbytes);
 
   /* Make sure point-max won't overflow after this insertion.  */
-  XSETINT (temp, nbytes + Z);
-  if (nbytes + Z != XINT (temp))
+  XSETINT (temp, outgoing_nbytes + Z);
+  if (outgoing_nbytes + Z != XINT (temp))
     error ("Maximum buffer size exceeded");
 
   prepare_to_modify_buffer (PT, PT, NULL);
 
   if (PT != GPT)
     move_gap_both (PT, PT_BYTE);
-  if (GAP_SIZE < nbytes)
-    make_gap (nbytes - GAP_SIZE);
+  if (GAP_SIZE < outgoing_nbytes)
+    make_gap (outgoing_nbytes - GAP_SIZE);
 
   record_insert (PT, nchars);
   MODIFF++;
@@ -832,32 +1029,38 @@
   if (from < BUF_GPT (buf))
     {
       chunk = BUF_GPT_BYTE (buf) - from_byte;
-      if (chunk > nbytes)
-	chunk = nbytes;
-      bcopy (BUF_BYTE_ADDRESS (buf, from_byte), GPT_ADDR, chunk);
+      if (chunk > incoming_nbytes)
+	chunk = incoming_nbytes;
+      copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
+		 GPT_ADDR, chunk,
+		 ! NILP (buf->enable_multibyte_characters),
+		 ! NILP (current_buffer->enable_multibyte_characters));
     }
   else
     chunk = 0;
-  if (chunk < nbytes)
-    bcopy (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
-	   GPT_ADDR + chunk, nbytes - chunk);
+  if (chunk < incoming_nbytes)
+    copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
+	       GPT_ADDR + chunk, incoming_nbytes - chunk,
+	       ! NILP (buf->enable_multibyte_characters),
+	       ! NILP (current_buffer->enable_multibyte_characters));
 
 #ifdef USE_TEXT_PROPERTIES
   if (BUF_INTERVALS (current_buffer) != 0)
     offset_intervals (current_buffer, PT, nchars);
 #endif
 
-  GAP_SIZE -= nbytes;
+  GAP_SIZE -= outgoing_nbytes;
   GPT += nchars;
   ZV += nchars;
   Z += nchars;
-  GPT_BYTE += nbytes;
-  ZV_BYTE += nbytes;
-  Z_BYTE += nbytes;
+  GPT_BYTE += outgoing_nbytes;
+  ZV_BYTE += outgoing_nbytes;
+  Z_BYTE += outgoing_nbytes;
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
   adjust_overlays_for_insert (PT, nchars);
-  adjust_markers_for_insert (PT, PT_BYTE, PT + nchars, PT_BYTE + nbytes, 0);
-  adjust_point (nchars, nbytes);
+  adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
+			     PT_BYTE + outgoing_nbytes, 0);
+  adjust_point (nchars, outgoing_nbytes);
 
   if (GPT_BYTE < GPT)
     abort ();
@@ -884,8 +1087,8 @@
      Lisp_Object new;
      int from, to, prepare, inherit;
 {
-  int insbytes = XSTRING (new)->size;
-  int inschars;
+  int inschars = XSTRING (new)->size;
+  int insbytes = XSTRING (new)->size_byte;
   int from_byte, to_byte;
   int nbytes_del, nchars_del;
   register Lisp_Object temp;
@@ -922,8 +1125,6 @@
   if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
     error ("Maximum buffer size exceeded");
 
-  inschars = XINT (Fchars_in_string (new));
-
   GCPRO1 (new);
 
   /* Make sure the gap is somewhere in or next to what we are deleting.  */