Auto-commit of generated files.
[emacs.git] / src / intervals.c
blob15dd67d06cb0aa8b5fbd68d56d8ee4d23ec1f827
1 /* Code for doing intervals.
2 Copyright (C) 1993-1995, 1997-1998, 2001-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* NOTES:
22 Have to ensure that we can't put symbol nil on a plist, or some
23 functions may work incorrectly.
25 An idea: Have the owner of the tree keep count of splits and/or
26 insertion lengths (in intervals), and balance after every N.
28 Need to call *_left_hook when buffer is killed.
30 Scan for zero-length, or 0-length to see notes about handling
31 zero length interval-markers.
33 There are comments around about freeing intervals. It might be
34 faster to explicitly free them (put them on the free list) than
35 to GC them.
40 #include <config.h>
41 #include <setjmp.h>
42 #include <intprops.h>
43 #include "lisp.h"
44 #include "intervals.h"
45 #include "character.h"
46 #include "buffer.h"
47 #include "puresize.h"
48 #include "keyboard.h"
49 #include "keymap.h"
51 /* Test for membership, allowing for t (actually any non-cons) to mean the
52 universal set. */
54 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
56 static Lisp_Object merge_properties_sticky (Lisp_Object, Lisp_Object);
57 static INTERVAL merge_interval_right (INTERVAL);
58 static INTERVAL reproduce_tree (INTERVAL, INTERVAL);
59 static INTERVAL reproduce_tree_obj (INTERVAL, Lisp_Object);
61 /* Utility functions for intervals. */
64 /* Create the root interval of some object, a buffer or string. */
66 INTERVAL
67 create_root_interval (Lisp_Object parent)
69 INTERVAL new;
71 CHECK_IMPURE (parent);
73 new = make_interval ();
75 if (BUFFERP (parent))
77 new->total_length = (BUF_Z (XBUFFER (parent))
78 - BUF_BEG (XBUFFER (parent)));
79 eassert (0 <= TOTAL_LENGTH (new));
80 buffer_set_intervals (XBUFFER (parent), new);
81 new->position = BEG;
83 else if (STRINGP (parent))
85 new->total_length = SCHARS (parent);
86 eassert (0 <= TOTAL_LENGTH (new));
87 string_set_intervals (parent, new);
88 new->position = 0;
91 interval_set_object (new, parent);
93 return new;
96 /* Make the interval TARGET have exactly the properties of SOURCE */
98 void
99 copy_properties (register INTERVAL source, register INTERVAL target)
101 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
102 return;
104 COPY_INTERVAL_CACHE (source, target);
105 interval_set_plist (target, Fcopy_sequence (source->plist));
108 /* Merge the properties of interval SOURCE into the properties
109 of interval TARGET. That is to say, each property in SOURCE
110 is added to TARGET if TARGET has no such property as yet. */
112 static void
113 merge_properties (register INTERVAL source, register INTERVAL target)
115 register Lisp_Object o, sym, val;
117 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
118 return;
120 MERGE_INTERVAL_CACHE (source, target);
122 o = source->plist;
123 while (CONSP (o))
125 sym = XCAR (o);
126 o = XCDR (o);
127 CHECK_CONS (o);
129 val = target->plist;
130 while (CONSP (val) && !EQ (XCAR (val), sym))
132 val = XCDR (val);
133 if (!CONSP (val))
134 break;
135 val = XCDR (val);
138 if (NILP (val))
140 val = XCAR (o);
141 interval_set_plist (target, Fcons (sym, Fcons (val, target->plist)));
143 o = XCDR (o);
147 /* Return 1 if the two intervals have the same properties,
148 0 otherwise. */
151 intervals_equal (INTERVAL i0, INTERVAL i1)
153 register Lisp_Object i0_cdr, i0_sym;
154 register Lisp_Object i1_cdr, i1_val;
156 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
157 return 1;
159 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
160 return 0;
162 i0_cdr = i0->plist;
163 i1_cdr = i1->plist;
164 while (CONSP (i0_cdr) && CONSP (i1_cdr))
166 i0_sym = XCAR (i0_cdr);
167 i0_cdr = XCDR (i0_cdr);
168 if (!CONSP (i0_cdr))
169 return 0; /* abort (); */
170 i1_val = i1->plist;
171 while (CONSP (i1_val) && !EQ (XCAR (i1_val), i0_sym))
173 i1_val = XCDR (i1_val);
174 if (!CONSP (i1_val))
175 return 0; /* abort (); */
176 i1_val = XCDR (i1_val);
179 /* i0 has something i1 doesn't. */
180 if (EQ (i1_val, Qnil))
181 return 0;
183 /* i0 and i1 both have sym, but it has different values in each. */
184 if (!CONSP (i1_val)
185 || (i1_val = XCDR (i1_val), !CONSP (i1_val))
186 || !EQ (XCAR (i1_val), XCAR (i0_cdr)))
187 return 0;
189 i0_cdr = XCDR (i0_cdr);
191 i1_cdr = XCDR (i1_cdr);
192 if (!CONSP (i1_cdr))
193 return 0; /* abort (); */
194 i1_cdr = XCDR (i1_cdr);
197 /* Lengths of the two plists were equal. */
198 return (NILP (i0_cdr) && NILP (i1_cdr));
202 /* Traverse an interval tree TREE, performing FUNCTION on each node.
203 No guarantee is made about the order of traversal.
204 Pass FUNCTION two args: an interval, and ARG. */
206 void
207 traverse_intervals_noorder (INTERVAL tree, void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
209 /* Minimize stack usage. */
210 while (tree)
212 (*function) (tree, arg);
213 if (!tree->right)
214 tree = tree->left;
215 else
217 traverse_intervals_noorder (tree->left, function, arg);
218 tree = tree->right;
223 /* Traverse an interval tree TREE, performing FUNCTION on each node.
224 Pass FUNCTION two args: an interval, and ARG. */
226 void
227 traverse_intervals (INTERVAL tree, ptrdiff_t position,
228 void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
230 while (tree)
232 traverse_intervals (tree->left, position, function, arg);
233 position += LEFT_TOTAL_LENGTH (tree);
234 tree->position = position;
235 (*function) (tree, arg);
236 position += LENGTH (tree); tree = tree->right;
240 #if 0
242 static int icount;
243 static int idepth;
244 static int zero_length;
246 /* These functions are temporary, for debugging purposes only. */
248 INTERVAL search_interval, found_interval;
250 void
251 check_for_interval (INTERVAL i)
253 if (i == search_interval)
255 found_interval = i;
256 icount++;
260 INTERVAL
261 search_for_interval (INTERVAL i, INTERVAL tree)
263 icount = 0;
264 search_interval = i;
265 found_interval = NULL;
266 traverse_intervals_noorder (tree, &check_for_interval, Qnil);
267 return found_interval;
270 static void
271 inc_interval_count (INTERVAL i)
273 icount++;
274 if (LENGTH (i) == 0)
275 zero_length++;
276 if (depth > idepth)
277 idepth = depth;
281 count_intervals (INTERVAL i)
283 icount = 0;
284 idepth = 0;
285 zero_length = 0;
286 traverse_intervals_noorder (i, &inc_interval_count, Qnil);
288 return icount;
291 static INTERVAL
292 root_interval (INTERVAL interval)
294 register INTERVAL i = interval;
296 while (! ROOT_INTERVAL_P (i))
297 i = INTERVAL_PARENT (i);
299 return i;
301 #endif
303 /* Assuming that a left child exists, perform the following operation:
306 / \ / \
307 B => A
308 / \ / \
312 static inline INTERVAL
313 rotate_right (INTERVAL interval)
315 INTERVAL i;
316 INTERVAL B = interval->left;
317 ptrdiff_t old_total = interval->total_length;
319 /* Deal with any Parent of A; make it point to B. */
320 if (! ROOT_INTERVAL_P (interval))
322 if (AM_LEFT_CHILD (interval))
323 interval_set_left (INTERVAL_PARENT (interval), B);
324 else
325 interval_set_right (INTERVAL_PARENT (interval), B);
327 interval_copy_parent (B, interval);
329 /* Make B the parent of A */
330 i = B->right;
331 interval_set_right (B, interval);
332 interval_set_parent (interval, B);
334 /* Make A point to c */
335 interval_set_left (interval, i);
336 if (i)
337 interval_set_parent (i, interval);
339 /* A's total length is decreased by the length of B and its left child. */
340 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
341 eassert (0 <= TOTAL_LENGTH (interval));
343 /* B must have the same total length of A. */
344 B->total_length = old_total;
345 eassert (0 <= TOTAL_LENGTH (B));
347 return B;
350 /* Assuming that a right child exists, perform the following operation:
353 / \ / \
354 B => A
355 / \ / \
359 static inline INTERVAL
360 rotate_left (INTERVAL interval)
362 INTERVAL i;
363 INTERVAL B = interval->right;
364 ptrdiff_t old_total = interval->total_length;
366 /* Deal with any parent of A; make it point to B. */
367 if (! ROOT_INTERVAL_P (interval))
369 if (AM_LEFT_CHILD (interval))
370 interval_set_left (INTERVAL_PARENT (interval), B);
371 else
372 interval_set_right (INTERVAL_PARENT (interval), B);
374 interval_copy_parent (B, interval);
376 /* Make B the parent of A */
377 i = B->left;
378 interval_set_left (B, interval);
379 interval_set_parent (interval, B);
381 /* Make A point to c */
382 interval_set_right (interval, i);
383 if (i)
384 interval_set_parent (i, interval);
386 /* A's total length is decreased by the length of B and its right child. */
387 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
388 eassert (0 <= TOTAL_LENGTH (interval));
390 /* B must have the same total length of A. */
391 B->total_length = old_total;
392 eassert (0 <= TOTAL_LENGTH (B));
394 return B;
397 /* Balance an interval tree with the assumption that the subtrees
398 themselves are already balanced. */
400 static INTERVAL
401 balance_an_interval (INTERVAL i)
403 register ptrdiff_t old_diff, new_diff;
405 while (1)
407 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
408 if (old_diff > 0)
410 /* Since the left child is longer, there must be one. */
411 new_diff = i->total_length - i->left->total_length
412 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
413 if (eabs (new_diff) >= old_diff)
414 break;
415 i = rotate_right (i);
416 balance_an_interval (i->right);
418 else if (old_diff < 0)
420 /* Since the right child is longer, there must be one. */
421 new_diff = i->total_length - i->right->total_length
422 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
423 if (eabs (new_diff) >= -old_diff)
424 break;
425 i = rotate_left (i);
426 balance_an_interval (i->left);
428 else
429 break;
431 return i;
434 /* Balance INTERVAL, potentially stuffing it back into its parent
435 Lisp Object. */
437 static inline INTERVAL
438 balance_possible_root_interval (register INTERVAL interval)
440 Lisp_Object parent;
441 int have_parent = 0;
443 if (!INTERVAL_HAS_OBJECT (interval) && !INTERVAL_HAS_PARENT (interval))
444 return interval;
446 if (INTERVAL_HAS_OBJECT (interval))
448 have_parent = 1;
449 GET_INTERVAL_OBJECT (parent, interval);
451 interval = balance_an_interval (interval);
453 if (have_parent)
455 if (BUFFERP (parent))
456 buffer_set_intervals (XBUFFER (parent), interval);
457 else if (STRINGP (parent))
458 string_set_intervals (parent, interval);
461 return interval;
464 /* Balance the interval tree TREE. Balancing is by weight
465 (the amount of text). */
467 static INTERVAL
468 balance_intervals_internal (register INTERVAL tree)
470 /* Balance within each side. */
471 if (tree->left)
472 balance_intervals_internal (tree->left);
473 if (tree->right)
474 balance_intervals_internal (tree->right);
475 return balance_an_interval (tree);
478 /* Advertised interface to balance intervals. */
480 INTERVAL
481 balance_intervals (INTERVAL tree)
483 return tree ? balance_intervals_internal (tree) : NULL;
486 /* Rebalance text properties of B. */
488 static void
489 buffer_balance_intervals (struct buffer *b)
491 INTERVAL i;
493 eassert (b != NULL);
494 i = buffer_get_intervals (b);
495 if (i)
496 buffer_set_intervals (b, balance_an_interval (i));
499 /* Split INTERVAL into two pieces, starting the second piece at
500 character position OFFSET (counting from 0), relative to INTERVAL.
501 INTERVAL becomes the left-hand piece, and the right-hand piece
502 (second, lexicographically) is returned.
504 The size and position fields of the two intervals are set based upon
505 those of the original interval. The property list of the new interval
506 is reset, thus it is up to the caller to do the right thing with the
507 result.
509 Note that this does not change the position of INTERVAL; if it is a root,
510 it is still a root after this operation. */
512 INTERVAL
513 split_interval_right (INTERVAL interval, ptrdiff_t offset)
515 INTERVAL new = make_interval ();
516 ptrdiff_t position = interval->position;
517 ptrdiff_t new_length = LENGTH (interval) - offset;
519 new->position = position + offset;
520 interval_set_parent (new, interval);
522 if (NULL_RIGHT_CHILD (interval))
524 interval_set_right (interval, new);
525 new->total_length = new_length;
526 eassert (0 <= TOTAL_LENGTH (new));
528 else
530 /* Insert the new node between INTERVAL and its right child. */
531 interval_set_right (new, interval->right);
532 interval_set_parent (interval->right, new);
533 interval_set_right (interval, new);
534 new->total_length = new_length + new->right->total_length;
535 eassert (0 <= TOTAL_LENGTH (new));
536 balance_an_interval (new);
539 balance_possible_root_interval (interval);
541 return new;
544 /* Split INTERVAL into two pieces, starting the second piece at
545 character position OFFSET (counting from 0), relative to INTERVAL.
546 INTERVAL becomes the right-hand piece, and the left-hand piece
547 (first, lexicographically) is returned.
549 The size and position fields of the two intervals are set based upon
550 those of the original interval. The property list of the new interval
551 is reset, thus it is up to the caller to do the right thing with the
552 result.
554 Note that this does not change the position of INTERVAL; if it is a root,
555 it is still a root after this operation. */
557 INTERVAL
558 split_interval_left (INTERVAL interval, ptrdiff_t offset)
560 INTERVAL new = make_interval ();
561 ptrdiff_t new_length = offset;
563 new->position = interval->position;
564 interval->position = interval->position + offset;
565 interval_set_parent (new, interval);
567 if (NULL_LEFT_CHILD (interval))
569 interval_set_left (interval, new);
570 new->total_length = new_length;
571 eassert (0 <= TOTAL_LENGTH (new));
573 else
575 /* Insert the new node between INTERVAL and its left child. */
576 interval_set_left (new, interval->left);
577 interval_set_parent (new->left, new);
578 interval_set_left (interval, new);
579 new->total_length = new_length + new->left->total_length;
580 eassert (0 <= TOTAL_LENGTH (new));
581 balance_an_interval (new);
584 balance_possible_root_interval (interval);
586 return new;
589 /* Return the proper position for the first character
590 described by the interval tree SOURCE.
591 This is 1 if the parent is a buffer,
592 0 if the parent is a string or if there is no parent.
594 Don't use this function on an interval which is the child
595 of another interval! */
597 static int
598 interval_start_pos (INTERVAL source)
600 Lisp_Object parent;
602 if (!source)
603 return 0;
605 if (! INTERVAL_HAS_OBJECT (source))
606 return 0;
607 GET_INTERVAL_OBJECT (parent, source);
608 if (BUFFERP (parent))
609 return BUF_BEG (XBUFFER (parent));
610 return 0;
613 /* Find the interval containing text position POSITION in the text
614 represented by the interval tree TREE. POSITION is a buffer
615 position (starting from 1) or a string index (starting from 0).
616 If POSITION is at the end of the buffer or string,
617 return the interval containing the last character.
619 The `position' field, which is a cache of an interval's position,
620 is updated in the interval found. Other functions (e.g., next_interval)
621 will update this cache based on the result of find_interval. */
623 INTERVAL
624 find_interval (register INTERVAL tree, register ptrdiff_t position)
626 /* The distance from the left edge of the subtree at TREE
627 to POSITION. */
628 register ptrdiff_t relative_position;
630 if (!tree)
631 return NULL;
633 relative_position = position;
634 if (INTERVAL_HAS_OBJECT (tree))
636 Lisp_Object parent;
637 GET_INTERVAL_OBJECT (parent, tree);
638 if (BUFFERP (parent))
639 relative_position -= BUF_BEG (XBUFFER (parent));
642 eassert (relative_position <= TOTAL_LENGTH (tree));
644 if (!handling_signal)
645 tree = balance_possible_root_interval (tree);
647 while (1)
649 if (relative_position < LEFT_TOTAL_LENGTH (tree))
651 tree = tree->left;
653 else if (! NULL_RIGHT_CHILD (tree)
654 && relative_position >= (TOTAL_LENGTH (tree)
655 - RIGHT_TOTAL_LENGTH (tree)))
657 relative_position -= (TOTAL_LENGTH (tree)
658 - RIGHT_TOTAL_LENGTH (tree));
659 tree = tree->right;
661 else
663 tree->position
664 = (position - relative_position /* left edge of *tree. */
665 + LEFT_TOTAL_LENGTH (tree)); /* left edge of this interval. */
667 return tree;
672 /* Find the succeeding interval (lexicographically) to INTERVAL.
673 Sets the `position' field based on that of INTERVAL (see
674 find_interval). */
676 INTERVAL
677 next_interval (register INTERVAL interval)
679 register INTERVAL i = interval;
680 register ptrdiff_t next_position;
682 if (!i)
683 return NULL;
684 next_position = interval->position + LENGTH (interval);
686 if (! NULL_RIGHT_CHILD (i))
688 i = i->right;
689 while (! NULL_LEFT_CHILD (i))
690 i = i->left;
692 i->position = next_position;
693 return i;
696 while (! NULL_PARENT (i))
698 if (AM_LEFT_CHILD (i))
700 i = INTERVAL_PARENT (i);
701 i->position = next_position;
702 return i;
705 i = INTERVAL_PARENT (i);
708 return NULL;
711 /* Find the preceding interval (lexicographically) to INTERVAL.
712 Sets the `position' field based on that of INTERVAL (see
713 find_interval). */
715 INTERVAL
716 previous_interval (register INTERVAL interval)
718 register INTERVAL i;
720 if (!interval)
721 return NULL;
723 if (! NULL_LEFT_CHILD (interval))
725 i = interval->left;
726 while (! NULL_RIGHT_CHILD (i))
727 i = i->right;
729 i->position = interval->position - LENGTH (i);
730 return i;
733 i = interval;
734 while (! NULL_PARENT (i))
736 if (AM_RIGHT_CHILD (i))
738 i = INTERVAL_PARENT (i);
740 i->position = interval->position - LENGTH (i);
741 return i;
743 i = INTERVAL_PARENT (i);
746 return NULL;
749 /* Find the interval containing POS given some non-NULL INTERVAL
750 in the same tree. Note that we need to update interval->position
751 if we go down the tree.
752 To speed up the process, we assume that the ->position of
753 I and all its parents is already uptodate. */
754 INTERVAL
755 update_interval (register INTERVAL i, ptrdiff_t pos)
757 if (!i)
758 return NULL;
760 while (1)
762 if (pos < i->position)
764 /* Move left. */
765 if (pos >= i->position - TOTAL_LENGTH (i->left))
767 i->left->position = i->position - TOTAL_LENGTH (i->left)
768 + LEFT_TOTAL_LENGTH (i->left);
769 i = i->left; /* Move to the left child */
771 else if (NULL_PARENT (i))
772 error ("Point before start of properties");
773 else
774 i = INTERVAL_PARENT (i);
775 continue;
777 else if (pos >= INTERVAL_LAST_POS (i))
779 /* Move right. */
780 if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right))
782 i->right->position = INTERVAL_LAST_POS (i)
783 + LEFT_TOTAL_LENGTH (i->right);
784 i = i->right; /* Move to the right child */
786 else if (NULL_PARENT (i))
787 error ("Point %"pD"d after end of properties", pos);
788 else
789 i = INTERVAL_PARENT (i);
790 continue;
792 else
793 return i;
797 /* Effect an adjustment corresponding to the addition of LENGTH characters
798 of text. Do this by finding the interval containing POSITION in the
799 interval tree TREE, and then adjusting all of its ancestors by adding
800 LENGTH to them.
802 If POSITION is the first character of an interval, meaning that point
803 is actually between the two intervals, make the new text belong to
804 the interval which is "sticky".
806 If both intervals are "sticky", then make them belong to the left-most
807 interval. Another possibility would be to create a new interval for
808 this text, and make it have the merged properties of both ends. */
810 static INTERVAL
811 adjust_intervals_for_insertion (INTERVAL tree,
812 ptrdiff_t position, ptrdiff_t length)
814 register INTERVAL i;
815 register INTERVAL temp;
816 int eobp = 0;
817 Lisp_Object parent;
818 ptrdiff_t offset;
820 eassert (TOTAL_LENGTH (tree) > 0);
822 GET_INTERVAL_OBJECT (parent, tree);
823 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
825 /* If inserting at point-max of a buffer, that position will be out
826 of range. Remember that buffer positions are 1-based. */
827 if (position >= TOTAL_LENGTH (tree) + offset)
829 position = TOTAL_LENGTH (tree) + offset;
830 eobp = 1;
833 i = find_interval (tree, position);
835 /* If in middle of an interval which is not sticky either way,
836 we must not just give its properties to the insertion.
837 So split this interval at the insertion point.
839 Originally, the if condition here was this:
840 (! (position == i->position || eobp)
841 && END_NONSTICKY_P (i)
842 && FRONT_NONSTICKY_P (i))
843 But, these macros are now unreliable because of introduction of
844 Vtext_property_default_nonsticky. So, we always check properties
845 one by one if POSITION is in middle of an interval. */
846 if (! (position == i->position || eobp))
848 Lisp_Object tail;
849 Lisp_Object front, rear;
851 tail = i->plist;
853 /* Properties font-sticky and rear-nonsticky override
854 Vtext_property_default_nonsticky. So, if they are t, we can
855 skip one by one checking of properties. */
856 rear = textget (i->plist, Qrear_nonsticky);
857 if (! CONSP (rear) && ! NILP (rear))
859 /* All properties are nonsticky. We split the interval. */
860 goto check_done;
862 front = textget (i->plist, Qfront_sticky);
863 if (! CONSP (front) && ! NILP (front))
865 /* All properties are sticky. We don't split the interval. */
866 tail = Qnil;
867 goto check_done;
870 /* Does any actual property pose an actual problem? We break
871 the loop if we find a nonsticky property. */
872 for (; CONSP (tail); tail = Fcdr (XCDR (tail)))
874 Lisp_Object prop, tmp;
875 prop = XCAR (tail);
877 /* Is this particular property front-sticky? */
878 if (CONSP (front) && ! NILP (Fmemq (prop, front)))
879 continue;
881 /* Is this particular property rear-nonsticky? */
882 if (CONSP (rear) && ! NILP (Fmemq (prop, rear)))
883 break;
885 /* Is this particular property recorded as sticky or
886 nonsticky in Vtext_property_default_nonsticky? */
887 tmp = Fassq (prop, Vtext_property_default_nonsticky);
888 if (CONSP (tmp))
890 if (NILP (tmp))
891 continue;
892 break;
895 /* By default, a text property is rear-sticky, thus we
896 continue the loop. */
899 check_done:
900 /* If any property is a real problem, split the interval. */
901 if (! NILP (tail))
903 temp = split_interval_right (i, position - i->position);
904 copy_properties (i, temp);
905 i = temp;
909 /* If we are positioned between intervals, check the stickiness of
910 both of them. We have to do this too, if we are at BEG or Z. */
911 if (position == i->position || eobp)
913 register INTERVAL prev;
915 if (position == BEG)
916 prev = 0;
917 else if (eobp)
919 prev = i;
920 i = 0;
922 else
923 prev = previous_interval (i);
925 /* Even if we are positioned between intervals, we default
926 to the left one if it exists. We extend it now and split
927 off a part later, if stickiness demands it. */
928 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
930 temp->total_length += length;
931 eassert (0 <= TOTAL_LENGTH (temp));
932 temp = balance_possible_root_interval (temp);
935 /* If at least one interval has sticky properties,
936 we check the stickiness property by property.
938 Originally, the if condition here was this:
939 (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
940 But, these macros are now unreliable because of introduction
941 of Vtext_property_default_nonsticky. So, we always have to
942 check stickiness of properties one by one. If cache of
943 stickiness is implemented in the future, we may be able to
944 use those macros again. */
945 if (1)
947 Lisp_Object pleft, pright;
948 struct interval newi;
950 RESET_INTERVAL (&newi);
951 pleft = prev ? prev->plist : Qnil;
952 pright = i ? i->plist : Qnil;
953 interval_set_plist (&newi, merge_properties_sticky (pleft, pright));
955 if (! prev) /* i.e. position == BEG */
957 if (! intervals_equal (i, &newi))
959 i = split_interval_left (i, length);
960 interval_set_plist (i, newi.plist);
963 else if (! intervals_equal (prev, &newi))
965 prev = split_interval_right (prev, position - prev->position);
966 interval_set_plist (prev, newi.plist);
967 if (i && intervals_equal (prev, i))
968 merge_interval_right (prev);
971 /* We will need to update the cache here later. */
973 else if (! prev && ! NILP (i->plist))
975 /* Just split off a new interval at the left.
976 Since I wasn't front-sticky, the empty plist is ok. */
977 i = split_interval_left (i, length);
981 /* Otherwise just extend the interval. */
982 else
984 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
986 temp->total_length += length;
987 eassert (0 <= TOTAL_LENGTH (temp));
988 temp = balance_possible_root_interval (temp);
992 return tree;
995 /* Any property might be front-sticky on the left, rear-sticky on the left,
996 front-sticky on the right, or rear-sticky on the right; the 16 combinations
997 can be arranged in a matrix with rows denoting the left conditions and
998 columns denoting the right conditions:
999 _ __ _
1000 _ FR FR FR FR
1001 FR__ 0 1 2 3
1002 _FR 4 5 6 7
1003 FR 8 9 A B
1004 FR C D E F
1006 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
1007 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
1008 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
1009 p8 L p9 L pa L pb L pc L pd L pe L pf L)
1010 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
1011 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
1012 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
1013 p8 R p9 R pa R pb R pc R pd R pe R pf R)
1015 We inherit from whoever has a sticky side facing us. If both sides
1016 do (cases 2, 3, E, and F), then we inherit from whichever side has a
1017 non-nil value for the current property. If both sides do, then we take
1018 from the left.
1020 When we inherit a property, we get its stickiness as well as its value.
1021 So, when we merge the above two lists, we expect to get this:
1023 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
1024 rear-nonsticky (p6 pa)
1025 p0 L p1 L p2 L p3 L p6 R p7 R
1026 pa R pb R pc L pd L pe L pf L)
1028 The optimizable special cases are:
1029 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
1030 left rear-nonsticky = t, right front-sticky = t (inherit right)
1031 left rear-nonsticky = t, right front-sticky = nil (inherit none)
1034 static Lisp_Object
1035 merge_properties_sticky (Lisp_Object pleft, Lisp_Object pright)
1037 register Lisp_Object props, front, rear;
1038 Lisp_Object lfront, lrear, rfront, rrear;
1039 register Lisp_Object tail1, tail2, sym, lval, rval, cat;
1040 int use_left, use_right;
1041 int lpresent;
1043 props = Qnil;
1044 front = Qnil;
1045 rear = Qnil;
1046 lfront = textget (pleft, Qfront_sticky);
1047 lrear = textget (pleft, Qrear_nonsticky);
1048 rfront = textget (pright, Qfront_sticky);
1049 rrear = textget (pright, Qrear_nonsticky);
1051 /* Go through each element of PRIGHT. */
1052 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1054 Lisp_Object tmp;
1056 sym = XCAR (tail1);
1058 /* Sticky properties get special treatment. */
1059 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1060 continue;
1062 rval = Fcar (XCDR (tail1));
1063 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1064 if (EQ (sym, XCAR (tail2)))
1065 break;
1067 /* Indicate whether the property is explicitly defined on the left.
1068 (We know it is defined explicitly on the right
1069 because otherwise we don't get here.) */
1070 lpresent = ! NILP (tail2);
1071 lval = (NILP (tail2) ? Qnil : Fcar (Fcdr (tail2)));
1073 /* Even if lrear or rfront say nothing about the stickiness of
1074 SYM, Vtext_property_default_nonsticky may give default
1075 stickiness to SYM. */
1076 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1077 use_left = (lpresent
1078 && ! (TMEM (sym, lrear)
1079 || (CONSP (tmp) && ! NILP (XCDR (tmp)))));
1080 use_right = (TMEM (sym, rfront)
1081 || (CONSP (tmp) && NILP (XCDR (tmp))));
1082 if (use_left && use_right)
1084 if (NILP (lval))
1085 use_left = 0;
1086 else if (NILP (rval))
1087 use_right = 0;
1089 if (use_left)
1091 /* We build props as (value sym ...) rather than (sym value ...)
1092 because we plan to nreverse it when we're done. */
1093 props = Fcons (lval, Fcons (sym, props));
1094 if (TMEM (sym, lfront))
1095 front = Fcons (sym, front);
1096 if (TMEM (sym, lrear))
1097 rear = Fcons (sym, rear);
1099 else if (use_right)
1101 props = Fcons (rval, Fcons (sym, props));
1102 if (TMEM (sym, rfront))
1103 front = Fcons (sym, front);
1104 if (TMEM (sym, rrear))
1105 rear = Fcons (sym, rear);
1109 /* Now go through each element of PLEFT. */
1110 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1112 Lisp_Object tmp;
1114 sym = XCAR (tail2);
1116 /* Sticky properties get special treatment. */
1117 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1118 continue;
1120 /* If sym is in PRIGHT, we've already considered it. */
1121 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1122 if (EQ (sym, XCAR (tail1)))
1123 break;
1124 if (! NILP (tail1))
1125 continue;
1127 lval = Fcar (XCDR (tail2));
1129 /* Even if lrear or rfront say nothing about the stickiness of
1130 SYM, Vtext_property_default_nonsticky may give default
1131 stickiness to SYM. */
1132 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1134 /* Since rval is known to be nil in this loop, the test simplifies. */
1135 if (! (TMEM (sym, lrear) || (CONSP (tmp) && ! NILP (XCDR (tmp)))))
1137 props = Fcons (lval, Fcons (sym, props));
1138 if (TMEM (sym, lfront))
1139 front = Fcons (sym, front);
1141 else if (TMEM (sym, rfront) || (CONSP (tmp) && NILP (XCDR (tmp))))
1143 /* The value is nil, but we still inherit the stickiness
1144 from the right. */
1145 front = Fcons (sym, front);
1146 if (TMEM (sym, rrear))
1147 rear = Fcons (sym, rear);
1150 props = Fnreverse (props);
1151 if (! NILP (rear))
1152 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
1154 cat = textget (props, Qcategory);
1155 if (! NILP (front)
1157 /* If we have inherited a front-stick category property that is t,
1158 we don't need to set up a detailed one. */
1159 ! (! NILP (cat) && SYMBOLP (cat)
1160 && EQ (Fget (cat, Qfront_sticky), Qt)))
1161 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
1162 return props;
1166 /* Delete a node I from its interval tree by merging its subtrees
1167 into one subtree which is then returned. Caller is responsible for
1168 storing the resulting subtree into its parent. */
1170 static INTERVAL
1171 delete_node (register INTERVAL i)
1173 register INTERVAL migrate, this;
1174 register ptrdiff_t migrate_amt;
1176 if (!i->left)
1177 return i->right;
1178 if (!i->right)
1179 return i->left;
1181 migrate = i->left;
1182 migrate_amt = i->left->total_length;
1183 this = i->right;
1184 this->total_length += migrate_amt;
1185 while (this->left)
1187 this = this->left;
1188 this->total_length += migrate_amt;
1190 eassert (0 <= TOTAL_LENGTH (this));
1191 interval_set_left (this, migrate);
1192 interval_set_parent (migrate, this);
1194 return i->right;
1197 /* Delete interval I from its tree by calling `delete_node'
1198 and properly connecting the resultant subtree.
1200 I is presumed to be empty; that is, no adjustments are made
1201 for the length of I. */
1203 static void
1204 delete_interval (register INTERVAL i)
1206 register INTERVAL parent;
1207 ptrdiff_t amt = LENGTH (i);
1209 eassert (amt == 0); /* Only used on zero-length intervals now. */
1211 if (ROOT_INTERVAL_P (i))
1213 Lisp_Object owner;
1214 GET_INTERVAL_OBJECT (owner, i);
1215 parent = delete_node (i);
1216 if (parent)
1217 interval_set_object (parent, owner);
1219 if (BUFFERP (owner))
1220 buffer_set_intervals (XBUFFER (owner), parent);
1221 else if (STRINGP (owner))
1222 string_set_intervals (owner, parent);
1223 else
1224 abort ();
1226 return;
1229 parent = INTERVAL_PARENT (i);
1230 if (AM_LEFT_CHILD (i))
1232 interval_set_left (parent, delete_node (i));
1233 if (parent->left)
1234 interval_set_parent (parent->left, parent);
1236 else
1238 interval_set_right (parent, delete_node (i));
1239 if (parent->right)
1240 interval_set_parent (parent->right, parent);
1244 /* Find the interval in TREE corresponding to the relative position
1245 FROM and delete as much as possible of AMOUNT from that interval.
1246 Return the amount actually deleted, and if the interval was
1247 zeroed-out, delete that interval node from the tree.
1249 Note that FROM is actually origin zero, aka relative to the
1250 leftmost edge of tree. This is appropriate since we call ourselves
1251 recursively on subtrees.
1253 Do this by recursing down TREE to the interval in question, and
1254 deleting the appropriate amount of text. */
1256 static ptrdiff_t
1257 interval_deletion_adjustment (register INTERVAL tree, register ptrdiff_t from,
1258 register ptrdiff_t amount)
1260 register ptrdiff_t relative_position = from;
1262 if (!tree)
1263 return 0;
1265 /* Left branch. */
1266 if (relative_position < LEFT_TOTAL_LENGTH (tree))
1268 ptrdiff_t subtract = interval_deletion_adjustment (tree->left,
1269 relative_position,
1270 amount);
1271 tree->total_length -= subtract;
1272 eassert (0 <= TOTAL_LENGTH (tree));
1273 return subtract;
1275 /* Right branch. */
1276 else if (relative_position >= (TOTAL_LENGTH (tree)
1277 - RIGHT_TOTAL_LENGTH (tree)))
1279 ptrdiff_t subtract;
1281 relative_position -= (tree->total_length
1282 - RIGHT_TOTAL_LENGTH (tree));
1283 subtract = interval_deletion_adjustment (tree->right,
1284 relative_position,
1285 amount);
1286 tree->total_length -= subtract;
1287 eassert (0 <= TOTAL_LENGTH (tree));
1288 return subtract;
1290 /* Here -- this node. */
1291 else
1293 /* How much can we delete from this interval? */
1294 ptrdiff_t my_amount = ((tree->total_length
1295 - RIGHT_TOTAL_LENGTH (tree))
1296 - relative_position);
1298 if (amount > my_amount)
1299 amount = my_amount;
1301 tree->total_length -= amount;
1302 eassert (0 <= TOTAL_LENGTH (tree));
1303 if (LENGTH (tree) == 0)
1304 delete_interval (tree);
1306 return amount;
1309 /* Never reach here. */
1312 /* Effect the adjustments necessary to the interval tree of BUFFER to
1313 correspond to the deletion of LENGTH characters from that buffer
1314 text. The deletion is effected at position START (which is a
1315 buffer position, i.e. origin 1). */
1317 static void
1318 adjust_intervals_for_deletion (struct buffer *buffer,
1319 ptrdiff_t start, ptrdiff_t length)
1321 register ptrdiff_t left_to_delete = length;
1322 register INTERVAL tree = buffer_get_intervals (buffer);
1323 Lisp_Object parent;
1324 ptrdiff_t offset;
1326 GET_INTERVAL_OBJECT (parent, tree);
1327 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
1329 if (!tree)
1330 return;
1332 eassert (start <= offset + TOTAL_LENGTH (tree)
1333 && start + length <= offset + TOTAL_LENGTH (tree));
1335 if (length == TOTAL_LENGTH (tree))
1337 buffer_set_intervals (buffer, NULL);
1338 return;
1341 if (ONLY_INTERVAL_P (tree))
1343 tree->total_length -= length;
1344 eassert (0 <= TOTAL_LENGTH (tree));
1345 return;
1348 if (start > offset + TOTAL_LENGTH (tree))
1349 start = offset + TOTAL_LENGTH (tree);
1350 while (left_to_delete > 0)
1352 left_to_delete -= interval_deletion_adjustment (tree, start - offset,
1353 left_to_delete);
1354 tree = buffer_get_intervals (buffer);
1355 if (left_to_delete == tree->total_length)
1357 buffer_set_intervals (buffer, NULL);
1358 return;
1363 /* Make the adjustments necessary to the interval tree of BUFFER to
1364 represent an addition or deletion of LENGTH characters starting
1365 at position START. Addition or deletion is indicated by the sign
1366 of LENGTH.
1368 The two inline functions (one static) pacify Sun C 5.8, a pre-C99
1369 compiler that does not allow calling a static function (here,
1370 adjust_intervals_for_deletion) from a non-static inline function. */
1372 void
1373 offset_intervals (struct buffer *buffer, ptrdiff_t start, ptrdiff_t length)
1375 if (!buffer_get_intervals (buffer) || length == 0)
1376 return;
1378 if (length > 0)
1379 adjust_intervals_for_insertion (buffer_get_intervals (buffer),
1380 start, length);
1381 else
1383 IF_LINT (if (length < - TYPE_MAXIMUM (ptrdiff_t)) abort ();)
1384 adjust_intervals_for_deletion (buffer, start, -length);
1388 /* Merge interval I with its lexicographic successor. The resulting
1389 interval is returned, and has the properties of the original
1390 successor. The properties of I are lost. I is removed from the
1391 interval tree.
1393 IMPORTANT:
1394 The caller must verify that this is not the last (rightmost)
1395 interval. */
1397 static INTERVAL
1398 merge_interval_right (register INTERVAL i)
1400 register ptrdiff_t absorb = LENGTH (i);
1401 register INTERVAL successor;
1403 /* Find the succeeding interval. */
1404 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
1405 as we descend. */
1407 successor = i->right;
1408 while (! NULL_LEFT_CHILD (successor))
1410 successor->total_length += absorb;
1411 eassert (0 <= TOTAL_LENGTH (successor));
1412 successor = successor->left;
1415 successor->total_length += absorb;
1416 eassert (0 <= TOTAL_LENGTH (successor));
1417 delete_interval (i);
1418 return successor;
1421 /* Zero out this interval. */
1422 i->total_length -= absorb;
1423 eassert (0 <= TOTAL_LENGTH (i));
1425 successor = i;
1426 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
1427 we ascend. */
1429 if (AM_LEFT_CHILD (successor))
1431 successor = INTERVAL_PARENT (successor);
1432 delete_interval (i);
1433 return successor;
1436 successor = INTERVAL_PARENT (successor);
1437 successor->total_length -= absorb;
1438 eassert (0 <= TOTAL_LENGTH (successor));
1441 /* This must be the rightmost or last interval and cannot
1442 be merged right. The caller should have known. */
1443 abort ();
1446 /* Merge interval I with its lexicographic predecessor. The resulting
1447 interval is returned, and has the properties of the original predecessor.
1448 The properties of I are lost. Interval node I is removed from the tree.
1450 IMPORTANT:
1451 The caller must verify that this is not the first (leftmost) interval. */
1453 INTERVAL
1454 merge_interval_left (register INTERVAL i)
1456 register ptrdiff_t absorb = LENGTH (i);
1457 register INTERVAL predecessor;
1459 /* Find the preceding interval. */
1460 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
1461 adding ABSORB as we go. */
1463 predecessor = i->left;
1464 while (! NULL_RIGHT_CHILD (predecessor))
1466 predecessor->total_length += absorb;
1467 eassert (0 <= TOTAL_LENGTH (predecessor));
1468 predecessor = predecessor->right;
1471 predecessor->total_length += absorb;
1472 eassert (0 <= TOTAL_LENGTH (predecessor));
1473 delete_interval (i);
1474 return predecessor;
1477 /* Zero out this interval. */
1478 i->total_length -= absorb;
1479 eassert (0 <= TOTAL_LENGTH (i));
1481 predecessor = i;
1482 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
1483 subtracting ABSORB. */
1485 if (AM_RIGHT_CHILD (predecessor))
1487 predecessor = INTERVAL_PARENT (predecessor);
1488 delete_interval (i);
1489 return predecessor;
1492 predecessor = INTERVAL_PARENT (predecessor);
1493 predecessor->total_length -= absorb;
1494 eassert (0 <= TOTAL_LENGTH (predecessor));
1497 /* This must be the leftmost or first interval and cannot
1498 be merged left. The caller should have known. */
1499 abort ();
1502 /* Make an exact copy of interval tree SOURCE which descends from
1503 PARENT. This is done by recursing through SOURCE, copying
1504 the current interval and its properties, and then adjusting
1505 the pointers of the copy. */
1507 static INTERVAL
1508 reproduce_tree (INTERVAL source, INTERVAL parent)
1510 register INTERVAL t = make_interval ();
1512 memcpy (t, source, sizeof *t);
1513 copy_properties (source, t);
1514 interval_set_parent (t, parent);
1515 if (! NULL_LEFT_CHILD (source))
1516 interval_set_left (t, reproduce_tree (source->left, t));
1517 if (! NULL_RIGHT_CHILD (source))
1518 interval_set_right (t, reproduce_tree (source->right, t));
1520 return t;
1523 static INTERVAL
1524 reproduce_tree_obj (INTERVAL source, Lisp_Object parent)
1526 register INTERVAL t = make_interval ();
1528 memcpy (t, source, sizeof *t);
1529 copy_properties (source, t);
1530 interval_set_object (t, parent);
1531 if (! NULL_LEFT_CHILD (source))
1532 interval_set_left (t, reproduce_tree (source->left, t));
1533 if (! NULL_RIGHT_CHILD (source))
1534 interval_set_right (t, reproduce_tree (source->right, t));
1536 return t;
1539 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1540 LENGTH is the length of the text in SOURCE.
1542 The `position' field of the SOURCE intervals is assumed to be
1543 consistent with its parent; therefore, SOURCE must be an
1544 interval tree made with copy_interval or must be the whole
1545 tree of a buffer or a string.
1547 This is used in insdel.c when inserting Lisp_Strings into the
1548 buffer. The text corresponding to SOURCE is already in the buffer
1549 when this is called. The intervals of new tree are a copy of those
1550 belonging to the string being inserted; intervals are never
1551 shared.
1553 If the inserted text had no intervals associated, and we don't
1554 want to inherit the surrounding text's properties, this function
1555 simply returns -- offset_intervals should handle placing the
1556 text in the correct interval, depending on the sticky bits.
1558 If the inserted text had properties (intervals), then there are two
1559 cases -- either insertion happened in the middle of some interval,
1560 or between two intervals.
1562 If the text goes into the middle of an interval, then new intervals
1563 are created in the middle, and new text has the union of its properties
1564 and those of the text into which it was inserted.
1566 If the text goes between two intervals, then if neither interval
1567 had its appropriate sticky property set (front_sticky, rear_sticky),
1568 the new text has only its properties. If one of the sticky properties
1569 is set, then the new text "sticks" to that region and its properties
1570 depend on merging as above. If both the preceding and succeeding
1571 intervals to the new text are "sticky", then the new text retains
1572 only its properties, as if neither sticky property were set. Perhaps
1573 we should consider merging all three sets of properties onto the new
1574 text... */
1576 void
1577 graft_intervals_into_buffer (INTERVAL source, ptrdiff_t position,
1578 ptrdiff_t length, struct buffer *buffer,
1579 int inherit)
1581 register INTERVAL under, over, this;
1582 register INTERVAL tree;
1583 ptrdiff_t over_used;
1585 tree = buffer_get_intervals (buffer);
1587 /* If the new text has no properties, then with inheritance it
1588 becomes part of whatever interval it was inserted into.
1589 To prevent inheritance, we must clear out the properties
1590 of the newly inserted text. */
1591 if (!source)
1593 Lisp_Object buf;
1594 if (!inherit && tree && length > 0)
1596 XSETBUFFER (buf, buffer);
1597 set_text_properties_1 (make_number (position),
1598 make_number (position + length),
1599 Qnil, buf, 0);
1601 /* Shouldn't be necessary. --Stef */
1602 buffer_balance_intervals (buffer);
1603 return;
1606 eassert (length == TOTAL_LENGTH (source));
1608 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == length)
1610 /* The inserted text constitutes the whole buffer, so
1611 simply copy over the interval structure. */
1612 Lisp_Object buf;
1614 XSETBUFFER (buf, buffer);
1615 buffer_set_intervals (buffer, reproduce_tree_obj (source, buf));
1616 buffer_get_intervals (buffer)->position = BUF_BEG (buffer);
1617 eassert (buffer_get_intervals (buffer)->up_obj == 1);
1618 return;
1620 else if (!tree)
1622 /* Create an interval tree in which to place a copy
1623 of the intervals of the inserted string. */
1624 Lisp_Object buf;
1626 XSETBUFFER (buf, buffer);
1627 tree = create_root_interval (buf);
1629 /* Paranoia -- the text has already been added, so
1630 this buffer should be of non-zero length. */
1631 eassert (TOTAL_LENGTH (tree) > 0);
1633 this = under = find_interval (tree, position);
1634 eassert (under);
1635 over = find_interval (source, interval_start_pos (source));
1637 /* Here for insertion in the middle of an interval.
1638 Split off an equivalent interval to the right,
1639 then don't bother with it any more. */
1641 if (position > under->position)
1643 INTERVAL end_unchanged
1644 = split_interval_left (this, position - under->position);
1645 copy_properties (under, end_unchanged);
1646 under->position = position;
1648 else
1650 /* This call may have some effect because previous_interval may
1651 update `position' fields of intervals. Thus, don't ignore it
1652 for the moment. Someone please tell me the truth (K.Handa). */
1653 INTERVAL prev = previous_interval (under);
1654 (void) prev;
1655 #if 0
1656 /* But, this code surely has no effect. And, anyway,
1657 END_NONSTICKY_P is unreliable now. */
1658 if (prev && !END_NONSTICKY_P (prev))
1659 prev = 0;
1660 #endif /* 0 */
1663 /* Insertion is now at beginning of UNDER. */
1665 /* The inserted text "sticks" to the interval `under',
1666 which means it gets those properties.
1667 The properties of under are the result of
1668 adjust_intervals_for_insertion, so stickiness has
1669 already been taken care of. */
1671 /* OVER is the interval we are copying from next.
1672 OVER_USED says how many characters' worth of OVER
1673 have already been copied into target intervals.
1674 UNDER is the next interval in the target. */
1675 over_used = 0;
1676 while (over)
1678 /* If UNDER is longer than OVER, split it. */
1679 if (LENGTH (over) - over_used < LENGTH (under))
1681 this = split_interval_left (under, LENGTH (over) - over_used);
1682 copy_properties (under, this);
1684 else
1685 this = under;
1687 /* THIS is now the interval to copy or merge into.
1688 OVER covers all of it. */
1689 if (inherit)
1690 merge_properties (over, this);
1691 else
1692 copy_properties (over, this);
1694 /* If THIS and OVER end at the same place,
1695 advance OVER to a new source interval. */
1696 if (LENGTH (this) == LENGTH (over) - over_used)
1698 over = next_interval (over);
1699 over_used = 0;
1701 else
1702 /* Otherwise just record that more of OVER has been used. */
1703 over_used += LENGTH (this);
1705 /* Always advance to a new target interval. */
1706 under = next_interval (this);
1709 buffer_balance_intervals (buffer);
1712 /* Get the value of property PROP from PLIST,
1713 which is the plist of an interval.
1714 We check for direct properties, for categories with property PROP,
1715 and for PROP appearing on the default-text-properties list. */
1717 Lisp_Object
1718 textget (Lisp_Object plist, register Lisp_Object prop)
1720 return lookup_char_property (plist, prop, 1);
1723 Lisp_Object
1724 lookup_char_property (Lisp_Object plist, register Lisp_Object prop, int textprop)
1726 register Lisp_Object tail, fallback = Qnil;
1728 for (tail = plist; CONSP (tail); tail = Fcdr (XCDR (tail)))
1730 register Lisp_Object tem;
1731 tem = XCAR (tail);
1732 if (EQ (prop, tem))
1733 return Fcar (XCDR (tail));
1734 if (EQ (tem, Qcategory))
1736 tem = Fcar (XCDR (tail));
1737 if (SYMBOLP (tem))
1738 fallback = Fget (tem, prop);
1742 if (! NILP (fallback))
1743 return fallback;
1744 /* Check for alternative properties */
1745 tail = Fassq (prop, Vchar_property_alias_alist);
1746 if (! NILP (tail))
1748 tail = XCDR (tail);
1749 for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
1750 fallback = Fplist_get (plist, XCAR (tail));
1753 if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties))
1754 fallback = Fplist_get (Vdefault_text_properties, prop);
1755 return fallback;
1759 /* Set point in BUFFER "temporarily" to CHARPOS, which corresponds to
1760 byte position BYTEPOS. */
1762 void
1763 temp_set_point_both (struct buffer *buffer,
1764 ptrdiff_t charpos, ptrdiff_t bytepos)
1766 /* In a single-byte buffer, the two positions must be equal. */
1767 if (BUF_ZV (buffer) == BUF_ZV_BYTE (buffer))
1768 eassert (charpos == bytepos);
1770 eassert (charpos <= bytepos);
1771 eassert (charpos <= BUF_ZV (buffer) || BUF_BEGV (buffer) <= charpos);
1773 SET_BUF_PT_BOTH (buffer, charpos, bytepos);
1776 /* Set point "temporarily", without checking any text properties. */
1778 void
1779 temp_set_point (struct buffer *buffer, ptrdiff_t charpos)
1781 temp_set_point_both (buffer, charpos,
1782 buf_charpos_to_bytepos (buffer, charpos));
1785 /* Set point in BUFFER to CHARPOS. If the target position is
1786 before an intangible character, move to an ok place. */
1788 void
1789 set_point (ptrdiff_t charpos)
1791 set_point_both (charpos, buf_charpos_to_bytepos (current_buffer, charpos));
1794 /* If there's an invisible character at position POS + TEST_OFFS in the
1795 current buffer, and the invisible property has a `stickiness' such that
1796 inserting a character at position POS would inherit the property it,
1797 return POS + ADJ, otherwise return POS. If TEST_INTANG is non-zero,
1798 then intangibility is required as well as invisibility.
1800 TEST_OFFS should be either 0 or -1, and ADJ should be either 1 or -1.
1802 Note that `stickiness' is determined by overlay marker insertion types,
1803 if the invisible property comes from an overlay. */
1805 static ptrdiff_t
1806 adjust_for_invis_intang (ptrdiff_t pos, ptrdiff_t test_offs, ptrdiff_t adj,
1807 int test_intang)
1809 Lisp_Object invis_propval, invis_overlay;
1810 Lisp_Object test_pos;
1812 if ((adj < 0 && pos + adj < BEGV) || (adj > 0 && pos + adj > ZV))
1813 /* POS + ADJ would be beyond the buffer bounds, so do no adjustment. */
1814 return pos;
1816 test_pos = make_number (pos + test_offs);
1818 invis_propval
1819 = get_char_property_and_overlay (test_pos, Qinvisible, Qnil,
1820 &invis_overlay);
1822 if ((!test_intang
1823 || ! NILP (Fget_char_property (test_pos, Qintangible, Qnil)))
1824 && TEXT_PROP_MEANS_INVISIBLE (invis_propval)
1825 /* This next test is true if the invisible property has a stickiness
1826 such that an insertion at POS would inherit it. */
1827 && (NILP (invis_overlay)
1828 /* Invisible property is from a text-property. */
1829 ? (text_property_stickiness (Qinvisible, make_number (pos), Qnil)
1830 == (test_offs == 0 ? 1 : -1))
1831 /* Invisible property is from an overlay. */
1832 : (test_offs == 0
1833 ? XMARKER (OVERLAY_START (invis_overlay))->insertion_type == 0
1834 : XMARKER (OVERLAY_END (invis_overlay))->insertion_type == 1)))
1835 pos += adj;
1837 return pos;
1840 /* Set point in BUFFER to CHARPOS, which corresponds to byte
1841 position BYTEPOS. If the target position is
1842 before an intangible character, move to an ok place. */
1844 void
1845 set_point_both (ptrdiff_t charpos, ptrdiff_t bytepos)
1847 register INTERVAL to, from, toprev, fromprev;
1848 ptrdiff_t buffer_point;
1849 ptrdiff_t old_position = PT;
1850 /* This ensures that we move forward past intangible text when the
1851 initial position is the same as the destination, in the rare
1852 instances where this is important, e.g. in line-move-finish
1853 (simple.el). */
1854 int backwards = (charpos < old_position ? 1 : 0);
1855 int have_overlays;
1856 ptrdiff_t original_position;
1858 BVAR (current_buffer, point_before_scroll) = Qnil;
1860 if (charpos == PT)
1861 return;
1863 /* In a single-byte buffer, the two positions must be equal. */
1864 eassert (ZV != ZV_BYTE || charpos == bytepos);
1866 /* Check this now, before checking if the buffer has any intervals.
1867 That way, we can catch conditions which break this sanity check
1868 whether or not there are intervals in the buffer. */
1869 eassert (charpos <= ZV && charpos >= BEGV);
1871 have_overlays = buffer_has_overlays ();
1873 /* If we have no text properties and overlays,
1874 then we can do it quickly. */
1875 if (!buffer_get_intervals (current_buffer) && ! have_overlays)
1877 temp_set_point_both (current_buffer, charpos, bytepos);
1878 return;
1881 /* Set TO to the interval containing the char after CHARPOS,
1882 and TOPREV to the interval containing the char before CHARPOS.
1883 Either one may be null. They may be equal. */
1884 to = find_interval (buffer_get_intervals (current_buffer), charpos);
1885 if (charpos == BEGV)
1886 toprev = 0;
1887 else if (to && to->position == charpos)
1888 toprev = previous_interval (to);
1889 else
1890 toprev = to;
1892 buffer_point = (PT == ZV ? ZV - 1 : PT);
1894 /* Set FROM to the interval containing the char after PT,
1895 and FROMPREV to the interval containing the char before PT.
1896 Either one may be null. They may be equal. */
1897 /* We could cache this and save time. */
1898 from = find_interval (buffer_get_intervals (current_buffer), buffer_point);
1899 if (buffer_point == BEGV)
1900 fromprev = 0;
1901 else if (from && from->position == PT)
1902 fromprev = previous_interval (from);
1903 else if (buffer_point != PT)
1904 fromprev = from, from = 0;
1905 else
1906 fromprev = from;
1908 /* Moving within an interval. */
1909 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)
1910 && ! have_overlays)
1912 temp_set_point_both (current_buffer, charpos, bytepos);
1913 return;
1916 original_position = charpos;
1918 /* If the new position is between two intangible characters
1919 with the same intangible property value,
1920 move forward or backward until a change in that property. */
1921 if (NILP (Vinhibit_point_motion_hooks)
1922 && ((to && toprev)
1923 || have_overlays)
1924 /* Intangibility never stops us from positioning at the beginning
1925 or end of the buffer, so don't bother checking in that case. */
1926 && charpos != BEGV && charpos != ZV)
1928 Lisp_Object pos;
1929 Lisp_Object intangible_propval;
1931 if (backwards)
1933 /* If the preceding character is both intangible and invisible,
1934 and the invisible property is `rear-sticky', perturb it so
1935 that the search starts one character earlier -- this ensures
1936 that point can never move to the end of an invisible/
1937 intangible/rear-sticky region. */
1938 charpos = adjust_for_invis_intang (charpos, -1, -1, 1);
1940 XSETINT (pos, charpos);
1942 /* If following char is intangible,
1943 skip back over all chars with matching intangible property. */
1945 intangible_propval = Fget_char_property (pos, Qintangible, Qnil);
1947 if (! NILP (intangible_propval))
1949 while (XINT (pos) > BEGV
1950 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
1951 Qintangible, Qnil),
1952 intangible_propval))
1953 pos = Fprevious_char_property_change (pos, Qnil);
1955 /* Set CHARPOS from POS, and if the final intangible character
1956 that we skipped over is also invisible, and the invisible
1957 property is `front-sticky', perturb it to be one character
1958 earlier -- this ensures that point can never move to the
1959 beginning of an invisible/intangible/front-sticky region. */
1960 charpos = adjust_for_invis_intang (XINT (pos), 0, -1, 0);
1963 else
1965 /* If the following character is both intangible and invisible,
1966 and the invisible property is `front-sticky', perturb it so
1967 that the search starts one character later -- this ensures
1968 that point can never move to the beginning of an
1969 invisible/intangible/front-sticky region. */
1970 charpos = adjust_for_invis_intang (charpos, 0, 1, 1);
1972 XSETINT (pos, charpos);
1974 /* If preceding char is intangible,
1975 skip forward over all chars with matching intangible property. */
1977 intangible_propval = Fget_char_property (make_number (charpos - 1),
1978 Qintangible, Qnil);
1980 if (! NILP (intangible_propval))
1982 while (XINT (pos) < ZV
1983 && EQ (Fget_char_property (pos, Qintangible, Qnil),
1984 intangible_propval))
1985 pos = Fnext_char_property_change (pos, Qnil);
1987 /* Set CHARPOS from POS, and if the final intangible character
1988 that we skipped over is also invisible, and the invisible
1989 property is `rear-sticky', perturb it to be one character
1990 later -- this ensures that point can never move to the
1991 end of an invisible/intangible/rear-sticky region. */
1992 charpos = adjust_for_invis_intang (XINT (pos), -1, 1, 0);
1996 bytepos = buf_charpos_to_bytepos (current_buffer, charpos);
1999 if (charpos != original_position)
2001 /* Set TO to the interval containing the char after CHARPOS,
2002 and TOPREV to the interval containing the char before CHARPOS.
2003 Either one may be null. They may be equal. */
2004 to = find_interval (buffer_get_intervals (current_buffer), charpos);
2005 if (charpos == BEGV)
2006 toprev = 0;
2007 else if (to && to->position == charpos)
2008 toprev = previous_interval (to);
2009 else
2010 toprev = to;
2013 /* Here TO is the interval after the stopping point
2014 and TOPREV is the interval before the stopping point.
2015 One or the other may be null. */
2017 temp_set_point_both (current_buffer, charpos, bytepos);
2019 /* We run point-left and point-entered hooks here, if the
2020 two intervals are not equivalent. These hooks take
2021 (old_point, new_point) as arguments. */
2022 if (NILP (Vinhibit_point_motion_hooks)
2023 && (! intervals_equal (from, to)
2024 || ! intervals_equal (fromprev, toprev)))
2026 Lisp_Object leave_after, leave_before, enter_after, enter_before;
2028 if (fromprev)
2029 leave_before = textget (fromprev->plist, Qpoint_left);
2030 else
2031 leave_before = Qnil;
2033 if (from)
2034 leave_after = textget (from->plist, Qpoint_left);
2035 else
2036 leave_after = Qnil;
2038 if (toprev)
2039 enter_before = textget (toprev->plist, Qpoint_entered);
2040 else
2041 enter_before = Qnil;
2043 if (to)
2044 enter_after = textget (to->plist, Qpoint_entered);
2045 else
2046 enter_after = Qnil;
2048 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
2049 call2 (leave_before, make_number (old_position),
2050 make_number (charpos));
2051 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
2052 call2 (leave_after, make_number (old_position),
2053 make_number (charpos));
2055 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
2056 call2 (enter_before, make_number (old_position),
2057 make_number (charpos));
2058 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
2059 call2 (enter_after, make_number (old_position),
2060 make_number (charpos));
2064 /* Move point to POSITION, unless POSITION is inside an intangible
2065 segment that reaches all the way to point. */
2067 void
2068 move_if_not_intangible (ptrdiff_t position)
2070 Lisp_Object pos;
2071 Lisp_Object intangible_propval;
2073 XSETINT (pos, position);
2075 if (! NILP (Vinhibit_point_motion_hooks))
2076 /* If intangible is inhibited, always move point to POSITION. */
2078 else if (PT < position && XINT (pos) < ZV)
2080 /* We want to move forward, so check the text before POSITION. */
2082 intangible_propval = Fget_char_property (pos,
2083 Qintangible, Qnil);
2085 /* If following char is intangible,
2086 skip back over all chars with matching intangible property. */
2087 if (! NILP (intangible_propval))
2088 while (XINT (pos) > BEGV
2089 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
2090 Qintangible, Qnil),
2091 intangible_propval))
2092 pos = Fprevious_char_property_change (pos, Qnil);
2094 else if (XINT (pos) > BEGV)
2096 /* We want to move backward, so check the text after POSITION. */
2098 intangible_propval = Fget_char_property (make_number (XINT (pos) - 1),
2099 Qintangible, Qnil);
2101 /* If following char is intangible,
2102 skip forward over all chars with matching intangible property. */
2103 if (! NILP (intangible_propval))
2104 while (XINT (pos) < ZV
2105 && EQ (Fget_char_property (pos, Qintangible, Qnil),
2106 intangible_propval))
2107 pos = Fnext_char_property_change (pos, Qnil);
2110 else if (position < BEGV)
2111 position = BEGV;
2112 else if (position > ZV)
2113 position = ZV;
2115 /* If the whole stretch between PT and POSITION isn't intangible,
2116 try moving to POSITION (which means we actually move farther
2117 if POSITION is inside of intangible text). */
2119 if (XINT (pos) != PT)
2120 SET_PT (position);
2123 /* If text at position POS has property PROP, set *VAL to the property
2124 value, *START and *END to the beginning and end of a region that
2125 has the same property, and return 1. Otherwise return 0.
2127 OBJECT is the string or buffer to look for the property in;
2128 nil means the current buffer. */
2131 get_property_and_range (ptrdiff_t pos, Lisp_Object prop, Lisp_Object *val,
2132 ptrdiff_t *start, ptrdiff_t *end, Lisp_Object object)
2134 INTERVAL i, prev, next;
2136 if (NILP (object))
2137 i = find_interval (buffer_get_intervals (current_buffer), pos);
2138 else if (BUFFERP (object))
2139 i = find_interval (buffer_get_intervals (XBUFFER (object)), pos);
2140 else if (STRINGP (object))
2141 i = find_interval (string_get_intervals (object), pos);
2142 else
2143 abort ();
2145 if (!i || (i->position + LENGTH (i) <= pos))
2146 return 0;
2147 *val = textget (i->plist, prop);
2148 if (NILP (*val))
2149 return 0;
2151 next = i; /* remember it in advance */
2152 prev = previous_interval (i);
2153 while (prev
2154 && EQ (*val, textget (prev->plist, prop)))
2155 i = prev, prev = previous_interval (prev);
2156 *start = i->position;
2158 next = next_interval (i);
2159 while (next && EQ (*val, textget (next->plist, prop)))
2160 i = next, next = next_interval (next);
2161 *end = i->position + LENGTH (i);
2163 return 1;
2166 /* Return the proper local keymap TYPE for position POSITION in
2167 BUFFER; TYPE should be one of `keymap' or `local-map'. Use the map
2168 specified by the PROP property, if any. Otherwise, if TYPE is
2169 `local-map' use BUFFER's local map.
2171 POSITION must be in the accessible part of BUFFER. */
2173 Lisp_Object
2174 get_local_map (register ptrdiff_t position, register struct buffer *buffer,
2175 Lisp_Object type)
2177 Lisp_Object prop, lispy_position, lispy_buffer;
2178 ptrdiff_t old_begv, old_zv, old_begv_byte, old_zv_byte;
2180 /* Perhaps we should just change `position' to the limit. */
2181 if (position > BUF_ZV (buffer) || position < BUF_BEGV (buffer))
2182 abort ();
2184 /* Ignore narrowing, so that a local map continues to be valid even if
2185 the visible region contains no characters and hence no properties. */
2186 old_begv = BUF_BEGV (buffer);
2187 old_zv = BUF_ZV (buffer);
2188 old_begv_byte = BUF_BEGV_BYTE (buffer);
2189 old_zv_byte = BUF_ZV_BYTE (buffer);
2191 SET_BUF_BEGV_BOTH (buffer, BUF_BEG (buffer), BUF_BEG_BYTE (buffer));
2192 SET_BUF_ZV_BOTH (buffer, BUF_Z (buffer), BUF_Z_BYTE (buffer));
2194 XSETFASTINT (lispy_position, position);
2195 XSETBUFFER (lispy_buffer, buffer);
2196 /* First check if the CHAR has any property. This is because when
2197 we click with the mouse, the mouse pointer is really pointing
2198 to the CHAR after POS. */
2199 prop = Fget_char_property (lispy_position, type, lispy_buffer);
2200 /* If not, look at the POS's properties. This is necessary because when
2201 editing a field with a `local-map' property, we want insertion at the end
2202 to obey the `local-map' property. */
2203 if (NILP (prop))
2204 prop = get_pos_property (lispy_position, type, lispy_buffer);
2206 SET_BUF_BEGV_BOTH (buffer, old_begv, old_begv_byte);
2207 SET_BUF_ZV_BOTH (buffer, old_zv, old_zv_byte);
2209 /* Use the local map only if it is valid. */
2210 prop = get_keymap (prop, 0, 0);
2211 if (CONSP (prop))
2212 return prop;
2214 if (EQ (type, Qkeymap))
2215 return Qnil;
2216 else
2217 return BVAR (buffer, keymap);
2220 /* Produce an interval tree reflecting the intervals in
2221 TREE from START to START + LENGTH.
2222 The new interval tree has no parent and has a starting-position of 0. */
2224 INTERVAL
2225 copy_intervals (INTERVAL tree, ptrdiff_t start, ptrdiff_t length)
2227 register INTERVAL i, new, t;
2228 register ptrdiff_t got, prevlen;
2230 if (!tree || length <= 0)
2231 return NULL;
2233 i = find_interval (tree, start);
2234 eassert (i && LENGTH (i) > 0);
2236 /* If there is only one interval and it's the default, return nil. */
2237 if ((start - i->position + 1 + length) < LENGTH (i)
2238 && DEFAULT_INTERVAL_P (i))
2239 return NULL;
2241 new = make_interval ();
2242 new->position = 0;
2243 got = (LENGTH (i) - (start - i->position));
2244 new->total_length = length;
2245 eassert (0 <= TOTAL_LENGTH (new));
2246 copy_properties (i, new);
2248 t = new;
2249 prevlen = got;
2250 while (got < length)
2252 i = next_interval (i);
2253 t = split_interval_right (t, prevlen);
2254 copy_properties (i, t);
2255 prevlen = LENGTH (i);
2256 got += prevlen;
2259 return balance_an_interval (new);
2262 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
2264 void
2265 copy_intervals_to_string (Lisp_Object string, struct buffer *buffer,
2266 ptrdiff_t position, ptrdiff_t length)
2268 INTERVAL interval_copy = copy_intervals (buffer_get_intervals (buffer),
2269 position, length);
2270 if (!interval_copy)
2271 return;
2273 interval_set_object (interval_copy, string);
2274 string_set_intervals (string, interval_copy);
2277 /* Return 1 if strings S1 and S2 have identical properties; 0 otherwise.
2278 Assume they have identical characters. */
2281 compare_string_intervals (Lisp_Object s1, Lisp_Object s2)
2283 INTERVAL i1, i2;
2284 ptrdiff_t pos = 0;
2285 ptrdiff_t end = SCHARS (s1);
2287 i1 = find_interval (string_get_intervals (s1), 0);
2288 i2 = find_interval (string_get_intervals (s2), 0);
2290 while (pos < end)
2292 /* Determine how far we can go before we reach the end of I1 or I2. */
2293 ptrdiff_t len1 = (i1 != 0 ? INTERVAL_LAST_POS (i1) : end) - pos;
2294 ptrdiff_t len2 = (i2 != 0 ? INTERVAL_LAST_POS (i2) : end) - pos;
2295 ptrdiff_t distance = min (len1, len2);
2297 /* If we ever find a mismatch between the strings,
2298 they differ. */
2299 if (! intervals_equal (i1, i2))
2300 return 0;
2302 /* Advance POS till the end of the shorter interval,
2303 and advance one or both interval pointers for the new position. */
2304 pos += distance;
2305 if (len1 == distance)
2306 i1 = next_interval (i1);
2307 if (len2 == distance)
2308 i2 = next_interval (i2);
2310 return 1;
2313 /* Recursively adjust interval I in the current buffer
2314 for setting enable_multibyte_characters to MULTI_FLAG.
2315 The range of interval I is START ... END in characters,
2316 START_BYTE ... END_BYTE in bytes. */
2318 static void
2319 set_intervals_multibyte_1 (INTERVAL i, int multi_flag,
2320 ptrdiff_t start, ptrdiff_t start_byte,
2321 ptrdiff_t end, ptrdiff_t end_byte)
2323 /* Fix the length of this interval. */
2324 if (multi_flag)
2325 i->total_length = end - start;
2326 else
2327 i->total_length = end_byte - start_byte;
2328 eassert (0 <= TOTAL_LENGTH (i));
2330 if (TOTAL_LENGTH (i) == 0)
2332 delete_interval (i);
2333 return;
2336 /* Recursively fix the length of the subintervals. */
2337 if (i->left)
2339 ptrdiff_t left_end, left_end_byte;
2341 if (multi_flag)
2343 ptrdiff_t temp;
2344 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
2345 left_end = BYTE_TO_CHAR (left_end_byte);
2347 temp = CHAR_TO_BYTE (left_end);
2349 /* If LEFT_END_BYTE is in the middle of a character,
2350 adjust it and LEFT_END to a char boundary. */
2351 if (left_end_byte > temp)
2353 left_end_byte = temp;
2355 if (left_end_byte < temp)
2357 left_end--;
2358 left_end_byte = CHAR_TO_BYTE (left_end);
2361 else
2363 left_end = start + LEFT_TOTAL_LENGTH (i);
2364 left_end_byte = CHAR_TO_BYTE (left_end);
2367 set_intervals_multibyte_1 (i->left, multi_flag, start, start_byte,
2368 left_end, left_end_byte);
2370 if (i->right)
2372 ptrdiff_t right_start_byte, right_start;
2374 if (multi_flag)
2376 ptrdiff_t temp;
2378 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
2379 right_start = BYTE_TO_CHAR (right_start_byte);
2381 /* If RIGHT_START_BYTE is in the middle of a character,
2382 adjust it and RIGHT_START to a char boundary. */
2383 temp = CHAR_TO_BYTE (right_start);
2385 if (right_start_byte < temp)
2387 right_start_byte = temp;
2389 if (right_start_byte > temp)
2391 right_start++;
2392 right_start_byte = CHAR_TO_BYTE (right_start);
2395 else
2397 right_start = end - RIGHT_TOTAL_LENGTH (i);
2398 right_start_byte = CHAR_TO_BYTE (right_start);
2401 set_intervals_multibyte_1 (i->right, multi_flag,
2402 right_start, right_start_byte,
2403 end, end_byte);
2406 /* Rounding to char boundaries can theoretically ake this interval
2407 spurious. If so, delete one child, and copy its property list
2408 to this interval. */
2409 if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i))
2411 if ((i)->left)
2413 interval_set_plist (i, i->left->plist);
2414 (i)->left->total_length = 0;
2415 delete_interval ((i)->left);
2417 else
2419 interval_set_plist (i, i->right->plist);
2420 (i)->right->total_length = 0;
2421 delete_interval ((i)->right);
2426 /* Update the intervals of the current buffer
2427 to fit the contents as multibyte (if MULTI_FLAG is 1)
2428 or to fit them as non-multibyte (if MULTI_FLAG is 0). */
2430 void
2431 set_intervals_multibyte (int multi_flag)
2433 INTERVAL i = buffer_get_intervals (current_buffer);
2435 if (i)
2436 set_intervals_multibyte_1 (i, multi_flag, BEG, BEG_BYTE, Z, Z_BYTE);