build: Don't include <config.h> in native programs when cross-compiling.
[bpt/guile.git] / libguile / srfi-14.c
index fe56270..af7c1d9 100644 (file)
@@ -1,6 +1,6 @@
 /* srfi-14.c --- SRFI-14 procedures for Guile
  *
- * Copyright (C) 2001, 2004, 2006, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2004, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
 #include "libguile.h"
 #include "libguile/srfi-14.h"
 #include "libguile/strings.h"
+#include "libguile/chars.h"
 
 /* Include the pre-computed standard charset data.  */
 #include "libguile/srfi-14.i.c"
 
+scm_t_char_range cs_full_ranges[] = {
+  {0x0000, SCM_CODEPOINT_SURROGATE_START - 1}
+  ,
+  {SCM_CODEPOINT_SURROGATE_END + 1, SCM_CODEPOINT_MAX}
+};
+
+scm_t_char_set cs_full = {
+  2,
+  cs_full_ranges
+};
+
+
 #define SCM_CHARSET_DATA(charset) ((scm_t_char_set *) SCM_SMOB_DATA (charset))
 
 #define SCM_CHARSET_SET(cs, idx)                        \
@@ -85,18 +98,11 @@ scm_i_charset_set (scm_t_char_set *cs, scm_t_wchar n)
           /* This char is one below the current range. */
           if (i > 0 && cs->ranges[i - 1].hi + 1 == n)
             {
-              /* It is also one above the previous range, so combine them.  */
-              cs->ranges[i - 1].hi = cs->ranges[i].hi;
-              if (i < len - 1)
-                memmove (cs->ranges + i, cs->ranges + (i + 1),
-                         sizeof (scm_t_char_range) * (len - i - 1));
-              cs->ranges = scm_gc_realloc (cs->ranges,
-                                           sizeof (scm_t_char_range) * len,
-                                           sizeof (scm_t_char_range) * (len -
-                                                                        1),
-                                           "character-set");
-              cs->len = len - 1;
-              return;
+              /* It is also one above the previous range.  */
+              /* This is an impossible condition: in the previous
+                 iteration, the test for 'one above the current range'
+                 should already have inserted the character here.  */
+              abort ();
             }
           else
             {
@@ -167,6 +173,103 @@ scm_i_charset_set (scm_t_char_set *cs, scm_t_wchar n)
   return;
 }
 
+/* Put LO to HI inclusive into charset CS.  */
+static void
+scm_i_charset_set_range (scm_t_char_set *cs, scm_t_wchar lo, scm_t_wchar hi)
+{
+  size_t i;
+
+  i = 0;
+  while (i < cs->len)
+    {
+      /* Already in this range  */
+      if (cs->ranges[i].lo <= lo && cs->ranges[i].hi >= hi)
+        return;
+
+      /* cur:       +---+
+         new: +---+
+      */
+      if (cs->ranges[i].lo - 1 > hi)
+        {
+          /* Add a new range below the current one.  */
+          cs->ranges = scm_gc_realloc (cs->ranges,
+                                       sizeof (scm_t_char_range) * cs->len,
+                                       sizeof (scm_t_char_range) * (cs->len + 1),
+                                       "character-set");
+          memmove (cs->ranges + (i + 1), cs->ranges + i,
+                   sizeof (scm_t_char_range) * (cs->len - i));
+          cs->ranges[i].lo = lo;
+          cs->ranges[i].hi = hi;
+          cs->len += 1;
+          return;
+        }
+
+      /* cur:      +---+  or     +---+  or    +---+
+         new: +---+          +---+         +---+
+      */
+      if (cs->ranges[i].lo > lo
+          && (cs->ranges[i].lo - 1 <= hi && cs->ranges[i].hi >= hi))
+        {
+          cs->ranges[i].lo = lo;
+          return;
+        }
+
+      /* cur: +---+    or +---+     or +---+
+         new:   +---+         +---+         +---+
+      */
+      else if (cs->ranges[i].hi + 1 >= lo && cs->ranges[i].hi < hi)
+        {
+          if (cs->ranges[i].lo > lo)
+            cs->ranges[i].lo = lo;
+          if (cs->ranges[i].hi < hi)
+            cs->ranges[i].hi = hi;
+          while (i < cs->len - 1)
+            {
+              /* cur: --+    +---+
+                 new: -----+
+              */
+              if (cs->ranges[i + 1].lo - 1 > hi)
+                break;
+              
+              /* cur: --+   +---+  or  --+  +---+  or --+ +--+
+                 new: -----+           ------+        ---------+
+              */
+              /* Combine this range with the previous one.  */
+              if (cs->ranges[i + 1].hi > hi)
+                cs->ranges[i].hi = cs->ranges[i + 1].hi;
+              if (i + 1 < cs->len)
+                memmove (cs->ranges + i + 1, cs->ranges + i + 2,
+                         sizeof (scm_t_char_range) * (cs->len - i - 2));
+              cs->ranges = scm_gc_realloc (cs->ranges,
+                                           sizeof (scm_t_char_range) * cs->len,
+                                           sizeof (scm_t_char_range) * (cs->len - 1),
+                                           "character-set");
+              cs->len -= 1;
+            }
+          return;
+        }
+      i ++;
+    }
+
+  /* This is a new range above all previous ranges.  */
+  if (cs->len == 0)
+    {
+      cs->ranges = scm_gc_malloc (sizeof (scm_t_char_range), "character-set");
+    }
+  else
+    {
+      cs->ranges = scm_gc_realloc (cs->ranges,
+                                   sizeof (scm_t_char_range) * cs->len,
+                                   sizeof (scm_t_char_range) * (cs->len + 1),
+                                   "character-set");
+    }
+  cs->len += 1;
+  cs->ranges[cs->len - 1].lo = lo;
+  cs->ranges[cs->len - 1].hi = hi;
+
+  return;
+}
+
 /* If N is in charset CS, remove it.  */
 void
 scm_i_charset_unset (scm_t_char_set *cs, scm_t_wchar n)
@@ -301,7 +404,7 @@ static void
 charsets_union (scm_t_char_set *a, scm_t_char_set *b)
 {
   size_t i = 0;
-  scm_t_wchar blo, bhi, n;
+  scm_t_wchar blo, bhi;
 
   if (b->len == 0)
     return;
@@ -315,13 +418,11 @@ charsets_union (scm_t_char_set *a, scm_t_char_set *b)
       return;
     }
 
-  /* This needs optimization.  */
   while (i < b->len)
     {
       blo = b->ranges[i].lo;
       bhi = b->ranges[i].hi;
-      for (n = blo; n <= bhi; n++)
-        scm_i_charset_set (a, n);
+      scm_i_charset_set_range (a, blo, bhi);
 
       i++;
     }
@@ -373,22 +474,35 @@ charsets_intersection (scm_t_char_set *a, scm_t_char_set *b)
   return;
 }
 
+#define SCM_ADD_RANGE(low, high)                        \
+  do {                                                  \
+    p->ranges[idx].lo = (low);                          \
+    p->ranges[idx++].hi = (high);                       \
+  } while (0)
+#define SCM_ADD_RANGE_SKIP_SURROGATES(low, high)                  \
+  do {                                                            \
+    p->ranges[idx].lo = (low);                                    \
+    p->ranges[idx++].hi = SCM_CODEPOINT_SURROGATE_START - 1;      \
+    p->ranges[idx].lo = SCM_CODEPOINT_SURROGATE_END + 1;          \
+    p->ranges[idx++].hi = (high);                                 \
+  } while (0)
+
+
+
 /* Make P the compelement of Q.  */
 static void
 charsets_complement (scm_t_char_set *p, scm_t_char_set *q)
 {
   int k, idx;
 
+  idx = 0;
   if (q->len == 0)
     {
       /* Fill with all valid codepoints.  */
       p->len = 2;
       p->ranges = scm_gc_malloc (sizeof (scm_t_char_range) * 2,
                                  "character-set");
-      p->ranges[0].lo = 0;
-      p->ranges[0].hi = 0xd7ff;
-      p->ranges[1].lo = 0xe000;
-      p->ranges[1].hi = SCM_CODEPOINT_MAX;
+      SCM_ADD_RANGE_SKIP_SURROGATES (0, SCM_CODEPOINT_MAX);
       return;
     }
 
@@ -396,33 +510,42 @@ charsets_complement (scm_t_char_set *p, scm_t_char_set *q)
     scm_gc_free (p->ranges, sizeof (scm_t_char_set) * p->len,
                  "character-set");
 
+  /* Count the number of ranges needed for the output.  */
   p->len = 0;
   if (q->ranges[0].lo > 0)
     p->len++;
   if (q->ranges[q->len - 1].hi < SCM_CODEPOINT_MAX)
     p->len++;
-  p->len += q->len - 1;
+  p->len += q->len;
   p->ranges =
     (scm_t_char_range *) scm_gc_malloc (sizeof (scm_t_char_range) * p->len,
                                         "character-set");
-  idx = 0;
   if (q->ranges[0].lo > 0)
     {
-      p->ranges[idx].lo = 0;
-      p->ranges[idx++].hi = q->ranges[0].lo - 1;
+      if (q->ranges[0].lo > SCM_CODEPOINT_SURROGATE_END)
+        SCM_ADD_RANGE_SKIP_SURROGATES (0, q->ranges[0].lo - 1);
+      else
+        SCM_ADD_RANGE (0, q->ranges[0].lo - 1);
     }
   for (k = 1; k < q->len; k++)
     {
-      p->ranges[idx].lo = q->ranges[k - 1].hi + 1;
-      p->ranges[idx++].hi = q->ranges[k].lo - 1;
+      if (q->ranges[k - 1].hi < SCM_CODEPOINT_SURROGATE_START
+          && q->ranges[k].lo - 1 > SCM_CODEPOINT_SURROGATE_END)
+        SCM_ADD_RANGE_SKIP_SURROGATES (q->ranges[k - 1].hi + 1, q->ranges[k].lo - 1);
+      else
+        SCM_ADD_RANGE (q->ranges[k - 1].hi + 1, q->ranges[k].lo - 1);
     }
   if (q->ranges[q->len - 1].hi < SCM_CODEPOINT_MAX)
     {
-      p->ranges[idx].lo = q->ranges[q->len - 1].hi + 1;
-      p->ranges[idx].hi = SCM_CODEPOINT_MAX;
+      if (q->ranges[q->len - 1].hi < SCM_CODEPOINT_SURROGATE_START)
+        SCM_ADD_RANGE_SKIP_SURROGATES (q->ranges[q->len - 1].hi + 1, SCM_CODEPOINT_MAX);
+      else
+        SCM_ADD_RANGE (q->ranges[q->len - 1].hi + 1, SCM_CODEPOINT_MAX);
     }
   return;
 }
+#undef SCM_ADD_RANGE
+#undef SCM_ADD_RANGE_SKIP_SURROGATES
 
 /* Replace A with elements only found in one of A or B.  */
 static void
@@ -498,32 +621,6 @@ charset_print (SCM charset, SCM port, scm_print_state *pstate SCM_UNUSED)
   return 1;
 }
 
-
-/* Smob free hook for character sets. */
-static size_t
-charset_free (SCM charset)
-{
-  scm_t_char_set *cs;
-  size_t len = 0;
-
-  cs = SCM_CHARSET_DATA (charset);
-  if (cs != NULL)
-    len = cs->len;
-  if (len > 0)
-    scm_gc_free (cs->ranges, sizeof (scm_t_char_range) * len,
-                 "character-set");
-
-  cs->ranges = NULL;
-  cs->len = 0;
-
-  scm_gc_free (cs, sizeof (scm_t_char_set), "character-set");
-
-  scm_remember_upto_here_1 (charset);
-
-  return 0;
-}
-
-
 /* Smob print hook for character sets cursors.  */
 static int
 charset_cursor_print (SCM cursor, SCM port,
@@ -546,19 +643,6 @@ charset_cursor_print (SCM cursor, SCM port,
   return 1;
 }
 
-/* Smob free hook for character sets. */
-static size_t
-charset_cursor_free (SCM charset)
-{
-  scm_t_char_set_cursor *cur;
-
-  cur = (scm_t_char_set_cursor *) SCM_SMOB_DATA (charset);
-  scm_gc_free (cur, sizeof (scm_t_char_set_cursor), "charset-cursor");
-  scm_remember_upto_here_1 (charset);
-
-  return 0;
-}
-
 
 /* Create a new, empty character set.  */
 static SCM
@@ -614,8 +698,8 @@ SCM_DEFINE (scm_char_set_eq, "char-set=", 0, 0, 1,
 
 SCM_DEFINE (scm_char_set_leq, "char-set<=", 0, 0, 1,
            (SCM char_sets),
-           "Return @code{#t} if every character set @var{cs}i is a subset\n"
-           "of character set @var{cs}i+1.")
+           "Return @code{#t} if every character set @var{char_set}i is a subset\n"
+           "of character set @var{char_set}i+1.")
 #define FUNC_NAME s_scm_char_set_leq
 {
   int argnum = 1;
@@ -648,7 +732,7 @@ SCM_DEFINE (scm_char_set_hash, "char-set-hash", 1, 1, 0,
            (SCM cs, SCM bound),
            "Compute a hash value for the character set @var{cs}.  If\n"
            "@var{bound} is given and non-zero, it restricts the\n"
-           "returned value to the range 0 @dots{} @var{bound - 1}.")
+           "returned value to the range 0 @dots{} @var{bound} - 1.")
 #define FUNC_NAME s_scm_char_set_hash
 {
   const unsigned long default_bnd = 871;
@@ -704,7 +788,6 @@ SCM_DEFINE (scm_char_set_cursor, "char-set-cursor", 1, 0, 0,
     }
   SCM_RETURN_NEWSMOB (scm_tc16_charset_cursor, cur_data);
 }
-
 #undef FUNC_NAME
 
 
@@ -734,7 +817,6 @@ SCM_DEFINE (scm_char_set_ref, "char-set-ref", 2, 0, 0,
     SCM_MISC_ERROR ("invalid character set cursor: ~A", scm_list_1 (cursor));
   return SCM_MAKE_CHAR (cur_data->n);
 }
-
 #undef FUNC_NAME
 
 
@@ -784,7 +866,6 @@ SCM_DEFINE (scm_char_set_cursor_next, "char-set-cursor-next", 2, 0, 0,
 
   return cursor;
 }
-
 #undef FUNC_NAME
 
 
@@ -803,7 +884,6 @@ SCM_DEFINE (scm_end_of_char_set_p, "end-of-char-set?", 1, 0, 0,
 
   return SCM_BOOL_F;
 }
-
 #undef FUNC_NAME
 
 
@@ -943,7 +1023,6 @@ SCM_DEFINE (scm_char_set_for_each, "char-set-for-each", 2, 0, 0,
 
   return SCM_UNSPECIFIED;
 }
-
 #undef FUNC_NAME
 
 
@@ -1007,7 +1086,6 @@ SCM_DEFINE (scm_char_set_copy, "char-set-copy", 1, 0, 0,
 
   return ret;
 }
-
 #undef FUNC_NAME
 
 
@@ -1182,7 +1260,6 @@ SCM_DEFINE (scm_char_set_filter, "char-set-filter", 2, 1, 0,
       }
   return ret;
 }
-
 #undef FUNC_NAME
 
 
@@ -1207,38 +1284,28 @@ SCM_DEFINE (scm_char_set_filter_x, "char-set-filter!", 3, 0, 0,
   for (k = 0; k < p->len; k++)
     for (n = p->ranges[k].lo; n <= p->ranges[k].hi; n++)
       {
-        SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
+        SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (n));
 
         if (scm_is_true (res))
           SCM_CHARSET_SET (base_cs, n);
       }
   return base_cs;
 }
-
 #undef FUNC_NAME
 
 
-SCM_DEFINE (scm_ucs_range_to_char_set, "ucs-range->char-set", 2, 2, 0,
-           (SCM lower, SCM upper, SCM error, SCM base_cs),
-           "Return a character set containing all characters whose\n"
-           "character codes lie in the half-open range\n"
-           "[@var{lower},@var{upper}).\n"
-           "\n"
-           "If @var{error} is a true value, an error is signalled if the\n"
-           "specified range contains characters which are not contained in\n"
-           "the implemented character range.  If @var{error} is @code{#f},\n"
-           "these characters are silently left out of the resultung\n"
-           "character set.\n"
-           "\n"
-           "The characters in @var{base_cs} are added to the result, if\n"
-           "given.")
-#define FUNC_NAME s_scm_ucs_range_to_char_set
+/* Return a character set containing all the characters from [LOWER,UPPER),
+   giving range errors if ERROR, adding chars from BASE_CS, and recycling
+   BASE_CS if REUSE is true.  */
+static SCM
+scm_i_ucs_range_to_char_set (const char *FUNC_NAME, SCM lower, SCM upper, 
+                             SCM error, SCM base_cs, int reuse)
 {
   SCM cs;
   size_t clower, cupper;
 
   clower = scm_to_size_t (lower);
-  cupper = scm_to_size_t (upper);
+  cupper = scm_to_size_t (upper) - 1;
   SCM_ASSERT_RANGE (2, upper, cupper >= clower);
   if (!SCM_UNBNDP (error))
     {
@@ -1246,28 +1313,66 @@ SCM_DEFINE (scm_ucs_range_to_char_set, "ucs-range->char-set", 2, 2, 0,
         {
           SCM_ASSERT_RANGE (1, lower, SCM_IS_UNICODE_CHAR (clower));
           SCM_ASSERT_RANGE (2, upper, SCM_IS_UNICODE_CHAR (cupper));
+          if (clower < SCM_CODEPOINT_SURROGATE_START 
+              && cupper > SCM_CODEPOINT_SURROGATE_END)
+            scm_error(scm_out_of_range_key,
+                      FUNC_NAME, "invalid range - contains surrogate characters: ~S to ~S",
+                      scm_list_2 (lower, upper), scm_list_1 (upper));
         }
     }
-  if (clower > 0x10FFFF)
-    clower = 0x10FFFF;
-  if (cupper > 0x10FFFF)
-    cupper = 0x10FFFF;
+
   if (SCM_UNBNDP (base_cs))
     cs = make_char_set (FUNC_NAME);
   else
     {
-      SCM_VALIDATE_SMOB (4, base_cs, charset);
-      cs = scm_char_set_copy (base_cs);
+      SCM_VALIDATE_SMOB (3, base_cs, charset);
+      if (reuse)
+        cs = base_cs;
+      else
+        cs = scm_char_set_copy (base_cs);
     }
-  /* It not be difficult to write a more optimized version of the
-     following.  */
-  while (clower < cupper)
+
+  if ((clower >= SCM_CODEPOINT_SURROGATE_START && clower <= SCM_CODEPOINT_SURROGATE_END)
+      && (cupper >= SCM_CODEPOINT_SURROGATE_START && cupper <= SCM_CODEPOINT_SURROGATE_END))
+    return cs;
+
+  if (clower > SCM_CODEPOINT_MAX)
+    clower = SCM_CODEPOINT_MAX;
+  if (clower >= SCM_CODEPOINT_SURROGATE_START  && clower <= SCM_CODEPOINT_SURROGATE_END)
+    clower = SCM_CODEPOINT_SURROGATE_END + 1;
+  if (cupper > SCM_CODEPOINT_MAX)
+    cupper = SCM_CODEPOINT_MAX;
+  if (cupper >= SCM_CODEPOINT_SURROGATE_START && cupper <= SCM_CODEPOINT_SURROGATE_END)
+    cupper = SCM_CODEPOINT_SURROGATE_START - 1;
+  if (clower < SCM_CODEPOINT_SURROGATE_START && cupper > SCM_CODEPOINT_SURROGATE_END)
     {
-      SCM_CHARSET_SET (cs, clower);
-      clower++;
+      scm_i_charset_set_range (SCM_CHARSET_DATA (cs), clower, SCM_CODEPOINT_SURROGATE_START - 1);
+      scm_i_charset_set_range (SCM_CHARSET_DATA (cs), SCM_CODEPOINT_SURROGATE_END + 1, cupper);
     }
+  else
+    scm_i_charset_set_range (SCM_CHARSET_DATA (cs), clower, cupper);
   return cs;
 }
+
+SCM_DEFINE (scm_ucs_range_to_char_set, "ucs-range->char-set", 2, 2, 0,
+           (SCM lower, SCM upper, SCM error, SCM base_cs),
+           "Return a character set containing all characters whose\n"
+           "character codes lie in the half-open range\n"
+           "[@var{lower},@var{upper}).\n"
+           "\n"
+           "If @var{error} is a true value, an error is signalled if the\n"
+           "specified range contains characters which are not valid\n"
+           "Unicode code points.  If @var{error} is @code{#f},\n"
+           "these characters are silently left out of the resulting\n"
+           "character set.\n"
+           "\n"
+           "The characters in @var{base_cs} are added to the result, if\n"
+           "given.")
+#define FUNC_NAME s_scm_ucs_range_to_char_set
+{
+  return scm_i_ucs_range_to_char_set (FUNC_NAME, lower, upper, 
+                                      error, base_cs, 0);
+}
 #undef FUNC_NAME
 
 
@@ -1280,35 +1385,16 @@ SCM_DEFINE (scm_ucs_range_to_char_set_x, "ucs-range->char-set!", 4, 0, 0,
            "If @var{error} is a true value, an error is signalled if the\n"
            "specified range contains characters which are not contained in\n"
            "the implemented character range.  If @var{error} is @code{#f},\n"
-           "these characters are silently left out of the resultung\n"
+           "these characters are silently left out of the resulting\n"
            "character set.\n"
            "\n"
            "The characters are added to @var{base_cs} and @var{base_cs} is\n"
            "returned.")
 #define FUNC_NAME s_scm_ucs_range_to_char_set_x
 {
-  size_t clower, cupper;
-
-  clower = scm_to_size_t (lower);
-  cupper = scm_to_size_t (upper);
-  SCM_ASSERT_RANGE (2, upper, cupper >= clower);
-  if (scm_is_true (error))
-    {
-      SCM_ASSERT_RANGE (1, lower, SCM_IS_UNICODE_CHAR (clower));
-      SCM_ASSERT_RANGE (2, upper, SCM_IS_UNICODE_CHAR (cupper));
-    }
-  if (clower > SCM_CODEPOINT_MAX)
-    clower = SCM_CODEPOINT_MAX;
-  if (cupper > SCM_CODEPOINT_MAX)
-    cupper = SCM_CODEPOINT_MAX;
-
-  while (clower < cupper)
-    {
-      if (SCM_IS_UNICODE_CHAR (clower))
-        SCM_CHARSET_SET (base_cs, clower);
-      clower++;
-    }
-  return base_cs;
+  SCM_VALIDATE_SMOB (4, base_cs, charset);  
+  return scm_i_ucs_range_to_char_set (FUNC_NAME, lower, upper, 
+                                      error, base_cs, 1);
 }
 #undef FUNC_NAME
 
@@ -1347,7 +1433,6 @@ SCM_DEFINE (scm_char_set_size, "char-set-size", 1, 0, 0,
 
   return scm_from_int (count);
 }
-
 #undef FUNC_NAME
 
 
@@ -1400,7 +1485,6 @@ SCM_DEFINE (scm_char_set_to_list, "char-set->list", 1, 0, 0,
       result = scm_cons (SCM_MAKE_CHAR (n), result);
   return result;
 }
-
 #undef FUNC_NAME
 
 
@@ -1431,9 +1515,9 @@ SCM_DEFINE (scm_char_set_to_string, "char-set->string", 1, 0, 0,
 
   count = scm_to_int (scm_char_set_size (cs));
   if (wide)
-    result = scm_i_make_wide_string (count, &wbuf);
+    result = scm_i_make_wide_string (count, &wbuf, 0);
   else
-    result = scm_i_make_string (count, &buf);
+    result = scm_i_make_string (count, &buf, 0);
 
   for (k = 0; k < cs_data->len; k++)
     for (n = cs_data->ranges[k].lo; n <= cs_data->ranges[k].hi; n++)
@@ -1445,7 +1529,6 @@ SCM_DEFINE (scm_char_set_to_string, "char-set->string", 1, 0, 0,
       }
   return result;
 }
-
 #undef FUNC_NAME
 
 
@@ -1489,7 +1572,6 @@ SCM_DEFINE (scm_char_set_every, "char-set-every", 2, 0, 0,
       }
   return SCM_BOOL_T;
 }
-
 #undef FUNC_NAME
 
 
@@ -1506,7 +1588,9 @@ SCM_DEFINE (scm_char_set_any, "char-set-any", 2, 0, 0,
   SCM_VALIDATE_PROC (1, pred);
   SCM_VALIDATE_SMOB (2, cs, charset);
 
-  cs_data = (scm_t_char_set *) cs;
+  cs_data = SCM_CHARSET_DATA (cs);
+  if (cs_data->len == 0)
+    return SCM_BOOL_T;
 
   for (k = 0; k < cs_data->len; k++)
     for (n = cs_data->ranges[k].lo; n <= cs_data->ranges[k].hi; n++)
@@ -1634,7 +1718,6 @@ SCM_DEFINE (scm_char_set_complement, "char-set-complement", 1, 0, 0,
   charsets_complement (p, q);
   return res;
 }
-
 #undef FUNC_NAME
 
 
@@ -1816,7 +1899,6 @@ SCM_DEFINE (scm_char_set_complement_x, "char-set-complement!", 1, 0, 0,
   cs = scm_char_set_complement (cs);
   return cs;
 }
-
 #undef FUNC_NAME
 
 
@@ -1831,7 +1913,6 @@ SCM_DEFINE (scm_char_set_union_x, "char-set-union!", 1, 0, 1,
   cs1 = scm_char_set_union (scm_cons (cs1, rest));
   return cs1;
 }
-
 #undef FUNC_NAME
 
 
@@ -1846,7 +1927,6 @@ SCM_DEFINE (scm_char_set_intersection_x, "char-set-intersection!", 1, 0, 1,
   cs1 = scm_char_set_intersection (scm_cons (cs1, rest));
   return cs1;
 }
-
 #undef FUNC_NAME
 
 
@@ -1861,7 +1941,6 @@ SCM_DEFINE (scm_char_set_difference_x, "char-set-difference!", 1, 0, 1,
   cs1 = scm_char_set_difference (cs1, rest);
   return cs1;
 }
-
 #undef FUNC_NAME
 
 
@@ -1875,9 +1954,9 @@ SCM_DEFINE (scm_char_set_xor_x, "char-set-xor!", 1, 0, 1,
      (char-set-xor a a a) -> char set #\a
      (char-set-xor! a a a) -> char set #\a
    */
-  return scm_char_set_xor (scm_cons (cs1, rest));
+  cs1 = scm_char_set_xor (scm_cons (cs1, rest));
+  return cs1;
 }
-
 #undef FUNC_NAME
 
 
@@ -1897,8 +1976,8 @@ SCM_DEFINE (scm_char_set_diff_plus_intersection_x,
   cs2 = intersect;
   return scm_values (scm_list_2 (cs1, cs2));
 }
-
 #undef FUNC_NAME
+
 \f
 
 /* Standard character sets.  */
@@ -1919,6 +1998,7 @@ SCM scm_char_set_hex_digit;
 SCM scm_char_set_blank;
 SCM scm_char_set_ascii;
 SCM scm_char_set_empty;
+SCM scm_char_set_designated;
 SCM scm_char_set_full;
 
 
@@ -1930,35 +2010,62 @@ define_charset (const char *name, const scm_t_char_set *p)
 
   SCM_NEWSMOB (cs, scm_tc16_charset, p);
   scm_c_define (name, cs);
-  return scm_permanent_object (cs);
+  return cs;
 }
 
-#ifdef SCM_CHARSET_DEBUG
-SCM_DEFINE (scm_debug_char_set, "debug-char-set", 1, 0, 0,
-            (SCM charset),
-            "Print out the internal C structure of @var{charset}.\n")
-#define FUNC_NAME s_debug_char_set
-{
-  int i;
-  scm_t_char_set *cs = SCM_CHARSET_DATA (charset);
-  fprintf (stderr, "cs %p\n", cs);
-  fprintf (stderr, "len %d\n", cs->len);
-  fprintf (stderr, "arr %p\n", cs->ranges);
+SCM_DEFINE (scm_sys_char_set_dump, "%char-set-dump", 1, 0, 0, (SCM charset), 
+            "Returns an association list containing debugging information\n"
+            "for @var{charset}. The association list has the following entries."
+            "@table @code\n"
+            "@item char-set\n"
+            "The char-set itself.\n"
+            "@item len\n"
+            "The number of character ranges the char-set contains\n"
+            "@item ranges\n"
+            "A list of lists where each sublist a range of code points\n"
+            "and their associated characters"
+            "@end table")
+#define FUNC_NAME s_scm_sys_char_set_dump
+{
+  SCM e1, e2, e3;
+  SCM ranges = SCM_EOL, elt;
+  size_t i;
+  scm_t_char_set *cs;
+  char codepoint_string_lo[9], codepoint_string_hi[9];
+
+  SCM_VALIDATE_SMOB (1, charset, charset);
+  cs = SCM_CHARSET_DATA (charset);
+
+  e1 = scm_cons (scm_from_latin1_symbol ("char-set"),
+                 charset);
+  e2 = scm_cons (scm_from_latin1_symbol ("n"),
+                 scm_from_size_t (cs->len));
+
   for (i = 0; i < cs->len; i++)
     {
-      if (cs->ranges[i].lo == cs->ranges[i].hi)
-        fprintf (stderr, "%04x\n", cs->ranges[i].lo);
+      if (cs->ranges[i].lo > 0xFFFF)
+        sprintf (codepoint_string_lo, "U+%06x", cs->ranges[i].lo);
+      else
+        sprintf (codepoint_string_lo, "U+%04x", cs->ranges[i].lo);
+      if (cs->ranges[i].hi > 0xFFFF)
+        sprintf (codepoint_string_hi, "U+%06x", cs->ranges[i].hi);
       else
-        fprintf (stderr, "%04x..%04x\t[%d]\n",
-                 cs->ranges[i].lo,
-                 cs->ranges[i].hi, cs->ranges[i].hi - cs->ranges[i].lo + 1);
+        sprintf (codepoint_string_hi, "U+%04x", cs->ranges[i].hi);
+
+      elt = scm_list_4 (SCM_MAKE_CHAR (cs->ranges[i].lo),
+                            SCM_MAKE_CHAR (cs->ranges[i].hi),
+                            scm_from_locale_string (codepoint_string_lo),
+                            scm_from_locale_string (codepoint_string_hi));
+      ranges = scm_append (scm_list_2 (ranges,
+                                       scm_list_1 (elt)));
     }
-  printf ("\n");
-  return SCM_UNSPECIFIED;
-}
+  e3 = scm_cons (scm_from_latin1_symbol ("ranges"),
+                 ranges);
 
+  return scm_list_3 (e1, e2, e3);
+}
 #undef FUNC_NAME
-#endif
+
 \f
 
 
@@ -1966,11 +2073,9 @@ void
 scm_init_srfi_14 (void)
 {
   scm_tc16_charset = scm_make_smob_type ("character-set", 0);
-  scm_set_smob_free (scm_tc16_charset, charset_free);
   scm_set_smob_print (scm_tc16_charset, charset_print);
 
   scm_tc16_charset_cursor = scm_make_smob_type ("char-set-cursor", 0);
-  scm_set_smob_free (scm_tc16_charset_cursor, charset_cursor_free);
   scm_set_smob_print (scm_tc16_charset_cursor, charset_cursor_print);
 
   scm_char_set_upper_case =
@@ -1997,6 +2102,7 @@ scm_init_srfi_14 (void)
   scm_char_set_blank = define_charset ("char-set:blank", &cs_blank);
   scm_char_set_ascii = define_charset ("char-set:ascii", &cs_ascii);
   scm_char_set_empty = define_charset ("char-set:empty", &cs_empty);
+  scm_char_set_designated = define_charset ("char-set:designated", &cs_designated);
   scm_char_set_full = define_charset ("char-set:full", &cs_full);
 
 #include "libguile/srfi-14.x"