changeset 25093:30bfdf581d6f

(count_combining): New function. (struct textproc_rec): New structure. (concat): Copy text properties correctly when byte combining occurs.
author Kenichi Handa <handa@m17n.org>
date Wed, 28 Jul 1999 02:10:51 +0000
parents 79a5a567bdb0
children 4df3b9d95d4a
files src/fns.c
diffstat 1 files changed, 82 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/fns.c	Tue Jul 27 23:55:58 1999 +0000
+++ b/src/fns.c	Wed Jul 28 02:10:51 1999 +0000
@@ -516,6 +516,37 @@
   return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
 }
 
+/* In string STR of length LEN, see if bytes before STR[I] combine
+   with bytes after STR[I] to form a single character.  If so, return
+   the number of bytes after STR[I] which combine in this way.
+   Otherwize, return 0.  */
+
+static int
+count_combining (str, len, i)
+     unsigned char *str;
+     int len, i;
+{
+  int j = i - 1;
+
+  if (i == 0 || i == len || CHAR_HEAD_P (str[i]))
+    return 0;
+  while (j >= 0 && !CHAR_HEAD_P (str[j])) j--;
+  if (j < 0 || ! BASE_LEADING_CODE_P (str[j]))
+    return 0;
+  j = i + 1;
+  while (j < len && ! CHAR_HEAD_P (str[j])) j++;
+  return j - i;
+}
+
+/* This structure holds information of an argument of `concat' that is
+   a string and has text properties to be copied.  */
+struct textproc_rec
+{
+  int argnum;			/* refer to ARGS (arguments of `concat') */
+  int from;			/* refer to ARGS[argnum] (argument string) */
+  int to;			/* refer to VAL (the target string) */
+};
+
 static Lisp_Object
 concat (nargs, args, target_type, last_special)
      int nargs;
@@ -534,11 +565,14 @@
   Lisp_Object last_tail;
   Lisp_Object prev;
   int some_multibyte;
-  /* When we make a multibyte string, we must pay attention to the
-     byte combining problem, i.e., a byte may be combined with a
-     multibyte charcter of the previous string.  This flag tells if we
-     must consider such a situation or not.  */
-  int maybe_combine_byte;
+  /* When we make a multibyte string, we can't copy text properties
+     while concatinating each string because the length of resulting
+     string can't be decided until we finish the whole concatination.
+     So, we record strings that have text properties to be copied
+     here, and copy the text properties after the concatination.  */
+  struct textproc_rec  *textprocs;
+  /* Number of elments in textprocs.  */
+  int num_textprocs = 0;
 
   /* In append, the last arg isn't treated like the others */
   if (last_special && nargs > 0)
@@ -642,13 +676,15 @@
 
   /* Copy the contents of the args into the result.  */
   if (CONSP (val))
-    tail = val, toindex = -1;		/* -1 in toindex is flag we are making a list */
+    tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */
   else
     toindex = 0, toindex_byte = 0;
 
   prev = Qnil;
-
-  maybe_combine_byte = 0;
+  if (STRINGP (val))
+    textprocs
+      = (struct textproc_rec *) alloca (sizeof (struct textproc_rec) * nargs);
+
   for (argnum = 0; argnum < nargs; argnum++)
     {
       Lisp_Object thislen;
@@ -660,29 +696,40 @@
       if (!CONSP (this))
 	thislen = Flength (this), thisleni = XINT (thislen);
 
-      if (STRINGP (this) && STRINGP (val)
-	  && ! NULL_INTERVAL_P (XSTRING (this)->intervals))
-	copy_text_properties (make_number (0), thislen, this,
-			      make_number (toindex), val, Qnil);
-
       /* Between strings of the same kind, copy fast.  */
       if (STRINGP (this) && STRINGP (val)
 	  && STRING_MULTIBYTE (this) == some_multibyte)
 	{
 	  int thislen_byte = STRING_BYTES (XSTRING (this));
+	  int combined;
+
 	  bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte,
 		 STRING_BYTES (XSTRING (this)));
-	  if (some_multibyte
-	      && toindex_byte > 0
-	      && !ASCII_BYTE_P (XSTRING (val)->data[toindex_byte - 1])
-	      && !CHAR_HEAD_P (XSTRING (this)->data[0]))
-	    maybe_combine_byte = 1;
+	  combined =  (some_multibyte && toindex_byte > 0
+		       ? count_combining (XSTRING (val)->data,
+					  toindex_byte + thislen_byte,
+					  toindex_byte)
+		       : 0);
+	  if (! NULL_INTERVAL_P (XSTRING (this)->intervals))
+	    {
+	      textprocs[num_textprocs].argnum = argnum;
+	      /* We ignore text properties on characters being combined.  */
+	      textprocs[num_textprocs].from = combined;
+	      textprocs[num_textprocs++].to = toindex;
+	    }
 	  toindex_byte += thislen_byte;
-	  toindex += thisleni;
+	  toindex += thisleni - combined;
+	  XSTRING (val)->size -= combined;
 	}
       /* Copy a single-byte string to a multibyte string.  */
       else if (STRINGP (this) && STRINGP (val))
 	{
+	  if (! NULL_INTERVAL_P (XSTRING (this)->intervals))
+	    {
+	      textprocs[num_textprocs].argnum = argnum;
+	      textprocs[num_textprocs].from = 0;
+	      textprocs[num_textprocs++].to = toindex;
+	    }
 	  toindex_byte += copy_text (XSTRING (this)->data,
 				     XSTRING (val)->data + toindex_byte,
 				     XSTRING (this)->size, 0, 1);
@@ -752,13 +799,14 @@
 		CHECK_NUMBER (elt, 0);
 		if (SINGLE_BYTE_CHAR_P (XINT (elt)))
 		  {
+		    XSTRING (val)->data[toindex_byte++] = XINT (elt);
 		    if (some_multibyte
 			&& toindex_byte > 0
-			&& !ASCII_BYTE_P (XSTRING (val)->data[toindex_byte - 1])
-			&& !CHAR_HEAD_P (XINT (elt)))
-		      maybe_combine_byte = 1;
-		    XSTRING (val)->data[toindex_byte++] = XINT (elt);
-		    toindex++;
+			&& count_combining (XSTRING (val)->data,
+					    toindex_byte, toindex_byte - 1))
+		      XSTRING (val)->size--;
+		    else
+		      toindex++;
 		  }
 		else
 		  /* If we have any multibyte characters,
@@ -781,12 +829,16 @@
   if (!NILP (prev))
     XCONS (prev)->cdr = last_tail;
 
-  if (maybe_combine_byte)
-    /* Character counter of the multibyte string VAL may be wrong
-       because of byte combining problem.  We must re-calculate it.  */
-    XSTRING (val)->size = multibyte_chars_in_text (XSTRING (val)->data,
-						   XSTRING (val)->size_byte);
-
+  if (num_textprocs > 0)
+    {
+      for (argnum = 0; argnum < num_textprocs; argnum++)
+	{
+	  this = args[textprocs[argnum].argnum];
+	  copy_text_properties (make_number (textprocs[argnum].from),
+				XSTRING (this)->size, this,
+				make_number (textprocs[argnum].to), val, Qnil);
+	}
+    }
   return val;
 }