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