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