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