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