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