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