1 /* srfi-13.c --- SRFI-13 procedures for Guile
3 * Copyright (C) 2001, 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
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.
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.
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
31 #include "libguile/srfi-13.h"
32 #include "libguile/srfi-14.h"
34 /* SCM_VALIDATE_SUBSTRING_SPEC_COPY is deprecated since it encourages
35 messing with the internal representation of strings. We define our
36 own version since we use it so much and are messing with Guile
40 #define MY_VALIDATE_SUBSTRING_SPEC_COPY(pos_str, str, c_str, \
41 pos_start, start, c_start, \
42 pos_end, end, c_end) \
44 SCM_VALIDATE_STRING (pos_str, str); \
45 c_str = scm_i_string_chars (str); \
46 scm_i_get_substring_spec (scm_i_string_length (str), \
47 start, &c_start, end, &c_end); \
50 /* Expecting "unsigned char *c_str" */
51 #define MY_VALIDATE_SUBSTRING_SPEC_UCOPY(pos_str, str, c_str, \
52 pos_start, start, c_start, \
53 pos_end, end, c_end) \
55 const char *signed_c_str; \
56 MY_VALIDATE_SUBSTRING_SPEC_COPY(pos_str, str, signed_c_str, \
57 pos_start, start, c_start, \
58 pos_end, end, c_end); \
59 c_str = (unsigned char *) signed_c_str; \
62 #define MY_VALIDATE_SUBSTRING_SPEC(pos_str, str, \
63 pos_start, start, c_start, \
64 pos_end, end, c_end) \
66 SCM_VALIDATE_STRING (pos_str, str); \
67 scm_i_get_substring_spec (scm_i_string_length (str), \
68 start, &c_start, end, &c_end); \
71 SCM_DEFINE (scm_string_null_p
, "string-null?", 1, 0, 0,
73 "Return @code{#t} if @var{str}'s length is zero, and\n"
74 "@code{#f} otherwise.\n"
76 "(string-null? \"\") @result{} #t\n"
77 "y @result{} \"foo\"\n"
78 "(string-null? y) @result{} #f\n"
80 #define FUNC_NAME s_scm_string_null_p
82 SCM_VALIDATE_STRING (1, str
);
83 return scm_from_bool (scm_i_string_length (str
) == 0);
91 scm_misc_error (NULL
, "race condition detected", SCM_EOL
);
95 SCM_DEFINE (scm_string_any
, "string-any-c-code", 2, 2, 0,
96 (SCM char_pred
, SCM s
, SCM start
, SCM end
),
97 "Check if @var{char_pred} is true for any character in string @var{s}.\n"
99 "@var{char_pred} can be a character to check for any equal to that, or\n"
100 "a character set (@pxref{Character Sets}) to check for any in that set,\n"
101 "or a predicate procedure to call.\n"
103 "For a procedure, calls @code{(@var{char_pred} c)} are made\n"
104 "successively on the characters from @var{start} to @var{end}. If\n"
105 "@var{char_pred} returns true (ie.@: non-@code{#f}), @code{string-any}\n"
106 "stops and that return value is the return from @code{string-any}. The\n"
107 "call on the last character (ie.@: at @math{@var{end}-1}), if that\n"
108 "point is reached, is a tail call.\n"
110 "If there are no characters in @var{s} (ie.@: @var{start} equals\n"
111 "@var{end}) then the return is @code{#f}.\n")
112 #define FUNC_NAME s_scm_string_any
116 SCM res
= SCM_BOOL_F
;
118 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s
, cstr
,
122 if (SCM_CHARP (char_pred
))
124 res
= (memchr (cstr
+cstart
, (int) SCM_CHAR (char_pred
),
126 ? SCM_BOOL_F
: SCM_BOOL_T
);
128 else if (SCM_CHARSETP (char_pred
))
131 for (i
= cstart
; i
< cend
; i
++)
132 if (SCM_CHARSET_GET (char_pred
, cstr
[i
]))
140 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
141 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG1
, FUNC_NAME
);
143 while (cstart
< cend
)
145 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
146 if (scm_is_true (res
))
148 cstr
= scm_i_string_chars (s
);
153 scm_remember_upto_here_1 (s
);
159 SCM_DEFINE (scm_string_every
, "string-every-c-code", 2, 2, 0,
160 (SCM char_pred
, SCM s
, SCM start
, SCM end
),
161 "Check if @var{char_pred} is true for every character in string\n"
164 "@var{char_pred} can be a character to check for every character equal\n"
165 "to that, or a character set (@pxref{Character Sets}) to check for\n"
166 "every character being in that set, or a predicate procedure to call.\n"
168 "For a procedure, calls @code{(@var{char_pred} c)} are made\n"
169 "successively on the characters from @var{start} to @var{end}. If\n"
170 "@var{char_pred} returns @code{#f}, @code{string-every} stops and\n"
171 "returns @code{#f}. The call on the last character (ie.@: at\n"
172 "@math{@var{end}-1}), if that point is reached, is a tail call and the\n"
173 "return from that call is the return from @code{string-every}.\n"
175 "If there are no characters in @var{s} (ie.@: @var{start} equals\n"
176 "@var{end}) then the return is @code{#t}.\n")
177 #define FUNC_NAME s_scm_string_every
181 SCM res
= SCM_BOOL_T
;
183 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s
, cstr
,
186 if (SCM_CHARP (char_pred
))
188 char cchr
= SCM_CHAR (char_pred
);
190 for (i
= cstart
; i
< cend
; i
++)
197 else if (SCM_CHARSETP (char_pred
))
200 for (i
= cstart
; i
< cend
; i
++)
201 if (!SCM_CHARSET_GET (char_pred
, cstr
[i
]))
209 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
210 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG1
, FUNC_NAME
);
212 while (cstart
< cend
)
214 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
215 if (scm_is_false (res
))
217 cstr
= scm_i_string_chars (s
);
222 scm_remember_upto_here_1 (s
);
228 SCM_DEFINE (scm_string_tabulate
, "string-tabulate", 2, 0, 0,
230 "@var{proc} is an integer->char procedure. Construct a string\n"
231 "of size @var{len} by applying @var{proc} to each index to\n"
232 "produce the corresponding string element. The order in which\n"
233 "@var{proc} is applied to the indices is not specified.")
234 #define FUNC_NAME s_scm_string_tabulate
240 scm_t_trampoline_1 proc_tramp
;
242 proc_tramp
= scm_trampoline_1 (proc
);
243 SCM_ASSERT (proc_tramp
, proc
, SCM_ARG1
, FUNC_NAME
);
245 clen
= scm_to_size_t (len
);
246 SCM_ASSERT_RANGE (2, len
, clen
>= 0);
248 res
= scm_i_make_string (clen
, &p
);
252 /* The RES string remains untouched since nobody knows about it
253 yet. No need to refetch P.
255 ch
= proc_tramp (proc
, scm_from_size_t (i
));
257 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc
));
258 *p
++ = SCM_CHAR (ch
);
266 SCM_DEFINE (scm_substring_to_list
, "string->list", 1, 2, 0,
267 (SCM str
, SCM start
, SCM end
),
268 "Convert the string @var{str} into a list of characters.")
269 #define FUNC_NAME s_scm_substring_to_list
273 SCM result
= SCM_EOL
;
275 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
278 while (cstart
< cend
)
281 result
= scm_cons (SCM_MAKE_CHAR (cstr
[cend
]), result
);
282 cstr
= scm_i_string_chars (str
);
284 scm_remember_upto_here_1 (str
);
289 /* We export scm_substring_to_list as "string->list" since it is
290 compatible and more general. This function remains for the benefit
291 of C code that used it.
295 scm_string_to_list (SCM str
)
297 return scm_substring_to_list (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
300 SCM_DEFINE (scm_reverse_list_to_string
, "reverse-list->string", 1, 0, 0,
302 "An efficient implementation of @code{(compose string->list\n"
306 "(reverse-list->string '(#\\a #\\B #\\c)) @result{} \"cBa\"\n"
308 #define FUNC_NAME s_scm_reverse_list_to_string
311 long i
= scm_ilength (chrs
);
315 SCM_WRONG_TYPE_ARG (1, chrs
);
316 result
= scm_i_make_string (i
, &data
);
321 while (i
> 0 && scm_is_pair (chrs
))
323 SCM elt
= SCM_CAR (chrs
);
325 SCM_VALIDATE_CHAR (SCM_ARGn
, elt
);
327 *data
= SCM_CHAR (elt
);
328 chrs
= SCM_CDR (chrs
);
338 SCM_SYMBOL (scm_sym_infix
, "infix");
339 SCM_SYMBOL (scm_sym_strict_infix
, "strict-infix");
340 SCM_SYMBOL (scm_sym_suffix
, "suffix");
341 SCM_SYMBOL (scm_sym_prefix
, "prefix");
344 append_string (char **sp
, size_t *lp
, SCM str
)
347 len
= scm_c_string_length (str
);
350 memcpy (*sp
, scm_i_string_chars (str
), len
);
355 SCM_DEFINE (scm_string_join
, "string-join", 1, 2, 0,
356 (SCM ls
, SCM delimiter
, SCM grammar
),
357 "Append the string in the string list @var{ls}, using the string\n"
358 "@var{delim} as a delimiter between the elements of @var{ls}.\n"
359 "@var{grammar} is a symbol which specifies how the delimiter is\n"
360 "placed between the strings, and defaults to the symbol\n"
365 "Insert the separator between list elements. An empty string\n"
366 "will produce an empty list.\n"
367 "@item string-infix\n"
368 "Like @code{infix}, but will raise an error if given the empty\n"
371 "Insert the separator after every list element.\n"
373 "Insert the separator before each list element.\n"
375 #define FUNC_NAME s_scm_string_join
378 #define GRAM_STRICT_INFIX 1
379 #define GRAM_SUFFIX 2
380 #define GRAM_PREFIX 3
383 int gram
= GRAM_INFIX
;
387 long strings
= scm_ilength (ls
);
389 /* Validate the string list. */
391 SCM_WRONG_TYPE_ARG (1, ls
);
393 /* Validate the delimiter and record its length. */
394 if (SCM_UNBNDP (delimiter
))
396 delimiter
= scm_from_locale_string (" ");
400 del_len
= scm_c_string_length (delimiter
);
402 /* Validate the grammar symbol and remember the grammar. */
403 if (SCM_UNBNDP (grammar
))
405 else if (scm_is_eq (grammar
, scm_sym_infix
))
407 else if (scm_is_eq (grammar
, scm_sym_strict_infix
))
408 gram
= GRAM_STRICT_INFIX
;
409 else if (scm_is_eq (grammar
, scm_sym_suffix
))
411 else if (scm_is_eq (grammar
, scm_sym_prefix
))
414 SCM_WRONG_TYPE_ARG (3, grammar
);
416 /* Check grammar constraints and calculate the space required for
421 if (!scm_is_null (ls
))
422 len
= (strings
> 0) ? ((strings
- 1) * del_len
) : 0;
424 case GRAM_STRICT_INFIX
:
426 SCM_MISC_ERROR ("strict-infix grammar requires non-empty list",
428 len
= (strings
- 1) * del_len
;
431 len
= strings
* del_len
;
436 while (scm_is_pair (tmp
))
438 len
+= scm_c_string_length (SCM_CAR (tmp
));
442 result
= scm_i_make_string (len
, &p
);
448 case GRAM_STRICT_INFIX
:
449 while (scm_is_pair (tmp
))
451 append_string (&p
, &len
, SCM_CAR (tmp
));
452 if (!scm_is_null (SCM_CDR (tmp
)) && del_len
> 0)
453 append_string (&p
, &len
, delimiter
);
458 while (scm_is_pair (tmp
))
460 append_string (&p
, &len
, SCM_CAR (tmp
));
462 append_string (&p
, &len
, delimiter
);
467 while (scm_is_pair (tmp
))
470 append_string (&p
, &len
, delimiter
);
471 append_string (&p
, &len
, SCM_CAR (tmp
));
479 #undef GRAM_STRICT_INFIX
486 /* There are a number of functions to consider here for Scheme and C:
488 string-copy STR [start [end]] ;; SRFI-13 variant of R5RS string-copy
489 substring/copy STR start [end] ;; Guile variant of R5RS substring
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
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
502 SCM
scm_srfi13_substring_copy (SCM str
, SCM start
, SCM end
);
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
514 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
517 return scm_c_substring_copy (str
, cstart
, cend
);
522 scm_string_copy (SCM str
)
524 return scm_c_substring (str
, 0, scm_c_string_length (str
));
527 SCM_DEFINE (scm_string_copy_x
, "string-copy!", 3, 2, 0,
528 (SCM target
, SCM tstart
, SCM s
, SCM start
, SCM end
),
529 "Copy the sequence of characters from index range [@var{start},\n"
530 "@var{end}) in string @var{s} to string @var{target}, beginning\n"
531 "at index @var{tstart}. The characters are copied left-to-right\n"
532 "or right-to-left as needed -- the copy is guaranteed to work,\n"
533 "even if @var{target} and @var{s} are the same string. It is an\n"
534 "error if the copy operation runs off the end of the target\n"
536 #define FUNC_NAME s_scm_string_copy_x
540 size_t cstart
, cend
, ctstart
, dummy
, len
;
541 SCM sdummy
= SCM_UNDEFINED
;
543 MY_VALIDATE_SUBSTRING_SPEC (1, target
,
546 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s
, cstr
,
550 SCM_ASSERT_RANGE (3, s
, len
<= scm_i_string_length (target
) - ctstart
);
552 ctarget
= scm_i_string_writable_chars (target
);
553 memmove (ctarget
+ ctstart
, cstr
+ cstart
, len
);
554 scm_i_string_stop_writing ();
555 scm_remember_upto_here_1 (target
);
557 return SCM_UNSPECIFIED
;
561 SCM_DEFINE (scm_substring_move_x
, "substring-move!", 5, 0, 0,
562 (SCM str1
, SCM start1
, SCM end1
, SCM str2
, SCM start2
),
563 "Copy the substring of @var{str1} bounded by @var{start1} and @var{end1}\n"
564 "into @var{str2} beginning at position @var{start2}.\n"
565 "@var{str1} and @var{str2} can be the same string.")
566 #define FUNC_NAME s_scm_substring_move_x
568 return scm_string_copy_x (str2
, start2
, str1
, start1
, end1
);
572 SCM_DEFINE (scm_string_take
, "string-take", 2, 0, 0,
574 "Return the @var{n} first characters of @var{s}.")
575 #define FUNC_NAME s_scm_string_take
577 return scm_substring (s
, SCM_INUM0
, n
);
582 SCM_DEFINE (scm_string_drop
, "string-drop", 2, 0, 0,
584 "Return all but the first @var{n} characters of @var{s}.")
585 #define FUNC_NAME s_scm_string_drop
587 return scm_substring (s
, n
, SCM_UNDEFINED
);
592 SCM_DEFINE (scm_string_take_right
, "string-take-right", 2, 0, 0,
594 "Return the @var{n} last characters of @var{s}.")
595 #define FUNC_NAME s_scm_string_take_right
597 return scm_substring (s
,
598 scm_difference (scm_string_length (s
), n
),
604 SCM_DEFINE (scm_string_drop_right
, "string-drop-right", 2, 0, 0,
606 "Return all but the last @var{n} characters of @var{s}.")
607 #define FUNC_NAME s_scm_string_drop_right
609 return scm_substring (s
,
611 scm_difference (scm_string_length (s
), n
));
616 SCM_DEFINE (scm_string_pad
, "string-pad", 2, 3, 0,
617 (SCM s
, SCM len
, SCM chr
, SCM start
, SCM end
),
618 "Take that characters from @var{start} to @var{end} from the\n"
619 "string @var{s} and return a new string, right-padded by the\n"
620 "character @var{chr} to length @var{len}. If the resulting\n"
621 "string is longer than @var{len}, it is truncated on the right.")
622 #define FUNC_NAME s_scm_string_pad
625 size_t cstart
, cend
, clen
;
627 MY_VALIDATE_SUBSTRING_SPEC (1, s
,
630 clen
= scm_to_size_t (len
);
632 if (SCM_UNBNDP (chr
))
636 SCM_VALIDATE_CHAR (3, chr
);
637 cchr
= SCM_CHAR (chr
);
639 if (clen
< (cend
- cstart
))
640 return scm_c_substring (s
, cend
- clen
, cend
);
646 result
= scm_i_make_string (clen
, &dst
);
647 memset (dst
, cchr
, (clen
- (cend
- cstart
)));
648 memmove (dst
+ clen
- (cend
- cstart
),
649 scm_i_string_chars (s
) + cstart
, cend
- cstart
);
656 SCM_DEFINE (scm_string_pad_right
, "string-pad-right", 2, 3, 0,
657 (SCM s
, SCM len
, SCM chr
, SCM start
, SCM end
),
658 "Take that characters from @var{start} to @var{end} from the\n"
659 "string @var{s} and return a new string, left-padded by the\n"
660 "character @var{chr} to length @var{len}. If the resulting\n"
661 "string is longer than @var{len}, it is truncated on the left.")
662 #define FUNC_NAME s_scm_string_pad_right
665 size_t cstart
, cend
, clen
;
667 MY_VALIDATE_SUBSTRING_SPEC (1, s
,
670 clen
= scm_to_size_t (len
);
672 if (SCM_UNBNDP (chr
))
676 SCM_VALIDATE_CHAR (3, chr
);
677 cchr
= SCM_CHAR (chr
);
679 if (clen
< (cend
- cstart
))
680 return scm_c_substring (s
, cstart
, cstart
+ clen
);
686 result
= scm_i_make_string (clen
, &dst
);
687 memset (dst
+ (cend
- cstart
), cchr
, clen
- (cend
- cstart
));
688 memmove (dst
, scm_i_string_chars (s
) + cstart
, cend
- cstart
);
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"
702 "if it is the character @var{ch}, characters equal to\n"
703 "@var{ch} are trimmed,\n"
706 "if it is a procedure @var{pred} characters that\n"
707 "satisfy @var{pred} are trimmed,\n"
710 "if it is a character set, characters in that set are trimmed.\n"
713 "If called without a @var{char_pred} argument, all whitespace is\n"
715 #define FUNC_NAME s_scm_string_trim
720 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
723 if (SCM_UNBNDP (char_pred
))
725 while (cstart
< cend
)
727 if (!isspace((int) (unsigned char) cstr
[cstart
]))
732 else if (SCM_CHARP (char_pred
))
734 char chr
= SCM_CHAR (char_pred
);
735 while (cstart
< cend
)
737 if (chr
!= cstr
[cstart
])
742 else if (SCM_CHARSETP (char_pred
))
744 while (cstart
< cend
)
746 if (!SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
753 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
754 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
756 while (cstart
< cend
)
760 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
761 if (scm_is_false (res
))
763 cstr
= scm_i_string_chars (s
);
767 return scm_c_substring (s
, cstart
, cend
);
772 SCM_DEFINE (scm_string_trim_right
, "string-trim-right", 1, 3, 0,
773 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
774 "Trim @var{s} by skipping over all characters on the rightt\n"
775 "that satisfy the parameter @var{char_pred}:\n"
779 "if it is the character @var{ch}, characters equal to @var{ch}\n"
783 "if it is a procedure @var{pred} characters that satisfy\n"
784 "@var{pred} are trimmed,\n"
787 "if it is a character sets, all characters in that set are\n"
791 "If called without a @var{char_pred} argument, all whitespace is\n"
793 #define FUNC_NAME s_scm_string_trim_right
798 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
801 if (SCM_UNBNDP (char_pred
))
803 while (cstart
< cend
)
805 if (!isspace((int) (unsigned char) cstr
[cend
- 1]))
810 else if (SCM_CHARP (char_pred
))
812 char chr
= SCM_CHAR (char_pred
);
813 while (cstart
< cend
)
815 if (chr
!= cstr
[cend
- 1])
820 else if (SCM_CHARSETP (char_pred
))
822 while (cstart
< cend
)
824 if (!SCM_CHARSET_GET (char_pred
, cstr
[cend
- 1]))
831 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
832 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
834 while (cstart
< cend
)
838 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cend
- 1]));
839 if (scm_is_false (res
))
841 cstr
= scm_i_string_chars (s
);
845 return scm_c_substring (s
, cstart
, cend
);
850 SCM_DEFINE (scm_string_trim_both
, "string-trim-both", 1, 3, 0,
851 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
852 "Trim @var{s} by skipping over all characters on both sides of\n"
853 "the string that satisfy the parameter @var{char_pred}:\n"
857 "if it is the character @var{ch}, characters equal to @var{ch}\n"
861 "if it is a procedure @var{pred} characters that satisfy\n"
862 "@var{pred} are trimmed,\n"
865 "if it is a character set, the characters in the set are\n"
869 "If called without a @var{char_pred} argument, all whitespace is\n"
871 #define FUNC_NAME s_scm_string_trim_both
876 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
879 if (SCM_UNBNDP (char_pred
))
881 while (cstart
< cend
)
883 if (!isspace((int) (unsigned char) cstr
[cstart
]))
887 while (cstart
< cend
)
889 if (!isspace((int) (unsigned char) cstr
[cend
- 1]))
894 else if (SCM_CHARP (char_pred
))
896 char chr
= SCM_CHAR (char_pred
);
897 while (cstart
< cend
)
899 if (chr
!= cstr
[cstart
])
903 while (cstart
< cend
)
905 if (chr
!= cstr
[cend
- 1])
910 else if (SCM_CHARSETP (char_pred
))
912 while (cstart
< cend
)
914 if (!SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
918 while (cstart
< cend
)
920 if (!SCM_CHARSET_GET (char_pred
, cstr
[cend
- 1]))
927 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
928 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
930 while (cstart
< cend
)
934 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
935 if (scm_is_false (res
))
937 cstr
= scm_i_string_chars (s
);
940 while (cstart
< cend
)
944 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cend
- 1]));
945 if (scm_is_false (res
))
947 cstr
= scm_i_string_chars (s
);
951 return scm_c_substring (s
, cstart
, cend
);
956 SCM_DEFINE (scm_substring_fill_x
, "string-fill!", 2, 2, 0,
957 (SCM str
, SCM chr
, SCM start
, SCM end
),
958 "Stores @var{chr} in every element of the given @var{str} and\n"
959 "returns an unspecified value.")
960 #define FUNC_NAME s_scm_substring_fill_x
967 /* Older versions of Guile provided the function
968 scm_substring_fill_x with the following order of arguments:
972 We accomodate this here by detecting such a usage and reordering
983 MY_VALIDATE_SUBSTRING_SPEC (1, str
,
986 SCM_VALIDATE_CHAR_COPY (2, chr
, c
);
988 cstr
= scm_i_string_writable_chars (str
);
989 for (k
= cstart
; k
< cend
; k
++)
991 scm_i_string_stop_writing ();
992 scm_remember_upto_here_1 (str
);
994 return SCM_UNSPECIFIED
;
999 scm_string_fill_x (SCM str
, SCM chr
)
1001 return scm_substring_fill_x (str
, chr
, SCM_UNDEFINED
, SCM_UNDEFINED
);
1004 SCM_DEFINE (scm_string_compare
, "string-compare", 5, 4, 0,
1005 (SCM s1
, SCM s2
, SCM proc_lt
, SCM proc_eq
, SCM proc_gt
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1006 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
1007 "mismatch index, depending upon whether @var{s1} is less than,\n"
1008 "equal to, or greater than @var{s2}. The mismatch index is the\n"
1009 "largest index @var{i} such that for every 0 <= @var{j} <\n"
1010 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
1011 "@var{i} is the first position that does not match.")
1012 #define FUNC_NAME s_scm_string_compare
1014 const unsigned char *cstr1
, *cstr2
;
1015 size_t cstart1
, cend1
, cstart2
, cend2
;
1018 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1021 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1024 SCM_VALIDATE_PROC (3, proc_lt
);
1025 SCM_VALIDATE_PROC (4, proc_eq
);
1026 SCM_VALIDATE_PROC (5, proc_gt
);
1028 while (cstart1
< cend1
&& cstart2
< cend2
)
1030 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1035 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1043 if (cstart1
< cend1
)
1045 else if (cstart2
< cend2
)
1051 scm_remember_upto_here_2 (s1
, s2
);
1052 return scm_call_1 (proc
, scm_from_size_t (cstart1
));
1057 SCM_DEFINE (scm_string_compare_ci
, "string-compare-ci", 5, 4, 0,
1058 (SCM s1
, SCM s2
, SCM proc_lt
, SCM proc_eq
, SCM proc_gt
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1059 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
1060 "mismatch index, depending upon whether @var{s1} is less than,\n"
1061 "equal to, or greater than @var{s2}. The mismatch index is the\n"
1062 "largest index @var{i} such that for every 0 <= @var{j} <\n"
1063 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
1064 "@var{i} is the first position that does not match. The\n"
1065 "character comparison is done case-insensitively.")
1066 #define FUNC_NAME s_scm_string_compare_ci
1068 const unsigned char *cstr1
, *cstr2
;
1069 size_t cstart1
, cend1
, cstart2
, cend2
;
1072 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1075 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1078 SCM_VALIDATE_PROC (3, proc_lt
);
1079 SCM_VALIDATE_PROC (4, proc_eq
);
1080 SCM_VALIDATE_PROC (5, proc_gt
);
1082 while (cstart1
< cend1
&& cstart2
< cend2
)
1084 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1089 else if (scm_c_downcase (cstr1
[cstart1
])
1090 > scm_c_downcase (cstr2
[cstart2
]))
1099 if (cstart1
< cend1
)
1101 else if (cstart2
< cend2
)
1107 scm_remember_upto_here (s1
, s2
);
1108 return scm_call_1 (proc
, scm_from_size_t (cstart1
));
1113 SCM_DEFINE (scm_string_eq
, "string=", 2, 4, 0,
1114 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1115 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
1117 #define FUNC_NAME s_scm_string_eq
1119 const char *cstr1
, *cstr2
;
1120 size_t cstart1
, cend1
, cstart2
, cend2
;
1122 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1125 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1129 if ((cend1
- cstart1
) != (cend2
- cstart2
))
1132 while (cstart1
< cend1
)
1134 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1136 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1142 scm_remember_upto_here_2 (s1
, s2
);
1143 return scm_from_size_t (cstart1
);
1146 scm_remember_upto_here_2 (s1
, s2
);
1152 SCM_DEFINE (scm_string_neq
, "string<>", 2, 4, 0,
1153 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1154 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
1156 #define FUNC_NAME s_scm_string_neq
1158 const char *cstr1
, *cstr2
;
1159 size_t cstart1
, cend1
, cstart2
, cend2
;
1161 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1164 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1168 while (cstart1
< cend1
&& cstart2
< cend2
)
1170 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1172 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1177 if (cstart1
< cend1
)
1179 else if (cstart2
< cend2
)
1185 scm_remember_upto_here_2 (s1
, s2
);
1186 return scm_from_size_t (cstart1
);
1189 scm_remember_upto_here_2 (s1
, s2
);
1195 SCM_DEFINE (scm_string_lt
, "string<", 2, 4, 0,
1196 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1197 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
1198 "true value otherwise.")
1199 #define FUNC_NAME s_scm_string_lt
1201 const unsigned char *cstr1
, *cstr2
;
1202 size_t cstart1
, cend1
, cstart2
, cend2
;
1204 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1207 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1211 while (cstart1
< cend1
&& cstart2
< cend2
)
1213 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1215 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1220 if (cstart1
< cend1
)
1222 else if (cstart2
< cend2
)
1228 scm_remember_upto_here_2 (s1
, s2
);
1229 return scm_from_size_t (cstart1
);
1232 scm_remember_upto_here_2 (s1
, s2
);
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
1244 const unsigned char *cstr1
, *cstr2
;
1245 size_t cstart1
, cend1
, cstart2
, cend2
;
1247 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1250 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1254 while (cstart1
< cend1
&& cstart2
< cend2
)
1256 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1258 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1263 if (cstart1
< cend1
)
1265 else if (cstart2
< cend2
)
1271 scm_remember_upto_here_2 (s1
, s2
);
1272 return scm_from_size_t (cstart1
);
1275 scm_remember_upto_here_2 (s1
, s2
);
1281 SCM_DEFINE (scm_string_le
, "string<=", 2, 4, 0,
1282 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1283 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1285 #define FUNC_NAME s_scm_string_le
1287 const unsigned char *cstr1
, *cstr2
;
1288 size_t cstart1
, cend1
, cstart2
, cend2
;
1290 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1293 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1297 while (cstart1
< cend1
&& cstart2
< cend2
)
1299 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1301 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1306 if (cstart1
< cend1
)
1308 else if (cstart2
< cend2
)
1314 scm_remember_upto_here_2 (s1
, s2
);
1315 return scm_from_size_t (cstart1
);
1318 scm_remember_upto_here_2 (s1
, s2
);
1324 SCM_DEFINE (scm_string_ge
, "string>=", 2, 4, 0,
1325 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1326 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1328 #define FUNC_NAME s_scm_string_ge
1330 const unsigned char *cstr1
, *cstr2
;
1331 size_t cstart1
, cend1
, cstart2
, cend2
;
1333 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1336 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1340 while (cstart1
< cend1
&& cstart2
< cend2
)
1342 if (cstr1
[cstart1
] < cstr2
[cstart2
])
1344 else if (cstr1
[cstart1
] > cstr2
[cstart2
])
1349 if (cstart1
< cend1
)
1351 else if (cstart2
< cend2
)
1357 scm_remember_upto_here_2 (s1
, s2
);
1358 return scm_from_size_t (cstart1
);
1361 scm_remember_upto_here_2 (s1
, s2
);
1367 SCM_DEFINE (scm_string_ci_eq
, "string-ci=", 2, 4, 0,
1368 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1369 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
1370 "value otherwise. The character comparison is done\n"
1371 "case-insensitively.")
1372 #define FUNC_NAME s_scm_string_ci_eq
1374 const char *cstr1
, *cstr2
;
1375 size_t cstart1
, cend1
, cstart2
, cend2
;
1377 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1380 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1384 while (cstart1
< cend1
&& cstart2
< cend2
)
1386 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1388 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1393 if (cstart1
< cend1
)
1395 else if (cstart2
< cend2
)
1401 scm_remember_upto_here_2 (s1
, s2
);
1402 return scm_from_size_t (cstart1
);
1405 scm_remember_upto_here_2 (s1
, s2
);
1411 SCM_DEFINE (scm_string_ci_neq
, "string-ci<>", 2, 4, 0,
1412 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1413 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
1414 "value otherwise. The character comparison is done\n"
1415 "case-insensitively.")
1416 #define FUNC_NAME s_scm_string_ci_neq
1418 const char *cstr1
, *cstr2
;
1419 size_t cstart1
, cend1
, cstart2
, cend2
;
1421 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1424 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1428 while (cstart1
< cend1
&& cstart2
< cend2
)
1430 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1432 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1437 if (cstart1
< cend1
)
1439 else if (cstart2
< cend2
)
1445 scm_remember_upto_here_2 (s1
, s2
);
1446 return scm_from_size_t (cstart1
);
1449 scm_remember_upto_here_2 (s1
, s2
);
1455 SCM_DEFINE (scm_string_ci_lt
, "string-ci<", 2, 4, 0,
1456 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1457 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
1458 "true value otherwise. The character comparison is done\n"
1459 "case-insensitively.")
1460 #define FUNC_NAME s_scm_string_ci_lt
1462 const unsigned char *cstr1
, *cstr2
;
1463 size_t cstart1
, cend1
, cstart2
, cend2
;
1465 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1468 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1472 while (cstart1
< cend1
&& cstart2
< cend2
)
1474 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1476 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1481 if (cstart1
< cend1
)
1483 else if (cstart2
< cend2
)
1489 scm_remember_upto_here_2 (s1
, s2
);
1490 return scm_from_size_t (cstart1
);
1493 scm_remember_upto_here_2 (s1
, s2
);
1499 SCM_DEFINE (scm_string_ci_gt
, "string-ci>", 2, 4, 0,
1500 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1501 "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
1502 "true value otherwise. The character comparison is done\n"
1503 "case-insensitively.")
1504 #define FUNC_NAME s_scm_string_ci_gt
1506 const unsigned char *cstr1
, *cstr2
;
1507 size_t cstart1
, cend1
, cstart2
, cend2
;
1509 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1512 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1516 while (cstart1
< cend1
&& cstart2
< cend2
)
1518 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1520 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1525 if (cstart1
< cend1
)
1527 else if (cstart2
< cend2
)
1533 scm_remember_upto_here_2 (s1
, s2
);
1534 return scm_from_size_t (cstart1
);
1537 scm_remember_upto_here_2 (s1
, s2
);
1543 SCM_DEFINE (scm_string_ci_le
, "string-ci<=", 2, 4, 0,
1544 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1545 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1546 "value otherwise. The character comparison is done\n"
1547 "case-insensitively.")
1548 #define FUNC_NAME s_scm_string_ci_le
1550 const unsigned char *cstr1
, *cstr2
;
1551 size_t cstart1
, cend1
, cstart2
, cend2
;
1553 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1556 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1560 while (cstart1
< cend1
&& cstart2
< cend2
)
1562 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1564 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1569 if (cstart1
< cend1
)
1571 else if (cstart2
< cend2
)
1577 scm_remember_upto_here_2 (s1
, s2
);
1578 return scm_from_size_t (cstart1
);
1581 scm_remember_upto_here_2 (s1
, s2
);
1587 SCM_DEFINE (scm_string_ci_ge
, "string-ci>=", 2, 4, 0,
1588 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1589 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1590 "otherwise. The character comparison is done\n"
1591 "case-insensitively.")
1592 #define FUNC_NAME s_scm_string_ci_ge
1594 const unsigned char *cstr1
, *cstr2
;
1595 size_t cstart1
, cend1
, cstart2
, cend2
;
1597 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (1, s1
, cstr1
,
1600 MY_VALIDATE_SUBSTRING_SPEC_UCOPY (2, s2
, cstr2
,
1604 while (cstart1
< cend1
&& cstart2
< cend2
)
1606 if (scm_c_downcase (cstr1
[cstart1
]) < scm_c_downcase (cstr2
[cstart2
]))
1608 else if (scm_c_downcase (cstr1
[cstart1
]) > scm_c_downcase (cstr2
[cstart2
]))
1613 if (cstart1
< cend1
)
1615 else if (cstart2
< cend2
)
1621 scm_remember_upto_here_2 (s1
, s2
);
1622 return scm_from_size_t (cstart1
);
1625 scm_remember_upto_here_2 (s1
, s2
);
1630 SCM_DEFINE (scm_substring_hash
, "string-hash", 1, 3, 0,
1631 (SCM s
, SCM bound
, SCM start
, SCM end
),
1632 "Compute a hash value for @var{S}. the optional argument "
1633 "@var{bound} is a non-negative exact "
1634 "integer specifying the range of the hash function. "
1635 "A positive value restricts the return value to the "
1637 #define FUNC_NAME s_scm_substring_hash
1639 if (SCM_UNBNDP (bound
))
1640 bound
= scm_from_intmax (SCM_MOST_POSITIVE_FIXNUM
);
1641 if (SCM_UNBNDP (start
))
1643 return scm_hash (scm_substring_shared (s
, start
, end
), bound
);
1647 SCM_DEFINE (scm_substring_hash_ci
, "string-hash-ci", 1, 3, 0,
1648 (SCM s
, SCM bound
, SCM start
, SCM end
),
1649 "Compute a hash value for @var{S}. the optional argument "
1650 "@var{bound} is a non-negative exact "
1651 "integer specifying the range of the hash function. "
1652 "A positive value restricts the return value to the "
1654 #define FUNC_NAME s_scm_substring_hash_ci
1656 return scm_substring_hash (scm_substring_downcase (s
, start
, end
),
1658 SCM_UNDEFINED
, SCM_UNDEFINED
);
1662 SCM_DEFINE (scm_string_prefix_length
, "string-prefix-length", 2, 4, 0,
1663 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1664 "Return the length of the longest common prefix of the two\n"
1666 #define FUNC_NAME s_scm_string_prefix_length
1668 const char *cstr1
, *cstr2
;
1669 size_t cstart1
, cend1
, cstart2
, cend2
;
1672 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1675 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1678 while (cstart1
< cend1
&& cstart2
< cend2
)
1680 if (cstr1
[cstart1
] != cstr2
[cstart2
])
1688 scm_remember_upto_here_2 (s1
, s2
);
1689 return scm_from_size_t (len
);
1694 SCM_DEFINE (scm_string_prefix_length_ci
, "string-prefix-length-ci", 2, 4, 0,
1695 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1696 "Return the length of the longest common prefix of the two\n"
1697 "strings, ignoring character case.")
1698 #define FUNC_NAME s_scm_string_prefix_length_ci
1700 const char *cstr1
, *cstr2
;
1701 size_t cstart1
, cend1
, cstart2
, cend2
;
1704 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1707 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1710 while (cstart1
< cend1
&& cstart2
< cend2
)
1712 if (scm_c_downcase (cstr1
[cstart1
]) != scm_c_downcase (cstr2
[cstart2
]))
1720 scm_remember_upto_here_2 (s1
, s2
);
1721 return scm_from_size_t (len
);
1726 SCM_DEFINE (scm_string_suffix_length
, "string-suffix-length", 2, 4, 0,
1727 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1728 "Return the length of the longest common suffix of the two\n"
1730 #define FUNC_NAME s_scm_string_suffix_length
1732 const char *cstr1
, *cstr2
;
1733 size_t cstart1
, cend1
, cstart2
, cend2
;
1736 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1739 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1742 while (cstart1
< cend1
&& cstart2
< cend2
)
1746 if (cstr1
[cend1
] != cstr2
[cend2
])
1752 scm_remember_upto_here_2 (s1
, s2
);
1753 return scm_from_size_t (len
);
1758 SCM_DEFINE (scm_string_suffix_length_ci
, "string-suffix-length-ci", 2, 4, 0,
1759 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1760 "Return the length of the longest common suffix of the two\n"
1761 "strings, ignoring character case.")
1762 #define FUNC_NAME s_scm_string_suffix_length_ci
1764 const char *cstr1
, *cstr2
;
1765 size_t cstart1
, cend1
, cstart2
, cend2
;
1768 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1771 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1774 while (cstart1
< cend1
&& cstart2
< cend2
)
1778 if (scm_c_downcase (cstr1
[cend1
]) != scm_c_downcase (cstr2
[cend2
]))
1784 scm_remember_upto_here_2 (s1
, s2
);
1785 return scm_from_size_t (len
);
1790 SCM_DEFINE (scm_string_prefix_p
, "string-prefix?", 2, 4, 0,
1791 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1792 "Is @var{s1} a prefix of @var{s2}?")
1793 #define FUNC_NAME s_scm_string_prefix_p
1795 const char *cstr1
, *cstr2
;
1796 size_t cstart1
, cend1
, cstart2
, cend2
;
1797 size_t len
= 0, len1
;
1799 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1802 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1805 len1
= cend1
- cstart1
;
1806 while (cstart1
< cend1
&& cstart2
< cend2
)
1808 if (cstr1
[cstart1
] != cstr2
[cstart2
])
1816 scm_remember_upto_here_2 (s1
, s2
);
1817 return scm_from_bool (len
== len1
);
1822 SCM_DEFINE (scm_string_prefix_ci_p
, "string-prefix-ci?", 2, 4, 0,
1823 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1824 "Is @var{s1} a prefix of @var{s2}, ignoring character case?")
1825 #define FUNC_NAME s_scm_string_prefix_ci_p
1827 const char *cstr1
, *cstr2
;
1828 size_t cstart1
, cend1
, cstart2
, cend2
;
1829 size_t len
= 0, len1
;
1831 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1834 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1837 len1
= cend1
- cstart1
;
1838 while (cstart1
< cend1
&& cstart2
< cend2
)
1840 if (scm_c_downcase (cstr1
[cstart1
]) != scm_c_downcase (cstr2
[cstart2
]))
1848 scm_remember_upto_here_2 (s1
, s2
);
1849 return scm_from_bool (len
== len1
);
1854 SCM_DEFINE (scm_string_suffix_p
, "string-suffix?", 2, 4, 0,
1855 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1856 "Is @var{s1} a suffix of @var{s2}?")
1857 #define FUNC_NAME s_scm_string_suffix_p
1859 const char *cstr1
, *cstr2
;
1860 size_t cstart1
, cend1
, cstart2
, cend2
;
1861 size_t len
= 0, len1
;
1863 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1866 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1869 len1
= cend1
- cstart1
;
1870 while (cstart1
< cend1
&& cstart2
< cend2
)
1874 if (cstr1
[cend1
] != cstr2
[cend2
])
1880 scm_remember_upto_here_2 (s1
, s2
);
1881 return scm_from_bool (len
== len1
);
1886 SCM_DEFINE (scm_string_suffix_ci_p
, "string-suffix-ci?", 2, 4, 0,
1887 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
1888 "Is @var{s1} a suffix of @var{s2}, ignoring character case?")
1889 #define FUNC_NAME s_scm_string_suffix_ci_p
1891 const char *cstr1
, *cstr2
;
1892 size_t cstart1
, cend1
, cstart2
, cend2
;
1893 size_t len
= 0, len1
;
1895 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cstr1
,
1898 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cstr2
,
1901 len1
= cend1
- cstart1
;
1902 while (cstart1
< cend1
&& cstart2
< cend2
)
1906 if (scm_c_downcase (cstr1
[cend1
]) != scm_c_downcase (cstr2
[cend2
]))
1912 scm_remember_upto_here_2 (s1
, s2
);
1913 return scm_from_bool (len
== len1
);
1918 SCM_DEFINE (scm_string_index
, "string-index", 2, 2, 0,
1919 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
1920 "Search through the string @var{s} from left to right, returning\n"
1921 "the index of the first occurence of a character which\n"
1923 "@itemize @bullet\n"
1925 "equals @var{char_pred}, if it is character,\n"
1928 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1931 "is in the set @var{char_pred}, if it is a character set.\n"
1933 #define FUNC_NAME s_scm_string_index
1936 size_t cstart
, cend
;
1938 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
1941 if (SCM_CHARP (char_pred
))
1943 char cchr
= SCM_CHAR (char_pred
);
1944 while (cstart
< cend
)
1946 if (cchr
== cstr
[cstart
])
1951 else if (SCM_CHARSETP (char_pred
))
1953 while (cstart
< cend
)
1955 if (SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
1962 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
1963 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
1965 while (cstart
< cend
)
1968 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
1969 if (scm_is_true (res
))
1971 cstr
= scm_i_string_chars (s
);
1976 scm_remember_upto_here_1 (s
);
1980 scm_remember_upto_here_1 (s
);
1981 return scm_from_size_t (cstart
);
1985 SCM_DEFINE (scm_string_index_right
, "string-index-right", 2, 2, 0,
1986 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
1987 "Search through the string @var{s} from right to left, returning\n"
1988 "the index of the last occurence of a character which\n"
1990 "@itemize @bullet\n"
1992 "equals @var{char_pred}, if it is character,\n"
1995 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1998 "is in the set if @var{char_pred} is a character set.\n"
2000 #define FUNC_NAME s_scm_string_index_right
2003 size_t cstart
, cend
;
2005 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
2008 if (SCM_CHARP (char_pred
))
2010 char cchr
= SCM_CHAR (char_pred
);
2011 while (cstart
< cend
)
2014 if (cchr
== cstr
[cend
])
2018 else if (SCM_CHARSETP (char_pred
))
2020 while (cstart
< cend
)
2023 if (SCM_CHARSET_GET (char_pred
, cstr
[cend
]))
2029 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
2030 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
2032 while (cstart
< cend
)
2036 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cend
]));
2037 if (scm_is_true (res
))
2039 cstr
= scm_i_string_chars (s
);
2043 scm_remember_upto_here_1 (s
);
2047 scm_remember_upto_here_1 (s
);
2048 return scm_from_size_t (cend
);
2052 SCM_DEFINE (scm_string_rindex
, "string-rindex", 2, 2, 0,
2053 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
2054 "Search through the string @var{s} from right to left, returning\n"
2055 "the index of the last occurence of a character which\n"
2057 "@itemize @bullet\n"
2059 "equals @var{char_pred}, if it is character,\n"
2062 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
2065 "is in the set if @var{char_pred} is a character set.\n"
2067 #define FUNC_NAME s_scm_string_rindex
2069 return scm_string_index_right (s
, char_pred
, start
, end
);
2073 SCM_DEFINE (scm_string_skip
, "string-skip", 2, 2, 0,
2074 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
2075 "Search through the string @var{s} from left to right, returning\n"
2076 "the index of the first occurence of a character which\n"
2078 "@itemize @bullet\n"
2080 "does not equal @var{char_pred}, if it is character,\n"
2083 "does not satisify the predicate @var{char_pred}, if it is a\n"
2087 "is not in the set if @var{char_pred} is a character set.\n"
2089 #define FUNC_NAME s_scm_string_skip
2092 size_t cstart
, cend
;
2094 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
2097 if (SCM_CHARP (char_pred
))
2099 char cchr
= SCM_CHAR (char_pred
);
2100 while (cstart
< cend
)
2102 if (cchr
!= cstr
[cstart
])
2107 else if (SCM_CHARSETP (char_pred
))
2109 while (cstart
< cend
)
2111 if (!SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
2118 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
2119 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
2121 while (cstart
< cend
)
2124 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
2125 if (scm_is_false (res
))
2127 cstr
= scm_i_string_chars (s
);
2132 scm_remember_upto_here_1 (s
);
2136 scm_remember_upto_here_1 (s
);
2137 return scm_from_size_t (cstart
);
2142 SCM_DEFINE (scm_string_skip_right
, "string-skip-right", 2, 2, 0,
2143 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
2144 "Search through the string @var{s} from right to left, returning\n"
2145 "the index of the last occurence of a character which\n"
2147 "@itemize @bullet\n"
2149 "does not equal @var{char_pred}, if it is character,\n"
2152 "does not satisfy the predicate @var{char_pred}, if it is a\n"
2156 "is not in the set if @var{char_pred} is a character set.\n"
2158 #define FUNC_NAME s_scm_string_skip_right
2161 size_t cstart
, cend
;
2163 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
2166 if (SCM_CHARP (char_pred
))
2168 char cchr
= SCM_CHAR (char_pred
);
2169 while (cstart
< cend
)
2172 if (cchr
!= cstr
[cend
])
2176 else if (SCM_CHARSETP (char_pred
))
2178 while (cstart
< cend
)
2181 if (!SCM_CHARSET_GET (char_pred
, cstr
[cend
]))
2187 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
2188 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
2190 while (cstart
< cend
)
2194 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cend
]));
2195 if (scm_is_false (res
))
2197 cstr
= scm_i_string_chars (s
);
2201 scm_remember_upto_here_1 (s
);
2205 scm_remember_upto_here_1 (s
);
2206 return scm_from_size_t (cend
);
2212 SCM_DEFINE (scm_string_count
, "string-count", 2, 2, 0,
2213 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
2214 "Return the count of the number of characters in the string\n"
2217 "@itemize @bullet\n"
2219 "equals @var{char_pred}, if it is character,\n"
2222 "satisifies the predicate @var{char_pred}, if it is a procedure.\n"
2225 "is in the set @var{char_pred}, if it is a character set.\n"
2227 #define FUNC_NAME s_scm_string_count
2230 size_t cstart
, cend
;
2233 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
2236 if (SCM_CHARP (char_pred
))
2238 char cchr
= SCM_CHAR (char_pred
);
2239 while (cstart
< cend
)
2241 if (cchr
== cstr
[cstart
])
2246 else if (SCM_CHARSETP (char_pred
))
2248 while (cstart
< cend
)
2250 if (SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
2257 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
2258 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
2260 while (cstart
< cend
)
2263 res
= pred_tramp (char_pred
, SCM_MAKE_CHAR (cstr
[cstart
]));
2264 if (scm_is_true (res
))
2266 cstr
= scm_i_string_chars (s
);
2271 scm_remember_upto_here_1 (s
);
2272 return scm_from_size_t (count
);
2277 /* FIXME::martin: This should definitely get implemented more
2278 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
2280 SCM_DEFINE (scm_string_contains
, "string-contains", 2, 4, 0,
2281 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
2282 "Does string @var{s1} contain string @var{s2}? Return the index\n"
2283 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
2284 "The optional start/end indices restrict the operation to the\n"
2285 "indicated substrings.")
2286 #define FUNC_NAME s_scm_string_contains
2288 const char *cs1
, * cs2
;
2289 size_t cstart1
, cend1
, cstart2
, cend2
;
2292 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cs1
,
2295 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cs2
,
2298 len2
= cend2
- cstart2
;
2299 if (cend1
- cstart1
>= len2
)
2300 while (cstart1
<= cend1
- len2
)
2304 while (i
< cend1
&& j
< cend2
&& cs1
[i
] == cs2
[j
])
2311 scm_remember_upto_here_2 (s1
, s2
);
2312 return scm_from_size_t (cstart1
);
2317 scm_remember_upto_here_2 (s1
, s2
);
2323 /* FIXME::martin: This should definitely get implemented more
2324 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
2326 SCM_DEFINE (scm_string_contains_ci
, "string-contains-ci", 2, 4, 0,
2327 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
2328 "Does string @var{s1} contain string @var{s2}? Return the index\n"
2329 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
2330 "The optional start/end indices restrict the operation to the\n"
2331 "indicated substrings. Character comparison is done\n"
2332 "case-insensitively.")
2333 #define FUNC_NAME s_scm_string_contains_ci
2335 const char *cs1
, * cs2
;
2336 size_t cstart1
, cend1
, cstart2
, cend2
;
2339 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s1
, cs1
,
2342 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s2
, cs2
,
2345 len2
= cend2
- cstart2
;
2346 if (cend1
- cstart1
>= len2
)
2347 while (cstart1
<= cend1
- len2
)
2351 while (i
< cend1
&& j
< cend2
&&
2352 scm_c_downcase (cs1
[i
]) == scm_c_downcase (cs2
[j
]))
2359 scm_remember_upto_here_2 (s1
, s2
);
2360 return scm_from_size_t (cstart1
);
2365 scm_remember_upto_here_2 (s1
, s2
);
2371 /* Helper function for the string uppercase conversion functions.
2372 * No argument checking is performed. */
2374 string_upcase_x (SCM v
, size_t start
, size_t end
)
2379 dst
= scm_i_string_writable_chars (v
);
2380 for (k
= start
; k
< end
; ++k
)
2381 dst
[k
] = scm_c_upcase (dst
[k
]);
2382 scm_i_string_stop_writing ();
2383 scm_remember_upto_here_1 (v
);
2388 SCM_DEFINE (scm_substring_upcase_x
, "string-upcase!", 1, 2, 0,
2389 (SCM str
, SCM start
, SCM end
),
2390 "Destructively upcase every character in @code{str}.\n"
2393 "(string-upcase! y)\n"
2394 "@result{} \"ARRDEFG\"\n"
2396 "@result{} \"ARRDEFG\"\n"
2398 #define FUNC_NAME s_scm_substring_upcase_x
2401 size_t cstart
, cend
;
2403 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2406 return string_upcase_x (str
, cstart
, cend
);
2411 scm_string_upcase_x (SCM str
)
2413 return scm_substring_upcase_x (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
2416 SCM_DEFINE (scm_substring_upcase
, "string-upcase", 1, 2, 0,
2417 (SCM str
, SCM start
, SCM end
),
2418 "Upcase every character in @code{str}.")
2419 #define FUNC_NAME s_scm_substring_upcase
2422 size_t cstart
, cend
;
2424 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2427 return string_upcase_x (scm_string_copy (str
), cstart
, cend
);
2432 scm_string_upcase (SCM str
)
2434 return scm_substring_upcase (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
2437 /* Helper function for the string lowercase conversion functions.
2438 * No argument checking is performed. */
2440 string_downcase_x (SCM v
, size_t start
, size_t end
)
2445 dst
= scm_i_string_writable_chars (v
);
2446 for (k
= start
; k
< end
; ++k
)
2447 dst
[k
] = scm_c_downcase (dst
[k
]);
2448 scm_i_string_stop_writing ();
2449 scm_remember_upto_here_1 (v
);
2454 SCM_DEFINE (scm_substring_downcase_x
, "string-downcase!", 1, 2, 0,
2455 (SCM str
, SCM start
, SCM end
),
2456 "Destructively downcase every character in @var{str}.\n"
2460 "@result{} \"ARRDEFG\"\n"
2461 "(string-downcase! y)\n"
2462 "@result{} \"arrdefg\"\n"
2464 "@result{} \"arrdefg\"\n"
2466 #define FUNC_NAME s_scm_substring_downcase_x
2469 size_t cstart
, cend
;
2471 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2474 return string_downcase_x (str
, cstart
, cend
);
2479 scm_string_downcase_x (SCM str
)
2481 return scm_substring_downcase_x (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
2484 SCM_DEFINE (scm_substring_downcase
, "string-downcase", 1, 2, 0,
2485 (SCM str
, SCM start
, SCM end
),
2486 "Downcase every character in @var{str}.")
2487 #define FUNC_NAME s_scm_substring_downcase
2490 size_t cstart
, cend
;
2492 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2495 return string_downcase_x (scm_string_copy (str
), cstart
, cend
);
2500 scm_string_downcase (SCM str
)
2502 return scm_substring_downcase (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
2505 /* Helper function for the string capitalization functions.
2506 * No argument checking is performed. */
2508 string_titlecase_x (SCM str
, size_t start
, size_t end
)
2514 sz
= (unsigned char *) scm_i_string_writable_chars (str
);
2515 for(i
= start
; i
< end
; i
++)
2517 if (scm_is_true (scm_char_alphabetic_p (SCM_MAKE_CHAR (sz
[i
]))))
2521 sz
[i
] = scm_c_upcase(sz
[i
]);
2526 sz
[i
] = scm_c_downcase(sz
[i
]);
2532 scm_i_string_stop_writing ();
2533 scm_remember_upto_here_1 (str
);
2539 SCM_DEFINE (scm_string_titlecase_x
, "string-titlecase!", 1, 2, 0,
2540 (SCM str
, SCM start
, SCM end
),
2541 "Destructively titlecase every first character in a word in\n"
2543 #define FUNC_NAME s_scm_string_titlecase_x
2546 size_t cstart
, cend
;
2548 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2551 return string_titlecase_x (str
, cstart
, cend
);
2556 SCM_DEFINE (scm_string_titlecase
, "string-titlecase", 1, 2, 0,
2557 (SCM str
, SCM start
, SCM end
),
2558 "Titlecase every first character in a word in @var{str}.")
2559 #define FUNC_NAME s_scm_string_titlecase
2562 size_t cstart
, cend
;
2564 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2567 return string_titlecase_x (scm_string_copy (str
), cstart
, cend
);
2571 SCM_DEFINE (scm_string_capitalize_x
, "string-capitalize!", 1, 0, 0,
2573 "Upcase the first character of every word in @var{str}\n"
2574 "destructively and return @var{str}.\n"
2577 "y @result{} \"hello world\"\n"
2578 "(string-capitalize! y) @result{} \"Hello World\"\n"
2579 "y @result{} \"Hello World\"\n"
2581 #define FUNC_NAME s_scm_string_capitalize_x
2583 return scm_string_titlecase_x (str
, SCM_UNDEFINED
, SCM_UNDEFINED
);
2588 SCM_DEFINE (scm_string_capitalize
, "string-capitalize", 1, 0, 0,
2590 "Return a freshly allocated string with the characters in\n"
2591 "@var{str}, where the first character of every word is\n"
2593 #define FUNC_NAME s_scm_string_capitalize
2595 return scm_string_capitalize_x (scm_string_copy (str
));
2600 /* Reverse the portion of @var{str} between str[cstart] (including)
2601 and str[cend] excluding. */
2603 string_reverse_x (char * str
, size_t cstart
, size_t cend
)
2610 while (cstart
< cend
)
2613 str
[cstart
] = str
[cend
];
2622 SCM_DEFINE (scm_string_reverse
, "string-reverse", 1, 2, 0,
2623 (SCM str
, SCM start
, SCM end
),
2624 "Reverse the string @var{str}. The optional arguments\n"
2625 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2627 #define FUNC_NAME s_scm_string_reverse
2631 size_t cstart
, cend
;
2634 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, cstr
,
2637 result
= scm_string_copy (str
);
2638 ctarget
= scm_i_string_writable_chars (result
);
2639 string_reverse_x (ctarget
, cstart
, cend
);
2640 scm_i_string_stop_writing ();
2641 scm_remember_upto_here_1 (str
);
2647 SCM_DEFINE (scm_string_reverse_x
, "string-reverse!", 1, 2, 0,
2648 (SCM str
, SCM start
, SCM end
),
2649 "Reverse the string @var{str} in-place. The optional arguments\n"
2650 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2651 "operate on. The return value is unspecified.")
2652 #define FUNC_NAME s_scm_string_reverse_x
2655 size_t cstart
, cend
;
2657 MY_VALIDATE_SUBSTRING_SPEC (1, str
,
2661 cstr
= scm_i_string_writable_chars (str
);
2662 string_reverse_x (cstr
, cstart
, cend
);
2663 scm_i_string_stop_writing ();
2664 scm_remember_upto_here_1 (str
);
2665 return SCM_UNSPECIFIED
;
2670 SCM_DEFINE (scm_string_append_shared
, "string-append/shared", 0, 0, 1,
2672 "Like @code{string-append}, but the result may share memory\n"
2673 "with the argument strings.")
2674 #define FUNC_NAME s_scm_string_append_shared
2676 /* If "rest" contains just one non-empty string, return that.
2677 If it's entirely empty strings, then return scm_nullstr.
2678 Otherwise use scm_string_concatenate. */
2680 SCM ret
= scm_nullstr
;
2681 int seen_nonempty
= 0;
2684 SCM_VALIDATE_REST_ARGUMENT (rest
);
2686 for (l
= rest
; scm_is_pair (l
); l
= SCM_CDR (l
))
2689 if (scm_c_string_length (s
) != 0)
2692 /* two or more non-empty strings, need full concat */
2693 return scm_string_append (rest
);
2704 SCM_DEFINE (scm_string_concatenate
, "string-concatenate", 1, 0, 0,
2706 "Append the elements of @var{ls} (which must be strings)\n"
2707 "together into a single string. Guaranteed to return a freshly\n"
2708 "allocated string.")
2709 #define FUNC_NAME s_scm_string_concatenate
2711 SCM_VALIDATE_LIST (SCM_ARG1
, ls
);
2712 return scm_string_append (ls
);
2717 SCM_DEFINE (scm_string_concatenate_reverse
, "string-concatenate-reverse", 1, 2, 0,
2718 (SCM ls
, SCM final_string
, SCM end
),
2719 "Without optional arguments, this procedure is equivalent to\n"
2722 "(string-concatenate (reverse ls))\n"
2725 "If the optional argument @var{final_string} is specified, it is\n"
2726 "consed onto the beginning to @var{ls} before performing the\n"
2727 "list-reverse and string-concatenate operations. If @var{end}\n"
2728 "is given, only the characters of @var{final_string} up to index\n"
2729 "@var{end} are used.\n"
2731 "Guaranteed to return a freshly allocated string.")
2732 #define FUNC_NAME s_scm_string_concatenate_reverse
2734 if (!SCM_UNBNDP (end
))
2735 final_string
= scm_substring (final_string
, SCM_INUM0
, end
);
2737 if (!SCM_UNBNDP (final_string
))
2738 ls
= scm_cons (final_string
, ls
);
2740 return scm_string_concatenate (scm_reverse (ls
));
2745 SCM_DEFINE (scm_string_concatenate_shared
, "string-concatenate/shared", 1, 0, 0,
2747 "Like @code{string-concatenate}, but the result may share memory\n"
2748 "with the strings in the list @var{ls}.")
2749 #define FUNC_NAME s_scm_string_concatenate_shared
2751 SCM_VALIDATE_LIST (SCM_ARG1
, ls
);
2752 return scm_string_append_shared (ls
);
2757 SCM_DEFINE (scm_string_concatenate_reverse_shared
, "string-concatenate-reverse/shared", 1, 2, 0,
2758 (SCM ls
, SCM final_string
, SCM end
),
2759 "Like @code{string-concatenate-reverse}, but the result may\n"
2760 "share memory with the the strings in the @var{ls} arguments.")
2761 #define FUNC_NAME s_scm_string_concatenate_reverse_shared
2763 /* Just call the non-sharing version. */
2764 return scm_string_concatenate_reverse (ls
, final_string
, end
);
2769 SCM_DEFINE (scm_string_map
, "string-map", 2, 2, 0,
2770 (SCM proc
, SCM s
, SCM start
, SCM end
),
2771 "@var{proc} is a char->char procedure, it is mapped over\n"
2772 "@var{s}. The order in which the procedure is applied to the\n"
2773 "string elements is not specified.")
2774 #define FUNC_NAME s_scm_string_map
2777 size_t cstart
, cend
;
2779 scm_t_trampoline_1 proc_tramp
= scm_trampoline_1 (proc
);
2781 SCM_ASSERT (proc_tramp
, proc
, SCM_ARG1
, FUNC_NAME
);
2782 MY_VALIDATE_SUBSTRING_SPEC (2, s
,
2785 result
= scm_i_make_string (cend
- cstart
, &p
);
2786 while (cstart
< cend
)
2788 SCM ch
= proc_tramp (proc
, scm_c_string_ref (s
, cstart
));
2789 if (!SCM_CHARP (ch
))
2790 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc
));
2792 *p
++ = SCM_CHAR (ch
);
2799 SCM_DEFINE (scm_string_map_x
, "string-map!", 2, 2, 0,
2800 (SCM proc
, SCM s
, SCM start
, SCM end
),
2801 "@var{proc} is a char->char procedure, it is mapped over\n"
2802 "@var{s}. The order in which the procedure is applied to the\n"
2803 "string elements is not specified. The string @var{s} is\n"
2804 "modified in-place, the return value is not specified.")
2805 #define FUNC_NAME s_scm_string_map_x
2807 size_t cstart
, cend
;
2808 scm_t_trampoline_1 proc_tramp
= scm_trampoline_1 (proc
);
2810 SCM_ASSERT (proc_tramp
, proc
, SCM_ARG1
, FUNC_NAME
);
2811 MY_VALIDATE_SUBSTRING_SPEC (2, s
,
2814 while (cstart
< cend
)
2816 SCM ch
= proc_tramp (proc
, scm_c_string_ref (s
, cstart
));
2817 if (!SCM_CHARP (ch
))
2818 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc
));
2819 scm_c_string_set_x (s
, cstart
, ch
);
2822 return SCM_UNSPECIFIED
;
2827 SCM_DEFINE (scm_string_fold
, "string-fold", 3, 2, 0,
2828 (SCM kons
, SCM knil
, SCM s
, SCM start
, SCM end
),
2829 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2830 "as the terminating element, from left to right. @var{kons}\n"
2831 "must expect two arguments: The actual character and the last\n"
2832 "result of @var{kons}' application.")
2833 #define FUNC_NAME s_scm_string_fold
2836 size_t cstart
, cend
;
2839 SCM_VALIDATE_PROC (1, kons
);
2840 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s
, cstr
,
2844 while (cstart
< cend
)
2846 unsigned int c
= (unsigned char) cstr
[cstart
];
2847 result
= scm_call_2 (kons
, SCM_MAKE_CHAR (c
), result
);
2848 cstr
= scm_i_string_chars (s
);
2852 scm_remember_upto_here_1 (s
);
2858 SCM_DEFINE (scm_string_fold_right
, "string-fold-right", 3, 2, 0,
2859 (SCM kons
, SCM knil
, SCM s
, SCM start
, SCM end
),
2860 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2861 "as the terminating element, from right to left. @var{kons}\n"
2862 "must expect two arguments: The actual character and the last\n"
2863 "result of @var{kons}' application.")
2864 #define FUNC_NAME s_scm_string_fold_right
2867 size_t cstart
, cend
;
2870 SCM_VALIDATE_PROC (1, kons
);
2871 MY_VALIDATE_SUBSTRING_SPEC_COPY (3, s
, cstr
,
2875 while (cstart
< cend
)
2877 unsigned int c
= (unsigned char) cstr
[cend
- 1];
2878 result
= scm_call_2 (kons
, SCM_MAKE_CHAR (c
), result
);
2879 cstr
= scm_i_string_chars (s
);
2883 scm_remember_upto_here_1 (s
);
2889 SCM_DEFINE (scm_string_unfold
, "string-unfold", 4, 2, 0,
2890 (SCM p
, SCM f
, SCM g
, SCM seed
, SCM base
, SCM make_final
),
2891 "@itemize @bullet\n"
2892 "@item @var{g} is used to generate a series of @emph{seed}\n"
2893 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2894 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2896 "@item @var{p} tells us when to stop -- when it returns true\n"
2897 "when applied to one of these seed values.\n"
2898 "@item @var{f} maps each seed value to the corresponding\n"
2899 "character in the result string. These chars are assembled\n"
2900 "into the string in a left-to-right order.\n"
2901 "@item @var{base} is the optional initial/leftmost portion\n"
2902 "of the constructed string; it default to the empty\n"
2904 "@item @var{make_final} is applied to the terminal seed\n"
2905 "value (on which @var{p} returns true) to produce\n"
2906 "the final/rightmost portion of the constructed string.\n"
2907 "It defaults to @code{(lambda (x) "")}.\n"
2909 #define FUNC_NAME s_scm_string_unfold
2913 SCM_VALIDATE_PROC (1, p
);
2914 SCM_VALIDATE_PROC (2, f
);
2915 SCM_VALIDATE_PROC (3, g
);
2916 if (!SCM_UNBNDP (base
))
2918 SCM_VALIDATE_STRING (5, base
);
2922 ans
= scm_i_make_string (0, NULL
);
2923 if (!SCM_UNBNDP (make_final
))
2924 SCM_VALIDATE_PROC (6, make_final
);
2926 res
= scm_call_1 (p
, seed
);
2927 while (scm_is_false (res
))
2931 SCM ch
= scm_call_1 (f
, seed
);
2932 if (!SCM_CHARP (ch
))
2933 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f
));
2934 str
= scm_i_make_string (1, &ptr
);
2935 *ptr
= SCM_CHAR (ch
);
2937 ans
= scm_string_append (scm_list_2 (ans
, str
));
2938 seed
= scm_call_1 (g
, seed
);
2939 res
= scm_call_1 (p
, seed
);
2941 if (!SCM_UNBNDP (make_final
))
2943 res
= scm_call_1 (make_final
, seed
);
2944 return scm_string_append (scm_list_2 (ans
, res
));
2952 SCM_DEFINE (scm_string_unfold_right
, "string-unfold-right", 4, 2, 0,
2953 (SCM p
, SCM f
, SCM g
, SCM seed
, SCM base
, SCM make_final
),
2954 "@itemize @bullet\n"
2955 "@item @var{g} is used to generate a series of @emph{seed}\n"
2956 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2957 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2959 "@item @var{p} tells us when to stop -- when it returns true\n"
2960 "when applied to one of these seed values.\n"
2961 "@item @var{f} maps each seed value to the corresponding\n"
2962 "character in the result string. These chars are assembled\n"
2963 "into the string in a right-to-left order.\n"
2964 "@item @var{base} is the optional initial/rightmost portion\n"
2965 "of the constructed string; it default to the empty\n"
2967 "@item @var{make_final} is applied to the terminal seed\n"
2968 "value (on which @var{p} returns true) to produce\n"
2969 "the final/leftmost portion of the constructed string.\n"
2970 "It defaults to @code{(lambda (x) "")}.\n"
2972 #define FUNC_NAME s_scm_string_unfold_right
2976 SCM_VALIDATE_PROC (1, p
);
2977 SCM_VALIDATE_PROC (2, f
);
2978 SCM_VALIDATE_PROC (3, g
);
2979 if (!SCM_UNBNDP (base
))
2981 SCM_VALIDATE_STRING (5, base
);
2985 ans
= scm_i_make_string (0, NULL
);
2986 if (!SCM_UNBNDP (make_final
))
2987 SCM_VALIDATE_PROC (6, make_final
);
2989 res
= scm_call_1 (p
, seed
);
2990 while (scm_is_false (res
))
2994 SCM ch
= scm_call_1 (f
, seed
);
2995 if (!SCM_CHARP (ch
))
2996 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f
));
2997 str
= scm_i_make_string (1, &ptr
);
2998 *ptr
= SCM_CHAR (ch
);
3000 ans
= scm_string_append (scm_list_2 (str
, ans
));
3001 seed
= scm_call_1 (g
, seed
);
3002 res
= scm_call_1 (p
, seed
);
3004 if (!SCM_UNBNDP (make_final
))
3006 res
= scm_call_1 (make_final
, seed
);
3007 return scm_string_append (scm_list_2 (res
, ans
));
3015 SCM_DEFINE (scm_string_for_each
, "string-for-each", 2, 2, 0,
3016 (SCM proc
, SCM s
, SCM start
, SCM end
),
3017 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
3018 "return value is not specified.")
3019 #define FUNC_NAME s_scm_string_for_each
3022 size_t cstart
, cend
;
3023 scm_t_trampoline_1 proc_tramp
= scm_trampoline_1 (proc
);
3025 SCM_ASSERT (proc_tramp
, proc
, SCM_ARG1
, FUNC_NAME
);
3026 MY_VALIDATE_SUBSTRING_SPEC_COPY (2, s
, cstr
,
3029 while (cstart
< cend
)
3031 unsigned int c
= (unsigned char) cstr
[cstart
];
3032 proc_tramp (proc
, SCM_MAKE_CHAR (c
));
3033 cstr
= scm_i_string_chars (s
);
3037 scm_remember_upto_here_1 (s
);
3038 return SCM_UNSPECIFIED
;
3042 SCM_DEFINE (scm_string_for_each_index
, "string-for-each-index", 2, 2, 0,
3043 (SCM proc
, SCM s
, SCM start
, SCM end
),
3044 "Call @code{(@var{proc} i)} for each index i in @var{s}, from\n"
3047 "For example, to change characters to alternately upper and\n"
3051 "(define str (string-copy \"studly\"))\n"
3052 "(string-for-each-index\n"
3054 " (string-set! str i\n"
3055 " ((if (even? i) char-upcase char-downcase)\n"
3056 " (string-ref str i))))\n"
3058 "str @result{} \"StUdLy\"\n"
3060 #define FUNC_NAME s_scm_string_for_each_index
3062 size_t cstart
, cend
;
3063 scm_t_trampoline_1 proc_tramp
= scm_trampoline_1 (proc
);
3065 SCM_ASSERT (proc_tramp
, proc
, SCM_ARG1
, FUNC_NAME
);
3066 MY_VALIDATE_SUBSTRING_SPEC (2, s
,
3070 while (cstart
< cend
)
3072 proc_tramp (proc
, scm_from_size_t (cstart
));
3076 scm_remember_upto_here_1 (s
);
3077 return SCM_UNSPECIFIED
;
3081 SCM_DEFINE (scm_xsubstring
, "xsubstring", 2, 3, 0,
3082 (SCM s
, SCM from
, SCM to
, SCM start
, SCM end
),
3083 "This is the @emph{extended substring} procedure that implements\n"
3084 "replicated copying of a substring of some string.\n"
3086 "@var{s} is a string, @var{start} and @var{end} are optional\n"
3087 "arguments that demarcate a substring of @var{s}, defaulting to\n"
3088 "0 and the length of @var{s}. Replicate this substring up and\n"
3089 "down index space, in both the positive and negative directions.\n"
3090 "@code{xsubstring} returns the substring of this string\n"
3091 "beginning at index @var{from}, and ending at @var{to}, which\n"
3092 "defaults to @var{from} + (@var{end} - @var{start}).")
3093 #define FUNC_NAME s_scm_xsubstring
3097 size_t cstart
, cend
;
3101 MY_VALIDATE_SUBSTRING_SPEC (1, s
,
3105 cfrom
= scm_to_int (from
);
3106 if (SCM_UNBNDP (to
))
3107 cto
= cfrom
+ (cend
- cstart
);
3109 cto
= scm_to_int (to
);
3110 if (cstart
== cend
&& cfrom
!= cto
)
3111 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL
);
3113 result
= scm_i_make_string (cto
- cfrom
, &p
);
3115 cs
= scm_i_string_chars (s
);
3118 size_t t
= ((cfrom
< 0) ? -cfrom
: cfrom
) % (cend
- cstart
);
3120 *p
= cs
[(cend
- cstart
) - t
];
3127 scm_remember_upto_here_1 (s
);
3133 SCM_DEFINE (scm_string_xcopy_x
, "string-xcopy!", 4, 3, 0,
3134 (SCM target
, SCM tstart
, SCM s
, SCM sfrom
, SCM sto
, SCM start
, SCM end
),
3135 "Exactly the same as @code{xsubstring}, but the extracted text\n"
3136 "is written into the string @var{target} starting at index\n"
3137 "@var{tstart}. The operation is not defined if @code{(eq?\n"
3138 "@var{target} @var{s})} or these arguments share storage -- you\n"
3139 "cannot copy a string on top of itself.")
3140 #define FUNC_NAME s_scm_string_xcopy_x
3144 size_t ctstart
, cstart
, cend
;
3146 SCM dummy
= SCM_UNDEFINED
;
3149 MY_VALIDATE_SUBSTRING_SPEC (1, target
,
3152 MY_VALIDATE_SUBSTRING_SPEC (3, s
,
3155 csfrom
= scm_to_int (sfrom
);
3156 if (SCM_UNBNDP (sto
))
3157 csto
= csfrom
+ (cend
- cstart
);
3159 csto
= scm_to_int (sto
);
3160 if (cstart
== cend
&& csfrom
!= csto
)
3161 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL
);
3162 SCM_ASSERT_RANGE (1, tstart
,
3163 ctstart
+ (csto
- csfrom
) <= scm_i_string_length (target
));
3165 p
= scm_i_string_writable_chars (target
) + ctstart
;
3166 cs
= scm_i_string_chars (s
);
3167 while (csfrom
< csto
)
3169 size_t t
= ((csfrom
< 0) ? -csfrom
: csfrom
) % (cend
- cstart
);
3171 *p
= cs
[(cend
- cstart
) - t
];
3177 scm_i_string_stop_writing ();
3179 scm_remember_upto_here_2 (target
, s
);
3180 return SCM_UNSPECIFIED
;
3185 SCM_DEFINE (scm_string_replace
, "string-replace", 2, 4, 0,
3186 (SCM s1
, SCM s2
, SCM start1
, SCM end1
, SCM start2
, SCM end2
),
3187 "Return the string @var{s1}, but with the characters\n"
3188 "@var{start1} @dots{} @var{end1} replaced by the characters\n"
3189 "@var{start2} @dots{} @var{end2} from @var{s2}.")
3190 #define FUNC_NAME s_scm_string_replace
3192 const char *cstr1
, *cstr2
;
3194 size_t cstart1
, cend1
, cstart2
, cend2
;
3197 MY_VALIDATE_SUBSTRING_SPEC (1, s1
,
3200 MY_VALIDATE_SUBSTRING_SPEC (2, s2
,
3203 result
= scm_i_make_string (cstart1
+ (cend2
- cstart2
) +
3204 scm_i_string_length (s1
) - cend1
, &p
);
3205 cstr1
= scm_i_string_chars (s1
);
3206 cstr2
= scm_i_string_chars (s2
);
3207 memmove (p
, cstr1
, cstart1
* sizeof (char));
3208 memmove (p
+ cstart1
, cstr2
+ cstart2
, (cend2
- cstart2
) * sizeof (char));
3209 memmove (p
+ cstart1
+ (cend2
- cstart2
),
3211 (scm_i_string_length (s1
) - cend1
) * sizeof (char));
3212 scm_remember_upto_here_2 (s1
, s2
);
3218 SCM_DEFINE (scm_string_tokenize
, "string-tokenize", 1, 3, 0,
3219 (SCM s
, SCM token_set
, SCM start
, SCM end
),
3220 "Split the string @var{s} into a list of substrings, where each\n"
3221 "substring is a maximal non-empty contiguous sequence of\n"
3222 "characters from the character set @var{token_set}, which\n"
3223 "defaults to @code{char-set:graphic}.\n"
3224 "If @var{start} or @var{end} indices are provided, they restrict\n"
3225 "@code{string-tokenize} to operating on the indicated substring\n"
3227 #define FUNC_NAME s_scm_string_tokenize
3230 size_t cstart
, cend
;
3231 SCM result
= SCM_EOL
;
3233 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
3237 if (SCM_UNBNDP (token_set
))
3238 token_set
= scm_char_set_graphic
;
3240 if (SCM_CHARSETP (token_set
))
3244 while (cstart
< cend
)
3246 while (cstart
< cend
)
3248 if (SCM_CHARSET_GET (token_set
, cstr
[cend
- 1]))
3255 while (cstart
< cend
)
3257 if (!SCM_CHARSET_GET (token_set
, cstr
[cend
- 1]))
3261 result
= scm_cons (scm_c_substring (s
, cend
, idx
), result
);
3262 cstr
= scm_i_string_chars (s
);
3266 SCM_WRONG_TYPE_ARG (2, token_set
);
3268 scm_remember_upto_here_1 (s
);
3273 SCM_DEFINE (scm_string_split
, "string-split", 2, 0, 0,
3275 "Split the string @var{str} into the a list of the substrings delimited\n"
3276 "by appearances of the character @var{chr}. Note that an empty substring\n"
3277 "between separator characters will result in an empty string in the\n"
3281 "(string-split \"root:x:0:0:root:/root:/bin/bash\" #\\:)\n"
3283 "(\"root\" \"x\" \"0\" \"0\" \"root\" \"/root\" \"/bin/bash\")\n"
3285 "(string-split \"::\" #\\:)\n"
3287 "(\"\" \"\" \"\")\n"
3289 "(string-split \"\" #\\:)\n"
3293 #define FUNC_NAME s_scm_string_split
3300 SCM_VALIDATE_STRING (1, str
);
3301 SCM_VALIDATE_CHAR (2, chr
);
3303 idx
= scm_i_string_length (str
);
3304 p
= scm_i_string_chars (str
);
3305 ch
= SCM_CHAR (chr
);
3309 while (idx
> 0 && p
[idx
- 1] != ch
)
3313 res
= scm_cons (scm_c_substring (str
, idx
, last_idx
), res
);
3314 p
= scm_i_string_chars (str
);
3318 scm_remember_upto_here_1 (str
);
3324 SCM_DEFINE (scm_string_filter
, "string-filter", 2, 2, 0,
3325 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
3326 "Filter the string @var{s}, retaining only those characters\n"
3327 "which satisfy @var{char_pred}.\n"
3329 "If @var{char_pred} is a procedure, it is applied to each\n"
3330 "character as a predicate, if it is a character, it is tested\n"
3331 "for equality and if it is a character set, it is tested for\n"
3333 #define FUNC_NAME s_scm_string_filter
3336 size_t cstart
, cend
;
3340 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
3344 /* The explicit loops below stripping leading and trailing non-matches
3345 mean we can return a substring if those are the only deletions, making
3346 string-filter as efficient as string-trim-both in that case. */
3348 if (SCM_CHARP (char_pred
))
3353 chr
= SCM_CHAR (char_pred
);
3355 /* strip leading non-matches by incrementing cstart */
3356 while (cstart
< cend
&& cstr
[cstart
] != chr
)
3359 /* strip trailing non-matches by decrementing cend */
3360 while (cend
> cstart
&& cstr
[cend
-1] != chr
)
3363 /* count chars to keep */
3365 for (idx
= cstart
; idx
< cend
; idx
++)
3366 if (cstr
[idx
] == chr
)
3369 if (count
== cend
- cstart
)
3371 /* whole of cstart to cend is to be kept, return a copy-on-write
3374 result
= scm_i_substring (s
, cstart
, cend
);
3377 result
= scm_c_make_string (count
, char_pred
);
3379 else if (SCM_CHARSETP (char_pred
))
3383 /* strip leading non-matches by incrementing cstart */
3384 while (cstart
< cend
&& ! SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
3387 /* strip trailing non-matches by decrementing cend */
3388 while (cend
> cstart
&& ! SCM_CHARSET_GET (char_pred
, cstr
[cend
-1]))
3391 /* count chars to be kept */
3393 for (idx
= cstart
; idx
< cend
; idx
++)
3394 if (SCM_CHARSET_GET (char_pred
, cstr
[idx
]))
3397 /* if whole of start to end kept then return substring */
3398 if (count
== cend
- cstart
)
3399 goto result_substring
;
3403 result
= scm_i_make_string (count
, &dst
);
3404 cstr
= scm_i_string_chars (s
);
3406 /* decrement "count" in this loop as well as using idx, so that if
3407 another thread is simultaneously changing "s" there's no chance
3408 it'll make us copy more than count characters */
3409 for (idx
= cstart
; idx
< cend
&& count
!= 0; idx
++)
3411 if (SCM_CHARSET_GET (char_pred
, cstr
[idx
]))
3422 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
3424 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
3429 ch
= SCM_MAKE_CHAR (cstr
[idx
]);
3430 res
= pred_tramp (char_pred
, ch
);
3431 if (scm_is_true (res
))
3432 ls
= scm_cons (ch
, ls
);
3433 cstr
= scm_i_string_chars (s
);
3436 result
= scm_reverse_list_to_string (ls
);
3439 scm_remember_upto_here_1 (s
);
3445 SCM_DEFINE (scm_string_delete
, "string-delete", 2, 2, 0,
3446 (SCM s
, SCM char_pred
, SCM start
, SCM end
),
3447 "Delete characters satisfying @var{char_pred} from @var{s}.\n"
3449 "If @var{char_pred} is a procedure, it is applied to each\n"
3450 "character as a predicate, if it is a character, it is tested\n"
3451 "for equality and if it is a character set, it is tested for\n"
3453 #define FUNC_NAME s_scm_string_delete
3456 size_t cstart
, cend
;
3460 MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s
, cstr
,
3464 /* The explicit loops below stripping leading and trailing matches mean we
3465 can return a substring if those are the only deletions, making
3466 string-delete as efficient as string-trim-both in that case. */
3468 if (SCM_CHARP (char_pred
))
3473 chr
= SCM_CHAR (char_pred
);
3475 /* strip leading matches by incrementing cstart */
3476 while (cstart
< cend
&& cstr
[cstart
] == chr
)
3479 /* strip trailing matches by decrementing cend */
3480 while (cend
> cstart
&& cstr
[cend
-1] == chr
)
3483 /* count chars to be kept */
3485 for (idx
= cstart
; idx
< cend
; idx
++)
3486 if (cstr
[idx
] != chr
)
3489 if (count
== cend
- cstart
)
3491 /* whole of cstart to cend is to be kept, return a copy-on-write
3494 result
= scm_i_substring (s
, cstart
, cend
);
3498 /* new string for retained portion */
3500 result
= scm_i_make_string (count
, &dst
);
3501 cstr
= scm_i_string_chars (s
);
3503 /* decrement "count" in this loop as well as using idx, so that if
3504 another thread is simultaneously changing "s" there's no chance
3505 it'll make us copy more than count characters */
3506 for (idx
= cstart
; idx
< cend
&& count
!= 0; idx
++)
3508 if (cstr
[idx
] != chr
)
3516 else if (SCM_CHARSETP (char_pred
))
3520 /* strip leading matches by incrementing cstart */
3521 while (cstart
< cend
&& SCM_CHARSET_GET (char_pred
, cstr
[cstart
]))
3524 /* strip trailing matches by decrementing cend */
3525 while (cend
> cstart
&& SCM_CHARSET_GET (char_pred
, cstr
[cend
-1]))
3528 /* count chars to be kept */
3530 for (idx
= cstart
; idx
< cend
; idx
++)
3531 if (! SCM_CHARSET_GET (char_pred
, cstr
[idx
]))
3534 if (count
== cend
- cstart
)
3535 goto result_substring
;
3538 /* new string for retained portion */
3540 result
= scm_i_make_string (count
, &dst
);
3541 cstr
= scm_i_string_chars (s
);
3543 /* decrement "count" in this loop as well as using idx, so that if
3544 another thread is simultaneously changing "s" there's no chance
3545 it'll make us copy more than count characters */
3546 for (idx
= cstart
; idx
< cend
&& count
!= 0; idx
++)
3548 if (! SCM_CHARSET_GET (char_pred
, cstr
[idx
]))
3559 scm_t_trampoline_1 pred_tramp
= scm_trampoline_1 (char_pred
);
3560 SCM_ASSERT (pred_tramp
, char_pred
, SCM_ARG2
, FUNC_NAME
);
3565 SCM res
, ch
= SCM_MAKE_CHAR (cstr
[idx
]);
3566 res
= pred_tramp (char_pred
, ch
);
3567 if (scm_is_false (res
))
3568 ls
= scm_cons (ch
, ls
);
3569 cstr
= scm_i_string_chars (s
);
3572 result
= scm_reverse_list_to_string (ls
);
3575 scm_remember_upto_here_1 (s
);
3581 scm_init_srfi_13 (void)
3583 #include "libguile/srfi-13.x"
3586 /* End of srfi-13.c. */