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