* srfi-13.c (scm_init_srfi_13), srfi-14.c (scm_init_srfi_14):
[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_string_concatenate_reverse, "string-concatenate-reverse", 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. If @var{end}\n"
2311 "is given, only the characters of @var{final_string} up to index\n"
2312 "@var{end} are used.\n"
2313 "\n"
2314 "Guaranteed to return a freshly allocated string.")
2315 #define FUNC_NAME s_scm_string_concatenate_reverse
2316 {
2317 long strings;
2318 SCM tmp, result;
2319 int len = 0;
2320 char * p;
2321 int cend = 0;
2322
2323 /* Check the optional arguments and calculate the additional length
2324 of the result string. */
2325 if (!SCM_UNBNDP (final_string))
2326 {
2327 SCM_VALIDATE_STRING (2, final_string);
2328 if (!SCM_UNBNDP (end))
2329 {
2330 SCM_VALIDATE_INUM_COPY (3, end, cend);
2331 SCM_ASSERT_RANGE (3, end,
2332 (cend >= 0) &&
2333 (cend <= SCM_STRING_LENGTH (final_string)));
2334 }
2335 else
2336 {
2337 cend = SCM_STRING_LENGTH (final_string);
2338 }
2339 len += cend;
2340 }
2341 strings = scm_ilength (ls);
2342 /* Validate the string list. */
2343 if (strings < 0)
2344 SCM_WRONG_TYPE_ARG (1, ls);
2345
2346 /* Calculate the length of the result string. */
2347 tmp = ls;
2348 while (!SCM_NULLP (tmp))
2349 {
2350 SCM elt = SCM_CAR (tmp);
2351 SCM_VALIDATE_STRING (1, elt);
2352 len += SCM_STRING_LENGTH (elt);
2353 tmp = SCM_CDR (tmp);
2354 }
2355
2356 result = scm_allocate_string (len);
2357
2358 p = SCM_STRING_CHARS (result) + len;
2359
2360 /* Construct the result string, possibly by using the optional final
2361 string. */
2362 if (!SCM_UNBNDP (final_string))
2363 {
2364 p -= cend;
2365 memmove (p, SCM_STRING_CHARS (final_string), cend * sizeof (char));
2366 }
2367 tmp = ls;
2368 while (!SCM_NULLP (tmp))
2369 {
2370 SCM elt = SCM_CAR (tmp);
2371 p -= SCM_STRING_LENGTH (elt);
2372 memmove (p, SCM_STRING_CHARS (elt),
2373 SCM_STRING_LENGTH (elt) * sizeof (char));
2374 tmp = SCM_CDR (tmp);
2375 }
2376 return result;
2377 }
2378 #undef FUNC_NAME
2379
2380
2381 SCM_DEFINE (scm_string_concatenate_shared, "string-concatenate/shared", 1, 0, 0,
2382 (SCM ls),
2383 "Like @code{string-concatenate}, but the result may share memory\n"
2384 "with the strings in the list @var{ls}.")
2385 #define FUNC_NAME s_scm_string_concatenate_shared
2386 {
2387 /* Optimize the one-string case. */
2388 long i = scm_ilength (ls);
2389 if (i == 1)
2390 {
2391 SCM_VALIDATE_STRING (1, SCM_CAR (ls));
2392 return SCM_CAR (ls);
2393 }
2394 return scm_string_concatenate (ls);
2395 }
2396 #undef FUNC_NAME
2397
2398
2399 SCM_DEFINE (scm_string_concatenate_reverse_shared, "string-concatenate-reverse/shared", 1, 2, 0,
2400 (SCM ls, SCM final_string, SCM end),
2401 "Like @code{string-concatenate-reverse}, but the result may\n"
2402 "share memory with the the strings in the @var{ls} arguments.")
2403 #define FUNC_NAME s_scm_string_concatenate_reverse_shared
2404 {
2405 /* Just call the non-sharing version. */
2406 return scm_string_concatenate_reverse (ls, final_string, end);
2407 }
2408 #undef FUNC_NAME
2409
2410
2411 SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0,
2412 (SCM s, SCM proc, SCM start, SCM end),
2413 "@var{proc} is a char->char procedure, it is mapped over\n"
2414 "@var{s}. The order in which the procedure is applied to the\n"
2415 "string elements is not specified.")
2416 #define FUNC_NAME s_scm_string_map
2417 {
2418 char * cstr, *p;
2419 int cstart, cend;
2420 SCM result;
2421
2422 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2423 3, start, cstart,
2424 4, end, cend);
2425 SCM_VALIDATE_PROC (2, proc);
2426 result = scm_allocate_string (cend - cstart);
2427 p = SCM_STRING_CHARS (result);
2428 while (cstart < cend)
2429 {
2430 SCM ch = scm_apply (proc, SCM_MAKE_CHAR (cstr[cstart]),
2431 scm_listofnull);
2432 if (!SCM_CHARP (ch))
2433 SCM_MISC_ERROR ("procedure ~S returned non-char", SCM_LIST1 (proc));
2434 cstart++;
2435 *p++ = SCM_CHAR (ch);
2436 }
2437 return result;
2438 }
2439 #undef FUNC_NAME
2440
2441
2442 SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0,
2443 (SCM s, SCM proc, SCM start, SCM end),
2444 "@var{proc} is a char->char procedure, it is mapped over\n"
2445 "@var{s}. The order in which the procedure is applied to the\n"
2446 "string elements is not specified. The string @var{s} is\n"
2447 "modified in-place, the return value is not specified.")
2448 #define FUNC_NAME s_scm_string_map_x
2449 {
2450 char * cstr, *p;
2451 int cstart, cend;
2452
2453 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2454 3, start, cstart,
2455 4, end, cend);
2456 SCM_VALIDATE_PROC (2, proc);
2457 p = SCM_STRING_CHARS (s) + cstart;
2458 while (cstart < cend)
2459 {
2460 SCM ch = scm_apply (proc, SCM_MAKE_CHAR (cstr[cstart]),
2461 scm_listofnull);
2462 if (!SCM_CHARP (ch))
2463 SCM_MISC_ERROR ("procedure ~S returned non-char", SCM_LIST1 (proc));
2464 cstart++;
2465 *p++ = SCM_CHAR (ch);
2466 }
2467 return SCM_UNSPECIFIED;
2468 }
2469 #undef FUNC_NAME
2470
2471
2472 SCM_DEFINE (scm_string_fold, "string-fold", 3, 2, 0,
2473 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2474 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2475 "as the terminating element, from left to right. @var{kons}\n"
2476 "must expect two arguments: The actual character and the last\n"
2477 "result of @var{kons}' application.")
2478 #define FUNC_NAME s_scm_string_fold
2479 {
2480 char * cstr;
2481 int cstart, cend;
2482 SCM result;
2483
2484 SCM_VALIDATE_PROC (1, kons);
2485 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2486 4, start, cstart,
2487 5, end, cend);
2488 result = knil;
2489 while (cstart < cend)
2490 {
2491 result = scm_apply (kons, SCM_LIST2 (SCM_MAKE_CHAR (cstr[cstart]),
2492 result), SCM_EOL);
2493 cstart++;
2494 }
2495 return result;
2496 }
2497 #undef FUNC_NAME
2498
2499
2500 SCM_DEFINE (scm_string_fold_right, "string-fold-right", 3, 2, 0,
2501 (SCM kons, SCM knil, SCM s, SCM start, SCM end),
2502 "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
2503 "as the terminating element, from right to left. @var{kons}\n"
2504 "must expect two arguments: The actual character and the last\n"
2505 "result of @var{kons}' application.")
2506 #define FUNC_NAME s_scm_string_fold_right
2507 {
2508 char * cstr;
2509 int cstart, cend;
2510 SCM result;
2511
2512 SCM_VALIDATE_PROC (1, kons);
2513 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cstr,
2514 4, start, cstart,
2515 5, end, cend);
2516 result = knil;
2517 while (cstart < cend)
2518 {
2519 result = scm_apply (kons, SCM_LIST2 (SCM_MAKE_CHAR (cstr[cend - 1]),
2520 result), SCM_EOL);
2521 cend--;
2522 }
2523 return result;
2524 }
2525 #undef FUNC_NAME
2526
2527
2528 SCM_DEFINE (scm_string_unfold, "string-unfold", 4, 2, 0,
2529 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2530 "@itemize\n"
2531 "@item @var{g} is used to generate a series of @emph{seed}\n"
2532 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2533 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2534 "@dots{}\n"
2535 "@item @var{p} tells us when to stop -- when it returns true\n"
2536 "when applied to one of these seed values.\n"
2537 "@item @var{f} maps each seed value to the corresponding \n"
2538 "character in the result string. These chars are assembled\n"
2539 "into the string in a left-to-right order.\n"
2540 "@item @var{base} is the optional initial/leftmost portion\n"
2541 "of the constructed string; it default to the empty\n"
2542 "string.\n"
2543 "@item @var{make_final} is applied to the terminal seed\n"
2544 "value (on which @var{p} returns true) to produce\n"
2545 "the final/rightmost portion of the constructed string.\n"
2546 "It defaults to @code{(lambda (x) "")}.\n"
2547 "@end itemize")
2548 #define FUNC_NAME s_scm_string_unfold
2549 {
2550 SCM res, ans;
2551
2552 SCM_VALIDATE_PROC (1, p);
2553 SCM_VALIDATE_PROC (2, f);
2554 SCM_VALIDATE_PROC (3, g);
2555 if (!SCM_UNBNDP (base))
2556 {
2557 SCM_VALIDATE_STRING (5, base);
2558 ans = base;
2559 }
2560 else
2561 ans = scm_allocate_string (0);
2562 if (!SCM_UNBNDP (make_final))
2563 SCM_VALIDATE_PROC (6, make_final);
2564
2565 res = scm_apply (p, seed, scm_listofnull);
2566 while (SCM_FALSEP (res))
2567 {
2568 SCM str;
2569 SCM ch = scm_apply (f, seed, scm_listofnull);
2570 if (!SCM_CHARP (ch))
2571 SCM_MISC_ERROR ("procedure ~S returned non-char", SCM_LIST1 (f));
2572 str = scm_allocate_string (1);
2573 *SCM_STRING_CHARS (str) = SCM_CHAR (ch);
2574
2575 ans = scm_string_append (SCM_LIST2 (ans, str));
2576 seed = scm_apply (g, seed, scm_listofnull);
2577 res = scm_apply (p, seed, scm_listofnull);
2578 }
2579 if (!SCM_UNBNDP (make_final))
2580 {
2581 res = scm_apply (make_final, seed, scm_listofnull);
2582 return scm_string_append (SCM_LIST2 (ans, res));
2583 }
2584 else
2585 return ans;
2586 }
2587 #undef FUNC_NAME
2588
2589
2590 SCM_DEFINE (scm_string_unfold_right, "string-unfold-right", 4, 2, 0,
2591 (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
2592 "@itemize\n"
2593 "@item @var{g} is used to generate a series of @emph{seed}\n"
2594 "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
2595 "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
2596 "@dots{}\n"
2597 "@item @var{p} tells us when to stop -- when it returns true\n"
2598 "when applied to one of these seed values.\n"
2599 "@item @var{f} maps each seed value to the corresponding \n"
2600 "character in the result string. These chars are assembled\n"
2601 "into the string in a right-to-left order.\n"
2602 "@item @var{base} is the optional initial/rightmost portion\n"
2603 "of the constructed string; it default to the empty\n"
2604 "string.\n"
2605 "@item @var{make_final} is applied to the terminal seed\n"
2606 "value (on which @var{p} returns true) to produce\n"
2607 "the final/leftmost portion of the constructed string.\n"
2608 "It defaults to @code{(lambda (x) "")}.\n"
2609 "@end itemize")
2610 #define FUNC_NAME s_scm_string_unfold_right
2611 {
2612 SCM res, ans;
2613
2614 SCM_VALIDATE_PROC (1, p);
2615 SCM_VALIDATE_PROC (2, f);
2616 SCM_VALIDATE_PROC (3, g);
2617 if (!SCM_UNBNDP (base))
2618 {
2619 SCM_VALIDATE_STRING (5, base);
2620 ans = base;
2621 }
2622 else
2623 ans = scm_allocate_string (0);
2624 if (!SCM_UNBNDP (make_final))
2625 SCM_VALIDATE_PROC (6, make_final);
2626
2627 res = scm_apply (p, seed, scm_listofnull);
2628 while (SCM_FALSEP (res))
2629 {
2630 SCM str;
2631 SCM ch = scm_apply (f, seed, scm_listofnull);
2632 if (!SCM_CHARP (ch))
2633 SCM_MISC_ERROR ("procedure ~S returned non-char", SCM_LIST1 (f));
2634 str = scm_allocate_string (1);
2635 *SCM_STRING_CHARS (str) = SCM_CHAR (ch);
2636
2637 ans = scm_string_append (SCM_LIST2 (str, ans));
2638 seed = scm_apply (g, seed, scm_listofnull);
2639 res = scm_apply (p, seed, scm_listofnull);
2640 }
2641 if (!SCM_UNBNDP (make_final))
2642 {
2643 res = scm_apply (make_final, seed, scm_listofnull);
2644 return scm_string_append (SCM_LIST2 (res, ans));
2645 }
2646 else
2647 return ans;
2648 }
2649 #undef FUNC_NAME
2650
2651
2652 SCM_DEFINE (scm_string_for_each, "string-for-each", 2, 2, 0,
2653 (SCM s, SCM proc, SCM start, SCM end),
2654 "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
2655 "return value is not specified.")
2656 #define FUNC_NAME s_scm_string_for_each
2657 {
2658 char * cstr;
2659 int cstart, cend;
2660
2661 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2662 3, start, cstart,
2663 4, end, cend);
2664 SCM_VALIDATE_PROC (2, proc);
2665 while (cstart < cend)
2666 {
2667 scm_apply (proc, SCM_MAKE_CHAR (cstr[cstart]), scm_listofnull);
2668 cstart++;
2669 }
2670 return SCM_UNSPECIFIED;
2671 }
2672 #undef FUNC_NAME
2673
2674 SCM_DEFINE (scm_xsubstring, "xsubstring", 2, 3, 0,
2675 (SCM s, SCM from, SCM to, SCM start, SCM end),
2676 "This is the @emph{extended substring} procedure that implements\n"
2677 "replicated copying of a substring of some string.\n"
2678 "\n"
2679 "@var{s} is a string, @var{start} and @var{end} are optional\n"
2680 "arguments that demarcate a substring of @var{s}, defaulting to\n"
2681 "0 and the length of @var{s}. Replicate this substring up and\n"
2682 "down index space, in both the positive and negative directions.\n"
2683 "@code{xsubstring} returns the substring of this string\n"
2684 "beginning at index @var{from}, and ending at @var{to}, which\n"
2685 "defaults to @var{from} + (@var{end} - @var{start}).")
2686 #define FUNC_NAME s_scm_xsubstring
2687 {
2688 char * cs, * p;
2689 int cstart, cend, cfrom, cto;
2690 SCM result;
2691
2692 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cs,
2693 4, start, cstart,
2694 5, end, cend);
2695 SCM_VALIDATE_INUM_COPY (2, from, cfrom);
2696 SCM_VALIDATE_INUM_DEF_COPY (3, to, cfrom + (cend - cstart), cto);
2697 if (cstart == cend && cfrom != cto)
2698 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
2699
2700 result = scm_allocate_string (cto - cfrom);
2701
2702 p = SCM_STRING_CHARS (result);
2703 while (cfrom < cto)
2704 {
2705 int t = ((cfrom < 0) ? -cfrom : cfrom) % (cend - cstart);
2706 if (cfrom < 0)
2707 *p = cs[(cend - cstart) - t];
2708 else
2709 *p = cs[t];
2710 cfrom++;
2711 p++;
2712 }
2713 return result;
2714 }
2715 #undef FUNC_NAME
2716
2717
2718 SCM_DEFINE (scm_string_xcopy_x, "string-xcopy!", 4, 3, 0,
2719 (SCM target, SCM tstart, SCM s, SCM sfrom, SCM sto, SCM start, SCM end),
2720 "Exactly the same as @code{xsubstring}, but the extracted text\n"
2721 "is written into the string @var{target} starting at index\n"
2722 "@var{tstart}. The operation is not defined if @code{(eq?\n"
2723 "@var{target} @var{s})} or these arguments share storage -- you\n"
2724 "cannot copy a string on top of itself.")
2725 #define FUNC_NAME s_scm_string_xcopy_x
2726 {
2727 char * ctarget, * cs, * p;
2728 int ctstart, csfrom, csto, cstart, cend;
2729 SCM dummy = SCM_UNDEFINED;
2730 int cdummy;
2731
2732 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, target, ctarget,
2733 2, tstart, ctstart,
2734 2, dummy, cdummy);
2735 SCM_VALIDATE_SUBSTRING_SPEC_COPY (3, s, cs,
2736 6, start, cstart,
2737 7, end, cend);
2738 SCM_VALIDATE_INUM_COPY (4, sfrom, csfrom);
2739 SCM_VALIDATE_INUM_DEF_COPY (5, sto, csfrom + (cend - cstart), csto);
2740 if (cstart == cend && csfrom != csto)
2741 SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
2742 SCM_ASSERT_RANGE (1, tstart,
2743 ctstart + (csto - csfrom) <= SCM_STRING_LENGTH (target));
2744
2745 p = ctarget + ctstart;
2746 while (csfrom < csto)
2747 {
2748 int t = ((csfrom < 0) ? -csfrom : csfrom) % (cend - cstart);
2749 if (csfrom < 0)
2750 *p = cs[(cend - cstart) - t];
2751 else
2752 *p = cs[t];
2753 csfrom++;
2754 p++;
2755 }
2756 return SCM_UNSPECIFIED;
2757 }
2758 #undef FUNC_NAME
2759
2760
2761 SCM_DEFINE (scm_string_replace, "string-replace", 2, 4, 0,
2762 (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
2763 "Return the string @var{s1}, but with the characters\n"
2764 "@var{start1} @dots{} @var{end1} replaced by the characters\n"
2765 "@var{start2} @dots{} @var{end2} from @var{s2}.")
2766 #define FUNC_NAME s_scm_string_replace
2767 {
2768 char * cstr1, * cstr2, * p;
2769 int cstart1, cend1, cstart2, cend2;
2770 SCM result;
2771
2772 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s1, cstr1,
2773 3, start1, cstart1,
2774 4, end1, cend1);
2775 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s2, cstr2,
2776 5, start2, cstart2,
2777 6, end2, cend2);
2778 result = scm_allocate_string (cstart1 + (cend2 - cstart2) +
2779 SCM_STRING_LENGTH (s1) - cend1);
2780 p = SCM_STRING_CHARS (result);
2781 memmove (p, cstr1, cstart1 * sizeof (char));
2782 memmove (p + cstart1, cstr2 + cstart2, (cend2 - cstart2) * sizeof (char));
2783 memmove (p + cstart1 + (cend2 - cstart2),
2784 cstr1 + cend1,
2785 (SCM_STRING_LENGTH (s1) - cend1) * sizeof (char));
2786 return result;
2787 }
2788 #undef FUNC_NAME
2789
2790
2791 SCM_DEFINE (scm_string_tokenize, "string-tokenize", 1, 3, 0,
2792 (SCM s, SCM token_char, SCM start, SCM end),
2793 "Split the string @var{s} into a list of substrings, where each\n"
2794 "substring is a maximal non-empty contiguous sequence of\n"
2795 "characters equal to the character @var{token_char}, or\n"
2796 "whitespace, if @var{token_char} is not given. If\n"
2797 "@var{token_char} is a character set, it is used for finding the\n"
2798 "token borders.")
2799 #define FUNC_NAME s_scm_string_tokenize
2800 {
2801 char * cstr;
2802 int cstart, cend;
2803 SCM result = SCM_EOL;
2804
2805 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2806 3, start, cstart,
2807 4, end, cend);
2808 if (SCM_UNBNDP (token_char))
2809 {
2810 int idx;
2811
2812 while (cstart < cend)
2813 {
2814 while (cstart < cend)
2815 {
2816 if (!isspace (cstr[cend - 1]))
2817 break;
2818 cend--;
2819 }
2820 if (cstart >= cend)
2821 break;
2822 idx = cend;
2823 while (cstart < cend)
2824 {
2825 if (isspace (cstr[cend - 1]))
2826 break;
2827 cend--;
2828 }
2829 result = scm_cons (scm_makfromstr (cstr + cend, idx - cend,
2830 0), result);
2831 }
2832 }
2833 else if (SCM_CHARSETP (token_char))
2834 {
2835 int idx;
2836
2837 while (cstart < cend)
2838 {
2839 while (cstart < cend)
2840 {
2841 if (!SCM_CHARSET_GET (token_char, cstr[cend - 1]))
2842 break;
2843 cend--;
2844 }
2845 if (cstart >= cend)
2846 break;
2847 idx = cend;
2848 while (cstart < cend)
2849 {
2850 if (SCM_CHARSET_GET (token_char, cstr[cend - 1]))
2851 break;
2852 cend--;
2853 }
2854 result = scm_cons (scm_makfromstr (cstr + cend, idx - cend,
2855 0), result);
2856 }
2857 }
2858 else
2859 {
2860 int idx;
2861 char chr;
2862
2863 SCM_VALIDATE_CHAR (2, token_char);
2864 chr = SCM_CHAR (token_char);
2865
2866 while (cstart < cend)
2867 {
2868 while (cstart < cend)
2869 {
2870 if (cstr[cend - 1] != chr)
2871 break;
2872 cend--;
2873 }
2874 if (cstart >= cend)
2875 break;
2876 idx = cend;
2877 while (cstart < cend)
2878 {
2879 if (cstr[cend - 1] == chr)
2880 break;
2881 cend--;
2882 }
2883 result = scm_cons (scm_makfromstr (cstr + cend, idx - cend,
2884 0), result);
2885 }
2886 }
2887 return result;
2888 }
2889 #undef FUNC_NAME
2890
2891
2892 SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
2893 (SCM s, SCM char_pred, SCM start, SCM end),
2894 "Filter the string @var{s}, retaining only those characters that\n"
2895 "satisfy the @var{char_pred} argument. If the argument is a\n"
2896 "procedure, it is applied to each character as a predicate, if\n"
2897 "it is a character, it is tested for equality and if it is a\n"
2898 "character set, it is tested for membership.")
2899 #define FUNC_NAME s_scm_string_filter
2900 {
2901 char * cstr;
2902 int cstart, cend;
2903 SCM result;
2904 int idx;
2905
2906 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2907 3, start, cstart,
2908 4, end, cend);
2909 if (SCM_CHARP (char_pred))
2910 {
2911 SCM ls = SCM_EOL;
2912 char chr;
2913
2914 chr = SCM_CHAR (char_pred);
2915 idx = cstart;
2916 while (idx < cend)
2917 {
2918 if (cstr[idx] == chr)
2919 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2920 idx++;
2921 }
2922 result = scm_reverse_list_to_string (ls);
2923 }
2924 else if (SCM_CHARSETP (char_pred))
2925 {
2926 SCM ls = SCM_EOL;
2927
2928 idx = cstart;
2929 while (idx < cend)
2930 {
2931 if (SCM_CHARSET_GET (char_pred, cstr[idx]))
2932 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2933 idx++;
2934 }
2935 result = scm_reverse_list_to_string (ls);
2936 }
2937 else
2938 {
2939 SCM ls = SCM_EOL;
2940
2941 SCM_VALIDATE_PROC (2, char_pred);
2942 idx = cstart;
2943 while (idx < cend)
2944 {
2945 SCM res;
2946 res = scm_apply (char_pred, SCM_MAKE_CHAR (cstr[idx]),
2947 scm_listofnull);
2948 if (!SCM_FALSEP (res))
2949 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2950 idx++;
2951 }
2952 result = scm_reverse_list_to_string (ls);
2953 }
2954 return result;
2955 }
2956 #undef FUNC_NAME
2957
2958
2959 SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
2960 (SCM s, SCM char_pred, SCM start, SCM end),
2961 "Filter the string @var{s}, retaining only those characters that\n"
2962 "do not satisfy the @var{char_pred} argument. If the argument\n"
2963 "is a procedure, it is applied to each character as a predicate,\n"
2964 "if it is a character, it is tested for equality and if it is a\n"
2965 "character set, it is tested for membership.")
2966 #define FUNC_NAME s_scm_string_delete
2967 {
2968 char * cstr;
2969 int cstart, cend;
2970 SCM result;
2971 int idx;
2972
2973 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
2974 3, start, cstart,
2975 4, end, cend);
2976 if (SCM_CHARP (char_pred))
2977 {
2978 SCM ls = SCM_EOL;
2979 char chr;
2980
2981 chr = SCM_CHAR (char_pred);
2982 idx = cstart;
2983 while (idx < cend)
2984 {
2985 if (cstr[idx] != chr)
2986 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
2987 idx++;
2988 }
2989 result = scm_reverse_list_to_string (ls);
2990 }
2991 else if (SCM_CHARSETP (char_pred))
2992 {
2993 SCM ls = SCM_EOL;
2994
2995 idx = cstart;
2996 while (idx < cend)
2997 {
2998 if (SCM_CHARSET_GET (char_pred, cstr[idx]))
2999 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3000 idx++;
3001 }
3002 result = scm_reverse_list_to_string (ls);
3003 }
3004 else
3005 {
3006 SCM ls = SCM_EOL;
3007
3008 SCM_VALIDATE_PROC (2, char_pred);
3009 idx = cstart;
3010 while (idx < cend)
3011 {
3012 SCM res;
3013 res = scm_apply (char_pred, SCM_MAKE_CHAR (cstr[idx]),
3014 scm_listofnull);
3015 if (SCM_FALSEP (res))
3016 ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
3017 idx++;
3018 }
3019 result = scm_reverse_list_to_string (ls);
3020 }
3021 return result;
3022 }
3023 #undef FUNC_NAME
3024
3025
3026 void
3027 scm_init_srfi_13 (void)
3028 {
3029 #ifndef SCM_MAGIC_SNARFER
3030 #include "srfi/srfi-13.x"
3031 #endif
3032 }
3033
3034
3035 void
3036 scm_init_srfi_13_14 (void)
3037 {
3038 static int initialized = 0;
3039
3040 if (!initialized)
3041 {
3042 SCM srfi_13_module = scm_make_module (scm_read_0str ("(srfi srfi-13)"));
3043 SCM srfi_14_module = scm_make_module (scm_read_0str ("(srfi srfi-14)"));
3044 SCM old_module;
3045
3046 initialized = 1;
3047
3048 old_module = scm_set_current_module (srfi_13_module);
3049 scm_init_srfi_13 ();
3050 scm_set_current_module (srfi_14_module);
3051 scm_init_srfi_14 ();
3052
3053 scm_set_current_module (old_module);
3054 }
3055 }