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