Small fixes. Gets to the REPL and `abort ()'s soon after.
[bpt/guile.git] / libguile / strings.c
1 /* Copyright (C) 1995,1996,1998,2000,2001, 2004, 2006 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library 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 GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18
19 \f
20
21 #include <string.h>
22 #include <stdio.h>
23
24 #include "libguile/_scm.h"
25 #include "libguile/chars.h"
26 #include "libguile/root.h"
27 #include "libguile/strings.h"
28 #include "libguile/deprecation.h"
29 #include "libguile/validate.h"
30 #include "libguile/dynwind.h"
31
32 \f
33
34 /* {Strings}
35 */
36
37
38 /* Stringbufs
39 *
40 * XXX - keeping an accurate refcount during GC seems to be quite
41 * tricky, so we just keep score of whether a stringbuf might be
42 * shared, not wether it definitely is.
43 *
44 * The scheme I (mvo) tried to keep an accurate reference count would
45 * recount all strings that point to a stringbuf during the mark-phase
46 * of the GC. This was done since one cannot access the stringbuf of
47 * a string when that string is freed (in order to decrease the
48 * reference count). The memory of the stringbuf might have been
49 * reused already for something completely different.
50 *
51 * This recounted worked for a small number of threads beating on
52 * cow-strings, but it failed randomly with more than 10 threads, say.
53 * I couldn't figure out what went wrong, so I used the conservative
54 * approach implemented below.
55 *
56 * A stringbuf needs to know its length, but only so that it can be
57 * reported when the stringbuf is freed.
58 *
59 * Stringbufs (and strings) are not stored very compactly: a stringbuf
60 * has room for about 2*sizeof(scm_t_bits)-1 bytes additional
61 * information. As a compensation, the code below is made more
62 * complicated by storing small strings inline in the double cell of a
63 * stringbuf. So we have fixstrings and bigstrings...
64 */
65
66 #define STRINGBUF_F_SHARED 0x100
67 #define STRINGBUF_F_INLINE 0x200
68
69 #define STRINGBUF_TAG scm_tc7_stringbuf
70 #define STRINGBUF_SHARED(buf) (SCM_CELL_WORD_0(buf) & STRINGBUF_F_SHARED)
71 #define STRINGBUF_INLINE(buf) (SCM_CELL_WORD_0(buf) & STRINGBUF_F_INLINE)
72
73 #define STRINGBUF_OUTLINE_CHARS(buf) ((char *)SCM_CELL_WORD_1(buf))
74 #define STRINGBUF_OUTLINE_LENGTH(buf) (SCM_CELL_WORD_2(buf))
75 #define STRINGBUF_INLINE_CHARS(buf) ((char *)SCM_CELL_OBJECT_LOC(buf,1))
76 #define STRINGBUF_INLINE_LENGTH(buf) (((size_t)SCM_CELL_WORD_0(buf))>>16)
77
78 #define STRINGBUF_CHARS(buf) (STRINGBUF_INLINE (buf) \
79 ? STRINGBUF_INLINE_CHARS (buf) \
80 : STRINGBUF_OUTLINE_CHARS (buf))
81 #define STRINGBUF_LENGTH(buf) (STRINGBUF_INLINE (buf) \
82 ? STRINGBUF_INLINE_LENGTH (buf) \
83 : STRINGBUF_OUTLINE_LENGTH (buf))
84
85 #define STRINGBUF_MAX_INLINE_LEN (3*sizeof(scm_t_bits))
86
87 #define SET_STRINGBUF_SHARED(buf) \
88 (SCM_SET_CELL_WORD_0 ((buf), SCM_CELL_WORD_0 (buf) | STRINGBUF_F_SHARED))
89
90 #if SCM_DEBUG
91 static size_t lenhist[1001];
92 #endif
93
94 static SCM
95 make_stringbuf (size_t len)
96 {
97 /* XXX - for the benefit of SCM_STRING_CHARS, SCM_SYMBOL_CHARS and
98 scm_i_symbol_chars, all stringbufs are null-terminated. Once
99 SCM_STRING_CHARS and SCM_SYMBOL_CHARS are removed and the code
100 has been changed for scm_i_symbol_chars, this null-termination
101 can be dropped.
102 */
103
104 #if SCM_DEBUG
105 if (len < 1000)
106 lenhist[len]++;
107 else
108 lenhist[1000]++;
109 #endif
110
111 if (len <= STRINGBUF_MAX_INLINE_LEN-1)
112 {
113 return scm_double_cell (STRINGBUF_TAG | STRINGBUF_F_INLINE | (len << 16),
114 0, 0, 0);
115 }
116 else
117 {
118 /* FIXME: Create an `scm_gc' equivalent to `GC_MALLOC_ATOMIC ()'. */
119 char *mem = GC_MALLOC_ATOMIC (len + 1);/* scm_gc_malloc (len+1, "string"); */
120 mem[len] = '\0';
121 return scm_double_cell (STRINGBUF_TAG, (scm_t_bits) mem,
122 (scm_t_bits) len, (scm_t_bits) 0);
123 }
124 }
125
126 /* Return a new stringbuf whose underlying storage consists of the LEN+1
127 octets pointed to by STR (the last octet is zero). */
128 SCM_C_INLINE_KEYWORD SCM
129 scm_i_take_stringbufn (char *str, size_t len)
130 {
131 scm_gc_register_collectable_memory (str, len + 1, "stringbuf");
132
133 return scm_double_cell (STRINGBUF_TAG, (scm_t_bits) str,
134 (scm_t_bits) len, (scm_t_bits) 0);
135 }
136
137 SCM
138 scm_i_stringbuf_mark (SCM buf)
139 {
140 return SCM_BOOL_F;
141 }
142
143 void
144 scm_i_stringbuf_free (SCM buf)
145 {
146 if (!STRINGBUF_INLINE (buf))
147 scm_gc_free (STRINGBUF_OUTLINE_CHARS (buf),
148 STRINGBUF_OUTLINE_LENGTH (buf) + 1, "string");
149 }
150
151 scm_i_pthread_mutex_t stringbuf_write_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
152
153 /* Copy-on-write strings.
154 */
155
156 #define STRING_TAG scm_tc7_string
157
158 #define STRING_STRINGBUF(str) (SCM_CELL_OBJECT_1(str))
159 #define STRING_START(str) ((size_t)SCM_CELL_WORD_2(str))
160 #define STRING_LENGTH(str) ((size_t)SCM_CELL_WORD_3(str))
161
162 #define SET_STRING_STRINGBUF(str,buf) (SCM_SET_CELL_OBJECT_1(str,buf))
163 #define SET_STRING_START(str,start) (SCM_SET_CELL_WORD_2(str,start))
164
165 #define IS_STRING(str) (SCM_NIMP(str) && SCM_TYP7(str) == STRING_TAG)
166
167 /* Read-only strings.
168 */
169
170 #define RO_STRING_TAG (scm_tc7_string + 0x200)
171 #define IS_RO_STRING(str) (SCM_CELL_TYPE(str)==RO_STRING_TAG)
172
173 /* Mutation-sharing substrings
174 */
175
176 #define SH_STRING_TAG (scm_tc7_string + 0x100)
177
178 #define SH_STRING_STRING(sh) (SCM_CELL_OBJECT_1(sh))
179 /* START and LENGTH as for STRINGs. */
180
181 #define IS_SH_STRING(str) (SCM_CELL_TYPE(str)==SH_STRING_TAG)
182
183 SCM
184 scm_i_make_string (size_t len, char **charsp)
185 {
186 SCM buf = make_stringbuf (len);
187 SCM res;
188 if (charsp)
189 *charsp = STRINGBUF_CHARS (buf);
190 res = scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
191 (scm_t_bits)0, (scm_t_bits) len);
192 return res;
193 }
194
195 static void
196 validate_substring_args (SCM str, size_t start, size_t end)
197 {
198 if (!IS_STRING (str))
199 scm_wrong_type_arg_msg (NULL, 0, str, "string");
200 if (start > STRING_LENGTH (str))
201 scm_out_of_range (NULL, scm_from_size_t (start));
202 if (end > STRING_LENGTH (str) || end < start)
203 scm_out_of_range (NULL, scm_from_size_t (end));
204 }
205
206 static inline void
207 get_str_buf_start (SCM *str, SCM *buf, size_t *start)
208 {
209 *start = STRING_START (*str);
210 if (IS_SH_STRING (*str))
211 {
212 *str = SH_STRING_STRING (*str);
213 *start += STRING_START (*str);
214 }
215 *buf = STRING_STRINGBUF (*str);
216 }
217
218 SCM
219 scm_i_substring (SCM str, size_t start, size_t end)
220 {
221 SCM buf;
222 size_t str_start;
223 get_str_buf_start (&str, &buf, &str_start);
224 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
225 SET_STRINGBUF_SHARED (buf);
226 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
227 return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
228 (scm_t_bits)str_start + start,
229 (scm_t_bits) end - start);
230 }
231
232 SCM
233 scm_i_substring_read_only (SCM str, size_t start, size_t end)
234 {
235 SCM buf;
236 size_t str_start;
237 get_str_buf_start (&str, &buf, &str_start);
238 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
239 SET_STRINGBUF_SHARED (buf);
240 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
241 return scm_double_cell (RO_STRING_TAG, SCM_UNPACK(buf),
242 (scm_t_bits)str_start + start,
243 (scm_t_bits) end - start);
244 }
245
246 SCM
247 scm_i_substring_copy (SCM str, size_t start, size_t end)
248 {
249 size_t len = end - start;
250 SCM buf, my_buf;
251 size_t str_start;
252 get_str_buf_start (&str, &buf, &str_start);
253 my_buf = make_stringbuf (len);
254 memcpy (STRINGBUF_CHARS (my_buf),
255 STRINGBUF_CHARS (buf) + str_start + start, len);
256 scm_remember_upto_here_1 (buf);
257 return scm_double_cell (STRING_TAG, SCM_UNPACK(my_buf),
258 (scm_t_bits)0, (scm_t_bits) len);
259 }
260
261 SCM
262 scm_i_substring_shared (SCM str, size_t start, size_t end)
263 {
264 if (start == 0 && end == STRING_LENGTH (str))
265 return str;
266 else
267 {
268 size_t len = end - start;
269 if (IS_SH_STRING (str))
270 {
271 start += STRING_START (str);
272 str = SH_STRING_STRING (str);
273 }
274 return scm_double_cell (SH_STRING_TAG, SCM_UNPACK(str),
275 (scm_t_bits)start, (scm_t_bits) len);
276 }
277 }
278
279 SCM
280 scm_c_substring (SCM str, size_t start, size_t end)
281 {
282 validate_substring_args (str, start, end);
283 return scm_i_substring (str, start, end);
284 }
285
286 SCM
287 scm_c_substring_read_only (SCM str, size_t start, size_t end)
288 {
289 validate_substring_args (str, start, end);
290 return scm_i_substring_read_only (str, start, end);
291 }
292
293 SCM
294 scm_c_substring_copy (SCM str, size_t start, size_t end)
295 {
296 validate_substring_args (str, start, end);
297 return scm_i_substring_copy (str, start, end);
298 }
299
300 SCM
301 scm_c_substring_shared (SCM str, size_t start, size_t end)
302 {
303 validate_substring_args (str, start, end);
304 return scm_i_substring_shared (str, start, end);
305 }
306
307 SCM
308 scm_i_string_mark (SCM str)
309 {
310 if (IS_SH_STRING (str))
311 return SH_STRING_STRING (str);
312 else
313 return STRING_STRINGBUF (str);
314 }
315
316 void
317 scm_i_string_free (SCM str)
318 {
319 }
320
321 /* Internal accessors
322 */
323
324 size_t
325 scm_i_string_length (SCM str)
326 {
327 return STRING_LENGTH (str);
328 }
329
330 const char *
331 scm_i_string_chars (SCM str)
332 {
333 SCM buf;
334 size_t start;
335 get_str_buf_start (&str, &buf, &start);
336 return STRINGBUF_CHARS (buf) + start;
337 }
338
339 char *
340 scm_i_string_writable_chars (SCM orig_str)
341 {
342 SCM buf, str = orig_str;
343 size_t start;
344
345 get_str_buf_start (&str, &buf, &start);
346 if (IS_RO_STRING (str))
347 scm_misc_error (NULL, "string is read-only: ~s", scm_list_1 (orig_str));
348
349 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
350 if (STRINGBUF_SHARED (buf))
351 {
352 /* Clone stringbuf. For this, we put all threads to sleep.
353 */
354
355 size_t len = STRING_LENGTH (str);
356 SCM new_buf;
357
358 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
359
360 new_buf = make_stringbuf (len);
361 memcpy (STRINGBUF_CHARS (new_buf),
362 STRINGBUF_CHARS (buf) + STRING_START (str), len);
363
364 scm_i_thread_put_to_sleep ();
365 SET_STRING_STRINGBUF (str, new_buf);
366 start -= STRING_START (str);
367 SET_STRING_START (str, 0);
368 scm_i_thread_wake_up ();
369
370 buf = new_buf;
371
372 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
373 }
374
375 return STRINGBUF_CHARS (buf) + start;
376 }
377
378 void
379 scm_i_string_stop_writing (void)
380 {
381 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
382 }
383
384 /* Symbols.
385
386 Basic symbol creation and accessing is done here, the rest is in
387 symbols.[hc]. This has been done to keep stringbufs and the
388 internals of strings and string-like objects confined to this file.
389 */
390
391 #define SYMBOL_STRINGBUF SCM_CELL_OBJECT_1
392
393 SCM
394 scm_i_make_symbol (SCM name, scm_t_bits flags,
395 unsigned long hash, SCM props)
396 {
397 SCM buf;
398 size_t start = STRING_START (name);
399 size_t length = STRING_LENGTH (name);
400
401 if (IS_SH_STRING (name))
402 {
403 name = SH_STRING_STRING (name);
404 start += STRING_START (name);
405 }
406 buf = SYMBOL_STRINGBUF (name);
407
408 if (start == 0 && length == STRINGBUF_LENGTH (buf))
409 {
410 /* reuse buf. */
411 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
412 SET_STRINGBUF_SHARED (buf);
413 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
414 }
415 else
416 {
417 /* make new buf. */
418 SCM new_buf = make_stringbuf (length);
419 memcpy (STRINGBUF_CHARS (new_buf),
420 STRINGBUF_CHARS (buf) + start, length);
421 buf = new_buf;
422 }
423 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
424 (scm_t_bits) hash, SCM_UNPACK (props));
425 }
426
427 SCM
428 scm_i_c_make_symbol (const char *name, size_t len,
429 scm_t_bits flags, unsigned long hash, SCM props)
430 {
431 SCM buf = make_stringbuf (len);
432 memcpy (STRINGBUF_CHARS (buf), name, len);
433
434 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
435 (scm_t_bits) hash, SCM_UNPACK (props));
436 }
437
438 /* Return a new symbol that uses the LEN bytes pointed to by NAME as its
439 underlying storage. */
440 SCM
441 scm_i_c_take_symbol (char *name, size_t len,
442 scm_t_bits flags, unsigned long hash, SCM props)
443 {
444 SCM buf = scm_i_take_stringbufn (name, len);
445
446 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
447 (scm_t_bits) hash, SCM_UNPACK (props));
448 }
449
450 size_t
451 scm_i_symbol_length (SCM sym)
452 {
453 return STRINGBUF_LENGTH (SYMBOL_STRINGBUF (sym));
454 }
455
456 const char *
457 scm_i_symbol_chars (SCM sym)
458 {
459 SCM buf = SYMBOL_STRINGBUF (sym);
460 return STRINGBUF_CHARS (buf);
461 }
462
463 SCM
464 scm_i_symbol_mark (SCM sym)
465 {
466 scm_gc_mark (SYMBOL_STRINGBUF (sym));
467 return SCM_CELL_OBJECT_3 (sym);
468 }
469
470 void
471 scm_i_symbol_free (SCM sym)
472 {
473 }
474
475 SCM
476 scm_i_symbol_substring (SCM sym, size_t start, size_t end)
477 {
478 SCM buf = SYMBOL_STRINGBUF (sym);
479 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
480 SET_STRINGBUF_SHARED (buf);
481 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
482 return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
483 (scm_t_bits)start, (scm_t_bits) end - start);
484 }
485
486 /* Debugging
487 */
488
489 #if SCM_DEBUG
490
491 SCM scm_sys_string_dump (SCM);
492 SCM scm_sys_symbol_dump (SCM);
493 SCM scm_sys_stringbuf_hist (void);
494
495 SCM_DEFINE (scm_sys_string_dump, "%string-dump", 1, 0, 0,
496 (SCM str),
497 "")
498 #define FUNC_NAME s_scm_sys_string_dump
499 {
500 SCM_VALIDATE_STRING (1, str);
501 fprintf (stderr, "%p:\n", str);
502 fprintf (stderr, " start: %u\n", STRING_START (str));
503 fprintf (stderr, " len: %u\n", STRING_LENGTH (str));
504 if (IS_SH_STRING (str))
505 {
506 fprintf (stderr, " string: %p\n", SH_STRING_STRING (str));
507 fprintf (stderr, "\n");
508 scm_sys_string_dump (SH_STRING_STRING (str));
509 }
510 else
511 {
512 SCM buf = STRING_STRINGBUF (str);
513 fprintf (stderr, " buf: %p\n", buf);
514 fprintf (stderr, " chars: %p\n", STRINGBUF_CHARS (buf));
515 fprintf (stderr, " length: %u\n", STRINGBUF_LENGTH (buf));
516 fprintf (stderr, " flags: %x\n", (SCM_CELL_WORD_0 (buf) & 0x300));
517 }
518 return SCM_UNSPECIFIED;
519 }
520 #undef FUNC_NAME
521
522 SCM_DEFINE (scm_sys_symbol_dump, "%symbol-dump", 1, 0, 0,
523 (SCM sym),
524 "")
525 #define FUNC_NAME s_scm_sys_symbol_dump
526 {
527 SCM_VALIDATE_SYMBOL (1, sym);
528 fprintf (stderr, "%p:\n", sym);
529 fprintf (stderr, " hash: %lu\n", scm_i_symbol_hash (sym));
530 {
531 SCM buf = SYMBOL_STRINGBUF (sym);
532 fprintf (stderr, " buf: %p\n", buf);
533 fprintf (stderr, " chars: %p\n", STRINGBUF_CHARS (buf));
534 fprintf (stderr, " length: %u\n", STRINGBUF_LENGTH (buf));
535 fprintf (stderr, " shared: %u\n", STRINGBUF_SHARED (buf));
536 }
537 return SCM_UNSPECIFIED;
538 }
539 #undef FUNC_NAME
540
541 SCM_DEFINE (scm_sys_stringbuf_hist, "%stringbuf-hist", 0, 0, 0,
542 (void),
543 "")
544 #define FUNC_NAME s_scm_sys_stringbuf_hist
545 {
546 int i;
547 for (i = 0; i < 1000; i++)
548 if (lenhist[i])
549 fprintf (stderr, " %3d: %u\n", i, lenhist[i]);
550 fprintf (stderr, ">999: %u\n", lenhist[1000]);
551 return SCM_UNSPECIFIED;
552 }
553 #undef FUNC_NAME
554
555 #endif
556
557 \f
558
559 SCM_DEFINE (scm_string_p, "string?", 1, 0, 0,
560 (SCM obj),
561 "Return @code{#t} if @var{obj} is a string, else @code{#f}.")
562 #define FUNC_NAME s_scm_string_p
563 {
564 return scm_from_bool (IS_STRING (obj));
565 }
566 #undef FUNC_NAME
567
568
569 SCM_REGISTER_PROC (s_scm_list_to_string, "list->string", 1, 0, 0, scm_string);
570
571 SCM_DEFINE (scm_string, "string", 0, 0, 1,
572 (SCM chrs),
573 "@deffnx {Scheme Procedure} list->string chrs\n"
574 "Return a newly allocated string composed of the arguments,\n"
575 "@var{chrs}.")
576 #define FUNC_NAME s_scm_string
577 {
578 SCM result;
579 size_t len;
580 char *data;
581
582 {
583 long i = scm_ilength (chrs);
584
585 SCM_ASSERT (i >= 0, chrs, SCM_ARG1, FUNC_NAME);
586 len = i;
587 }
588
589 result = scm_i_make_string (len, &data);
590 while (len > 0 && scm_is_pair (chrs))
591 {
592 SCM elt = SCM_CAR (chrs);
593
594 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
595 *data++ = SCM_CHAR (elt);
596 chrs = SCM_CDR (chrs);
597 len--;
598 }
599 if (len > 0)
600 scm_misc_error (NULL, "list changed while constructing string", SCM_EOL);
601 if (!scm_is_null (chrs))
602 scm_wrong_type_arg_msg (NULL, 0, chrs, "proper list");
603
604 return result;
605 }
606 #undef FUNC_NAME
607
608 SCM_DEFINE (scm_make_string, "make-string", 1, 1, 0,
609 (SCM k, SCM chr),
610 "Return a newly allocated string of\n"
611 "length @var{k}. If @var{chr} is given, then all elements of\n"
612 "the string are initialized to @var{chr}, otherwise the contents\n"
613 "of the @var{string} are unspecified.")
614 #define FUNC_NAME s_scm_make_string
615 {
616 return scm_c_make_string (scm_to_size_t (k), chr);
617 }
618 #undef FUNC_NAME
619
620 SCM
621 scm_c_make_string (size_t len, SCM chr)
622 #define FUNC_NAME NULL
623 {
624 char *dst;
625 SCM res = scm_i_make_string (len, &dst);
626
627 if (!SCM_UNBNDP (chr))
628 {
629 SCM_VALIDATE_CHAR (0, chr);
630 memset (dst, SCM_CHAR (chr), len);
631 }
632
633 return res;
634 }
635 #undef FUNC_NAME
636
637 SCM_DEFINE (scm_string_length, "string-length", 1, 0, 0,
638 (SCM string),
639 "Return the number of characters in @var{string}.")
640 #define FUNC_NAME s_scm_string_length
641 {
642 SCM_VALIDATE_STRING (1, string);
643 return scm_from_size_t (STRING_LENGTH (string));
644 }
645 #undef FUNC_NAME
646
647 size_t
648 scm_c_string_length (SCM string)
649 {
650 if (!IS_STRING (string))
651 scm_wrong_type_arg_msg (NULL, 0, string, "string");
652 return STRING_LENGTH (string);
653 }
654
655 SCM_DEFINE (scm_string_ref, "string-ref", 2, 0, 0,
656 (SCM str, SCM k),
657 "Return character @var{k} of @var{str} using zero-origin\n"
658 "indexing. @var{k} must be a valid index of @var{str}.")
659 #define FUNC_NAME s_scm_string_ref
660 {
661 unsigned long idx;
662
663 SCM_VALIDATE_STRING (1, str);
664 idx = scm_to_unsigned_integer (k, 0, scm_i_string_length (str)-1);
665 return SCM_MAKE_CHAR (scm_i_string_chars (str)[idx]);
666 }
667 #undef FUNC_NAME
668
669 SCM
670 scm_c_string_ref (SCM str, size_t p)
671 {
672 if (p >= scm_i_string_length (str))
673 scm_out_of_range (NULL, scm_from_size_t (p));
674 return SCM_MAKE_CHAR (scm_i_string_chars (str)[p]);
675 }
676
677 SCM_DEFINE (scm_string_set_x, "string-set!", 3, 0, 0,
678 (SCM str, SCM k, SCM chr),
679 "Store @var{chr} in element @var{k} of @var{str} and return\n"
680 "an unspecified value. @var{k} must be a valid index of\n"
681 "@var{str}.")
682 #define FUNC_NAME s_scm_string_set_x
683 {
684 unsigned long idx;
685
686 SCM_VALIDATE_STRING (1, str);
687 idx = scm_to_unsigned_integer (k, 0, scm_i_string_length(str)-1);
688 SCM_VALIDATE_CHAR (3, chr);
689 {
690 char *dst = scm_i_string_writable_chars (str);
691 dst[idx] = SCM_CHAR (chr);
692 scm_i_string_stop_writing ();
693 }
694 return SCM_UNSPECIFIED;
695 }
696 #undef FUNC_NAME
697
698 void
699 scm_c_string_set_x (SCM str, size_t p, SCM chr)
700 {
701 if (p >= scm_i_string_length (str))
702 scm_out_of_range (NULL, scm_from_size_t (p));
703 {
704 char *dst = scm_i_string_writable_chars (str);
705 dst[p] = SCM_CHAR (chr);
706 scm_i_string_stop_writing ();
707 }
708 }
709
710 SCM_DEFINE (scm_substring, "substring", 2, 1, 0,
711 (SCM str, SCM start, SCM end),
712 "Return a newly allocated string formed from the characters\n"
713 "of @var{str} beginning with index @var{start} (inclusive) and\n"
714 "ending with index @var{end} (exclusive).\n"
715 "@var{str} must be a string, @var{start} and @var{end} must be\n"
716 "exact integers satisfying:\n\n"
717 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
718 #define FUNC_NAME s_scm_substring
719 {
720 size_t len, from, to;
721
722 SCM_VALIDATE_STRING (1, str);
723 len = scm_i_string_length (str);
724 from = scm_to_unsigned_integer (start, 0, len);
725 if (SCM_UNBNDP (end))
726 to = len;
727 else
728 to = scm_to_unsigned_integer (end, from, len);
729 return scm_i_substring (str, from, to);
730 }
731 #undef FUNC_NAME
732
733 SCM_DEFINE (scm_substring_read_only, "substring/read-only", 2, 1, 0,
734 (SCM str, SCM start, SCM end),
735 "Return a newly allocated string formed from the characters\n"
736 "of @var{str} beginning with index @var{start} (inclusive) and\n"
737 "ending with index @var{end} (exclusive).\n"
738 "@var{str} must be a string, @var{start} and @var{end} must be\n"
739 "exact integers satisfying:\n"
740 "\n"
741 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).\n"
742 "\n"
743 "The returned string is read-only.\n")
744 #define FUNC_NAME s_scm_substring_read_only
745 {
746 size_t len, from, to;
747
748 SCM_VALIDATE_STRING (1, str);
749 len = scm_i_string_length (str);
750 from = scm_to_unsigned_integer (start, 0, len);
751 if (SCM_UNBNDP (end))
752 to = len;
753 else
754 to = scm_to_unsigned_integer (end, from, len);
755 return scm_i_substring_read_only (str, from, to);
756 }
757 #undef FUNC_NAME
758
759 SCM_DEFINE (scm_substring_copy, "substring/copy", 2, 1, 0,
760 (SCM str, SCM start, SCM end),
761 "Return a newly allocated string formed from the characters\n"
762 "of @var{str} beginning with index @var{start} (inclusive) and\n"
763 "ending with index @var{end} (exclusive).\n"
764 "@var{str} must be a string, @var{start} and @var{end} must be\n"
765 "exact integers satisfying:\n\n"
766 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
767 #define FUNC_NAME s_scm_substring_copy
768 {
769 /* For the Scheme version, START is mandatory, but for the C
770 version, it is optional. See scm_string_copy in srfi-13.c for a
771 rationale.
772 */
773
774 size_t from, to;
775
776 SCM_VALIDATE_STRING (1, str);
777 scm_i_get_substring_spec (scm_i_string_length (str),
778 start, &from, end, &to);
779 return scm_i_substring_copy (str, from, to);
780 }
781 #undef FUNC_NAME
782
783 SCM_DEFINE (scm_substring_shared, "substring/shared", 2, 1, 0,
784 (SCM str, SCM start, SCM end),
785 "Return string that indirectly refers to the characters\n"
786 "of @var{str} beginning with index @var{start} (inclusive) and\n"
787 "ending with index @var{end} (exclusive).\n"
788 "@var{str} must be a string, @var{start} and @var{end} must be\n"
789 "exact integers satisfying:\n\n"
790 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
791 #define FUNC_NAME s_scm_substring_shared
792 {
793 size_t len, from, to;
794
795 SCM_VALIDATE_STRING (1, str);
796 len = scm_i_string_length (str);
797 from = scm_to_unsigned_integer (start, 0, len);
798 if (SCM_UNBNDP (end))
799 to = len;
800 else
801 to = scm_to_unsigned_integer (end, from, len);
802 return scm_i_substring_shared (str, from, to);
803 }
804 #undef FUNC_NAME
805
806 SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
807 (SCM args),
808 "Return a newly allocated string whose characters form the\n"
809 "concatenation of the given strings, @var{args}.")
810 #define FUNC_NAME s_scm_string_append
811 {
812 SCM res;
813 size_t i = 0;
814 SCM l, s;
815 char *data;
816
817 SCM_VALIDATE_REST_ARGUMENT (args);
818 for (l = args; !scm_is_null (l); l = SCM_CDR (l))
819 {
820 s = SCM_CAR (l);
821 SCM_VALIDATE_STRING (SCM_ARGn, s);
822 i += scm_i_string_length (s);
823 }
824 res = scm_i_make_string (i, &data);
825 for (l = args; !scm_is_null (l); l = SCM_CDR (l))
826 {
827 size_t len;
828 s = SCM_CAR (l);
829 SCM_VALIDATE_STRING (SCM_ARGn, s);
830 len = scm_i_string_length (s);
831 memcpy (data, scm_i_string_chars (s), len);
832 data += len;
833 scm_remember_upto_here_1 (s);
834 }
835 return res;
836 }
837 #undef FUNC_NAME
838
839 int
840 scm_is_string (SCM obj)
841 {
842 return IS_STRING (obj);
843 }
844
845 SCM
846 scm_from_locale_stringn (const char *str, size_t len)
847 {
848 SCM res;
849 char *dst;
850
851 if (len == (size_t)-1)
852 len = strlen (str);
853 res = scm_i_make_string (len, &dst);
854 memcpy (dst, str, len);
855 return res;
856 }
857
858 SCM
859 scm_from_locale_string (const char *str)
860 {
861 return scm_from_locale_stringn (str, -1);
862 }
863
864 SCM
865 scm_take_locale_stringn (char *str, size_t len)
866 {
867 SCM buf, res;
868
869 if (len == (size_t)-1)
870 len = strlen (str);
871 else
872 {
873 /* Ensure STR is null terminated. A realloc for 1 extra byte should
874 often be satisfied from the alignment padding after the block, with
875 no actual data movement. */
876 str = scm_realloc (str, len+1);
877 str[len] = '\0';
878 }
879
880 buf = scm_i_take_stringbufn (str, len);
881 res = scm_double_cell (STRING_TAG,
882 SCM_UNPACK (buf),
883 (scm_t_bits) 0, (scm_t_bits) len);
884 return res;
885 }
886
887 SCM
888 scm_take_locale_string (char *str)
889 {
890 return scm_take_locale_stringn (str, -1);
891 }
892
893 char *
894 scm_to_locale_stringn (SCM str, size_t *lenp)
895 {
896 char *res;
897 size_t len;
898
899 if (!scm_is_string (str))
900 scm_wrong_type_arg_msg (NULL, 0, str, "string");
901 len = scm_i_string_length (str);
902 res = scm_malloc (len + ((lenp==NULL)? 1 : 0));
903 memcpy (res, scm_i_string_chars (str), len);
904 if (lenp == NULL)
905 {
906 res[len] = '\0';
907 if (strlen (res) != len)
908 {
909 free (res);
910 scm_misc_error (NULL,
911 "string contains #\\nul character: ~S",
912 scm_list_1 (str));
913 }
914 }
915 else
916 *lenp = len;
917
918 scm_remember_upto_here_1 (str);
919 return res;
920 }
921
922 char *
923 scm_to_locale_string (SCM str)
924 {
925 return scm_to_locale_stringn (str, NULL);
926 }
927
928 size_t
929 scm_to_locale_stringbuf (SCM str, char *buf, size_t max_len)
930 {
931 size_t len;
932
933 if (!scm_is_string (str))
934 scm_wrong_type_arg_msg (NULL, 0, str, "string");
935 len = scm_i_string_length (str);
936 memcpy (buf, scm_i_string_chars (str), (len > max_len)? max_len : len);
937 scm_remember_upto_here_1 (str);
938 return len;
939 }
940
941 /* converts C scm_array of strings to SCM scm_list of strings. */
942 /* If argc < 0, a null terminated scm_array is assumed. */
943 SCM
944 scm_makfromstrs (int argc, char **argv)
945 {
946 int i = argc;
947 SCM lst = SCM_EOL;
948 if (0 > i)
949 for (i = 0; argv[i]; i++);
950 while (i--)
951 lst = scm_cons (scm_from_locale_string (argv[i]), lst);
952 return lst;
953 }
954
955 /* Return a newly allocated array of char pointers to each of the strings
956 in args, with a terminating NULL pointer. */
957
958 char **
959 scm_i_allocate_string_pointers (SCM list)
960 {
961 char **result;
962 int len = scm_ilength (list);
963 int i;
964
965 if (len < 0)
966 scm_wrong_type_arg_msg (NULL, 0, list, "proper list");
967
968 scm_dynwind_begin (0);
969
970 result = (char **) scm_malloc ((len + 1) * sizeof (char *));
971 result[len] = NULL;
972 scm_dynwind_unwind_handler (free, result, 0);
973
974 /* The list might be have been modified in another thread, so
975 we check LIST before each access.
976 */
977 for (i = 0; i < len && scm_is_pair (list); i++)
978 {
979 result[i] = scm_to_locale_string (SCM_CAR (list));
980 list = SCM_CDR (list);
981 }
982
983 scm_dynwind_end ();
984 return result;
985 }
986
987 void
988 scm_i_free_string_pointers (char **pointers)
989 {
990 int i;
991
992 for (i = 0; pointers[i]; i++)
993 free (pointers[i]);
994 free (pointers);
995 }
996
997 void
998 scm_i_get_substring_spec (size_t len,
999 SCM start, size_t *cstart,
1000 SCM end, size_t *cend)
1001 {
1002 if (SCM_UNBNDP (start))
1003 *cstart = 0;
1004 else
1005 *cstart = scm_to_unsigned_integer (start, 0, len);
1006
1007 if (SCM_UNBNDP (end))
1008 *cend = len;
1009 else
1010 *cend = scm_to_unsigned_integer (end, *cstart, len);
1011 }
1012
1013 #if SCM_ENABLE_DEPRECATED
1014
1015 /* When these definitions are removed, it becomes reasonable to use
1016 read-only strings for string literals. For that, change the reader
1017 to create string literals with scm_c_substring_read_only instead of
1018 with scm_c_substring_copy.
1019 */
1020
1021 int
1022 scm_i_deprecated_stringp (SCM str)
1023 {
1024 scm_c_issue_deprecation_warning
1025 ("SCM_STRINGP is deprecated. Use scm_is_string instead.");
1026
1027 return scm_is_string (str);
1028 }
1029
1030 char *
1031 scm_i_deprecated_string_chars (SCM str)
1032 {
1033 char *chars;
1034
1035 scm_c_issue_deprecation_warning
1036 ("SCM_STRING_CHARS is deprecated. See the manual for alternatives.");
1037
1038 /* We don't accept shared substrings here since they are not
1039 null-terminated.
1040 */
1041 if (IS_SH_STRING (str))
1042 scm_misc_error (NULL,
1043 "SCM_STRING_CHARS does not work with shared substrings.",
1044 SCM_EOL);
1045
1046 /* We explicitely test for read-only strings to produce a better
1047 error message.
1048 */
1049
1050 if (IS_RO_STRING (str))
1051 scm_misc_error (NULL,
1052 "SCM_STRING_CHARS does not work with read-only strings.",
1053 SCM_EOL);
1054
1055 /* The following is still wrong, of course...
1056 */
1057 chars = scm_i_string_writable_chars (str);
1058 scm_i_string_stop_writing ();
1059 return chars;
1060 }
1061
1062 size_t
1063 scm_i_deprecated_string_length (SCM str)
1064 {
1065 scm_c_issue_deprecation_warning
1066 ("SCM_STRING_LENGTH is deprecated. Use scm_c_string_length instead.");
1067 return scm_c_string_length (str);
1068 }
1069
1070 #endif
1071
1072 void
1073 scm_init_strings ()
1074 {
1075 scm_nullstr = scm_i_make_string (0, NULL);
1076
1077 #include "libguile/strings.x"
1078 }
1079
1080
1081 /*
1082 Local Variables:
1083 c-file-style: "gnu"
1084 End:
1085 */