* srfi-13.c, srfi-13.h, srfi-14.c, srfi-14.h: New files.
[bpt/guile.git] / libguile / srfi-13.c
1 /* srfi-13.c --- SRFI-13 procedures for Guile
2 *
3 * Copyright (C) 2001, 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 #include <string.h>
22 #include <ctype.h>
23
24 #include "libguile.h"
25
26 #include "libguile/srfi-13.h"
27 #include "libguile/srfi-14.h"
28
29 /* SCM_VALIDATE_SUBSTRING_SPEC_COPY is deprecated since it encourages
30 messing with the internal representation of strings. We define our
31 own version since we use it so much and are messing with Guile
32 internals anyway.
33 */
34
35 #define MY_VALIDATE_SUBSTRING_SPEC_COPY(pos_str, str, c_str, \
36 pos_start, start, c_start, \
37 pos_end, end, c_end) \
38 do { \
39 SCM_VALIDATE_STRING (pos_str, str); \
40 c_str = scm_i_string_chars (str); \
41 scm_i_get_substring_spec (scm_i_string_length (str), \
42 start, &c_start, end, &c_end); \
43 } while (0)
44
45 #define MY_VALIDATE_SUBSTRING_SPEC(pos_str, str, \
46 pos_start, start, c_start, \
47 pos_end, end, c_end) \
48 do { \
49 SCM_VALIDATE_STRING (pos_str, str); \
50 scm_i_get_substring_spec (scm_i_string_length (str), \
51 start, &c_start, end, &c_end); \
52 } while (0)
53
54 /* Likewise for SCM_VALIDATE_STRING_COPY. */
55
56 #define MY_VALIDATE_STRING_COPY(pos, str, cvar) \
57 do { \
58 scm_validate_string (pos, str); \
59 cvar = scm_i_string_chars (str); \
60 } while (0)
61
62
63 SCM_DEFINE (scm_string_null_p, "string-null?", 1, 0, 0,
64 (SCM str),
65 "Return @code{#t} if @var{str}'s length is zero, and\n"
66 "@code{#f} otherwise.\n"
67 "@lisp\n"
68 "(string-null? \"\") @result{} #t\n"
69 "y @result{} \"foo\"\n"
70 "(string-null? y) @result{} #f\n"
71 "@end lisp")
72 #define FUNC_NAME s_scm_string_null_p
73 {
74 SCM_VALIDATE_STRING (1, str);
75 return scm_from_bool (scm_i_string_length (str) == 0);
76 }
77 #undef FUNC_NAME
78
79 SCM_DEFINE (scm_string_any, "string-any", 2, 2, 0,
80 (SCM char_pred, SCM s, SCM start, SCM end),
81 "Check if the predicate @var{pred} is true for any character in\n"
82 "the string @var{s}.\n"
83 "\n"
84 "Calls to @var{pred} are made from left to right across @var{s}.\n"
85 "When it returns true (ie.@: non-@code{#f}), that return value\n"
86 "is the return from @code{string-any}.\n"
87 "\n"
88 "The SRFI-13 specification requires that the call to @var{pred}\n"
89 "on the last character of @var{s} (assuming that point is\n"
90 "reached) be a tail call, but currently in Guile this is not the\n"
91 "case.")
92 #define FUNC_NAME s_scm_string_any
93 {
94 const char *cstr;
95 int cstart, cend;
96 SCM res;
97
98 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
99 3, start, cstart,
100 4, end, cend);
101
102 if (SCM_CHARP (char_pred))
103 {
104 return (memchr (cstr+cstart, (int) SCM_CHAR (char_pred),
105 cend-cstart) == NULL
106 ? SCM_BOOL_F : SCM_BOOL_T);
107 }
108 else if (SCM_CHARSETP (char_pred))
109 {
110 int i;
111 for (i = cstart; i < cend; i++)
112 if (SCM_CHARSET_GET (char_pred, cstr[i]))
113 return SCM_BOOL_T;
114 }
115 else
116 {
117 SCM_VALIDATE_PROC (1, char_pred);
118
119 cstr += cstart;
120 while (cstart < cend)
121 {
122 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (*cstr));
123 if (scm_is_true (res))
124 return res;
125 cstr++;
126 cstart++;
127 }
128 }
129 return SCM_BOOL_F;
130 }
131 #undef FUNC_NAME
132
133
134 SCM_DEFINE (scm_string_every, "string-every", 2, 2, 0,
135 (SCM char_pred, SCM s, SCM start, SCM end),
136 "Check if the predicate @var{pred} is true for every character\n"
137 "in the string @var{s}.\n"
138 "\n"
139 "Calls to @var{pred} are made from left to right across @var{s}.\n"
140 "If the predicate is true for every character then the return\n"
141 "value from the last @var{pred} call is the return from\n"
142 "@code{string-every}.\n"
143 "\n"
144 "If there are no characters in @var{s} (ie.@: @var{start} equals\n"
145 "@var{end}) then the return is @code{#t}.\n"
146 "\n"
147 "The SRFI-13 specification requires that the call to @var{pred}\n"
148 "on the last character of @var{s} (assuming that point is\n"
149 "reached) be a tail call, but currently in Guile this is not the\n"
150 "case.")
151 #define FUNC_NAME s_scm_string_every
152 {
153 const char *cstr;
154 int cstart, cend;
155 SCM res;
156
157 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
158 3, start, cstart,
159 4, end, cend);
160 if (SCM_CHARP (char_pred))
161 {
162 char cchr = SCM_CHAR (char_pred);
163 int i;
164 for (i = cstart; i < cend; i++)
165 if (cstr[i] != cchr)
166 return SCM_BOOL_F;
167 return SCM_BOOL_T;
168 }
169 else if (SCM_CHARSETP (char_pred))
170 {
171 int i;
172 for (i = cstart; i < cend; i++)
173 if (! SCM_CHARSET_GET (char_pred, cstr[i]))
174 return SCM_BOOL_F;
175 return SCM_BOOL_T;
176 }
177 else
178 {
179 SCM_VALIDATE_PROC (1, char_pred);
180
181 res = SCM_BOOL_T;
182 cstr += cstart;
183 while (cstart < cend)
184 {
185 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (*cstr));
186 if (scm_is_false (res))
187 return res;
188 cstr++;
189 cstart++;
190 }
191 return res;
192 }
193 }
194 #undef FUNC_NAME
195
196
197 SCM_DEFINE (scm_string_tabulate, "string-tabulate", 2, 0, 0,
198 (SCM proc, SCM len),
199 "@var{proc} is an integer->char procedure. Construct a string\n"
200 "of size @var{len} by applying @var{proc} to each index to\n"
201 "produce the corresponding string element. The order in which\n"
202 "@var{proc} is applied to the indices is not specified.")
203 #define FUNC_NAME s_scm_string_tabulate
204 {
205 size_t clen, i;
206 SCM res;
207 SCM ch;
208 char *p;
209
210 SCM_VALIDATE_PROC (1, proc);
211 clen = scm_to_size_t (len);
212 SCM_ASSERT_RANGE (2, len, clen >= 0);
213
214 res = scm_i_make_string (clen, &p);
215 i = 0;
216 while (i < clen)
217 {
218 /* The RES string remains untouched since nobody knows about it
219 yet. No need to refetch P.
220 */
221 ch = scm_call_1 (proc, scm_from_int (i));
222 if (!SCM_CHARP (ch))
223 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
224 *p++ = SCM_CHAR (ch);
225 i++;
226 }
227 return res;
228 }
229 #undef FUNC_NAME
230
231
232 SCM_DEFINE (scm_substring_to_list, "string->list", 1, 2, 0,
233 (SCM str, SCM start, SCM end),
234 "Convert the string @var{str} into a list of characters.")
235 #define FUNC_NAME s_scm_substring_to_list
236 {
237 const char *cstr;
238 int cstart, cend;
239 SCM result = SCM_EOL;
240
241 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
242 2, start, cstart,
243 3, end, cend);
244 while (cstart < cend)
245 {
246 cend--;
247 result = scm_cons (SCM_MAKE_CHAR (cstr[cend]), result);
248 }
249 return result;
250 }
251 #undef FUNC_NAME
252
253 /* We export scm_substring_to_list as "string->list" since it is
254 compatible and more general. This function remains for the benefit
255 of C code that used it.
256 */
257
258 SCM
259 scm_string_to_list (SCM str)
260 {
261 return scm_substring_to_list (str, SCM_UNDEFINED, SCM_UNDEFINED);
262 }
263
264 SCM_DEFINE (scm_reverse_list_to_string, "reverse-list->string", 1, 0, 0,
265 (SCM chrs),
266 "An efficient implementation of @code{(compose string->list\n"
267 "reverse)}:\n"
268 "\n"
269 "@smalllisp\n"
270 "(reverse-list->string '(#\\a #\\B #\\c)) @result{} \"cBa\"\n"
271 "@end smalllisp")
272 #define FUNC_NAME s_scm_reverse_list_to_string
273 {
274 SCM result;
275 long i = scm_ilength (chrs);
276 char *data;
277
278 if (i < 0)
279 SCM_WRONG_TYPE_ARG (1, chrs);
280 result = scm_i_make_string (i, &data);
281
282 {
283
284 data += i;
285 while (!SCM_NULLP (chrs))
286 {
287 SCM elt = SCM_CAR (chrs);
288
289 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
290 data--;
291 *data = SCM_CHAR (elt);
292 chrs = SCM_CDR (chrs);
293 }
294 }
295 return result;
296 }
297 #undef FUNC_NAME
298
299
300 SCM_SYMBOL (scm_sym_infix, "infix");
301 SCM_SYMBOL (scm_sym_strict_infix, "strict-infix");
302 SCM_SYMBOL (scm_sym_suffix, "suffix");
303 SCM_SYMBOL (scm_sym_prefix, "prefix");
304
305 SCM_DEFINE (scm_string_join, "string-join", 1, 2, 0,
306 (SCM ls, SCM delimiter, SCM grammar),
307 "Append the string in the string list @var{ls}, using the string\n"
308 "@var{delim} as a delimiter between the elements of @var{ls}.\n"
309 "@var{grammar} is a symbol which specifies how the delimiter is\n"
310 "placed between the strings, and defaults to the symbol\n"
311 "@code{infix}.\n"
312 "\n"
313 "@table @code\n"
314 "@item infix\n"
315 "Insert the separator between list elements. An empty string\n"
316 "will produce an empty list.\n"
317 "@item string-infix\n"
318 "Like @code{infix}, but will raise an error if given the empty\n"
319 "list.\n"
320 "@item suffix\n"
321 "Insert the separator after every list element.\n"
322 "@item prefix\n"
323 "Insert the separator before each list element.\n"
324 "@end table")
325 #define FUNC_NAME s_scm_string_join
326 {
327 #define GRAM_INFIX 0
328 #define GRAM_STRICT_INFIX 1
329 #define GRAM_SUFFIX 2
330 #define GRAM_PREFIX 3
331 SCM tmp;
332 SCM result;
333 int gram = GRAM_INFIX;
334 int del_len = 0, extra_len = 0;
335 int len = 0;
336 char * p;
337 long strings = scm_ilength (ls);
338
339 /* Validate the string list. */
340 if (strings < 0)
341 SCM_WRONG_TYPE_ARG (1, ls);
342
343 /* Validate the delimiter and record its length. */
344 if (SCM_UNBNDP (delimiter))
345 {
346 delimiter = scm_from_locale_string (" ");
347 del_len = 1;
348 }
349 else
350 {
351 SCM_VALIDATE_STRING (2, delimiter);
352 del_len = scm_i_string_length (delimiter);
353 }
354
355 /* Validate the grammar symbol and remember the grammar. */
356 if (SCM_UNBNDP (grammar))
357 gram = GRAM_INFIX;
358 else if (scm_is_eq (grammar, scm_sym_infix))
359 gram = GRAM_INFIX;
360 else if (scm_is_eq (grammar, scm_sym_strict_infix))
361 gram = GRAM_STRICT_INFIX;
362 else if (scm_is_eq (grammar, scm_sym_suffix))
363 gram = GRAM_SUFFIX;
364 else if (scm_is_eq (grammar, scm_sym_prefix))
365 gram = GRAM_PREFIX;
366 else
367 SCM_WRONG_TYPE_ARG (3, grammar);
368
369 /* Check grammar constraints and calculate the space required for
370 the delimiter(s). */
371 switch (gram)
372 {
373 case GRAM_INFIX:
374 if (!SCM_NULLP (ls))
375 extra_len = (strings > 0) ? ((strings - 1) * del_len) : 0;
376 break;
377 case GRAM_STRICT_INFIX:
378 if (strings == 0)
379 SCM_MISC_ERROR ("strict-infix grammar requires non-empty list",
380 SCM_EOL);
381 extra_len = (strings - 1) * del_len;
382 break;
383 default:
384 extra_len = strings * del_len;
385 break;
386 }
387
388 tmp = ls;
389 while (SCM_CONSP (tmp))
390 {
391 SCM elt = SCM_CAR (tmp);
392 SCM_VALIDATE_STRING (1, elt);
393 len += scm_i_string_length (elt);
394 tmp = SCM_CDR (tmp);
395 }
396
397 result = scm_i_make_string (len + extra_len, &p);
398
399 tmp = ls;
400 switch (gram)
401 {
402 case GRAM_INFIX:
403 case GRAM_STRICT_INFIX:
404 while (!SCM_NULLP (tmp))
405 {
406 SCM elt = SCM_CAR (tmp);
407 memmove (p, scm_i_string_chars (elt),
408 scm_i_string_length (elt));
409 p += scm_i_string_length (elt);
410 if (!SCM_NULLP (SCM_CDR (tmp)) && del_len > 0)
411 {
412 memmove (p, scm_i_string_chars (delimiter), del_len);
413 p += del_len;
414 }
415 tmp = SCM_CDR (tmp);
416 }
417 break;
418 case GRAM_SUFFIX:
419 while (!SCM_NULLP (tmp))
420 {
421 SCM elt = SCM_CAR (tmp);
422 memmove (p, scm_i_string_chars (elt),
423 scm_i_string_length (elt));
424 p += scm_i_string_length (elt);
425 if (del_len > 0)
426 {
427 memmove (p, scm_i_string_chars (delimiter), del_len);
428 p += del_len;
429 }
430 tmp = SCM_CDR (tmp);
431 }
432 break;
433 case GRAM_PREFIX:
434 while (!SCM_NULLP (tmp))
435 {
436 SCM elt = SCM_CAR (tmp);
437 if (del_len > 0)
438 {
439 memmove (p, scm_i_string_chars (delimiter), del_len);
440 p += del_len;
441 }
442 memmove (p, scm_i_string_chars (elt),
443 scm_i_string_length (elt));
444 p += scm_i_string_length (elt);
445 tmp = SCM_CDR (tmp);
446 }
447 break;
448 }
449 return result;
450 #undef GRAM_INFIX
451 #undef GRAM_STRICT_INFIX
452 #undef GRAM_SUFFIX
453 #undef GRAM_PREFIX
454 }
455 #undef FUNC_NAME
456
457
458 /* There are a number of functions to consider here for Scheme and C:
459
460 string-copy STR [start [end]] ;; SRFI-13 variant of R5RS string-copy
461 substring/copy STR start [end] ;; Guile variant of R5RS substring
462
463 scm_string_copy (str) ;; Old function from Guile
464 scm_substring_copy (str, [start, [end]])
465 ;; C version of SRFI-13 string-copy
466 ;; and C version of substring/copy
467
468 The C function underlying string-copy is not exported to C
469 programs. scm_substring_copy is defined in strings.c as the
470 underlying function of substring/copy and allows an optional START
471 argument.
472 */
473
474 SCM scm_srfi13_substring_copy (SCM str, SCM start, SCM end);
475
476 SCM_DEFINE (scm_srfi13_substring_copy, "string-copy", 1, 2, 0,
477 (SCM str, SCM start, SCM end),
478 "Return a freshly allocated copy of the string @var{str}. If\n"
479 "given, @var{start} and @var{end} delimit the portion of\n"
480 "@var{str} which is copied.")
481 #define FUNC_NAME s_scm_srfi13_substring_copy
482 {
483 const char *cstr;
484 size_t cstart, cend;
485
486 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
487 2, start, cstart,
488 3, end, cend);
489 return scm_c_substring_copy (str, cstart, cend);
490 }
491 #undef FUNC_NAME
492
493 SCM
494 scm_string_copy (SCM str)
495 {
496 return scm_c_substring (str, 0, scm_c_string_length (str));
497 }
498
499 SCM_DEFINE (scm_string_copy_x, "string-copy!", 3, 2, 0,
500 (SCM target, SCM tstart, SCM s, SCM start, SCM end),
501 "Copy the sequence of characters from index range [@var{start},\n"
502 "@var{end}) in string @var{s} to string @var{target}, beginning\n"
503 "at index @var{tstart}. The characters are copied left-to-right\n"
504 "or right-to-left as needed -- the copy is guaranteed to work,\n"
505 "even if @var{target} and @var{s} are the same string. It is an\n"
506 "error if the copy operation runs off the end of the target\n"
507 "string.")
508 #define FUNC_NAME s_scm_string_copy_x
509 {
510 const char *cstr;
511 char *ctarget;
512 size_t cstart, cend, ctstart, dummy, len;
513 SCM sdummy = SCM_UNDEFINED;
514
515 MY_VALIDATE_SUBSTRING_SPEC (1, target,
516 2, tstart, ctstart,
517 2, sdummy, dummy);
518 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
519 4, start, cstart,
520 5, end, cend);
521 len = cend - cstart;
522 SCM_ASSERT_RANGE (3, s, len <= scm_i_string_length (target) - ctstart);
523
524 ctarget = scm_i_string_writable_chars (target);
525 memmove (ctarget + ctstart, cstr + cstart, len);
526 scm_i_string_stop_writing ();
527
528 return SCM_UNSPECIFIED;
529 }
530 #undef FUNC_NAME
531
532 SCM_DEFINE (scm_substring_move_x, "substring-move!", 5, 0, 0,
533 (SCM str1, SCM start1, SCM end1, SCM str2, SCM start2),
534 "Copy the substring of @var{str1} bounded by @var{start1} and @var{end1}\n"
535 "into @var{str2} beginning at position @var{start2}.\n"
536 "@var{str1} and @var{str2} can be the same string.")
537 #define FUNC_NAME s_scm_substring_move_x
538 {
539 return scm_string_copy_x (str2, start2, str1, start1, end1);
540 }
541 #undef FUNC_NAME
542
543 SCM_DEFINE (scm_string_take, "string-take", 2, 0, 0,
544 (SCM s, SCM n),
545 "Return the @var{n} first characters of @var{s}.")
546 #define FUNC_NAME s_scm_string_take
547 {
548 return scm_substring (s, SCM_INUM0, n);
549 }
550 #undef FUNC_NAME
551
552
553 SCM_DEFINE (scm_string_drop, "string-drop", 2, 0, 0,
554 (SCM s, SCM n),
555 "Return all but the first @var{n} characters of @var{s}.")
556 #define FUNC_NAME s_scm_string_drop
557 {
558 return scm_substring (s, n, SCM_UNDEFINED);
559 }
560 #undef FUNC_NAME
561
562
563 SCM_DEFINE (scm_string_take_right, "string-take-right", 2, 0, 0,
564 (SCM s, SCM n),
565 "Return the @var{n} last characters of @var{s}.")
566 #define FUNC_NAME s_scm_string_take_right
567 {
568 return scm_substring (s,
569 scm_difference (scm_string_length (s), n),
570 SCM_UNDEFINED);
571 }
572 #undef FUNC_NAME
573
574
575 SCM_DEFINE (scm_string_drop_right, "string-drop-right", 2, 0, 0,
576 (SCM s, SCM n),
577 "Return all but the last @var{n} characters of @var{s}.")
578 #define FUNC_NAME s_scm_string_drop_right
579 {
580 return scm_substring (s,
581 SCM_INUM0,
582 scm_difference (scm_string_length (s), n));
583 }
584 #undef FUNC_NAME
585
586
587 SCM_DEFINE (scm_string_pad, "string-pad", 2, 3, 0,
588 (SCM s, SCM len, SCM chr, SCM start, SCM end),
589 "Take that characters from @var{start} to @var{end} from the\n"
590 "string @var{s} and return a new string, right-padded by the\n"
591 "character @var{chr} to length @var{len}. If the resulting\n"
592 "string is longer than @var{len}, it is truncated on the right.")
593 #define FUNC_NAME s_scm_string_pad
594 {
595 char cchr;
596 const char *cstr;
597 size_t cstart, cend, clen;
598
599 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
600 4, start, cstart,
601 5, end, cend);
602 clen = scm_to_size_t (len);
603
604 if (SCM_UNBNDP (chr))
605 cchr = ' ';
606 else
607 {
608 SCM_VALIDATE_CHAR (3, chr);
609 cchr = SCM_CHAR (chr);
610 }
611 if (clen < (cend - cstart))
612 return scm_c_substring (s, cend - clen, cend);
613 else
614 {
615 SCM result;
616 char *dst;
617
618 result = scm_i_make_string (clen, &dst);
619 memset (dst, cchr, (clen - (cend - cstart)));
620 memmove (dst + clen - (cend - cstart), cstr + cstart, cend - cstart);
621 return result;
622 }
623 }
624 #undef FUNC_NAME
625
626
627 SCM_DEFINE (scm_string_pad_right, "string-pad-right", 2, 3, 0,
628 (SCM s, SCM len, SCM chr, SCM start, SCM end),
629 "Take that characters from @var{start} to @var{end} from the\n"
630 "string @var{s} and return a new string, left-padded by the\n"
631 "character @var{chr} to length @var{len}. If the resulting\n"
632 "string is longer than @var{len}, it is truncated on the left.")
633 #define FUNC_NAME s_scm_string_pad_right
634 {
635 char cchr;
636 const char *cstr;
637 size_t cstart, cend, clen;
638
639 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
640 4, start, cstart,
641 5, end, cend);
642 clen = scm_to_size_t (len);
643
644 if (SCM_UNBNDP (chr))
645 cchr = ' ';
646 else
647 {
648 SCM_VALIDATE_CHAR (3, chr);
649 cchr = SCM_CHAR (chr);
650 }
651 if (clen < (cend - cstart))
652 return scm_c_substring (s, cstart, cstart + clen);
653 else
654 {
655 SCM result;
656 char *dst;
657
658 result = scm_i_make_string (clen, &dst);
659 memset (dst + (cend - cstart), cchr, clen - (cend - cstart));
660 memmove (dst, cstr + cstart, cend - cstart);
661 return result;
662 }
663 }
664 #undef FUNC_NAME
665
666
667 SCM_DEFINE (scm_string_trim, "string-trim", 1, 3, 0,
668 (SCM s, SCM char_pred, SCM start, SCM end),
669 "Trim @var{s} by skipping over all characters on the left\n"
670 "that satisfy the parameter @var{char_pred}:\n"
671 "\n"
672 "@itemize @bullet\n"
673 "@item\n"
674 "if it is the character @var{ch}, characters equal to\n"
675 "@var{ch} are trimmed,\n"
676 "\n"
677 "@item\n"
678 "if it is a procedure @var{pred} characters that\n"
679 "satisfy @var{pred} are trimmed,\n"
680 "\n"
681 "@item\n"
682 "if it is a character set, characters in that set are trimmed.\n"
683 "@end itemize\n"
684 "\n"
685 "If called without a @var{char_pred} argument, all whitespace is\n"
686 "trimmed.")
687 #define FUNC_NAME s_scm_string_trim
688 {
689 const char *cstr;
690 size_t cstart, cend;
691
692 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
693 3, start, cstart,
694 4, end, cend);
695 if (SCM_UNBNDP (char_pred))
696 {
697 while (cstart < cend)
698 {
699 if (!isspace((int) (unsigned char) cstr[cstart]))
700 break;
701 cstart++;
702 }
703 }
704 else if (SCM_CHARP (char_pred))
705 {
706 char chr = SCM_CHAR (char_pred);
707 while (cstart < cend)
708 {
709 if (chr != cstr[cstart])
710 break;
711 cstart++;
712 }
713 }
714 else if (SCM_CHARSETP (char_pred))
715 {
716 while (cstart < cend)
717 {
718 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
719 break;
720 cstart++;
721 }
722 }
723 else
724 {
725 SCM_VALIDATE_PROC (2, char_pred);
726 while (cstart < cend)
727 {
728 SCM res;
729
730 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
731 if (scm_is_false (res))
732 break;
733 cstr = scm_i_string_chars (s);
734 cstart++;
735 }
736 }
737 return scm_c_substring (s, cstart, cend);
738 }
739 #undef FUNC_NAME
740
741
742 SCM_DEFINE (scm_string_trim_right, "string-trim-right", 1, 3, 0,
743 (SCM s, SCM char_pred, SCM start, SCM end),
744 "Trim @var{s} by skipping over all characters on the rightt\n"
745 "that satisfy the parameter @var{char_pred}:\n"
746 "\n"
747 "@itemize @bullet\n"
748 "@item\n"
749 "if it is the character @var{ch}, characters equal to @var{ch}\n"
750 "are trimmed,\n"
751 "\n"
752 "@item\n"
753 "if it is a procedure @var{pred} characters that satisfy\n"
754 "@var{pred} are trimmed,\n"
755 "\n"
756 "@item\n"
757 "if it is a character sets, all characters in that set are\n"
758 "trimmed.\n"
759 "@end itemize\n"
760 "\n"
761 "If called without a @var{char_pred} argument, all whitespace is\n"
762 "trimmed.")
763 #define FUNC_NAME s_scm_string_trim_right
764 {
765 const char *cstr;
766 int cstart, cend;
767
768 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
769 3, start, cstart,
770 4, end, cend);
771 if (SCM_UNBNDP (char_pred))
772 {
773 while (cstart < cend)
774 {
775 if (!isspace((int) (unsigned char) cstr[cend - 1]))
776 break;
777 cend--;
778 }
779 }
780 else if (SCM_CHARP (char_pred))
781 {
782 char chr = SCM_CHAR (char_pred);
783 while (cstart < cend)
784 {
785 if (chr != cstr[cend - 1])
786 break;
787 cend--;
788 }
789 }
790 else if (SCM_CHARSETP (char_pred))
791 {
792 while (cstart < cend)
793 {
794 if (!SCM_CHARSET_GET (char_pred, cstr[cend - 1]))
795 break;
796 cend--;
797 }
798 }
799 else
800 {
801 SCM_VALIDATE_PROC (2, char_pred);
802 while (cstart < cend)
803 {
804 SCM res;
805
806 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend - 1]));
807 if (scm_is_false (res))
808 break;
809 cstr = scm_i_string_chars (s);
810 cend--;
811 }
812 }
813 return scm_c_substring (s, cstart, cend);
814 }
815 #undef FUNC_NAME
816
817
818 SCM_DEFINE (scm_string_trim_both, "string-trim-both", 1, 3, 0,
819 (SCM s, SCM char_pred, SCM start, SCM end),
820 "Trim @var{s} by skipping over all characters on both sides of\n"
821 "the string that satisfy the parameter @var{char_pred}:\n"
822 "\n"
823 "@itemize @bullet\n"
824 "@item\n"
825 "if it is the character @var{ch}, characters equal to @var{ch}\n"
826 "are trimmed,\n"
827 "\n"
828 "@item\n"
829 "if it is a procedure @var{pred} characters that satisfy\n"
830 "@var{pred} are trimmed,\n"
831 "\n"
832 "@item\n"
833 "if it is a character set, the characters in the set are\n"
834 "trimmed.\n"
835 "@end itemize\n"
836 "\n"
837 "If called without a @var{char_pred} argument, all whitespace is\n"
838 "trimmed.")
839 #define FUNC_NAME s_scm_string_trim_both
840 {
841 const char *cstr;
842 size_t cstart, cend;
843
844 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
845 3, start, cstart,
846 4, end, cend);
847 if (SCM_UNBNDP (char_pred))
848 {
849 while (cstart < cend)
850 {
851 if (!isspace((int) (unsigned char) cstr[cstart]))
852 break;
853 cstart++;
854 }
855 while (cstart < cend)
856 {
857 if (!isspace((int) (unsigned char) cstr[cend - 1]))
858 break;
859 cend--;
860 }
861 }
862 else if (SCM_CHARP (char_pred))
863 {
864 char chr = SCM_CHAR (char_pred);
865 while (cstart < cend)
866 {
867 if (chr != cstr[cstart])
868 break;
869 cstart++;
870 }
871 while (cstart < cend)
872 {
873 if (chr != cstr[cend - 1])
874 break;
875 cend--;
876 }
877 }
878 else if (SCM_CHARSETP (char_pred))
879 {
880 while (cstart < cend)
881 {
882 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
883 break;
884 cstart++;
885 }
886 while (cstart < cend)
887 {
888 if (!SCM_CHARSET_GET (char_pred, cstr[cend - 1]))
889 break;
890 cend--;
891 }
892 }
893 else
894 {
895 SCM_VALIDATE_PROC (2, char_pred);
896 while (cstart < cend)
897 {
898 SCM res;
899
900 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
901 if (scm_is_false (res))
902 break;
903 cstr = scm_i_string_chars (s);
904 cstart++;
905 }
906 while (cstart < cend)
907 {
908 SCM res;
909
910 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend - 1]));
911 if (scm_is_false (res))
912 break;
913 cstr = scm_i_string_chars (s);
914 cend--;
915 }
916 }
917 return scm_c_substring (s, cstart, cend);
918 }
919 #undef FUNC_NAME
920
921
922 SCM_DEFINE (scm_substring_fill_x, "string-fill!", 2, 2, 0,
923 (SCM str, SCM chr, SCM start, SCM end),
924 "Stores @var{chr} in every element of the given @var{str} and\n"
925 "returns an unspecified value.")
926 #define FUNC_NAME s_scm_substring_fill_x
927 {
928 char *cstr;
929 size_t cstart, cend;
930 int c;
931 size_t k;
932
933 /* Older versions of Guile provided the function
934 scm_substring_fill_x with the following order of arguments:
935
936 str, start, end, chr
937
938 We accomodate this here by detecting such a usage and reordering
939 the arguments.
940 */
941 if (SCM_CHARP (end))
942 {
943 SCM tmp = end;
944 end = start;
945 start = chr;
946 chr = tmp;
947 }
948
949 MY_VALIDATE_SUBSTRING_SPEC (1, str,
950 3, start, cstart,
951 4, end, cend);
952 SCM_VALIDATE_CHAR_COPY (2, chr, c);
953
954 cstr = scm_i_string_writable_chars (str);
955 for (k = cstart; k < cend; k++)
956 cstr[k] = c;
957 scm_i_string_stop_writing ();
958 return SCM_UNSPECIFIED;
959 }
960 #undef FUNC_NAME
961
962 SCM
963 scm_string_fill_x (SCM str, SCM chr)
964 {
965 return scm_substring_fill_x (str, chr, SCM_UNDEFINED, SCM_UNDEFINED);
966 }
967
968 SCM_DEFINE (scm_string_compare, "string-compare", 5, 4, 0,
969 (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
970 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
971 "mismatch index, depending upon whether @var{s1} is less than,\n"
972 "equal to, or greater than @var{s2}. The mismatch index is the\n"
973 "largest index @var{i} such that for every 0 <= @var{j} <\n"
974 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
975 "@var{i} is the first position that does not match.")
976 #define FUNC_NAME s_scm_string_compare
977 {
978 const char *cstr1, *cstr2;
979 size_t cstart1, cend1, cstart2, cend2;
980
981 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
982 6, start1, cstart1,
983 7, end1, cend1);
984 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
985 8, start2, cstart2,
986 9, end2, cend2);
987 SCM_VALIDATE_PROC (3, proc_lt);
988 SCM_VALIDATE_PROC (4, proc_eq);
989 SCM_VALIDATE_PROC (5, proc_gt);
990
991 while (cstart1 < cend1 && cstart2 < cend2)
992 {
993 if (cstr1[cstart1] < cstr2[cstart2])
994 return scm_call_1 (proc_lt, scm_from_size_t (cstart1));
995 else if (cstr1[cstart1] > cstr2[cstart2])
996 return scm_call_1 (proc_gt, scm_from_size_t (cstart1));
997 cstart1++;
998 cstart2++;
999 }
1000 if (cstart1 < cend1)
1001 return scm_call_1 (proc_gt, scm_from_size_t (cstart1));
1002 else if (cstart2 < cend2)
1003 return scm_call_1 (proc_lt, scm_from_size_t (cstart1));
1004 else
1005 return scm_call_1 (proc_eq, scm_from_size_t (cstart1));
1006 }
1007 #undef FUNC_NAME
1008
1009
1010 SCM_DEFINE (scm_string_compare_ci, "string-compare-ci", 5, 4, 0,
1011 (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
1012 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
1013 "mismatch index, depending upon whether @var{s1} is less than,\n"
1014 "equal to, or greater than @var{s2}. The mismatch index is the\n"
1015 "largest index @var{i} such that for every 0 <= @var{j} <\n"
1016 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
1017 "@var{i} is the first position that does not match. The\n"
1018 "character comparison is done case-insensitively.")
1019 #define FUNC_NAME s_scm_string_compare_ci
1020 {
1021 const char *cstr1, *cstr2;
1022 size_t cstart1, cend1, cstart2, cend2;
1023
1024 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1025 6, start1, cstart1,
1026 7, end1, cend1);
1027 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1028 8, start2, cstart2,
1029 9, end2, cend2);
1030 SCM_VALIDATE_PROC (3, proc_lt);
1031 SCM_VALIDATE_PROC (4, proc_eq);
1032 SCM_VALIDATE_PROC (5, proc_gt);
1033
1034 while (cstart1 < cend1 && cstart2 < cend2)
1035 {
1036 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1037 return scm_call_1 (proc_lt, scm_from_size_t (cstart1));
1038 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1039 return scm_call_1 (proc_gt, scm_from_size_t (cstart1));
1040 cstart1++;
1041 cstart2++;
1042 }
1043 if (cstart1 < cend1)
1044 return scm_call_1 (proc_gt, scm_from_size_t (cstart1));
1045 else if (cstart2 < cend2)
1046 return scm_call_1 (proc_lt, scm_from_size_t (cstart1));
1047 else
1048 return scm_call_1 (proc_eq, scm_from_size_t (cstart1));
1049 }
1050 #undef FUNC_NAME
1051
1052
1053 SCM_DEFINE (scm_string_eq, "string=", 2, 4, 0,
1054 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1055 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
1056 "value otherwise.")
1057 #define FUNC_NAME s_scm_string_eq
1058 {
1059 const char *cstr1, *cstr2;
1060 size_t cstart1, cend1, cstart2, cend2;
1061
1062 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1063 3, start1, cstart1,
1064 4, end1, cend1);
1065 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1066 5, start2, cstart2,
1067 6, end2, cend2);
1068
1069 if ((cend1 - cstart1) != (cend2 - cstart2))
1070 goto false;
1071
1072 while (cstart1 < cend1)
1073 {
1074 if (cstr1[cstart1] < cstr2[cstart2])
1075 goto false;
1076 else if (cstr1[cstart1] > cstr2[cstart2])
1077 goto false;
1078 cstart1++;
1079 cstart2++;
1080 }
1081
1082 scm_remember_upto_here_2 (s1, s2);
1083 return scm_from_size_t (cstart1);
1084
1085 false:
1086 scm_remember_upto_here_2 (s1, s2);
1087 return SCM_BOOL_F;
1088 }
1089 #undef FUNC_NAME
1090
1091
1092 SCM_DEFINE (scm_string_neq, "string<>", 2, 4, 0,
1093 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1094 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
1095 "value otherwise.")
1096 #define FUNC_NAME s_scm_string_neq
1097 {
1098 const char *cstr1, *cstr2;
1099 size_t cstart1, cend1, cstart2, cend2;
1100
1101 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1102 3, start1, cstart1,
1103 4, end1, cend1);
1104 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1105 5, start2, cstart2,
1106 6, end2, cend2);
1107
1108 while (cstart1 < cend1 && cstart2 < cend2)
1109 {
1110 if (cstr1[cstart1] < cstr2[cstart2])
1111 goto true;
1112 else if (cstr1[cstart1] > cstr2[cstart2])
1113 goto true;
1114 cstart1++;
1115 cstart2++;
1116 }
1117 if (cstart1 < cend1)
1118 goto true;
1119 else if (cstart2 < cend2)
1120 goto true;
1121 else
1122 goto false;
1123
1124 true:
1125 scm_remember_upto_here_2 (s1, s2);
1126 return scm_from_size_t (cstart1);
1127
1128 false:
1129 scm_remember_upto_here_2 (s1, s2);
1130 return SCM_BOOL_F;
1131 }
1132 #undef FUNC_NAME
1133
1134
1135 SCM_DEFINE (scm_string_lt, "string<", 2, 4, 0,
1136 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1137 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
1138 "true value otherwise.")
1139 #define FUNC_NAME s_scm_string_lt
1140 {
1141 const char *cstr1, *cstr2;
1142 size_t cstart1, cend1, cstart2, cend2;
1143
1144 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1145 3, start1, cstart1,
1146 4, end1, cend1);
1147 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1148 5, start2, cstart2,
1149 6, end2, cend2);
1150
1151 while (cstart1 < cend1 && cstart2 < cend2)
1152 {
1153 if (cstr1[cstart1] < cstr2[cstart2])
1154 goto true;
1155 else if (cstr1[cstart1] > cstr2[cstart2])
1156 goto false;
1157 cstart1++;
1158 cstart2++;
1159 }
1160 if (cstart1 < cend1)
1161 goto false;
1162 else if (cstart2 < cend2)
1163 goto true;
1164 else
1165 goto false;
1166
1167 true:
1168 scm_remember_upto_here_2 (s1, s2);
1169 return scm_from_size_t (cstart1);
1170
1171 false:
1172 scm_remember_upto_here_2 (s1, s2);
1173 return SCM_BOOL_F;
1174 }
1175 #undef FUNC_NAME
1176
1177
1178 SCM_DEFINE (scm_string_gt, "string>", 2, 4, 0,
1179 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1180 "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
1181 "true value otherwise.")
1182 #define FUNC_NAME s_scm_string_gt
1183 {
1184 const char *cstr1, *cstr2;
1185 size_t cstart1, cend1, cstart2, cend2;
1186
1187 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1188 3, start1, cstart1,
1189 4, end1, cend1);
1190 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1191 5, start2, cstart2,
1192 6, end2, cend2);
1193
1194 while (cstart1 < cend1 && cstart2 < cend2)
1195 {
1196 if (cstr1[cstart1] < cstr2[cstart2])
1197 goto false;
1198 else if (cstr1[cstart1] > cstr2[cstart2])
1199 goto true;
1200 cstart1++;
1201 cstart2++;
1202 }
1203 if (cstart1 < cend1)
1204 goto true;
1205 else if (cstart2 < cend2)
1206 goto false;
1207 else
1208 goto false;
1209
1210 true:
1211 scm_remember_upto_here_2 (s1, s2);
1212 return scm_from_size_t (cstart1);
1213
1214 false:
1215 scm_remember_upto_here_2 (s1, s2);
1216 return SCM_BOOL_F;
1217 }
1218 #undef FUNC_NAME
1219
1220
1221 SCM_DEFINE (scm_string_le, "string<=", 2, 4, 0,
1222 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1223 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1224 "value otherwise.")
1225 #define FUNC_NAME s_scm_string_le
1226 {
1227 const char *cstr1, *cstr2;
1228 size_t cstart1, cend1, cstart2, cend2;
1229
1230 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1231 3, start1, cstart1,
1232 4, end1, cend1);
1233 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1234 5, start2, cstart2,
1235 6, end2, cend2);
1236
1237 while (cstart1 < cend1 && cstart2 < cend2)
1238 {
1239 if (cstr1[cstart1] < cstr2[cstart2])
1240 goto true;
1241 else if (cstr1[cstart1] > cstr2[cstart2])
1242 goto false;
1243 cstart1++;
1244 cstart2++;
1245 }
1246 if (cstart1 < cend1)
1247 goto false;
1248 else if (cstart2 < cend2)
1249 goto true;
1250 else
1251 goto true;
1252
1253 true:
1254 scm_remember_upto_here_2 (s1, s2);
1255 return scm_from_size_t (cstart1);
1256
1257 false:
1258 scm_remember_upto_here_2 (s1, s2);
1259 return SCM_BOOL_F;
1260 }
1261 #undef FUNC_NAME
1262
1263
1264 SCM_DEFINE (scm_string_ge, "string>=", 2, 4, 0,
1265 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1266 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1267 "otherwise.")
1268 #define FUNC_NAME s_scm_string_ge
1269 {
1270 const char *cstr1, *cstr2;
1271 size_t cstart1, cend1, cstart2, cend2;
1272
1273 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1274 3, start1, cstart1,
1275 4, end1, cend1);
1276 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1277 5, start2, cstart2,
1278 6, end2, cend2);
1279
1280 while (cstart1 < cend1 && cstart2 < cend2)
1281 {
1282 if (cstr1[cstart1] < cstr2[cstart2])
1283 goto false;
1284 else if (cstr1[cstart1] > cstr2[cstart2])
1285 goto true;
1286 cstart1++;
1287 cstart2++;
1288 }
1289 if (cstart1 < cend1)
1290 goto true;
1291 else if (cstart2 < cend2)
1292 goto false;
1293 else
1294 goto true;
1295
1296 true:
1297 scm_remember_upto_here_2 (s1, s2);
1298 return scm_from_size_t (cstart1);
1299
1300 false:
1301 scm_remember_upto_here_2 (s1, s2);
1302 return SCM_BOOL_F;
1303 }
1304 #undef FUNC_NAME
1305
1306
1307 SCM_DEFINE (scm_string_ci_eq, "string-ci=", 2, 4, 0,
1308 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1309 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
1310 "value otherwise. The character comparison is done\n"
1311 "case-insensitively.")
1312 #define FUNC_NAME s_scm_string_ci_eq
1313 {
1314 const char *cstr1, *cstr2;
1315 size_t cstart1, cend1, cstart2, cend2;
1316
1317 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1318 3, start1, cstart1,
1319 4, end1, cend1);
1320 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1321 5, start2, cstart2,
1322 6, end2, cend2);
1323
1324 while (cstart1 < cend1 && cstart2 < cend2)
1325 {
1326 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1327 goto false;
1328 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1329 goto false;
1330 cstart1++;
1331 cstart2++;
1332 }
1333 if (cstart1 < cend1)
1334 goto false;
1335 else if (cstart2 < cend2)
1336 goto false;
1337 else
1338 goto true;
1339
1340 true:
1341 scm_remember_upto_here_2 (s1, s2);
1342 return scm_from_size_t (cstart1);
1343
1344 false:
1345 scm_remember_upto_here_2 (s1, s2);
1346 return SCM_BOOL_F;
1347 }
1348 #undef FUNC_NAME
1349
1350
1351 SCM_DEFINE (scm_string_ci_neq, "string-ci<>", 2, 4, 0,
1352 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1353 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
1354 "value otherwise. The character comparison is done\n"
1355 "case-insensitively.")
1356 #define FUNC_NAME s_scm_string_ci_neq
1357 {
1358 const char *cstr1, *cstr2;
1359 size_t cstart1, cend1, cstart2, cend2;
1360
1361 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1362 3, start1, cstart1,
1363 4, end1, cend1);
1364 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1365 5, start2, cstart2,
1366 6, end2, cend2);
1367
1368 while (cstart1 < cend1 && cstart2 < cend2)
1369 {
1370 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1371 goto true;
1372 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1373 goto true;
1374 cstart1++;
1375 cstart2++;
1376 }
1377 if (cstart1 < cend1)
1378 goto true;
1379 else if (cstart2 < cend2)
1380 goto true;
1381 else
1382 goto false;
1383
1384 true:
1385 scm_remember_upto_here_2 (s1, s2);
1386 return scm_from_size_t (cstart1);
1387
1388 false:
1389 scm_remember_upto_here_2 (s1, s2);
1390 return SCM_BOOL_F;
1391 }
1392 #undef FUNC_NAME
1393
1394
1395 SCM_DEFINE (scm_string_ci_lt, "string-ci<", 2, 4, 0,
1396 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1397 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
1398 "true value otherwise. The character comparison is done\n"
1399 "case-insensitively.")
1400 #define FUNC_NAME s_scm_string_ci_lt
1401 {
1402 const char *cstr1, *cstr2;
1403 size_t cstart1, cend1, cstart2, cend2;
1404
1405 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1406 3, start1, cstart1,
1407 4, end1, cend1);
1408 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1409 5, start2, cstart2,
1410 6, end2, cend2);
1411
1412 while (cstart1 < cend1 && cstart2 < cend2)
1413 {
1414 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1415 goto true;
1416 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1417 goto false;
1418 cstart1++;
1419 cstart2++;
1420 }
1421 if (cstart1 < cend1)
1422 goto false;
1423 else if (cstart2 < cend2)
1424 goto true;
1425 else
1426 goto false;
1427
1428 true:
1429 scm_remember_upto_here_2 (s1, s2);
1430 return scm_from_size_t (cstart1);
1431
1432 false:
1433 scm_remember_upto_here_2 (s1, s2);
1434 return SCM_BOOL_F;
1435 }
1436 #undef FUNC_NAME
1437
1438
1439 SCM_DEFINE (scm_string_ci_gt, "string-ci>", 2, 4, 0,
1440 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1441 "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
1442 "true value otherwise. The character comparison is done\n"
1443 "case-insensitively.")
1444 #define FUNC_NAME s_scm_string_ci_gt
1445 {
1446 const char *cstr1, *cstr2;
1447 size_t cstart1, cend1, cstart2, cend2;
1448
1449 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1450 3, start1, cstart1,
1451 4, end1, cend1);
1452 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1453 5, start2, cstart2,
1454 6, end2, cend2);
1455
1456 while (cstart1 < cend1 && cstart2 < cend2)
1457 {
1458 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1459 goto false;
1460 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1461 goto true;
1462 cstart1++;
1463 cstart2++;
1464 }
1465 if (cstart1 < cend1)
1466 goto true;
1467 else if (cstart2 < cend2)
1468 goto false;
1469 else
1470 goto false;
1471
1472 true:
1473 scm_remember_upto_here_2 (s1, s2);
1474 return scm_from_size_t (cstart1);
1475
1476 false:
1477 scm_remember_upto_here_2 (s1, s2);
1478 return SCM_BOOL_F;
1479 }
1480 #undef FUNC_NAME
1481
1482
1483 SCM_DEFINE (scm_string_ci_le, "string-ci<=", 2, 4, 0,
1484 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1485 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1486 "value otherwise. The character comparison is done\n"
1487 "case-insensitively.")
1488 #define FUNC_NAME s_scm_string_ci_le
1489 {
1490 const char *cstr1, *cstr2;
1491 size_t cstart1, cend1, cstart2, cend2;
1492
1493 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1494 3, start1, cstart1,
1495 4, end1, cend1);
1496 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1497 5, start2, cstart2,
1498 6, end2, cend2);
1499
1500 while (cstart1 < cend1 && cstart2 < cend2)
1501 {
1502 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1503 goto true;
1504 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1505 goto false;
1506 cstart1++;
1507 cstart2++;
1508 }
1509 if (cstart1 < cend1)
1510 goto false;
1511 else if (cstart2 < cend2)
1512 goto true;
1513 else
1514 goto true;
1515
1516 true:
1517 scm_remember_upto_here_2 (s1, s2);
1518 return scm_from_size_t (cstart1);
1519
1520 false:
1521 scm_remember_upto_here_2 (s1, s2);
1522 return SCM_BOOL_F;
1523 }
1524 #undef FUNC_NAME
1525
1526
1527 SCM_DEFINE (scm_string_ci_ge, "string-ci>=", 2, 4, 0,
1528 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1529 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1530 "otherwise. The character comparison is done\n"
1531 "case-insensitively.")
1532 #define FUNC_NAME s_scm_string_ci_ge
1533 {
1534 const char *cstr1, *cstr2;
1535 size_t cstart1, cend1, cstart2, cend2;
1536
1537 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1538 3, start1, cstart1,
1539 4, end1, cend1);
1540 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1541 5, start2, cstart2,
1542 6, end2, cend2);
1543
1544 while (cstart1 < cend1 && cstart2 < cend2)
1545 {
1546 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1547 goto false;
1548 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1549 goto true;
1550 cstart1++;
1551 cstart2++;
1552 }
1553 if (cstart1 < cend1)
1554 goto true;
1555 else if (cstart2 < cend2)
1556 goto false;
1557 else
1558 goto true;
1559
1560 true:
1561 scm_remember_upto_here_2 (s1, s2);
1562 return scm_from_size_t (cstart1);
1563
1564 false:
1565 scm_remember_upto_here_2 (s1, s2);
1566 return SCM_BOOL_F;
1567 }
1568 #undef FUNC_NAME
1569
1570 SCM_DEFINE (scm_substring_hash, "string-hash", 1, 3, 0,
1571 (SCM s, SCM bound, SCM start, SCM end),
1572 "Compute a hash value for @var{S}. the optional argument "
1573 "@var{bound} is a non-negative exact "
1574 "integer specifying the range of the hash function. "
1575 "A positive value restricts the return value to the "
1576 "range [0,bound).")
1577 #define FUNC_NAME s_scm_substring_hash
1578 {
1579 if (SCM_UNBNDP (bound))
1580 bound = scm_from_intmax (SCM_MOST_POSITIVE_FIXNUM);
1581 if (SCM_UNBNDP (start))
1582 start = SCM_INUM0;
1583 return scm_hash (scm_substring_shared (s, start, end), bound);
1584 }
1585 #undef FUNC_NAME
1586
1587 SCM_DEFINE (scm_substring_hash_ci, "string-hash-ci", 1, 3, 0,
1588 (SCM s, SCM bound, SCM start, SCM end),
1589 "Compute a hash value for @var{S}. the optional argument "
1590 "@var{bound} is a non-negative exact "
1591 "integer specifying the range of the hash function. "
1592 "A positive value restricts the return value to the "
1593 "range [0,bound).")
1594 #define FUNC_NAME s_scm_substring_hash_ci
1595 {
1596 return scm_substring_hash (scm_substring_downcase (s, start, end),
1597 bound,
1598 SCM_UNDEFINED, SCM_UNDEFINED);
1599 }
1600 #undef FUNC_NAME
1601
1602 SCM_DEFINE (scm_string_prefix_length, "string-prefix-length", 2, 4, 0,
1603 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1604 "Return the length of the longest common prefix of the two\n"
1605 "strings.")
1606 #define FUNC_NAME s_scm_string_prefix_length
1607 {
1608 const char *cstr1, *cstr2;
1609 size_t cstart1, cend1, cstart2, cend2;
1610 size_t len = 0;
1611
1612 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1613 3, start1, cstart1,
1614 4, end1, cend1);
1615 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1616 5, start2, cstart2,
1617 6, end2, cend2);
1618 while (cstart1 < cend1 && cstart2 < cend2)
1619 {
1620 if (cstr1[cstart1] != cstr2[cstart2])
1621 return scm_from_size_t (len);
1622 len++;
1623 cstart1++;
1624 cstart2++;
1625 }
1626 return scm_from_size_t (len);
1627 }
1628 #undef FUNC_NAME
1629
1630
1631 SCM_DEFINE (scm_string_prefix_length_ci, "string-prefix-length-ci", 2, 4, 0,
1632 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1633 "Return the length of the longest common prefix of the two\n"
1634 "strings, ignoring character case.")
1635 #define FUNC_NAME s_scm_string_prefix_length_ci
1636 {
1637 const char *cstr1, *cstr2;
1638 size_t cstart1, cend1, cstart2, cend2;
1639 size_t len = 0;
1640
1641 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1642 3, start1, cstart1,
1643 4, end1, cend1);
1644 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1645 5, start2, cstart2,
1646 6, end2, cend2);
1647 while (cstart1 < cend1 && cstart2 < cend2)
1648 {
1649 if (scm_c_downcase (cstr1[cstart1]) != scm_c_downcase (cstr2[cstart2]))
1650 return scm_from_size_t (len);
1651 len++;
1652 cstart1++;
1653 cstart2++;
1654 }
1655 return scm_from_size_t (len);
1656 }
1657 #undef FUNC_NAME
1658
1659
1660 SCM_DEFINE (scm_string_suffix_length, "string-suffix-length", 2, 4, 0,
1661 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1662 "Return the length of the longest common suffix of the two\n"
1663 "strings.")
1664 #define FUNC_NAME s_scm_string_suffix_length
1665 {
1666 const char *cstr1, *cstr2;
1667 size_t cstart1, cend1, cstart2, cend2;
1668 size_t len = 0;
1669
1670 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1671 3, start1, cstart1,
1672 4, end1, cend1);
1673 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1674 5, start2, cstart2,
1675 6, end2, cend2);
1676 while (cstart1 < cend1 && cstart2 < cend2)
1677 {
1678 cend1--;
1679 cend2--;
1680 if (cstr1[cend1] != cstr2[cend2])
1681 return scm_from_size_t (len);
1682 len++;
1683 }
1684 return scm_from_size_t (len);
1685 }
1686 #undef FUNC_NAME
1687
1688
1689 SCM_DEFINE (scm_string_suffix_length_ci, "string-suffix-length-ci", 2, 4, 0,
1690 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1691 "Return the length of the longest common suffix of the two\n"
1692 "strings, ignoring character case.")
1693 #define FUNC_NAME s_scm_string_suffix_length_ci
1694 {
1695 const char *cstr1, *cstr2;
1696 size_t cstart1, cend1, cstart2, cend2;
1697 size_t len = 0;
1698
1699 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1700 3, start1, cstart1,
1701 4, end1, cend1);
1702 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1703 5, start2, cstart2,
1704 6, end2, cend2);
1705 while (cstart1 < cend1 && cstart2 < cend2)
1706 {
1707 cend1--;
1708 cend2--;
1709 if (scm_c_downcase (cstr1[cend1]) != scm_c_downcase (cstr2[cend2]))
1710 return scm_from_size_t (len);
1711 len++;
1712 }
1713 return scm_from_size_t (len);
1714 }
1715 #undef FUNC_NAME
1716
1717
1718 SCM_DEFINE (scm_string_prefix_p, "string-prefix?", 2, 4, 0,
1719 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1720 "Is @var{s1} a prefix of @var{s2}?")
1721 #define FUNC_NAME s_scm_string_prefix_p
1722 {
1723 const char *cstr1, *cstr2;
1724 size_t cstart1, cend1, cstart2, cend2;
1725 size_t len = 0, len1;
1726
1727 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1728 3, start1, cstart1,
1729 4, end1, cend1);
1730 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1731 5, start2, cstart2,
1732 6, end2, cend2);
1733 len1 = cend1 - cstart1;
1734 while (cstart1 < cend1 && cstart2 < cend2)
1735 {
1736 if (cstr1[cstart1] != cstr2[cstart2])
1737 return scm_from_bool (len == len1);
1738 len++;
1739 cstart1++;
1740 cstart2++;
1741 }
1742 return scm_from_bool (len == len1);
1743 }
1744 #undef FUNC_NAME
1745
1746
1747 SCM_DEFINE (scm_string_prefix_ci_p, "string-prefix-ci?", 2, 4, 0,
1748 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1749 "Is @var{s1} a prefix of @var{s2}, ignoring character case?")
1750 #define FUNC_NAME s_scm_string_prefix_ci_p
1751 {
1752 const char *cstr1, *cstr2;
1753 size_t cstart1, cend1, cstart2, cend2;
1754 size_t len = 0, len1;
1755
1756 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1757 3, start1, cstart1,
1758 4, end1, cend1);
1759 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1760 5, start2, cstart2,
1761 6, end2, cend2);
1762 len1 = cend1 - cstart1;
1763 while (cstart1 < cend1 && cstart2 < cend2)
1764 {
1765 if (scm_c_downcase (cstr1[cstart1]) != scm_c_downcase (cstr2[cstart2]))
1766 return scm_from_bool (len == len1);
1767 len++;
1768 cstart1++;
1769 cstart2++;
1770 }
1771 return scm_from_bool (len == len1);
1772 }
1773 #undef FUNC_NAME
1774
1775
1776 SCM_DEFINE (scm_string_suffix_p, "string-suffix?", 2, 4, 0,
1777 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1778 "Is @var{s1} a suffix of @var{s2}?")
1779 #define FUNC_NAME s_scm_string_suffix_p
1780 {
1781 const char *cstr1, *cstr2;
1782 size_t cstart1, cend1, cstart2, cend2;
1783 size_t len = 0, len1;
1784
1785 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1786 3, start1, cstart1,
1787 4, end1, cend1);
1788 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1789 5, start2, cstart2,
1790 6, end2, cend2);
1791 len1 = cend1 - cstart1;
1792 while (cstart1 < cend1 && cstart2 < cend2)
1793 {
1794 cend1--;
1795 cend2--;
1796 if (cstr1[cend1] != cstr2[cend2])
1797 return scm_from_bool (len == len1);
1798 len++;
1799 }
1800 return scm_from_bool (len == len1);
1801 }
1802 #undef FUNC_NAME
1803
1804
1805 SCM_DEFINE (scm_string_suffix_ci_p, "string-suffix-ci?", 2, 4, 0,
1806 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1807 "Is @var{s1} a suffix of @var{s2}, ignoring character case?")
1808 #define FUNC_NAME s_scm_string_suffix_ci_p
1809 {
1810 const char *cstr1, *cstr2;
1811 size_t cstart1, cend1, cstart2, cend2;
1812 size_t len = 0, len1;
1813
1814 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1815 3, start1, cstart1,
1816 4, end1, cend1);
1817 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1818 5, start2, cstart2,
1819 6, end2, cend2);
1820 len1 = cend1 - cstart1;
1821 while (cstart1 < cend1 && cstart2 < cend2)
1822 {
1823 cend1--;
1824 cend2--;
1825 if (scm_c_downcase (cstr1[cend1]) != scm_c_downcase (cstr2[cend2]))
1826 return scm_from_bool (len == len1);
1827 len++;
1828 }
1829 return scm_from_bool (len == len1);
1830 }
1831 #undef FUNC_NAME
1832
1833
1834 SCM_DEFINE (scm_string_index, "string-index", 2, 2, 0,
1835 (SCM s, SCM char_pred, SCM start, SCM end),
1836 "Search through the string @var{s} from left to right, returning\n"
1837 "the index of the first occurence of a character which\n"
1838 "\n"
1839 "@itemize @bullet\n"
1840 "@item\n"
1841 "equals @var{char_pred}, if it is character,\n"
1842 "\n"
1843 "@item\n"
1844 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1845 "\n"
1846 "@item\n"
1847 "is in the set @var{char_pred}, if it is a character set.\n"
1848 "@end itemize")
1849 #define FUNC_NAME s_scm_string_index
1850 {
1851 const char *cstr;
1852 size_t cstart, cend;
1853
1854 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1855 3, start, cstart,
1856 4, end, cend);
1857 if (SCM_CHARP (char_pred))
1858 {
1859 char cchr = SCM_CHAR (char_pred);
1860 while (cstart < cend)
1861 {
1862 if (cchr == cstr[cstart])
1863 return scm_from_size_t (cstart);
1864 cstart++;
1865 }
1866 }
1867 else if (SCM_CHARSETP (char_pred))
1868 {
1869 while (cstart < cend)
1870 {
1871 if (SCM_CHARSET_GET (char_pred, cstr[cstart]))
1872 return scm_from_size_t (cstart);
1873 cstart++;
1874 }
1875 }
1876 else
1877 {
1878 SCM_VALIDATE_PROC (2, char_pred);
1879 while (cstart < cend)
1880 {
1881 SCM res;
1882 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
1883 if (scm_is_true (res))
1884 return scm_from_size_t (cstart);
1885 cstr = scm_i_string_chars (s);
1886 cstart++;
1887 }
1888 }
1889 return SCM_BOOL_F;
1890 }
1891 #undef FUNC_NAME
1892
1893 SCM_DEFINE (scm_string_index_right, "string-index-right", 2, 2, 0,
1894 (SCM s, SCM char_pred, SCM start, SCM end),
1895 "Search through the string @var{s} from right to left, returning\n"
1896 "the index of the last occurence of a character which\n"
1897 "\n"
1898 "@itemize @bullet\n"
1899 "@item\n"
1900 "equals @var{char_pred}, if it is character,\n"
1901 "\n"
1902 "@item\n"
1903 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1904 "\n"
1905 "@item\n"
1906 "is in the set if @var{char_pred} is a character set.\n"
1907 "@end itemize")
1908 #define FUNC_NAME s_scm_string_index_right
1909 {
1910 const char *cstr;
1911 size_t cstart, cend;
1912
1913 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1914 3, start, cstart,
1915 4, end, cend);
1916 if (SCM_CHARP (char_pred))
1917 {
1918 char cchr = SCM_CHAR (char_pred);
1919 while (cstart < cend)
1920 {
1921 cend--;
1922 if (cchr == cstr[cend])
1923 return scm_from_size_t (cend);
1924 }
1925 }
1926 else if (SCM_CHARSETP (char_pred))
1927 {
1928 while (cstart < cend)
1929 {
1930 cend--;
1931 if (SCM_CHARSET_GET (char_pred, cstr[cend]))
1932 return scm_from_size_t (cend);
1933 }
1934 }
1935 else
1936 {
1937 SCM_VALIDATE_PROC (2, char_pred);
1938 while (cstart < cend)
1939 {
1940 SCM res;
1941 cend--;
1942 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend]));
1943 if (scm_is_true (res))
1944 return scm_from_size_t (cend);
1945 cstr = scm_i_string_chars (s);
1946 }
1947 }
1948 return SCM_BOOL_F;
1949 }
1950 #undef FUNC_NAME
1951
1952 SCM
1953 scm_string_rindex (SCM str, SCM chr, SCM frm, SCM to)
1954 {
1955 return scm_string_index_right (str, chr, frm, to);
1956 }
1957
1958 SCM_DEFINE (scm_string_skip, "string-skip", 2, 2, 0,
1959 (SCM s, SCM char_pred, SCM start, SCM end),
1960 "Search through the string @var{s} from left to right, returning\n"
1961 "the index of the first occurence of a character which\n"
1962 "\n"
1963 "@itemize @bullet\n"
1964 "@item\n"
1965 "does not equal @var{char_pred}, if it is character,\n"
1966 "\n"
1967 "@item\n"
1968 "does not satisify the predicate @var{char_pred}, if it is a\n"
1969 "procedure,\n"
1970 "\n"
1971 "@item\n"
1972 "is not in the set if @var{char_pred} is a character set.\n"
1973 "@end itemize")
1974 #define FUNC_NAME s_scm_string_skip
1975 {
1976 const char *cstr;
1977 size_t cstart, cend;
1978
1979 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1980 3, start, cstart,
1981 4, end, cend);
1982 if (SCM_CHARP (char_pred))
1983 {
1984 char cchr = SCM_CHAR (char_pred);
1985 while (cstart < cend)
1986 {
1987 if (cchr != cstr[cstart])
1988 return scm_from_size_t (cstart);
1989 cstart++;
1990 }
1991 }
1992 else if (SCM_CHARSETP (char_pred))
1993 {
1994 while (cstart < cend)
1995 {
1996 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
1997 return scm_from_size_t (cstart);
1998 cstart++;
1999 }
2000 }
2001 else
2002 {
2003 SCM_VALIDATE_PROC (2, char_pred);
2004 while (cstart < cend)
2005 {
2006 SCM res;
2007 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
2008 if (scm_is_false (res))
2009 return scm_from_size_t (cstart);
2010 cstr = scm_i_string_chars (s);
2011 cstart++;
2012 }
2013 }
2014 return SCM_BOOL_F;
2015 }
2016 #undef FUNC_NAME
2017
2018
2019 SCM_DEFINE (scm_string_skip_right, "string-skip-right", 2, 2, 0,
2020 (SCM s, SCM char_pred, SCM start, SCM end),
2021 "Search through the string @var{s} from right to left, returning\n"
2022 "the index of the last occurence of a character which\n"
2023 "\n"
2024 "@itemize @bullet\n"
2025 "@item\n"
2026 "does not equal @var{char_pred}, if it is character,\n"
2027 "\n"
2028 "@item\n"
2029 "does not satisfy the predicate @var{char_pred}, if it is a\n"
2030 "procedure,\n"
2031 "\n"
2032 "@item\n"
2033 "is not in the set if @var{char_pred} is a character set.\n"
2034 "@end itemize")
2035 #define FUNC_NAME s_scm_string_skip_right
2036 {
2037 const char *cstr;
2038 size_t cstart, cend;
2039
2040 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2041 3, start, cstart,
2042 4, end, cend);
2043 if (SCM_CHARP (char_pred))
2044 {
2045 char cchr = SCM_CHAR (char_pred);
2046 while (cstart < cend)
2047 {
2048 cend--;
2049 if (cchr != cstr[cend])
2050 return scm_from_size_t (cend);
2051 }
2052 }
2053 else if (SCM_CHARSETP (char_pred))
2054 {
2055 while (cstart < cend)
2056 {
2057 cend--;
2058 if (!SCM_CHARSET_GET (char_pred, cstr[cend]))
2059 return scm_from_size_t (cend);
2060 }
2061 }
2062 else
2063 {
2064 SCM_VALIDATE_PROC (2, char_pred);
2065 while (cstart < cend)
2066 {
2067 SCM res;
2068 cend--;
2069 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend]));
2070 if (scm_is_false (res))
2071 return scm_from_size_t (cend);
2072 cstr = scm_i_string_chars (s);
2073 }
2074 }
2075 return SCM_BOOL_F;
2076 }
2077 #undef FUNC_NAME
2078
2079
2080 SCM_DEFINE (scm_string_count, "string-count", 2, 2, 0,
2081 (SCM s, SCM char_pred, SCM start, SCM end),
2082 "Return the count of the number of characters in the string\n"
2083 "@var{s} which\n"
2084 "\n"
2085 "@itemize @bullet\n"
2086 "@item\n"
2087 "equals @var{char_pred}, if it is character,\n"
2088 "\n"
2089 "@item\n"
2090 "satisifies the predicate @var{char_pred}, if it is a procedure.\n"
2091 "\n"
2092 "@item\n"
2093 "is in the set @var{char_pred}, if it is a character set.\n"
2094 "@end itemize")
2095 #define FUNC_NAME s_scm_string_count
2096 {
2097 const char *cstr;
2098 size_t cstart, cend;
2099 size_t count = 0;
2100
2101 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2102 3, start, cstart,
2103 4, end, cend);
2104 if (SCM_CHARP (char_pred))
2105 {
2106 char cchr = SCM_CHAR (char_pred);
2107 while (cstart < cend)
2108 {
2109 if (cchr == cstr[cstart])
2110 count++;
2111 cstart++;
2112 }
2113 }
2114 else if (SCM_CHARSETP (char_pred))
2115 {
2116 while (cstart < cend)
2117 {
2118 if (SCM_CHARSET_GET (char_pred, cstr[cstart]))
2119 count++;
2120 cstart++;
2121 }
2122 }
2123 else
2124 {
2125 SCM_VALIDATE_PROC (2, char_pred);
2126 while (cstart < cend)
2127 {
2128 SCM res;
2129 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
2130 if (scm_is_true (res))
2131 count++;
2132 cstr = scm_i_string_chars (s);
2133 cstart++;
2134 }
2135 }
2136 return scm_from_size_t (count);
2137 }
2138 #undef FUNC_NAME
2139
2140
2141 /* FIXME::martin: This should definitely get implemented more
2142 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
2143 implementation. */
2144 SCM_DEFINE (scm_string_contains, "string-contains", 2, 4, 0,
2145 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
2146 "Does string @var{s1} contain string @var{s2}? Return the index\n"
2147 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
2148 "The optional start/end indices restrict the operation to the\n"
2149 "indicated substrings.")
2150 #define FUNC_NAME s_scm_string_contains
2151 {
2152 const char *cs1, * cs2;
2153 size_t cstart1, cend1, cstart2, cend2;
2154 size_t len2, i, j;
2155
2156 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cs1,
2157 3, start1, cstart1,
2158 4, end1, cend1);
2159 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cs2,
2160 5, start2, cstart2,
2161 6, end2, cend2);
2162 len2 = cend2 - cstart2;
2163 while (cstart1 <= cend1 - len2)
2164 {
2165 i = cstart1;
2166 j = cstart2;
2167 while (i < cend1 && j < cend2 && cs1[i] == cs2[j])
2168 {
2169 i++;
2170 j++;
2171 }
2172 if (j == cend2)
2173 return scm_from_size_t (cstart1);
2174 cstart1++;
2175 }
2176 return SCM_BOOL_F;
2177 }
2178 #undef FUNC_NAME
2179
2180
2181 /* FIXME::martin: This should definitely get implemented more
2182 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
2183 implementation. */
2184 SCM_DEFINE (scm_string_contains_ci, "string-contains-ci", 2, 4, 0,
2185 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
2186 "Does string @var{s1} contain string @var{s2}? Return the index\n"
2187 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
2188 "The optional start/end indices restrict the operation to the\n"
2189 "indicated substrings. Character comparison is done\n"
2190 "case-insensitively.")
2191 #define FUNC_NAME s_scm_string_contains_ci
2192 {
2193 const char *cs1, * cs2;
2194 size_t cstart1, cend1, cstart2, cend2;
2195 size_t len2, i, j;
2196
2197 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cs1,
2198 3, start1, cstart1,
2199 4, end1, cend1);
2200 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cs2,
2201 5, start2, cstart2,
2202 6, end2, cend2);
2203 len2 = cend2 - cstart2;
2204 while (cstart1 <= cend1 - len2)
2205 {
2206 i = cstart1;
2207 j = cstart2;
2208 while (i < cend1 && j < cend2 &&
2209 scm_c_downcase (cs1[i]) == scm_c_downcase (cs2[j]))
2210 {
2211 i++;
2212 j++;
2213 }
2214 if (j == cend2)
2215 return scm_from_size_t (cstart1);
2216 cstart1++;
2217 }
2218 return SCM_BOOL_F;
2219 }
2220 #undef FUNC_NAME
2221
2222
2223 /* Helper function for the string uppercase conversion functions.
2224 * No argument checking is performed. */
2225 static SCM
2226 string_upcase_x (SCM v, int start, int end)
2227 {
2228 size_t k;
2229 char *dst;
2230
2231 dst = scm_i_string_writable_chars (v);
2232 for (k = start; k < end; ++k)
2233 dst[k] = scm_c_upcase (dst[k]);
2234 scm_i_string_stop_writing ();
2235
2236 return v;
2237 }
2238
2239 SCM_DEFINE (scm_substring_upcase_x, "string-upcase!", 1, 2, 0,
2240 (SCM str, SCM start, SCM end),
2241 "Destructively upcase every character in @code{str}.\n"
2242 "\n"
2243 "@lisp\n"
2244 "(string-upcase! y)\n"
2245 "@result{} \"ARRDEFG\"\n"
2246 "y\n"
2247 "@result{} \"ARRDEFG\"\n"
2248 "@end lisp")
2249 #define FUNC_NAME s_scm_substring_upcase_x
2250 {
2251 const char *cstr;
2252 size_t cstart, cend;
2253
2254 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2255 2, start, cstart,
2256 3, end, cend);
2257 return string_upcase_x (str, cstart, cend);
2258 }
2259 #undef FUNC_NAME
2260
2261 SCM
2262 scm_string_upcase_x (SCM str)
2263 {
2264 return scm_substring_upcase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
2265 }
2266
2267 SCM_DEFINE (scm_substring_upcase, "string-upcase", 1, 2, 0,
2268 (SCM str, SCM start, SCM end),
2269 "Upcase every character in @code{str}.")
2270 #define FUNC_NAME s_scm_substring_upcase
2271 {
2272 const char *cstr;
2273 size_t cstart, cend;
2274
2275 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2276 2, start, cstart,
2277 3, end, cend);
2278 return string_upcase_x (scm_string_copy (str), cstart, cend);
2279 }
2280 #undef FUNC_NAME
2281
2282 SCM
2283 scm_string_upcase (SCM str)
2284 {
2285 return scm_substring_upcase (str, SCM_UNDEFINED, SCM_UNDEFINED);
2286 }
2287
2288 /* Helper function for the string lowercase conversion functions.
2289 * No argument checking is performed. */
2290 static SCM
2291 string_downcase_x (SCM v, int start, int end)
2292 {
2293 size_t k;
2294 char *dst;
2295
2296 dst = scm_i_string_writable_chars (v);
2297 for (k = start; k < end; ++k)
2298 dst[k] = scm_c_downcase (dst[k]);
2299 scm_i_string_stop_writing ();
2300
2301 return v;
2302 }
2303
2304 SCM_DEFINE (scm_substring_downcase_x, "string-downcase!", 1, 2, 0,
2305 (SCM str, SCM start, SCM end),
2306 "Destructively downcase every character in @var{str}.\n"
2307 "\n"
2308 "@lisp\n"
2309 "y\n"
2310 "@result{} \"ARRDEFG\"\n"
2311 "(string-downcase! y)\n"
2312 "@result{} \"arrdefg\"\n"
2313 "y\n"
2314 "@result{} \"arrdefg\"\n"
2315 "@end lisp")
2316 #define FUNC_NAME s_scm_substring_downcase_x
2317 {
2318 const char *cstr;
2319 size_t cstart, cend;
2320
2321 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2322 2, start, cstart,
2323 3, end, cend);
2324 return string_downcase_x (str, cstart, cend);
2325 }
2326 #undef FUNC_NAME
2327
2328 SCM
2329 scm_string_downcase_x (SCM str)
2330 {
2331 return scm_substring_downcase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
2332 }
2333
2334 SCM_DEFINE (scm_substring_downcase, "string-downcase", 1, 2, 0,
2335 (SCM str, SCM start, SCM end),
2336 "Downcase every character in @var{str}.")
2337 #define FUNC_NAME s_scm_substring_downcase
2338 {
2339 const char *cstr;
2340 size_t cstart, cend;
2341
2342 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2343 2, start, cstart,
2344 3, end, cend);
2345 return string_downcase_x (scm_string_copy (str), cstart, cend);
2346 }
2347 #undef FUNC_NAME
2348
2349 SCM
2350 scm_string_downcase (SCM str)
2351 {
2352 return scm_substring_downcase (str, SCM_UNDEFINED, SCM_UNDEFINED);
2353 }
2354
2355 /* Helper function for the string capitalization functions.
2356 * No argument checking is performed. */
2357 static SCM
2358 string_titlecase_x (SCM str, int start, int end)
2359 {
2360 unsigned char *sz;
2361 size_t i;
2362 int in_word = 0;
2363
2364 sz = scm_i_string_writable_chars (str);
2365 for(i = start; i < end; i++)
2366 {
2367 if (scm_is_true (scm_char_alphabetic_p (SCM_MAKE_CHAR (sz[i]))))
2368 {
2369 if (!in_word)
2370 {
2371 sz[i] = scm_c_upcase(sz[i]);
2372 in_word = 1;
2373 }
2374 else
2375 {
2376 sz[i] = scm_c_downcase(sz[i]);
2377 }
2378 }
2379 else
2380 in_word = 0;
2381 }
2382 scm_i_string_stop_writing ();
2383
2384 return str;
2385 }
2386
2387
2388 SCM_DEFINE (scm_string_titlecase_x, "string-titlecase!", 1, 2, 0,
2389 (SCM str, SCM start, SCM end),
2390 "Destructively titlecase every first character in a word in\n"
2391 "@var{str}.")
2392 #define FUNC_NAME s_scm_string_titlecase_x
2393 {
2394 const char *cstr;
2395 size_t cstart, cend;
2396
2397 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2398 2, start, cstart,
2399 3, end, cend);
2400 return string_titlecase_x (str, cstart, cend);
2401 }
2402 #undef FUNC_NAME
2403
2404
2405 SCM_DEFINE (scm_string_titlecase, "string-titlecase", 1, 2, 0,
2406 (SCM str, SCM start, SCM end),
2407 "Titlecase every first character in a word in @var{str}.")
2408 #define FUNC_NAME s_scm_string_titlecase
2409 {
2410 const char *cstr;
2411 size_t cstart, cend;
2412
2413 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2414 2, start, cstart,
2415 3, end, cend);
2416 return string_titlecase_x (scm_string_copy (str), cstart, cend);
2417 }
2418 #undef FUNC_NAME
2419
2420 /* Old names, the functions.
2421 */
2422
2423 SCM_DEFINE (scm_string_capitalize_x, "string-capitalize!", 1, 0, 0,
2424 (SCM str),
2425 "Upcase the first character of every word in @var{str}\n"
2426 "destructively and return @var{str}.\n"
2427 "\n"
2428 "@lisp\n"
2429 "y @result{} \"hello world\"\n"
2430 "(string-capitalize! y) @result{} \"Hello World\"\n"
2431 "y @result{} \"Hello World\"\n"
2432 "@end lisp")
2433 #define FUNC_NAME s_scm_string_capitalize_x
2434 {
2435 return scm_string_titlecase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
2436 }
2437 #undef FUNC_NAME
2438
2439
2440 SCM_DEFINE (scm_string_capitalize, "string-capitalize", 1, 0, 0,
2441 (SCM str),
2442 "Return a freshly allocated string with the characters in\n"
2443 "@var{str}, where the first character of every word is\n"
2444 "capitalized.")
2445 #define FUNC_NAME s_scm_string_capitalize
2446 {
2447 return scm_string_capitalize_x (scm_string_copy (str));
2448 }
2449 #undef FUNC_NAME
2450
2451
2452 /* Reverse the portion of @var{str} between str[cstart] (including)
2453 and str[cend] excluding. */
2454 static void
2455 string_reverse_x (char * str, int cstart, int cend)
2456 {
2457 char tmp;
2458
2459 cend--;
2460 while (cstart < cend)
2461 {
2462 tmp = str[cstart];
2463 str[cstart] = str[cend];
2464 str[cend] = tmp;
2465 cstart++;
2466 cend--;
2467 }
2468 }
2469
2470
2471 SCM_DEFINE (scm_string_reverse, "string-reverse", 1, 2, 0,
2472 (SCM str, SCM start, SCM end),
2473 "Reverse the string @var{str}. The optional arguments\n"
2474 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2475 "operate on.")
2476 #define FUNC_NAME s_scm_string_reverse
2477 {
2478 const char *cstr;
2479 char *ctarget;
2480 size_t cstart, cend;
2481 SCM result;
2482
2483 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2484 2, start, cstart,
2485 3, end, cend);
2486 result = scm_string_copy (str);
2487 ctarget = scm_i_string_writable_chars (result);
2488 string_reverse_x (ctarget, cstart, cend);
2489 scm_i_string_stop_writing ();
2490 return result;
2491 }
2492 #undef FUNC_NAME
2493
2494
2495 SCM_DEFINE (scm_string_reverse_x, "string-reverse!", 1, 2, 0,
2496 (SCM str, SCM start, SCM end),
2497 "Reverse the string @var{str} in-place. The optional arguments\n"
2498 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2499 "operate on. The return value is unspecified.")
2500 #define FUNC_NAME s_scm_string_reverse_x
2501 {
2502 char *cstr;
2503 size_t cstart, cend;
2504
2505 MY_VALIDATE_SUBSTRING_SPEC (1, str,
2506 2, start, cstart,
2507 3, end, cend);
2508
2509 cstr = scm_i_string_writable_chars (str);
2510 string_reverse_x (cstr, cstart, cend);
2511 scm_i_string_stop_writing ();
2512
2513 scm_remember_upto_here_1 (str);
2514 return SCM_UNSPECIFIED;
2515 }
2516 #undef FUNC_NAME
2517
2518
2519 SCM_DEFINE (scm_string_append_shared, "string-append/shared", 0, 0, 1,
2520 (SCM ls),
2521 "Like @code{string-append}, but the result may share memory\n"
2522 "with the argument strings.")
2523 #define FUNC_NAME s_scm_string_append_shared
2524 {
2525 long i;
2526
2527 SCM_VALIDATE_REST_ARGUMENT (ls);
2528
2529 /* Optimize the one-argument case. */
2530 i = scm_ilength (ls);
2531 if (i == 1)
2532 return SCM_CAR (ls);
2533 else
2534 return scm_string_append (ls);
2535 }
2536 #undef FUNC_NAME
2537
2538
2539 SCM_DEFINE (scm_string_concatenate, "string-concatenate", 1, 0, 0,
2540 (SCM ls),
2541 "Append the elements of @var{ls} (which must be strings)\n"
2542 "together into a single string. Guaranteed to return a freshly\n"
2543 "allocated string.")
2544 #define FUNC_NAME s_scm_string_concatenate
2545 {
2546 return scm_string_append (ls);
2547 }
2548 #undef FUNC_NAME
2549
2550
2551 SCM_DEFINE (scm_string_concatenate_reverse, "string-concatenate-reverse", 1, 2, 0,
2552 (SCM ls, SCM final_string, SCM end),
2553 "Without optional arguments, this procedure is equivalent to\n"
2554 "\n"
2555 "@smalllisp\n"
2556 "(string-concatenate (reverse ls))\n"
2557 "@end smalllisp\n"
2558 "\n"
2559 "If the optional argument @var{final_string} is specified, it is\n"
2560 "consed onto the beginning to @var{ls} before performing the\n"
2561 "list-reverse and string-concatenate operations. If @var{end}\n"
2562 "is given, only the characters of @var{final_string} up to index\n"
2563 "@var{end} are used.\n"
2564 "\n"
2565 "Guaranteed to return a freshly allocated string.")
2566 #define FUNC_NAME s_scm_string_concatenate_reverse
2567 {
2568 long strings;
2569 SCM tmp, result;
2570 size_t len = 0;
2571 char * p;
2572 size_t cend = 0;
2573
2574 /* Check the optional arguments and calculate the additional length
2575 of the result string. */
2576 if (!SCM_UNBNDP (final_string))
2577 {
2578 SCM_VALIDATE_STRING (2, final_string);
2579 if (!SCM_UNBNDP (end))
2580 {
2581 cend = scm_to_unsigned_integer (end,
2582 0,
2583 scm_i_string_length (final_string));
2584 }
2585 else
2586 {
2587 cend = scm_i_string_length (final_string);
2588 }
2589 len += cend;
2590 }
2591 strings = scm_ilength (ls);
2592 /* Validate the string list. */
2593 if (strings < 0)
2594 SCM_WRONG_TYPE_ARG (1, ls);
2595
2596 /* Calculate the length of the result string. */
2597 tmp = ls;
2598 while (!SCM_NULLP (tmp))
2599 {
2600 SCM elt = SCM_CAR (tmp);
2601 SCM_VALIDATE_STRING (1, elt);
2602 len += scm_i_string_length (elt);
2603 tmp = SCM_CDR (tmp);
2604 }
2605
2606 result = scm_i_make_string (len, &p);
2607
2608 p += len;
2609
2610 /* Construct the result string, possibly by using the optional final
2611 string. */
2612 if (!SCM_UNBNDP (final_string))
2613 {
2614 p -= cend;
2615 memmove (p, scm_i_string_chars (final_string), cend);
2616 }
2617 tmp = ls;
2618 while (!SCM_NULLP (tmp))
2619 {
2620 SCM elt = SCM_CAR (tmp);
2621 p -= scm_i_string_length (elt);
2622 memmove (p, scm_i_string_chars (elt),
2623 scm_i_string_length (elt));
2624 tmp = SCM_CDR (tmp);
2625 }
2626 return result;
2627 }
2628 #undef FUNC_NAME
2629
2630
2631 SCM_DEFINE (scm_string_concatenate_shared, "string-concatenate/shared", 1, 0, 0,
2632 (SCM ls),
2633 "Like @code{string-concatenate}, but the result may share memory\n"
2634 "with the strings in the list @var{ls}.")
2635 #define FUNC_NAME s_scm_string_concatenate_shared
2636 {
2637 return scm_string_append_shared (ls);
2638 }
2639 #undef FUNC_NAME
2640
2641
2642 SCM_DEFINE (scm_string_concatenate_reverse_shared, "string-concatenate-reverse/shared", 1, 2, 0,
2643 (SCM ls, SCM final_string, SCM end),
2644 "Like @code{string-concatenate-reverse}, but the result may\n"
2645 "share memory with the the strings in the @var{ls} arguments.")
2646 #define FUNC_NAME s_scm_string_concatenate_reverse_shared
2647 {
2648 /* Just call the non-sharing version. */
2649 return scm_string_concatenate_reverse (ls, final_string, end);
2650 }
2651 #undef FUNC_NAME
2652
2653
2654 SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0,
2655 (SCM proc, SCM s, SCM start, SCM end),
2656 "@var{proc} is a char->char procedure, it is mapped over\n"
2657 "@var{s}. The order in which the procedure is applied to the\n"
2658 "string elements is not specified.")
2659 #define FUNC_NAME s_scm_string_map
2660 {
2661 const char *cstr;
2662 char *p;
2663 size_t cstart, cend;
2664 SCM result;
2665
2666 SCM_VALIDATE_PROC (1, proc);
2667 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2668 3, start, cstart,
2669 4, end, cend);
2670 result = scm_i_make_string (cend - cstart, &p);
2671 while (cstart < cend)
2672 {
2673 unsigned int c = (unsigned char) cstr[cstart];
2674 SCM ch = scm_call_1 (proc, SCM_MAKE_CHAR (c));
2675 if (!SCM_CHARP (ch))
2676 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
2677 cstr = scm_i_string_chars (s);
2678 cstart++;
2679 *p++ = SCM_CHAR (ch);
2680 }
2681 return result;
2682 }
2683 #undef FUNC_NAME
2684
2685
2686 SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0,
2687 (SCM proc, SCM s, SCM start, SCM end),
2688 "@var{proc} is a char->char procedure, it is mapped over\n"
2689 "@var{s}. The order in which the procedure is applied to the\n"
2690 "string elements is not specified. The string @var{s} is\n"
2691 "modified in-place, the return value is not specified.")
2692 #define FUNC_NAME s_scm_string_map_x
2693 {
2694 size_t cstart, cend;
2695
2696 SCM_VALIDATE_PROC (1, proc);
2697 MY_VALIDATE_SUBSTRING_SPEC (2, s,
2698 3, start, cstart,
2699 4, end, cend);
2700 while (cstart < cend)
2701 {
2702 SCM ch = scm_call_1 (proc, scm_c_string_ref (s, cstart));
2703 if (!SCM_CHARP (ch))
2704 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
2705 scm_c_string_set_x (s, cstart, ch);
2706 cstart++;
2707 }
2708 return SCM_UNSPECIFIED;
2709 }
2710 #undef FUNC_NAME
2711
2712
2713 SCM_DEFINE (scm_string_fold, "string-fold", 3, 2, 0,
2714 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2715 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2716 "as the terminating element, from left to right. @var{kons}\n"
2717 "must expect two arguments: The actual character and the last\n"
2718 "result of @var{kons}' application.")
2719 #define FUNC_NAME s_scm_string_fold
2720 {
2721 const char *cstr;
2722 size_t cstart, cend;
2723 SCM result;
2724
2725 SCM_VALIDATE_PROC (1, kons);
2726 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2727 4, start, cstart,
2728 5, end, cend);
2729 result = knil;
2730 while (cstart < cend)
2731 {
2732 unsigned int c = (unsigned char) cstr[cstart];
2733 result = scm_call_2 (kons, SCM_MAKE_CHAR (c), result);
2734 cstr = scm_i_string_chars (s);
2735 cstart++;
2736 }
2737 return result;
2738 }
2739 #undef FUNC_NAME
2740
2741
2742 SCM_DEFINE (scm_string_fold_right, "string-fold-right", 3, 2, 0,
2743 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2744 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2745 "as the terminating element, from right to left. @var{kons}\n"
2746 "must expect two arguments: The actual character and the last\n"
2747 "result of @var{kons}' application.")
2748 #define FUNC_NAME s_scm_string_fold_right
2749 {
2750 const char *cstr;
2751 size_t cstart, cend;
2752 SCM result;
2753
2754 SCM_VALIDATE_PROC (1, kons);
2755 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2756 4, start, cstart,
2757 5, end, cend);
2758 result = knil;
2759 while (cstart < cend)
2760 {
2761 unsigned int c = (unsigned char) cstr[cend - 1];
2762 result = scm_call_2 (kons, SCM_MAKE_CHAR (c), result);
2763 cstr = scm_i_string_chars (s);
2764 cend--;
2765 }
2766 return result;
2767 }
2768 #undef FUNC_NAME
2769
2770
2771 SCM_DEFINE (scm_string_unfold, "string-unfold", 4, 2, 0,
2772 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2773 "@itemize @bullet\n"
2774 "@item @var{g} is used to generate a series of @emph{seed}\n"
2775 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2776 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2777 "@dots{}\n"
2778 "@item @var{p} tells us when to stop -- when it returns true\n"
2779 "when applied to one of these seed values.\n"
2780 "@item @var{f} maps each seed value to the corresponding\n"
2781 "character in the result string. These chars are assembled\n"
2782 "into the string in a left-to-right order.\n"
2783 "@item @var{base} is the optional initial/leftmost portion\n"
2784 "of the constructed string; it default to the empty\n"
2785 "string.\n"
2786 "@item @var{make_final} is applied to the terminal seed\n"
2787 "value (on which @var{p} returns true) to produce\n"
2788 "the final/rightmost portion of the constructed string.\n"
2789 "It defaults to @code{(lambda (x) "")}.\n"
2790 "@end itemize")
2791 #define FUNC_NAME s_scm_string_unfold
2792 {
2793 SCM res, ans;
2794
2795 SCM_VALIDATE_PROC (1, p);
2796 SCM_VALIDATE_PROC (2, f);
2797 SCM_VALIDATE_PROC (3, g);
2798 if (!SCM_UNBNDP (base))
2799 {
2800 SCM_VALIDATE_STRING (5, base);
2801 ans = base;
2802 }
2803 else
2804 ans = scm_i_make_string (0, NULL);
2805 if (!SCM_UNBNDP (make_final))
2806 SCM_VALIDATE_PROC (6, make_final);
2807
2808 res = scm_call_1 (p, seed);
2809 while (scm_is_false (res))
2810 {
2811 SCM str;
2812 char *ptr;
2813 SCM ch = scm_call_1 (f, seed);
2814 if (!SCM_CHARP (ch))
2815 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
2816 str = scm_i_make_string (1, &ptr);
2817 *ptr = SCM_CHAR (ch);
2818
2819 ans = scm_string_append (scm_list_2 (ans, str));
2820 seed = scm_call_1 (g, seed);
2821 res = scm_call_1 (p, seed);
2822 }
2823 if (!SCM_UNBNDP (make_final))
2824 {
2825 res = scm_call_1 (make_final, seed);
2826 return scm_string_append (scm_list_2 (ans, res));
2827 }
2828 else
2829 return ans;
2830 }
2831 #undef FUNC_NAME
2832
2833
2834 SCM_DEFINE (scm_string_unfold_right, "string-unfold-right", 4, 2, 0,
2835 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2836 "@itemize @bullet\n"
2837 "@item @var{g} is used to generate a series of @emph{seed}\n"
2838 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2839 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2840 "@dots{}\n"
2841 "@item @var{p} tells us when to stop -- when it returns true\n"
2842 "when applied to one of these seed values.\n"
2843 "@item @var{f} maps each seed value to the corresponding\n"
2844 "character in the result string. These chars are assembled\n"
2845 "into the string in a right-to-left order.\n"
2846 "@item @var{base} is the optional initial/rightmost portion\n"
2847 "of the constructed string; it default to the empty\n"
2848 "string.\n"
2849 "@item @var{make_final} is applied to the terminal seed\n"
2850 "value (on which @var{p} returns true) to produce\n"
2851 "the final/leftmost portion of the constructed string.\n"
2852 "It defaults to @code{(lambda (x) "")}.\n"
2853 "@end itemize")
2854 #define FUNC_NAME s_scm_string_unfold_right
2855 {
2856 SCM res, ans;
2857
2858 SCM_VALIDATE_PROC (1, p);
2859 SCM_VALIDATE_PROC (2, f);
2860 SCM_VALIDATE_PROC (3, g);
2861 if (!SCM_UNBNDP (base))
2862 {
2863 SCM_VALIDATE_STRING (5, base);
2864 ans = base;
2865 }
2866 else
2867 ans = scm_i_make_string (0, NULL);
2868 if (!SCM_UNBNDP (make_final))
2869 SCM_VALIDATE_PROC (6, make_final);
2870
2871 res = scm_call_1 (p, seed);
2872 while (scm_is_false (res))
2873 {
2874 SCM str;
2875 char *ptr;
2876 SCM ch = scm_call_1 (f, seed);
2877 if (!SCM_CHARP (ch))
2878 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
2879 str = scm_i_make_string (1, &ptr);
2880 *ptr = SCM_CHAR (ch);
2881
2882 ans = scm_string_append (scm_list_2 (str, ans));
2883 seed = scm_call_1 (g, seed);
2884 res = scm_call_1 (p, seed);
2885 }
2886 if (!SCM_UNBNDP (make_final))
2887 {
2888 res = scm_call_1 (make_final, seed);
2889 return scm_string_append (scm_list_2 (res, ans));
2890 }
2891 else
2892 return ans;
2893 }
2894 #undef FUNC_NAME
2895
2896
2897 SCM_DEFINE (scm_string_for_each, "string-for-each", 2, 2, 0,
2898 (SCM proc, SCM s, SCM start, SCM end),
2899 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
2900 "return value is not specified.")
2901 #define FUNC_NAME s_scm_string_for_each
2902 {
2903 const char *cstr;
2904 size_t cstart, cend;
2905
2906 SCM_VALIDATE_PROC (1, proc);
2907 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2908 3, start, cstart,
2909 4, end, cend);
2910 while (cstart < cend)
2911 {
2912 unsigned int c = (unsigned char) cstr[cstart];
2913 scm_call_1 (proc, SCM_MAKE_CHAR (c));
2914 cstr = scm_i_string_chars (s);
2915 cstart++;
2916 }
2917 return SCM_UNSPECIFIED;
2918 }
2919 #undef FUNC_NAME
2920
2921 SCM_DEFINE (scm_string_for_each_index, "string-for-each-index", 2, 2, 0,
2922 (SCM proc, SCM s, SCM start, SCM end),
2923 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
2924 "return value is not specified.")
2925 #define FUNC_NAME s_scm_string_for_each_index
2926 {
2927 const char *cstr;
2928 size_t cstart, cend;
2929
2930 SCM_VALIDATE_PROC (1, proc);
2931 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2932 3, start, cstart,
2933 4, end, cend);
2934 while (cstart < cend)
2935 {
2936 scm_call_1 (proc, scm_from_size_t (cstart));
2937 cstart++;
2938 }
2939 return SCM_UNSPECIFIED;
2940 }
2941 #undef FUNC_NAME
2942
2943 SCM_DEFINE (scm_xsubstring, "xsubstring", 2, 3, 0,
2944 (SCM s, SCM from, SCM to, SCM start, SCM end),
2945 "This is the @emph{extended substring} procedure that implements\n"
2946 "replicated copying of a substring of some string.\n"
2947 "\n"
2948 "@var{s} is a string, @var{start} and @var{end} are optional\n"
2949 "arguments that demarcate a substring of @var{s}, defaulting to\n"
2950 "0 and the length of @var{s}. Replicate this substring up and\n"
2951 "down index space, in both the positive and negative directions.\n"
2952 "@code{xsubstring} returns the substring of this string\n"
2953 "beginning at index @var{from}, and ending at @var{to}, which\n"
2954 "defaults to @var{from} + (@var{end} - @var{start}).")
2955 #define FUNC_NAME s_scm_xsubstring
2956 {
2957 const char *cs;
2958 char *p;
2959 size_t cstart, cend, cfrom, cto;
2960 SCM result;
2961
2962 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cs,
2963 4, start, cstart,
2964 5, end, cend);
2965 cfrom = scm_to_size_t (from);
2966 if (SCM_UNBNDP (to))
2967 cto = cfrom + (cend - cstart);
2968 else
2969 cto = scm_to_size_t (to);
2970 if (cstart == cend && cfrom != cto)
2971 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
2972
2973 result = scm_i_make_string (cto - cfrom, &p);
2974
2975 while (cfrom < cto)
2976 {
2977 int t = ((cfrom < 0) ? -cfrom : cfrom) % (cend - cstart);
2978 if (cfrom < 0)
2979 *p = cs[(cend - cstart) - t];
2980 else
2981 *p = cs[t];
2982 cfrom++;
2983 p++;
2984 }
2985 scm_remember_upto_here_1 (s);
2986 return result;
2987 }
2988 #undef FUNC_NAME
2989
2990
2991 SCM_DEFINE (scm_string_xcopy_x, "string-xcopy!", 4, 3, 0,
2992 (SCM target, SCM tstart, SCM s, SCM sfrom, SCM sto, SCM start, SCM end),
2993 "Exactly the same as @code{xsubstring}, but the extracted text\n"
2994 "is written into the string @var{target} starting at index\n"
2995 "@var{tstart}. The operation is not defined if @code{(eq?\n"
2996 "@var{target} @var{s})} or these arguments share storage -- you\n"
2997 "cannot copy a string on top of itself.")
2998 #define FUNC_NAME s_scm_string_xcopy_x
2999 {
3000 char *p;
3001 const char *cs;
3002 size_t ctstart, csfrom, csto, cstart, cend;
3003 SCM dummy = SCM_UNDEFINED;
3004 int cdummy;
3005
3006 MY_VALIDATE_SUBSTRING_SPEC (1, target,
3007 2, tstart, ctstart,
3008 2, dummy, cdummy);
3009 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cs,
3010 6, start, cstart,
3011 7, end, cend);
3012 csfrom = scm_to_size_t (sfrom);
3013 if (SCM_UNBNDP (sto))
3014 csto = csfrom + (cend - cstart);
3015 else
3016 csto = scm_to_size_t (sto);
3017 if (cstart == cend && csfrom != csto)
3018 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
3019 SCM_ASSERT_RANGE (1, tstart,
3020 ctstart + (csto - csfrom) <= scm_i_string_length (target));
3021
3022 p = scm_i_string_writable_chars (target) + ctstart;
3023 while (csfrom < csto)
3024 {
3025 int t = ((csfrom < 0) ? -csfrom : csfrom) % (cend - cstart);
3026 if (csfrom < 0)
3027 *p = cs[(cend - cstart) - t];
3028 else
3029 *p = cs[t];
3030 csfrom++;
3031 p++;
3032 }
3033 scm_i_string_stop_writing ();
3034
3035 scm_remember_upto_here_2 (target, s);
3036 return SCM_UNSPECIFIED;
3037 }
3038 #undef FUNC_NAME
3039
3040
3041 SCM_DEFINE (scm_string_replace, "string-replace", 2, 4, 0,
3042 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
3043 "Return the string @var{s1}, but with the characters\n"
3044 "@var{start1} @dots{} @var{end1} replaced by the characters\n"
3045 "@var{start2} @dots{} @var{end2} from @var{s2}.")
3046 #define FUNC_NAME s_scm_string_replace
3047 {
3048 const char *cstr1, *cstr2;
3049 char *p;
3050 size_t cstart1, cend1, cstart2, cend2;
3051 SCM result;
3052
3053 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
3054 3, start1, cstart1,
3055 4, end1, cend1);
3056 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
3057 5, start2, cstart2,
3058 6, end2, cend2);
3059 result = scm_i_make_string (cstart1 + (cend2 - cstart2) +
3060 scm_i_string_length (s1) - cend1, &p);
3061 memmove (p, cstr1, cstart1 * sizeof (char));
3062 memmove (p + cstart1, cstr2 + cstart2, (cend2 - cstart2) * sizeof (char));
3063 memmove (p + cstart1 + (cend2 - cstart2),
3064 cstr1 + cend1,
3065 (scm_i_string_length (s1) - cend1) * sizeof (char));
3066 scm_remember_upto_here_2 (s1, s2);
3067 return result;
3068 }
3069 #undef FUNC_NAME
3070
3071
3072 SCM_DEFINE (scm_string_tokenize, "string-tokenize", 1, 3, 0,
3073 (SCM s, SCM token_set, SCM start, SCM end),
3074 "Split the string @var{s} into a list of substrings, where each\n"
3075 "substring is a maximal non-empty contiguous sequence of\n"
3076 "characters from the character set @var{token_set}, which\n"
3077 "defaults to @code{char-set:graphic}.\n"
3078 "If @var{start} or @var{end} indices are provided, they restrict\n"
3079 "@code{string-tokenize} to operating on the indicated substring\n"
3080 "of @var{s}.")
3081 #define FUNC_NAME s_scm_string_tokenize
3082 {
3083 const char *cstr;
3084 size_t cstart, cend;
3085 SCM result = SCM_EOL;
3086
3087 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
3088 3, start, cstart,
3089 4, end, cend);
3090
3091 if (SCM_UNBNDP (token_set))
3092 token_set = scm_char_set_graphic;
3093
3094 if (SCM_CHARSETP (token_set))
3095 {
3096 int idx;
3097
3098 while (cstart < cend)
3099 {
3100 while (cstart < cend)
3101 {
3102 if (SCM_CHARSET_GET (token_set, cstr[cend - 1]))
3103 break;
3104 cend--;
3105 }
3106 if (cstart >= cend)
3107 break;
3108 idx = cend;
3109 while (cstart < cend)
3110 {
3111 if (!SCM_CHARSET_GET (token_set, cstr[cend - 1]))
3112 break;
3113 cend--;
3114 }
3115 result = scm_cons (scm_c_substring (s, cend, idx), result);
3116 cstr = scm_i_string_chars (s);
3117 }
3118 }
3119 else SCM_WRONG_TYPE_ARG (2, token_set);
3120 scm_remember_upto_here_1 (s);
3121 return result;
3122 }
3123 #undef FUNC_NAME
3124
3125 SCM_DEFINE (scm_string_split, "string-split", 2, 0, 0,
3126 (SCM str, SCM chr),
3127 "Split the string @var{str} into the a list of the substrings delimited\n"
3128 "by appearances of the character @var{chr}. Note that an empty substring\n"
3129 "between separator characters will result in an empty string in the\n"
3130 "result list.\n"
3131 "\n"
3132 "@lisp\n"
3133 "(string-split \"root:x:0:0:root:/root:/bin/bash\" #\\:)\n"
3134 "@result{}\n"
3135 "(\"root\" \"x\" \"0\" \"0\" \"root\" \"/root\" \"/bin/bash\")\n"
3136 "\n"
3137 "(string-split \"::\" #\\:)\n"
3138 "@result{}\n"
3139 "(\"\" \"\" \"\")\n"
3140 "\n"
3141 "(string-split \"\" #\\:)\n"
3142 "@result{}\n"
3143 "(\"\")\n"
3144 "@end lisp")
3145 #define FUNC_NAME s_scm_string_split
3146 {
3147 long idx, last_idx;
3148 const char * p;
3149 int ch;
3150 SCM res = SCM_EOL;
3151
3152 SCM_VALIDATE_STRING (1, str);
3153 SCM_VALIDATE_CHAR (2, chr);
3154
3155 idx = scm_i_string_length (str);
3156 p = scm_i_string_chars (str);
3157 ch = SCM_CHAR (chr);
3158 while (idx >= 0)
3159 {
3160 last_idx = idx;
3161 while (idx > 0 && p[idx - 1] != ch)
3162 idx--;
3163 if (idx >= 0)
3164 {
3165 res = scm_cons (scm_c_substring (str, idx, last_idx), res);
3166 p = scm_i_string_chars (str);
3167 idx--;
3168 }
3169 }
3170 scm_remember_upto_here_1 (str);
3171 return res;
3172 }
3173 #undef FUNC_NAME
3174
3175
3176 SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
3177 (SCM s, SCM char_pred, SCM start, SCM end),
3178 "Filter the string @var{s}, retaining only those characters that\n"
3179 "satisfy the @var{char_pred} argument. If the argument is a\n"
3180 "procedure, it is applied to each character as a predicate, if\n"
3181 "it is a character, it is tested for equality and if it is a\n"
3182 "character set, it is tested for membership.")
3183 #define FUNC_NAME s_scm_string_filter
3184 {
3185 const char *cstr;
3186 size_t cstart, cend;
3187 SCM result;
3188 size_t idx;
3189
3190 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
3191 3, start, cstart,
3192 4, end, cend);
3193 if (SCM_CHARP (char_pred))
3194 {
3195 SCM ls = SCM_EOL;
3196 char chr;
3197
3198 chr = SCM_CHAR (char_pred);
3199 idx = cstart;
3200 while (idx < cend)
3201 {
3202 if (cstr[idx] == chr)
3203 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3204 cstr = scm_i_string_chars (s);
3205 idx++;
3206 }
3207 result = scm_reverse_list_to_string (ls);
3208 }
3209 else if (SCM_CHARSETP (char_pred))
3210 {
3211 SCM ls = SCM_EOL;
3212
3213 idx = cstart;
3214 while (idx < cend)
3215 {
3216 if (SCM_CHARSET_GET (char_pred, cstr[idx]))
3217 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3218 cstr = scm_i_string_chars (s);
3219 idx++;
3220 }
3221 result = scm_reverse_list_to_string (ls);
3222 }
3223 else
3224 {
3225 SCM ls = SCM_EOL;
3226
3227 SCM_VALIDATE_PROC (2, char_pred);
3228 idx = cstart;
3229 while (idx < cend)
3230 {
3231 SCM res;
3232 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[idx]));
3233 if (scm_is_true (res))
3234 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3235 cstr = scm_i_string_chars (s);
3236 idx++;
3237 }
3238 result = scm_reverse_list_to_string (ls);
3239 }
3240 scm_remember_upto_here_1 (s);
3241 return result;
3242 }
3243 #undef FUNC_NAME
3244
3245
3246 SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
3247 (SCM s, SCM char_pred, SCM start, SCM end),
3248 "Filter the string @var{s}, retaining only those characters that\n"
3249 "do not satisfy the @var{char_pred} argument. If the argument\n"
3250 "is a procedure, it is applied to each character as a predicate,\n"
3251 "if it is a character, it is tested for equality and if it is a\n"
3252 "character set, it is tested for membership.")
3253 #define FUNC_NAME s_scm_string_delete
3254 {
3255 const char *cstr;
3256 size_t cstart, cend;
3257 SCM result;
3258 size_t idx;
3259
3260 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
3261 3, start, cstart,
3262 4, end, cend);
3263 if (SCM_CHARP (char_pred))
3264 {
3265 SCM ls = SCM_EOL;
3266 char chr;
3267
3268 chr = SCM_CHAR (char_pred);
3269 idx = cstart;
3270 while (idx < cend)
3271 {
3272 if (cstr[idx] != chr)
3273 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3274 cstr = scm_i_string_chars (s);
3275 idx++;
3276 }
3277 result = scm_reverse_list_to_string (ls);
3278 }
3279 else if (SCM_CHARSETP (char_pred))
3280 {
3281 SCM ls = SCM_EOL;
3282
3283 idx = cstart;
3284 while (idx < cend)
3285 {
3286 if (!SCM_CHARSET_GET (char_pred, cstr[idx]))
3287 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3288 cstr = scm_i_string_chars (s);
3289 idx++;
3290 }
3291 result = scm_reverse_list_to_string (ls);
3292 }
3293 else
3294 {
3295 SCM ls = SCM_EOL;
3296
3297 SCM_VALIDATE_PROC (2, char_pred);
3298 idx = cstart;
3299 while (idx < cend)
3300 {
3301 SCM res;
3302 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[idx]));
3303 if (scm_is_false (res))
3304 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3305 cstr = scm_i_string_chars (s);
3306 idx++;
3307 }
3308 result = scm_reverse_list_to_string (ls);
3309 }
3310 return result;
3311 }
3312 #undef FUNC_NAME
3313
3314
3315 /* Initialize the SRFI-13 module. This function will be called by the
3316 loading Scheme module. */
3317 void
3318 scm_init_srfi_13 (void)
3319 {
3320 #include "libguile/srfi-13.x"
3321 }
3322
3323 /* End of srfi-13.c. */