]> git.donarmstrong.com Git - lilypond.git/blob - guile18/libguile/srfi-14.c
Import guile-1.8 as multiple upstream tarball component
[lilypond.git] / guile18 / libguile / srfi-14.c
1 /* srfi-14.c --- SRFI-14 procedures for Guile
2  *
3  * Copyright (C) 2001, 2004, 2006, 2008 Free Software Foundation, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but 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.
14  *
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 02110-1301 USA
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "libguile.h"
28 #include "libguile/srfi-14.h"
29
30
31 #define SCM_CHARSET_SET(cs, idx)                                \
32   (((long *) SCM_SMOB_DATA (cs))[(idx) / SCM_BITS_PER_LONG] |=  \
33     (1L << ((idx) % SCM_BITS_PER_LONG)))
34
35 #define SCM_CHARSET_UNSET(cs, idx)                              \
36   (((long *) SCM_SMOB_DATA (cs))[(idx) / SCM_BITS_PER_LONG] &=  \
37     (~(1L << ((idx) % SCM_BITS_PER_LONG))))
38
39 #define BYTES_PER_CHARSET (SCM_CHARSET_SIZE / 8)
40 #define LONGS_PER_CHARSET (SCM_CHARSET_SIZE / SCM_BITS_PER_LONG)
41
42
43 /* Smob type code for character sets.  */
44 int scm_tc16_charset = 0;
45
46
47 /* Smob print hook for character sets.  */
48 static int
49 charset_print (SCM charset, SCM port, scm_print_state *pstate SCM_UNUSED)
50 {
51   int i;
52   int first = 1;
53
54   scm_puts ("#<charset {", port);
55   for (i = 0; i < SCM_CHARSET_SIZE; i++)
56     if (SCM_CHARSET_GET (charset, i))
57       {
58         if (first)
59           first = 0;
60         else
61           scm_puts (" ", port);
62         scm_write (SCM_MAKE_CHAR (i), port);
63       }
64   scm_puts ("}>", port);
65   return 1;
66 }
67
68
69 /* Smob free hook for character sets. */
70 static size_t
71 charset_free (SCM charset)
72 {
73   return scm_smob_free (charset);
74 }
75
76
77 /* Create a new, empty character set.  */
78 static SCM
79 make_char_set (const char * func_name)
80 {
81   long * p;
82
83   p = scm_gc_malloc (BYTES_PER_CHARSET, "character-set");
84   memset (p, 0, BYTES_PER_CHARSET);
85   SCM_RETURN_NEWSMOB (scm_tc16_charset, p);
86 }
87
88
89 SCM_DEFINE (scm_char_set_p, "char-set?", 1, 0, 0,
90             (SCM obj),
91             "Return @code{#t} if @var{obj} is a character set, @code{#f}\n"
92             "otherwise.")
93 #define FUNC_NAME s_scm_char_set_p
94 {
95   return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_charset, obj));
96 }
97 #undef FUNC_NAME
98
99
100 SCM_DEFINE (scm_char_set_eq, "char-set=", 0, 0, 1,
101             (SCM char_sets),
102             "Return @code{#t} if all given character sets are equal.")
103 #define FUNC_NAME s_scm_char_set_eq
104 {
105   int argnum = 1;
106   long *cs1_data = NULL;
107
108   SCM_VALIDATE_REST_ARGUMENT (char_sets);
109
110   while (!scm_is_null (char_sets))
111     {
112       SCM csi = SCM_CAR (char_sets);
113       long *csi_data;
114
115       SCM_VALIDATE_SMOB (argnum, csi, charset);
116       argnum++;
117       csi_data = (long *) SCM_SMOB_DATA (csi);
118       if (cs1_data == NULL)
119         cs1_data = csi_data;
120       else if (memcmp (cs1_data, csi_data, BYTES_PER_CHARSET) != 0)
121         return SCM_BOOL_F;
122       char_sets = SCM_CDR (char_sets);
123     }
124   return SCM_BOOL_T;
125 }
126 #undef FUNC_NAME
127
128
129 SCM_DEFINE (scm_char_set_leq, "char-set<=", 0, 0, 1,
130             (SCM char_sets),
131             "Return @code{#t} if every character set @var{cs}i is a subset\n"
132             "of character set @var{cs}i+1.")
133 #define FUNC_NAME s_scm_char_set_leq
134 {
135   int argnum = 1;
136   long *prev_data = NULL;
137
138   SCM_VALIDATE_REST_ARGUMENT (char_sets);
139
140   while (!scm_is_null (char_sets))
141     {
142       SCM csi = SCM_CAR (char_sets);
143       long *csi_data;
144
145       SCM_VALIDATE_SMOB (argnum, csi, charset);
146       argnum++;
147       csi_data = (long *) SCM_SMOB_DATA (csi);
148       if (prev_data)
149         {
150           int k;
151
152           for (k = 0; k < LONGS_PER_CHARSET; k++)
153             {
154               if ((prev_data[k] & csi_data[k]) != prev_data[k])
155                 return SCM_BOOL_F;
156             }
157         }
158       prev_data = csi_data;
159       char_sets = SCM_CDR (char_sets);
160     }
161   return SCM_BOOL_T;
162 }
163 #undef FUNC_NAME
164
165
166 SCM_DEFINE (scm_char_set_hash, "char-set-hash", 1, 1, 0,
167             (SCM cs, SCM bound),
168             "Compute a hash value for the character set @var{cs}.  If\n"
169             "@var{bound} is given and non-zero, it restricts the\n"
170             "returned value to the range 0 @dots{} @var{bound - 1}.")
171 #define FUNC_NAME s_scm_char_set_hash
172 {
173   const unsigned long default_bnd = 871;
174   unsigned long bnd;
175   long * p;
176   unsigned long val = 0;
177   int k;
178
179   SCM_VALIDATE_SMOB (1, cs, charset);
180
181   if (SCM_UNBNDP (bound))
182     bnd = default_bnd;
183   else
184     {
185       bnd = scm_to_ulong (bound);
186       if (bnd == 0)
187         bnd = default_bnd;
188     }
189
190   p = (long *) SCM_SMOB_DATA (cs);
191   for (k = 0; k < LONGS_PER_CHARSET; k++)
192     {
193       if (p[k] != 0)
194         val = p[k] + (val << 1);
195     }
196   return scm_from_ulong (val % bnd);
197 }
198 #undef FUNC_NAME
199
200
201 SCM_DEFINE (scm_char_set_cursor, "char-set-cursor", 1, 0, 0,
202             (SCM cs),
203             "Return a cursor into the character set @var{cs}.")
204 #define FUNC_NAME s_scm_char_set_cursor
205 {
206   int idx;
207
208   SCM_VALIDATE_SMOB (1, cs, charset);
209   for (idx = 0; idx < SCM_CHARSET_SIZE; idx++)
210     {
211       if (SCM_CHARSET_GET (cs, idx))
212         break;
213     }
214   return SCM_I_MAKINUM (idx);
215 }
216 #undef FUNC_NAME
217
218
219 SCM_DEFINE (scm_char_set_ref, "char-set-ref", 2, 0, 0,
220             (SCM cs, SCM cursor),
221             "Return the character at the current cursor position\n"
222             "@var{cursor} in the character set @var{cs}.  It is an error to\n"
223             "pass a cursor for which @code{end-of-char-set?} returns true.")
224 #define FUNC_NAME s_scm_char_set_ref
225 {
226   size_t ccursor = scm_to_size_t (cursor);
227   SCM_VALIDATE_SMOB (1, cs, charset);
228
229   if (ccursor >= SCM_CHARSET_SIZE || !SCM_CHARSET_GET (cs, ccursor))
230     SCM_MISC_ERROR ("invalid character set cursor: ~A", scm_list_1 (cursor));
231   return SCM_MAKE_CHAR (ccursor);
232 }
233 #undef FUNC_NAME
234
235
236 SCM_DEFINE (scm_char_set_cursor_next, "char-set-cursor-next", 2, 0, 0,
237             (SCM cs, SCM cursor),
238             "Advance the character set cursor @var{cursor} to the next\n"
239             "character in the character set @var{cs}.  It is an error if the\n"
240             "cursor given satisfies @code{end-of-char-set?}.")
241 #define FUNC_NAME s_scm_char_set_cursor_next
242 {
243   size_t ccursor = scm_to_size_t (cursor);
244   SCM_VALIDATE_SMOB (1, cs, charset);
245
246   if (ccursor >= SCM_CHARSET_SIZE || !SCM_CHARSET_GET (cs, ccursor))
247     SCM_MISC_ERROR ("invalid character set cursor: ~A", scm_list_1 (cursor));
248   for (ccursor++; ccursor < SCM_CHARSET_SIZE; ccursor++)
249     {
250       if (SCM_CHARSET_GET (cs, ccursor))
251         break;
252     }
253   return SCM_I_MAKINUM (ccursor);
254 }
255 #undef FUNC_NAME
256
257
258 SCM_DEFINE (scm_end_of_char_set_p, "end-of-char-set?", 1, 0, 0,
259             (SCM cursor),
260             "Return @code{#t} if @var{cursor} has reached the end of a\n"
261             "character set, @code{#f} otherwise.")
262 #define FUNC_NAME s_scm_end_of_char_set_p
263 {
264   size_t ccursor = scm_to_size_t (cursor);
265   return scm_from_bool (ccursor >= SCM_CHARSET_SIZE);
266 }
267 #undef FUNC_NAME
268
269
270 SCM_DEFINE (scm_char_set_fold, "char-set-fold", 3, 0, 0,
271             (SCM kons, SCM knil, SCM cs),
272             "Fold the procedure @var{kons} over the character set @var{cs},\n"
273             "initializing it with @var{knil}.")
274 #define FUNC_NAME s_scm_char_set_fold
275 {
276   int k;
277
278   SCM_VALIDATE_PROC (1, kons);
279   SCM_VALIDATE_SMOB (3, cs, charset);
280
281   for (k = 0; k < SCM_CHARSET_SIZE; k++)
282     if (SCM_CHARSET_GET (cs, k))
283       {
284         knil = scm_call_2 (kons, SCM_MAKE_CHAR (k), knil);
285       }
286   return knil;
287 }
288 #undef FUNC_NAME
289
290
291 SCM_DEFINE (scm_char_set_unfold, "char-set-unfold", 4, 1, 0,
292             (SCM p, SCM f, SCM g, SCM seed, SCM base_cs),
293             "This is a fundamental constructor for character sets.\n"
294             "@itemize @bullet\n"
295             "@item @var{g} is used to generate a series of ``seed'' values\n"
296             "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
297             "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
298             "@item @var{p} tells us when to stop -- when it returns true\n"
299             "when applied to one of the seed values.\n"
300             "@item @var{f} maps each seed value to a character. These\n"
301             "characters are added to the base character set @var{base_cs} to\n"
302             "form the result; @var{base_cs} defaults to the empty set.\n"
303             "@end itemize")
304 #define FUNC_NAME s_scm_char_set_unfold
305 {
306   SCM result, tmp;
307
308   SCM_VALIDATE_PROC (1, p);
309   SCM_VALIDATE_PROC (2, f);
310   SCM_VALIDATE_PROC (3, g);
311   if (!SCM_UNBNDP (base_cs))
312     {
313       SCM_VALIDATE_SMOB (5, base_cs, charset);
314       result = scm_char_set_copy (base_cs);
315     }
316   else
317     result = make_char_set (FUNC_NAME);
318
319   tmp = scm_call_1 (p, seed);
320   while (scm_is_false (tmp))
321     {
322       SCM ch = scm_call_1 (f, seed);
323       if (!SCM_CHARP (ch))
324         SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
325       SCM_CHARSET_SET (result, SCM_CHAR (ch));
326
327       seed = scm_call_1 (g, seed);
328       tmp = scm_call_1 (p, seed);
329     }
330   return result;
331 }
332 #undef FUNC_NAME
333
334
335 SCM_DEFINE (scm_char_set_unfold_x, "char-set-unfold!", 5, 0, 0,
336             (SCM p, SCM f, SCM g, SCM seed, SCM base_cs),
337             "This is a fundamental constructor for character sets.\n"
338             "@itemize @bullet\n"
339             "@item @var{g} is used to generate a series of ``seed'' values\n"
340             "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
341             "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
342             "@item @var{p} tells us when to stop -- when it returns true\n"
343             "when applied to one of the seed values.\n"
344             "@item @var{f} maps each seed value to a character. These\n"
345             "characters are added to the base character set @var{base_cs} to\n"
346             "form the result; @var{base_cs} defaults to the empty set.\n"
347             "@end itemize")
348 #define FUNC_NAME s_scm_char_set_unfold_x
349 {
350   SCM tmp;
351
352   SCM_VALIDATE_PROC (1, p);
353   SCM_VALIDATE_PROC (2, f);
354   SCM_VALIDATE_PROC (3, g);
355   SCM_VALIDATE_SMOB (5, base_cs, charset);
356
357   tmp = scm_call_1 (p, seed);
358   while (scm_is_false (tmp))
359     {
360       SCM ch = scm_call_1 (f, seed);
361       if (!SCM_CHARP (ch))
362         SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
363       SCM_CHARSET_SET (base_cs, SCM_CHAR (ch));
364
365       seed = scm_call_1 (g, seed);
366       tmp = scm_call_1 (p, seed);
367     }
368   return base_cs;
369 }
370 #undef FUNC_NAME
371
372
373 SCM_DEFINE (scm_char_set_for_each, "char-set-for-each", 2, 0, 0,
374             (SCM proc, SCM cs),
375             "Apply @var{proc} to every character in the character set\n"
376             "@var{cs}.  The return value is not specified.")
377 #define FUNC_NAME s_scm_char_set_for_each
378 {
379   int k;
380
381   SCM_VALIDATE_PROC (1, proc);
382   SCM_VALIDATE_SMOB (2, cs, charset);
383
384   for (k = 0; k < SCM_CHARSET_SIZE; k++)
385     if (SCM_CHARSET_GET (cs, k))
386       scm_call_1 (proc, SCM_MAKE_CHAR (k));
387   return SCM_UNSPECIFIED;
388 }
389 #undef FUNC_NAME
390
391
392 SCM_DEFINE (scm_char_set_map, "char-set-map", 2, 0, 0,
393             (SCM proc, SCM cs),
394             "Map the procedure @var{proc} over every character in @var{cs}.\n"
395             "@var{proc} must be a character -> character procedure.")
396 #define FUNC_NAME s_scm_char_set_map
397 {
398   SCM result;
399   int k;
400
401   SCM_VALIDATE_PROC (1, proc);
402   SCM_VALIDATE_SMOB (2, cs, charset);
403
404   result = make_char_set (FUNC_NAME);
405   for (k = 0; k < SCM_CHARSET_SIZE; k++)
406     if (SCM_CHARSET_GET (cs, k))
407       {
408         SCM ch = scm_call_1 (proc, SCM_MAKE_CHAR (k));
409         if (!SCM_CHARP (ch))
410           SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
411         SCM_CHARSET_SET (result, SCM_CHAR (ch));
412       }
413   return result;
414 }
415 #undef FUNC_NAME
416
417
418 SCM_DEFINE (scm_char_set_copy, "char-set-copy", 1, 0, 0,
419             (SCM cs),
420             "Return a newly allocated character set containing all\n"
421             "characters in @var{cs}.")
422 #define FUNC_NAME s_scm_char_set_copy
423 {
424   SCM ret;
425   long * p1, * p2;
426   int k;
427
428   SCM_VALIDATE_SMOB (1, cs, charset);
429   ret = make_char_set (FUNC_NAME);
430   p1 = (long *) SCM_SMOB_DATA (cs);
431   p2 = (long *) SCM_SMOB_DATA (ret);
432   for (k = 0; k < LONGS_PER_CHARSET; k++)
433     p2[k] = p1[k];
434   return ret;
435 }
436 #undef FUNC_NAME
437
438
439 SCM_DEFINE (scm_char_set, "char-set", 0, 0, 1,
440             (SCM rest),
441             "Return a character set containing all given characters.")
442 #define FUNC_NAME s_scm_char_set
443 {
444   SCM cs;
445   long * p;
446   int argnum = 1;
447
448   SCM_VALIDATE_REST_ARGUMENT (rest);
449   cs = make_char_set (FUNC_NAME);
450   p = (long *) SCM_SMOB_DATA (cs);
451   while (!scm_is_null (rest))
452     {
453       int c;
454
455       SCM_VALIDATE_CHAR_COPY (argnum, SCM_CAR (rest), c);
456       argnum++;
457       rest = SCM_CDR (rest);
458       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
459     }
460   return cs;
461 }
462 #undef FUNC_NAME
463
464
465 SCM_DEFINE (scm_list_to_char_set, "list->char-set", 1, 1, 0,
466             (SCM list, SCM base_cs),
467             "Convert the character list @var{list} to a character set.  If\n"
468             "the character set @var{base_cs} is given, the character in this\n"
469             "set are also included in the result.")
470 #define FUNC_NAME s_scm_list_to_char_set
471 {
472   SCM cs;
473   long * p;
474
475   SCM_VALIDATE_LIST (1, list);
476   if (SCM_UNBNDP (base_cs))
477     cs = make_char_set (FUNC_NAME);
478   else
479     {
480       SCM_VALIDATE_SMOB (2, base_cs, charset);
481       cs = scm_char_set_copy (base_cs);
482     }
483   p = (long *) SCM_SMOB_DATA (cs);
484   while (!scm_is_null (list))
485     {
486       SCM chr = SCM_CAR (list);
487       int c;
488
489       SCM_VALIDATE_CHAR_COPY (0, chr, c);
490       list = SCM_CDR (list);
491
492       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
493     }
494   return cs;
495 }
496 #undef FUNC_NAME
497
498
499 SCM_DEFINE (scm_list_to_char_set_x, "list->char-set!", 2, 0, 0,
500             (SCM list, SCM base_cs),
501             "Convert the character list @var{list} to a character set.  The\n"
502             "characters are added to @var{base_cs} and @var{base_cs} is\n"
503             "returned.")
504 #define FUNC_NAME s_scm_list_to_char_set_x
505 {
506   long * p;
507
508   SCM_VALIDATE_LIST (1, list);
509   SCM_VALIDATE_SMOB (2, base_cs, charset);
510   p = (long *) SCM_SMOB_DATA (base_cs);
511   while (!scm_is_null (list))
512     {
513       SCM chr = SCM_CAR (list);
514       int c;
515
516       SCM_VALIDATE_CHAR_COPY (0, chr, c);
517       list = SCM_CDR (list);
518
519       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
520     }
521   return base_cs;
522 }
523 #undef FUNC_NAME
524
525
526 SCM_DEFINE (scm_string_to_char_set, "string->char-set", 1, 1, 0,
527             (SCM str, SCM base_cs),
528             "Convert the string @var{str} to a character set.  If the\n"
529             "character set @var{base_cs} is given, the characters in this\n"
530             "set are also included in the result.")
531 #define FUNC_NAME s_scm_string_to_char_set
532 {
533   SCM cs;
534   long * p;
535   const char * s;
536   size_t k = 0, len;
537
538   SCM_VALIDATE_STRING (1, str);
539   if (SCM_UNBNDP (base_cs))
540     cs = make_char_set (FUNC_NAME);
541   else
542     {
543       SCM_VALIDATE_SMOB (2, base_cs, charset);
544       cs = scm_char_set_copy (base_cs);
545     }
546   p = (long *) SCM_SMOB_DATA (cs);
547   s = scm_i_string_chars (str);
548   len = scm_i_string_length (str);
549   while (k < len)
550     {
551       int c = s[k++];
552       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
553     }
554   scm_remember_upto_here_1 (str);
555   return cs;
556 }
557 #undef FUNC_NAME
558
559
560 SCM_DEFINE (scm_string_to_char_set_x, "string->char-set!", 2, 0, 0,
561             (SCM str, SCM base_cs),
562             "Convert the string @var{str} to a character set.  The\n"
563             "characters from the string are added to @var{base_cs}, and\n"
564             "@var{base_cs} is returned.")
565 #define FUNC_NAME s_scm_string_to_char_set_x
566 {
567   long * p;
568   const char * s;
569   size_t k = 0, len;
570
571   SCM_VALIDATE_STRING (1, str);
572   SCM_VALIDATE_SMOB (2, base_cs, charset);
573   p = (long *) SCM_SMOB_DATA (base_cs);
574   s = scm_i_string_chars (str);
575   len = scm_i_string_length (str);
576   while (k < len)
577     {
578       int c = s[k++];
579       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
580     }
581   scm_remember_upto_here_1 (str);
582   return base_cs;
583 }
584 #undef FUNC_NAME
585
586
587 SCM_DEFINE (scm_char_set_filter, "char-set-filter", 2, 1, 0,
588             (SCM pred, SCM cs, SCM base_cs),
589             "Return a character set containing every character from @var{cs}\n"
590             "so that it satisfies @var{pred}.  If provided, the characters\n"
591             "from @var{base_cs} are added to the result.")
592 #define FUNC_NAME s_scm_char_set_filter
593 {
594   SCM ret;
595   int k;
596   long * p;
597
598   SCM_VALIDATE_PROC (1, pred);
599   SCM_VALIDATE_SMOB (2, cs, charset);
600   if (!SCM_UNBNDP (base_cs))
601     {
602       SCM_VALIDATE_SMOB (3, base_cs, charset);
603       ret = scm_char_set_copy (base_cs);
604     }
605   else
606     ret = make_char_set (FUNC_NAME);
607   p = (long *) SCM_SMOB_DATA (ret);
608   for (k = 0; k < SCM_CHARSET_SIZE; k++)
609     {
610       if (SCM_CHARSET_GET (cs, k))
611         {
612           SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
613
614           if (scm_is_true (res))
615             p[k / SCM_BITS_PER_LONG] |= 1L << (k % SCM_BITS_PER_LONG);
616         }
617     }
618   return ret;
619 }
620 #undef FUNC_NAME
621
622
623 SCM_DEFINE (scm_char_set_filter_x, "char-set-filter!", 3, 0, 0,
624             (SCM pred, SCM cs, SCM base_cs),
625             "Return a character set containing every character from @var{cs}\n"
626             "so that it satisfies @var{pred}.  The characters are added to\n"
627             "@var{base_cs} and @var{base_cs} is returned.")
628 #define FUNC_NAME s_scm_char_set_filter_x
629 {
630   int k;
631   long * p;
632
633   SCM_VALIDATE_PROC (1, pred);
634   SCM_VALIDATE_SMOB (2, cs, charset);
635   SCM_VALIDATE_SMOB (3, base_cs, charset);
636   p = (long *) SCM_SMOB_DATA (base_cs);
637   for (k = 0; k < SCM_CHARSET_SIZE; k++)
638     {
639       if (SCM_CHARSET_GET (cs, k))
640         {
641           SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
642
643           if (scm_is_true (res))
644             p[k / SCM_BITS_PER_LONG] |= 1L << (k % SCM_BITS_PER_LONG);
645         }
646     }
647   return base_cs;
648 }
649 #undef FUNC_NAME
650
651
652 SCM_DEFINE (scm_ucs_range_to_char_set, "ucs-range->char-set", 2, 2, 0,
653             (SCM lower, SCM upper, SCM error, SCM base_cs),
654             "Return a character set containing all characters whose\n"
655             "character codes lie in the half-open range\n"
656             "[@var{lower},@var{upper}).\n"
657             "\n"
658             "If @var{error} is a true value, an error is signalled if the\n"
659             "specified range contains characters which are not contained in\n"
660             "the implemented character range.  If @var{error} is @code{#f},\n"
661             "these characters are silently left out of the resultung\n"
662             "character set.\n"
663             "\n"
664             "The characters in @var{base_cs} are added to the result, if\n"
665             "given.")
666 #define FUNC_NAME s_scm_ucs_range_to_char_set
667 {
668   SCM cs;
669   size_t clower, cupper;
670   long * p;
671
672   clower = scm_to_size_t (lower);
673   cupper = scm_to_size_t (upper);
674   SCM_ASSERT_RANGE (2, upper, cupper >= clower);
675   if (!SCM_UNBNDP (error))
676     {
677       if (scm_is_true (error))
678         {
679           SCM_ASSERT_RANGE (1, lower, clower <= SCM_CHARSET_SIZE);
680           SCM_ASSERT_RANGE (2, upper, cupper <= SCM_CHARSET_SIZE);
681         }
682     }
683   if (clower > SCM_CHARSET_SIZE)
684     clower = SCM_CHARSET_SIZE;
685   if (cupper > SCM_CHARSET_SIZE)
686     cupper = SCM_CHARSET_SIZE;
687   if (SCM_UNBNDP (base_cs))
688     cs = make_char_set (FUNC_NAME);
689   else
690     {
691       SCM_VALIDATE_SMOB (4, base_cs, charset);
692       cs = scm_char_set_copy (base_cs);
693     }
694   p = (long *) SCM_SMOB_DATA (cs);
695   while (clower < cupper)
696     {
697       p[clower / SCM_BITS_PER_LONG] |= 1L << (clower % SCM_BITS_PER_LONG);
698       clower++;
699     }
700   return cs;
701 }
702 #undef FUNC_NAME
703
704
705 SCM_DEFINE (scm_ucs_range_to_char_set_x, "ucs-range->char-set!", 4, 0, 0,
706             (SCM lower, SCM upper, SCM error, SCM base_cs),
707             "Return a character set containing all characters whose\n"
708             "character codes lie in the half-open range\n"
709             "[@var{lower},@var{upper}).\n"
710             "\n"
711             "If @var{error} is a true value, an error is signalled if the\n"
712             "specified range contains characters which are not contained in\n"
713             "the implemented character range.  If @var{error} is @code{#f},\n"
714             "these characters are silently left out of the resultung\n"
715             "character set.\n"
716             "\n"
717             "The characters are added to @var{base_cs} and @var{base_cs} is\n"
718             "returned.")
719 #define FUNC_NAME s_scm_ucs_range_to_char_set_x
720 {
721   size_t clower, cupper;
722   long * p;
723
724   clower = scm_to_size_t (lower);
725   cupper = scm_to_size_t (upper);
726   SCM_ASSERT_RANGE (2, upper, cupper >= clower);
727   if (scm_is_true (error))
728     {
729       SCM_ASSERT_RANGE (1, lower, clower <= SCM_CHARSET_SIZE);
730       SCM_ASSERT_RANGE (2, upper, cupper <= SCM_CHARSET_SIZE);
731     }
732   if (clower > SCM_CHARSET_SIZE)
733     clower = SCM_CHARSET_SIZE;
734   if (cupper > SCM_CHARSET_SIZE)
735     cupper = SCM_CHARSET_SIZE;
736   p = (long *) SCM_SMOB_DATA (base_cs);
737   while (clower < cupper)
738     {
739       p[clower / SCM_BITS_PER_LONG] |= 1L << (clower % SCM_BITS_PER_LONG);
740       clower++;
741     }
742   return base_cs;
743 }
744 #undef FUNC_NAME
745
746 SCM_DEFINE (scm_to_char_set, "->char-set", 1, 0, 0,
747             (SCM x),
748             "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.")
749 #define FUNC_NAME s_scm_to_char_set
750 {
751   if (scm_is_string (x))
752     return scm_string_to_char_set (x, SCM_UNDEFINED);
753   else if (SCM_CHARP (x))
754     return scm_char_set (scm_list_1 (x));
755   else if (SCM_SMOB_PREDICATE (scm_tc16_charset, x))
756     return x;
757   else
758     scm_wrong_type_arg (NULL, 0, x);
759 }
760 #undef FUNC_NAME
761
762 SCM_DEFINE (scm_char_set_size, "char-set-size", 1, 0, 0,
763             (SCM cs),
764             "Return the number of elements in character set @var{cs}.")
765 #define FUNC_NAME s_scm_char_set_size
766 {
767   int k, count = 0;
768
769   SCM_VALIDATE_SMOB (1, cs, charset);
770   for (k = 0; k < SCM_CHARSET_SIZE; k++)
771     if (SCM_CHARSET_GET (cs, k))
772       count++;
773   return SCM_I_MAKINUM (count);
774 }
775 #undef FUNC_NAME
776
777
778 SCM_DEFINE (scm_char_set_count, "char-set-count", 2, 0, 0,
779             (SCM pred, SCM cs),
780             "Return the number of the elements int the character set\n"
781             "@var{cs} which satisfy the predicate @var{pred}.")
782 #define FUNC_NAME s_scm_char_set_count
783 {
784   int k, count = 0;
785
786   SCM_VALIDATE_PROC (1, pred);
787   SCM_VALIDATE_SMOB (2, cs, charset);
788
789   for (k = 0; k < SCM_CHARSET_SIZE; k++)
790     if (SCM_CHARSET_GET (cs, k))
791       {
792         SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
793         if (scm_is_true (res))
794           count++;
795       }
796   return SCM_I_MAKINUM (count);
797 }
798 #undef FUNC_NAME
799
800
801 SCM_DEFINE (scm_char_set_to_list, "char-set->list", 1, 0, 0,
802             (SCM cs),
803             "Return a list containing the elements of the character set\n"
804             "@var{cs}.")
805 #define FUNC_NAME s_scm_char_set_to_list
806 {
807   int k;
808   SCM result = SCM_EOL;
809
810   SCM_VALIDATE_SMOB (1, cs, charset);
811   for (k = SCM_CHARSET_SIZE; k > 0; k--)
812     if (SCM_CHARSET_GET (cs, k - 1))
813       result = scm_cons (SCM_MAKE_CHAR (k - 1), result);
814   return result;
815 }
816 #undef FUNC_NAME
817
818
819 SCM_DEFINE (scm_char_set_to_string, "char-set->string", 1, 0, 0,
820             (SCM cs),
821             "Return a string containing the elements of the character set\n"
822             "@var{cs}.  The order in which the characters are placed in the\n"
823             "string is not defined.")
824 #define FUNC_NAME s_scm_char_set_to_string
825 {
826   int k;
827   int count = 0;
828   int idx = 0;
829   SCM result;
830   char * p;
831
832   SCM_VALIDATE_SMOB (1, cs, charset);
833   for (k = 0; k < SCM_CHARSET_SIZE; k++)
834     if (SCM_CHARSET_GET (cs, k))
835       count++;
836   result = scm_i_make_string (count, &p);
837   for (k = 0; k < SCM_CHARSET_SIZE; k++)
838     if (SCM_CHARSET_GET (cs, k))
839       p[idx++] = k;
840   return result;
841 }
842 #undef FUNC_NAME
843
844
845 SCM_DEFINE (scm_char_set_contains_p, "char-set-contains?", 2, 0, 0,
846             (SCM cs, SCM ch),
847             "Return @code{#t} iff the character @var{ch} is contained in the\n"
848             "character set @var{cs}.")
849 #define FUNC_NAME s_scm_char_set_contains_p
850 {
851   SCM_VALIDATE_SMOB (1, cs, charset);
852   SCM_VALIDATE_CHAR (2, ch);
853   return scm_from_bool (SCM_CHARSET_GET (cs, SCM_CHAR (ch)));
854 }
855 #undef FUNC_NAME
856
857
858 SCM_DEFINE (scm_char_set_every, "char-set-every", 2, 0, 0,
859             (SCM pred, SCM cs),
860             "Return a true value if every character in the character set\n"
861             "@var{cs} satisfies the predicate @var{pred}.")
862 #define FUNC_NAME s_scm_char_set_every
863 {
864   int k;
865   SCM res = SCM_BOOL_T;
866
867   SCM_VALIDATE_PROC (1, pred);
868   SCM_VALIDATE_SMOB (2, cs, charset);
869
870   for (k = 0; k < SCM_CHARSET_SIZE; k++)
871     if (SCM_CHARSET_GET (cs, k))
872       {
873         res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
874         if (scm_is_false (res))
875           return res;
876       }
877   return res;
878 }
879 #undef FUNC_NAME
880
881
882 SCM_DEFINE (scm_char_set_any, "char-set-any", 2, 0, 0,
883             (SCM pred, SCM cs),
884             "Return a true value if any character in the character set\n"
885             "@var{cs} satisfies the predicate @var{pred}.")
886 #define FUNC_NAME s_scm_char_set_any
887 {
888   int k;
889
890   SCM_VALIDATE_PROC (1, pred);
891   SCM_VALIDATE_SMOB (2, cs, charset);
892
893   for (k = 0; k < SCM_CHARSET_SIZE; k++)
894     if (SCM_CHARSET_GET (cs, k))
895       {
896         SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
897         if (scm_is_true (res))
898           return res;
899       }
900   return SCM_BOOL_F;
901 }
902 #undef FUNC_NAME
903
904
905 SCM_DEFINE (scm_char_set_adjoin, "char-set-adjoin", 1, 0, 1,
906             (SCM cs, SCM rest),
907             "Add all character arguments to the first argument, which must\n"
908             "be a character set.")
909 #define FUNC_NAME s_scm_char_set_adjoin
910 {
911   long * p;
912
913   SCM_VALIDATE_SMOB (1, cs, charset);
914   SCM_VALIDATE_REST_ARGUMENT (rest);
915   cs = scm_char_set_copy (cs);
916
917   p = (long *) SCM_SMOB_DATA (cs);
918   while (!scm_is_null (rest))
919     {
920       SCM chr = SCM_CAR (rest);
921       int c;
922
923       SCM_VALIDATE_CHAR_COPY (1, chr, c);
924       rest = SCM_CDR (rest);
925
926       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
927     }
928   return cs;
929 }
930 #undef FUNC_NAME
931
932
933 SCM_DEFINE (scm_char_set_delete, "char-set-delete", 1, 0, 1,
934             (SCM cs, SCM rest),
935             "Delete all character arguments from the first argument, which\n"
936             "must be a character set.")
937 #define FUNC_NAME s_scm_char_set_delete
938 {
939   long * p;
940
941   SCM_VALIDATE_SMOB (1, cs, charset);
942   SCM_VALIDATE_REST_ARGUMENT (rest);
943   cs = scm_char_set_copy (cs);
944
945   p = (long *) SCM_SMOB_DATA (cs);
946   while (!scm_is_null (rest))
947     {
948       SCM chr = SCM_CAR (rest);
949       int c;
950
951       SCM_VALIDATE_CHAR_COPY (1, chr, c);
952       rest = SCM_CDR (rest);
953
954       p[c / SCM_BITS_PER_LONG] &= ~(1L << (c % SCM_BITS_PER_LONG));
955     }
956   return cs;
957 }
958 #undef FUNC_NAME
959
960
961 SCM_DEFINE (scm_char_set_adjoin_x, "char-set-adjoin!", 1, 0, 1,
962             (SCM cs, SCM rest),
963             "Add all character arguments to the first argument, which must\n"
964             "be a character set.")
965 #define FUNC_NAME s_scm_char_set_adjoin_x
966 {
967   long * p;
968
969   SCM_VALIDATE_SMOB (1, cs, charset);
970   SCM_VALIDATE_REST_ARGUMENT (rest);
971
972   p = (long *) SCM_SMOB_DATA (cs);
973   while (!scm_is_null (rest))
974     {
975       SCM chr = SCM_CAR (rest);
976       int c;
977
978       SCM_VALIDATE_CHAR_COPY (1, chr, c);
979       rest = SCM_CDR (rest);
980
981       p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
982     }
983   return cs;
984 }
985 #undef FUNC_NAME
986
987
988 SCM_DEFINE (scm_char_set_delete_x, "char-set-delete!", 1, 0, 1,
989             (SCM cs, SCM rest),
990             "Delete all character arguments from the first argument, which\n"
991             "must be a character set.")
992 #define FUNC_NAME s_scm_char_set_delete_x
993 {
994   long * p;
995
996   SCM_VALIDATE_SMOB (1, cs, charset);
997   SCM_VALIDATE_REST_ARGUMENT (rest);
998
999   p = (long *) SCM_SMOB_DATA (cs);
1000   while (!scm_is_null (rest))
1001     {
1002       SCM chr = SCM_CAR (rest);
1003       int c;
1004
1005       SCM_VALIDATE_CHAR_COPY (1, chr, c);
1006       rest = SCM_CDR (rest);
1007
1008       p[c / SCM_BITS_PER_LONG] &= ~(1L << (c % SCM_BITS_PER_LONG));
1009     }
1010   return cs;
1011 }
1012 #undef FUNC_NAME
1013
1014
1015 SCM_DEFINE (scm_char_set_complement, "char-set-complement", 1, 0, 0,
1016             (SCM cs),
1017             "Return the complement of the character set @var{cs}.")
1018 #define FUNC_NAME s_scm_char_set_complement
1019 {
1020   int k;
1021   SCM res;
1022   long * p, * q;
1023
1024   SCM_VALIDATE_SMOB (1, cs, charset);
1025
1026   res = make_char_set (FUNC_NAME);
1027   p = (long *) SCM_SMOB_DATA (res);
1028   q = (long *) SCM_SMOB_DATA (cs);
1029   for (k = 0; k < LONGS_PER_CHARSET; k++)
1030     p[k] = ~q[k];
1031   return res;
1032 }
1033 #undef FUNC_NAME
1034
1035
1036 SCM_DEFINE (scm_char_set_union, "char-set-union", 0, 0, 1,
1037             (SCM rest),
1038             "Return the union of all argument character sets.")
1039 #define FUNC_NAME s_scm_char_set_union
1040 {
1041   int c = 1;
1042   SCM res;
1043   long * p;
1044
1045   SCM_VALIDATE_REST_ARGUMENT (rest);
1046
1047   res = make_char_set (FUNC_NAME);
1048   p = (long *) SCM_SMOB_DATA (res);
1049   while (!scm_is_null (rest))
1050     {
1051       int k;
1052       SCM cs = SCM_CAR (rest);
1053       SCM_VALIDATE_SMOB (c, cs, charset);
1054       c++;
1055       rest = SCM_CDR (rest);
1056
1057       for (k = 0; k < LONGS_PER_CHARSET; k++)
1058         p[k] |= ((long *) SCM_SMOB_DATA (cs))[k];
1059     }
1060   return res;
1061 }
1062 #undef FUNC_NAME
1063
1064
1065 SCM_DEFINE (scm_char_set_intersection, "char-set-intersection", 0, 0, 1,
1066             (SCM rest),
1067             "Return the intersection of all argument character sets.")
1068 #define FUNC_NAME s_scm_char_set_intersection
1069 {
1070   SCM res;
1071
1072   SCM_VALIDATE_REST_ARGUMENT (rest);
1073
1074   if (scm_is_null (rest))
1075     res = make_char_set (FUNC_NAME);
1076   else
1077     {
1078       long *p;
1079       int argnum = 2;
1080
1081       res = scm_char_set_copy (SCM_CAR (rest));
1082       p = (long *) SCM_SMOB_DATA (res);
1083       rest = SCM_CDR (rest);
1084
1085       while (scm_is_pair (rest))
1086         {
1087           int k;
1088           SCM cs = SCM_CAR (rest);
1089           long *cs_data;
1090
1091           SCM_VALIDATE_SMOB (argnum, cs, charset);
1092           argnum++;
1093           cs_data = (long *) SCM_SMOB_DATA (cs);
1094           rest = SCM_CDR (rest);
1095           for (k = 0; k < LONGS_PER_CHARSET; k++)
1096             p[k] &= cs_data[k];
1097         }
1098     }
1099
1100   return res;
1101 }
1102 #undef FUNC_NAME
1103
1104
1105 SCM_DEFINE (scm_char_set_difference, "char-set-difference", 1, 0, 1,
1106             (SCM cs1, SCM rest),
1107             "Return the difference of all argument character sets.")
1108 #define FUNC_NAME s_scm_char_set_difference
1109 {
1110   int c = 2;
1111   SCM res;
1112   long * p;
1113
1114   SCM_VALIDATE_SMOB (1, cs1, charset);
1115   SCM_VALIDATE_REST_ARGUMENT (rest);
1116
1117   res = scm_char_set_copy (cs1);
1118   p = (long *) SCM_SMOB_DATA (res);
1119   while (!scm_is_null (rest))
1120     {
1121       int k;
1122       SCM cs = SCM_CAR (rest);
1123       SCM_VALIDATE_SMOB (c, cs, charset);
1124       c++;
1125       rest = SCM_CDR (rest);
1126
1127       for (k = 0; k < LONGS_PER_CHARSET; k++)
1128         p[k] &= ~((long *) SCM_SMOB_DATA (cs))[k];
1129     }
1130   return res;
1131 }
1132 #undef FUNC_NAME
1133
1134
1135 SCM_DEFINE (scm_char_set_xor, "char-set-xor", 0, 0, 1,
1136             (SCM rest),
1137             "Return the exclusive-or of all argument character sets.")
1138 #define FUNC_NAME s_scm_char_set_xor
1139 {
1140   SCM res;
1141
1142   SCM_VALIDATE_REST_ARGUMENT (rest);
1143
1144   if (scm_is_null (rest))
1145     res = make_char_set (FUNC_NAME);
1146   else
1147     {
1148       int argnum = 2;
1149       long * p;
1150
1151       res = scm_char_set_copy (SCM_CAR (rest));
1152       p = (long *) SCM_SMOB_DATA (res);
1153       rest = SCM_CDR (rest);
1154
1155       while (scm_is_pair (rest))
1156         {
1157           SCM cs = SCM_CAR (rest);
1158           long *cs_data;
1159           int k;
1160
1161           SCM_VALIDATE_SMOB (argnum, cs, charset);
1162           argnum++;
1163           cs_data = (long *) SCM_SMOB_DATA (cs);
1164           rest = SCM_CDR (rest);
1165
1166           for (k = 0; k < LONGS_PER_CHARSET; k++)
1167             p[k] ^= cs_data[k];
1168         }
1169     }
1170   return res;
1171 }
1172 #undef FUNC_NAME
1173
1174
1175 SCM_DEFINE (scm_char_set_diff_plus_intersection, "char-set-diff+intersection", 1, 0, 1,
1176             (SCM cs1, SCM rest),
1177             "Return the difference and the intersection of all argument\n"
1178             "character sets.")
1179 #define FUNC_NAME s_scm_char_set_diff_plus_intersection
1180 {
1181   int c = 2;
1182   SCM res1, res2;
1183   long * p, * q;
1184
1185   SCM_VALIDATE_SMOB (1, cs1, charset);
1186   SCM_VALIDATE_REST_ARGUMENT (rest);
1187
1188   res1 = scm_char_set_copy (cs1);
1189   res2 = make_char_set (FUNC_NAME);
1190   p = (long *) SCM_SMOB_DATA (res1);
1191   q = (long *) SCM_SMOB_DATA (res2);
1192   while (!scm_is_null (rest))
1193     {
1194       int k;
1195       SCM cs = SCM_CAR (rest);
1196       long *r;
1197
1198       SCM_VALIDATE_SMOB (c, cs, charset);
1199       c++;
1200       r = (long *) SCM_SMOB_DATA (cs);
1201
1202       for (k = 0; k < LONGS_PER_CHARSET; k++)
1203         {
1204           q[k] |= p[k] & r[k];
1205           p[k] &= ~r[k];
1206         }
1207       rest = SCM_CDR (rest);
1208     }
1209   return scm_values (scm_list_2 (res1, res2));
1210 }
1211 #undef FUNC_NAME
1212
1213
1214 SCM_DEFINE (scm_char_set_complement_x, "char-set-complement!", 1, 0, 0,
1215             (SCM cs),
1216             "Return the complement of the character set @var{cs}.")
1217 #define FUNC_NAME s_scm_char_set_complement_x
1218 {
1219   int k;
1220   long * p;
1221
1222   SCM_VALIDATE_SMOB (1, cs, charset);
1223   p = (long *) SCM_SMOB_DATA (cs);
1224   for (k = 0; k < LONGS_PER_CHARSET; k++)
1225     p[k] = ~p[k];
1226   return cs;
1227 }
1228 #undef FUNC_NAME
1229
1230
1231 SCM_DEFINE (scm_char_set_union_x, "char-set-union!", 1, 0, 1,
1232             (SCM cs1, SCM rest),
1233             "Return the union of all argument character sets.")
1234 #define FUNC_NAME s_scm_char_set_union_x
1235 {
1236   int c = 2;
1237   long * p;
1238
1239   SCM_VALIDATE_SMOB (1, cs1, charset);
1240   SCM_VALIDATE_REST_ARGUMENT (rest);
1241
1242   p = (long *) SCM_SMOB_DATA (cs1);
1243   while (!scm_is_null (rest))
1244     {
1245       int k;
1246       SCM cs = SCM_CAR (rest);
1247       SCM_VALIDATE_SMOB (c, cs, charset);
1248       c++;
1249       rest = SCM_CDR (rest);
1250
1251       for (k = 0; k < LONGS_PER_CHARSET; k++)
1252         p[k] |= ((long *) SCM_SMOB_DATA (cs))[k];
1253     }
1254   return cs1;
1255 }
1256 #undef FUNC_NAME
1257
1258
1259 SCM_DEFINE (scm_char_set_intersection_x, "char-set-intersection!", 1, 0, 1,
1260             (SCM cs1, SCM rest),
1261             "Return the intersection of all argument character sets.")
1262 #define FUNC_NAME s_scm_char_set_intersection_x
1263 {
1264   int c = 2;
1265   long * p;
1266
1267   SCM_VALIDATE_SMOB (1, cs1, charset);
1268   SCM_VALIDATE_REST_ARGUMENT (rest);
1269
1270   p = (long *) SCM_SMOB_DATA (cs1);
1271   while (!scm_is_null (rest))
1272     {
1273       int k;
1274       SCM cs = SCM_CAR (rest);
1275       SCM_VALIDATE_SMOB (c, cs, charset);
1276       c++;
1277       rest = SCM_CDR (rest);
1278
1279       for (k = 0; k < LONGS_PER_CHARSET; k++)
1280         p[k] &= ((long *) SCM_SMOB_DATA (cs))[k];
1281     }
1282   return cs1;
1283 }
1284 #undef FUNC_NAME
1285
1286
1287 SCM_DEFINE (scm_char_set_difference_x, "char-set-difference!", 1, 0, 1,
1288             (SCM cs1, SCM rest),
1289             "Return the difference of all argument character sets.")
1290 #define FUNC_NAME s_scm_char_set_difference_x
1291 {
1292   int c = 2;
1293   long * p;
1294
1295   SCM_VALIDATE_SMOB (1, cs1, charset);
1296   SCM_VALIDATE_REST_ARGUMENT (rest);
1297
1298   p = (long *) SCM_SMOB_DATA (cs1);
1299   while (!scm_is_null (rest))
1300     {
1301       int k;
1302       SCM cs = SCM_CAR (rest);
1303       SCM_VALIDATE_SMOB (c, cs, charset);
1304       c++;
1305       rest = SCM_CDR (rest);
1306
1307       for (k = 0; k < LONGS_PER_CHARSET; k++)
1308         p[k] &= ~((long *) SCM_SMOB_DATA (cs))[k];
1309     }
1310   return cs1;
1311 }
1312 #undef FUNC_NAME
1313
1314
1315 SCM_DEFINE (scm_char_set_xor_x, "char-set-xor!", 1, 0, 1,
1316             (SCM cs1, SCM rest),
1317             "Return the exclusive-or of all argument character sets.")
1318 #define FUNC_NAME s_scm_char_set_xor_x
1319 {
1320   /* a side-effecting variant should presumably give consistent results:
1321      (define a (char-set #\a))
1322      (char-set-xor a a a) -> char set #\a
1323      (char-set-xor! a a a) -> char set #\a
1324   */
1325   return scm_char_set_xor (scm_cons (cs1, rest));
1326
1327 #if 0
1328   /* this would give (char-set-xor! a a a) -> empty char set.  */
1329   int c = 2;
1330   long * p;
1331
1332   SCM_VALIDATE_SMOB (1, cs1, charset);
1333   SCM_VALIDATE_REST_ARGUMENT (rest);
1334
1335   p = (long *) SCM_SMOB_DATA (cs1);
1336   while (!scm_is_null (rest))
1337     {
1338       int k;
1339       SCM cs = SCM_CAR (rest);
1340       SCM_VALIDATE_SMOB (c, cs, charset);
1341       c++;
1342       rest = SCM_CDR (rest);
1343
1344       for (k = 0; k < LONGS_PER_CHARSET; k++)
1345         p[k] ^= ((long *) SCM_SMOB_DATA (cs))[k];
1346     }
1347   return cs1;
1348 #endif
1349 }
1350 #undef FUNC_NAME
1351
1352
1353 SCM_DEFINE (scm_char_set_diff_plus_intersection_x, "char-set-diff+intersection!", 2, 0, 1,
1354             (SCM cs1, SCM cs2, SCM rest),
1355             "Return the difference and the intersection of all argument\n"
1356             "character sets.")
1357 #define FUNC_NAME s_scm_char_set_diff_plus_intersection_x
1358 {
1359   int c = 3;
1360   long * p, * q;
1361   int k;
1362
1363   SCM_VALIDATE_SMOB (1, cs1, charset);
1364   SCM_VALIDATE_SMOB (2, cs2, charset);
1365   SCM_VALIDATE_REST_ARGUMENT (rest);
1366
1367   p = (long *) SCM_SMOB_DATA (cs1);
1368   q = (long *) SCM_SMOB_DATA (cs2);
1369   if (p == q)
1370     {
1371       /* (char-set-diff+intersection! a a ...): can't share storage,
1372          but we know the answer without checking for further
1373          arguments.  */
1374       return scm_values (scm_list_2 (make_char_set (FUNC_NAME), cs1));
1375     }
1376   for (k = 0; k < LONGS_PER_CHARSET; k++)
1377     {
1378       long t = p[k];
1379
1380       p[k] &= ~q[k];
1381       q[k] = t & q[k];
1382     }
1383   while (!scm_is_null (rest))
1384     {
1385       SCM cs = SCM_CAR (rest);
1386       long *r;
1387
1388       SCM_VALIDATE_SMOB (c, cs, charset);
1389       c++;
1390       r = (long *) SCM_SMOB_DATA (cs);
1391
1392       for (k = 0; k < LONGS_PER_CHARSET; k++)
1393         {
1394           q[k] |= p[k] & r[k];
1395           p[k] &= ~r[k];
1396         }
1397       rest = SCM_CDR (rest);
1398     }
1399   return scm_values (scm_list_2 (cs1, cs2));
1400 }
1401 #undef FUNC_NAME
1402
1403 \f
1404 /* Standard character sets.  */
1405
1406 SCM scm_char_set_lower_case;
1407 SCM scm_char_set_upper_case;
1408 SCM scm_char_set_title_case;
1409 SCM scm_char_set_letter;
1410 SCM scm_char_set_digit;
1411 SCM scm_char_set_letter_and_digit;
1412 SCM scm_char_set_graphic;
1413 SCM scm_char_set_printing;
1414 SCM scm_char_set_whitespace;
1415 SCM scm_char_set_iso_control;
1416 SCM scm_char_set_punctuation;
1417 SCM scm_char_set_symbol;
1418 SCM scm_char_set_hex_digit;
1419 SCM scm_char_set_blank;
1420 SCM scm_char_set_ascii;
1421 SCM scm_char_set_empty;
1422 SCM scm_char_set_full;
1423
1424
1425 /* Create an empty character set and return it after binding it to NAME.  */
1426 static inline SCM
1427 define_charset (const char *name)
1428 {
1429   SCM cs = make_char_set (NULL);
1430   scm_c_define (name, cs);
1431   return scm_permanent_object (cs);
1432 }
1433
1434 /* Membership predicates for the various char sets.
1435
1436    XXX: The `punctuation' and `symbol' char sets have no direct equivalent in
1437    <ctype.h>.  Thus, the predicates below yield correct results for ASCII,
1438    but they do not provide the result described by the SRFI for Latin-1.  The
1439    correct Latin-1 result could only be obtained by hard-coding the
1440    characters listed by the SRFI, but the problem would remain for other
1441    8-bit charsets.
1442
1443    Similarly, character 0xA0 in Latin-1 (unbreakable space, `#\0240') should
1444    be part of `char-set:blank'.  However, glibc's current (2006/09) Latin-1
1445    locales (which use the ISO 14652 "i18n" FDCC-set) do not consider it
1446    `blank' so it ends up in `char-set:punctuation'.  */
1447 #ifdef HAVE_ISBLANK
1448 # define CSET_BLANK_PRED(c)  (isblank (c))
1449 #else
1450 # define CSET_BLANK_PRED(c)                     \
1451    (((c) == ' ') || ((c) == '\t'))
1452 #endif
1453
1454 #define CSET_SYMBOL_PRED(c)                                     \
1455   (((c) != '\0') && (strchr ("$+<=>^`|~", (c)) != NULL))
1456 #define CSET_PUNCT_PRED(c)                                      \
1457   ((ispunct (c)) && (!CSET_SYMBOL_PRED (c)))
1458
1459 #define CSET_LOWER_PRED(c)       (islower (c))
1460 #define CSET_UPPER_PRED(c)       (isupper (c))
1461 #define CSET_LETTER_PRED(c)      (isalpha (c))
1462 #define CSET_DIGIT_PRED(c)       (isdigit (c))
1463 #define CSET_WHITESPACE_PRED(c)  (isspace (c))
1464 #define CSET_CONTROL_PRED(c)     (iscntrl (c))
1465 #define CSET_HEX_DIGIT_PRED(c)   (isxdigit (c))
1466 #define CSET_ASCII_PRED(c)       (isascii (c))
1467
1468 /* Some char sets are explicitly defined by the SRFI as a union of other char
1469    sets so we try to follow this closely.  */
1470
1471 #define CSET_LETTER_AND_DIGIT_PRED(c)           \
1472   (CSET_LETTER_PRED (c) || CSET_DIGIT_PRED (c))
1473
1474 #define CSET_GRAPHIC_PRED(c)                            \
1475   (CSET_LETTER_PRED (c) || CSET_DIGIT_PRED (c)          \
1476    || CSET_PUNCT_PRED (c) || CSET_SYMBOL_PRED (c))
1477
1478 #define CSET_PRINTING_PRED(c)                           \
1479   (CSET_GRAPHIC_PRED (c) || CSET_WHITESPACE_PRED (c))
1480
1481 /* False and true predicates.  */
1482 #define CSET_TRUE_PRED(c)    (1)
1483 #define CSET_FALSE_PRED(c)   (0)
1484
1485
1486 /* Compute the contents of all the standard character sets.  Computation may
1487    need to be re-done at `setlocale'-time because some char sets (e.g.,
1488    `char-set:letter') need to reflect the character set supported by Guile.
1489
1490    For instance, at startup time, the "C" locale is used, thus Guile supports
1491    only ASCII; therefore, `char-set:letter' only contains English letters.
1492    The user can change this by invoking `setlocale' and specifying a locale
1493    with an 8-bit charset, thereby augmenting some of the SRFI-14 standard
1494    character sets.
1495
1496    This works because some of the predicates used below to construct
1497    character sets (e.g., `isalpha(3)') are locale-dependent (so
1498    charset-dependent, though generally not language-dependent).  For details,
1499    please see the `guile-devel' mailing list archive of September 2006.  */
1500 void
1501 scm_srfi_14_compute_char_sets (void)
1502 {
1503 #define UPDATE_CSET(c, cset, pred)              \
1504   do                                            \
1505     {                                           \
1506       if (pred (c))                             \
1507         SCM_CHARSET_SET ((cset), (c));          \
1508       else                                      \
1509         SCM_CHARSET_UNSET ((cset), (c));        \
1510     }                                           \
1511   while (0)
1512
1513   register int ch;
1514
1515   for (ch = 0; ch < 256; ch++)
1516     {
1517       UPDATE_CSET (ch, scm_char_set_upper_case, CSET_UPPER_PRED);
1518       UPDATE_CSET (ch, scm_char_set_lower_case, CSET_LOWER_PRED);
1519       UPDATE_CSET (ch, scm_char_set_title_case, CSET_FALSE_PRED);
1520       UPDATE_CSET (ch, scm_char_set_letter, CSET_LETTER_PRED);
1521       UPDATE_CSET (ch, scm_char_set_digit, CSET_DIGIT_PRED);
1522       UPDATE_CSET (ch, scm_char_set_letter_and_digit,
1523                    CSET_LETTER_AND_DIGIT_PRED);
1524       UPDATE_CSET (ch, scm_char_set_graphic, CSET_GRAPHIC_PRED);
1525       UPDATE_CSET (ch, scm_char_set_printing, CSET_PRINTING_PRED);
1526       UPDATE_CSET (ch, scm_char_set_whitespace, CSET_WHITESPACE_PRED);
1527       UPDATE_CSET (ch, scm_char_set_iso_control, CSET_CONTROL_PRED);
1528       UPDATE_CSET (ch, scm_char_set_punctuation, CSET_PUNCT_PRED);
1529       UPDATE_CSET (ch, scm_char_set_symbol, CSET_SYMBOL_PRED);
1530       UPDATE_CSET (ch, scm_char_set_hex_digit, CSET_HEX_DIGIT_PRED);
1531       UPDATE_CSET (ch, scm_char_set_blank, CSET_BLANK_PRED);
1532       UPDATE_CSET (ch, scm_char_set_ascii, CSET_ASCII_PRED);
1533       UPDATE_CSET (ch, scm_char_set_empty, CSET_FALSE_PRED);
1534       UPDATE_CSET (ch, scm_char_set_full, CSET_TRUE_PRED);
1535     }
1536
1537 #undef UPDATE_CSET
1538 }
1539
1540 \f
1541 void
1542 scm_init_srfi_14 (void)
1543 {
1544   scm_tc16_charset = scm_make_smob_type ("character-set",
1545                                          BYTES_PER_CHARSET);
1546   scm_set_smob_free (scm_tc16_charset, charset_free);
1547   scm_set_smob_print (scm_tc16_charset, charset_print);
1548
1549   scm_char_set_upper_case = define_charset ("char-set:upper-case");
1550   scm_char_set_lower_case = define_charset ("char-set:lower-case");
1551   scm_char_set_title_case = define_charset ("char-set:title-case");
1552   scm_char_set_letter = define_charset ("char-set:letter");
1553   scm_char_set_digit = define_charset ("char-set:digit");
1554   scm_char_set_letter_and_digit = define_charset ("char-set:letter+digit");
1555   scm_char_set_graphic = define_charset ("char-set:graphic");
1556   scm_char_set_printing = define_charset ("char-set:printing");
1557   scm_char_set_whitespace = define_charset ("char-set:whitespace");
1558   scm_char_set_iso_control = define_charset ("char-set:iso-control");
1559   scm_char_set_punctuation = define_charset ("char-set:punctuation");
1560   scm_char_set_symbol = define_charset ("char-set:symbol");
1561   scm_char_set_hex_digit = define_charset ("char-set:hex-digit");
1562   scm_char_set_blank = define_charset ("char-set:blank");
1563   scm_char_set_ascii = define_charset ("char-set:ascii");
1564   scm_char_set_empty = define_charset ("char-set:empty");
1565   scm_char_set_full = define_charset ("char-set:full");
1566
1567   scm_srfi_14_compute_char_sets ();
1568
1569 #include "libguile/srfi-14.x"
1570 }
1571
1572 /* End of srfi-14.c.  */