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