diff src/specifier.c @ 5125:b5df3737028a ben-lisp-object

merge
author Ben Wing <ben@xemacs.org>
date Wed, 24 Feb 2010 01:58:04 -0600
parents 623d57b7fbe8 2ade80e8c640
children a9c41067dd88
line wrap: on
line diff
--- a/src/specifier.c	Wed Jan 20 07:05:57 2010 -0600
+++ b/src/specifier.c	Wed Feb 24 01:58:04 2010 -0600
@@ -1,6 +1,6 @@
 /* Specifier implementation
    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
-   Copyright (C) 1995, 1996, 2002, 2005 Ben Wing.
+   Copyright (C) 1995, 1996, 2002, 2005, 2010 Ben Wing.
    Copyright (C) 1995 Sun Microsystems, Inc.
 
 This file is part of XEmacs.
@@ -33,6 +33,7 @@
 #include "buffer.h"
 #include "chartab.h"
 #include "device-impl.h"
+#include "elhash.h"
 #include "frame.h"
 #include "glyphs.h"
 #include "opaque.h"
@@ -47,6 +48,14 @@
 Lisp_Object Qconsole_type, Qdevice_class;
 
 static Lisp_Object Vuser_defined_tags;
+/* This is a hash table mapping charsets to "tag lists".  A tag list here
+   is an assoc list mapping charset tags to size-two vectors (one for the
+   initial stage, one for the final stage) containing t or nil, indicating
+   whether the charset tag matches the charset for the given stage.  These
+   values are determined at the time a charset tag is defined by calling
+   the charset predicate on all the existing charsets, and at the time a
+   charset is defined by calling the predicate on all existing charset
+   tags. */
 static Lisp_Object Vcharset_tag_lists;
 
 typedef struct specifier_type_entry specifier_type_entry;
@@ -285,7 +294,7 @@
   the_specs = Fspecifier_specs (obj, Qglobal, Qnil, Qnil);
   if (NILP (the_specs))
     /* there are no global specs */
-    write_c_string (printcharfun, "<unspecified>");
+    write_ascstring (printcharfun, "<unspecified>");
   else
     print_internal (the_specs, printcharfun, 1);
   if (!NILP (sp->fallback))
@@ -303,14 +312,14 @@
   Lisp_Specifier *sp = (Lisp_Specifier *) header;
   if (!GHOST_SPECIFIER_P(sp) && sp->caching)
     {
-      xfree (sp->caching, struct specifier_caching *);
+      xfree (sp->caching);
       sp->caching = 0;
     }
 }
 #endif /* not NEW_GC */
 
 static int
-specifier_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
+specifier_equal (Lisp_Object obj1, Lisp_Object obj2, int depth, int foldcase)
 {
   Lisp_Specifier *s1 = XSPECIFIER (obj1);
   Lisp_Specifier *s2 = XSPECIFIER (obj2);
@@ -324,12 +333,12 @@
   depth++;
   retval =
     (s1->methods == s2->methods &&
-     internal_equal (s1->global_specs, s2->global_specs, depth) &&
-     internal_equal (s1->device_specs, s2->device_specs, depth) &&
-     internal_equal (s1->frame_specs,  s2->frame_specs,  depth) &&
-     internal_equal (s1->window_specs, s2->window_specs, depth) &&
-     internal_equal (s1->buffer_specs, s2->buffer_specs, depth) &&
-     internal_equal (s1->fallback,     s2->fallback,     depth));
+     internal_equal_0 (s1->global_specs, s2->global_specs, depth, foldcase) &&
+     internal_equal_0 (s1->device_specs, s2->device_specs, depth, foldcase) &&
+     internal_equal_0 (s1->frame_specs,  s2->frame_specs,  depth, foldcase) &&
+     internal_equal_0 (s1->window_specs, s2->window_specs, depth, foldcase) &&
+     internal_equal_0 (s1->buffer_specs, s2->buffer_specs, depth, foldcase) &&
+     internal_equal_0 (s1->fallback,     s2->fallback,     depth, foldcase));
 
   if (retval && HAS_SPECMETH_P (s1, equal))
     retval = SPECMETH (s1, equal, (obj1, obj2, depth - 1));
@@ -974,46 +983,42 @@
 }
 
 static int
-charset_matches_specifier_tag_set_p (Lisp_Object charset,
-				     Lisp_Object tag_set,
+charset_matches_specifier_tag_set_p (Lisp_Object charset, Lisp_Object tag_set,
 				     enum font_specifier_matchspec_stages
 				     stage)
 {
   Lisp_Object rest;
   int res = 0;
 
-  assert(stage != impossible);
+  assert(stage < NUM_MATCHSPEC_STAGES);
 
   LIST_LOOP (rest, tag_set)
     {
       Lisp_Object tag = XCAR (rest);
       Lisp_Object assoc;
+      Lisp_Object tag_list = Fgethash (charset, Vcharset_tag_lists, Qnil);
 
       /* In the event that, during the creation of a charset, no specifier
 	 tags exist for which CHARSET-PREDICATE has been specified, then
 	 that charset's entry in Vcharset_tag_lists will be nil, and this
 	 charset shouldn't match. */
 
-      if (NILP (XVECTOR_DATA(Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset)
-						 - MIN_LEADING_BYTE]))
+      if (NILP (tag_list))
 	{
 	  return 0;
 	}
 
       /* Now, find out what the pre-calculated value is. */
-      assoc = assq_no_quit(tag,
-			   XVECTOR_DATA(Vcharset_tag_lists)
-			   [XCHARSET_LEADING_BYTE(charset)
-			    - MIN_LEADING_BYTE]);
-
-      if (!(NILP(assoc)) && !(NILP(XCDR(assoc))))
+      assoc = assq_no_quit (tag, tag_list);
+
+      if (!(NILP (assoc)))
 	{
-	  assert(VECTORP(XCDR(assoc)));
+	  assert (VECTORP (XCDR (assoc)));
 
 	  /* In the event that a tag specifies a charset, then the specifier
 	     must match for (this stage and this charset) for all
 	     charset-specifying tags.  */
-	  if (NILP(XVECTOR_DATA(XCDR(assoc))[stage]))
+	  if (NILP (XVECTOR_DATA (XCDR (assoc))[stage]))
 	    {
 	      /* It doesn't match for this tag, even though the tag
 		 specifies a charset. Return 0. */
@@ -1051,13 +1056,65 @@
   return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil;
 }
 
+/* Call CHARSET_PREDICATE on CHARSET, evaluating it at both stages (initial
+   and final) and returning a size-two vector of the results. */
+
+static Lisp_Object
+call_charset_predicate (Lisp_Object charset_predicate, Lisp_Object charset)
+{
+  struct gcpro gcpro1;
+  Lisp_Object charpres = make_vector (NUM_MATCHSPEC_STAGES, Qnil);
+  int max_args = XINT (Ffunction_max_args (charset_predicate));
+  GCPRO1 (charpres);
+    
+
+#define DEFINE_SPECIFIER_TAG_FROB(stage, enumstage)		\
+  do {								\
+    if (max_args > 1)						\
+      {								\
+	XVECTOR_DATA (charpres)[enumstage] =			\
+	  call2_trapping_problems				\
+	  ("Error during specifier tag charset predicate,"	\
+	   " stage " #stage, charset_predicate,			\
+	   charset, Q##stage, 0);				\
+      }								\
+    else							\
+      {								\
+	XVECTOR_DATA (charpres)[enumstage] =			\
+	  call1_trapping_problems				\
+	  ("Error during specifier tag charset predicate,"	\
+	   " stage " #stage, charset_predicate,			\
+	   charset, 0);						\
+      }								\
+								\
+    if (UNBOUNDP (XVECTOR_DATA (charpres)[enumstage]))		\
+      {								\
+	XVECTOR_DATA (charpres)[enumstage] = Qnil;		\
+      }								\
+    else if (!NILP (XVECTOR_DATA (charpres)[enumstage]))	\
+      {								\
+	/* Don't want refs to random other objects.  */		\
+	XVECTOR_DATA (charpres)[enumstage] = Qt;		\
+      }								\
+  } while (0)
+
+  DEFINE_SPECIFIER_TAG_FROB (initial, STAGE_INITIAL);
+  DEFINE_SPECIFIER_TAG_FROB (final, STAGE_FINAL);
+
+#undef DEFINE_SPECIFIER_TAG_FROB
+
+  UNGCPRO;
+
+  return charpres;
+}
+
 Lisp_Object
-define_specifier_tag(Lisp_Object tag, Lisp_Object device_predicate,
-		     Lisp_Object charset_predicate)
+define_specifier_tag (Lisp_Object tag, Lisp_Object device_predicate,
+		      Lisp_Object charset_predicate)
 {
   Lisp_Object assoc = assq_no_quit (tag, Vuser_defined_tags),
-    concons, devcons, charpres = Qnil;
-  int recompute_devices = 0, recompute_charsets = 0, i, max_args = -1;
+    concons, devcons;
+  int recompute_devices = 0, recompute_charsets = 0;
 
   if (NILP (assoc))
     {
@@ -1073,31 +1130,14 @@
 	  DEVICE_USER_DEFINED_TAGS (d) =
 	    Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d));
 	}
-
-      if (!NILP (charset_predicate))
-	{
-	  max_args = XINT(Ffunction_max_args(charset_predicate));
-	  if (max_args < 1)
-	    {
-	      invalid_argument
-		("Charset predicate must be able to take an argument", tag);
-	    }
-	}
     }
   else if (!NILP (device_predicate) && !NILP (XCADR (assoc)))
     {
       recompute_devices = 1;
-      XCDR (assoc) = list2(device_predicate, charset_predicate);
+      XCDR (assoc) = list2 (device_predicate, charset_predicate);
     }
-  else if (!NILP (charset_predicate) || !NILP(XCADDR (assoc)))
+  else if (!NILP (charset_predicate) || !NILP (XCADDR (assoc)))
     {
-      max_args = XINT(Ffunction_max_args(charset_predicate));
-      if (max_args < 1)
-	{
-	  invalid_argument
-	    ("Charset predicate must be able to take an argument", tag);
-	}
-
       /* If there exists a charset_predicate for the tag currently (even if
 	 the new charset_predicate is nil), or if we're adding one, we need
 	 to recompute.  This contrasts with the device predicates, where we
@@ -1105,7 +1145,7 @@
 	 both nil.  */
 
       recompute_charsets = 1;
-      XCDR (assoc) = list2(device_predicate, charset_predicate);
+      XCDR (assoc) = list2 (device_predicate, charset_predicate);
     }
 
   /* Recompute the tag values for all devices and charsets, if necessary. In
@@ -1133,80 +1173,28 @@
 
   if (recompute_charsets)
     {
-      if (NILP(charset_predicate))
-	{
-	  charpres = Qnil;
-	}
-
-      for (i = 0; i < NUM_LEADING_BYTES; ++i)
+
+      LIST_LOOP_2 (charset_name, Fcharset_list ())
 	{
-	  if (NILP(charset_by_leading_byte(MIN_LEADING_BYTE + i)))
-	    {
-	      continue;
-	    }
-
-	  assoc = assq_no_quit (tag,
-				XVECTOR_DATA(Vcharset_tag_lists)[i]);
-
-	  if (!NILP(charset_predicate))
+	  Lisp_Object charset = Fget_charset (charset_name);
+	  Lisp_Object tag_list = Fgethash (charset, Vcharset_tag_lists, Qnil);
+	  Lisp_Object charpres;
+
+	  if (NILP (charset_predicate))
+	    continue;
+
+	  charpres = call_charset_predicate (charset_predicate, charset);
+
+	  assoc = assq_no_quit (tag, tag_list);
+	  if (!NILP (assoc))
 	    {
-	      struct gcpro gcpro1;
-	      charpres = make_vector(impossible, Qnil);
-	      GCPRO1 (charpres);
-
-	      /* If you want to extend the number of stages available, here
-		 in setup_charset_initial_specifier_tags, and in specifier.h
-		 is where you want to go. */
-
-#define DEFINE_SPECIFIER_TAG_FROB(stage)	do {			\
-		if (max_args > 1)					\
-		  {							\
-		    XVECTOR_DATA(charpres)[stage] =			\
-		      call2_trapping_problems				\
-		      ("Error during specifier tag charset predicate,"	\
-		       " stage " #stage, charset_predicate,		\
-		       charset_by_leading_byte(MIN_LEADING_BYTE + i),	\
-		       Q##stage, 0);					\
-		  }							\
-		else							\
-		  {							\
-		    XVECTOR_DATA(charpres)[stage] =			\
-		      call1_trapping_problems				\
-		      ("Error during specifier tag charset predicate,"	\
-		       " stage " #stage, charset_predicate,		\
-		       charset_by_leading_byte(MIN_LEADING_BYTE + i),	\
-		       0);						\
-		  }							\
-									\
-		if (UNBOUNDP(XVECTOR_DATA(charpres)[stage]))		\
-		  {							\
-		    XVECTOR_DATA(charpres)[stage] = Qnil;		\
-		  }							\
-		else if (!NILP(XVECTOR_DATA(charpres)[stage]))		\
-		  {							\
-		    /* Don't want refs to random other objects.  */	\
-		    XVECTOR_DATA(charpres)[stage] = Qt;			\
-		  }							\
-	      } while (0)
-
-	      DEFINE_SPECIFIER_TAG_FROB (initial);
-	      DEFINE_SPECIFIER_TAG_FROB (final);
-
-#undef DEFINE_SPECIFIER_TAG_FROB
-
-	      UNGCPRO;
-	    }
-
-	  if (!NILP(assoc))
-	    {
-	      assert(CONSP(assoc));
+	      assert (CONSP (assoc));
 	      XCDR (assoc) = charpres;
 	    }
 	  else
 	    {
-	      XVECTOR_DATA(Vcharset_tag_lists)[i]
-		= Fcons(Fcons(tag, charpres),
-			XVECTOR_DATA (Vcharset_tag_lists)[i]);
+	      Fputhash (charset, Fcons (Fcons (tag, charpres), tag_list),
+			Vcharset_tag_lists);
 	    }
 	}
     }
@@ -1251,8 +1239,6 @@
 */
        (tag, device_predicate, charset_predicate))
 {
-  int max_args;
-
   CHECK_SYMBOL (tag);
   if (valid_device_class_p (tag) ||
       valid_console_type_p (tag) ||
@@ -1265,8 +1251,10 @@
 
   if (!NILP (charset_predicate))
     {
-      max_args = XINT(Ffunction_max_args(charset_predicate));
-      if (max_args != 1)
+      Lisp_Object min_args = Ffunction_min_args (charset_predicate);
+      Lisp_Object max_args = Ffunction_max_args (charset_predicate);
+      if (!(INTP (min_args) && XINT (min_args) == 1 &&
+	    INTP (max_args) && XINT (max_args) == 1))
 	{
 	  /* We only allow the stage argument to be specifed from C.  */
 	  invalid_change ("Charset predicate must take one argument",
@@ -1325,47 +1313,19 @@
 
   LIST_LOOP (rest, Vuser_defined_tags)
     {
-      tag = XCAR(XCAR(rest));
-      charset_predicate = XCADDR(XCAR (rest));
-
-      if (NILP(charset_predicate))
+      tag = XCAR (XCAR (rest));
+      charset_predicate = XCADDR (XCAR (rest));
+
+      if (NILP (charset_predicate))
 	{
 	  continue;
 	}
 
-      new_value = make_vector(impossible, Qnil);
-
-#define SETUP_CHARSET_TAGS_FROB(stage)		do {			\
-									\
-	XVECTOR_DATA(new_value)[stage] = call2_trapping_problems	\
-	  ("Error during specifier tag charset predicate,"		\
-	   " stage " #stage,						\
-	   charset_predicate, charset, Q##stage, 0);			\
-									\
-	if (UNBOUNDP(XVECTOR_DATA(new_value)[stage]))			\
-	  {								\
-	    XVECTOR_DATA(new_value)[stage] = Qnil;			\
-	  }								\
-	else if (!NILP(XVECTOR_DATA(new_value)[stage]))			\
-	  {								\
-	    /* Don't want random other objects hanging around. */	\
-	    XVECTOR_DATA(new_value)[stage] = Qt;			\
-	  }								\
-									\
-      } while (0)
-
-      SETUP_CHARSET_TAGS_FROB (initial);
-      SETUP_CHARSET_TAGS_FROB (final);
-      /* More later?  */
-
-#undef SETUP_CHARSET_TAGS_FROB
-
-      charset_tag_list = Fcons(Fcons(tag, new_value), charset_tag_list);
+      new_value = call_charset_predicate (charset_predicate, charset);
+      charset_tag_list = Fcons (Fcons (tag, new_value), charset_tag_list);
     }
 
-  XVECTOR_DATA
-    (Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset) - MIN_LEADING_BYTE]
-    = charset_tag_list;
+  Fputhash (charset, charset_tag_list, Vcharset_tag_lists);
 }
 
 /* VM calls this, in vm-multiple-frames-possible-p, in the event that you're
@@ -2804,10 +2764,7 @@
   Lisp_Object device, charset = Qnil, rest;
   int count = specpdl_depth (), respected_charsets = 0;
   struct gcpro gcpro1, gcpro2;
-  enum font_specifier_matchspec_stages stage = initial;
-#ifdef DEBUG_XEMACS
-  int non_ascii;
-#endif
+  enum font_specifier_matchspec_stages stage = STAGE_INITIAL;
 
   GCPRO2 (specifier, inst_list);
 
@@ -2822,28 +2779,31 @@
     specbind (Qinhibit_quit, Qt);
 
 #ifdef MULE
-  if (CONSP(matchspec) && (CHARSETP(Ffind_charset(XCAR(matchspec)))))
+  /* #### FIXME Does this font-specific stuff need to be here and not in
+     the font-specifier-specific code? --ben */
+  if (CONSP (matchspec) && (CHARSETP (Ffind_charset (XCAR (matchspec)))))
     {
-      charset = Ffind_charset(XCAR(matchspec));
+      charset = Ffind_charset (XCAR (matchspec));
 
 #ifdef DEBUG_XEMACS
       /* This is mostly to have somewhere to set debug breakpoints. */
-      if (!EQ(charset, Vcharset_ascii))
+      if (!EQ (charset, Vcharset_ascii))
 	{
-	  non_ascii = 1;
+	  (void) 0;
 	}
 #endif /* DEBUG_XEMACS */
 
-      if (!NILP(XCDR(matchspec)))
+      if (!NILP (XCDR (matchspec)))
 	{
 
-#define FROB(new_stage) if (EQ(Q##new_stage, XCDR(matchspec)))	\
-	    {							\
-	      stage = new_stage;				\
+#define FROB(new_stage, enumstage)			\
+          if (EQ (Q##new_stage, XCDR (matchspec)))	\
+	    {						\
+	      stage = enumstage;			\
 	    }
 
-	  FROB(initial)
-	  else FROB(final)
+	  FROB (initial, STAGE_INITIAL)
+	  else FROB (final, STAGE_FINAL)
 	  else assert(0);
 #undef FROB
 
@@ -3540,7 +3500,7 @@
 {
   Lisp_Object specifier = Qnil;
 
-  specifier = VOID_TO_LISP (closure);
+  specifier = GET_LISP_FROM_VOID (closure);
   recompute_one_cached_specifier_in_window (specifier, w);
   return 0;
 }
@@ -3560,7 +3520,7 @@
       FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
 	map_windows (XFRAME (XCAR (frmcons)),
 		     recompute_cached_specifier_everywhere_mapfun,
-		     LISP_TO_VOID (specifier));
+		     STORE_LISP_IN_VOID (specifier));
     }
 
   if (XSPECIFIER (specifier)->caching->offset_into_struct_frame)
@@ -3915,6 +3875,7 @@
   Vunlock_ghost_specifiers = Qnil;
   staticpro (&Vunlock_ghost_specifiers);
 
-  Vcharset_tag_lists = make_vector(NUM_LEADING_BYTES, Qnil);
+  Vcharset_tag_lists =
+    make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
   staticpro (&Vcharset_tag_lists);
 }