+ @brief Replace sub-text of M-text with another.
+
+ The mtext_replace () function replaces sub-text of M-text $MT1
+ between $FROM1 (inclusive) and $TO1 (exclusinve) with the sub-text
+ of M-text $MT2 between $FROM2 (inclusive) and $TO2 (exclusinve).
+ The new sub-text inherits text properties of the old sub-text.
+
+ @return If the operation was successful, mtext_replace () returns
+ 0. Otherwise, it returns -1 and assigns an error code to the
+ external variable #merror_code. */
+
+/***ja
+ @brief M-text ¤Î°ìÉô¤òÊ̤ΠM-text ¤Î°ìÉô¤ÇÃÖ´¹¤¹¤ë.
+
+ ´Ø¿ô mtext_replace () ¤Ï¡¢ M-text $MT1 ¤Î $FROM1 ¡Ê$FROM1 ¼«ÂΤâ´Þ
+ ¤à¡Ë¤«¤é $TO1 ¡Ê$TO1 ¼«ÂΤϴޤޤʤ¤¡Ë¤Þ¤Ç¤ò¡¢ M-text $MT2 ¤Î
+ $FROM2 ¡Ê$FROM2 ¼«ÂΤâ´Þ¤à¡Ë¤«¤é $TO2 ¡Ê$TO2 ¼«ÂΤϴޤޤʤ¤¡Ë¤ÇÃÖ
+ ¤´¹¤¨¤ë¡£¿·¤·¤¯ÁÞÆþ¤µ¤ì¤¿Éôʬ¤Ï¡¢ÃÖ¤´¹¤¨¤ëÁ°¤Î¥Æ¥¥¹¥È¥×¥í¥Ñ¥Æ¥£
+ ¤¹¤Ù¤Æ¤ò·Ñ¾µ¤¹¤ë¡£
+
+ @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢ mtext_replace () ¤Ï 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê
+ ¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£ */
+
+/***
+ @errors
+ @c MERROR_MTEXT , @c MERROR_RANGE
+
+ @seealso
+ mtext_insert () */
+
+int
+mtext_replace (MText *mt1, int from1, int to1,
+ MText *mt2, int from2, int to2)
+{
+ int len1, len2;
+ int from1_byte, from2_byte, old_bytes, new_bytes;
+ int unit_bytes, total_bytes;
+ unsigned char *p;
+ int free_mt2 = 0;
+
+ M_CHECK_READONLY (mt1, -1);
+ M_CHECK_RANGE_X (mt1, from1, to1, -1);
+ M_CHECK_RANGE_X (mt2, from2, to2, -1);
+
+ if (from1 == to1)
+ {
+ struct MTextPlist *saved = mt2->plist;
+
+ mt2->plist = NULL;
+ insert (mt1, from1, mt2, from2, to2);
+ mt2->plist = saved;
+ return 0;
+ }
+
+ if (from2 == to2)
+ {
+ return mtext_del (mt1, from1, to1);
+ }
+
+ if (mt1 == mt2)
+ {
+ mt2 = mtext_duplicate (mt2, from2, to2);
+ to2 -= from2;
+ from2 = 0;
+ free_mt2 = 1;
+ }
+
+ if (mt1->format != mt2->format
+ && mt1->format == MTEXT_FORMAT_US_ASCII)
+ mt1->format = MTEXT_FORMAT_UTF_8;
+ if (mt1->format != mt2->format
+ && mt1->coverage < mt2->coverage)
+ mtext__adjust_format (mt1, mt2->format);
+ if (mt1->format != mt2->format)
+ {
+ mt2 = mtext_duplicate (mt2, from2, to2);
+ mtext__adjust_format (mt2, mt1->format);
+ to2 -= from2;
+ from2 = 0;
+ free_mt2 = 1;
+ }
+
+ len1 = to1 - from1;
+ len2 = to2 - from2;
+ mtext__adjust_plist_for_change (mt1, from1, len1, len2);
+
+ unit_bytes = UNIT_BYTES (mt1->format);
+ from1_byte = POS_CHAR_TO_BYTE (mt1, from1) * unit_bytes;
+ from2_byte = POS_CHAR_TO_BYTE (mt2, from2) * unit_bytes;
+ old_bytes = POS_CHAR_TO_BYTE (mt1, to1) * unit_bytes - from1_byte;
+ new_bytes = POS_CHAR_TO_BYTE (mt2, to2) * unit_bytes - from2_byte;
+ total_bytes = mt1->nbytes * unit_bytes + (new_bytes - old_bytes);
+ if (total_bytes + unit_bytes > mt1->allocated)
+ {
+ mt1->allocated = total_bytes + unit_bytes;
+ MTABLE_REALLOC (mt1->data, mt1->allocated, MERROR_MTEXT);
+ }
+ p = mt1->data + from1_byte;
+ if (to1 < mt1->nchars
+ && old_bytes != new_bytes)
+ memmove (p + new_bytes, p + old_bytes,
+ (mt1->nbytes + 1) * unit_bytes - (from1_byte + old_bytes));
+ memcpy (p, mt2->data + from2_byte, new_bytes);
+ mt1->nchars += len2 - len1;
+ mt1->nbytes += (new_bytes - old_bytes) / unit_bytes;
+ if (mt1->cache_char_pos >= to1)
+ {
+ mt1->cache_char_pos += len2 - len1;
+ mt1->cache_byte_pos += new_bytes - old_bytes;
+ }
+ else if (mt1->cache_char_pos > from1)
+ {
+ mt1->cache_char_pos = from1;
+ mt1->cache_byte_pos = from1_byte;
+ }
+
+ if (free_mt2)
+ M17N_OBJECT_UNREF (mt2);
+ return 0;
+}
+
+/*=*/
+
+/***en