Mercurial > hg > xemacs-beta
comparison src/marker.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 8de8e3f6228a |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* Markers: examining, setting and killing. | |
2 Copyright (C) 1985, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | |
3 | |
4 This file is part of XEmacs. | |
5 | |
6 XEmacs is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with XEmacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* Synched up with: FSF 19.30. */ | |
22 | |
23 /* This file has been Mule-ized. */ | |
24 | |
25 /* Note that markers are currently kept in an unordered list. | |
26 This means that marker operations may be inefficient if | |
27 there are a bunch of markers in the buffer. This probably | |
28 won't have a significant impact on redisplay (which uses | |
29 markers), but if it does, it wouldn't be too hard to change | |
30 to an ordered gap array. (Just copy the code from extents.c.) | |
31 */ | |
32 | |
33 #include <config.h> | |
34 #include "lisp.h" | |
35 | |
36 #include "buffer.h" | |
37 | |
38 static Lisp_Object | |
39 mark_marker (Lisp_Object obj) | |
40 { | |
41 struct Lisp_Marker *marker = XMARKER (obj); | |
42 Lisp_Object buf; | |
43 /* DO NOT mark through the marker's chain. | |
44 The buffer's markers chain does not preserve markers from gc; | |
45 Instead, markers are removed from the chain when they are freed | |
46 by gc. | |
47 */ | |
48 if (!marker->buffer) | |
49 return (Qnil); | |
50 | |
51 XSETBUFFER (buf, marker->buffer); | |
52 return (buf); | |
53 } | |
54 | |
55 static void | |
56 print_marker (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | |
57 { | |
58 struct Lisp_Marker *marker = XMARKER (obj); | |
59 char buf[200]; | |
60 | |
61 if (print_readably) | |
62 error ("printing unreadable object #<marker 0x%lx>", (long) marker); | |
63 | |
64 write_c_string (GETTEXT ("#<marker "), printcharfun); | |
65 if (!marker->buffer) | |
66 write_c_string (GETTEXT ("in no buffer"), printcharfun); | |
67 else | |
68 { | |
69 sprintf (buf, "at %ld in ", (long) marker_position (obj)); | |
70 write_c_string (buf, printcharfun); | |
71 print_internal (marker->buffer->name, printcharfun, 0); | |
72 } | |
73 sprintf (buf, " 0x%lx>", (long) marker); | |
74 write_c_string (buf, printcharfun); | |
75 } | |
76 | |
77 static int | |
78 marker_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) | |
79 { | |
80 struct Lisp_Marker *marker1 = XMARKER (obj1); | |
81 struct Lisp_Marker *marker2 = XMARKER (obj2); | |
82 | |
83 return ((marker1->buffer == marker2->buffer) && | |
84 (marker1->memind == marker2->memind || | |
85 /* All markers pointing nowhere are equal */ | |
86 !marker1->buffer)); | |
87 } | |
88 | |
89 static unsigned long | |
90 marker_hash (Lisp_Object obj, int depth) | |
91 { | |
92 unsigned long hash = (unsigned long) XMARKER (obj)->buffer; | |
93 if (hash) | |
94 hash = HASH2 (hash, XMARKER (obj)->memind); | |
95 return hash; | |
96 } | |
97 | |
98 static const struct lrecord_description marker_description[] = { | |
99 { XD_LISP_OBJECT, offsetof(struct Lisp_Marker, next), 3 }, | |
100 { XD_END } | |
101 }; | |
102 | |
103 DEFINE_BASIC_LRECORD_IMPLEMENTATION ("marker", marker, | |
104 mark_marker, print_marker, 0, | |
105 marker_equal, marker_hash, marker_description, | |
106 struct Lisp_Marker); | |
107 | |
108 /* Operations on markers. */ | |
109 | |
110 DEFUN ("marker-buffer", Fmarker_buffer, 1, 1, 0, /* | |
111 Return the buffer that MARKER points into, or nil if none. | |
112 Return nil if MARKER points into a dead buffer or doesn't point anywhere. | |
113 */ | |
114 (marker)) | |
115 { | |
116 struct buffer *buf; | |
117 CHECK_MARKER (marker); | |
118 /* Return marker's buffer only if it is not dead. */ | |
119 if ((buf = XMARKER (marker)->buffer) && BUFFER_LIVE_P (buf)) | |
120 { | |
121 Lisp_Object buffer; | |
122 XSETBUFFER (buffer, buf); | |
123 return buffer; | |
124 } | |
125 return Qnil; | |
126 } | |
127 | |
128 DEFUN ("marker-position", Fmarker_position, 1, 1, 0, /* | |
129 Return the position MARKER points at, as a character number. | |
130 Return `nil' if marker doesn't point anywhere. | |
131 */ | |
132 (marker)) | |
133 { | |
134 CHECK_MARKER (marker); | |
135 return XMARKER (marker)->buffer ? make_int (marker_position (marker)) : Qnil; | |
136 } | |
137 | |
138 #if 0 /* useful debugging function */ | |
139 | |
140 static void | |
141 check_marker_circularities (struct buffer *buf) | |
142 { | |
143 struct Lisp_Marker *tortoise, *hare; | |
144 | |
145 tortoise = BUF_MARKERS (buf); | |
146 hare = tortoise; | |
147 | |
148 if (!tortoise) | |
149 return; | |
150 | |
151 while (1) | |
152 { | |
153 assert (hare->buffer == buf); | |
154 hare = hare->next; | |
155 if (!hare) | |
156 return; | |
157 assert (hare->buffer == buf); | |
158 hare = hare->next; | |
159 if (!hare) | |
160 return; | |
161 tortoise = tortoise->next; | |
162 assert (tortoise != hare); | |
163 } | |
164 } | |
165 | |
166 #endif | |
167 | |
168 static Lisp_Object | |
169 set_marker_internal (Lisp_Object marker, Lisp_Object pos, Lisp_Object buffer, | |
170 int restricted_p) | |
171 { | |
172 Bufpos charno; | |
173 struct buffer *b; | |
174 struct Lisp_Marker *m; | |
175 int point_p; | |
176 | |
177 CHECK_MARKER (marker); | |
178 | |
179 point_p = POINT_MARKER_P (marker); | |
180 | |
181 /* If position is nil or a marker that points nowhere, | |
182 make this marker point nowhere. */ | |
183 if (NILP (pos) || | |
184 (MARKERP (pos) && !XMARKER (pos)->buffer)) | |
185 { | |
186 if (point_p) | |
187 signal_simple_error ("Can't make point-marker point nowhere", | |
188 marker); | |
189 if (XMARKER (marker)->buffer) | |
190 unchain_marker (marker); | |
191 return marker; | |
192 } | |
193 | |
194 CHECK_INT_COERCE_MARKER (pos); | |
195 if (NILP (buffer)) | |
196 b = current_buffer; | |
197 else | |
198 { | |
199 CHECK_BUFFER (buffer); | |
200 b = XBUFFER (buffer); | |
201 /* If buffer is dead, set marker to point nowhere. */ | |
202 if (!BUFFER_LIVE_P (XBUFFER (buffer))) | |
203 { | |
204 if (point_p) | |
205 signal_simple_error | |
206 ("Can't move point-marker in a killed buffer", marker); | |
207 if (XMARKER (marker)->buffer) | |
208 unchain_marker (marker); | |
209 return marker; | |
210 } | |
211 } | |
212 | |
213 charno = XINT (pos); | |
214 m = XMARKER (marker); | |
215 | |
216 if (restricted_p) | |
217 { | |
218 if (charno < BUF_BEGV (b)) charno = BUF_BEGV (b); | |
219 if (charno > BUF_ZV (b)) charno = BUF_ZV (b); | |
220 } | |
221 else | |
222 { | |
223 if (charno < BUF_BEG (b)) charno = BUF_BEG (b); | |
224 if (charno > BUF_Z (b)) charno = BUF_Z (b); | |
225 } | |
226 | |
227 if (point_p) | |
228 { | |
229 #ifndef moving_point_by_moving_its_marker_is_a_bug | |
230 BUF_SET_PT (b, charno); /* this will move the marker */ | |
231 #else /* It's not a feature, so it must be a bug */ | |
232 signal_simple_error ("DEBUG: attempt to move point via point-marker", | |
233 marker); | |
234 #endif | |
235 } | |
236 else | |
237 { | |
238 m->memind = bufpos_to_memind (b, charno); | |
239 } | |
240 | |
241 if (m->buffer != b) | |
242 { | |
243 if (point_p) | |
244 signal_simple_error ("Can't change buffer of point-marker", marker); | |
245 if (m->buffer != 0) | |
246 unchain_marker (marker); | |
247 m->buffer = b; | |
248 marker_next (m) = BUF_MARKERS (b); | |
249 marker_prev (m) = 0; | |
250 if (BUF_MARKERS (b)) | |
251 marker_prev (BUF_MARKERS (b)) = m; | |
252 BUF_MARKERS (b) = m; | |
253 } | |
254 | |
255 return marker; | |
256 } | |
257 | |
258 | |
259 DEFUN ("set-marker", Fset_marker, 2, 3, 0, /* | |
260 Position MARKER before character number NUMBER in BUFFER. | |
261 BUFFER defaults to the current buffer. | |
262 If NUMBER is nil, makes marker point nowhere. | |
263 Then it no longer slows down editing in any buffer. | |
264 If this marker was returned by (point-marker t), then changing its position | |
265 moves point. You cannot change its buffer or make it point nowhere. | |
266 Returns MARKER. | |
267 */ | |
268 (marker, number, buffer)) | |
269 { | |
270 return set_marker_internal (marker, number, buffer, 0); | |
271 } | |
272 | |
273 | |
274 /* This version of Fset_marker won't let the position | |
275 be outside the visible part. */ | |
276 Lisp_Object | |
277 set_marker_restricted (Lisp_Object marker, Lisp_Object pos, Lisp_Object buffer) | |
278 { | |
279 return set_marker_internal (marker, pos, buffer, 1); | |
280 } | |
281 | |
282 | |
283 /* This is called during garbage collection, | |
284 so we must be careful to ignore and preserve mark bits, | |
285 including those in chain fields of markers. */ | |
286 | |
287 void | |
288 unchain_marker (Lisp_Object m) | |
289 { | |
290 struct Lisp_Marker *marker = XMARKER (m); | |
291 struct buffer *b = marker->buffer; | |
292 | |
293 if (b == 0) | |
294 return; | |
295 | |
296 #ifdef ERROR_CHECK_GC | |
297 assert (BUFFER_LIVE_P (b)); | |
298 #endif | |
299 | |
300 if (marker_next (marker)) | |
301 marker_prev (marker_next (marker)) = marker_prev (marker); | |
302 if (marker_prev (marker)) | |
303 marker_next (marker_prev (marker)) = marker_next (marker); | |
304 else | |
305 BUF_MARKERS (b) = marker_next (marker); | |
306 | |
307 #ifdef ERROR_CHECK_GC | |
308 assert (marker != XMARKER (b->point_marker)); | |
309 #endif | |
310 | |
311 marker->buffer = 0; | |
312 } | |
313 | |
314 Bytind | |
315 bi_marker_position (Lisp_Object marker) | |
316 { | |
317 struct Lisp_Marker *m = XMARKER (marker); | |
318 struct buffer *buf = m->buffer; | |
319 Bytind pos; | |
320 | |
321 if (!buf) | |
322 error ("Marker does not point anywhere"); | |
323 | |
324 /* FSF claims that marker indices could end up denormalized, i.e. | |
325 in the gap. This is way bogus if it ever happens, and means | |
326 something fucked up elsewhere. Since I've overhauled all this | |
327 shit, I don't think this can happen. In any case, the following | |
328 macro has an assert() in it that will catch these denormalized | |
329 positions. */ | |
330 pos = memind_to_bytind (buf, m->memind); | |
331 | |
332 #ifdef ERROR_CHECK_BUFPOS | |
333 if (pos < BI_BUF_BEG (buf) || pos > BI_BUF_Z (buf)) | |
334 abort (); | |
335 #endif | |
336 | |
337 return pos; | |
338 } | |
339 | |
340 Bufpos | |
341 marker_position (Lisp_Object marker) | |
342 { | |
343 struct buffer *buf = XMARKER (marker)->buffer; | |
344 | |
345 if (!buf) | |
346 error ("Marker does not point anywhere"); | |
347 | |
348 return bytind_to_bufpos (buf, bi_marker_position (marker)); | |
349 } | |
350 | |
351 void | |
352 set_bi_marker_position (Lisp_Object marker, Bytind pos) | |
353 { | |
354 struct Lisp_Marker *m = XMARKER (marker); | |
355 struct buffer *buf = m->buffer; | |
356 | |
357 if (!buf) | |
358 error ("Marker does not point anywhere"); | |
359 | |
360 #ifdef ERROR_CHECK_BUFPOS | |
361 if (pos < BI_BUF_BEG (buf) || pos > BI_BUF_Z (buf)) | |
362 abort (); | |
363 #endif | |
364 | |
365 m->memind = bytind_to_memind (buf, pos); | |
366 } | |
367 | |
368 void | |
369 set_marker_position (Lisp_Object marker, Bufpos pos) | |
370 { | |
371 struct buffer *buf = XMARKER (marker)->buffer; | |
372 | |
373 if (!buf) | |
374 error ("Marker does not point anywhere"); | |
375 | |
376 set_bi_marker_position (marker, bufpos_to_bytind (buf, pos)); | |
377 } | |
378 | |
379 static Lisp_Object | |
380 copy_marker_1 (Lisp_Object marker, Lisp_Object type, int noseeum) | |
381 { | |
382 REGISTER Lisp_Object new; | |
383 | |
384 while (1) | |
385 { | |
386 if (INTP (marker) || MARKERP (marker)) | |
387 { | |
388 if (noseeum) | |
389 new = noseeum_make_marker (); | |
390 else | |
391 new = Fmake_marker (); | |
392 Fset_marker (new, marker, | |
393 (MARKERP (marker) ? Fmarker_buffer (marker) : Qnil)); | |
394 XMARKER (new)->insertion_type = !NILP (type); | |
395 return new; | |
396 } | |
397 else | |
398 marker = wrong_type_argument (Qinteger_or_marker_p, marker); | |
399 } | |
400 | |
401 RETURN_NOT_REACHED (Qnil) /* not reached */ | |
402 } | |
403 | |
404 DEFUN ("copy-marker", Fcopy_marker, 1, 2, 0, /* | |
405 Return a new marker pointing at the same place as MARKER. | |
406 If argument is a number, makes a new marker pointing | |
407 at that position in the current buffer. | |
408 The optional argument TYPE specifies the insertion type of the new marker; | |
409 see `marker-insertion-type'. | |
410 */ | |
411 (marker, type)) | |
412 { | |
413 return copy_marker_1 (marker, type, 0); | |
414 } | |
415 | |
416 Lisp_Object | |
417 noseeum_copy_marker (Lisp_Object marker, Lisp_Object type) | |
418 { | |
419 return copy_marker_1 (marker, type, 1); | |
420 } | |
421 | |
422 DEFUN ("marker-insertion-type", Fmarker_insertion_type, 1, 1, 0, /* | |
423 Return insertion type of MARKER: t if it stays after inserted text. | |
424 nil means the marker stays before text inserted there. | |
425 */ | |
426 (marker)) | |
427 { | |
428 CHECK_MARKER (marker); | |
429 return XMARKER (marker)->insertion_type ? Qt : Qnil; | |
430 } | |
431 | |
432 DEFUN ("set-marker-insertion-type", Fset_marker_insertion_type, 2, 2, 0, /* | |
433 Set the insertion-type of MARKER to TYPE. | |
434 If TYPE is t, it means the marker advances when you insert text at it. | |
435 If TYPE is nil, it means the marker stays behind when you insert text at it. | |
436 */ | |
437 (marker, type)) | |
438 { | |
439 CHECK_MARKER (marker); | |
440 | |
441 XMARKER (marker)->insertion_type = ! NILP (type); | |
442 return type; | |
443 } | |
444 | |
445 /* #### What is the possible use of this? It looks quite useless to | |
446 me, because there is no way to find *which* markers are positioned | |
447 at POSITION. Additional bogosity bonus: (buffer-has-markers-at | |
448 (point)) will always return t because of the `point-marker'. The | |
449 same goes for the position of mark. Bletch! | |
450 | |
451 Someone should discuss this with Stallman, but I don't have the | |
452 stomach. In fact, this function sucks so badly that I'm disabling | |
453 it by default (although I've debugged it). If you want to use it, | |
454 use extents instead. --hniksic */ | |
455 #if 0 | |
456 xxDEFUN ("buffer-has-markers-at", Fbuffer_has_markers_at, 1, 1, 0, /* | |
457 Return t if there are markers pointing at POSITION in the current buffer. | |
458 */ | |
459 (position)) | |
460 { | |
461 struct Lisp_Marker *marker; | |
462 Memind pos; | |
463 | |
464 /* A small optimization trick: convert POS to memind now, rather | |
465 than converting every marker's memory index to bufpos. */ | |
466 pos = bytind_to_memind (current_buffer, | |
467 get_buffer_pos_byte (current_buffer, position, | |
468 GB_COERCE_RANGE)); | |
469 | |
470 for (marker = BUF_MARKERS (current_buffer); | |
471 marker; | |
472 marker = marker_next (marker)) | |
473 { | |
474 /* We use marker->memind, so we don't have to go through the | |
475 unwieldy operation of creating a Lisp_Object for | |
476 marker_position() every time around. */ | |
477 if (marker->memind == pos) | |
478 return Qt; | |
479 } | |
480 | |
481 return Qnil; | |
482 } | |
483 #endif /* 0 */ | |
484 | |
485 #ifdef MEMORY_USAGE_STATS | |
486 | |
487 int | |
488 compute_buffer_marker_usage (struct buffer *b, struct overhead_stats *ovstats) | |
489 { | |
490 struct Lisp_Marker *m; | |
491 int total = 0; | |
492 int overhead; | |
493 | |
494 for (m = BUF_MARKERS (b); m; m = m->next) | |
495 total += sizeof (struct Lisp_Marker); | |
496 ovstats->was_requested += total; | |
497 overhead = fixed_type_block_overhead (total); | |
498 /* #### claiming this is all malloc overhead is not really right, | |
499 but it has to go somewhere. */ | |
500 ovstats->malloc_overhead += overhead; | |
501 return total + overhead; | |
502 } | |
503 | |
504 #endif /* MEMORY_USAGE_STATS */ | |
505 | |
506 | |
507 void | |
508 syms_of_marker (void) | |
509 { | |
510 DEFSUBR (Fmarker_position); | |
511 DEFSUBR (Fmarker_buffer); | |
512 DEFSUBR (Fset_marker); | |
513 DEFSUBR (Fcopy_marker); | |
514 DEFSUBR (Fmarker_insertion_type); | |
515 DEFSUBR (Fset_marker_insertion_type); | |
516 #if 0 /* FSFmacs crock */ | |
517 DEFSUBR (Fbuffer_has_markers_at); | |
518 #endif | |
519 } | |
520 | |
521 void | |
522 init_buffer_markers (struct buffer *b) | |
523 { | |
524 Lisp_Object buf; | |
525 | |
526 XSETBUFFER (buf, b); | |
527 b->mark = Fmake_marker (); | |
528 BUF_MARKERS (b) = 0; | |
529 b->point_marker = Fmake_marker (); | |
530 Fset_marker (b->point_marker, | |
531 /* For indirect buffers, point is already set. */ | |
532 b->base_buffer ? make_int (BUF_PT (b)) : make_int (1), | |
533 buf); | |
534 } | |
535 | |
536 void | |
537 uninit_buffer_markers (struct buffer *b) | |
538 { | |
539 /* Unchain all markers of this buffer | |
540 and leave them pointing nowhere. */ | |
541 REGISTER struct Lisp_Marker *m, *next; | |
542 for (m = BUF_MARKERS (b); m; m = next) | |
543 { | |
544 m->buffer = 0; | |
545 next = marker_next (m); | |
546 marker_next (m) = 0; | |
547 marker_prev (m) = 0; | |
548 } | |
549 BUF_MARKERS (b) = 0; | |
550 } |