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