1 /* srfi-14.c --- SRFI-14 procedures for Guile
3 * Copyright (C) 2001, 2004, 2006, 2007 Free Software Foundation, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 3 of
8 * the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "libguile/srfi-14.h"
31 #include "libguile/strings.h"
32 #include "libguile/chars.h"
34 /* Include the pre-computed standard charset data. */
35 #include "libguile/srfi-14.i.c"
37 #define SCM_CHARSET_DATA(charset) ((scm_t_char_set *) SCM_SMOB_DATA (charset))
39 #define SCM_CHARSET_SET(cs, idx) \
40 scm_i_charset_set (SCM_CHARSET_DATA (cs), idx)
42 #define SCM_CHARSET_UNSET(cs, idx) \
43 scm_i_charset_unset (SCM_CHARSET_DATA (cs), idx)
45 /* Smob type code for character sets. */
46 int scm_tc16_charset
= 0;
47 int scm_tc16_charset_cursor
= 0;
49 /* True if N exists in charset CS. */
51 scm_i_charset_get (scm_t_char_set
*cs
, scm_t_wchar n
)
58 if (cs
->ranges
[i
].lo
<= n
&& n
<= cs
->ranges
[i
].hi
)
66 /* Put N into charset CS. */
68 scm_i_charset_set (scm_t_char_set
*cs
, scm_t_wchar n
)
78 /* Already in this range */
79 if (cs
->ranges
[i
].lo
<= n
&& n
<= cs
->ranges
[i
].hi
)
84 if (n
== cs
->ranges
[i
].lo
- 1)
86 /* This char is one below the current range. */
87 if (i
> 0 && cs
->ranges
[i
- 1].hi
+ 1 == n
)
89 /* It is also one above the previous range. */
90 /* This is an impossible condition: in the previous
91 iteration, the test for 'one above the current range'
92 should already have inserted the character here. */
97 /* Expand the range down by one. */
102 else if (n
== cs
->ranges
[i
].hi
+ 1)
104 /* This char is one above the current range. */
105 if (i
< len
- 1 && cs
->ranges
[i
+ 1].lo
- 1 == n
)
107 /* It is also one below the next range, so combine them. */
108 cs
->ranges
[i
].hi
= cs
->ranges
[i
+ 1].hi
;
110 memmove (cs
->ranges
+ (i
+ 1), cs
->ranges
+ (i
+ 2),
111 sizeof (scm_t_char_range
) * (len
- i
- 2));
112 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
113 sizeof (scm_t_char_range
) * len
,
114 sizeof (scm_t_char_range
) * (len
-
122 /* Expand the range up by one. */
123 cs
->ranges
[i
].hi
= n
;
127 else if (n
< cs
->ranges
[i
].lo
- 1)
129 /* This is a new range below the current one. */
130 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
131 sizeof (scm_t_char_range
) * len
,
132 sizeof (scm_t_char_range
) * (len
+ 1),
134 memmove (cs
->ranges
+ (i
+ 1), cs
->ranges
+ i
,
135 sizeof (scm_t_char_range
) * (len
- i
));
136 cs
->ranges
[i
].lo
= n
;
137 cs
->ranges
[i
].hi
= n
;
145 /* This is a new range above all previous ranges. */
148 cs
->ranges
= scm_gc_malloc (sizeof (scm_t_char_range
), "character-set");
152 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
153 sizeof (scm_t_char_range
) * len
,
154 sizeof (scm_t_char_range
) * (len
+ 1),
157 cs
->ranges
[len
].lo
= n
;
158 cs
->ranges
[len
].hi
= n
;
164 /* Put LO to HI inclusive into charset CS. */
166 scm_i_charset_set_range (scm_t_char_set
*cs
, scm_t_wchar lo
, scm_t_wchar hi
)
173 /* Already in this range */
174 if (cs
->ranges
[i
].lo
<= lo
&& cs
->ranges
[i
].hi
>= hi
)
180 if (cs
->ranges
[i
].lo
- 1 > hi
)
182 /* Add a new range below the current one. */
183 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
184 sizeof (scm_t_char_range
) * cs
->len
,
185 sizeof (scm_t_char_range
) * (cs
->len
+ 1),
187 memmove (cs
->ranges
+ (i
+ 1), cs
->ranges
+ i
,
188 sizeof (scm_t_char_range
) * (cs
->len
- i
));
189 cs
->ranges
[i
].lo
= lo
;
190 cs
->ranges
[i
].hi
= hi
;
195 /* cur: +---+ or +---+ or +---+
196 new: +---+ +---+ +---+
198 if (cs
->ranges
[i
].lo
> lo
199 && (cs
->ranges
[i
].lo
- 1 <= hi
&& cs
->ranges
[i
].hi
>= hi
))
201 cs
->ranges
[i
].lo
= lo
;
205 /* cur: +---+ or +---+ or +---+
206 new: +---+ +---+ +---+
208 else if (cs
->ranges
[i
].hi
+ 1 >= lo
&& cs
->ranges
[i
].hi
< hi
)
210 if (cs
->ranges
[i
].lo
> lo
)
211 cs
->ranges
[i
].lo
= lo
;
212 if (cs
->ranges
[i
].hi
< hi
)
213 cs
->ranges
[i
].hi
= hi
;
214 while (i
< cs
->len
- 1)
219 if (cs
->ranges
[i
+ 1].lo
- 1 > hi
)
222 /* cur: --+ +---+ or --+ +---+ or --+ +--+
223 new: -----+ ------+ ---------+
225 /* Combine this range with the previous one. */
226 if (cs
->ranges
[i
+ 1].hi
> hi
)
227 cs
->ranges
[i
].hi
= cs
->ranges
[i
+ 1].hi
;
229 memmove (cs
->ranges
+ i
+ 1, cs
->ranges
+ i
+ 2,
230 sizeof (scm_t_char_range
) * (cs
->len
- i
- 2));
231 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
232 sizeof (scm_t_char_range
) * cs
->len
,
233 sizeof (scm_t_char_range
) * (cs
->len
- 1),
242 /* This is a new range above all previous ranges. */
245 cs
->ranges
= scm_gc_malloc (sizeof (scm_t_char_range
), "character-set");
249 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
250 sizeof (scm_t_char_range
) * cs
->len
,
251 sizeof (scm_t_char_range
) * (cs
->len
+ 1),
255 cs
->ranges
[cs
->len
- 1].lo
= lo
;
256 cs
->ranges
[cs
->len
- 1].hi
= hi
;
261 /* If N is in charset CS, remove it. */
263 scm_i_charset_unset (scm_t_char_set
*cs
, scm_t_wchar n
)
273 if (n
< cs
->ranges
[i
].lo
)
274 /* Not in this set. */
277 if (n
== cs
->ranges
[i
].lo
&& n
== cs
->ranges
[i
].hi
)
279 /* Remove this one-character range. */
282 scm_gc_free (cs
->ranges
,
283 sizeof (scm_t_char_range
) * cs
->len
,
289 else if (i
< len
- 1)
291 memmove (cs
->ranges
+ i
, cs
->ranges
+ (i
+ 1),
292 sizeof (scm_t_char_range
) * (len
- i
- 1));
293 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
294 sizeof (scm_t_char_range
) * len
,
295 sizeof (scm_t_char_range
) * (len
-
301 else if (i
== len
- 1)
303 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
304 sizeof (scm_t_char_range
) * len
,
305 sizeof (scm_t_char_range
) * (len
-
312 else if (n
== cs
->ranges
[i
].lo
)
314 /* Shrink this range from the left. */
315 cs
->ranges
[i
].lo
= n
+ 1;
318 else if (n
== cs
->ranges
[i
].hi
)
320 /* Shrink this range from the right. */
321 cs
->ranges
[i
].hi
= n
- 1;
324 else if (n
> cs
->ranges
[i
].lo
&& n
< cs
->ranges
[i
].hi
)
326 /* Split this range into two pieces. */
327 cs
->ranges
= scm_gc_realloc (cs
->ranges
,
328 sizeof (scm_t_char_range
) * len
,
329 sizeof (scm_t_char_range
) * (len
+ 1),
332 memmove (cs
->ranges
+ (i
+ 2), cs
->ranges
+ (i
+ 1),
333 sizeof (scm_t_char_range
) * (len
- i
- 1));
334 cs
->ranges
[i
+ 1].hi
= cs
->ranges
[i
].hi
;
335 cs
->ranges
[i
+ 1].lo
= n
+ 1;
336 cs
->ranges
[i
].hi
= n
- 1;
344 /* This value is above all ranges, so do nothing here. */
349 charsets_equal (scm_t_char_set
*a
, scm_t_char_set
*b
)
351 if (a
->len
!= b
->len
)
354 if (memcmp (a
->ranges
, b
->ranges
, sizeof (scm_t_char_range
) * a
->len
) != 0)
360 /* Return true if every character in A is also in B. */
362 charsets_leq (scm_t_char_set
*a
, scm_t_char_set
*b
)
365 scm_t_wchar alo
, ahi
;
373 alo
= a
->ranges
[i
].lo
;
374 ahi
= a
->ranges
[i
].hi
;
375 while (b
->ranges
[j
].hi
< alo
)
382 if (alo
< b
->ranges
[j
].lo
|| ahi
> b
->ranges
[j
].hi
)
390 /* Merge B into A. */
392 charsets_union (scm_t_char_set
*a
, scm_t_char_set
*b
)
395 scm_t_wchar blo
, bhi
;
403 a
->ranges
= scm_gc_malloc (sizeof (scm_t_char_range
) * b
->len
,
405 memcpy (a
->ranges
, b
->ranges
, sizeof (scm_t_char_range
) * b
->len
);
411 blo
= b
->ranges
[i
].lo
;
412 bhi
= b
->ranges
[i
].hi
;
413 scm_i_charset_set_range (a
, blo
, bhi
);
421 /* Remove elements not both in A and B from A. */
423 charsets_intersection (scm_t_char_set
*a
, scm_t_char_set
*b
)
426 scm_t_wchar blo
, bhi
, n
;
434 scm_gc_free (a
->ranges
, sizeof (scm_t_char_range
) * a
->len
,
440 c
= (scm_t_char_set
*) scm_malloc (sizeof (scm_t_char_set
));
446 blo
= b
->ranges
[i
].lo
;
447 bhi
= b
->ranges
[i
].hi
;
448 for (n
= blo
; n
<= bhi
; n
++)
449 if (scm_i_charset_get (a
, n
))
450 scm_i_charset_set (c
, n
);
453 scm_gc_free (a
->ranges
, sizeof (scm_t_char_range
) * a
->len
,
458 a
->ranges
= c
->ranges
;
465 #define SCM_ADD_RANGE(low, high) \
467 p->ranges[idx].lo = (low); \
468 p->ranges[idx++].hi = (high); \
470 #define SCM_ADD_RANGE_SKIP_SURROGATES(low, high) \
472 p->ranges[idx].lo = (low); \
473 p->ranges[idx++].hi = SCM_CODEPOINT_SURROGATE_START - 1; \
474 p->ranges[idx].lo = SCM_CODEPOINT_SURROGATE_END + 1; \
475 p->ranges[idx++].hi = (high); \
480 /* Make P the compelement of Q. */
482 charsets_complement (scm_t_char_set
*p
, scm_t_char_set
*q
)
489 /* Fill with all valid codepoints. */
491 p
->ranges
= scm_gc_malloc (sizeof (scm_t_char_range
) * 2,
493 SCM_ADD_RANGE_SKIP_SURROGATES (0, SCM_CODEPOINT_MAX
);
498 scm_gc_free (p
->ranges
, sizeof (scm_t_char_set
) * p
->len
,
501 /* Count the number of ranges needed for the output. */
503 if (q
->ranges
[0].lo
> 0)
505 if (q
->ranges
[q
->len
- 1].hi
< SCM_CODEPOINT_MAX
)
509 (scm_t_char_range
*) scm_gc_malloc (sizeof (scm_t_char_range
) * p
->len
,
511 if (q
->ranges
[0].lo
> 0)
513 if (q
->ranges
[0].lo
> SCM_CODEPOINT_SURROGATE_END
)
514 SCM_ADD_RANGE_SKIP_SURROGATES (0, q
->ranges
[0].lo
- 1);
516 SCM_ADD_RANGE (0, q
->ranges
[0].lo
- 1);
518 for (k
= 1; k
< q
->len
; k
++)
520 if (q
->ranges
[k
- 1].hi
< SCM_CODEPOINT_SURROGATE_START
521 && q
->ranges
[k
].lo
- 1 > SCM_CODEPOINT_SURROGATE_END
)
522 SCM_ADD_RANGE_SKIP_SURROGATES (q
->ranges
[k
- 1].hi
+ 1, q
->ranges
[k
].lo
- 1);
524 SCM_ADD_RANGE (q
->ranges
[k
- 1].hi
+ 1, q
->ranges
[k
].lo
- 1);
526 if (q
->ranges
[q
->len
- 1].hi
< SCM_CODEPOINT_MAX
)
528 if (q
->ranges
[q
->len
- 1].hi
< SCM_CODEPOINT_SURROGATE_START
)
529 SCM_ADD_RANGE_SKIP_SURROGATES (q
->ranges
[q
->len
- 1].hi
+ 1, SCM_CODEPOINT_MAX
);
531 SCM_ADD_RANGE (q
->ranges
[q
->len
- 1].hi
+ 1, SCM_CODEPOINT_MAX
);
536 #undef SCM_ADD_RANGE_SKIP_SURROGATES
538 /* Replace A with elements only found in one of A or B. */
540 charsets_xor (scm_t_char_set
*a
, scm_t_char_set
*b
)
543 scm_t_wchar blo
, bhi
, n
;
553 (scm_t_char_range
*) scm_gc_malloc (sizeof (scm_t_char_range
) *
554 b
->len
, "character-set");
556 memcpy (a
->ranges
, b
->ranges
, sizeof (scm_t_char_range
) * a
->len
);
562 blo
= b
->ranges
[i
].lo
;
563 bhi
= b
->ranges
[i
].hi
;
564 for (n
= blo
; n
<= bhi
; n
++)
566 if (scm_i_charset_get (a
, n
))
567 scm_i_charset_unset (a
, n
);
569 scm_i_charset_set (a
, n
);
577 /* Smob print hook for character sets. */
579 charset_print (SCM charset
, SCM port
, scm_print_state
*pstate SCM_UNUSED
)
584 const size_t max_ranges_to_print
= 50;
586 p
= SCM_CHARSET_DATA (charset
);
588 scm_puts ("#<charset {", port
);
589 for (i
= 0; i
< p
->len
; i
++)
594 scm_puts (" ", port
);
595 scm_write (SCM_MAKE_CHAR (p
->ranges
[i
].lo
), port
);
596 if (p
->ranges
[i
].lo
!= p
->ranges
[i
].hi
)
598 scm_puts ("..", port
);
599 scm_write (SCM_MAKE_CHAR (p
->ranges
[i
].hi
), port
);
601 if (i
>= max_ranges_to_print
)
603 /* Too many to print here. Quit early. */
604 scm_puts (" ...", port
);
608 scm_puts ("}>", port
);
613 /* Smob free hook for character sets. */
615 charset_free (SCM charset
)
620 cs
= SCM_CHARSET_DATA (charset
);
624 scm_gc_free (cs
->ranges
, sizeof (scm_t_char_range
) * len
,
630 scm_gc_free (cs
, sizeof (scm_t_char_set
), "character-set");
632 scm_remember_upto_here_1 (charset
);
638 /* Smob print hook for character sets cursors. */
640 charset_cursor_print (SCM cursor
, SCM port
,
641 scm_print_state
*pstate SCM_UNUSED
)
643 scm_t_char_set_cursor
*cur
;
645 cur
= (scm_t_char_set_cursor
*) SCM_SMOB_DATA (cursor
);
647 scm_puts ("#<charset-cursor ", port
);
648 if (cur
->range
== (size_t) (-1))
649 scm_puts ("(empty)", port
);
652 scm_write (scm_from_size_t (cur
->range
), port
);
653 scm_puts (":", port
);
654 scm_write (scm_from_int32 (cur
->n
), port
);
656 scm_puts (">", port
);
660 /* Smob free hook for character sets. */
662 charset_cursor_free (SCM charset
)
664 scm_t_char_set_cursor
*cur
;
666 cur
= (scm_t_char_set_cursor
*) SCM_SMOB_DATA (charset
);
667 scm_gc_free (cur
, sizeof (scm_t_char_set_cursor
), "charset-cursor");
668 scm_remember_upto_here_1 (charset
);
674 /* Create a new, empty character set. */
676 make_char_set (const char *func_name
)
680 p
= scm_gc_malloc (sizeof (scm_t_char_set
), "character-set");
681 memset (p
, 0, sizeof (scm_t_char_set
));
682 SCM_RETURN_NEWSMOB (scm_tc16_charset
, p
);
686 SCM_DEFINE (scm_char_set_p
, "char-set?", 1, 0, 0,
688 "Return @code{#t} if @var{obj} is a character set, @code{#f}\n"
690 #define FUNC_NAME s_scm_char_set_p
692 return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_charset
, obj
));
697 SCM_DEFINE (scm_char_set_eq
, "char-set=", 0, 0, 1,
699 "Return @code{#t} if all given character sets are equal.")
700 #define FUNC_NAME s_scm_char_set_eq
703 scm_t_char_set
*cs1_data
= NULL
;
705 SCM_VALIDATE_REST_ARGUMENT (char_sets
);
707 while (!scm_is_null (char_sets
))
709 SCM csi
= SCM_CAR (char_sets
);
710 scm_t_char_set
*csi_data
;
712 SCM_VALIDATE_SMOB (argnum
, csi
, charset
);
714 csi_data
= SCM_CHARSET_DATA (csi
);
715 if (cs1_data
== NULL
)
717 else if (!charsets_equal (cs1_data
, csi_data
))
719 char_sets
= SCM_CDR (char_sets
);
726 SCM_DEFINE (scm_char_set_leq
, "char-set<=", 0, 0, 1,
728 "Return @code{#t} if every character set @var{cs}i is a subset\n"
729 "of character set @var{cs}i+1.")
730 #define FUNC_NAME s_scm_char_set_leq
733 scm_t_char_set
*prev_data
= NULL
;
735 SCM_VALIDATE_REST_ARGUMENT (char_sets
);
737 while (!scm_is_null (char_sets
))
739 SCM csi
= SCM_CAR (char_sets
);
740 scm_t_char_set
*csi_data
;
742 SCM_VALIDATE_SMOB (argnum
, csi
, charset
);
744 csi_data
= SCM_CHARSET_DATA (csi
);
747 if (!charsets_leq (prev_data
, csi_data
))
750 prev_data
= csi_data
;
751 char_sets
= SCM_CDR (char_sets
);
758 SCM_DEFINE (scm_char_set_hash
, "char-set-hash", 1, 1, 0,
760 "Compute a hash value for the character set @var{cs}. If\n"
761 "@var{bound} is given and non-zero, it restricts the\n"
762 "returned value to the range 0 @dots{} @var{bound - 1}.")
763 #define FUNC_NAME s_scm_char_set_hash
765 const unsigned long default_bnd
= 871;
768 unsigned long val
= 0;
772 SCM_VALIDATE_SMOB (1, cs
, charset
);
774 if (SCM_UNBNDP (bound
))
778 bnd
= scm_to_ulong (bound
);
783 p
= SCM_CHARSET_DATA (cs
);
784 for (k
= 0; k
< p
->len
; k
++)
786 for (c
= p
->ranges
[k
].lo
; c
<= p
->ranges
[k
].hi
; c
++)
787 val
= c
+ (val
<< 1);
789 return scm_from_ulong (val
% bnd
);
794 SCM_DEFINE (scm_char_set_cursor
, "char-set-cursor", 1, 0, 0,
795 (SCM cs
), "Return a cursor into the character set @var{cs}.")
796 #define FUNC_NAME s_scm_char_set_cursor
798 scm_t_char_set
*cs_data
;
799 scm_t_char_set_cursor
*cur_data
;
801 SCM_VALIDATE_SMOB (1, cs
, charset
);
802 cs_data
= SCM_CHARSET_DATA (cs
);
804 (scm_t_char_set_cursor
*) scm_gc_malloc (sizeof (scm_t_char_set_cursor
),
806 if (cs_data
->len
== 0)
808 cur_data
->range
= (size_t) (-1);
814 cur_data
->n
= cs_data
->ranges
[0].lo
;
816 SCM_RETURN_NEWSMOB (scm_tc16_charset_cursor
, cur_data
);
821 SCM_DEFINE (scm_char_set_ref
, "char-set-ref", 2, 0, 0,
822 (SCM cs
, SCM cursor
),
823 "Return the character at the current cursor position\n"
824 "@var{cursor} in the character set @var{cs}. It is an error to\n"
825 "pass a cursor for which @code{end-of-char-set?} returns true.")
826 #define FUNC_NAME s_scm_char_set_ref
828 scm_t_char_set
*cs_data
;
829 scm_t_char_set_cursor
*cur_data
;
832 SCM_VALIDATE_SMOB (1, cs
, charset
);
833 SCM_VALIDATE_SMOB (2, cursor
, charset_cursor
);
835 cs_data
= SCM_CHARSET_DATA (cs
);
836 cur_data
= (scm_t_char_set_cursor
*) SCM_SMOB_DATA (cursor
);
838 /* Validate that this cursor is still true. */
840 if (i
== (size_t) (-1)
842 || cur_data
->n
< cs_data
->ranges
[i
].lo
843 || cur_data
->n
> cs_data
->ranges
[i
].hi
)
844 SCM_MISC_ERROR ("invalid character set cursor: ~A", scm_list_1 (cursor
));
845 return SCM_MAKE_CHAR (cur_data
->n
);
850 SCM_DEFINE (scm_char_set_cursor_next
, "char-set-cursor-next", 2, 0, 0,
851 (SCM cs
, SCM cursor
),
852 "Advance the character set cursor @var{cursor} to the next\n"
853 "character in the character set @var{cs}. It is an error if the\n"
854 "cursor given satisfies @code{end-of-char-set?}.")
855 #define FUNC_NAME s_scm_char_set_cursor_next
857 scm_t_char_set
*cs_data
;
858 scm_t_char_set_cursor
*cur_data
;
861 SCM_VALIDATE_SMOB (1, cs
, charset
);
862 SCM_VALIDATE_SMOB (2, cursor
, charset_cursor
);
864 cs_data
= SCM_CHARSET_DATA (cs
);
865 cur_data
= (scm_t_char_set_cursor
*) SCM_SMOB_DATA (cursor
);
867 /* Validate that this cursor is still true. */
869 if (i
== (size_t) (-1)
871 || cur_data
->n
< cs_data
->ranges
[i
].lo
872 || cur_data
->n
> cs_data
->ranges
[i
].hi
)
873 SCM_MISC_ERROR ("invalid character set cursor: ~A", scm_list_1 (cursor
));
874 /* Increment the cursor. */
875 if (cur_data
->n
== cs_data
->ranges
[i
].hi
)
877 if (i
+ 1 < cs_data
->len
)
879 cur_data
->range
= i
+ 1;
880 cur_data
->n
= cs_data
->ranges
[i
+ 1].lo
;
884 /* This is the end of the road. */
885 cur_data
->range
= (size_t) (-1);
891 cur_data
->n
= cur_data
->n
+ 1;
899 SCM_DEFINE (scm_end_of_char_set_p
, "end-of-char-set?", 1, 0, 0,
901 "Return @code{#t} if @var{cursor} has reached the end of a\n"
902 "character set, @code{#f} otherwise.")
903 #define FUNC_NAME s_scm_end_of_char_set_p
905 scm_t_char_set_cursor
*cur_data
;
906 SCM_VALIDATE_SMOB (1, cursor
, charset_cursor
);
908 cur_data
= (scm_t_char_set_cursor
*) SCM_SMOB_DATA (cursor
);
909 if (cur_data
->range
== (size_t) (-1))
917 SCM_DEFINE (scm_char_set_fold
, "char-set-fold", 3, 0, 0,
918 (SCM kons
, SCM knil
, SCM cs
),
919 "Fold the procedure @var{kons} over the character set @var{cs},\n"
920 "initializing it with @var{knil}.")
921 #define FUNC_NAME s_scm_char_set_fold
923 scm_t_char_set
*cs_data
;
927 SCM_VALIDATE_PROC (1, kons
);
928 SCM_VALIDATE_SMOB (3, cs
, charset
);
930 cs_data
= SCM_CHARSET_DATA (cs
);
932 if (cs_data
->len
== 0)
935 for (k
= 0; k
< cs_data
->len
; k
++)
936 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
938 knil
= scm_call_2 (kons
, SCM_MAKE_CHAR (n
), knil
);
945 SCM_DEFINE (scm_char_set_unfold
, "char-set-unfold", 4, 1, 0,
946 (SCM p
, SCM f
, SCM g
, SCM seed
, SCM base_cs
),
947 "This is a fundamental constructor for character sets.\n"
949 "@item @var{g} is used to generate a series of ``seed'' values\n"
950 "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
951 "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
952 "@item @var{p} tells us when to stop -- when it returns true\n"
953 "when applied to one of the seed values.\n"
954 "@item @var{f} maps each seed value to a character. These\n"
955 "characters are added to the base character set @var{base_cs} to\n"
956 "form the result; @var{base_cs} defaults to the empty set.\n"
958 #define FUNC_NAME s_scm_char_set_unfold
962 SCM_VALIDATE_PROC (1, p
);
963 SCM_VALIDATE_PROC (2, f
);
964 SCM_VALIDATE_PROC (3, g
);
965 if (!SCM_UNBNDP (base_cs
))
967 SCM_VALIDATE_SMOB (5, base_cs
, charset
);
968 result
= scm_char_set_copy (base_cs
);
971 result
= make_char_set (FUNC_NAME
);
973 tmp
= scm_call_1 (p
, seed
);
974 while (scm_is_false (tmp
))
976 SCM ch
= scm_call_1 (f
, seed
);
978 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f
));
979 SCM_CHARSET_SET (result
, SCM_CHAR (ch
));
981 seed
= scm_call_1 (g
, seed
);
982 tmp
= scm_call_1 (p
, seed
);
989 SCM_DEFINE (scm_char_set_unfold_x
, "char-set-unfold!", 5, 0, 0,
990 (SCM p
, SCM f
, SCM g
, SCM seed
, SCM base_cs
),
991 "This is a fundamental constructor for character sets.\n"
993 "@item @var{g} is used to generate a series of ``seed'' values\n"
994 "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
995 "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
996 "@item @var{p} tells us when to stop -- when it returns true\n"
997 "when applied to one of the seed values.\n"
998 "@item @var{f} maps each seed value to a character. These\n"
999 "characters are added to the base character set @var{base_cs} to\n"
1000 "form the result; @var{base_cs} defaults to the empty set.\n"
1002 #define FUNC_NAME s_scm_char_set_unfold_x
1006 SCM_VALIDATE_PROC (1, p
);
1007 SCM_VALIDATE_PROC (2, f
);
1008 SCM_VALIDATE_PROC (3, g
);
1009 SCM_VALIDATE_SMOB (5, base_cs
, charset
);
1011 tmp
= scm_call_1 (p
, seed
);
1012 while (scm_is_false (tmp
))
1014 SCM ch
= scm_call_1 (f
, seed
);
1015 if (!SCM_CHARP (ch
))
1016 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f
));
1017 SCM_CHARSET_SET (base_cs
, SCM_CHAR (ch
));
1019 seed
= scm_call_1 (g
, seed
);
1020 tmp
= scm_call_1 (p
, seed
);
1027 SCM_DEFINE (scm_char_set_for_each
, "char-set-for-each", 2, 0, 0,
1029 "Apply @var{proc} to every character in the character set\n"
1030 "@var{cs}. The return value is not specified.")
1031 #define FUNC_NAME s_scm_char_set_for_each
1033 scm_t_char_set
*cs_data
;
1037 SCM_VALIDATE_PROC (1, proc
);
1038 SCM_VALIDATE_SMOB (2, cs
, charset
);
1040 cs_data
= SCM_CHARSET_DATA (cs
);
1042 if (cs_data
->len
== 0)
1043 return SCM_UNSPECIFIED
;
1045 for (k
= 0; k
< cs_data
->len
; k
++)
1046 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1048 scm_call_1 (proc
, SCM_MAKE_CHAR (n
));
1051 return SCM_UNSPECIFIED
;
1056 SCM_DEFINE (scm_char_set_map
, "char-set-map", 2, 0, 0,
1058 "Map the procedure @var{proc} over every character in @var{cs}.\n"
1059 "@var{proc} must be a character -> character procedure.")
1060 #define FUNC_NAME s_scm_char_set_map
1064 scm_t_char_set
*cs_data
;
1067 SCM_VALIDATE_PROC (1, proc
);
1068 SCM_VALIDATE_SMOB (2, cs
, charset
);
1070 result
= make_char_set (FUNC_NAME
);
1071 cs_data
= SCM_CHARSET_DATA (cs
);
1073 if (cs_data
->len
== 0)
1076 for (k
= 0; k
< cs_data
->len
; k
++)
1077 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1079 SCM ch
= scm_call_1 (proc
, SCM_MAKE_CHAR (n
));
1080 if (!SCM_CHARP (ch
))
1081 SCM_MISC_ERROR ("procedure ~S returned non-char",
1083 SCM_CHARSET_SET (result
, SCM_CHAR (ch
));
1090 SCM_DEFINE (scm_char_set_copy
, "char-set-copy", 1, 0, 0,
1092 "Return a newly allocated character set containing all\n"
1093 "characters in @var{cs}.")
1094 #define FUNC_NAME s_scm_char_set_copy
1097 scm_t_char_set
*p1
, *p2
;
1099 SCM_VALIDATE_SMOB (1, cs
, charset
);
1100 ret
= make_char_set (FUNC_NAME
);
1101 p1
= SCM_CHARSET_DATA (cs
);
1102 p2
= SCM_CHARSET_DATA (ret
);
1109 p2
->ranges
= scm_gc_malloc (sizeof (scm_t_char_range
) * p1
->len
,
1111 memcpy (p2
->ranges
, p1
->ranges
, sizeof (scm_t_char_range
) * p1
->len
);
1119 SCM_DEFINE (scm_char_set
, "char-set", 0, 0, 1,
1121 "Return a character set containing all given characters.")
1122 #define FUNC_NAME s_scm_char_set
1127 SCM_VALIDATE_REST_ARGUMENT (rest
);
1128 cs
= make_char_set (FUNC_NAME
);
1129 while (!scm_is_null (rest
))
1133 SCM_VALIDATE_CHAR_COPY (argnum
, SCM_CAR (rest
), c
);
1135 rest
= SCM_CDR (rest
);
1136 SCM_CHARSET_SET (cs
, c
);
1143 SCM_DEFINE (scm_list_to_char_set
, "list->char-set", 1, 1, 0,
1144 (SCM list
, SCM base_cs
),
1145 "Convert the character list @var{list} to a character set. If\n"
1146 "the character set @var{base_cs} is given, the character in this\n"
1147 "set are also included in the result.")
1148 #define FUNC_NAME s_scm_list_to_char_set
1152 SCM_VALIDATE_LIST (1, list
);
1153 if (SCM_UNBNDP (base_cs
))
1154 cs
= make_char_set (FUNC_NAME
);
1157 SCM_VALIDATE_SMOB (2, base_cs
, charset
);
1158 cs
= scm_char_set_copy (base_cs
);
1160 while (!scm_is_null (list
))
1162 SCM chr
= SCM_CAR (list
);
1165 SCM_VALIDATE_CHAR_COPY (0, chr
, c
);
1166 list
= SCM_CDR (list
);
1169 SCM_CHARSET_SET (cs
, c
);
1176 SCM_DEFINE (scm_list_to_char_set_x
, "list->char-set!", 2, 0, 0,
1177 (SCM list
, SCM base_cs
),
1178 "Convert the character list @var{list} to a character set. The\n"
1179 "characters are added to @var{base_cs} and @var{base_cs} is\n"
1181 #define FUNC_NAME s_scm_list_to_char_set_x
1183 SCM_VALIDATE_LIST (1, list
);
1184 SCM_VALIDATE_SMOB (2, base_cs
, charset
);
1185 while (!scm_is_null (list
))
1187 SCM chr
= SCM_CAR (list
);
1190 SCM_VALIDATE_CHAR_COPY (0, chr
, c
);
1191 list
= SCM_CDR (list
);
1193 SCM_CHARSET_SET (base_cs
, c
);
1200 SCM_DEFINE (scm_string_to_char_set
, "string->char-set", 1, 1, 0,
1201 (SCM str
, SCM base_cs
),
1202 "Convert the string @var{str} to a character set. If the\n"
1203 "character set @var{base_cs} is given, the characters in this\n"
1204 "set are also included in the result.")
1205 #define FUNC_NAME s_scm_string_to_char_set
1210 SCM_VALIDATE_STRING (1, str
);
1211 if (SCM_UNBNDP (base_cs
))
1212 cs
= make_char_set (FUNC_NAME
);
1215 SCM_VALIDATE_SMOB (2, base_cs
, charset
);
1216 cs
= scm_char_set_copy (base_cs
);
1218 len
= scm_i_string_length (str
);
1221 scm_t_wchar c
= scm_i_string_ref (str
, k
++);
1222 SCM_CHARSET_SET (cs
, c
);
1224 scm_remember_upto_here_1 (str
);
1230 SCM_DEFINE (scm_string_to_char_set_x
, "string->char-set!", 2, 0, 0,
1231 (SCM str
, SCM base_cs
),
1232 "Convert the string @var{str} to a character set. The\n"
1233 "characters from the string are added to @var{base_cs}, and\n"
1234 "@var{base_cs} is returned.")
1235 #define FUNC_NAME s_scm_string_to_char_set_x
1239 SCM_VALIDATE_STRING (1, str
);
1240 SCM_VALIDATE_SMOB (2, base_cs
, charset
);
1241 len
= scm_i_string_length (str
);
1244 scm_t_wchar c
= scm_i_string_ref (str
, k
++);
1245 SCM_CHARSET_SET (base_cs
, c
);
1247 scm_remember_upto_here_1 (str
);
1253 SCM_DEFINE (scm_char_set_filter
, "char-set-filter", 2, 1, 0,
1254 (SCM pred
, SCM cs
, SCM base_cs
),
1255 "Return a character set containing every character from @var{cs}\n"
1256 "so that it satisfies @var{pred}. If provided, the characters\n"
1257 "from @var{base_cs} are added to the result.")
1258 #define FUNC_NAME s_scm_char_set_filter
1265 SCM_VALIDATE_PROC (1, pred
);
1266 SCM_VALIDATE_SMOB (2, cs
, charset
);
1267 if (!SCM_UNBNDP (base_cs
))
1269 SCM_VALIDATE_SMOB (3, base_cs
, charset
);
1270 ret
= scm_char_set_copy (base_cs
);
1273 ret
= make_char_set (FUNC_NAME
);
1275 p
= SCM_CHARSET_DATA (cs
);
1280 for (k
= 0; k
< p
->len
; k
++)
1281 for (n
= p
->ranges
[k
].lo
; n
<= p
->ranges
[k
].hi
; n
++)
1283 SCM res
= scm_call_1 (pred
, SCM_MAKE_CHAR (n
));
1285 if (scm_is_true (res
))
1286 SCM_CHARSET_SET (ret
, n
);
1293 SCM_DEFINE (scm_char_set_filter_x
, "char-set-filter!", 3, 0, 0,
1294 (SCM pred
, SCM cs
, SCM base_cs
),
1295 "Return a character set containing every character from @var{cs}\n"
1296 "so that it satisfies @var{pred}. The characters are added to\n"
1297 "@var{base_cs} and @var{base_cs} is returned.")
1298 #define FUNC_NAME s_scm_char_set_filter_x
1304 SCM_VALIDATE_PROC (1, pred
);
1305 SCM_VALIDATE_SMOB (2, cs
, charset
);
1306 SCM_VALIDATE_SMOB (3, base_cs
, charset
);
1307 p
= SCM_CHARSET_DATA (cs
);
1311 for (k
= 0; k
< p
->len
; k
++)
1312 for (n
= p
->ranges
[k
].lo
; n
<= p
->ranges
[k
].hi
; n
++)
1314 SCM res
= scm_call_1 (pred
, SCM_MAKE_CHAR (n
));
1316 if (scm_is_true (res
))
1317 SCM_CHARSET_SET (base_cs
, n
);
1324 /* Return a character set containing all the characters from [LOWER,UPPER),
1325 giving range errors if ERROR, adding chars from BASE_CS, and recycling
1326 BASE_CS if REUSE is true. */
1328 scm_i_ucs_range_to_char_set (const char *FUNC_NAME
, SCM lower
, SCM upper
,
1329 SCM error
, SCM base_cs
, int reuse
)
1332 size_t clower
, cupper
;
1334 clower
= scm_to_size_t (lower
);
1335 cupper
= scm_to_size_t (upper
) - 1;
1336 SCM_ASSERT_RANGE (2, upper
, cupper
>= clower
);
1337 if (!SCM_UNBNDP (error
))
1339 if (scm_is_true (error
))
1341 SCM_ASSERT_RANGE (1, lower
, SCM_IS_UNICODE_CHAR (clower
));
1342 SCM_ASSERT_RANGE (2, upper
, SCM_IS_UNICODE_CHAR (cupper
));
1343 if (clower
< SCM_CODEPOINT_SURROGATE_START
1344 && cupper
> SCM_CODEPOINT_SURROGATE_END
)
1345 scm_error(scm_out_of_range_key
,
1346 FUNC_NAME
, "invalid range - contains surrogate characters: ~S to ~S",
1347 scm_list_2 (lower
, upper
), scm_list_1 (upper
));
1351 if (SCM_UNBNDP (base_cs
))
1352 cs
= make_char_set (FUNC_NAME
);
1355 SCM_VALIDATE_SMOB (4, base_cs
, charset
);
1359 cs
= scm_char_set_copy (base_cs
);
1362 if ((clower
>= SCM_CODEPOINT_SURROGATE_START
&& clower
<= SCM_CODEPOINT_SURROGATE_END
)
1363 && (cupper
>= SCM_CODEPOINT_SURROGATE_START
&& cupper
<= SCM_CODEPOINT_SURROGATE_END
))
1366 if (clower
> SCM_CODEPOINT_MAX
)
1367 clower
= SCM_CODEPOINT_MAX
;
1368 if (clower
>= SCM_CODEPOINT_SURROGATE_START
&& clower
<= SCM_CODEPOINT_SURROGATE_END
)
1369 clower
= SCM_CODEPOINT_SURROGATE_END
+ 1;
1370 if (cupper
> SCM_CODEPOINT_MAX
)
1371 cupper
= SCM_CODEPOINT_MAX
;
1372 if (cupper
>= SCM_CODEPOINT_SURROGATE_START
&& cupper
<= SCM_CODEPOINT_SURROGATE_END
)
1373 cupper
= SCM_CODEPOINT_SURROGATE_START
- 1;
1374 if (clower
< SCM_CODEPOINT_SURROGATE_START
&& cupper
> SCM_CODEPOINT_SURROGATE_END
)
1376 scm_i_charset_set_range (SCM_CHARSET_DATA (cs
), clower
, SCM_CODEPOINT_SURROGATE_START
- 1);
1377 scm_i_charset_set_range (SCM_CHARSET_DATA (cs
), SCM_CODEPOINT_SURROGATE_END
+ 1, cupper
);
1380 scm_i_charset_set_range (SCM_CHARSET_DATA (cs
), clower
, cupper
);
1384 SCM_DEFINE (scm_ucs_range_to_char_set
, "ucs-range->char-set", 2, 2, 0,
1385 (SCM lower
, SCM upper
, SCM error
, SCM base_cs
),
1386 "Return a character set containing all characters whose\n"
1387 "character codes lie in the half-open range\n"
1388 "[@var{lower},@var{upper}).\n"
1390 "If @var{error} is a true value, an error is signalled if the\n"
1391 "specified range contains characters which are not valid\n"
1392 "Unicode code points. If @var{error} is @code{#f},\n"
1393 "these characters are silently left out of the resultung\n"
1396 "The characters in @var{base_cs} are added to the result, if\n"
1398 #define FUNC_NAME s_scm_ucs_range_to_char_set
1400 return scm_i_ucs_range_to_char_set (FUNC_NAME
, lower
, upper
,
1406 SCM_DEFINE (scm_ucs_range_to_char_set_x
, "ucs-range->char-set!", 4, 0, 0,
1407 (SCM lower
, SCM upper
, SCM error
, SCM base_cs
),
1408 "Return a character set containing all characters whose\n"
1409 "character codes lie in the half-open range\n"
1410 "[@var{lower},@var{upper}).\n"
1412 "If @var{error} is a true value, an error is signalled if the\n"
1413 "specified range contains characters which are not contained in\n"
1414 "the implemented character range. If @var{error} is @code{#f},\n"
1415 "these characters are silently left out of the resultung\n"
1418 "The characters are added to @var{base_cs} and @var{base_cs} is\n"
1420 #define FUNC_NAME s_scm_ucs_range_to_char_set_x
1422 SCM_VALIDATE_SMOB (4, base_cs
, charset
);
1423 return scm_i_ucs_range_to_char_set (FUNC_NAME
, lower
, upper
,
1428 SCM_DEFINE (scm_to_char_set
, "->char-set", 1, 0, 0,
1430 "Coerces x into a char-set. @var{x} may be a string, character or char-set. A string is converted to the set of its constituent characters; a character is converted to a singleton set; a char-set is returned as-is.")
1431 #define FUNC_NAME s_scm_to_char_set
1433 if (scm_is_string (x
))
1434 return scm_string_to_char_set (x
, SCM_UNDEFINED
);
1435 else if (SCM_CHARP (x
))
1436 return scm_char_set (scm_list_1 (x
));
1437 else if (SCM_SMOB_PREDICATE (scm_tc16_charset
, x
))
1440 scm_wrong_type_arg (NULL
, 0, x
);
1444 SCM_DEFINE (scm_char_set_size
, "char-set-size", 1, 0, 0,
1446 "Return the number of elements in character set @var{cs}.")
1447 #define FUNC_NAME s_scm_char_set_size
1450 scm_t_char_set
*cs_data
;
1452 SCM_VALIDATE_SMOB (1, cs
, charset
);
1453 cs_data
= SCM_CHARSET_DATA (cs
);
1455 if (cs_data
->len
== 0)
1456 return scm_from_int (0);
1458 for (k
= 0; k
< cs_data
->len
; k
++)
1459 count
+= cs_data
->ranges
[k
].hi
- cs_data
->ranges
[k
].lo
+ 1;
1461 return scm_from_int (count
);
1466 SCM_DEFINE (scm_char_set_count
, "char-set-count", 2, 0, 0,
1468 "Return the number of the elements int the character set\n"
1469 "@var{cs} which satisfy the predicate @var{pred}.")
1470 #define FUNC_NAME s_scm_char_set_count
1474 scm_t_char_set
*cs_data
;
1476 SCM_VALIDATE_PROC (1, pred
);
1477 SCM_VALIDATE_SMOB (2, cs
, charset
);
1478 cs_data
= SCM_CHARSET_DATA (cs
);
1479 if (cs_data
->len
== 0)
1480 return scm_from_int (0);
1482 for (k
= 0; k
< cs_data
->len
; k
++)
1483 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1485 SCM res
= scm_call_1 (pred
, SCM_MAKE_CHAR (n
));
1486 if (scm_is_true (res
))
1489 return SCM_I_MAKINUM (count
);
1494 SCM_DEFINE (scm_char_set_to_list
, "char-set->list", 1, 0, 0,
1496 "Return a list containing the elements of the character set\n"
1498 #define FUNC_NAME s_scm_char_set_to_list
1502 SCM result
= SCM_EOL
;
1505 SCM_VALIDATE_SMOB (1, cs
, charset
);
1506 p
= SCM_CHARSET_DATA (cs
);
1510 for (k
= p
->len
- 1; k
>= 0; k
--)
1511 for (n
= p
->ranges
[k
].hi
; n
>= p
->ranges
[k
].lo
; n
--)
1512 result
= scm_cons (SCM_MAKE_CHAR (n
), result
);
1518 SCM_DEFINE (scm_char_set_to_string
, "char-set->string", 1, 0, 0,
1520 "Return a string containing the elements of the character set\n"
1521 "@var{cs}. The order in which the characters are placed in the\n"
1522 "string is not defined.")
1523 #define FUNC_NAME s_scm_char_set_to_string
1531 scm_t_char_set
*cs_data
;
1535 SCM_VALIDATE_SMOB (1, cs
, charset
);
1536 cs_data
= SCM_CHARSET_DATA (cs
);
1537 if (cs_data
->len
== 0)
1540 if (cs_data
->ranges
[cs_data
->len
- 1].hi
> 255)
1543 count
= scm_to_int (scm_char_set_size (cs
));
1545 result
= scm_i_make_wide_string (count
, &wbuf
);
1547 result
= scm_i_make_string (count
, &buf
);
1549 for (k
= 0; k
< cs_data
->len
; k
++)
1550 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1562 SCM_DEFINE (scm_char_set_contains_p
, "char-set-contains?", 2, 0, 0,
1564 "Return @code{#t} iff the character @var{ch} is contained in the\n"
1565 "character set @var{cs}.")
1566 #define FUNC_NAME s_scm_char_set_contains_p
1568 SCM_VALIDATE_SMOB (1, cs
, charset
);
1569 SCM_VALIDATE_CHAR (2, ch
);
1570 return scm_from_bool (SCM_CHARSET_GET (cs
, SCM_CHAR (ch
)));
1575 SCM_DEFINE (scm_char_set_every
, "char-set-every", 2, 0, 0,
1577 "Return a true value if every character in the character set\n"
1578 "@var{cs} satisfies the predicate @var{pred}.")
1579 #define FUNC_NAME s_scm_char_set_every
1583 SCM res
= SCM_BOOL_T
;
1584 scm_t_char_set
*cs_data
;
1586 SCM_VALIDATE_PROC (1, pred
);
1587 SCM_VALIDATE_SMOB (2, cs
, charset
);
1589 cs_data
= SCM_CHARSET_DATA (cs
);
1590 if (cs_data
->len
== 0)
1593 for (k
= 0; k
< cs_data
->len
; k
++)
1594 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1596 res
= scm_call_1 (pred
, SCM_MAKE_CHAR (n
));
1597 if (scm_is_false (res
))
1605 SCM_DEFINE (scm_char_set_any
, "char-set-any", 2, 0, 0,
1607 "Return a true value if any character in the character set\n"
1608 "@var{cs} satisfies the predicate @var{pred}.")
1609 #define FUNC_NAME s_scm_char_set_any
1613 scm_t_char_set
*cs_data
;
1615 SCM_VALIDATE_PROC (1, pred
);
1616 SCM_VALIDATE_SMOB (2, cs
, charset
);
1618 cs_data
= SCM_CHARSET_DATA (cs
);
1619 if (cs_data
->len
== 0)
1622 for (k
= 0; k
< cs_data
->len
; k
++)
1623 for (n
= cs_data
->ranges
[k
].lo
; n
<= cs_data
->ranges
[k
].hi
; n
++)
1625 SCM res
= scm_call_1 (pred
, SCM_MAKE_CHAR (n
));
1626 if (scm_is_true (res
))
1634 SCM_DEFINE (scm_char_set_adjoin
, "char-set-adjoin", 1, 0, 1,
1636 "Add all character arguments to the first argument, which must\n"
1637 "be a character set.")
1638 #define FUNC_NAME s_scm_char_set_adjoin
1640 SCM_VALIDATE_SMOB (1, cs
, charset
);
1641 SCM_VALIDATE_REST_ARGUMENT (rest
);
1642 cs
= scm_char_set_copy (cs
);
1644 while (!scm_is_null (rest
))
1646 SCM chr
= SCM_CAR (rest
);
1649 SCM_VALIDATE_CHAR_COPY (1, chr
, c
);
1650 rest
= SCM_CDR (rest
);
1652 SCM_CHARSET_SET (cs
, c
);
1659 SCM_DEFINE (scm_char_set_delete
, "char-set-delete", 1, 0, 1,
1661 "Delete all character arguments from the first argument, which\n"
1662 "must be a character set.")
1663 #define FUNC_NAME s_scm_char_set_delete
1665 SCM_VALIDATE_SMOB (1, cs
, charset
);
1666 SCM_VALIDATE_REST_ARGUMENT (rest
);
1667 cs
= scm_char_set_copy (cs
);
1669 while (!scm_is_null (rest
))
1671 SCM chr
= SCM_CAR (rest
);
1674 SCM_VALIDATE_CHAR_COPY (1, chr
, c
);
1675 rest
= SCM_CDR (rest
);
1677 SCM_CHARSET_UNSET (cs
, c
);
1684 SCM_DEFINE (scm_char_set_adjoin_x
, "char-set-adjoin!", 1, 0, 1,
1686 "Add all character arguments to the first argument, which must\n"
1687 "be a character set.")
1688 #define FUNC_NAME s_scm_char_set_adjoin_x
1690 SCM_VALIDATE_SMOB (1, cs
, charset
);
1691 SCM_VALIDATE_REST_ARGUMENT (rest
);
1693 while (!scm_is_null (rest
))
1695 SCM chr
= SCM_CAR (rest
);
1698 SCM_VALIDATE_CHAR_COPY (1, chr
, c
);
1699 rest
= SCM_CDR (rest
);
1701 SCM_CHARSET_SET (cs
, c
);
1708 SCM_DEFINE (scm_char_set_delete_x
, "char-set-delete!", 1, 0, 1,
1710 "Delete all character arguments from the first argument, which\n"
1711 "must be a character set.")
1712 #define FUNC_NAME s_scm_char_set_delete_x
1714 SCM_VALIDATE_SMOB (1, cs
, charset
);
1715 SCM_VALIDATE_REST_ARGUMENT (rest
);
1717 while (!scm_is_null (rest
))
1719 SCM chr
= SCM_CAR (rest
);
1722 SCM_VALIDATE_CHAR_COPY (1, chr
, c
);
1723 rest
= SCM_CDR (rest
);
1725 SCM_CHARSET_UNSET (cs
, c
);
1732 SCM_DEFINE (scm_char_set_complement
, "char-set-complement", 1, 0, 0,
1733 (SCM cs
), "Return the complement of the character set @var{cs}.")
1734 #define FUNC_NAME s_scm_char_set_complement
1737 scm_t_char_set
*p
, *q
;
1739 SCM_VALIDATE_SMOB (1, cs
, charset
);
1741 res
= make_char_set (FUNC_NAME
);
1742 p
= SCM_CHARSET_DATA (res
);
1743 q
= SCM_CHARSET_DATA (cs
);
1745 charsets_complement (p
, q
);
1751 SCM_DEFINE (scm_char_set_union
, "char-set-union", 0, 0, 1,
1753 "Return the union of all argument character sets.")
1754 #define FUNC_NAME s_scm_char_set_union
1760 SCM_VALIDATE_REST_ARGUMENT (rest
);
1762 res
= make_char_set (FUNC_NAME
);
1763 p
= SCM_CHARSET_DATA (res
);
1764 while (!scm_is_null (rest
))
1766 SCM cs
= SCM_CAR (rest
);
1767 SCM_VALIDATE_SMOB (c
, cs
, charset
);
1769 rest
= SCM_CDR (rest
);
1772 charsets_union (p
, (scm_t_char_set
*) SCM_SMOB_DATA (cs
));
1779 SCM_DEFINE (scm_char_set_intersection
, "char-set-intersection", 0, 0, 1,
1781 "Return the intersection of all argument character sets.")
1782 #define FUNC_NAME s_scm_char_set_intersection
1786 SCM_VALIDATE_REST_ARGUMENT (rest
);
1788 if (scm_is_null (rest
))
1789 res
= make_char_set (FUNC_NAME
);
1795 res
= scm_char_set_copy (SCM_CAR (rest
));
1796 p
= SCM_CHARSET_DATA (res
);
1797 rest
= SCM_CDR (rest
);
1799 while (scm_is_pair (rest
))
1801 SCM cs
= SCM_CAR (rest
);
1802 scm_t_char_set
*cs_data
;
1804 SCM_VALIDATE_SMOB (argnum
, cs
, charset
);
1806 cs_data
= SCM_CHARSET_DATA (cs
);
1807 rest
= SCM_CDR (rest
);
1808 charsets_intersection (p
, cs_data
);
1817 SCM_DEFINE (scm_char_set_difference
, "char-set-difference", 1, 0, 1,
1818 (SCM cs1
, SCM rest
),
1819 "Return the difference of all argument character sets.")
1820 #define FUNC_NAME s_scm_char_set_difference
1824 scm_t_char_set
*p
, *q
;
1826 SCM_VALIDATE_SMOB (1, cs1
, charset
);
1827 SCM_VALIDATE_REST_ARGUMENT (rest
);
1829 res
= scm_char_set_copy (cs1
);
1830 p
= SCM_CHARSET_DATA (res
);
1831 compl = make_char_set (FUNC_NAME
);
1832 q
= SCM_CHARSET_DATA (compl);
1833 while (!scm_is_null (rest
))
1835 SCM cs
= SCM_CAR (rest
);
1836 SCM_VALIDATE_SMOB (c
, cs
, charset
);
1838 rest
= SCM_CDR (rest
);
1840 charsets_complement (q
, SCM_CHARSET_DATA (cs
));
1841 charsets_intersection (p
, q
);
1848 SCM_DEFINE (scm_char_set_xor
, "char-set-xor", 0, 0, 1,
1850 "Return the exclusive-or of all argument character sets.")
1851 #define FUNC_NAME s_scm_char_set_xor
1855 SCM_VALIDATE_REST_ARGUMENT (rest
);
1857 if (scm_is_null (rest
))
1858 res
= make_char_set (FUNC_NAME
);
1864 res
= scm_char_set_copy (SCM_CAR (rest
));
1865 p
= SCM_CHARSET_DATA (res
);
1866 rest
= SCM_CDR (rest
);
1868 while (scm_is_pair (rest
))
1870 SCM cs
= SCM_CAR (rest
);
1871 scm_t_char_set
*cs_data
;
1873 SCM_VALIDATE_SMOB (argnum
, cs
, charset
);
1875 cs_data
= SCM_CHARSET_DATA (cs
);
1876 rest
= SCM_CDR (rest
);
1878 charsets_xor (p
, cs_data
);
1886 SCM_DEFINE (scm_char_set_diff_plus_intersection
, "char-set-diff+intersection", 1, 0, 1,
1887 (SCM cs1
, SCM rest
),
1888 "Return the difference and the intersection of all argument\n"
1890 #define FUNC_NAME s_scm_char_set_diff_plus_intersection
1894 scm_t_char_set
*p
, *q
;
1896 SCM_VALIDATE_SMOB (1, cs1
, charset
);
1897 SCM_VALIDATE_REST_ARGUMENT (rest
);
1899 res1
= scm_char_set_copy (cs1
);
1900 res2
= make_char_set (FUNC_NAME
);
1901 p
= SCM_CHARSET_DATA (res1
);
1902 q
= SCM_CHARSET_DATA (res2
);
1903 while (!scm_is_null (rest
))
1905 SCM cs
= SCM_CAR (rest
);
1908 SCM_VALIDATE_SMOB (c
, cs
, charset
);
1910 r
= SCM_CHARSET_DATA (cs
);
1912 charsets_union (q
, r
);
1913 charsets_intersection (p
, r
);
1914 rest
= SCM_CDR (rest
);
1916 return scm_values (scm_list_2 (res1
, res2
));
1921 SCM_DEFINE (scm_char_set_complement_x
, "char-set-complement!", 1, 0, 0,
1922 (SCM cs
), "Return the complement of the character set @var{cs}.")
1923 #define FUNC_NAME s_scm_char_set_complement_x
1925 SCM_VALIDATE_SMOB (1, cs
, charset
);
1926 cs
= scm_char_set_complement (cs
);
1932 SCM_DEFINE (scm_char_set_union_x
, "char-set-union!", 1, 0, 1,
1933 (SCM cs1
, SCM rest
),
1934 "Return the union of all argument character sets.")
1935 #define FUNC_NAME s_scm_char_set_union_x
1937 SCM_VALIDATE_SMOB (1, cs1
, charset
);
1938 SCM_VALIDATE_REST_ARGUMENT (rest
);
1940 cs1
= scm_char_set_union (scm_cons (cs1
, rest
));
1946 SCM_DEFINE (scm_char_set_intersection_x
, "char-set-intersection!", 1, 0, 1,
1947 (SCM cs1
, SCM rest
),
1948 "Return the intersection of all argument character sets.")
1949 #define FUNC_NAME s_scm_char_set_intersection_x
1951 SCM_VALIDATE_SMOB (1, cs1
, charset
);
1952 SCM_VALIDATE_REST_ARGUMENT (rest
);
1954 cs1
= scm_char_set_intersection (scm_cons (cs1
, rest
));
1960 SCM_DEFINE (scm_char_set_difference_x
, "char-set-difference!", 1, 0, 1,
1961 (SCM cs1
, SCM rest
),
1962 "Return the difference of all argument character sets.")
1963 #define FUNC_NAME s_scm_char_set_difference_x
1965 SCM_VALIDATE_SMOB (1, cs1
, charset
);
1966 SCM_VALIDATE_REST_ARGUMENT (rest
);
1968 cs1
= scm_char_set_difference (cs1
, rest
);
1974 SCM_DEFINE (scm_char_set_xor_x
, "char-set-xor!", 1, 0, 1,
1975 (SCM cs1
, SCM rest
),
1976 "Return the exclusive-or of all argument character sets.")
1977 #define FUNC_NAME s_scm_char_set_xor_x
1979 /* a side-effecting variant should presumably give consistent results:
1980 (define a (char-set #\a))
1981 (char-set-xor a a a) -> char set #\a
1982 (char-set-xor! a a a) -> char set #\a
1984 cs1
= scm_char_set_xor (scm_cons (cs1
, rest
));
1990 SCM_DEFINE (scm_char_set_diff_plus_intersection_x
,
1991 "char-set-diff+intersection!", 2, 0, 1, (SCM cs1
, SCM cs2
,
1993 "Return the difference and the intersection of all argument\n"
1995 #define FUNC_NAME s_scm_char_set_diff_plus_intersection_x
1997 SCM diff
, intersect
;
1999 diff
= scm_char_set_difference (cs1
, scm_cons (cs2
, rest
));
2001 scm_char_set_intersection (scm_cons (cs1
, scm_cons (cs2
, rest
)));
2004 return scm_values (scm_list_2 (cs1
, cs2
));
2010 /* Standard character sets. */
2012 SCM scm_char_set_lower_case
;
2013 SCM scm_char_set_upper_case
;
2014 SCM scm_char_set_title_case
;
2015 SCM scm_char_set_letter
;
2016 SCM scm_char_set_digit
;
2017 SCM scm_char_set_letter_and_digit
;
2018 SCM scm_char_set_graphic
;
2019 SCM scm_char_set_printing
;
2020 SCM scm_char_set_whitespace
;
2021 SCM scm_char_set_iso_control
;
2022 SCM scm_char_set_punctuation
;
2023 SCM scm_char_set_symbol
;
2024 SCM scm_char_set_hex_digit
;
2025 SCM scm_char_set_blank
;
2026 SCM scm_char_set_ascii
;
2027 SCM scm_char_set_empty
;
2028 SCM scm_char_set_full
;
2031 /* Create an empty character set and return it after binding it to NAME. */
2033 define_charset (const char *name
, const scm_t_char_set
*p
)
2037 SCM_NEWSMOB (cs
, scm_tc16_charset
, p
);
2038 scm_c_define (name
, cs
);
2039 return scm_permanent_object (cs
);
2042 #ifdef SCM_CHARSET_DEBUG
2043 SCM_DEFINE (scm_debug_char_set
, "debug-char-set", 1, 0, 0,
2045 "Print out the internal C structure of @var{charset}.\n")
2046 #define FUNC_NAME s_scm_debug_char_set
2049 scm_t_char_set
*cs
= SCM_CHARSET_DATA (charset
);
2050 fprintf (stderr
, "cs %p\n", cs
);
2051 fprintf (stderr
, "len %d\n", cs
->len
);
2052 fprintf (stderr
, "arr %p\n", cs
->ranges
);
2053 for (i
= 0; i
< cs
->len
; i
++)
2055 if (cs
->ranges
[i
].lo
== cs
->ranges
[i
].hi
)
2056 fprintf (stderr
, "%04x\n", cs
->ranges
[i
].lo
);
2058 fprintf (stderr
, "%04x..%04x\t[%d]\n",
2060 cs
->ranges
[i
].hi
, cs
->ranges
[i
].hi
- cs
->ranges
[i
].lo
+ 1);
2063 return SCM_UNSPECIFIED
;
2066 #endif /* SCM_CHARSET_DEBUG */
2071 scm_init_srfi_14 (void)
2073 scm_tc16_charset
= scm_make_smob_type ("character-set", 0);
2074 scm_set_smob_free (scm_tc16_charset
, charset_free
);
2075 scm_set_smob_print (scm_tc16_charset
, charset_print
);
2077 scm_tc16_charset_cursor
= scm_make_smob_type ("char-set-cursor", 0);
2078 scm_set_smob_free (scm_tc16_charset_cursor
, charset_cursor_free
);
2079 scm_set_smob_print (scm_tc16_charset_cursor
, charset_cursor_print
);
2081 scm_char_set_upper_case
=
2082 define_charset ("char-set:upper-case", &cs_upper_case
);
2083 scm_char_set_lower_case
=
2084 define_charset ("char-set:lower-case", &cs_lower_case
);
2085 scm_char_set_title_case
=
2086 define_charset ("char-set:title-case", &cs_title_case
);
2087 scm_char_set_letter
= define_charset ("char-set:letter", &cs_letter
);
2088 scm_char_set_digit
= define_charset ("char-set:digit", &cs_digit
);
2089 scm_char_set_letter_and_digit
=
2090 define_charset ("char-set:letter+digit", &cs_letter_plus_digit
);
2091 scm_char_set_graphic
= define_charset ("char-set:graphic", &cs_graphic
);
2092 scm_char_set_printing
= define_charset ("char-set:printing", &cs_printing
);
2093 scm_char_set_whitespace
=
2094 define_charset ("char-set:whitespace", &cs_whitespace
);
2095 scm_char_set_iso_control
=
2096 define_charset ("char-set:iso-control", &cs_iso_control
);
2097 scm_char_set_punctuation
=
2098 define_charset ("char-set:punctuation", &cs_punctuation
);
2099 scm_char_set_symbol
= define_charset ("char-set:symbol", &cs_symbol
);
2100 scm_char_set_hex_digit
=
2101 define_charset ("char-set:hex-digit", &cs_hex_digit
);
2102 scm_char_set_blank
= define_charset ("char-set:blank", &cs_blank
);
2103 scm_char_set_ascii
= define_charset ("char-set:ascii", &cs_ascii
);
2104 scm_char_set_empty
= define_charset ("char-set:empty", &cs_empty
);
2105 scm_char_set_full
= define_charset ("char-set:full", &cs_full
);
2107 #include "libguile/srfi-14.x"
2110 /* End of srfi-14.c. */