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