+
+ UNGCPRO;
+
+ /* Make args be valid */
+ if (from < BEGV)
+ from = BEGV;
+ if (to > ZV)
+ to = ZV;
+
+ from_byte = CHAR_TO_BYTE (from);
+ to_byte = CHAR_TO_BYTE (to);
+
+ nchars_del = to - from;
+ nbytes_del = to_byte - from_byte;
+
+ if (nbytes_del <= 0 && insbytes == 0)
+ return;
+
+ /* Make OUTGOING_INSBYTES describe the text
+ as it will be inserted in this buffer. */
+
+ if (NILP (current_buffer->enable_multibyte_characters))
+ outgoing_insbytes = inschars;
+ else if (inschars == insbytes)
+ outgoing_insbytes
+ = count_size_as_multibyte (XSTRING (new)->data, insbytes);
+
+ /* Make sure point-max won't overflow after this insertion. */
+ XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
+ if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
+ error ("Maximum buffer size exceeded");
+
+ GCPRO1 (new);
+
+ /* Make sure the gap is somewhere in or next to what we are deleting. */
+ if (from > GPT)
+ gap_right (from, from_byte);
+ if (to < GPT)
+ gap_left (to, to_byte, 0);
+
+ deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
+
+ if (nomarkers)
+ /* Relocate all markers pointing into the new, larger gap
+ to point at the end of the text before the gap.
+ Do this before recording the deletion,
+ so that undo handles this after reinserting the text. */
+ adjust_markers_for_delete (from, from_byte, to, to_byte);
+
+ record_delete (from, deletion);
+
+ GAP_SIZE += nbytes_del;
+ ZV -= nchars_del;
+ Z -= nchars_del;
+ ZV_BYTE -= nbytes_del;
+ Z_BYTE -= nbytes_del;
+ GPT = from;
+ GPT_BYTE = from_byte;
+ *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (GPT_BYTE < GPT)
+ abort ();
+
+ if (GPT - BEG < beg_unchanged)
+ beg_unchanged = GPT - BEG;
+ if (Z - GPT < end_unchanged)
+ end_unchanged = Z - GPT;
+
+ if (GAP_SIZE < insbytes)
+ make_gap (insbytes - GAP_SIZE);
+
+ /* Copy the string text into the buffer, perhaps converting
+ between single-byte and multibyte. */
+ copy_text (XSTRING (new)->data, GPT_ADDR, insbytes,
+ /* If these are equal, it is a single-byte string.
+ Its chars are either ASCII, in which case copy_text
+ won't change it, or single-byte non-ASCII chars,
+ that need to be changed. */
+ inschars != insbytes,
+ ! NILP (current_buffer->enable_multibyte_characters));
+
+ /* We have copied text into the gap, but we have not altered
+ PT or PT_BYTE yet. So we can pass PT and PT_BYTE
+ to these functions and get the same results as we would
+ have got earlier on. Meanwhile, GPT_ADDR does point to
+ the text that has been stored by copy_text. */
+
+ combined_before_bytes
+ = count_combining_before (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
+ combined_after_bytes
+ = count_combining_after (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
+
+ /* Record deletion of the surrounding text that combines with
+ the insertion. This, together with recording the insertion,
+ will add up to the right stuff in the undo list.
+
+ But there is no need to actually delete the combining bytes
+ from the buffer and reinsert them. */
+
+ if (combined_after_bytes)
+ {
+ deletion = make_buffer_string_both (PT, PT_BYTE,
+ PT + combined_after_bytes,
+ PT_BYTE + combined_after_bytes, 1);
+
+ adjust_markers_for_record_delete (PT, PT_BYTE,
+ PT + combined_after_bytes,
+ PT_BYTE + combined_after_bytes);
+ record_delete (PT, deletion);
+ }
+
+ if (combined_before_bytes)
+ {
+ deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
+ PT, PT_BYTE, 1);
+ adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
+ PT, PT_BYTE);
+ record_delete (PT - 1, deletion);
+ }
+
+ record_insert (PT - !!combined_before_bytes,
+ inschars - combined_before_bytes + !!combined_before_bytes);
+
+ GAP_SIZE -= outgoing_insbytes;
+ GPT += inschars;
+ ZV += inschars;
+ Z += inschars;
+ GPT_BYTE += outgoing_insbytes;
+ ZV_BYTE += outgoing_insbytes;
+ Z_BYTE += outgoing_insbytes;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (combined_after_bytes)
+ move_gap_both (GPT + combined_after_bytes,
+ GPT_BYTE + combined_after_bytes);
+
+ if (GPT_BYTE < GPT)
+ abort ();
+
+ /* Adjust the overlay center as needed. This must be done after
+ adjusting the markers that bound the overlays. */
+ adjust_overlays_for_delete (from, nchars_del);
+ adjust_overlays_for_insert (from, inschars);
+ if (nomarkers)
+ adjust_markers_for_insert (from, from_byte,
+ from + inschars, from_byte + outgoing_insbytes,
+ combined_before_bytes, combined_after_bytes, 0);
+
+#ifdef USE_TEXT_PROPERTIES
+ offset_intervals (current_buffer, PT, inschars - nchars_del);
+
+ /* Get the intervals for the part of the string we are inserting--
+ not including the combined-before bytes. */
+ intervals = XSTRING (new)->intervals;
+ /* Insert those intervals. */
+ graft_intervals_into_buffer (intervals, from, inschars,
+ current_buffer, inherit);
+#endif
+
+ /* Relocate point as if it were a marker. */
+ if (from < PT)
+ adjust_point ((from + inschars - (PT < to ? PT : to)
+ + combined_after_bytes),
+ (from_byte + outgoing_insbytes
+ - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
+ + combined_after_bytes));
+
+ if (combined_after_bytes)
+ combine_bytes (from + inschars, from_byte + outgoing_insbytes,
+ combined_after_bytes);
+
+ if (combined_before_bytes)
+ combine_bytes (from, from_byte, combined_before_bytes);
+
+ if (outgoing_insbytes == 0)
+ evaporate_overlays (from);
+
+ MODIFF++;
+ UNGCPRO;
+
+ signal_after_change (from, nchars_del, PT - from);