changeset 92992:49c4ea77b83a

(CHAR_STRING_ADVANCE_NO_UNIFY) (STRING_CHAR_ADVANCE_NO_UNIFY): New macros. (coding_alloc_by_making_gap): Fix the way to preserve data in the gap. (alloc_destination): Fix the 2nd arg to coding_alloc_by_making_gap. (encode_coding_utf_8): Use CHAR_STRING_ADVANCE_NO_UNIFY instead of CHAR_STRING_ADVANCE. (produce_chars): Fix for the case that the source and the destination are the same buffer. Use CHAR_STRING_ADVANCE_NO_UNIFY instead of CHAR_STRING_ADVANCE. (consume_chars): Use STRING_CHAR_ADVANCE_NO_UNIFY instead of STRING_CHAR_ADVANCE.
author Kenichi Handa <handa@m17n.org>
date Sun, 16 Mar 2008 01:24:55 +0000
parents 24a6717aed7f
children 61c2483cb400
files src/coding.c
diffstat 1 files changed, 109 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/coding.c	Sun Mar 16 01:24:21 2008 +0000
+++ b/src/coding.c	Sun Mar 16 01:24:55 2008 +0000
@@ -972,6 +972,66 @@
   } while (0)
 
 
+/* Store multibyte form of the character C in P, and advance P to the
+   end of the multibyte form.  This is like CHAR_STRING_ADVANCE but it
+   never calls MAYBE_UNIFY_CHAR.  */
+
+#define CHAR_STRING_ADVANCE_NO_UNIFY(c, p)	\
+  do {						\
+    if ((c) <= MAX_1_BYTE_CHAR)			\
+      *(p)++ = (c);				\
+    else if ((c) <= MAX_2_BYTE_CHAR)		\
+      *(p)++ = (0xC0 | ((c) >> 6)),		\
+	*(p)++ = (0x80 | ((c) & 0x3F));		\
+    else if ((c) <= MAX_3_BYTE_CHAR)		\
+      *(p)++ = (0xE0 | ((c) >> 12)),		\
+	*(p)++ = (0x80 | (((c) >> 6) & 0x3F)),	\
+	*(p)++ = (0x80 | ((c) & 0x3F));		\
+    else if ((c) <= MAX_4_BYTE_CHAR)		\
+      *(p)++ = (0xF0 | (c >> 18)),		\
+	*(p)++ = (0x80 | ((c >> 12) & 0x3F)),	\
+	*(p)++ = (0x80 | ((c >> 6) & 0x3F)),	\
+	*(p)++ = (0x80 | (c & 0x3F));		\
+    else if ((c) <= MAX_5_BYTE_CHAR)		\
+      *(p)++ = 0xF8,				\
+	*(p)++ = (0x80 | ((c >> 18) & 0x0F)),	\
+	*(p)++ = (0x80 | ((c >> 12) & 0x3F)),	\
+	*(p)++ = (0x80 | ((c >> 6) & 0x3F)),	\
+	*(p)++ = (0x80 | (c & 0x3F));		\
+    else					\
+      (p) += BYTE8_STRING ((c) - 0x3FFF80, p);	\
+  } while (0)
+
+
+/* Return the character code of character whose multibyte form is at
+   P, and advance P to the end of the multibyte form.  This is like
+   STRING_CHAR_ADVANCE, but it never calls MAYBE_UNIFY_CHAR.  */
+
+#define STRING_CHAR_ADVANCE_NO_UNIFY(p)				\
+  (!((p)[0] & 0x80)						\
+   ? *(p)++							\
+   : ! ((p)[0] & 0x20)						\
+   ? ((p) += 2,							\
+      ((((p)[-2] & 0x1F) << 6)					\
+       | ((p)[-1] & 0x3F)					\
+       | ((unsigned char) ((p)[-2]) < 0xC2 ? 0x3FFF80 : 0)))	\
+   : ! ((p)[0] & 0x10)						\
+   ? ((p) += 3,							\
+      ((((p)[-3] & 0x0F) << 12)					\
+       | (((p)[-2] & 0x3F) << 6)				\
+       | ((p)[-1] & 0x3F)))					\
+   : ! ((p)[0] & 0x08)						\
+   ? ((p) += 4,							\
+      ((((p)[-4] & 0xF) << 18)					\
+       | (((p)[-3] & 0x3F) << 12)				\
+       | (((p)[-2] & 0x3F) << 6)				\
+       | ((p)[-1] & 0x3F)))					\
+   : ((p) += 5,							\
+      ((((p)[-4] & 0x3F) << 18)					\
+       | (((p)[-3] & 0x3F) << 12)				\
+       | (((p)[-2] & 0x3F) << 6)				\
+       | ((p)[-1] & 0x3F))))
+
 
 static void
 coding_set_source (coding)
@@ -1037,20 +1097,23 @@
 }
 
 static void
-coding_alloc_by_making_gap (coding, offset, bytes)
+coding_alloc_by_making_gap (coding, gap_head_used, bytes)
      struct coding_system *coding;
-     EMACS_INT offset, bytes;
-{
-  if (BUFFERP (coding->dst_object)
-      && EQ (coding->src_object, coding->dst_object))
-    {
-      EMACS_INT add = offset + (coding->src_bytes - coding->consumed);
-
-      GPT += offset, GPT_BYTE += offset;
-      GAP_SIZE -= add; ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
+     EMACS_INT gap_head_used, bytes;
+{
+  if (EQ (coding->src_object, coding->dst_object))
+    {
+      /* The gap may contain the produced data at the head and not-yet
+	 consumed data at the tail.  To preserve those data, we at
+	 first make the gap size to zero, then increase the gap
+	 size.  */
+      EMACS_INT add = GAP_SIZE;
+
+      GPT += gap_head_used, GPT_BYTE += gap_head_used;
+      GAP_SIZE = 0; ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
       make_gap (bytes);
       GAP_SIZE += add; ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
-      GPT -= offset, GPT_BYTE -= offset;
+      GPT -= gap_head_used, GPT_BYTE -= gap_head_used;
     }
   else
     {
@@ -1073,7 +1136,11 @@
   EMACS_INT offset = dst - coding->destination;
 
   if (BUFFERP (coding->dst_object))
-    coding_alloc_by_making_gap (coding, offset, nbytes);
+    {
+      struct buffer *buf = XBUFFER (coding->dst_object);
+
+      coding_alloc_by_making_gap (coding, dst - BUF_GPT_ADDR (buf), nbytes);
+    }
   else
     coding_alloc_by_realloc (coding, nbytes);
   record_conversion_result (coding, CODING_RESULT_SUCCESS);
@@ -1365,7 +1432,7 @@
 	    }
 	  else
 	    {
-	      CHAR_STRING_ADVANCE (c, pend);
+	      CHAR_STRING_ADVANCE_NO_UNIFY (c, pend);
 	      for (p = str; p < pend; p++)
 		EMIT_ONE_BYTE (*p);
 	    }
@@ -1382,7 +1449,7 @@
 	  if (CHAR_BYTE8_P (c))
 	    *dst++ = CHAR_TO_BYTE8 (c);
 	  else
-	    dst += CHAR_STRING (c, dst);
+	    CHAR_STRING_ADVANCE_NO_UNIFY (c, dst);
 	  produced_chars++;
 	}
     }
@@ -5971,9 +6038,11 @@
       int *buf = coding->charbuf;
       int *buf_end = buf + coding->charbuf_used;
 
-      if (BUFFERP (coding->src_object)
-	  && EQ (coding->src_object, coding->dst_object))
-	dst_end = ((unsigned char *) coding->source) + coding->consumed;
+      if (EQ (coding->src_object, coding->dst_object))
+	{
+	  coding_set_source (coding);
+	  dst_end = ((unsigned char *) coding->source) + coding->consumed;
+	}
 
       while (buf < buf_end)
 	{
@@ -6000,7 +6069,13 @@
 					   buf_end - buf
 					   + MAX_MULTIBYTE_LENGTH * to_nchars,
 					   dst);
-		  dst_end = coding->destination + coding->dst_bytes;
+		  if (EQ (coding->src_object, coding->dst_object))
+		    {
+		      coding_set_source (coding);
+		      dst_end = ((unsigned char *) coding->source) + coding->consumed;
+		    }
+		  else
+		    dst_end = coding->destination + coding->dst_bytes;
 		}
 
 	      for (i = 0; i < to_nchars; i++)
@@ -6009,7 +6084,7 @@
 		    c = XINT (AREF (trans, i));
 		  if (coding->dst_multibyte
 		      || ! CHAR_BYTE8_P (c))
-		    CHAR_STRING_ADVANCE (c, dst);
+		    CHAR_STRING_ADVANCE_NO_UNIFY (c, dst);
 		  else
 		    *dst++ = CHAR_TO_BYTE8 (c);
 		}
@@ -6030,6 +6105,8 @@
       const unsigned char *src = coding->source;
       const unsigned char *src_end = src + coding->consumed;
 
+      if (EQ (coding->dst_object, coding->src_object))
+	dst_end = (unsigned char *) src;
       if (coding->src_multibyte != coding->dst_multibyte)
 	{
 	  if (coding->src_multibyte)
@@ -6057,6 +6134,8 @@
 			  coding_set_source (coding);
 			  src = coding->source + offset;
 			  src_end = coding->source + coding->src_bytes;
+			  if (EQ (coding->src_object, coding->dst_object))
+			    dst_end = (unsigned char *) src;
 			}
 		    }
 		  *dst++ = c;
@@ -6078,13 +6157,19 @@
 		    if (dst >= dst_end - 1)
 		      {
 			EMACS_INT offset = src - coding->source;
-
-			dst = alloc_destination (coding, src_end - src + 2,
-						 dst);
+			EMACS_INT more_bytes;
+
+			if (EQ (coding->src_object, coding->dst_object))
+			  more_bytes = ((src_end - src) / 2) + 2;
+			else
+			  more_bytes = src_end - src + 2;
+			dst = alloc_destination (coding, more_bytes, dst);
 			dst_end = coding->destination + coding->dst_bytes;
 			coding_set_source (coding);
 			src = coding->source + offset;
 			src_end = coding->source + coding->src_bytes;
+			if (EQ (coding->src_object, coding->dst_object))
+			  dst_end = (unsigned char *) src;
 		      }
 		  }
 		EMIT_ONE_BYTE (c);
@@ -6572,12 +6657,12 @@
 	  if (coding->encoder == encode_coding_raw_text)
 	    c = *src++, pos++;
 	  else if ((bytes = MULTIBYTE_LENGTH (src, src_end)) > 0)
-	    c = STRING_CHAR_ADVANCE (src), pos += bytes;
+	    c = STRING_CHAR_ADVANCE_NO_UNIFY (src), pos += bytes;
 	  else
 	    c = BYTE8_TO_CHAR (*src), src++, pos++;
 	}
       else
-	c = STRING_CHAR_ADVANCE (src), pos++;
+	c = STRING_CHAR_ADVANCE_NO_UNIFY (src), pos++;
       if ((c == '\r') && (coding->mode & CODING_MODE_SELECTIVE_DISPLAY))
 	c = '\n';
       if (! EQ (eol_type, Qunix))