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