(insert_1, insert_from_string_1): Use new accessor macros instead of calling
[bpt/emacs.git] / src / intervals.c
CommitLineData
a50699fd 1/* Code for doing intervals.
3a22ee35 2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
a50699fd
JA
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7ce503fd 8the Free Software Foundation; either version 2, or (at your option)
a50699fd
JA
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21/* NOTES:
22
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
25
26 An idea: Have the owner of the tree keep count of splits and/or
27 insertion lengths (in intervals), and balance after every N.
28
29 Need to call *_left_hook when buffer is killed.
30
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
33
34 There are comments around about freeing intervals. It might be
35 faster to explicitly free them (put them on the free list) than
36 to GC them.
37
38*/
39
40
18160b98 41#include <config.h>
a50699fd
JA
42#include "lisp.h"
43#include "intervals.h"
44#include "buffer.h"
328c0f1f 45#include "puresize.h"
f54a8c1a 46#include "keyboard.h"
a50699fd 47
7ce503fd 48/* The rest of the file is within this conditional. */
d2f7a802
JA
49#ifdef USE_TEXT_PROPERTIES
50
45d82bdc
KH
51/* Test for membership, allowing for t (actually any non-cons) to mean the
52 universal set. */
53
54#define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
55
b5f37d3f 56Lisp_Object merge_properties_sticky ();
a50699fd 57\f
7ce503fd 58/* Utility functions for intervals. */
a50699fd
JA
59
60
7ce503fd 61/* Create the root interval of some object, a buffer or string. */
a50699fd
JA
62
63INTERVAL
64create_root_interval (parent)
65 Lisp_Object parent;
66{
328c0f1f
RS
67 INTERVAL new;
68
69 CHECK_IMPURE (parent);
70
71 new = make_interval ();
a50699fd 72
b629dd47 73 if (BUFFERP (parent))
a50699fd 74 {
2bc7a79b
JB
75 new->total_length = (BUF_Z (XBUFFER (parent))
76 - BUF_BEG (XBUFFER (parent)));
a50699fd
JA
77 XBUFFER (parent)->intervals = new;
78 }
b629dd47 79 else if (STRINGP (parent))
a50699fd
JA
80 {
81 new->total_length = XSTRING (parent)->size;
82 XSTRING (parent)->intervals = new;
83 }
84
85 new->parent = (INTERVAL) parent;
86 new->position = 1;
87
88 return new;
89}
90
91/* Make the interval TARGET have exactly the properties of SOURCE */
92
93void
94copy_properties (source, target)
95 register INTERVAL source, target;
96{
97 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
98 return;
99
100 COPY_INTERVAL_CACHE (source, target);
101 target->plist = Fcopy_sequence (source->plist);
102}
103
104/* Merge the properties of interval SOURCE into the properties
323a7ad4
RS
105 of interval TARGET. That is to say, each property in SOURCE
106 is added to TARGET if TARGET has no such property as yet. */
a50699fd
JA
107
108static void
109merge_properties (source, target)
110 register INTERVAL source, target;
111{
112 register Lisp_Object o, sym, val;
113
114 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
115 return;
116
117 MERGE_INTERVAL_CACHE (source, target);
118
119 o = source->plist;
120 while (! EQ (o, Qnil))
121 {
122 sym = Fcar (o);
123 val = Fmemq (sym, target->plist);
124
125 if (NILP (val))
126 {
127 o = Fcdr (o);
128 val = Fcar (o);
129 target->plist = Fcons (sym, Fcons (val, target->plist));
130 o = Fcdr (o);
131 }
132 else
133 o = Fcdr (Fcdr (o));
134 }
135}
136
137/* Return 1 if the two intervals have the same properties,
7ce503fd 138 0 otherwise. */
a50699fd
JA
139
140int
141intervals_equal (i0, i1)
142 INTERVAL i0, i1;
143{
144 register Lisp_Object i0_cdr, i0_sym, i1_val;
145 register i1_len;
146
147 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
148 return 1;
149
323a7ad4
RS
150 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
151 return 0;
152
a50699fd
JA
153 i1_len = XFASTINT (Flength (i1->plist));
154 if (i1_len & 0x1) /* Paranoia -- plists are always even */
155 abort ();
156 i1_len /= 2;
157 i0_cdr = i0->plist;
158 while (!NILP (i0_cdr))
159 {
7ce503fd 160 /* Lengths of the two plists were unequal. */
a50699fd
JA
161 if (i1_len == 0)
162 return 0;
163
164 i0_sym = Fcar (i0_cdr);
165 i1_val = Fmemq (i0_sym, i1->plist);
166
7ce503fd 167 /* i0 has something i1 doesn't. */
a50699fd
JA
168 if (EQ (i1_val, Qnil))
169 return 0;
170
7ce503fd 171 /* i0 and i1 both have sym, but it has different values in each. */
a50699fd 172 i0_cdr = Fcdr (i0_cdr);
7ce503fd 173 if (! EQ (Fcar (Fcdr (i1_val)), Fcar (i0_cdr)))
a50699fd
JA
174 return 0;
175
176 i0_cdr = Fcdr (i0_cdr);
177 i1_len--;
178 }
179
7ce503fd 180 /* Lengths of the two plists were unequal. */
a50699fd
JA
181 if (i1_len > 0)
182 return 0;
183
184 return 1;
185}
186\f
187static int icount;
188static int idepth;
189static int zero_length;
190
a50699fd 191/* Traverse an interval tree TREE, performing FUNCTION on each node.
4a93c905 192 Pass FUNCTION two args: an interval, and ARG. */
a50699fd
JA
193
194void
4a93c905 195traverse_intervals (tree, position, depth, function, arg)
a50699fd 196 INTERVAL tree;
e0b63493 197 int position, depth;
a50699fd 198 void (* function) ();
4a93c905 199 Lisp_Object arg;
a50699fd
JA
200{
201 if (NULL_INTERVAL_P (tree))
202 return;
203
323a7ad4 204 traverse_intervals (tree->left, position, depth + 1, function, arg);
a50699fd
JA
205 position += LEFT_TOTAL_LENGTH (tree);
206 tree->position = position;
4a93c905 207 (*function) (tree, arg);
a50699fd 208 position += LENGTH (tree);
323a7ad4 209 traverse_intervals (tree->right, position, depth + 1, function, arg);
a50699fd
JA
210}
211\f
212#if 0
7ce503fd 213/* These functions are temporary, for debugging purposes only. */
a50699fd
JA
214
215INTERVAL search_interval, found_interval;
216
217void
218check_for_interval (i)
219 register INTERVAL i;
220{
221 if (i == search_interval)
222 {
223 found_interval = i;
224 icount++;
225 }
226}
227
228INTERVAL
229search_for_interval (i, tree)
230 register INTERVAL i, tree;
231{
232 icount = 0;
233 search_interval = i;
234 found_interval = NULL_INTERVAL;
4a93c905 235 traverse_intervals (tree, 1, 0, &check_for_interval, Qnil);
a50699fd
JA
236 return found_interval;
237}
238
239static void
240inc_interval_count (i)
241 INTERVAL i;
242{
243 icount++;
244 if (LENGTH (i) == 0)
245 zero_length++;
246 if (depth > idepth)
247 idepth = depth;
248}
249
250int
251count_intervals (i)
252 register INTERVAL i;
253{
254 icount = 0;
255 idepth = 0;
256 zero_length = 0;
4a93c905 257 traverse_intervals (i, 1, 0, &inc_interval_count, Qnil);
a50699fd
JA
258
259 return icount;
260}
261
262static INTERVAL
263root_interval (interval)
264 INTERVAL interval;
265{
266 register INTERVAL i = interval;
267
268 while (! ROOT_INTERVAL_P (i))
269 i = i->parent;
270
271 return i;
272}
273#endif
274\f
275/* Assuming that a left child exists, perform the following operation:
276
277 A B
278 / \ / \
279 B => A
280 / \ / \
281 c c
282*/
283
284static INTERVAL
285rotate_right (interval)
286 INTERVAL interval;
287{
288 INTERVAL i;
289 INTERVAL B = interval->left;
4314dea4 290 int old_total = interval->total_length;
a50699fd 291
7ce503fd 292 /* Deal with any Parent of A; make it point to B. */
a50699fd
JA
293 if (! ROOT_INTERVAL_P (interval))
294 if (AM_LEFT_CHILD (interval))
4314dea4 295 interval->parent->left = B;
a50699fd 296 else
4314dea4
RS
297 interval->parent->right = B;
298 B->parent = interval->parent;
a50699fd 299
4314dea4
RS
300 /* Make B the parent of A */
301 i = B->right;
302 B->right = interval;
303 interval->parent = B;
a50699fd 304
4314dea4 305 /* Make A point to c */
a50699fd
JA
306 interval->left = i;
307 if (! NULL_INTERVAL_P (i))
308 i->parent = interval;
4314dea4 309
550bd63a 310 /* A's total length is decreased by the length of B and its left child. */
4314dea4
RS
311 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
312
313 /* B must have the same total length of A. */
314 B->total_length = old_total;
a50699fd
JA
315
316 return B;
317}
4314dea4 318
a50699fd
JA
319/* Assuming that a right child exists, perform the following operation:
320
321 A B
322 / \ / \
323 B => A
324 / \ / \
325 c c
326*/
327
328static INTERVAL
329rotate_left (interval)
330 INTERVAL interval;
331{
332 INTERVAL i;
333 INTERVAL B = interval->right;
4314dea4 334 int old_total = interval->total_length;
a50699fd 335
4314dea4 336 /* Deal with any parent of A; make it point to B. */
a50699fd
JA
337 if (! ROOT_INTERVAL_P (interval))
338 if (AM_LEFT_CHILD (interval))
4314dea4 339 interval->parent->left = B;
a50699fd 340 else
4314dea4
RS
341 interval->parent->right = B;
342 B->parent = interval->parent;
a50699fd
JA
343
344 /* Make B the parent of A */
4314dea4
RS
345 i = B->left;
346 B->left = interval;
347 interval->parent = B;
a50699fd
JA
348
349 /* Make A point to c */
350 interval->right = i;
351 if (! NULL_INTERVAL_P (i))
352 i->parent = interval;
4314dea4 353
550bd63a 354 /* A's total length is decreased by the length of B and its right child. */
4314dea4
RS
355 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
356
357 /* B must have the same total length of A. */
358 B->total_length = old_total;
a50699fd
JA
359
360 return B;
361}
362\f
4314dea4
RS
363/* Balance an interval tree with the assumption that the subtrees
364 themselves are already balanced. */
365
366static INTERVAL
367balance_an_interval (i)
368 INTERVAL i;
369{
370 register int old_diff, new_diff;
371
372 while (1)
373 {
374 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
375 if (old_diff > 0)
376 {
377 new_diff = i->total_length - i->left->total_length
378 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
379 if (abs (new_diff) >= old_diff)
380 break;
381 i = rotate_right (i);
382 balance_an_interval (i->right);
383 }
384 else if (old_diff < 0)
385 {
386 new_diff = i->total_length - i->right->total_length
387 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
388 if (abs (new_diff) >= -old_diff)
389 break;
390 i = rotate_left (i);
391 balance_an_interval (i->left);
392 }
393 else
394 break;
395 }
396 return i;
397}
398
399/* Balance INTERVAL, potentially stuffing it back into its parent
400 Lisp Object. */
401
402static INLINE INTERVAL
403balance_possible_root_interval (interval)
404 register INTERVAL interval;
405{
406 Lisp_Object parent;
407
408 if (interval->parent == NULL_INTERVAL)
409 return interval;
410
411 parent = (Lisp_Object) (interval->parent);
412 interval = balance_an_interval (interval);
413
b629dd47 414 if (BUFFERP (parent))
4314dea4 415 XBUFFER (parent)->intervals = interval;
b629dd47 416 else if (STRINGP (parent))
4314dea4
RS
417 XSTRING (parent)->intervals = interval;
418
419 return interval;
420}
421
422/* Balance the interval tree TREE. Balancing is by weight
423 (the amount of text). */
424
425static INTERVAL
426balance_intervals_internal (tree)
427 register INTERVAL tree;
428{
429 /* Balance within each side. */
430 if (tree->left)
431 balance_intervals (tree->left);
432 if (tree->right)
433 balance_intervals (tree->right);
434 return balance_an_interval (tree);
435}
436
437/* Advertised interface to balance intervals. */
438
439INTERVAL
440balance_intervals (tree)
441 INTERVAL tree;
442{
443 if (tree == NULL_INTERVAL)
444 return NULL_INTERVAL;
445
446 return balance_intervals_internal (tree);
447}
448\f
2bc7a79b
JB
449/* Split INTERVAL into two pieces, starting the second piece at
450 character position OFFSET (counting from 0), relative to INTERVAL.
451 INTERVAL becomes the left-hand piece, and the right-hand piece
452 (second, lexicographically) is returned.
90ba40fc
JA
453
454 The size and position fields of the two intervals are set based upon
455 those of the original interval. The property list of the new interval
456 is reset, thus it is up to the caller to do the right thing with the
457 result.
a50699fd
JA
458
459 Note that this does not change the position of INTERVAL; if it is a root,
7ce503fd 460 it is still a root after this operation. */
a50699fd
JA
461
462INTERVAL
90ba40fc 463split_interval_right (interval, offset)
a50699fd 464 INTERVAL interval;
90ba40fc 465 int offset;
a50699fd
JA
466{
467 INTERVAL new = make_interval ();
468 int position = interval->position;
2bc7a79b 469 int new_length = LENGTH (interval) - offset;
a50699fd 470
2bc7a79b 471 new->position = position + offset;
a50699fd 472 new->parent = interval;
a50699fd 473
4314dea4 474 if (NULL_RIGHT_CHILD (interval))
a50699fd
JA
475 {
476 interval->right = new;
477 new->total_length = new_length;
478
479 return new;
480 }
481
7ce503fd 482 /* Insert the new node between INTERVAL and its right child. */
a50699fd
JA
483 new->right = interval->right;
484 interval->right->parent = new;
485 interval->right = new;
a50699fd
JA
486 new->total_length = new_length + new->right->total_length;
487
4314dea4
RS
488 balance_an_interval (new);
489 balance_possible_root_interval (interval);
490
a50699fd
JA
491 return new;
492}
493
2bc7a79b
JB
494/* Split INTERVAL into two pieces, starting the second piece at
495 character position OFFSET (counting from 0), relative to INTERVAL.
496 INTERVAL becomes the right-hand piece, and the left-hand piece
497 (first, lexicographically) is returned.
a50699fd 498
90ba40fc
JA
499 The size and position fields of the two intervals are set based upon
500 those of the original interval. The property list of the new interval
501 is reset, thus it is up to the caller to do the right thing with the
502 result.
503
504 Note that this does not change the position of INTERVAL; if it is a root,
7ce503fd 505 it is still a root after this operation. */
a50699fd
JA
506
507INTERVAL
90ba40fc 508split_interval_left (interval, offset)
a50699fd 509 INTERVAL interval;
90ba40fc 510 int offset;
a50699fd
JA
511{
512 INTERVAL new = make_interval ();
513 int position = interval->position;
2bc7a79b 514 int new_length = offset;
a50699fd 515
a50699fd 516 new->position = interval->position;
2bc7a79b 517 interval->position = interval->position + offset;
a50699fd
JA
518 new->parent = interval;
519
520 if (NULL_LEFT_CHILD (interval))
521 {
522 interval->left = new;
523 new->total_length = new_length;
524
525 return new;
526 }
527
7ce503fd 528 /* Insert the new node between INTERVAL and its left child. */
a50699fd
JA
529 new->left = interval->left;
530 new->left->parent = new;
531 interval->left = new;
4314dea4
RS
532 new->total_length = new_length + new->left->total_length;
533
534 balance_an_interval (new);
535 balance_possible_root_interval (interval);
a50699fd
JA
536
537 return new;
538}
539\f
90ba40fc 540/* Find the interval containing text position POSITION in the text
24e3d3bf
JB
541 represented by the interval tree TREE. POSITION is a buffer
542 position; the earliest position is 1. If POSITION is at the end of
543 the buffer, return the interval containing the last character.
a50699fd 544
90ba40fc
JA
545 The `position' field, which is a cache of an interval's position,
546 is updated in the interval found. Other functions (e.g., next_interval)
7ce503fd 547 will update this cache based on the result of find_interval. */
90ba40fc
JA
548
549INLINE INTERVAL
a50699fd
JA
550find_interval (tree, position)
551 register INTERVAL tree;
552 register int position;
553{
24e3d3bf
JB
554 /* The distance from the left edge of the subtree at TREE
555 to POSITION. */
556 register int relative_position = position - BEG;
a50699fd
JA
557
558 if (NULL_INTERVAL_P (tree))
559 return NULL_INTERVAL;
560
24e3d3bf 561 if (relative_position > TOTAL_LENGTH (tree))
a50699fd 562 abort (); /* Paranoia */
a50699fd 563
4314dea4
RS
564 tree = balance_possible_root_interval (tree);
565
a50699fd
JA
566 while (1)
567 {
24e3d3bf 568 if (relative_position < LEFT_TOTAL_LENGTH (tree))
a50699fd
JA
569 {
570 tree = tree->left;
571 }
24e3d3bf
JB
572 else if (! NULL_RIGHT_CHILD (tree)
573 && relative_position >= (TOTAL_LENGTH (tree)
574 - RIGHT_TOTAL_LENGTH (tree)))
a50699fd
JA
575 {
576 relative_position -= (TOTAL_LENGTH (tree)
577 - RIGHT_TOTAL_LENGTH (tree));
578 tree = tree->right;
579 }
580 else
581 {
24e3d3bf
JB
582 tree->position =
583 (position - relative_position /* the left edge of *tree */
584 + LEFT_TOTAL_LENGTH (tree)); /* the left edge of this interval */
585
a50699fd
JA
586 return tree;
587 }
588 }
589}
590\f
591/* Find the succeeding interval (lexicographically) to INTERVAL.
90ba40fc 592 Sets the `position' field based on that of INTERVAL (see
7ce503fd 593 find_interval). */
a50699fd
JA
594
595INTERVAL
596next_interval (interval)
597 register INTERVAL interval;
598{
599 register INTERVAL i = interval;
600 register int next_position;
601
602 if (NULL_INTERVAL_P (i))
603 return NULL_INTERVAL;
604 next_position = interval->position + LENGTH (interval);
605
606 if (! NULL_RIGHT_CHILD (i))
607 {
608 i = i->right;
609 while (! NULL_LEFT_CHILD (i))
610 i = i->left;
611
612 i->position = next_position;
613 return i;
614 }
615
616 while (! NULL_PARENT (i))
617 {
618 if (AM_LEFT_CHILD (i))
619 {
620 i = i->parent;
621 i->position = next_position;
622 return i;
623 }
624
625 i = i->parent;
626 }
627
628 return NULL_INTERVAL;
629}
630
631/* Find the preceding interval (lexicographically) to INTERVAL.
90ba40fc 632 Sets the `position' field based on that of INTERVAL (see
7ce503fd 633 find_interval). */
a50699fd
JA
634
635INTERVAL
636previous_interval (interval)
637 register INTERVAL interval;
638{
639 register INTERVAL i;
640 register position_of_previous;
641
642 if (NULL_INTERVAL_P (interval))
643 return NULL_INTERVAL;
644
645 if (! NULL_LEFT_CHILD (interval))
646 {
647 i = interval->left;
648 while (! NULL_RIGHT_CHILD (i))
649 i = i->right;
650
651 i->position = interval->position - LENGTH (i);
652 return i;
653 }
654
655 i = interval;
656 while (! NULL_PARENT (i))
657 {
658 if (AM_RIGHT_CHILD (i))
659 {
660 i = i->parent;
661
662 i->position = interval->position - LENGTH (i);
663 return i;
664 }
665 i = i->parent;
666 }
667
668 return NULL_INTERVAL;
669}
670\f
90ba40fc 671#if 0
a50699fd
JA
672/* Traverse a path down the interval tree TREE to the interval
673 containing POSITION, adjusting all nodes on the path for
674 an addition of LENGTH characters. Insertion between two intervals
675 (i.e., point == i->position, where i is second interval) means
676 text goes into second interval.
677
678 Modifications are needed to handle the hungry bits -- after simply
679 finding the interval at position (don't add length going down),
680 if it's the beginning of the interval, get the previous interval
681 and check the hugry bits of both. Then add the length going back up
7ce503fd 682 to the root. */
a50699fd
JA
683
684static INTERVAL
685adjust_intervals_for_insertion (tree, position, length)
686 INTERVAL tree;
687 int position, length;
688{
689 register int relative_position;
690 register INTERVAL this;
691
692 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
693 abort ();
694
695 /* If inserting at point-max of a buffer, that position
696 will be out of range */
697 if (position > TOTAL_LENGTH (tree))
698 position = TOTAL_LENGTH (tree);
699 relative_position = position;
700 this = tree;
701
702 while (1)
703 {
704 if (relative_position <= LEFT_TOTAL_LENGTH (this))
705 {
706 this->total_length += length;
707 this = this->left;
708 }
709 else if (relative_position > (TOTAL_LENGTH (this)
710 - RIGHT_TOTAL_LENGTH (this)))
711 {
712 relative_position -= (TOTAL_LENGTH (this)
713 - RIGHT_TOTAL_LENGTH (this));
714 this->total_length += length;
715 this = this->right;
716 }
717 else
718 {
719 /* If we are to use zero-length intervals as buffer pointers,
7ce503fd 720 then this code will have to change. */
a50699fd
JA
721 this->total_length += length;
722 this->position = LEFT_TOTAL_LENGTH (this)
723 + position - relative_position + 1;
724 return tree;
725 }
726 }
727}
90ba40fc
JA
728#endif
729
730/* Effect an adjustment corresponding to the addition of LENGTH characters
731 of text. Do this by finding the interval containing POSITION in the
550bd63a 732 interval tree TREE, and then adjusting all of its ancestors by adding
90ba40fc
JA
733 LENGTH to them.
734
735 If POSITION is the first character of an interval, meaning that point
736 is actually between the two intervals, make the new text belong to
737 the interval which is "sticky".
738
1d1d7ba0 739 If both intervals are "sticky", then make them belong to the left-most
90ba40fc 740 interval. Another possibility would be to create a new interval for
7ce503fd 741 this text, and make it have the merged properties of both ends. */
90ba40fc
JA
742
743static INTERVAL
744adjust_intervals_for_insertion (tree, position, length)
745 INTERVAL tree;
746 int position, length;
747{
748 register INTERVAL i;
7ce503fd
RS
749 register INTERVAL temp;
750 int eobp = 0;
751
90ba40fc
JA
752 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
753 abort ();
754
24e3d3bf
JB
755 /* If inserting at point-max of a buffer, that position will be out
756 of range. Remember that buffer positions are 1-based. */
7ce503fd 757 if (position >= BEG + TOTAL_LENGTH (tree)){
24e3d3bf 758 position = BEG + TOTAL_LENGTH (tree);
7ce503fd
RS
759 eobp = 1;
760 }
90ba40fc
JA
761
762 i = find_interval (tree, position);
7ce503fd 763
2313b945
RS
764 /* If in middle of an interval which is not sticky either way,
765 we must not just give its properties to the insertion.
766 So split this interval at the insertion point. */
767 if (! (position == i->position || eobp)
768 && END_NONSTICKY_P (i)
769 && ! FRONT_STICKY_P (i))
770 {
771 temp = split_interval_right (i, position - i->position);
772 copy_properties (i, temp);
773 i = temp;
774 }
775
90ba40fc 776 /* If we are positioned between intervals, check the stickiness of
7ce503fd
RS
777 both of them. We have to do this too, if we are at BEG or Z. */
778 if (position == i->position || eobp)
90ba40fc 779 {
7ce503fd
RS
780 register INTERVAL prev;
781
782 if (position == BEG)
783 prev = 0;
784 else if (eobp)
785 {
786 prev = i;
787 i = 0;
788 }
789 else
790 prev = previous_interval (i);
90ba40fc 791
7ce503fd
RS
792 /* Even if we are positioned between intervals, we default
793 to the left one if it exists. We extend it now and split
794 off a part later, if stickyness demands it. */
4314dea4
RS
795 for (temp = prev ? prev : i;! NULL_INTERVAL_P (temp); temp = temp->parent)
796 {
797 temp->total_length += length;
798 temp = balance_possible_root_interval (temp);
799 }
7ce503fd
RS
800
801 /* If at least one interval has sticky properties,
802 we check the stickyness property by property. */
803 if (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
804 {
dd675b05 805 Lisp_Object pleft, pright;
7ce503fd
RS
806 struct interval newi;
807
dd675b05
KH
808 pleft = NULL_INTERVAL_P (prev) ? Qnil : prev->plist;
809 pright = NULL_INTERVAL_P (i) ? Qnil : i->plist;
7ce503fd
RS
810 newi.plist = merge_properties_sticky (pleft, pright);
811
812 if(! prev) /* i.e. position == BEG */
813 {
814 if (! intervals_equal (i, &newi))
815 {
816 i = split_interval_left (i, length);
817 i->plist = newi.plist;
818 }
819 }
820 else if (! intervals_equal (prev, &newi))
821 {
822 prev = split_interval_right (prev,
823 position - prev->position);
824 prev->plist = newi.plist;
825 if (! NULL_INTERVAL_P (i)
826 && intervals_equal (prev, i))
827 merge_interval_right (prev);
828 }
829
830 /* We will need to update the cache here later. */
831 }
832 else if (! prev && ! NILP (i->plist))
833 {
834 /* Just split off a new interval at the left.
835 Since I wasn't front-sticky, the empty plist is ok. */
836 i = split_interval_left (i, length);
837 }
90ba40fc
JA
838 }
839
7ce503fd
RS
840 /* Otherwise just extend the interval. */
841 else
90ba40fc 842 {
7ce503fd 843 for (temp = i; ! NULL_INTERVAL_P (temp); temp = temp->parent)
4314dea4
RS
844 {
845 temp->total_length += length;
846 temp = balance_possible_root_interval (temp);
847 }
90ba40fc 848 }
7ce503fd 849
90ba40fc
JA
850 return tree;
851}
7ce503fd 852
45d82bdc
KH
853/* Any property might be front-sticky on the left, rear-sticky on the left,
854 front-sticky on the right, or rear-sticky on the right; the 16 combinations
855 can be arranged in a matrix with rows denoting the left conditions and
856 columns denoting the right conditions:
857 _ __ _
858_ FR FR FR FR
859FR__ 0 1 2 3
860 _FR 4 5 6 7
861FR 8 9 A B
862 FR C D E F
863
864 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
865 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
866 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
867 p8 L p9 L pa L pb L pc L pd L pe L pf L)
868 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
869 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
870 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
871 p8 R p9 R pa R pb R pc R pd R pe R pf R)
872
873 We inherit from whoever has a sticky side facing us. If both sides
874 do (cases 2, 3, E, and F), then we inherit from whichever side has a
875 non-nil value for the current property. If both sides do, then we take
876 from the left.
877
878 When we inherit a property, we get its stickiness as well as its value.
879 So, when we merge the above two lists, we expect to get this:
880
881 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
882 rear-nonsticky (p6 pa)
883 p0 L p1 L p2 L p3 L p6 R p7 R
884 pa R pb R pc L pd L pe L pf L)
885
886 The optimizable special cases are:
887 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
888 left rear-nonsticky = t, right front-sticky = t (inherit right)
889 left rear-nonsticky = t, right front-sticky = nil (inherit none)
890*/
891
7ce503fd
RS
892Lisp_Object
893merge_properties_sticky (pleft, pright)
894 Lisp_Object pleft, pright;
895{
dd675b05
KH
896 register Lisp_Object props, front, rear;
897 Lisp_Object lfront, lrear, rfront, rrear;
45d82bdc
KH
898 register Lisp_Object tail1, tail2, sym, lval, rval;
899 int use_left, use_right;
7ce503fd 900
dd675b05
KH
901 props = Qnil;
902 front = Qnil;
903 rear = Qnil;
904 lfront = textget (pleft, Qfront_sticky);
905 lrear = textget (pleft, Qrear_nonsticky);
906 rfront = textget (pright, Qfront_sticky);
907 rrear = textget (pright, Qrear_nonsticky);
908
45d82bdc
KH
909 /* Go through each element of PRIGHT. */
910 for (tail1 = pright; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
7ce503fd
RS
911 {
912 sym = Fcar (tail1);
913
914 /* Sticky properties get special treatment. */
915 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
916 continue;
45d82bdc
KH
917
918 rval = Fcar (Fcdr (tail1));
919 for (tail2 = pleft; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2)))
920 if (EQ (sym, Fcar (tail2)))
921 break;
922 lval = (NILP (tail2) ? Qnil : Fcar( Fcdr (tail2)));
923
924 use_left = ! TMEM (sym, lrear);
925 use_right = TMEM (sym, rfront);
926 if (use_left && use_right)
927 {
928 use_left = ! NILP (lval);
929 use_right = ! NILP (rval);
930 }
931 if (use_left)
7ce503fd 932 {
45d82bdc
KH
933 /* We build props as (value sym ...) rather than (sym value ...)
934 because we plan to nreverse it when we're done. */
935 if (! NILP (lval))
936 props = Fcons (lval, Fcons (sym, props));
937 if (TMEM (sym, lfront))
7ce503fd 938 front = Fcons (sym, front);
45d82bdc
KH
939 if (TMEM (sym, lrear))
940 rear = Fcons (sym, rear);
7ce503fd 941 }
45d82bdc 942 else if (use_right)
7ce503fd 943 {
45d82bdc
KH
944 if (! NILP (rval))
945 props = Fcons (rval, Fcons (sym, props));
946 if (TMEM (sym, rfront))
947 front = Fcons (sym, front);
948 if (TMEM (sym, rrear))
949 rear = Fcons (sym, rear);
7ce503fd
RS
950 }
951 }
45d82bdc
KH
952
953 /* Now go through each element of PLEFT. */
954 for (tail2 = pleft; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2)))
7ce503fd
RS
955 {
956 sym = Fcar (tail2);
957
958 /* Sticky properties get special treatment. */
959 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
960 continue;
961
45d82bdc
KH
962 /* If sym is in PRIGHT, we've already considered it. */
963 for (tail1 = pright; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
7ce503fd
RS
964 if (EQ (sym, Fcar (tail1)))
965 break;
45d82bdc
KH
966 if (! NILP (tail1))
967 continue;
968
969 lval = Fcar (Fcdr (tail2));
970
971 /* Since rval is known to be nil in this loop, the test simplifies. */
972 if (! TMEM (sym, lrear))
7ce503fd 973 {
45d82bdc
KH
974 if (! NILP (lval))
975 props = Fcons (lval, Fcons (sym, props));
976 if (TMEM (sym, lfront))
977 front = Fcons (sym, front);
978 }
979 else if (TMEM (sym, rfront))
980 {
981 /* The value is nil, but we still inherit the stickiness
982 from the right. */
7ce503fd 983 front = Fcons (sym, front);
45d82bdc 984 if (TMEM (sym, rrear))
7ce503fd
RS
985 rear = Fcons (sym, rear);
986 }
987 }
550bd63a 988 props = Fnreverse (props);
7ce503fd 989 if (! NILP (rear))
550bd63a 990 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
45d82bdc
KH
991 if (! NILP (front))
992 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
7ce503fd 993 return props;
7ce503fd
RS
994}
995
a50699fd 996\f
90ba40fc
JA
997/* Delete an node I from its interval tree by merging its subtrees
998 into one subtree which is then returned. Caller is responsible for
7ce503fd 999 storing the resulting subtree into its parent. */
a50699fd
JA
1000
1001static INTERVAL
1002delete_node (i)
1003 register INTERVAL i;
1004{
1005 register INTERVAL migrate, this;
1006 register int migrate_amt;
1007
1008 if (NULL_INTERVAL_P (i->left))
1009 return i->right;
1010 if (NULL_INTERVAL_P (i->right))
1011 return i->left;
1012
1013 migrate = i->left;
1014 migrate_amt = i->left->total_length;
1015 this = i->right;
1016 this->total_length += migrate_amt;
1017 while (! NULL_INTERVAL_P (this->left))
1018 {
1019 this = this->left;
1020 this->total_length += migrate_amt;
1021 }
1022 this->left = migrate;
1023 migrate->parent = this;
1024
1025 return i->right;
1026}
1027
1028/* Delete interval I from its tree by calling `delete_node'
1029 and properly connecting the resultant subtree.
1030
1031 I is presumed to be empty; that is, no adjustments are made
7ce503fd 1032 for the length of I. */
a50699fd
JA
1033
1034void
1035delete_interval (i)
1036 register INTERVAL i;
1037{
1038 register INTERVAL parent;
1039 int amt = LENGTH (i);
1040
7ce503fd 1041 if (amt > 0) /* Only used on zero-length intervals now. */
a50699fd
JA
1042 abort ();
1043
1044 if (ROOT_INTERVAL_P (i))
1045 {
dd675b05
KH
1046 Lisp_Object owner;
1047 owner = (Lisp_Object) i->parent;
a50699fd
JA
1048 parent = delete_node (i);
1049 if (! NULL_INTERVAL_P (parent))
1050 parent->parent = (INTERVAL) owner;
1051
b629dd47 1052 if (BUFFERP (owner))
a50699fd 1053 XBUFFER (owner)->intervals = parent;
b629dd47 1054 else if (STRINGP (owner))
a50699fd
JA
1055 XSTRING (owner)->intervals = parent;
1056 else
1057 abort ();
1058
1059 return;
1060 }
1061
1062 parent = i->parent;
1063 if (AM_LEFT_CHILD (i))
1064 {
1065 parent->left = delete_node (i);
1066 if (! NULL_INTERVAL_P (parent->left))
1067 parent->left->parent = parent;
1068 }
1069 else
1070 {
1071 parent->right = delete_node (i);
1072 if (! NULL_INTERVAL_P (parent->right))
1073 parent->right->parent = parent;
1074 }
1075}
1076\f
24e3d3bf
JB
1077/* Find the interval in TREE corresponding to the relative position
1078 FROM and delete as much as possible of AMOUNT from that interval.
1079 Return the amount actually deleted, and if the interval was
1080 zeroed-out, delete that interval node from the tree.
1081
1082 Note that FROM is actually origin zero, aka relative to the
1083 leftmost edge of tree. This is appropriate since we call ourselves
1084 recursively on subtrees.
a50699fd 1085
1d1d7ba0 1086 Do this by recursing down TREE to the interval in question, and
7ce503fd 1087 deleting the appropriate amount of text. */
a50699fd
JA
1088
1089static int
1090interval_deletion_adjustment (tree, from, amount)
1091 register INTERVAL tree;
1092 register int from, amount;
1093{
1094 register int relative_position = from;
1095
1096 if (NULL_INTERVAL_P (tree))
1097 return 0;
1098
1099 /* Left branch */
24e3d3bf 1100 if (relative_position < LEFT_TOTAL_LENGTH (tree))
a50699fd
JA
1101 {
1102 int subtract = interval_deletion_adjustment (tree->left,
1103 relative_position,
1104 amount);
1105 tree->total_length -= subtract;
1106 return subtract;
1107 }
1108 /* Right branch */
24e3d3bf
JB
1109 else if (relative_position >= (TOTAL_LENGTH (tree)
1110 - RIGHT_TOTAL_LENGTH (tree)))
a50699fd
JA
1111 {
1112 int subtract;
1113
1114 relative_position -= (tree->total_length
1115 - RIGHT_TOTAL_LENGTH (tree));
1116 subtract = interval_deletion_adjustment (tree->right,
1117 relative_position,
1118 amount);
1119 tree->total_length -= subtract;
1120 return subtract;
1121 }
7ce503fd 1122 /* Here -- this node. */
a50699fd
JA
1123 else
1124 {
24e3d3bf
JB
1125 /* How much can we delete from this interval? */
1126 int my_amount = ((tree->total_length
1127 - RIGHT_TOTAL_LENGTH (tree))
1128 - relative_position);
1129
1130 if (amount > my_amount)
1131 amount = my_amount;
1132
1133 tree->total_length -= amount;
1134 if (LENGTH (tree) == 0)
1135 delete_interval (tree);
1136
1137 return amount;
a50699fd
JA
1138 }
1139
7ce503fd 1140 /* Never reach here. */
a50699fd
JA
1141}
1142
24e3d3bf
JB
1143/* Effect the adjustments necessary to the interval tree of BUFFER to
1144 correspond to the deletion of LENGTH characters from that buffer
1145 text. The deletion is effected at position START (which is a
7ce503fd 1146 buffer position, i.e. origin 1). */
1d1d7ba0 1147
a50699fd
JA
1148static void
1149adjust_intervals_for_deletion (buffer, start, length)
1150 struct buffer *buffer;
1151 int start, length;
1152{
1153 register int left_to_delete = length;
1154 register INTERVAL tree = buffer->intervals;
1155 register int deleted;
1156
1157 if (NULL_INTERVAL_P (tree))
1158 return;
1159
24e3d3bf
JB
1160 if (start > BEG + TOTAL_LENGTH (tree)
1161 || start + length > BEG + TOTAL_LENGTH (tree))
1162 abort ();
1163
a50699fd
JA
1164 if (length == TOTAL_LENGTH (tree))
1165 {
1166 buffer->intervals = NULL_INTERVAL;
1167 return;
1168 }
1169
1170 if (ONLY_INTERVAL_P (tree))
1171 {
1172 tree->total_length -= length;
1173 return;
1174 }
1175
24e3d3bf
JB
1176 if (start > BEG + TOTAL_LENGTH (tree))
1177 start = BEG + TOTAL_LENGTH (tree);
a50699fd
JA
1178 while (left_to_delete > 0)
1179 {
24e3d3bf 1180 left_to_delete -= interval_deletion_adjustment (tree, start - 1,
a50699fd
JA
1181 left_to_delete);
1182 tree = buffer->intervals;
1183 if (left_to_delete == tree->total_length)
1184 {
1185 buffer->intervals = NULL_INTERVAL;
1186 return;
1187 }
1188 }
1189}
1190\f
eb8c3be9 1191/* Make the adjustments necessary to the interval tree of BUFFER to
1d1d7ba0
JA
1192 represent an addition or deletion of LENGTH characters starting
1193 at position START. Addition or deletion is indicated by the sign
7ce503fd 1194 of LENGTH. */
a50699fd
JA
1195
1196INLINE void
1197offset_intervals (buffer, start, length)
1198 struct buffer *buffer;
1199 int start, length;
1200{
1201 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
1202 return;
1203
1204 if (length > 0)
1205 adjust_intervals_for_insertion (buffer->intervals, start, length);
1206 else
1207 adjust_intervals_for_deletion (buffer, start, -length);
1208}
9c79dd1b
JA
1209\f
1210/* Merge interval I with its lexicographic successor. The resulting
1211 interval is returned, and has the properties of the original
1212 successor. The properties of I are lost. I is removed from the
1213 interval tree.
1214
1215 IMPORTANT:
1216 The caller must verify that this is not the last (rightmost)
7ce503fd 1217 interval. */
9c79dd1b
JA
1218
1219INTERVAL
1220merge_interval_right (i)
1221 register INTERVAL i;
1222{
1223 register int absorb = LENGTH (i);
1224 register INTERVAL successor;
1225
7ce503fd 1226 /* Zero out this interval. */
9c79dd1b
JA
1227 i->total_length -= absorb;
1228
7ce503fd 1229 /* Find the succeeding interval. */
9c79dd1b 1230 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
7ce503fd 1231 as we descend. */
9c79dd1b
JA
1232 {
1233 successor = i->right;
1234 while (! NULL_LEFT_CHILD (successor))
1235 {
1236 successor->total_length += absorb;
1237 successor = successor->left;
1238 }
1239
1240 successor->total_length += absorb;
1241 delete_interval (i);
1242 return successor;
1243 }
1244
1245 successor = i;
1246 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
7ce503fd 1247 we ascend. */
9c79dd1b
JA
1248 {
1249 if (AM_LEFT_CHILD (successor))
1250 {
1251 successor = successor->parent;
1252 delete_interval (i);
1253 return successor;
1254 }
1255
1256 successor = successor->parent;
1257 successor->total_length -= absorb;
1258 }
1259
1260 /* This must be the rightmost or last interval and cannot
7ce503fd 1261 be merged right. The caller should have known. */
9c79dd1b
JA
1262 abort ();
1263}
1264\f
1265/* Merge interval I with its lexicographic predecessor. The resulting
1266 interval is returned, and has the properties of the original predecessor.
1267 The properties of I are lost. Interval node I is removed from the tree.
1268
1269 IMPORTANT:
7ce503fd 1270 The caller must verify that this is not the first (leftmost) interval. */
9c79dd1b
JA
1271
1272INTERVAL
1273merge_interval_left (i)
1274 register INTERVAL i;
1275{
1276 register int absorb = LENGTH (i);
1277 register INTERVAL predecessor;
1278
7ce503fd 1279 /* Zero out this interval. */
9c79dd1b
JA
1280 i->total_length -= absorb;
1281
7ce503fd 1282 /* Find the preceding interval. */
9c79dd1b 1283 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
7ce503fd 1284 adding ABSORB as we go. */
9c79dd1b
JA
1285 {
1286 predecessor = i->left;
1287 while (! NULL_RIGHT_CHILD (predecessor))
1288 {
1289 predecessor->total_length += absorb;
1290 predecessor = predecessor->right;
1291 }
1292
1293 predecessor->total_length += absorb;
1294 delete_interval (i);
1295 return predecessor;
1296 }
1297
1298 predecessor = i;
1299 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
7ce503fd 1300 subtracting ABSORB. */
9c79dd1b
JA
1301 {
1302 if (AM_RIGHT_CHILD (predecessor))
1303 {
1304 predecessor = predecessor->parent;
1305 delete_interval (i);
1306 return predecessor;
1307 }
1308
1309 predecessor = predecessor->parent;
1310 predecessor->total_length -= absorb;
1311 }
a50699fd 1312
9c79dd1b 1313 /* This must be the leftmost or first interval and cannot
7ce503fd 1314 be merged left. The caller should have known. */
9c79dd1b
JA
1315 abort ();
1316}
1317\f
1d1d7ba0
JA
1318/* Make an exact copy of interval tree SOURCE which descends from
1319 PARENT. This is done by recursing through SOURCE, copying
1320 the current interval and its properties, and then adjusting
7ce503fd 1321 the pointers of the copy. */
1d1d7ba0 1322
a50699fd
JA
1323static INTERVAL
1324reproduce_tree (source, parent)
1325 INTERVAL source, parent;
1326{
1327 register INTERVAL t = make_interval ();
1328
1329 bcopy (source, t, INTERVAL_SIZE);
1330 copy_properties (source, t);
1331 t->parent = parent;
1332 if (! NULL_LEFT_CHILD (source))
1333 t->left = reproduce_tree (source->left, t);
1334 if (! NULL_RIGHT_CHILD (source))
1335 t->right = reproduce_tree (source->right, t);
1336
1337 return t;
1338}
1339
24e3d3bf
JB
1340#if 0
1341/* Nobody calls this. Perhaps it's a vestige of an earlier design. */
1342
1d1d7ba0
JA
1343/* Make a new interval of length LENGTH starting at START in the
1344 group of intervals INTERVALS, which is actually an interval tree.
1345 Returns the new interval.
1346
1347 Generate an error if the new positions would overlap an existing
7ce503fd 1348 interval. */
1d1d7ba0 1349
a50699fd
JA
1350static INTERVAL
1351make_new_interval (intervals, start, length)
1352 INTERVAL intervals;
1353 int start, length;
1354{
1355 INTERVAL slot;
1356
1357 slot = find_interval (intervals, start);
1358 if (start + length > slot->position + LENGTH (slot))
1359 error ("Interval would overlap");
1360
1361 if (start == slot->position && length == LENGTH (slot))
1362 return slot;
1363
1364 if (slot->position == start)
1365 {
7ce503fd 1366 /* New right node. */
2bc7a79b 1367 split_interval_right (slot, length);
a50699fd
JA
1368 return slot;
1369 }
1370
1371 if (slot->position + LENGTH (slot) == start + length)
1372 {
7ce503fd 1373 /* New left node. */
2bc7a79b 1374 split_interval_left (slot, LENGTH (slot) - length);
a50699fd
JA
1375 return slot;
1376 }
1377
7ce503fd 1378 /* Convert interval SLOT into three intervals. */
2bc7a79b
JB
1379 split_interval_left (slot, start - slot->position);
1380 split_interval_right (slot, length);
a50699fd
JA
1381 return slot;
1382}
24e3d3bf 1383#endif
294efdbe 1384\f
9c79dd1b 1385/* Insert the intervals of SOURCE into BUFFER at POSITION.
0b79989f 1386 LENGTH is the length of the text in SOURCE.
a50699fd 1387
2bc7a79b
JB
1388 This is used in insdel.c when inserting Lisp_Strings into the
1389 buffer. The text corresponding to SOURCE is already in the buffer
1390 when this is called. The intervals of new tree are a copy of those
1391 belonging to the string being inserted; intervals are never
1392 shared.
a50699fd 1393
0b79989f
RS
1394 If the inserted text had no intervals associated, and we don't
1395 want to inherit the surrounding text's properties, this function
a50699fd 1396 simply returns -- offset_intervals should handle placing the
90ba40fc 1397 text in the correct interval, depending on the sticky bits.
a50699fd
JA
1398
1399 If the inserted text had properties (intervals), then there are two
1400 cases -- either insertion happened in the middle of some interval,
1401 or between two intervals.
1402
1403 If the text goes into the middle of an interval, then new
1404 intervals are created in the middle with only the properties of
1405 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1406 which case the new text has the union of its properties and those
1407 of the text into which it was inserted.
1408
1409 If the text goes between two intervals, then if neither interval
90ba40fc
JA
1410 had its appropriate sticky property set (front_sticky, rear_sticky),
1411 the new text has only its properties. If one of the sticky properties
a50699fd 1412 is set, then the new text "sticks" to that region and its properties
eb8c3be9 1413 depend on merging as above. If both the preceding and succeeding
90ba40fc
JA
1414 intervals to the new text are "sticky", then the new text retains
1415 only its properties, as if neither sticky property were set. Perhaps
a50699fd 1416 we should consider merging all three sets of properties onto the new
7ce503fd 1417 text... */
a50699fd
JA
1418
1419void
0b79989f 1420graft_intervals_into_buffer (source, position, length, buffer, inherit)
9c79dd1b 1421 INTERVAL source;
0b79989f 1422 int position, length;
9c79dd1b 1423 struct buffer *buffer;
7ea69158 1424 int inherit;
a50699fd 1425{
323a7ad4 1426 register INTERVAL under, over, this, prev;
9c79dd1b 1427 register INTERVAL tree = buffer->intervals;
323a7ad4 1428 int middle;
a50699fd
JA
1429
1430 /* If the new text has no properties, it becomes part of whatever
7ce503fd 1431 interval it was inserted into. */
9c79dd1b 1432 if (NULL_INTERVAL_P (source))
0b79989f
RS
1433 {
1434 Lisp_Object buf;
08b05272 1435 if (!inherit && ! NULL_INTERVAL_P (tree))
0b79989f
RS
1436 {
1437 XSET (buf, Lisp_Buffer, buffer);
1438 Fset_text_properties (make_number (position),
1439 make_number (position + length),
1440 Qnil, buf);
1441 }
4314dea4
RS
1442 if (! NULL_INTERVAL_P (buffer->intervals))
1443 buffer->intervals = balance_an_interval (buffer->intervals);
0b79989f
RS
1444 return;
1445 }
a50699fd 1446
a50699fd
JA
1447 if (NULL_INTERVAL_P (tree))
1448 {
1449 /* The inserted text constitutes the whole buffer, so
7ce503fd 1450 simply copy over the interval structure. */
2bc7a79b 1451 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == TOTAL_LENGTH (source))
a50699fd 1452 {
b8e4857c
RS
1453 Lisp_Object buf;
1454 XSET (buf, Lisp_Buffer, buffer);
1455 buffer->intervals = reproduce_tree (source, buf);
7ce503fd 1456 /* Explicitly free the old tree here. */
a50699fd
JA
1457
1458 return;
1459 }
1460
1461 /* Create an interval tree in which to place a copy
7ce503fd 1462 of the intervals of the inserted string. */
a50699fd 1463 {
249a6da9
JA
1464 Lisp_Object buf;
1465 XSET (buf, Lisp_Buffer, buffer);
323a7ad4 1466 tree = create_root_interval (buf);
a50699fd
JA
1467 }
1468 }
7ea69158
RS
1469 else if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
1470 /* If the buffer contains only the new string, but
1471 there was already some interval tree there, then it may be
1472 some zero length intervals. Eventually, do something clever
1473 about inserting properly. For now, just waste the old intervals. */
1474 {
1475 buffer->intervals = reproduce_tree (source, tree->parent);
1476 /* Explicitly free the old tree here. */
a50699fd 1477
7ea69158
RS
1478 return;
1479 }
1480 /* Paranoia -- the text has already been added, so this buffer
1481 should be of non-zero length. */
1482 else if (TOTAL_LENGTH (tree) == 0)
1483 abort ();
a50699fd
JA
1484
1485 this = under = find_interval (tree, position);
1486 if (NULL_INTERVAL_P (under)) /* Paranoia */
1487 abort ();
9c79dd1b 1488 over = find_interval (source, 1);
a50699fd 1489
323a7ad4
RS
1490 /* Here for insertion in the middle of an interval.
1491 Split off an equivalent interval to the right,
1492 then don't bother with it any more. */
a50699fd 1493
323a7ad4 1494 if (position > under->position)
a50699fd
JA
1495 {
1496 INTERVAL end_unchanged
2bc7a79b 1497 = split_interval_left (this, position - under->position);
a50699fd 1498 copy_properties (under, end_unchanged);
323a7ad4
RS
1499 under->position = position;
1500 prev = 0;
1501 middle = 1;
a50699fd 1502 }
323a7ad4
RS
1503 else
1504 {
1505 prev = previous_interval (under);
7ce503fd 1506 if (prev && !END_NONSTICKY_P (prev))
323a7ad4
RS
1507 prev = 0;
1508 }
1509
1510 /* Insertion is now at beginning of UNDER. */
a50699fd 1511
323a7ad4 1512 /* The inserted text "sticks" to the interval `under',
7ce503fd
RS
1513 which means it gets those properties.
1514 The properties of under are the result of
1515 adjust_intervals_for_insertion, so stickyness has
1516 already been taken care of. */
1517
a50699fd
JA
1518 while (! NULL_INTERVAL_P (over))
1519 {
767809fb 1520 if (LENGTH (over) < LENGTH (under))
7ce503fd
RS
1521 {
1522 this = split_interval_left (under, LENGTH (over));
1523 copy_properties (under, this);
1524 }
323a7ad4
RS
1525 else
1526 this = under;
a50699fd 1527 copy_properties (over, this);
7ea69158 1528 if (inherit)
7ce503fd
RS
1529 merge_properties (over, this);
1530 else
1531 copy_properties (over, this);
a50699fd
JA
1532 over = next_interval (over);
1533 }
1534
4314dea4
RS
1535 if (! NULL_INTERVAL_P (buffer->intervals))
1536 buffer->intervals = balance_an_interval (buffer->intervals);
a50699fd
JA
1537 return;
1538}
1539
5cae0ec6
RS
1540/* Get the value of property PROP from PLIST,
1541 which is the plist of an interval.
1542 We check for direct properties and for categories with property PROP. */
1543
1544Lisp_Object
323a7ad4
RS
1545textget (plist, prop)
1546 Lisp_Object plist;
1547 register Lisp_Object prop;
1548{
5cae0ec6
RS
1549 register Lisp_Object tail, fallback;
1550 fallback = Qnil;
323a7ad4
RS
1551
1552 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1553 {
1554 register Lisp_Object tem;
1555 tem = Fcar (tail);
1556 if (EQ (prop, tem))
1557 return Fcar (Fcdr (tail));
5cae0ec6 1558 if (EQ (tem, Qcategory))
5dd6606e
RS
1559 {
1560 tem = Fcar (Fcdr (tail));
1561 if (SYMBOLP (tem))
1562 fallback = Fget (tem, prop);
1563 }
323a7ad4 1564 }
5cae0ec6
RS
1565
1566 return fallback;
323a7ad4 1567}
7ce503fd
RS
1568
1569/* Get the value of property PROP from PLIST,
1570 which is the plist of an interval.
1571 We check for direct properties only! */
1572
1573Lisp_Object
1574textget_direct (plist, prop)
1575 Lisp_Object plist;
1576 register Lisp_Object prop;
1577{
1578 register Lisp_Object tail;
1579
1580 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1581 {
1582 if (EQ (prop, Fcar (tail)))
1583 return Fcar (Fcdr (tail));
1584 }
1585
1586 return Qnil;
1587}
294efdbe 1588\f
5cae0ec6 1589/* Set point in BUFFER to POSITION. If the target position is
f65013b0 1590 before an intangible character, move to an ok place. */
a50699fd
JA
1591
1592void
1593set_point (position, buffer)
1594 register int position;
1595 register struct buffer *buffer;
1596{
323a7ad4 1597 register INTERVAL to, from, toprev, fromprev, target;
a50699fd
JA
1598 int buffer_point;
1599 register Lisp_Object obj;
1600 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
9c79dd1b 1601 int old_position = buffer->text.pt;
a50699fd
JA
1602
1603 if (position == buffer->text.pt)
1604 return;
1605
62056764
JB
1606 /* Check this now, before checking if the buffer has any intervals.
1607 That way, we can catch conditions which break this sanity check
1608 whether or not there are intervals in the buffer. */
1609 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1610 abort ();
1611
a50699fd
JA
1612 if (NULL_INTERVAL_P (buffer->intervals))
1613 {
1614 buffer->text.pt = position;
1615 return;
1616 }
1617
323a7ad4
RS
1618 /* Set TO to the interval containing the char after POSITION,
1619 and TOPREV to the interval containing the char before POSITION.
1620 Either one may be null. They may be equal. */
24e3d3bf 1621 to = find_interval (buffer->intervals, position);
294efdbe
RS
1622 if (position == BUF_BEGV (buffer))
1623 toprev = 0;
1624 else if (to->position == position)
323a7ad4 1625 toprev = previous_interval (to);
323a7ad4
RS
1626 else
1627 toprev = to;
1628
294efdbe
RS
1629 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1630 ? BUF_ZV (buffer) - 1
323a7ad4 1631 : BUF_PT (buffer));
9c79dd1b 1632
323a7ad4
RS
1633 /* Set FROM to the interval containing the char after PT,
1634 and FROMPREV to the interval containing the char before PT.
1635 Either one may be null. They may be equal. */
7ce503fd 1636 /* We could cache this and save time. */
a50699fd 1637 from = find_interval (buffer->intervals, buffer_point);
7ce503fd 1638 if (buffer_point == BUF_BEGV (buffer))
294efdbe
RS
1639 fromprev = 0;
1640 else if (from->position == BUF_PT (buffer))
323a7ad4
RS
1641 fromprev = previous_interval (from);
1642 else if (buffer_point != BUF_PT (buffer))
1643 fromprev = from, from = 0;
1644 else
1645 fromprev = from;
a50699fd 1646
7ce503fd 1647 /* Moving within an interval. */
323a7ad4 1648 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to))
a50699fd
JA
1649 {
1650 buffer->text.pt = position;
1651 return;
1652 }
1653
d5219de5
RS
1654 /* If the new position is between two intangible characters,
1655 move forward or backward across all such characters. */
1656 if (NILP (Vinhibit_point_motion_hooks) && ! NULL_INTERVAL_P (to)
1657 && ! NULL_INTERVAL_P (toprev))
a50699fd 1658 {
d5219de5
RS
1659 if (backwards)
1660 {
1661 /* Make sure the following character is intangible
1662 if the previous one is. */
1663 if (toprev == to
1664 || ! NILP (textget (to->plist, Qintangible)))
1665 /* Ok, that is so. Back up across intangible text. */
1666 while (! NULL_INTERVAL_P (toprev)
1667 && ! NILP (textget (toprev->plist, Qintangible)))
1668 {
1669 to = toprev;
1670 toprev = previous_interval (toprev);
1671 if (NULL_INTERVAL_P (toprev))
1672 position = BUF_BEGV (buffer);
1673 else
1674 /* This is the only line that's not
1675 dual to the following loop.
1676 That's because we want the position
1677 at the end of TOPREV. */
1678 position = to->position;
1679 }
1680 }
0df8950e 1681 else
d5219de5
RS
1682 {
1683 /* Make sure the previous character is intangible
1684 if the following one is. */
1685 if (toprev == to
1686 || ! NILP (textget (toprev->plist, Qintangible)))
1687 /* Ok, that is so. Advance across intangible text. */
1688 while (! NULL_INTERVAL_P (to)
1689 && ! NILP (textget (to->plist, Qintangible)))
1690 {
1691 toprev = to;
1692 to = next_interval (to);
1693 if (NULL_INTERVAL_P (to))
1694 position = BUF_ZV (buffer);
1695 else
1696 position = to->position;
1697 }
1698 }
1699 /* Here TO is the interval after the stopping point
1700 and TOPREV is the interval before the stopping point.
1701 One or the other may be null. */
a50699fd 1702 }
323a7ad4
RS
1703
1704 buffer->text.pt = position;
a50699fd 1705
d7e3e52b
JA
1706 /* We run point-left and point-entered hooks here, iff the
1707 two intervals are not equivalent. These hooks take
323a7ad4 1708 (old_point, new_point) as arguments. */
ddd931ff
RS
1709 if (NILP (Vinhibit_point_motion_hooks)
1710 && (! intervals_equal (from, to)
1711 || ! intervals_equal (fromprev, toprev)))
9c79dd1b 1712 {
323a7ad4
RS
1713 Lisp_Object leave_after, leave_before, enter_after, enter_before;
1714
1715 if (fromprev)
1716 leave_after = textget (fromprev->plist, Qpoint_left);
1717 else
1718 leave_after = Qnil;
1719 if (from)
1720 leave_before = textget (from->plist, Qpoint_left);
1721 else
1722 leave_before = Qnil;
1723
1724 if (toprev)
1725 enter_after = textget (toprev->plist, Qpoint_entered);
1726 else
1727 enter_after = Qnil;
1728 if (to)
1729 enter_before = textget (to->plist, Qpoint_entered);
1730 else
1731 enter_before = Qnil;
9c79dd1b 1732
323a7ad4
RS
1733 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
1734 call2 (leave_before, old_position, position);
1735 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
1736 call2 (leave_after, old_position, position);
9c79dd1b 1737
323a7ad4
RS
1738 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
1739 call2 (enter_before, old_position, position);
1740 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
1741 call2 (enter_after, old_position, position);
9c79dd1b 1742 }
a50699fd
JA
1743}
1744
7ce503fd 1745/* Set point temporarily, without checking any text properties. */
a50699fd 1746
9c79dd1b
JA
1747INLINE void
1748temp_set_point (position, buffer)
1749 int position;
1750 struct buffer *buffer;
1751{
1752 buffer->text.pt = position;
1753}
294efdbe 1754\f
5cae0ec6
RS
1755/* Return the proper local map for position POSITION in BUFFER.
1756 Use the map specified by the local-map property, if any.
1757 Otherwise, use BUFFER's local map. */
1758
1759Lisp_Object
1760get_local_map (position, buffer)
1761 register int position;
1762 register struct buffer *buffer;
1763{
1764 register INTERVAL interval;
1765 Lisp_Object prop, tem;
1766
1767 if (NULL_INTERVAL_P (buffer->intervals))
1768 return current_buffer->keymap;
1769
7ce503fd 1770 /* Perhaps we should just change `position' to the limit. */
5cae0ec6
RS
1771 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1772 abort ();
1773
5cae0ec6
RS
1774 interval = find_interval (buffer->intervals, position);
1775 prop = textget (interval->plist, Qlocal_map);
1776 if (NILP (prop))
1777 return current_buffer->keymap;
1778
1779 /* Use the local map only if it is valid. */
1780 tem = Fkeymapp (prop);
1781 if (!NILP (tem))
1782 return prop;
1783
1784 return current_buffer->keymap;
1785}
1786\f
294efdbe
RS
1787/* Call the modification hook functions in LIST, each with START and END. */
1788
1789static void
1790call_mod_hooks (list, start, end)
1791 Lisp_Object list, start, end;
1792{
1793 struct gcpro gcpro1;
1794 GCPRO1 (list);
1795 while (!NILP (list))
1796 {
1797 call2 (Fcar (list), start, end);
1798 list = Fcdr (list);
1799 }
1800 UNGCPRO;
1801}
9c79dd1b
JA
1802
1803/* Check for read-only intervals and signal an error if we find one.
1804 Then check for any modification hooks in the range START up to
1805 (but not including) TO. Create a list of all these hooks in
1806 lexicographic order, eliminating consecutive extra copies of the
1807 same hook. Then call those hooks in order, with START and END - 1
7ce503fd 1808 as arguments. */
a50699fd
JA
1809
1810void
1811verify_interval_modification (buf, start, end)
1812 struct buffer *buf;
1813 int start, end;
1814{
1815 register INTERVAL intervals = buf->intervals;
294efdbe
RS
1816 register INTERVAL i, prev;
1817 Lisp_Object hooks;
1818 register Lisp_Object prev_mod_hooks;
1819 Lisp_Object mod_hooks;
9c79dd1b 1820 struct gcpro gcpro1;
a50699fd 1821
294efdbe
RS
1822 hooks = Qnil;
1823 prev_mod_hooks = Qnil;
1824 mod_hooks = Qnil;
1825
a50699fd
JA
1826 if (NULL_INTERVAL_P (intervals))
1827 return;
1828
1829 if (start > end)
1830 {
1831 int temp = start;
1832 start = end;
1833 end = temp;
1834 }
1835
294efdbe
RS
1836 /* For an insert operation, check the two chars around the position. */
1837 if (start == end)
a50699fd 1838 {
294efdbe
RS
1839 INTERVAL prev;
1840 Lisp_Object before, after;
a50699fd 1841
294efdbe
RS
1842 /* Set I to the interval containing the char after START,
1843 and PREV to the interval containing the char before START.
1844 Either one may be null. They may be equal. */
24e3d3bf 1845 i = find_interval (intervals, start);
294efdbe
RS
1846
1847 if (start == BUF_BEGV (buf))
1848 prev = 0;
7ce503fd 1849 else if (i->position == start)
294efdbe
RS
1850 prev = previous_interval (i);
1851 else if (i->position < start)
1852 prev = i;
1853 if (start == BUF_ZV (buf))
1854 i = 0;
1855
7ce503fd
RS
1856 /* If Vinhibit_read_only is set and is not a list, we can
1857 skip the read_only checks. */
1858 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only))
294efdbe 1859 {
7ce503fd
RS
1860 /* If I and PREV differ we need to check for the read-only
1861 property together with its stickyness. If either I or
1862 PREV are 0, this check is all we need.
1863 We have to take special care, since read-only may be
1864 indirectly defined via the category property. */
1865 if (i != prev)
1866 {
1867 if (! NULL_INTERVAL_P (i))
1868 {
1869 after = textget (i->plist, Qread_only);
1870
1871 /* If interval I is read-only and read-only is
1872 front-sticky, inhibit insertion.
1873 Check for read-only as well as category. */
1874 if (! NILP (after)
3e76261f
KH
1875 && NILP (Fmemq (after, Vinhibit_read_only)))
1876 {
1877 Lisp_Object tem;
1878
1879 tem = textget (i->plist, Qfront_sticky);
1880 if (TMEM (Qread_only, tem)
7ce503fd 1881 || (NILP (textget_direct (i->plist, Qread_only))
3e76261f
KH
1882 && TMEM (Qcategory, tem)))
1883 error ("Attempt to insert within read-only text");
1884 }
7ce503fd 1885 }
df28eb7b 1886
7ce503fd
RS
1887 if (! NULL_INTERVAL_P (prev))
1888 {
1889 before = textget (prev->plist, Qread_only);
1890
1891 /* If interval PREV is read-only and read-only isn't
1892 rear-nonsticky, inhibit insertion.
1893 Check for read-only as well as category. */
1894 if (! NILP (before)
3e76261f
KH
1895 && NILP (Fmemq (before, Vinhibit_read_only)))
1896 {
1897 Lisp_Object tem;
1898
1899 tem = textget (prev->plist, Qrear_nonsticky);
1900 if (! TMEM (Qread_only, tem)
1901 && (! NILP (textget_direct (prev->plist,Qread_only))
1902 || ! TMEM (Qcategory, tem)))
1903 error ("Attempt to insert within read-only text");
1904 }
7ce503fd 1905 }
7ce503fd
RS
1906 }
1907 else if (! NULL_INTERVAL_P (i))
7ce503fd 1908 {
df28eb7b
RS
1909 after = textget (i->plist, Qread_only);
1910
1911 /* If interval I is read-only and read-only is
1912 front-sticky, inhibit insertion.
1913 Check for read-only as well as category. */
1914 if (! NILP (after) && NILP (Fmemq (after, Vinhibit_read_only)))
1915 {
1916 Lisp_Object tem;
1917
1918 tem = textget (i->plist, Qfront_sticky);
1919 if (TMEM (Qread_only, tem)
1920 || (NILP (textget_direct (i->plist, Qread_only))
1921 && TMEM (Qcategory, tem)))
1922 error ("Attempt to insert within read-only text");
1923
1924 tem = textget (prev->plist, Qrear_nonsticky);
1925 if (! TMEM (Qread_only, tem)
1926 && (! NILP (textget_direct (prev->plist, Qread_only))
1927 || ! TMEM (Qcategory, tem)))
1928 error ("Attempt to insert within read-only text");
1929 }
7ce503fd 1930 }
294efdbe
RS
1931 }
1932
c3649419 1933 /* Run both insert hooks (just once if they're the same). */
294efdbe 1934 if (!NULL_INTERVAL_P (prev))
f1ca9012 1935 prev_mod_hooks = textget (prev->plist, Qinsert_behind_hooks);
294efdbe 1936 if (!NULL_INTERVAL_P (i))
f1ca9012 1937 mod_hooks = textget (i->plist, Qinsert_in_front_hooks);
294efdbe
RS
1938 GCPRO1 (mod_hooks);
1939 if (! NILP (prev_mod_hooks))
1940 call_mod_hooks (prev_mod_hooks, make_number (start),
1941 make_number (end));
1942 UNGCPRO;
1943 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1944 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
a50699fd
JA
1945 }
1946 else
a50699fd 1947 {
294efdbe
RS
1948 /* Loop over intervals on or next to START...END,
1949 collecting their hooks. */
9c79dd1b 1950
294efdbe
RS
1951 i = find_interval (intervals, start);
1952 do
9c79dd1b 1953 {
294efdbe
RS
1954 if (! INTERVAL_WRITABLE_P (i))
1955 error ("Attempt to modify read-only text");
9c79dd1b 1956
294efdbe
RS
1957 mod_hooks = textget (i->plist, Qmodification_hooks);
1958 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1959 {
1960 hooks = Fcons (mod_hooks, hooks);
1961 prev_mod_hooks = mod_hooks;
1962 }
a50699fd 1963
294efdbe
RS
1964 i = next_interval (i);
1965 }
1966 /* Keep going thru the interval containing the char before END. */
1967 while (! NULL_INTERVAL_P (i) && i->position < end);
1968
1969 GCPRO1 (hooks);
1970 hooks = Fnreverse (hooks);
1971 while (! EQ (hooks, Qnil))
1972 {
1973 call_mod_hooks (Fcar (hooks), make_number (start),
1974 make_number (end));
1975 hooks = Fcdr (hooks);
1976 }
1977 UNGCPRO;
9c79dd1b 1978 }
a50699fd
JA
1979}
1980
9c79dd1b 1981/* Produce an interval tree reflecting the intervals in
7ce503fd 1982 TREE from START to START + LENGTH. */
a50699fd 1983
7b1d5b85 1984INTERVAL
a50699fd
JA
1985copy_intervals (tree, start, length)
1986 INTERVAL tree;
1987 int start, length;
1988{
1989 register INTERVAL i, new, t;
95e3e1ef 1990 register int got, prevlen;
a50699fd
JA
1991
1992 if (NULL_INTERVAL_P (tree) || length <= 0)
1993 return NULL_INTERVAL;
1994
1995 i = find_interval (tree, start);
1996 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1997 abort ();
1998
7ce503fd 1999 /* If there is only one interval and it's the default, return nil. */
a50699fd
JA
2000 if ((start - i->position + 1 + length) < LENGTH (i)
2001 && DEFAULT_INTERVAL_P (i))
2002 return NULL_INTERVAL;
2003
2004 new = make_interval ();
2005 new->position = 1;
2006 got = (LENGTH (i) - (start - i->position));
9c79dd1b 2007 new->total_length = length;
a50699fd
JA
2008 copy_properties (i, new);
2009
2010 t = new;
95e3e1ef 2011 prevlen = got;
a50699fd
JA
2012 while (got < length)
2013 {
2014 i = next_interval (i);
2bc7a79b 2015 t = split_interval_right (t, prevlen);
a50699fd 2016 copy_properties (i, t);
95e3e1ef
RS
2017 prevlen = LENGTH (i);
2018 got += prevlen;
a50699fd
JA
2019 }
2020
4314dea4 2021 return balance_an_interval (new);
a50699fd
JA
2022}
2023
7ce503fd 2024/* Give STRING the properties of BUFFER from POSITION to LENGTH. */
a50699fd 2025
d7e3e52b 2026INLINE void
a50699fd
JA
2027copy_intervals_to_string (string, buffer, position, length)
2028 Lisp_Object string, buffer;
2029 int position, length;
2030{
2031 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
2032 position, length);
2033 if (NULL_INTERVAL_P (interval_copy))
2034 return;
2035
2036 interval_copy->parent = (INTERVAL) string;
2037 XSTRING (string)->intervals = interval_copy;
2038}
d2f7a802
JA
2039
2040#endif /* USE_TEXT_PROPERTIES */