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