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