Compare the values of text properties using EQ, not Fequal.
[bpt/emacs.git] / src / intervals.c
1 /* Code for doing intervals.
2 Copyright (C) 1993 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the 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
41 #include "config.h"
42 #include "lisp.h"
43 #include "intervals.h"
44 #include "buffer.h"
45
46 /* The rest of the file is within this conditional. */
47 #ifdef USE_TEXT_PROPERTIES
48
49 /* Factor for weight-balancing interval trees. */
50 Lisp_Object interval_balance_threshold;
51 \f
52 /* Utility functions for intervals. */
53
54
55 /* Create the root interval of some object, a buffer or string. */
56
57 INTERVAL
58 create_root_interval (parent)
59 Lisp_Object parent;
60 {
61 INTERVAL new = make_interval ();
62
63 if (XTYPE (parent) == Lisp_Buffer)
64 {
65 new->total_length = BUF_Z (XBUFFER (parent)) - 1;
66 XBUFFER (parent)->intervals = new;
67 }
68 else if (XTYPE (parent) == Lisp_String)
69 {
70 new->total_length = XSTRING (parent)->size;
71 XSTRING (parent)->intervals = new;
72 }
73
74 new->parent = (INTERVAL) parent;
75 new->position = 1;
76
77 return new;
78 }
79
80 /* Make the interval TARGET have exactly the properties of SOURCE */
81
82 void
83 copy_properties (source, target)
84 register INTERVAL source, target;
85 {
86 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
87 return;
88
89 COPY_INTERVAL_CACHE (source, target);
90 target->plist = Fcopy_sequence (source->plist);
91 }
92
93 /* Merge the properties of interval SOURCE into the properties
94 of interval TARGET. That is to say, each property in SOURCE
95 is added to TARGET if TARGET has no such property as yet. */
96
97 static void
98 merge_properties (source, target)
99 register INTERVAL source, target;
100 {
101 register Lisp_Object o, sym, val;
102
103 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
104 return;
105
106 MERGE_INTERVAL_CACHE (source, target);
107
108 o = source->plist;
109 while (! EQ (o, Qnil))
110 {
111 sym = Fcar (o);
112 val = Fmemq (sym, target->plist);
113
114 if (NILP (val))
115 {
116 o = Fcdr (o);
117 val = Fcar (o);
118 target->plist = Fcons (sym, Fcons (val, target->plist));
119 o = Fcdr (o);
120 }
121 else
122 o = Fcdr (Fcdr (o));
123 }
124 }
125
126 /* Return 1 if the two intervals have the same properties,
127 0 otherwise. */
128
129 int
130 intervals_equal (i0, i1)
131 INTERVAL i0, i1;
132 {
133 register Lisp_Object i0_cdr, i0_sym, i1_val;
134 register i1_len;
135
136 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
137 return 1;
138
139 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
140 return 0;
141
142 i1_len = XFASTINT (Flength (i1->plist));
143 if (i1_len & 0x1) /* Paranoia -- plists are always even */
144 abort ();
145 i1_len /= 2;
146 i0_cdr = i0->plist;
147 while (!NILP (i0_cdr))
148 {
149 /* Lengths of the two plists were unequal */
150 if (i1_len == 0)
151 return 0;
152
153 i0_sym = Fcar (i0_cdr);
154 i1_val = Fmemq (i0_sym, i1->plist);
155
156 /* i0 has something i1 doesn't */
157 if (EQ (i1_val, Qnil))
158 return 0;
159
160 /* i0 and i1 both have sym, but it has different values in each */
161 i0_cdr = Fcdr (i0_cdr);
162 if (! EQ (i1_val, Fcar (i0_cdr)))
163 return 0;
164
165 i0_cdr = Fcdr (i0_cdr);
166 i1_len--;
167 }
168
169 /* Lengths of the two plists were unequal */
170 if (i1_len > 0)
171 return 0;
172
173 return 1;
174 }
175 \f
176 static int icount;
177 static int idepth;
178 static int zero_length;
179
180 /* Traverse an interval tree TREE, performing FUNCTION on each node.
181 Pass FUNCTION two args: an interval, and ARG. */
182
183 void
184 traverse_intervals (tree, position, depth, function, arg)
185 INTERVAL tree;
186 int position, depth;
187 void (* function) ();
188 Lisp_Object arg;
189 {
190 if (NULL_INTERVAL_P (tree))
191 return;
192
193 traverse_intervals (tree->left, position, depth + 1, function, arg);
194 position += LEFT_TOTAL_LENGTH (tree);
195 tree->position = position;
196 (*function) (tree, arg);
197 position += LENGTH (tree);
198 traverse_intervals (tree->right, position, depth + 1, function, arg);
199 }
200 \f
201 #if 0
202 /* These functions are temporary, for debugging purposes only. */
203
204 INTERVAL search_interval, found_interval;
205
206 void
207 check_for_interval (i)
208 register INTERVAL i;
209 {
210 if (i == search_interval)
211 {
212 found_interval = i;
213 icount++;
214 }
215 }
216
217 INTERVAL
218 search_for_interval (i, tree)
219 register INTERVAL i, tree;
220 {
221 icount = 0;
222 search_interval = i;
223 found_interval = NULL_INTERVAL;
224 traverse_intervals (tree, 1, 0, &check_for_interval, Qnil);
225 return found_interval;
226 }
227
228 static void
229 inc_interval_count (i)
230 INTERVAL i;
231 {
232 icount++;
233 if (LENGTH (i) == 0)
234 zero_length++;
235 if (depth > idepth)
236 idepth = depth;
237 }
238
239 int
240 count_intervals (i)
241 register INTERVAL i;
242 {
243 icount = 0;
244 idepth = 0;
245 zero_length = 0;
246 traverse_intervals (i, 1, 0, &inc_interval_count, Qnil);
247
248 return icount;
249 }
250
251 static INTERVAL
252 root_interval (interval)
253 INTERVAL interval;
254 {
255 register INTERVAL i = interval;
256
257 while (! ROOT_INTERVAL_P (i))
258 i = i->parent;
259
260 return i;
261 }
262 #endif
263 \f
264 /* Assuming that a left child exists, perform the following operation:
265
266 A B
267 / \ / \
268 B => A
269 / \ / \
270 c c
271 */
272
273 static INTERVAL
274 rotate_right (interval)
275 INTERVAL interval;
276 {
277 INTERVAL i;
278 INTERVAL B = interval->left;
279 int len = LENGTH (interval);
280
281 /* Deal with any Parent of A; make it point to B. */
282 if (! ROOT_INTERVAL_P (interval))
283 if (AM_LEFT_CHILD (interval))
284 interval->parent->left = interval->left;
285 else
286 interval->parent->right = interval->left;
287 interval->left->parent = interval->parent;
288
289 /* B gets the same length as A, since it get A's position in the tree. */
290 interval->left->total_length = interval->total_length;
291
292 /* B becomes the parent of A. */
293 i = interval->left->right;
294 interval->left->right = interval;
295 interval->parent = interval->left;
296
297 /* A gets c as left child. */
298 interval->left = i;
299 if (! NULL_INTERVAL_P (i))
300 i->parent = interval;
301 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
302 + RIGHT_TOTAL_LENGTH (interval));
303
304 return B;
305 }
306 \f
307 /* Assuming that a right child exists, perform the following operation:
308
309 A B
310 / \ / \
311 B => A
312 / \ / \
313 c c
314 */
315
316 static INTERVAL
317 rotate_left (interval)
318 INTERVAL interval;
319 {
320 INTERVAL i;
321 INTERVAL B = interval->right;
322 int len = LENGTH (interval);
323
324 /* Deal with the parent of A. */
325 if (! ROOT_INTERVAL_P (interval))
326 if (AM_LEFT_CHILD (interval))
327 interval->parent->left = interval->right;
328 else
329 interval->parent->right = interval->right;
330 interval->right->parent = interval->parent;
331
332 /* B must have the same total length of A. */
333 interval->right->total_length = interval->total_length;
334
335 /* Make B the parent of A */
336 i = interval->right->left;
337 interval->right->left = interval;
338 interval->parent = interval->right;
339
340 /* Make A point to c */
341 interval->right = i;
342 if (! NULL_INTERVAL_P (i))
343 i->parent = interval;
344 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
345 + RIGHT_TOTAL_LENGTH (interval));
346
347 return B;
348 }
349 \f
350 /* Split INTERVAL into two pieces, starting the second piece at character
351 position OFFSET (counting from 1), relative to INTERVAL. The right-hand
352 piece (second, lexicographically) is returned.
353
354 The size and position fields of the two intervals are set based upon
355 those of the original interval. The property list of the new interval
356 is reset, thus it is up to the caller to do the right thing with the
357 result.
358
359 Note that this does not change the position of INTERVAL; if it is a root,
360 it is still a root after this operation. */
361
362 INTERVAL
363 split_interval_right (interval, offset)
364 INTERVAL interval;
365 int offset;
366 {
367 INTERVAL new = make_interval ();
368 int position = interval->position;
369 int new_length = LENGTH (interval) - offset + 1;
370
371 new->position = position + offset - 1;
372 new->parent = interval;
373
374 if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval))
375 {
376 interval->right = new;
377 new->total_length = new_length;
378
379 return new;
380 }
381
382 /* Insert the new node between INTERVAL and its right child. */
383 new->right = interval->right;
384 interval->right->parent = new;
385 interval->right = new;
386
387 new->total_length = new_length + new->right->total_length;
388
389 return new;
390 }
391
392 /* Split INTERVAL into two pieces, starting the second piece at character
393 position OFFSET (counting from 1), relative to INTERVAL. The left-hand
394 piece (first, lexicographically) is returned.
395
396 The size and position fields of the two intervals are set based upon
397 those of the original interval. The property list of the new interval
398 is reset, thus it is up to the caller to do the right thing with the
399 result.
400
401 Note that this does not change the position of INTERVAL; if it is a root,
402 it is still a root after this operation. */
403
404 INTERVAL
405 split_interval_left (interval, offset)
406 INTERVAL interval;
407 int offset;
408 {
409 INTERVAL new = make_interval ();
410 int position = interval->position;
411 int new_length = offset - 1;
412
413 new->position = interval->position;
414 interval->position = interval->position + offset - 1;
415 new->parent = interval;
416
417 if (NULL_LEFT_CHILD (interval))
418 {
419 interval->left = new;
420 new->total_length = new_length;
421
422 return new;
423 }
424
425 /* Insert the new node between INTERVAL and its left child. */
426 new->left = interval->left;
427 new->left->parent = new;
428 interval->left = new;
429 new->total_length = new_length + LEFT_TOTAL_LENGTH (new);
430
431 return new;
432 }
433 \f
434 /* Find the interval containing text position POSITION in the text
435 represented by the interval tree TREE. POSITION is relative to
436 the beginning of that text.
437
438 The `position' field, which is a cache of an interval's position,
439 is updated in the interval found. Other functions (e.g., next_interval)
440 will update this cache based on the result of find_interval. */
441
442 INLINE INTERVAL
443 find_interval (tree, position)
444 register INTERVAL tree;
445 register int position;
446 {
447 register int relative_position = position;
448
449 if (NULL_INTERVAL_P (tree))
450 return NULL_INTERVAL;
451
452 if (position > TOTAL_LENGTH (tree))
453 abort (); /* Paranoia */
454 #if 0
455 position = TOTAL_LENGTH (tree);
456 #endif
457
458 while (1)
459 {
460 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
461 {
462 tree = tree->left;
463 }
464 else if (relative_position > (TOTAL_LENGTH (tree)
465 - RIGHT_TOTAL_LENGTH (tree)))
466 {
467 relative_position -= (TOTAL_LENGTH (tree)
468 - RIGHT_TOTAL_LENGTH (tree));
469 tree = tree->right;
470 }
471 else
472 {
473 tree->position = LEFT_TOTAL_LENGTH (tree)
474 + position - relative_position + 1;
475 return tree;
476 }
477 }
478 }
479 \f
480 /* Find the succeeding interval (lexicographically) to INTERVAL.
481 Sets the `position' field based on that of INTERVAL (see
482 find_interval). */
483
484 INTERVAL
485 next_interval (interval)
486 register INTERVAL interval;
487 {
488 register INTERVAL i = interval;
489 register int next_position;
490
491 if (NULL_INTERVAL_P (i))
492 return NULL_INTERVAL;
493 next_position = interval->position + LENGTH (interval);
494
495 if (! NULL_RIGHT_CHILD (i))
496 {
497 i = i->right;
498 while (! NULL_LEFT_CHILD (i))
499 i = i->left;
500
501 i->position = next_position;
502 return i;
503 }
504
505 while (! NULL_PARENT (i))
506 {
507 if (AM_LEFT_CHILD (i))
508 {
509 i = i->parent;
510 i->position = next_position;
511 return i;
512 }
513
514 i = i->parent;
515 }
516
517 return NULL_INTERVAL;
518 }
519
520 /* Find the preceding interval (lexicographically) to INTERVAL.
521 Sets the `position' field based on that of INTERVAL (see
522 find_interval). */
523
524 INTERVAL
525 previous_interval (interval)
526 register INTERVAL interval;
527 {
528 register INTERVAL i;
529 register position_of_previous;
530
531 if (NULL_INTERVAL_P (interval))
532 return NULL_INTERVAL;
533
534 if (! NULL_LEFT_CHILD (interval))
535 {
536 i = interval->left;
537 while (! NULL_RIGHT_CHILD (i))
538 i = i->right;
539
540 i->position = interval->position - LENGTH (i);
541 return i;
542 }
543
544 i = interval;
545 while (! NULL_PARENT (i))
546 {
547 if (AM_RIGHT_CHILD (i))
548 {
549 i = i->parent;
550
551 i->position = interval->position - LENGTH (i);
552 return i;
553 }
554 i = i->parent;
555 }
556
557 return NULL_INTERVAL;
558 }
559 \f
560 #if 0
561 /* Traverse a path down the interval tree TREE to the interval
562 containing POSITION, adjusting all nodes on the path for
563 an addition of LENGTH characters. Insertion between two intervals
564 (i.e., point == i->position, where i is second interval) means
565 text goes into second interval.
566
567 Modifications are needed to handle the hungry bits -- after simply
568 finding the interval at position (don't add length going down),
569 if it's the beginning of the interval, get the previous interval
570 and check the hugry bits of both. Then add the length going back up
571 to the root. */
572
573 static INTERVAL
574 adjust_intervals_for_insertion (tree, position, length)
575 INTERVAL tree;
576 int position, length;
577 {
578 register int relative_position;
579 register INTERVAL this;
580
581 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
582 abort ();
583
584 /* If inserting at point-max of a buffer, that position
585 will be out of range */
586 if (position > TOTAL_LENGTH (tree))
587 position = TOTAL_LENGTH (tree);
588 relative_position = position;
589 this = tree;
590
591 while (1)
592 {
593 if (relative_position <= LEFT_TOTAL_LENGTH (this))
594 {
595 this->total_length += length;
596 this = this->left;
597 }
598 else if (relative_position > (TOTAL_LENGTH (this)
599 - RIGHT_TOTAL_LENGTH (this)))
600 {
601 relative_position -= (TOTAL_LENGTH (this)
602 - RIGHT_TOTAL_LENGTH (this));
603 this->total_length += length;
604 this = this->right;
605 }
606 else
607 {
608 /* If we are to use zero-length intervals as buffer pointers,
609 then this code will have to change. */
610 this->total_length += length;
611 this->position = LEFT_TOTAL_LENGTH (this)
612 + position - relative_position + 1;
613 return tree;
614 }
615 }
616 }
617 #endif
618
619 /* Effect an adjustment corresponding to the addition of LENGTH characters
620 of text. Do this by finding the interval containing POSITION in the
621 interval tree TREE, and then adjusting all of it's ancestors by adding
622 LENGTH to them.
623
624 If POSITION is the first character of an interval, meaning that point
625 is actually between the two intervals, make the new text belong to
626 the interval which is "sticky".
627
628 If both intervals are "sticky", then make them belong to the left-most
629 interval. Another possibility would be to create a new interval for
630 this text, and make it have the merged properties of both ends. */
631
632 static INTERVAL
633 adjust_intervals_for_insertion (tree, position, length)
634 INTERVAL tree;
635 int position, length;
636 {
637 register INTERVAL i;
638
639 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
640 abort ();
641
642 /* If inserting at point-max of a buffer, that position
643 will be out of range. */
644 if (position > TOTAL_LENGTH (tree))
645 position = TOTAL_LENGTH (tree);
646
647 i = find_interval (tree, position);
648 /* If we are positioned between intervals, check the stickiness of
649 both of them. */
650 if (position == i->position
651 && position != 1)
652 {
653 register INTERVAL prev = previous_interval (i);
654
655 /* If both intervals are sticky here, then default to the
656 left-most one. But perhaps we should create a new
657 interval here instead... */
658 if (END_STICKY_P (prev) || ! FRONT_STICKY_P (i))
659 i = prev;
660 }
661
662 while (! NULL_INTERVAL_P (i))
663 {
664 i->total_length += length;
665 i = i->parent;
666 }
667
668 return tree;
669 }
670 \f
671 /* Delete an node I from its interval tree by merging its subtrees
672 into one subtree which is then returned. Caller is responsible for
673 storing the resulting subtree into its parent. */
674
675 static INTERVAL
676 delete_node (i)
677 register INTERVAL i;
678 {
679 register INTERVAL migrate, this;
680 register int migrate_amt;
681
682 if (NULL_INTERVAL_P (i->left))
683 return i->right;
684 if (NULL_INTERVAL_P (i->right))
685 return i->left;
686
687 migrate = i->left;
688 migrate_amt = i->left->total_length;
689 this = i->right;
690 this->total_length += migrate_amt;
691 while (! NULL_INTERVAL_P (this->left))
692 {
693 this = this->left;
694 this->total_length += migrate_amt;
695 }
696 this->left = migrate;
697 migrate->parent = this;
698
699 return i->right;
700 }
701
702 /* Delete interval I from its tree by calling `delete_node'
703 and properly connecting the resultant subtree.
704
705 I is presumed to be empty; that is, no adjustments are made
706 for the length of I. */
707
708 void
709 delete_interval (i)
710 register INTERVAL i;
711 {
712 register INTERVAL parent;
713 int amt = LENGTH (i);
714
715 if (amt > 0) /* Only used on zero-length intervals now. */
716 abort ();
717
718 if (ROOT_INTERVAL_P (i))
719 {
720 Lisp_Object owner = (Lisp_Object) i->parent;
721 parent = delete_node (i);
722 if (! NULL_INTERVAL_P (parent))
723 parent->parent = (INTERVAL) owner;
724
725 if (XTYPE (owner) == Lisp_Buffer)
726 XBUFFER (owner)->intervals = parent;
727 else if (XTYPE (owner) == Lisp_String)
728 XSTRING (owner)->intervals = parent;
729 else
730 abort ();
731
732 return;
733 }
734
735 parent = i->parent;
736 if (AM_LEFT_CHILD (i))
737 {
738 parent->left = delete_node (i);
739 if (! NULL_INTERVAL_P (parent->left))
740 parent->left->parent = parent;
741 }
742 else
743 {
744 parent->right = delete_node (i);
745 if (! NULL_INTERVAL_P (parent->right))
746 parent->right->parent = parent;
747 }
748 }
749 \f
750 /* Find the interval in TREE corresponding to the character position FROM
751 and delete as much as possible of AMOUNT from that interval, starting
752 after the relative position of FROM within it. Return the amount
753 actually deleted, and if the interval was zeroed-out, delete that
754 interval node from the tree.
755
756 Do this by recursing down TREE to the interval in question, and
757 deleting the appropriate amount of text. */
758
759 static int
760 interval_deletion_adjustment (tree, from, amount)
761 register INTERVAL tree;
762 register int from, amount;
763 {
764 register int relative_position = from;
765
766 if (NULL_INTERVAL_P (tree))
767 return 0;
768
769 /* Left branch */
770 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
771 {
772 int subtract = interval_deletion_adjustment (tree->left,
773 relative_position,
774 amount);
775 tree->total_length -= subtract;
776 return subtract;
777 }
778 /* Right branch */
779 else if (relative_position > (TOTAL_LENGTH (tree)
780 - RIGHT_TOTAL_LENGTH (tree)))
781 {
782 int subtract;
783
784 relative_position -= (tree->total_length
785 - RIGHT_TOTAL_LENGTH (tree));
786 subtract = interval_deletion_adjustment (tree->right,
787 relative_position,
788 amount);
789 tree->total_length -= subtract;
790 return subtract;
791 }
792 /* Here -- this node */
793 else
794 {
795 /* If this is a zero-length, marker interval, then
796 we must skip it. */
797
798 if (relative_position == LEFT_TOTAL_LENGTH (tree) + 1)
799 {
800 /* This means we're deleting from the beginning of this interval. */
801 register int my_amount = LENGTH (tree);
802
803 if (amount < my_amount)
804 {
805 tree->total_length -= amount;
806 return amount;
807 }
808 else
809 {
810 tree->total_length -= my_amount;
811 if (LENGTH (tree) != 0)
812 abort (); /* Paranoia */
813
814 delete_interval (tree);
815 return my_amount;
816 }
817 }
818 else /* Deleting starting in the middle. */
819 {
820 register int my_amount = ((tree->total_length
821 - RIGHT_TOTAL_LENGTH (tree))
822 - relative_position + 1);
823
824 if (amount <= my_amount)
825 {
826 tree->total_length -= amount;
827 return amount;
828 }
829 else
830 {
831 tree->total_length -= my_amount;
832 return my_amount;
833 }
834 }
835 }
836
837 /* Never reach here */
838 }
839
840 /* Effect the adjustments necessary to the interval tree of BUFFER
841 to correspond to the deletion of LENGTH characters from that buffer
842 text. The deletion is effected at position START (relative to the
843 buffer). */
844
845 static void
846 adjust_intervals_for_deletion (buffer, start, length)
847 struct buffer *buffer;
848 int start, length;
849 {
850 register int left_to_delete = length;
851 register INTERVAL tree = buffer->intervals;
852 register int deleted;
853
854 if (NULL_INTERVAL_P (tree))
855 return;
856
857 if (length == TOTAL_LENGTH (tree))
858 {
859 buffer->intervals = NULL_INTERVAL;
860 return;
861 }
862
863 if (ONLY_INTERVAL_P (tree))
864 {
865 tree->total_length -= length;
866 return;
867 }
868
869 if (start > TOTAL_LENGTH (tree))
870 start = TOTAL_LENGTH (tree);
871 while (left_to_delete > 0)
872 {
873 left_to_delete -= interval_deletion_adjustment (tree, start,
874 left_to_delete);
875 tree = buffer->intervals;
876 if (left_to_delete == tree->total_length)
877 {
878 buffer->intervals = NULL_INTERVAL;
879 return;
880 }
881 }
882 }
883 \f
884 /* Make the adjustments necessary to the interval tree of BUFFER to
885 represent an addition or deletion of LENGTH characters starting
886 at position START. Addition or deletion is indicated by the sign
887 of LENGTH. */
888
889 INLINE void
890 offset_intervals (buffer, start, length)
891 struct buffer *buffer;
892 int start, length;
893 {
894 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
895 return;
896
897 if (length > 0)
898 adjust_intervals_for_insertion (buffer->intervals, start, length);
899 else
900 adjust_intervals_for_deletion (buffer, start, -length);
901 }
902 \f
903 /* Merge interval I with its lexicographic successor. The resulting
904 interval is returned, and has the properties of the original
905 successor. The properties of I are lost. I is removed from the
906 interval tree.
907
908 IMPORTANT:
909 The caller must verify that this is not the last (rightmost)
910 interval. */
911
912 INTERVAL
913 merge_interval_right (i)
914 register INTERVAL i;
915 {
916 register int absorb = LENGTH (i);
917 register INTERVAL successor;
918
919 /* Zero out this interval. */
920 i->total_length -= absorb;
921
922 /* Find the succeeding interval. */
923 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
924 as we descend. */
925 {
926 successor = i->right;
927 while (! NULL_LEFT_CHILD (successor))
928 {
929 successor->total_length += absorb;
930 successor = successor->left;
931 }
932
933 successor->total_length += absorb;
934 delete_interval (i);
935 return successor;
936 }
937
938 successor = i;
939 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
940 we ascend. */
941 {
942 if (AM_LEFT_CHILD (successor))
943 {
944 successor = successor->parent;
945 delete_interval (i);
946 return successor;
947 }
948
949 successor = successor->parent;
950 successor->total_length -= absorb;
951 }
952
953 /* This must be the rightmost or last interval and cannot
954 be merged right. The caller should have known. */
955 abort ();
956 }
957 \f
958 /* Merge interval I with its lexicographic predecessor. The resulting
959 interval is returned, and has the properties of the original predecessor.
960 The properties of I are lost. Interval node I is removed from the tree.
961
962 IMPORTANT:
963 The caller must verify that this is not the first (leftmost) interval. */
964
965 INTERVAL
966 merge_interval_left (i)
967 register INTERVAL i;
968 {
969 register int absorb = LENGTH (i);
970 register INTERVAL predecessor;
971
972 /* Zero out this interval. */
973 i->total_length -= absorb;
974
975 /* Find the preceding interval. */
976 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
977 adding ABSORB as we go. */
978 {
979 predecessor = i->left;
980 while (! NULL_RIGHT_CHILD (predecessor))
981 {
982 predecessor->total_length += absorb;
983 predecessor = predecessor->right;
984 }
985
986 predecessor->total_length += absorb;
987 delete_interval (i);
988 return predecessor;
989 }
990
991 predecessor = i;
992 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
993 subtracting ABSORB. */
994 {
995 if (AM_RIGHT_CHILD (predecessor))
996 {
997 predecessor = predecessor->parent;
998 delete_interval (i);
999 return predecessor;
1000 }
1001
1002 predecessor = predecessor->parent;
1003 predecessor->total_length -= absorb;
1004 }
1005
1006 /* This must be the leftmost or first interval and cannot
1007 be merged left. The caller should have known. */
1008 abort ();
1009 }
1010 \f
1011 /* Make an exact copy of interval tree SOURCE which descends from
1012 PARENT. This is done by recursing through SOURCE, copying
1013 the current interval and its properties, and then adjusting
1014 the pointers of the copy. */
1015
1016 static INTERVAL
1017 reproduce_tree (source, parent)
1018 INTERVAL source, parent;
1019 {
1020 register INTERVAL t = make_interval ();
1021
1022 bcopy (source, t, INTERVAL_SIZE);
1023 copy_properties (source, t);
1024 t->parent = parent;
1025 if (! NULL_LEFT_CHILD (source))
1026 t->left = reproduce_tree (source->left, t);
1027 if (! NULL_RIGHT_CHILD (source))
1028 t->right = reproduce_tree (source->right, t);
1029
1030 return t;
1031 }
1032
1033 /* Make a new interval of length LENGTH starting at START in the
1034 group of intervals INTERVALS, which is actually an interval tree.
1035 Returns the new interval.
1036
1037 Generate an error if the new positions would overlap an existing
1038 interval. */
1039
1040 static INTERVAL
1041 make_new_interval (intervals, start, length)
1042 INTERVAL intervals;
1043 int start, length;
1044 {
1045 INTERVAL slot;
1046
1047 slot = find_interval (intervals, start);
1048 if (start + length > slot->position + LENGTH (slot))
1049 error ("Interval would overlap");
1050
1051 if (start == slot->position && length == LENGTH (slot))
1052 return slot;
1053
1054 if (slot->position == start)
1055 {
1056 /* New right node. */
1057 split_interval_right (slot, length + 1);
1058 return slot;
1059 }
1060
1061 if (slot->position + LENGTH (slot) == start + length)
1062 {
1063 /* New left node. */
1064 split_interval_left (slot, LENGTH (slot) - length + 1);
1065 return slot;
1066 }
1067
1068 /* Convert interval SLOT into three intervals. */
1069 split_interval_left (slot, start - slot->position + 1);
1070 split_interval_right (slot, length + 1);
1071 return slot;
1072 }
1073 \f
1074 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1075
1076 This is used in insdel.c when inserting Lisp_Strings into
1077 the buffer. The text corresponding to SOURCE is already in
1078 the buffer when this is called. The intervals of new tree are
1079 those belonging to the string being inserted; a copy is not made.
1080
1081 If the inserted text had no intervals associated, this function
1082 simply returns -- offset_intervals should handle placing the
1083 text in the correct interval, depending on the sticky bits.
1084
1085 If the inserted text had properties (intervals), then there are two
1086 cases -- either insertion happened in the middle of some interval,
1087 or between two intervals.
1088
1089 If the text goes into the middle of an interval, then new
1090 intervals are created in the middle with only the properties of
1091 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1092 which case the new text has the union of its properties and those
1093 of the text into which it was inserted.
1094
1095 If the text goes between two intervals, then if neither interval
1096 had its appropriate sticky property set (front_sticky, rear_sticky),
1097 the new text has only its properties. If one of the sticky properties
1098 is set, then the new text "sticks" to that region and its properties
1099 depend on merging as above. If both the preceding and succeeding
1100 intervals to the new text are "sticky", then the new text retains
1101 only its properties, as if neither sticky property were set. Perhaps
1102 we should consider merging all three sets of properties onto the new
1103 text... */
1104
1105 void
1106 graft_intervals_into_buffer (source, position, buffer)
1107 INTERVAL source;
1108 int position;
1109 struct buffer *buffer;
1110 {
1111 register INTERVAL under, over, this, prev;
1112 register INTERVAL tree = buffer->intervals;
1113 int middle;
1114
1115 /* If the new text has no properties, it becomes part of whatever
1116 interval it was inserted into. */
1117 if (NULL_INTERVAL_P (source))
1118 return;
1119
1120 if (NULL_INTERVAL_P (tree))
1121 {
1122 /* The inserted text constitutes the whole buffer, so
1123 simply copy over the interval structure. */
1124 if (BUF_Z (buffer) == TOTAL_LENGTH (source))
1125 {
1126 buffer->intervals = reproduce_tree (source, tree->parent);
1127 /* Explicitly free the old tree here. */
1128
1129 return;
1130 }
1131
1132 /* Create an interval tree in which to place a copy
1133 of the intervals of the inserted string. */
1134 {
1135 Lisp_Object buf;
1136 XSET (buf, Lisp_Buffer, buffer);
1137 tree = create_root_interval (buf);
1138 }
1139 }
1140 else
1141 if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
1142 /* If the buffer contains only the new string, but
1143 there was already some interval tree there, then it may be
1144 some zero length intervals. Eventually, do something clever
1145 about inserting properly. For now, just waste the old intervals. */
1146 {
1147 buffer->intervals = reproduce_tree (source, tree->parent);
1148 /* Explicitly free the old tree here. */
1149
1150 return;
1151 }
1152 else
1153 /* Paranoia -- the text has already been added, so this buffer
1154 should be of non-zero length. */
1155 if (TOTAL_LENGTH (tree) == 0)
1156 abort ();
1157
1158 this = under = find_interval (tree, position);
1159 if (NULL_INTERVAL_P (under)) /* Paranoia */
1160 abort ();
1161 over = find_interval (source, 1);
1162
1163 /* Here for insertion in the middle of an interval.
1164 Split off an equivalent interval to the right,
1165 then don't bother with it any more. */
1166
1167 if (position > under->position)
1168 {
1169 INTERVAL end_unchanged
1170 = split_interval_left (this, position - under->position + 1);
1171 copy_properties (under, end_unchanged);
1172 under->position = position;
1173 prev = 0;
1174 middle = 1;
1175 }
1176 else
1177 {
1178 prev = previous_interval (under);
1179 if (prev && !END_STICKY_P (prev))
1180 prev = 0;
1181 }
1182
1183 /* Insertion is now at beginning of UNDER. */
1184
1185 /* The inserted text "sticks" to the interval `under',
1186 which means it gets those properties. */
1187 while (! NULL_INTERVAL_P (over))
1188 {
1189 position = LENGTH (over) + 1;
1190 if (position < LENGTH (under))
1191 this = split_interval_left (under, position);
1192 else
1193 this = under;
1194 copy_properties (over, this);
1195 /* Insertion at the end of an interval, PREV,
1196 inherits from PREV if PREV is sticky at the end. */
1197 if (prev && ! FRONT_STICKY_P (under)
1198 && MERGE_INSERTIONS (prev))
1199 merge_properties (prev, this);
1200 /* Maybe it inherits from the following interval
1201 if that is sticky at the front. */
1202 else if ((FRONT_STICKY_P (under) || middle)
1203 && MERGE_INSERTIONS (under))
1204 merge_properties (under, this);
1205 over = next_interval (over);
1206 }
1207
1208 buffer->intervals = balance_intervals (buffer->intervals);
1209 return;
1210 }
1211
1212 /* Get the value of property PROP from PLIST,
1213 which is the plist of an interval.
1214 We check for direct properties and for categories with property PROP. */
1215
1216 Lisp_Object
1217 textget (plist, prop)
1218 Lisp_Object plist;
1219 register Lisp_Object prop;
1220 {
1221 register Lisp_Object tail, fallback;
1222 fallback = Qnil;
1223
1224 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1225 {
1226 register Lisp_Object tem;
1227 tem = Fcar (tail);
1228 if (EQ (prop, tem))
1229 return Fcar (Fcdr (tail));
1230 if (EQ (tem, Qcategory))
1231 fallback = Fget (Fcar (Fcdr (tail)), prop);
1232 }
1233
1234 return fallback;
1235 }
1236 \f
1237 /* Set point in BUFFER to POSITION. If the target position is
1238 before an invisible character which is not displayed with a special glyph,
1239 move back to an ok place to display. */
1240
1241 void
1242 set_point (position, buffer)
1243 register int position;
1244 register struct buffer *buffer;
1245 {
1246 register INTERVAL to, from, toprev, fromprev, target;
1247 register int iposition = position;
1248 int buffer_point;
1249 register Lisp_Object obj;
1250 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
1251 int old_position = buffer->text.pt;
1252
1253 if (position == buffer->text.pt)
1254 return;
1255
1256 /* Check this now, before checking if the buffer has any intervals.
1257 That way, we can catch conditions which break this sanity check
1258 whether or not there are intervals in the buffer. */
1259 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1260 abort ();
1261
1262 if (NULL_INTERVAL_P (buffer->intervals))
1263 {
1264 buffer->text.pt = position;
1265 return;
1266 }
1267
1268 /* Position Z is really one past the last char in the buffer. */
1269 if (position == BUF_ZV (buffer))
1270 iposition = position - 1;
1271
1272 /* Set TO to the interval containing the char after POSITION,
1273 and TOPREV to the interval containing the char before POSITION.
1274 Either one may be null. They may be equal. */
1275 to = find_interval (buffer->intervals, iposition);
1276 if (position == BUF_BEGV (buffer))
1277 toprev = 0;
1278 else if (to->position == position)
1279 toprev = previous_interval (to);
1280 else if (iposition != position)
1281 toprev = to, to = 0;
1282 else
1283 toprev = to;
1284
1285 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1286 ? BUF_ZV (buffer) - 1
1287 : BUF_PT (buffer));
1288
1289 /* Set FROM to the interval containing the char after PT,
1290 and FROMPREV to the interval containing the char before PT.
1291 Either one may be null. They may be equal. */
1292 /* We could cache this and save time. */
1293 from = find_interval (buffer->intervals, buffer_point);
1294 if (from->position == BUF_BEGV (buffer))
1295 fromprev = 0;
1296 else if (from->position == BUF_PT (buffer))
1297 fromprev = previous_interval (from);
1298 else if (buffer_point != BUF_PT (buffer))
1299 fromprev = from, from = 0;
1300 else
1301 fromprev = from;
1302
1303 /* Moving within an interval */
1304 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to))
1305 {
1306 buffer->text.pt = position;
1307 return;
1308 }
1309
1310 /* If the new position is before an invisible character,
1311 move forward over all such. */
1312 while (! NULL_INTERVAL_P (to)
1313 && ! INTERVAL_VISIBLE_P (to)
1314 && ! DISPLAY_INVISIBLE_GLYPH (to))
1315 {
1316 toprev = to;
1317 to = next_interval (to);
1318 if (NULL_INTERVAL_P (to))
1319 position = BUF_ZV (buffer);
1320 else
1321 position = to->position;
1322 }
1323
1324 buffer->text.pt = position;
1325
1326 /* We run point-left and point-entered hooks here, iff the
1327 two intervals are not equivalent. These hooks take
1328 (old_point, new_point) as arguments. */
1329 if (! intervals_equal (from, to)
1330 || ! intervals_equal (fromprev, toprev))
1331 {
1332 Lisp_Object leave_after, leave_before, enter_after, enter_before;
1333
1334 if (fromprev)
1335 leave_after = textget (fromprev->plist, Qpoint_left);
1336 else
1337 leave_after = Qnil;
1338 if (from)
1339 leave_before = textget (from->plist, Qpoint_left);
1340 else
1341 leave_before = Qnil;
1342
1343 if (toprev)
1344 enter_after = textget (toprev->plist, Qpoint_entered);
1345 else
1346 enter_after = Qnil;
1347 if (to)
1348 enter_before = textget (to->plist, Qpoint_entered);
1349 else
1350 enter_before = Qnil;
1351
1352 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
1353 call2 (leave_before, old_position, position);
1354 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
1355 call2 (leave_after, old_position, position);
1356
1357 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
1358 call2 (enter_before, old_position, position);
1359 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
1360 call2 (enter_after, old_position, position);
1361 }
1362 }
1363
1364 /* Set point temporarily, without checking any text properties. */
1365
1366 INLINE void
1367 temp_set_point (position, buffer)
1368 int position;
1369 struct buffer *buffer;
1370 {
1371 buffer->text.pt = position;
1372 }
1373 \f
1374 /* Return the proper local map for position POSITION in BUFFER.
1375 Use the map specified by the local-map property, if any.
1376 Otherwise, use BUFFER's local map. */
1377
1378 Lisp_Object
1379 get_local_map (position, buffer)
1380 register int position;
1381 register struct buffer *buffer;
1382 {
1383 register INTERVAL interval;
1384 Lisp_Object prop, tem;
1385
1386 if (NULL_INTERVAL_P (buffer->intervals))
1387 return current_buffer->keymap;
1388
1389 /* Perhaps we should just change `position' to the limit. */
1390 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1391 abort ();
1392
1393 /* Position Z is really one past the last char in the buffer. */
1394 if (position == BUF_ZV (buffer))
1395 return current_buffer->keymap;
1396
1397 interval = find_interval (buffer->intervals, position);
1398 prop = textget (interval->plist, Qlocal_map);
1399 if (NILP (prop))
1400 return current_buffer->keymap;
1401
1402 /* Use the local map only if it is valid. */
1403 tem = Fkeymapp (prop);
1404 if (!NILP (tem))
1405 return prop;
1406
1407 return current_buffer->keymap;
1408 }
1409 \f
1410 /* Call the modification hook functions in LIST, each with START and END. */
1411
1412 static void
1413 call_mod_hooks (list, start, end)
1414 Lisp_Object list, start, end;
1415 {
1416 struct gcpro gcpro1;
1417 GCPRO1 (list);
1418 while (!NILP (list))
1419 {
1420 call2 (Fcar (list), start, end);
1421 list = Fcdr (list);
1422 }
1423 UNGCPRO;
1424 }
1425
1426 /* Check for read-only intervals and signal an error if we find one.
1427 Then check for any modification hooks in the range START up to
1428 (but not including) TO. Create a list of all these hooks in
1429 lexicographic order, eliminating consecutive extra copies of the
1430 same hook. Then call those hooks in order, with START and END - 1
1431 as arguments. */
1432
1433 void
1434 verify_interval_modification (buf, start, end)
1435 struct buffer *buf;
1436 int start, end;
1437 {
1438 register INTERVAL intervals = buf->intervals;
1439 register INTERVAL i, prev;
1440 Lisp_Object hooks;
1441 register Lisp_Object prev_mod_hooks;
1442 Lisp_Object mod_hooks;
1443 struct gcpro gcpro1;
1444
1445 hooks = Qnil;
1446 prev_mod_hooks = Qnil;
1447 mod_hooks = Qnil;
1448
1449 if (NULL_INTERVAL_P (intervals))
1450 return;
1451
1452 if (start > end)
1453 {
1454 int temp = start;
1455 start = end;
1456 end = temp;
1457 }
1458
1459 /* For an insert operation, check the two chars around the position. */
1460 if (start == end)
1461 {
1462 INTERVAL prev;
1463 Lisp_Object before, after;
1464
1465 /* Set I to the interval containing the char after START,
1466 and PREV to the interval containing the char before START.
1467 Either one may be null. They may be equal. */
1468 i = find_interval (intervals,
1469 (start == BUF_ZV (buf) ? start - 1 : start));
1470
1471 if (start == BUF_BEGV (buf))
1472 prev = 0;
1473 if (i->position == start)
1474 prev = previous_interval (i);
1475 else if (i->position < start)
1476 prev = i;
1477 if (start == BUF_ZV (buf))
1478 i = 0;
1479
1480 if (NULL_INTERVAL_P (prev))
1481 {
1482 if (! INTERVAL_WRITABLE_P (i))
1483 error ("Attempt to insert within read-only text");
1484 }
1485 else if (NULL_INTERVAL_P (i))
1486 {
1487 if (! INTERVAL_WRITABLE_P (prev))
1488 error ("Attempt to insert within read-only text");
1489 }
1490 else
1491 {
1492 before = textget (prev->plist, Qread_only);
1493 after = textget (i->plist, Qread_only);
1494 if (! NILP (before) && EQ (before, after)
1495 /* This checks Vinhibit_read_only properly
1496 for the common value of the read-only property. */
1497 && ! INTERVAL_WRITABLE_P (i))
1498 error ("Attempt to insert within read-only text");
1499 }
1500
1501 /* Run both mod hooks (just once if they're the same). */
1502 if (!NULL_INTERVAL_P (prev))
1503 prev_mod_hooks = textget (prev->plist, Qmodification_hooks);
1504 if (!NULL_INTERVAL_P (i))
1505 mod_hooks = textget (i->plist, Qmodification_hooks);
1506 GCPRO1 (mod_hooks);
1507 if (! NILP (prev_mod_hooks))
1508 call_mod_hooks (prev_mod_hooks, make_number (start),
1509 make_number (end));
1510 UNGCPRO;
1511 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1512 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
1513 }
1514 else
1515 {
1516 /* Loop over intervals on or next to START...END,
1517 collecting their hooks. */
1518
1519 i = find_interval (intervals, start);
1520 do
1521 {
1522 if (! INTERVAL_WRITABLE_P (i))
1523 error ("Attempt to modify read-only text");
1524
1525 mod_hooks = textget (i->plist, Qmodification_hooks);
1526 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1527 {
1528 hooks = Fcons (mod_hooks, hooks);
1529 prev_mod_hooks = mod_hooks;
1530 }
1531
1532 i = next_interval (i);
1533 }
1534 /* Keep going thru the interval containing the char before END. */
1535 while (! NULL_INTERVAL_P (i) && i->position < end);
1536
1537 GCPRO1 (hooks);
1538 hooks = Fnreverse (hooks);
1539 while (! EQ (hooks, Qnil))
1540 {
1541 call_mod_hooks (Fcar (hooks), make_number (start),
1542 make_number (end));
1543 hooks = Fcdr (hooks);
1544 }
1545 UNGCPRO;
1546 }
1547 }
1548
1549 /* Balance an interval node if the amount of text in its left and right
1550 subtrees differs by more than the percentage specified by
1551 `interval-balance-threshold'. */
1552
1553 static INTERVAL
1554 balance_an_interval (i)
1555 INTERVAL i;
1556 {
1557 register int total_children_size = (LEFT_TOTAL_LENGTH (i)
1558 + RIGHT_TOTAL_LENGTH (i));
1559 register int threshold = (XFASTINT (interval_balance_threshold)
1560 * (total_children_size / 100));
1561
1562 /* Balance within each side. */
1563 balance_intervals (i->left);
1564 balance_intervals (i->right);
1565
1566 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1567 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1568 {
1569 i = rotate_right (i);
1570 /* If that made it unbalanced the other way, take it back. */
1571 if (RIGHT_TOTAL_LENGTH (i) > LEFT_TOTAL_LENGTH (i)
1572 && (RIGHT_TOTAL_LENGTH (i) - LEFT_TOTAL_LENGTH (i)) > threshold)
1573 return rotate_left (i);
1574 return i;
1575 }
1576
1577 if (RIGHT_TOTAL_LENGTH (i) > LEFT_TOTAL_LENGTH (i)
1578 && (RIGHT_TOTAL_LENGTH (i) - LEFT_TOTAL_LENGTH (i)) > threshold)
1579 {
1580 i = rotate_left (i);
1581 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1582 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1583 return rotate_right (i);
1584 return i;
1585 }
1586
1587 return i;
1588 }
1589
1590 /* Balance the interval tree TREE. Balancing is by weight
1591 (the amount of text). */
1592
1593 INTERVAL
1594 balance_intervals (tree)
1595 register INTERVAL tree;
1596 {
1597 register INTERVAL new_tree;
1598
1599 if (NULL_INTERVAL_P (tree))
1600 return NULL_INTERVAL;
1601
1602 new_tree = tree;
1603 do
1604 {
1605 tree = new_tree;
1606 new_tree = balance_an_interval (new_tree);
1607 }
1608 while (new_tree != tree);
1609
1610 return new_tree;
1611 }
1612
1613 /* Produce an interval tree reflecting the intervals in
1614 TREE from START to START + LENGTH. */
1615
1616 INTERVAL
1617 copy_intervals (tree, start, length)
1618 INTERVAL tree;
1619 int start, length;
1620 {
1621 register INTERVAL i, new, t;
1622 register int got, prevlen;
1623
1624 if (NULL_INTERVAL_P (tree) || length <= 0)
1625 return NULL_INTERVAL;
1626
1627 i = find_interval (tree, start);
1628 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1629 abort ();
1630
1631 /* If there is only one interval and it's the default, return nil. */
1632 if ((start - i->position + 1 + length) < LENGTH (i)
1633 && DEFAULT_INTERVAL_P (i))
1634 return NULL_INTERVAL;
1635
1636 new = make_interval ();
1637 new->position = 1;
1638 got = (LENGTH (i) - (start - i->position));
1639 new->total_length = length;
1640 copy_properties (i, new);
1641
1642 t = new;
1643 prevlen = got;
1644 while (got < length)
1645 {
1646 i = next_interval (i);
1647 t = split_interval_right (t, prevlen + 1);
1648 copy_properties (i, t);
1649 prevlen = LENGTH (i);
1650 got += prevlen;
1651 }
1652
1653 return balance_intervals (new);
1654 }
1655
1656 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1657
1658 INLINE void
1659 copy_intervals_to_string (string, buffer, position, length)
1660 Lisp_Object string, buffer;
1661 int position, length;
1662 {
1663 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
1664 position, length);
1665 if (NULL_INTERVAL_P (interval_copy))
1666 return;
1667
1668 interval_copy->parent = (INTERVAL) string;
1669 XSTRING (string)->intervals = interval_copy;
1670 }
1671
1672 #endif /* USE_TEXT_PROPERTIES */