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