+ TEMP_SET_PT_BOTH (from, from_byte);
+ orig_point = from;
+ }
+
+ if (replace)
+ {
+ int saved_from = from;
+
+ prepare_to_modify_buffer (from, to, &from);
+ if (saved_from != from)
+ {
+ to = from + len;
+ if (multibyte)
+ from_byte = CHAR_TO_BYTE (from), to_byte = CHAR_TO_BYTE (to);
+ else
+ from_byte = from, to_byte = to;
+ len_byte = to_byte - from_byte;
+ }
+ }
+
+ if (! encodep && CODING_REQUIRE_DETECTION (coding))
+ {
+ /* We must detect encoding of text and eol format. */
+
+ if (from < GPT && to > GPT)
+ move_gap_both (from, from_byte);
+ if (coding->type == coding_type_undecided)
+ {
+ detect_coding (coding, BYTE_POS_ADDR (from_byte), len_byte);
+ if (coding->type == coding_type_undecided)
+ /* It seems that the text contains only ASCII, but we
+ should not left it undecided because the deeper
+ decoding routine (decode_coding) tries to detect the
+ encodings again in vain. */
+ coding->type = coding_type_emacs_mule;
+ }
+ if (coding->eol_type == CODING_EOL_UNDECIDED)
+ {
+ saved_coding_symbol = coding->symbol;
+ detect_eol (coding, BYTE_POS_ADDR (from_byte), len_byte);
+ if (coding->eol_type == CODING_EOL_UNDECIDED)
+ coding->eol_type = CODING_EOL_LF;
+ /* We had better recover the original eol format if we
+ encounter an inconsitent eol format while decoding. */
+ coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
+ }
+ }
+
+ coding->consumed_char = len, coding->consumed = len_byte;
+
+ if (encodep
+ ? ! CODING_REQUIRE_ENCODING (coding)
+ : ! CODING_REQUIRE_DECODING (coding))
+ {
+ coding->produced = len_byte;
+ if (multibyte
+ && ! replace
+ /* See the comment of the member heading_ascii in coding.h. */
+ && coding->heading_ascii < len_byte)
+ {
+ /* We still may have to combine byte at the head and the
+ tail of the text in the region. */
+ if (from < GPT && GPT < to)
+ move_gap_both (to, to_byte);
+ len = multibyte_chars_in_text (BYTE_POS_ADDR (from_byte), len_byte);
+ adjust_after_insert (from, from_byte, to, to_byte, len);
+ coding->produced_char = len;
+ }
+ else
+ {
+ if (!replace)
+ adjust_after_insert (from, from_byte, to, to_byte, len_byte);
+ coding->produced_char = len_byte;
+ }
+ return 0;
+ }
+
+ /* Now we convert the text. */
+
+ /* For encoding, we must process pre-write-conversion in advance. */
+ if (encodep
+ && ! NILP (coding->pre_write_conversion)
+ && SYMBOLP (coding->pre_write_conversion)
+ && ! NILP (Ffboundp (coding->pre_write_conversion)))
+ {
+ /* The function in pre-write-conversion may put a new text in a
+ new buffer. */
+ struct buffer *prev = current_buffer;
+ Lisp_Object new;
+
+ call2 (coding->pre_write_conversion,
+ make_number (from), make_number (to));
+ if (current_buffer != prev)
+ {
+ len = ZV - BEGV;
+ new = Fcurrent_buffer ();
+ set_buffer_internal_1 (prev);
+ del_range_2 (from, from_byte, to, to_byte);
+ TEMP_SET_PT_BOTH (from, from_byte);
+ insert_from_buffer (XBUFFER (new), 1, len, 0);
+ Fkill_buffer (new);
+ if (orig_point >= to)
+ orig_point += len - orig_len;
+ else if (orig_point > from)
+ orig_point = from;
+ orig_len = len;
+ to = from + len;
+ from_byte = multibyte ? CHAR_TO_BYTE (from) : from_byte;
+ to_byte = multibyte ? CHAR_TO_BYTE (to) : to;
+ len_byte = to_byte - from_byte;
+ TEMP_SET_PT_BOTH (from, from_byte);
+ }
+ }
+
+ if (replace)
+ deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
+
+ /* Try to skip the heading and tailing ASCIIs. */
+ {
+ int from_byte_orig = from_byte, to_byte_orig = to_byte;
+
+ if (from < GPT && GPT < to)
+ move_gap_both (from, from_byte);
+ SHRINK_CONVERSION_REGION (&from_byte, &to_byte, coding, NULL, encodep);
+ if (from_byte == to_byte
+ && coding->type != coding_type_ccl
+ && ! (coding->mode & CODING_MODE_LAST_BLOCK
+ && CODING_REQUIRE_FLUSHING (coding)))
+ {
+ coding->produced = len_byte;
+ coding->produced_char = multibyte ? len : len_byte;
+ if (!replace)
+ /* We must record and adjust for this new text now. */
+ adjust_after_insert (from, from_byte_orig, to, to_byte_orig, len);
+ return 0;
+ }
+
+ head_skip = from_byte - from_byte_orig;
+ tail_skip = to_byte_orig - to_byte;
+ total_skip = head_skip + tail_skip;
+ from += head_skip;
+ to -= tail_skip;
+ len -= total_skip; len_byte -= total_skip;
+ }
+
+ /* The code conversion routine can not preserve text properties for
+ now. So, we must remove all text properties in the region.
+ Here, we must suppress all modification hooks. */
+ if (replace)
+ {
+ int saved_inhibit_modification_hooks = inhibit_modification_hooks;
+ inhibit_modification_hooks = 1;
+ Fset_text_properties (make_number (from), make_number (to), Qnil, Qnil);
+ inhibit_modification_hooks = saved_inhibit_modification_hooks;
+ }
+
+ /* For converion, we must put the gap before the text in addition to
+ making the gap larger for efficient decoding. The required gap
+ size starts from 2000 which is the magic number used in make_gap.
+ But, after one batch of conversion, it will be incremented if we
+ find that it is not enough . */
+ require = 2000;
+
+ if (GAP_SIZE < require)
+ make_gap (require - GAP_SIZE);
+ move_gap_both (from, from_byte);
+
+ inserted = inserted_byte = 0;
+ src = GAP_END_ADDR, dst = GPT_ADDR;
+
+ GAP_SIZE += len_byte;
+ ZV -= len;
+ Z -= len;
+ ZV_BYTE -= len_byte;
+ Z_BYTE -= len_byte;
+
+ if (GPT - BEG < beg_unchanged)
+ beg_unchanged = GPT - BEG;
+ if (Z - GPT < end_unchanged)
+ end_unchanged = Z - GPT;
+
+ for (;;)
+ {
+ int result;
+
+ /* The buffer memory is changed from:
+ +--------+converted-text+---------+-------original-text------+---+
+ |<-from->|<--inserted-->|---------|<-----------len---------->|---|
+ |<------------------- GAP_SIZE -------------------->| */
+ if (encodep)
+ result = encode_coding (coding, src, dst, len_byte, 0);
+ else
+ result = decode_coding (coding, src, dst, len_byte, 0);
+ /* to:
+ +--------+-------converted-text--------+--+---original-text--+---+
+ |<-from->|<--inserted-->|<--produced-->|--|<-(len-consumed)->|---|
+ |<------------------- GAP_SIZE -------------------->| */
+ if (coding->fake_multibyte)
+ fake_multibyte = 1;
+
+ if (!encodep && !multibyte)
+ coding->produced_char = coding->produced;
+ inserted += coding->produced_char;
+ inserted_byte += coding->produced;
+ len_byte -= coding->consumed;
+ src += coding->consumed;
+ dst += inserted_byte;
+
+ if (result == CODING_FINISH_NORMAL)
+ {
+ src += len_byte;
+ break;
+ }
+ if (! encodep && result == CODING_FINISH_INCONSISTENT_EOL)
+ {
+ unsigned char *pend = dst, *p = pend - inserted_byte;
+
+ /* Encode LFs back to the original eol format (CR or CRLF). */
+ if (coding->eol_type == CODING_EOL_CR)
+ {
+ while (p < pend) if (*p++ == '\n') p[-1] = '\r';
+ }
+ else
+ {
+ int count = 0;
+
+ while (p < pend) if (*p++ == '\n') count++;
+ if (src - dst < count)
+ {
+ /* We don't have sufficient room for putting LFs
+ back to CRLF. We must record converted and
+ not-yet-converted text back to the buffer
+ content, enlarge the gap, then record them out of
+ the buffer contents again. */
+ int add = len_byte + inserted_byte;
+
+ GAP_SIZE -= add;
+ ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
+ GPT += inserted_byte; GPT_BYTE += inserted_byte;
+ make_gap (count - GAP_SIZE);
+ GAP_SIZE += add;
+ ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
+ GPT -= inserted_byte; GPT_BYTE -= inserted_byte;
+ /* Don't forget to update SRC, DST, and PEND. */
+ src = GAP_END_ADDR - len_byte;
+ dst = GPT_ADDR + inserted_byte;
+ pend = dst;
+ }
+ inserted += count;
+ inserted_byte += count;
+ coding->produced += count;
+ p = dst = pend + count;
+ while (count)
+ {
+ *--p = *--pend;
+ if (*p == '\n') count--, *--p = '\r';
+ }
+ }
+
+ /* Suppress eol-format conversion in the further conversion. */
+ coding->eol_type = CODING_EOL_LF;
+
+ /* Restore the original symbol. */
+ coding->symbol = saved_coding_symbol;
+
+ continue;
+ }
+ if (len_byte <= 0)
+ {
+ if (coding->type != coding_type_ccl
+ || coding->mode & CODING_MODE_LAST_BLOCK)
+ break;
+ coding->mode |= CODING_MODE_LAST_BLOCK;
+ continue;
+ }
+ if (result == CODING_FINISH_INSUFFICIENT_SRC)
+ {
+ /* The source text ends in invalid codes. Let's just
+ make them valid buffer contents, and finish conversion. */
+ inserted += len_byte;
+ inserted_byte += len_byte;
+ while (len_byte--)
+ *dst++ = *src++;
+ fake_multibyte = 1;
+ break;
+ }
+ if (result == CODING_FINISH_INTERRUPT)
+ {
+ /* The conversion procedure was interrupted by a user. */
+ fake_multibyte = 1;
+ break;
+ }
+ /* Now RESULT == CODING_FINISH_INSUFFICIENT_DST */
+ if (coding->consumed < 1)
+ {
+ /* It's quite strange to require more memory without
+ consuming any bytes. Perhaps CCL program bug. */
+ fake_multibyte = 1;
+ break;
+ }
+ if (first)
+ {
+ /* We have just done the first batch of conversion which was
+ stoped because of insufficient gap. Let's reconsider the
+ required gap size (i.e. SRT - DST) now.
+
+ We have converted ORIG bytes (== coding->consumed) into
+ NEW bytes (coding->produced). To convert the remaining
+ LEN bytes, we may need REQUIRE bytes of gap, where:
+ REQUIRE + LEN_BYTE = LEN_BYTE * (NEW / ORIG)
+ REQUIRE = LEN_BYTE * (NEW - ORIG) / ORIG
+ Here, we are sure that NEW >= ORIG. */
+ float ratio = coding->produced - coding->consumed;
+ ratio /= coding->consumed;
+ require = len_byte * ratio;
+ first = 0;
+ }
+ if ((src - dst) < (require + 2000))
+ {
+ /* See the comment above the previous call of make_gap. */
+ int add = len_byte + inserted_byte;
+
+ GAP_SIZE -= add;
+ ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
+ GPT += inserted_byte; GPT_BYTE += inserted_byte;
+ make_gap (require + 2000);
+ GAP_SIZE += add;
+ ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
+ GPT -= inserted_byte; GPT_BYTE -= inserted_byte;
+ /* Don't forget to update SRC, DST. */
+ src = GAP_END_ADDR - len_byte;
+ dst = GPT_ADDR + inserted_byte;
+ }
+ }
+ if (src - dst > 0) *dst = 0; /* Put an anchor. */
+
+ if (multibyte
+ && (encodep
+ || fake_multibyte
+ || (to - from) != (to_byte - from_byte)))
+ inserted = multibyte_chars_in_text (GPT_ADDR, inserted_byte);
+
+ /* If we have shrinked the conversion area, adjust it now. */
+ if (total_skip > 0)
+ {
+ if (tail_skip > 0)
+ safe_bcopy (GAP_END_ADDR, GPT_ADDR + inserted_byte, tail_skip);
+ inserted += total_skip; inserted_byte += total_skip;
+ GAP_SIZE += total_skip;
+ GPT -= head_skip; GPT_BYTE -= head_skip;
+ ZV -= total_skip; ZV_BYTE -= total_skip;
+ Z -= total_skip; Z_BYTE -= total_skip;
+ from -= head_skip; from_byte -= head_skip;
+ to += tail_skip; to_byte += tail_skip;
+ }
+
+ prev_Z = Z;
+ adjust_after_replace (from, from_byte, deletion, inserted, inserted_byte);
+ inserted = Z - prev_Z;
+
+ if (! encodep && ! NILP (coding->post_read_conversion))
+ {
+ Lisp_Object val;
+
+ if (from != PT)
+ TEMP_SET_PT_BOTH (from, from_byte);
+ prev_Z = Z;
+ val = call1 (coding->post_read_conversion, make_number (inserted));
+ CHECK_NUMBER (val, 0);
+ inserted += Z - prev_Z;
+ }
+
+ if (orig_point >= from)
+ {
+ if (orig_point >= from + orig_len)
+ orig_point += inserted - orig_len;
+ else
+ orig_point = from;
+ TEMP_SET_PT (orig_point);
+ }
+
+ signal_after_change (from, to - from, inserted);
+
+ {
+ coding->consumed = to_byte - from_byte;
+ coding->consumed_char = to - from;
+ coding->produced = inserted_byte;
+ coding->produced_char = inserted;
+ }
+
+ return 0;
+}
+
+Lisp_Object
+code_convert_string (str, coding, encodep, nocopy)
+ Lisp_Object str;
+ struct coding_system *coding;
+ int encodep, nocopy;
+{
+ int len;
+ char *buf;
+ int from = 0, to = XSTRING (str)->size;
+ int to_byte = STRING_BYTES (XSTRING (str));
+ struct gcpro gcpro1;
+ Lisp_Object saved_coding_symbol;
+ int result;
+
+ saved_coding_symbol = Qnil;
+ if (encodep && !NILP (coding->pre_write_conversion)
+ || !encodep && !NILP (coding->post_read_conversion))
+ {
+ /* Since we have to call Lisp functions which assume target text
+ is in a buffer, after setting a temporary buffer, call
+ code_convert_region. */
+ int count = specpdl_ptr - specpdl;
+ struct buffer *prev = current_buffer;
+
+ record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+ temp_output_buffer_setup (" *code-converting-work*");
+ set_buffer_internal (XBUFFER (Vstandard_output));
+ if (encodep)
+ insert_from_string (str, 0, 0, to, to_byte, 0);
+ else
+ {
+ /* We must insert the contents of STR as is without
+ unibyte<->multibyte conversion. */
+ current_buffer->enable_multibyte_characters = Qnil;
+ insert_from_string (str, 0, 0, to_byte, to_byte, 0);
+ current_buffer->enable_multibyte_characters = Qt;
+ }
+ code_convert_region (BEGV, BEGV_BYTE, ZV, ZV_BYTE, coding, encodep, 1);
+ if (encodep)
+ /* We must return the buffer contents as unibyte string. */
+ current_buffer->enable_multibyte_characters = Qnil;
+ str = make_buffer_string (BEGV, ZV, 0);
+ set_buffer_internal (prev);
+ return unbind_to (count, str);
+ }
+
+ if (! encodep && CODING_REQUIRE_DETECTION (coding))
+ {
+ /* See the comments in code_convert_region. */
+ if (coding->type == coding_type_undecided)
+ {
+ detect_coding (coding, XSTRING (str)->data, to_byte);
+ if (coding->type == coding_type_undecided)
+ coding->type = coding_type_emacs_mule;
+ }
+ if (coding->eol_type == CODING_EOL_UNDECIDED)
+ {
+ saved_coding_symbol = coding->symbol;
+ detect_eol (coding, XSTRING (str)->data, to_byte);
+ if (coding->eol_type == CODING_EOL_UNDECIDED)
+ coding->eol_type = CODING_EOL_LF;
+ /* We had better recover the original eol format if we
+ encounter an inconsitent eol format while decoding. */
+ coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
+ }
+ }
+
+ if (encodep
+ ? ! CODING_REQUIRE_ENCODING (coding)
+ : ! CODING_REQUIRE_DECODING (coding))
+ from = to_byte;
+ else
+ {
+ /* Try to skip the heading and tailing ASCIIs. */
+ SHRINK_CONVERSION_REGION (&from, &to_byte, coding, XSTRING (str)->data,
+ encodep);
+ }
+ if (from == to_byte
+ && coding->type != coding_type_ccl)
+ return (nocopy ? str : Fcopy_sequence (str));
+
+ if (encodep)
+ len = encoding_buffer_size (coding, to_byte - from);
+ else
+ len = decoding_buffer_size (coding, to_byte - from);
+ len += from + STRING_BYTES (XSTRING (str)) - to_byte;
+ GCPRO1 (str);
+ buf = get_conversion_buffer (len);
+ UNGCPRO;
+
+ if (from > 0)
+ bcopy (XSTRING (str)->data, buf, from);
+ result = (encodep
+ ? encode_coding (coding, XSTRING (str)->data + from,
+ buf + from, to_byte - from, len)
+ : decode_coding (coding, XSTRING (str)->data + from,
+ buf + from, to_byte - from, len));
+ if (! encodep && result == CODING_FINISH_INCONSISTENT_EOL)
+ {
+ /* We simple try to decode the whole string again but without
+ eol-conversion this time. */
+ coding->eol_type = CODING_EOL_LF;
+ coding->symbol = saved_coding_symbol;
+ return code_convert_string (str, coding, encodep, nocopy);
+ }