* tags.h, deprecated.h (SCM_EQ_P): Deprecated by moving it into
[bpt/guile.git] / srfi / srfi-13.c
1 /* srfi-13.c --- SRFI-13 procedures for Guile
2 *
3 * Copyright (C) 2001, 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 #include <string.h>
22 #include <ctype.h>
23
24 #include <libguile.h>
25
26 #include "srfi-13.h"
27 #include "srfi-14.h"
28
29 SCM_DEFINE (scm_string_any, "string-any", 2, 2, 0,
30 (SCM pred, SCM s, SCM start, SCM end),
31 "Check if the predicate @var{pred} is true for any character in\n"
32 "the string @var{s}, proceeding from left (index @var{start}) to\n"
33 "right (index @var{end}). If @code{string-any} returns true,\n"
34 "the returned true value is the one produced by the first\n"
35 "successful application of @var{pred}.")
36 #define FUNC_NAME s_scm_string_any
37 {
38 char * cstr;
39 int cstart, cend;
40 SCM res;
41
42 SCM_VALIDATE_PROC (1, pred);
43 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
44 3, start, cstart,
45 4, end, cend);
46 cstr += cstart;
47 while (cstart < cend)
48 {
49 res = scm_call_1 (pred, SCM_MAKE_CHAR (*cstr));
50 if (scm_is_true (res))
51 return res;
52 cstr++;
53 cstart++;
54 }
55 return SCM_BOOL_F;
56 }
57 #undef FUNC_NAME
58
59
60 SCM_DEFINE (scm_string_every, "string-every", 2, 2, 0,
61 (SCM pred, SCM s, SCM start, SCM end),
62 "Check if the predicate @var{pred} is true for every character\n"
63 "in the string @var{s}, proceeding from left (index @var{start})\n"
64 "to right (index @var{end}). If @code{string-every} returns\n"
65 "true, the returned true value is the one produced by the final\n"
66 "application of @var{pred} to the last character of @var{s}.")
67 #define FUNC_NAME s_scm_string_every
68 {
69 char * cstr;
70 int cstart, cend;
71 SCM res;
72
73 SCM_VALIDATE_PROC (1, pred);
74 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
75 3, start, cstart,
76 4, end, cend);
77 res = SCM_BOOL_F;
78 cstr += cstart;
79 while (cstart < cend)
80 {
81 res = scm_call_1 (pred, SCM_MAKE_CHAR (*cstr));
82 if (scm_is_false (res))
83 return res;
84 cstr++;
85 cstart++;
86 }
87 return res;
88 }
89 #undef FUNC_NAME
90
91
92 SCM_DEFINE (scm_string_tabulate, "string-tabulate", 2, 0, 0,
93 (SCM proc, SCM len),
94 "@var{proc} is an integer->char procedure. Construct a string\n"
95 "of size @var{len} by applying @var{proc} to each index to\n"
96 "produce the corresponding string element. The order in which\n"
97 "@var{proc} is applied to the indices is not specified.")
98 #define FUNC_NAME s_scm_string_tabulate
99 {
100 size_t clen, i;
101 SCM res;
102 SCM ch;
103 char * p;
104
105 SCM_VALIDATE_PROC (1, proc);
106 clen = scm_to_size_t (len);
107 SCM_ASSERT_RANGE (2, len, clen >= 0);
108
109 res = scm_allocate_string (clen);
110 p = SCM_STRING_CHARS (res);
111 i = 0;
112 while (i < clen)
113 {
114 ch = scm_call_1 (proc, scm_from_int (i));
115 if (!SCM_CHARP (ch))
116 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
117 *p++ = SCM_CHAR (ch);
118 i++;
119 }
120 return res;
121 }
122 #undef FUNC_NAME
123
124
125 SCM_DEFINE (scm_string_to_listS, "string->list", 1, 2, 0,
126 (SCM str, SCM start, SCM end),
127 "Convert the string @var{str} into a list of characters.")
128 #define FUNC_NAME s_scm_string_to_listS
129 {
130 char * cstr;
131 int cstart, cend;
132 SCM result = SCM_EOL;
133
134 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
135 2, start, cstart,
136 3, end, cend);
137 while (cstart < cend)
138 {
139 cend--;
140 result = scm_cons (SCM_MAKE_CHAR (cstr[cend]), result);
141 }
142 return result;
143 }
144 #undef FUNC_NAME
145
146 SCM_DEFINE (scm_reverse_list_to_string, "reverse-list->string", 1, 0, 0,
147 (SCM chrs),
148 "An efficient implementation of @code{(compose string->list\n"
149 "reverse)}:\n"
150 "\n"
151 "@smalllisp\n"
152 "(reverse-list->string '(#\a #\B #\c)) @result{} \"cBa\"\n"
153 "@end smalllisp")
154 #define FUNC_NAME s_scm_reverse_list_to_string
155 {
156 SCM result;
157 long i = scm_ilength (chrs);
158
159 if (i < 0)
160 SCM_WRONG_TYPE_ARG (1, chrs);
161 result = scm_allocate_string (i);
162
163 {
164 unsigned char *data = SCM_STRING_UCHARS (result) + i;
165
166 while (!SCM_NULLP (chrs))
167 {
168 SCM elt = SCM_CAR (chrs);
169
170 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
171 data--;
172 *data = SCM_CHAR (elt);
173 chrs = SCM_CDR (chrs);
174 }
175 }
176 return result;
177 }
178 #undef FUNC_NAME
179
180
181 SCM_SYMBOL (scm_sym_infix, "infix");
182 SCM_SYMBOL (scm_sym_strict_infix, "strict-infix");
183 SCM_SYMBOL (scm_sym_suffix, "suffix");
184 SCM_SYMBOL (scm_sym_prefix, "prefix");
185
186 SCM_DEFINE (scm_string_join, "string-join", 1, 2, 0,
187 (SCM ls, SCM delimiter, SCM grammar),
188 "Append the string in the string list @var{ls}, using the string\n"
189 "@var{delim} as a delimiter between the elements of @var{ls}.\n"
190 "@var{grammar} is a symbol which specifies how the delimiter is\n"
191 "placed between the strings, and defaults to the symbol\n"
192 "@code{infix}.\n"
193 "\n"
194 "@table @code\n"
195 "@item infix\n"
196 "Insert the separator between list elements. An empty string\n"
197 "will produce an empty list.\n"
198 "@item string-infix\n"
199 "Like @code{infix}, but will raise an error if given the empty\n"
200 "list.\n"
201 "@item suffix\n"
202 "Insert the separator after every list element.\n"
203 "@item prefix\n"
204 "Insert the separator before each list element.\n"
205 "@end table")
206 #define FUNC_NAME s_scm_string_join
207 {
208 #define GRAM_INFIX 0
209 #define GRAM_STRICT_INFIX 1
210 #define GRAM_SUFFIX 2
211 #define GRAM_PREFIX 3
212 SCM tmp;
213 SCM result;
214 int gram = GRAM_INFIX;
215 int del_len = 0, extra_len = 0;
216 int len = 0;
217 char * p;
218 long strings = scm_ilength (ls);
219
220 /* Validate the string list. */
221 if (strings < 0)
222 SCM_WRONG_TYPE_ARG (1, ls);
223
224 /* Validate the delimiter and record its length. */
225 if (SCM_UNBNDP (delimiter))
226 {
227 delimiter = scm_makfrom0str (" ");
228 del_len = 1;
229 }
230 else
231 {
232 SCM_VALIDATE_STRING (2, delimiter);
233 del_len = SCM_STRING_LENGTH (delimiter);
234 }
235
236 /* Validate the grammar symbol and remember the grammar. */
237 if (SCM_UNBNDP (grammar))
238 gram = GRAM_INFIX;
239 else if (scm_is_eq (grammar, scm_sym_infix))
240 gram = GRAM_INFIX;
241 else if (scm_is_eq (grammar, scm_sym_strict_infix))
242 gram = GRAM_STRICT_INFIX;
243 else if (scm_is_eq (grammar, scm_sym_suffix))
244 gram = GRAM_SUFFIX;
245 else if (scm_is_eq (grammar, scm_sym_prefix))
246 gram = GRAM_PREFIX;
247 else
248 SCM_WRONG_TYPE_ARG (3, grammar);
249
250 /* Check grammar constraints and calculate the space required for
251 the delimiter(s). */
252 switch (gram)
253 {
254 case GRAM_INFIX:
255 if (!SCM_NULLP (ls))
256 extra_len = (strings > 0) ? ((strings - 1) * del_len) : 0;
257 break;
258 case GRAM_STRICT_INFIX:
259 if (strings == 0)
260 SCM_MISC_ERROR ("strict-infix grammar requires non-empty list",
261 SCM_EOL);
262 extra_len = (strings - 1) * del_len;
263 break;
264 default:
265 extra_len = strings * del_len;
266 break;
267 }
268
269 tmp = ls;
270 while (SCM_CONSP (tmp))
271 {
272 SCM elt = SCM_CAR (tmp);
273 SCM_VALIDATE_STRING (1, elt);
274 len += SCM_STRING_LENGTH (elt);
275 tmp = SCM_CDR (tmp);
276 }
277
278 result = scm_allocate_string (len + extra_len);
279 p = SCM_STRING_CHARS (result);
280
281 tmp = ls;
282 switch (gram)
283 {
284 case GRAM_INFIX:
285 case GRAM_STRICT_INFIX:
286 while (!SCM_NULLP (tmp))
287 {
288 SCM elt = SCM_CAR (tmp);
289 memmove (p, SCM_STRING_CHARS (elt),
290 SCM_STRING_LENGTH (elt) * sizeof (char));
291 p += SCM_STRING_LENGTH (elt);
292 if (!SCM_NULLP (SCM_CDR (tmp)) && del_len > 0)
293 {
294 memmove (p, SCM_STRING_CHARS (delimiter),
295 SCM_STRING_LENGTH (delimiter) * sizeof (char));
296 p += del_len;
297 }
298 tmp = SCM_CDR (tmp);
299 }
300 break;
301 case GRAM_SUFFIX:
302 while (!SCM_NULLP (tmp))
303 {
304 SCM elt = SCM_CAR (tmp);
305 memmove (p, SCM_STRING_CHARS (elt),
306 SCM_STRING_LENGTH (elt) * sizeof (char));
307 p += SCM_STRING_LENGTH (elt);
308 if (del_len > 0)
309 {
310 memmove (p, SCM_STRING_CHARS (delimiter),
311 SCM_STRING_LENGTH (delimiter) * sizeof (char));
312 p += del_len;
313 }
314 tmp = SCM_CDR (tmp);
315 }
316 break;
317 case GRAM_PREFIX:
318 while (!SCM_NULLP (tmp))
319 {
320 SCM elt = SCM_CAR (tmp);
321 if (del_len > 0)
322 {
323 memmove (p, SCM_STRING_CHARS (delimiter),
324 SCM_STRING_LENGTH (delimiter) * sizeof (char));
325 p += del_len;
326 }
327 memmove (p, SCM_STRING_CHARS (elt),
328 SCM_STRING_LENGTH (elt) * sizeof (char));
329 p += SCM_STRING_LENGTH (elt);
330 tmp = SCM_CDR (tmp);
331 }
332 break;
333 }
334 return result;
335 #undef GRAM_INFIX
336 #undef GRAM_STRICT_INFIX
337 #undef GRAM_SUFFIX
338 #undef GRAM_PREFIX
339 }
340 #undef FUNC_NAME
341
342
343 SCM_DEFINE (scm_string_copyS, "string-copy", 1, 2, 0,
344 (SCM str, SCM start, SCM end),
345 "Return a freshly allocated copy of the string @var{str}. If\n"
346 "given, @var{start} and @var{end} delimit the portion of\n"
347 "@var{str} which is copied.")
348 #define FUNC_NAME s_scm_string_copyS
349 {
350 char * cstr;
351 int cstart, cend;
352
353 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
354 2, start, cstart,
355 3, end, cend);
356 return scm_mem2string (cstr + cstart, cend - cstart);
357
358 }
359 #undef FUNC_NAME
360
361
362 SCM_DEFINE (scm_substring_shared, "substring/shared", 2, 1, 0,
363 (SCM str, SCM start, SCM end),
364 "Like @code{substring}, but the result may share memory with the\n"
365 "argument @var{str}.")
366 #define FUNC_NAME s_scm_substring_shared
367 {
368 size_t s, e;
369 SCM_VALIDATE_STRING (1, str);
370 s = scm_to_size_t (start);
371 if (SCM_UNBNDP (end))
372 e = SCM_STRING_LENGTH (str);
373 else
374 e = scm_to_size_t (end);
375 if (s == 0 && e == SCM_STRING_LENGTH (str))
376 return str;
377 else
378 return scm_substring (str, start, end);
379 }
380 #undef FUNC_NAME
381
382
383 SCM_DEFINE (scm_string_copy_x, "string-copy!", 3, 2, 0,
384 (SCM target, SCM tstart, SCM s, SCM start, SCM end),
385 "Copy the sequence of characters from index range [@var{start},\n"
386 "@var{end}) in string @var{s} to string @var{target}, beginning\n"
387 "at index @var{tstart}. The characters are copied left-to-right\n"
388 "or right-to-left as needed -- the copy is guaranteed to work,\n"
389 "even if @var{target} and @var{s} are the same string. It is an\n"
390 "error if the copy operation runs off the end of the target\n"
391 "string.")
392 #define FUNC_NAME s_scm_string_copy_x
393 {
394 char * cstr, * ctarget;
395 int cstart, cend, ctstart, dummy;
396 int len;
397 SCM sdummy = SCM_UNDEFINED;
398
399 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, target, ctarget,
400 2, tstart, ctstart,
401 2, sdummy, dummy);
402 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
403 4, start, cstart,
404 5, end, cend);
405 len = cend - cstart;
406 SCM_ASSERT_RANGE (3, s, len <= SCM_STRING_LENGTH (target) - ctstart);
407
408 memmove (SCM_STRING_CHARS (target) + ctstart,
409 SCM_STRING_CHARS (s) + cstart,
410 len * sizeof (char));
411 return SCM_UNSPECIFIED;
412 }
413 #undef FUNC_NAME
414
415
416 SCM_DEFINE (scm_string_take, "string-take", 2, 0, 0,
417 (SCM s, SCM n),
418 "Return the @var{n} first characters of @var{s}.")
419 #define FUNC_NAME s_scm_string_take
420 {
421 char * cstr;
422 size_t cn;
423
424 SCM_VALIDATE_STRING_COPY (1, s, cstr);
425 cn = scm_to_unsigned_integer (n, 0, SCM_STRING_LENGTH (s));
426
427 return scm_mem2string (cstr, cn);
428 }
429 #undef FUNC_NAME
430
431
432 SCM_DEFINE (scm_string_drop, "string-drop", 2, 0, 0,
433 (SCM s, SCM n),
434 "Return all but the first @var{n} characters of @var{s}.")
435 #define FUNC_NAME s_scm_string_drop
436 {
437 char * cstr;
438 size_t cn;
439
440 SCM_VALIDATE_STRING_COPY (1, s, cstr);
441 cn = scm_to_unsigned_integer (n, 0, SCM_STRING_LENGTH (s));
442
443 return scm_mem2string (cstr + cn, SCM_STRING_LENGTH (s) - cn);
444 }
445 #undef FUNC_NAME
446
447
448 SCM_DEFINE (scm_string_take_right, "string-take-right", 2, 0, 0,
449 (SCM s, SCM n),
450 "Return the @var{n} last characters of @var{s}.")
451 #define FUNC_NAME s_scm_string_take_right
452 {
453 char * cstr;
454 size_t cn;
455
456 SCM_VALIDATE_STRING_COPY (1, s, cstr);
457 cn = scm_to_unsigned_integer (n, 0, SCM_STRING_LENGTH (s));
458
459 return scm_mem2string (cstr + SCM_STRING_LENGTH (s) - cn, cn);
460 }
461 #undef FUNC_NAME
462
463
464 SCM_DEFINE (scm_string_drop_right, "string-drop-right", 2, 0, 0,
465 (SCM s, SCM n),
466 "Return all but the last @var{n} characters of @var{s}.")
467 #define FUNC_NAME s_scm_string_drop_right
468 {
469 char * cstr;
470 size_t cn;
471
472 SCM_VALIDATE_STRING_COPY (1, s, cstr);
473 cn = scm_to_unsigned_integer (n, 0, SCM_STRING_LENGTH (s));
474
475 return scm_mem2string (cstr, SCM_STRING_LENGTH (s) - cn);
476 }
477 #undef FUNC_NAME
478
479
480 SCM_DEFINE (scm_string_pad, "string-pad", 2, 3, 0,
481 (SCM s, SCM len, SCM chr, SCM start, SCM end),
482 "Take that characters from @var{start} to @var{end} from the\n"
483 "string @var{s} and return a new string, right-padded by the\n"
484 "character @var{chr} to length @var{len}. If the resulting\n"
485 "string is longer than @var{len}, it is truncated on the right.")
486 #define FUNC_NAME s_scm_string_pad
487 {
488 char cchr;
489 char * cstr;
490 size_t cstart, cend, clen;
491 SCM result;
492
493 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
494 4, start, cstart,
495 5, end, cend);
496 clen = scm_to_size_t (len);
497
498 if (SCM_UNBNDP (chr))
499 cchr = ' ';
500 else
501 {
502 SCM_VALIDATE_CHAR (3, chr);
503 cchr = SCM_CHAR (chr);
504 }
505 result = scm_allocate_string (clen);
506 if (clen < (cend - cstart))
507 memmove (SCM_STRING_CHARS (result),
508 cstr + cend - clen,
509 clen * sizeof (char));
510 else
511 {
512 memset (SCM_STRING_CHARS (result), cchr,
513 (clen - (cend - cstart)) * sizeof (char));
514 memmove (SCM_STRING_CHARS (result) + (clen - (cend - cstart)),
515 cstr + cstart,
516 (cend - cstart) * sizeof (char));
517 }
518 return result;
519 }
520 #undef FUNC_NAME
521
522
523 SCM_DEFINE (scm_string_pad_right, "string-pad-right", 2, 3, 0,
524 (SCM s, SCM len, SCM chr, SCM start, SCM end),
525 "Take that characters from @var{start} to @var{end} from the\n"
526 "string @var{s} and return a new string, left-padded by the\n"
527 "character @var{chr} to length @var{len}. If the resulting\n"
528 "string is longer than @var{len}, it is truncated on the left.")
529 #define FUNC_NAME s_scm_string_pad_right
530 {
531 char cchr;
532 char * cstr;
533 size_t cstart, cend, clen;
534 SCM result;
535
536 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
537 4, start, cstart,
538 5, end, cend);
539 clen = scm_to_size_t (len);
540
541 if (SCM_UNBNDP (chr))
542 cchr = ' ';
543 else
544 {
545 SCM_VALIDATE_CHAR (3, chr);
546 cchr = SCM_CHAR (chr);
547 }
548 result = scm_allocate_string (clen);
549 if (clen < (cend - cstart))
550 memmove (SCM_STRING_CHARS (result), cstr + cstart, clen * sizeof (char));
551 else
552 {
553 memset (SCM_STRING_CHARS (result) + (cend - cstart),
554 cchr, (clen - (cend - cstart)) * sizeof (char));
555 memmove (SCM_STRING_CHARS (result), cstr + cstart,
556 (cend - cstart) * sizeof (char));
557 }
558 return result;
559 }
560 #undef FUNC_NAME
561
562
563 SCM_DEFINE (scm_string_trim, "string-trim", 1, 3, 0,
564 (SCM s, SCM char_pred, SCM start, SCM end),
565 "Trim @var{s} by skipping over all characters on the left\n"
566 "that satisfy the parameter @var{char_pred}:\n"
567 "\n"
568 "@itemize @bullet\n"
569 "@item\n"
570 "if it is the character @var{ch}, characters equal to\n"
571 "@var{ch} are trimmed,\n"
572 "\n"
573 "@item\n"
574 "if it is a procedure @var{pred} characters that\n"
575 "satisfy @var{pred} are trimmed,\n"
576 "\n"
577 "@item\n"
578 "if it is a character set, characters in that set are trimmed.\n"
579 "@end itemize\n"
580 "\n"
581 "If called without a @var{char_pred} argument, all whitespace is\n"
582 "trimmed.")
583 #define FUNC_NAME s_scm_string_trim
584 {
585 char * cstr;
586 size_t cstart, cend;
587
588 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
589 3, start, cstart,
590 4, end, cend);
591 if (SCM_UNBNDP (char_pred))
592 {
593 while (cstart < cend)
594 {
595 if (!isspace((int) (unsigned char) cstr[cstart]))
596 break;
597 cstart++;
598 }
599 }
600 else if (SCM_CHARP (char_pred))
601 {
602 char chr = SCM_CHAR (char_pred);
603 while (cstart < cend)
604 {
605 if (chr != cstr[cstart])
606 break;
607 cstart++;
608 }
609 }
610 else if (SCM_CHARSETP (char_pred))
611 {
612 while (cstart < cend)
613 {
614 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
615 break;
616 cstart++;
617 }
618 }
619 else
620 {
621 SCM_VALIDATE_PROC (2, char_pred);
622 while (cstart < cend)
623 {
624 SCM res;
625
626 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
627 if (scm_is_false (res))
628 break;
629 cstart++;
630 }
631 }
632 return scm_mem2string (cstr + cstart, cend - cstart);
633 }
634 #undef FUNC_NAME
635
636
637 SCM_DEFINE (scm_string_trim_right, "string-trim-right", 1, 3, 0,
638 (SCM s, SCM char_pred, SCM start, SCM end),
639 "Trim @var{s} by skipping over all characters on the rightt\n"
640 "that satisfy the parameter @var{char_pred}:\n"
641 "\n"
642 "@itemize @bullet\n"
643 "@item\n"
644 "if it is the character @var{ch}, characters equal to @var{ch}\n"
645 "are trimmed,\n"
646 "\n"
647 "@item\n"
648 "if it is a procedure @var{pred} characters that satisfy\n"
649 "@var{pred} are trimmed,\n"
650 "\n"
651 "@item\n"
652 "if it is a character sets, all characters in that set are\n"
653 "trimmed.\n"
654 "@end itemize\n"
655 "\n"
656 "If called without a @var{char_pred} argument, all whitespace is\n"
657 "trimmed.")
658 #define FUNC_NAME s_scm_string_trim_right
659 {
660 char * cstr;
661 int cstart, cend;
662
663 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
664 3, start, cstart,
665 4, end, cend);
666 if (SCM_UNBNDP (char_pred))
667 {
668 while (cstart < cend)
669 {
670 if (!isspace((int) (unsigned char) cstr[cend - 1]))
671 break;
672 cend--;
673 }
674 }
675 else if (SCM_CHARP (char_pred))
676 {
677 char chr = SCM_CHAR (char_pred);
678 while (cstart < cend)
679 {
680 if (chr != cstr[cend - 1])
681 break;
682 cend--;
683 }
684 }
685 else if (SCM_CHARSETP (char_pred))
686 {
687 while (cstart < cend)
688 {
689 if (!SCM_CHARSET_GET (char_pred, cstr[cend - 1]))
690 break;
691 cend--;
692 }
693 }
694 else
695 {
696 SCM_VALIDATE_PROC (2, char_pred);
697 while (cstart < cend)
698 {
699 SCM res;
700
701 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend - 1]));
702 if (scm_is_false (res))
703 break;
704 cend--;
705 }
706 }
707 return scm_mem2string (cstr + cstart, cend - cstart);
708 }
709 #undef FUNC_NAME
710
711
712 SCM_DEFINE (scm_string_trim_both, "string-trim-both", 1, 3, 0,
713 (SCM s, SCM char_pred, SCM start, SCM end),
714 "Trim @var{s} by skipping over all characters on both sides of\n"
715 "the string that satisfy the parameter @var{char_pred}:\n"
716 "\n"
717 "@itemize @bullet\n"
718 "@item\n"
719 "if it is the character @var{ch}, characters equal to @var{ch}\n"
720 "are trimmed,\n"
721 "\n"
722 "@item\n"
723 "if it is a procedure @var{pred} characters that satisfy\n"
724 "@var{pred} are trimmed,\n"
725 "\n"
726 "@item\n"
727 "if it is a character set, the characters in the set are\n"
728 "trimmed.\n"
729 "@end itemize\n"
730 "\n"
731 "If called without a @var{char_pred} argument, all whitespace is\n"
732 "trimmed.")
733 #define FUNC_NAME s_scm_string_trim_both
734 {
735 char * cstr;
736 int cstart, cend;
737
738 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
739 3, start, cstart,
740 4, end, cend);
741 if (SCM_UNBNDP (char_pred))
742 {
743 while (cstart < cend)
744 {
745 if (!isspace((int) (unsigned char) cstr[cstart]))
746 break;
747 cstart++;
748 }
749 while (cstart < cend)
750 {
751 if (!isspace((int) (unsigned char) cstr[cend - 1]))
752 break;
753 cend--;
754 }
755 }
756 else if (SCM_CHARP (char_pred))
757 {
758 char chr = SCM_CHAR (char_pred);
759 while (cstart < cend)
760 {
761 if (chr != cstr[cstart])
762 break;
763 cstart++;
764 }
765 while (cstart < cend)
766 {
767 if (chr != cstr[cend - 1])
768 break;
769 cend--;
770 }
771 }
772 else if (SCM_CHARSETP (char_pred))
773 {
774 while (cstart < cend)
775 {
776 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
777 break;
778 cstart++;
779 }
780 while (cstart < cend)
781 {
782 if (!SCM_CHARSET_GET (char_pred, cstr[cend - 1]))
783 break;
784 cend--;
785 }
786 }
787 else
788 {
789 SCM_VALIDATE_PROC (2, char_pred);
790 while (cstart < cend)
791 {
792 SCM res;
793
794 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
795 if (scm_is_false (res))
796 break;
797 cstart++;
798 }
799 while (cstart < cend)
800 {
801 SCM res;
802
803 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend - 1]));
804 if (scm_is_false (res))
805 break;
806 cend--;
807 }
808 }
809 return scm_mem2string (cstr + cstart, cend - cstart);
810 }
811 #undef FUNC_NAME
812
813
814 SCM_DEFINE (scm_string_fill_xS, "string-fill!", 2, 2, 0,
815 (SCM str, SCM chr, SCM start, SCM end),
816 "Stores @var{chr} in every element of the given @var{str} and\n"
817 "returns an unspecified value.")
818 #define FUNC_NAME s_scm_string_fill_xS
819 {
820 char * cstr;
821 int cstart, cend;
822 int c;
823 long k;
824
825 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
826 3, start, cstart,
827 4, end, cend);
828 SCM_VALIDATE_CHAR_COPY (2, chr, c);
829 for (k = cstart; k < cend; k++)
830 cstr[k] = c;
831 return SCM_UNSPECIFIED;
832 }
833 #undef FUNC_NAME
834
835
836 SCM_DEFINE (scm_string_compare, "string-compare", 5, 4, 0,
837 (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
838 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
839 "mismatch index, depending upon whether @var{s1} is less than,\n"
840 "equal to, or greater than @var{s2}. The mismatch index is the\n"
841 "largest index @var{i} such that for every 0 <= @var{j} <\n"
842 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
843 "@var{i} is the first position that does not match.")
844 #define FUNC_NAME s_scm_string_compare
845 {
846 char * cstr1, * cstr2;
847 int cstart1, cend1, cstart2, cend2;
848
849 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
850 6, start1, cstart1,
851 7, end1, cend1);
852 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
853 8, start2, cstart2,
854 9, end2, cend2);
855 SCM_VALIDATE_PROC (3, proc_lt);
856 SCM_VALIDATE_PROC (4, proc_eq);
857 SCM_VALIDATE_PROC (5, proc_gt);
858
859 while (cstart1 < cend1 && cstart2 < cend2)
860 {
861 if (cstr1[cstart1] < cstr2[cstart2])
862 return scm_call_1 (proc_lt, SCM_I_MAKINUM (cstart1));
863 else if (cstr1[cstart1] > cstr2[cstart2])
864 return scm_call_1 (proc_gt, SCM_I_MAKINUM (cstart1));
865 cstart1++;
866 cstart2++;
867 }
868 if (cstart1 < cend1)
869 return scm_call_1 (proc_gt, SCM_I_MAKINUM (cstart1));
870 else if (cstart2 < cend2)
871 return scm_call_1 (proc_lt, SCM_I_MAKINUM (cstart1));
872 else
873 return scm_call_1 (proc_eq, SCM_I_MAKINUM (cstart1));
874 }
875 #undef FUNC_NAME
876
877
878 SCM_DEFINE (scm_string_compare_ci, "string-compare-ci", 5, 4, 0,
879 (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
880 "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
881 "mismatch index, depending upon whether @var{s1} is less than,\n"
882 "equal to, or greater than @var{s2}. The mismatch index is the\n"
883 "largest index @var{i} such that for every 0 <= @var{j} <\n"
884 "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
885 "@var{i} is the first position that does not match. The\n"
886 "character comparison is done case-insensitively.")
887 #define FUNC_NAME s_scm_string_compare_ci
888 {
889 char * cstr1, * cstr2;
890 int cstart1, cend1, cstart2, cend2;
891
892 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
893 6, start1, cstart1,
894 7, end1, cend1);
895 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
896 8, start2, cstart2,
897 9, end2, cend2);
898 SCM_VALIDATE_PROC (3, proc_lt);
899 SCM_VALIDATE_PROC (4, proc_eq);
900 SCM_VALIDATE_PROC (5, proc_gt);
901
902 while (cstart1 < cend1 && cstart2 < cend2)
903 {
904 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
905 return scm_call_1 (proc_lt, SCM_I_MAKINUM (cstart1));
906 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
907 return scm_call_1 (proc_gt, SCM_I_MAKINUM (cstart1));
908 cstart1++;
909 cstart2++;
910 }
911 if (cstart1 < cend1)
912 return scm_call_1 (proc_gt, SCM_I_MAKINUM (cstart1));
913 else if (cstart2 < cend2)
914 return scm_call_1 (proc_lt, SCM_I_MAKINUM (cstart1));
915 else
916 return scm_call_1 (proc_eq, SCM_I_MAKINUM (cstart1));
917 }
918 #undef FUNC_NAME
919
920
921 SCM_DEFINE (scm_string_eq, "string=", 2, 4, 0,
922 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
923 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
924 "value otherwise.")
925 #define FUNC_NAME s_scm_string_eq
926 {
927 char * cstr1, * cstr2;
928 int cstart1, cend1, cstart2, cend2;
929
930 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
931 3, start1, cstart1,
932 4, end1, cend1);
933 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
934 5, start2, cstart2,
935 6, end2, cend2);
936
937 while (cstart1 < cend1 && cstart2 < cend2)
938 {
939 if (cstr1[cstart1] < cstr2[cstart2])
940 return SCM_BOOL_F;
941 else if (cstr1[cstart1] > cstr2[cstart2])
942 return SCM_BOOL_F;
943 cstart1++;
944 cstart2++;
945 }
946 if (cstart1 < cend1)
947 return SCM_BOOL_F;
948 else if (cstart2 < cend2)
949 return SCM_BOOL_F;
950 else
951 return SCM_I_MAKINUM (cstart1);
952 }
953 #undef FUNC_NAME
954
955
956 SCM_DEFINE (scm_string_neq, "string<>", 2, 4, 0,
957 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
958 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
959 "value otherwise.")
960 #define FUNC_NAME s_scm_string_neq
961 {
962 char * cstr1, * cstr2;
963 int cstart1, cend1, cstart2, cend2;
964
965 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
966 3, start1, cstart1,
967 4, end1, cend1);
968 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
969 5, start2, cstart2,
970 6, end2, cend2);
971
972 while (cstart1 < cend1 && cstart2 < cend2)
973 {
974 if (cstr1[cstart1] < cstr2[cstart2])
975 return SCM_I_MAKINUM (cstart1);
976 else if (cstr1[cstart1] > cstr2[cstart2])
977 return SCM_I_MAKINUM (cstart1);
978 cstart1++;
979 cstart2++;
980 }
981 if (cstart1 < cend1)
982 return SCM_I_MAKINUM (cstart1);
983 else if (cstart2 < cend2)
984 return SCM_I_MAKINUM (cstart1);
985 else
986 return SCM_BOOL_F;
987 }
988 #undef FUNC_NAME
989
990
991 SCM_DEFINE (scm_string_lt, "string<", 2, 4, 0,
992 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
993 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
994 "true value otherwise.")
995 #define FUNC_NAME s_scm_string_lt
996 {
997 char * cstr1, * cstr2;
998 int cstart1, cend1, cstart2, cend2;
999
1000 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1001 3, start1, cstart1,
1002 4, end1, cend1);
1003 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1004 5, start2, cstart2,
1005 6, end2, cend2);
1006
1007 while (cstart1 < cend1 && cstart2 < cend2)
1008 {
1009 if (cstr1[cstart1] < cstr2[cstart2])
1010 return SCM_I_MAKINUM (cstart1);
1011 else if (cstr1[cstart1] > cstr2[cstart2])
1012 return SCM_BOOL_F;
1013 cstart1++;
1014 cstart2++;
1015 }
1016 if (cstart1 < cend1)
1017 return SCM_BOOL_F;
1018 else if (cstart2 < cend2)
1019 return SCM_I_MAKINUM (cstart1);
1020 else
1021 return SCM_BOOL_F;
1022 }
1023 #undef FUNC_NAME
1024
1025
1026 SCM_DEFINE (scm_string_gt, "string>", 2, 4, 0,
1027 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1028 "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
1029 "true value otherwise.")
1030 #define FUNC_NAME s_scm_string_gt
1031 {
1032 char * cstr1, * cstr2;
1033 int cstart1, cend1, cstart2, cend2;
1034
1035 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1036 3, start1, cstart1,
1037 4, end1, cend1);
1038 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1039 5, start2, cstart2,
1040 6, end2, cend2);
1041
1042 while (cstart1 < cend1 && cstart2 < cend2)
1043 {
1044 if (cstr1[cstart1] < cstr2[cstart2])
1045 return SCM_BOOL_F;
1046 else if (cstr1[cstart1] > cstr2[cstart2])
1047 return SCM_I_MAKINUM (cstart1);
1048 cstart1++;
1049 cstart2++;
1050 }
1051 if (cstart1 < cend1)
1052 return SCM_I_MAKINUM (cstart1);
1053 else if (cstart2 < cend2)
1054 return SCM_BOOL_F;
1055 else
1056 return SCM_BOOL_F;
1057 }
1058 #undef FUNC_NAME
1059
1060
1061 SCM_DEFINE (scm_string_le, "string<=", 2, 4, 0,
1062 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1063 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1064 "value otherwise.")
1065 #define FUNC_NAME s_scm_string_le
1066 {
1067 char * cstr1, * cstr2;
1068 int cstart1, cend1, cstart2, cend2;
1069
1070 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1071 3, start1, cstart1,
1072 4, end1, cend1);
1073 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1074 5, start2, cstart2,
1075 6, end2, cend2);
1076
1077 while (cstart1 < cend1 && cstart2 < cend2)
1078 {
1079 if (cstr1[cstart1] < cstr2[cstart2])
1080 return SCM_I_MAKINUM (cstart1);
1081 else if (cstr1[cstart1] > cstr2[cstart2])
1082 return SCM_BOOL_F;
1083 cstart1++;
1084 cstart2++;
1085 }
1086 if (cstart1 < cend1)
1087 return SCM_BOOL_F;
1088 else if (cstart2 < cend2)
1089 return SCM_I_MAKINUM (cstart1);
1090 else
1091 return SCM_I_MAKINUM (cstart1);
1092 }
1093 #undef FUNC_NAME
1094
1095
1096 SCM_DEFINE (scm_string_ge, "string>=", 2, 4, 0,
1097 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1098 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1099 "otherwise.")
1100 #define FUNC_NAME s_scm_string_ge
1101 {
1102 char * cstr1, * cstr2;
1103 int cstart1, cend1, cstart2, cend2;
1104
1105 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1106 3, start1, cstart1,
1107 4, end1, cend1);
1108 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1109 5, start2, cstart2,
1110 6, end2, cend2);
1111
1112 while (cstart1 < cend1 && cstart2 < cend2)
1113 {
1114 if (cstr1[cstart1] < cstr2[cstart2])
1115 return SCM_BOOL_F;
1116 else if (cstr1[cstart1] > cstr2[cstart2])
1117 return SCM_I_MAKINUM (cstart1);
1118 cstart1++;
1119 cstart2++;
1120 }
1121 if (cstart1 < cend1)
1122 return SCM_I_MAKINUM (cstart1);
1123 else if (cstart2 < cend2)
1124 return SCM_BOOL_F;
1125 else
1126 return SCM_I_MAKINUM (cstart1);
1127 }
1128 #undef FUNC_NAME
1129
1130
1131 SCM_DEFINE (scm_string_ci_eq, "string-ci=", 2, 4, 0,
1132 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1133 "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
1134 "value otherwise. The character comparison is done\n"
1135 "case-insensitively.")
1136 #define FUNC_NAME s_scm_string_ci_eq
1137 {
1138 char * cstr1, * cstr2;
1139 int cstart1, cend1, cstart2, cend2;
1140
1141 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1142 3, start1, cstart1,
1143 4, end1, cend1);
1144 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1145 5, start2, cstart2,
1146 6, end2, cend2);
1147
1148 while (cstart1 < cend1 && cstart2 < cend2)
1149 {
1150 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1151 return SCM_BOOL_F;
1152 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1153 return SCM_BOOL_F;
1154 cstart1++;
1155 cstart2++;
1156 }
1157 if (cstart1 < cend1)
1158 return SCM_BOOL_F;
1159 else if (cstart2 < cend2)
1160 return SCM_BOOL_F;
1161 else
1162 return SCM_I_MAKINUM (cstart1);
1163 }
1164 #undef FUNC_NAME
1165
1166
1167 SCM_DEFINE (scm_string_ci_neq, "string-ci<>", 2, 4, 0,
1168 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1169 "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
1170 "value otherwise. The character comparison is done\n"
1171 "case-insensitively.")
1172 #define FUNC_NAME s_scm_string_ci_neq
1173 {
1174 char * cstr1, * cstr2;
1175 int cstart1, cend1, cstart2, cend2;
1176
1177 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1178 3, start1, cstart1,
1179 4, end1, cend1);
1180 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1181 5, start2, cstart2,
1182 6, end2, cend2);
1183
1184 while (cstart1 < cend1 && cstart2 < cend2)
1185 {
1186 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1187 return SCM_I_MAKINUM (cstart1);
1188 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1189 return SCM_I_MAKINUM (cstart1);
1190 cstart1++;
1191 cstart2++;
1192 }
1193 if (cstart1 < cend1)
1194 return SCM_I_MAKINUM (cstart1);
1195 else if (cstart2 < cend2)
1196 return SCM_I_MAKINUM (cstart1);
1197 else
1198 return SCM_BOOL_F;
1199 }
1200 #undef FUNC_NAME
1201
1202
1203 SCM_DEFINE (scm_string_ci_lt, "string-ci<", 2, 4, 0,
1204 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1205 "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
1206 "true value otherwise. The character comparison is done\n"
1207 "case-insensitively.")
1208 #define FUNC_NAME s_scm_string_ci_lt
1209 {
1210 char * cstr1, * cstr2;
1211 int cstart1, cend1, cstart2, cend2;
1212
1213 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1214 3, start1, cstart1,
1215 4, end1, cend1);
1216 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1217 5, start2, cstart2,
1218 6, end2, cend2);
1219
1220 while (cstart1 < cend1 && cstart2 < cend2)
1221 {
1222 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1223 return SCM_I_MAKINUM (cstart1);
1224 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1225 return SCM_BOOL_F;
1226 cstart1++;
1227 cstart2++;
1228 }
1229 if (cstart1 < cend1)
1230 return SCM_BOOL_F;
1231 else if (cstart2 < cend2)
1232 return SCM_I_MAKINUM (cstart1);
1233 else
1234 return SCM_BOOL_F;
1235 }
1236 #undef FUNC_NAME
1237
1238
1239 SCM_DEFINE (scm_string_ci_gt, "string-ci>", 2, 4, 0,
1240 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1241 "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
1242 "true value otherwise. The character comparison is done\n"
1243 "case-insensitively.")
1244 #define FUNC_NAME s_scm_string_ci_gt
1245 {
1246 char * cstr1, * cstr2;
1247 int cstart1, cend1, cstart2, cend2;
1248
1249 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1250 3, start1, cstart1,
1251 4, end1, cend1);
1252 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1253 5, start2, cstart2,
1254 6, end2, cend2);
1255
1256 while (cstart1 < cend1 && cstart2 < cend2)
1257 {
1258 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1259 return SCM_BOOL_F;
1260 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1261 return SCM_I_MAKINUM (cstart1);
1262 cstart1++;
1263 cstart2++;
1264 }
1265 if (cstart1 < cend1)
1266 return SCM_I_MAKINUM (cstart1);
1267 else if (cstart2 < cend2)
1268 return SCM_BOOL_F;
1269 else
1270 return SCM_BOOL_F;
1271 }
1272 #undef FUNC_NAME
1273
1274
1275 SCM_DEFINE (scm_string_ci_le, "string-ci<=", 2, 4, 0,
1276 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1277 "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
1278 "value otherwise. The character comparison is done\n"
1279 "case-insensitively.")
1280 #define FUNC_NAME s_scm_string_ci_le
1281 {
1282 char * cstr1, * cstr2;
1283 int cstart1, cend1, cstart2, cend2;
1284
1285 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1286 3, start1, cstart1,
1287 4, end1, cend1);
1288 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1289 5, start2, cstart2,
1290 6, end2, cend2);
1291
1292 while (cstart1 < cend1 && cstart2 < cend2)
1293 {
1294 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1295 return SCM_I_MAKINUM (cstart1);
1296 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1297 return SCM_BOOL_F;
1298 cstart1++;
1299 cstart2++;
1300 }
1301 if (cstart1 < cend1)
1302 return SCM_BOOL_F;
1303 else if (cstart2 < cend2)
1304 return SCM_I_MAKINUM (cstart1);
1305 else
1306 return SCM_I_MAKINUM (cstart1);
1307 }
1308 #undef FUNC_NAME
1309
1310
1311 SCM_DEFINE (scm_string_ci_ge, "string-ci>=", 2, 4, 0,
1312 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1313 "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
1314 "otherwise. The character comparison is done\n"
1315 "case-insensitively.")
1316 #define FUNC_NAME s_scm_string_ci_ge
1317 {
1318 char * cstr1, * cstr2;
1319 int cstart1, cend1, cstart2, cend2;
1320
1321 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1322 3, start1, cstart1,
1323 4, end1, cend1);
1324 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1325 5, start2, cstart2,
1326 6, end2, cend2);
1327
1328 while (cstart1 < cend1 && cstart2 < cend2)
1329 {
1330 if (scm_c_downcase (cstr1[cstart1]) < scm_c_downcase (cstr2[cstart2]))
1331 return SCM_BOOL_F;
1332 else if (scm_c_downcase (cstr1[cstart1]) > scm_c_downcase (cstr2[cstart2]))
1333 return SCM_I_MAKINUM (cstart1);
1334 cstart1++;
1335 cstart2++;
1336 }
1337 if (cstart1 < cend1)
1338 return SCM_I_MAKINUM (cstart1);
1339 else if (cstart2 < cend2)
1340 return SCM_BOOL_F;
1341 else
1342 return SCM_I_MAKINUM (cstart1);
1343 }
1344 #undef FUNC_NAME
1345
1346
1347 SCM_DEFINE (scm_string_prefix_length, "string-prefix-length", 2, 4, 0,
1348 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1349 "Return the length of the longest common prefix of the two\n"
1350 "strings.")
1351 #define FUNC_NAME s_scm_string_prefix_length
1352 {
1353 char * cstr1, * cstr2;
1354 int cstart1, cend1, cstart2, cend2;
1355 int len = 0;
1356
1357 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1358 3, start1, cstart1,
1359 4, end1, cend1);
1360 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1361 5, start2, cstart2,
1362 6, end2, cend2);
1363 while (cstart1 < cend1 && cstart2 < cend2)
1364 {
1365 if (cstr1[cstart1] != cstr2[cstart2])
1366 return SCM_I_MAKINUM (len);
1367 len++;
1368 cstart1++;
1369 cstart2++;
1370 }
1371 return SCM_I_MAKINUM (len);
1372 }
1373 #undef FUNC_NAME
1374
1375
1376 SCM_DEFINE (scm_string_prefix_length_ci, "string-prefix-length-ci", 2, 4, 0,
1377 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1378 "Return the length of the longest common prefix of the two\n"
1379 "strings, ignoring character case.")
1380 #define FUNC_NAME s_scm_string_prefix_length_ci
1381 {
1382 char * cstr1, * cstr2;
1383 int cstart1, cend1, cstart2, cend2;
1384 int len = 0;
1385
1386 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1387 3, start1, cstart1,
1388 4, end1, cend1);
1389 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1390 5, start2, cstart2,
1391 6, end2, cend2);
1392 while (cstart1 < cend1 && cstart2 < cend2)
1393 {
1394 if (scm_c_downcase (cstr1[cstart1]) != scm_c_downcase (cstr2[cstart2]))
1395 return SCM_I_MAKINUM (len);
1396 len++;
1397 cstart1++;
1398 cstart2++;
1399 }
1400 return SCM_I_MAKINUM (len);
1401 }
1402 #undef FUNC_NAME
1403
1404
1405 SCM_DEFINE (scm_string_suffix_length, "string-suffix-length", 2, 4, 0,
1406 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1407 "Return the length of the longest common suffix of the two\n"
1408 "strings.")
1409 #define FUNC_NAME s_scm_string_suffix_length
1410 {
1411 char * cstr1, * cstr2;
1412 int cstart1, cend1, cstart2, cend2;
1413 int len = 0;
1414
1415 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1416 3, start1, cstart1,
1417 4, end1, cend1);
1418 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1419 5, start2, cstart2,
1420 6, end2, cend2);
1421 while (cstart1 < cend1 && cstart2 < cend2)
1422 {
1423 cend1--;
1424 cend2--;
1425 if (cstr1[cend1] != cstr2[cend2])
1426 return SCM_I_MAKINUM (len);
1427 len++;
1428 }
1429 return SCM_I_MAKINUM (len);
1430 }
1431 #undef FUNC_NAME
1432
1433
1434 SCM_DEFINE (scm_string_suffix_length_ci, "string-suffix-length-ci", 2, 4, 0,
1435 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1436 "Return the length of the longest common suffix of the two\n"
1437 "strings, ignoring character case.")
1438 #define FUNC_NAME s_scm_string_suffix_length_ci
1439 {
1440 char * cstr1, * cstr2;
1441 int cstart1, cend1, cstart2, cend2;
1442 int len = 0;
1443
1444 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1445 3, start1, cstart1,
1446 4, end1, cend1);
1447 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1448 5, start2, cstart2,
1449 6, end2, cend2);
1450 while (cstart1 < cend1 && cstart2 < cend2)
1451 {
1452 cend1--;
1453 cend2--;
1454 if (scm_c_downcase (cstr1[cend1]) != scm_c_downcase (cstr2[cend2]))
1455 return SCM_I_MAKINUM (len);
1456 len++;
1457 }
1458 return SCM_I_MAKINUM (len);
1459 }
1460 #undef FUNC_NAME
1461
1462
1463 SCM_DEFINE (scm_string_prefix_p, "string-prefix?", 2, 4, 0,
1464 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1465 "Is @var{s1} a prefix of @var{s2}?")
1466 #define FUNC_NAME s_scm_string_prefix_p
1467 {
1468 char * cstr1, * cstr2;
1469 int cstart1, cend1, cstart2, cend2;
1470 int len = 0, len1;
1471
1472 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1473 3, start1, cstart1,
1474 4, end1, cend1);
1475 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1476 5, start2, cstart2,
1477 6, end2, cend2);
1478 len1 = cend1 - cstart1;
1479 while (cstart1 < cend1 && cstart2 < cend2)
1480 {
1481 if (cstr1[cstart1] != cstr2[cstart2])
1482 return scm_from_bool (len == len1);
1483 len++;
1484 cstart1++;
1485 cstart2++;
1486 }
1487 return scm_from_bool (len == len1);
1488 }
1489 #undef FUNC_NAME
1490
1491
1492 SCM_DEFINE (scm_string_prefix_ci_p, "string-prefix-ci?", 2, 4, 0,
1493 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1494 "Is @var{s1} a prefix of @var{s2}, ignoring character case?")
1495 #define FUNC_NAME s_scm_string_prefix_ci_p
1496 {
1497 char * cstr1, * cstr2;
1498 int cstart1, cend1, cstart2, cend2;
1499 int len = 0, len1;
1500
1501 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1502 3, start1, cstart1,
1503 4, end1, cend1);
1504 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1505 5, start2, cstart2,
1506 6, end2, cend2);
1507 len1 = cend1 - cstart1;
1508 while (cstart1 < cend1 && cstart2 < cend2)
1509 {
1510 if (scm_c_downcase (cstr1[cstart1]) != scm_c_downcase (cstr2[cstart2]))
1511 return scm_from_bool (len == len1);
1512 len++;
1513 cstart1++;
1514 cstart2++;
1515 }
1516 return scm_from_bool (len == len1);
1517 }
1518 #undef FUNC_NAME
1519
1520
1521 SCM_DEFINE (scm_string_suffix_p, "string-suffix?", 2, 4, 0,
1522 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1523 "Is @var{s1} a suffix of @var{s2}?")
1524 #define FUNC_NAME s_scm_string_suffix_p
1525 {
1526 char * cstr1, * cstr2;
1527 int cstart1, cend1, cstart2, cend2;
1528 int len = 0, len1;
1529
1530 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1531 3, start1, cstart1,
1532 4, end1, cend1);
1533 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1534 5, start2, cstart2,
1535 6, end2, cend2);
1536 len1 = cend1 - cstart1;
1537 while (cstart1 < cend1 && cstart2 < cend2)
1538 {
1539 cend1--;
1540 cend2--;
1541 if (cstr1[cend1] != cstr2[cend2])
1542 return scm_from_bool (len == len1);
1543 len++;
1544 }
1545 return scm_from_bool (len == len1);
1546 }
1547 #undef FUNC_NAME
1548
1549
1550 SCM_DEFINE (scm_string_suffix_ci_p, "string-suffix-ci?", 2, 4, 0,
1551 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1552 "Is @var{s1} a suffix of @var{s2}, ignoring character case?")
1553 #define FUNC_NAME s_scm_string_suffix_ci_p
1554 {
1555 char * cstr1, * cstr2;
1556 int cstart1, cend1, cstart2, cend2;
1557 int len = 0, len1;
1558
1559 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
1560 3, start1, cstart1,
1561 4, end1, cend1);
1562 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
1563 5, start2, cstart2,
1564 6, end2, cend2);
1565 len1 = cend1 - cstart1;
1566 while (cstart1 < cend1 && cstart2 < cend2)
1567 {
1568 cend1--;
1569 cend2--;
1570 if (scm_c_downcase (cstr1[cend1]) != scm_c_downcase (cstr2[cend2]))
1571 return scm_from_bool (len == len1);
1572 len++;
1573 }
1574 return scm_from_bool (len == len1);
1575 }
1576 #undef FUNC_NAME
1577
1578
1579 /* FIXME::martin: The `S' is to avoid a name clash with the procedure
1580 in the core, which does not accept a predicate. */
1581 SCM_DEFINE (scm_string_indexS, "string-index", 2, 2, 0,
1582 (SCM s, SCM char_pred, SCM start, SCM end),
1583 "Search through the string @var{s} from left to right, returning\n"
1584 "the index of the first occurence of a character which\n"
1585 "\n"
1586 "@itemize @bullet\n"
1587 "@item\n"
1588 "equals @var{char_pred}, if it is character,\n"
1589 "\n"
1590 "@item\n"
1591 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1592 "\n"
1593 "@item\n"
1594 "is in the set @var{char_pred}, if it is a character set.\n"
1595 "@end itemize")
1596 #define FUNC_NAME s_scm_string_indexS
1597 {
1598 char * cstr;
1599 int cstart, cend;
1600
1601 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1602 3, start, cstart,
1603 4, end, cend);
1604 if (SCM_CHARP (char_pred))
1605 {
1606 char cchr = SCM_CHAR (char_pred);
1607 while (cstart < cend)
1608 {
1609 if (cchr == cstr[cstart])
1610 return SCM_I_MAKINUM (cstart);
1611 cstart++;
1612 }
1613 }
1614 else if (SCM_CHARSETP (char_pred))
1615 {
1616 while (cstart < cend)
1617 {
1618 if (SCM_CHARSET_GET (char_pred, cstr[cstart]))
1619 return SCM_I_MAKINUM (cstart);
1620 cstart++;
1621 }
1622 }
1623 else
1624 {
1625 SCM_VALIDATE_PROC (2, char_pred);
1626 while (cstart < cend)
1627 {
1628 SCM res;
1629 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
1630 if (scm_is_true (res))
1631 return SCM_I_MAKINUM (cstart);
1632 cstart++;
1633 }
1634 }
1635 return SCM_BOOL_F;
1636 }
1637 #undef FUNC_NAME
1638
1639
1640 SCM_DEFINE (scm_string_index_right, "string-index-right", 2, 2, 0,
1641 (SCM s, SCM char_pred, SCM start, SCM end),
1642 "Search through the string @var{s} from right to left, returning\n"
1643 "the index of the last occurence of a character which\n"
1644 "\n"
1645 "@itemize @bullet\n"
1646 "@item\n"
1647 "equals @var{char_pred}, if it is character,\n"
1648 "\n"
1649 "@item\n"
1650 "satisifies the predicate @var{char_pred}, if it is a procedure,\n"
1651 "\n"
1652 "@item\n"
1653 "is in the set if @var{char_pred} is a character set.\n"
1654 "@end itemize")
1655 #define FUNC_NAME s_scm_string_index_right
1656 {
1657 char * cstr;
1658 int cstart, cend;
1659
1660 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1661 3, start, cstart,
1662 4, end, cend);
1663 if (SCM_CHARP (char_pred))
1664 {
1665 char cchr = SCM_CHAR (char_pred);
1666 while (cstart < cend)
1667 {
1668 cend--;
1669 if (cchr == cstr[cend])
1670 return SCM_I_MAKINUM (cend);
1671 }
1672 }
1673 else if (SCM_CHARSETP (char_pred))
1674 {
1675 while (cstart < cend)
1676 {
1677 cend--;
1678 if (SCM_CHARSET_GET (char_pred, cstr[cend]))
1679 return SCM_I_MAKINUM (cend);
1680 }
1681 }
1682 else
1683 {
1684 SCM_VALIDATE_PROC (2, char_pred);
1685 while (cstart < cend)
1686 {
1687 SCM res;
1688 cend--;
1689 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend]));
1690 if (scm_is_true (res))
1691 return SCM_I_MAKINUM (cend);
1692 }
1693 }
1694 return SCM_BOOL_F;
1695 }
1696 #undef FUNC_NAME
1697
1698
1699 SCM_DEFINE (scm_string_skip, "string-skip", 2, 2, 0,
1700 (SCM s, SCM char_pred, SCM start, SCM end),
1701 "Search through the string @var{s} from left to right, returning\n"
1702 "the index of the first occurence of a character which\n"
1703 "\n"
1704 "@itemize @bullet\n"
1705 "@item\n"
1706 "does not equal @var{char_pred}, if it is character,\n"
1707 "\n"
1708 "@item\n"
1709 "does not satisify the predicate @var{char_pred}, if it is a\n"
1710 "procedure,\n"
1711 "\n"
1712 "@item\n"
1713 "is not in the set if @var{char_pred} is a character set.\n"
1714 "@end itemize")
1715 #define FUNC_NAME s_scm_string_skip
1716 {
1717 char * cstr;
1718 int cstart, cend;
1719
1720 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1721 3, start, cstart,
1722 4, end, cend);
1723 if (SCM_CHARP (char_pred))
1724 {
1725 char cchr = SCM_CHAR (char_pred);
1726 while (cstart < cend)
1727 {
1728 if (cchr != cstr[cstart])
1729 return SCM_I_MAKINUM (cstart);
1730 cstart++;
1731 }
1732 }
1733 else if (SCM_CHARSETP (char_pred))
1734 {
1735 while (cstart < cend)
1736 {
1737 if (!SCM_CHARSET_GET (char_pred, cstr[cstart]))
1738 return SCM_I_MAKINUM (cstart);
1739 cstart++;
1740 }
1741 }
1742 else
1743 {
1744 SCM_VALIDATE_PROC (2, char_pred);
1745 while (cstart < cend)
1746 {
1747 SCM res;
1748 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
1749 if (scm_is_false (res))
1750 return SCM_I_MAKINUM (cstart);
1751 cstart++;
1752 }
1753 }
1754 return SCM_BOOL_F;
1755 }
1756 #undef FUNC_NAME
1757
1758
1759 SCM_DEFINE (scm_string_skip_right, "string-skip-right", 2, 2, 0,
1760 (SCM s, SCM char_pred, SCM start, SCM end),
1761 "Search through the string @var{s} from right to left, returning\n"
1762 "the index of the last occurence of a character which\n"
1763 "\n"
1764 "@itemize @bullet\n"
1765 "@item\n"
1766 "does not equal @var{char_pred}, if it is character,\n"
1767 "\n"
1768 "@item\n"
1769 "does not satisifie the predicate @var{char_pred}, if it is a\n"
1770 "procedure,\n"
1771 "\n"
1772 "@item\n"
1773 "is not in the set if @var{char_pred} is a character set.\n"
1774 "@end itemize")
1775 #define FUNC_NAME s_scm_string_skip_right
1776 {
1777 char * cstr;
1778 int cstart, cend;
1779
1780 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1781 3, start, cstart,
1782 4, end, cend);
1783 if (SCM_CHARP (char_pred))
1784 {
1785 char cchr = SCM_CHAR (char_pred);
1786 while (cstart < cend)
1787 {
1788 cend--;
1789 if (cchr != cstr[cend])
1790 return SCM_I_MAKINUM (cend);
1791 }
1792 }
1793 else if (SCM_CHARSETP (char_pred))
1794 {
1795 while (cstart < cend)
1796 {
1797 cend--;
1798 if (!SCM_CHARSET_GET (char_pred, cstr[cend]))
1799 return SCM_I_MAKINUM (cend);
1800 }
1801 }
1802 else
1803 {
1804 SCM_VALIDATE_PROC (2, char_pred);
1805 while (cstart < cend)
1806 {
1807 SCM res;
1808 cend--;
1809 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cend]));
1810 if (scm_is_false (res))
1811 return SCM_I_MAKINUM (cend);
1812 }
1813 }
1814 return SCM_BOOL_F;
1815 }
1816 #undef FUNC_NAME
1817
1818
1819 SCM_DEFINE (scm_string_count, "string-count", 2, 2, 0,
1820 (SCM s, SCM char_pred, SCM start, SCM end),
1821 "Return the count of the number of characters in the string\n"
1822 "@var{s} which\n"
1823 "\n"
1824 "@itemize @bullet\n"
1825 "@item\n"
1826 "equals @var{char_pred}, if it is character,\n"
1827 "\n"
1828 "@item\n"
1829 "satisifies the predicate @var{char_pred}, if it is a procedure.\n"
1830 "\n"
1831 "@item\n"
1832 "is in the set @var{char_pred}, if it is a character set.\n"
1833 "@end itemize")
1834 #define FUNC_NAME s_scm_string_count
1835 {
1836 char * cstr;
1837 int cstart, cend;
1838 int count = 0;
1839
1840 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
1841 3, start, cstart,
1842 4, end, cend);
1843 if (SCM_CHARP (char_pred))
1844 {
1845 char cchr = SCM_CHAR (char_pred);
1846 while (cstart < cend)
1847 {
1848 if (cchr == cstr[cstart])
1849 count++;
1850 cstart++;
1851 }
1852 }
1853 else if (SCM_CHARSETP (char_pred))
1854 {
1855 while (cstart < cend)
1856 {
1857 if (SCM_CHARSET_GET (char_pred, cstr[cstart]))
1858 count++;
1859 cstart++;
1860 }
1861 }
1862 else
1863 {
1864 SCM_VALIDATE_PROC (2, char_pred);
1865 while (cstart < cend)
1866 {
1867 SCM res;
1868 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[cstart]));
1869 if (scm_is_true (res))
1870 count++;
1871 cstart++;
1872 }
1873 }
1874 return SCM_I_MAKINUM (count);
1875 }
1876 #undef FUNC_NAME
1877
1878
1879 /* FIXME::martin: This should definitely get implemented more
1880 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
1881 implementation. */
1882 SCM_DEFINE (scm_string_contains, "string-contains", 2, 4, 0,
1883 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1884 "Does string @var{s1} contain string @var{s2}? Return the index\n"
1885 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
1886 "The optional start/end indices restrict the operation to the\n"
1887 "indicated substrings.")
1888 #define FUNC_NAME s_scm_string_contains
1889 {
1890 char * cs1, * cs2;
1891 int cstart1, cend1, cstart2, cend2;
1892 int len2, i, j;
1893
1894 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cs1,
1895 3, start1, cstart1,
1896 4, end1, cend1);
1897 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cs2,
1898 5, start2, cstart2,
1899 6, end2, cend2);
1900 len2 = cend2 - cstart2;
1901 while (cstart1 <= cend1 - len2)
1902 {
1903 i = cstart1;
1904 j = cstart2;
1905 while (i < cend1 && j < cend2 && cs1[i] == cs2[j])
1906 {
1907 i++;
1908 j++;
1909 }
1910 if (j == cend2)
1911 return SCM_I_MAKINUM (cstart1);
1912 cstart1++;
1913 }
1914 return SCM_BOOL_F;
1915 }
1916 #undef FUNC_NAME
1917
1918
1919 /* FIXME::martin: This should definitely get implemented more
1920 efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
1921 implementation. */
1922 SCM_DEFINE (scm_string_contains_ci, "string-contains-ci", 2, 4, 0,
1923 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
1924 "Does string @var{s1} contain string @var{s2}? Return the index\n"
1925 "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
1926 "The optional start/end indices restrict the operation to the\n"
1927 "indicated substrings. Character comparison is done\n"
1928 "case-insensitively.")
1929 #define FUNC_NAME s_scm_string_contains_ci
1930 {
1931 char * cs1, * cs2;
1932 int cstart1, cend1, cstart2, cend2;
1933 int len2, i, j;
1934
1935 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cs1,
1936 3, start1, cstart1,
1937 4, end1, cend1);
1938 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cs2,
1939 5, start2, cstart2,
1940 6, end2, cend2);
1941 len2 = cend2 - cstart2;
1942 while (cstart1 <= cend1 - len2)
1943 {
1944 i = cstart1;
1945 j = cstart2;
1946 while (i < cend1 && j < cend2 &&
1947 scm_c_downcase (cs1[i]) == scm_c_downcase (cs2[j]))
1948 {
1949 i++;
1950 j++;
1951 }
1952 if (j == cend2)
1953 return SCM_I_MAKINUM (cstart1);
1954 cstart1++;
1955 }
1956 return SCM_BOOL_F;
1957 }
1958 #undef FUNC_NAME
1959
1960
1961 /* Helper function for the string uppercase conversion functions.
1962 * No argument checking is performed. */
1963 static SCM
1964 string_upcase_x (SCM v, int start, int end)
1965 {
1966 unsigned long k;
1967
1968 for (k = start; k < end; ++k)
1969 SCM_STRING_UCHARS (v) [k] = scm_c_upcase (SCM_STRING_UCHARS (v) [k]);
1970
1971 return v;
1972 }
1973
1974
1975 /* FIXME::martin: The `S' is to avoid a name clash with the procedure
1976 in the core, which does not accept start/end indices */
1977 SCM_DEFINE (scm_string_upcase_xS, "string-upcase!", 1, 2, 0,
1978 (SCM str, SCM start, SCM end),
1979 "Destructively upcase every character in @code{str}.\n"
1980 "\n"
1981 "@lisp\n"
1982 "(string-upcase! y)\n"
1983 "@result{} \"ARRDEFG\"\n"
1984 "y\n"
1985 "@result{} \"ARRDEFG\"\n"
1986 "@end lisp")
1987 #define FUNC_NAME s_scm_string_upcase_xS
1988 {
1989 char * cstr;
1990 int cstart, cend;
1991
1992 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
1993 2, start, cstart,
1994 3, end, cend);
1995 return string_upcase_x (str, cstart, cend);
1996 }
1997 #undef FUNC_NAME
1998
1999
2000 /* FIXME::martin: The `S' is to avoid a name clash with the procedure
2001 in the core, which does not accept start/end indices */
2002 SCM_DEFINE (scm_string_upcaseS, "string-upcase", 1, 2, 0,
2003 (SCM str, SCM start, SCM end),
2004 "Upcase every character in @code{str}.")
2005 #define FUNC_NAME s_scm_string_upcaseS
2006 {
2007 char * cstr;
2008 int cstart, cend;
2009
2010 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2011 2, start, cstart,
2012 3, end, cend);
2013 return string_upcase_x (scm_string_copy (str), cstart, cend);
2014 }
2015 #undef FUNC_NAME
2016
2017
2018 /* Helper function for the string lowercase conversion functions.
2019 * No argument checking is performed. */
2020 static SCM
2021 string_downcase_x (SCM v, int start, int end)
2022 {
2023 unsigned long k;
2024
2025 for (k = start; k < end; ++k)
2026 SCM_STRING_UCHARS (v) [k] = scm_c_downcase (SCM_STRING_UCHARS (v) [k]);
2027
2028 return v;
2029 }
2030
2031
2032 /* FIXME::martin: The `S' is to avoid a name clash with the procedure
2033 in the core, which does not accept start/end indices */
2034 SCM_DEFINE (scm_string_downcase_xS, "string-downcase!", 1, 2, 0,
2035 (SCM str, SCM start, SCM end),
2036 "Destructively downcase every character in @var{str}.\n"
2037 "\n"
2038 "@lisp\n"
2039 "y\n"
2040 "@result{} \"ARRDEFG\"\n"
2041 "(string-downcase! y)\n"
2042 "@result{} \"arrdefg\"\n"
2043 "y\n"
2044 "@result{} \"arrdefg\"\n"
2045 "@end lisp")
2046 #define FUNC_NAME s_scm_string_downcase_xS
2047 {
2048 char * cstr;
2049 int cstart, cend;
2050
2051 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2052 2, start, cstart,
2053 3, end, cend);
2054 return string_downcase_x (str, cstart, cend);
2055 }
2056 #undef FUNC_NAME
2057
2058
2059 /* FIXME::martin: The `S' is to avoid a name clash with the procedure
2060 in the core, which does not accept start/end indices */
2061 SCM_DEFINE (scm_string_downcaseS, "string-downcase", 1, 2, 0,
2062 (SCM str, SCM start, SCM end),
2063 "Downcase every character in @var{str}.")
2064 #define FUNC_NAME s_scm_string_downcaseS
2065 {
2066 char * cstr;
2067 int cstart, cend;
2068
2069 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2070 2, start, cstart,
2071 3, end, cend);
2072 return string_downcase_x (scm_string_copy (str), cstart, cend);
2073 }
2074 #undef FUNC_NAME
2075
2076
2077 /* Helper function for the string capitalization functions.
2078 * No argument checking is performed. */
2079 static SCM
2080 string_titlecase_x (SCM str, int start, int end)
2081 {
2082 unsigned char * sz;
2083 int i, in_word = 0;
2084
2085 sz = SCM_STRING_UCHARS (str);
2086 for(i = start; i < end; i++)
2087 {
2088 if (scm_is_true (scm_char_alphabetic_p (SCM_MAKE_CHAR (sz[i]))))
2089 {
2090 if (!in_word)
2091 {
2092 sz[i] = scm_c_upcase(sz[i]);
2093 in_word = 1;
2094 }
2095 else
2096 {
2097 sz[i] = scm_c_downcase(sz[i]);
2098 }
2099 }
2100 else
2101 in_word = 0;
2102 }
2103 return str;
2104 }
2105
2106
2107 SCM_DEFINE (scm_string_titlecase_x, "string-titlecase!", 1, 2, 0,
2108 (SCM str, SCM start, SCM end),
2109 "Destructively titlecase every first character in a word in\n"
2110 "@var{str}.")
2111 #define FUNC_NAME s_scm_string_titlecase_x
2112 {
2113 char * cstr;
2114 int cstart, cend;
2115
2116 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2117 2, start, cstart,
2118 3, end, cend);
2119 return string_titlecase_x (str, cstart, cend);
2120 }
2121 #undef FUNC_NAME
2122
2123
2124 SCM_DEFINE (scm_string_titlecase, "string-titlecase", 1, 2, 0,
2125 (SCM str, SCM start, SCM end),
2126 "Titlecase every first character in a word in @var{str}.")
2127 #define FUNC_NAME s_scm_string_titlecase
2128 {
2129 char * cstr;
2130 int cstart, cend;
2131
2132 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2133 2, start, cstart,
2134 3, end, cend);
2135 return string_titlecase_x (scm_string_copy (str), cstart, cend);
2136 }
2137 #undef FUNC_NAME
2138
2139
2140 /* Reverse the portion of @var{str} between str[cstart] (including)
2141 and str[cend] excluding. */
2142 static void
2143 string_reverse_x (char * str, int cstart, int cend)
2144 {
2145 char tmp;
2146
2147 cend--;
2148 while (cstart < cend)
2149 {
2150 tmp = str[cstart];
2151 str[cstart] = str[cend];
2152 str[cend] = tmp;
2153 cstart++;
2154 cend--;
2155 }
2156 }
2157
2158
2159 SCM_DEFINE (scm_string_reverse, "string-reverse", 1, 2, 0,
2160 (SCM str, SCM start, SCM end),
2161 "Reverse the string @var{str}. The optional arguments\n"
2162 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2163 "operate on.")
2164 #define FUNC_NAME s_scm_string_reverse
2165 {
2166 char * cstr;
2167 int cstart;
2168 int cend;
2169 SCM result;
2170
2171 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2172 2, start, cstart,
2173 3, end, cend);
2174 result = scm_string_copy (str);
2175 string_reverse_x (SCM_STRING_CHARS (result), cstart, cend);
2176 return result;
2177 }
2178 #undef FUNC_NAME
2179
2180
2181 SCM_DEFINE (scm_string_reverse_x, "string-reverse!", 1, 2, 0,
2182 (SCM str, SCM start, SCM end),
2183 "Reverse the string @var{str} in-place. The optional arguments\n"
2184 "@var{start} and @var{end} delimit the region of @var{str} to\n"
2185 "operate on. The return value is unspecified.")
2186 #define FUNC_NAME s_scm_string_reverse_x
2187 {
2188 char * cstr;
2189 int cstart;
2190 int cend;
2191
2192 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str, cstr,
2193 2, start, cstart,
2194 3, end, cend);
2195 string_reverse_x (SCM_STRING_CHARS (str), cstart, cend);
2196 return SCM_UNSPECIFIED;
2197 }
2198 #undef FUNC_NAME
2199
2200
2201 SCM_DEFINE (scm_string_append_shared, "string-append/shared", 0, 0, 1,
2202 (SCM ls),
2203 "Like @code{string-append}, but the result may share memory\n"
2204 "with the argument strings.")
2205 #define FUNC_NAME s_scm_string_append_shared
2206 {
2207 long i;
2208
2209 SCM_VALIDATE_REST_ARGUMENT (ls);
2210
2211 /* Optimize the one-argument case. */
2212 i = scm_ilength (ls);
2213 if (i == 1)
2214 return SCM_CAR (ls);
2215 else
2216 return scm_string_append (ls);
2217 }
2218 #undef FUNC_NAME
2219
2220
2221 SCM_DEFINE (scm_string_concatenate, "string-concatenate", 1, 0, 0,
2222 (SCM ls),
2223 "Append the elements of @var{ls} (which must be strings)\n"
2224 "together into a single string. Guaranteed to return a freshly\n"
2225 "allocated string.")
2226 #define FUNC_NAME s_scm_string_concatenate
2227 {
2228 long strings = scm_ilength (ls);
2229 SCM tmp, result;
2230 int len = 0;
2231 char * p;
2232
2233 /* Validate the string list. */
2234 if (strings < 0)
2235 SCM_WRONG_TYPE_ARG (1, ls);
2236
2237 /* Calculate the size of the result string. */
2238 tmp = ls;
2239 while (!SCM_NULLP (tmp))
2240 {
2241 SCM elt = SCM_CAR (tmp);
2242 SCM_VALIDATE_STRING (1, elt);
2243 len += SCM_STRING_LENGTH (elt);
2244 tmp = SCM_CDR (tmp);
2245 }
2246 result = scm_allocate_string (len);
2247
2248 /* Copy the list elements into the result. */
2249 p = SCM_STRING_CHARS (result);
2250 tmp = ls;
2251 while (!SCM_NULLP (tmp))
2252 {
2253 SCM elt = SCM_CAR (tmp);
2254 memmove (p, SCM_STRING_CHARS (elt),
2255 SCM_STRING_LENGTH (elt) * sizeof (char));
2256 p += SCM_STRING_LENGTH (elt);
2257 tmp = SCM_CDR (tmp);
2258 }
2259 return result;
2260 }
2261 #undef FUNC_NAME
2262
2263
2264 SCM_DEFINE (scm_string_concatenate_reverse, "string-concatenate-reverse", 1, 2, 0,
2265 (SCM ls, SCM final_string, SCM end),
2266 "Without optional arguments, this procedure is equivalent to\n"
2267 "\n"
2268 "@smalllisp\n"
2269 "(string-concatenate (reverse ls))\n"
2270 "@end smalllisp\n"
2271 "\n"
2272 "If the optional argument @var{final_string} is specified, it is\n"
2273 "consed onto the beginning to @var{ls} before performing the\n"
2274 "list-reverse and string-concatenate operations. If @var{end}\n"
2275 "is given, only the characters of @var{final_string} up to index\n"
2276 "@var{end} are used.\n"
2277 "\n"
2278 "Guaranteed to return a freshly allocated string.")
2279 #define FUNC_NAME s_scm_string_concatenate_reverse
2280 {
2281 long strings;
2282 SCM tmp, result;
2283 size_t len = 0;
2284 char * p;
2285 size_t cend = 0;
2286
2287 /* Check the optional arguments and calculate the additional length
2288 of the result string. */
2289 if (!SCM_UNBNDP (final_string))
2290 {
2291 SCM_VALIDATE_STRING (2, final_string);
2292 if (!SCM_UNBNDP (end))
2293 {
2294 cend = scm_to_unsigned_integer (end,
2295 0, SCM_STRING_LENGTH (final_string));
2296 }
2297 else
2298 {
2299 cend = SCM_STRING_LENGTH (final_string);
2300 }
2301 len += cend;
2302 }
2303 strings = scm_ilength (ls);
2304 /* Validate the string list. */
2305 if (strings < 0)
2306 SCM_WRONG_TYPE_ARG (1, ls);
2307
2308 /* Calculate the length of the result string. */
2309 tmp = ls;
2310 while (!SCM_NULLP (tmp))
2311 {
2312 SCM elt = SCM_CAR (tmp);
2313 SCM_VALIDATE_STRING (1, elt);
2314 len += SCM_STRING_LENGTH (elt);
2315 tmp = SCM_CDR (tmp);
2316 }
2317
2318 result = scm_allocate_string (len);
2319
2320 p = SCM_STRING_CHARS (result) + len;
2321
2322 /* Construct the result string, possibly by using the optional final
2323 string. */
2324 if (!SCM_UNBNDP (final_string))
2325 {
2326 p -= cend;
2327 memmove (p, SCM_STRING_CHARS (final_string), cend * sizeof (char));
2328 }
2329 tmp = ls;
2330 while (!SCM_NULLP (tmp))
2331 {
2332 SCM elt = SCM_CAR (tmp);
2333 p -= SCM_STRING_LENGTH (elt);
2334 memmove (p, SCM_STRING_CHARS (elt),
2335 SCM_STRING_LENGTH (elt) * sizeof (char));
2336 tmp = SCM_CDR (tmp);
2337 }
2338 return result;
2339 }
2340 #undef FUNC_NAME
2341
2342
2343 SCM_DEFINE (scm_string_concatenate_shared, "string-concatenate/shared", 1, 0, 0,
2344 (SCM ls),
2345 "Like @code{string-concatenate}, but the result may share memory\n"
2346 "with the strings in the list @var{ls}.")
2347 #define FUNC_NAME s_scm_string_concatenate_shared
2348 {
2349 /* Optimize the one-string case. */
2350 long i = scm_ilength (ls);
2351 if (i == 1)
2352 {
2353 SCM_VALIDATE_STRING (1, SCM_CAR (ls));
2354 return SCM_CAR (ls);
2355 }
2356 return scm_string_concatenate (ls);
2357 }
2358 #undef FUNC_NAME
2359
2360
2361 SCM_DEFINE (scm_string_concatenate_reverse_shared, "string-concatenate-reverse/shared", 1, 2, 0,
2362 (SCM ls, SCM final_string, SCM end),
2363 "Like @code{string-concatenate-reverse}, but the result may\n"
2364 "share memory with the the strings in the @var{ls} arguments.")
2365 #define FUNC_NAME s_scm_string_concatenate_reverse_shared
2366 {
2367 /* Just call the non-sharing version. */
2368 return scm_string_concatenate_reverse (ls, final_string, end);
2369 }
2370 #undef FUNC_NAME
2371
2372
2373 SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0,
2374 (SCM proc, SCM s, SCM start, SCM end),
2375 "@var{proc} is a char->char procedure, it is mapped over\n"
2376 "@var{s}. The order in which the procedure is applied to the\n"
2377 "string elements is not specified.")
2378 #define FUNC_NAME s_scm_string_map
2379 {
2380 char * cstr, *p;
2381 int cstart, cend;
2382 SCM result;
2383
2384 SCM_VALIDATE_PROC (1, proc);
2385 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2386 3, start, cstart,
2387 4, end, cend);
2388 result = scm_allocate_string (cend - cstart);
2389 p = SCM_STRING_CHARS (result);
2390 while (cstart < cend)
2391 {
2392 unsigned int c = (unsigned char) cstr[cstart];
2393 SCM ch = scm_call_1 (proc, SCM_MAKE_CHAR (c));
2394 if (!SCM_CHARP (ch))
2395 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
2396 cstart++;
2397 *p++ = SCM_CHAR (ch);
2398 }
2399 return result;
2400 }
2401 #undef FUNC_NAME
2402
2403
2404 SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0,
2405 (SCM proc, SCM s, SCM start, SCM end),
2406 "@var{proc} is a char->char procedure, it is mapped over\n"
2407 "@var{s}. The order in which the procedure is applied to the\n"
2408 "string elements is not specified. The string @var{s} is\n"
2409 "modified in-place, the return value is not specified.")
2410 #define FUNC_NAME s_scm_string_map_x
2411 {
2412 char * cstr, *p;
2413 int cstart, cend;
2414
2415 SCM_VALIDATE_PROC (1, proc);
2416 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2417 3, start, cstart,
2418 4, end, cend);
2419 p = SCM_STRING_CHARS (s) + cstart;
2420 while (cstart < cend)
2421 {
2422 unsigned int c = (unsigned char) cstr[cstart];
2423 SCM ch = scm_call_1 (proc, SCM_MAKE_CHAR (c));
2424 if (!SCM_CHARP (ch))
2425 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
2426 cstart++;
2427 *p++ = SCM_CHAR (ch);
2428 }
2429 return SCM_UNSPECIFIED;
2430 }
2431 #undef FUNC_NAME
2432
2433
2434 SCM_DEFINE (scm_string_fold, "string-fold", 3, 2, 0,
2435 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2436 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2437 "as the terminating element, from left to right. @var{kons}\n"
2438 "must expect two arguments: The actual character and the last\n"
2439 "result of @var{kons}' application.")
2440 #define FUNC_NAME s_scm_string_fold
2441 {
2442 char * cstr;
2443 int cstart, cend;
2444 SCM result;
2445
2446 SCM_VALIDATE_PROC (1, kons);
2447 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2448 4, start, cstart,
2449 5, end, cend);
2450 result = knil;
2451 while (cstart < cend)
2452 {
2453 unsigned int c = (unsigned char) cstr[cstart];
2454 result = scm_call_2 (kons, SCM_MAKE_CHAR (c), result);
2455 cstart++;
2456 }
2457 return result;
2458 }
2459 #undef FUNC_NAME
2460
2461
2462 SCM_DEFINE (scm_string_fold_right, "string-fold-right", 3, 2, 0,
2463 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2464 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2465 "as the terminating element, from right to left. @var{kons}\n"
2466 "must expect two arguments: The actual character and the last\n"
2467 "result of @var{kons}' application.")
2468 #define FUNC_NAME s_scm_string_fold_right
2469 {
2470 char * cstr;
2471 int cstart, cend;
2472 SCM result;
2473
2474 SCM_VALIDATE_PROC (1, kons);
2475 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2476 4, start, cstart,
2477 5, end, cend);
2478 result = knil;
2479 while (cstart < cend)
2480 {
2481 unsigned int c = (unsigned char) cstr[cend - 1];
2482 result = scm_call_2 (kons, SCM_MAKE_CHAR (c), result);
2483 cend--;
2484 }
2485 return result;
2486 }
2487 #undef FUNC_NAME
2488
2489
2490 SCM_DEFINE (scm_string_unfold, "string-unfold", 4, 2, 0,
2491 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2492 "@itemize @bullet\n"
2493 "@item @var{g} is used to generate a series of @emph{seed}\n"
2494 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2495 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2496 "@dots{}\n"
2497 "@item @var{p} tells us when to stop -- when it returns true\n"
2498 "when applied to one of these seed values.\n"
2499 "@item @var{f} maps each seed value to the corresponding\n"
2500 "character in the result string. These chars are assembled\n"
2501 "into the string in a left-to-right order.\n"
2502 "@item @var{base} is the optional initial/leftmost portion\n"
2503 "of the constructed string; it default to the empty\n"
2504 "string.\n"
2505 "@item @var{make_final} is applied to the terminal seed\n"
2506 "value (on which @var{p} returns true) to produce\n"
2507 "the final/rightmost portion of the constructed string.\n"
2508 "It defaults to @code{(lambda (x) "")}.\n"
2509 "@end itemize")
2510 #define FUNC_NAME s_scm_string_unfold
2511 {
2512 SCM res, ans;
2513
2514 SCM_VALIDATE_PROC (1, p);
2515 SCM_VALIDATE_PROC (2, f);
2516 SCM_VALIDATE_PROC (3, g);
2517 if (!SCM_UNBNDP (base))
2518 {
2519 SCM_VALIDATE_STRING (5, base);
2520 ans = base;
2521 }
2522 else
2523 ans = scm_allocate_string (0);
2524 if (!SCM_UNBNDP (make_final))
2525 SCM_VALIDATE_PROC (6, make_final);
2526
2527 res = scm_call_1 (p, seed);
2528 while (scm_is_false (res))
2529 {
2530 SCM str;
2531 SCM ch = scm_call_1 (f, seed);
2532 if (!SCM_CHARP (ch))
2533 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
2534 str = scm_allocate_string (1);
2535 *SCM_STRING_CHARS (str) = SCM_CHAR (ch);
2536
2537 ans = scm_string_append (scm_list_2 (ans, str));
2538 seed = scm_call_1 (g, seed);
2539 res = scm_call_1 (p, seed);
2540 }
2541 if (!SCM_UNBNDP (make_final))
2542 {
2543 res = scm_call_1 (make_final, seed);
2544 return scm_string_append (scm_list_2 (ans, res));
2545 }
2546 else
2547 return ans;
2548 }
2549 #undef FUNC_NAME
2550
2551
2552 SCM_DEFINE (scm_string_unfold_right, "string-unfold-right", 4, 2, 0,
2553 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2554 "@itemize @bullet\n"
2555 "@item @var{g} is used to generate a series of @emph{seed}\n"
2556 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2557 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2558 "@dots{}\n"
2559 "@item @var{p} tells us when to stop -- when it returns true\n"
2560 "when applied to one of these seed values.\n"
2561 "@item @var{f} maps each seed value to the corresponding\n"
2562 "character in the result string. These chars are assembled\n"
2563 "into the string in a right-to-left order.\n"
2564 "@item @var{base} is the optional initial/rightmost portion\n"
2565 "of the constructed string; it default to the empty\n"
2566 "string.\n"
2567 "@item @var{make_final} is applied to the terminal seed\n"
2568 "value (on which @var{p} returns true) to produce\n"
2569 "the final/leftmost portion of the constructed string.\n"
2570 "It defaults to @code{(lambda (x) "")}.\n"
2571 "@end itemize")
2572 #define FUNC_NAME s_scm_string_unfold_right
2573 {
2574 SCM res, ans;
2575
2576 SCM_VALIDATE_PROC (1, p);
2577 SCM_VALIDATE_PROC (2, f);
2578 SCM_VALIDATE_PROC (3, g);
2579 if (!SCM_UNBNDP (base))
2580 {
2581 SCM_VALIDATE_STRING (5, base);
2582 ans = base;
2583 }
2584 else
2585 ans = scm_allocate_string (0);
2586 if (!SCM_UNBNDP (make_final))
2587 SCM_VALIDATE_PROC (6, make_final);
2588
2589 res = scm_call_1 (p, seed);
2590 while (scm_is_false (res))
2591 {
2592 SCM str;
2593 SCM ch = scm_call_1 (f, seed);
2594 if (!SCM_CHARP (ch))
2595 SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
2596 str = scm_allocate_string (1);
2597 *SCM_STRING_CHARS (str) = SCM_CHAR (ch);
2598
2599 ans = scm_string_append (scm_list_2 (str, ans));
2600 seed = scm_call_1 (g, seed);
2601 res = scm_call_1 (p, seed);
2602 }
2603 if (!SCM_UNBNDP (make_final))
2604 {
2605 res = scm_call_1 (make_final, seed);
2606 return scm_string_append (scm_list_2 (res, ans));
2607 }
2608 else
2609 return ans;
2610 }
2611 #undef FUNC_NAME
2612
2613
2614 SCM_DEFINE (scm_string_for_each, "string-for-each", 2, 2, 0,
2615 (SCM proc, SCM s, SCM start, SCM end),
2616 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
2617 "return value is not specified.")
2618 #define FUNC_NAME s_scm_string_for_each
2619 {
2620 char * cstr;
2621 int cstart, cend;
2622
2623 SCM_VALIDATE_PROC (1, proc);
2624 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2625 3, start, cstart,
2626 4, end, cend);
2627 while (cstart < cend)
2628 {
2629 unsigned int c = (unsigned char) cstr[cstart];
2630 scm_call_1 (proc, SCM_MAKE_CHAR (c));
2631 cstart++;
2632 }
2633 return SCM_UNSPECIFIED;
2634 }
2635 #undef FUNC_NAME
2636
2637 SCM_DEFINE (scm_string_for_each_index, "string-for-each-index", 2, 2, 0,
2638 (SCM proc, SCM s, SCM start, SCM end),
2639 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
2640 "return value is not specified.")
2641 #define FUNC_NAME s_scm_string_for_each
2642 {
2643 char * cstr;
2644 int cstart, cend;
2645
2646 SCM_VALIDATE_PROC (1, proc);
2647 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr,
2648 3, start, cstart,
2649 4, end, cend);
2650 while (cstart < cend)
2651 {
2652 scm_call_1 (proc, SCM_I_MAKINUM (cstart));
2653 cstart++;
2654 }
2655 return SCM_UNSPECIFIED;
2656 }
2657 #undef FUNC_NAME
2658
2659 SCM_DEFINE (scm_xsubstring, "xsubstring", 2, 3, 0,
2660 (SCM s, SCM from, SCM to, SCM start, SCM end),
2661 "This is the @emph{extended substring} procedure that implements\n"
2662 "replicated copying of a substring of some string.\n"
2663 "\n"
2664 "@var{s} is a string, @var{start} and @var{end} are optional\n"
2665 "arguments that demarcate a substring of @var{s}, defaulting to\n"
2666 "0 and the length of @var{s}. Replicate this substring up and\n"
2667 "down index space, in both the positive and negative directions.\n"
2668 "@code{xsubstring} returns the substring of this string\n"
2669 "beginning at index @var{from}, and ending at @var{to}, which\n"
2670 "defaults to @var{from} + (@var{end} - @var{start}).")
2671 #define FUNC_NAME s_scm_xsubstring
2672 {
2673 char * cs, * p;
2674 size_t cstart, cend, cfrom, cto;
2675 SCM result;
2676
2677 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cs,
2678 4, start, cstart,
2679 5, end, cend);
2680 cfrom = scm_to_size_t (from);
2681 if (SCM_UNBNDP (to))
2682 cto = cfrom + (cend - cstart);
2683 else
2684 cto = scm_to_size_t (to);
2685 if (cstart == cend && cfrom != cto)
2686 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
2687
2688 result = scm_allocate_string (cto - cfrom);
2689
2690 p = SCM_STRING_CHARS (result);
2691 while (cfrom < cto)
2692 {
2693 int t = ((cfrom < 0) ? -cfrom : cfrom) % (cend - cstart);
2694 if (cfrom < 0)
2695 *p = cs[(cend - cstart) - t];
2696 else
2697 *p = cs[t];
2698 cfrom++;
2699 p++;
2700 }
2701 return result;
2702 }
2703 #undef FUNC_NAME
2704
2705
2706 SCM_DEFINE (scm_string_xcopy_x, "string-xcopy!", 4, 3, 0,
2707 (SCM target, SCM tstart, SCM s, SCM sfrom, SCM sto, SCM start, SCM end),
2708 "Exactly the same as @code{xsubstring}, but the extracted text\n"
2709 "is written into the string @var{target} starting at index\n"
2710 "@var{tstart}. The operation is not defined if @code{(eq?\n"
2711 "@var{target} @var{s})} or these arguments share storage -- you\n"
2712 "cannot copy a string on top of itself.")
2713 #define FUNC_NAME s_scm_string_xcopy_x
2714 {
2715 char * ctarget, * cs, * p;
2716 size_t ctstart, csfrom, csto, cstart, cend;
2717 SCM dummy = SCM_UNDEFINED;
2718 int cdummy;
2719
2720 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, target, ctarget,
2721 2, tstart, ctstart,
2722 2, dummy, cdummy);
2723 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cs,
2724 6, start, cstart,
2725 7, end, cend);
2726 csfrom = scm_to_size_t (sfrom);
2727 if (SCM_UNBNDP (sto))
2728 csto = csfrom + (cend - cstart);
2729 else
2730 csto = scm_to_size_t (sto);
2731 if (cstart == cend && csfrom != csto)
2732 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
2733 SCM_ASSERT_RANGE (1, tstart,
2734 ctstart + (csto - csfrom) <= SCM_STRING_LENGTH (target));
2735
2736 p = ctarget + ctstart;
2737 while (csfrom < csto)
2738 {
2739 int t = ((csfrom < 0) ? -csfrom : csfrom) % (cend - cstart);
2740 if (csfrom < 0)
2741 *p = cs[(cend - cstart) - t];
2742 else
2743 *p = cs[t];
2744 csfrom++;
2745 p++;
2746 }
2747 return SCM_UNSPECIFIED;
2748 }
2749 #undef FUNC_NAME
2750
2751
2752 SCM_DEFINE (scm_string_replace, "string-replace", 2, 4, 0,
2753 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
2754 "Return the string @var{s1}, but with the characters\n"
2755 "@var{start1} @dots{} @var{end1} replaced by the characters\n"
2756 "@var{start2} @dots{} @var{end2} from @var{s2}.")
2757 #define FUNC_NAME s_scm_string_replace
2758 {
2759 char * cstr1, * cstr2, * p;
2760 size_t cstart1, cend1, cstart2, cend2;
2761 SCM result;
2762
2763 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
2764 3, start1, cstart1,
2765 4, end1, cend1);
2766 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
2767 5, start2, cstart2,
2768 6, end2, cend2);
2769 result = scm_allocate_string (cstart1 + (cend2 - cstart2) +
2770 SCM_STRING_LENGTH (s1) - cend1);
2771 p = SCM_STRING_CHARS (result);
2772 memmove (p, cstr1, cstart1 * sizeof (char));
2773 memmove (p + cstart1, cstr2 + cstart2, (cend2 - cstart2) * sizeof (char));
2774 memmove (p + cstart1 + (cend2 - cstart2),
2775 cstr1 + cend1,
2776 (SCM_STRING_LENGTH (s1) - cend1) * sizeof (char));
2777 return result;
2778 }
2779 #undef FUNC_NAME
2780
2781
2782 SCM_DEFINE (scm_string_tokenize, "string-tokenize", 1, 3, 0,
2783 (SCM s, SCM token_set, SCM start, SCM end),
2784 "Split the string @var{s} into a list of substrings, where each\n"
2785 "substring is a maximal non-empty contiguous sequence of\n"
2786 "characters from the character set @var{token_set}, which\n"
2787 "defaults to @code{char-set:graphic} from module (srfi srfi-14).\n"
2788 "If @var{start} or @var{end} indices are provided, they restrict\n"
2789 "@code{string-tokenize} to operating on the indicated substring\n"
2790 "of @var{s}.")
2791 #define FUNC_NAME s_scm_string_tokenize
2792 {
2793 char * cstr;
2794 size_t cstart, cend;
2795 SCM result = SCM_EOL;
2796
2797 static SCM charset_graphic = SCM_BOOL_F;
2798
2799 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2800 3, start, cstart,
2801 4, end, cend);
2802
2803 if (SCM_UNBNDP (token_set))
2804 {
2805 if (charset_graphic == SCM_BOOL_F)
2806 {
2807 SCM srfi_14_module = scm_c_resolve_module ("srfi srfi-14");
2808 SCM charset_graphic_var = scm_c_module_lookup (srfi_14_module,
2809 "char-set:graphic");
2810 charset_graphic =
2811 scm_permanent_object (SCM_VARIABLE_REF (charset_graphic_var));
2812 }
2813 token_set = charset_graphic;
2814 }
2815
2816 if (SCM_CHARSETP (token_set))
2817 {
2818 int idx;
2819
2820 while (cstart < cend)
2821 {
2822 while (cstart < cend)
2823 {
2824 if (SCM_CHARSET_GET (token_set, cstr[cend - 1]))
2825 break;
2826 cend--;
2827 }
2828 if (cstart >= cend)
2829 break;
2830 idx = cend;
2831 while (cstart < cend)
2832 {
2833 if (!SCM_CHARSET_GET (token_set, cstr[cend - 1]))
2834 break;
2835 cend--;
2836 }
2837 result = scm_cons (scm_mem2string (cstr + cend, idx - cend), result);
2838 }
2839 }
2840 else SCM_WRONG_TYPE_ARG (2, token_set);
2841 return result;
2842 }
2843 #undef FUNC_NAME
2844
2845
2846 SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
2847 (SCM s, SCM char_pred, SCM start, SCM end),
2848 "Filter the string @var{s}, retaining only those characters that\n"
2849 "satisfy the @var{char_pred} argument. If the argument is a\n"
2850 "procedure, it is applied to each character as a predicate, if\n"
2851 "it is a character, it is tested for equality and if it is a\n"
2852 "character set, it is tested for membership.")
2853 #define FUNC_NAME s_scm_string_filter
2854 {
2855 char * cstr;
2856 size_t cstart, cend;
2857 SCM result;
2858 int idx;
2859
2860 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2861 3, start, cstart,
2862 4, end, cend);
2863 if (SCM_CHARP (char_pred))
2864 {
2865 SCM ls = SCM_EOL;
2866 char chr;
2867
2868 chr = SCM_CHAR (char_pred);
2869 idx = cstart;
2870 while (idx < cend)
2871 {
2872 if (cstr[idx] == chr)
2873 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2874 idx++;
2875 }
2876 result = scm_reverse_list_to_string (ls);
2877 }
2878 else if (SCM_CHARSETP (char_pred))
2879 {
2880 SCM ls = SCM_EOL;
2881
2882 idx = cstart;
2883 while (idx < cend)
2884 {
2885 if (SCM_CHARSET_GET (char_pred, cstr[idx]))
2886 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2887 idx++;
2888 }
2889 result = scm_reverse_list_to_string (ls);
2890 }
2891 else
2892 {
2893 SCM ls = SCM_EOL;
2894
2895 SCM_VALIDATE_PROC (2, char_pred);
2896 idx = cstart;
2897 while (idx < cend)
2898 {
2899 SCM res;
2900 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[idx]));
2901 if (scm_is_true (res))
2902 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2903 idx++;
2904 }
2905 result = scm_reverse_list_to_string (ls);
2906 }
2907 return result;
2908 }
2909 #undef FUNC_NAME
2910
2911
2912 SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
2913 (SCM s, SCM char_pred, SCM start, SCM end),
2914 "Filter the string @var{s}, retaining only those characters that\n"
2915 "do not satisfy the @var{char_pred} argument. If the argument\n"
2916 "is a procedure, it is applied to each character as a predicate,\n"
2917 "if it is a character, it is tested for equality and if it is a\n"
2918 "character set, it is tested for membership.")
2919 #define FUNC_NAME s_scm_string_delete
2920 {
2921 char * cstr;
2922 size_t cstart, cend;
2923 SCM result;
2924 int idx;
2925
2926 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2927 3, start, cstart,
2928 4, end, cend);
2929 if (SCM_CHARP (char_pred))
2930 {
2931 SCM ls = SCM_EOL;
2932 char chr;
2933
2934 chr = SCM_CHAR (char_pred);
2935 idx = cstart;
2936 while (idx < cend)
2937 {
2938 if (cstr[idx] != chr)
2939 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2940 idx++;
2941 }
2942 result = scm_reverse_list_to_string (ls);
2943 }
2944 else if (SCM_CHARSETP (char_pred))
2945 {
2946 SCM ls = SCM_EOL;
2947
2948 idx = cstart;
2949 while (idx < cend)
2950 {
2951 if (!SCM_CHARSET_GET (char_pred, cstr[idx]))
2952 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2953 idx++;
2954 }
2955 result = scm_reverse_list_to_string (ls);
2956 }
2957 else
2958 {
2959 SCM ls = SCM_EOL;
2960
2961 SCM_VALIDATE_PROC (2, char_pred);
2962 idx = cstart;
2963 while (idx < cend)
2964 {
2965 SCM res;
2966 res = scm_call_1 (char_pred, SCM_MAKE_CHAR (cstr[idx]));
2967 if (scm_is_false (res))
2968 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2969 idx++;
2970 }
2971 result = scm_reverse_list_to_string (ls);
2972 }
2973 return result;
2974 }
2975 #undef FUNC_NAME
2976
2977
2978 /* Initialize the SRFI-13 module. This function will be called by the
2979 loading Scheme module. */
2980 void
2981 scm_init_srfi_13 (void)
2982 {
2983 /* We initialize the SRFI-14 module here, because the string
2984 primitives need the charset smob type created by that module. */
2985 scm_c_init_srfi_14 ();
2986
2987 /* Install the string primitives. */
2988 #include "srfi/srfi-13.x"
2989 }
2990
2991 /* End of srfi-13.c. */