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