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