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