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