+static void
+insert_from_buffer_1 (buf, from, nchars, inherit)
+ struct buffer *buf;
+ int from, nchars;
+ int inherit;
+{
+ register Lisp_Object temp, deletion;
+ int chunk;
+ int from_byte = buf_charpos_to_bytepos (buf, from);
+ int to_byte = buf_charpos_to_bytepos (buf, from + nchars);
+ int incoming_nbytes = to_byte - from_byte;
+ int outgoing_nbytes = incoming_nbytes;
+ int combined_before_bytes, combined_after_bytes;
+ int adjusted_nchars;
+ INTERVAL intervals;
+
+ /* Make OUTGOING_NBYTES describe the text
+ as it will be inserted in this buffer. */
+
+ if (NILP (current_buffer->enable_multibyte_characters))
+ outgoing_nbytes = nchars;
+ else if (NILP (buf->enable_multibyte_characters))
+ outgoing_nbytes
+ = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
+ incoming_nbytes);
+
+ /* Make sure point-max won't overflow after this insertion. */
+ XSETINT (temp, outgoing_nbytes + Z);
+ if (outgoing_nbytes + Z != XINT (temp))
+ error ("Maximum buffer size exceeded");
+
+ prepare_to_modify_buffer (PT, PT, NULL);
+
+ if (PT != GPT)
+ move_gap_both (PT, PT_BYTE);
+ if (GAP_SIZE < outgoing_nbytes)
+ make_gap (outgoing_nbytes - GAP_SIZE);
+
+ if (from < BUF_GPT (buf))
+ {
+ chunk = BUF_GPT_BYTE (buf) - from_byte;
+ if (chunk > incoming_nbytes)
+ chunk = incoming_nbytes;
+ copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
+ GPT_ADDR, chunk,
+ ! NILP (buf->enable_multibyte_characters),
+ ! NILP (current_buffer->enable_multibyte_characters));
+ }
+ else
+ chunk = 0;
+ if (chunk < incoming_nbytes)
+ copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
+ GPT_ADDR + chunk, incoming_nbytes - chunk,
+ ! NILP (buf->enable_multibyte_characters),
+ ! 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_nbytes, PT, PT_BYTE);
+ combined_after_bytes
+ = count_combining_after (GPT_ADDR, outgoing_nbytes,
+ 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,
+ nchars - combined_before_bytes + !!combined_before_bytes);
+ MODIFF++;
+
+ GAP_SIZE -= outgoing_nbytes;
+ GPT += nchars;
+ ZV += nchars;
+ Z += nchars;
+ GPT_BYTE += outgoing_nbytes;
+ ZV_BYTE += outgoing_nbytes;
+ Z_BYTE += outgoing_nbytes;
+ 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_overlays_for_insert (PT, nchars);
+ adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
+ PT_BYTE + outgoing_nbytes,
+ combined_before_bytes, combined_after_bytes, 0);
+
+#ifdef USE_TEXT_PROPERTIES
+ if (BUF_INTERVALS (current_buffer) != 0)
+ offset_intervals (current_buffer, PT, nchars);
+#endif
+
+ /* Get the intervals for the part of the string we are inserting--
+ not including the combined-before bytes. */
+ intervals = BUF_INTERVALS (buf);
+ if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
+ intervals = copy_intervals (intervals, from, nchars);
+
+ /* Insert those intervals. */
+ graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
+
+ {
+ int pos = PT, pos_byte = PT_BYTE;
+
+ adjust_point (nchars + combined_after_bytes,
+ outgoing_nbytes + combined_after_bytes);
+
+ if (combined_after_bytes)
+ combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
+ combined_after_bytes);
+
+ if (combined_before_bytes)
+ combine_bytes (pos, pos_byte, combined_before_bytes);
+ }
+}
+\f
+/* This function should be called after moving gap to FROM and before
+ altering text between FROM and TO. This adjusts various position
+ keepers and markers as if the text is deleted. Don't forget to
+ call adjust_after_replace after you actually alter the text. */