Merge branch 'master' of http://git.sxemacs.org/sxemacs
[sxemacs] / src / extents.c
1 /* Copyright (c) 1994, 1995 Free Software Foundation, Inc.
2    Copyright (c) 1995 Sun Microsystems, Inc.
3    Copyright (c) 1995, 1996, 2000 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 /* This file has been Mule-ized. */
24
25 /* Written by Ben Wing <ben@xemacs.org>.
26
27    [Originally written by some people at Lucid.
28    Hacked on by jwz.
29    Start/end-open stuff added by John Rose (john.rose@eng.sun.com).
30    Rewritten from scratch by Ben Wing, December 1994.] */
31
32 /* Commentary:
33
34    Extents are regions over a buffer, with a start and an end position
35    denoting the region of the buffer included in the extent.  In
36    addition, either end can be closed or open, meaning that the endpoint
37    is or is not logically included in the extent.  Insertion of a character
38    at a closed endpoint causes the character to go inside the extent;
39    insertion at an open endpoint causes the character to go outside.
40
41    Extent endpoints are stored using memory indices (see insdel.c),
42    to minimize the amount of adjusting that needs to be done when
43    characters are inserted or deleted.
44
45    (Formerly, extent endpoints at the gap could be either before or
46    after the gap, depending on the open/closedness of the endpoint.
47    The intent of this was to make it so that insertions would
48    automatically go inside or out of extents as necessary with no
49    further work needing to be done.  It didn't work out that way,
50    however, and just ended up complexifying and buggifying all the
51    rest of the code.)
52
53    Extents are compared using memory indices.  There are two orderings
54    for extents and both orders are kept current at all times.  The normal
55    or "display" order is as follows:
56
57    Extent A is "less than" extent B, that is, earlier in the display order,
58    if:    A-start < B-start,
59    or if: A-start = B-start, and A-end > B-end
60
61    So if two extents begin at the same position, the larger of them is the
62    earlier one in the display order (EXTENT_LESS is true).
63
64    For the e-order, the same thing holds: Extent A is "less than" extent B
65    in e-order, that is, later in the buffer,
66    if:    A-end < B-end,
67    or if: A-end = B-end, and A-start > B-start
68
69    So if two extents end at the same position, the smaller of them is the
70    earlier one in the e-order (EXTENT_E_LESS is true).
71
72    The display order and the e-order are complementary orders: any
73    theorem about the display order also applies to the e-order if you
74    swap all occurrences of "display order" and "e-order", "less than"
75    and "greater than", and "extent start" and "extent end".
76
77    Extents can be zero-length, and will end up that way if their endpoints
78    are explicitly set that way or if their detachable property is nil
79    and all the text in the extent is deleted. (The exception is open-open
80    zero-length extents, which are barred from existing because there is
81    no sensible way to define their properties.  Deletion of the text in
82    an open-open extent causes it to be converted into a closed-open
83    extent.)  Zero-length extents are primarily used to represent
84    annotations, and behave as follows:
85
86    1) Insertion at the position of a zero-length extent expands the extent
87    if both endpoints are closed; goes after the extent if it is closed-open;
88    and goes before the extent if it is open-closed.
89
90    2) Deletion of a character on a side of a zero-length extent whose
91    corresponding endpoint is closed causes the extent to be detached if
92    it is detachable; if the extent is not detachable or the corresponding
93    endpoint is open, the extent remains in the buffer, moving as necessary.
94
95    Note that closed-open, non-detachable zero-length extents behave exactly
96    like markers and that open-closed, non-detachable zero-length extents
97    behave like the "point-type" marker in Mule.
98
99    #### The following information is wrong in places.
100
101    More about the different orders:
102    --------------------------------
103
104    The extents in a buffer are ordered by "display order" because that
105    is that order that the redisplay mechanism needs to process them in.
106    The e-order is an auxiliary ordering used to facilitate operations
107    over extents.  The operations that can be performed on the ordered
108    list of extents in a buffer are
109
110    1) Locate where an extent would go if inserted into the list.
111    2) Insert an extent into the list.
112    3) Remove an extent from the list.
113    4) Map over all the extents that overlap a range.
114
115    (4) requires being able to determine the first and last extents
116    that overlap a range.
117
118    NOTE: "overlap" is used as follows:
119
120    -- two ranges overlap if they have at least one point in common.
121       Whether the endpoints are open or closed makes a difference here.
122    -- a point overlaps a range if the point is contained within the
123       range; this is equivalent to treating a point P as the range
124       [P, P].
125    -- In the case of an *extent* overlapping a point or range, the
126       extent is normally treated as having closed endpoints.  This
127       applies consistently in the discussion of stacks of extents
128       and such below.  Note that this definition of overlap is not
129       necessarily consistent with the extents that `map-extents'
130       maps over, since `map-extents' sometimes pays attention to
131       whether the endpoints of an extents are open or closed.
132       But for our purposes, it greatly simplifies things to treat
133       all extents as having closed endpoints.
134
135    First, define >, <, <=, etc. as applied to extents to mean
136      comparison according to the display order.  Comparison between an
137      extent E and an index I means comparison between E and the range
138      [I, I].
139    Also define e>, e<, e<=, etc. to mean comparison according to the
140      e-order.
141    For any range R, define R(0) to be the starting index of the range
142      and R(1) to be the ending index of the range.
143    For any extent E, define E(next) to be the extent directly following
144      E, and E(prev) to be the extent directly preceding E.  Assume
145      E(next) and E(prev) can be determined from E in constant time.
146      (This is because we store the extent list as a doubly linked
147      list.)
148    Similarly, define E(e-next) and E(e-prev) to be the extents
149      directly following and preceding E in the e-order.
150
151    Now:
152
153    Let R be a range.
154    Let F be the first extent overlapping R.
155    Let L be the last extent overlapping R.
156
157    Theorem 1: R(1) lies between L and L(next), i.e. L <= R(1) < L(next).
158
159    This follows easily from the definition of display order.  The
160    basic reason that this theorem applies is that the display order
161    sorts by increasing starting index.
162
163    Therefore, we can determine L just by looking at where we would
164    insert R(1) into the list, and if we know F and are moving forward
165    over extents, we can easily determine when we've hit L by comparing
166    the extent we're at to R(1).
167
168    Theorem 2: F(e-prev) e< [1, R(0)] e<= F.
169
170    This is the analog of Theorem 1, and applies because the e-order
171    sorts by increasing ending index.
172
173    Therefore, F can be found in the same amount of time as operation (1),
174    i.e. the time that it takes to locate where an extent would go if
175    inserted into the e-order list.
176
177    If the lists were stored as balanced binary trees, then operation (1)
178    would take logarithmic time, which is usually quite fast.  However,
179    currently they're stored as simple doubly-linked lists, and instead
180    we do some caching to try to speed things up.
181
182    Define a "stack of extents" (or "SOE") as the set of extents
183    (ordered in the display order) that overlap an index I, together with
184    the SOE's "previous" extent, which is an extent that precedes I in
185    the e-order. (Hopefully there will not be very many extents between
186    I and the previous extent.)
187
188    Now:
189
190    Let I be an index, let S be the stack of extents on I, let F be
191    the first extent in S, and let P be S's previous extent.
192
193    Theorem 3: The first extent in S is the first extent that overlaps
194    any range [I, J].
195
196    Proof: Any extent that overlaps [I, J] but does not include I must
197    have a start index > I, and thus be greater than any extent in S.
198
199    Therefore, finding the first extent that overlaps a range R is the
200    same as finding the first extent that overlaps R(0).
201
202    Theorem 4: Let I2 be an index such that I2 > I, and let F2 be the
203    first extent that overlaps I2.  Then, either F2 is in S or F2 is
204    greater than any extent in S.
205
206    Proof: If F2 does not include I then its start index is greater
207    than I and thus it is greater than any extent in S, including F.
208    Otherwise, F2 includes I and thus is in S, and thus F2 >= F.
209
210 */
211
212 #include <config.h>
213 #include "lisp.h"
214
215 #include "buffer.h"
216 #include "debug.h"
217 #include "ui/device.h"
218 #include "elhash.h"
219 #include "extents.h"
220 #include "ui/faces.h"
221 #include "ui/frame.h"
222 #include "ui/glyphs.h"
223 #include "ui/insdel.h"
224 #include "ui/keymap.h"
225 #include "opaque.h"
226 #include "process.h"
227 #include "ui/redisplay.h"
228 #include "ui/gutter.h"
229
230 /* ------------------------------- */
231 /*            gap array            */
232 /* ------------------------------- */
233
234 /* Note that this object is not extent-specific and should perhaps be
235    moved into another file. */
236
237 typedef struct gap_array_marker_s *gap_array_marker_t;
238 typedef struct gap_array_s *gap_array_t;
239
240 /* Holds a marker that moves as elements in the array are inserted and
241    deleted, similar to standard markers. */
242
243 struct gap_array_marker_s {
244         int pos;
245         gap_array_marker_t next;
246 };
247
248 /* Holds a "gap array", which is an array of elements with a gap located
249    in it.  Insertions and deletions with a high degree of locality
250    are very fast, essentially in constant time.  Array positions as
251    used and returned in the gap array functions are independent of
252    the gap. */
253
254 struct gap_array_s {
255         char *array;
256         int gap;
257         int gapsize;
258         int numels;
259         int elsize;
260         gap_array_marker_t markers;
261 };
262
263 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
264 static gap_array_marker_t gap_array_marker_freelist;
265 #endif  /* !BDWGC */
266
267 /* Convert a "memory position" (i.e. taking the gap into account) into
268    the address of the element at (i.e. after) that position.  "Memory
269    positions" are only used internally and are of type Memind.
270    "Array positions" are used externally and are of type int. */
271 #define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel))
272
273 /* Number of elements currently in a gap array */
274 #define GAP_ARRAY_NUM_ELS(ga) ((ga)->numels)
275
276 #define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos)                  \
277         ((pos) <= (ga)->gap ? (pos) : (pos) + (ga)->gapsize)
278
279 #define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos)                  \
280         ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize)
281
282 /* Convert an array position into the address of the element at
283    (i.e. after) that position. */
284 #define GAP_ARRAY_EL_ADDR(ga, pos)                                      \
285         ((pos) < (ga)->gap                                              \
286          ? GAP_ARRAY_MEMEL_ADDR(ga, pos)                                \
287          : GAP_ARRAY_MEMEL_ADDR(ga, (pos) + (ga)->gapsize))
288
289 /* ------------------------------- */
290 /*          extent list            */
291 /* ------------------------------- */
292
293 typedef struct extent_list_marker_s *extent_list_marker_t;
294 typedef struct extent_list_s *extent_list_t;
295
296 struct extent_list_marker_s {
297         gap_array_marker_t m;
298         int endp;
299         extent_list_marker_t next;
300 };
301
302 struct extent_list_s {
303         gap_array_t start;
304         gap_array_t end;
305         extent_list_marker_t markers;
306 };
307
308 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
309 static extent_list_marker_t extent_list_marker_freelist;
310 #endif  /* !BDWGC */
311
312 #define EXTENT_LESS_VALS(e,st,nd)               \
313         ((extent_start (e) < (st)) ||           \
314          ((extent_start (e) == (st)) &&         \
315           (extent_end (e) > (nd))))
316
317 #define EXTENT_EQUAL_VALS(e,st,nd)              \
318         ((extent_start (e) == (st)) &&          \
319          (extent_end (e) == (nd)))
320
321 #define EXTENT_LESS_EQUAL_VALS(e,st,nd)         \
322         ((extent_start (e) < (st)) ||           \
323          ((extent_start (e) == (st)) &&         \
324           (extent_end (e) >= (nd))))
325
326 /* Is extent E1 less than extent E2 in the display order? */
327 #define EXTENT_LESS(e1,e2)                                              \
328         EXTENT_LESS_VALS (e1, extent_start (e2), extent_end (e2))
329
330 /* Is extent E1 equal to extent E2? */
331 #define EXTENT_EQUAL(e1,e2)                                             \
332         EXTENT_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
333
334 /* Is extent E1 less than or equal to extent E2 in the display order? */
335 #define EXTENT_LESS_EQUAL(e1,e2)                                        \
336         EXTENT_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
337
338 #define EXTENT_E_LESS_VALS(e,st,nd)             \
339         ((extent_end (e) < (nd)) ||             \
340          ((extent_end (e) == (nd)) &&           \
341           (extent_start (e) > (st))))
342
343 #define EXTENT_E_LESS_EQUAL_VALS(e,st,nd)       \
344         ((extent_end (e) < (nd)) ||             \
345          ((extent_end (e) == (nd)) &&           \
346           (extent_start (e) >= (st))))
347
348 /* Is extent E1 less than extent E2 in the e-order? */
349 #define EXTENT_E_LESS(e1,e2)                                            \
350         EXTENT_E_LESS_VALS(e1, extent_start (e2), extent_end (e2))
351
352 /* Is extent E1 less than or equal to extent E2 in the e-order? */
353 #define EXTENT_E_LESS_EQUAL(e1,e2)                                      \
354         EXTENT_E_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
355
356 #define EXTENT_GAP_ARRAY_AT(ga, pos) (*(EXTENT*)GAP_ARRAY_EL_ADDR(ga, pos))
357
358 /* ------------------------------- */
359 /*    auxiliary extent structure   */
360 /* ------------------------------- */
361
362 struct extent_auxiliary extent_auxiliary_defaults;
363
364 /* ------------------------------- */
365 /*     buffer-extent primitives    */
366 /* ------------------------------- */
367 typedef struct extent_stack_s *extent_stack_t;
368
369 struct extent_stack_s {
370         extent_list_t extents;
371         /* Position of stack of extents.  EXTENTS is the list of
372            all extents that overlap this position.  This position
373            can be -1 if the stack of extents is invalid (this
374            happens when a buffer is first created or a string's
375            stack of extents is created [a string's stack of extents
376            is nuked when a GC occurs, to conserve memory]). */
377         Memind pos;
378 };
379
380 /* ------------------------------- */
381 /*           map-extents           */
382 /* ------------------------------- */
383
384 typedef int Endpoint_Index;
385
386 #define memind_to_startind(x, start_open)               \
387         ((Endpoint_Index) (((x) << 1) + !!(start_open)))
388 #define memind_to_endind(x, end_open)                   \
389         ((Endpoint_Index) (((x) << 1) - !!(end_open)))
390
391 /* Combination macros */
392 #define bytind_to_startind(buf, x, start_open)                  \
393         memind_to_startind (bytind_to_memind (buf, x), start_open)
394 #define bytind_to_endind(buf, x, end_open)                      \
395         memind_to_endind (bytind_to_memind (buf, x), end_open)
396
397 /* ------------------------------- */
398 /*    buffer-or-string primitives  */
399 /* ------------------------------- */
400
401 /* Similar for Bytinds and start/end indices. */
402
403 #define buffer_or_string_bytind_to_startind(obj, ind, start_open)       \
404         memind_to_startind(buffer_or_string_bytind_to_memind (obj, ind), \
405                            start_open)
406
407 #define buffer_or_string_bytind_to_endind(obj, ind, end_open)           \
408         memind_to_endind(buffer_or_string_bytind_to_memind (obj, ind),  \
409                          end_open)
410
411 /* ------------------------------- */
412 /*      Lisp-level functions       */
413 /* ------------------------------- */
414
415 /* flags for decode_extent() */
416 #define DE_MUST_HAVE_BUFFER 1
417 #define DE_MUST_BE_ATTACHED 2
418
419 Lisp_Object Vlast_highlighted_extent;
420 Fixnum mouse_highlight_priority;
421
422 Lisp_Object Qextentp;
423 Lisp_Object Qextent_live_p;
424
425 Lisp_Object Qall_extents_closed;
426 Lisp_Object Qall_extents_open;
427 Lisp_Object Qall_extents_closed_open;
428 Lisp_Object Qall_extents_open_closed;
429 Lisp_Object Qstart_in_region;
430 Lisp_Object Qend_in_region;
431 Lisp_Object Qstart_and_end_in_region;
432 Lisp_Object Qstart_or_end_in_region;
433 Lisp_Object Qnegate_in_region;
434
435 Lisp_Object Qdetached;
436 Lisp_Object Qdestroyed;
437 Lisp_Object Qbegin_glyph;
438 Lisp_Object Qend_glyph;
439 Lisp_Object Qstart_open;
440 Lisp_Object Qend_open;
441 Lisp_Object Qstart_closed;
442 Lisp_Object Qend_closed;
443 Lisp_Object Qread_only;
444 /* Qhighlight defined in general.c */
445 Lisp_Object Qunique;
446 Lisp_Object Qduplicable;
447 Lisp_Object Qdetachable;
448 Lisp_Object Qpriority;
449 Lisp_Object Qmouse_face;
450 Lisp_Object Qinitial_redisplay_function;
451
452 /* This exists only for backwards compatibility. */
453 Lisp_Object Qglyph_layout;
454 Lisp_Object Qbegin_glyph_layout, Qend_glyph_layout;
455 Lisp_Object Qoutside_margin;
456 Lisp_Object Qinside_margin;
457 Lisp_Object Qwhitespace;
458 /* Qtext defined in general.c */
459
460 Lisp_Object Qcopy_function;
461 Lisp_Object Qpaste_function;
462
463 /* The idea here is that if we're given a list of faces, we
464    need to "memoize" this so that two lists of faces that are `equal'
465    turn into the same object.  When `set-extent-face' is called, we
466    "memoize" into a list of actual faces; when `extent-face' is called,
467    we do a reverse lookup to get the list of symbols. */
468
469 static Lisp_Object canonicalize_extent_property(Lisp_Object prop,
470                                                 Lisp_Object value);
471 Lisp_Object Vextent_face_memoize_hash_table;
472 Lisp_Object Vextent_face_reverse_memoize_hash_table;
473 Lisp_Object Vextent_face_reusable_list;
474 /* FSFmacs bogosity */
475 Lisp_Object Vdefault_text_properties;
476
477 EXFUN(Fextent_properties, 1);
478 EXFUN(Fset_extent_property, 3);
479
480 /* if true, we don't want to set any redisplay flags on modeline extent
481    changes */
482 int in_modeline_generation;
483 \f
484 /************************************************************************/
485 /*                       Generalized gap array                          */
486 /************************************************************************/
487
488 /* This generalizes the "array with a gap" model used to store buffer
489    characters.  This is based on the stuff in insdel.c and should
490    probably be merged with it.  This is not extent-specific and should
491    perhaps be moved into a separate file. */
492
493 /* ------------------------------- */
494 /*        internal functions       */
495 /* ------------------------------- */
496
497 /* Adjust the gap array markers in the range (FROM, TO].  Parallel to
498    adjust_markers() in insdel.c. */
499
500 static void
501 gap_array_adjust_markers(gap_array_t ga, Memind from, Memind to, int amount)
502 {
503         gap_array_marker_t m;
504
505         for (m = ga->markers; m; m = m->next) {
506                 m->pos = do_marker_adjustment(m->pos, from, to, amount);
507         }
508         return;
509 }
510
511 /* Move the gap to array position POS.  Parallel to move_gap() in
512    insdel.c but somewhat simplified. */
513
514 static void
515 gap_array_move_gap(gap_array_t ga, int pos)
516 {
517         int gap = ga->gap;
518         int gapsize = ga->gapsize;
519
520         assert(ga->array);
521         if (pos < gap) {
522                 memmove(GAP_ARRAY_MEMEL_ADDR(ga, pos + gapsize),
523                         GAP_ARRAY_MEMEL_ADDR(ga, pos),
524                         (gap - pos) * ga->elsize);
525                 gap_array_adjust_markers(ga, (Memind) pos, (Memind) gap,
526                                          gapsize);
527         } else if (pos > gap) {
528                 memmove(GAP_ARRAY_MEMEL_ADDR(ga, gap),
529                         GAP_ARRAY_MEMEL_ADDR(ga, gap + gapsize),
530                         (pos - gap) * ga->elsize);
531                 gap_array_adjust_markers(ga, (Memind) (gap + gapsize),
532                                          (Memind) (pos + gapsize), -gapsize);
533         }
534         ga->gap = pos;
535         return;
536 }
537
538 /* Make the gap INCREMENT characters longer.  Parallel to make_gap() in
539    insdel.c. */
540
541 static void
542 gap_array_make_gap(gap_array_t ga, int increment)
543 {
544         char *ptr = ga->array;
545         int real_gap_loc;
546         int old_gap_size;
547
548         /* If we have to get more space, get enough to last a while.  We use
549            a geometric progression that saves on realloc space. */
550         increment += 100 + ga->numels / 8;
551
552         ptr = (char*)xrealloc(ptr,
553                               (ga->numels + ga->gapsize +
554                                increment) * ga->elsize);
555         if (ptr == 0) {
556                 memory_full();
557         }
558         ga->array = ptr;
559
560         real_gap_loc = ga->gap;
561         old_gap_size = ga->gapsize;
562
563         /* Call the newly allocated space a gap at the end of the whole
564            space.  */
565         ga->gap = ga->numels + ga->gapsize;
566         ga->gapsize = increment;
567
568         /* Move the new gap down to be consecutive with the end of the old one.
569            This adjusts the markers properly too.  */
570         gap_array_move_gap(ga, real_gap_loc + old_gap_size);
571
572         /* Now combine the two into one large gap.  */
573         ga->gapsize += old_gap_size;
574         ga->gap = real_gap_loc;
575         return;
576 }
577
578 /* ------------------------------- */
579 /*        external functions       */
580 /* ------------------------------- */
581
582 /* Insert NUMELS elements (pointed to by ELPTR) into the specified
583    gap array at POS. */
584
585 static void
586 gap_array_insert_els(gap_array_t ga, int pos, void *elptr, int numels)
587 {
588         assert(pos >= 0 && pos <= ga->numels);
589         if (ga->gapsize < numels) {
590                 gap_array_make_gap(ga, numels - ga->gapsize);
591         }
592         if (pos != ga->gap) {
593                 gap_array_move_gap(ga, pos);
594         }
595         memcpy(GAP_ARRAY_MEMEL_ADDR(ga, ga->gap), (char *)elptr,
596                numels * ga->elsize);
597         ga->gapsize -= numels;
598         ga->gap += numels;
599         ga->numels += numels;
600         /* This is the equivalent of insert-before-markers.
601
602            #### Should only happen if marker is "moves forward at insert" type.
603          */
604
605         gap_array_adjust_markers(ga, pos - 1, pos, numels);
606         return;
607 }
608
609 /* Delete NUMELS elements from the specified gap array, starting at FROM. */
610
611 static void
612 gap_array_delete_els(gap_array_t ga, int from, int numdel)
613 {
614         int to = from + numdel;
615         int gapsize = ga->gapsize;
616
617         assert(from >= 0);
618         assert(numdel >= 0);
619         assert(to <= ga->numels);
620
621         /* Make sure the gap is somewhere in or next to what we are deleting.  */
622         if (to < ga->gap) {
623                 gap_array_move_gap(ga, to);
624         }
625         if (from > ga->gap) {
626                 gap_array_move_gap(ga, from);
627         }
628         /* Relocate all markers pointing into the new, larger gap
629            to point at the end of the text before the gap.  */
630         gap_array_adjust_markers(ga, to + gapsize, to + gapsize,
631                                  -numdel - gapsize);
632
633         ga->gapsize += numdel;
634         ga->numels -= numdel;
635         ga->gap = from;
636         return;
637 }
638
639 static gap_array_marker_t
640 gap_array_make_marker(gap_array_t ga, int pos)
641 {
642         gap_array_marker_t m;
643
644         assert(pos >= 0 && pos <= ga->numels);
645 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
646         m = xnew(struct gap_array_marker_s);
647 #else  /* !BDWGC */
648         if (gap_array_marker_freelist) {
649                 m = gap_array_marker_freelist;
650                 gap_array_marker_freelist = gap_array_marker_freelist->next;
651         } else {
652                 m = xnew(struct gap_array_marker_s);
653         }
654 #endif  /* BDWGC */
655
656         m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos);
657         m->next = ga->markers;
658         ga->markers = m;
659         return m;
660 }
661
662 static void
663 gap_array_delete_marker(gap_array_t ga, gap_array_marker_t m)
664 {
665         volatile gap_array_marker_t p, prev;
666
667         for (prev = 0, p = ga->markers; p && p != m; prev = p, p = p->next);
668         if (UNLIKELY(p == NULL)) {
669                 return;
670         }
671         assert(p);
672         if (prev) {
673                 prev->next = p->next;
674         } else {
675                 ga->markers = p->next;
676         }
677 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
678         xfree(m);
679 #else  /* !BDWGC */
680         m->next = gap_array_marker_freelist;
681         m->pos = 0xDEADBEEF;
682         gap_array_marker_freelist = m;
683 #endif  /* BDWGC */
684         return;
685 }
686
687 static void
688 gap_array_delete_all_markers(gap_array_t ga)
689 {
690         for (volatile gap_array_marker_t p = ga->markers, next; p; p = next) {
691                 next = p->next;
692 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
693                 xfree(p);
694 #else  /* !BDWGC */
695                 p->next = gap_array_marker_freelist;
696                 p->pos = 0xDEADBEEF;
697                 gap_array_marker_freelist = p;
698 #endif  /* BDWGC */
699         }
700         ga->markers = NULL;
701         return;
702 }
703
704 static void
705 gap_array_move_marker(gap_array_t ga, gap_array_marker_t m, int pos)
706 {
707         assert(pos >= 0 && pos <= ga->numels);
708         m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos);
709 }
710
711 #define gap_array_marker_pos(ga, m)                     \
712         GAP_ARRAY_MEMORY_TO_ARRAY_POS (ga, (m)->pos)
713
714 static gap_array_t
715 make_gap_array(int elsize)
716 {
717         gap_array_t ga = xnew_and_zero(struct gap_array_s);
718         ga->elsize = elsize;
719         return ga;
720 }
721
722 static void
723 free_gap_array(gap_array_t ga)
724 {
725         if (ga->array) {
726                 xfree(ga->array);
727         }
728         gap_array_delete_all_markers(ga);
729         xfree(ga);
730         return;
731 }
732 \f
733 /************************************************************************/
734 /*                       Extent list primitives                         */
735 /************************************************************************/
736
737 /* A list of extents is maintained as a double gap array: one gap array
738    is ordered by start index (the "display order") and the other is
739    ordered by end index (the "e-order").  Note that positions in an
740    extent list should logically be conceived of as referring *to*
741    a particular extent (as is the norm in programs) rather than
742    sitting between two extents.  Note also that callers of these
743    functions should not be aware of the fact that the extent list is
744    implemented as an array, except for the fact that positions are
745    integers (this should be generalized to handle integers and linked
746    list equally well).
747 */
748
749 /* Number of elements in an extent list */
750 #define extent_list_num_els(el) GAP_ARRAY_NUM_ELS(el->start)
751
752 /* Return the position at which EXTENT is located in the specified extent
753    list (in the display order if ENDP is 0, in the e-order otherwise).
754    If the extent is not found, the position where the extent would
755    be inserted is returned.  If ENDP is 0, the insertion would go after
756    all other equal extents.  If ENDP is not 0, the insertion would go
757    before all other equal extents.  If FOUNDP is not 0, then whether
758    the extent was found will get written into it. */
759
760 static int
761 extent_list_locate(extent_list_t el, EXTENT extent, int endp, bool *foundp)
762 {
763         gap_array_t ga = endp ? el->end : el->start;
764         int left = 0, right = GAP_ARRAY_NUM_ELS(ga);
765         int oldfoundpos, foundpos;
766         bool found;
767
768         while (left != right) {
769                 /* RIGHT might not point to a valid extent (i.e. it's at the end
770                    of the list), so NEWPOS must round down. */
771                 unsigned int newpos = (left + right) >> 1;
772                 EXTENT e = EXTENT_GAP_ARRAY_AT(ga, (int)newpos);
773
774                 if (endp ? EXTENT_E_LESS(e, extent) : EXTENT_LESS(e, extent)) {
775                         left = newpos + 1;
776                 } else {
777                         right = newpos;
778                 }
779         }
780
781         /* Now we're at the beginning of all equal extents. */
782         found = false;
783         oldfoundpos = foundpos = left;
784         while (foundpos < GAP_ARRAY_NUM_ELS(ga)) {
785                 EXTENT e = EXTENT_GAP_ARRAY_AT(ga, foundpos);
786                 if (e == extent) {
787                         found = 1;
788                         break;
789                 }
790                 if (!EXTENT_EQUAL(e, extent)) {
791                         break;
792                 }
793                 foundpos++;
794         }
795         if (foundp) {
796                 *foundp = found;
797         }
798         if (found || !endp) {
799                 return foundpos;
800         } else {
801                 return oldfoundpos;
802         }
803 }
804
805 /* Return the position of the first extent that begins at or after POS
806    (or ends at or after POS, if ENDP is not 0).
807
808    An out-of-range value for POS is allowed, and guarantees that the
809    position at the beginning or end of the extent list is returned. */
810
811 static int
812 extent_list_locate_from_pos(extent_list_t el, Memind pos, int endp)
813 {
814         struct extent fake_extent;
815         /*
816
817            Note that if we search for [POS, POS], then we get the following:
818
819            -- if ENDP is 0, then all extents whose start position is <= POS
820            lie before the returned position, and all extents whose start
821            position is > POS lie at or after the returned position.
822
823            -- if ENDP is not 0, then all extents whose end position is < POS
824            lie before the returned position, and all extents whose end
825            position is >= POS lie at or after the returned position.
826
827          */
828         set_extent_start(&fake_extent, endp ? pos : pos - 1);
829         set_extent_end(&fake_extent, endp ? pos : pos - 1);
830         return extent_list_locate(el, &fake_extent, endp, 0);
831 }
832
833 /* Return the extent at POS. */
834
835 static EXTENT
836 extent_list_at(extent_list_t el, Memind pos, int endp)
837 {
838         gap_array_t ga = endp ? el->end : el->start;
839
840         assert(pos >= 0 && pos < GAP_ARRAY_NUM_ELS(ga));
841         return EXTENT_GAP_ARRAY_AT(ga, pos);
842 }
843
844 /* Insert an extent into an extent list. */
845
846 static void
847 extent_list_insert(extent_list_t el, EXTENT extent)
848 {
849         int pos;
850         bool foundp;
851
852         pos = extent_list_locate(el, extent, 0, &foundp);
853         assert(!foundp);
854         gap_array_insert_els(el->start, pos, &extent, 1);
855         pos = extent_list_locate(el, extent, 1, &foundp);
856         assert(!foundp);
857         gap_array_insert_els(el->end, pos, &extent, 1);
858         return;
859 }
860
861 /* Delete an extent from an extent list. */
862
863 static void
864 extent_list_delete(extent_list_t el, EXTENT extent)
865 {
866         int pos;
867         bool foundp;
868
869         pos = extent_list_locate(el, extent, 0, &foundp);
870         assert(foundp);
871         gap_array_delete_els(el->start, pos, 1);
872         pos = extent_list_locate(el, extent, 1, &foundp);
873         assert(foundp);
874         gap_array_delete_els(el->end, pos, 1);
875         return;
876 }
877
878 static void
879 extent_list_delete_all(extent_list_t el)
880 {
881         gap_array_delete_els(el->start, 0, GAP_ARRAY_NUM_ELS(el->start));
882         gap_array_delete_els(el->end, 0, GAP_ARRAY_NUM_ELS(el->end));
883         return;
884 }
885
886 static extent_list_marker_t
887 extent_list_make_marker(extent_list_t el, int pos, int endp)
888 {
889         extent_list_marker_t m;
890
891 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
892         m = xnew(struct extent_list_marker_s);
893 #else  /* !BDWGC */
894         if (extent_list_marker_freelist) {
895                 m = extent_list_marker_freelist;
896                 extent_list_marker_freelist = extent_list_marker_freelist->next;
897         } else {
898                 m = xnew(struct extent_list_marker_s);
899         }
900 #endif  /* BDWGC */
901
902         m->m = gap_array_make_marker(endp ? el->end : el->start, pos);
903         m->endp = endp;
904         m->next = el->markers;
905         el->markers = m;
906         return m;
907 }
908
909 #define extent_list_move_marker(el, mkr, pos)                           \
910         gap_array_move_marker((mkr)->endp                               \
911                               ? (el)->end                               \
912                               : (el)->start, (mkr)->m, pos)
913
914 static void
915 extent_list_delete_marker(extent_list_t el, extent_list_marker_t m)
916 {
917         extent_list_marker_t p, prev;
918
919         for (prev = 0, p = el->markers; p && p != m; prev = p, p = p->next);
920         assert(p);
921         if (prev) {
922                 prev->next = p->next;
923         } else {
924                 el->markers = p->next;
925         }
926 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
927         xfree(m);
928 #else  /* !BDWGC */
929         m->next = extent_list_marker_freelist;
930         extent_list_marker_freelist = m;
931 #endif  /* BDWGC */
932         gap_array_delete_marker(m->endp ? el->end : el->start, m->m);
933         return;
934 }
935
936 #define extent_list_marker_pos(el, mkr)                                 \
937         gap_array_marker_pos ((mkr)->endp                               \
938                               ? (el)->end                               \
939                               : (el)->start, (mkr)->m)
940
941 static extent_list_t
942 allocate_extent_list(void)
943 {
944         extent_list_t el = xnew(struct extent_list_s);
945         el->start = make_gap_array(sizeof(EXTENT));
946         el->end = make_gap_array(sizeof(EXTENT));
947         el->markers = 0;
948         return el;
949 }
950
951 static void
952 free_extent_list(extent_list_t el)
953 {
954         free_gap_array(el->start);
955         free_gap_array(el->end);
956         xfree(el);
957         return;
958 }
959 \f
960 /************************************************************************/
961 /*                       Auxiliary extent structure                     */
962 /************************************************************************/
963
964 static Lisp_Object mark_extent_auxiliary(Lisp_Object obj)
965 {
966         struct extent_auxiliary *data = XEXTENT_AUXILIARY(obj);
967         mark_object(data->begin_glyph);
968         mark_object(data->end_glyph);
969         mark_object(data->invisible);
970         mark_object(data->children);
971         mark_object(data->read_only);
972         mark_object(data->mouse_face);
973         mark_object(data->initial_redisplay_function);
974         mark_object(data->before_change_functions);
975         mark_object(data->after_change_functions);
976         return data->parent;
977 }
978
979 DEFINE_LRECORD_IMPLEMENTATION("extent-auxiliary", extent_auxiliary,
980                               mark_extent_auxiliary, internal_object_printer,
981                               0, 0, 0, 0, struct extent_auxiliary);
982
983 void allocate_extent_auxiliary(EXTENT ext)
984 {
985         Lisp_Object extent_aux;
986         struct extent_auxiliary *data =
987                 alloc_lcrecord_type(struct extent_auxiliary,
988                                     &lrecord_extent_auxiliary);
989
990         copy_lcrecord(data, &extent_auxiliary_defaults);
991         XSETEXTENT_AUXILIARY(extent_aux, data);
992         ext->plist = Fcons(extent_aux, ext->plist);
993         ext->flags.has_aux = 1;
994         return;
995 }
996 \f
997 /************************************************************************/
998 /*                         Extent info structure                        */
999 /************************************************************************/
1000
1001 /* An extent-info structure consists of a list of the buffer or string's
1002    extents and a "stack of extents" that lists all of the extents over
1003    a particular position.  The stack-of-extents info is used for
1004    optimization purposes -- it basically caches some info that might
1005    be expensive to compute.  Certain otherwise hard computations are easy
1006    given the stack of extents over a particular position, and if the
1007    stack of extents over a nearby position is known (because it was
1008    calculated at some prior point in time), it's easy to move the stack
1009    of extents to the proper position.
1010
1011    Given that the stack of extents is an optimization, and given that
1012    it requires memory, a string's stack of extents is wiped out each
1013    time a garbage collection occurs.  Therefore, any time you retrieve
1014    the stack of extents, it might not be there.  If you need it to
1015    be there, use the _force version.
1016
1017    Similarly, a string may or may not have an extent_info structure.
1018    (Generally it won't if there haven't been any extents added to the
1019    string.) So use the _force version if you need the extent_info
1020    structure to be there. */
1021
1022 static extent_stack_t allocate_soe(void);
1023 static void free_soe(extent_stack_t);
1024 static void soe_invalidate(Lisp_Object obj);
1025
1026 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1027 static Lisp_Object
1028 mark_extent_info(Lisp_Object obj)
1029 {
1030         struct extent_info *data = (struct extent_info *)XEXTENT_INFO(obj);
1031         int i;
1032         extent_list_t list = data->extents;
1033
1034         /* Vbuffer_defaults and Vbuffer_local_symbols are buffer-like
1035            objects that are created specially and never have their extent
1036            list initialized (or rather, it is set to zero in
1037            nuke_all_buffer_slots()).  However, these objects get
1038            garbage-collected so we have to deal.
1039
1040            (Also the list can be zero when we're dealing with a destroyed
1041            buffer.) */
1042
1043         if (list) {
1044                 for (i = 0; i < extent_list_num_els(list); i++) {
1045                         struct extent *extent = extent_list_at(list, i, 0);
1046                         Lisp_Object exobj;
1047
1048                         XSETEXTENT(exobj, extent);
1049                         mark_object(exobj);
1050                 }
1051         }
1052
1053         return Qnil;
1054 }
1055
1056 static void
1057 finalize_extent_info(void *header, int for_disksave)
1058 {
1059         struct extent_info *data = (struct extent_info *)header;
1060
1061         if (for_disksave)
1062                 return;
1063
1064         if (data->soe) {
1065                 free_soe(data->soe);
1066                 data->soe = 0;
1067         }
1068         if (data->extents) {
1069                 free_extent_list(data->extents);
1070                 data->extents = 0;
1071         }
1072 }
1073 #else  /* BDWGC */
1074 /* just define dummies */
1075 static Lisp_Object
1076 mark_extent_info(Lisp_Object UNUSED(obj))
1077 {
1078         return Qnil;
1079 }
1080
1081 static void
1082 finalize_extent_info(void *UNUSED(header), int UNUSED(for_disksave))
1083 {
1084         return;
1085 }
1086 #endif  /* !BDWGC */
1087
1088 DEFINE_LRECORD_IMPLEMENTATION("extent-info", extent_info,
1089                               mark_extent_info, internal_object_printer,
1090                               finalize_extent_info, 0, 0, 0,
1091                               struct extent_info);
1092 \f
1093 static Lisp_Object
1094 allocate_extent_info(void)
1095 {
1096         Lisp_Object extent_info;
1097         struct extent_info *data =
1098                 alloc_lcrecord_type(struct extent_info, &lrecord_extent_info);
1099
1100         XSETEXTENT_INFO(extent_info, data);
1101         data->extents = allocate_extent_list();
1102         data->soe = 0;
1103         return extent_info;
1104 }
1105
1106 void
1107 flush_cached_extent_info(Lisp_Object extent_info)
1108 {
1109         struct extent_info *data = XEXTENT_INFO(extent_info);
1110
1111         if (data->soe) {
1112                 free_soe(data->soe);
1113                 data->soe = 0;
1114         }
1115 }
1116 \f
1117 /************************************************************************/
1118 /*                    Buffer/string extent primitives                   */
1119 /************************************************************************/
1120
1121 /* The functions in this section are the ONLY ones that should know
1122    about the internal implementation of the extent lists.  Other functions
1123    should only know that there are two orderings on extents, the "display"
1124    order (sorted by start position, basically) and the e-order (sorted
1125    by end position, basically), and that certain operations are provided
1126    to manipulate the list. */
1127
1128 /* ------------------------------- */
1129 /*        basic primitives         */
1130 /* ------------------------------- */
1131
1132 static Lisp_Object
1133 decode_buffer_or_string(Lisp_Object object)
1134 {
1135         if (LIKELY(NILP(object))) {
1136                 XSETBUFFER(object, current_buffer);
1137         } else if (BUFFERP(object)) {
1138                 CHECK_LIVE_BUFFER(object);
1139         } else if (STRINGP(object)) {
1140                 ;
1141         } else {
1142                 dead_wrong_type_argument(Qbuffer_or_string_p, object);
1143         }
1144         return object;
1145 }
1146
1147 EXTENT extent_ancestor_1(EXTENT e)
1148 {
1149         while (e->flags.has_parent) {
1150                 /* There should be no circularities except in case of a logic
1151                    error somewhere in the extent code */
1152                 e = XEXTENT(XEXTENT_AUXILIARY(XCAR(e->plist))->parent);
1153         }
1154         return e;
1155 }
1156
1157 /* Given an extent object (string or buffer or nil), return its extent info.
1158    This may be 0 for a string. */
1159
1160 static struct extent_info*
1161 buffer_or_string_extent_info(Lisp_Object object)
1162 {
1163         if (STRINGP(object)) {
1164                 Lisp_Object plist = XSTRING(object)->plist;
1165                 if (!CONSP(plist) || !EXTENT_INFOP(XCAR(plist))) {
1166                         return NULL;
1167                 }
1168                 return XEXTENT_INFO(XCAR(plist));
1169         } else if (NILP(object)) {
1170                 return NULL;
1171         } else {
1172                 return XEXTENT_INFO(XBUFFER(object)->extent_info);
1173         }
1174 }
1175
1176 /* Given a string or buffer, return its extent list.  This may be
1177    0 for a string. */
1178
1179 static extent_list_t
1180 buffer_or_string_extent_list(Lisp_Object object)
1181 {
1182         struct extent_info *info = buffer_or_string_extent_info(object);
1183
1184         if (!info) {
1185                 return 0;
1186         }
1187         return info->extents;
1188 }
1189
1190 /* Given a string or buffer, return its extent info.  If it's not there,
1191    create it. */
1192
1193 static struct extent_info*
1194 buffer_or_string_extent_info_force(Lisp_Object object)
1195 {
1196         struct extent_info *info = buffer_or_string_extent_info(object);
1197
1198         if (!info) {
1199                 Lisp_Object extent_info;
1200
1201                 /* should never happen for buffers --
1202                    the only buffers without an extent
1203                    info are those after finalization,
1204                    destroyed buffers, or special
1205                    Lisp-inaccessible buffer objects. */
1206                 assert(STRINGP(object));
1207
1208                 extent_info = allocate_extent_info();
1209                 XSTRING(object)->plist =
1210                         Fcons(extent_info, XSTRING(object)->plist);
1211                 return XEXTENT_INFO(extent_info);
1212         }
1213         return info;
1214 }
1215
1216 /* Detach all the extents in OBJECT.  Called from redisplay. */
1217
1218 void
1219 detach_all_extents(Lisp_Object object)
1220 {
1221         struct extent_info *data = buffer_or_string_extent_info(object);
1222
1223         if (data) {
1224                 if (data->extents) {
1225                         for (int i = 0;
1226                              i < extent_list_num_els(data->extents);
1227                              i++) {
1228                                 EXTENT e = extent_list_at(data->extents, i, 0);
1229                                 /* No need to do detach_extent().  Just nuke the
1230                                    damn things, which results in the equivalent
1231                                    but faster. */
1232                                 set_extent_start(e, -1);
1233                                 set_extent_end(e, -1);
1234                         }
1235                         /* But we need to clear all the lists containing extents
1236                            or havoc will result. */
1237                         extent_list_delete_all(data->extents);
1238                 }
1239                 soe_invalidate(object);
1240         }
1241         return;
1242 }
1243
1244 void
1245 init_buffer_extents(struct buffer *b)
1246 {
1247         b->extent_info = allocate_extent_info();
1248         return;
1249 }
1250
1251 void
1252 uninit_buffer_extents(struct buffer *b)
1253 {
1254         struct extent_info *data = XEXTENT_INFO(b->extent_info);
1255
1256         /* Don't destroy the extents here -- there may still be children
1257            extents pointing to the extents. */
1258         detach_all_extents(make_buffer(b));
1259         finalize_extent_info(data, 0);
1260         return;
1261 }
1262
1263 /* Retrieve the extent list that an extent is a member of; the
1264    return value will never be 0 except in destroyed buffers (in which
1265    case the only extents that can refer to this buffer are detached
1266    ones). */
1267
1268 #define extent_extent_list(e) buffer_or_string_extent_list (extent_object (e))
1269
1270 /* ------------------------------- */
1271 /*        stack of extents         */
1272 /* ------------------------------- */
1273
1274 #ifdef ERROR_CHECK_EXTENTS
1275
1276 void
1277 sledgehammer_extent_check(Lisp_Object object)
1278 {
1279         extent_list_t el = buffer_or_string_extent_list(object);
1280         struct buffer *buf = 0;
1281
1282         if (!el) {
1283                 return;
1284         }
1285         if (BUFFERP(object)) {
1286                 buf = XBUFFER(object);
1287         }
1288         for (int endp = 0; endp < 2; endp++) {
1289                 for (int i = 1; i < extent_list_num_els(el); i++) {
1290                         EXTENT e1 = extent_list_at(el, i - 1, endp);
1291                         EXTENT e2 = extent_list_at(el, i, endp);
1292                         if (buf) {
1293                                 assert(extent_start(e1) <= buf->text->gpt ||
1294                                        extent_start(e1) >
1295                                        buf->text->gpt + buf->text->gap_size);
1296                                 assert(extent_end(e1) <= buf->text->gpt
1297                                        || extent_end(e1) >
1298                                        buf->text->gpt + buf->text->gap_size);
1299                         }
1300                         assert(extent_start(e1) <= extent_end(e1));
1301                         assert(endp
1302                                ? (EXTENT_E_LESS_EQUAL(e1, e2))
1303                                : (EXTENT_LESS_EQUAL(e1, e2)));
1304                 }
1305         }
1306 }
1307
1308 #endif  /* ERROR_CHECK_EXTENTS */
1309
1310 static extent_stack_t
1311 buffer_or_string_stack_of_extents(Lisp_Object object)
1312 {
1313         struct extent_info *info = buffer_or_string_extent_info(object);
1314         if (!info) {
1315                 return NULL;
1316         }
1317         return info->soe;
1318 }
1319
1320 static extent_stack_t
1321 buffer_or_string_stack_of_extents_force(Lisp_Object object)
1322 {
1323         struct extent_info *info = buffer_or_string_extent_info_force(object);
1324         if (!info->soe) {
1325                 info->soe = allocate_soe();
1326         }
1327         return info->soe;
1328 }
1329
1330 /* #define SOE_DEBUG */
1331
1332 #ifdef SOE_DEBUG
1333
1334 static void print_extent_1(char *buf, Lisp_Object extent);
1335
1336 static void
1337 print_extent_2(EXTENT e)
1338 {
1339         Lisp_Object extent;
1340         char buf[200];
1341
1342         XSETEXTENT(extent, e);
1343         print_extent_1(buf, extent);
1344         fputs(buf, stdout);
1345 }
1346
1347 static void
1348 soe_dump(Lisp_Object obj)
1349 {
1350         int i;
1351         extent_stack_t soe = buffer_or_string_stack_of_extents(obj);
1352         extent_list_t sel;
1353         int endp;
1354
1355         if (!soe) {
1356                 printf("No SOE");
1357                 return;
1358         }
1359         sel = soe->extents;
1360         printf("SOE pos is %d (memind %d)\n",
1361                soe->pos < 0 ? soe->pos :
1362                buffer_or_string_memind_to_bytind(obj, soe->pos), soe->pos);
1363         for (endp = 0; endp < 2; endp++) {
1364                 printf(endp ? "SOE end:" : "SOE start:");
1365                 for (i = 0; i < extent_list_num_els(sel); i++) {
1366                         EXTENT e = extent_list_at(sel, i, endp);
1367                         putchar('\t');
1368                         print_extent_2(e);
1369                 }
1370                 putchar('\n');
1371         }
1372         putchar('\n');
1373 }
1374
1375 #endif  /* SOE_DEBUG */
1376
1377 /* Insert EXTENT into OBJ's stack of extents, if necessary. */
1378
1379 static void
1380 soe_insert(Lisp_Object obj, EXTENT extent)
1381 {
1382         extent_stack_t soe = buffer_or_string_stack_of_extents(obj);
1383
1384 #ifdef SOE_DEBUG
1385         printf("Inserting into SOE: ");
1386         print_extent_2(extent);
1387         putchar('\n');
1388 #endif
1389         if (!soe || soe->pos < extent_start(extent) ||
1390             soe->pos > extent_end(extent)) {
1391 #ifdef SOE_DEBUG
1392                 printf("(not needed)\n\n");
1393 #endif
1394                 return;
1395         }
1396         extent_list_insert(soe->extents, extent);
1397 #ifdef SOE_DEBUG
1398         puts("SOE afterwards is:");
1399         soe_dump(obj);
1400 #endif
1401         return;
1402 }
1403
1404 /* Delete EXTENT from OBJ's stack of extents, if necessary. */
1405
1406 static void
1407 soe_delete(Lisp_Object obj, EXTENT extent)
1408 {
1409         extent_stack_t soe = buffer_or_string_stack_of_extents(obj);
1410
1411 #ifdef SOE_DEBUG
1412         printf("Deleting from SOE: ");
1413         print_extent_2(extent);
1414         putchar('\n');
1415 #endif
1416         if (!soe || soe->pos < extent_start(extent) ||
1417             soe->pos > extent_end(extent)) {
1418 #ifdef SOE_DEBUG
1419                 puts("(not needed)\n");
1420 #endif
1421                 return;
1422         }
1423         extent_list_delete(soe->extents, extent);
1424 #ifdef SOE_DEBUG
1425         puts("SOE afterwards is:");
1426         soe_dump(obj);
1427 #endif
1428         return;
1429 }
1430
1431 /* Move OBJ's stack of extents to lie over the specified position. */
1432
1433 static void
1434 soe_move(Lisp_Object obj, Memind pos)
1435 {
1436         extent_stack_t soe = buffer_or_string_stack_of_extents_force(obj);
1437         extent_list_t sel = soe->extents;
1438         int numsoe = extent_list_num_els(sel);
1439         extent_list_t bel = buffer_or_string_extent_list(obj);
1440         int direction;
1441         int endp;
1442
1443 #ifdef ERROR_CHECK_EXTENTS
1444         assert(bel);
1445 #endif
1446
1447 #ifdef SOE_DEBUG
1448         printf("Moving SOE from %d (memind %d) to %d (memind %d)\n",
1449                soe->pos < 0 ? soe->pos :
1450                buffer_or_string_memind_to_bytind(obj, soe->pos), soe->pos,
1451                buffer_or_string_memind_to_bytind(obj, pos), pos);
1452 #endif
1453         if (soe->pos < pos) {
1454                 direction = 1;
1455                 endp = 0;
1456         } else if (soe->pos > pos) {
1457                 direction = -1;
1458                 endp = 1;
1459         } else {
1460 #ifdef SOE_DEBUG
1461                 puts("(not needed)\n");
1462 #endif
1463                 return;
1464         }
1465
1466         /* For DIRECTION = 1: Any extent that overlaps POS is either in the
1467            SOE (if the extent starts at or before SOE->POS) or is greater
1468            (in the display order) than any extent in the SOE (if it starts
1469            after SOE->POS).
1470
1471            For DIRECTION = -1: Any extent that overlaps POS is either in the
1472            SOE (if the extent ends at or after SOE->POS) or is less (in the
1473            e-order) than any extent in the SOE (if it ends before SOE->POS).
1474
1475            We proceed in two stages:
1476
1477            1) delete all extents in the SOE that don't overlap POS.
1478            2) insert all extents into the SOE that start (or end, when
1479            DIRECTION = -1) in (SOE->POS, POS] and that overlap
1480            POS. (Don't include SOE->POS in the range because those
1481            extents would already be in the SOE.)
1482          */
1483
1484         /* STAGE 1. */
1485
1486         if (numsoe > 0) {
1487                 /* Delete all extents in the SOE that don't overlap POS.
1488                    This is all extents that end before (or start after,
1489                    if DIRECTION = -1) POS.
1490                  */
1491
1492                 /* Deleting extents from the SOE is tricky because it changes
1493                    the positions of extents.  If we are deleting in the forward
1494                    direction we have to call extent_list_at() on the same position
1495                    over and over again because positions after the deleted element
1496                    get shifted back by 1.  To make life simplest, we delete forward
1497                    irrespective of DIRECTION.
1498                  */
1499                 int start, end;
1500                 int i;
1501
1502                 if (direction > 0) {
1503                         start = 0;
1504                         end = extent_list_locate_from_pos(sel, pos, 1);
1505                 } else {
1506                         start = extent_list_locate_from_pos(sel, pos + 1, 0);
1507                         end = numsoe;
1508                 }
1509
1510                 for (i = start; i < end; i++) {
1511                         extent_list_delete(
1512                                 sel, extent_list_at(sel, start, !endp));
1513                 }
1514         }
1515
1516         /* STAGE 2. */
1517
1518         {
1519                 int start_pos;
1520
1521                 if (direction < 0) {
1522                         start_pos =
1523                                 extent_list_locate_from_pos(
1524                                         bel, soe->pos, endp) - 1;
1525                 } else {
1526                         start_pos =
1527                                 extent_list_locate_from_pos(
1528                                         bel, soe->pos + 1, endp);
1529                 }
1530
1531                 for (; start_pos >= 0 && start_pos < extent_list_num_els(bel);
1532                      start_pos += direction) {
1533                         EXTENT e = extent_list_at(bel, start_pos, endp);
1534                         if ((direction > 0)
1535                             ? (extent_start(e) > pos)
1536                             : (extent_end(e) < pos)) {
1537                                 /* All further extents lie on the far side of
1538                                    POS and thus can't overlap. */
1539                                 break;  
1540                         }
1541                         if ((direction > 0)
1542                             ? (extent_end(e) >= pos)
1543                             : (extent_start(e) <= pos)) {
1544                                 extent_list_insert(sel, e);
1545                         }
1546                 }
1547         }
1548
1549         soe->pos = pos;
1550 #ifdef SOE_DEBUG
1551         puts("SOE afterwards is:");
1552         soe_dump(obj);
1553 #endif
1554         return;
1555 }
1556
1557 static void
1558 soe_invalidate(Lisp_Object obj)
1559 {
1560         extent_stack_t soe = buffer_or_string_stack_of_extents(obj);
1561
1562         if (soe) {
1563                 extent_list_delete_all(soe->extents);
1564                 soe->pos = -1;
1565         }
1566         return;
1567 }
1568
1569 static extent_stack_t
1570 allocate_soe(void)
1571 {
1572         extent_stack_t soe = xnew_and_zero(struct extent_stack_s);
1573         soe->extents = allocate_extent_list();
1574         soe->pos = -1;
1575         return soe;
1576 }
1577
1578 static void
1579 free_soe(extent_stack_t soe)
1580 {
1581         free_extent_list(soe->extents);
1582         xfree(soe);
1583         return;
1584 }
1585
1586 /* ------------------------------- */
1587 /*        other primitives         */
1588 /* ------------------------------- */
1589
1590 /* Return the start (endp == 0) or end (endp == 1) of an extent as
1591    a byte index.  If you want the value as a memory index, use
1592    extent_endpoint().  If you want the value as a buffer position,
1593    use extent_endpoint_bufpos(). */
1594
1595 static Bytind extent_endpoint_bytind(EXTENT extent, int endp)
1596 {
1597         assert(EXTENT_LIVE_P(extent));
1598         assert(!extent_detached_p(extent));
1599         {
1600                 Memind i = endp ? extent_end(extent) : extent_start(extent);
1601                 Lisp_Object obj = extent_object(extent);
1602                 return buffer_or_string_memind_to_bytind(obj, i);
1603         }
1604 }
1605
1606 static Bufpos extent_endpoint_bufpos(EXTENT extent, int endp)
1607 {
1608         assert(EXTENT_LIVE_P(extent));
1609         assert(!extent_detached_p(extent));
1610         {
1611                 Memind i = endp ? extent_end(extent) : extent_start(extent);
1612                 Lisp_Object obj = extent_object(extent);
1613                 return buffer_or_string_memind_to_bufpos(obj, i);
1614         }
1615 }
1616
1617 /* A change to an extent occurred that will change the display, so
1618    notify redisplay.  Maybe also recurse over all the extent's
1619    descendants. */
1620
1621 static void
1622 extent_changed_for_redisplay(EXTENT extent, int descendants_too,
1623                              int invisibility_change)
1624 {
1625         Lisp_Object object;
1626         Lisp_Object rest;
1627
1628         /* we could easily encounter a detached extent while traversing the
1629            children, but we should never be able to encounter a dead extent. */
1630         assert(EXTENT_LIVE_P(extent));
1631
1632         if (descendants_too) {
1633                 Lisp_Object children = extent_children(extent);
1634
1635                 if (!NILP(children)) {
1636                         /* first mark all of the extent's children.  We will
1637                            lose big-time if there are any circularities here, so
1638                            we sure as hell better ensure that there aren't. */
1639                         LIST_LOOP(rest, XWEAK_LIST_LIST(children)) {
1640                                 extent_changed_for_redisplay(
1641                                         XEXTENT(XCAR(rest)), 1,
1642                                         invisibility_change);
1643                         }
1644                 }
1645         }
1646
1647         /* now mark the extent itself. */
1648
1649         object = extent_object(extent);
1650
1651         if (extent_detached_p(extent)) {
1652                 return;
1653
1654         } else if (STRINGP(object)) {
1655                 /* #### Changes to string extents can affect redisplay if they
1656                    are in the modeline or in the gutters.
1657
1658                    If the extent is in some generated-modeline-string: when we
1659                    change an extent in generated-modeline-string, this changes
1660                    its parent, which is in `modeline-format', so we should force
1661                    the modeline to be updated.  But how to determine whether a
1662                    string is a `generated-modeline-string'?  Looping through all
1663                    buffers is not very efficient.  Should we add all
1664                    `generated-modeline-string' strings to a hash table?  Maybe
1665                    efficiency is not the greatest concern here and there's no
1666                    big loss in looping over the buffers.
1667
1668                    If the extent is in a gutter we mark the gutter as
1669                    changed. This means (a) we can update extents in the gutters
1670                    when we need it. (b) we don't have to update the gutters when
1671                    only extents attached to buffers have changed. */
1672
1673                 if (!in_modeline_generation) {
1674                         MARK_EXTENTS_CHANGED;
1675                 }
1676                 gutter_extent_signal_changed_region_maybe(
1677                         object,
1678                         extent_endpoint_bufpos(extent, 0),
1679                         extent_endpoint_bufpos(extent, 1));
1680
1681         } else if (BUFFERP(object)) {
1682                 struct buffer *b;
1683                 b = XBUFFER(object);
1684                 BUF_FACECHANGE(b)++;
1685                 MARK_EXTENTS_CHANGED;
1686                 if (invisibility_change) {
1687                         MARK_CLIP_CHANGED;
1688                 }
1689                 buffer_extent_signal_changed_region(
1690                         b,
1691                         extent_endpoint_bufpos(extent, 0),
1692                         extent_endpoint_bufpos(extent, 1));
1693         }
1694 }
1695
1696 /* A change to an extent occurred that might affect redisplay.
1697    This is called when properties such as the endpoints, the layout,
1698    or the priority changes.  Redisplay will be affected only if
1699    the extent has any displayable attributes. */
1700
1701 static void
1702 extent_maybe_changed_for_redisplay(EXTENT extent, int descendants_too,
1703                                    int invisibility_change)
1704 {
1705         /* Retrieve the ancestor for efficiency */
1706         EXTENT anc = extent_ancestor(extent);
1707         if (!NILP(extent_face(anc)) ||
1708             !NILP(extent_begin_glyph(anc)) ||
1709             !NILP(extent_end_glyph(anc)) ||
1710             !NILP(extent_mouse_face(anc)) ||
1711             !NILP(extent_invisible(anc)) ||
1712             !NILP(extent_initial_redisplay_function(anc)) ||
1713             invisibility_change)
1714                 extent_changed_for_redisplay(extent, descendants_too,
1715                                              invisibility_change);
1716 }
1717
1718 static EXTENT
1719 make_extent_detached(Lisp_Object object)
1720 {
1721         EXTENT extent = allocate_extent();
1722
1723         assert(NILP(object) || STRINGP(object) ||
1724                (BUFFERP(object) && BUFFER_LIVE_P(XBUFFER(object))));
1725         extent_object(extent) = object;
1726         /* Now make sure the extent info exists. */
1727         if (!NILP(object)) {
1728                 buffer_or_string_extent_info_force(object);
1729         }
1730         return extent;
1731 }
1732
1733 /* A "real" extent is any extent other than the internal (not-user-visible)
1734    extents used by `map-extents'. */
1735
1736 static EXTENT
1737 real_extent_at_forward(extent_list_t el, int pos, int endp)
1738 {
1739         for (; pos < extent_list_num_els(el); pos++) {
1740                 EXTENT e = extent_list_at(el, pos, endp);
1741                 if (!extent_internal_p(e)) {
1742                         return e;
1743                 }
1744         }
1745         return NULL;
1746 }
1747
1748 static EXTENT
1749 real_extent_at_backward(extent_list_t el, int pos, int endp)
1750 {
1751         for (; pos >= 0; pos--) {
1752                 EXTENT e = extent_list_at(el, pos, endp);
1753                 if (!extent_internal_p(e)) {
1754                         return e;
1755                 }
1756         }
1757         return NULL;
1758 }
1759
1760 static EXTENT
1761 extent_first(Lisp_Object obj)
1762 {
1763         extent_list_t el = buffer_or_string_extent_list(obj);
1764
1765         if (!el) {
1766                 return NULL;
1767         }
1768         return real_extent_at_forward(el, 0, 0);
1769 }
1770
1771 #ifdef DEBUG_SXEMACS
1772 static EXTENT
1773 extent_e_first(Lisp_Object obj)
1774 {
1775         extent_list_t el = buffer_or_string_extent_list(obj);
1776
1777         if (!el) {
1778                 return 0;
1779         }
1780         return real_extent_at_forward(el, 0, 1);
1781 }
1782 #endif  /* DEBUG_SXEMACS */
1783
1784 static EXTENT
1785 extent_next(EXTENT e)
1786 {
1787         extent_list_t el = extent_extent_list(e);
1788         bool foundp;
1789         int pos = extent_list_locate(el, e, 0, &foundp);
1790         assert(foundp);
1791         return real_extent_at_forward(el, pos + 1, 0);
1792 }
1793
1794 #ifdef DEBUG_SXEMACS
1795 static EXTENT
1796 extent_e_next(EXTENT e)
1797 {
1798         extent_list_t el = extent_extent_list(e);
1799         bool foundp;
1800         int pos = extent_list_locate(el, e, 1, &foundp);
1801         assert(foundp);
1802         return real_extent_at_forward(el, pos + 1, 1);
1803 }
1804 #endif  /* DEBUG_SXEMACS */
1805
1806 static EXTENT
1807 extent_last(Lisp_Object obj)
1808 {
1809         extent_list_t el = buffer_or_string_extent_list(obj);
1810
1811         if (!el) {
1812                 return 0;
1813         }
1814         return real_extent_at_backward(el, extent_list_num_els(el) - 1, 0);
1815 }
1816
1817 #ifdef DEBUG_SXEMACS
1818 static EXTENT
1819 extent_e_last(Lisp_Object obj)
1820 {
1821         extent_list_t el = buffer_or_string_extent_list(obj);
1822
1823         if (!el) {
1824                 return 0;
1825         }
1826         return real_extent_at_backward(el, extent_list_num_els(el) - 1, 1);
1827 }
1828 #endif  /* DEBUG_SXEMACS */
1829
1830 static EXTENT
1831 extent_previous(EXTENT e)
1832 {
1833         extent_list_t el = extent_extent_list(e);
1834         bool foundp;
1835         int pos = extent_list_locate(el, e, 0, &foundp);
1836         assert(foundp);
1837         return real_extent_at_backward(el, pos - 1, 0);
1838 }
1839
1840 #ifdef DEBUG_SXEMACS
1841 static EXTENT
1842 extent_e_previous(EXTENT e)
1843 {
1844         extent_list_t el = extent_extent_list(e);
1845         bool foundp;
1846         int pos = extent_list_locate(el, e, 1, &foundp);
1847         assert(foundp);
1848         return real_extent_at_backward(el, pos - 1, 1);
1849 }
1850 #endif  /* DEBUG_SXEMACS */
1851
1852 static void
1853 extent_attach(EXTENT extent)
1854 {
1855         extent_list_t el = extent_extent_list(extent);
1856
1857         extent_list_insert(el, extent);
1858         soe_insert(extent_object(extent), extent);
1859         /* only this extent changed */
1860         extent_maybe_changed_for_redisplay(
1861                 extent, 0, !NILP(extent_invisible(extent)));
1862         return;
1863 }
1864
1865 static void
1866 extent_detach(EXTENT extent)
1867 {
1868         extent_list_t el;
1869
1870         if (extent_detached_p(extent)) {
1871                 return;
1872         }
1873         el = extent_extent_list(extent);
1874
1875         /* call this before messing with the extent. */
1876         extent_maybe_changed_for_redisplay(
1877                 extent, 0, !NILP(extent_invisible(extent)));
1878         extent_list_delete(el, extent);
1879         soe_delete(extent_object(extent), extent);
1880         set_extent_start(extent, -1);
1881         set_extent_end(extent, -1);
1882         return;
1883 }
1884
1885 /* ------------------------------- */
1886 /*        map-extents et al.       */
1887 /* ------------------------------- */
1888
1889 /* Returns true iff map_extents() would visit the given extent.
1890    See the comments at map_extents() for info on the overlap rule.
1891    Assumes that all validation on the extent and buffer positions has
1892    already been performed (see Fextent_in_region_p ()).
1893  */
1894 static bool
1895 extent_in_region_p(EXTENT extent, Bytind from, Bytind to, unsigned int flags)
1896 {
1897         Lisp_Object obj = extent_object(extent);
1898         Endpoint_Index start, end, exs, exe;
1899         int start_open, end_open;
1900         unsigned int all_extents_flags = flags & ME_ALL_EXTENTS_MASK;
1901         unsigned int in_region_flags = flags & ME_IN_REGION_MASK;
1902         int retval;
1903
1904         /* A zero-length region is treated as closed-closed. */
1905         if (from == to) {
1906                 flags |= ME_END_CLOSED;
1907                 flags &= ~ME_START_OPEN;
1908         }
1909
1910         /* So is a zero-length extent. */
1911         if (extent_start(extent) == extent_end(extent)) {
1912                 start_open = 0, end_open = 0;
1913         } else if (LIKELY(all_extents_flags == 0)) {
1914                 /* `all_extents_flags' will almost always be zero. */
1915                 start_open = extent_start_open_p(extent);
1916                 end_open = extent_end_open_p(extent);
1917         } else {
1918                 switch (all_extents_flags) {
1919                 case ME_ALL_EXTENTS_CLOSED:
1920                         start_open = 0, end_open = 0;
1921                         break;
1922                 case ME_ALL_EXTENTS_OPEN:
1923                         start_open = 1, end_open = 1;
1924                         break;
1925                 case ME_ALL_EXTENTS_CLOSED_OPEN:
1926                         start_open = 0, end_open = 1;
1927                         break;
1928                 case ME_ALL_EXTENTS_OPEN_CLOSED:
1929                         start_open = 1, end_open = 0;
1930                         break;
1931                 default:
1932                         abort();
1933                         return false;
1934                 }
1935         }
1936         start = buffer_or_string_bytind_to_startind(obj, from,
1937                                                     flags & ME_START_OPEN);
1938         end = buffer_or_string_bytind_to_endind(obj, to,
1939                                                 !(flags & ME_END_CLOSED));
1940         exs = memind_to_startind(extent_start(extent), start_open);
1941         exe = memind_to_endind(extent_end(extent), end_open);
1942
1943         /* It's easy to determine whether an extent lies *outside* the
1944            region -- just determine whether it's completely before
1945            or completely after the region.  Reject all such extents, so
1946            we're now left with only the extents that overlap the region.
1947          */
1948
1949         if (exs > end || exe < start) {
1950                 return false;
1951         }
1952         /* See if any further restrictions are called for. */
1953         /* in_region_flags will almost always be zero. */
1954         if (in_region_flags == 0) {
1955                 retval = 1;
1956         } else {
1957                 switch (in_region_flags) {
1958                 case ME_START_IN_REGION:
1959                         retval = start <= exs && exs <= end;
1960                         break;
1961                 case ME_END_IN_REGION:
1962                         retval = start <= exe && exe <= end;
1963                         break;
1964                 case ME_START_AND_END_IN_REGION:
1965                         retval = start <= exs && exe <= end;
1966                         break;
1967                 case ME_START_OR_END_IN_REGION:
1968                         retval = (start <= exs && exs <= end) ||
1969                                 (start <= exe && exe <= end);
1970                         break;
1971                 default:
1972                         abort();
1973                         return false;
1974                 }
1975         }
1976         return flags & ME_NEGATE_IN_REGION ? !retval : retval;
1977 }
1978
1979 struct map_extents_struct {
1980         extent_list_t el;
1981         extent_list_marker_t mkr;
1982         EXTENT range;
1983 };
1984
1985 static Lisp_Object
1986 map_extents_unwind(Lisp_Object obj)
1987 {
1988         struct map_extents_struct *closure =
1989                 (struct map_extents_struct *)get_opaque_ptr(obj);
1990         free_opaque_ptr(obj);
1991         if (closure->range) {
1992                 extent_detach(closure->range);
1993         }
1994         if (closure->mkr) {
1995                 extent_list_delete_marker(closure->el, closure->mkr);
1996         }
1997         return Qnil;
1998 }
1999
2000 /* This is the guts of `map-extents' and the other functions that
2001    map over extents.  In theory the operation of this function is
2002    simple: just figure out what extents we're mapping over, and
2003    call the function on each one of them in the range.  Unfortunately
2004    there are a wide variety of things that the mapping function
2005    might do, and we have to be very tricky to avoid getting messed
2006    up.  Furthermore, this function needs to be very fast (it is
2007    called multiple times every time text is inserted or deleted
2008    from a buffer), and so we can't always afford the overhead of
2009    dealing with all the possible things that the mapping function
2010    might do; thus, there are many flags that can be specified
2011    indicating what the mapping function might or might not do.
2012
2013    The result of all this is that this is the most complicated
2014    function in this file.  Change it at your own risk!
2015
2016    A potential simplification to the logic below is to determine
2017    all the extents that the mapping function should be called on
2018    before any calls are actually made and save them in an array.
2019    That introduces its own complications, however (the array
2020    needs to be marked for garbage-collection, and a static array
2021    cannot be used because map_extents() needs to be reentrant).
2022    Furthermore, the results might be a little less sensible than
2023    the logic below. */
2024
2025 static void
2026 map_extents_bytind(Bytind from, Bytind to, map_extents_fun fn, void *arg,
2027                    Lisp_Object obj, EXTENT after, unsigned int flags)
2028 {
2029         Memind st, en;          /* range we're mapping over */
2030         EXTENT range = 0;       /* extent for this, if ME_MIGHT_MODIFY_TEXT */
2031         extent_list_t el = 0;   /* extent list we're iterating over */
2032         extent_list_marker_t posm = 0;  /* marker for extent list,
2033                                            if ME_MIGHT_MODIFY_EXTENTS */
2034         /* count and struct for unwind-protect, if ME_MIGHT_THROW */
2035         int count = 0;
2036         struct map_extents_struct closure;
2037
2038 #ifdef ERROR_CHECK_EXTENTS
2039         assert(from <= to);
2040         assert(from >= buffer_or_string_absolute_begin_byte(obj) &&
2041                from <= buffer_or_string_absolute_end_byte(obj) &&
2042                to >= buffer_or_string_absolute_begin_byte(obj) &&
2043                to <= buffer_or_string_absolute_end_byte(obj));
2044 #endif
2045
2046         if (after) {
2047                 assert(EQ(obj, extent_object(after)));
2048                 assert(!extent_detached_p(after));
2049         }
2050
2051         el = buffer_or_string_extent_list(obj);
2052         if (!el || !extent_list_num_els(el))
2053                 return;
2054         el = 0;
2055
2056         st = buffer_or_string_bytind_to_memind(obj, from);
2057         en = buffer_or_string_bytind_to_memind(obj, to);
2058
2059         if (flags & ME_MIGHT_MODIFY_TEXT) {
2060                 /* The mapping function might change the text in the buffer,
2061                    so make an internal extent to hold the range we're mapping
2062                    over. */
2063                 range = make_extent_detached(obj);
2064                 set_extent_start(range, st);
2065                 set_extent_end(range, en);
2066                 range->flags.start_open = flags & ME_START_OPEN;
2067                 range->flags.end_open = !(flags & ME_END_CLOSED);
2068                 range->flags.internal = 1;
2069                 range->flags.detachable = 0;
2070                 extent_attach(range);
2071         }
2072
2073         if (flags & ME_MIGHT_THROW) {
2074                 /* The mapping function might throw past us so we need to use an
2075                    unwind_protect() to eliminate the internal extent and range
2076                    that we use. */
2077                 count = specpdl_depth();
2078                 closure.range = range;
2079                 closure.mkr = 0;
2080                 record_unwind_protect(map_extents_unwind,
2081                                       make_opaque_ptr(&closure));
2082         }
2083
2084         /* ---------- Figure out where we start and what direction
2085            we move in.  This is the trickiest part of this
2086            function. ---------- */
2087
2088         /* If ME_START_IN_REGION, ME_END_IN_REGION or ME_START_AND_END_IN_REGION
2089            was specified and ME_NEGATE_IN_REGION was not specified, our job
2090            is simple because of the presence of the display order and e-order.
2091            (Note that theoretically do something similar for
2092            ME_START_OR_END_IN_REGION, but that would require more trickiness
2093            than it's worth to avoid hitting the same extent twice.)
2094
2095            In the general case, all the extents that overlap a range can be
2096            divided into two classes: those whose start position lies within
2097            the range (including the range's end but not including the
2098            range's start), and those that overlap the start position,
2099            i.e. those in the SOE for the start position.  Or equivalently,
2100            the extents can be divided into those whose end position lies
2101            within the range and those in the SOE for the end position.  Note
2102            that for this purpose we treat both the range and all extents in
2103            the buffer as closed on both ends.  If this is not what the ME_
2104            flags specified, then we've mapped over a few too many extents,
2105            but no big deal because extent_in_region_p() will filter them
2106            out.   Ideally, we could move the SOE to the closer of the range's
2107            two ends and work forwards or backwards from there.  However, in
2108            order to make the semantics of the AFTER argument work out, we
2109            have to always go in the same direction; so we choose to always
2110            move the SOE to the start position.
2111
2112            When it comes time to do the SOE stage, we first call soe_move()
2113            so that the SOE gets set up.  Note that the SOE might get
2114            changed while we are mapping over its contents.  If we can
2115            guarantee that the SOE won't get moved to a new position, we
2116            simply need to put a marker in the SOE and we will track deletions
2117            and insertions of extents in the SOE.  If the SOE might get moved,
2118            however (this would happen as a result of a recursive invocation
2119            of map-extents or a call to a redisplay-type function), then
2120            trying to track its changes is hopeless, so we just keep a
2121            marker to the first (or last) extent in the SOE and use that as
2122            our bound.
2123
2124            Finally, if DONT_USE_SOE is defined, we don't use the SOE at all
2125            and instead just map from the beginning of the buffer.  This is
2126            used for testing purposes and allows the SOE to be calculated
2127            using map_extents() instead of the other way around. */
2128
2129         {
2130                 int range_flag; /* ME_*_IN_REGION subset of flags */
2131                 int do_soe_stage = 0;   /* Are we mapping over the SOE? */
2132                 /* Does the range stage map over start or end positions? */
2133                 int range_endp;
2134                 /* If type == 0, we include the start position in the range
2135                    stage mapping.
2136                    If type == 1, we exclude the start position in the range
2137                    stage mapping.
2138                    If type == 2, we begin at range_start_pos, an extent-list
2139                    position.
2140                  */
2141                 int range_start_type = 0;
2142                 int range_start_pos = 0;
2143                 int stage;
2144
2145                 range_flag = flags & ME_IN_REGION_MASK;
2146                 if ((range_flag == ME_START_IN_REGION ||
2147                      range_flag == ME_START_AND_END_IN_REGION) &&
2148                     !(flags & ME_NEGATE_IN_REGION)) {
2149                         /* map over start position in [range-start, range-end].
2150                            No SOE stage. */
2151                         range_endp = 0;
2152                 } else if (range_flag == ME_END_IN_REGION
2153                            && !(flags & ME_NEGATE_IN_REGION)) {
2154                         /* map over end position in [range-start, range-end].
2155                            No SOE stage. */
2156                         range_endp = 1;
2157                 } else {
2158                         /* Need to include the SOE extents. */
2159 #ifdef DONT_USE_SOE
2160                         /* Just brute-force it: start from the beginning. */
2161                         range_endp = 0;
2162                         range_start_type = 2;
2163                         range_start_pos = 0;
2164 #else
2165                         extent_stack_t soe =
2166                                 buffer_or_string_stack_of_extents_force(obj);
2167                         int numsoe;
2168
2169                         /* Move the SOE to the closer end of the range.  This
2170                            dictates whether we map over start positions or end
2171                            positions. */
2172                         range_endp = 0;
2173                         soe_move(obj, st);
2174                         numsoe = extent_list_num_els(soe->extents);
2175                         if (numsoe) {
2176                                 if (flags & ME_MIGHT_MOVE_SOE) {
2177                                         bool foundp;
2178                                         /* Can't map over SOE, so just extend
2179                                            range to cover the SOE. */
2180                                         EXTENT e = extent_list_at(
2181                                                 soe->extents, 0, 0);
2182                                         range_start_pos = extent_list_locate
2183                                                 (buffer_or_string_extent_list
2184                                                  (obj), e, 0, &foundp);
2185                                         assert(foundp);
2186                                         range_start_type = 2;
2187                                 } else {
2188                                         /* We can map over the SOE. */
2189                                         do_soe_stage = 1;
2190                                         range_start_type = 1;
2191                                 }
2192                         } else {
2193                                 /* No extents in the SOE to map over, so we act
2194                                    just as if ME_START_IN_REGION or
2195                                    ME_END_IN_REGION was specified.  RANGE_ENDP
2196                                    already specified so no need to do anything
2197                                    else. */
2198                         }
2199                 }
2200 #endif
2201
2202                 /* ---------- Now loop over the extents. ---------- */
2203
2204                 /* We combine the code for the two stages because much of it
2205                    overlaps. */
2206                 for (stage = 0; stage < 2; stage++) {
2207                         int pos = 0;    /* Position in extent list */
2208
2209                         /* First set up start conditions */
2210                         if (stage == 0) {       /* The SOE stage */
2211                                 if (!do_soe_stage)
2212                                         continue;
2213                                 el = buffer_or_string_stack_of_extents_force
2214                                     (obj)->extents;
2215                                 /* We will always be looping over start extents
2216                                    here. */
2217                                 assert(!range_endp);
2218                                 pos = 0;
2219                         } else {        /* The range stage */
2220                                 el = buffer_or_string_extent_list(obj);
2221                                 switch (range_start_type) {
2222                                 case 0:
2223                                         pos = extent_list_locate_from_pos
2224                                                 (el, st, range_endp);
2225                                         break;
2226                                 case 1:
2227                                         pos = extent_list_locate_from_pos
2228                                                 (el, st + 1, range_endp);
2229                                         break;
2230                                 case 2:
2231                                         pos = range_start_pos;
2232                                         break;
2233                                 default:
2234                                         break;
2235                                 }
2236                         }
2237
2238                         if (flags & ME_MIGHT_MODIFY_EXTENTS) {
2239                                 /* Create a marker to track changes to the
2240                                    extent list */
2241                                 if (posm)
2242                                         /* Delete the marker used in the SOE
2243                                            stage. */
2244                                         extent_list_delete_marker
2245                                                 (buffer_or_string_stack_of_extents_force
2246                                                  (obj)->extents, posm);
2247                                 posm = extent_list_make_marker(
2248                                         el, pos, range_endp);
2249                                 /* tell the unwind function about the marker. */
2250                                 closure.el = el;
2251                                 closure.mkr = posm;
2252                         }
2253
2254                         /* Now loop! */
2255                         for (;;) {
2256                                 EXTENT e;
2257                                 Lisp_Object obj2;
2258
2259                                 /* ----- update position in extent list
2260                                    and fetch next extent ----- */
2261
2262                                 if (posm) {
2263                                         /* fetch POS again to track extent
2264                                            insertions or deletions */
2265                                         pos = extent_list_marker_pos(el, posm);
2266                                 }
2267                                 if (pos >= extent_list_num_els(el)) {
2268                                         break;
2269                                 }
2270                                 e = extent_list_at(el, pos, range_endp);
2271                                 pos++;
2272                                 if (posm) {
2273                                         /* now point the marker to the next one
2274                                            we're going to process.  This ensures
2275                                            graceful behavior if this extent is
2276                                            deleted. */
2277                                         extent_list_move_marker(el, posm, pos);
2278                                 }
2279                                 /* ----- deal with internal extents ----- */
2280
2281                                 if (extent_internal_p(e)) {
2282                                         if (!(flags & ME_INCLUDE_INTERNAL)) {
2283                                                 continue;
2284                                         } else if (e == range) {
2285                                                 /* We're processing internal
2286                                                    extents and we've come across
2287                                                    our own special range extent.
2288                                                    (This happens only in
2289                                                    adjust_extents*() and
2290                                                    process_extents*(), which
2291                                                    handle text insertion and
2292                                                    deletion.) We need to omit
2293                                                    processing of this extent;
2294                                                    otherwise we will probably
2295                                                    end up prematurely
2296                                                    terminating this loop. */
2297                                                 continue;
2298                                         }
2299                                 }
2300
2301                                 /* ----- deal with AFTER condition ----- */
2302
2303                                 if (after) {
2304                                         /* if e > after, then we can stop
2305                                            skipping extents. */
2306                                         if (EXTENT_LESS(after, e)) {
2307                                                 after = 0;
2308                                         } else {
2309                                                 /* otherwise, skip this
2310                                                    extent. */
2311                                                 continue;
2312                                         }
2313                                 }
2314
2315                                 /* ----- stop if we're completely outside the
2316                                          range ----- */
2317
2318                                 /* fetch ST and EN again to track text
2319                                    insertions or deletions */
2320                                 if (range) {
2321                                         st = extent_start(range);
2322                                         en = extent_end(range);
2323                                 }
2324                                 if (extent_endpoint(e, range_endp) > en) {
2325                                         /* Can't be mapping over SOE because all
2326                                            extents in there should overlap ST */
2327                                         assert(stage == 1);
2328                                         break;
2329                                 }
2330
2331                                 /* ----- Now actually call the function ----- */
2332
2333                                 obj2 = extent_object(e);
2334                                 if (extent_in_region_p(
2335                                             e,
2336                                             buffer_or_string_memind_to_bytind
2337                                             (obj2, st),
2338                                             buffer_or_string_memind_to_bytind
2339                                             (obj2, en), flags)) {
2340                                         if ((*fn) (e, arg)) {
2341                                                 /* Function wants us to stop
2342                                                    mapping. */
2343                                                 stage = 1;
2344                                                 /* so outer for loop will
2345                                                    terminate */
2346                                                 break;
2347                                         }
2348                                 }
2349                         }
2350                 }
2351                 /* ---------- Finished looping. ---------- */
2352         }
2353
2354         if (flags & ME_MIGHT_THROW) {
2355                 /* This deletes the range extent and frees the marker. */
2356                 unbind_to(count, Qnil);
2357         } else {
2358                 /* Delete them ourselves */
2359                 if (range) {
2360                         extent_detach(range);
2361                 }
2362                 if (posm) {
2363                         extent_list_delete_marker(el, posm);
2364                 }
2365         }
2366 }
2367
2368 void
2369 map_extents(Bufpos from, Bufpos to, map_extents_fun fn,
2370             void *arg, Lisp_Object obj, EXTENT after, unsigned int flags)
2371 {
2372         map_extents_bytind(buffer_or_string_bufpos_to_bytind(obj, from),
2373                            buffer_or_string_bufpos_to_bytind(obj, to), fn, arg,
2374                            obj, after, flags);
2375 }
2376
2377 /* ------------------------------- */
2378 /*         adjust_extents()        */
2379 /* ------------------------------- */
2380
2381 /* Add AMOUNT to all extent endpoints in the range (FROM, TO].  This
2382    happens whenever the gap is moved or (under Mule) a character in a
2383    string is substituted for a different-length one.  The reason for
2384    this is that extent endpoints behave just like markers (all memory
2385    indices do) and this adjustment correct for markers -- see
2386    adjust_markers().  Note that it is important that we visit all
2387    extent endpoints in the range, irrespective of whether the
2388    endpoints are open or closed.
2389
2390    We could use map_extents() for this (and in fact the function
2391    was originally written that way), but the gap is in an incoherent
2392    state when this function is called and this function plays
2393    around with extent endpoints without detaching and reattaching
2394    the extents (this is provably correct and saves lots of time),
2395    so for safety we make it just look at the extent lists directly. */
2396
2397 void
2398 adjust_extents(Lisp_Object obj, Memind from, Memind to, int amount)
2399 {
2400         int endp;
2401         int pos;
2402         int startpos[2];
2403         extent_list_t el;
2404         extent_stack_t soe;
2405
2406 #ifdef ERROR_CHECK_EXTENTS
2407         sledgehammer_extent_check(obj);
2408 #endif
2409         el = buffer_or_string_extent_list(obj);
2410
2411         if (!el || !extent_list_num_els(el)) {
2412                 return;
2413         }
2414         /* IMPORTANT! Compute the starting positions of the extents to
2415            modify BEFORE doing any modification!  Otherwise the starting
2416            position for the second time through the loop might get
2417            incorrectly calculated (I got bit by this bug real bad). */
2418         startpos[0] = extent_list_locate_from_pos(el, from + 1, 0);
2419         startpos[1] = extent_list_locate_from_pos(el, from + 1, 1);
2420         for (endp = 0; endp < 2; endp++) {
2421                 for (pos = startpos[endp]; pos < extent_list_num_els(el);
2422                      pos++) {
2423                         EXTENT e = extent_list_at(el, pos, endp);
2424                         if (extent_endpoint(e, endp) > to) {
2425                                 break;
2426                         }
2427                         set_extent_endpoint(
2428                                 e,
2429                                 do_marker_adjustment(
2430                                         extent_endpoint(e, endp),
2431                                         from, to, amount),
2432                                 endp);
2433                 }
2434         }
2435
2436         /* The index for the buffer's SOE is a memory index and thus
2437            needs to be adjusted like a marker. */
2438         soe = buffer_or_string_stack_of_extents(obj);
2439         if (soe && soe->pos >= 0) {
2440                 soe->pos = do_marker_adjustment(soe->pos, from, to, amount);
2441         }
2442         return;
2443 }
2444
2445 /* ------------------------------- */
2446 /*  adjust_extents_for_deletion()  */
2447 /* ------------------------------- */
2448
2449 struct adjust_extents_for_deletion_arg {
2450         EXTENT_dynarr *list;
2451 };
2452
2453 static int adjust_extents_for_deletion_mapper(EXTENT extent, void *arg)
2454 {
2455         struct adjust_extents_for_deletion_arg *closure =
2456                 (struct adjust_extents_for_deletion_arg *)arg;
2457
2458         Dynarr_add(closure->list, extent);
2459         /* continue mapping */
2460         return 0;
2461 }
2462
2463 /* For all extent endpoints in the range (FROM, TO], move them to the beginning
2464    of the new gap.   Note that it is important that we visit all extent
2465    endpoints in the range, irrespective of whether the endpoints are open or
2466    closed.
2467
2468    This function deals with weird stuff such as the fact that extents
2469    may get reordered.
2470
2471    There is no string correspondent for this because you can't
2472    delete characters from a string.
2473  */
2474
2475 void
2476 adjust_extents_for_deletion(Lisp_Object object, Bytind from,
2477                             Bytind to, int gapsize, int numdel, int movegapsize)
2478 {
2479         struct adjust_extents_for_deletion_arg closure;
2480         int i;
2481         Memind adjust_to = (Memind) (to + gapsize);
2482         Bytecount amount = -numdel - movegapsize;
2483         Memind oldsoe = 0, newsoe = 0;
2484         extent_stack_t soe = buffer_or_string_stack_of_extents(object);
2485
2486 #ifdef ERROR_CHECK_EXTENTS
2487         sledgehammer_extent_check(object);
2488 #endif
2489         closure.list = Dynarr_new(EXTENT);
2490
2491         /* We're going to be playing weird games below with extents and the SOE
2492            and such, so compute the list now of all the extents that we're going
2493            to muck with.  If we do the mapping and adjusting together, things
2494            can get all screwed up. */
2495
2496         map_extents_bytind(from, to, adjust_extents_for_deletion_mapper,
2497                            (void *)&closure, object, 0,
2498                            /* extent endpoints move like markers regardless
2499                               of their open/closeness. */
2500                            ME_ALL_EXTENTS_CLOSED | ME_END_CLOSED |
2501                            ME_START_OR_END_IN_REGION | ME_INCLUDE_INTERNAL);
2502
2503         /*
2504            Old and new values for the SOE's position. (It gets adjusted
2505            like a marker, just like extent endpoints.)
2506          */
2507
2508         if (soe) {
2509                 oldsoe = soe->pos;
2510                 if (soe->pos >= 0) {
2511                         newsoe = do_marker_adjustment(
2512                                 soe->pos, adjust_to, adjust_to, amount);
2513                 } else {
2514                         newsoe = soe->pos;
2515                 }
2516         }
2517
2518         for (i = 0; i < Dynarr_length(closure.list); i++) {
2519                 EXTENT extent = Dynarr_at(closure.list, i);
2520                 Memind new_start = extent_start(extent);
2521                 Memind new_end = extent_end(extent);
2522
2523                 /* do_marker_adjustment() will not adjust values that should not
2524                    be adjusted.  We're passing the same funky arguments to
2525                    do_marker_adjustment() as buffer_delete_range() does. */
2526                 new_start = do_marker_adjustment(
2527                         new_start, adjust_to, adjust_to, amount);
2528                 new_end = do_marker_adjustment(
2529                         new_end, adjust_to, adjust_to, amount);
2530
2531                 /* We need to be very careful here so that the SOE doesn't get
2532                    corrupted.  We are shrinking extents out of the deleted
2533                    region and simultaneously moving the SOE's pos out of the
2534                    deleted region, so the SOE should contain the same extents at
2535                    the end as at the beginning.  However, extents may get
2536                    reordered by this process, so we have to operate by pulling
2537                    the extents out of the buffer and SOE, changing their bounds,
2538                    and then reinserting them.  In order for the SOE not to get
2539                    screwed up, we have to make sure that the SOE's pos points to
2540                    its old location whenever we pull an extent out, and points
2541                    to its new location whenever we put the extent back in.
2542                  */
2543
2544                 if (new_start != extent_start(extent) ||
2545                     new_end != extent_end(extent)) {
2546                         extent_detach(extent);
2547                         set_extent_start(extent, new_start);
2548                         set_extent_end(extent, new_end);
2549                         if (soe) {
2550                                 soe->pos = newsoe;
2551                         }
2552                         extent_attach(extent);
2553                         if (soe) {
2554                                 soe->pos = oldsoe;
2555                         }
2556                 }
2557         }
2558
2559         if (soe) {
2560                 soe->pos = newsoe;
2561         }
2562
2563 #ifdef ERROR_CHECK_EXTENTS
2564         sledgehammer_extent_check(object);
2565 #endif
2566         Dynarr_free(closure.list);
2567         return;
2568 }
2569
2570 /* ------------------------------- */
2571 /*         extent fragments        */
2572 /* ------------------------------- */
2573
2574 /* Imagine that the buffer is divided up into contiguous,
2575    nonoverlapping "runs" of text such that no extent
2576    starts or ends within a run (extents that abut the
2577    run don't count).
2578
2579    An extent fragment is a structure that holds data about
2580    the run that contains a particular buffer position (if
2581    the buffer position is at the junction of two runs, the
2582    run after the position is used) -- the beginning and
2583    end of the run, a list of all of the extents in that
2584    run, the "merged face" that results from merging all of
2585    the faces corresponding to those extents, the begin and
2586    end glyphs at the beginning of the run, etc.  This is
2587    the information that redisplay needs in order to
2588    display this run.
2589
2590    Extent fragments have to be very quick to update to
2591    a new buffer position when moving linearly through
2592    the buffer.  They rely on the stack-of-extents code,
2593    which does the heavy-duty algorithmic work of determining
2594    which extents overly a particular position. */
2595
2596 /* This function returns the position of the beginning of
2597    the first run that begins after POS, or returns POS if
2598    there are no such runs. */
2599
2600 static Bytind
2601 extent_find_end_of_run(Lisp_Object obj, Bytind pos, int outside_accessible)
2602 {
2603         extent_list_t sel;
2604         extent_list_t bel = buffer_or_string_extent_list(obj);
2605         Bytind pos1, pos2;
2606         int elind1, elind2;
2607         Memind mempos = buffer_or_string_bytind_to_memind(obj, pos);
2608         Bytind limit = outside_accessible ?
2609             buffer_or_string_absolute_end_byte(obj) :
2610             buffer_or_string_accessible_end_byte(obj);
2611
2612         if (!bel || !extent_list_num_els(bel)) {
2613                 return limit;
2614         }
2615         sel = buffer_or_string_stack_of_extents_force(obj)->extents;
2616         soe_move(obj, mempos);
2617
2618         /* Find the first start position after POS. */
2619         elind1 = extent_list_locate_from_pos(bel, mempos + 1, 0);
2620         if (elind1 < extent_list_num_els(bel)) {
2621                 pos1 = buffer_or_string_memind_to_bytind(
2622                         obj, extent_start(extent_list_at(bel, elind1, 0)));
2623         } else {
2624                 pos1 = limit;
2625         }
2626
2627         /* Find the first end position after POS.  The extent corresponding
2628            to this position is either in the SOE or is greater than or
2629            equal to POS1, so we just have to look in the SOE. */
2630         elind2 = extent_list_locate_from_pos(sel, mempos + 1, 1);
2631         if (elind2 < extent_list_num_els(sel)) {
2632                 pos2 = buffer_or_string_memind_to_bytind(
2633                         obj, extent_end(extent_list_at(sel, elind2, 1)));
2634         } else {
2635                 pos2 = limit;
2636         }
2637         return min(min(pos1, pos2), limit);
2638 }
2639
2640 static Bytind
2641 extent_find_beginning_of_run(Lisp_Object obj, Bytind pos,
2642                              int outside_accessible)
2643 {
2644         extent_list_t sel;
2645         extent_list_t bel = buffer_or_string_extent_list(obj);
2646         Bytind pos1, pos2;
2647         int elind1, elind2;
2648         Memind mempos = buffer_or_string_bytind_to_memind(obj, pos);
2649         Bytind limit = outside_accessible
2650                 ? buffer_or_string_absolute_begin_byte(obj)
2651                 : buffer_or_string_accessible_begin_byte(obj);
2652
2653         if (!bel || !extent_list_num_els(bel)) {
2654                 return limit;
2655         }
2656         sel = buffer_or_string_stack_of_extents_force(obj)->extents;
2657         soe_move(obj, mempos);
2658
2659         /* Find the first end position before POS. */
2660         elind1 = extent_list_locate_from_pos(bel, mempos, 1);
2661         if (elind1 > 0) {
2662                 pos1 = buffer_or_string_memind_to_bytind(
2663                         obj, extent_end(extent_list_at(bel, elind1 - 1, 1)));
2664         } else {
2665                 pos1 = limit;
2666         }
2667         /* Find the first start position before POS.  The extent corresponding
2668            to this position is either in the SOE or is less than or
2669            equal to POS1, so we just have to look in the SOE. */
2670         elind2 = extent_list_locate_from_pos(sel, mempos, 0);
2671         if (elind2 > 0) {
2672                 pos2 = buffer_or_string_memind_to_bytind(
2673                         obj, extent_start(extent_list_at(sel, elind2 - 1, 0)));
2674         } else {
2675                 pos2 = limit;
2676         }
2677         return max(max(pos1, pos2), limit);
2678 }
2679
2680 struct extent_fragment*
2681 extent_fragment_new(Lisp_Object buffer_or_string, struct frame *frm)
2682 {
2683         struct extent_fragment *ef = xnew_and_zero(struct extent_fragment);
2684
2685         ef->object = buffer_or_string;
2686         ef->frm = frm;
2687         ef->extents = Dynarr_new(EXTENT);
2688         ef->glyphs = Dynarr_new(glyph_block);
2689
2690         return ef;
2691 }
2692
2693 void extent_fragment_delete(struct extent_fragment *ef)
2694 {
2695         Dynarr_free(ef->extents);
2696         Dynarr_free(ef->glyphs);
2697         xfree(ef);
2698 }
2699
2700 static int
2701 extent_priority_sort_function(const void *humpty, const void *dumpty)
2702 {
2703         const EXTENT foo = *(const EXTENT *)humpty;
2704         const EXTENT bar = *(const EXTENT *)dumpty;
2705         if (extent_priority(foo) < extent_priority(bar)) {
2706                 return -1;
2707         }
2708         return extent_priority(foo) > extent_priority(bar);
2709 }
2710
2711 static void
2712 extent_fragment_sort_by_priority(EXTENT_dynarr * extarr)
2713 {
2714         int i;
2715
2716         /* Sort our copy of the stack by extent_priority.  We use a bubble
2717            sort here because it's going to be faster than qsort() for small
2718            numbers of extents (less than 10 or so), and 99.999% of the time
2719            there won't ever be more extents than this in the stack. */
2720         if (Dynarr_length(extarr) < 10) {
2721                 for (i = 1; i < Dynarr_length(extarr); i++) {
2722                         int j = i - 1;
2723                         while (j >= 0 &&
2724                                (extent_priority(Dynarr_at(extarr, j)) >
2725                                 extent_priority(Dynarr_at(extarr, j + 1)))) {
2726                                 EXTENT tmp = Dynarr_at(extarr, j);
2727                                 Dynarr_at(extarr, j) = Dynarr_at(extarr, j + 1);
2728                                 Dynarr_at(extarr, j + 1) = tmp;
2729                                 j--;
2730                         }
2731                 }
2732         } else {
2733                 /* But some loser programs mess up and may create a large number
2734                    of extents overlapping the same spot.  This will result in
2735                    catastrophic behavior if we use the bubble sort above. */
2736                 qsort(Dynarr_atp(extarr, 0), Dynarr_length(extarr),
2737                       sizeof(EXTENT), extent_priority_sort_function);
2738         }
2739 }
2740
2741 /* If PROP is the `invisible' property of an extent,
2742    this is 1 if the extent should be treated as invisible.  */
2743
2744 #define EXTENT_PROP_MEANS_INVISIBLE(buf, prop)                  \
2745   (EQ (buf->invisibility_spec, Qt)                              \
2746    ? ! NILP (prop)                                              \
2747    : invisible_p (prop, buf->invisibility_spec))
2748
2749 /* If PROP is the `invisible' property of a extent,
2750    this is 1 if the extent should be treated as invisible
2751    and should have an ellipsis.  */
2752
2753 #define EXTENT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS(buf, prop)    \
2754   (EQ (buf->invisibility_spec, Qt)                              \
2755    ? 0                                                          \
2756    : invisible_ellipsis_p (prop, buf->invisibility_spec))
2757
2758 /* This is like a combination of memq and assq.
2759    Return 1 if PROPVAL appears as an element of LIST
2760    or as the car of an element of LIST.
2761    If PROPVAL is a list, compare each element against LIST
2762    in that way, and return 1 if any element of PROPVAL is found in LIST.
2763    Otherwise return 0.
2764    This function cannot quit.  */
2765
2766 static int
2767 invisible_p(REGISTER Lisp_Object propval, Lisp_Object list)
2768 {
2769         REGISTER Lisp_Object tail, proptail;
2770         for (tail = list; CONSP(tail); tail = XCDR(tail)) {
2771                 REGISTER Lisp_Object tem;
2772                 tem = XCAR(tail);
2773                 if (EQ(propval, tem))
2774                         return 1;
2775                 if (CONSP(tem) && EQ(propval, XCAR(tem)))
2776                         return 1;
2777         }
2778         if (CONSP(propval)) {
2779                 for (proptail = propval; CONSP(proptail);
2780                      proptail = XCDR(proptail)) {
2781                         Lisp_Object propelt;
2782                         propelt = XCAR(proptail);
2783                         for (tail = list; CONSP(tail); tail = XCDR(tail)) {
2784                                 REGISTER Lisp_Object tem;
2785                                 tem = XCAR(tail);
2786                                 if (EQ(propelt, tem)) {
2787                                         return 1;
2788                                 }
2789                                 if (CONSP(tem) && EQ(propelt, XCAR(tem))) {
2790                                         return 1;
2791                                 }
2792                         }
2793                 }
2794         }
2795         return 0;
2796 }
2797
2798 /* Return 1 if PROPVAL appears as the car of an element of LIST
2799    and the cdr of that element is non-nil.
2800    If PROPVAL is a list, check each element of PROPVAL in that way,
2801    and the first time some element is found,
2802    return 1 if the cdr of that element is non-nil.
2803    Otherwise return 0.
2804    This function cannot quit.  */
2805
2806 static int
2807 invisible_ellipsis_p(REGISTER Lisp_Object propval, Lisp_Object list)
2808 {
2809         REGISTER Lisp_Object tail, proptail;
2810
2811         for (tail = list; CONSP(tail); tail = XCDR(tail)) {
2812                 REGISTER Lisp_Object tem;
2813                 tem = XCAR(tail);
2814                 if (CONSP(tem) && EQ(propval, XCAR(tem))) {
2815                         return !NILP(XCDR(tem));
2816                 }
2817         }
2818         if (CONSP(propval)) {
2819                 for (proptail = propval; CONSP(proptail);
2820                      proptail = XCDR(proptail)) {
2821                         Lisp_Object propelt;
2822                         propelt = XCAR(proptail);
2823                         for (tail = list; CONSP(tail); tail = XCDR(tail)) {
2824                                 REGISTER Lisp_Object tem;
2825                                 tem = XCAR(tail);
2826                                 if (CONSP(tem) && EQ(propelt, XCAR(tem))) {
2827                                         return !NILP(XCDR(tem));
2828                                 }
2829                         }
2830                 }
2831         }
2832         return 0;
2833 }
2834
2835 face_index
2836 extent_fragment_update(struct window * w, struct extent_fragment * ef,
2837                        Bytind pos, Lisp_Object last_glyph)
2838 {
2839         int i, j;
2840         int seen_glyph = NILP(last_glyph) ? 1 : 0;
2841         extent_list_t sel =
2842                 buffer_or_string_stack_of_extents_force(ef->object)->extents;
2843         EXTENT lhe = 0;
2844         struct extent dummy_lhe_extent;
2845         Memind mempos = buffer_or_string_bytind_to_memind(ef->object, pos);
2846         glyph_block_dynarr *glyphs; /* List of glyphs to post process */
2847         int invis_before = 0;  /* Exiting an invisible extent.  */
2848         int invis_after = 0;   /* Entering an invisible extent. */
2849         int insert_empty = 0;  /* Position to insert empty extent glyphs  */
2850         int queuing_begin = 0;  /* Queuing begin glyphs. */
2851
2852 #ifdef ERROR_CHECK_EXTENTS
2853         assert(pos >= buffer_or_string_accessible_begin_byte(ef->object)
2854                && pos <= buffer_or_string_accessible_end_byte(ef->object));
2855 #endif
2856
2857         Dynarr_reset(ef->extents);
2858         Dynarr_reset(ef->glyphs);
2859
2860         ef->previously_invisible = ef->invisible;
2861         if (ef->invisible) {
2862                 if (ef->invisible_ellipses)
2863                         ef->invisible_ellipses_already_displayed = 1;
2864         } else {
2865                 ef->invisible_ellipses_already_displayed = 0;
2866         }
2867         ef->invisible = 0;
2868         ef->invisible_ellipses = 0;
2869
2870         /* Set up the begin and end positions. */
2871         ef->pos = pos;
2872         ef->end = extent_find_end_of_run(ef->object, pos, 0);
2873
2874         /* Note that extent_find_end_of_run() already moved the SOE for us. */
2875         /* soe_move (ef->object, mempos); */
2876
2877         /* We tried determining all the charsets used in the run here,
2878            but that fails even if we only do the current line -- display
2879            tables or non-printable characters might cause other charsets
2880            to be used. */
2881
2882         /* Determine whether the last-highlighted-extent is present. */
2883         if (EXTENTP(Vlast_highlighted_extent))
2884                 lhe = XEXTENT(Vlast_highlighted_extent);
2885
2886         /* Now add all extents that overlap the character after POS and
2887            have a non-nil face.  Also check if the character is
2888            invisible.  We also queue begin and end glyphs of extents
2889            that being/end at just before POS.  These are ordered as
2890            follows. 1) end glyphs of non-empty extents in reverse
2891            display order.  2) begin glyphs of empty extents.  3) end
2892            glyphs of empty extents.  4) begin glyphs of non-empty
2893            extents in display order.  Empty extents are shown nested,
2894            but the invisibility property of an empty extent is
2895            ignored and not used to determine whether an 'interior'
2896            empty extent's glyphs should be shown or not.  */
2897         glyphs = Dynarr_new(glyph_block);
2898         for (i = 0; i < extent_list_num_els(sel); i++) {
2899                 EXTENT e = extent_list_at(sel, i, 0);
2900                 int zero_width = extent_start(e) == extent_end(e);
2901                 Lisp_Object invis_prop = extent_invisible(e);
2902                 Lisp_Object glyph;
2903
2904                 if (extent_start(e) == mempos) {
2905                         /* The extent starts here.  If we are queuing
2906                            end glyphs, we should display all the end
2907                            glyphs we've pushed.  */
2908
2909                         if (!queuing_begin) {
2910                                 /* Append any already seen end glyphs */
2911                                 for (j = Dynarr_length(glyphs); j--;) {
2912                                         struct glyph_block *gbp
2913                                           = Dynarr_atp(glyphs, j);
2914                         
2915                                         if (seen_glyph)
2916                                                 Dynarr_add(ef->glyphs, *gbp);
2917                                         else if (EQ(gbp->glyph, last_glyph))
2918                                                 seen_glyph = 1;
2919                                 }
2920
2921                                 /* Pop the end glyphs just displayed. */
2922                                 Dynarr_set_size(glyphs, 0);
2923                                 /* We are now queuing begin glyphs. */
2924                                 queuing_begin = 1;
2925                                 /* And will insert empty extent glyphs
2926                                    just here.  */
2927                                 insert_empty = Dynarr_length (ef->glyphs);
2928                         }
2929
2930                         glyph = extent_begin_glyph(e);
2931                         
2932                         if (!NILP(glyph)) {
2933                                 struct glyph_block gb;
2934
2935                                 gb.glyph = glyph;
2936                                 gb.active = 0; /* BEGIN_GLYPH */
2937                                 gb.width = 0;
2938                                 XSETEXTENT(gb.extent, e);
2939                     
2940                                 if (zero_width) {
2941                                         if (insert_empty
2942                                             == Dynarr_length (ef->glyphs))
2943                                                 Dynarr_add (ef->glyphs, gb);
2944                                         else
2945                                                 Dynarr_insert_many
2946                                                   (ef->glyphs, &gb,
2947                                                    1, insert_empty);
2948                                 } else if (!invis_after) 
2949                                         Dynarr_add (glyphs, gb);
2950                         }
2951                 }
2952                 
2953                 if (extent_end(e) == mempos) {
2954                         /* The extend ends here.  Push the end glyph.  */
2955                         glyph = extent_end_glyph(e);
2956
2957                         if (!NILP (glyph)) {
2958                                 struct glyph_block gb;
2959
2960                                 gb.width = gb.findex = 0; /* just init */
2961                                 gb.glyph = glyph;
2962                                 gb.active = 1; /* END_GLYPH */
2963                                 XSETEXTENT(gb.extent, e);
2964
2965                                 if (zero_width)
2966                                   Dynarr_add (ef->glyphs, gb);
2967                                 else if (!invis_before)
2968                                   Dynarr_add(glyphs, gb);
2969                         }
2970                         /* If this extent is not empty, any inner
2971                            extents ending here will not be visible.  */
2972                         if (extent_start (e) < mempos && !NILP (invis_prop))
2973                           invis_before = 1;
2974                 }
2975                 
2976                 if (extent_end(e) > mempos) {
2977                         /* This extent covers POS. */
2978                         if (!NILP(invis_prop)) {
2979                                 invis_after = 1;
2980                                 /* If this extend spans POS, all
2981                                    glyphs are invisible.  */
2982                                 if (extent_start (e) < mempos)
2983                                         Dynarr_set_size (glyphs, 0);
2984                           
2985                                 if (!BUFFERP(ef->object))
2986                                         /* #### no `string-invisibility-spec' */
2987                                         ef->invisible = 1;
2988                                 else {
2989                                         if (!ef->
2990                                             invisible_ellipses_already_displayed
2991                                             &&
2992                                             EXTENT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS
2993                                             (XBUFFER(ef->object), invis_prop)) {
2994                                                 ef->invisible = 1;
2995                                                 ef->invisible_ellipses = 1;
2996                                         } else if (EXTENT_PROP_MEANS_INVISIBLE
2997                                                    (XBUFFER(ef->object),
2998                                                     invis_prop))
2999                                                 ef->invisible = 1;
3000                                 }
3001                         }
3002
3003                         /* Remember that one of the extents in the list might be
3004                            our dummy extent representing the highlighting that
3005                            is attached to some other extent that is currently
3006                            mouse-highlighted.  When an extent is
3007                            mouse-highlighted, it is as if there are two extents
3008                            there, of potentially different priorities: the
3009                            extent being highlighted, with whatever face and
3010                            priority it has; and an ephemeral extent in the
3011                            `mouse-face' face with `mouse-highlight-priority'.
3012                          */
3013
3014                         if (!NILP(extent_face(e)))
3015                                 Dynarr_add(ef->extents, e);
3016                         if (e == lhe) {
3017                                 Lisp_Object f;
3018                                 /* zeroing isn't really necessary; we only deref
3019                                    `priority' and `face' */
3020                                 xzero(dummy_lhe_extent);
3021                                 set_extent_priority(&dummy_lhe_extent,
3022                                                     mouse_highlight_priority);
3023                                 /* Need to break up the following expression,
3024                                    due to an */
3025                                 /* error in the Digital UNIX 3.2g C compiler
3026                                    (Digital */
3027                                 /* UNIX Compiler Driver 3.11). */
3028                                 f = extent_mouse_face(lhe);
3029                                 extent_face(&dummy_lhe_extent) = f;
3030                                 Dynarr_add(ef->extents, &dummy_lhe_extent);
3031                         }
3032                         /* since we are looping anyway, we might as well do this
3033                            here */
3034                         if ((!NILP(extent_initial_redisplay_function(e))) &&
3035                             !extent_in_red_event_p(e)) {
3036                                 Lisp_Object function =
3037                                         extent_initial_redisplay_function(e);
3038                                 Lisp_Object obj;
3039
3040                                 /* print_extent_2 (e);
3041                                    printf ("\n"); */
3042
3043                                 /* FIXME: One should probably inhibit the
3044                                    displaying of this extent to reduce
3045                                    flicker */
3046                                 extent_in_red_event_p(e) = 1;
3047
3048                                 /* call the function */
3049                                 XSETEXTENT(obj, e);
3050                                 if (!NILP(function)) {
3051                                         Fenqueue_eval_event(function, obj);
3052                                 }
3053                         }
3054                 }
3055         }
3056
3057         if (!queuing_begin) {
3058                 /* Append end glyphs in reverse order */
3059                 for (j = Dynarr_length(glyphs); j--;) {
3060                         struct glyph_block *gbp = Dynarr_atp(glyphs, j);
3061             
3062                         if (seen_glyph)
3063                                 Dynarr_add(ef->glyphs, *gbp);
3064                         else if (EQ(gbp->glyph, last_glyph))
3065                                 seen_glyph = 1;
3066                 }
3067         } else {
3068                 if (!seen_glyph) {
3069                         /* Scan the zero length glyphs and see where we
3070                            start a glyph that has not been displayed yet.  */
3071                         for (j = insert_empty;
3072                              j != Dynarr_length (ef->glyphs); j++) {
3073                                 struct glyph_block *gbp
3074                                         = Dynarr_atp(ef->glyphs, j);
3075                     
3076                                 if (EQ(gbp->glyph, last_glyph)) {
3077                                         seen_glyph = 1;
3078                                         j++;
3079                                         break;
3080                                 }
3081                         }
3082                         Dynarr_delete_many (ef->glyphs, insert_empty,
3083                                             j - insert_empty);
3084                 }
3085
3086                 /* Now copy the begin glyphs. */
3087                 for (j = 0; j != Dynarr_length (glyphs); j++) {
3088                         struct glyph_block *gbp = Dynarr_atp(glyphs, j);
3089                 
3090                         if (seen_glyph)
3091                                 Dynarr_add(ef->glyphs, *gbp);
3092                         else if (EQ(gbp->glyph, last_glyph))
3093                                 seen_glyph = 1;
3094                 }
3095         }
3096
3097         Dynarr_free(glyphs);
3098
3099         extent_fragment_sort_by_priority(ef->extents);
3100
3101         /* Now merge the faces together into a single face.  The code to
3102            do this is in faces.c because it involves manipulating faces. */
3103         return get_extent_fragment_face_cache_index(w, ef);
3104 }
3105 \f
3106 /************************************************************************/
3107 /*                      extent-object methods                           */
3108 /************************************************************************/
3109
3110 /* These are the basic helper functions for handling the allocation of
3111    extent objects.  They are similar to the functions for other
3112    lrecord objects.  allocate_extent() is in alloc.c, not here. */
3113
3114 static Lisp_Object mark_extent(Lisp_Object obj)
3115 {
3116         struct extent *extent = XEXTENT(obj);
3117
3118         mark_object(extent_object(extent));
3119         mark_object(extent_no_chase_normal_field(extent, face));
3120         return extent->plist;
3121 }
3122
3123 static void
3124 print_extent_1(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3125 {
3126         EXTENT ext = XEXTENT(obj);
3127         EXTENT anc = extent_ancestor(ext);
3128         Lisp_Object tail;
3129         char buf[100], *bp = buf;
3130
3131         /* Retrieve the ancestor and use it, for faster retrieval of properties */
3132
3133         if (!NILP(extent_begin_glyph(anc)))
3134                 *bp++ = '*';
3135         *bp++ = (extent_start_open_p(anc) ? '(' : '[');
3136         if (extent_detached_p(ext))
3137                 strcpy(bp, "detached");
3138         else
3139                 sprintf(bp, "%ld, %ld",
3140                         XINT(Fextent_start_position(obj)),
3141                         XINT(Fextent_end_position(obj)));
3142         bp += strlen(bp);
3143         *bp++ = (extent_end_open_p(anc) ? ')' : ']');
3144         if (!NILP(extent_end_glyph(anc)))
3145                 *bp++ = '*';
3146         *bp++ = ' ';
3147
3148         if (!NILP(extent_read_only(anc)))
3149                 *bp++ = '%';
3150         if (!NILP(extent_mouse_face(anc)))
3151                 *bp++ = 'H';
3152         if (extent_unique_p(anc))
3153                 *bp++ = 'U';
3154         else if (extent_duplicable_p(anc))
3155                 *bp++ = 'D';
3156         if (!NILP(extent_invisible(anc)))
3157                 *bp++ = 'I';
3158
3159         if (!NILP(extent_read_only(anc)) || !NILP(extent_mouse_face(anc)) ||
3160             extent_unique_p(anc) ||
3161             extent_duplicable_p(anc) || !NILP(extent_invisible(anc)))
3162                 *bp++ = ' ';
3163         *bp = '\0';
3164         write_c_string(buf, printcharfun);
3165
3166         tail = extent_plist_slot(anc);
3167
3168         for (; !NILP(tail); tail = Fcdr(Fcdr(tail))) {
3169                 Lisp_Object v = XCAR(XCDR(tail));
3170                 if (NILP(v))
3171                         continue;
3172                 print_internal(XCAR(tail), printcharfun, escapeflag);
3173                 write_c_string(" ", printcharfun);
3174         }
3175
3176         sprintf(buf, "0x%lx", (long)ext);
3177         write_c_string(buf, printcharfun);
3178 }
3179
3180 static void
3181 print_extent(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3182 {
3183         if (escapeflag) {
3184                 const char *title = "";
3185                 const char *name = "";
3186                 const char *posttitle = "";
3187                 Lisp_Object obj2 = Qnil;
3188
3189                 /* Destroyed extents have 't' in the object field, causing
3190                    extent_object() to abort (maybe). */
3191                 if (EXTENT_LIVE_P(XEXTENT(obj)))
3192                         obj2 = extent_object(XEXTENT(obj));
3193
3194                 if (NILP(obj2))
3195                         title = "no buffer";
3196                 else if (BUFFERP(obj2)) {
3197                         if (BUFFER_LIVE_P(XBUFFER(obj2))) {
3198                                 title = "buffer ";
3199                                 name =
3200                                     (char *)XSTRING_DATA(XBUFFER(obj2)->name);
3201                         } else {
3202                                 title = "Killed Buffer";
3203                                 name = "";
3204                         }
3205                 } else {
3206                         assert(STRINGP(obj2));
3207                         title = "string \"";
3208                         posttitle = "\"";
3209                         name = (char *)XSTRING_DATA(obj2);
3210                 }
3211
3212                 if (print_readably) {
3213                         if (!EXTENT_LIVE_P(XEXTENT(obj))) {
3214                                 error("printing unreadable object "
3215                                       "#<destroyed extent>");
3216                         } else {
3217                                 error("printing unreadable object "
3218                                       "#<extent %p>", XEXTENT(obj));
3219                         }
3220                 }
3221
3222                 if (!EXTENT_LIVE_P(XEXTENT(obj))) {
3223                         write_c_string("#<destroyed extent", printcharfun);
3224                 } else {
3225                         /* C99ified */
3226                         size_t bufsz = strlen(title) + strlen(name) +
3227                                 strlen(posttitle) + 1;
3228                         char buf[bufsz];
3229
3230                         write_c_string("#<extent ", printcharfun);
3231                         print_extent_1(obj, printcharfun, escapeflag);
3232                         write_c_string(extent_detached_p(XEXTENT(obj))
3233                                        ? " from " : " in ", printcharfun);
3234                         snprintf(buf, bufsz, "%s%s%s", title, name, posttitle);
3235                         write_c_string(buf, printcharfun);
3236                 }
3237         } else {
3238                 if (print_readably)
3239                         error("printing unreadable object #<extent>");
3240                 write_c_string("#<extent", printcharfun);
3241         }
3242         write_c_string(">", printcharfun);
3243 }
3244
3245 static int properties_equal(EXTENT e1, EXTENT e2, int depth)
3246 {
3247         /* When this function is called, all indirections have been followed.
3248            Thus, the indirection checks in the various macros below will not
3249            amount to anything, and could be removed.  However, the time
3250            savings would probably not be significant. */
3251         if (!(EQ(extent_face(e1), extent_face(e2)) &&
3252               extent_priority(e1) == extent_priority(e2) &&
3253               internal_equal(extent_begin_glyph(e1), extent_begin_glyph(e2),
3254                              depth + 1) &&
3255               internal_equal(extent_end_glyph(e1), extent_end_glyph(e2),
3256                              depth + 1)))
3257                 return 0;
3258
3259         /* compare the bit flags. */
3260         {
3261                 /* The has_aux field should not be relevant. */
3262                 int e1_has_aux = e1->flags.has_aux;
3263                 int e2_has_aux = e2->flags.has_aux;
3264                 int value;
3265
3266                 e1->flags.has_aux = e2->flags.has_aux = 0;
3267                 value = memcmp(&e1->flags, &e2->flags, sizeof(e1->flags));
3268                 e1->flags.has_aux = e1_has_aux;
3269                 e2->flags.has_aux = e2_has_aux;
3270                 if (value)
3271                         return 0;
3272         }
3273
3274         /* compare the random elements of the plists. */
3275         return !plists_differ(extent_no_chase_plist(e1),
3276                               extent_no_chase_plist(e2), 0, 0, depth + 1);
3277 }
3278
3279 static int extent_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
3280 {
3281         struct extent *e1 = XEXTENT(obj1);
3282         struct extent *e2 = XEXTENT(obj2);
3283         return
3284             (extent_start(e1) == extent_start(e2) &&
3285              extent_end(e1) == extent_end(e2) &&
3286              internal_equal(extent_object(e1), extent_object(e2), depth + 1) &&
3287              properties_equal(extent_ancestor(e1), extent_ancestor(e2), depth));
3288 }
3289
3290 static unsigned long extent_hash(Lisp_Object obj, int depth)
3291 {
3292         struct extent *e = XEXTENT(obj);
3293         /* No need to hash all of the elements; that would take too long.
3294            Just hash the most common ones. */
3295         return HASH3(extent_start(e), extent_end(e),
3296                      internal_hash(extent_object(e), depth + 1));
3297 }
3298
3299 static const struct lrecord_description extent_description[] = {
3300         {XD_LISP_OBJECT, offsetof(struct extent, object)},
3301         {XD_LISP_OBJECT, offsetof(struct extent, flags.face)},
3302         {XD_LISP_OBJECT, offsetof(struct extent, plist)},
3303         {XD_END}
3304 };
3305
3306 static Lisp_Object extent_getprop(Lisp_Object obj, Lisp_Object prop)
3307 {
3308         return Fextent_property(obj, prop, Qunbound);
3309 }
3310
3311 static int extent_putprop(Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3312 {
3313         Fset_extent_property(obj, prop, value);
3314         return 1;
3315 }
3316
3317 static int extent_remprop(Lisp_Object obj, Lisp_Object prop)
3318 {
3319         EXTENT ext = XEXTENT(obj);
3320
3321         /* This list is taken from Fset_extent_property, and should be kept
3322            in synch.  */
3323         if (EQ(prop, Qread_only)
3324             || EQ(prop, Qunique)
3325             || EQ(prop, Qduplicable)
3326             || EQ(prop, Qinvisible)
3327             || EQ(prop, Qdetachable)
3328             || EQ(prop, Qdetached)
3329             || EQ(prop, Qdestroyed)
3330             || EQ(prop, Qpriority)
3331             || EQ(prop, Qface)
3332             || EQ(prop, Qinitial_redisplay_function)
3333             || EQ(prop, Qafter_change_functions)
3334             || EQ(prop, Qbefore_change_functions)
3335             || EQ(prop, Qmouse_face)
3336             || EQ(prop, Qhighlight)
3337             || EQ(prop, Qbegin_glyph_layout)
3338             || EQ(prop, Qend_glyph_layout)
3339             || EQ(prop, Qglyph_layout)
3340             || EQ(prop, Qbegin_glyph)
3341             || EQ(prop, Qend_glyph)
3342             || EQ(prop, Qstart_open)
3343             || EQ(prop, Qend_open)
3344             || EQ(prop, Qstart_closed)
3345             || EQ(prop, Qend_closed)
3346             || EQ(prop, Qkeymap)) {
3347                 /* #### Is this correct, anyway?  */
3348                 return -1;
3349         }
3350
3351         return external_remprop(extent_plist_addr(ext), prop, 0, ERROR_ME);
3352 }
3353
3354 static Lisp_Object extent_plist(Lisp_Object obj)
3355 {
3356         return Fextent_properties(obj);
3357 }
3358
3359 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS("extent", extent,
3360                                                mark_extent, print_extent,
3361                                                /* NOTE: If you declare a
3362                                                   finalization method here,
3363                                                   it will NOT be called.
3364                                                   Shaft city. */
3365                                                0,
3366                                                extent_equal, extent_hash,
3367                                                extent_description,
3368                                                extent_getprop, extent_putprop,
3369                                                extent_remprop, extent_plist,
3370                                                struct extent);
3371 \f
3372 /************************************************************************/
3373 /*                      basic extent accessors                          */
3374 /************************************************************************/
3375
3376 /* These functions are for checking externally-passed extent objects
3377    and returning an extent's basic properties, which include the
3378    buffer the extent is associated with, the endpoints of the extent's
3379    range, the open/closed-ness of those endpoints, and whether the
3380    extent is detached.  Manipulating these properties requires
3381    manipulating the ordered lists that hold extents; thus, functions
3382    to do that are in a later section. */
3383
3384 /* Given a Lisp_Object that is supposed to be an extent, make sure it
3385    is OK and return an extent pointer.  Extents can be in one of four
3386    states:
3387
3388    1) destroyed
3389    2) detached and not associated with a buffer
3390    3) detached and associated with a buffer
3391    4) attached to a buffer
3392
3393    If FLAGS is 0, types 2-4 are allowed.  If FLAGS is DE_MUST_HAVE_BUFFER,
3394    types 3-4 are allowed.  If FLAGS is DE_MUST_BE_ATTACHED, only type 4
3395    is allowed.
3396    */
3397
3398 static EXTENT decode_extent(Lisp_Object extent_obj, unsigned int flags)
3399 {
3400         EXTENT extent;
3401         Lisp_Object obj;
3402
3403         CHECK_LIVE_EXTENT(extent_obj);
3404         extent = XEXTENT(extent_obj);
3405         obj = extent_object(extent);
3406
3407         /* the following condition will fail if we're dealing with a freed extent */
3408         assert(NILP(obj) || BUFFERP(obj) || STRINGP(obj));
3409
3410         if (flags & DE_MUST_BE_ATTACHED)
3411                 flags |= DE_MUST_HAVE_BUFFER;
3412
3413         /* if buffer is dead, then convert extent to have no buffer. */
3414         if (BUFFERP(obj) && !BUFFER_LIVE_P(XBUFFER(obj)))
3415                 obj = extent_object(extent) = Qnil;
3416
3417         assert(!NILP(obj) || extent_detached_p(extent));
3418
3419         if ((NILP(obj) && (flags & DE_MUST_HAVE_BUFFER))
3420             || (extent_detached_p(extent) && (flags & DE_MUST_BE_ATTACHED))) {
3421                 invalid_argument("extent doesn't belong to a buffer or string",
3422                                  extent_obj);
3423         }
3424
3425         return extent;
3426 }
3427
3428 /* Note that the returned value is a buffer position, not a byte index. */
3429
3430 static Lisp_Object extent_endpoint_external(Lisp_Object extent_obj, int endp)
3431 {
3432         EXTENT extent = decode_extent(extent_obj, 0);
3433
3434         if (extent_detached_p(extent))
3435                 return Qnil;
3436         else
3437                 return make_int(extent_endpoint_bufpos(extent, endp));
3438 }
3439
3440 DEFUN("extentp", Fextentp, 1, 1, 0,     /*
3441 Return t if OBJECT is an extent.
3442 */
3443       (object))
3444 {
3445         return EXTENTP(object) ? Qt : Qnil;
3446 }
3447
3448 DEFUN("extent-live-p", Fextent_live_p, 1, 1, 0, /*
3449 Return t if OBJECT is an extent that has not been destroyed.
3450 */
3451       (object))
3452 {
3453         return EXTENTP(object) && EXTENT_LIVE_P(XEXTENT(object)) ? Qt : Qnil;
3454 }
3455
3456 DEFUN("extent-detached-p", Fextent_detached_p, 1, 1, 0, /*
3457 Return t if EXTENT is detached.
3458 */
3459       (extent))
3460 {
3461         return extent_detached_p(decode_extent(extent, 0)) ? Qt : Qnil;
3462 }
3463
3464 DEFUN("extent-object", Fextent_object, 1, 1, 0, /*
3465 Return object (buffer or string) that EXTENT refers to.
3466 */
3467       (extent))
3468 {
3469         return extent_object(decode_extent(extent, 0));
3470 }
3471
3472 DEFUN("extent-start-position", Fextent_start_position, 1, 1, 0, /*
3473 Return start position of EXTENT, or nil if EXTENT is detached.
3474 */
3475       (extent))
3476 {
3477         return extent_endpoint_external(extent, 0);
3478 }
3479
3480 DEFUN("extent-end-position", Fextent_end_position, 1, 1, 0,     /*
3481 Return end position of EXTENT, or nil if EXTENT is detached.
3482 */
3483       (extent))
3484 {
3485         return extent_endpoint_external(extent, 1);
3486 }
3487
3488 DEFUN("extent-length", Fextent_length, 1, 1, 0, /*
3489 Return length of EXTENT in characters.
3490 */
3491       (extent))
3492 {
3493         EXTENT e = decode_extent(extent, DE_MUST_BE_ATTACHED);
3494         return make_int(extent_endpoint_bufpos(e, 1)
3495                         - extent_endpoint_bufpos(e, 0));
3496 }
3497
3498 DEFUN("next-extent", Fnext_extent, 1, 1, 0,     /*
3499 Find next extent after EXTENT.
3500 If EXTENT is a buffer return the first extent in the buffer; likewise
3501 for strings.
3502 Extents in a buffer are ordered in what is called the "display"
3503 order, which sorts by increasing start positions and then by *decreasing*
3504 end positions.
3505 If you want to perform an operation on a series of extents, use
3506 `map-extents' instead of this function; it is much more efficient.
3507 The primary use of this function should be to enumerate all the
3508 extents in a buffer.
3509 Note: The display order is not necessarily the order that `map-extents'
3510 processes extents in!
3511 */
3512       (extent))
3513 {
3514         Lisp_Object val;
3515         EXTENT next;
3516
3517         if (EXTENTP(extent))
3518                 next = extent_next(decode_extent(extent, DE_MUST_BE_ATTACHED));
3519         else
3520                 next = extent_first(decode_buffer_or_string(extent));
3521
3522         if (!next)
3523                 return Qnil;
3524         XSETEXTENT(val, next);
3525         return val;
3526 }
3527
3528 DEFUN("previous-extent", Fprevious_extent, 1, 1, 0,     /*
3529 Find last extent before EXTENT.
3530 If EXTENT is a buffer return the last extent in the buffer; likewise
3531 for strings.
3532 This function is analogous to `next-extent'.
3533 */
3534       (extent))
3535 {
3536         Lisp_Object val;
3537         EXTENT prev;
3538
3539         if (EXTENTP(extent))
3540                 prev =
3541                     extent_previous(decode_extent(extent, DE_MUST_BE_ATTACHED));
3542         else
3543                 prev = extent_last(decode_buffer_or_string(extent));
3544
3545         if (!prev)
3546                 return Qnil;
3547         XSETEXTENT(val, prev);
3548         return val;
3549 }
3550
3551 #ifdef DEBUG_SXEMACS
3552
3553 DEFUN("next-e-extent", Fnext_e_extent, 1, 1, 0, /*
3554 Find next extent after EXTENT using the "e" order.
3555 If EXTENT is a buffer return the first extent in the buffer; likewise
3556 for strings.
3557 */
3558       (extent))
3559 {
3560         Lisp_Object val;
3561         EXTENT next;
3562
3563         if (EXTENTP(extent))
3564                 next =
3565                     extent_e_next(decode_extent(extent, DE_MUST_BE_ATTACHED));
3566         else
3567                 next = extent_e_first(decode_buffer_or_string(extent));
3568
3569         if (!next)
3570                 return Qnil;
3571         XSETEXTENT(val, next);
3572         return val;
3573 }
3574
3575 DEFUN("previous-e-extent", Fprevious_e_extent, 1, 1, 0, /*
3576 Find last extent before EXTENT using the "e" order.
3577 If EXTENT is a buffer return the last extent in the buffer; likewise
3578 for strings.
3579 This function is analogous to `next-e-extent'.
3580 */
3581       (extent))
3582 {
3583         Lisp_Object val;
3584         EXTENT prev;
3585
3586         if (EXTENTP(extent))
3587                 prev =
3588                     extent_e_previous(decode_extent
3589                                       (extent, DE_MUST_BE_ATTACHED));
3590         else
3591                 prev = extent_e_last(decode_buffer_or_string(extent));
3592
3593         if (!prev)
3594                 return Qnil;
3595         XSETEXTENT(val, prev);
3596         return val;
3597 }
3598
3599 #endif
3600
3601 DEFUN("next-extent-change", Fnext_extent_change, 1, 2, 0,       /*
3602 Return the next position after POS where an extent begins or ends.
3603 If POS is at the end of the buffer or string, POS will be returned;
3604 otherwise a position greater than POS will always be returned.
3605 If OBJECT is nil, the current buffer is assumed.
3606 */
3607       (pos, object))
3608 {
3609         Lisp_Object obj = decode_buffer_or_string(object);
3610         Bytind bpos;
3611
3612         bpos =
3613             get_buffer_or_string_pos_byte(obj, pos, GB_ALLOW_PAST_ACCESSIBLE);
3614         bpos = extent_find_end_of_run(obj, bpos, 1);
3615         return make_int(buffer_or_string_bytind_to_bufpos(obj, bpos));
3616 }
3617
3618 DEFUN("previous-extent-change", Fprevious_extent_change, 1, 2, 0,       /*
3619 Return the last position before POS where an extent begins or ends.
3620 If POS is at the beginning of the buffer or string, POS will be returned;
3621 otherwise a position less than POS will always be returned.
3622 If OBJECT is nil, the current buffer is assumed.
3623 */
3624       (pos, object))
3625 {
3626         Lisp_Object obj = decode_buffer_or_string(object);
3627         Bytind bpos;
3628
3629         bpos =
3630             get_buffer_or_string_pos_byte(obj, pos, GB_ALLOW_PAST_ACCESSIBLE);
3631         bpos = extent_find_beginning_of_run(obj, bpos, 1);
3632         return make_int(buffer_or_string_bytind_to_bufpos(obj, bpos));
3633 }
3634 \f
3635 /************************************************************************/
3636 /*                      parent and children stuff                       */
3637 /************************************************************************/
3638
3639 DEFUN("extent-parent", Fextent_parent, 1, 1, 0, /*
3640 Return the parent (if any) of EXTENT.
3641 If an extent has a parent, it derives all its properties from that extent
3642 and has no properties of its own. (The only "properties" that the
3643 extent keeps are the buffer/string it refers to and the start and end
3644 points.) It is possible for an extent's parent to itself have a parent.
3645 */
3646       (extent))
3647 /* do I win the prize for the strangest split infinitive? */
3648 {
3649         EXTENT e = decode_extent(extent, 0);
3650         return extent_parent(e);
3651 }
3652
3653 DEFUN("extent-children", Fextent_children, 1, 1, 0,     /*
3654 Return a list of the children (if any) of EXTENT.
3655 The children of an extent are all those extents whose parent is that extent.
3656 This function does not recursively trace children of children.
3657 \(To do that, use `extent-descendants'.)
3658 */
3659       (extent))
3660 {
3661         EXTENT e = decode_extent(extent, 0);
3662         Lisp_Object children = extent_children(e);
3663
3664         if (!NILP(children))
3665                 return Fcopy_sequence(XWEAK_LIST_LIST(children));
3666         else
3667                 return Qnil;
3668 }
3669
3670 static void remove_extent_from_children_list(EXTENT e, Lisp_Object child)
3671 {
3672         Lisp_Object children = extent_children(e);
3673
3674 #ifdef ERROR_CHECK_EXTENTS
3675         assert(!NILP(memq_no_quit(child, XWEAK_LIST_LIST(children))));
3676 #endif
3677         XWEAK_LIST_LIST(children) =
3678             delq_no_quit(child, XWEAK_LIST_LIST(children));
3679 }
3680
3681 static void add_extent_to_children_list(EXTENT e, Lisp_Object child)
3682 {
3683         Lisp_Object children = extent_children(e);
3684
3685         if (NILP(children)) {
3686                 children = make_weak_list(WEAK_LIST_SIMPLE);
3687                 set_extent_no_chase_aux_field(e, children, children);
3688         }
3689 #ifdef ERROR_CHECK_EXTENTS
3690         assert(NILP(memq_no_quit(child, XWEAK_LIST_LIST(children))));
3691 #endif
3692         XWEAK_LIST_LIST(children) = Fcons(child, XWEAK_LIST_LIST(children));
3693 }
3694
3695 DEFUN("set-extent-parent", Fset_extent_parent, 2, 2, 0, /*
3696 Set the parent of EXTENT to PARENT (may be nil).
3697 See `extent-parent'.
3698 */
3699       (extent, parent))
3700 {
3701         EXTENT e = decode_extent(extent, 0);
3702         Lisp_Object cur_parent = extent_parent(e);
3703         Lisp_Object rest;
3704
3705         XSETEXTENT(extent, e);
3706         if (!NILP(parent))
3707                 CHECK_LIVE_EXTENT(parent);
3708         if (EQ(parent, cur_parent))
3709                 return Qnil;
3710         for (rest = parent; !NILP(rest); rest = extent_parent(XEXTENT(rest)))
3711                 if (EQ(rest, extent))
3712                         signal_type_error(Qinvalid_change,
3713                                           "Circular parent chain would result",
3714                                           extent);
3715         if (NILP(parent)) {
3716                 remove_extent_from_children_list(XEXTENT(cur_parent), extent);
3717                 set_extent_no_chase_aux_field(e, parent, Qnil);
3718                 e->flags.has_parent = 0;
3719         } else {
3720                 add_extent_to_children_list(XEXTENT(parent), extent);
3721                 set_extent_no_chase_aux_field(e, parent, parent);
3722                 e->flags.has_parent = 1;
3723         }
3724         /* changing the parent also changes the properties of all children. */
3725         {
3726                 int old_invis = (!NILP(cur_parent) &&
3727                                  !NILP(extent_invisible(XEXTENT(cur_parent))));
3728                 int new_invis = (!NILP(parent) &&
3729                                  !NILP(extent_invisible(XEXTENT(parent))));
3730
3731                 extent_maybe_changed_for_redisplay(e, 1,
3732                                                    new_invis != old_invis);
3733         }
3734
3735         return Qnil;
3736 }
3737 \f
3738 /************************************************************************/
3739 /*                      basic extent mutators                           */
3740 /************************************************************************/
3741
3742 /* Note:  If you track non-duplicable extents by undo, you'll get bogus
3743    undo records for transient extents via update-extent.
3744    For example, query-replace will do this.
3745  */
3746
3747 static void set_extent_endpoints_1(EXTENT extent, Memind start, Memind end)
3748 {
3749 #ifdef ERROR_CHECK_EXTENTS
3750         Lisp_Object obj = extent_object(extent);
3751
3752         assert(start <= end);
3753         if (BUFFERP(obj)) {
3754                 assert(valid_memind_p(XBUFFER(obj), start));
3755                 assert(valid_memind_p(XBUFFER(obj), end));
3756         }
3757 #endif
3758
3759         /* Optimization: if the extent is already where we want it to be,
3760            do nothing. */
3761         if (!extent_detached_p(extent) && extent_start(extent) == start &&
3762             extent_end(extent) == end)
3763                 return;
3764
3765         if (extent_detached_p(extent)) {
3766                 if (extent_duplicable_p(extent)) {
3767                         Lisp_Object extent_obj;
3768                         XSETEXTENT(extent_obj, extent);
3769                         record_extent(extent_obj, 1);
3770                 }
3771         } else
3772                 extent_detach(extent);
3773
3774         set_extent_start(extent, start);
3775         set_extent_end(extent, end);
3776         extent_attach(extent);
3777 }
3778
3779 /* Set extent's endpoints to S and E, and put extent in buffer or string
3780    OBJECT. (If OBJECT is nil, do not change the extent's object.) */
3781
3782 void set_extent_endpoints(EXTENT extent, Bytind s, Bytind e, Lisp_Object object)
3783 {
3784         Memind start, end;
3785
3786         if (NILP(object)) {
3787                 object = extent_object(extent);
3788                 assert(!NILP(object));
3789         } else if (!EQ(object, extent_object(extent))) {
3790                 extent_detach(extent);
3791                 extent_object(extent) = object;
3792         }
3793
3794         start = s < 0 ? extent_start(extent) :
3795             buffer_or_string_bytind_to_memind(object, s);
3796         end = e < 0 ? extent_end(extent) :
3797             buffer_or_string_bytind_to_memind(object, e);
3798         set_extent_endpoints_1(extent, start, end);
3799 }
3800
3801 static void set_extent_openness(EXTENT extent, int start_open, int end_open)
3802 {
3803         if (start_open != -1)
3804                 extent_start_open_p(extent) = start_open;
3805         if (end_open != -1)
3806                 extent_end_open_p(extent) = end_open;
3807         /* changing the open/closedness of an extent does not affect
3808            redisplay. */
3809 }
3810
3811 static EXTENT make_extent_internal(Lisp_Object object, Bytind from, Bytind to)
3812 {
3813         EXTENT extent;
3814
3815         extent = make_extent_detached(object);
3816         set_extent_endpoints(extent, from, to, Qnil);
3817         return extent;
3818 }
3819
3820 static EXTENT
3821 copy_extent(EXTENT original, Bytind from, Bytind to, Lisp_Object object)
3822 {
3823         EXTENT e;
3824
3825         e = make_extent_detached(object);
3826         if (from >= 0)
3827                 set_extent_endpoints(e, from, to, Qnil);
3828
3829         e->plist = Fcopy_sequence(original->plist);
3830         memcpy(&e->flags, &original->flags, sizeof(e->flags));
3831         if (e->flags.has_aux) {
3832                 /* also need to copy the aux struct.  It won't work for
3833                    this extent to share the same aux struct as the original
3834                    one. */
3835                 struct extent_auxiliary *data =
3836                     alloc_lcrecord_type(struct extent_auxiliary,
3837                                         &lrecord_extent_auxiliary);
3838
3839                 copy_lcrecord(data, XEXTENT_AUXILIARY(XCAR(original->plist)));
3840                 XSETEXTENT_AUXILIARY(XCAR(e->plist), data);
3841         }
3842
3843         {
3844                 /* we may have just added another child to the parent extent. */
3845                 Lisp_Object parent = extent_parent(e);
3846                 if (!NILP(parent)) {
3847                         Lisp_Object extent;
3848                         XSETEXTENT(extent, e);
3849                         add_extent_to_children_list(XEXTENT(parent), extent);
3850                 }
3851         }
3852
3853         return e;
3854 }
3855
3856 static void destroy_extent(EXTENT extent)
3857 {
3858         Lisp_Object rest, nextrest, children;
3859         Lisp_Object extent_obj;
3860
3861         if (!extent_detached_p(extent))
3862                 extent_detach(extent);
3863         /* disassociate the extent from its children and parent */
3864         children = extent_children(extent);
3865         if (!NILP(children)) {
3866                 LIST_LOOP_DELETING(rest, nextrest, XWEAK_LIST_LIST(children))
3867                     Fset_extent_parent(XCAR(rest), Qnil);
3868         }
3869         XSETEXTENT(extent_obj, extent);
3870         Fset_extent_parent(extent_obj, Qnil);
3871         /* mark the extent as destroyed */
3872         extent_object(extent) = Qt;
3873 }
3874
3875 DEFUN("make-extent", Fmake_extent, 2, 3, 0,     /*
3876 Make an extent for the range [FROM, TO) in BUFFER-OR-STRING.
3877 BUFFER-OR-STRING defaults to the current buffer.  Insertions at point
3878 TO will be outside of the extent; insertions at FROM will be inside the
3879 extent, causing the extent to grow. (This is the same way that markers
3880 behave.) You can change the behavior of insertions at the endpoints
3881 using `set-extent-property'.  The extent is initially detached if both
3882 FROM and TO are nil, and in this case BUFFER-OR-STRING defaults to nil,
3883 meaning the extent is in no buffer and no string.
3884 */
3885       (from, to, buffer_or_string))
3886 {
3887         Lisp_Object extent_obj;
3888         Lisp_Object obj;
3889
3890         obj = decode_buffer_or_string(buffer_or_string);
3891         if (NILP(from) && NILP(to)) {
3892                 if (NILP(buffer_or_string))
3893                         obj = Qnil;
3894                 XSETEXTENT(extent_obj, make_extent_detached(obj));
3895         } else {
3896                 Bytind start, end;
3897
3898                 get_buffer_or_string_range_byte(obj, from, to, &start, &end,
3899                                                 GB_ALLOW_PAST_ACCESSIBLE);
3900                 XSETEXTENT(extent_obj, make_extent_internal(obj, start, end));
3901         }
3902         return extent_obj;
3903 }
3904
3905 DEFUN("copy-extent", Fcopy_extent, 1, 2, 0,     /*
3906 Make a copy of EXTENT.  It is initially detached.
3907 Optional argument BUFFER-OR-STRING defaults to EXTENT's buffer or string.
3908 */
3909       (extent, buffer_or_string))
3910 {
3911         EXTENT ext = decode_extent(extent, 0);
3912
3913         if (NILP(buffer_or_string))
3914                 buffer_or_string = extent_object(ext);
3915         else
3916                 buffer_or_string = decode_buffer_or_string(buffer_or_string);
3917
3918         XSETEXTENT(extent, copy_extent(ext, -1, -1, buffer_or_string));
3919         return extent;
3920 }
3921
3922 DEFUN("delete-extent", Fdelete_extent, 1, 1, 0, /*
3923 Remove EXTENT from its buffer and destroy it.
3924 This does not modify the buffer's text, only its display properties.
3925 The extent cannot be used thereafter.
3926 */
3927       (extent))
3928 {
3929         EXTENT ext;
3930
3931         /* We do not call decode_extent() here because already-destroyed
3932            extents are OK. */
3933         CHECK_EXTENT(extent);
3934         ext = XEXTENT(extent);
3935
3936         if (!EXTENT_LIVE_P(ext))
3937                 return Qnil;
3938         destroy_extent(ext);
3939         return Qnil;
3940 }
3941
3942 DEFUN("detach-extent", Fdetach_extent, 1, 1, 0, /*
3943 Remove EXTENT from its buffer in such a way that it can be re-inserted.
3944 An extent is also detached when all of its characters are all killed by a
3945 deletion, unless its `detachable' property has been unset.
3946
3947 Extents which have the `duplicable' attribute are tracked by the undo
3948 mechanism.  Detachment via `detach-extent' and string deletion is recorded,
3949 as is attachment via `insert-extent' and string insertion.  Extent motion,
3950 face changes, and attachment via `make-extent' and `set-extent-endpoints'
3951 are not recorded.  This means that extent changes which are to be undo-able
3952 must be performed by character editing, or by insertion and detachment of
3953 duplicable extents.
3954 */
3955       (extent))
3956 {
3957         EXTENT ext = decode_extent(extent, 0);
3958
3959         if (extent_detached_p(ext))
3960                 return extent;
3961         if (extent_duplicable_p(ext))
3962                 record_extent(extent, 0);
3963         extent_detach(ext);
3964
3965         return extent;
3966 }
3967
3968 DEFUN("set-extent-endpoints", Fset_extent_endpoints, 3, 4, 0,   /*
3969 Set the endpoints of EXTENT to START, END.
3970 If START and END are null, call detach-extent on EXTENT.
3971 BUFFER-OR-STRING specifies the new buffer or string that the extent should
3972 be in, and defaults to EXTENT's buffer or string. (If nil, and EXTENT
3973 is in no buffer and no string, it defaults to the current buffer.)
3974 See documentation on `detach-extent' for a discussion of undo recording.
3975 */
3976       (extent, start, end, buffer_or_string))
3977 {
3978         EXTENT ext;
3979         Bytind s, e;
3980
3981         ext = decode_extent(extent, 0);
3982
3983         if (NILP(buffer_or_string)) {
3984                 buffer_or_string = extent_object(ext);
3985                 if (NILP(buffer_or_string))
3986                         buffer_or_string = Fcurrent_buffer();
3987         } else
3988                 buffer_or_string = decode_buffer_or_string(buffer_or_string);
3989
3990         if (NILP(start) && NILP(end))
3991                 return Fdetach_extent(extent);
3992
3993         get_buffer_or_string_range_byte(buffer_or_string, start, end, &s, &e,
3994                                         GB_ALLOW_PAST_ACCESSIBLE);
3995
3996         buffer_or_string_extent_info_force(buffer_or_string);
3997         set_extent_endpoints(ext, s, e, buffer_or_string);
3998         return extent;
3999 }
4000 \f
4001 /************************************************************************/
4002 /*                         mapping over extents                         */
4003 /************************************************************************/
4004
4005 static unsigned int decode_map_extents_flags(Lisp_Object flags)
4006 {
4007         unsigned int retval = 0;
4008         unsigned int all_extents_specified = 0;
4009         unsigned int in_region_specified = 0;
4010
4011         if (EQ(flags, Qt))      /* obsoleteness compatibility */
4012                 return ME_END_CLOSED;
4013         if (NILP(flags))
4014                 return 0;
4015         if (SYMBOLP(flags))
4016                 flags = Fcons(flags, Qnil);
4017         while (!NILP(flags)) {
4018                 Lisp_Object sym;
4019                 CHECK_CONS(flags);
4020                 sym = XCAR(flags);
4021                 CHECK_SYMBOL(sym);
4022                 if (EQ(sym, Qall_extents_closed) || EQ(sym, Qall_extents_open)
4023                     || EQ(sym, Qall_extents_closed_open)
4024                     || EQ(sym, Qall_extents_open_closed)) {
4025                         if (all_extents_specified)
4026                                 error
4027                                     ("Only one `all-extents-*' flag may be specified");
4028                         all_extents_specified = 1;
4029                 }
4030                 if (EQ(sym, Qstart_in_region) || EQ(sym, Qend_in_region) ||
4031                     EQ(sym, Qstart_and_end_in_region) ||
4032                     EQ(sym, Qstart_or_end_in_region)) {
4033                         if (in_region_specified)
4034                                 error
4035                                     ("Only one `*-in-region' flag may be specified");
4036                         in_region_specified = 1;
4037                 }
4038
4039                 /* I do so love that conditional operator ... */
4040                 retval |=
4041                     EQ(sym, Qend_closed) ? ME_END_CLOSED :
4042                     EQ(sym, Qstart_open) ? ME_START_OPEN :
4043                     EQ(sym, Qall_extents_closed) ? ME_ALL_EXTENTS_CLOSED :
4044                     EQ(sym, Qall_extents_open) ? ME_ALL_EXTENTS_OPEN :
4045                     EQ(sym,
4046                        Qall_extents_closed_open) ? ME_ALL_EXTENTS_CLOSED_OPEN :
4047                     EQ(sym,
4048                        Qall_extents_open_closed) ? ME_ALL_EXTENTS_OPEN_CLOSED :
4049                     EQ(sym, Qstart_in_region) ? ME_START_IN_REGION : EQ(sym,
4050                                                                         Qend_in_region)
4051                     ? ME_END_IN_REGION : EQ(sym,
4052                                             Qstart_and_end_in_region) ?
4053                     ME_START_AND_END_IN_REGION : EQ(sym,
4054                                                     Qstart_or_end_in_region) ?
4055                     ME_START_OR_END_IN_REGION : EQ(sym,
4056                                                    Qnegate_in_region) ?
4057                     ME_NEGATE_IN_REGION
4058                     : (invalid_argument("Invalid `map-extents' flag", sym), 0);
4059
4060                 flags = XCDR(flags);
4061         }
4062         return retval;
4063 }
4064
4065 DEFUN("extent-in-region-p", Fextent_in_region_p, 1, 4, 0,       /*
4066 Return whether EXTENT overlaps a specified region.
4067 This is equivalent to whether `map-extents' would visit EXTENT when called
4068 with these args.
4069 */
4070       (extent, from, to, flags))
4071 {
4072         Bytind start, end;
4073         EXTENT ext = decode_extent(extent, DE_MUST_BE_ATTACHED);
4074         Lisp_Object obj = extent_object(ext);
4075
4076         get_buffer_or_string_range_byte(obj, from, to, &start, &end,
4077                                         GB_ALLOW_NIL |
4078                                         GB_ALLOW_PAST_ACCESSIBLE);
4079
4080         return extent_in_region_p(ext, start, end,
4081                                   decode_map_extents_flags(flags)) ? Qt : Qnil;
4082 }
4083
4084 struct slow_map_extents_arg {
4085         Lisp_Object map_arg;
4086         Lisp_Object map_routine;
4087         Lisp_Object result;
4088         Lisp_Object property;
4089         Lisp_Object value;
4090 };
4091
4092 static int slow_map_extents_function(EXTENT extent, void *arg)
4093 {
4094         /* This function can GC */
4095         struct slow_map_extents_arg *closure =
4096             (struct slow_map_extents_arg *)arg;
4097         Lisp_Object extent_obj;
4098
4099         XSETEXTENT(extent_obj, extent);
4100
4101         /* make sure this extent qualifies according to the PROPERTY
4102            and VALUE args */
4103
4104         if (!NILP(closure->property)) {
4105                 Lisp_Object value =
4106                     Fextent_property(extent_obj, closure->property,
4107                                      Qnil);
4108                 if ((NILP(closure->value) && NILP(value)) ||
4109                     (!NILP(closure->value) && !EQ(value, closure->value)))
4110                         return 0;
4111         }
4112
4113         closure->result = call2(closure->map_routine, extent_obj,
4114                                 closure->map_arg);
4115         return !NILP(closure->result);
4116 }
4117
4118 DEFUN("map-extents", Fmap_extents, 1, 8, 0,     /*
4119 Map FUNCTION over the extents which overlap a region in OBJECT.
4120 OBJECT is normally a buffer or string but could be an extent (see below).
4121 The region is normally bounded by [FROM, TO) (i.e. the beginning of the
4122 region is closed and the end of the region is open), but this can be
4123 changed with the FLAGS argument (see below for a complete discussion).
4124
4125 FUNCTION is called with the arguments (extent, MAPARG).  The arguments
4126 OBJECT, FROM, TO, MAPARG, and FLAGS are all optional and default to
4127 the current buffer, the beginning of OBJECT, the end of OBJECT, nil,
4128 and nil, respectively.  `map-extents' returns the first non-nil result
4129 produced by FUNCTION, and no more calls to FUNCTION are made after it
4130 returns non-nil.
4131
4132 If OBJECT is an extent, FROM and TO default to the extent's endpoints,
4133 and the mapping omits that extent and its predecessors.  This feature
4134 supports restarting a loop based on `map-extents'.  Note: OBJECT must
4135 be attached to a buffer or string, and the mapping is done over that
4136 buffer or string.
4137
4138 An extent overlaps the region if there is any point in the extent that is
4139 also in the region. (For the purpose of overlap, zero-length extents and
4140 regions are treated as closed on both ends regardless of their endpoints'
4141 specified open/closedness.) Note that the endpoints of an extent or region
4142 are considered to be in that extent or region if and only if the
4143 corresponding end is closed.  For example, the extent [5,7] overlaps the
4144 region [2,5] because 5 is in both the extent and the region.  However, (5,7]
4145 does not overlap [2,5] because 5 is not in the extent, and neither [5,7] nor
4146 \(5,7] overlaps the region [2,5) because 5 is not in the region.
4147
4148 The optional FLAGS can be a symbol or a list of one or more symbols,
4149 modifying the behavior of `map-extents'.  Allowed symbols are:
4150
4151 end-closed              The region's end is closed.
4152
4153 start-open              The region's start is open.
4154
4155 all-extents-closed      Treat all extents as closed on both ends for the
4156 purpose of determining whether they overlap the
4157 region, irrespective of their actual open- or
4158 closedness.
4159 all-extents-open        Treat all extents as open on both ends.
4160 all-extents-closed-open Treat all extents as start-closed, end-open.
4161 all-extents-open-closed Treat all extents as start-open, end-closed.
4162
4163 start-in-region         In addition to the above conditions for extent
4164 overlap, the extent's start position must lie within
4165 the specified region.  Note that, for this
4166 condition, open start positions are treated as if
4167 0.5 was added to the endpoint's value, and open
4168 end positions are treated as if 0.5 was subtracted
4169 from the endpoint's value.
4170 end-in-region           The extent's end position must lie within the
4171 region.
4172 start-and-end-in-region Both the extent's start and end positions must lie
4173 within the region.
4174 start-or-end-in-region  Either the extent's start or end position must lie
4175 within the region.
4176
4177 negate-in-region        The condition specified by a `*-in-region' flag
4178 must NOT hold for the extent to be considered.
4179
4180 At most one of `all-extents-closed', `all-extents-open',
4181 `all-extents-closed-open', and `all-extents-open-closed' may be specified.
4182
4183 At most one of `start-in-region', `end-in-region',
4184 `start-and-end-in-region', and `start-or-end-in-region' may be specified.
4185
4186 If optional arg PROPERTY is non-nil, only extents with that property set
4187 on them will be visited.  If optional arg VALUE is non-nil, only extents
4188 whose value for that property is `eq' to VALUE will be visited.
4189 */
4190       (function, object, from, to, maparg, flags, property, value))
4191 {
4192         /* This function can GC */
4193         struct slow_map_extents_arg closure;
4194         unsigned int me_flags;
4195         Bytind start, end;
4196         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
4197         EXTENT after = 0;
4198
4199         if (EXTENTP(object)) {
4200                 after = decode_extent(object, DE_MUST_BE_ATTACHED);
4201                 if (NILP(from))
4202                         from = Fextent_start_position(object);
4203                 if (NILP(to))
4204                         to = Fextent_end_position(object);
4205                 object = extent_object(after);
4206         } else
4207                 object = decode_buffer_or_string(object);
4208
4209         get_buffer_or_string_range_byte(object, from, to, &start, &end,
4210                                         GB_ALLOW_NIL |
4211                                         GB_ALLOW_PAST_ACCESSIBLE);
4212
4213         me_flags = decode_map_extents_flags(flags);
4214
4215         if (!NILP(property)) {
4216                 if (!NILP(value))
4217                         value = canonicalize_extent_property(property, value);
4218         }
4219
4220         GCPRO5(function, maparg, object, property, value);
4221
4222         closure.map_arg = maparg;
4223         closure.map_routine = function;
4224         closure.result = Qnil;
4225         closure.property = property;
4226         closure.value = value;
4227
4228         map_extents_bytind(start, end, slow_map_extents_function,
4229                            (void *)&closure, object, after,
4230                            /* You never know what the user might do ... */
4231                            me_flags | ME_MIGHT_CALL_ELISP);
4232
4233         UNGCPRO;
4234         return closure.result;
4235 }
4236 \f
4237 /************************************************************************/
4238 /*              mapping over extents -- other functions                 */
4239 /************************************************************************/
4240
4241 /* ------------------------------- */
4242 /*      map-extent-children        */
4243 /* ------------------------------- */
4244
4245 struct slow_map_extent_children_arg {
4246         Lisp_Object map_arg;
4247         Lisp_Object map_routine;
4248         Lisp_Object result;
4249         Lisp_Object property;
4250         Lisp_Object value;
4251         Bytind start_min;
4252         Bytind prev_start;
4253         Bytind prev_end;
4254 };
4255
4256 static int slow_map_extent_children_function(EXTENT extent, void *arg)
4257 {
4258         /* This function can GC */
4259         struct slow_map_extent_children_arg *closure =
4260             (struct slow_map_extent_children_arg *)arg;
4261         Lisp_Object extent_obj;
4262         Bytind start = extent_endpoint_bytind(extent, 0);
4263         Bytind end = extent_endpoint_bytind(extent, 1);
4264         /* Make sure the extent starts inside the region of interest,
4265            rather than just overlaps it.
4266          */
4267         if (start < closure->start_min)
4268                 return 0;
4269         /* Make sure the extent is not a child of a previous visited one.
4270            We know already, because of extent ordering,
4271            that start >= prev_start, and that if
4272            start == prev_start, then end <= prev_end.
4273          */
4274         if (start == closure->prev_start) {
4275                 if (end < closure->prev_end)
4276                         return 0;
4277         } else {                /* start > prev_start */
4278
4279                 if (start < closure->prev_end)
4280                         return 0;
4281                 /* corner case:  prev_end can be -1 if there is no prev */
4282         }
4283         XSETEXTENT(extent_obj, extent);
4284
4285         /* make sure this extent qualifies according to the PROPERTY
4286            and VALUE args */
4287
4288         if (!NILP(closure->property)) {
4289                 Lisp_Object value =
4290                     Fextent_property(extent_obj, closure->property,
4291                                      Qnil);
4292                 if ((NILP(closure->value) && NILP(value)) ||
4293                     (!NILP(closure->value) && !EQ(value, closure->value)))
4294                         return 0;
4295         }
4296
4297         closure->result = call2(closure->map_routine, extent_obj,
4298                                 closure->map_arg);
4299
4300         /* Since the callback may change the buffer, compute all stored
4301            buffer positions here.
4302          */
4303         closure->start_min = -1;        /* no need for this any more */
4304         closure->prev_start = extent_endpoint_bytind(extent, 0);
4305         closure->prev_end = extent_endpoint_bytind(extent, 1);
4306
4307         return !NILP(closure->result);
4308 }
4309
4310 DEFUN("map-extent-children", Fmap_extent_children, 1, 8, 0,     /*
4311 Map FUNCTION over the extents in the region from FROM to TO.
4312 FUNCTION is called with arguments (extent, MAPARG).  See `map-extents'
4313 for a full discussion of the arguments FROM, TO, and FLAGS.
4314
4315 The arguments are the same as for `map-extents', but this function differs
4316 in that it only visits extents which start in the given region, and also
4317 in that, after visiting an extent E, it skips all other extents which start
4318 inside E but end before E's end.
4319
4320 Thus, this function may be used to walk a tree of extents in a buffer:
4321 (defun walk-extents (buffer &optional ignore)
4322 (map-extent-children 'walk-extents buffer))
4323 */
4324       (function, object, from, to, maparg, flags, property, value))
4325 {
4326         /* This function can GC */
4327         struct slow_map_extent_children_arg closure;
4328         unsigned int me_flags;
4329         Bytind start, end;
4330         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
4331         EXTENT after = 0;
4332
4333         if (EXTENTP(object)) {
4334                 after = decode_extent(object, DE_MUST_BE_ATTACHED);
4335                 if (NILP(from))
4336                         from = Fextent_start_position(object);
4337                 if (NILP(to))
4338                         to = Fextent_end_position(object);
4339                 object = extent_object(after);
4340         } else
4341                 object = decode_buffer_or_string(object);
4342
4343         get_buffer_or_string_range_byte(object, from, to, &start, &end,
4344                                         GB_ALLOW_NIL |
4345                                         GB_ALLOW_PAST_ACCESSIBLE);
4346
4347         me_flags = decode_map_extents_flags(flags);
4348
4349         if (!NILP(property)) {
4350                 if (!NILP(value))
4351                         value = canonicalize_extent_property(property, value);
4352         }
4353
4354         GCPRO5(function, maparg, object, property, value);
4355
4356         closure.map_arg = maparg;
4357         closure.map_routine = function;
4358         closure.result = Qnil;
4359         closure.property = property;
4360         closure.value = value;
4361         closure.start_min = start;
4362         closure.prev_start = -1;
4363         closure.prev_end = -1;
4364         map_extents_bytind(start, end, slow_map_extent_children_function,
4365                            (void *)&closure, object, after,
4366                            /* You never know what the user might do ... */
4367                            me_flags | ME_MIGHT_CALL_ELISP);
4368
4369         UNGCPRO;
4370         return closure.result;
4371 }
4372
4373 /* ------------------------------- */
4374 /*             extent-at           */
4375 /* ------------------------------- */
4376
4377 /* find "smallest" matching extent containing pos -- (flag == 0) means
4378    all extents match, else (EXTENT_FLAGS (extent) & flag) must be true;
4379    for more than one matching extent with precisely the same endpoints,
4380    we choose the last extent in the extents_list.
4381    The search stops just before "before", if that is non-null.
4382    */
4383
4384 struct extent_at_arg {
4385         Lisp_Object best_match; /* or list of extents */
4386         Memind best_start;
4387         Memind best_end;
4388         Lisp_Object prop;
4389         EXTENT before;
4390         int all_extents;
4391 };
4392
4393 enum extent_at_flag {
4394         EXTENT_AT_AFTER,
4395         EXTENT_AT_BEFORE,
4396         EXTENT_AT_AT
4397 };
4398
4399 static enum extent_at_flag decode_extent_at_flag(Lisp_Object at_flag)
4400 {
4401         if (NILP(at_flag))
4402                 return EXTENT_AT_AFTER;
4403
4404         CHECK_SYMBOL(at_flag);
4405         if (EQ(at_flag, Qafter))
4406                 return EXTENT_AT_AFTER;
4407         if (EQ(at_flag, Qbefore))
4408                 return EXTENT_AT_BEFORE;
4409         if (EQ(at_flag, Qat))
4410                 return EXTENT_AT_AT;
4411
4412         invalid_argument("Invalid AT-FLAG in `extent-at'", at_flag);
4413         return EXTENT_AT_AFTER; /* unreached */
4414 }
4415
4416 static int extent_at_mapper(EXTENT e, void *arg)
4417 {
4418         struct extent_at_arg *closure = (struct extent_at_arg *)arg;
4419
4420         if (e == closure->before)
4421                 return 1;
4422
4423         /* If closure->prop is non-nil, then the extent is only acceptable
4424            if it has a non-nil value for that property. */
4425         if (!NILP(closure->prop)) {
4426                 Lisp_Object extent;
4427                 XSETEXTENT(extent, e);
4428                 if (NILP(Fextent_property(extent, closure->prop, Qnil)))
4429                         return 0;
4430         }
4431
4432         if (!closure->all_extents) {
4433                 EXTENT current;
4434
4435                 if (NILP(closure->best_match))
4436                         goto accept;
4437                 current = XEXTENT(closure->best_match);
4438                 /* redundant but quick test */
4439                 if (extent_start(current) > extent_start(e))
4440                         return 0;
4441
4442                 /* we return the "last" best fit, instead of the first --
4443                    this is because then the glyph closest to two equivalent
4444                    extents corresponds to the "extent-at" the text just past
4445                    that same glyph */
4446                 else if (!EXTENT_LESS_VALS(e, closure->best_start,
4447                                            closure->best_end))
4448                         goto accept;
4449                 else
4450                         return 0;
4451               accept:
4452                 XSETEXTENT(closure->best_match, e);
4453                 closure->best_start = extent_start(e);
4454                 closure->best_end = extent_end(e);
4455         } else {
4456                 Lisp_Object extent;
4457
4458                 XSETEXTENT(extent, e);
4459                 closure->best_match = Fcons(extent, closure->best_match);
4460         }
4461
4462         return 0;
4463 }
4464
4465 static Lisp_Object
4466 extent_at_bytind(Bytind position, Lisp_Object object, Lisp_Object property,
4467                  EXTENT before, enum extent_at_flag at_flag, int all_extents)
4468 {
4469         struct extent_at_arg closure;
4470         struct gcpro gcpro1;
4471
4472         /* it might be argued that invalid positions should cause
4473            errors, but the principle of least surprise dictates that
4474            nil should be returned (extent-at is often used in
4475            response to a mouse event, and in many cases previous events
4476            have changed the buffer contents).
4477
4478            Also, the openness stuff in the text-property code currently
4479            does not check its limits and might go off the end. */
4480         if ((at_flag == EXTENT_AT_BEFORE
4481              ? position <= buffer_or_string_absolute_begin_byte(object)
4482              : position < buffer_or_string_absolute_begin_byte(object))
4483             || (at_flag == EXTENT_AT_AFTER
4484                 ? position >= buffer_or_string_absolute_end_byte(object)
4485                 : position > buffer_or_string_absolute_end_byte(object)))
4486                 return Qnil;
4487
4488         closure.best_match = Qnil;
4489         closure.prop = property;
4490         closure.before = before;
4491         closure.all_extents = all_extents;
4492
4493         GCPRO1(closure.best_match);
4494         map_extents_bytind(at_flag ==
4495                            EXTENT_AT_BEFORE ? position - 1 : position,
4496                            at_flag == EXTENT_AT_AFTER ? position + 1 : position,
4497                            extent_at_mapper, (void *)&closure, object, 0,
4498                            ME_START_OPEN | ME_ALL_EXTENTS_CLOSED);
4499         if (all_extents)
4500                 closure.best_match = Fnreverse(closure.best_match);
4501         UNGCPRO;
4502
4503         return closure.best_match;
4504 }
4505
4506 DEFUN("extent-at", Fextent_at, 1, 5, 0, /*
4507 Find "smallest" extent at POS in OBJECT having PROPERTY set.
4508 Normally, an extent is "at" POS if it overlaps the region (POS, POS+1);
4509 i.e. if it covers the character after POS. (However, see the definition
4510 of AT-FLAG.) "Smallest" means the extent that comes last in the display
4511 order; this normally means the extent whose start position is closest to
4512 POS.  See `next-extent' for more information.
4513 OBJECT specifies a buffer or string and defaults to the current buffer.
4514 PROPERTY defaults to nil, meaning that any extent will do.
4515 Properties are attached to extents with `set-extent-property', which see.
4516 Returns nil if POS is invalid or there is no matching extent at POS.
4517 If the fourth argument BEFORE is not nil, it must be an extent; any returned
4518 extent will precede that extent.  This feature allows `extent-at' to be
4519 used by a loop over extents.
4520 AT-FLAG controls how end cases are handled, and should be one of:
4521
4522 nil or `after'              An extent is at POS if it covers the character
4523 after POS.  This is consistent with the way
4524 that text properties work.
4525 `before'            An extent is at POS if it covers the character
4526 before POS.
4527 `at'                        An extent is at POS if it overlaps or abuts POS.
4528 This includes all zero-length extents at POS.
4529
4530 Note that in all cases, the start-openness and end-openness of the extents
4531 considered is ignored.  If you want to pay attention to those properties,
4532 you should use `map-extents', which gives you more control.
4533 */
4534       (pos, object, property, before, at_flag))
4535 {
4536         Bytind position;
4537         EXTENT before_extent;
4538         enum extent_at_flag fl;
4539
4540         object = decode_buffer_or_string(object);
4541         position =
4542             get_buffer_or_string_pos_byte(object, pos, GB_NO_ERROR_IF_BAD);
4543         if (NILP(before))
4544                 before_extent = 0;
4545         else
4546                 before_extent = decode_extent(before, DE_MUST_BE_ATTACHED);
4547         if (before_extent && !EQ(object, extent_object(before_extent)))
4548                 invalid_argument("extent not in specified buffer or string",
4549                                  object);
4550         fl = decode_extent_at_flag(at_flag);
4551
4552         return extent_at_bytind(position, object, property, before_extent, fl,
4553                                 0);
4554 }
4555
4556 DEFUN("extents-at", Fextents_at, 1, 5, 0,       /*
4557 Find all extents at POS in OBJECT having PROPERTY set.
4558 Normally, an extent is "at" POS if it overlaps the region (POS, POS+1);
4559 i.e. if it covers the character after POS. (However, see the definition
4560 of AT-FLAG.)
4561 This provides similar functionality to `extent-list', but does so in a way
4562 that is compatible with `extent-at'. (For example, errors due to POS out of
4563 range are ignored; this makes it safer to use this function in response to
4564 a mouse event, because in many cases previous events have changed the buffer
4565 contents.)
4566 OBJECT specifies a buffer or string and defaults to the current buffer.
4567 PROPERTY defaults to nil, meaning that any extent will do.
4568 Properties are attached to extents with `set-extent-property', which see.
4569 Returns nil if POS is invalid or there is no matching extent at POS.
4570 If the fourth argument BEFORE is not nil, it must be an extent; any returned
4571 extent will precede that extent.  This feature allows `extents-at' to be
4572 used by a loop over extents.
4573 AT-FLAG controls how end cases are handled, and should be one of:
4574
4575 nil or `after'            An extent is at POS if it covers the character
4576 after POS.  This is consistent with the way
4577 that text properties work.
4578 `before'          An extent is at POS if it covers the character
4579 before POS.
4580 `at'                      An extent is at POS if it overlaps or abuts POS.
4581 This includes all zero-length extents at POS.
4582
4583 Note that in all cases, the start-openness and end-openness of the extents
4584 considered is ignored.  If you want to pay attention to those properties,
4585 you should use `map-extents', which gives you more control.
4586 */
4587       (pos, object, property, before, at_flag))
4588 {
4589         Bytind position;
4590         EXTENT before_extent;
4591         enum extent_at_flag fl;
4592
4593         object = decode_buffer_or_string(object);
4594         position =
4595             get_buffer_or_string_pos_byte(object, pos, GB_NO_ERROR_IF_BAD);
4596         if (NILP(before))
4597                 before_extent = 0;
4598         else
4599                 before_extent = decode_extent(before, DE_MUST_BE_ATTACHED);
4600         if (before_extent && !EQ(object, extent_object(before_extent)))
4601                 invalid_argument("extent not in specified buffer or string",
4602                                  object);
4603         fl = decode_extent_at_flag(at_flag);
4604
4605         return extent_at_bytind(position, object, property, before_extent, fl,
4606                                 1);
4607 }
4608
4609 /* ------------------------------- */
4610 /*   verify_extent_modification()  */
4611 /* ------------------------------- */
4612
4613 /* verify_extent_modification() is called when a buffer or string is
4614    modified to check whether the modification is occuring inside a
4615    read-only extent.
4616  */
4617
4618 struct verify_extents_arg {
4619         Lisp_Object object;
4620         Memind start;
4621         Memind end;
4622         Lisp_Object iro;        /* value of inhibit-read-only */
4623 };
4624
4625 static int verify_extent_mapper(EXTENT extent, void *arg)
4626 {
4627         struct verify_extents_arg *closure = (struct verify_extents_arg *)arg;
4628         Lisp_Object prop = extent_read_only(extent);
4629
4630         if (NILP(prop))
4631                 return 0;
4632
4633         if (CONSP(closure->iro) && !NILP(Fmemq(prop, closure->iro)))
4634                 return 0;
4635
4636 #if 0                           /* Nobody seems to care for this any more -sb */
4637         /* Allow deletion if the extent is completely contained in
4638            the region being deleted.
4639            This is important for supporting tokens which are internally
4640            write-protected, but which can be killed and yanked as a whole.
4641            Ignore open/closed distinctions at this point.
4642            -- Rose
4643          */
4644         if (closure->start != closure->end &&
4645             extent_start(extent) >= closure->start &&
4646             extent_end(extent) <= closure->end)
4647                 return 0;
4648 #endif
4649
4650         while (1)
4651                 Fsignal(Qbuffer_read_only, (list1(closure->object)));
4652
4653         RETURN_NOT_REACHED(0)
4654 }
4655
4656 /* Value of Vinhibit_read_only is precomputed and passed in for
4657    efficiency */
4658
4659 void
4660 verify_extent_modification(Lisp_Object object, Bytind from, Bytind to,
4661                            Lisp_Object inhibit_read_only_value)
4662 {
4663         int closed;
4664         struct verify_extents_arg closure;
4665
4666         /* If insertion, visit closed-endpoint extents touching the insertion
4667            point because the text would go inside those extents.  If deletion,
4668            treat the range as open on both ends so that touching extents are not
4669            visited.  Note that we assume that an insertion is occurring if the
4670            changed range has zero length, and a deletion otherwise.  This
4671            fails if a change (i.e. non-insertion, non-deletion) is happening.
4672            As far as I know, this doesn't currently occur in XEmacs. --ben */
4673         closed = (from == to);
4674         closure.object = object;
4675         closure.start = buffer_or_string_bytind_to_memind(object, from);
4676         closure.end = buffer_or_string_bytind_to_memind(object, to);
4677         closure.iro = inhibit_read_only_value;
4678
4679         map_extents_bytind(from, to, verify_extent_mapper, (void *)&closure,
4680                            object, 0, closed ? ME_END_CLOSED : ME_START_OPEN);
4681 }
4682
4683 /* ------------------------------------ */
4684 /*    process_extents_for_insertion()   */
4685 /* ------------------------------------ */
4686
4687 struct process_extents_for_insertion_arg {
4688         Bytind opoint;
4689         int length;
4690         Lisp_Object object;
4691 };
4692
4693 /*   A region of length LENGTH was just inserted at OPOINT.  Modify all
4694      of the extents as required for the insertion, based on their
4695      start-open/end-open properties.
4696  */
4697
4698 static int process_extents_for_insertion_mapper(EXTENT extent, void *arg)
4699 {
4700         struct process_extents_for_insertion_arg *closure =
4701             (struct process_extents_for_insertion_arg *)arg;
4702         Memind indice = buffer_or_string_bytind_to_memind(closure->object,
4703                                                           closure->opoint);
4704
4705         /* When this function is called, one end of the newly-inserted text should
4706            be adjacent to some endpoint of the extent, or disjoint from it.  If
4707            the insertion overlaps any existing extent, something is wrong.
4708          */
4709 #ifdef ERROR_CHECK_EXTENTS
4710         if (extent_start(extent) > indice &&
4711             extent_start(extent) < indice + closure->length)
4712                 abort();
4713         if (extent_end(extent) > indice &&
4714             extent_end(extent) < indice + closure->length)
4715                 abort();
4716 #endif
4717
4718         /* The extent-adjustment code adjusted the extent's endpoints as if
4719            all extents were closed-open -- endpoints at the insertion point
4720            remain unchanged.  We need to fix the other kinds of extents:
4721
4722            1. Start position of start-open extents needs to be moved.
4723
4724            2. End position of end-closed extents needs to be moved.
4725
4726            Note that both conditions hold for zero-length (] extents at the
4727            insertion point.  But under these rules, zero-length () extents
4728            would get adjusted such that their start is greater than their
4729            end; instead of allowing that, we treat them as [) extents by
4730            modifying condition #1 to not fire nothing when dealing with a
4731            zero-length open-open extent.
4732
4733            Existence of zero-length open-open extents is unfortunately an
4734            inelegant part of the extent model, but there is no way around
4735            it. */
4736
4737         {
4738                 Memind new_start = extent_start(extent);
4739                 Memind new_end = extent_end(extent);
4740
4741                 if (indice == extent_start(extent)
4742                     && extent_start_open_p(extent)
4743                     /* zero-length () extents are exempt; see comment above. */
4744                     && !(new_start == new_end && extent_end_open_p(extent))
4745                     )
4746                         new_start += closure->length;
4747                 if (indice == extent_end(extent) && !extent_end_open_p(extent))
4748                         new_end += closure->length;
4749
4750                 set_extent_endpoints_1(extent, new_start, new_end);
4751         }
4752
4753         return 0;
4754 }
4755
4756 void
4757 process_extents_for_insertion(Lisp_Object object, Bytind opoint,
4758                               Bytecount length)
4759 {
4760         struct process_extents_for_insertion_arg closure;
4761
4762         closure.opoint = opoint;
4763         closure.length = length;
4764         closure.object = object;
4765
4766         map_extents_bytind(opoint, opoint + length,
4767                            process_extents_for_insertion_mapper,
4768                            (void *)&closure, object, 0,
4769                            ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS |
4770                            ME_INCLUDE_INTERNAL);
4771 }
4772
4773 /* ------------------------------------ */
4774 /*    process_extents_for_deletion()    */
4775 /* ------------------------------------ */
4776
4777 struct process_extents_for_deletion_arg {
4778         Memind start, end;
4779         int destroy_included_extents;
4780 };
4781
4782 /* This function is called when we're about to delete the range [from, to].
4783    Detach all of the extents that are completely inside the range [from, to],
4784    if they're detachable or open-open. */
4785
4786 static int process_extents_for_deletion_mapper(EXTENT extent, void *arg)
4787 {
4788         struct process_extents_for_deletion_arg *closure =
4789             (struct process_extents_for_deletion_arg *)arg;
4790
4791         /* If the extent lies completely within the range that
4792            is being deleted, then nuke the extent if it's detachable
4793            (otherwise, it will become a zero-length extent). */
4794
4795         if (closure->start <= extent_start(extent) &&
4796             extent_end(extent) <= closure->end) {
4797                 if (extent_detachable_p(extent)) {
4798                         if (closure->destroy_included_extents)
4799                                 destroy_extent(extent);
4800                         else
4801                                 extent_detach(extent);
4802                 }
4803         }
4804
4805         return 0;
4806 }
4807
4808 /* DESTROY_THEM means destroy the extents instead of just deleting them.
4809    It is unused currently, but perhaps might be used (there used to
4810    be a function process_extents_for_destruction(), #if 0'd out,
4811    that did the equivalent). */
4812 void
4813 process_extents_for_deletion(Lisp_Object object, Bytind from,
4814                              Bytind to, int destroy_them)
4815 {
4816         struct process_extents_for_deletion_arg closure;
4817
4818         closure.start = buffer_or_string_bytind_to_memind(object, from);
4819         closure.end = buffer_or_string_bytind_to_memind(object, to);
4820         closure.destroy_included_extents = destroy_them;
4821
4822         map_extents_bytind(from, to, process_extents_for_deletion_mapper,
4823                            (void *)&closure, object, 0,
4824                            ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS);
4825 }
4826
4827 /* ------------------------------- */
4828 /*   report_extent_modification()  */
4829 /* ------------------------------- */
4830 struct report_extent_modification_closure {
4831         Lisp_Object buffer;
4832         Bufpos start, end;
4833         int afterp;
4834         int speccount;
4835 };
4836
4837 static Lisp_Object report_extent_modification_restore(Lisp_Object buffer)
4838 {
4839         if (current_buffer != XBUFFER(buffer))
4840                 Fset_buffer(buffer);
4841         return Qnil;
4842 }
4843
4844 static int report_extent_modification_mapper(EXTENT extent, void *arg)
4845 {
4846         struct report_extent_modification_closure *closure =
4847             (struct report_extent_modification_closure *)arg;
4848         Lisp_Object exobj, startobj, endobj;
4849         Lisp_Object hook = (closure->afterp
4850                             ? extent_after_change_functions(extent)
4851                             : extent_before_change_functions(extent));
4852         if (NILP(hook))
4853                 return 0;
4854
4855         XSETEXTENT(exobj, extent);
4856         XSETINT(startobj, closure->start);
4857         XSETINT(endobj, closure->end);
4858
4859         /* Now that we are sure to call elisp, set up an unwind-protect so
4860            inside_change_hook gets restored in case we throw.  Also record
4861            the current buffer, in case we change it.  Do the recording only
4862            once.
4863
4864            One confusing thing here is that our caller never actually calls
4865            unbind_to (closure.speccount, Qnil).  This is because
4866            map_extents_bytind() unbinds before, and with a smaller
4867            speccount.  The additional unbind_to() in
4868            report_extent_modification() would cause XEmacs to abort.  */
4869         if (closure->speccount == -1) {
4870                 closure->speccount = specpdl_depth();
4871                 record_unwind_protect(report_extent_modification_restore,
4872                                       Fcurrent_buffer());
4873         }
4874
4875         /* The functions will expect closure->buffer to be the current
4876            buffer, so change it if it isn't.  */
4877         if (current_buffer != XBUFFER(closure->buffer))
4878                 Fset_buffer(closure->buffer);
4879
4880         /* #### It's a shame that we can't use any of the existing run_hook*
4881            functions here.  This is so because all of them work with
4882            symbols, to be able to retrieve default values of local hooks.
4883            <sigh>
4884
4885            #### Idea: we could set up a dummy symbol, and call the hook
4886            functions on *that*.  */
4887
4888         if (!CONSP(hook) || EQ(XCAR(hook), Qlambda))
4889                 call3(hook, exobj, startobj, endobj);
4890         else {
4891                 Lisp_Object tail;
4892                 EXTERNAL_LIST_LOOP(tail, hook)
4893                     /* #### Shouldn't this perform the same Fset_buffer() check as
4894                        above?  */
4895                     call3(XCAR(tail), exobj, startobj, endobj);
4896         }
4897         return 0;
4898 }
4899
4900 void
4901 report_extent_modification(Lisp_Object buffer, Bufpos start, Bufpos end,
4902                            int afterp)
4903 {
4904         struct report_extent_modification_closure closure;
4905
4906         closure.buffer = buffer;
4907         closure.start = start;
4908         closure.end = end;
4909         closure.afterp = afterp;
4910         closure.speccount = -1;
4911
4912         map_extents(start, end, report_extent_modification_mapper,
4913                     (void *)&closure, buffer, NULL, ME_MIGHT_CALL_ELISP);
4914 }
4915 \f
4916 /************************************************************************/
4917 /*                      extent properties                               */
4918 /************************************************************************/
4919
4920 static void set_extent_invisible(EXTENT extent, Lisp_Object value)
4921 {
4922         if (!EQ(extent_invisible(extent), value)) {
4923                 set_extent_invisible_1(extent, value);
4924                 extent_changed_for_redisplay(extent, 1, 1);
4925         }
4926 }
4927
4928 /* This function does "memoization" -- similar to the interning
4929    that happens with symbols.  Given a list of faces, an equivalent
4930    list is returned such that if this function is called twice with
4931    input that is `equal', the resulting outputs will be `eq'.
4932
4933    Note that the inputs and outputs are in general *not* `equal' --
4934    faces in symbol form become actual face objects in the output.
4935    This is necessary so that temporary faces stay around. */
4936
4937 static Lisp_Object memoize_extent_face_internal(Lisp_Object list)
4938 {
4939         int len;
4940         int thelen;
4941         Lisp_Object cons, thecons;
4942         Lisp_Object oldtail, tail;
4943         struct gcpro gcpro1;
4944
4945         if (NILP(list))
4946                 return Qnil;
4947         if (!CONSP(list))
4948                 return Fget_face(list);
4949
4950         /* To do the memoization, we use a hash table mapping from
4951            external lists to internal lists.  We do `equal' comparisons
4952            on the keys so the memoization works correctly.
4953
4954            Note that we canonicalize things so that the keys in the
4955            hash table (the external lists) always contain symbols and
4956            the values (the internal lists) always contain face objects.
4957
4958            We also maintain a "reverse" table that maps from the internal
4959            lists to the external equivalents.  The idea here is twofold:
4960
4961            1) `extent-face' wants to return a list containing face symbols
4962            rather than face objects.
4963            2) We don't want things to get quite so messed up if the user
4964            maliciously side-effects the returned lists.
4965          */
4966
4967         len = XINT(Flength(list));
4968         thelen = XINT(Flength(Vextent_face_reusable_list));
4969         oldtail = Qnil;
4970         tail = Qnil;
4971         GCPRO1(oldtail);
4972
4973         /* We canonicalize the given list into another list.
4974            We try to avoid consing except when necessary, so we have
4975            a reusable list.
4976          */
4977
4978         if (thelen < len) {
4979                 cons = Vextent_face_reusable_list;
4980                 while (!NILP(XCDR(cons)))
4981                         cons = XCDR(cons);
4982                 XCDR(cons) = Fmake_list(make_int(len - thelen), Qnil);
4983         } else if (thelen > len) {
4984                 int i;
4985
4986                 /* Truncate the list temporarily so it's the right length;
4987                    remember the old tail. */
4988                 cons = Vextent_face_reusable_list;
4989                 for (i = 0; i < len - 1; i++)
4990                         cons = XCDR(cons);
4991                 tail = cons;
4992                 oldtail = XCDR(cons);
4993                 XCDR(cons) = Qnil;
4994         }
4995
4996         thecons = Vextent_face_reusable_list;
4997         EXTERNAL_LIST_LOOP(cons, list) {
4998                 Lisp_Object face = Fget_face(XCAR(cons));
4999
5000                 XCAR(thecons) = Fface_name(face);
5001                 thecons = XCDR(thecons);
5002         }
5003
5004         list =
5005             Fgethash(Vextent_face_reusable_list,
5006                      Vextent_face_memoize_hash_table, Qnil);
5007         if (NILP(list)) {
5008                 Lisp_Object symlist =
5009                     Fcopy_sequence(Vextent_face_reusable_list);
5010                 Lisp_Object facelist =
5011                     Fcopy_sequence(Vextent_face_reusable_list);
5012
5013                 LIST_LOOP(cons, facelist) {
5014                         XCAR(cons) = Fget_face(XCAR(cons));
5015                 }
5016                 Fputhash(symlist, facelist, Vextent_face_memoize_hash_table);
5017                 Fputhash(facelist, symlist,
5018                          Vextent_face_reverse_memoize_hash_table);
5019                 list = facelist;
5020         }
5021
5022         /* Now restore the truncated tail of the reusable list, if necessary. */
5023         if (!NILP(tail))
5024                 XCDR(tail) = oldtail;
5025
5026         UNGCPRO;
5027         return list;
5028 }
5029
5030 static Lisp_Object external_of_internal_memoized_face(Lisp_Object face)
5031 {
5032         if (NILP(face))
5033                 return Qnil;
5034         else if (!CONSP(face))
5035                 return XFACE(face)->name;
5036         else {
5037                 face = Fgethash(face, Vextent_face_reverse_memoize_hash_table,
5038                                 Qunbound);
5039                 assert(!UNBOUNDP(face));
5040                 return face;
5041         }
5042 }
5043
5044 static Lisp_Object
5045 canonicalize_extent_property(Lisp_Object prop, Lisp_Object value)
5046 {
5047         if (EQ(prop, Qface) || EQ(prop, Qmouse_face))
5048                 value = (external_of_internal_memoized_face
5049                          (memoize_extent_face_internal(value)));
5050         return value;
5051 }
5052
5053 /* Do we need a lisp-level function ? */
5054 DEFUN("set-extent-initial-redisplay-function", Fset_extent_initial_redisplay_function, 2, 2, 0, /*
5055 Note: This feature is experimental!
5056
5057 Set initial-redisplay-function of EXTENT to the function
5058 FUNCTION.
5059
5060 The first time the EXTENT is (re)displayed, an eval event will be
5061 dispatched calling FUNCTION with EXTENT as its only argument.
5062 */
5063       (extent, function))
5064 {
5065         EXTENT e = decode_extent(extent, DE_MUST_BE_ATTACHED);
5066
5067         e = extent_ancestor(e); /* Is this needed? Macro also does chasing! */
5068         set_extent_initial_redisplay_function(e, function);
5069         extent_in_red_event_p(e) = 0;   /* If the function changed we can spawn
5070                                            new events */
5071         extent_changed_for_redisplay(e, 1, 0);  /* Do we need to mark children too ? */
5072
5073         return function;
5074 }
5075
5076 DEFUN("extent-face", Fextent_face, 1, 1, 0,     /*
5077 Return the name of the face in which EXTENT is displayed, or nil
5078 if the extent's face is unspecified.  This might also return a list
5079 of face names.
5080 */
5081       (extent))
5082 {
5083         Lisp_Object face;
5084
5085         CHECK_EXTENT(extent);
5086         face = extent_face(XEXTENT(extent));
5087
5088         return external_of_internal_memoized_face(face);
5089 }
5090
5091 DEFUN("set-extent-face", Fset_extent_face, 2, 2, 0,     /*
5092 Make the given EXTENT have the graphic attributes specified by FACE.
5093 FACE can also be a list of faces, and all faces listed will apply,
5094 with faces earlier in the list taking priority over those later in the
5095 list.
5096 */
5097       (extent, face))
5098 {
5099         EXTENT e = decode_extent(extent, 0);
5100         Lisp_Object orig_face = face;
5101
5102         /* retrieve the ancestor for efficiency and proper redisplay noting. */
5103         e = extent_ancestor(e);
5104
5105         face = memoize_extent_face_internal(face);
5106
5107         extent_face(e) = face;
5108         extent_changed_for_redisplay(e, 1, 0);
5109
5110         return orig_face;
5111 }
5112
5113 DEFUN("extent-mouse-face", Fextent_mouse_face, 1, 1, 0, /*
5114 Return the face used to highlight EXTENT when the mouse passes over it.
5115 The return value will be a face name, a list of face names, or nil
5116 if the extent's mouse face is unspecified.
5117 */
5118       (extent))
5119 {
5120         Lisp_Object face;
5121
5122         CHECK_EXTENT(extent);
5123         face = extent_mouse_face(XEXTENT(extent));
5124
5125         return external_of_internal_memoized_face(face);
5126 }
5127
5128 DEFUN("set-extent-mouse-face", Fset_extent_mouse_face, 2, 2, 0, /*
5129 Set the face used to highlight EXTENT when the mouse passes over it.
5130 FACE can also be a list of faces, and all faces listed will apply,
5131 with faces earlier in the list taking priority over those later in the
5132 list.
5133 */
5134       (extent, face))
5135 {
5136         EXTENT e;
5137         Lisp_Object orig_face = face;
5138
5139         CHECK_EXTENT(extent);
5140         e = XEXTENT(extent);
5141         /* retrieve the ancestor for efficiency and proper redisplay noting. */
5142         e = extent_ancestor(e);
5143
5144         face = memoize_extent_face_internal(face);
5145
5146         set_extent_mouse_face(e, face);
5147         extent_changed_for_redisplay(e, 1, 0);
5148
5149         return orig_face;
5150 }
5151
5152 void
5153 set_extent_glyph(EXTENT extent, Lisp_Object glyph, int endp,
5154                  glyph_layout layout)
5155 {
5156         extent = extent_ancestor(extent);
5157
5158         if (!endp) {
5159                 set_extent_begin_glyph(extent, glyph);
5160                 extent_begin_glyph_layout(extent) = layout;
5161         } else {
5162                 set_extent_end_glyph(extent, glyph);
5163                 extent_end_glyph_layout(extent) = layout;
5164         }
5165
5166         extent_changed_for_redisplay(extent, 1, 0);
5167 }
5168
5169 static Lisp_Object glyph_layout_to_symbol(glyph_layout layout)
5170 {
5171         switch (layout) {
5172         case GL_TEXT:
5173                 return Qtext;
5174         case GL_OUTSIDE_MARGIN:
5175                 return Qoutside_margin;
5176         case GL_INSIDE_MARGIN:
5177                 return Qinside_margin;
5178         case GL_WHITESPACE:
5179                 return Qwhitespace;
5180         default:
5181                 abort();
5182                 return Qnil;    /* unreached */
5183         }
5184 }
5185
5186 static glyph_layout symbol_to_glyph_layout(Lisp_Object layout_obj)
5187 {
5188         if (NILP(layout_obj))
5189                 return GL_TEXT;
5190
5191         CHECK_SYMBOL(layout_obj);
5192         if (EQ(layout_obj, Qoutside_margin))
5193                 return GL_OUTSIDE_MARGIN;
5194         if (EQ(layout_obj, Qinside_margin))
5195                 return GL_INSIDE_MARGIN;
5196         if (EQ(layout_obj, Qwhitespace))
5197                 return GL_WHITESPACE;
5198         if (EQ(layout_obj, Qtext))
5199                 return GL_TEXT;
5200
5201         invalid_argument("Unknown glyph layout type", layout_obj);
5202         return GL_TEXT;         /* unreached */
5203 }
5204
5205 static Lisp_Object
5206 set_extent_glyph_1(Lisp_Object extent_obj, Lisp_Object glyph, int endp,
5207                    Lisp_Object layout_obj)
5208 {
5209         EXTENT extent = decode_extent(extent_obj, 0);
5210         glyph_layout layout = symbol_to_glyph_layout(layout_obj);
5211
5212         /* Make sure we've actually been given a valid glyph or it's nil
5213            (meaning we're deleting a glyph from an extent). */
5214         if (!NILP(glyph))
5215                 CHECK_BUFFER_GLYPH(glyph);
5216
5217         set_extent_glyph(extent, glyph, endp, layout);
5218         return glyph;
5219 }
5220
5221 DEFUN("set-extent-begin-glyph", Fset_extent_begin_glyph, 2, 3, 0,       /*
5222 Display a bitmap, subwindow or string at the beginning of EXTENT.
5223 BEGIN-GLYPH must be a glyph object.  The layout policy defaults to `text'.
5224 */
5225       (extent, begin_glyph, layout))
5226 {
5227         return set_extent_glyph_1(extent, begin_glyph, 0, layout);
5228 }
5229
5230 DEFUN("set-extent-end-glyph", Fset_extent_end_glyph, 2, 3, 0,   /*
5231 Display a bitmap, subwindow or string at the end of EXTENT.
5232 END-GLYPH must be a glyph object.  The layout policy defaults to `text'.
5233 */
5234       (extent, end_glyph, layout))
5235 {
5236         return set_extent_glyph_1(extent, end_glyph, 1, layout);
5237 }
5238
5239 DEFUN("extent-begin-glyph", Fextent_begin_glyph, 1, 1, 0,       /*
5240 Return the glyph object displayed at the beginning of EXTENT.
5241 If there is none, nil is returned.
5242 */
5243       (extent))
5244 {
5245         return extent_begin_glyph(decode_extent(extent, 0));
5246 }
5247
5248 DEFUN("extent-end-glyph", Fextent_end_glyph, 1, 1, 0,   /*
5249 Return the glyph object displayed at the end of EXTENT.
5250 If there is none, nil is returned.
5251 */
5252       (extent))
5253 {
5254         return extent_end_glyph(decode_extent(extent, 0));
5255 }
5256
5257 DEFUN("set-extent-begin-glyph-layout", Fset_extent_begin_glyph_layout, 2, 2, 0, /*
5258 Set the layout policy of EXTENT's begin glyph.
5259 Access this using the `extent-begin-glyph-layout' function.
5260 */
5261       (extent, layout))
5262 {
5263         EXTENT e = decode_extent(extent, 0);
5264         e = extent_ancestor(e);
5265         extent_begin_glyph_layout(e) = symbol_to_glyph_layout(layout);
5266         extent_maybe_changed_for_redisplay(e, 1, 0);
5267         return layout;
5268 }
5269
5270 DEFUN("set-extent-end-glyph-layout", Fset_extent_end_glyph_layout, 2, 2, 0,     /*
5271 Set the layout policy of EXTENT's end glyph.
5272 Access this using the `extent-end-glyph-layout' function.
5273 */
5274       (extent, layout))
5275 {
5276         EXTENT e = decode_extent(extent, 0);
5277         e = extent_ancestor(e);
5278         extent_end_glyph_layout(e) = symbol_to_glyph_layout(layout);
5279         extent_maybe_changed_for_redisplay(e, 1, 0);
5280         return layout;
5281 }
5282
5283 DEFUN("extent-begin-glyph-layout", Fextent_begin_glyph_layout, 1, 1, 0, /*
5284 Return the layout policy associated with EXTENT's begin glyph.
5285 Set this using the `set-extent-begin-glyph-layout' function.
5286 */
5287       (extent))
5288 {
5289         EXTENT e = decode_extent(extent, 0);
5290         return glyph_layout_to_symbol((glyph_layout)
5291                                       extent_begin_glyph_layout(e));
5292 }
5293
5294 DEFUN("extent-end-glyph-layout", Fextent_end_glyph_layout, 1, 1, 0,     /*
5295 Return the layout policy associated with EXTENT's end glyph.
5296 Set this using the `set-extent-end-glyph-layout' function.
5297 */
5298       (extent))
5299 {
5300         EXTENT e = decode_extent(extent, 0);
5301         return glyph_layout_to_symbol((glyph_layout)
5302                                       extent_end_glyph_layout(e));
5303 }
5304
5305 DEFUN("set-extent-priority", Fset_extent_priority, 2, 2, 0,     /*
5306 Set the display priority of EXTENT to PRIORITY (an integer).
5307 When the extent attributes are being merged for display, the priority
5308 is used to determine which extent takes precedence in the event of a
5309 conflict (two extents whose faces both specify font, for example: the
5310 font of the extent with the higher priority will be used).
5311 Extents are created with priority 0; priorities may be negative.
5312 */
5313       (extent, priority))
5314 {
5315         EXTENT e = decode_extent(extent, 0);
5316
5317         CHECK_INT(priority);
5318         e = extent_ancestor(e);
5319         set_extent_priority(e, XINT(priority));
5320         extent_maybe_changed_for_redisplay(e, 1, 0);
5321         return priority;
5322 }
5323
5324 DEFUN("extent-priority", Fextent_priority, 1, 1, 0,     /*
5325 Return the display priority of EXTENT; see `set-extent-priority'.
5326 */
5327       (extent))
5328 {
5329         EXTENT e = decode_extent(extent, 0);
5330         return make_int(extent_priority(e));
5331 }
5332
5333 DEFUN("set-extent-property", Fset_extent_property, 3, 3, 0,     /*
5334 Change a property of an extent.
5335 PROPERTY may be any symbol; the value stored may be accessed with
5336 the `extent-property' function.
5337 The following symbols have predefined meanings:
5338
5339 detached           Removes the extent from its buffer; setting this is
5340 the same as calling `detach-extent'.
5341
5342 destroyed          Removes the extent from its buffer, and makes it
5343 unusable in the future; this is the same calling
5344 `delete-extent'.
5345
5346 priority           Change redisplay priority; same as `set-extent-priority'.
5347
5348 start-open         Whether the set of characters within the extent is
5349 treated being open on the left, that is, whether
5350 the start position is an exclusive, rather than
5351 inclusive, boundary.  If true, then characters
5352 inserted exactly at the beginning of the extent
5353 will remain outside of the extent; otherwise they
5354 will go into the extent, extending it.
5355
5356 end-open           Whether the set of characters within the extent is
5357 treated being open on the right, that is, whether
5358 the end position is an exclusive, rather than
5359 inclusive, boundary.  If true, then characters
5360 inserted exactly at the end of the extent will
5361 remain outside of the extent; otherwise they will
5362 go into the extent, extending it.
5363
5364 By default, extents have the `end-open' but not the
5365 `start-open' property set.
5366
5367 read-only          Text within this extent will be unmodifiable.
5368
5369 initial-redisplay-function (EXPERIMENTAL)
5370 function to be called the first time (part of) the extent
5371 is redisplayed. It will be called with the extent as its
5372 first argument.
5373 Note: The function will not be called immediately
5374 during redisplay, an eval event will be dispatched.
5375
5376 detachable         Whether the extent gets detached (as with
5377 `detach-extent') when all the text within the
5378 extent is deleted.  This is true by default.  If
5379 this property is not set, the extent becomes a
5380 zero-length extent when its text is deleted. (In
5381 such a case, the `start-open' property is
5382 automatically removed if both the `start-open' and
5383 `end-open' properties are set, since zero-length
5384 extents open on both ends are not allowed.)
5385
5386 face               The face in which to display the text.  Setting
5387 this is the same as calling `set-extent-face'.
5388
5389 mouse-face          If non-nil, the extent will be highlighted in this
5390 face when the mouse moves over it.
5391
5392 pointer            If non-nil, and a valid pointer glyph, this specifies
5393 the shape of the mouse pointer while over the extent.
5394
5395 highlight          Obsolete: Setting this property is equivalent to
5396 setting a `mouse-face' property of `highlight'.
5397 Reading this property returns non-nil if
5398 the extent has a non-nil `mouse-face' property.
5399
5400 duplicable         Whether this extent should be copied into strings,
5401 so that kill, yank, and undo commands will restore
5402 or copy it.  `duplicable' extents are copied from
5403 an extent into a string when `buffer-substring' or
5404 a similar function creates a string.  The extents
5405 in a string are copied into other strings created
5406 from the string using `concat' or `substring'.
5407 When `insert' or a similar function inserts the
5408 string into a buffer, the extents are copied back
5409 into the buffer.
5410
5411 unique             Meaningful only in conjunction with `duplicable'.
5412 When this is set, there may be only one instance
5413 of this extent attached at a time: if it is copied
5414 to the kill ring and then yanked, the extent is
5415 not copied.  If, however, it is killed (removed
5416 from the buffer) and then yanked, it will be
5417 re-attached at the new position.
5418
5419 invisible          If the value is non-nil, text under this extent
5420 may be treated as not present for the purpose of
5421 redisplay, or may be displayed using an ellipsis
5422 or other marker; see `buffer-invisibility-spec'
5423 and `invisible-text-glyph'.  In all cases,
5424 however, the text is still visible to other
5425 functions that examine a buffer's text.
5426
5427 keymap             This keymap is consulted for mouse clicks on this
5428 extent, or keypresses made while point is within the
5429 extent.
5430
5431 copy-function      This is a hook that is run when a duplicable extent
5432 is about to be copied from a buffer to a string (or
5433 the kill ring).  It is called with three arguments,
5434 the extent, and the buffer-positions within it
5435 which are being copied.  If this function returns
5436 nil, then the extent will not be copied; otherwise
5437 it will.
5438
5439 paste-function     This is a hook that is run when a duplicable extent is
5440 about to be copied from a string (or the kill ring)
5441 into a buffer.  It is called with three arguments,
5442 the original extent, and the buffer positions which
5443 the copied extent will occupy.  (This hook is run
5444 after the corresponding text has already been
5445 inserted into the buffer.)  Note that the extent
5446 argument may be detached when this function is run.
5447 If this function returns nil, no extent will be
5448 inserted.  Otherwise, there will be an extent
5449 covering the range in question.
5450
5451 If the original extent is not attached to a buffer,
5452 then it will be re-attached at this range.
5453 Otherwise, a copy will be made, and that copy
5454 attached here.
5455
5456 The copy-function and paste-function are meaningful
5457 only for extents with the `duplicable' flag set,
5458 and if they are not specified, behave as if `t' was
5459 the returned value.  When these hooks are invoked,
5460 the current buffer is the buffer which the extent
5461 is being copied from/to, respectively.
5462
5463 begin-glyph        A glyph to be displayed at the beginning of the extent,
5464 or nil.
5465
5466 end-glyph          A glyph to be displayed at the end of the extent,
5467 or nil.
5468
5469 begin-glyph-layout The layout policy (one of `text', `whitespace',
5470 `inside-margin', or `outside-margin') of the extent's
5471 begin glyph.
5472
5473 end-glyph-layout   The layout policy of the extent's end glyph.
5474
5475 syntax-table       A cons or a syntax table object.  If a cons, the car must
5476 be an integer (interpreted as a syntax code, applicable to
5477 all characters in the extent).  Otherwise, syntax of
5478 characters in the extent is looked up in the syntax table.
5479 You should use the text property API to manipulate this
5480 property.  (This may be required in the future.)
5481 */
5482       (extent, property, value))
5483 {
5484         /* This function can GC if property is `keymap' */
5485         EXTENT e = decode_extent(extent, 0);
5486
5487         if (EQ(property, Qread_only))
5488                 set_extent_read_only(e, value);
5489         else if (EQ(property, Qunique))
5490                 extent_unique_p(e) = !NILP(value);
5491         else if (EQ(property, Qduplicable))
5492                 extent_duplicable_p(e) = !NILP(value);
5493         else if (EQ(property, Qinvisible))
5494                 set_extent_invisible(e, value);
5495         else if (EQ(property, Qdetachable))
5496                 extent_detachable_p(e) = !NILP(value);
5497
5498         else if (EQ(property, Qdetached)) {
5499                 if (NILP(value))
5500                         error("can only set `detached' to t");
5501                 Fdetach_extent(extent);
5502         } else if (EQ(property, Qdestroyed)) {
5503                 if (NILP(value))
5504                         error("can only set `destroyed' to t");
5505                 Fdelete_extent(extent);
5506         } else if (EQ(property, Qpriority))
5507                 Fset_extent_priority(extent, value);
5508         else if (EQ(property, Qface))
5509                 Fset_extent_face(extent, value);
5510         else if (EQ(property, Qinitial_redisplay_function))
5511                 Fset_extent_initial_redisplay_function(extent, value);
5512         else if (EQ(property, Qbefore_change_functions))
5513                 set_extent_before_change_functions(e, value);
5514         else if (EQ(property, Qafter_change_functions))
5515                 set_extent_after_change_functions(e, value);
5516         else if (EQ(property, Qmouse_face))
5517                 Fset_extent_mouse_face(extent, value);
5518         /* Obsolete: */
5519         else if (EQ(property, Qhighlight))
5520                 Fset_extent_mouse_face(extent, Qhighlight);
5521         else if (EQ(property, Qbegin_glyph_layout))
5522                 Fset_extent_begin_glyph_layout(extent, value);
5523         else if (EQ(property, Qend_glyph_layout))
5524                 Fset_extent_end_glyph_layout(extent, value);
5525         /* For backwards compatibility.  We use begin glyph because it is by
5526            far the more used of the two. */
5527         else if (EQ(property, Qglyph_layout))
5528                 Fset_extent_begin_glyph_layout(extent, value);
5529         else if (EQ(property, Qbegin_glyph))
5530                 Fset_extent_begin_glyph(extent, value, Qnil);
5531         else if (EQ(property, Qend_glyph))
5532                 Fset_extent_end_glyph(extent, value, Qnil);
5533         else if (EQ(property, Qstart_open))
5534                 set_extent_openness(e, !NILP(value), -1);
5535         else if (EQ(property, Qend_open))
5536                 set_extent_openness(e, -1, !NILP(value));
5537         /* Support (but don't document...) the obvious *_closed antonyms. */
5538         else if (EQ(property, Qstart_closed))
5539                 set_extent_openness(e, NILP(value), -1);
5540         else if (EQ(property, Qend_closed))
5541                 set_extent_openness(e, -1, NILP(value));
5542         else {
5543                 if (EQ(property, Qkeymap))
5544                         while (!NILP(value) && NILP(Fkeymapp(value)))
5545                                 value = wrong_type_argument(Qkeymapp, value);
5546
5547                 external_plist_put(extent_plist_addr(e), property, value, 0,
5548                                    ERROR_ME);
5549         }
5550
5551         return value;
5552 }
5553
5554 DEFUN("set-extent-properties", Fset_extent_properties, 2, 2, 0, /*
5555 Change some properties of EXTENT.
5556 PLIST is a property list.
5557 For a list of built-in properties, see `set-extent-property'.
5558 */
5559       (extent, plist))
5560 {
5561         /* This function can GC, if one of the properties is `keymap' */
5562         Lisp_Object property, value;
5563         struct gcpro gcpro1;
5564         GCPRO1(plist);
5565
5566         plist = Fcopy_sequence(plist);
5567         Fcanonicalize_plist(plist, Qnil);
5568
5569         while (!NILP(plist)) {
5570                 property = Fcar(plist);
5571                 plist = Fcdr(plist);
5572                 value = Fcar(plist);
5573                 plist = Fcdr(plist);
5574                 Fset_extent_property(extent, property, value);
5575         }
5576         UNGCPRO;
5577         return Qnil;
5578 }
5579
5580 DEFUN("extent-property", Fextent_property, 2, 3, 0,     /*
5581 Return EXTENT's value for property PROPERTY.
5582 If no such property exists, DEFAULT is returned.
5583 See `set-extent-property' for the built-in property names.
5584 */
5585       (extent, property, default_))
5586 {
5587         EXTENT e = decode_extent(extent, 0);
5588
5589         if (EQ(property, Qdetached))
5590                 return extent_detached_p(e) ? Qt : Qnil;
5591         else if (EQ(property, Qdestroyed))
5592                 return !EXTENT_LIVE_P(e) ? Qt : Qnil;
5593         else if (EQ(property, Qstart_open))
5594                 return extent_normal_field(e, start_open) ? Qt : Qnil;
5595         else if (EQ(property, Qend_open))
5596                 return extent_normal_field(e, end_open) ? Qt : Qnil;
5597         else if (EQ(property, Qunique))
5598                 return extent_normal_field(e, unique) ? Qt : Qnil;
5599         else if (EQ(property, Qduplicable))
5600                 return extent_normal_field(e, duplicable) ? Qt : Qnil;
5601         else if (EQ(property, Qdetachable))
5602                 return extent_normal_field(e, detachable) ? Qt : Qnil;
5603         /* Support (but don't document...) the obvious *_closed antonyms. */
5604         else if (EQ(property, Qstart_closed))
5605                 return extent_start_open_p(e) ? Qnil : Qt;
5606         else if (EQ(property, Qend_closed))
5607                 return extent_end_open_p(e) ? Qnil : Qt;
5608         else if (EQ(property, Qpriority))
5609                 return make_int(extent_priority(e));
5610         else if (EQ(property, Qread_only))
5611                 return extent_read_only(e);
5612         else if (EQ(property, Qinvisible))
5613                 return extent_invisible(e);
5614         else if (EQ(property, Qface))
5615                 return Fextent_face(extent);
5616         else if (EQ(property, Qinitial_redisplay_function))
5617                 return extent_initial_redisplay_function(e);
5618         else if (EQ(property, Qbefore_change_functions))
5619                 return extent_before_change_functions(e);
5620         else if (EQ(property, Qafter_change_functions))
5621                 return extent_after_change_functions(e);
5622         else if (EQ(property, Qmouse_face))
5623                 return Fextent_mouse_face(extent);
5624         /* Obsolete: */
5625         else if (EQ(property, Qhighlight))
5626                 return !NILP(Fextent_mouse_face(extent)) ? Qt : Qnil;
5627         else if (EQ(property, Qbegin_glyph_layout))
5628                 return Fextent_begin_glyph_layout(extent);
5629         else if (EQ(property, Qend_glyph_layout))
5630                 return Fextent_end_glyph_layout(extent);
5631         /* For backwards compatibility.  We use begin glyph because it is by
5632            far the more used of the two. */
5633         else if (EQ(property, Qglyph_layout))
5634                 return Fextent_begin_glyph_layout(extent);
5635         else if (EQ(property, Qbegin_glyph))
5636                 return extent_begin_glyph(e);
5637         else if (EQ(property, Qend_glyph))
5638                 return extent_end_glyph(e);
5639         else {
5640                 Lisp_Object value = external_plist_get(extent_plist_addr(e),
5641                                                        property, 0, ERROR_ME);
5642                 return UNBOUNDP(value) ? default_ : value;
5643         }
5644 }
5645
5646 DEFUN("extent-properties", Fextent_properties, 1, 1, 0, /*
5647 Return a property list of the attributes of EXTENT.
5648 Do not modify this list; use `set-extent-property' instead.
5649 */
5650       (extent))
5651 {
5652         EXTENT e, anc;
5653         Lisp_Object result, face, anc_obj;
5654         glyph_layout layout;
5655
5656         CHECK_EXTENT(extent);
5657         e = XEXTENT(extent);
5658         if (!EXTENT_LIVE_P(e))
5659                 return cons3(Qdestroyed, Qt, Qnil);
5660
5661         anc = extent_ancestor(e);
5662         XSETEXTENT(anc_obj, anc);
5663
5664         /* For efficiency, use the ancestor for all properties except detached */
5665
5666         result = extent_plist_slot(anc);
5667
5668         if (!NILP(face = Fextent_face(anc_obj)))
5669                 result = cons3(Qface, face, result);
5670
5671         if (!NILP(face = Fextent_mouse_face(anc_obj)))
5672                 result = cons3(Qmouse_face, face, result);
5673
5674         if ((layout = (glyph_layout) extent_begin_glyph_layout(anc)) != GL_TEXT) {
5675                 Lisp_Object sym = glyph_layout_to_symbol(layout);
5676                 result = cons3(Qglyph_layout, sym, result);     /* compatibility */
5677                 result = cons3(Qbegin_glyph_layout, sym, result);
5678         }
5679
5680         if ((layout = (glyph_layout) extent_end_glyph_layout(anc)) != GL_TEXT)
5681                 result =
5682                     cons3(Qend_glyph_layout, glyph_layout_to_symbol(layout),
5683                           result);
5684
5685         if (!NILP(extent_end_glyph(anc)))
5686                 result = cons3(Qend_glyph, extent_end_glyph(anc), result);
5687
5688         if (!NILP(extent_begin_glyph(anc)))
5689                 result = cons3(Qbegin_glyph, extent_begin_glyph(anc), result);
5690
5691         if (extent_priority(anc) != 0)
5692                 result =
5693                     cons3(Qpriority, make_int(extent_priority(anc)), result);
5694
5695         if (!NILP(extent_initial_redisplay_function(anc)))
5696                 result = cons3(Qinitial_redisplay_function,
5697                                extent_initial_redisplay_function(anc), result);
5698
5699         if (!NILP(extent_before_change_functions(anc)))
5700                 result = cons3(Qbefore_change_functions,
5701                                extent_before_change_functions(anc), result);
5702
5703         if (!NILP(extent_after_change_functions(anc)))
5704                 result = cons3(Qafter_change_functions,
5705                                extent_after_change_functions(anc), result);
5706
5707         if (!NILP(extent_invisible(anc)))
5708                 result = cons3(Qinvisible, extent_invisible(anc), result);
5709
5710         if (!NILP(extent_read_only(anc)))
5711                 result = cons3(Qread_only, extent_read_only(anc), result);
5712
5713         if (extent_normal_field(anc, end_open))
5714                 result = cons3(Qend_open, Qt, result);
5715
5716         if (extent_normal_field(anc, start_open))
5717                 result = cons3(Qstart_open, Qt, result);
5718
5719         if (extent_normal_field(anc, detachable))
5720                 result = cons3(Qdetachable, Qt, result);
5721
5722         if (extent_normal_field(anc, duplicable))
5723                 result = cons3(Qduplicable, Qt, result);
5724
5725         if (extent_normal_field(anc, unique))
5726                 result = cons3(Qunique, Qt, result);
5727
5728         /* detached is not an inherited property */
5729         if (extent_detached_p(e))
5730                 result = cons3(Qdetached, Qt, result);
5731
5732         return result;
5733 }
5734 \f
5735 /************************************************************************/
5736 /*                           highlighting                               */
5737 /************************************************************************/
5738
5739 /* The display code looks into the Vlast_highlighted_extent variable to
5740    correctly display highlighted extents.  This updates that variable,
5741    and marks the appropriate buffers as needing some redisplay.
5742  */
5743 static void do_highlight(Lisp_Object extent_obj, int highlight_p)
5744 {
5745         if ((highlight_p && (EQ(Vlast_highlighted_extent, extent_obj))) ||
5746             (!highlight_p && (EQ(Vlast_highlighted_extent, Qnil))))
5747                 return;
5748         if (EXTENTP(Vlast_highlighted_extent) &&
5749             EXTENT_LIVE_P(XEXTENT(Vlast_highlighted_extent))) {
5750                 /* do not recurse on descendants.  Only one extent is highlighted
5751                    at a time. */
5752                 extent_changed_for_redisplay(XEXTENT(Vlast_highlighted_extent),
5753                                              0, 0);
5754         }
5755         Vlast_highlighted_extent = Qnil;
5756         if (!NILP(extent_obj)
5757             && BUFFERP(extent_object(XEXTENT(extent_obj)))
5758             && highlight_p) {
5759                 extent_changed_for_redisplay(XEXTENT(extent_obj), 0, 0);
5760                 Vlast_highlighted_extent = extent_obj;
5761         }
5762 }
5763
5764 DEFUN("force-highlight-extent", Fforce_highlight_extent, 1, 2, 0,       /*
5765 Highlight or unhighlight the given extent.
5766 If the second arg is non-nil, it will be highlighted, else dehighlighted.
5767 This is the same as `highlight-extent', except that it will work even
5768 on extents without the `mouse-face' property.
5769 */
5770       (extent, highlight_p))
5771 {
5772         if (NILP(extent))
5773                 highlight_p = Qnil;
5774         else
5775                 XSETEXTENT(extent, decode_extent(extent, DE_MUST_BE_ATTACHED));
5776         do_highlight(extent, !NILP(highlight_p));
5777         return Qnil;
5778 }
5779
5780 DEFUN("highlight-extent", Fhighlight_extent, 1, 2, 0,   /*
5781 Highlight EXTENT, if it is highlightable.
5782 \(that is, if it has the `mouse-face' property).
5783 If the second arg is non-nil, it will be highlighted, else dehighlighted.
5784 Highlighted extents are displayed as if they were merged with the face
5785 or faces specified by the `mouse-face' property.
5786 */
5787       (extent, highlight_p))
5788 {
5789         if (EXTENTP(extent) && NILP(extent_mouse_face(XEXTENT(extent))))
5790                 return Qnil;
5791         else
5792                 return Fforce_highlight_extent(extent, highlight_p);
5793 }
5794 \f
5795 /************************************************************************/
5796 /*                         strings and extents                          */
5797 /************************************************************************/
5798
5799 /* copy/paste hooks */
5800
5801 static int
5802 run_extent_copy_paste_internal(EXTENT e, Bufpos from, Bufpos to,
5803                                Lisp_Object object, Lisp_Object prop)
5804 {
5805         /* This function can GC */
5806         Lisp_Object extent;
5807         Lisp_Object copy_fn;
5808         XSETEXTENT(extent, e);
5809         copy_fn = Fextent_property(extent, prop, Qnil);
5810         if (!NILP(copy_fn)) {
5811                 Lisp_Object flag;
5812                 struct gcpro gcpro1, gcpro2, gcpro3;
5813                 GCPRO3(extent, copy_fn, object);
5814                 if (BUFFERP(object))
5815                         flag = call3_in_buffer(XBUFFER(object), copy_fn, extent,
5816                                                make_int(from), make_int(to));
5817                 else
5818                         flag =
5819                             call3(copy_fn, extent, make_int(from),
5820                                   make_int(to));
5821                 UNGCPRO;
5822                 if (NILP(flag) || !EXTENT_LIVE_P(XEXTENT(extent)))
5823                         return 0;
5824         }
5825         return 1;
5826 }
5827
5828 static int run_extent_copy_function(EXTENT e, Bytind from, Bytind to)
5829 {
5830         Lisp_Object object = extent_object(e);
5831         /* This function can GC */
5832         return run_extent_copy_paste_internal
5833             (e, buffer_or_string_bytind_to_bufpos(object, from),
5834              buffer_or_string_bytind_to_bufpos(object, to), object,
5835              Qcopy_function);
5836 }
5837
5838 static int
5839 run_extent_paste_function(EXTENT e, Bytind from, Bytind to, Lisp_Object object)
5840 {
5841         /* This function can GC */
5842         return run_extent_copy_paste_internal
5843             (e, buffer_or_string_bytind_to_bufpos(object, from),
5844              buffer_or_string_bytind_to_bufpos(object, to), object,
5845              Qpaste_function);
5846 }
5847
5848 static void update_extent(EXTENT extent, Bytind from, Bytind to)
5849 {
5850         set_extent_endpoints(extent, from, to, Qnil);
5851 }
5852
5853 /* Insert an extent, usually from the dup_list of a string which
5854    has just been inserted.
5855    This code does not handle the case of undo.
5856    */
5857 static Lisp_Object
5858 insert_extent(EXTENT extent, Bytind new_start, Bytind new_end,
5859               Lisp_Object object, int run_hooks)
5860 {
5861         /* This function can GC */
5862         Lisp_Object tmp;
5863
5864         if (!EQ(extent_object(extent), object))
5865                 goto copy_it;
5866
5867         if (extent_detached_p(extent)) {
5868                 if (run_hooks &&
5869                     !run_extent_paste_function(extent, new_start, new_end,
5870                                                object))
5871                         /* The paste-function said don't re-attach this extent here. */
5872                         return Qnil;
5873                 else
5874                         update_extent(extent, new_start, new_end);
5875         } else {
5876                 Bytind exstart = extent_endpoint_bytind(extent, 0);
5877                 Bytind exend = extent_endpoint_bytind(extent, 1);
5878
5879                 if (exend < new_start || exstart > new_end)
5880                         goto copy_it;
5881                 else {
5882                         new_start = min(exstart, new_start);
5883                         new_end = max(exend, new_end);
5884                         if (exstart != new_start || exend != new_end)
5885                                 update_extent(extent, new_start, new_end);
5886                 }
5887         }
5888
5889         XSETEXTENT(tmp, extent);
5890         return tmp;
5891
5892       copy_it:
5893         if (run_hooks &&
5894             !run_extent_paste_function(extent, new_start, new_end, object))
5895                 /* The paste-function said don't attach a copy of the extent here. */
5896                 return Qnil;
5897         else {
5898                 XSETEXTENT(tmp,
5899                            copy_extent(extent, new_start, new_end, object));
5900                 return tmp;
5901         }
5902 }
5903
5904 DEFUN("insert-extent", Finsert_extent, 1, 5, 0, /*
5905 Insert EXTENT from START to END in BUFFER-OR-STRING.
5906 BUFFER-OR-STRING defaults to the current buffer if omitted.
5907 This operation does not insert any characters,
5908 but otherwise acts as if there were a replicating extent whose
5909 parent is EXTENT in some string that was just inserted.
5910 Returns the newly-inserted extent.
5911 The fourth arg, NO-HOOKS, can be used to inhibit the running of the
5912 extent's `paste-function' property if it has one.
5913 See documentation on `detach-extent' for a discussion of undo recording.
5914 */
5915       (extent, start, end, no_hooks, buffer_or_string))
5916 {
5917         EXTENT ext = decode_extent(extent, 0);
5918         Lisp_Object copy;
5919         Bytind s, e;
5920
5921         buffer_or_string = decode_buffer_or_string(buffer_or_string);
5922         get_buffer_or_string_range_byte(buffer_or_string, start, end, &s, &e,
5923                                         GB_ALLOW_PAST_ACCESSIBLE);
5924
5925         copy = insert_extent(ext, s, e, buffer_or_string, NILP(no_hooks));
5926         if (EXTENTP(copy)) {
5927                 if (extent_duplicable_p(XEXTENT(copy)))
5928                         record_extent(copy, 1);
5929         }
5930         return copy;
5931 }
5932 \f
5933 /* adding buffer extents to a string */
5934
5935 struct add_string_extents_arg {
5936         Bytind from;
5937         Bytecount length;
5938         Lisp_Object string;
5939 };
5940
5941 static int add_string_extents_mapper(EXTENT extent, void *arg)
5942 {
5943         /* This function can GC */
5944         struct add_string_extents_arg *closure =
5945             (struct add_string_extents_arg *)arg;
5946         Bytecount start = extent_endpoint_bytind(extent, 0) - closure->from;
5947         Bytecount end = extent_endpoint_bytind(extent, 1) - closure->from;
5948
5949         if (extent_duplicable_p(extent)) {
5950                 start = max(start, 0);
5951                 end = min(end, closure->length);
5952
5953                 /* Run the copy-function to give an extent the option of
5954                    not being copied into the string (or kill ring).
5955                  */
5956                 if (extent_duplicable_p(extent) &&
5957                     !run_extent_copy_function(extent, start + closure->from,
5958                                               end + closure->from))
5959                         return 0;
5960                 copy_extent(extent, start, end, closure->string);
5961         }
5962
5963         return 0;
5964 }
5965
5966 /* Add the extents in buffer BUF from OPOINT to OPOINT+LENGTH to
5967    the string STRING. */
5968 void
5969 add_string_extents(Lisp_Object string, struct buffer *buf, Bytind opoint,
5970                    Bytecount length)
5971 {
5972         /* This function can GC */
5973         struct add_string_extents_arg closure;
5974         struct gcpro gcpro1, gcpro2;
5975         Lisp_Object buffer;
5976
5977         closure.from = opoint;
5978         closure.length = length;
5979         closure.string = string;
5980         buffer = make_buffer(buf);
5981         GCPRO2(buffer, string);
5982         map_extents_bytind(opoint, opoint + length, add_string_extents_mapper,
5983                            (void *)&closure, buffer, 0,
5984                            /* ignore extents that just abut the region */
5985                            ME_END_CLOSED | ME_ALL_EXTENTS_OPEN |
5986                            /* we are calling E-Lisp (the extent's copy function)
5987                               so anything might happen */
5988                            ME_MIGHT_CALL_ELISP);
5989         UNGCPRO;
5990 }
5991
5992 struct splice_in_string_extents_arg {
5993         Bytecount pos;
5994         Bytecount length;
5995         Bytind opoint;
5996         Lisp_Object buffer;
5997 };
5998
5999 static int splice_in_string_extents_mapper(EXTENT extent, void *arg)
6000 {
6001         /* This function can GC */
6002         struct splice_in_string_extents_arg *closure =
6003             (struct splice_in_string_extents_arg *)arg;
6004         /* BASE_START and BASE_END are the limits in the buffer of the string
6005            that was just inserted.
6006
6007            NEW_START and NEW_END are the prospective buffer positions of the
6008            extent that is going into the buffer. */
6009         Bytind base_start = closure->opoint;
6010         Bytind base_end = base_start + closure->length;
6011         Bytind new_start = (base_start + extent_endpoint_bytind(extent, 0) -
6012                             closure->pos);
6013         Bytind new_end = (base_start + extent_endpoint_bytind(extent, 1) -
6014                           closure->pos);
6015
6016         if (new_start < base_start)
6017                 new_start = base_start;
6018         if (new_end > base_end)
6019                 new_end = base_end;
6020         if (new_end <= new_start)
6021                 return 0;
6022
6023         if (!extent_duplicable_p(extent))
6024                 return 0;
6025
6026         if (!inside_undo &&
6027             !run_extent_paste_function(extent, new_start, new_end,
6028                                        closure->buffer))
6029                 return 0;
6030         copy_extent(extent, new_start, new_end, closure->buffer);
6031
6032         return 0;
6033 }
6034
6035 /* We have just inserted a section of STRING (starting at POS, of
6036    length LENGTH) into buffer BUF at OPOINT.  Do whatever is necessary
6037    to get the string's extents into the buffer. */
6038
6039 void
6040 splice_in_string_extents(Lisp_Object string, struct buffer *buf,
6041                          Bytind opoint, Bytecount length, Bytecount pos)
6042 {
6043         struct splice_in_string_extents_arg closure;
6044         struct gcpro gcpro1, gcpro2;
6045         Lisp_Object buffer;
6046
6047         buffer = make_buffer(buf);
6048         closure.opoint = opoint;
6049         closure.pos = pos;
6050         closure.length = length;
6051         closure.buffer = buffer;
6052         GCPRO2(buffer, string);
6053         map_extents_bytind(pos, pos + length,
6054                            splice_in_string_extents_mapper,
6055                            (void *)&closure, string, 0,
6056                            /* ignore extents that just abut the region */
6057                            ME_END_CLOSED | ME_ALL_EXTENTS_OPEN |
6058                            /* we are calling E-Lisp (the extent's copy function)
6059                               so anything might happen */
6060                            ME_MIGHT_CALL_ELISP);
6061         UNGCPRO;
6062 }
6063
6064 struct copy_string_extents_arg {
6065         Bytecount new_pos;
6066         Bytecount old_pos;
6067         Bytecount length;
6068         Lisp_Object new_string;
6069 };
6070
6071 struct copy_string_extents_1_arg {
6072         Lisp_Object parent_in_question;
6073         EXTENT found_extent;
6074 };
6075
6076 static int copy_string_extents_mapper(EXTENT extent, void *arg)
6077 {
6078         struct copy_string_extents_arg *closure =
6079             (struct copy_string_extents_arg *)arg;
6080         Bytecount old_start, old_end, new_start, new_end;
6081
6082         old_start = extent_endpoint_bytind(extent, 0);
6083         old_end = extent_endpoint_bytind(extent, 1);
6084
6085         old_start = max(closure->old_pos, old_start);
6086         old_end = min(closure->old_pos + closure->length, old_end);
6087
6088         if (old_start >= old_end)
6089                 return 0;
6090
6091         new_start = old_start + closure->new_pos - closure->old_pos;
6092         new_end = old_end + closure->new_pos - closure->old_pos;
6093
6094         copy_extent(extent, new_start, new_end, closure->new_string);
6095         return 0;
6096 }
6097
6098 /* The string NEW_STRING was partially constructed from OLD_STRING.
6099    In particular, the section of length LEN starting at NEW_POS in
6100    NEW_STRING came from the section of the same length starting at
6101    OLD_POS in OLD_STRING.  Copy the extents as appropriate. */
6102
6103 void
6104 copy_string_extents(Lisp_Object new_string, Lisp_Object old_string,
6105                     Bytecount new_pos, Bytecount old_pos, Bytecount length)
6106 {
6107         struct copy_string_extents_arg closure;
6108         struct gcpro gcpro1, gcpro2;
6109
6110         closure.new_pos = new_pos;
6111         closure.old_pos = old_pos;
6112         closure.new_string = new_string;
6113         closure.length = length;
6114         GCPRO2(new_string, old_string);
6115         map_extents_bytind(old_pos, old_pos + length,
6116                            copy_string_extents_mapper,
6117                            (void *)&closure, old_string, 0,
6118                            /* ignore extents that just abut the region */
6119                            ME_END_CLOSED | ME_ALL_EXTENTS_OPEN |
6120                            /* we are calling E-Lisp (the extent's copy function)
6121                               so anything might happen */
6122                            ME_MIGHT_CALL_ELISP);
6123         UNGCPRO;
6124 }
6125
6126 /* Checklist for sanity checking:
6127    - {kill, yank, copy} at {open, closed} {start, end} of {writable, read-only} extent
6128    - {kill, copy} & yank {once, repeatedly} duplicable extent in {same, different} buffer
6129  */
6130 \f
6131 /************************************************************************/
6132 /*                              text properties                         */
6133 /************************************************************************/
6134
6135 /* Text properties
6136    Originally this stuff was implemented in lisp (all of the functionality
6137    exists to make that possible) but speed was a problem.
6138  */
6139
6140 Lisp_Object Qtext_prop;
6141 Lisp_Object Qtext_prop_extent_paste_function;
6142
6143 static Lisp_Object
6144 get_text_property_bytind(Bytind position, Lisp_Object prop,
6145                          Lisp_Object object, enum extent_at_flag fl,
6146                          int text_props_only)
6147 {
6148         Lisp_Object extent;
6149
6150         /* text_props_only specifies whether we only consider text-property
6151            extents (those with the 'text-prop property set) or all extents. */
6152         if (!text_props_only)
6153                 extent = extent_at_bytind(position, object, prop, 0, fl, 0);
6154         else {
6155                 EXTENT prior = 0;
6156                 while (1) {
6157                         extent =
6158                             extent_at_bytind(position, object, Qtext_prop,
6159                                              prior, fl, 0);
6160                         if (NILP(extent))
6161                                 return Qnil;
6162                         if (EQ
6163                             (prop, Fextent_property(extent, Qtext_prop, Qnil)))
6164                                 break;
6165                         prior = XEXTENT(extent);
6166                 }
6167         }
6168
6169         if (!NILP(extent))
6170                 return Fextent_property(extent, prop, Qnil);
6171         if (!NILP(Vdefault_text_properties))
6172                 return Fplist_get(Vdefault_text_properties, prop, Qnil);
6173         return Qnil;
6174 }
6175
6176 static Lisp_Object
6177 get_text_property_1(Lisp_Object pos, Lisp_Object prop, Lisp_Object object,
6178                     Lisp_Object at_flag, int text_props_only)
6179 {
6180         Bytind position;
6181         int invert = 0;
6182
6183         object = decode_buffer_or_string(object);
6184         position =
6185             get_buffer_or_string_pos_byte(object, pos, GB_NO_ERROR_IF_BAD);
6186
6187         /* We canonicalize the start/end-open/closed properties to the
6188            non-default version -- "adding" the default property really
6189            needs to remove the non-default one.  See below for more
6190            on this. */
6191         if (EQ(prop, Qstart_closed)) {
6192                 prop = Qstart_open;
6193                 invert = 1;
6194         }
6195
6196         if (EQ(prop, Qend_open)) {
6197                 prop = Qend_closed;
6198                 invert = 1;
6199         }
6200
6201         {
6202                 Lisp_Object val =
6203                     get_text_property_bytind(position, prop, object,
6204                                              decode_extent_at_flag(at_flag),
6205                                              text_props_only);
6206                 if (invert)
6207                         val = NILP(val) ? Qt : Qnil;
6208                 return val;
6209         }
6210 }
6211
6212 DEFUN("get-text-property", Fget_text_property, 2, 4, 0, /*
6213 Return the value of the PROP property at the given position.
6214 Optional arg OBJECT specifies the buffer or string to look in, and
6215 defaults to the current buffer.
6216 Optional arg AT-FLAG controls what it means for a property to be "at"
6217 a position, and has the same meaning as in `extent-at'.
6218 This examines only those properties added with `put-text-property'.
6219 See also `get-char-property'.
6220 */
6221       (pos, prop, object, at_flag))
6222 {
6223         return get_text_property_1(pos, prop, object, at_flag, 1);
6224 }
6225
6226 DEFUN("get-char-property", Fget_char_property, 2, 4, 0, /*
6227 Return the value of the PROP property at the given position.
6228 Optional arg OBJECT specifies the buffer or string to look in, and
6229 defaults to the current buffer.
6230 Optional arg AT-FLAG controls what it means for a property to be "at"
6231 a position, and has the same meaning as in `extent-at'.
6232 This examines properties on all extents.
6233 See also `get-text-property'.
6234 */
6235       (pos, prop, object, at_flag))
6236 {
6237         return get_text_property_1(pos, prop, object, at_flag, 0);
6238 }
6239
6240 /* About start/end-open/closed:
6241
6242    These properties have to be handled specially because of their
6243    strange behavior.  If I put the "start-open" property on a region,
6244    then *all* text-property extents in the region have to have their
6245    start be open.  This is unlike all other properties, which don't
6246    affect the extents of text properties other than their own.
6247
6248    So:
6249
6250    1) We have to map start-closed to (not start-open) and end-open
6251       to (not end-closed) -- i.e. adding the default is really the
6252       same as remove the non-default property.  It won't work, for
6253       example, to have both "start-open" and "start-closed" on
6254       the same region.
6255    2) Whenever we add one of these properties, we go through all
6256       text-property extents in the region and set the appropriate
6257       open/closedness on them.
6258    3) Whenever we change a text-property extent for a property,
6259       we have to make sure we set the open/closedness properly.
6260
6261       (2) and (3) together rely on, and maintain, the invariant
6262       that the open/closedness of text-property extents is correct
6263       at the beginning and end of each operation.
6264    */
6265
6266 struct put_text_prop_arg {
6267         Lisp_Object prop, value;        /* The property and value we are storing */
6268         Bytind start, end;      /* The region into which we are storing it */
6269         Lisp_Object object;
6270         Lisp_Object the_extent; /* Our chosen extent; this is used for
6271                                    communication between subsequent passes. */
6272         int changed_p;          /* Output: whether we have modified anything */
6273 };
6274
6275 static int put_text_prop_mapper(EXTENT e, void *arg)
6276 {
6277         struct put_text_prop_arg *closure = (struct put_text_prop_arg *)arg;
6278
6279         Lisp_Object object = closure->object;
6280         Lisp_Object value = closure->value;
6281         Bytind e_start, e_end;
6282         Bytind start = closure->start;
6283         Bytind end = closure->end;
6284         Lisp_Object extent, e_val;
6285         int is_eq;
6286
6287         XSETEXTENT(extent, e);
6288
6289         /* Note: in some cases when the property itself is 'start-open
6290            or 'end-closed, the checks to set the openness may do a bit
6291            of extra work; but it won't hurt because we then fix up the
6292            openness later on in put_text_prop_openness_mapper(). */
6293         if (!EQ(Fextent_property(extent, Qtext_prop, Qnil), closure->prop))
6294                 /* It's not for this property; do nothing. */
6295                 return 0;
6296
6297         e_start = extent_endpoint_bytind(e, 0);
6298         e_end = extent_endpoint_bytind(e, 1);
6299         e_val = Fextent_property(extent, closure->prop, Qnil);
6300         is_eq = EQ(value, e_val);
6301
6302         if (!NILP(value) && NILP(closure->the_extent) && is_eq) {
6303                 /* We want there to be an extent here at the end, and we haven't picked
6304                    one yet, so use this one.  Extend it as necessary.  We only reuse an
6305                    extent which has an EQ value for the prop in question to avoid
6306                    side-effecting the kill ring (that is, we never change the property
6307                    on an extent after it has been created.)
6308                  */
6309                 if (e_start != start || e_end != end) {
6310                         Bytind new_start = min(e_start, start);
6311                         Bytind new_end = max(e_end, end);
6312                         set_extent_endpoints(e, new_start, new_end, Qnil);
6313                         /* If we changed the endpoint, then we need to set its
6314                            openness. */
6315                         set_extent_openness(e, new_start != e_start
6316                                             ? !NILP(get_text_property_bytind
6317                                                     (start, Qstart_open, object,
6318                                                      EXTENT_AT_AFTER, 1)) : -1,
6319                                             new_end != e_end
6320                                             ? NILP(get_text_property_bytind
6321                                                    (end - 1, Qend_closed,
6322                                                     object, EXTENT_AT_AFTER, 1))
6323                                             : -1);
6324                         closure->changed_p = 1;
6325                 }
6326                 closure->the_extent = extent;
6327         }
6328
6329         /* Even if we're adding a prop, at this point, we want all other extents of
6330            this prop to go away (as now they overlap).  So the theory here is that,
6331            when we are adding a prop to a region that has multiple (disjoint)
6332            occurrences of that prop in it already, we pick one of those and extend
6333            it, and remove the others.
6334          */
6335
6336         else if (EQ(extent, closure->the_extent)) {
6337                 /* just in case map-extents hits it again (does that happen?) */
6338                 ;
6339         } else if (e_start >= start && e_end <= end) {
6340                 /* Extent is contained in region; remove it.  Don't destroy or modify
6341                    it, because we don't want to change the attributes pointed to by the
6342                    duplicates in the kill ring.
6343                  */
6344                 extent_detach(e);
6345                 closure->changed_p = 1;
6346         } else if (!NILP(closure->the_extent) &&
6347                    is_eq && e_start <= end && e_end >= start) {
6348                 EXTENT te = XEXTENT(closure->the_extent);
6349                 /* This extent overlaps, and has the same prop/value as the extent we've
6350                    decided to reuse, so we can remove this existing extent as well (the
6351                    whole thing, even the part outside of the region) and extend
6352                    the-extent to cover it, resulting in the minimum number of extents in
6353                    the buffer.
6354                  */
6355                 Bytind the_start = extent_endpoint_bytind(te, 0);
6356                 Bytind the_end = extent_endpoint_bytind(te, 1);
6357                 if (e_start != the_start &&     /* note AND not OR -- hmm, why is this
6358                                                    the case? I think it's because the
6359                                                    assumption that the text-property
6360                                                    extents don't overlap makes it
6361                                                    OK; changing it to an OR would
6362                                                    result in changed_p sometimes getting
6363                                                    falsely marked.  Is this bad? */
6364                     e_end != the_end) {
6365                         Bytind new_start = min(e_start, the_start);
6366                         Bytind new_end = max(e_end, the_end);
6367                         set_extent_endpoints(te, new_start, new_end, Qnil);
6368                         /* If we changed the endpoint, then we need to set its
6369                            openness.  We are setting the endpoint to be the same as
6370                            that of the extent we're about to remove, and we assume
6371                            (the invariant mentioned above) that extent has the
6372                            proper endpoint setting, so we just use it. */
6373                         set_extent_openness(te, new_start != e_start ?
6374                                             (int)extent_start_open_p(e) : -1,
6375                                             new_end != e_end ?
6376                                             (int)extent_end_open_p(e) : -1);
6377                         closure->changed_p = 1;
6378                 }
6379                 extent_detach(e);
6380         } else if (e_end <= end) {
6381                 /* Extent begins before start but ends before end, so we can just
6382                    decrease its end position.
6383                  */
6384                 if (e_end != start) {
6385                         set_extent_endpoints(e, e_start, start, Qnil);
6386                         set_extent_openness(e, -1, NILP(get_text_property_bytind
6387                                                         (start - 1, Qend_closed,
6388                                                          object,
6389                                                          EXTENT_AT_AFTER, 1)));
6390                         closure->changed_p = 1;
6391                 }
6392         } else if (e_start >= start) {
6393                 /* Extent ends after end but begins after start, so we can just
6394                    increase its start position.
6395                  */
6396                 if (e_start != end) {
6397                         set_extent_endpoints(e, end, e_end, Qnil);
6398                         set_extent_openness(e, !NILP(get_text_property_bytind
6399                                                      (end, Qstart_open, object,
6400                                                       EXTENT_AT_AFTER, 1)), -1);
6401                         closure->changed_p = 1;
6402                 }
6403         } else {
6404                 /* Otherwise, `extent' straddles the region.  We need to split it.
6405                  */
6406                 set_extent_endpoints(e, e_start, start, Qnil);
6407                 set_extent_openness(e, -1, NILP(get_text_property_bytind
6408                                                 (start - 1, Qend_closed, object,
6409                                                  EXTENT_AT_AFTER, 1)));
6410                 set_extent_openness(copy_extent
6411                                     (e, end, e_end, extent_object(e)),
6412                                     !NILP(get_text_property_bytind
6413                                           (end, Qstart_open, object,
6414                                            EXTENT_AT_AFTER, 1)), -1);
6415                 closure->changed_p = 1;
6416         }
6417
6418         return 0;               /* to continue mapping. */
6419 }
6420
6421 static int put_text_prop_openness_mapper(EXTENT e, void *arg)
6422 {
6423         struct put_text_prop_arg *closure = (struct put_text_prop_arg *)arg;
6424         Bytind e_start, e_end;
6425         Bytind start = closure->start;
6426         Bytind end = closure->end;
6427         Lisp_Object extent;
6428         XSETEXTENT(extent, e);
6429         e_start = extent_endpoint_bytind(e, 0);
6430         e_end = extent_endpoint_bytind(e, 1);
6431
6432         if (NILP(Fextent_property(extent, Qtext_prop, Qnil))) {
6433                 /* It's not a text-property extent; do nothing. */
6434                 ;
6435         }
6436         /* Note end conditions and NILP/!NILP's carefully. */
6437         else if (EQ(closure->prop, Qstart_open)
6438                  && e_start >= start && e_start < end)
6439                 set_extent_openness(e, !NILP(closure->value), -1);
6440         else if (EQ(closure->prop, Qend_closed)
6441                  && e_end > start && e_end <= end)
6442                 set_extent_openness(e, -1, NILP(closure->value));
6443
6444         return 0;               /* to continue mapping. */
6445 }
6446
6447 static int
6448 put_text_prop(Bytind start, Bytind end, Lisp_Object object,
6449               Lisp_Object prop, Lisp_Object value, int duplicable_p)
6450 {
6451         /* This function can GC */
6452         struct put_text_prop_arg closure;
6453
6454         if (start == end)       /* There are no characters in the region. */
6455                 return 0;
6456
6457         /* convert to the non-default versions, since a nil property is
6458            the same as it not being present. */
6459         if (EQ(prop, Qstart_closed)) {
6460                 prop = Qstart_open;
6461                 value = NILP(value) ? Qt : Qnil;
6462         } else if (EQ(prop, Qend_open)) {
6463                 prop = Qend_closed;
6464                 value = NILP(value) ? Qt : Qnil;
6465         }
6466
6467         value = canonicalize_extent_property(prop, value);
6468
6469         closure.prop = prop;
6470         closure.value = value;
6471         closure.start = start;
6472         closure.end = end;
6473         closure.object = object;
6474         closure.changed_p = 0;
6475         closure.the_extent = Qnil;
6476
6477         map_extents_bytind(start, end,
6478                            put_text_prop_mapper, (void *)&closure, object, 0,
6479                            /* get all extents that abut the region */
6480                            ME_ALL_EXTENTS_CLOSED | ME_END_CLOSED |
6481                            /* it might QUIT or error if the user has
6482                               fucked with the extent plist. */
6483                            /* #### dmoore - I think this should include
6484                               ME_MIGHT_MOVE_SOE, since the callback function
6485                               might recurse back into map_extents_bytind. */
6486                            ME_MIGHT_THROW | ME_MIGHT_MODIFY_EXTENTS);
6487
6488         /* If we made it through the loop without reusing an extent
6489            (and we want there to be one) make it now.
6490          */
6491         if (!NILP(value) && NILP(closure.the_extent)) {
6492                 Lisp_Object extent;
6493
6494                 XSETEXTENT(extent, make_extent_internal(object, start, end));
6495                 closure.changed_p = 1;
6496                 Fset_extent_property(extent, Qtext_prop, prop);
6497                 Fset_extent_property(extent, prop, value);
6498                 if (duplicable_p) {
6499                         extent_duplicable_p(XEXTENT(extent)) = 1;
6500                         Fset_extent_property(extent, Qpaste_function,
6501                                              Qtext_prop_extent_paste_function);
6502                 }
6503                 set_extent_openness(XEXTENT(extent),
6504                                     !NILP(get_text_property_bytind
6505                                           (start, Qstart_open, object,
6506                                            EXTENT_AT_AFTER, 1)),
6507                                     NILP(get_text_property_bytind
6508                                          (end - 1, Qend_closed, object,
6509                                           EXTENT_AT_AFTER, 1)));
6510         }
6511
6512         if (EQ(prop, Qstart_open) || EQ(prop, Qend_closed)) {
6513                 map_extents_bytind(start, end,
6514                                    put_text_prop_openness_mapper,
6515                                    (void *)&closure, object, 0,
6516                                    /* get all extents that abut the region */
6517                                    ME_ALL_EXTENTS_CLOSED | ME_END_CLOSED |
6518                                    ME_MIGHT_MODIFY_EXTENTS);
6519         }
6520
6521         return closure.changed_p;
6522 }
6523
6524 DEFUN("put-text-property", Fput_text_property, 4, 5, 0, /*
6525 Adds the given property/value to all characters in the specified region.
6526 The property is conceptually attached to the characters rather than the
6527 region.  The properties are copied when the characters are copied/pasted.
6528 Fifth argument OBJECT is the buffer or string containing the text, and
6529 defaults to the current buffer.
6530 */
6531       (start, end, prop, value, object))
6532 {
6533         /* This function can GC */
6534         Bytind s, e;
6535
6536         object = decode_buffer_or_string(object);
6537         get_buffer_or_string_range_byte(object, start, end, &s, &e, 0);
6538         put_text_prop(s, e, object, prop, value, 1);
6539         return prop;
6540 }
6541
6542 DEFUN("put-nonduplicable-text-property", Fput_nonduplicable_text_property, 4, 5, 0,     /*
6543 Adds the given property/value to all characters in the specified region.
6544 The property is conceptually attached to the characters rather than the
6545 region, however the properties will not be copied when the characters
6546 are copied.
6547 Fifth argument OBJECT is the buffer or string containing the text, and
6548 defaults to the current buffer.
6549 */
6550       (start, end, prop, value, object))
6551 {
6552         /* This function can GC */
6553         Bytind s, e;
6554
6555         object = decode_buffer_or_string(object);
6556         get_buffer_or_string_range_byte(object, start, end, &s, &e, 0);
6557         put_text_prop(s, e, object, prop, value, 0);
6558         return prop;
6559 }
6560
6561 DEFUN("add-text-properties", Fadd_text_properties, 3, 4, 0,     /*
6562 Add properties to the characters from START to END.
6563 The third argument PROPS is a property list specifying the property values
6564 to add.  The optional fourth argument, OBJECT, is the buffer or string
6565 containing the text and defaults to the current buffer.  Returns t if
6566 any property was changed, nil otherwise.
6567 */
6568       (start, end, props, object))
6569 {
6570         /* This function can GC */
6571         int changed = 0;
6572         Bytind s, e;
6573
6574         object = decode_buffer_or_string(object);
6575         get_buffer_or_string_range_byte(object, start, end, &s, &e, 0);
6576         CHECK_LIST(props);
6577         for (; !NILP(props); props = Fcdr(Fcdr(props))) {
6578                 Lisp_Object prop = XCAR(props);
6579                 Lisp_Object value = Fcar(XCDR(props));
6580                 changed |= put_text_prop(s, e, object, prop, value, 1);
6581         }
6582         return changed ? Qt : Qnil;
6583 }
6584
6585 DEFUN("add-nonduplicable-text-properties", Fadd_nonduplicable_text_properties, 3, 4, 0, /*
6586 Add nonduplicable properties to the characters from START to END.
6587 \(The properties will not be copied when the characters are copied.)
6588 The third argument PROPS is a property list specifying the property values
6589 to add.  The optional fourth argument, OBJECT, is the buffer or string
6590 containing the text and defaults to the current buffer.  Returns t if
6591 any property was changed, nil otherwise.
6592 */
6593       (start, end, props, object))
6594 {
6595         /* This function can GC */
6596         int changed = 0;
6597         Bytind s, e;
6598
6599         object = decode_buffer_or_string(object);
6600         get_buffer_or_string_range_byte(object, start, end, &s, &e, 0);
6601         CHECK_LIST(props);
6602         for (; !NILP(props); props = Fcdr(Fcdr(props))) {
6603                 Lisp_Object prop = XCAR(props);
6604                 Lisp_Object value = Fcar(XCDR(props));
6605                 changed |= put_text_prop(s, e, object, prop, value, 0);
6606         }
6607         return changed ? Qt : Qnil;
6608 }
6609
6610 DEFUN("remove-text-properties", Fremove_text_properties, 3, 4, 0,       /*
6611 Remove the given properties from all characters in the specified region.
6612 PROPS should be a plist, but the values in that plist are ignored (treated
6613 as nil).  Returns t if any property was changed, nil otherwise.
6614 Fourth argument OBJECT is the buffer or string containing the text, and
6615 defaults to the current buffer.
6616 */
6617       (start, end, props, object))
6618 {
6619         /* This function can GC */
6620         int changed = 0;
6621         Bytind s, e;
6622
6623         object = decode_buffer_or_string(object);
6624         get_buffer_or_string_range_byte(object, start, end, &s, &e, 0);
6625         CHECK_LIST(props);
6626         for (; !NILP(props); props = Fcdr(Fcdr(props))) {
6627                 Lisp_Object prop = XCAR(props);
6628                 changed |= put_text_prop(s, e, object, prop, Qnil, 1);
6629         }
6630         return changed ? Qt : Qnil;
6631 }
6632
6633 /* Whenever a text-prop extent is pasted into a buffer (via `yank' or `insert'
6634    or whatever) we attach the properties to the buffer by calling
6635    `put-text-property' instead of by simply allowing the extent to be copied or
6636    re-attached.  Then we return nil, telling the extents code not to attach it
6637    again.  By handing the insertion hackery in this way, we make kill/yank
6638    behave consistently with put-text-property and not fragment the extents
6639    (since text-prop extents must partition, not overlap).
6640
6641    The lisp implementation of this was probably fast enough, but since I moved
6642    the rest of the put-text-prop code here, I moved this as well for
6643    completeness.
6644  */
6645 DEFUN("text-prop-extent-paste-function", Ftext_prop_extent_paste_function, 3, 3, 0,     /*
6646 Used as the `paste-function' property of `text-prop' extents.
6647 */
6648       (extent, from, to))
6649 {
6650         /* This function can GC */
6651         Lisp_Object prop, val;
6652
6653         prop = Fextent_property(extent, Qtext_prop, Qnil);
6654         if (NILP(prop))
6655                 signal_type_error(Qinternal_error,
6656                                   "Internal error: no text-prop", extent);
6657         val = Fextent_property(extent, prop, Qnil);
6658 #if 0
6659         /* removed by bill perry, 2/9/97
6660          ** This little bit of code would not allow you to have a text property
6661          ** with a value of Qnil.  This is bad bad bad.
6662          */
6663         if (NILP(val))
6664                 signal_type_error_2(Qinternal_error,
6665                                     "Internal error: no text-prop",
6666                                     extent, prop);
6667 #endif
6668         Fput_text_property(from, to, prop, val, Qnil);
6669         return Qnil;            /* important! */
6670 }
6671
6672 /* This function could easily be written in Lisp but the C code wants
6673    to use it in connection with invisible extents (at least currently).
6674    If this changes, consider moving this back into Lisp. */
6675
6676 DEFUN("next-single-property-change", Fnext_single_property_change, 2, 4, 0,     /*
6677 Return the position of next property change for a specific property.
6678 Scans characters forward from POS till it finds a change in the PROP
6679 property, then returns the position of the change.  The optional third
6680 argument OBJECT is the buffer or string to scan (defaults to the current
6681 buffer).
6682 The property values are compared with `eq'.
6683 Return nil if the property is constant all the way to the end of OBJECT.
6684 If the value is non-nil, it is a position greater than POS, never equal.
6685
6686 If the optional fourth argument LIMIT is non-nil, don't search
6687 past position LIMIT; return LIMIT if nothing is found before LIMIT.
6688 If two or more extents with conflicting non-nil values for PROP overlap
6689 a particular character, it is undefined which value is considered to be
6690 the value of PROP. (Note that this situation will not happen if you always
6691 use the text-property primitives.)
6692 */
6693       (pos, prop, object, limit))
6694 {
6695         Bufpos bpos;
6696         Bufpos blim;
6697         Lisp_Object extent, value;
6698         int limit_was_nil;
6699
6700         object = decode_buffer_or_string(object);
6701         bpos = get_buffer_or_string_pos_char(object, pos, 0);
6702         if (NILP(limit)) {
6703                 blim = buffer_or_string_accessible_end_char(object);
6704                 limit_was_nil = 1;
6705         } else {
6706                 blim = get_buffer_or_string_pos_char(object, limit, 0);
6707                 limit_was_nil = 0;
6708         }
6709
6710         extent = Fextent_at(make_int(bpos), object, prop, Qnil, Qnil);
6711         if (!NILP(extent))
6712                 value = Fextent_property(extent, prop, Qnil);
6713         else
6714                 value = Qnil;
6715
6716         while (1) {
6717                 bpos = XINT(Fnext_extent_change(make_int(bpos), object));
6718                 if (bpos >= blim)
6719                         break;  /* property is the same all the way to the end */
6720                 extent = Fextent_at(make_int(bpos), object, prop, Qnil, Qnil);
6721                 if ((NILP(extent) && !NILP(value)) ||
6722                     (!NILP(extent) && !EQ(value,
6723                                           Fextent_property(extent, prop,
6724                                                            Qnil))))
6725                         return make_int(bpos);
6726         }
6727
6728         /* I think it's more sensible for this function to return nil always
6729            in this situation and it used to do it this way, but it's been changed
6730            for FSF compatibility. */
6731         if (limit_was_nil)
6732                 return Qnil;
6733         else
6734                 return make_int(blim);
6735 }
6736
6737 /* See comment on previous function about why this is written in C. */
6738
6739 DEFUN("previous-single-property-change", Fprevious_single_property_change, 2, 4, 0,     /*
6740 Return the position of next property change for a specific property.
6741 Scans characters backward from POS till it finds a change in the PROP
6742 property, then returns the position of the change.  The optional third
6743 argument OBJECT is the buffer or string to scan (defaults to the current
6744 buffer).
6745 The property values are compared with `eq'.
6746 Return nil if the property is constant all the way to the start of OBJECT.
6747 If the value is non-nil, it is a position less than POS, never equal.
6748
6749 If the optional fourth argument LIMIT is non-nil, don't search back
6750 past position LIMIT; return LIMIT if nothing is found until LIMIT.
6751 If two or more extents with conflicting non-nil values for PROP overlap
6752 a particular character, it is undefined which value is considered to be
6753 the value of PROP. (Note that this situation will not happen if you always
6754 use the text-property primitives.)
6755 */
6756       (pos, prop, object, limit))
6757 {
6758         Bufpos bpos;
6759         Bufpos blim;
6760         Lisp_Object extent, value;
6761         int limit_was_nil;
6762
6763         object = decode_buffer_or_string(object);
6764         bpos = get_buffer_or_string_pos_char(object, pos, 0);
6765         if (NILP(limit)) {
6766                 blim = buffer_or_string_accessible_begin_char(object);
6767                 limit_was_nil = 1;
6768         } else {
6769                 blim = get_buffer_or_string_pos_char(object, limit, 0);
6770                 limit_was_nil = 0;
6771         }
6772
6773         /* extent-at refers to the character AFTER bpos, but we want the
6774            character before bpos.  Thus the - 1.  extent-at simply
6775            returns nil on bogus positions, so not to worry. */
6776         extent = Fextent_at(make_int(bpos - 1), object, prop, Qnil, Qnil);
6777         if (!NILP(extent))
6778                 value = Fextent_property(extent, prop, Qnil);
6779         else
6780                 value = Qnil;
6781
6782         while (1) {
6783                 bpos = XINT(Fprevious_extent_change(make_int(bpos), object));
6784                 if (bpos <= blim)
6785                         break;  /* property is the same all the way to the beginning */
6786                 extent =
6787                     Fextent_at(make_int(bpos - 1), object, prop, Qnil, Qnil);
6788                 if ((NILP(extent) && !NILP(value))
6789                     || (!NILP(extent)
6790                         && !EQ(value, Fextent_property(extent, prop, Qnil))))
6791                         return make_int(bpos);
6792         }
6793
6794         /* I think it's more sensible for this function to return nil always
6795            in this situation and it used to do it this way, but it's been changed
6796            for FSF compatibility. */
6797         if (limit_was_nil)
6798                 return Qnil;
6799         else
6800                 return make_int(blim);
6801 }
6802
6803 #ifdef MEMORY_USAGE_STATS
6804
6805 int
6806 compute_buffer_extent_usage(struct buffer *b, struct overhead_stats *ovstats)
6807 {
6808         /* #### not yet written */
6809         return 0;
6810 }
6811
6812 #endif                          /* MEMORY_USAGE_STATS */
6813 \f
6814 /************************************************************************/
6815 /*                              initialization                          */
6816 /************************************************************************/
6817
6818 void syms_of_extents(void)
6819 {
6820         INIT_LRECORD_IMPLEMENTATION(extent);
6821         INIT_LRECORD_IMPLEMENTATION(extent_info);
6822         INIT_LRECORD_IMPLEMENTATION(extent_auxiliary);
6823
6824         defsymbol(&Qextentp, "extentp");
6825         defsymbol(&Qextent_live_p, "extent-live-p");
6826
6827         defsymbol(&Qall_extents_closed, "all-extents-closed");
6828         defsymbol(&Qall_extents_open, "all-extents-open");
6829         defsymbol(&Qall_extents_closed_open, "all-extents-closed-open");
6830         defsymbol(&Qall_extents_open_closed, "all-extents-open-closed");
6831         defsymbol(&Qstart_in_region, "start-in-region");
6832         defsymbol(&Qend_in_region, "end-in-region");
6833         defsymbol(&Qstart_and_end_in_region, "start-and-end-in-region");
6834         defsymbol(&Qstart_or_end_in_region, "start-or-end-in-region");
6835         defsymbol(&Qnegate_in_region, "negate-in-region");
6836
6837         defsymbol(&Qdetached, "detached");
6838         defsymbol(&Qdestroyed, "destroyed");
6839         defsymbol(&Qbegin_glyph, "begin-glyph");
6840         defsymbol(&Qend_glyph, "end-glyph");
6841         defsymbol(&Qstart_open, "start-open");
6842         defsymbol(&Qend_open, "end-open");
6843         defsymbol(&Qstart_closed, "start-closed");
6844         defsymbol(&Qend_closed, "end-closed");
6845         defsymbol(&Qread_only, "read-only");
6846         /* defsymbol (&Qhighlight, "highlight"); in faces.c */
6847         defsymbol(&Qunique, "unique");
6848         defsymbol(&Qduplicable, "duplicable");
6849         defsymbol(&Qdetachable, "detachable");
6850         defsymbol(&Qpriority, "priority");
6851         defsymbol(&Qmouse_face, "mouse-face");
6852         defsymbol(&Qinitial_redisplay_function, "initial-redisplay-function");
6853
6854         defsymbol(&Qglyph_layout, "glyph-layout");      /* backwards compatibility */
6855         defsymbol(&Qbegin_glyph_layout, "begin-glyph-layout");
6856         defsymbol(&Qend_glyph_layout, "end-glyph-layout");
6857         defsymbol(&Qoutside_margin, "outside-margin");
6858         defsymbol(&Qinside_margin, "inside-margin");
6859         defsymbol(&Qwhitespace, "whitespace");
6860         /* Qtext defined in general.c */
6861
6862         defsymbol(&Qpaste_function, "paste-function");
6863         defsymbol(&Qcopy_function, "copy-function");
6864
6865         defsymbol(&Qtext_prop, "text-prop");
6866         defsymbol(&Qtext_prop_extent_paste_function,
6867                   "text-prop-extent-paste-function");
6868
6869         DEFSUBR(Fextentp);
6870         DEFSUBR(Fextent_live_p);
6871         DEFSUBR(Fextent_detached_p);
6872         DEFSUBR(Fextent_start_position);
6873         DEFSUBR(Fextent_end_position);
6874         DEFSUBR(Fextent_object);
6875         DEFSUBR(Fextent_length);
6876
6877         DEFSUBR(Fmake_extent);
6878         DEFSUBR(Fcopy_extent);
6879         DEFSUBR(Fdelete_extent);
6880         DEFSUBR(Fdetach_extent);
6881         DEFSUBR(Fset_extent_endpoints);
6882         DEFSUBR(Fnext_extent);
6883         DEFSUBR(Fprevious_extent);
6884 #if DEBUG_SXEMACS
6885         DEFSUBR(Fnext_e_extent);
6886         DEFSUBR(Fprevious_e_extent);
6887 #endif
6888         DEFSUBR(Fnext_extent_change);
6889         DEFSUBR(Fprevious_extent_change);
6890
6891         DEFSUBR(Fextent_parent);
6892         DEFSUBR(Fextent_children);
6893         DEFSUBR(Fset_extent_parent);
6894
6895         DEFSUBR(Fextent_in_region_p);
6896         DEFSUBR(Fmap_extents);
6897         DEFSUBR(Fmap_extent_children);
6898         DEFSUBR(Fextent_at);
6899         DEFSUBR(Fextents_at);
6900
6901         DEFSUBR(Fset_extent_initial_redisplay_function);
6902         DEFSUBR(Fextent_face);
6903         DEFSUBR(Fset_extent_face);
6904         DEFSUBR(Fextent_mouse_face);
6905         DEFSUBR(Fset_extent_mouse_face);
6906         DEFSUBR(Fset_extent_begin_glyph);
6907         DEFSUBR(Fset_extent_end_glyph);
6908         DEFSUBR(Fextent_begin_glyph);
6909         DEFSUBR(Fextent_end_glyph);
6910         DEFSUBR(Fset_extent_begin_glyph_layout);
6911         DEFSUBR(Fset_extent_end_glyph_layout);
6912         DEFSUBR(Fextent_begin_glyph_layout);
6913         DEFSUBR(Fextent_end_glyph_layout);
6914         DEFSUBR(Fset_extent_priority);
6915         DEFSUBR(Fextent_priority);
6916         DEFSUBR(Fset_extent_property);
6917         DEFSUBR(Fset_extent_properties);
6918         DEFSUBR(Fextent_property);
6919         DEFSUBR(Fextent_properties);
6920
6921         DEFSUBR(Fhighlight_extent);
6922         DEFSUBR(Fforce_highlight_extent);
6923
6924         DEFSUBR(Finsert_extent);
6925
6926         DEFSUBR(Fget_text_property);
6927         DEFSUBR(Fget_char_property);
6928         DEFSUBR(Fput_text_property);
6929         DEFSUBR(Fput_nonduplicable_text_property);
6930         DEFSUBR(Fadd_text_properties);
6931         DEFSUBR(Fadd_nonduplicable_text_properties);
6932         DEFSUBR(Fremove_text_properties);
6933         DEFSUBR(Ftext_prop_extent_paste_function);
6934         DEFSUBR(Fnext_single_property_change);
6935         DEFSUBR(Fprevious_single_property_change);
6936 }
6937
6938 void reinit_vars_of_extents(void)
6939 {
6940         extent_auxiliary_defaults.begin_glyph = Qnil;
6941         extent_auxiliary_defaults.end_glyph = Qnil;
6942         extent_auxiliary_defaults.parent = Qnil;
6943         extent_auxiliary_defaults.children = Qnil;
6944         extent_auxiliary_defaults.priority = 0;
6945         extent_auxiliary_defaults.invisible = Qnil;
6946         extent_auxiliary_defaults.read_only = Qnil;
6947         extent_auxiliary_defaults.mouse_face = Qnil;
6948         extent_auxiliary_defaults.initial_redisplay_function = Qnil;
6949         extent_auxiliary_defaults.before_change_functions = Qnil;
6950         extent_auxiliary_defaults.after_change_functions = Qnil;
6951 }
6952
6953 void vars_of_extents(void)
6954 {
6955         reinit_vars_of_extents();
6956
6957         DEFVAR_INT("mouse-highlight-priority", &mouse_highlight_priority        /*
6958 The priority to use for the mouse-highlighting pseudo-extent
6959 that is used to highlight extents with the `mouse-face' attribute set.
6960 See `set-extent-priority'.
6961                                                                                  */ );
6962         /* Set mouse-highlight-priority (which ends up being used both for the
6963            mouse-highlighting pseudo-extent and the primary selection extent)
6964            to a very high value because very few extents should override it.
6965            1000 gives lots of room below it for different-prioritized extents.
6966            10 doesn't. ediff, for example, likes to use priorities around 100.
6967            --ben */
6968         mouse_highlight_priority = /* 10 */ 1000;
6969
6970         DEFVAR_LISP("default-text-properties", &Vdefault_text_properties        /*
6971 Property list giving default values for text properties.
6972 Whenever a character does not specify a value for a property, the value
6973 stored in this list is used instead.  This only applies when the
6974 functions `get-text-property' or `get-char-property' are called.
6975                                                                                  */ );
6976         Vdefault_text_properties = Qnil;
6977
6978         staticpro(&Vlast_highlighted_extent);
6979         Vlast_highlighted_extent = Qnil;
6980
6981         Vextent_face_reusable_list = Fcons(Qnil, Qnil);
6982         staticpro(&Vextent_face_reusable_list);
6983 }
6984
6985 void complex_vars_of_extents(void)
6986 {
6987         staticpro(&Vextent_face_memoize_hash_table);
6988         /* The memoize hash table maps from lists of symbols to lists of
6989            faces.  It needs to be `equal' to implement the memoization.
6990            The reverse table maps in the other direction and just needs
6991            to do `eq' comparison because the lists of faces are already
6992            memoized. */
6993         Vextent_face_memoize_hash_table =
6994             make_lisp_hash_table(100, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQUAL);
6995         staticpro(&Vextent_face_reverse_memoize_hash_table);
6996         Vextent_face_reverse_memoize_hash_table =
6997             make_lisp_hash_table(100, HASH_TABLE_KEY_WEAK, HASH_TABLE_EQ);
6998 }