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