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