2002-07-20 Han-Wen <hanwen@cs.uu.nl>
[bpt/guile.git] / libguile / strings.c
CommitLineData
be54b15d 1/* Copyright (C) 1995,1996,1998,2000,2001 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
1bbd0b84 42
0f2d19dd
JB
43\f
44
faf2c9d7
MD
45#include <string.h>
46
a0599745
MD
47#include "libguile/_scm.h"
48#include "libguile/chars.h"
7c33806a 49#include "libguile/root.h"
a0599745 50#include "libguile/strings.h"
1afff620 51#include "libguile/deprecation.h"
a0599745 52#include "libguile/validate.h"
1afff620 53
0f2d19dd
JB
54\f
55
56/* {Strings}
57 */
58
3b3b36dd 59SCM_DEFINE (scm_string_p, "string?", 1, 0, 0,
0d26a824 60 (SCM obj),
bb2c02f2 61 "Return @code{#t} if @var{obj} is a string, else @code{#f}.")
1bbd0b84 62#define FUNC_NAME s_scm_string_p
0f2d19dd 63{
e53cc817 64 return SCM_BOOL (SCM_STRINGP (obj));
0f2d19dd 65}
1bbd0b84 66#undef FUNC_NAME
0f2d19dd 67
e53cc817 68
bd9e24b3 69SCM_REGISTER_PROC (s_scm_list_to_string, "list->string", 1, 0, 0, scm_string);
1bbd0b84 70
3b3b36dd 71SCM_DEFINE (scm_string, "string", 0, 0, 1,
6fa73e72 72 (SCM chrs),
8f85c0c6 73 "@deffnx {Scheme Procedure} list->string chrs\n"
1e6808ea 74 "Return a newly allocated string composed of the arguments,\n"
0d26a824 75 "@var{chrs}.")
1bbd0b84 76#define FUNC_NAME s_scm_string
0f2d19dd 77{
bd9e24b3
GH
78 SCM result;
79
0f2d19dd 80 {
c014a02e 81 long i = scm_ilength (chrs);
bd9e24b3 82
4d6aae71 83 SCM_ASSERT (i >= 0, chrs, SCM_ARG1, FUNC_NAME);
be54b15d 84 result = scm_allocate_string (i);
0f2d19dd 85 }
bd9e24b3
GH
86
87 {
322ac0c5 88 unsigned char *data = SCM_STRING_UCHARS (result);
bd9e24b3 89
36284627 90 while (!SCM_NULLP (chrs))
bd9e24b3
GH
91 {
92 SCM elt = SCM_CAR (chrs);
93
7866a09b
GB
94 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
95 *data++ = SCM_CHAR (elt);
bd9e24b3
GH
96 chrs = SCM_CDR (chrs);
97 }
98 }
99 return result;
0f2d19dd 100}
1bbd0b84 101#undef FUNC_NAME
0f2d19dd 102
0f2d19dd
JB
103
104/* converts C scm_array of strings to SCM scm_list of strings. */
105/* If argc < 0, a null terminated scm_array is assumed. */
0f2d19dd 106SCM
1bbd0b84 107scm_makfromstrs (int argc, char **argv)
0f2d19dd
JB
108{
109 int i = argc;
110 SCM lst = SCM_EOL;
111 if (0 > i)
112 for (i = 0; argv[i]; i++);
113 while (i--)
36284627 114 lst = scm_cons (scm_mem2string (argv[i], strlen (argv[i])), lst);
0f2d19dd
JB
115 return lst;
116}
117
118
ee149d03
JB
119/* This function must only be applied to memory obtained via malloc,
120 since the GC is going to apply `free' to it when the string is
121 dropped.
122
123 Also, s[len] must be `\0', since we promise that strings are
124 null-terminated. Perhaps we could handle non-null-terminated
125 strings by claiming they're shared substrings of a string we just
126 made up. */
0f2d19dd 127SCM
1be6b49c 128scm_take_str (char *s, size_t len)
cb0d8be2 129#define FUNC_NAME "scm_take_str"
0f2d19dd
JB
130{
131 SCM answer;
cb0d8be2
DH
132
133 SCM_ASSERT_RANGE (2, scm_ulong2num (len), len <= SCM_STRING_MAX_LENGTH);
134
228a24ef 135 answer = scm_cell (SCM_MAKE_STRING_TAG (len), (scm_t_bits) s);
4c9419ac 136 scm_gc_register_collectable_memory (s, len+1, "string");
cb0d8be2 137
0f2d19dd
JB
138 return answer;
139}
cb0d8be2
DH
140#undef FUNC_NAME
141
0f2d19dd 142
ee149d03
JB
143/* `s' must be a malloc'd string. See scm_take_str. */
144SCM
145scm_take0str (char *s)
146{
147 return scm_take_str (s, strlen (s));
148}
149
36284627
DH
150
151SCM
152scm_mem2string (const char *src, size_t len)
0f2d19dd 153{
be54b15d 154 SCM s = scm_allocate_string (len);
86c991c2 155 char *dst = SCM_STRING_CHARS (s);
bd9e24b3 156
0f2d19dd
JB
157 while (len--)
158 *dst++ = *src++;
159 return s;
160}
161
b00418df
DH
162
163SCM
164scm_str2string (const char *src)
165{
166 return scm_mem2string (src, strlen (src));
167}
168
169
0f2d19dd 170SCM
1bbd0b84 171scm_makfrom0str (const char *src)
0f2d19dd
JB
172{
173 if (!src) return SCM_BOOL_F;
36284627 174 return scm_mem2string (src, strlen (src));
0f2d19dd
JB
175}
176
1cc91f1b 177
0f2d19dd 178SCM
1bbd0b84 179scm_makfrom0str_opt (const char *src)
0f2d19dd
JB
180{
181 return scm_makfrom0str (src);
182}
183
184
be54b15d 185SCM
1be6b49c 186scm_allocate_string (size_t len)
be54b15d
DH
187#define FUNC_NAME "scm_allocate_string"
188{
189 char *mem;
190 SCM s;
191
192 SCM_ASSERT_RANGE (1, scm_long2num (len), len <= SCM_STRING_MAX_LENGTH);
193
4c9419ac 194 mem = (char *) scm_gc_malloc (len + 1, "string");
be54b15d
DH
195 mem[len] = 0;
196
228a24ef 197 s = scm_cell (SCM_MAKE_STRING_TAG (len), (scm_t_bits) mem);
be54b15d
DH
198
199 return s;
200}
201#undef FUNC_NAME
202
203
3b3b36dd 204SCM_DEFINE (scm_make_string, "make-string", 1, 1, 0,
6fa73e72 205 (SCM k, SCM chr),
0d26a824
MG
206 "Return a newly allocated string of\n"
207 "length @var{k}. If @var{chr} is given, then all elements of\n"
208 "the string are initialized to @var{chr}, otherwise the contents\n"
9401323e 209 "of the @var{string} are unspecified.")
1bbd0b84 210#define FUNC_NAME s_scm_make_string
0f2d19dd 211{
cb0d8be2 212 if (SCM_INUMP (k))
0f2d19dd 213 {
c014a02e 214 long int i = SCM_INUM (k);
cb0d8be2
DH
215 SCM res;
216
217 SCM_ASSERT_RANGE (1, k, i >= 0);
218
be54b15d 219 res = scm_allocate_string (i);
cb0d8be2
DH
220 if (!SCM_UNBNDP (chr))
221 {
222 unsigned char *dst;
223
224 SCM_VALIDATE_CHAR (2, chr);
225
226 dst = SCM_STRING_UCHARS (res);
227 memset (dst, SCM_CHAR (chr), i);
228 }
229
230 return res;
0f2d19dd 231 }
cb0d8be2
DH
232 else if (SCM_BIGP (k))
233 SCM_OUT_OF_RANGE (1, k);
234 else
235 SCM_WRONG_TYPE_ARG (1, k);
0f2d19dd 236}
1bbd0b84 237#undef FUNC_NAME
0f2d19dd 238
cb0d8be2 239
3b3b36dd 240SCM_DEFINE (scm_string_length, "string-length", 1, 0, 0,
0d26a824
MG
241 (SCM string),
242 "Return the number of characters in @var{string}.")
1bbd0b84 243#define FUNC_NAME s_scm_string_length
0f2d19dd 244{
d1ca2c64 245 SCM_VALIDATE_STRING (1, string);
bfa974f0 246 return SCM_MAKINUM (SCM_STRING_LENGTH (string));
0f2d19dd 247}
1bbd0b84 248#undef FUNC_NAME
0f2d19dd 249
bd9e24b3 250SCM_DEFINE (scm_string_ref, "string-ref", 2, 0, 0,
6fa73e72 251 (SCM str, SCM k),
0d26a824
MG
252 "Return character @var{k} of @var{str} using zero-origin\n"
253 "indexing. @var{k} must be a valid index of @var{str}.")
1bbd0b84 254#define FUNC_NAME s_scm_string_ref
0f2d19dd 255{
c014a02e 256 long idx;
bd9e24b3 257
d1ca2c64 258 SCM_VALIDATE_STRING (1, str);
bd9e24b3 259 SCM_VALIDATE_INUM_COPY (2, k, idx);
d1ca2c64 260 SCM_ASSERT_RANGE (2, k, idx >= 0 && idx < SCM_STRING_LENGTH (str));
34f0f2b8 261 return SCM_MAKE_CHAR (SCM_STRING_UCHARS (str)[idx]);
0f2d19dd 262}
1bbd0b84 263#undef FUNC_NAME
0f2d19dd 264
f0942910 265
3b3b36dd 266SCM_DEFINE (scm_string_set_x, "string-set!", 3, 0, 0,
6fa73e72 267 (SCM str, SCM k, SCM chr),
0d26a824
MG
268 "Store @var{chr} in element @var{k} of @var{str} and return\n"
269 "an unspecified value. @var{k} must be a valid index of\n"
270 "@var{str}.")
1bbd0b84 271#define FUNC_NAME s_scm_string_set_x
0f2d19dd 272{
f0942910 273 SCM_VALIDATE_STRING (1, str);
34d19ef6
HWN
274 SCM_VALIDATE_INUM_RANGE (2, k,0, SCM_STRING_LENGTH(str));
275 SCM_VALIDATE_CHAR (3, chr);
322ac0c5 276 SCM_STRING_UCHARS (str)[SCM_INUM (k)] = SCM_CHAR (chr);
0f2d19dd
JB
277 return SCM_UNSPECIFIED;
278}
1bbd0b84 279#undef FUNC_NAME
0f2d19dd
JB
280
281
3b3b36dd 282SCM_DEFINE (scm_substring, "substring", 2, 1, 0,
0d26a824
MG
283 (SCM str, SCM start, SCM end),
284 "Return a newly allocated string formed from the characters\n"
285 "of @var{str} beginning with index @var{start} (inclusive) and\n"
286 "ending with index @var{end} (exclusive).\n"
287 "@var{str} must be a string, @var{start} and @var{end} must be\n"
288 "exact integers satisfying:\n\n"
289 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
1bbd0b84 290#define FUNC_NAME s_scm_substring
0f2d19dd 291{
c014a02e
ML
292 long int from;
293 long int to;
36284627 294 SCM substr;
685c0d71 295
d1ca2c64 296 SCM_VALIDATE_STRING (1, str);
685c0d71 297 SCM_VALIDATE_INUM (2, start);
d1ca2c64 298 SCM_VALIDATE_INUM_DEF (3, end, SCM_STRING_LENGTH (str));
685c0d71
DH
299
300 from = SCM_INUM (start);
d1ca2c64 301 SCM_ASSERT_RANGE (2, start, 0 <= from && from <= SCM_STRING_LENGTH (str));
685c0d71 302 to = SCM_INUM (end);
d1ca2c64 303 SCM_ASSERT_RANGE (3, end, from <= to && to <= SCM_STRING_LENGTH (str));
685c0d71 304
36284627
DH
305 substr = scm_mem2string (&SCM_STRING_CHARS (str)[from], to - from);
306 scm_remember_upto_here_1 (str);
307 return substr;
0f2d19dd 308}
1bbd0b84 309#undef FUNC_NAME
0f2d19dd 310
685c0d71 311
3b3b36dd 312SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
6fa73e72 313 (SCM args),
0d26a824
MG
314 "Return a newly allocated string whose characters form the\n"
315 "concatenation of the given strings, @var{args}.")
1bbd0b84 316#define FUNC_NAME s_scm_string_append
0f2d19dd
JB
317{
318 SCM res;
1be6b49c 319 size_t i = 0;
0f2d19dd 320 register SCM l, s;
a65b9c80 321 register unsigned char *data;
af45e3b0
DH
322
323 SCM_VALIDATE_REST_ARGUMENT (args);
324 for (l = args; !SCM_NULLP (l); l = SCM_CDR (l)) {
0f2d19dd 325 s = SCM_CAR (l);
34d19ef6 326 SCM_VALIDATE_STRING (SCM_ARGn, s);
d1ca2c64 327 i += SCM_STRING_LENGTH (s);
0f2d19dd 328 }
be54b15d 329 res = scm_allocate_string (i);
322ac0c5 330 data = SCM_STRING_UCHARS (res);
36284627 331 for (l = args; !SCM_NULLP (l);l = SCM_CDR (l)) {
0f2d19dd 332 s = SCM_CAR (l);
34f0f2b8 333 for (i = 0;i<SCM_STRING_LENGTH (s);i++) *data++ = SCM_STRING_UCHARS (s)[i];
0f2d19dd
JB
334 }
335 return res;
336}
1bbd0b84 337#undef FUNC_NAME
0f2d19dd 338
24933780 339
4d4528e7
SJ
340/* Converts the given Scheme string OBJ into a C string, containing a copy
341 of OBJ's content with a trailing null byte. If LENP is non-NULL, set
342 *LENP to the string's length.
343
344 When STR is non-NULL it receives the copy and is returned by the function,
345 otherwise new memory is allocated and the caller is responsible for
346 freeing it via free(). If out of memory, NULL is returned.
347
348 Note that Scheme strings may contain arbitrary data, including null
349 characters. This means that null termination is not a reliable way to
350 determine the length of the returned value. However, the function always
24933780
DH
351 copies the complete contents of OBJ, and sets *LENP to the length of the
352 scheme string (if LENP is non-null). */
af68e5e5 353#define FUNC_NAME "scm_c_string2str"
4d4528e7
SJ
354char *
355scm_c_string2str (SCM obj, char *str, size_t *lenp)
356{
357 size_t len;
358
af68e5e5 359 SCM_ASSERT (SCM_STRINGP (obj), obj, SCM_ARG1, FUNC_NAME);
4d4528e7
SJ
360 len = SCM_STRING_LENGTH (obj);
361
4d4528e7 362 if (str == NULL)
24933780
DH
363 {
364 /* FIXME: Should we use exported wrappers for malloc (and free), which
365 * allow windows DLLs to call the correct freeing function? */
366 str = (char *) malloc ((len + 1) * sizeof (char));
367 if (str == NULL)
368 return NULL;
369 }
4d4528e7
SJ
370
371 memcpy (str, SCM_STRING_CHARS (obj), len);
4d4528e7
SJ
372 scm_remember_upto_here_1 (obj);
373 str[len] = '\0';
374
375 if (lenp != NULL)
376 *lenp = len;
24933780 377
4d4528e7
SJ
378 return str;
379}
af68e5e5
SJ
380#undef FUNC_NAME
381
382
383/* Copy LEN characters at START from the Scheme string OBJ to memory
384 at STR. START is an index into OBJ; zero means the beginning of
385 the string. STR has already been allocated by the caller.
386
387 If START + LEN is off the end of OBJ, silently truncate the source
388 region to fit the string. If truncation occurs, the corresponding
389 area of STR is left unchanged. */
390#define FUNC_NAME "scm_c_substring2str"
391char *
392scm_c_substring2str (SCM obj, char *str, size_t start, size_t len)
393{
394 size_t src_length, effective_length;
395
396 SCM_ASSERT (SCM_STRINGP (obj), obj, SCM_ARG2, FUNC_NAME);
397 src_length = SCM_STRING_LENGTH (obj);
398 effective_length = (len + start <= src_length) ? len : src_length - start;
399 memcpy (str, SCM_STRING_CHARS (obj) + start, effective_length);
400 scm_remember_upto_here_1 (obj);
401 return str;
402}
403#undef FUNC_NAME
e53cc817 404
24933780 405
0f2d19dd
JB
406void
407scm_init_strings ()
0f2d19dd 408{
7c33806a
DH
409 scm_nullstr = scm_allocate_string (0);
410
a0599745 411#include "libguile/strings.x"
0f2d19dd
JB
412}
413
89e00824
ML
414
415/*
416 Local Variables:
417 c-file-style: "gnu"
418 End:
419*/