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