Stop assuming interval pointers and lisp objects can be distinguished by
[bpt/emacs.git] / src / intervals.c
CommitLineData
a50699fd 1/* Code for doing intervals.
31c8f881 2 Copyright (C) 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
a50699fd
JA
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7ce503fd 8the Free Software Foundation; either version 2, or (at your option)
a50699fd
JA
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
a50699fd
JA
20
21
22/* NOTES:
23
24 Have to ensure that we can't put symbol nil on a plist, or some
25 functions may work incorrectly.
26
27 An idea: Have the owner of the tree keep count of splits and/or
28 insertion lengths (in intervals), and balance after every N.
29
30 Need to call *_left_hook when buffer is killed.
31
32 Scan for zero-length, or 0-length to see notes about handling
33 zero length interval-markers.
34
35 There are comments around about freeing intervals. It might be
36 faster to explicitly free them (put them on the free list) than
37 to GC them.
38
39*/
40
41
18160b98 42#include <config.h>
a50699fd
JA
43#include "lisp.h"
44#include "intervals.h"
45#include "buffer.h"
328c0f1f 46#include "puresize.h"
f54a8c1a 47#include "keyboard.h"
a50699fd 48
45d82bdc
KH
49/* Test for membership, allowing for t (actually any non-cons) to mean the
50 universal set. */
51
52#define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
53
d8638d30
RS
54#define min(x, y) ((x) < (y) ? (x) : (y))
55
b5f37d3f 56Lisp_Object merge_properties_sticky ();
439d5cb4
KR
57static INTERVAL reproduce_tree P_ ((INTERVAL, INTERVAL));
58static INTERVAL reproduce_tree_obj P_ ((INTERVAL, Lisp_Object));
a50699fd 59\f
7ce503fd 60/* Utility functions for intervals. */
a50699fd
JA
61
62
7ce503fd 63/* Create the root interval of some object, a buffer or string. */
a50699fd
JA
64
65INTERVAL
66create_root_interval (parent)
67 Lisp_Object parent;
68{
328c0f1f
RS
69 INTERVAL new;
70
71 CHECK_IMPURE (parent);
72
73 new = make_interval ();
a50699fd 74
b629dd47 75 if (BUFFERP (parent))
a50699fd 76 {
2bc7a79b
JB
77 new->total_length = (BUF_Z (XBUFFER (parent))
78 - BUF_BEG (XBUFFER (parent)));
e5d967c9 79 BUF_INTERVALS (XBUFFER (parent)) = new;
944d4e4b 80 new->position = 1;
a50699fd 81 }
b629dd47 82 else if (STRINGP (parent))
a50699fd
JA
83 {
84 new->total_length = XSTRING (parent)->size;
85 XSTRING (parent)->intervals = new;
944d4e4b 86 new->position = 0;
a50699fd
JA
87 }
88
439d5cb4 89 SET_INTERVAL_OBJECT (new, parent);
a50699fd
JA
90
91 return new;
92}
93
94/* Make the interval TARGET have exactly the properties of SOURCE */
95
96void
97copy_properties (source, target)
98 register INTERVAL source, target;
99{
100 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
101 return;
102
103 COPY_INTERVAL_CACHE (source, target);
104 target->plist = Fcopy_sequence (source->plist);
105}
106
107/* Merge the properties of interval SOURCE into the properties
323a7ad4
RS
108 of interval TARGET. That is to say, each property in SOURCE
109 is added to TARGET if TARGET has no such property as yet. */
a50699fd
JA
110
111static void
112merge_properties (source, target)
113 register INTERVAL source, target;
114{
115 register Lisp_Object o, sym, val;
116
117 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
118 return;
119
120 MERGE_INTERVAL_CACHE (source, target);
121
122 o = source->plist;
123 while (! EQ (o, Qnil))
124 {
125 sym = Fcar (o);
126 val = Fmemq (sym, target->plist);
127
128 if (NILP (val))
129 {
130 o = Fcdr (o);
131 val = Fcar (o);
132 target->plist = Fcons (sym, Fcons (val, target->plist));
133 o = Fcdr (o);
134 }
135 else
136 o = Fcdr (Fcdr (o));
137 }
138}
139
140/* Return 1 if the two intervals have the same properties,
7ce503fd 141 0 otherwise. */
a50699fd
JA
142
143int
144intervals_equal (i0, i1)
145 INTERVAL i0, i1;
146{
147 register Lisp_Object i0_cdr, i0_sym, i1_val;
dfcf069d 148 register int i1_len;
a50699fd
JA
149
150 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
151 return 1;
152
323a7ad4
RS
153 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
154 return 0;
155
a50699fd
JA
156 i1_len = XFASTINT (Flength (i1->plist));
157 if (i1_len & 0x1) /* Paranoia -- plists are always even */
158 abort ();
159 i1_len /= 2;
160 i0_cdr = i0->plist;
161 while (!NILP (i0_cdr))
162 {
7ce503fd 163 /* Lengths of the two plists were unequal. */
a50699fd
JA
164 if (i1_len == 0)
165 return 0;
166
167 i0_sym = Fcar (i0_cdr);
168 i1_val = Fmemq (i0_sym, i1->plist);
169
7ce503fd 170 /* i0 has something i1 doesn't. */
a50699fd
JA
171 if (EQ (i1_val, Qnil))
172 return 0;
173
7ce503fd 174 /* i0 and i1 both have sym, but it has different values in each. */
a50699fd 175 i0_cdr = Fcdr (i0_cdr);
7ce503fd 176 if (! EQ (Fcar (Fcdr (i1_val)), Fcar (i0_cdr)))
a50699fd
JA
177 return 0;
178
179 i0_cdr = Fcdr (i0_cdr);
180 i1_len--;
181 }
182
7ce503fd 183 /* Lengths of the two plists were unequal. */
a50699fd
JA
184 if (i1_len > 0)
185 return 0;
186
187 return 1;
188}
189\f
a50699fd 190
a50699fd 191/* Traverse an interval tree TREE, performing FUNCTION on each node.
4a93c905 192 Pass FUNCTION two args: an interval, and ARG. */
a50699fd
JA
193
194void
4a93c905 195traverse_intervals (tree, position, depth, function, arg)
a50699fd 196 INTERVAL tree;
e0b63493 197 int position, depth;
0c60dfd7 198 void (* function) P_ ((INTERVAL, Lisp_Object));
4a93c905 199 Lisp_Object arg;
a50699fd
JA
200{
201 if (NULL_INTERVAL_P (tree))
202 return;
203
323a7ad4 204 traverse_intervals (tree->left, position, depth + 1, function, arg);
a50699fd
JA
205 position += LEFT_TOTAL_LENGTH (tree);
206 tree->position = position;
4a93c905 207 (*function) (tree, arg);
a50699fd 208 position += LENGTH (tree);
323a7ad4 209 traverse_intervals (tree->right, position, depth + 1, function, arg);
a50699fd
JA
210}
211\f
212#if 0
e39adcda
GM
213
214static int icount;
215static int idepth;
216static int zero_length;
217
7ce503fd 218/* These functions are temporary, for debugging purposes only. */
a50699fd
JA
219
220INTERVAL search_interval, found_interval;
221
222void
223check_for_interval (i)
224 register INTERVAL i;
225{
226 if (i == search_interval)
227 {
228 found_interval = i;
229 icount++;
230 }
231}
232
233INTERVAL
234search_for_interval (i, tree)
235 register INTERVAL i, tree;
236{
237 icount = 0;
238 search_interval = i;
239 found_interval = NULL_INTERVAL;
4a93c905 240 traverse_intervals (tree, 1, 0, &check_for_interval, Qnil);
a50699fd
JA
241 return found_interval;
242}
243
244static void
245inc_interval_count (i)
246 INTERVAL i;
247{
248 icount++;
249 if (LENGTH (i) == 0)
250 zero_length++;
251 if (depth > idepth)
252 idepth = depth;
253}
254
255int
256count_intervals (i)
257 register INTERVAL i;
258{
259 icount = 0;
260 idepth = 0;
261 zero_length = 0;
4a93c905 262 traverse_intervals (i, 1, 0, &inc_interval_count, Qnil);
a50699fd
JA
263
264 return icount;
265}
266
267static INTERVAL
268root_interval (interval)
269 INTERVAL interval;
270{
271 register INTERVAL i = interval;
272
273 while (! ROOT_INTERVAL_P (i))
439d5cb4 274 i = INTERVAL_PARENT (i);
a50699fd
JA
275
276 return i;
277}
278#endif
279\f
280/* Assuming that a left child exists, perform the following operation:
281
282 A B
283 / \ / \
284 B => A
285 / \ / \
286 c c
287*/
288
289static INTERVAL
290rotate_right (interval)
291 INTERVAL interval;
292{
293 INTERVAL i;
294 INTERVAL B = interval->left;
4314dea4 295 int old_total = interval->total_length;
a50699fd 296
7ce503fd 297 /* Deal with any Parent of A; make it point to B. */
a50699fd 298 if (! ROOT_INTERVAL_P (interval))
e39adcda
GM
299 {
300 if (AM_LEFT_CHILD (interval))
439d5cb4 301 INTERVAL_PARENT (interval)->left = B;
e39adcda 302 else
439d5cb4 303 INTERVAL_PARENT (interval)->right = B;
e39adcda 304 }
439d5cb4 305 COPY_INTERVAL_PARENT (B, interval);
a50699fd 306
4314dea4
RS
307 /* Make B the parent of A */
308 i = B->right;
309 B->right = interval;
439d5cb4 310 SET_INTERVAL_PARENT (interval, B);
a50699fd 311
4314dea4 312 /* Make A point to c */
a50699fd
JA
313 interval->left = i;
314 if (! NULL_INTERVAL_P (i))
439d5cb4 315 SET_INTERVAL_PARENT (i, interval);
4314dea4 316
550bd63a 317 /* A's total length is decreased by the length of B and its left child. */
4314dea4
RS
318 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
319
320 /* B must have the same total length of A. */
321 B->total_length = old_total;
a50699fd
JA
322
323 return B;
324}
4314dea4 325
a50699fd
JA
326/* Assuming that a right child exists, perform the following operation:
327
328 A B
329 / \ / \
330 B => A
331 / \ / \
332 c c
333*/
334
335static INTERVAL
336rotate_left (interval)
337 INTERVAL interval;
338{
339 INTERVAL i;
340 INTERVAL B = interval->right;
4314dea4 341 int old_total = interval->total_length;
a50699fd 342
4314dea4 343 /* Deal with any parent of A; make it point to B. */
a50699fd 344 if (! ROOT_INTERVAL_P (interval))
e39adcda
GM
345 {
346 if (AM_LEFT_CHILD (interval))
439d5cb4 347 INTERVAL_PARENT (interval)->left = B;
e39adcda 348 else
439d5cb4 349 INTERVAL_PARENT (interval)->right = B;
e39adcda 350 }
439d5cb4 351 COPY_INTERVAL_PARENT (B, interval);
a50699fd
JA
352
353 /* Make B the parent of A */
4314dea4
RS
354 i = B->left;
355 B->left = interval;
439d5cb4 356 SET_INTERVAL_PARENT (interval, B);
a50699fd
JA
357
358 /* Make A point to c */
359 interval->right = i;
360 if (! NULL_INTERVAL_P (i))
439d5cb4 361 SET_INTERVAL_PARENT (i, interval);
4314dea4 362
550bd63a 363 /* A's total length is decreased by the length of B and its right child. */
4314dea4
RS
364 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
365
366 /* B must have the same total length of A. */
367 B->total_length = old_total;
a50699fd
JA
368
369 return B;
370}
371\f
4314dea4
RS
372/* Balance an interval tree with the assumption that the subtrees
373 themselves are already balanced. */
374
375static INTERVAL
376balance_an_interval (i)
377 INTERVAL i;
378{
379 register int old_diff, new_diff;
380
381 while (1)
382 {
383 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
384 if (old_diff > 0)
385 {
386 new_diff = i->total_length - i->left->total_length
387 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
388 if (abs (new_diff) >= old_diff)
389 break;
390 i = rotate_right (i);
391 balance_an_interval (i->right);
392 }
393 else if (old_diff < 0)
394 {
395 new_diff = i->total_length - i->right->total_length
396 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
397 if (abs (new_diff) >= -old_diff)
398 break;
399 i = rotate_left (i);
400 balance_an_interval (i->left);
401 }
402 else
403 break;
404 }
405 return i;
406}
407
408/* Balance INTERVAL, potentially stuffing it back into its parent
409 Lisp Object. */
410
411static INLINE INTERVAL
412balance_possible_root_interval (interval)
413 register INTERVAL interval;
414{
415 Lisp_Object parent;
439d5cb4 416 int have_parent = 0;
4314dea4 417
439d5cb4 418 if (!INTERVAL_HAS_OBJECT (interval) && !INTERVAL_HAS_PARENT (interval))
4314dea4
RS
419 return interval;
420
439d5cb4
KR
421 if (INTERVAL_HAS_OBJECT (interval))
422 {
423 have_parent = 1;
424 GET_INTERVAL_OBJECT (parent, interval);
425 }
4314dea4
RS
426 interval = balance_an_interval (interval);
427
439d5cb4
KR
428 if (have_parent)
429 {
430 if (BUFFERP (parent))
431 BUF_INTERVALS (XBUFFER (parent)) = interval;
432 else if (STRINGP (parent))
433 XSTRING (parent)->intervals = interval;
434 }
4314dea4
RS
435
436 return interval;
437}
438
439/* Balance the interval tree TREE. Balancing is by weight
440 (the amount of text). */
441
442static INTERVAL
443balance_intervals_internal (tree)
444 register INTERVAL tree;
445{
446 /* Balance within each side. */
447 if (tree->left)
8f3b9b95 448 balance_intervals_internal (tree->left);
4314dea4 449 if (tree->right)
8f3b9b95 450 balance_intervals_internal (tree->right);
4314dea4
RS
451 return balance_an_interval (tree);
452}
453
454/* Advertised interface to balance intervals. */
455
456INTERVAL
457balance_intervals (tree)
458 INTERVAL tree;
459{
460 if (tree == NULL_INTERVAL)
461 return NULL_INTERVAL;
462
463 return balance_intervals_internal (tree);
464}
465\f
2bc7a79b
JB
466/* Split INTERVAL into two pieces, starting the second piece at
467 character position OFFSET (counting from 0), relative to INTERVAL.
468 INTERVAL becomes the left-hand piece, and the right-hand piece
469 (second, lexicographically) is returned.
90ba40fc
JA
470
471 The size and position fields of the two intervals are set based upon
472 those of the original interval. The property list of the new interval
473 is reset, thus it is up to the caller to do the right thing with the
474 result.
a50699fd
JA
475
476 Note that this does not change the position of INTERVAL; if it is a root,
7ce503fd 477 it is still a root after this operation. */
a50699fd
JA
478
479INTERVAL
90ba40fc 480split_interval_right (interval, offset)
a50699fd 481 INTERVAL interval;
90ba40fc 482 int offset;
a50699fd
JA
483{
484 INTERVAL new = make_interval ();
485 int position = interval->position;
2bc7a79b 486 int new_length = LENGTH (interval) - offset;
a50699fd 487
2bc7a79b 488 new->position = position + offset;
439d5cb4 489 SET_INTERVAL_PARENT (new, interval);
a50699fd 490
4314dea4 491 if (NULL_RIGHT_CHILD (interval))
a50699fd
JA
492 {
493 interval->right = new;
494 new->total_length = new_length;
a50699fd 495 }
cc6e2aaa
RS
496 else
497 {
498 /* Insert the new node between INTERVAL and its right child. */
499 new->right = interval->right;
439d5cb4 500 SET_INTERVAL_PARENT (interval->right, new);
cc6e2aaa
RS
501 interval->right = new;
502 new->total_length = new_length + new->right->total_length;
503 balance_an_interval (new);
504 }
505
4314dea4
RS
506 balance_possible_root_interval (interval);
507
a50699fd
JA
508 return new;
509}
510
2bc7a79b
JB
511/* Split INTERVAL into two pieces, starting the second piece at
512 character position OFFSET (counting from 0), relative to INTERVAL.
513 INTERVAL becomes the right-hand piece, and the left-hand piece
514 (first, lexicographically) is returned.
a50699fd 515
90ba40fc
JA
516 The size and position fields of the two intervals are set based upon
517 those of the original interval. The property list of the new interval
518 is reset, thus it is up to the caller to do the right thing with the
519 result.
520
521 Note that this does not change the position of INTERVAL; if it is a root,
7ce503fd 522 it is still a root after this operation. */
a50699fd
JA
523
524INTERVAL
90ba40fc 525split_interval_left (interval, offset)
a50699fd 526 INTERVAL interval;
90ba40fc 527 int offset;
a50699fd
JA
528{
529 INTERVAL new = make_interval ();
2bc7a79b 530 int new_length = offset;
a50699fd 531
a50699fd 532 new->position = interval->position;
2bc7a79b 533 interval->position = interval->position + offset;
439d5cb4 534 SET_INTERVAL_PARENT (new, interval);
a50699fd
JA
535
536 if (NULL_LEFT_CHILD (interval))
537 {
538 interval->left = new;
539 new->total_length = new_length;
a50699fd 540 }
cc6e2aaa
RS
541 else
542 {
543 /* Insert the new node between INTERVAL and its left child. */
544 new->left = interval->left;
439d5cb4 545 SET_INTERVAL_PARENT (new->left, new);
cc6e2aaa
RS
546 interval->left = new;
547 new->total_length = new_length + new->left->total_length;
548 balance_an_interval (new);
549 }
550
4314dea4 551 balance_possible_root_interval (interval);
a50699fd
JA
552
553 return new;
554}
555\f
944d4e4b
KH
556/* Return the proper position for the first character
557 described by the interval tree SOURCE.
558 This is 1 if the parent is a buffer,
559 0 if the parent is a string or if there is no parent.
560
561 Don't use this function on an interval which is the child
562 of another interval! */
563
564int
565interval_start_pos (source)
566 INTERVAL source;
567{
568 Lisp_Object parent;
569
570 if (NULL_INTERVAL_P (source))
571 return 0;
572
e0b8c689
KR
573 if (! INTERVAL_HAS_OBJECT (source))
574 return 0;
439d5cb4 575 GET_INTERVAL_OBJECT (parent, source);
944d4e4b
KH
576 if (BUFFERP (parent))
577 return BUF_BEG (XBUFFER (parent));
578 return 0;
579}
580
90ba40fc 581/* Find the interval containing text position POSITION in the text
24e3d3bf 582 represented by the interval tree TREE. POSITION is a buffer
944d4e4b
KH
583 position (starting from 1) or a string index (starting from 0).
584 If POSITION is at the end of the buffer or string,
585 return the interval containing the last character.
a50699fd 586
90ba40fc
JA
587 The `position' field, which is a cache of an interval's position,
588 is updated in the interval found. Other functions (e.g., next_interval)
7ce503fd 589 will update this cache based on the result of find_interval. */
90ba40fc 590
1863bbf8 591INTERVAL
a50699fd
JA
592find_interval (tree, position)
593 register INTERVAL tree;
594 register int position;
595{
24e3d3bf
JB
596 /* The distance from the left edge of the subtree at TREE
597 to POSITION. */
944d4e4b 598 register int relative_position;
a50699fd
JA
599
600 if (NULL_INTERVAL_P (tree))
601 return NULL_INTERVAL;
602
944d4e4b 603 relative_position = position;
439d5cb4
KR
604 if (INTERVAL_HAS_OBJECT (tree))
605 {
606 Lisp_Object parent;
607 GET_INTERVAL_OBJECT (parent, tree);
608 if (BUFFERP (parent))
609 relative_position -= BUF_BEG (XBUFFER (parent));
610 }
944d4e4b 611
24e3d3bf 612 if (relative_position > TOTAL_LENGTH (tree))
a50699fd 613 abort (); /* Paranoia */
a50699fd 614
4314dea4
RS
615 tree = balance_possible_root_interval (tree);
616
a50699fd
JA
617 while (1)
618 {
24e3d3bf 619 if (relative_position < LEFT_TOTAL_LENGTH (tree))
a50699fd
JA
620 {
621 tree = tree->left;
622 }
24e3d3bf
JB
623 else if (! NULL_RIGHT_CHILD (tree)
624 && relative_position >= (TOTAL_LENGTH (tree)
625 - RIGHT_TOTAL_LENGTH (tree)))
a50699fd
JA
626 {
627 relative_position -= (TOTAL_LENGTH (tree)
628 - RIGHT_TOTAL_LENGTH (tree));
629 tree = tree->right;
630 }
631 else
632 {
944d4e4b
KH
633 tree->position
634 = (position - relative_position /* the left edge of *tree */
635 + LEFT_TOTAL_LENGTH (tree)); /* the left edge of this interval */
24e3d3bf 636
a50699fd
JA
637 return tree;
638 }
639 }
640}
641\f
642/* Find the succeeding interval (lexicographically) to INTERVAL.
90ba40fc 643 Sets the `position' field based on that of INTERVAL (see
7ce503fd 644 find_interval). */
a50699fd
JA
645
646INTERVAL
647next_interval (interval)
648 register INTERVAL interval;
649{
650 register INTERVAL i = interval;
651 register int next_position;
652
653 if (NULL_INTERVAL_P (i))
654 return NULL_INTERVAL;
655 next_position = interval->position + LENGTH (interval);
656
657 if (! NULL_RIGHT_CHILD (i))
658 {
659 i = i->right;
660 while (! NULL_LEFT_CHILD (i))
661 i = i->left;
662
663 i->position = next_position;
664 return i;
665 }
666
667 while (! NULL_PARENT (i))
668 {
669 if (AM_LEFT_CHILD (i))
670 {
439d5cb4 671 i = INTERVAL_PARENT (i);
a50699fd
JA
672 i->position = next_position;
673 return i;
674 }
675
439d5cb4 676 i = INTERVAL_PARENT (i);
a50699fd
JA
677 }
678
679 return NULL_INTERVAL;
680}
681
682/* Find the preceding interval (lexicographically) to INTERVAL.
90ba40fc 683 Sets the `position' field based on that of INTERVAL (see
7ce503fd 684 find_interval). */
a50699fd
JA
685
686INTERVAL
687previous_interval (interval)
688 register INTERVAL interval;
689{
690 register INTERVAL i;
a50699fd
JA
691
692 if (NULL_INTERVAL_P (interval))
693 return NULL_INTERVAL;
694
695 if (! NULL_LEFT_CHILD (interval))
696 {
697 i = interval->left;
698 while (! NULL_RIGHT_CHILD (i))
699 i = i->right;
700
701 i->position = interval->position - LENGTH (i);
702 return i;
703 }
704
705 i = interval;
706 while (! NULL_PARENT (i))
707 {
708 if (AM_RIGHT_CHILD (i))
709 {
439d5cb4 710 i = INTERVAL_PARENT (i);
a50699fd
JA
711
712 i->position = interval->position - LENGTH (i);
713 return i;
714 }
439d5cb4 715 i = INTERVAL_PARENT (i);
a50699fd
JA
716 }
717
718 return NULL_INTERVAL;
719}
25eeac41
RS
720
721/* Find the interval containing POS given some non-NULL INTERVAL
75167cd4
RS
722 in the same tree. Note that we need to update interval->position
723 if we go down the tree. */
25eeac41
RS
724INTERVAL
725update_interval (i, pos)
726 register INTERVAL i;
727 int pos;
728{
729 if (NULL_INTERVAL_P (i))
730 return NULL_INTERVAL;
731
732 while (1)
733 {
734 if (pos < i->position)
735 {
736 /* Move left. */
75167cd4
RS
737 if (pos >= i->position - TOTAL_LENGTH (i->left))
738 {
739 i->left->position = i->position - TOTAL_LENGTH (i->left)
740 + LEFT_TOTAL_LENGTH (i->left);
741 i = i->left; /* Move to the left child */
742 }
25eeac41
RS
743 else if (NULL_PARENT (i))
744 error ("Point before start of properties");
75167cd4 745 else
439d5cb4 746 i = INTERVAL_PARENT (i);
25eeac41
RS
747 continue;
748 }
749 else if (pos >= INTERVAL_LAST_POS (i))
750 {
751 /* Move right. */
75167cd4
RS
752 if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right))
753 {
754 i->right->position = INTERVAL_LAST_POS (i) +
755 LEFT_TOTAL_LENGTH (i->right);
756 i = i->right; /* Move to the right child */
757 }
25eeac41
RS
758 else if (NULL_PARENT (i))
759 error ("Point after end of properties");
760 else
439d5cb4 761 i = INTERVAL_PARENT (i);
25eeac41
RS
762 continue;
763 }
764 else
765 return i;
766 }
767}
768
a50699fd 769\f
90ba40fc 770#if 0
a50699fd
JA
771/* Traverse a path down the interval tree TREE to the interval
772 containing POSITION, adjusting all nodes on the path for
773 an addition of LENGTH characters. Insertion between two intervals
774 (i.e., point == i->position, where i is second interval) means
775 text goes into second interval.
776
777 Modifications are needed to handle the hungry bits -- after simply
778 finding the interval at position (don't add length going down),
779 if it's the beginning of the interval, get the previous interval
8e6208c5 780 and check the hungry bits of both. Then add the length going back up
7ce503fd 781 to the root. */
a50699fd
JA
782
783static INTERVAL
784adjust_intervals_for_insertion (tree, position, length)
785 INTERVAL tree;
786 int position, length;
787{
788 register int relative_position;
789 register INTERVAL this;
790
791 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
792 abort ();
793
794 /* If inserting at point-max of a buffer, that position
795 will be out of range */
796 if (position > TOTAL_LENGTH (tree))
797 position = TOTAL_LENGTH (tree);
798 relative_position = position;
799 this = tree;
800
801 while (1)
802 {
803 if (relative_position <= LEFT_TOTAL_LENGTH (this))
804 {
805 this->total_length += length;
806 this = this->left;
807 }
808 else if (relative_position > (TOTAL_LENGTH (this)
809 - RIGHT_TOTAL_LENGTH (this)))
810 {
811 relative_position -= (TOTAL_LENGTH (this)
812 - RIGHT_TOTAL_LENGTH (this));
813 this->total_length += length;
814 this = this->right;
815 }
816 else
817 {
818 /* If we are to use zero-length intervals as buffer pointers,
7ce503fd 819 then this code will have to change. */
a50699fd
JA
820 this->total_length += length;
821 this->position = LEFT_TOTAL_LENGTH (this)
822 + position - relative_position + 1;
823 return tree;
824 }
825 }
826}
90ba40fc
JA
827#endif
828
829/* Effect an adjustment corresponding to the addition of LENGTH characters
830 of text. Do this by finding the interval containing POSITION in the
550bd63a 831 interval tree TREE, and then adjusting all of its ancestors by adding
90ba40fc
JA
832 LENGTH to them.
833
834 If POSITION is the first character of an interval, meaning that point
835 is actually between the two intervals, make the new text belong to
836 the interval which is "sticky".
837
1d1d7ba0 838 If both intervals are "sticky", then make them belong to the left-most
90ba40fc 839 interval. Another possibility would be to create a new interval for
7ce503fd 840 this text, and make it have the merged properties of both ends. */
90ba40fc
JA
841
842static INTERVAL
843adjust_intervals_for_insertion (tree, position, length)
844 INTERVAL tree;
845 int position, length;
846{
847 register INTERVAL i;
7ce503fd
RS
848 register INTERVAL temp;
849 int eobp = 0;
944d4e4b
KH
850 Lisp_Object parent;
851 int offset;
7ce503fd 852
90ba40fc
JA
853 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
854 abort ();
855
439d5cb4 856 GET_INTERVAL_OBJECT (parent, tree);
944d4e4b
KH
857 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
858
24e3d3bf
JB
859 /* If inserting at point-max of a buffer, that position will be out
860 of range. Remember that buffer positions are 1-based. */
944d4e4b
KH
861 if (position >= TOTAL_LENGTH (tree) + offset)
862 {
863 position = TOTAL_LENGTH (tree) + offset;
864 eobp = 1;
865 }
90ba40fc
JA
866
867 i = find_interval (tree, position);
7ce503fd 868
2313b945
RS
869 /* If in middle of an interval which is not sticky either way,
870 we must not just give its properties to the insertion.
f56b42ac
KH
871 So split this interval at the insertion point.
872
873 Originally, the if condition here was this:
874 (! (position == i->position || eobp)
875 && END_NONSTICKY_P (i)
876 && FRONT_NONSTICKY_P (i))
877 But, these macros are now unreliable because of introduction of
878 Vtext_property_default_nonsticky. So, we always check properties
879 one by one if POSITION is in middle of an interval. */
880 if (! (position == i->position || eobp))
2313b945 881 {
ca41a64d
RS
882 Lisp_Object tail;
883 Lisp_Object front, rear;
884
f56b42ac
KH
885 tail = i->plist;
886
887 /* Properties font-sticky and rear-nonsticky override
888 Vtext_property_default_nonsticky. So, if they are t, we can
889 skip one by one checking of properties. */
890 rear = textget (i->plist, Qrear_nonsticky);
891 if (! CONSP (rear) && ! NILP (rear))
892 {
893 /* All properties are nonsticky. We split the interval. */
894 goto check_done;
895 }
ca41a64d 896 front = textget (i->plist, Qfront_sticky);
f56b42ac
KH
897 if (! CONSP (front) && ! NILP (front))
898 {
899 /* All properties are sticky. We don't split the interval. */
900 tail = Qnil;
901 goto check_done;
902 }
ca41a64d 903
f56b42ac
KH
904 /* Does any actual property pose an actual problem? We break
905 the loop if we find a nonsticky property. */
906 for (; CONSP (tail); tail = Fcdr (XCDR (tail)))
ca41a64d 907 {
f56b42ac 908 Lisp_Object prop, tmp;
03699b14 909 prop = XCAR (tail);
ca41a64d 910
f56b42ac 911 /* Is this particular property front-sticky? */
ca41a64d
RS
912 if (CONSP (front) && ! NILP (Fmemq (prop, front)))
913 continue;
914
f56b42ac
KH
915 /* Is this particular property rear-nonsticky? */
916 if (CONSP (rear) && ! NILP (Fmemq (prop, rear)))
917 break;
918
919 /* Is this particular property recorded as sticky or
920 nonsticky in Vtext_property_default_nonsticky? */
921 tmp = Fassq (prop, Vtext_property_default_nonsticky);
922 if (CONSP (tmp))
923 {
924 if (NILP (tmp))
925 continue;
926 break;
927 }
928
929 /* By default, a text property is rear-sticky, thus we
930 continue the loop. */
ca41a64d
RS
931 }
932
f56b42ac 933 check_done:
ca41a64d
RS
934 /* If any property is a real problem, split the interval. */
935 if (! NILP (tail))
936 {
937 temp = split_interval_right (i, position - i->position);
938 copy_properties (i, temp);
939 i = temp;
940 }
2313b945
RS
941 }
942
90ba40fc 943 /* If we are positioned between intervals, check the stickiness of
7ce503fd
RS
944 both of them. We have to do this too, if we are at BEG or Z. */
945 if (position == i->position || eobp)
90ba40fc 946 {
7ce503fd
RS
947 register INTERVAL prev;
948
949 if (position == BEG)
950 prev = 0;
951 else if (eobp)
952 {
953 prev = i;
954 i = 0;
955 }
956 else
957 prev = previous_interval (i);
90ba40fc 958
7ce503fd
RS
959 /* Even if we are positioned between intervals, we default
960 to the left one if it exists. We extend it now and split
8e6208c5 961 off a part later, if stickiness demands it. */
439d5cb4 962 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
4314dea4
RS
963 {
964 temp->total_length += length;
965 temp = balance_possible_root_interval (temp);
966 }
7ce503fd
RS
967
968 /* If at least one interval has sticky properties,
f56b42ac
KH
969 we check the stickiness property by property.
970
971 Originally, the if condition here was this:
972 (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
973 But, these macros are now unreliable because of introduction
974 of Vtext_property_default_nonsticky. So, we always have to
975 check stickiness of properties one by one. If cache of
976 stickiness is implemented in the future, we may be able to
977 use those macros again. */
978 if (1)
7ce503fd 979 {
dd675b05 980 Lisp_Object pleft, pright;
7ce503fd
RS
981 struct interval newi;
982
dd675b05
KH
983 pleft = NULL_INTERVAL_P (prev) ? Qnil : prev->plist;
984 pright = NULL_INTERVAL_P (i) ? Qnil : i->plist;
7ce503fd
RS
985 newi.plist = merge_properties_sticky (pleft, pright);
986
ef1900f3 987 if (! prev) /* i.e. position == BEG */
7ce503fd
RS
988 {
989 if (! intervals_equal (i, &newi))
990 {
991 i = split_interval_left (i, length);
992 i->plist = newi.plist;
993 }
994 }
995 else if (! intervals_equal (prev, &newi))
996 {
997 prev = split_interval_right (prev,
998 position - prev->position);
999 prev->plist = newi.plist;
1000 if (! NULL_INTERVAL_P (i)
1001 && intervals_equal (prev, i))
1002 merge_interval_right (prev);
1003 }
1004
1005 /* We will need to update the cache here later. */
1006 }
1007 else if (! prev && ! NILP (i->plist))
1008 {
1009 /* Just split off a new interval at the left.
1010 Since I wasn't front-sticky, the empty plist is ok. */
1011 i = split_interval_left (i, length);
1012 }
90ba40fc
JA
1013 }
1014
7ce503fd
RS
1015 /* Otherwise just extend the interval. */
1016 else
90ba40fc 1017 {
439d5cb4 1018 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
4314dea4
RS
1019 {
1020 temp->total_length += length;
1021 temp = balance_possible_root_interval (temp);
1022 }
90ba40fc 1023 }
7ce503fd 1024
90ba40fc
JA
1025 return tree;
1026}
7ce503fd 1027
45d82bdc
KH
1028/* Any property might be front-sticky on the left, rear-sticky on the left,
1029 front-sticky on the right, or rear-sticky on the right; the 16 combinations
1030 can be arranged in a matrix with rows denoting the left conditions and
1031 columns denoting the right conditions:
1032 _ __ _
1033_ FR FR FR FR
1034FR__ 0 1 2 3
1035 _FR 4 5 6 7
1036FR 8 9 A B
1037 FR C D E F
1038
1039 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
1040 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
1041 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
1042 p8 L p9 L pa L pb L pc L pd L pe L pf L)
1043 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
1044 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
1045 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
1046 p8 R p9 R pa R pb R pc R pd R pe R pf R)
1047
1048 We inherit from whoever has a sticky side facing us. If both sides
1049 do (cases 2, 3, E, and F), then we inherit from whichever side has a
1050 non-nil value for the current property. If both sides do, then we take
1051 from the left.
1052
1053 When we inherit a property, we get its stickiness as well as its value.
1054 So, when we merge the above two lists, we expect to get this:
1055
1056 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
1057 rear-nonsticky (p6 pa)
1058 p0 L p1 L p2 L p3 L p6 R p7 R
1059 pa R pb R pc L pd L pe L pf L)
1060
1061 The optimizable special cases are:
1062 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
1063 left rear-nonsticky = t, right front-sticky = t (inherit right)
1064 left rear-nonsticky = t, right front-sticky = nil (inherit none)
1065*/
1066
7ce503fd
RS
1067Lisp_Object
1068merge_properties_sticky (pleft, pright)
1069 Lisp_Object pleft, pright;
1070{
dd675b05
KH
1071 register Lisp_Object props, front, rear;
1072 Lisp_Object lfront, lrear, rfront, rrear;
4ab19eb3 1073 register Lisp_Object tail1, tail2, sym, lval, rval, cat;
45d82bdc 1074 int use_left, use_right;
4ab19eb3 1075 int lpresent;
7ce503fd 1076
dd675b05
KH
1077 props = Qnil;
1078 front = Qnil;
1079 rear = Qnil;
1080 lfront = textget (pleft, Qfront_sticky);
1081 lrear = textget (pleft, Qrear_nonsticky);
1082 rfront = textget (pright, Qfront_sticky);
1083 rrear = textget (pright, Qrear_nonsticky);
1084
45d82bdc 1085 /* Go through each element of PRIGHT. */
f56b42ac 1086 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1)))
7ce503fd 1087 {
f56b42ac
KH
1088 Lisp_Object tmp;
1089
7ce503fd
RS
1090 sym = Fcar (tail1);
1091
1092 /* Sticky properties get special treatment. */
1093 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1094 continue;
45d82bdc
KH
1095
1096 rval = Fcar (Fcdr (tail1));
f56b42ac 1097 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2)))
45d82bdc
KH
1098 if (EQ (sym, Fcar (tail2)))
1099 break;
45d82bdc 1100
4ab19eb3
RS
1101 /* Indicate whether the property is explicitly defined on the left.
1102 (We know it is defined explicitly on the right
1103 because otherwise we don't get here.) */
1104 lpresent = ! NILP (tail2);
1105 lval = (NILP (tail2) ? Qnil : Fcar (Fcdr (tail2)));
1106
f56b42ac
KH
1107 /* Even if lrear or rfront say nothing about the stickiness of
1108 SYM, Vtext_property_default_nonsticky may give default
1109 stickiness to SYM. */
1110 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1111 use_left = (lpresent
1112 && ! (TMEM (sym, lrear)
1113 || CONSP (tmp) && ! NILP (XCDR (tmp))));
1114 use_right = (TMEM (sym, rfront)
1115 || (CONSP (tmp) && NILP (XCDR (tmp))));
45d82bdc
KH
1116 if (use_left && use_right)
1117 {
4ab19eb3
RS
1118 if (NILP (lval))
1119 use_left = 0;
1120 else if (NILP (rval))
1121 use_right = 0;
45d82bdc
KH
1122 }
1123 if (use_left)
7ce503fd 1124 {
45d82bdc
KH
1125 /* We build props as (value sym ...) rather than (sym value ...)
1126 because we plan to nreverse it when we're done. */
4ab19eb3 1127 props = Fcons (lval, Fcons (sym, props));
45d82bdc 1128 if (TMEM (sym, lfront))
7ce503fd 1129 front = Fcons (sym, front);
45d82bdc
KH
1130 if (TMEM (sym, lrear))
1131 rear = Fcons (sym, rear);
7ce503fd 1132 }
45d82bdc 1133 else if (use_right)
7ce503fd 1134 {
4ab19eb3 1135 props = Fcons (rval, Fcons (sym, props));
45d82bdc
KH
1136 if (TMEM (sym, rfront))
1137 front = Fcons (sym, front);
1138 if (TMEM (sym, rrear))
1139 rear = Fcons (sym, rear);
7ce503fd
RS
1140 }
1141 }
45d82bdc
KH
1142
1143 /* Now go through each element of PLEFT. */
f56b42ac 1144 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2)))
7ce503fd 1145 {
f56b42ac
KH
1146 Lisp_Object tmp;
1147
7ce503fd
RS
1148 sym = Fcar (tail2);
1149
1150 /* Sticky properties get special treatment. */
1151 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1152 continue;
1153
45d82bdc 1154 /* If sym is in PRIGHT, we've already considered it. */
f56b42ac 1155 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1)))
7ce503fd
RS
1156 if (EQ (sym, Fcar (tail1)))
1157 break;
45d82bdc
KH
1158 if (! NILP (tail1))
1159 continue;
1160
1161 lval = Fcar (Fcdr (tail2));
1162
f56b42ac
KH
1163 /* Even if lrear or rfront say nothing about the stickiness of
1164 SYM, Vtext_property_default_nonsticky may give default
1165 stickiness to SYM. */
1166 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1167
45d82bdc 1168 /* Since rval is known to be nil in this loop, the test simplifies. */
f56b42ac 1169 if (! (TMEM (sym, lrear) || (CONSP (tmp) && ! NILP (XCDR (tmp)))))
7ce503fd 1170 {
4ab19eb3 1171 props = Fcons (lval, Fcons (sym, props));
45d82bdc
KH
1172 if (TMEM (sym, lfront))
1173 front = Fcons (sym, front);
1174 }
f56b42ac 1175 else if (TMEM (sym, rfront) || (CONSP (tmp) && NILP (XCDR (tmp))))
45d82bdc
KH
1176 {
1177 /* The value is nil, but we still inherit the stickiness
1178 from the right. */
7ce503fd 1179 front = Fcons (sym, front);
45d82bdc 1180 if (TMEM (sym, rrear))
7ce503fd
RS
1181 rear = Fcons (sym, rear);
1182 }
1183 }
550bd63a 1184 props = Fnreverse (props);
7ce503fd 1185 if (! NILP (rear))
550bd63a 1186 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
4ab19eb3
RS
1187
1188 cat = textget (props, Qcategory);
1189 if (! NILP (front)
1190 &&
1191 /* If we have inherited a front-stick category property that is t,
1192 we don't need to set up a detailed one. */
1193 ! (! NILP (cat) && SYMBOLP (cat)
1194 && EQ (Fget (cat, Qfront_sticky), Qt)))
45d82bdc 1195 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
7ce503fd 1196 return props;
7ce503fd
RS
1197}
1198
a50699fd 1199\f
90ba40fc
JA
1200/* Delete an node I from its interval tree by merging its subtrees
1201 into one subtree which is then returned. Caller is responsible for
7ce503fd 1202 storing the resulting subtree into its parent. */
a50699fd
JA
1203
1204static INTERVAL
1205delete_node (i)
1206 register INTERVAL i;
1207{
1208 register INTERVAL migrate, this;
1209 register int migrate_amt;
1210
1211 if (NULL_INTERVAL_P (i->left))
1212 return i->right;
1213 if (NULL_INTERVAL_P (i->right))
1214 return i->left;
1215
1216 migrate = i->left;
1217 migrate_amt = i->left->total_length;
1218 this = i->right;
1219 this->total_length += migrate_amt;
1220 while (! NULL_INTERVAL_P (this->left))
1221 {
1222 this = this->left;
1223 this->total_length += migrate_amt;
1224 }
1225 this->left = migrate;
439d5cb4 1226 SET_INTERVAL_PARENT (migrate, this);
a50699fd
JA
1227
1228 return i->right;
1229}
1230
1231/* Delete interval I from its tree by calling `delete_node'
1232 and properly connecting the resultant subtree.
1233
1234 I is presumed to be empty; that is, no adjustments are made
7ce503fd 1235 for the length of I. */
a50699fd
JA
1236
1237void
1238delete_interval (i)
1239 register INTERVAL i;
1240{
1241 register INTERVAL parent;
1242 int amt = LENGTH (i);
1243
7ce503fd 1244 if (amt > 0) /* Only used on zero-length intervals now. */
a50699fd
JA
1245 abort ();
1246
1247 if (ROOT_INTERVAL_P (i))
1248 {
dd675b05 1249 Lisp_Object owner;
439d5cb4 1250 GET_INTERVAL_OBJECT (owner, i);
a50699fd
JA
1251 parent = delete_node (i);
1252 if (! NULL_INTERVAL_P (parent))
439d5cb4 1253 SET_INTERVAL_OBJECT (parent, owner);
a50699fd 1254
b629dd47 1255 if (BUFFERP (owner))
e5d967c9 1256 BUF_INTERVALS (XBUFFER (owner)) = parent;
b629dd47 1257 else if (STRINGP (owner))
a50699fd
JA
1258 XSTRING (owner)->intervals = parent;
1259 else
1260 abort ();
1261
1262 return;
1263 }
1264
439d5cb4 1265 parent = INTERVAL_PARENT (i);
a50699fd
JA
1266 if (AM_LEFT_CHILD (i))
1267 {
1268 parent->left = delete_node (i);
1269 if (! NULL_INTERVAL_P (parent->left))
439d5cb4 1270 SET_INTERVAL_PARENT (parent->left, parent);
a50699fd
JA
1271 }
1272 else
1273 {
1274 parent->right = delete_node (i);
1275 if (! NULL_INTERVAL_P (parent->right))
439d5cb4 1276 SET_INTERVAL_PARENT (parent->right, parent);
a50699fd
JA
1277 }
1278}
1279\f
24e3d3bf
JB
1280/* Find the interval in TREE corresponding to the relative position
1281 FROM and delete as much as possible of AMOUNT from that interval.
1282 Return the amount actually deleted, and if the interval was
1283 zeroed-out, delete that interval node from the tree.
1284
1285 Note that FROM is actually origin zero, aka relative to the
1286 leftmost edge of tree. This is appropriate since we call ourselves
1287 recursively on subtrees.
a50699fd 1288
1d1d7ba0 1289 Do this by recursing down TREE to the interval in question, and
7ce503fd 1290 deleting the appropriate amount of text. */
a50699fd
JA
1291
1292static int
1293interval_deletion_adjustment (tree, from, amount)
1294 register INTERVAL tree;
1295 register int from, amount;
1296{
1297 register int relative_position = from;
1298
1299 if (NULL_INTERVAL_P (tree))
1300 return 0;
1301
1302 /* Left branch */
24e3d3bf 1303 if (relative_position < LEFT_TOTAL_LENGTH (tree))
a50699fd
JA
1304 {
1305 int subtract = interval_deletion_adjustment (tree->left,
1306 relative_position,
1307 amount);
1308 tree->total_length -= subtract;
1309 return subtract;
1310 }
1311 /* Right branch */
24e3d3bf
JB
1312 else if (relative_position >= (TOTAL_LENGTH (tree)
1313 - RIGHT_TOTAL_LENGTH (tree)))
a50699fd
JA
1314 {
1315 int subtract;
1316
1317 relative_position -= (tree->total_length
1318 - RIGHT_TOTAL_LENGTH (tree));
1319 subtract = interval_deletion_adjustment (tree->right,
1320 relative_position,
1321 amount);
1322 tree->total_length -= subtract;
1323 return subtract;
1324 }
7ce503fd 1325 /* Here -- this node. */
a50699fd
JA
1326 else
1327 {
24e3d3bf
JB
1328 /* How much can we delete from this interval? */
1329 int my_amount = ((tree->total_length
1330 - RIGHT_TOTAL_LENGTH (tree))
1331 - relative_position);
1332
1333 if (amount > my_amount)
1334 amount = my_amount;
1335
1336 tree->total_length -= amount;
1337 if (LENGTH (tree) == 0)
1338 delete_interval (tree);
1339
1340 return amount;
a50699fd
JA
1341 }
1342
7ce503fd 1343 /* Never reach here. */
a50699fd
JA
1344}
1345
24e3d3bf
JB
1346/* Effect the adjustments necessary to the interval tree of BUFFER to
1347 correspond to the deletion of LENGTH characters from that buffer
1348 text. The deletion is effected at position START (which is a
7ce503fd 1349 buffer position, i.e. origin 1). */
1d1d7ba0 1350
a50699fd
JA
1351static void
1352adjust_intervals_for_deletion (buffer, start, length)
1353 struct buffer *buffer;
1354 int start, length;
1355{
1356 register int left_to_delete = length;
e5d967c9 1357 register INTERVAL tree = BUF_INTERVALS (buffer);
944d4e4b
KH
1358 Lisp_Object parent;
1359 int offset;
1360
439d5cb4 1361 GET_INTERVAL_OBJECT (parent, tree);
944d4e4b 1362 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
a50699fd
JA
1363
1364 if (NULL_INTERVAL_P (tree))
1365 return;
1366
944d4e4b
KH
1367 if (start > offset + TOTAL_LENGTH (tree)
1368 || start + length > offset + TOTAL_LENGTH (tree))
24e3d3bf
JB
1369 abort ();
1370
a50699fd
JA
1371 if (length == TOTAL_LENGTH (tree))
1372 {
e5d967c9 1373 BUF_INTERVALS (buffer) = NULL_INTERVAL;
a50699fd
JA
1374 return;
1375 }
1376
1377 if (ONLY_INTERVAL_P (tree))
1378 {
1379 tree->total_length -= length;
1380 return;
1381 }
1382
944d4e4b
KH
1383 if (start > offset + TOTAL_LENGTH (tree))
1384 start = offset + TOTAL_LENGTH (tree);
a50699fd
JA
1385 while (left_to_delete > 0)
1386 {
944d4e4b 1387 left_to_delete -= interval_deletion_adjustment (tree, start - offset,
a50699fd 1388 left_to_delete);
e5d967c9 1389 tree = BUF_INTERVALS (buffer);
a50699fd
JA
1390 if (left_to_delete == tree->total_length)
1391 {
e5d967c9 1392 BUF_INTERVALS (buffer) = NULL_INTERVAL;
a50699fd
JA
1393 return;
1394 }
1395 }
1396}
1397\f
eb8c3be9 1398/* Make the adjustments necessary to the interval tree of BUFFER to
1d1d7ba0
JA
1399 represent an addition or deletion of LENGTH characters starting
1400 at position START. Addition or deletion is indicated by the sign
7ce503fd 1401 of LENGTH. */
a50699fd
JA
1402
1403INLINE void
1404offset_intervals (buffer, start, length)
1405 struct buffer *buffer;
1406 int start, length;
1407{
e5d967c9 1408 if (NULL_INTERVAL_P (BUF_INTERVALS (buffer)) || length == 0)
a50699fd
JA
1409 return;
1410
1411 if (length > 0)
e5d967c9 1412 adjust_intervals_for_insertion (BUF_INTERVALS (buffer), start, length);
a50699fd
JA
1413 else
1414 adjust_intervals_for_deletion (buffer, start, -length);
1415}
9c79dd1b
JA
1416\f
1417/* Merge interval I with its lexicographic successor. The resulting
1418 interval is returned, and has the properties of the original
1419 successor. The properties of I are lost. I is removed from the
1420 interval tree.
1421
1422 IMPORTANT:
1423 The caller must verify that this is not the last (rightmost)
7ce503fd 1424 interval. */
9c79dd1b
JA
1425
1426INTERVAL
1427merge_interval_right (i)
1428 register INTERVAL i;
1429{
1430 register int absorb = LENGTH (i);
1431 register INTERVAL successor;
1432
7ce503fd 1433 /* Zero out this interval. */
9c79dd1b
JA
1434 i->total_length -= absorb;
1435
7ce503fd 1436 /* Find the succeeding interval. */
9c79dd1b 1437 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
7ce503fd 1438 as we descend. */
9c79dd1b
JA
1439 {
1440 successor = i->right;
1441 while (! NULL_LEFT_CHILD (successor))
1442 {
1443 successor->total_length += absorb;
1444 successor = successor->left;
1445 }
1446
1447 successor->total_length += absorb;
1448 delete_interval (i);
1449 return successor;
1450 }
1451
1452 successor = i;
1453 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
7ce503fd 1454 we ascend. */
9c79dd1b
JA
1455 {
1456 if (AM_LEFT_CHILD (successor))
1457 {
439d5cb4 1458 successor = INTERVAL_PARENT (successor);
9c79dd1b
JA
1459 delete_interval (i);
1460 return successor;
1461 }
1462
439d5cb4 1463 successor = INTERVAL_PARENT (successor);
9c79dd1b
JA
1464 successor->total_length -= absorb;
1465 }
1466
1467 /* This must be the rightmost or last interval and cannot
7ce503fd 1468 be merged right. The caller should have known. */
9c79dd1b
JA
1469 abort ();
1470}
1471\f
1472/* Merge interval I with its lexicographic predecessor. The resulting
1473 interval is returned, and has the properties of the original predecessor.
1474 The properties of I are lost. Interval node I is removed from the tree.
1475
1476 IMPORTANT:
7ce503fd 1477 The caller must verify that this is not the first (leftmost) interval. */
9c79dd1b
JA
1478
1479INTERVAL
1480merge_interval_left (i)
1481 register INTERVAL i;
1482{
1483 register int absorb = LENGTH (i);
1484 register INTERVAL predecessor;
1485
7ce503fd 1486 /* Zero out this interval. */
9c79dd1b
JA
1487 i->total_length -= absorb;
1488
7ce503fd 1489 /* Find the preceding interval. */
9c79dd1b 1490 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
7ce503fd 1491 adding ABSORB as we go. */
9c79dd1b
JA
1492 {
1493 predecessor = i->left;
1494 while (! NULL_RIGHT_CHILD (predecessor))
1495 {
1496 predecessor->total_length += absorb;
1497 predecessor = predecessor->right;
1498 }
1499
1500 predecessor->total_length += absorb;
1501 delete_interval (i);
1502 return predecessor;
1503 }
1504
1505 predecessor = i;
1506 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
7ce503fd 1507 subtracting ABSORB. */
9c79dd1b
JA
1508 {
1509 if (AM_RIGHT_CHILD (predecessor))
1510 {
439d5cb4 1511 predecessor = INTERVAL_PARENT (predecessor);
9c79dd1b
JA
1512 delete_interval (i);
1513 return predecessor;
1514 }
1515
439d5cb4 1516 predecessor = INTERVAL_PARENT (predecessor);
9c79dd1b
JA
1517 predecessor->total_length -= absorb;
1518 }
a50699fd 1519
9c79dd1b 1520 /* This must be the leftmost or first interval and cannot
7ce503fd 1521 be merged left. The caller should have known. */
9c79dd1b
JA
1522 abort ();
1523}
1524\f
1d1d7ba0
JA
1525/* Make an exact copy of interval tree SOURCE which descends from
1526 PARENT. This is done by recursing through SOURCE, copying
1527 the current interval and its properties, and then adjusting
7ce503fd 1528 the pointers of the copy. */
1d1d7ba0 1529
a50699fd
JA
1530static INTERVAL
1531reproduce_tree (source, parent)
1532 INTERVAL source, parent;
1533{
1534 register INTERVAL t = make_interval ();
1535
1536 bcopy (source, t, INTERVAL_SIZE);
1537 copy_properties (source, t);
439d5cb4
KR
1538 SET_INTERVAL_PARENT (t, parent);
1539 if (! NULL_LEFT_CHILD (source))
1540 t->left = reproduce_tree (source->left, t);
1541 if (! NULL_RIGHT_CHILD (source))
1542 t->right = reproduce_tree (source->right, t);
1543
1544 return t;
1545}
1546
1547static INTERVAL
1548reproduce_tree_obj (source, parent)
1549 INTERVAL source;
1550 Lisp_Object parent;
1551{
1552 register INTERVAL t = make_interval ();
1553
1554 bcopy (source, t, INTERVAL_SIZE);
1555 copy_properties (source, t);
1556 SET_INTERVAL_OBJECT (t, parent);
a50699fd
JA
1557 if (! NULL_LEFT_CHILD (source))
1558 t->left = reproduce_tree (source->left, t);
1559 if (! NULL_RIGHT_CHILD (source))
1560 t->right = reproduce_tree (source->right, t);
1561
1562 return t;
1563}
1564
24e3d3bf
JB
1565#if 0
1566/* Nobody calls this. Perhaps it's a vestige of an earlier design. */
1567
1d1d7ba0
JA
1568/* Make a new interval of length LENGTH starting at START in the
1569 group of intervals INTERVALS, which is actually an interval tree.
1570 Returns the new interval.
1571
1572 Generate an error if the new positions would overlap an existing
7ce503fd 1573 interval. */
1d1d7ba0 1574
a50699fd
JA
1575static INTERVAL
1576make_new_interval (intervals, start, length)
1577 INTERVAL intervals;
1578 int start, length;
1579{
1580 INTERVAL slot;
1581
1582 slot = find_interval (intervals, start);
1583 if (start + length > slot->position + LENGTH (slot))
1584 error ("Interval would overlap");
1585
1586 if (start == slot->position && length == LENGTH (slot))
1587 return slot;
1588
1589 if (slot->position == start)
1590 {
7ce503fd 1591 /* New right node. */
2bc7a79b 1592 split_interval_right (slot, length);
a50699fd
JA
1593 return slot;
1594 }
1595
1596 if (slot->position + LENGTH (slot) == start + length)
1597 {
7ce503fd 1598 /* New left node. */
2bc7a79b 1599 split_interval_left (slot, LENGTH (slot) - length);
a50699fd
JA
1600 return slot;
1601 }
1602
7ce503fd 1603 /* Convert interval SLOT into three intervals. */
2bc7a79b
JB
1604 split_interval_left (slot, start - slot->position);
1605 split_interval_right (slot, length);
a50699fd
JA
1606 return slot;
1607}
24e3d3bf 1608#endif
294efdbe 1609\f
9c79dd1b 1610/* Insert the intervals of SOURCE into BUFFER at POSITION.
0b79989f 1611 LENGTH is the length of the text in SOURCE.
a50699fd 1612
944d4e4b
KH
1613 The `position' field of the SOURCE intervals is assumed to be
1614 consistent with its parent; therefore, SOURCE must be an
1615 interval tree made with copy_interval or must be the whole
1616 tree of a buffer or a string.
1617
2bc7a79b
JB
1618 This is used in insdel.c when inserting Lisp_Strings into the
1619 buffer. The text corresponding to SOURCE is already in the buffer
1620 when this is called. The intervals of new tree are a copy of those
1621 belonging to the string being inserted; intervals are never
1622 shared.
a50699fd 1623
0b79989f
RS
1624 If the inserted text had no intervals associated, and we don't
1625 want to inherit the surrounding text's properties, this function
a50699fd 1626 simply returns -- offset_intervals should handle placing the
90ba40fc 1627 text in the correct interval, depending on the sticky bits.
a50699fd
JA
1628
1629 If the inserted text had properties (intervals), then there are two
1630 cases -- either insertion happened in the middle of some interval,
1631 or between two intervals.
1632
1633 If the text goes into the middle of an interval, then new
1634 intervals are created in the middle with only the properties of
1635 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1636 which case the new text has the union of its properties and those
1637 of the text into which it was inserted.
1638
1639 If the text goes between two intervals, then if neither interval
90ba40fc
JA
1640 had its appropriate sticky property set (front_sticky, rear_sticky),
1641 the new text has only its properties. If one of the sticky properties
a50699fd 1642 is set, then the new text "sticks" to that region and its properties
eb8c3be9 1643 depend on merging as above. If both the preceding and succeeding
90ba40fc
JA
1644 intervals to the new text are "sticky", then the new text retains
1645 only its properties, as if neither sticky property were set. Perhaps
a50699fd 1646 we should consider merging all three sets of properties onto the new
7ce503fd 1647 text... */
a50699fd
JA
1648
1649void
0b79989f 1650graft_intervals_into_buffer (source, position, length, buffer, inherit)
9c79dd1b 1651 INTERVAL source;
0b79989f 1652 int position, length;
9c79dd1b 1653 struct buffer *buffer;
7ea69158 1654 int inherit;
a50699fd 1655{
323a7ad4 1656 register INTERVAL under, over, this, prev;
e5d967c9 1657 register INTERVAL tree;
323a7ad4 1658 int middle;
a50699fd 1659
e5d967c9
RS
1660 tree = BUF_INTERVALS (buffer);
1661
a50699fd 1662 /* If the new text has no properties, it becomes part of whatever
7ce503fd 1663 interval it was inserted into. */
9c79dd1b 1664 if (NULL_INTERVAL_P (source))
0b79989f
RS
1665 {
1666 Lisp_Object buf;
08b05272 1667 if (!inherit && ! NULL_INTERVAL_P (tree))
0b79989f 1668 {
6445414a 1669 int saved_inhibit_modification_hooks = inhibit_modification_hooks;
55cfc731 1670 XSETBUFFER (buf, buffer);
6445414a 1671 inhibit_modification_hooks = 1;
0b79989f
RS
1672 Fset_text_properties (make_number (position),
1673 make_number (position + length),
1674 Qnil, buf);
6445414a 1675 inhibit_modification_hooks = saved_inhibit_modification_hooks;
0b79989f 1676 }
e5d967c9
RS
1677 if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer)))
1678 BUF_INTERVALS (buffer) = balance_an_interval (BUF_INTERVALS (buffer));
0b79989f
RS
1679 return;
1680 }
a50699fd 1681
a50699fd
JA
1682 if (NULL_INTERVAL_P (tree))
1683 {
1684 /* The inserted text constitutes the whole buffer, so
7ce503fd 1685 simply copy over the interval structure. */
2bc7a79b 1686 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == TOTAL_LENGTH (source))
a50699fd 1687 {
b8e4857c 1688 Lisp_Object buf;
55cfc731 1689 XSETBUFFER (buf, buffer);
439d5cb4 1690 BUF_INTERVALS (buffer) = reproduce_tree_obj (source, buf);
944d4e4b
KH
1691 BUF_INTERVALS (buffer)->position = 1;
1692
1693 /* Explicitly free the old tree here? */
a50699fd
JA
1694
1695 return;
1696 }
1697
1698 /* Create an interval tree in which to place a copy
7ce503fd 1699 of the intervals of the inserted string. */
a50699fd 1700 {
249a6da9 1701 Lisp_Object buf;
55cfc731 1702 XSETBUFFER (buf, buffer);
323a7ad4 1703 tree = create_root_interval (buf);
a50699fd
JA
1704 }
1705 }
7ea69158
RS
1706 else if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
1707 /* If the buffer contains only the new string, but
1708 there was already some interval tree there, then it may be
1709 some zero length intervals. Eventually, do something clever
1710 about inserting properly. For now, just waste the old intervals. */
1711 {
439d5cb4 1712 BUF_INTERVALS (buffer) = reproduce_tree (source, INTERVAL_PARENT (tree));
944d4e4b 1713 BUF_INTERVALS (buffer)->position = 1;
7ea69158 1714 /* Explicitly free the old tree here. */
a50699fd 1715
7ea69158
RS
1716 return;
1717 }
1718 /* Paranoia -- the text has already been added, so this buffer
1719 should be of non-zero length. */
1720 else if (TOTAL_LENGTH (tree) == 0)
1721 abort ();
a50699fd
JA
1722
1723 this = under = find_interval (tree, position);
1724 if (NULL_INTERVAL_P (under)) /* Paranoia */
1725 abort ();
944d4e4b 1726 over = find_interval (source, interval_start_pos (source));
a50699fd 1727
323a7ad4
RS
1728 /* Here for insertion in the middle of an interval.
1729 Split off an equivalent interval to the right,
1730 then don't bother with it any more. */
a50699fd 1731
323a7ad4 1732 if (position > under->position)
a50699fd
JA
1733 {
1734 INTERVAL end_unchanged
2bc7a79b 1735 = split_interval_left (this, position - under->position);
a50699fd 1736 copy_properties (under, end_unchanged);
323a7ad4 1737 under->position = position;
f56b42ac
KH
1738#if 0
1739 /* This code has no effect. */
323a7ad4
RS
1740 prev = 0;
1741 middle = 1;
f56b42ac 1742#endif /* 0 */
a50699fd 1743 }
323a7ad4
RS
1744 else
1745 {
f56b42ac
KH
1746 /* This call may have some effect because previous_interval may
1747 update `position' fields of intervals. Thus, don't ignore it
1748 for the moment. Someone please tell me the truth (K.Handa). */
323a7ad4 1749 prev = previous_interval (under);
f56b42ac
KH
1750#if 0
1751 /* But, this code surely has no effect. And, anyway,
1752 END_NONSTICKY_P is unreliable now. */
7ce503fd 1753 if (prev && !END_NONSTICKY_P (prev))
323a7ad4 1754 prev = 0;
f56b42ac 1755#endif /* 0 */
323a7ad4
RS
1756 }
1757
1758 /* Insertion is now at beginning of UNDER. */
a50699fd 1759
323a7ad4 1760 /* The inserted text "sticks" to the interval `under',
7ce503fd
RS
1761 which means it gets those properties.
1762 The properties of under are the result of
8e6208c5 1763 adjust_intervals_for_insertion, so stickiness has
7ce503fd
RS
1764 already been taken care of. */
1765
a50699fd
JA
1766 while (! NULL_INTERVAL_P (over))
1767 {
767809fb 1768 if (LENGTH (over) < LENGTH (under))
7ce503fd
RS
1769 {
1770 this = split_interval_left (under, LENGTH (over));
1771 copy_properties (under, this);
1772 }
323a7ad4
RS
1773 else
1774 this = under;
a50699fd 1775 copy_properties (over, this);
7ea69158 1776 if (inherit)
7ce503fd
RS
1777 merge_properties (over, this);
1778 else
1779 copy_properties (over, this);
a50699fd
JA
1780 over = next_interval (over);
1781 }
1782
e5d967c9
RS
1783 if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer)))
1784 BUF_INTERVALS (buffer) = balance_an_interval (BUF_INTERVALS (buffer));
a50699fd
JA
1785 return;
1786}
1787
5cae0ec6
RS
1788/* Get the value of property PROP from PLIST,
1789 which is the plist of an interval.
70743ff1 1790 We check for direct properties, for categories with property PROP,
06d92327 1791 and for PROP appearing on the default-text-properties list. */
5cae0ec6
RS
1792
1793Lisp_Object
323a7ad4
RS
1794textget (plist, prop)
1795 Lisp_Object plist;
1796 register Lisp_Object prop;
1797{
5cae0ec6
RS
1798 register Lisp_Object tail, fallback;
1799 fallback = Qnil;
323a7ad4
RS
1800
1801 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1802 {
1803 register Lisp_Object tem;
1804 tem = Fcar (tail);
1805 if (EQ (prop, tem))
1806 return Fcar (Fcdr (tail));
5cae0ec6 1807 if (EQ (tem, Qcategory))
5dd6606e
RS
1808 {
1809 tem = Fcar (Fcdr (tail));
1810 if (SYMBOLP (tem))
1811 fallback = Fget (tem, prop);
1812 }
323a7ad4 1813 }
5cae0ec6 1814
70743ff1
BG
1815 if (! NILP (fallback))
1816 return fallback;
06d92327
BG
1817 if (CONSP (Vdefault_text_properties))
1818 return Fplist_get (Vdefault_text_properties, prop);
70743ff1 1819 return Qnil;
323a7ad4 1820}
7ce503fd 1821
294efdbe 1822\f
ef1900f3
RS
1823/* Set point "temporarily", without checking any text properties. */
1824
1825INLINE void
1826temp_set_point (buffer, charpos)
1827 struct buffer *buffer;
1828 int charpos;
1829{
1830 temp_set_point_both (buffer, charpos,
1831 buf_charpos_to_bytepos (buffer, charpos));
1832}
1833
1834/* Set point in BUFFER "temporarily" to CHARPOS, which corresponds to
1835 byte position BYTEPOS. */
1836
1837INLINE void
1838temp_set_point_both (buffer, charpos, bytepos)
2189766e 1839 int charpos, bytepos;
ef1900f3
RS
1840 struct buffer *buffer;
1841{
1842 /* In a single-byte buffer, the two positions must be equal. */
1843 if (BUF_ZV (buffer) == BUF_ZV_BYTE (buffer)
1844 && charpos != bytepos)
1845 abort ();
1846
1847 if (charpos > bytepos)
1848 abort ();
1849
1850 if (charpos > BUF_ZV (buffer) || charpos < BUF_BEGV (buffer))
1851 abort ();
1852
1853 BUF_PT_BYTE (buffer) = bytepos;
1854 BUF_PT (buffer) = charpos;
1855}
1856
1857/* Set point in BUFFER to CHARPOS. If the target position is
f65013b0 1858 before an intangible character, move to an ok place. */
a50699fd
JA
1859
1860void
ef1900f3 1861set_point (buffer, charpos)
a50699fd 1862 register struct buffer *buffer;
ef1900f3
RS
1863 register int charpos;
1864{
1865 set_point_both (buffer, charpos, buf_charpos_to_bytepos (buffer, charpos));
1866}
1867
1868/* Set point in BUFFER to CHARPOS, which corresponds to byte
1869 position BYTEPOS. If the target position is
1870 before an intangible character, move to an ok place. */
1871
1872void
1873set_point_both (buffer, charpos, bytepos)
1874 register struct buffer *buffer;
2189766e 1875 register int charpos, bytepos;
a50699fd 1876{
e39adcda 1877 register INTERVAL to, from, toprev, fromprev;
a50699fd 1878 int buffer_point;
e5d967c9 1879 int old_position = BUF_PT (buffer);
ef1900f3 1880 int backwards = (charpos < old_position ? 1 : 0);
580fae94
RS
1881 int have_overlays;
1882 int original_position;
a50699fd 1883
b6a0ebc3
RS
1884 buffer->point_before_scroll = Qnil;
1885
ef1900f3 1886 if (charpos == BUF_PT (buffer))
a50699fd
JA
1887 return;
1888
ef1900f3
RS
1889 /* In a single-byte buffer, the two positions must be equal. */
1890 if (BUF_ZV (buffer) == BUF_ZV_BYTE (buffer)
1891 && charpos != bytepos)
1892 abort ();
1893
62056764
JB
1894 /* Check this now, before checking if the buffer has any intervals.
1895 That way, we can catch conditions which break this sanity check
1896 whether or not there are intervals in the buffer. */
ef1900f3 1897 if (charpos > BUF_ZV (buffer) || charpos < BUF_BEGV (buffer))
62056764
JB
1898 abort ();
1899
580fae94
RS
1900 have_overlays = (! NILP (buffer->overlays_before)
1901 || ! NILP (buffer->overlays_after));
1902
1903 /* If we have no text properties and overlays,
1904 then we can do it quickly. */
1905 if (NULL_INTERVAL_P (BUF_INTERVALS (buffer)) && ! have_overlays)
a50699fd 1906 {
ef1900f3 1907 temp_set_point_both (buffer, charpos, bytepos);
a50699fd
JA
1908 return;
1909 }
1910
ef1900f3
RS
1911 /* Set TO to the interval containing the char after CHARPOS,
1912 and TOPREV to the interval containing the char before CHARPOS.
323a7ad4 1913 Either one may be null. They may be equal. */
ef1900f3
RS
1914 to = find_interval (BUF_INTERVALS (buffer), charpos);
1915 if (charpos == BUF_BEGV (buffer))
294efdbe 1916 toprev = 0;
ef1900f3 1917 else if (to && to->position == charpos)
323a7ad4 1918 toprev = previous_interval (to);
323a7ad4
RS
1919 else
1920 toprev = to;
1921
294efdbe
RS
1922 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1923 ? BUF_ZV (buffer) - 1
323a7ad4 1924 : BUF_PT (buffer));
9c79dd1b 1925
323a7ad4
RS
1926 /* Set FROM to the interval containing the char after PT,
1927 and FROMPREV to the interval containing the char before PT.
1928 Either one may be null. They may be equal. */
7ce503fd 1929 /* We could cache this and save time. */
e5d967c9 1930 from = find_interval (BUF_INTERVALS (buffer), buffer_point);
7ce503fd 1931 if (buffer_point == BUF_BEGV (buffer))
294efdbe 1932 fromprev = 0;
580fae94 1933 else if (from && from->position == BUF_PT (buffer))
323a7ad4
RS
1934 fromprev = previous_interval (from);
1935 else if (buffer_point != BUF_PT (buffer))
1936 fromprev = from, from = 0;
1937 else
1938 fromprev = from;
a50699fd 1939
7ce503fd 1940 /* Moving within an interval. */
580fae94
RS
1941 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)
1942 && ! have_overlays)
a50699fd 1943 {
ef1900f3 1944 temp_set_point_both (buffer, charpos, bytepos);
a50699fd
JA
1945 return;
1946 }
1947
ef1900f3 1948 original_position = charpos;
580fae94 1949
5eabb4e7
RS
1950 /* If the new position is between two intangible characters
1951 with the same intangible property value,
1952 move forward or backward until a change in that property. */
580fae94
RS
1953 if (NILP (Vinhibit_point_motion_hooks)
1954 && ((! NULL_INTERVAL_P (to) && ! NULL_INTERVAL_P (toprev))
b827a9e3
RS
1955 || have_overlays)
1956 /* Intangibility never stops us from positioning at the beginning
1957 or end of the buffer, so don't bother checking in that case. */
ef1900f3 1958 && charpos != BEGV && charpos != ZV)
a50699fd 1959 {
580fae94
RS
1960 Lisp_Object intangible_propval;
1961 Lisp_Object pos;
1962
ef1900f3 1963 XSETINT (pos, charpos);
580fae94 1964
d5219de5
RS
1965 if (backwards)
1966 {
ef1900f3 1967 intangible_propval = Fget_char_property (make_number (charpos),
580fae94 1968 Qintangible, Qnil);
5eabb4e7
RS
1969
1970 /* If following char is intangible,
1971 skip back over all chars with matching intangible property. */
1972 if (! NILP (intangible_propval))
580fae94
RS
1973 while (XINT (pos) > BUF_BEGV (buffer)
1974 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
1975 Qintangible, Qnil),
1976 intangible_propval))
1977 pos = Fprevious_char_property_change (pos, Qnil);
d5219de5 1978 }
0df8950e 1979 else
d5219de5 1980 {
ef1900f3 1981 intangible_propval = Fget_char_property (make_number (charpos - 1),
580fae94 1982 Qintangible, Qnil);
5eabb4e7 1983
580fae94 1984 /* If following char is intangible,
887f2a2d 1985 skip forward over all chars with matching intangible property. */
5eabb4e7 1986 if (! NILP (intangible_propval))
580fae94
RS
1987 while (XINT (pos) < BUF_ZV (buffer)
1988 && EQ (Fget_char_property (pos, Qintangible, Qnil),
1989 intangible_propval))
1990 pos = Fnext_char_property_change (pos, Qnil);
1991
d5219de5 1992 }
580fae94 1993
ef1900f3
RS
1994 charpos = XINT (pos);
1995 bytepos = buf_charpos_to_bytepos (buffer, charpos);
580fae94
RS
1996 }
1997
ef1900f3 1998 if (charpos != original_position)
580fae94 1999 {
ef1900f3
RS
2000 /* Set TO to the interval containing the char after CHARPOS,
2001 and TOPREV to the interval containing the char before CHARPOS.
580fae94 2002 Either one may be null. They may be equal. */
ef1900f3
RS
2003 to = find_interval (BUF_INTERVALS (buffer), charpos);
2004 if (charpos == BUF_BEGV (buffer))
580fae94 2005 toprev = 0;
ef1900f3 2006 else if (to && to->position == charpos)
580fae94
RS
2007 toprev = previous_interval (to);
2008 else
2009 toprev = to;
a50699fd 2010 }
323a7ad4 2011
5eabb4e7
RS
2012 /* Here TO is the interval after the stopping point
2013 and TOPREV is the interval before the stopping point.
2014 One or the other may be null. */
2015
ef1900f3 2016 temp_set_point_both (buffer, charpos, bytepos);
a50699fd 2017
d7e3e52b
JA
2018 /* We run point-left and point-entered hooks here, iff the
2019 two intervals are not equivalent. These hooks take
323a7ad4 2020 (old_point, new_point) as arguments. */
ddd931ff
RS
2021 if (NILP (Vinhibit_point_motion_hooks)
2022 && (! intervals_equal (from, to)
2023 || ! intervals_equal (fromprev, toprev)))
9c79dd1b 2024 {
323a7ad4
RS
2025 Lisp_Object leave_after, leave_before, enter_after, enter_before;
2026
2027 if (fromprev)
2028 leave_after = textget (fromprev->plist, Qpoint_left);
2029 else
2030 leave_after = Qnil;
2031 if (from)
2032 leave_before = textget (from->plist, Qpoint_left);
2033 else
2034 leave_before = Qnil;
2035
2036 if (toprev)
2037 enter_after = textget (toprev->plist, Qpoint_entered);
2038 else
2039 enter_after = Qnil;
2040 if (to)
2041 enter_before = textget (to->plist, Qpoint_entered);
2042 else
2043 enter_before = Qnil;
9c79dd1b 2044
323a7ad4 2045 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
4dcb3ee3 2046 call2 (leave_before, make_number (old_position),
ef1900f3 2047 make_number (charpos));
323a7ad4 2048 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
4dcb3ee3 2049 call2 (leave_after, make_number (old_position),
ef1900f3 2050 make_number (charpos));
9c79dd1b 2051
323a7ad4 2052 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
4dcb3ee3 2053 call2 (enter_before, make_number (old_position),
ef1900f3 2054 make_number (charpos));
323a7ad4 2055 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
4dcb3ee3 2056 call2 (enter_after, make_number (old_position),
ef1900f3 2057 make_number (charpos));
9c79dd1b 2058 }
a50699fd 2059}
294efdbe 2060\f
a7fa233f
RS
2061/* Move point to POSITION, unless POSITION is inside an intangible
2062 segment that reaches all the way to point. */
2063
2064void
2065move_if_not_intangible (position)
2066 int position;
2067{
2068 Lisp_Object pos;
2069 Lisp_Object intangible_propval;
2070
2071 XSETINT (pos, position);
2072
2073 if (! NILP (Vinhibit_point_motion_hooks))
2074 /* If intangible is inhibited, always move point to POSITION. */
2075 ;
2e34157c 2076 else if (PT < position && XINT (pos) < ZV)
a7fa233f
RS
2077 {
2078 /* We want to move forward, so check the text before POSITION. */
2079
2080 intangible_propval = Fget_char_property (pos,
2081 Qintangible, Qnil);
2082
2083 /* If following char is intangible,
2084 skip back over all chars with matching intangible property. */
2085 if (! NILP (intangible_propval))
2086 while (XINT (pos) > BEGV
2087 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
2088 Qintangible, Qnil),
2089 intangible_propval))
2090 pos = Fprevious_char_property_change (pos, Qnil);
2091 }
2e34157c 2092 else if (XINT (pos) > BEGV)
a7fa233f
RS
2093 {
2094 /* We want to move backward, so check the text after POSITION. */
2095
2096 intangible_propval = Fget_char_property (make_number (XINT (pos) - 1),
2097 Qintangible, Qnil);
2098
2099 /* If following char is intangible,
887f2a2d 2100 skip forward over all chars with matching intangible property. */
a7fa233f
RS
2101 if (! NILP (intangible_propval))
2102 while (XINT (pos) < ZV
2103 && EQ (Fget_char_property (pos, Qintangible, Qnil),
2104 intangible_propval))
2105 pos = Fnext_char_property_change (pos, Qnil);
2106
2107 }
2108
2109 /* If the whole stretch between PT and POSITION isn't intangible,
2110 try moving to POSITION (which means we actually move farther
2111 if POSITION is inside of intangible text). */
2112
2113 if (XINT (pos) != PT)
2114 SET_PT (position);
2115}
2116\f
f56b42ac
KH
2117/* If text at position POS has property PROP, set *VAL to the property
2118 value, *START and *END to the beginning and end of a region that
2119 has the same property, and return 1. Otherwise return 0.
2120
2121 OBJECT is the string or buffer to look for the property in;
2122 nil means the current buffer. */
2123
2124int
2125get_property_and_range (pos, prop, val, start, end, object)
2126 int pos;
2127 Lisp_Object prop, *val;
2128 int *start, *end;
2129 Lisp_Object object;
2130{
2131 INTERVAL i, prev, next;
2132
2133 if (NILP (object))
2134 i = find_interval (BUF_INTERVALS (current_buffer), pos);
2135 else if (BUFFERP (object))
2136 i = find_interval (BUF_INTERVALS (XBUFFER (object)), pos);
2137 else if (STRINGP (object))
2138 i = find_interval (XSTRING (object)->intervals, pos);
2139 else
2140 abort ();
2141
2142 if (NULL_INTERVAL_P (i) || (i->position + LENGTH (i) <= pos))
2143 return 0;
2144 *val = textget (i->plist, prop);
2145 if (NILP (*val))
2146 return 0;
2147
2148 next = i; /* remember it in advance */
2149 prev = previous_interval (i);
2150 while (! NULL_INTERVAL_P (prev)
2151 && EQ (*val, textget (prev->plist, prop)))
2152 i = prev, prev = previous_interval (prev);
2153 *start = i->position;
2154
2155 next = next_interval (i);
2156 while (! NULL_INTERVAL_P (next)
2157 && EQ (*val, textget (next->plist, prop)))
2158 i = next, next = next_interval (next);
2159 *end = i->position + LENGTH (i);
2160
2161 return 1;
2162}
2163\f
5cae0ec6
RS
2164/* Return the proper local map for position POSITION in BUFFER.
2165 Use the map specified by the local-map property, if any.
2166 Otherwise, use BUFFER's local map. */
2167
2168Lisp_Object
2169get_local_map (position, buffer)
2170 register int position;
2171 register struct buffer *buffer;
2172{
0f7a5fda 2173 Lisp_Object prop, tem, lispy_position, lispy_buffer;
ef1900f3 2174 int old_begv, old_zv, old_begv_byte, old_zv_byte;
5cae0ec6 2175
7ce503fd 2176 /* Perhaps we should just change `position' to the limit. */
5cae0ec6
RS
2177 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
2178 abort ();
2179
0f7a5fda
KH
2180 /* Ignore narrowing, so that a local map continues to be valid even if
2181 the visible region contains no characters and hence no properties. */
2182 old_begv = BUF_BEGV (buffer);
2183 old_zv = BUF_ZV (buffer);
ef1900f3
RS
2184 old_begv_byte = BUF_BEGV_BYTE (buffer);
2185 old_zv_byte = BUF_ZV_BYTE (buffer);
0f7a5fda
KH
2186 BUF_BEGV (buffer) = BUF_BEG (buffer);
2187 BUF_ZV (buffer) = BUF_Z (buffer);
ef1900f3
RS
2188 BUF_BEGV_BYTE (buffer) = BUF_BEG_BYTE (buffer);
2189 BUF_ZV_BYTE (buffer) = BUF_Z_BYTE (buffer);
0f7a5fda
KH
2190
2191 /* There are no properties at the end of the buffer, so in that case
2192 check for a local map on the last character of the buffer instead. */
2193 if (position == BUF_Z (buffer) && BUF_Z (buffer) > BUF_BEG (buffer))
2194 --position;
2195 XSETFASTINT (lispy_position, position);
2196 XSETBUFFER (lispy_buffer, buffer);
2197 prop = Fget_char_property (lispy_position, Qlocal_map, lispy_buffer);
2198
2199 BUF_BEGV (buffer) = old_begv;
2200 BUF_ZV (buffer) = old_zv;
ef1900f3
RS
2201 BUF_BEGV_BYTE (buffer) = old_begv_byte;
2202 BUF_ZV_BYTE (buffer) = old_zv_byte;
5cae0ec6
RS
2203
2204 /* Use the local map only if it is valid. */
4a9f44cd
RS
2205 /* Do allow symbols that are defined as keymaps. */
2206 if (SYMBOLP (prop) && !NILP (prop))
b988a842 2207 prop = indirect_function (prop);
0f7a5fda
KH
2208 if (!NILP (prop)
2209 && (tem = Fkeymapp (prop), !NILP (tem)))
5cae0ec6
RS
2210 return prop;
2211
e5d967c9 2212 return buffer->keymap;
5cae0ec6
RS
2213}
2214\f
9c79dd1b 2215/* Produce an interval tree reflecting the intervals in
944d4e4b
KH
2216 TREE from START to START + LENGTH.
2217 The new interval tree has no parent and has a starting-position of 0. */
a50699fd 2218
7b1d5b85 2219INTERVAL
a50699fd
JA
2220copy_intervals (tree, start, length)
2221 INTERVAL tree;
2222 int start, length;
2223{
2224 register INTERVAL i, new, t;
95e3e1ef 2225 register int got, prevlen;
a50699fd
JA
2226
2227 if (NULL_INTERVAL_P (tree) || length <= 0)
2228 return NULL_INTERVAL;
2229
2230 i = find_interval (tree, start);
2231 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
2232 abort ();
2233
7ce503fd 2234 /* If there is only one interval and it's the default, return nil. */
a50699fd
JA
2235 if ((start - i->position + 1 + length) < LENGTH (i)
2236 && DEFAULT_INTERVAL_P (i))
2237 return NULL_INTERVAL;
2238
2239 new = make_interval ();
944d4e4b 2240 new->position = 0;
a50699fd 2241 got = (LENGTH (i) - (start - i->position));
9c79dd1b 2242 new->total_length = length;
a50699fd
JA
2243 copy_properties (i, new);
2244
2245 t = new;
95e3e1ef 2246 prevlen = got;
a50699fd
JA
2247 while (got < length)
2248 {
2249 i = next_interval (i);
2bc7a79b 2250 t = split_interval_right (t, prevlen);
a50699fd 2251 copy_properties (i, t);
95e3e1ef
RS
2252 prevlen = LENGTH (i);
2253 got += prevlen;
a50699fd
JA
2254 }
2255
4314dea4 2256 return balance_an_interval (new);
a50699fd
JA
2257}
2258
7ce503fd 2259/* Give STRING the properties of BUFFER from POSITION to LENGTH. */
a50699fd 2260
d7e3e52b 2261INLINE void
a50699fd 2262copy_intervals_to_string (string, buffer, position, length)
46d8a55b
RS
2263 Lisp_Object string;
2264 struct buffer *buffer;
a50699fd
JA
2265 int position, length;
2266{
46d8a55b 2267 INTERVAL interval_copy = copy_intervals (BUF_INTERVALS (buffer),
a50699fd
JA
2268 position, length);
2269 if (NULL_INTERVAL_P (interval_copy))
2270 return;
2271
439d5cb4 2272 SET_INTERVAL_OBJECT (interval_copy, string);
a50699fd
JA
2273 XSTRING (string)->intervals = interval_copy;
2274}
d8638d30 2275\f
944d4e4b 2276/* Return 1 if strings S1 and S2 have identical properties; 0 otherwise.
d8638d30
RS
2277 Assume they have identical characters. */
2278
2279int
2280compare_string_intervals (s1, s2)
2281 Lisp_Object s1, s2;
2282{
2283 INTERVAL i1, i2;
944d4e4b
KH
2284 int pos = 0;
2285 int end = XSTRING (s1)->size;
d8638d30 2286
944d4e4b
KH
2287 i1 = find_interval (XSTRING (s1)->intervals, 0);
2288 i2 = find_interval (XSTRING (s2)->intervals, 0);
d8638d30
RS
2289
2290 while (pos < end)
2291 {
2292 /* Determine how far we can go before we reach the end of I1 or I2. */
2293 int len1 = (i1 != 0 ? INTERVAL_LAST_POS (i1) : end) - pos;
2294 int len2 = (i2 != 0 ? INTERVAL_LAST_POS (i2) : end) - pos;
2295 int distance = min (len1, len2);
2296
2297 /* If we ever find a mismatch between the strings,
2298 they differ. */
2299 if (! intervals_equal (i1, i2))
2300 return 0;
2301
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);
2309 }
2310 return 1;
2311}
37f26f3c 2312\f
37f26f3c
RS
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. */
2317
2318static void
2319set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte)
2320 INTERVAL i;
2321 int multi_flag;
2322 int start, start_byte, end, end_byte;
2323{
37f26f3c
RS
2324 /* Fix the length of this interval. */
2325 if (multi_flag)
2326 i->total_length = end - start;
2327 else
2328 i->total_length = end_byte - start_byte;
2329
2330 /* Recursively fix the length of the subintervals. */
2331 if (i->left)
2332 {
2333 int left_end, left_end_byte;
2334
2335 if (multi_flag)
2336 {
2337 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
2338 left_end = BYTE_TO_CHAR (left_end_byte);
2339 }
2340 else
2341 {
2342 left_end = start + LEFT_TOTAL_LENGTH (i);
2343 left_end_byte = CHAR_TO_BYTE (left_end);
2344 }
2345
2346 set_intervals_multibyte_1 (i->left, multi_flag, start, start_byte,
2347 left_end, left_end_byte);
2348 }
2349 if (i->right)
2350 {
2351 int right_start_byte, right_start;
2352
2353 if (multi_flag)
2354 {
2355 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
2356 right_start = BYTE_TO_CHAR (right_start_byte);
2357 }
2358 else
2359 {
2360 right_start = end - RIGHT_TOTAL_LENGTH (i);
2361 right_start_byte = CHAR_TO_BYTE (right_start);
2362 }
2363
2364 set_intervals_multibyte_1 (i->right, multi_flag,
2365 right_start, right_start_byte,
2366 end, end_byte);
2367 }
2368}
d2f7a802 2369
24cef261
RS
2370/* Update the intervals of the current buffer
2371 to fit the contents as multibyte (if MULTI_FLAG is 1)
2372 or to fit them as non-multibyte (if MULTI_FLAG is 0). */
2373
2374void
2375set_intervals_multibyte (multi_flag)
2376 int multi_flag;
2377{
2378 if (BUF_INTERVALS (current_buffer))
2379 set_intervals_multibyte_1 (BUF_INTERVALS (current_buffer), multi_flag,
2380 BEG, BEG_BYTE, Z, Z_BYTE);
2381}