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