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