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