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