comparison src/specifier.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 9d177e8d4150
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /* Specifier implementation
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995, 1996 Ben Wing.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23 /* Synched up with: Not in FSF. */
24
25 /* Design by Ben Wing;
26 Original version by Chuck Thompson;
27 rewritten by Ben Wing;
28 Magic specifiers by Kirill Katsnelson;
29 */
30
31 #include <config.h>
32 #include "lisp.h"
33
34 #include "buffer.h"
35 #include "device.h"
36 #include "frame.h"
37 #include "opaque.h"
38 #include "specifier.h"
39 #include "window.h"
40 #include "chartab.h"
41 #include "rangetab.h"
42
43 Lisp_Object Qspecifierp;
44 Lisp_Object Qprepend, Qappend, Qremove_tag_set_prepend, Qremove_tag_set_append;
45 Lisp_Object Qremove_locale, Qremove_locale_type, Qremove_all;
46 Lisp_Object Qfallback;
47
48 /* Qinteger, Qboolean, Qgeneric defined in general.c. */
49 Lisp_Object Qnatnum;
50
51 Lisp_Object Qconsole_type, Qdevice_class;
52
53 static Lisp_Object Vuser_defined_tags;
54
55 typedef struct specifier_type_entry specifier_type_entry;
56 struct specifier_type_entry
57 {
58 Lisp_Object symbol;
59 struct specifier_methods *meths;
60 };
61
62 typedef struct
63 {
64 Dynarr_declare (specifier_type_entry);
65 } specifier_type_entry_dynarr;
66
67 static specifier_type_entry_dynarr *the_specifier_type_entry_dynarr;
68
69 static const struct lrecord_description ste_description_1[] = {
70 { XD_LISP_OBJECT, offsetof(specifier_type_entry, symbol), 1 },
71 { XD_STRUCT_PTR, offsetof(specifier_type_entry, meths), 1, &specifier_methods_description },
72 { XD_END }
73 };
74
75 static const struct struct_description ste_description = {
76 sizeof(specifier_type_entry),
77 ste_description_1
78 };
79
80 static const struct lrecord_description sted_description_1[] = {
81 XD_DYNARR_DESC(specifier_type_entry_dynarr, &ste_description),
82 { XD_END }
83 };
84
85 static const struct struct_description sted_description = {
86 sizeof(specifier_type_entry_dynarr),
87 sted_description_1
88 };
89
90 static Lisp_Object Vspecifier_type_list;
91
92 static Lisp_Object Vcached_specifiers;
93 /* Do NOT mark through this, or specifiers will never be GC'd. */
94 static Lisp_Object Vall_specifiers;
95
96 static Lisp_Object Vunlock_ghost_specifiers;
97
98 /* #### The purpose of this is to check for inheritance loops
99 in specifiers that can inherit from other specifiers, but it's
100 not yet implemented.
101
102 #### Look into this for 19.14. */
103 /* static Lisp_Object_dynarr current_specifiers; */
104
105 static void recompute_cached_specifier_everywhere (Lisp_Object specifier);
106
107 EXFUN (Fspecifier_specs, 4);
108 EXFUN (Fremove_specifier, 4);
109
110
111 /************************************************************************/
112 /* Specifier object methods */
113 /************************************************************************/
114
115 /* Remove dead objects from the specified assoc list. */
116
117 static Lisp_Object
118 cleanup_assoc_list (Lisp_Object list)
119 {
120 Lisp_Object loop, prev, retval;
121
122 loop = retval = list;
123 prev = Qnil;
124
125 while (!NILP (loop))
126 {
127 Lisp_Object entry = XCAR (loop);
128 Lisp_Object key = XCAR (entry);
129
130 /* remember, dead windows can become alive again. */
131 if (!WINDOWP (key) && object_dead_p (key))
132 {
133 if (NILP (prev))
134 {
135 /* Removing the head. */
136 retval = XCDR (retval);
137 }
138 else
139 {
140 Fsetcdr (prev, XCDR (loop));
141 }
142 }
143 else
144 prev = loop;
145
146 loop = XCDR (loop);
147 }
148
149 return retval;
150 }
151
152 /* Remove dead objects from the various lists so that they
153 don't keep getting marked as long as this specifier exists and
154 therefore wasting memory. */
155
156 void
157 cleanup_specifiers (void)
158 {
159 Lisp_Object rest;
160
161 for (rest = Vall_specifiers;
162 !NILP (rest);
163 rest = XSPECIFIER (rest)->next_specifier)
164 {
165 struct Lisp_Specifier *sp = XSPECIFIER (rest);
166 /* This effectively changes the specifier specs.
167 However, there's no need to call
168 recompute_cached_specifier_everywhere() or the
169 after-change methods because the only specs we
170 are removing are for dead objects, and they can
171 never have any effect on the specifier values:
172 specifiers can only be instantiated over live
173 objects, and you can't derive a dead object
174 from a live one. */
175 sp->device_specs = cleanup_assoc_list (sp->device_specs);
176 sp->frame_specs = cleanup_assoc_list (sp->frame_specs);
177 sp->buffer_specs = cleanup_assoc_list (sp->buffer_specs);
178 /* windows are handled specially because dead windows
179 can be resurrected */
180 }
181 }
182
183 void
184 kill_specifier_buffer_locals (Lisp_Object buffer)
185 {
186 Lisp_Object rest;
187
188 for (rest = Vall_specifiers;
189 !NILP (rest);
190 rest = XSPECIFIER (rest)->next_specifier)
191 {
192 struct Lisp_Specifier *sp = XSPECIFIER (rest);
193
194 /* Make sure we're actually going to be changing something.
195 Fremove_specifier() always calls
196 recompute_cached_specifier_everywhere() (#### but should
197 be smarter about this). */
198 if (!NILP (assq_no_quit (buffer, sp->buffer_specs)))
199 Fremove_specifier (rest, buffer, Qnil, Qnil);
200 }
201 }
202
203 static Lisp_Object
204 mark_specifier (Lisp_Object obj)
205 {
206 struct Lisp_Specifier *specifier = XSPECIFIER (obj);
207
208 mark_object (specifier->global_specs);
209 mark_object (specifier->device_specs);
210 mark_object (specifier->frame_specs);
211 mark_object (specifier->window_specs);
212 mark_object (specifier->buffer_specs);
213 mark_object (specifier->magic_parent);
214 mark_object (specifier->fallback);
215 if (!GHOST_SPECIFIER_P (XSPECIFIER (obj)))
216 MAYBE_SPECMETH (specifier, mark, (obj));
217 return Qnil;
218 }
219
220 /* The idea here is that the specifier specs point to locales
221 (windows, buffers, frames, and devices), and we want to make sure
222 that the specs disappear automatically when the associated locale
223 is no longer in use. For all but windows, "no longer in use"
224 corresponds exactly to when the object is deleted (non-deleted
225 objects are always held permanently in special lists, and deleted
226 objects are never on these lists and never reusable). To handle
227 this, we just have cleanup_specifiers() called periodically
228 (at the beginning of garbage collection); it removes all dead
229 objects.
230
231 For windows, however, it's trickier because dead objects can be
232 converted to live ones again if the dead object is in a window
233 configuration. Therefore, for windows, "no longer in use"
234 corresponds to when the window object is garbage-collected.
235 We now use weak lists for this purpose.
236
237 */
238
239 void
240 prune_specifiers (void)
241 {
242 Lisp_Object rest, prev = Qnil;
243
244 for (rest = Vall_specifiers;
245 !NILP (rest);
246 rest = XSPECIFIER (rest)->next_specifier)
247 {
248 if (! marked_p (rest))
249 {
250 struct Lisp_Specifier* sp = XSPECIFIER (rest);
251 /* A bit of assertion that we're removing both parts of the
252 magic one altogether */
253 assert (!MAGIC_SPECIFIER_P(sp)
254 || (BODILY_SPECIFIER_P(sp) && marked_p (sp->fallback))
255 || (GHOST_SPECIFIER_P(sp) && marked_p (sp->magic_parent)));
256 /* This specifier is garbage. Remove it from the list. */
257 if (NILP (prev))
258 Vall_specifiers = sp->next_specifier;
259 else
260 XSPECIFIER (prev)->next_specifier = sp->next_specifier;
261 }
262 else
263 prev = rest;
264 }
265 }
266
267 static void
268 print_specifier (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
269 {
270 struct Lisp_Specifier *sp = XSPECIFIER (obj);
271 char buf[100];
272 int count = specpdl_depth ();
273 Lisp_Object the_specs;
274
275 if (print_readably)
276 error ("printing unreadable object #<%s-specifier 0x%x>",
277 sp->methods->name, sp->header.uid);
278
279 sprintf (buf, "#<%s-specifier global=", sp->methods->name);
280 write_c_string (buf, printcharfun);
281 specbind (Qprint_string_length, make_int (100));
282 specbind (Qprint_length, make_int (5));
283 the_specs = Fspecifier_specs (obj, Qglobal, Qnil, Qnil);
284 if (NILP (the_specs))
285 /* there are no global specs */
286 write_c_string ("<unspecified>", printcharfun);
287 else
288 print_internal (the_specs, printcharfun, 1);
289 if (!NILP (sp->fallback))
290 {
291 write_c_string (" fallback=", printcharfun);
292 print_internal (sp->fallback, printcharfun, escapeflag);
293 }
294 unbind_to (count, Qnil);
295 sprintf (buf, " 0x%x>", sp->header.uid);
296 write_c_string (buf, printcharfun);
297 }
298
299 static void
300 finalize_specifier (void *header, int for_disksave)
301 {
302 struct Lisp_Specifier *sp = (struct Lisp_Specifier *) header;
303 /* don't be snafued by the disksave finalization. */
304 if (!for_disksave && !GHOST_SPECIFIER_P(sp) && sp->caching)
305 {
306 xfree (sp->caching);
307 sp->caching = 0;
308 }
309 }
310
311 static int
312 specifier_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
313 {
314 struct Lisp_Specifier *s1 = XSPECIFIER (obj1);
315 struct Lisp_Specifier *s2 = XSPECIFIER (obj2);
316 int retval;
317 Lisp_Object old_inhibit_quit = Vinhibit_quit;
318
319 /* This function can be called from within redisplay.
320 internal_equal can trigger a quit. That leads to Bad Things. */
321 Vinhibit_quit = Qt;
322
323 depth++;
324 retval =
325 (s1->methods == s2->methods &&
326 internal_equal (s1->global_specs, s2->global_specs, depth) &&
327 internal_equal (s1->device_specs, s2->device_specs, depth) &&
328 internal_equal (s1->frame_specs, s2->frame_specs, depth) &&
329 internal_equal (s1->window_specs, s2->window_specs, depth) &&
330 internal_equal (s1->buffer_specs, s2->buffer_specs, depth) &&
331 internal_equal (s1->fallback, s2->fallback, depth));
332
333 if (retval && HAS_SPECMETH_P (s1, equal))
334 retval = SPECMETH (s1, equal, (obj1, obj2, depth - 1));
335
336 Vinhibit_quit = old_inhibit_quit;
337 return retval;
338 }
339
340 static unsigned long
341 specifier_hash (Lisp_Object obj, int depth)
342 {
343 struct Lisp_Specifier *s = XSPECIFIER (obj);
344
345 /* specifier hashing is a bit problematic because there are so
346 many places where data can be stored. We pick what are perhaps
347 the most likely places where interesting stuff will be. */
348 return HASH5 ((HAS_SPECMETH_P (s, hash) ?
349 SPECMETH (s, hash, (obj, depth)) : 0),
350 (unsigned long) s->methods,
351 internal_hash (s->global_specs, depth + 1),
352 internal_hash (s->frame_specs, depth + 1),
353 internal_hash (s->buffer_specs, depth + 1));
354 }
355
356 static size_t
357 sizeof_specifier (CONST void *header)
358 {
359 if (GHOST_SPECIFIER_P ((struct Lisp_Specifier *) header))
360 return offsetof (struct Lisp_Specifier, data);
361 else
362 {
363 CONST struct Lisp_Specifier *p = (CONST struct Lisp_Specifier *) header;
364 return offsetof (struct Lisp_Specifier, data) + p->methods->extra_data_size;
365 }
366 }
367
368 static const struct lrecord_description specifier_methods_description_1[] = {
369 { XD_LISP_OBJECT, offsetof(struct specifier_methods, predicate_symbol), 1 },
370 { XD_END }
371 };
372
373 const struct struct_description specifier_methods_description = {
374 sizeof(struct specifier_methods),
375 specifier_methods_description_1
376 };
377
378 static const struct lrecord_description specifier_caching_description_1[] = {
379 { XD_END }
380 };
381
382 static const struct struct_description specifier_caching_description = {
383 sizeof(struct specifier_caching),
384 specifier_caching_description_1
385 };
386
387 static const struct lrecord_description specifier_description[] = {
388 { XD_STRUCT_PTR, offsetof(struct Lisp_Specifier, methods), 1, &specifier_methods_description },
389 { XD_LO_LINK, offsetof(struct Lisp_Specifier, next_specifier) },
390 { XD_LISP_OBJECT, offsetof(struct Lisp_Specifier, global_specs), 5 },
391 { XD_STRUCT_PTR, offsetof(struct Lisp_Specifier, caching), 1, &specifier_caching_description },
392 { XD_LISP_OBJECT, offsetof(struct Lisp_Specifier, magic_parent), 2 },
393 { XD_SPECIFIER_END }
394 };
395
396 const struct lrecord_description specifier_empty_extra_description[] = {
397 { XD_END }
398 };
399
400 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("specifier", specifier,
401 mark_specifier, print_specifier,
402 finalize_specifier,
403 specifier_equal, specifier_hash,
404 specifier_description,
405 sizeof_specifier,
406 struct Lisp_Specifier);
407
408 /************************************************************************/
409 /* Creating specifiers */
410 /************************************************************************/
411
412 static struct specifier_methods *
413 decode_specifier_type (Lisp_Object type, Error_behavior errb)
414 {
415 int i;
416
417 for (i = 0; i < Dynarr_length (the_specifier_type_entry_dynarr); i++)
418 {
419 if (EQ (type, Dynarr_at (the_specifier_type_entry_dynarr, i).symbol))
420 return Dynarr_at (the_specifier_type_entry_dynarr, i).meths;
421 }
422
423 maybe_signal_simple_error ("Invalid specifier type", type,
424 Qspecifier, errb);
425
426 return 0;
427 }
428
429 static int
430 valid_specifier_type_p (Lisp_Object type)
431 {
432 return decode_specifier_type (type, ERROR_ME_NOT) != 0;
433 }
434
435 DEFUN ("valid-specifier-type-p", Fvalid_specifier_type_p, 1, 1, 0, /*
436 Given a SPECIFIER-TYPE, return non-nil if it is valid.
437 Valid types are 'generic, 'integer, boolean, 'color, 'font, 'image,
438 'face-boolean, and 'toolbar.
439 */
440 (specifier_type))
441 {
442 return valid_specifier_type_p (specifier_type) ? Qt : Qnil;
443 }
444
445 DEFUN ("specifier-type-list", Fspecifier_type_list, 0, 0, 0, /*
446 Return a list of valid specifier types.
447 */
448 ())
449 {
450 return Fcopy_sequence (Vspecifier_type_list);
451 }
452
453 void
454 add_entry_to_specifier_type_list (Lisp_Object symbol,
455 struct specifier_methods *meths)
456 {
457 struct specifier_type_entry entry;
458
459 entry.symbol = symbol;
460 entry.meths = meths;
461 Dynarr_add (the_specifier_type_entry_dynarr, entry);
462 Vspecifier_type_list = Fcons (symbol, Vspecifier_type_list);
463 }
464
465 static Lisp_Object
466 make_specifier_internal (struct specifier_methods *spec_meths,
467 size_t data_size, int call_create_meth)
468 {
469 Lisp_Object specifier;
470 struct Lisp_Specifier *sp = (struct Lisp_Specifier *)
471 alloc_lcrecord (offsetof (struct Lisp_Specifier, data) +
472 data_size, &lrecord_specifier);
473
474 sp->methods = spec_meths;
475 sp->global_specs = Qnil;
476 sp->device_specs = Qnil;
477 sp->frame_specs = Qnil;
478 sp->window_specs = make_weak_list (WEAK_LIST_KEY_ASSOC);
479 sp->buffer_specs = Qnil;
480 sp->fallback = Qnil;
481 sp->magic_parent = Qnil;
482 sp->caching = 0;
483 sp->next_specifier = Vall_specifiers;
484
485 XSETSPECIFIER (specifier, sp);
486 Vall_specifiers = specifier;
487
488 if (call_create_meth)
489 {
490 struct gcpro gcpro1;
491 GCPRO1 (specifier);
492 MAYBE_SPECMETH (XSPECIFIER (specifier), create, (specifier));
493 UNGCPRO;
494 }
495 return specifier;
496 }
497
498 static Lisp_Object
499 make_specifier (struct specifier_methods *meths)
500 {
501 return make_specifier_internal (meths, meths->extra_data_size, 1);
502 }
503
504 Lisp_Object
505 make_magic_specifier (Lisp_Object type)
506 {
507 /* This function can GC */
508 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
509 Lisp_Object bodily, ghost;
510 struct gcpro gcpro1;
511
512 bodily = make_specifier (meths);
513 GCPRO1 (bodily);
514 ghost = make_specifier_internal (meths, 0, 0);
515 UNGCPRO;
516
517 /* Connect guys together */
518 XSPECIFIER(bodily)->magic_parent = Qt;
519 XSPECIFIER(bodily)->fallback = ghost;
520 XSPECIFIER(ghost)->magic_parent = bodily;
521
522 return bodily;
523 }
524
525 DEFUN ("make-specifier", Fmake_specifier, 1, 1, 0, /*
526 Return a new specifier object of type TYPE.
527
528 A specifier is an object that can be used to keep track of a property
529 whose value can be per-buffer, per-window, per-frame, or per-device,
530 and can further be restricted to a particular console-type or device-class.
531 Specifiers are used, for example, for the various built-in properties of a
532 face; this allows a face to have different values in different frames,
533 buffers, etc. For more information, see `specifier-instance',
534 `specifier-specs', and `add-spec-to-specifier'; or, for a detailed
535 description of specifiers, including how they are instantiated over a
536 particular domain (i.e. how their value in that domain is determined),
537 see the chapter on specifiers in the XEmacs Lisp Reference Manual.
538
539 TYPE specifies the particular type of specifier, and should be one of
540 the symbols 'generic, 'integer, 'boolean, 'color, 'font, 'image,
541 'face-boolean, or 'toolbar.
542
543 For more information on particular types of specifiers, see the functions
544 `generic-specifier-p', `integer-specifier-p', `boolean-specifier-p',
545 `color-specifier-p', `font-specifier-p', `image-specifier-p',
546 `face-boolean-specifier-p', and `toolbar-specifier-p'.
547 */
548 (type))
549 {
550 /* This function can GC */
551 struct specifier_methods *meths = decode_specifier_type (type,
552 ERROR_ME);
553
554 return make_specifier (meths);
555 }
556
557 DEFUN ("specifierp", Fspecifierp, 1, 1, 0, /*
558 Return t if OBJECT is a specifier.
559
560 A specifier is an object that can be used to keep track of a property
561 whose value can be per-buffer, per-window, per-frame, or per-device,
562 and can further be restricted to a particular console-type or device-class.
563 See `make-specifier'.
564 */
565 (object))
566 {
567 return SPECIFIERP (object) ? Qt : Qnil;
568 }
569
570 DEFUN ("specifier-type", Fspecifier_type, 1, 1, 0, /*
571 Return the type of SPECIFIER.
572 */
573 (specifier))
574 {
575 CHECK_SPECIFIER (specifier);
576 return intern (XSPECIFIER (specifier)->methods->name);
577 }
578
579
580 /************************************************************************/
581 /* Locales and domains */
582 /************************************************************************/
583
584 DEFUN ("valid-specifier-locale-p", Fvalid_specifier_locale_p, 1, 1, 0, /*
585 Return t if LOCALE is a valid specifier locale.
586 Valid locales are devices, frames, windows, buffers, and 'global.
587 \(nil is not valid.)
588 */
589 (locale))
590 {
591 /* This cannot GC. */
592 return ((DEVICEP (locale) && DEVICE_LIVE_P (XDEVICE (locale))) ||
593 (FRAMEP (locale) && FRAME_LIVE_P (XFRAME (locale))) ||
594 (BUFFERP (locale) && BUFFER_LIVE_P (XBUFFER (locale))) ||
595 /* dead windows are allowed because they may become live
596 windows again when a window configuration is restored */
597 WINDOWP (locale) ||
598 EQ (locale, Qglobal))
599 ? Qt : Qnil;
600 }
601
602 DEFUN ("valid-specifier-domain-p", Fvalid_specifier_domain_p, 1, 1, 0, /*
603 Return t if DOMAIN is a valid specifier domain.
604 A domain is used to instance a specifier (i.e. determine the specifier's
605 value in that domain). Valid domains are windows, frames, and devices.
606 \(nil is not valid.)
607 */
608 (domain))
609 {
610 /* This cannot GC. */
611 return ((DEVICEP (domain) && DEVICE_LIVE_P (XDEVICE (domain))) ||
612 (FRAMEP (domain) && FRAME_LIVE_P (XFRAME (domain))) ||
613 (WINDOWP (domain) && WINDOW_LIVE_P (XWINDOW (domain))))
614 ? Qt : Qnil;
615 }
616
617 DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1, 1, 0, /*
618 Given a specifier LOCALE-TYPE, return non-nil if it is valid.
619 Valid locale types are 'global, 'device, 'frame, 'window, and 'buffer.
620 \(Note, however, that in functions that accept either a locale or a locale
621 type, 'global is considered an individual locale.)
622 */
623 (locale_type))
624 {
625 /* This cannot GC. */
626 return (EQ (locale_type, Qglobal) ||
627 EQ (locale_type, Qdevice) ||
628 EQ (locale_type, Qframe) ||
629 EQ (locale_type, Qwindow) ||
630 EQ (locale_type, Qbuffer)) ? Qt : Qnil;
631 }
632
633 static void
634 check_valid_locale_or_locale_type (Lisp_Object locale)
635 {
636 /* This cannot GC. */
637 if (EQ (locale, Qall) ||
638 !NILP (Fvalid_specifier_locale_p (locale)) ||
639 !NILP (Fvalid_specifier_locale_type_p (locale)))
640 return;
641 signal_simple_error ("Invalid specifier locale or locale type", locale);
642 }
643
644 DEFUN ("specifier-locale-type-from-locale", Fspecifier_locale_type_from_locale,
645 1, 1, 0, /*
646 Given a specifier LOCALE, return its type.
647 */
648 (locale))
649 {
650 /* This cannot GC. */
651 if (NILP (Fvalid_specifier_locale_p (locale)))
652 signal_simple_error ("Invalid specifier locale", locale);
653 if (DEVICEP (locale)) return Qdevice;
654 if (FRAMEP (locale)) return Qframe;
655 if (WINDOWP (locale)) return Qwindow;
656 if (BUFFERP (locale)) return Qbuffer;
657 assert (EQ (locale, Qglobal));
658 return Qglobal;
659 }
660
661 static Lisp_Object
662 decode_locale (Lisp_Object locale)
663 {
664 /* This cannot GC. */
665 if (NILP (locale))
666 return Qglobal;
667 else if (!NILP (Fvalid_specifier_locale_p (locale)))
668 return locale;
669 else
670 signal_simple_error ("Invalid specifier locale", locale);
671
672 return Qnil;
673 }
674
675 static enum spec_locale_type
676 decode_locale_type (Lisp_Object locale_type)
677 {
678 /* This cannot GC. */
679 if (EQ (locale_type, Qglobal)) return LOCALE_GLOBAL;
680 if (EQ (locale_type, Qdevice)) return LOCALE_DEVICE;
681 if (EQ (locale_type, Qframe)) return LOCALE_FRAME;
682 if (EQ (locale_type, Qwindow)) return LOCALE_WINDOW;
683 if (EQ (locale_type, Qbuffer)) return LOCALE_BUFFER;
684
685 signal_simple_error ("Invalid specifier locale type", locale_type);
686 return LOCALE_GLOBAL; /* not reached */
687 }
688
689 Lisp_Object
690 decode_locale_list (Lisp_Object locale)
691 {
692 /* This cannot GC. */
693 /* The return value of this function must be GCPRO'd. */
694 if (NILP (locale))
695 {
696 return list1 (Qall);
697 }
698 else if (CONSP (locale))
699 {
700 Lisp_Object elt;
701 EXTERNAL_LIST_LOOP_2 (elt, locale)
702 check_valid_locale_or_locale_type (elt);
703 return locale;
704 }
705 else
706 {
707 check_valid_locale_or_locale_type (locale);
708 return list1 (locale);
709 }
710 }
711
712 static enum spec_locale_type
713 locale_type_from_locale (Lisp_Object locale)
714 {
715 return decode_locale_type (Fspecifier_locale_type_from_locale (locale));
716 }
717
718 static void
719 check_valid_domain (Lisp_Object domain)
720 {
721 if (NILP (Fvalid_specifier_domain_p (domain)))
722 signal_simple_error ("Invalid specifier domain", domain);
723 }
724
725 static Lisp_Object
726 decode_domain (Lisp_Object domain)
727 {
728 if (NILP (domain))
729 return Fselected_window (Qnil);
730 check_valid_domain (domain);
731 return domain;
732 }
733
734
735 /************************************************************************/
736 /* Tags */
737 /************************************************************************/
738
739 DEFUN ("valid-specifier-tag-p", Fvalid_specifier_tag_p, 1, 1, 0, /*
740 Return non-nil if TAG is a valid specifier tag.
741 See also `valid-specifier-tag-set-p'.
742 */
743 (tag))
744 {
745 return (valid_console_type_p (tag) ||
746 valid_device_class_p (tag) ||
747 !NILP (assq_no_quit (tag, Vuser_defined_tags))) ? Qt : Qnil;
748 }
749
750 DEFUN ("valid-specifier-tag-set-p", Fvalid_specifier_tag_set_p, 1, 1, 0, /*
751 Return non-nil if TAG-SET is a valid specifier tag set.
752
753 A specifier tag set is an entity that is attached to an instantiator
754 and can be used to restrict the scope of that instantiator to a
755 particular device class or device type and/or to mark instantiators
756 added by a particular package so that they can be later removed.
757
758 A specifier tag set consists of a list of zero of more specifier tags,
759 each of which is a symbol that is recognized by XEmacs as a tag.
760 \(The valid device types and device classes are always tags, as are
761 any tags defined by `define-specifier-tag'.) It is called a "tag set"
762 \(as opposed to a list) because the order of the tags or the number of
763 times a particular tag occurs does not matter.
764
765 Each tag has a predicate associated with it, which specifies whether
766 that tag applies to a particular device. The tags which are device types
767 and classes match devices of that type or class. User-defined tags can
768 have any predicate, or none (meaning that all devices match). When
769 attempting to instance a specifier, a particular instantiator is only
770 considered if the device of the domain being instanced over matches
771 all tags in the tag set attached to that instantiator.
772
773 Most of the time, a tag set is not specified, and the instantiator
774 gets a null tag set, which matches all devices.
775 */
776 (tag_set))
777 {
778 Lisp_Object rest;
779
780 for (rest = tag_set; !NILP (rest); rest = XCDR (rest))
781 {
782 if (!CONSP (rest))
783 return Qnil;
784 if (NILP (Fvalid_specifier_tag_p (XCAR (rest))))
785 return Qnil;
786 QUIT;
787 }
788 return Qt;
789 }
790
791 Lisp_Object
792 decode_specifier_tag_set (Lisp_Object tag_set)
793 {
794 /* The return value of this function must be GCPRO'd. */
795 if (!NILP (Fvalid_specifier_tag_p (tag_set)))
796 return list1 (tag_set);
797 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
798 signal_simple_error ("Invalid specifier tag-set", tag_set);
799 return tag_set;
800 }
801
802 static Lisp_Object
803 canonicalize_tag_set (Lisp_Object tag_set)
804 {
805 int len = XINT (Flength (tag_set));
806 Lisp_Object *tags, rest;
807 int i, j;
808
809 /* We assume in this function that the tag_set has already been
810 validated, so there are no surprises. */
811
812 if (len == 0 || len == 1)
813 /* most common case */
814 return tag_set;
815
816 tags = alloca_array (Lisp_Object, len);
817
818 i = 0;
819 LIST_LOOP (rest, tag_set)
820 tags[i++] = XCAR (rest);
821
822 /* Sort the list of tags. We use a bubble sort here (copied from
823 extent_fragment_update()) -- reduces the function call overhead,
824 and is the fastest sort for small numbers of items. */
825
826 for (i = 1; i < len; i++)
827 {
828 j = i - 1;
829 while (j >= 0 &&
830 strcmp ((char *) string_data (XSYMBOL (tags[j])->name),
831 (char *) string_data (XSYMBOL (tags[j+1])->name)) > 0)
832 {
833 Lisp_Object tmp = tags[j];
834 tags[j] = tags[j+1];
835 tags[j+1] = tmp;
836 j--;
837 }
838 }
839
840 /* Now eliminate duplicates. */
841
842 for (i = 1, j = 1; i < len; i++)
843 {
844 /* j holds the destination, i the source. */
845 if (!EQ (tags[i], tags[i-1]))
846 tags[j++] = tags[i];
847 }
848
849 return Flist (j, tags);
850 }
851
852 DEFUN ("canonicalize-tag-set", Fcanonicalize_tag_set, 1, 1, 0, /*
853 Canonicalize the given tag set.
854 Two canonicalized tag sets can be compared with `equal' to see if they
855 represent the same tag set. (Specifically, canonicalizing involves
856 sorting by symbol name and removing duplicates.)
857 */
858 (tag_set))
859 {
860 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
861 signal_simple_error ("Invalid tag set", tag_set);
862 return canonicalize_tag_set (tag_set);
863 }
864
865 static int
866 device_matches_specifier_tag_set_p (Lisp_Object device, Lisp_Object tag_set)
867 {
868 Lisp_Object devtype, devclass, rest;
869 struct device *d = XDEVICE (device);
870
871 devtype = DEVICE_TYPE (d);
872 devclass = DEVICE_CLASS (d);
873
874 LIST_LOOP (rest, tag_set)
875 {
876 Lisp_Object tag = XCAR (rest);
877 Lisp_Object assoc;
878
879 if (EQ (tag, devtype) || EQ (tag, devclass))
880 continue;
881 assoc = assq_no_quit (tag, DEVICE_USER_DEFINED_TAGS (d));
882 /* other built-in tags (device types/classes) are not in
883 the user-defined-tags list. */
884 if (NILP (assoc) || NILP (XCDR (assoc)))
885 return 0;
886 }
887
888 return 1;
889 }
890
891 DEFUN ("device-matches-specifier-tag-set-p", Fdevice_matches_specifier_tag_set_p, 2, 2, 0, /*
892 Return non-nil if DEVICE matches specifier tag set TAG-SET.
893 This means that DEVICE matches each tag in the tag set. (Every
894 tag recognized by XEmacs has a predicate associated with it that
895 specifies which devices match it.)
896 */
897 (device, tag_set))
898 {
899 CHECK_LIVE_DEVICE (device);
900
901 if (NILP (Fvalid_specifier_tag_set_p (tag_set)))
902 signal_simple_error ("Invalid tag set", tag_set);
903
904 return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil;
905 }
906
907 DEFUN ("define-specifier-tag", Fdefine_specifier_tag, 1, 2, 0, /*
908 Define a new specifier tag.
909 If PREDICATE is specified, it should be a function of one argument
910 \(a device) that specifies whether the tag matches that particular
911 device. If PREDICATE is omitted, the tag matches all devices.
912
913 You can redefine an existing user-defined specifier tag. However,
914 you cannot redefine the built-in specifier tags (the device types
915 and classes) or the symbols nil, t, 'all, or 'global.
916 */
917 (tag, predicate))
918 {
919 Lisp_Object assoc, devcons, concons;
920 int recompute = 0;
921
922 CHECK_SYMBOL (tag);
923 if (valid_device_class_p (tag) ||
924 valid_console_type_p (tag))
925 signal_simple_error ("Cannot redefine built-in specifier tags", tag);
926 /* Try to prevent common instantiators and locales from being
927 redefined, to reduce ambiguity */
928 if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal))
929 signal_simple_error ("Cannot define nil, t, 'all, or 'global",
930 tag);
931 assoc = assq_no_quit (tag, Vuser_defined_tags);
932 if (NILP (assoc))
933 {
934 recompute = 1;
935 Vuser_defined_tags = Fcons (Fcons (tag, predicate), Vuser_defined_tags);
936 DEVICE_LOOP_NO_BREAK (devcons, concons)
937 {
938 struct device *d = XDEVICE (XCAR (devcons));
939 /* Initially set the value to t in case of error
940 in predicate */
941 DEVICE_USER_DEFINED_TAGS (d) =
942 Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d));
943 }
944 }
945 else if (!NILP (predicate) && !NILP (XCDR (assoc)))
946 {
947 recompute = 1;
948 XCDR (assoc) = predicate;
949 }
950
951 /* recompute the tag values for all devices. However, in the special
952 case where both the old and new predicates are nil, we know that
953 we don't have to do this. (It's probably common for people to
954 call (define-specifier-tag) more than once on the same tag,
955 and the most common case is where PREDICATE is not specified.) */
956
957 if (recompute)
958 {
959 DEVICE_LOOP_NO_BREAK (devcons, concons)
960 {
961 Lisp_Object device = XCAR (devcons);
962 assoc = assq_no_quit (tag,
963 DEVICE_USER_DEFINED_TAGS (XDEVICE (device)));
964 assert (CONSP (assoc));
965 if (NILP (predicate))
966 XCDR (assoc) = Qt;
967 else
968 XCDR (assoc) = !NILP (call1 (predicate, device)) ? Qt : Qnil;
969 }
970 }
971
972 return Qnil;
973 }
974
975 /* Called at device-creation time to initialize the user-defined
976 tag values for the newly-created device. */
977
978 void
979 setup_device_initial_specifier_tags (struct device *d)
980 {
981 Lisp_Object rest, rest2;
982 Lisp_Object device;
983
984 XSETDEVICE (device, d);
985
986 DEVICE_USER_DEFINED_TAGS (d) = Fcopy_alist (Vuser_defined_tags);
987
988 /* Now set up the initial values */
989 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
990 XCDR (XCAR (rest)) = Qt;
991
992 for (rest = Vuser_defined_tags, rest2 = DEVICE_USER_DEFINED_TAGS (d);
993 !NILP (rest); rest = XCDR (rest), rest2 = XCDR (rest2))
994 {
995 Lisp_Object predicate = XCDR (XCAR (rest));
996 if (NILP (predicate))
997 XCDR (XCAR (rest2)) = Qt;
998 else
999 XCDR (XCAR (rest2)) = !NILP (call1 (predicate, device)) ? Qt : Qnil;
1000 }
1001 }
1002
1003 DEFUN ("device-matching-specifier-tag-list", Fdevice_matching_specifier_tag_list,
1004 0, 1, 0, /*
1005 Return a list of all specifier tags matching DEVICE.
1006 DEVICE defaults to the selected device if omitted.
1007 */
1008 (device))
1009 {
1010 struct device *d = decode_device (device);
1011 Lisp_Object rest, list = Qnil;
1012 struct gcpro gcpro1;
1013
1014 GCPRO1 (list);
1015
1016 LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d))
1017 {
1018 if (!NILP (XCDR (XCAR (rest))))
1019 list = Fcons (XCAR (XCAR (rest)), list);
1020 }
1021
1022 list = Fnreverse (list);
1023 list = Fcons (DEVICE_CLASS (d), list);
1024 list = Fcons (DEVICE_TYPE (d), list);
1025
1026 RETURN_UNGCPRO (list);
1027 }
1028
1029 DEFUN ("specifier-tag-list", Fspecifier_tag_list, 0, 0, 0, /*
1030 Return a list of all currently-defined specifier tags.
1031 This includes the built-in ones (the device types and classes).
1032 */
1033 ())
1034 {
1035 Lisp_Object list = Qnil, rest;
1036 struct gcpro gcpro1;
1037
1038 GCPRO1 (list);
1039
1040 LIST_LOOP (rest, Vuser_defined_tags)
1041 list = Fcons (XCAR (XCAR (rest)), list);
1042
1043 list = Fnreverse (list);
1044 list = nconc2 (Fcopy_sequence (Vdevice_class_list), list);
1045 list = nconc2 (Fcopy_sequence (Vconsole_type_list), list);
1046
1047 RETURN_UNGCPRO (list);
1048 }
1049
1050 DEFUN ("specifier-tag-predicate", Fspecifier_tag_predicate, 1, 1, 0, /*
1051 Return the predicate for the given specifier tag.
1052 */
1053 (tag))
1054 {
1055 /* The return value of this function must be GCPRO'd. */
1056 CHECK_SYMBOL (tag);
1057
1058 if (NILP (Fvalid_specifier_tag_p (tag)))
1059 signal_simple_error ("Invalid specifier tag", tag);
1060
1061 /* Make up some predicates for the built-in types */
1062
1063 if (valid_console_type_p (tag))
1064 return list3 (Qlambda, list1 (Qdevice),
1065 list3 (Qeq, list2 (Qquote, tag),
1066 list2 (Qconsole_type, Qdevice)));
1067
1068 if (valid_device_class_p (tag))
1069 return list3 (Qlambda, list1 (Qdevice),
1070 list3 (Qeq, list2 (Qquote, tag),
1071 list2 (Qdevice_class, Qdevice)));
1072
1073 return XCDR (assq_no_quit (tag, Vuser_defined_tags));
1074 }
1075
1076 /* Return true if A "matches" B. If EXACT_P is 0, A must be a subset of B.
1077 Otherwise, A must be `equal' to B. The sets must be canonicalized. */
1078 static int
1079 tag_sets_match_p (Lisp_Object a, Lisp_Object b, int exact_p)
1080 {
1081 if (!exact_p)
1082 {
1083 while (!NILP (a) && !NILP (b))
1084 {
1085 if (EQ (XCAR (a), XCAR (b)))
1086 a = XCDR (a);
1087 b = XCDR (b);
1088 }
1089
1090 return NILP (a);
1091 }
1092 else
1093 {
1094 while (!NILP (a) && !NILP (b))
1095 {
1096 if (!EQ (XCAR (a), XCAR (b)))
1097 return 0;
1098 a = XCDR (a);
1099 b = XCDR (b);
1100 }
1101
1102 return NILP (a) && NILP (b);
1103 }
1104 }
1105
1106
1107 /************************************************************************/
1108 /* Spec-lists and inst-lists */
1109 /************************************************************************/
1110
1111 static Lisp_Object
1112 call_validate_method (Lisp_Object boxed_method, Lisp_Object instantiator)
1113 {
1114 ((void (*)(Lisp_Object)) get_opaque_ptr (boxed_method)) (instantiator);
1115 return Qt;
1116 }
1117
1118 static Lisp_Object
1119 check_valid_instantiator (Lisp_Object instantiator,
1120 struct specifier_methods *meths,
1121 Error_behavior errb)
1122 {
1123 if (meths->validate_method)
1124 {
1125 Lisp_Object retval;
1126
1127 if (ERRB_EQ (errb, ERROR_ME))
1128 {
1129 (meths->validate_method) (instantiator);
1130 retval = Qt;
1131 }
1132 else
1133 {
1134 Lisp_Object opaque = make_opaque_ptr ((void *)
1135 meths->validate_method);
1136 struct gcpro gcpro1;
1137
1138 GCPRO1 (opaque);
1139 retval = call_with_suspended_errors
1140 ((lisp_fn_t) call_validate_method,
1141 Qnil, Qspecifier, errb, 2, opaque, instantiator);
1142
1143 free_opaque_ptr (opaque);
1144 UNGCPRO;
1145 }
1146
1147 return retval;
1148 }
1149 return Qt;
1150 }
1151
1152 DEFUN ("check-valid-instantiator", Fcheck_valid_instantiator, 2, 2, 0, /*
1153 Signal an error if INSTANTIATOR is invalid for SPECIFIER-TYPE.
1154 */
1155 (instantiator, specifier_type))
1156 {
1157 struct specifier_methods *meths = decode_specifier_type (specifier_type,
1158 ERROR_ME);
1159
1160 return check_valid_instantiator (instantiator, meths, ERROR_ME);
1161 }
1162
1163 DEFUN ("valid-instantiator-p", Fvalid_instantiator_p, 2, 2, 0, /*
1164 Return non-nil if INSTANTIATOR is valid for SPECIFIER-TYPE.
1165 */
1166 (instantiator, specifier_type))
1167 {
1168 struct specifier_methods *meths = decode_specifier_type (specifier_type,
1169 ERROR_ME);
1170
1171 return check_valid_instantiator (instantiator, meths, ERROR_ME_NOT);
1172 }
1173
1174 static Lisp_Object
1175 check_valid_inst_list (Lisp_Object inst_list, struct specifier_methods *meths,
1176 Error_behavior errb)
1177 {
1178 Lisp_Object rest;
1179
1180 LIST_LOOP (rest, inst_list)
1181 {
1182 Lisp_Object inst_pair, tag_set;
1183
1184 if (!CONSP (rest))
1185 {
1186 maybe_signal_simple_error ("Invalid instantiator list", inst_list,
1187 Qspecifier, errb);
1188 return Qnil;
1189 }
1190 if (!CONSP (inst_pair = XCAR (rest)))
1191 {
1192 maybe_signal_simple_error ("Invalid instantiator pair", inst_pair,
1193 Qspecifier, errb);
1194 return Qnil;
1195 }
1196 if (NILP (Fvalid_specifier_tag_set_p (tag_set = XCAR (inst_pair))))
1197 {
1198 maybe_signal_simple_error ("Invalid specifier tag", tag_set,
1199 Qspecifier, errb);
1200 return Qnil;
1201 }
1202
1203 if (NILP (check_valid_instantiator (XCDR (inst_pair), meths, errb)))
1204 return Qnil;
1205 }
1206
1207 return Qt;
1208 }
1209
1210 DEFUN ("check-valid-inst-list", Fcheck_valid_inst_list, 2, 2, 0, /*
1211 Signal an error if INST-LIST is invalid for specifier type TYPE.
1212 */
1213 (inst_list, type))
1214 {
1215 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1216
1217 return check_valid_inst_list (inst_list, meths, ERROR_ME);
1218 }
1219
1220 DEFUN ("valid-inst-list-p", Fvalid_inst_list_p, 2, 2, 0, /*
1221 Return non-nil if INST-LIST is valid for specifier type TYPE.
1222 */
1223 (inst_list, type))
1224 {
1225 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1226
1227 return check_valid_inst_list (inst_list, meths, ERROR_ME_NOT);
1228 }
1229
1230 static Lisp_Object
1231 check_valid_spec_list (Lisp_Object spec_list, struct specifier_methods *meths,
1232 Error_behavior errb)
1233 {
1234 Lisp_Object rest;
1235
1236 LIST_LOOP (rest, spec_list)
1237 {
1238 Lisp_Object spec, locale;
1239 if (!CONSP (rest) || !CONSP (spec = XCAR (rest)))
1240 {
1241 maybe_signal_simple_error ("Invalid specification list", spec_list,
1242 Qspecifier, errb);
1243 return Qnil;
1244 }
1245 if (NILP (Fvalid_specifier_locale_p (locale = XCAR (spec))))
1246 {
1247 maybe_signal_simple_error ("Invalid specifier locale", locale,
1248 Qspecifier, errb);
1249 return Qnil;
1250 }
1251
1252 if (NILP (check_valid_inst_list (XCDR (spec), meths, errb)))
1253 return Qnil;
1254 }
1255
1256 return Qt;
1257 }
1258
1259 DEFUN ("check-valid-spec-list", Fcheck_valid_spec_list, 2, 2, 0, /*
1260 Signal an error if SPEC-LIST is invalid for specifier type TYPE.
1261 */
1262 (spec_list, type))
1263 {
1264 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1265
1266 return check_valid_spec_list (spec_list, meths, ERROR_ME);
1267 }
1268
1269 DEFUN ("valid-spec-list-p", Fvalid_spec_list_p, 2, 2, 0, /*
1270 Return non-nil if SPEC-LIST is valid for specifier type TYPE.
1271 */
1272 (spec_list, type))
1273 {
1274 struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME);
1275
1276 return check_valid_spec_list (spec_list, meths, ERROR_ME_NOT);
1277 }
1278
1279 enum spec_add_meth
1280 decode_how_to_add_specification (Lisp_Object how_to_add)
1281 {
1282 if (NILP (how_to_add) || EQ (Qremove_tag_set_prepend, how_to_add))
1283 return SPEC_REMOVE_TAG_SET_PREPEND;
1284 if (EQ (Qremove_tag_set_append, how_to_add))
1285 return SPEC_REMOVE_TAG_SET_APPEND;
1286 if (EQ (Qappend, how_to_add))
1287 return SPEC_APPEND;
1288 if (EQ (Qprepend, how_to_add))
1289 return SPEC_PREPEND;
1290 if (EQ (Qremove_locale, how_to_add))
1291 return SPEC_REMOVE_LOCALE;
1292 if (EQ (Qremove_locale_type, how_to_add))
1293 return SPEC_REMOVE_LOCALE_TYPE;
1294 if (EQ (Qremove_all, how_to_add))
1295 return SPEC_REMOVE_ALL;
1296
1297 signal_simple_error ("Invalid `how-to-add' flag", how_to_add);
1298
1299 return SPEC_PREPEND; /* not reached */
1300 }
1301
1302 /* Given a specifier object SPEC, return bodily specifier if SPEC is a
1303 ghost specifier, otherwise return the object itself
1304 */
1305 static Lisp_Object
1306 bodily_specifier (Lisp_Object spec)
1307 {
1308 return (GHOST_SPECIFIER_P (XSPECIFIER (spec))
1309 ? XSPECIFIER(spec)->magic_parent : spec);
1310 }
1311
1312 /* Signal error if (specifier SPEC is read-only.
1313 Read only are ghost specifiers unless Vunlock_ghost_specifiers is
1314 non-nil. All other specifiers are read-write.
1315 */
1316 static void
1317 check_modifiable_specifier (Lisp_Object spec)
1318 {
1319 if (NILP (Vunlock_ghost_specifiers)
1320 && GHOST_SPECIFIER_P (XSPECIFIER (spec)))
1321 signal_simple_error ("Attempt to modify read-only specifier",
1322 list1 (spec));
1323 }
1324
1325 /* Helper function which unwind protects the value of
1326 Vunlock_ghost_specifiers, then sets it to non-nil value */
1327 static Lisp_Object
1328 restore_unlock_value (Lisp_Object val)
1329 {
1330 Vunlock_ghost_specifiers = val;
1331 return val;
1332 }
1333
1334 int
1335 unlock_ghost_specifiers_protected (void)
1336 {
1337 int depth = specpdl_depth ();
1338 record_unwind_protect (restore_unlock_value,
1339 Vunlock_ghost_specifiers);
1340 Vunlock_ghost_specifiers = Qt;
1341 return depth;
1342 }
1343
1344 /* This gets hit so much that the function call overhead had a
1345 measurable impact (according to Quantify). #### We should figure
1346 out the frequency with which this is called with the various types
1347 and reorder the check accordingly. */
1348 #define SPECIFIER_GET_SPEC_LIST(specifier, type) \
1349 (type == LOCALE_GLOBAL ? &(XSPECIFIER (specifier)->global_specs) : \
1350 type == LOCALE_DEVICE ? &(XSPECIFIER (specifier)->device_specs) : \
1351 type == LOCALE_FRAME ? &(XSPECIFIER (specifier)->frame_specs) : \
1352 type == LOCALE_WINDOW ? &(XWEAK_LIST_LIST \
1353 (XSPECIFIER (specifier)->window_specs)) : \
1354 type == LOCALE_BUFFER ? &(XSPECIFIER (specifier)->buffer_specs) : \
1355 0)
1356
1357 static Lisp_Object *
1358 specifier_get_inst_list (Lisp_Object specifier, Lisp_Object locale,
1359 enum spec_locale_type type)
1360 {
1361 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1362 Lisp_Object specification;
1363
1364 if (type == LOCALE_GLOBAL)
1365 return spec_list;
1366 /* Calling assq_no_quit when it is just going to return nil anyhow
1367 is extremely expensive. So sayeth Quantify. */
1368 if (!CONSP (*spec_list))
1369 return 0;
1370 specification = assq_no_quit (locale, *spec_list);
1371 if (NILP (specification))
1372 return 0;
1373 return &XCDR (specification);
1374 }
1375
1376 /* For the given INST_LIST, return a new INST_LIST containing all elements
1377 where TAG-SET matches the element's tag set. EXACT_P indicates whether
1378 the match must be exact (as opposed to a subset). SHORT_P indicates
1379 that the short form (for `specifier-specs') should be returned if
1380 possible. If COPY_TREE_P, `copy-tree' is used to ensure that no
1381 elements of the new list are shared with the initial list.
1382 */
1383
1384 static Lisp_Object
1385 specifier_process_inst_list (Lisp_Object inst_list,
1386 Lisp_Object tag_set, int exact_p,
1387 int short_p, int copy_tree_p)
1388 {
1389 Lisp_Object retval = Qnil;
1390 Lisp_Object rest;
1391 struct gcpro gcpro1;
1392
1393 GCPRO1 (retval);
1394 LIST_LOOP (rest, inst_list)
1395 {
1396 Lisp_Object tagged_inst = XCAR (rest);
1397 Lisp_Object tagged_inst_tag = XCAR (tagged_inst);
1398 if (tag_sets_match_p (tag_set, tagged_inst_tag, exact_p))
1399 {
1400 if (short_p && NILP (tagged_inst_tag))
1401 retval = Fcons (copy_tree_p ?
1402 Fcopy_tree (XCDR (tagged_inst), Qt) :
1403 XCDR (tagged_inst),
1404 retval);
1405 else
1406 retval = Fcons (copy_tree_p ? Fcopy_tree (tagged_inst, Qt) :
1407 tagged_inst, retval);
1408 }
1409 }
1410 retval = Fnreverse (retval);
1411 UNGCPRO;
1412 /* If there is a single instantiator and the short form is
1413 requested, return just the instantiator (rather than a one-element
1414 list of it) unless it is nil (so that it can be distinguished from
1415 no instantiators at all). */
1416 if (short_p && CONSP (retval) && !NILP (XCAR (retval)) &&
1417 NILP (XCDR (retval)))
1418 return XCAR (retval);
1419 else
1420 return retval;
1421 }
1422
1423 static Lisp_Object
1424 specifier_get_external_inst_list (Lisp_Object specifier, Lisp_Object locale,
1425 enum spec_locale_type type,
1426 Lisp_Object tag_set, int exact_p,
1427 int short_p, int copy_tree_p)
1428 {
1429 Lisp_Object *inst_list = specifier_get_inst_list (specifier, locale,
1430 type);
1431 if (!inst_list || NILP (*inst_list))
1432 {
1433 /* nil for *inst_list should only occur in 'global */
1434 assert (!inst_list || EQ (locale, Qglobal));
1435 return Qnil;
1436 }
1437
1438 return specifier_process_inst_list (*inst_list, tag_set, exact_p,
1439 short_p, copy_tree_p);
1440 }
1441
1442 static Lisp_Object
1443 specifier_get_external_spec_list (Lisp_Object specifier,
1444 enum spec_locale_type type,
1445 Lisp_Object tag_set, int exact_p)
1446 {
1447 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1448 Lisp_Object retval = Qnil;
1449 Lisp_Object rest;
1450 struct gcpro gcpro1;
1451
1452 assert (type != LOCALE_GLOBAL);
1453 /* We're about to let stuff go external; make sure there aren't
1454 any dead objects */
1455 *spec_list = cleanup_assoc_list (*spec_list);
1456
1457 GCPRO1 (retval);
1458 LIST_LOOP (rest, *spec_list)
1459 {
1460 Lisp_Object spec = XCAR (rest);
1461 Lisp_Object inst_list =
1462 specifier_process_inst_list (XCDR (spec), tag_set, exact_p, 0, 1);
1463 if (!NILP (inst_list))
1464 retval = Fcons (Fcons (XCAR (spec), inst_list), retval);
1465 }
1466 RETURN_UNGCPRO (Fnreverse (retval));
1467 }
1468
1469 static Lisp_Object *
1470 specifier_new_spec (Lisp_Object specifier, Lisp_Object locale,
1471 enum spec_locale_type type)
1472 {
1473 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1474 Lisp_Object new_spec = Fcons (locale, Qnil);
1475 assert (type != LOCALE_GLOBAL);
1476 *spec_list = Fcons (new_spec, *spec_list);
1477 return &XCDR (new_spec);
1478 }
1479
1480 /* For the given INST_LIST, return a new list comprised of elements
1481 where TAG_SET does not match the element's tag set. This operation
1482 is destructive. */
1483
1484 static Lisp_Object
1485 specifier_process_remove_inst_list (Lisp_Object inst_list,
1486 Lisp_Object tag_set, int exact_p,
1487 int *was_removed)
1488 {
1489 Lisp_Object prev = Qnil, rest;
1490
1491 *was_removed = 0;
1492
1493 LIST_LOOP (rest, inst_list)
1494 {
1495 if (tag_sets_match_p (tag_set, XCAR (XCAR (rest)), exact_p))
1496 {
1497 /* time to remove. */
1498 *was_removed = 1;
1499 if (NILP (prev))
1500 inst_list = XCDR (rest);
1501 else
1502 XCDR (prev) = XCDR (rest);
1503 }
1504 else
1505 prev = rest;
1506 }
1507
1508 return inst_list;
1509 }
1510
1511 static void
1512 specifier_remove_spec (Lisp_Object specifier, Lisp_Object locale,
1513 enum spec_locale_type type,
1514 Lisp_Object tag_set, int exact_p)
1515 {
1516 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1517 Lisp_Object assoc;
1518 int was_removed;
1519
1520 if (type == LOCALE_GLOBAL)
1521 *spec_list = specifier_process_remove_inst_list (*spec_list, tag_set,
1522 exact_p, &was_removed);
1523 else
1524 {
1525 assoc = assq_no_quit (locale, *spec_list);
1526 if (NILP (assoc))
1527 /* this locale is not found. */
1528 return;
1529 XCDR (assoc) = specifier_process_remove_inst_list (XCDR (assoc),
1530 tag_set, exact_p,
1531 &was_removed);
1532 if (NILP (XCDR (assoc)))
1533 /* no inst-pairs left; remove this locale entirely. */
1534 *spec_list = remassq_no_quit (locale, *spec_list);
1535 }
1536
1537 if (was_removed)
1538 MAYBE_SPECMETH (XSPECIFIER (specifier), after_change,
1539 (bodily_specifier (specifier), locale));
1540 }
1541
1542 static void
1543 specifier_remove_locale_type (Lisp_Object specifier,
1544 enum spec_locale_type type,
1545 Lisp_Object tag_set, int exact_p)
1546 {
1547 Lisp_Object *spec_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1548 Lisp_Object prev = Qnil, rest;
1549
1550 assert (type != LOCALE_GLOBAL);
1551 LIST_LOOP (rest, *spec_list)
1552 {
1553 int was_removed;
1554 int remove_spec = 0;
1555 Lisp_Object spec = XCAR (rest);
1556
1557 /* There may be dead objects floating around */
1558 /* remember, dead windows can become alive again. */
1559 if (!WINDOWP (XCAR (spec)) && object_dead_p (XCAR (spec)))
1560 {
1561 remove_spec = 1;
1562 was_removed = 0;
1563 }
1564 else
1565 {
1566 XCDR (spec) = specifier_process_remove_inst_list (XCDR (spec),
1567 tag_set, exact_p,
1568 &was_removed);
1569 if (NILP (XCDR (spec)))
1570 remove_spec = 1;
1571 }
1572
1573 if (remove_spec)
1574 {
1575 if (NILP (prev))
1576 *spec_list = XCDR (rest);
1577 else
1578 XCDR (prev) = XCDR (rest);
1579 }
1580 else
1581 prev = rest;
1582
1583 if (was_removed)
1584 MAYBE_SPECMETH (XSPECIFIER (specifier), after_change,
1585 (bodily_specifier (specifier), XCAR (spec)));
1586 }
1587 }
1588
1589 /* NEW_LIST is going to be added to INST_LIST, with add method ADD_METH.
1590 Frob INST_LIST according to ADD_METH. No need to call an after-change
1591 function; the calling function will do this. Return either SPEC_PREPEND
1592 or SPEC_APPEND, indicating whether to prepend or append the NEW_LIST. */
1593
1594 static enum spec_add_meth
1595 handle_multiple_add_insts (Lisp_Object *inst_list,
1596 Lisp_Object new_list,
1597 enum spec_add_meth add_meth)
1598 {
1599 switch (add_meth)
1600 {
1601 case SPEC_REMOVE_TAG_SET_APPEND:
1602 add_meth = SPEC_APPEND;
1603 goto remove_tag_set;
1604 case SPEC_REMOVE_TAG_SET_PREPEND:
1605 add_meth = SPEC_PREPEND;
1606 remove_tag_set:
1607 {
1608 Lisp_Object rest;
1609
1610 LIST_LOOP (rest, new_list)
1611 {
1612 Lisp_Object canontag = canonicalize_tag_set (XCAR (XCAR (rest)));
1613 struct gcpro gcpro1;
1614
1615 GCPRO1 (canontag);
1616 /* pull out all elements from the existing list with the
1617 same tag as any tags in NEW_LIST. */
1618 *inst_list = remassoc_no_quit (canontag, *inst_list);
1619 UNGCPRO;
1620 }
1621 }
1622 return add_meth;
1623 case SPEC_REMOVE_LOCALE:
1624 *inst_list = Qnil;
1625 return SPEC_PREPEND;
1626 case SPEC_APPEND:
1627 return add_meth;
1628 default:
1629 return SPEC_PREPEND;
1630 }
1631 }
1632
1633 /* Given a LOCALE and INST_LIST that is going to be added to SPECIFIER,
1634 copy, canonicalize, and call the going_to_add methods as necessary
1635 to produce a new list that is the one that really will be added
1636 to the specifier. */
1637
1638 static Lisp_Object
1639 build_up_processed_list (Lisp_Object specifier, Lisp_Object locale,
1640 Lisp_Object inst_list)
1641 {
1642 /* The return value of this function must be GCPRO'd. */
1643 Lisp_Object rest, list_to_build_up = Qnil;
1644 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
1645 struct gcpro gcpro1;
1646
1647 GCPRO1 (list_to_build_up);
1648 LIST_LOOP (rest, inst_list)
1649 {
1650 Lisp_Object tag_set = XCAR (XCAR (rest));
1651 Lisp_Object instantiator = Fcopy_tree (XCDR (XCAR (rest)), Qt);
1652 Lisp_Object sub_inst_list = Qnil;
1653 struct gcpro ngcpro1, ngcpro2;
1654
1655 NGCPRO2 (instantiator, sub_inst_list);
1656 /* call the will-add method; it may GC */
1657 sub_inst_list = HAS_SPECMETH_P (sp, going_to_add) ?
1658 SPECMETH (sp, going_to_add,
1659 (bodily_specifier (specifier), locale,
1660 tag_set, instantiator)) :
1661 Qt;
1662 if (EQ (sub_inst_list, Qt))
1663 /* no change here. */
1664 sub_inst_list = list1 (Fcons (canonicalize_tag_set (tag_set),
1665 instantiator));
1666 else
1667 {
1668 /* now canonicalize all the tag sets in the new objects */
1669 Lisp_Object rest2;
1670 LIST_LOOP (rest2, sub_inst_list)
1671 XCAR (XCAR (rest2)) = canonicalize_tag_set (XCAR (XCAR (rest2)));
1672 }
1673
1674 list_to_build_up = nconc2 (sub_inst_list, list_to_build_up);
1675 NUNGCPRO;
1676 }
1677
1678 RETURN_UNGCPRO (Fnreverse (list_to_build_up));
1679 }
1680
1681 /* Add a specification (locale and instantiator list) to a specifier.
1682 ADD_METH specifies what to do with existing specifications in the
1683 specifier, and is an enum that corresponds to the values in
1684 `add-spec-to-specifier'. The calling routine is responsible for
1685 validating LOCALE and INST-LIST, but the tag-sets in INST-LIST
1686 do not need to be canonicalized. */
1687
1688 /* #### I really need to rethink the after-change
1689 functions to make them easier to use and more efficient. */
1690
1691 static void
1692 specifier_add_spec (Lisp_Object specifier, Lisp_Object locale,
1693 Lisp_Object inst_list, enum spec_add_meth add_meth)
1694 {
1695 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
1696 enum spec_locale_type type = locale_type_from_locale (locale);
1697 Lisp_Object *orig_inst_list, tem;
1698 Lisp_Object list_to_build_up = Qnil;
1699 struct gcpro gcpro1;
1700
1701 GCPRO1 (list_to_build_up);
1702 list_to_build_up = build_up_processed_list (specifier, locale, inst_list);
1703 /* Now handle REMOVE_LOCALE_TYPE and REMOVE_ALL. These are the
1704 add-meth types that affect locales other than this one. */
1705 if (add_meth == SPEC_REMOVE_LOCALE_TYPE)
1706 specifier_remove_locale_type (specifier, type, Qnil, 0);
1707 else if (add_meth == SPEC_REMOVE_ALL)
1708 {
1709 specifier_remove_locale_type (specifier, LOCALE_BUFFER, Qnil, 0);
1710 specifier_remove_locale_type (specifier, LOCALE_WINDOW, Qnil, 0);
1711 specifier_remove_locale_type (specifier, LOCALE_FRAME, Qnil, 0);
1712 specifier_remove_locale_type (specifier, LOCALE_DEVICE, Qnil, 0);
1713 specifier_remove_spec (specifier, Qglobal, LOCALE_GLOBAL, Qnil, 0);
1714 }
1715
1716 orig_inst_list = specifier_get_inst_list (specifier, locale, type);
1717 if (!orig_inst_list)
1718 orig_inst_list = specifier_new_spec (specifier, locale, type);
1719 add_meth = handle_multiple_add_insts (orig_inst_list, list_to_build_up,
1720 add_meth);
1721
1722 if (add_meth == SPEC_PREPEND)
1723 tem = nconc2 (list_to_build_up, *orig_inst_list);
1724 else if (add_meth == SPEC_APPEND)
1725 tem = nconc2 (*orig_inst_list, list_to_build_up);
1726 else
1727 abort ();
1728
1729 *orig_inst_list = tem;
1730
1731 UNGCPRO;
1732
1733 /* call the after-change method */
1734 MAYBE_SPECMETH (sp, after_change,
1735 (bodily_specifier (specifier), locale));
1736 }
1737
1738 static void
1739 specifier_copy_spec (Lisp_Object specifier, Lisp_Object dest,
1740 Lisp_Object locale, enum spec_locale_type type,
1741 Lisp_Object tag_set, int exact_p,
1742 enum spec_add_meth add_meth)
1743 {
1744 Lisp_Object inst_list =
1745 specifier_get_external_inst_list (specifier, locale, type, tag_set,
1746 exact_p, 0, 0);
1747 specifier_add_spec (dest, locale, inst_list, add_meth);
1748 }
1749
1750 static void
1751 specifier_copy_locale_type (Lisp_Object specifier, Lisp_Object dest,
1752 enum spec_locale_type type,
1753 Lisp_Object tag_set, int exact_p,
1754 enum spec_add_meth add_meth)
1755 {
1756 Lisp_Object *src_list = SPECIFIER_GET_SPEC_LIST (specifier, type);
1757 Lisp_Object rest;
1758
1759 /* This algorithm is O(n^2) in running time.
1760 It's certainly possible to implement an O(n log n) algorithm,
1761 but I doubt there's any need to. */
1762
1763 LIST_LOOP (rest, *src_list)
1764 {
1765 Lisp_Object spec = XCAR (rest);
1766 /* There may be dead objects floating around */
1767 /* remember, dead windows can become alive again. */
1768 if (WINDOWP (XCAR (spec)) || !object_dead_p (XCAR (spec)))
1769 specifier_add_spec
1770 (dest, XCAR (spec),
1771 specifier_process_inst_list (XCDR (spec), tag_set, exact_p, 0, 0),
1772 add_meth);
1773 }
1774 }
1775
1776 /* map MAPFUN over the locales in SPECIFIER that are given in LOCALE.
1777 CLOSURE is passed unchanged to MAPFUN. LOCALE can be one of
1778
1779 -- nil (same as 'all)
1780 -- a single locale, locale type, or 'all
1781 -- a list of locales, locale types, and/or 'all
1782
1783 MAPFUN is called for each locale and locale type given; for 'all,
1784 it is called for the locale 'global and for the four possible
1785 locale types. In each invocation, either LOCALE will be a locale
1786 and LOCALE_TYPE will be the locale type of this locale,
1787 or LOCALE will be nil and LOCALE_TYPE will be a locale type.
1788 If MAPFUN ever returns non-zero, the mapping is halted and the
1789 value returned is returned from map_specifier(). Otherwise, the
1790 mapping proceeds to the end and map_specifier() returns 0.
1791 */
1792
1793 static int
1794 map_specifier (Lisp_Object specifier, Lisp_Object locale,
1795 int (*mapfun) (Lisp_Object specifier,
1796 Lisp_Object locale,
1797 enum spec_locale_type locale_type,
1798 Lisp_Object tag_set,
1799 int exact_p,
1800 void *closure),
1801 Lisp_Object tag_set, Lisp_Object exact_p,
1802 void *closure)
1803 {
1804 int retval = 0;
1805 Lisp_Object rest;
1806 struct gcpro gcpro1, gcpro2;
1807
1808 GCPRO2 (tag_set, locale);
1809 locale = decode_locale_list (locale);
1810 tag_set = decode_specifier_tag_set (tag_set);
1811 tag_set = canonicalize_tag_set (tag_set);
1812
1813 LIST_LOOP (rest, locale)
1814 {
1815 Lisp_Object theloc = XCAR (rest);
1816 if (!NILP (Fvalid_specifier_locale_p (theloc)))
1817 {
1818 retval = (*mapfun) (specifier, theloc,
1819 locale_type_from_locale (theloc),
1820 tag_set, !NILP (exact_p), closure);
1821 if (retval)
1822 break;
1823 }
1824 else if (!NILP (Fvalid_specifier_locale_type_p (theloc)))
1825 {
1826 retval = (*mapfun) (specifier, Qnil,
1827 decode_locale_type (theloc), tag_set,
1828 !NILP (exact_p), closure);
1829 if (retval)
1830 break;
1831 }
1832 else
1833 {
1834 assert (EQ (theloc, Qall));
1835 retval = (*mapfun) (specifier, Qnil, LOCALE_BUFFER, tag_set,
1836 !NILP (exact_p), closure);
1837 if (retval)
1838 break;
1839 retval = (*mapfun) (specifier, Qnil, LOCALE_WINDOW, tag_set,
1840 !NILP (exact_p), closure);
1841 if (retval)
1842 break;
1843 retval = (*mapfun) (specifier, Qnil, LOCALE_FRAME, tag_set,
1844 !NILP (exact_p), closure);
1845 if (retval)
1846 break;
1847 retval = (*mapfun) (specifier, Qnil, LOCALE_DEVICE, tag_set,
1848 !NILP (exact_p), closure);
1849 if (retval)
1850 break;
1851 retval = (*mapfun) (specifier, Qglobal, LOCALE_GLOBAL, tag_set,
1852 !NILP (exact_p), closure);
1853 if (retval)
1854 break;
1855 }
1856 }
1857
1858 UNGCPRO;
1859 return retval;
1860 }
1861
1862 DEFUN ("add-spec-to-specifier", Fadd_spec_to_specifier, 2, 5, 0, /*
1863 Add a specification to SPECIFIER.
1864 The specification maps from LOCALE (which should be a window, buffer,
1865 frame, device, or 'global, and defaults to 'global) to INSTANTIATOR,
1866 whose allowed values depend on the type of the specifier. Optional
1867 argument TAG-SET limits the instantiator to apply only to the specified
1868 tag set, which should be a list of tags all of which must match the
1869 device being instantiated over (tags are a device type, a device class,
1870 or tags defined with `define-specifier-tag'). Specifying a single
1871 symbol for TAG-SET is equivalent to specifying a one-element list
1872 containing that symbol. Optional argument HOW-TO-ADD specifies what to
1873 do if there are already specifications in the specifier.
1874 It should be one of
1875
1876 'prepend Put at the beginning of the current list of
1877 instantiators for LOCALE.
1878 'append Add to the end of the current list of
1879 instantiators for LOCALE.
1880 'remove-tag-set-prepend (this is the default)
1881 Remove any existing instantiators whose tag set is
1882 the same as TAG-SET; then put the new instantiator
1883 at the beginning of the current list. ("Same tag
1884 set" means that they contain the same elements.
1885 The order may be different.)
1886 'remove-tag-set-append
1887 Remove any existing instantiators whose tag set is
1888 the same as TAG-SET; then put the new instantiator
1889 at the end of the current list.
1890 'remove-locale Remove all previous instantiators for this locale
1891 before adding the new spec.
1892 'remove-locale-type Remove all specifications for all locales of the
1893 same type as LOCALE (this includes LOCALE itself)
1894 before adding the new spec.
1895 'remove-all Remove all specifications from the specifier
1896 before adding the new spec.
1897
1898 You can retrieve the specifications for a particular locale or locale type
1899 with the function `specifier-spec-list' or `specifier-specs'.
1900 */
1901 (specifier, instantiator, locale, tag_set, how_to_add))
1902 {
1903 enum spec_add_meth add_meth;
1904 Lisp_Object inst_list;
1905 struct gcpro gcpro1;
1906
1907 CHECK_SPECIFIER (specifier);
1908 check_modifiable_specifier (specifier);
1909
1910 locale = decode_locale (locale);
1911 check_valid_instantiator (instantiator,
1912 decode_specifier_type
1913 (Fspecifier_type (specifier), ERROR_ME),
1914 ERROR_ME);
1915 /* tag_set might be newly-created material, but it's part of inst_list
1916 so is properly GC-protected. */
1917 tag_set = decode_specifier_tag_set (tag_set);
1918 add_meth = decode_how_to_add_specification (how_to_add);
1919
1920 inst_list = list1 (Fcons (tag_set, instantiator));
1921 GCPRO1 (inst_list);
1922 specifier_add_spec (specifier, locale, inst_list, add_meth);
1923 recompute_cached_specifier_everywhere (specifier);
1924 RETURN_UNGCPRO (Qnil);
1925 }
1926
1927 DEFUN ("add-spec-list-to-specifier", Fadd_spec_list_to_specifier, 2, 3, 0, /*
1928 Add a spec-list (a list of specifications) to SPECIFIER.
1929 The format of a spec-list is
1930
1931 ((LOCALE (TAG-SET . INSTANTIATOR) ...) ...)
1932
1933 where
1934 LOCALE := a window, a buffer, a frame, a device, or 'global
1935 TAG-SET := an unordered list of zero or more TAGS, each of which
1936 is a symbol
1937 TAG := a device class (see `valid-device-class-p'), a device type
1938 (see `valid-console-type-p'), or a tag defined with
1939 `define-specifier-tag'
1940 INSTANTIATOR := format determined by the type of specifier
1941
1942 The pair (TAG-SET . INSTANTIATOR) is called an `inst-pair'.
1943 A list of inst-pairs is called an `inst-list'.
1944 The pair (LOCALE . INST-LIST) is called a `specification' or `spec'.
1945 A spec-list, then, can be viewed as a list of specifications.
1946
1947 HOW-TO-ADD specifies how to combine the new specifications with
1948 the existing ones, and has the same semantics as for
1949 `add-spec-to-specifier'.
1950
1951 In many circumstances, the higher-level function `set-specifier' is
1952 more convenient and should be used instead.
1953 */
1954 (specifier, spec_list, how_to_add))
1955 {
1956 enum spec_add_meth add_meth;
1957 Lisp_Object rest;
1958
1959 CHECK_SPECIFIER (specifier);
1960 check_modifiable_specifier (specifier);
1961
1962 check_valid_spec_list (spec_list,
1963 decode_specifier_type
1964 (Fspecifier_type (specifier), ERROR_ME),
1965 ERROR_ME);
1966 add_meth = decode_how_to_add_specification (how_to_add);
1967
1968 LIST_LOOP (rest, spec_list)
1969 {
1970 /* Placating the GCC god. */
1971 Lisp_Object specification = XCAR (rest);
1972 Lisp_Object locale = XCAR (specification);
1973 Lisp_Object inst_list = XCDR (specification);
1974
1975 specifier_add_spec (specifier, locale, inst_list, add_meth);
1976 }
1977 recompute_cached_specifier_everywhere (specifier);
1978 return Qnil;
1979 }
1980
1981 void
1982 add_spec_to_ghost_specifier (Lisp_Object specifier, Lisp_Object instantiator,
1983 Lisp_Object locale, Lisp_Object tag_set,
1984 Lisp_Object how_to_add)
1985 {
1986 int depth = unlock_ghost_specifiers_protected ();
1987 Fadd_spec_to_specifier (XSPECIFIER(specifier)->fallback,
1988 instantiator, locale, tag_set, how_to_add);
1989 unbind_to (depth, Qnil);
1990 }
1991
1992 struct specifier_spec_list_closure
1993 {
1994 Lisp_Object head, tail;
1995 };
1996
1997 static int
1998 specifier_spec_list_mapfun (Lisp_Object specifier,
1999 Lisp_Object locale,
2000 enum spec_locale_type locale_type,
2001 Lisp_Object tag_set,
2002 int exact_p,
2003 void *closure)
2004 {
2005 struct specifier_spec_list_closure *cl =
2006 (struct specifier_spec_list_closure *) closure;
2007 Lisp_Object partial;
2008
2009 if (NILP (locale))
2010 partial = specifier_get_external_spec_list (specifier,
2011 locale_type,
2012 tag_set, exact_p);
2013 else
2014 {
2015 partial = specifier_get_external_inst_list (specifier, locale,
2016 locale_type, tag_set,
2017 exact_p, 0, 1);
2018 if (!NILP (partial))
2019 partial = list1 (Fcons (locale, partial));
2020 }
2021 if (NILP (partial))
2022 return 0;
2023
2024 /* tack on the new list */
2025 if (NILP (cl->tail))
2026 cl->head = cl->tail = partial;
2027 else
2028 XCDR (cl->tail) = partial;
2029 /* find the new tail */
2030 while (CONSP (XCDR (cl->tail)))
2031 cl->tail = XCDR (cl->tail);
2032 return 0;
2033 }
2034
2035 /* For the given SPECIFIER create and return a list of all specs
2036 contained within it, subject to LOCALE. If LOCALE is a locale, only
2037 specs in that locale will be returned. If LOCALE is a locale type,
2038 all specs in all locales of that type will be returned. If LOCALE is
2039 nil, all specs will be returned. This always copies lists and never
2040 returns the actual lists, because we do not want someone manipulating
2041 the actual objects. This may cause a slight loss of potential
2042 functionality but if we were to allow it then a user could manage to
2043 violate our assertion that the specs contained in the actual
2044 specifier lists are all valid. */
2045
2046 DEFUN ("specifier-spec-list", Fspecifier_spec_list, 1, 4, 0, /*
2047 Return the spec-list of specifications for SPECIFIER in LOCALE.
2048
2049 If LOCALE is a particular locale (a buffer, window, frame, device,
2050 or 'global), a spec-list consisting of the specification for that
2051 locale will be returned.
2052
2053 If LOCALE is a locale type (i.e. 'buffer, 'window, 'frame, or 'device),
2054 a spec-list of the specifications for all locales of that type will be
2055 returned.
2056
2057 If LOCALE is nil or 'all, a spec-list of all specifications in SPECIFIER
2058 will be returned.
2059
2060 LOCALE can also be a list of locales, locale types, and/or 'all; the
2061 result is as if `specifier-spec-list' were called on each element of the
2062 list and the results concatenated together.
2063
2064 Only instantiators where TAG-SET (a list of zero or more tags) is a
2065 subset of (or possibly equal to) the instantiator's tag set are returned.
2066 \(The default value of nil is a subset of all tag sets, so in this case
2067 no instantiators will be screened out.) If EXACT-P is non-nil, however,
2068 TAG-SET must be equal to an instantiator's tag set for the instantiator
2069 to be returned.
2070 */
2071 (specifier, locale, tag_set, exact_p))
2072 {
2073 struct specifier_spec_list_closure cl;
2074 struct gcpro gcpro1, gcpro2;
2075
2076 CHECK_SPECIFIER (specifier);
2077 cl.head = cl.tail = Qnil;
2078 GCPRO2 (cl.head, cl.tail);
2079 map_specifier (specifier, locale, specifier_spec_list_mapfun,
2080 tag_set, exact_p, &cl);
2081 UNGCPRO;
2082 return cl.head;
2083 }
2084
2085
2086 DEFUN ("specifier-specs", Fspecifier_specs, 1, 4, 0, /*
2087 Return the specification(s) for SPECIFIER in LOCALE.
2088
2089 If LOCALE is a single locale or is a list of one element containing a
2090 single locale, then a "short form" of the instantiators for that locale
2091 will be returned. Otherwise, this function is identical to
2092 `specifier-spec-list'.
2093
2094 The "short form" is designed for readability and not for ease of use
2095 in Lisp programs, and is as follows:
2096
2097 1. If there is only one instantiator, then an inst-pair (i.e. cons of
2098 tag and instantiator) will be returned; otherwise a list of
2099 inst-pairs will be returned.
2100 2. For each inst-pair returned, if the instantiator's tag is 'any,
2101 the tag will be removed and the instantiator itself will be returned
2102 instead of the inst-pair.
2103 3. If there is only one instantiator, its value is nil, and its tag is
2104 'any, a one-element list containing nil will be returned rather
2105 than just nil, to distinguish this case from there being no
2106 instantiators at all.
2107 */
2108 (specifier, locale, tag_set, exact_p))
2109 {
2110 if (!NILP (Fvalid_specifier_locale_p (locale)) ||
2111 (CONSP (locale) && !NILP (Fvalid_specifier_locale_p (XCAR (locale))) &&
2112 NILP (XCDR (locale))))
2113 {
2114 struct gcpro gcpro1;
2115
2116 CHECK_SPECIFIER (specifier);
2117 if (CONSP (locale))
2118 locale = XCAR (locale);
2119 GCPRO1 (tag_set);
2120 tag_set = decode_specifier_tag_set (tag_set);
2121 tag_set = canonicalize_tag_set (tag_set);
2122 RETURN_UNGCPRO
2123 (specifier_get_external_inst_list (specifier, locale,
2124 locale_type_from_locale (locale),
2125 tag_set, !NILP (exact_p), 1, 1));
2126 }
2127 else
2128 return Fspecifier_spec_list (specifier, locale, tag_set, exact_p);
2129 }
2130
2131 static int
2132 remove_specifier_mapfun (Lisp_Object specifier,
2133 Lisp_Object locale,
2134 enum spec_locale_type locale_type,
2135 Lisp_Object tag_set,
2136 int exact_p,
2137 void *ignored_closure)
2138 {
2139 if (NILP (locale))
2140 specifier_remove_locale_type (specifier, locale_type, tag_set, exact_p);
2141 else
2142 specifier_remove_spec (specifier, locale, locale_type, tag_set, exact_p);
2143 return 0;
2144 }
2145
2146 DEFUN ("remove-specifier", Fremove_specifier, 1, 4, 0, /*
2147 Remove specification(s) for SPECIFIER.
2148
2149 If LOCALE is a particular locale (a window, buffer, frame, device,
2150 or 'global), the specification for that locale will be removed.
2151
2152 If instead, LOCALE is a locale type (i.e. 'window, 'buffer, 'frame,
2153 or 'device), the specifications for all locales of that type will be
2154 removed.
2155
2156 If LOCALE is nil or 'all, all specifications will be removed.
2157
2158 LOCALE can also be a list of locales, locale types, and/or 'all; this
2159 is equivalent to calling `remove-specifier' for each of the elements
2160 in the list.
2161
2162 Only instantiators where TAG-SET (a list of zero or more tags) is a
2163 subset of (or possibly equal to) the instantiator's tag set are removed.
2164 The default value of nil is a subset of all tag sets, so in this case
2165 no instantiators will be screened out. If EXACT-P is non-nil, however,
2166 TAG-SET must be equal to an instantiator's tag set for the instantiator
2167 to be removed.
2168 */
2169 (specifier, locale, tag_set, exact_p))
2170 {
2171 CHECK_SPECIFIER (specifier);
2172 check_modifiable_specifier (specifier);
2173
2174 map_specifier (specifier, locale, remove_specifier_mapfun,
2175 tag_set, exact_p, 0);
2176 recompute_cached_specifier_everywhere (specifier);
2177 return Qnil;
2178 }
2179
2180 void
2181 remove_ghost_specifier (Lisp_Object specifier, Lisp_Object locale,
2182 Lisp_Object tag_set, Lisp_Object exact_p)
2183 {
2184 int depth = unlock_ghost_specifiers_protected ();
2185 Fremove_specifier (XSPECIFIER(specifier)->fallback,
2186 locale, tag_set, exact_p);
2187 unbind_to (depth, Qnil);
2188 }
2189
2190 struct copy_specifier_closure
2191 {
2192 Lisp_Object dest;
2193 enum spec_add_meth add_meth;
2194 int add_meth_is_nil;
2195 };
2196
2197 static int
2198 copy_specifier_mapfun (Lisp_Object specifier,
2199 Lisp_Object locale,
2200 enum spec_locale_type locale_type,
2201 Lisp_Object tag_set,
2202 int exact_p,
2203 void *closure)
2204 {
2205 struct copy_specifier_closure *cl =
2206 (struct copy_specifier_closure *) closure;
2207
2208 if (NILP (locale))
2209 specifier_copy_locale_type (specifier, cl->dest, locale_type,
2210 tag_set, exact_p,
2211 cl->add_meth_is_nil ?
2212 SPEC_REMOVE_LOCALE_TYPE :
2213 cl->add_meth);
2214 else
2215 specifier_copy_spec (specifier, cl->dest, locale, locale_type,
2216 tag_set, exact_p,
2217 cl->add_meth_is_nil ? SPEC_REMOVE_LOCALE :
2218 cl->add_meth);
2219 return 0;
2220 }
2221
2222 DEFUN ("copy-specifier", Fcopy_specifier, 1, 6, 0, /*
2223 Copy SPECIFIER to DEST, or create a new one if DEST is nil.
2224
2225 If DEST is nil or omitted, a new specifier will be created and the
2226 specifications copied into it. Otherwise, the specifications will be
2227 copied into the existing specifier in DEST.
2228
2229 If LOCALE is nil or 'all, all specifications will be copied. If LOCALE
2230 is a particular locale, the specification for that particular locale will
2231 be copied. If LOCALE is a locale type, the specifications for all locales
2232 of that type will be copied. LOCALE can also be a list of locales,
2233 locale types, and/or 'all; this is equivalent to calling `copy-specifier'
2234 for each of the elements of the list. See `specifier-spec-list' for more
2235 information about LOCALE.
2236
2237 Only instantiators where TAG-SET (a list of zero or more tags) is a
2238 subset of (or possibly equal to) the instantiator's tag set are copied.
2239 The default value of nil is a subset of all tag sets, so in this case
2240 no instantiators will be screened out. If EXACT-P is non-nil, however,
2241 TAG-SET must be equal to an instantiator's tag set for the instantiator
2242 to be copied.
2243
2244 Optional argument HOW-TO-ADD specifies what to do with existing
2245 specifications in DEST. If nil, then whichever locales or locale types
2246 are copied will first be completely erased in DEST. Otherwise, it is
2247 the same as in `add-spec-to-specifier'.
2248 */
2249 (specifier, dest, locale, tag_set, exact_p, how_to_add))
2250 {
2251 struct gcpro gcpro1;
2252 struct copy_specifier_closure cl;
2253
2254 CHECK_SPECIFIER (specifier);
2255 if (NILP (how_to_add))
2256 cl.add_meth_is_nil = 1;
2257 else
2258 cl.add_meth_is_nil = 0;
2259 cl.add_meth = decode_how_to_add_specification (how_to_add);
2260 if (NILP (dest))
2261 {
2262 /* #### What about copying the extra data? */
2263 dest = make_specifier (XSPECIFIER (specifier)->methods);
2264 }
2265 else
2266 {
2267 CHECK_SPECIFIER (dest);
2268 check_modifiable_specifier (dest);
2269 if (XSPECIFIER (dest)->methods != XSPECIFIER (specifier)->methods)
2270 error ("Specifiers not of same type");
2271 }
2272
2273 cl.dest = dest;
2274 GCPRO1 (dest);
2275 map_specifier (specifier, locale, copy_specifier_mapfun,
2276 tag_set, exact_p, &cl);
2277 UNGCPRO;
2278 recompute_cached_specifier_everywhere (dest);
2279 return dest;
2280 }
2281
2282
2283 /************************************************************************/
2284 /* Instancing */
2285 /************************************************************************/
2286
2287 static Lisp_Object
2288 call_validate_matchspec_method (Lisp_Object boxed_method,
2289 Lisp_Object matchspec)
2290 {
2291 ((void (*)(Lisp_Object)) get_opaque_ptr (boxed_method)) (matchspec);
2292 return Qt;
2293 }
2294
2295 static Lisp_Object
2296 check_valid_specifier_matchspec (Lisp_Object matchspec,
2297 struct specifier_methods *meths,
2298 Error_behavior errb)
2299 {
2300 if (meths->validate_matchspec_method)
2301 {
2302 Lisp_Object retval;
2303
2304 if (ERRB_EQ (errb, ERROR_ME))
2305 {
2306 (meths->validate_matchspec_method) (matchspec);
2307 retval = Qt;
2308 }
2309 else
2310 {
2311 Lisp_Object opaque =
2312 make_opaque_ptr ((void *) meths->validate_matchspec_method);
2313 struct gcpro gcpro1;
2314
2315 GCPRO1 (opaque);
2316 retval = call_with_suspended_errors
2317 ((lisp_fn_t) call_validate_matchspec_method,
2318 Qnil, Qspecifier, errb, 2, opaque, matchspec);
2319
2320 free_opaque_ptr (opaque);
2321 UNGCPRO;
2322 }
2323
2324 return retval;
2325 }
2326 else
2327 {
2328 maybe_signal_simple_error
2329 ("Matchspecs not allowed for this specifier type",
2330 intern (meths->name), Qspecifier, errb);
2331 return Qnil;
2332 }
2333 }
2334
2335 DEFUN ("check-valid-specifier-matchspec", Fcheck_valid_specifier_matchspec, 2, 2, 0, /*
2336 Signal an error if MATCHSPEC is invalid for SPECIFIER-TYPE.
2337 See `specifier-matching-instance' for a description of matchspecs.
2338 */
2339 (matchspec, specifier_type))
2340 {
2341 struct specifier_methods *meths = decode_specifier_type (specifier_type,
2342 ERROR_ME);
2343
2344 return check_valid_specifier_matchspec (matchspec, meths, ERROR_ME);
2345 }
2346
2347 DEFUN ("valid-specifier-matchspec-p", Fvalid_specifier_matchspec_p, 2, 2, 0, /*
2348 Return non-nil if MATCHSPEC is valid for SPECIFIER-TYPE.
2349 See `specifier-matching-instance' for a description of matchspecs.
2350 */
2351 (matchspec, specifier_type))
2352 {
2353 struct specifier_methods *meths = decode_specifier_type (specifier_type,
2354 ERROR_ME);
2355
2356 return check_valid_specifier_matchspec (matchspec, meths, ERROR_ME_NOT);
2357 }
2358
2359 /* This function is purposely not callable from Lisp. If a Lisp
2360 caller wants to set a fallback, they should just set the
2361 global value. */
2362
2363 void
2364 set_specifier_fallback (Lisp_Object specifier, Lisp_Object fallback)
2365 {
2366 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2367 assert (SPECIFIERP (fallback) ||
2368 !NILP (Fvalid_inst_list_p (fallback, Fspecifier_type (specifier))));
2369 if (SPECIFIERP (fallback))
2370 assert (EQ (Fspecifier_type (specifier), Fspecifier_type (fallback)));
2371 if (BODILY_SPECIFIER_P (sp))
2372 GHOST_SPECIFIER(sp)->fallback = fallback;
2373 else
2374 sp->fallback = fallback;
2375 /* call the after-change method */
2376 MAYBE_SPECMETH (sp, after_change,
2377 (bodily_specifier (specifier), Qfallback));
2378 recompute_cached_specifier_everywhere (specifier);
2379 }
2380
2381 DEFUN ("specifier-fallback", Fspecifier_fallback, 1, 1, 0, /*
2382 Return the fallback value for SPECIFIER.
2383 Fallback values are provided by the C code for certain built-in
2384 specifiers to make sure that instancing won't fail even if all
2385 specs are removed from the specifier, or to implement simple
2386 inheritance behavior (e.g. this method is used to ensure that
2387 faces other than 'default inherit their attributes from 'default).
2388 By design, you cannot change the fallback value, and specifiers
2389 created with `make-specifier' will never have a fallback (although
2390 a similar, Lisp-accessible capability may be provided in the future
2391 to allow for inheritance).
2392
2393 The fallback value will be an inst-list that is instanced like
2394 any other inst-list, a specifier of the same type as SPECIFIER
2395 \(results in inheritance), or nil for no fallback.
2396
2397 When you instance a specifier, you can explicitly request that the
2398 fallback not be consulted. (The C code does this, for example, when
2399 merging faces.) See `specifier-instance'.
2400 */
2401 (specifier))
2402 {
2403 CHECK_SPECIFIER (specifier);
2404 return Fcopy_tree (XSPECIFIER (specifier)->fallback, Qt);
2405 }
2406
2407 static Lisp_Object
2408 specifier_instance_from_inst_list (Lisp_Object specifier,
2409 Lisp_Object matchspec,
2410 Lisp_Object domain,
2411 Lisp_Object inst_list,
2412 Error_behavior errb, int no_quit,
2413 Lisp_Object depth)
2414 {
2415 /* This function can GC */
2416 struct Lisp_Specifier *sp;
2417 Lisp_Object device;
2418 Lisp_Object rest;
2419 int count = specpdl_depth ();
2420 struct gcpro gcpro1, gcpro2;
2421
2422 GCPRO2 (specifier, inst_list);
2423
2424 sp = XSPECIFIER (specifier);
2425 device = DFW_DEVICE (domain);
2426
2427 if (no_quit)
2428 /* The instantiate method is allowed to call eval. Since it
2429 is quite common for this function to get called from somewhere in
2430 redisplay we need to make sure that quits are ignored. Otherwise
2431 Fsignal will abort. */
2432 specbind (Qinhibit_quit, Qt);
2433
2434 LIST_LOOP (rest, inst_list)
2435 {
2436 Lisp_Object tagged_inst = XCAR (rest);
2437 Lisp_Object tag_set = XCAR (tagged_inst);
2438
2439 if (device_matches_specifier_tag_set_p (device, tag_set))
2440 {
2441 Lisp_Object val = XCDR (tagged_inst);
2442
2443 if (HAS_SPECMETH_P (sp, instantiate))
2444 val = call_with_suspended_errors
2445 ((lisp_fn_t) RAW_SPECMETH (sp, instantiate),
2446 Qunbound, Qspecifier, errb, 5, specifier,
2447 matchspec, domain, val, depth);
2448
2449 if (!UNBOUNDP (val))
2450 {
2451 unbind_to (count, Qnil);
2452 UNGCPRO;
2453 return val;
2454 }
2455 }
2456 }
2457
2458 unbind_to (count, Qnil);
2459 UNGCPRO;
2460 return Qunbound;
2461 }
2462
2463 /* Given a SPECIFIER and a DOMAIN, return a specific instance for that
2464 specifier. Try to find one by checking the specifier types from most
2465 specific (buffer) to most general (global). If we find an instance,
2466 return it. Otherwise return Qunbound. */
2467
2468 #define CHECK_INSTANCE_ENTRY(key, matchspec, type) do { \
2469 Lisp_Object *CIE_inst_list = \
2470 specifier_get_inst_list (specifier, key, type); \
2471 if (CIE_inst_list) \
2472 { \
2473 Lisp_Object CIE_val = \
2474 specifier_instance_from_inst_list (specifier, matchspec, \
2475 domain, *CIE_inst_list, \
2476 errb, no_quit, depth); \
2477 if (!UNBOUNDP (CIE_val)) \
2478 return CIE_val; \
2479 } \
2480 } while (0)
2481
2482 /* We accept any window, frame or device domain and do our checking
2483 starting from as specific a locale type as we can determine from the
2484 domain we are passed and going on up through as many other locale types
2485 as we can determine. In practice, when called from redisplay the
2486 arg will usually be a window and occasionally a frame. If
2487 triggered by a user call, who knows what it will usually be. */
2488 Lisp_Object
2489 specifier_instance (Lisp_Object specifier, Lisp_Object matchspec,
2490 Lisp_Object domain, Error_behavior errb, int no_quit,
2491 int no_fallback, Lisp_Object depth)
2492 {
2493 Lisp_Object buffer = Qnil;
2494 Lisp_Object window = Qnil;
2495 Lisp_Object frame = Qnil;
2496 Lisp_Object device = Qnil;
2497 Lisp_Object tag = Qnil;
2498 struct device *d;
2499 struct Lisp_Specifier *sp;
2500
2501 sp = XSPECIFIER (specifier);
2502
2503 /* Attempt to determine buffer, window, frame, and device from the
2504 domain. */
2505 if (WINDOWP (domain))
2506 window = domain;
2507 else if (FRAMEP (domain))
2508 frame = domain;
2509 else if (DEVICEP (domain))
2510 device = domain;
2511 else
2512 /* #### dmoore - dammit, this should just signal an error or something
2513 shouldn't it?
2514 #### No. Errors are handled in Lisp primitives implementation.
2515 Invalid domain is a design error here - kkm. */
2516 abort ();
2517
2518 if (NILP (buffer) && !NILP (window))
2519 buffer = XWINDOW (window)->buffer;
2520 if (NILP (frame) && !NILP (window))
2521 frame = XWINDOW (window)->frame;
2522 if (NILP (device))
2523 /* frame had better exist; if device is undeterminable, something
2524 really went wrong. */
2525 device = XFRAME (frame)->device;
2526
2527 /* device had better be determined by now; abort if not. */
2528 d = XDEVICE (device);
2529 tag = DEVICE_CLASS (d);
2530
2531 depth = make_int (1 + XINT (depth));
2532 if (XINT (depth) > 20)
2533 {
2534 maybe_error (Qspecifier, errb, "Apparent loop in specifier inheritance");
2535 /* The specification is fucked; at least try the fallback
2536 (which better not be fucked, because it's not changeable
2537 from Lisp). */
2538 depth = Qzero;
2539 goto do_fallback;
2540 }
2541
2542 retry:
2543 /* First see if we can generate one from the window specifiers. */
2544 if (!NILP (window))
2545 CHECK_INSTANCE_ENTRY (window, matchspec, LOCALE_WINDOW);
2546
2547 /* Next see if we can generate one from the buffer specifiers. */
2548 if (!NILP (buffer))
2549 CHECK_INSTANCE_ENTRY (buffer, matchspec, LOCALE_BUFFER);
2550
2551 /* Next see if we can generate one from the frame specifiers. */
2552 if (!NILP (frame))
2553 CHECK_INSTANCE_ENTRY (frame, matchspec, LOCALE_FRAME);
2554
2555 /* If we still haven't succeeded try with the device specifiers. */
2556 CHECK_INSTANCE_ENTRY (device, matchspec, LOCALE_DEVICE);
2557
2558 /* Last and least try the global specifiers. */
2559 CHECK_INSTANCE_ENTRY (Qglobal, matchspec, LOCALE_GLOBAL);
2560
2561 do_fallback:
2562 /* We're out of specifiers and we still haven't generated an
2563 instance. At least try the fallback ... If this fails,
2564 then we just return Qunbound. */
2565
2566 if (no_fallback || NILP (sp->fallback))
2567 /* I said, I don't want the fallbacks. */
2568 return Qunbound;
2569
2570 if (SPECIFIERP (sp->fallback))
2571 {
2572 /* If you introduced loops in the default specifier chain,
2573 then you're fucked, so you better not do this. */
2574 specifier = sp->fallback;
2575 sp = XSPECIFIER (specifier);
2576 goto retry;
2577 }
2578
2579 assert (CONSP (sp->fallback));
2580 return specifier_instance_from_inst_list (specifier, matchspec, domain,
2581 sp->fallback, errb, no_quit,
2582 depth);
2583 }
2584 #undef CHECK_INSTANCE_ENTRY
2585
2586 Lisp_Object
2587 specifier_instance_no_quit (Lisp_Object specifier, Lisp_Object matchspec,
2588 Lisp_Object domain, Error_behavior errb,
2589 int no_fallback, Lisp_Object depth)
2590 {
2591 return specifier_instance (specifier, matchspec, domain, errb,
2592 1, no_fallback, depth);
2593 }
2594
2595 DEFUN ("specifier-instance", Fspecifier_instance, 1, 4, 0, /*
2596 Instantiate SPECIFIER (return its value) in DOMAIN.
2597 If no instance can be generated for this domain, return DEFAULT.
2598
2599 DOMAIN should be a window, frame, or device. Other values that are legal
2600 as a locale (e.g. a buffer) are not valid as a domain because they do not
2601 provide enough information to identify a particular device (see
2602 `valid-specifier-domain-p'). DOMAIN defaults to the selected window
2603 if omitted.
2604
2605 "Instantiating" a specifier in a particular domain means determining
2606 the specifier's "value" in that domain. This is accomplished by
2607 searching through the specifications in the specifier that correspond
2608 to all locales that can be derived from the given domain, from specific
2609 to general. In most cases, the domain is an Emacs window. In that case
2610 specifications are searched for as follows:
2611
2612 1. A specification whose locale is the window itself;
2613 2. A specification whose locale is the window's buffer;
2614 3. A specification whose locale is the window's frame;
2615 4. A specification whose locale is the window's frame's device;
2616 5. A specification whose locale is 'global.
2617
2618 If all of those fail, then the C-code-provided fallback value for
2619 this specifier is consulted (see `specifier-fallback'). If it is
2620 an inst-list, then this function attempts to instantiate that list
2621 just as when a specification is located in the first five steps above.
2622 If the fallback is a specifier, `specifier-instance' is called
2623 recursively on this specifier and the return value used. Note,
2624 however, that if the optional argument NO-FALLBACK is non-nil,
2625 the fallback value will not be consulted.
2626
2627 Note that there may be more than one specification matching a particular
2628 locale; all such specifications are considered before looking for any
2629 specifications for more general locales. Any particular specification
2630 that is found may be rejected because its tag set does not match the
2631 device being instantiated over, or because the specification is not
2632 valid for the device of the given domain (e.g. the font or color name
2633 does not exist for this particular X server).
2634
2635 The returned value is dependent on the type of specifier. For example,
2636 for a font specifier (as returned by the `face-font' function), the returned
2637 value will be a font-instance object. For glyphs, the returned value
2638 will be a string, pixmap, or subwindow.
2639
2640 See also `specifier-matching-instance'.
2641 */
2642 (specifier, domain, default_, no_fallback))
2643 {
2644 Lisp_Object instance;
2645
2646 CHECK_SPECIFIER (specifier);
2647 domain = decode_domain (domain);
2648
2649 instance = specifier_instance (specifier, Qunbound, domain, ERROR_ME, 0,
2650 !NILP (no_fallback), Qzero);
2651 return UNBOUNDP (instance) ? default_ : instance;
2652 }
2653
2654 DEFUN ("specifier-matching-instance", Fspecifier_matching_instance, 2, 5, 0, /*
2655 Return an instance for SPECIFIER in DOMAIN that matches MATCHSPEC.
2656 If no instance can be generated for this domain, return DEFAULT.
2657
2658 This function is identical to `specifier-instance' except that a
2659 specification will only be considered if it matches MATCHSPEC.
2660 The definition of "match", and allowed values for MATCHSPEC, are
2661 dependent on the particular type of specifier. Here are some examples:
2662
2663 -- For chartable (e.g. display table) specifiers, MATCHSPEC should be a
2664 character, and the specification (a chartable) must give a value for
2665 that character in order to be considered. This allows you to specify,
2666 e.g., a buffer-local display table that only gives values for particular
2667 characters. All other characters are handled as if the buffer-local
2668 display table is not there. (Chartable specifiers are not yet
2669 implemented.)
2670
2671 -- For font specifiers, MATCHSPEC should be a charset, and the specification
2672 (a font string) must have a registry that matches the charset's registry.
2673 (This only makes sense with Mule support.) This makes it easy to choose a
2674 font that can display a particular character. (This is what redisplay
2675 does, in fact.)
2676 */
2677 (specifier, matchspec, domain, default_, no_fallback))
2678 {
2679 Lisp_Object instance;
2680
2681 CHECK_SPECIFIER (specifier);
2682 check_valid_specifier_matchspec (matchspec, XSPECIFIER (specifier)->methods,
2683 ERROR_ME);
2684 domain = decode_domain (domain);
2685
2686 instance = specifier_instance (specifier, matchspec, domain, ERROR_ME,
2687 0, !NILP (no_fallback), Qzero);
2688 return UNBOUNDP (instance) ? default_ : instance;
2689 }
2690
2691 DEFUN ("specifier-instance-from-inst-list", Fspecifier_instance_from_inst_list,
2692 3, 4, 0, /*
2693 Attempt to convert a particular inst-list into an instance.
2694 This attempts to instantiate INST-LIST in the given DOMAIN,
2695 as if INST-LIST existed in a specification in SPECIFIER. If
2696 the instantiation fails, DEFAULT is returned. In most circumstances,
2697 you should not use this function; use `specifier-instance' instead.
2698 */
2699 (specifier, domain, inst_list, default_))
2700 {
2701 Lisp_Object val = Qunbound;
2702 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2703 struct gcpro gcpro1;
2704 Lisp_Object built_up_list = Qnil;
2705
2706 CHECK_SPECIFIER (specifier);
2707 check_valid_domain (domain);
2708 check_valid_inst_list (inst_list, sp->methods, ERROR_ME);
2709 GCPRO1 (built_up_list);
2710 built_up_list = build_up_processed_list (specifier, domain, inst_list);
2711 if (!NILP (built_up_list))
2712 val = specifier_instance_from_inst_list (specifier, Qunbound, domain,
2713 built_up_list, ERROR_ME,
2714 0, Qzero);
2715 UNGCPRO;
2716 return UNBOUNDP (val) ? default_ : val;
2717 }
2718
2719 DEFUN ("specifier-matching-instance-from-inst-list", Fspecifier_matching_instance_from_inst_list,
2720 4, 5, 0, /*
2721 Attempt to convert a particular inst-list into an instance.
2722 This attempts to instantiate INST-LIST in the given DOMAIN
2723 \(as if INST-LIST existed in a specification in SPECIFIER),
2724 matching the specifications against MATCHSPEC.
2725
2726 This function is analogous to `specifier-instance-from-inst-list'
2727 but allows for specification-matching as in `specifier-matching-instance'.
2728 See that function for a description of exactly how the matching process
2729 works.
2730 */
2731 (specifier, matchspec, domain, inst_list, default_))
2732 {
2733 Lisp_Object val = Qunbound;
2734 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2735 struct gcpro gcpro1;
2736 Lisp_Object built_up_list = Qnil;
2737
2738 CHECK_SPECIFIER (specifier);
2739 check_valid_specifier_matchspec (matchspec, XSPECIFIER (specifier)->methods,
2740 ERROR_ME);
2741 check_valid_domain (domain);
2742 check_valid_inst_list (inst_list, sp->methods, ERROR_ME);
2743 GCPRO1 (built_up_list);
2744 built_up_list = build_up_processed_list (specifier, domain, inst_list);
2745 if (!NILP (built_up_list))
2746 val = specifier_instance_from_inst_list (specifier, matchspec, domain,
2747 built_up_list, ERROR_ME,
2748 0, Qzero);
2749 UNGCPRO;
2750 return UNBOUNDP (val) ? default_ : val;
2751 }
2752
2753
2754 /************************************************************************/
2755 /* Caching in the struct window or frame */
2756 /************************************************************************/
2757
2758 /* Either STRUCT_WINDOW_OFFSET or STRUCT_FRAME_OFFSET can be 0 to indicate
2759 no caching in that sort of object. */
2760
2761 /* #### It would be nice if the specifier caching automatically knew
2762 about specifier fallbacks, so we didn't have to do it ourselves. */
2763
2764 void
2765 set_specifier_caching (Lisp_Object specifier, int struct_window_offset,
2766 void (*value_changed_in_window)
2767 (Lisp_Object specifier, struct window *w,
2768 Lisp_Object oldval),
2769 int struct_frame_offset,
2770 void (*value_changed_in_frame)
2771 (Lisp_Object specifier, struct frame *f,
2772 Lisp_Object oldval))
2773 {
2774 struct Lisp_Specifier *sp = XSPECIFIER (specifier);
2775 assert (!GHOST_SPECIFIER_P (sp));
2776
2777 if (!sp->caching)
2778 sp->caching = xnew_and_zero (struct specifier_caching);
2779 sp->caching->offset_into_struct_window = struct_window_offset;
2780 sp->caching->value_changed_in_window = value_changed_in_window;
2781 sp->caching->offset_into_struct_frame = struct_frame_offset;
2782 sp->caching->value_changed_in_frame = value_changed_in_frame;
2783 Vcached_specifiers = Fcons (specifier, Vcached_specifiers);
2784 if (BODILY_SPECIFIER_P (sp))
2785 GHOST_SPECIFIER(sp)->caching = sp->caching;
2786 recompute_cached_specifier_everywhere (specifier);
2787 }
2788
2789 static void
2790 recompute_one_cached_specifier_in_window (Lisp_Object specifier,
2791 struct window *w)
2792 {
2793 Lisp_Object window;
2794 Lisp_Object newval, *location;
2795
2796 assert (!GHOST_SPECIFIER_P (XSPECIFIER (specifier)));
2797
2798 XSETWINDOW (window, w);
2799
2800 newval = specifier_instance (specifier, Qunbound, window, ERROR_ME_WARN,
2801 0, 0, Qzero);
2802 /* If newval ended up Qunbound, then the calling functions
2803 better be able to deal. If not, set a default so this
2804 never happens or correct it in the value_changed_in_window
2805 method. */
2806 location = (Lisp_Object *)
2807 ((char *) w + XSPECIFIER (specifier)->caching->offset_into_struct_window);
2808 if (!EQ (newval, *location))
2809 {
2810 Lisp_Object oldval = *location;
2811 *location = newval;
2812 (XSPECIFIER (specifier)->caching->value_changed_in_window)
2813 (specifier, w, oldval);
2814 }
2815 }
2816
2817 static void
2818 recompute_one_cached_specifier_in_frame (Lisp_Object specifier,
2819 struct frame *f)
2820 {
2821 Lisp_Object frame;
2822 Lisp_Object newval, *location;
2823
2824 assert (!GHOST_SPECIFIER_P (XSPECIFIER (specifier)));
2825
2826 XSETFRAME (frame, f);
2827
2828 newval = specifier_instance (specifier, Qunbound, frame, ERROR_ME_WARN,
2829 0, 0, Qzero);
2830 /* If newval ended up Qunbound, then the calling functions
2831 better be able to deal. If not, set a default so this
2832 never happens or correct it in the value_changed_in_frame
2833 method. */
2834 location = (Lisp_Object *)
2835 ((char *) f + XSPECIFIER (specifier)->caching->offset_into_struct_frame);
2836 if (!EQ (newval, *location))
2837 {
2838 Lisp_Object oldval = *location;
2839 *location = newval;
2840 (XSPECIFIER (specifier)->caching->value_changed_in_frame)
2841 (specifier, f, oldval);
2842 }
2843 }
2844
2845 void
2846 recompute_all_cached_specifiers_in_window (struct window *w)
2847 {
2848 Lisp_Object rest;
2849
2850 LIST_LOOP (rest, Vcached_specifiers)
2851 {
2852 Lisp_Object specifier = XCAR (rest);
2853 if (XSPECIFIER (specifier)->caching->offset_into_struct_window)
2854 recompute_one_cached_specifier_in_window (specifier, w);
2855 }
2856 }
2857
2858 void
2859 recompute_all_cached_specifiers_in_frame (struct frame *f)
2860 {
2861 Lisp_Object rest;
2862
2863 LIST_LOOP (rest, Vcached_specifiers)
2864 {
2865 Lisp_Object specifier = XCAR (rest);
2866 if (XSPECIFIER (specifier)->caching->offset_into_struct_frame)
2867 recompute_one_cached_specifier_in_frame (specifier, f);
2868 }
2869 }
2870
2871 static int
2872 recompute_cached_specifier_everywhere_mapfun (struct window *w,
2873 void *closure)
2874 {
2875 Lisp_Object specifier = Qnil;
2876
2877 VOID_TO_LISP (specifier, closure);
2878 recompute_one_cached_specifier_in_window (specifier, w);
2879 return 0;
2880 }
2881
2882 static void
2883 recompute_cached_specifier_everywhere (Lisp_Object specifier)
2884 {
2885 Lisp_Object frmcons, devcons, concons;
2886
2887 specifier = bodily_specifier (specifier);
2888
2889 if (!XSPECIFIER (specifier)->caching)
2890 return;
2891
2892 if (XSPECIFIER (specifier)->caching->offset_into_struct_window)
2893 {
2894 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
2895 map_windows (XFRAME (XCAR (frmcons)),
2896 recompute_cached_specifier_everywhere_mapfun,
2897 LISP_TO_VOID (specifier));
2898 }
2899
2900 if (XSPECIFIER (specifier)->caching->offset_into_struct_frame)
2901 {
2902 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
2903 recompute_one_cached_specifier_in_frame (specifier,
2904 XFRAME (XCAR (frmcons)));
2905 }
2906 }
2907
2908 DEFUN ("set-specifier-dirty-flag", Fset_specifier_dirty_flag, 1, 1, 0, /*
2909 Force recomputation of any caches associated with SPECIFIER.
2910 Note that this automatically happens whenever you change a specification
2911 in SPECIFIER; you do not have to call this function then.
2912 One example of where this function is useful is when you have a
2913 toolbar button whose `active-p' field is an expression to be
2914 evaluated. Calling `set-specifier-dirty-flag' on the
2915 toolbar specifier will force the `active-p' fields to be
2916 recomputed.
2917 */
2918 (specifier))
2919 {
2920 CHECK_SPECIFIER (specifier);
2921 recompute_cached_specifier_everywhere (specifier);
2922 return Qnil;
2923 }
2924
2925
2926 /************************************************************************/
2927 /* Generic specifier type */
2928 /************************************************************************/
2929
2930 DEFINE_SPECIFIER_TYPE (generic);
2931
2932 #if 0
2933
2934 /* This is the string that used to be in `generic-specifier-p'.
2935 The idea is good, but it doesn't quite work in the form it's
2936 in. (One major problem is that validating an instantiator
2937 is supposed to require only that the specifier type is passed,
2938 while with this approach the actual specifier is needed.)
2939
2940 What really needs to be done is to write a function
2941 `make-specifier-type' that creates new specifier types.
2942 #### I'll look into this for 19.14.
2943 */
2944
2945 "A generic specifier is a generalized kind of specifier with user-defined\n"
2946 "semantics. The instantiator can be any kind of Lisp object, and the\n"
2947 "instance computed from it is likewise any kind of Lisp object. The\n"
2948 "SPECIFIER-DATA should be an alist of methods governing how the specifier\n"
2949 "works. All methods are optional, and reasonable default methods will be\n"
2950 "provided. Currently there are two defined methods: 'instantiate and\n"
2951 "'validate.\n"
2952 "\n"
2953 "'instantiate specifies how to do the instantiation; if omitted, the\n"
2954 "instantiator itself is simply returned as the instance. The method\n"
2955 "should be a function that accepts three parameters (a specifier, the\n"
2956 "instantiator that matched the domain being instantiated over, and that\n"
2957 "domain), and should return a one-element list containing the instance,\n"
2958 "or nil if no instance exists. Note that the domain passed to this function\n"
2959 "is the domain being instantiated over, which may not be the same as the\n"
2960 "locale contained in the specification corresponding to the instantiator\n"
2961 "(for example, the domain being instantiated over could be a window, but\n"
2962 "the locale corresponding to the passed instantiator could be the window's\n"
2963 "buffer or frame).\n"
2964 "\n"
2965 "'validate specifies whether a given instantiator is valid; if omitted,\n"
2966 "all instantiators are considered valid. It should be a function of\n"
2967 "two arguments: an instantiator and a flag CAN-SIGNAL-ERROR. If this\n"
2968 "flag is false, the function must simply return t or nil indicating\n"
2969 "whether the instantiator is valid. If this flag is true, the function\n"
2970 "is free to signal an error if it encounters an invalid instantiator\n"
2971 "(this can be useful for issuing a specific error about exactly why the\n"
2972 "instantiator is valid). It can also return nil to indicate an invalid\n"
2973 "instantiator; in this case, a general error will be signalled."
2974
2975 #endif /* 0 */
2976
2977 DEFUN ("generic-specifier-p", Fgeneric_specifier_p, 1, 1, 0, /*
2978 Return non-nil if OBJECT is a generic specifier.
2979
2980 A generic specifier allows any kind of Lisp object as an instantiator,
2981 and returns back the Lisp object unchanged when it is instantiated.
2982 */
2983 (object))
2984 {
2985 return GENERIC_SPECIFIERP (object) ? Qt : Qnil;
2986 }
2987
2988
2989 /************************************************************************/
2990 /* Integer specifier type */
2991 /************************************************************************/
2992
2993 DEFINE_SPECIFIER_TYPE (integer);
2994
2995 static void
2996 integer_validate (Lisp_Object instantiator)
2997 {
2998 CHECK_INT (instantiator);
2999 }
3000
3001 DEFUN ("integer-specifier-p", Finteger_specifier_p, 1, 1, 0, /*
3002 Return non-nil if OBJECT is an integer specifier.
3003 */
3004 (object))
3005 {
3006 return INTEGER_SPECIFIERP (object) ? Qt : Qnil;
3007 }
3008
3009 /************************************************************************/
3010 /* Non-negative-integer specifier type */
3011 /************************************************************************/
3012
3013 DEFINE_SPECIFIER_TYPE (natnum);
3014
3015 static void
3016 natnum_validate (Lisp_Object instantiator)
3017 {
3018 CHECK_NATNUM (instantiator);
3019 }
3020
3021 DEFUN ("natnum-specifier-p", Fnatnum_specifier_p, 1, 1, 0, /*
3022 Return non-nil if OBJECT is a natnum (non-negative-integer) specifier.
3023 */
3024 (object))
3025 {
3026 return NATNUM_SPECIFIERP (object) ? Qt : Qnil;
3027 }
3028
3029 /************************************************************************/
3030 /* Boolean specifier type */
3031 /************************************************************************/
3032
3033 DEFINE_SPECIFIER_TYPE (boolean);
3034
3035 static void
3036 boolean_validate (Lisp_Object instantiator)
3037 {
3038 if (!EQ (instantiator, Qt) && !EQ (instantiator, Qnil))
3039 signal_simple_error ("Must be t or nil", instantiator);
3040 }
3041
3042 DEFUN ("boolean-specifier-p", Fboolean_specifier_p, 1, 1, 0, /*
3043 Return non-nil if OBJECT is a boolean specifier.
3044 */
3045 (object))
3046 {
3047 return BOOLEAN_SPECIFIERP (object) ? Qt : Qnil;
3048 }
3049
3050 /************************************************************************/
3051 /* Display table specifier type */
3052 /************************************************************************/
3053
3054 DEFINE_SPECIFIER_TYPE (display_table);
3055
3056 #define VALID_SINGLE_DISPTABLE_INSTANTIATOR_P(instantiator) \
3057 (VECTORP (instantiator) \
3058 || (CHAR_TABLEP (instantiator) \
3059 && (XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_CHAR \
3060 || XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_GENERIC)) \
3061 || RANGE_TABLEP (instantiator))
3062
3063 static void
3064 display_table_validate (Lisp_Object instantiator)
3065 {
3066 if (NILP (instantiator))
3067 /* OK */
3068 ;
3069 else if (CONSP (instantiator))
3070 {
3071 Lisp_Object tail;
3072 EXTERNAL_LIST_LOOP (tail, instantiator)
3073 {
3074 Lisp_Object car = XCAR (tail);
3075 if (!VALID_SINGLE_DISPTABLE_INSTANTIATOR_P (car))
3076 goto lose;
3077 }
3078 }
3079 else
3080 {
3081 if (!VALID_SINGLE_DISPTABLE_INSTANTIATOR_P (instantiator))
3082 {
3083 lose:
3084 dead_wrong_type_argument (display_table_specifier_methods->predicate_symbol,
3085 instantiator);
3086 }
3087 }
3088 }
3089
3090 DEFUN ("display-table-specifier-p", Fdisplay_table_specifier_p, 1, 1, 0, /*
3091 Return non-nil if OBJECT is a display-table specifier.
3092 */
3093 (object))
3094 {
3095 return DISPLAYTABLE_SPECIFIERP (object) ? Qt : Qnil;
3096 }
3097
3098
3099 /************************************************************************/
3100 /* Initialization */
3101 /************************************************************************/
3102
3103 void
3104 syms_of_specifier (void)
3105 {
3106 defsymbol (&Qspecifierp, "specifierp");
3107
3108 defsymbol (&Qconsole_type, "console-type");
3109 defsymbol (&Qdevice_class, "device-class");
3110
3111 /* Qinteger, Qboolean, Qgeneric defined in general.c */
3112 defsymbol (&Qnatnum, "natnum");
3113
3114 DEFSUBR (Fvalid_specifier_type_p);
3115 DEFSUBR (Fspecifier_type_list);
3116 DEFSUBR (Fmake_specifier);
3117 DEFSUBR (Fspecifierp);
3118 DEFSUBR (Fspecifier_type);
3119
3120 DEFSUBR (Fvalid_specifier_locale_p);
3121 DEFSUBR (Fvalid_specifier_domain_p);
3122 DEFSUBR (Fvalid_specifier_locale_type_p);
3123 DEFSUBR (Fspecifier_locale_type_from_locale);
3124
3125 DEFSUBR (Fvalid_specifier_tag_p);
3126 DEFSUBR (Fvalid_specifier_tag_set_p);
3127 DEFSUBR (Fcanonicalize_tag_set);
3128 DEFSUBR (Fdevice_matches_specifier_tag_set_p);
3129 DEFSUBR (Fdefine_specifier_tag);
3130 DEFSUBR (Fdevice_matching_specifier_tag_list);
3131 DEFSUBR (Fspecifier_tag_list);
3132 DEFSUBR (Fspecifier_tag_predicate);
3133
3134 DEFSUBR (Fcheck_valid_instantiator);
3135 DEFSUBR (Fvalid_instantiator_p);
3136 DEFSUBR (Fcheck_valid_inst_list);
3137 DEFSUBR (Fvalid_inst_list_p);
3138 DEFSUBR (Fcheck_valid_spec_list);
3139 DEFSUBR (Fvalid_spec_list_p);
3140 DEFSUBR (Fadd_spec_to_specifier);
3141 DEFSUBR (Fadd_spec_list_to_specifier);
3142 DEFSUBR (Fspecifier_spec_list);
3143 DEFSUBR (Fspecifier_specs);
3144 DEFSUBR (Fremove_specifier);
3145 DEFSUBR (Fcopy_specifier);
3146
3147 DEFSUBR (Fcheck_valid_specifier_matchspec);
3148 DEFSUBR (Fvalid_specifier_matchspec_p);
3149 DEFSUBR (Fspecifier_fallback);
3150 DEFSUBR (Fspecifier_instance);
3151 DEFSUBR (Fspecifier_matching_instance);
3152 DEFSUBR (Fspecifier_instance_from_inst_list);
3153 DEFSUBR (Fspecifier_matching_instance_from_inst_list);
3154 DEFSUBR (Fset_specifier_dirty_flag);
3155
3156 DEFSUBR (Fgeneric_specifier_p);
3157 DEFSUBR (Finteger_specifier_p);
3158 DEFSUBR (Fnatnum_specifier_p);
3159 DEFSUBR (Fboolean_specifier_p);
3160 DEFSUBR (Fdisplay_table_specifier_p);
3161
3162 /* Symbols pertaining to specifier creation. Specifiers are created
3163 in the syms_of() functions. */
3164
3165 /* locales are defined in general.c. */
3166
3167 defsymbol (&Qprepend, "prepend");
3168 defsymbol (&Qappend, "append");
3169 defsymbol (&Qremove_tag_set_prepend, "remove-tag-set-prepend");
3170 defsymbol (&Qremove_tag_set_append, "remove-tag-set-append");
3171 defsymbol (&Qremove_locale, "remove-locale");
3172 defsymbol (&Qremove_locale_type, "remove-locale-type");
3173 defsymbol (&Qremove_all, "remove-all");
3174
3175 defsymbol (&Qfallback, "fallback");
3176 }
3177
3178 void
3179 specifier_type_create (void)
3180 {
3181 the_specifier_type_entry_dynarr = Dynarr_new (specifier_type_entry);
3182 dumpstruct (&the_specifier_type_entry_dynarr, &sted_description);
3183
3184 Vspecifier_type_list = Qnil;
3185 staticpro (&Vspecifier_type_list);
3186
3187 INITIALIZE_SPECIFIER_TYPE (generic, "generic", "generic-specifier-p");
3188
3189 INITIALIZE_SPECIFIER_TYPE (integer, "integer", "integer-specifier-p");
3190
3191 SPECIFIER_HAS_METHOD (integer, validate);
3192
3193 INITIALIZE_SPECIFIER_TYPE (natnum, "natnum", "natnum-specifier-p");
3194
3195 SPECIFIER_HAS_METHOD (natnum, validate);
3196
3197 INITIALIZE_SPECIFIER_TYPE (boolean, "boolean", "boolean-specifier-p");
3198
3199 SPECIFIER_HAS_METHOD (boolean, validate);
3200
3201 INITIALIZE_SPECIFIER_TYPE (display_table, "display-table", "display-table-p");
3202
3203 SPECIFIER_HAS_METHOD (display_table, validate);
3204 }
3205
3206 void
3207 reinit_specifier_type_create (void)
3208 {
3209 REINITIALIZE_SPECIFIER_TYPE (generic);
3210 REINITIALIZE_SPECIFIER_TYPE (integer);
3211 REINITIALIZE_SPECIFIER_TYPE (natnum);
3212 REINITIALIZE_SPECIFIER_TYPE (boolean);
3213 REINITIALIZE_SPECIFIER_TYPE (display_table);
3214 }
3215
3216 void
3217 vars_of_specifier (void)
3218 {
3219 Vcached_specifiers = Qnil;
3220 staticpro (&Vcached_specifiers);
3221
3222 /* Do NOT mark through this, or specifiers will never be GC'd.
3223 This is the same deal as for weak hash tables. */
3224 Vall_specifiers = Qnil;
3225 pdump_wire_list (&Vall_specifiers);
3226
3227 Vuser_defined_tags = Qnil;
3228 staticpro (&Vuser_defined_tags);
3229
3230 Vunlock_ghost_specifiers = Qnil;
3231 staticpro (&Vunlock_ghost_specifiers);
3232 }