changeset 30356:b600a31684db

(Faset): Allow storing any multibyte character in a string. Convert unibyte string to multibyte if necessary.
author Kenichi Handa <handa@m17n.org>
date Fri, 21 Jul 2000 06:45:30 +0000
parents 36c049a9730b
children 2696b797cd2f
files src/data.c
diffstat 1 files changed, 69 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/data.c	Fri Jul 21 02:39:45 2000 +0000
+++ b/src/data.c	Fri Jul 21 06:45:30 2000 +0000
@@ -1835,6 +1835,11 @@
     }
 }
 
+/* Don't use alloca for relocating string data larger than this, lest
+   we overflow their stack.  The value is the same as what used in
+   fns.c for base64 handling.  */
+#define MAX_ALLOCA 16*1024
+
 DEFUN ("aset", Faset, Saset, 3, 3, 0,
   "Store into the element of ARRAY at index IDX the value NEWELT.\n\
 ARRAY may be a vector, a string, a char-table or a bool-vector.\n\
@@ -1916,41 +1921,81 @@
     }
   else if (STRING_MULTIBYTE (array))
     {
-      int idxval_byte, new_len, actual_len;
-      int prev_byte;
-      unsigned char *p, workbuf[MAX_MULTIBYTE_LENGTH], *str = workbuf;
+      int idxval_byte, prev_bytes, new_bytes;
+      unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1;
 
       if (idxval < 0 || idxval >= XSTRING (array)->size)
 	args_out_of_range (array, idx);
+      CHECK_NUMBER (newelt, 2);
 
       idxval_byte = string_char_to_byte (array, idxval);
-      p = &XSTRING (array)->data[idxval_byte];
-
-      actual_len = MULTIBYTE_FORM_LENGTH (p, STRING_BYTES (XSTRING (array)));
-      CHECK_NUMBER (newelt, 2);
-      new_len = CHAR_STRING (XINT (newelt), str);
-      if (actual_len != new_len)
-	error ("Attempt to change byte length of a string");
-
-      /* We can't accept a change causing byte combining.  */
-      if (!ASCII_BYTE_P (*str)
-	  && ((idxval > 0 && !CHAR_HEAD_P (*str)
-	       && (prev_byte = string_char_to_byte (array, idxval - 1),
-		   BYTES_BY_CHAR_HEAD (XSTRING (array)->data[prev_byte])
-		   > idxval_byte - prev_byte))
-	      || (idxval < XSTRING (array)->size - 1
-		  && !CHAR_HEAD_P (p[actual_len])
-		  && new_len < BYTES_BY_CHAR_HEAD (*str))))
-	error ("Attempt to change char length of a string");
-      while (new_len--)
-	*p++ = *str++;
+      p1 = &XSTRING (array)->data[idxval_byte];
+      PARSE_MULTIBYTE_SEQ (p1, nbytes - idxval_byte, prev_bytes);
+      new_bytes = CHAR_STRING (XINT (newelt), p0);
+      if (prev_bytes != new_bytes)
+	{
+	  /* We must relocate the string data.  */
+	  int nchars = XSTRING (array)->size;
+	  int nbytes = STRING_BYTES (XSTRING (array));
+	  unsigned char *str;
+
+	  str = (nbytes <= MAX_ALLOCA
+		 ? (unsigned char *) alloca (nbytes)
+		 : (unsigned char *) xmalloc (nbytes));
+	  bcopy (XSTRING (array)->data, str, nbytes);
+	  allocate_string_data (XSTRING (array), nchars,
+				nbytes + new_bytes - prev_bytes);
+	  bcopy (str, XSTRING (array)->data, idxval_byte);
+	  p1 = XSTRING (array)->data + idxval_byte;
+	  bcopy (str + idxval_byte + prev_bytes, p1 + new_bytes,
+		 nbytes - (idxval_byte + prev_bytes));
+	  if (nbytes > MAX_ALLOCA)
+	    xfree (str);
+	  clear_string_char_byte_cache ();
+	}
+      while (new_bytes--)
+	*p1++ = *p0++;
     }
   else
     {
       if (idxval < 0 || idxval >= XSTRING (array)->size)
 	args_out_of_range (array, idx);
       CHECK_NUMBER (newelt, 2);
-      XSTRING (array)->data[idxval] = XINT (newelt);
+
+      if (XINT (newelt) < 0 || SINGLE_BYTE_CHAR_P (XINT (newelt)))
+	XSTRING (array)->data[idxval] = XINT (newelt);
+      else
+	{
+	  /* We must relocate the string data while converting it to
+	     multibyte.  */
+	  int idxval_byte, prev_bytes, new_bytes;
+	  unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1;
+	  unsigned char *origstr = XSTRING (array)->data, *str;
+	  int nchars, nbytes;
+
+	  nchars = XSTRING (array)->size;
+	  nbytes = idxval_byte = count_size_as_multibyte (origstr, idxval);
+	  nbytes += count_size_as_multibyte (origstr + idxval,
+					     nchars - idxval);
+	  str = (nbytes <= MAX_ALLOCA
+		 ? (unsigned char *) alloca (nbytes)
+		 : (unsigned char *) xmalloc (nbytes));
+	  copy_text (XSTRING (array)->data, str, nchars, 0, 1);
+	  PARSE_MULTIBYTE_SEQ (str + idxval_byte, nbytes - idxval_byte,
+			       prev_bytes);
+	  new_bytes = CHAR_STRING (XINT (newelt), p0);
+	  allocate_string_data (XSTRING (array), nchars,
+				nbytes + new_bytes - prev_bytes);
+	  bcopy (str, XSTRING (array)->data, idxval_byte);
+	  p1 = XSTRING (array)->data + idxval_byte;
+	  while (new_bytes--)
+	    *p1++ = *p0++;
+	  bcopy (str + idxval_byte + prev_bytes, p1,
+		 nbytes - (idxval_byte + prev_bytes));
+	  if (nbytes > MAX_ALLOCA)
+	    xfree (str);
+	  clear_string_char_byte_cache ();
+	}
     }
 
   return newelt;